summaryrefslogtreecommitdiff
path: root/sys/src/cmd/unix/drawterm/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/src/cmd/unix/drawterm/kern')
-rw-r--r--sys/src/cmd/unix/drawterm/kern/Makefile50
-rw-r--r--sys/src/cmd/unix/drawterm/kern/allocb.c165
-rw-r--r--sys/src/cmd/unix/drawterm/kern/cache.c46
-rw-r--r--sys/src/cmd/unix/drawterm/kern/chan.c1494
-rw-r--r--sys/src/cmd/unix/drawterm/kern/dat.h519
-rw-r--r--sys/src/cmd/unix/drawterm/kern/data.c31
-rw-r--r--sys/src/cmd/unix/drawterm/kern/dev.c468
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devaudio-none.c49
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devaudio-unix.c183
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devaudio.c372
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devaudio.h25
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devcons.c1193
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devdraw.c2148
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devfs-posix.c635
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devfs-win32.c707
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devip-posix.c210
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devip-win32.c212
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devip.c938
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devip.h19
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devlfd.c126
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devmnt.c1216
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devmouse.c237
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devpipe.c398
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devroot.c299
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devssl.c1517
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devtab.c35
-rw-r--r--sys/src/cmd/unix/drawterm/kern/devtls.c2185
-rw-r--r--sys/src/cmd/unix/drawterm/kern/error.c50
-rw-r--r--sys/src/cmd/unix/drawterm/kern/error.h50
-rw-r--r--sys/src/cmd/unix/drawterm/kern/exportfs.c821
-rw-r--r--sys/src/cmd/unix/drawterm/kern/fns.h392
-rw-r--r--sys/src/cmd/unix/drawterm/kern/netif.h133
-rw-r--r--sys/src/cmd/unix/drawterm/kern/parse.c113
-rw-r--r--sys/src/cmd/unix/drawterm/kern/pgrp.c272
-rw-r--r--sys/src/cmd/unix/drawterm/kern/posix.c225
-rw-r--r--sys/src/cmd/unix/drawterm/kern/procinit.c67
-rw-r--r--sys/src/cmd/unix/drawterm/kern/qio.c1524
-rw-r--r--sys/src/cmd/unix/drawterm/kern/qlock.c94
-rw-r--r--sys/src/cmd/unix/drawterm/kern/rendez.c90
-rw-r--r--sys/src/cmd/unix/drawterm/kern/rwlock.c39
-rw-r--r--sys/src/cmd/unix/drawterm/kern/screen.h63
-rw-r--r--sys/src/cmd/unix/drawterm/kern/sleep.c90
-rw-r--r--sys/src/cmd/unix/drawterm/kern/smalloc.c18
-rw-r--r--sys/src/cmd/unix/drawterm/kern/stub.c171
-rw-r--r--sys/src/cmd/unix/drawterm/kern/sysfile.c1244
-rw-r--r--sys/src/cmd/unix/drawterm/kern/sysproc.c32
-rw-r--r--sys/src/cmd/unix/drawterm/kern/term.c205
-rw-r--r--sys/src/cmd/unix/drawterm/kern/uart.c15
-rw-r--r--sys/src/cmd/unix/drawterm/kern/unused/syscall.c837
-rw-r--r--sys/src/cmd/unix/drawterm/kern/waserror.c27
-rw-r--r--sys/src/cmd/unix/drawterm/kern/win32.c470
51 files changed, 0 insertions, 22519 deletions
diff --git a/sys/src/cmd/unix/drawterm/kern/Makefile b/sys/src/cmd/unix/drawterm/kern/Makefile
deleted file mode 100644
index c4cf4b21b..000000000
--- a/sys/src/cmd/unix/drawterm/kern/Makefile
+++ /dev/null
@@ -1,50 +0,0 @@
-ROOT=..
-include ../Make.config
-LIB=libkern.a
-
-OFILES=\
- allocb.$O\
- cache.$O\
- chan.$O\
- data.$O\
- dev.$O\
- devaudio.$O\
- devaudio-$(AUDIO).$O\
- devcons.$O\
- devdraw.$O\
- devfs-$(OS).$O\
- devip.$O\
- devip-$(OS).$O\
- devlfd.$O\
- devmnt.$O\
- devmouse.$O\
- devpipe.$O\
- devroot.$O\
- devssl.$O\
- devtls.$O\
- devtab.$O\
- error.$O\
- parse.$O\
- pgrp.$O\
- procinit.$O\
- rwlock.$O\
- sleep.$O\
- smalloc.$O\
- stub.$O\
- sysfile.$O\
- sysproc.$O\
- qio.$O\
- qlock.$O\
- term.$O\
- uart.$O\
- waserror.$O\
- $(OS).$O
-
-default: $(LIB)
-$(LIB): $(OFILES)
- $(AR) r $(LIB) $(OFILES)
- $(RANLIB) $(LIB)
-
-%.$O: %.c
- $(CC) $(CFLAGS) $*.c
-
diff --git a/sys/src/cmd/unix/drawterm/kern/allocb.c b/sys/src/cmd/unix/drawterm/kern/allocb.c
deleted file mode 100644
index ab1595c89..000000000
--- a/sys/src/cmd/unix/drawterm/kern/allocb.c
+++ /dev/null
@@ -1,165 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-enum
-{
- Hdrspc = 64, /* leave room for high-level headers */
- Bdead = 0x51494F42, /* "QIOB" */
-};
-
-struct
-{
- Lock lk;
- ulong bytes;
-} ialloc;
-
-static Block*
-_allocb(int size)
-{
- Block *b;
- uintptr addr;
-
- if((b = mallocz(sizeof(Block)+size+Hdrspc, 0)) == nil)
- return nil;
-
- b->next = nil;
- b->list = nil;
- b->free = 0;
- b->flag = 0;
-
- /* align start of data portion by rounding up */
- addr = (uintptr)b;
- addr = ROUND(addr + sizeof(Block), BLOCKALIGN);
- b->base = (uchar*)addr;
-
- /* align end of data portion by rounding down */
- b->lim = ((uchar*)b) + sizeof(Block)+size+Hdrspc;
- addr = (uintptr)(b->lim);
- addr = addr & ~(BLOCKALIGN-1);
- b->lim = (uchar*)addr;
-
- /* leave sluff at beginning for added headers */
- b->rp = b->lim - ROUND(size, BLOCKALIGN);
- if(b->rp < b->base)
- panic("_allocb");
- b->wp = b->rp;
-
- return b;
-}
-
-Block*
-allocb(int size)
-{
- Block *b;
-
- /*
- * Check in a process and wait until successful.
- * Can still error out of here, though.
- */
- if(up == nil)
- panic("allocb without up: %p\n", getcallerpc(&size));
- if((b = _allocb(size)) == nil){
- panic("allocb: no memory for %d bytes\n", size);
- }
- setmalloctag(b, getcallerpc(&size));
-
- return b;
-}
-
-Block*
-iallocb(int size)
-{
- Block *b;
- static int m1, m2;
-
- if(ialloc.bytes > conf.ialloc){
- if((m1++%10000)==0)
- print("iallocb: limited %lud/%lud\n",
- ialloc.bytes, conf.ialloc);
- return 0;
- }
-
- if((b = _allocb(size)) == nil){
- if((m2++%10000)==0)
- print("iallocb: no memory %lud/%lud\n",
- ialloc.bytes, conf.ialloc);
- return nil;
- }
- setmalloctag(b, getcallerpc(&size));
- b->flag = BINTR;
-
- ilock(&ialloc.lk);
- ialloc.bytes += b->lim - b->base;
- iunlock(&ialloc.lk);
-
- return b;
-}
-
-void
-freeb(Block *b)
-{
- void *dead = (void*)Bdead;
-
- if(b == nil)
- return;
-
- /*
- * drivers which perform non cache coherent DMA manage their own buffer
- * pool of uncached buffers and provide their own free routine.
- */
- if(b->free) {
- b->free(b);
- return;
- }
- if(b->flag & BINTR) {
- ilock(&ialloc.lk);
- ialloc.bytes -= b->lim - b->base;
- iunlock(&ialloc.lk);
- }
-
- /* poison the block in case someone is still holding onto it */
- b->next = dead;
- b->rp = dead;
- b->wp = dead;
- b->lim = dead;
- b->base = dead;
-
- free(b);
-}
-
-void
-checkb(Block *b, char *msg)
-{
- void *dead = (void*)Bdead;
-
- if(b == dead)
- panic("checkb b %s %lux", msg, b);
- if(b->base == dead || b->lim == dead || b->next == dead
- || b->rp == dead || b->wp == dead){
- print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n",
- b->base, b->lim, b->next);
- print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp);
- panic("checkb dead: %s\n", msg);
- }
-
- if(b->base > b->lim)
- panic("checkb 0 %s %lux %lux", msg, b->base, b->lim);
- if(b->rp < b->base)
- panic("checkb 1 %s %lux %lux", msg, b->base, b->rp);
- if(b->wp < b->base)
- panic("checkb 2 %s %lux %lux", msg, b->base, b->wp);
- if(b->rp > b->lim)
- panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim);
- if(b->wp > b->lim)
- panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim);
-
-}
-
-void
-iallocsummary(void)
-{
- print("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc);
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/cache.c b/sys/src/cmd/unix/drawterm/kern/cache.c
deleted file mode 100644
index 56ee23ca7..000000000
--- a/sys/src/cmd/unix/drawterm/kern/cache.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-
-void
-cinit(void)
-{
-}
-
-void
-copen(Chan *c)
-{
- USED(c);
-}
-
-int
-cread(Chan *c, uchar *buf, int len, vlong off)
-{
- USED(c);
- USED(buf);
- USED(len);
- USED(off);
-
- return 0;
-}
-
-void
-cupdate(Chan *c, uchar *buf, int len, vlong off)
-{
- USED(c);
- USED(buf);
- USED(len);
- USED(off);
-}
-
-void
-cwrite(Chan* c, uchar *buf, int len, vlong off)
-{
- USED(c);
- USED(buf);
- USED(len);
- USED(off);
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/chan.c b/sys/src/cmd/unix/drawterm/kern/chan.c
deleted file mode 100644
index 7105f3a69..000000000
--- a/sys/src/cmd/unix/drawterm/kern/chan.c
+++ /dev/null
@@ -1,1494 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-int chandebug=0; /* toggled by sysr1 */
-QLock chanprint; /* probably asking for trouble (deadlocks) -rsc */
-
-int domount(Chan**, Mhead**);
-
-void
-dumpmount(void) /* DEBUGGING */
-{
- Pgrp *pg;
- Mount *t;
- Mhead **h, **he, *f;
-
- if(up == nil){
- print("no process for dumpmount\n");
- return;
- }
- pg = up->pgrp;
- if(pg == nil){
- print("no pgrp for dumpmount\n");
- return;
- }
- rlock(&pg->ns);
- if(waserror()) {
- runlock(&pg->ns);
- nexterror();
- }
-
- he = &pg->mnthash[MNTHASH];
- for(h = pg->mnthash; h < he; h++) {
- for(f = *h; f; f = f->hash) {
- print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f,
- f->from->name->s, f->from->qid.path,
- f->from->qid.vers, devtab[f->from->type]->dc,
- f->from->dev);
- for(t = f->mount; t; t = t->next)
- print("\t%p: %s (umh %p) (path %.8llux dev %C %lud)\n", t, t->to->name->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev);
- }
- }
- poperror();
- runlock(&pg->ns);
-}
-
-
-char*
-c2name(Chan *c) /* DEBUGGING */
-{
- if(c == nil)
- return "<nil chan>";
- if(c->name == nil)
- return "<nil name>";
- if(c->name->s == nil)
- return "<nil name.s>";
- return c->name->s;
-}
-
-enum
-{
- CNAMESLOP = 20
-};
-
-struct
-{
- Lock lk;
- int fid;
- Chan *free;
- Chan *list;
-}chanalloc;
-
-typedef struct Elemlist Elemlist;
-
-struct Elemlist
-{
- char *name; /* copy of name, so '/' can be overwritten */
- int nelems;
- char **elems;
- int *off;
- int mustbedir;
-};
-
-#define SEP(c) ((c) == 0 || (c) == '/')
-void cleancname(Cname*);
-
-int
-isdotdot(char *p)
-{
- return p[0]=='.' && p[1]=='.' && p[2]=='\0';
-}
-
-int
-incref(Ref *r)
-{
- int x;
-
- lock(&r->lk);
- x = ++r->ref;
- unlock(&r->lk);
- return x;
-}
-
-int
-decref(Ref *r)
-{
- int x;
-
- lock(&r->lk);
- x = --r->ref;
- unlock(&r->lk);
- if(x < 0)
- panic("decref, pc=0x%p", getcallerpc(&r));
-
- return x;
-}
-
-/*
- * Rather than strncpy, which zeros the rest of the buffer, kstrcpy
- * truncates if necessary, always zero terminates, does not zero fill,
- * and puts ... at the end of the string if it's too long. Usually used to
- * save a string in up->genbuf;
- */
-void
-kstrcpy(char *s, char *t, int ns)
-{
- int nt;
-
- nt = strlen(t);
- if(nt+1 <= ns){
- memmove(s, t, nt+1);
- return;
- }
- /* too long */
- if(ns < 4){
- /* but very short! */
- strncpy(s, t, ns);
- return;
- }
- /* truncate with ... at character boundary (very rare case) */
- memmove(s, t, ns-4);
- ns -= 4;
- s[ns] = '\0';
- /* look for first byte of UTF-8 sequence by skipping continuation bytes */
- while(ns>0 && (s[--ns]&0xC0)==0x80)
- ;
- strcpy(s+ns, "...");
-}
-
-int
-emptystr(char *s)
-{
- if(s == nil)
- return 1;
- if(s[0] == '\0')
- return 1;
- return 0;
-}
-
-/*
- * Atomically replace *p with copy of s
- */
-void
-kstrdup(char **p, char *s)
-{
- int n;
- char *t, *prev;
-
- n = strlen(s)+1;
- /* if it's a user, we can wait for memory; if not, something's very wrong */
- if(up){
- t = smalloc(n);
- setmalloctag(t, getcallerpc(&p));
- }else{
- t = malloc(n);
- if(t == nil)
- panic("kstrdup: no memory");
- }
- memmove(t, s, n);
- prev = *p;
- *p = t;
- free(prev);
-}
-
-void
-chandevreset(void)
-{
- int i;
-
- for(i=0; devtab[i] != nil; i++)
- devtab[i]->reset();
-}
-
-void
-chandevinit(void)
-{
- int i;
-
- for(i=0; devtab[i] != nil; i++)
- devtab[i]->init();
-}
-
-void
-chandevshutdown(void)
-{
- int i;
-
- /* shutdown in reverse order */
- for(i=0; devtab[i] != nil; i++)
- ;
- for(i--; i >= 0; i--)
- devtab[i]->shutdown();
-}
-
-Chan*
-newchan(void)
-{
- Chan *c;
-
- lock(&chanalloc.lk);
- c = chanalloc.free;
- if(c != 0)
- chanalloc.free = c->next;
- unlock(&chanalloc.lk);
-
- if(c == nil) {
- c = smalloc(sizeof(Chan));
- lock(&chanalloc.lk);
- c->fid = ++chanalloc.fid;
- c->link = chanalloc.list;
- chanalloc.list = c;
- unlock(&chanalloc.lk);
- }
-
- /* if you get an error before associating with a dev,
- close calls rootclose, a nop */
- c->type = 0;
- c->flag = 0;
- c->ref.ref = 1;
- c->dev = 0;
- c->offset = 0;
- c->iounit = 0;
- c->umh = 0;
- c->uri = 0;
- c->dri = 0;
- c->aux = 0;
- c->mchan = 0;
- c->mcp = 0;
- c->mux = 0;
- memset(&c->mqid, 0, sizeof(c->mqid));
- c->name = 0;
- return c;
-}
-
-static Ref ncname;
-
-Cname*
-newcname(char *s)
-{
- Cname *n;
- int i;
-
- n = smalloc(sizeof(Cname));
- i = strlen(s);
- n->len = i;
- n->alen = i+CNAMESLOP;
- n->s = smalloc(n->alen);
- memmove(n->s, s, i+1);
- n->ref.ref = 1;
- incref(&ncname);
- return n;
-}
-
-void
-cnameclose(Cname *n)
-{
- if(n == nil)
- return;
- if(decref(&n->ref))
- return;
- decref(&ncname);
- free(n->s);
- free(n);
-}
-
-Cname*
-addelem(Cname *n, char *s)
-{
- int i, a;
- char *t;
- Cname *new;
-
- if(s[0]=='.' && s[1]=='\0')
- return n;
-
- if(n->ref.ref > 1){
- /* copy on write */
- new = newcname(n->s);
- cnameclose(n);
- n = new;
- }
-
- i = strlen(s);
- if(n->len+1+i+1 > n->alen){
- a = n->len+1+i+1 + CNAMESLOP;
- t = smalloc(a);
- memmove(t, n->s, n->len+1);
- free(n->s);
- n->s = t;
- n->alen = a;
- }
- if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/') /* don't insert extra slash if one is present */
- n->s[n->len++] = '/';
- memmove(n->s+n->len, s, i+1);
- n->len += i;
- if(isdotdot(s))
- cleancname(n);
- return n;
-}
-
-void
-chanfree(Chan *c)
-{
- c->flag = CFREE;
-
- if(c->umh != nil){
- putmhead(c->umh);
- c->umh = nil;
- }
- if(c->umc != nil){
- cclose(c->umc);
- c->umc = nil;
- }
- if(c->mux != nil){
- muxclose(c->mux);
- c->mux = nil;
- }
- if(c->mchan != nil){
- cclose(c->mchan);
- c->mchan = nil;
- }
-
- cnameclose(c->name);
-
- lock(&chanalloc.lk);
- c->next = chanalloc.free;
- chanalloc.free = c;
- unlock(&chanalloc.lk);
-}
-
-void
-cclose(Chan *c)
-{
- if(c->flag&CFREE)
- panic("cclose %p", getcallerpc(&c));
-
- if(decref(&c->ref))
- return;
-
- if(!waserror()){
- devtab[c->type]->close(c);
- poperror();
- }
- chanfree(c);
-}
-
-/*
- * Make sure we have the only copy of c. (Copy on write.)
- */
-Chan*
-cunique(Chan *c)
-{
- Chan *nc;
-
- if(c->ref.ref != 1) {
- nc = cclone(c);
- cclose(c);
- c = nc;
- }
-
- return c;
-}
-
-int
-eqqid(Qid a, Qid b)
-{
- return a.path==b.path && a.vers==b.vers;
-}
-
-int
-eqchan(Chan *a, Chan *b, int pathonly)
-{
- if(a->qid.path != b->qid.path)
- return 0;
- if(!pathonly && a->qid.vers!=b->qid.vers)
- return 0;
- if(a->type != b->type)
- return 0;
- if(a->dev != b->dev)
- return 0;
- return 1;
-}
-
-int
-eqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly)
-{
- if(a->qid.path != qid.path)
- return 0;
- if(!pathonly && a->qid.vers!=qid.vers)
- return 0;
- if(a->type != type)
- return 0;
- if(a->dev != dev)
- return 0;
- return 1;
-}
-
-Mhead*
-newmhead(Chan *from)
-{
- Mhead *mh;
-
- mh = smalloc(sizeof(Mhead));
- mh->ref.ref = 1;
- mh->from = from;
- incref(&from->ref);
-
-/*
- n = from->name->len;
- if(n >= sizeof(mh->fromname))
- n = sizeof(mh->fromname)-1;
- memmove(mh->fromname, from->name->s, n);
- mh->fromname[n] = 0;
-*/
- return mh;
-}
-
-int
-cmount(Chan **newp, Chan *old, int flag, char *spec)
-{
- Pgrp *pg;
- int order, flg;
- Mhead *m, **l, *mh;
- Mount *nm, *f, *um, **h;
- Chan *new;
-
- if(QTDIR & (old->qid.type^(*newp)->qid.type))
- error(Emount);
-
-if(old->umh)print("cmount old extra umh\n");
-
- order = flag&MORDER;
-
- if((old->qid.type&QTDIR)==0 && order != MREPL)
- error(Emount);
-
- new = *newp;
- mh = new->umh;
-
- /*
- * Not allowed to bind when the old directory
- * is itself a union. (Maybe it should be allowed, but I don't see
- * what the semantics would be.)
- *
- * We need to check mh->mount->next to tell unions apart from
- * simple mount points, so that things like
- * mount -c fd /root
- * bind -c /root /
- * work. The check of mount->mflag catches things like
- * mount fd /root
- * bind -c /root /
- *
- * This is far more complicated than it should be, but I don't
- * see an easier way at the moment. -rsc
- */
- if((flag&MCREATE) && mh && mh->mount
- && (mh->mount->next || !(mh->mount->mflag&MCREATE)))
- error(Emount);
-
- pg = up->pgrp;
- wlock(&pg->ns);
-
- l = &MOUNTH(pg, old->qid);
- for(m = *l; m; m = m->hash) {
- if(eqchan(m->from, old, 1))
- break;
- l = &m->hash;
- }
-
- if(m == nil) {
- /*
- * nothing mounted here yet. create a mount
- * head and add to the hash table.
- */
- m = newmhead(old);
- *l = m;
-
- /*
- * if this is a union mount, add the old
- * node to the mount chain.
- */
- if(order != MREPL)
- m->mount = newmount(m, old, 0, 0);
- }
- wlock(&m->lock);
- if(waserror()){
- wunlock(&m->lock);
- nexterror();
- }
- wunlock(&pg->ns);
-
- nm = newmount(m, new, flag, spec);
- if(mh != nil && mh->mount != nil) {
- /*
- * copy a union when binding it onto a directory
- */
- flg = order;
- if(order == MREPL)
- flg = MAFTER;
- h = &nm->next;
- um = mh->mount;
- for(um = um->next; um; um = um->next) {
- f = newmount(m, um->to, flg, um->spec);
- *h = f;
- h = &f->next;
- }
- }
-
- if(m->mount && order == MREPL) {
- mountfree(m->mount);
- m->mount = 0;
- }
-
- if(flag & MCREATE)
- nm->mflag |= MCREATE;
-
- if(m->mount && order == MAFTER) {
- for(f = m->mount; f->next; f = f->next)
- ;
- f->next = nm;
- }
- else {
- for(f = nm; f->next; f = f->next)
- ;
- f->next = m->mount;
- m->mount = nm;
- }
-
- wunlock(&m->lock);
- poperror();
- return nm->mountid;
-}
-
-void
-cunmount(Chan *mnt, Chan *mounted)
-{
- Pgrp *pg;
- Mhead *m, **l;
- Mount *f, **p;
-
- if(mnt->umh) /* should not happen */
- print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);
-
- /*
- * It _can_ happen that mounted->umh is non-nil,
- * because mounted is the result of namec(Aopen)
- * (see sysfile.c:/^sysunmount).
- * If we open a union directory, it will have a umh.
- * Although surprising, this is okay, since the
- * cclose will take care of freeing the umh.
- */
-
- pg = up->pgrp;
- wlock(&pg->ns);
-
- l = &MOUNTH(pg, mnt->qid);
- for(m = *l; m; m = m->hash) {
- if(eqchan(m->from, mnt, 1))
- break;
- l = &m->hash;
- }
-
- if(m == 0) {
- wunlock(&pg->ns);
- error(Eunmount);
- }
-
- wlock(&m->lock);
- if(mounted == 0) {
- *l = m->hash;
- wunlock(&pg->ns);
- mountfree(m->mount);
- m->mount = nil;
- cclose(m->from);
- wunlock(&m->lock);
- putmhead(m);
- return;
- }
-
- p = &m->mount;
- for(f = *p; f; f = f->next) {
- /* BUG: Needs to be 2 pass */
- if(eqchan(f->to, mounted, 1) ||
- (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) {
- *p = f->next;
- f->next = 0;
- mountfree(f);
- if(m->mount == nil) {
- *l = m->hash;
- cclose(m->from);
- wunlock(&m->lock);
- wunlock(&pg->ns);
- putmhead(m);
- return;
- }
- wunlock(&m->lock);
- wunlock(&pg->ns);
- return;
- }
- p = &f->next;
- }
- wunlock(&m->lock);
- wunlock(&pg->ns);
- error(Eunion);
-}
-
-Chan*
-cclone(Chan *c)
-{
- Chan *nc;
- Walkqid *wq;
-
- wq = devtab[c->type]->walk(c, nil, nil, 0);
- if(wq == nil)
- error("clone failed");
- nc = wq->clone;
- free(wq);
- nc->name = c->name;
- if(c->name)
- incref(&c->name->ref);
- return nc;
-}
-
-int
-findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid)
-{
- Pgrp *pg;
- Mhead *m;
-
- pg = up->pgrp;
- rlock(&pg->ns);
- for(m = MOUNTH(pg, qid); m; m = m->hash){
- rlock(&m->lock);
-if(m->from == nil){
- print("m %p m->from 0\n", m);
- runlock(&m->lock);
- continue;
-}
- if(eqchantdqid(m->from, type, dev, qid, 1)) {
- runlock(&pg->ns);
- if(mp != nil){
- incref(&m->ref);
- if(*mp != nil)
- putmhead(*mp);
- *mp = m;
- }
- if(*cp != nil)
- cclose(*cp);
- incref(&m->mount->to->ref);
- *cp = m->mount->to;
- runlock(&m->lock);
- return 1;
- }
- runlock(&m->lock);
- }
-
- runlock(&pg->ns);
- return 0;
-}
-
-int
-domount(Chan **cp, Mhead **mp)
-{
- return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid);
-}
-
-Chan*
-undomount(Chan *c, Cname *name)
-{
- Chan *nc;
- Pgrp *pg;
- Mount *t;
- Mhead **h, **he, *f;
-
- pg = up->pgrp;
- rlock(&pg->ns);
- if(waserror()) {
- runlock(&pg->ns);
- nexterror();
- }
-
- he = &pg->mnthash[MNTHASH];
- for(h = pg->mnthash; h < he; h++) {
- for(f = *h; f; f = f->hash) {
- if(strcmp(f->from->name->s, name->s) != 0)
- continue;
- for(t = f->mount; t; t = t->next) {
- if(eqchan(c, t->to, 1)) {
- /*
- * We want to come out on the left hand side of the mount
- * point using the element of the union that we entered on.
- * To do this, find the element that has a from name of
- * c->name->s.
- */
- if(strcmp(t->head->from->name->s, name->s) != 0)
- continue;
- nc = t->head->from;
- incref(&nc->ref);
- cclose(c);
- c = nc;
- break;
- }
- }
- }
- }
- poperror();
- runlock(&pg->ns);
- return c;
-}
-
-/*
- * Either walks all the way or not at all. No partial results in *cp.
- * *nerror is the number of names to display in an error message.
- */
-static char Edoesnotexist[] = "does not exist";
-int
-walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
-{
- int dev, dotdot, i, n, nhave, ntry, type;
- Chan *c, *nc;
- Cname *cname;
- Mount *f;
- Mhead *mh, *nmh;
- Walkqid *wq;
-
- c = *cp;
- incref(&c->ref);
- cname = c->name;
- incref(&cname->ref);
- mh = nil;
-
- /*
- * While we haven't gotten all the way down the path:
- * 1. step through a mount point, if any
- * 2. send a walk request for initial dotdot or initial prefix without dotdot
- * 3. move to the first mountpoint along the way.
- * 4. repeat.
- *
- * An invariant is that each time through the loop, c is on the undomount
- * side of the mount point, and c's name is cname.
- */
- for(nhave=0; nhave<nnames; nhave+=n){
- if((c->qid.type&QTDIR)==0){
- if(nerror)
- *nerror = nhave;
- cnameclose(cname);
- cclose(c);
- strcpy(up->errstr, Enotdir);
- if(mh != nil)
-{print("walk 1\n");
- putmhead(mh);
-}
- return -1;
- }
- ntry = nnames - nhave;
- if(ntry > MAXWELEM)
- ntry = MAXWELEM;
- dotdot = 0;
- for(i=0; i<ntry; i++){
- if(isdotdot(names[nhave+i])){
- if(i==0) {
- dotdot = 1;
- ntry = 1;
- } else
- ntry = i;
- break;
- }
- }
-
- if(!dotdot && !nomount)
- domount(&c, &mh);
-
- type = c->type;
- dev = c->dev;
-
- if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){
- /* try a union mount, if any */
- if(mh && !nomount){
- /*
- * mh->mount == c, so start at mh->mount->next
- */
- rlock(&mh->lock);
- for(f = mh->mount->next; f; f = f->next)
- if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil)
- break;
- runlock(&mh->lock);
- if(f != nil){
- type = f->to->type;
- dev = f->to->dev;
- }
- }
- if(wq == nil){
- cclose(c);
- cnameclose(cname);
- if(nerror)
- *nerror = nhave+1;
- if(mh != nil)
- putmhead(mh);
- return -1;
- }
- }
-
- nmh = nil;
- if(dotdot) {
- assert(wq->nqid == 1);
- assert(wq->clone != nil);
-
- cname = addelem(cname, "..");
- nc = undomount(wq->clone, cname);
- n = 1;
- } else {
- nc = nil;
- if(!nomount)
- for(i=0; i<wq->nqid && i<ntry-1; i++)
- if(findmount(&nc, &nmh, type, dev, wq->qid[i]))
- break;
- if(nc == nil){ /* no mount points along path */
- if(wq->clone == nil){
- cclose(c);
- cnameclose(cname);
- if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
- if(nerror)
- *nerror = nhave+wq->nqid+1;
- strcpy(up->errstr, Edoesnotexist);
- }else{
- if(nerror)
- *nerror = nhave+wq->nqid;
- strcpy(up->errstr, Enotdir);
- }
- free(wq);
- if(mh != nil)
- putmhead(mh);
- return -1;
- }
- n = wq->nqid;
- nc = wq->clone;
- }else{ /* stopped early, at a mount point */
- if(wq->clone != nil){
- cclose(wq->clone);
- wq->clone = nil;
- }
- n = i+1;
- }
- for(i=0; i<n; i++)
- cname = addelem(cname, names[nhave+i]);
- }
- cclose(c);
- c = nc;
- putmhead(mh);
- mh = nmh;
- free(wq);
- }
-
- putmhead(mh);
-
- c = cunique(c);
-
- if(c->umh != nil){ //BUG
- print("walk umh\n");
- putmhead(c->umh);
- c->umh = nil;
- }
-
- cnameclose(c->name);
- c->name = cname;
-
- cclose(*cp);
- *cp = c;
- if(nerror)
- *nerror = 0;
- return 0;
-}
-
-/*
- * c is a mounted non-creatable directory. find a creatable one.
- */
-Chan*
-createdir(Chan *c, Mhead *m)
-{
- Chan *nc;
- Mount *f;
-
- rlock(&m->lock);
- if(waserror()) {
- runlock(&m->lock);
- nexterror();
- }
- for(f = m->mount; f; f = f->next) {
- if(f->mflag&MCREATE) {
- nc = cclone(f->to);
- runlock(&m->lock);
- poperror();
- cclose(c);
- return nc;
- }
- }
- error(Enocreate);
- return 0;
-}
-
-void
-saveregisters(void)
-{
-}
-
-/*
- * In place, rewrite name to compress multiple /, eliminate ., and process ..
- */
-void
-cleancname(Cname *n)
-{
- char *p;
-
- if(n->s[0] == '#'){
- p = strchr(n->s, '/');
- if(p == nil)
- return;
- cleanname(p);
-
- /*
- * The correct name is #i rather than #i/,
- * but the correct name of #/ is #/.
- */
- if(strcmp(p, "/")==0 && n->s[1] != '/')
- *p = '\0';
- }else
- cleanname(n->s);
- n->len = strlen(n->s);
-}
-
-static void
-growparse(Elemlist *e)
-{
- char **new;
- int *inew;
- enum { Delta = 8 };
-
- if(e->nelems % Delta == 0){
- new = smalloc((e->nelems+Delta) * sizeof(char*));
- memmove(new, e->elems, e->nelems*sizeof(char*));
- free(e->elems);
- e->elems = new;
- inew = smalloc((e->nelems+Delta+1) * sizeof(int));
- memmove(inew, e->off, e->nelems*sizeof(int));
- free(e->off);
- e->off = inew;
- }
-}
-
-/*
- * The name is known to be valid.
- * Copy the name so slashes can be overwritten.
- * An empty string will set nelem=0.
- * A path ending in / or /. or /.//./ etc. will have
- * e.mustbedir = 1, so that we correctly
- * reject, e.g., "/adm/users/." when /adm/users is a file
- * rather than a directory.
- */
-static void
-parsename(char *name, Elemlist *e)
-{
- char *slash;
-
- kstrdup(&e->name, name);
- name = e->name;
- e->nelems = 0;
- e->elems = nil;
- e->off = smalloc(sizeof(int));
- e->off[0] = skipslash(name) - name;
- for(;;){
- name = skipslash(name);
- if(*name=='\0'){
- e->mustbedir = 1;
- break;
- }
- growparse(e);
- e->elems[e->nelems++] = name;
- slash = utfrune(name, '/');
- if(slash == nil){
- e->off[e->nelems] = name+strlen(name) - e->name;
- e->mustbedir = 0;
- break;
- }
- e->off[e->nelems] = slash - e->name;
- *slash++ = '\0';
- name = slash;
- }
-}
-
-void*
-mymemrchr(void *va, int c, long n)
-{
- uchar *a, *e;
-
- a = va;
- for(e=a+n-1; e>a; e--)
- if(*e == c)
- return e;
- return nil;
-}
-
-/*
- * Turn a name into a channel.
- * &name[0] is known to be a valid address. It may be a kernel address.
- *
- * Opening with amode Aopen, Acreate, or Aremove guarantees
- * that the result will be the only reference to that particular fid.
- * This is necessary since we might pass the result to
- * devtab[]->remove().
- *
- * Opening Atodir, Amount, or Aaccess does not guarantee this.
- *
- * Opening Aaccess can, under certain conditions, return a
- * correct Chan* but with an incorrect Cname attached.
- * Since the functions that open Aaccess (sysstat, syswstat, sys_stat)
- * do not use the Cname*, this avoids an unnecessary clone.
- */
-Chan*
-namec(char *aname, int amode, int omode, ulong perm)
-{
- int n, prefix, len, t, nomount, npath;
- Chan *c, *cnew;
- Cname *cname;
- Elemlist e;
- Rune r;
- Mhead *m;
- char *createerr, tmperrbuf[ERRMAX];
- char *name;
-
- name = aname;
- if(name[0] == '\0')
- error("empty file name");
- validname(name, 1);
-
- /*
- * Find the starting off point (the current slash, the root of
- * a device tree, or the current dot) as well as the name to
- * evaluate starting there.
- */
- nomount = 0;
- switch(name[0]){
- case '/':
- c = up->slash;
- incref(&c->ref);
- break;
-
- case '#':
- nomount = 1;
- up->genbuf[0] = '\0';
- n = 0;
- while(*name!='\0' && (*name != '/' || n < 2)){
- if(n >= sizeof(up->genbuf)-1)
- error(Efilename);
- up->genbuf[n++] = *name++;
- }
- up->genbuf[n] = '\0';
- /*
- * noattach is sandboxing.
- *
- * the OK exceptions are:
- * | it only gives access to pipes you create
- * d this process's file descriptors
- * e this process's environment
- * the iffy exceptions are:
- * c time and pid, but also cons and consctl
- * p control of your own processes (and unfortunately
- * any others left unprotected)
- */
- n = chartorune(&r, up->genbuf+1)+1;
- /* actually / is caught by parsing earlier */
- if(utfrune("M", r))
- error(Enoattach);
- if(up->pgrp->noattach && utfrune("|decp", r)==nil)
- error(Enoattach);
- t = devno(r, 1);
- if(t == -1)
- error(Ebadsharp);
- c = devtab[t]->attach(up->genbuf+n);
- break;
-
- default:
- c = up->dot;
- incref(&c->ref);
- break;
- }
- prefix = name - aname;
-
- e.name = nil;
- e.elems = nil;
- e.off = nil;
- e.nelems = 0;
- if(waserror()){
- cclose(c);
- free(e.name);
- free(e.elems);
- free(e.off);
-//dumpmount();
- nexterror();
- }
-
- /*
- * Build a list of elements in the path.
- */
- parsename(name, &e);
-
- /*
- * On create, ....
- */
- if(amode == Acreate){
- /* perm must have DMDIR if last element is / or /. */
- if(e.mustbedir && !(perm&DMDIR)){
- npath = e.nelems;
- strcpy(tmperrbuf, "create without DMDIR");
- goto NameError;
- }
-
- /* don't try to walk the last path element just yet. */
- if(e.nelems == 0)
- error(Eexist);
- e.nelems--;
- }
-
- if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){
- if(npath < 0 || npath > e.nelems){
- print("namec %s walk error npath=%d\n", aname, npath);
- nexterror();
- }
- strcpy(tmperrbuf, up->errstr);
- NameError:
- len = prefix+e.off[npath];
- if(len < ERRMAX/3 || (name=mymemrchr(aname, '/', len))==nil || name==aname)
- snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname);
- else
- snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name);
- snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, tmperrbuf);
- nexterror();
- }
-
- if(e.mustbedir && !(c->qid.type&QTDIR)){
- npath = e.nelems;
- strcpy(tmperrbuf, "not a directory");
- goto NameError;
- }
-
- if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){
- npath = e.nelems;
- error("cannot exec directory");
- }
-
- switch(amode){
- case Aaccess:
- if(!nomount)
- domount(&c, nil);
- break;
-
- case Abind:
- m = nil;
- if(!nomount)
- domount(&c, &m);
- if(c->umh != nil)
- putmhead(c->umh);
- c->umh = m;
- break;
-
- case Aremove:
- case Aopen:
- Open:
- /* save the name; domount might change c */
- cname = c->name;
- incref(&cname->ref);
- m = nil;
- if(!nomount)
- domount(&c, &m);
-
- /* our own copy to open or remove */
- c = cunique(c);
-
- /* now it's our copy anyway, we can put the name back */
- cnameclose(c->name);
- c->name = cname;
-
- switch(amode){
- case Aremove:
- putmhead(m);
- break;
-
- case Aopen:
- case Acreate:
-if(c->umh != nil){
- print("cunique umh Open\n");
- putmhead(c->umh);
- c->umh = nil;
-}
-
- /* only save the mount head if it's a multiple element union */
- if(m && m->mount && m->mount->next)
- c->umh = m;
- else
- putmhead(m);
-
- /* save registers else error() in open has wrong value of c saved */
- saveregisters();
-
- if(omode == OEXEC)
- c->flag &= ~CCACHE;
-
- c = devtab[c->type]->open(c, omode&~OCEXEC);
-
- if(omode & OCEXEC)
- c->flag |= CCEXEC;
- if(omode & ORCLOSE)
- c->flag |= CRCLOSE;
- break;
- }
- break;
-
- case Atodir:
- /*
- * Directories (e.g. for cd) are left before the mount point,
- * so one may mount on / or . and see the effect.
- */
- if(!(c->qid.type & QTDIR))
- error(Enotdir);
- break;
-
- case Amount:
- /*
- * When mounting on an already mounted upon directory,
- * one wants subsequent mounts to be attached to the
- * original directory, not the replacement. Don't domount.
- */
- break;
-
- case Acreate:
- /*
- * We've already walked all but the last element.
- * If the last exists, try to open it OTRUNC.
- * If omode&OEXCL is set, just give up.
- */
- e.nelems++;
- if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){
- if(omode&OEXCL)
- error(Eexist);
- omode |= OTRUNC;
- goto Open;
- }
-
- /*
- * The semantics of the create(2) system call are that if the
- * file exists and can be written, it is to be opened with truncation.
- * On the other hand, the create(5) message fails if the file exists.
- * If we get two create(2) calls happening simultaneously,
- * they might both get here and send create(5) messages, but only
- * one of the messages will succeed. To provide the expected create(2)
- * semantics, the call with the failed message needs to try the above
- * walk again, opening for truncation. This correctly solves the
- * create/create race, in the sense that any observable outcome can
- * be explained as one happening before the other.
- * The create/create race is quite common. For example, it happens
- * when two rc subshells simultaneously update the same
- * environment variable.
- *
- * The implementation still admits a create/create/remove race:
- * (A) walk to file, fails
- * (B) walk to file, fails
- * (A) create file, succeeds, returns
- * (B) create file, fails
- * (A) remove file, succeeds, returns
- * (B) walk to file, return failure.
- *
- * This is hardly as common as the create/create race, and is really
- * not too much worse than what might happen if (B) got a hold of a
- * file descriptor and then the file was removed -- either way (B) can't do
- * anything with the result of the create call. So we don't care about this race.
- *
- * Applications that care about more fine-grained decision of the races
- * can use the OEXCL flag to get at the underlying create(5) semantics;
- * by default we provide the common case.
- *
- * We need to stay behind the mount point in case we
- * need to do the first walk again (should the create fail).
- *
- * We also need to cross the mount point and find the directory
- * in the union in which we should be creating.
- *
- * The channel staying behind is c, the one moving forward is cnew.
- */
- m = nil;
- cnew = nil; /* is this assignment necessary? */
- if(!waserror()){ /* try create */
- if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid))
- cnew = createdir(cnew, m);
- else{
- cnew = c;
- incref(&cnew->ref);
- }
-
- /*
- * We need our own copy of the Chan because we're
- * about to send a create, which will move it. Once we have
- * our own copy, we can fix the name, which might be wrong
- * if findmount gave us a new Chan.
- */
- cnew = cunique(cnew);
- cnameclose(cnew->name);
- cnew->name = c->name;
- incref(&cnew->name->ref);
-
- devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
- poperror();
- if(omode & OCEXEC)
- cnew->flag |= CCEXEC;
- if(omode & ORCLOSE)
- cnew->flag |= CRCLOSE;
- if(m)
- putmhead(m);
- cclose(c);
- c = cnew;
- c->name = addelem(c->name, e.elems[e.nelems-1]);
- break;
- }else{ /* create failed */
- cclose(cnew);
- if(m)
- putmhead(m);
- if(omode & OEXCL)
- nexterror();
- /* save error */
- createerr = up->errstr;
- up->errstr = tmperrbuf;
- /* note: we depend that walk does not error */
- if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
- up->errstr = createerr;
- error(createerr); /* report true error */
- }
- up->errstr = createerr;
- omode |= OTRUNC;
- goto Open;
- }
- panic("namec: not reached");
-
- default:
- panic("unknown namec access %d\n", amode);
- }
-
- poperror();
-
- /* place final element in genbuf for e.g. exec */
- if(e.nelems > 0)
- kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf);
- else
- kstrcpy(up->genbuf, ".", sizeof up->genbuf);
- free(e.name);
- free(e.elems);
- free(e.off);
-
- return c;
-}
-
-/*
- * name is valid. skip leading / and ./ as much as possible
- */
-char*
-skipslash(char *name)
-{
- while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/')))
- name++;
- return name;
-}
-
-char isfrog[256]={
- /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
- /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x08 */
- /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 */
- /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x18 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
- 0, 0, 0, 0, 0, 0, 0, 1, /* 0x28 (1 is '/', 0x2F) */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
- 0, 0, 0, 0, 0, 0, 0, 1, /* 0x78 (1 is DEL, 0x7F) */
-};
-
-/*
- * Check that the name
- * a) is in valid memory.
- * b) is shorter than 2^16 bytes, so it can fit in a 9P string field.
- * c) contains no frogs.
- * The first byte is known to be addressible by the requester, so the
- * routine works for kernel and user memory both.
- * The parameter slashok flags whether a slash character is an error
- * or a valid character.
- */
-void
-validname(char *aname, int slashok)
-{
- char *ename, *name;
- int c;
- Rune r;
-
- name = aname;
-/*
- if(((ulong)name & KZERO) != KZERO) {
- p = name;
- t = BY2PG-((ulong)p&(BY2PG-1));
- while((ename=vmemchr(p, 0, t)) == nil) {
- p += t;
- t = BY2PG;
- }
- }else
-*/
- ename = memchr(name, 0, (1<<16));
-
- if(ename==nil || ename-name>=(1<<16))
- error("name too long");
-
- while(*name){
- /* all characters above '~' are ok */
- c = *(uchar*)name;
- if(c >= Runeself)
- name += chartorune(&r, name);
- else{
- if(isfrog[c])
- if(!slashok || c!='/'){
- snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
- error(up->genbuf);
- }
- name++;
- }
- }
-}
-
-void
-isdir(Chan *c)
-{
- if(c->qid.type & QTDIR)
- return;
- error(Enotdir);
-}
-
-/*
- * This is necessary because there are many
- * pointers to the top of a given mount list:
- *
- * - the mhead in the namespace hash table
- * - the mhead in chans returned from findmount:
- * used in namec and then by unionread.
- * - the mhead in chans returned from createdir:
- * used in the open/create race protect, which is gone.
- *
- * The RWlock in the Mhead protects the mount list it contains.
- * The mount list is deleted when we cunmount.
- * The RWlock ensures that nothing is using the mount list at that time.
- *
- * It is okay to replace c->mh with whatever you want as
- * long as you are sure you have a unique reference to it.
- *
- * This comment might belong somewhere else.
- */
-void
-putmhead(Mhead *m)
-{
- if(m && decref(&m->ref) == 0){
- m->mount = (Mount*)0xCafeBeef;
- free(m);
- }
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/dat.h b/sys/src/cmd/unix/drawterm/kern/dat.h
deleted file mode 100644
index 9d00d0085..000000000
--- a/sys/src/cmd/unix/drawterm/kern/dat.h
+++ /dev/null
@@ -1,519 +0,0 @@
-#define KNAMELEN 28 /* max length of name held in kernel */
-#define DOMLEN 64
-
-#define BLOCKALIGN 8
-
-typedef struct Alarms Alarms;
-typedef struct Block Block;
-typedef struct CSN CSN;
-typedef struct Chan Chan;
-typedef struct Cmdbuf Cmdbuf;
-typedef struct Cmdtab Cmdtab;
-typedef struct Cname Cname;
-typedef struct Conf Conf;
-typedef struct Dev Dev;
-typedef struct Dirtab Dirtab;
-typedef struct Edfinterface Edfinterface;
-typedef struct Egrp Egrp;
-typedef struct Evalue Evalue;
-typedef struct Fgrp Fgrp;
-typedef struct FPsave FPsave;
-typedef struct DevConf DevConf;
-typedef struct Label Label;
-typedef struct List List;
-typedef struct Log Log;
-typedef struct Logflag Logflag;
-typedef struct Mntcache Mntcache;
-typedef struct Mount Mount;
-typedef struct Mntrpc Mntrpc;
-typedef struct Mntwalk Mntwalk;
-typedef struct Mnt Mnt;
-typedef struct Mhead Mhead;
-typedef struct Note Note;
-typedef struct Page Page;
-typedef struct Palloc Palloc;
-typedef struct Perf Perf;
-typedef struct Pgrps Pgrps;
-typedef struct PhysUart PhysUart;
-typedef struct Pgrp Pgrp;
-typedef struct Physseg Physseg;
-typedef struct Proc Proc;
-typedef struct Pte Pte;
-typedef struct Pthash Pthash;
-typedef struct Queue Queue;
-typedef struct Ref Ref;
-typedef struct Rendez Rendez;
-typedef struct Rgrp Rgrp;
-typedef struct RWlock RWlock;
-typedef struct Schedq Schedq;
-typedef struct Segment Segment;
-typedef struct Session Session;
-typedef struct Task Task;
-typedef struct Talarm Talarm;
-typedef struct Timer Timer;
-typedef struct Uart Uart;
-typedef struct Ureg Ureg;
-typedef struct Waitq Waitq;
-typedef struct Walkqid Walkqid;
-typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*);
-
-#include "fcall.h"
-
-enum
-{
- SnarfSize = 64*1024,
-};
-
-struct Conf
-{
- ulong nmach; /* processors */
- ulong nproc; /* processes */
- ulong monitor; /* has monitor? */
- ulong npage0; /* total physical pages of memory */
- ulong npage1; /* total physical pages of memory */
- ulong npage; /* total physical pages of memory */
- ulong upages; /* user page pool */
- ulong nimage; /* number of page cache image headers */
- ulong nswap; /* number of swap pages */
- int nswppo; /* max # of pageouts per segment pass */
- ulong base0; /* base of bank 0 */
- ulong base1; /* base of bank 1 */
- ulong copymode; /* 0 is copy on write, 1 is copy on reference */
- ulong ialloc; /* max interrupt time allocation in bytes */
- ulong pipeqsize; /* size in bytes of pipe queues */
- int nuart; /* number of uart devices */
-};
-
-struct Label
-{
- jmp_buf buf;
-};
-
-struct Ref
-{
- Lock lk;
- long ref;
-};
-
-struct Rendez
-{
- Lock lk;
- Proc *p;
-};
-
-struct RWlock /* changed from kernel */
-{
- int readers;
- Lock lk;
- QLock x;
- QLock k;
-};
-
-struct Talarm
-{
- Lock lk;
- Proc *list;
-};
-
-struct Alarms
-{
- QLock lk;
- Proc *head;
-};
-
-/*
- * Access types in namec & channel flags
- */
-enum
-{
- Aaccess, /* as in stat, wstat */
- Abind, /* for left-hand-side of bind */
- Atodir, /* as in chdir */
- Aopen, /* for i/o */
- Amount, /* to be mounted or mounted upon */
- Acreate, /* is to be created */
- Aremove, /* will be removed by caller */
-
- COPEN = 0x0001, /* for i/o */
- CMSG = 0x0002, /* the message channel for a mount */
-/* CCREATE = 0x0004, permits creation if c->mnt */
- CCEXEC = 0x0008, /* close on exec */
- CFREE = 0x0010, /* not in use */
- CRCLOSE = 0x0020, /* remove on close */
- CCACHE = 0x0080, /* client cache */
-};
-
-/* flag values */
-enum
-{
- BINTR = (1<<0),
- BFREE = (1<<1),
- Bipck = (1<<2), /* ip checksum */
- Budpck = (1<<3), /* udp checksum */
- Btcpck = (1<<4), /* tcp checksum */
- Bpktck = (1<<5), /* packet checksum */
-};
-
-struct Block
-{
- Block* next;
- Block* list;
- uchar* rp; /* first unconsumed byte */
- uchar* wp; /* first empty byte */
- uchar* lim; /* 1 past the end of the buffer */
- uchar* base; /* start of the buffer */
- void (*free)(Block*);
- ushort flag;
- ushort checksum; /* IP checksum of complete packet (minus media header) */
-};
-#define BLEN(s) ((s)->wp - (s)->rp)
-#define BALLOC(s) ((s)->lim - (s)->base)
-
-struct Chan
-{
- Ref ref;
- Chan* next; /* allocation */
- Chan* link;
- vlong offset; /* in file */
- ushort type;
- ulong dev;
- ushort mode; /* read/write */
- ushort flag;
- Qid qid;
- int fid; /* for devmnt */
- ulong iounit; /* chunk size for i/o; 0==default */
- Mhead* umh; /* mount point that derived Chan; used in unionread */
- Chan* umc; /* channel in union; held for union read */
- QLock umqlock; /* serialize unionreads */
- int uri; /* union read index */
- int dri; /* devdirread index */
- ulong mountid;
- Mntcache *mcp; /* Mount cache pointer */
- Mnt *mux; /* Mnt for clients using me for messages */
- void* aux;
- Qid pgrpid; /* for #p/notepg */
- ulong mid; /* for ns in devproc */
- Chan* mchan; /* channel to mounted server */
- Qid mqid; /* qid of root of mount point */
- Session*session;
- Cname *name;
-};
-
-struct Cname
-{
- Ref ref;
- int alen; /* allocated length */
- int len; /* strlen(s) */
- char *s;
-};
-
-struct Dev
-{
- int dc;
- char* name;
-
- void (*reset)(void);
- void (*init)(void);
- void (*shutdown)(void);
- Chan* (*attach)(char*);
- Walkqid* (*walk)(Chan*, Chan*, char**, int);
- int (*stat)(Chan*, uchar*, int);
- Chan* (*open)(Chan*, int);
- void (*create)(Chan*, char*, int, ulong);
- void (*close)(Chan*);
- long (*read)(Chan*, void*, long, vlong);
- Block* (*bread)(Chan*, long, ulong);
- long (*write)(Chan*, void*, long, vlong);
- long (*bwrite)(Chan*, Block*, ulong);
- void (*remove)(Chan*);
- int (*wstat)(Chan*, uchar*, int);
- void (*power)(int); /* power mgt: power(1) => on, power (0) => off */
- int (*config)(int, char*, DevConf*); // returns nil on error
-};
-
-struct Dirtab
-{
- char name[KNAMELEN];
- Qid qid;
- vlong length;
- ulong perm;
-};
-
-struct Walkqid
-{
- Chan *clone;
- int nqid;
- Qid qid[1];
-};
-
-enum
-{
- NSMAX = 1000,
- NSLOG = 7,
- NSCACHE = (1<<NSLOG),
-};
-
-struct Mntwalk /* state for /proc/#/ns */
-{
- int cddone;
- ulong id;
- Mhead* mh;
- Mount* cm;
-};
-
-struct Mount
-{
- ulong mountid;
- Mount* next;
- Mhead* head;
- Mount* copy;
- Mount* order;
- Chan* to; /* channel replacing channel */
- int mflag;
- char *spec;
-};
-
-struct Mhead
-{
- Ref ref;
- RWlock lock;
- Chan* from; /* channel mounted upon */
- Mount* mount; /* what's mounted upon it */
- Mhead* hash; /* Hash chain */
-};
-
-struct Mnt
-{
- Lock lk;
- /* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
- Chan *c; /* Channel to file service */
- Proc *rip; /* Reader in progress */
- Mntrpc *queue; /* Queue of pending requests on this channel */
- ulong id; /* Multiplexer id for channel check */
- Mnt *list; /* Free list */
- int flags; /* cache */
- int msize; /* data + IOHDRSZ */
- char *version; /* 9P version */
- Queue *q; /* input queue */
-};
-
-enum
-{
- NUser, /* note provided externally */
- NExit, /* deliver note quietly */
- NDebug, /* print debug message */
-};
-
-struct Note
-{
- char msg[ERRMAX];
- int flag; /* whether system posted it */
-};
-
-enum
-{
- RENDLOG = 5,
- RENDHASH = 1<<RENDLOG, /* Hash to lookup rendezvous tags */
- MNTLOG = 5,
- MNTHASH = 1<<MNTLOG, /* Hash to walk mount table */
- NFD = 100, /* per process file descriptors */
- PGHLOG = 9,
- PGHSIZE = 1<<PGHLOG, /* Page hash for image lookup */
-};
-#define REND(p,s) ((p)->rendhash[(s)&((1<<RENDLOG)-1)])
-#define MOUNTH(p,qid) ((p)->mnthash[(qid).path&((1<<MNTLOG)-1)])
-
-struct Pgrp
-{
- Ref ref; /* also used as a lock when mounting */
- int noattach;
- ulong pgrpid;
- QLock debug; /* single access via devproc.c */
- RWlock ns; /* Namespace n read/one write lock */
- Mhead *mnthash[MNTHASH];
-};
-
-struct Rgrp
-{
- Ref ref;
- Proc *rendhash[RENDHASH]; /* Rendezvous tag hash */
-};
-
-struct Egrp
-{
- Ref ref;
- RWlock lk;
- Evalue **ent;
- int nent;
- int ment;
- ulong path; /* qid.path of next Evalue to be allocated */
- ulong vers; /* of Egrp */
-};
-
-struct Evalue
-{
- char *name;
- char *value;
- int len;
- Evalue *link;
- Qid qid;
-};
-
-struct Fgrp
-{
- Ref ref;
- Chan **fd;
- int nfd; /* number allocated */
- int maxfd; /* highest fd in use */
- int exceed; /* debugging */
-};
-
-enum
-{
- DELTAFD = 20, /* incremental increase in Fgrp.fd's */
- NERR = 20
-};
-
-typedef uvlong Ticks;
-
-enum
-{
- Running,
- Rendezvous,
- Wakeme,
-};
-
-struct Proc
-{
- uint state;
- uint mach;
-
- ulong pid;
- ulong parentpid;
-
- Pgrp *pgrp; /* Process group for namespace */
- Fgrp *fgrp; /* File descriptor group */
- Rgrp *rgrp;
-
- Lock rlock; /* sync sleep/wakeup with postnote */
- Rendez *r; /* rendezvous point slept on */
- Rendez sleep; /* place for syssleep/debug */
- int notepending; /* note issued but not acted on */
- int kp; /* true if a kernel process */
-
- void* rendtag; /* Tag for rendezvous */
- void* rendval; /* Value for rendezvous */
- Proc *rendhash; /* Hash list for tag values */
-
- int nerrlab;
- Label errlab[NERR];
- char user[KNAMELEN];
- char *syserrstr; /* last error from a system call, errbuf0 or 1 */
- char *errstr; /* reason we're unwinding the error stack, errbuf1 or 0 */
- char errbuf0[ERRMAX];
- char errbuf1[ERRMAX];
- char genbuf[128]; /* buffer used e.g. for last name element from namec */
- char text[KNAMELEN];
-
- Chan *slash;
- Chan *dot;
-
- Proc *qnext;
-
- void (*fn)(void*);
- void *arg;
-
- char oproc[1024]; /* reserved for os */
-
-};
-
-enum
-{
- PRINTSIZE = 256,
- MAXCRYPT = 127,
- NUMSIZE = 12, /* size of formatted number */
- MB = (1024*1024),
- READSTR = 1000, /* temporary buffer size for device reads */
-};
-
-extern char* conffile;
-extern int cpuserver;
-extern Dev* devtab[];
-extern char *eve;
-extern char hostdomain[];
-extern uchar initcode[];
-extern Queue* kbdq;
-extern Queue* kprintoq;
-extern Ref noteidalloc;
-extern Palloc palloc;
-extern Queue *serialoq;
-extern char* statename[];
-extern int nsyscall;
-extern char *sysname;
-extern uint qiomaxatomic;
-extern Conf conf;
-enum
-{
- LRESPROF = 3,
-};
-
-/*
- * action log
- */
-struct Log {
- Lock lk;
- int opens;
- char* buf;
- char *end;
- char *rptr;
- int len;
- int nlog;
- int minread;
-
- int logmask; /* mask of things to debug */
-
- QLock readq;
- Rendez readr;
-};
-
-struct Logflag {
- char* name;
- int mask;
-};
-
-enum
-{
- NCMDFIELD = 128
-};
-
-struct Cmdbuf
-{
- char *buf;
- char **f;
- int nf;
-};
-
-struct Cmdtab
-{
- int index; /* used by client to switch on result */
- char *cmd; /* command name */
- int narg; /* expected #args; 0 ==> variadic */
-};
-
-/* queue state bits, Qmsg, Qcoalesce, and Qkick can be set in qopen */
-enum
-{
- /* Queue.state */
- Qstarve = (1<<0), /* consumer starved */
- Qmsg = (1<<1), /* message stream */
- Qclosed = (1<<2), /* queue has been closed/hungup */
- Qflow = (1<<3), /* producer flow controlled */
- Qcoalesce = (1<<4), /* coallesce packets on read */
- Qkick = (1<<5), /* always call the kick routine after qwrite */
-};
-
-#define DEVDOTDOT -1
-
-extern Proc *_getproc(void);
-extern void _setproc(Proc*);
-#define up (_getproc())
diff --git a/sys/src/cmd/unix/drawterm/kern/data.c b/sys/src/cmd/unix/drawterm/kern/data.c
deleted file mode 100644
index 735e5e0c4..000000000
--- a/sys/src/cmd/unix/drawterm/kern/data.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-Proc *up;
-Conf conf =
-{
- 1,
- 100,
- 0,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 1024*1024*1024,
- 0,
-};
-
-char *eve = "eve";
-ulong kerndate;
-int cpuserver;
-char hostdomain[] = "drawterm.net";
diff --git a/sys/src/cmd/unix/drawterm/kern/dev.c b/sys/src/cmd/unix/drawterm/kern/dev.c
deleted file mode 100644
index 83bf624f3..000000000
--- a/sys/src/cmd/unix/drawterm/kern/dev.c
+++ /dev/null
@@ -1,468 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-extern ulong kerndate;
-
-void
-mkqid(Qid *q, vlong path, ulong vers, int type)
-{
- q->type = type;
- q->vers = vers;
- q->path = path;
-}
-
-int
-devno(int c, int user)
-{
- int i;
-
- for(i = 0; devtab[i] != nil; i++) {
- if(devtab[i]->dc == c)
- return i;
- }
- if(user == 0)
- panic("devno %C 0x%ux", c, c);
-
- return -1;
-}
-
-void
-devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
-{
- db->name = n;
- if(c->flag&CMSG)
- qid.type |= QTMOUNT;
- db->qid = qid;
- db->type = devtab[c->type]->dc;
- db->dev = c->dev;
- db->mode = perm;
- db->mode |= qid.type << 24;
- db->atime = seconds();
- db->mtime = kerndate;
- db->length = length;
- db->uid = user;
- db->gid = eve;
- db->muid = user;
-}
-
-/*
- * (here, Devgen is the prototype; devgen is the function in dev.c.)
- *
- * a Devgen is expected to return the directory entry for ".."
- * if you pass it s==DEVDOTDOT (-1). otherwise...
- *
- * there are two contradictory rules.
- *
- * (i) if c is a directory, a Devgen is expected to list its children
- * as you iterate s.
- *
- * (ii) whether or not c is a directory, a Devgen is expected to list
- * its siblings as you iterate s.
- *
- * devgen always returns the list of children in the root
- * directory. thus it follows (i) when c is the root and (ii) otherwise.
- * many other Devgens follow (i) when c is a directory and (ii) otherwise.
- *
- * devwalk assumes (i). it knows that devgen breaks (i)
- * for children that are themselves directories, and explicitly catches them.
- *
- * devstat assumes (ii). if the Devgen in question follows (i)
- * for this particular c, devstat will not find the necessary info.
- * with our particular Devgen functions, this happens only for
- * directories, so devstat makes something up, assuming
- * c->name, c->qid, eve, DMDIR|0555.
- *
- * devdirread assumes (i). the callers have to make sure
- * that the Devgen satisfies (i) for the chan being read.
- */
-/*
- * the zeroth element of the table MUST be the directory itself for ..
-*/
-int
-devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
-{
- if(tab == 0)
- return -1;
- if(i == DEVDOTDOT){
- /* nothing */
- }else if(name){
- for(i=1; i<ntab; i++)
- if(strcmp(tab[i].name, name) == 0)
- break;
- if(i==ntab)
- return -1;
- tab += i;
- }else{
- /* skip over the first element, that for . itself */
- i++;
- if(i >= ntab)
- return -1;
- tab += i;
- }
- devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
- return 1;
-}
-
-void
-devreset(void)
-{
-}
-
-void
-devinit(void)
-{
-}
-
-void
-devshutdown(void)
-{
-}
-
-Chan*
-devattach(int tc, char *spec)
-{
- Chan *c;
- char *buf;
-
- c = newchan();
- mkqid(&c->qid, 0, 0, QTDIR);
- c->type = devno(tc, 0);
- if(spec == nil)
- spec = "";
- buf = smalloc(4+strlen(spec)+1);
- sprint(buf, "#%C%s", tc, spec);
- c->name = newcname(buf);
- free(buf);
- return c;
-}
-
-
-Chan*
-devclone(Chan *c)
-{
- Chan *nc;
-
- if(c->flag & COPEN)
- panic("clone of open file type %C\n", devtab[c->type]->dc);
-
- nc = newchan();
-
- nc->type = c->type;
- nc->dev = c->dev;
- nc->mode = c->mode;
- nc->qid = c->qid;
- nc->offset = c->offset;
- nc->umh = nil;
- nc->mountid = c->mountid;
- nc->aux = c->aux;
- nc->pgrpid = c->pgrpid;
- nc->mid = c->mid;
- nc->mqid = c->mqid;
- nc->mcp = c->mcp;
- return nc;
-}
-
-Walkqid*
-devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
-{
- int i, j, alloc;
- Walkqid *wq;
- char *n;
- Dir dir;
-
- if(nname > 0)
- isdir(c);
-
- alloc = 0;
- wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
- if(waserror()){
- if(alloc && wq->clone!=nil)
- cclose(wq->clone);
- free(wq);
- return nil;
- }
- if(nc == nil){
- nc = devclone(c);
- nc->type = 0; /* device doesn't know about this channel yet */
- alloc = 1;
- }
- wq->clone = nc;
-
- for(j=0; j<nname; j++){
- if(!(nc->qid.type&QTDIR)){
- if(j==0)
- error(Enotdir);
- goto Done;
- }
- n = name[j];
- if(strcmp(n, ".") == 0){
- Accept:
- wq->qid[wq->nqid++] = nc->qid;
- continue;
- }
- if(strcmp(n, "..") == 0){
- if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){
- print("devgen walk .. in dev%s %llux broken\n",
- devtab[nc->type]->name, nc->qid.path);
- error("broken devgen");
- }
- nc->qid = dir.qid;
- goto Accept;
- }
- /*
- * Ugly problem: If we're using devgen, make sure we're
- * walking the directory itself, represented by the first
- * entry in the table, and not trying to step into a sub-
- * directory of the table, e.g. /net/net. Devgen itself
- * should take care of the problem, but it doesn't have
- * the necessary information (that we're doing a walk).
- */
- if(gen==devgen && nc->qid.path!=tab[0].qid.path)
- goto Notfound;
- for(i=0;; i++) {
- switch((*gen)(nc, n, tab, ntab, i, &dir)){
- case -1:
- Notfound:
- if(j == 0)
- error(Enonexist);
- kstrcpy(up->errstr, Enonexist, ERRMAX);
- goto Done;
- case 0:
- continue;
- case 1:
- if(strcmp(n, dir.name) == 0){
- nc->qid = dir.qid;
- goto Accept;
- }
- continue;
- }
- }
- }
- /*
- * We processed at least one name, so will return some data.
- * If we didn't process all nname entries succesfully, we drop
- * the cloned channel and return just the Qids of the walks.
- */
-Done:
- poperror();
- if(wq->nqid < nname){
- if(alloc)
- cclose(wq->clone);
- wq->clone = nil;
- }else if(wq->clone){
- /* attach cloned channel to same device */
- wq->clone->type = c->type;
- }
- return wq;
-}
-
-int
-devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
-{
- int i;
- Dir dir;
- char *p, *elem;
-
- for(i=0;; i++)
- switch((*gen)(c, nil, tab, ntab, i, &dir)){
- case -1:
- if(c->qid.type & QTDIR){
- if(c->name == nil)
- elem = "???";
- else if(strcmp(c->name->s, "/") == 0)
- elem = "/";
- else
- for(elem=p=c->name->s; *p; p++)
- if(*p == '/')
- elem = p+1;
- devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
- n = convD2M(&dir, db, n);
- if(n == 0)
- error(Ebadarg);
- return n;
- }
- print("devstat %C %llux\n", devtab[c->type]->dc, c->qid.path);
-
- error(Enonexist);
- case 0:
- break;
- case 1:
- if(c->qid.path == dir.qid.path) {
- if(c->flag&CMSG)
- dir.mode |= DMMOUNT;
- n = convD2M(&dir, db, n);
- if(n == 0)
- error(Ebadarg);
- return n;
- }
- break;
- }
- error(Egreg); /* not reached? */
- return -1;
-}
-
-long
-devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
-{
- long m, dsz;
- struct{
- Dir d;
- char slop[100];
- }dir;
-
- for(m=0; m<n; c->dri++) {
- switch((*gen)(c, nil, tab, ntab, c->dri, &dir.d)){
- case -1:
- return m;
-
- case 0:
- break;
-
- case 1:
- dsz = convD2M(&dir.d, (uchar*)d, n-m);
- if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */
- if(m == 0)
- error(Eshort);
- return m;
- }
- m += dsz;
- d += dsz;
- break;
- }
- }
-
- return m;
-}
-
-/*
- * error(Eperm) if open permission not granted for up->user.
- */
-void
-devpermcheck(char *fileuid, ulong perm, int omode)
-{
- ulong t;
- static int access[] = { 0400, 0200, 0600, 0100 };
-
- if(strcmp(up->user, fileuid) == 0)
- perm <<= 0;
- else
- if(strcmp(up->user, eve) == 0)
- perm <<= 3;
- else
- perm <<= 6;
-
- t = access[omode&3];
- if((t&perm) != t)
- error(Eperm);
-}
-
-Chan*
-devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
-{
- int i;
- Dir dir;
-
- for(i=0;; i++) {
- switch((*gen)(c, nil, tab, ntab, i, &dir)){
- case -1:
- goto Return;
- case 0:
- break;
- case 1:
- if(c->qid.path == dir.qid.path) {
- devpermcheck(dir.uid, dir.mode, omode);
- goto Return;
- }
- break;
- }
- }
-Return:
- c->offset = 0;
- if((c->qid.type&QTDIR) && omode!=OREAD)
- error(Eperm);
- c->mode = openmode(omode);
- c->flag |= COPEN;
- return c;
-}
-
-void
-devcreate(Chan *c, char *name, int mode, ulong perm)
-{
- USED(c);
- USED(name);
- USED(mode);
- USED(perm);
-
- error(Eperm);
-}
-
-Block*
-devbread(Chan *c, long n, ulong offset)
-{
- Block *bp;
-
- bp = allocb(n);
- if(bp == 0)
- error(Enomem);
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);
- poperror();
- return bp;
-}
-
-long
-devbwrite(Chan *c, Block *bp, ulong offset)
-{
- long n;
-
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
- poperror();
- freeb(bp);
-
- return n;
-}
-
-void
-devremove(Chan *c)
-{
- USED(c);
- error(Eperm);
-}
-
-int
-devwstat(Chan *c, uchar *a, int n)
-{
- USED(c);
- USED(a);
- USED(n);
-
- error(Eperm);
- return 0;
-}
-
-void
-devpower(int a)
-{
- USED(a);
- error(Eperm);
-}
-
-int
-devconfig(int a, char *b, DevConf *c)
-{
- USED(a);
- USED(b);
- USED(c);
- error(Eperm);
- return 0;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/devaudio-none.c b/sys/src/cmd/unix/drawterm/kern/devaudio-none.c
deleted file mode 100644
index 57a536651..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devaudio-none.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Linux and BSD
- */
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-#include "devaudio.h"
-
-/* maybe this should return -1 instead of sysfatal */
-void
-audiodevopen(void)
-{
- error("no audio support");
-}
-
-void
-audiodevclose(void)
-{
- error("no audio support");
-}
-
-int
-audiodevread(void *a, int n)
-{
- error("no audio support");
- return -1;
-}
-
-int
-audiodevwrite(void *a, int n)
-{
- error("no audio support");
- return -1;
-}
-
-void
-audiodevsetvol(int what, int left, int right)
-{
- error("no audio support");
-}
-
-void
-audiodevgetvol(int what, int *left, int *right)
-{
- error("no audio support");
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/devaudio-unix.c b/sys/src/cmd/unix/drawterm/kern/devaudio-unix.c
deleted file mode 100644
index ad5af7458..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devaudio-unix.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Linux and BSD
- */
-#include <sys/ioctl.h>
-#ifdef __linux__
-#include <linux/soundcard.h>
-#else
-#include <sys/soundcard.h>
-#endif
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-#include "devaudio.h"
-
-enum
-{
- Channels = 2,
- Rate = 44100,
- Bits = 16,
- Bigendian = 1,
-};
-
-static int afd = -1;
-static int cfd= -1;
-static int speed;
-
-/* maybe this should return -1 instead of sysfatal */
-void
-audiodevopen(void)
-{
- int t;
- ulong ul;
-
- afd = -1;
- cfd = -1;
- if((afd = open("/dev/dsp", OWRITE)) < 0)
- goto err;
- if((cfd = open("/dev/mixer", ORDWR)) < 0)
- goto err;
-
- t = Bits;
- if(ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &t) < 0)
- goto err;
-
- t = Channels-1;
- if(ioctl(afd, SNDCTL_DSP_STEREO, &t) < 0)
- goto err;
-
- speed = Rate;
- ul = Rate;
- if(ioctl(afd, SNDCTL_DSP_SPEED, &ul) < 0)
- goto err;
-
- return;
-
-err:
- if(afd >= 0)
- close(afd);
- afd = -1;
- oserror();
-}
-
-void
-audiodevclose(void)
-{
- close(afd);
- close(cfd);
- afd = -1;
- cfd = -1;
-}
-
-static struct {
- int id9;
- int id;
-} names[] = {
- Vaudio, SOUND_MIXER_VOLUME,
- Vbass, SOUND_MIXER_BASS,
- Vtreb, SOUND_MIXER_TREBLE,
- Vline, SOUND_MIXER_LINE,
- Vpcm, SOUND_MIXER_PCM,
- Vsynth, SOUND_MIXER_SYNTH,
- Vcd, SOUND_MIXER_CD,
- Vmic, SOUND_MIXER_MIC,
-// "record", SOUND_MIXER_RECLEV,
-// "mix", SOUND_MIXER_IMIX,
-// "pcm2", SOUND_MIXER_ALTPCM,
- Vspeaker, SOUND_MIXER_SPEAKER
-// "line1", SOUND_MIXER_LINE1,
-// "line2", SOUND_MIXER_LINE2,
-// "line3", SOUND_MIXER_LINE3,
-// "digital1", SOUND_MIXER_DIGITAL1,
-// "digital2", SOUND_MIXER_DIGITAL2,
-// "digital3", SOUND_MIXER_DIGITAL3,
-// "phonein", SOUND_MIXER_PHONEIN,
-// "phoneout", SOUND_MIXER_PHONEOUT,
-// "radio", SOUND_MIXER_RADIO,
-// "video", SOUND_MIXER_VIDEO,
-// "monitor", SOUND_MIXER_MONITOR,
-// "igain", SOUND_MIXER_IGAIN,
-// "ogain", SOUND_MIXER_OGAIN,
-};
-
-static int
-lookname(int id9)
-{
- int i;
-
- for(i=0; i<nelem(names); i++)
- if(names[i].id9 == id9)
- return names[i].id;
- return -1;
-}
-
-void
-audiodevsetvol(int what, int left, int right)
-{
- int id;
- ulong x;
- int can, v;
-
- if(cfd < 0)
- error("audio device not open");
- if(what == Vspeed){
- x = left;
- if(ioctl(afd, SNDCTL_DSP_SPEED, &x) < 0)
- oserror();
- speed = x;
- return;
- }
- if((id = lookname(what)) < 0)
- return;
- if(ioctl(cfd, SOUND_MIXER_READ_DEVMASK, &can) < 0)
- can = ~0;
- if(!(can & (1<<id)))
- return;
- v = left | (right<<8);
- if(ioctl(cfd, MIXER_WRITE(id), &v) < 0)
- oserror();
-}
-
-void
-audiodevgetvol(int what, int *left, int *right)
-{
- int id;
- int can, v;
-
- if(cfd < 0)
- error("audio device not open");
- if(what == Vspeed){
- *left = *right = speed;
- return;
- }
- if((id = lookname(what)) < 0)
- return;
- if(ioctl(cfd, SOUND_MIXER_READ_DEVMASK, &can) < 0)
- can = ~0;
- if(!(can & (1<<id)))
- return;
- if(ioctl(cfd, MIXER_READ(id), &v) < 0)
- oserror();
- *left = v&0xFF;
- *right = (v>>8)&0xFF;
-}
-
-int
-audiodevwrite(void *v, int n)
-{
- int m, tot;
-
- for(tot=0; tot<n; tot+=m)
- if((m = write(afd, (uchar*)v+tot, n-tot)) <= 0)
- oserror();
- return tot;
-}
-
-int
-audiodevread(void *v, int n)
-{
- error("no reading");
- return -1;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/devaudio.c b/sys/src/cmd/unix/drawterm/kern/devaudio.c
deleted file mode 100644
index b6d0cc512..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devaudio.c
+++ /dev/null
@@ -1,372 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-#include "devaudio.h"
-
-enum
-{
- Qdir = 0,
- Qaudio,
- Qvolume,
-
- Aclosed = 0,
- Aread,
- Awrite,
-
- Speed = 44100,
- Ncmd = 50, /* max volume command words */
-};
-
-Dirtab
-audiodir[] =
-{
- ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
- "audio", {Qaudio}, 0, 0666,
- "volume", {Qvolume}, 0, 0666,
-};
-
-static struct
-{
- QLock lk;
- Rendez vous;
- int amode; /* Aclosed/Aread/Awrite for /audio */
-} audio;
-
-#define aqlock(a) qlock(&(a)->lk)
-#define aqunlock(a) qunlock(&(a)->lk)
-
-static struct
-{
- char* name;
- int flag;
- int ilval; /* initial values */
- int irval;
-} volumes[] =
-{
- "audio", Fout, 50, 50,
- "synth", Fin|Fout, 0, 0,
- "cd", Fin|Fout, 0, 0,
- "line", Fin|Fout, 0, 0,
- "mic", Fin|Fout|Fmono, 0, 0,
- "speaker", Fout|Fmono, 0, 0,
-
- "treb", Fout, 50, 50,
- "bass", Fout, 50, 50,
-
- "speed", Fin|Fout|Fmono, Speed, Speed,
- 0
-};
-
-static char Emode[] = "illegal open mode";
-static char Evolume[] = "illegal volume specifier";
-
-static void
-resetlevel(void)
-{
- int i;
-
- for(i=0; volumes[i].name; i++)
- audiodevsetvol(i, volumes[i].ilval, volumes[i].irval);
-}
-
-static void
-audioinit(void)
-{
-}
-
-static Chan*
-audioattach(char *param)
-{
- return devattach('A', param);
-}
-
-static Walkqid*
-audiowalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
-}
-
-static int
-audiostat(Chan *c, uchar *db, int n)
-{
- return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
-}
-
-static Chan*
-audioopen(Chan *c, int omode)
-{
- int amode;
-
- switch((ulong)c->qid.path) {
- default:
- error(Eperm);
- break;
-
- case Qvolume:
- case Qdir:
- break;
-
- case Qaudio:
- amode = Awrite;
- if((omode&7) == OREAD)
- amode = Aread;
- aqlock(&audio);
- if(waserror()){
- aqunlock(&audio);
- nexterror();
- }
- if(audio.amode != Aclosed)
- error(Einuse);
- audiodevopen();
- audio.amode = amode;
- poperror();
- aqunlock(&audio);
- break;
- }
- c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
-
- return c;
-}
-
-static void
-audioclose(Chan *c)
-{
- switch((ulong)c->qid.path) {
- default:
- error(Eperm);
- break;
-
- case Qdir:
- case Qvolume:
- break;
-
- case Qaudio:
- if(c->flag & COPEN) {
- aqlock(&audio);
- audiodevclose();
- audio.amode = Aclosed;
- aqunlock(&audio);
- }
- break;
- }
-}
-
-static long
-audioread(Chan *c, void *v, long n, vlong off)
-{
- int liv, riv, lov, rov;
- long m;
- char buf[300];
- int j;
- ulong offset = off;
- char *a;
-
- a = v;
- switch((ulong)c->qid.path) {
- default:
- error(Eperm);
- break;
-
- case Qdir:
- return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
-
- case Qaudio:
- if(audio.amode != Aread)
- error(Emode);
- aqlock(&audio);
- if(waserror()){
- aqunlock(&audio);
- nexterror();
- }
- n = audiodevread(v, n);
- poperror();
- aqunlock(&audio);
- break;
-
- case Qvolume:
- j = 0;
- buf[0] = 0;
- for(m=0; volumes[m].name; m++){
- audiodevgetvol(m, &lov, &rov);
- liv = lov;
- riv = rov;
- j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
- if((volumes[m].flag & Fmono) || (liv==riv && lov==rov)){
- if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
- j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
- else{
- if(volumes[m].flag & Fin)
- j += snprint(buf+j, sizeof(buf)-j,
- " in %d", liv);
- if(volumes[m].flag & Fout)
- j += snprint(buf+j, sizeof(buf)-j,
- " out %d", lov);
- }
- }else{
- if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
- liv==lov && riv==rov)
- j += snprint(buf+j, sizeof(buf)-j,
- " left %d right %d",
- liv, riv);
- else{
- if(volumes[m].flag & Fin)
- j += snprint(buf+j, sizeof(buf)-j,
- " in left %d right %d",
- liv, riv);
- if(volumes[m].flag & Fout)
- j += snprint(buf+j, sizeof(buf)-j,
- " out left %d right %d",
- lov, rov);
- }
- }
- j += snprint(buf+j, sizeof(buf)-j, "\n");
- }
- return readstr(offset, a, n, buf);
- }
- return n;
-}
-
-static long
-audiowrite(Chan *c, void *vp, long n, vlong off)
-{
- long m;
- int i, v, left, right, in, out;
- Cmdbuf *cb;
- char *a;
-
- USED(off);
- a = vp;
- switch((ulong)c->qid.path) {
- default:
- error(Eperm);
- break;
-
- case Qvolume:
- v = Vaudio;
- left = 1;
- right = 1;
- in = 1;
- out = 1;
- cb = parsecmd(vp, n);
- if(waserror()){
- free(cb);
- nexterror();
- }
-
- for(i = 0; i < cb->nf; i++){
- /*
- * a number is volume
- */
- if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
- m = strtoul(cb->f[i], 0, 10);
- if(!out)
- goto cont0;
- if(left && right)
- audiodevsetvol(v, m, m);
- else if(left)
- audiodevsetvol(v, m, -1);
- else if(right)
- audiodevsetvol(v, -1, m);
- goto cont0;
- }
-
- for(m=0; volumes[m].name; m++) {
- if(strcmp(cb->f[i], volumes[m].name) == 0) {
- v = m;
- in = 1;
- out = 1;
- left = 1;
- right = 1;
- goto cont0;
- }
- }
-
- if(strcmp(cb->f[i], "reset") == 0) {
- resetlevel();
- goto cont0;
- }
- if(strcmp(cb->f[i], "in") == 0) {
- in = 1;
- out = 0;
- goto cont0;
- }
- if(strcmp(cb->f[i], "out") == 0) {
- in = 0;
- out = 1;
- goto cont0;
- }
- if(strcmp(cb->f[i], "left") == 0) {
- left = 1;
- right = 0;
- goto cont0;
- }
- if(strcmp(cb->f[i], "right") == 0) {
- left = 0;
- right = 1;
- goto cont0;
- }
- error(Evolume);
- break;
- cont0:;
- }
- free(cb);
- poperror();
- break;
-
- case Qaudio:
- if(audio.amode != Awrite)
- error(Emode);
- aqlock(&audio);
- if(waserror()){
- aqunlock(&audio);
- nexterror();
- }
- n = audiodevwrite(vp, n);
- poperror();
- aqunlock(&audio);
- break;
- }
- return n;
-}
-
-void
-audioswab(uchar *a, uint n)
-{
- ulong *p, *ep, b;
-
- p = (ulong*)a;
- ep = p + (n>>2);
- while(p < ep) {
- b = *p;
- b = (b>>24) | (b<<24) |
- ((b&0xff0000) >> 8) |
- ((b&0x00ff00) << 8);
- *p++ = b;
- }
-}
-
-Dev audiodevtab = {
- 'A',
- "audio",
-
- devreset,
- audioinit,
- devshutdown,
- audioattach,
- audiowalk,
- audiostat,
- audioopen,
- devcreate,
- audioclose,
- audioread,
- devbread,
- audiowrite,
- devbwrite,
- devremove,
- devwstat,
-};
diff --git a/sys/src/cmd/unix/drawterm/kern/devaudio.h b/sys/src/cmd/unix/drawterm/kern/devaudio.h
deleted file mode 100644
index e6cc7ed21..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devaudio.h
+++ /dev/null
@@ -1,25 +0,0 @@
-enum
-{
- Fmono = 1,
- Fin = 2,
- Fout = 4,
-
- Vaudio = 0,
- Vsynth,
- Vcd,
- Vline,
- Vmic,
- Vspeaker,
- Vtreb,
- Vbass,
- Vspeed,
- Vpcm,
- Nvol,
-};
-
-void audiodevopen(void);
-void audiodevclose(void);
-int audiodevread(void*, int);
-int audiodevwrite(void*, int);
-void audiodevgetvol(int, int*, int*);
-void audiodevsetvol(int, int, int);
diff --git a/sys/src/cmd/unix/drawterm/kern/devcons.c b/sys/src/cmd/unix/drawterm/kern/devcons.c
deleted file mode 100644
index bd80d6eae..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devcons.c
+++ /dev/null
@@ -1,1193 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "keyboard.h"
-
-void (*consdebug)(void) = 0;
-void (*screenputs)(char*, int) = 0;
-
-Queue* kbdq; /* unprocessed console input */
-Queue* lineq; /* processed console input */
-Queue* serialoq; /* serial console output */
-Queue* kprintoq; /* console output, for /dev/kprint */
-long kprintinuse; /* test and set whether /dev/kprint is open */
-Lock kprintlock;
-int iprintscreenputs = 0;
-
-int panicking;
-
-struct
-{
- int exiting;
- int machs;
-} active;
-
-static struct
-{
- QLock lk;
-
- int raw; /* true if we shouldn't process input */
- int ctl; /* number of opens to the control file */
- int x; /* index into line */
- char line[1024]; /* current input line */
-
- int count;
- int ctlpoff;
-
- /* a place to save up characters at interrupt time before dumping them in the queue */
- Lock lockputc;
- char istage[1024];
- char *iw;
- char *ir;
- char *ie;
-} kbd = {
- { 0 },
- 0,
- 0,
- 0,
- { 0 },
- 0,
- 0,
- { 0 },
- { 0 },
- kbd.istage,
- kbd.istage,
- kbd.istage + sizeof(kbd.istage),
-};
-
-char *sysname;
-vlong fasthz;
-
-static int readtime(ulong, char*, int);
-static int readbintime(char*, int);
-static int writetime(char*, int);
-static int writebintime(char*, int);
-
-enum
-{
- CMreboot,
- CMpanic,
-};
-
-Cmdtab rebootmsg[] =
-{
- CMreboot, "reboot", 0,
- CMpanic, "panic", 0,
-};
-
-int
-return0(void *v)
-{
- return 0;
-}
-
-void
-printinit(void)
-{
- lineq = qopen(2*1024, 0, 0, nil);
- if(lineq == nil)
- panic("printinit");
- qnoblock(lineq, 1);
-
- kbdq = qopen(4*1024, 0, 0, 0);
- if(kbdq == nil)
- panic("kbdinit");
- qnoblock(kbdq, 1);
-}
-
-int
-consactive(void)
-{
- if(serialoq)
- return qlen(serialoq) > 0;
- return 0;
-}
-
-void
-prflush(void)
-{
-/*
- ulong now;
-
- now = m->ticks;
- while(consactive())
- if(m->ticks - now >= HZ)
- break;
-*/
-}
-
-/*
- * Print a string on the console. Convert \n to \r\n for serial
- * line consoles. Locking of the queues is left up to the screen
- * or uart code. Multi-line messages to serial consoles may get
- * interspersed with other messages.
- */
-static void
-putstrn0(char *str, int n, int usewrite)
-{
- /*
- * if someone is reading /dev/kprint,
- * put the message there.
- * if not and there's an attached bit mapped display,
- * put the message there.
- *
- * if there's a serial line being used as a console,
- * put the message there.
- */
- if(kprintoq != nil && !qisclosed(kprintoq)){
- if(usewrite)
- qwrite(kprintoq, str, n);
- else
- qiwrite(kprintoq, str, n);
- }else if(screenputs != 0)
- screenputs(str, n);
-}
-
-void
-putstrn(char *str, int n)
-{
- putstrn0(str, n, 0);
-}
-
-int noprint;
-
-int
-print(char *fmt, ...)
-{
- int n;
- va_list arg;
- char buf[PRINTSIZE];
-
- if(noprint)
- return -1;
-
- va_start(arg, fmt);
- n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
- va_end(arg);
- putstrn(buf, n);
-
- return n;
-}
-
-void
-panic(char *fmt, ...)
-{
- int n;
- va_list arg;
- char buf[PRINTSIZE];
-
- kprintoq = nil; /* don't try to write to /dev/kprint */
-
- if(panicking)
- for(;;);
- panicking = 1;
-
- splhi();
- strcpy(buf, "panic: ");
- va_start(arg, fmt);
- n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
- va_end(arg);
- buf[n] = '\n';
- uartputs(buf, n+1);
- if(consdebug)
- (*consdebug)();
- spllo();
- prflush();
- putstrn(buf, n+1);
- dumpstack();
-
- exit(1);
-}
-
-int
-pprint(char *fmt, ...)
-{
- int n;
- Chan *c;
- va_list arg;
- char buf[2*PRINTSIZE];
-
- if(up == nil || up->fgrp == nil)
- return 0;
-
- c = up->fgrp->fd[2];
- if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
- return 0;
- n = sprint(buf, "%s %lud: ", up->text, up->pid);
- va_start(arg, fmt);
- n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
- va_end(arg);
-
- if(waserror())
- return 0;
- devtab[c->type]->write(c, buf, n, c->offset);
- poperror();
-
- lock(&c->ref.lk);
- c->offset += n;
- unlock(&c->ref.lk);
-
- return n;
-}
-
-static void
-echoscreen(char *buf, int n)
-{
- char *e, *p;
- char ebuf[128];
- int x;
-
- p = ebuf;
- e = ebuf + sizeof(ebuf) - 4;
- while(n-- > 0){
- if(p >= e){
- screenputs(ebuf, p - ebuf);
- p = ebuf;
- }
- x = *buf++;
- if(x == 0x15){
- *p++ = '^';
- *p++ = 'U';
- *p++ = '\n';
- } else
- *p++ = x;
- }
- if(p != ebuf)
- screenputs(ebuf, p - ebuf);
-}
-
-static void
-echoserialoq(char *buf, int n)
-{
- char *e, *p;
- char ebuf[128];
- int x;
-
- p = ebuf;
- e = ebuf + sizeof(ebuf) - 4;
- while(n-- > 0){
- if(p >= e){
- qiwrite(serialoq, ebuf, p - ebuf);
- p = ebuf;
- }
- x = *buf++;
- if(x == '\n'){
- *p++ = '\r';
- *p++ = '\n';
- } else if(x == 0x15){
- *p++ = '^';
- *p++ = 'U';
- *p++ = '\n';
- } else
- *p++ = x;
- }
- if(p != ebuf)
- qiwrite(serialoq, ebuf, p - ebuf);
-}
-
-static void
-echo(char *buf, int n)
-{
- static int ctrlt;
- int x;
- char *e, *p;
-
- e = buf+n;
- for(p = buf; p < e; p++){
- switch(*p){
- case 0x10: /* ^P */
- if(cpuserver && !kbd.ctlpoff){
- active.exiting = 1;
- return;
- }
- break;
- case 0x14: /* ^T */
- ctrlt++;
- if(ctrlt > 2)
- ctrlt = 2;
- continue;
- }
-
- if(ctrlt != 2)
- continue;
-
- /* ^T escapes */
- ctrlt = 0;
- switch(*p){
- case 'S':
- x = splhi();
- dumpstack();
- procdump();
- splx(x);
- return;
- case 's':
- dumpstack();
- return;
- case 'x':
- xsummary();
- ixsummary();
- mallocsummary();
- pagersummary();
- return;
- case 'd':
- if(consdebug == 0)
- consdebug = rdb;
- else
- consdebug = 0;
- print("consdebug now 0x%p\n", consdebug);
- return;
- case 'D':
- if(consdebug == 0)
- consdebug = rdb;
- consdebug();
- return;
- case 'p':
- x = spllo();
- procdump();
- splx(x);
- return;
- case 'q':
- scheddump();
- return;
- case 'k':
- killbig();
- return;
- case 'r':
- exit(0);
- return;
- }
- }
-
- qproduce(kbdq, buf, n);
- if(kbd.raw)
- return;
- if(screenputs != 0)
- echoscreen(buf, n);
- if(serialoq)
- echoserialoq(buf, n);
-}
-
-/*
- * Called by a uart interrupt for console input.
- *
- * turn '\r' into '\n' before putting it into the queue.
- */
-int
-kbdcr2nl(Queue *q, int ch)
-{
- char *next;
-
- USED(q);
- ilock(&kbd.lockputc); /* just a mutex */
- if(ch == '\r' && !kbd.raw)
- ch = '\n';
- next = kbd.iw+1;
- if(next >= kbd.ie)
- next = kbd.istage;
- if(next != kbd.ir){
- *kbd.iw = ch;
- kbd.iw = next;
- }
- iunlock(&kbd.lockputc);
- return 0;
-}
-static
-void
-_kbdputc(int c)
-{
- Rune r;
- char buf[UTFmax];
- int n;
-
- r = c;
- n = runetochar(buf, &r);
- if(n == 0)
- return;
- echo(buf, n);
-// kbd.c = r;
-// qproduce(kbdq, buf, n);
-}
-
-/* _kbdputc, but with compose translation */
-int
-kbdputc(Queue *q, int c)
-{
- int i;
- static int collecting, nk;
- static Rune kc[5];
-
- if(c == Kalt){
- collecting = 1;
- nk = 0;
- return 0;
- }
-
- if(!collecting){
- _kbdputc(c);
- return 0;
- }
-
- kc[nk++] = c;
- c = latin1(kc, nk);
- if(c < -1) /* need more keystrokes */
- return 0;
- if(c != -1) /* valid sequence */
- _kbdputc(c);
- else
- for(i=0; i<nk; i++)
- _kbdputc(kc[i]);
- nk = 0;
- collecting = 0;
-
- return 0;
-}
-
-
-enum{
- Qdir,
- Qbintime,
- Qcons,
- Qconsctl,
- Qcpunote,
- Qcputime,
- Qdrivers,
- Qkprint,
- Qhostdomain,
- Qhostowner,
- Qnull,
- Qosversion,
- Qpgrpid,
- Qpid,
- Qppid,
- Qrandom,
- Qreboot,
- Qsecstore,
- Qshowfile,
- Qsnarf,
- Qswap,
- Qsysname,
- Qsysstat,
- Qtime,
- Quser,
- Qzero,
-};
-
-enum
-{
- VLNUMSIZE= 22,
-};
-
-static Dirtab consdir[]={
- ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
- "bintime", {Qbintime}, 24, 0664,
- "cons", {Qcons}, 0, 0660,
- "consctl", {Qconsctl}, 0, 0220,
- "cpunote", {Qcpunote}, 0, 0444,
- "cputime", {Qcputime}, 6*NUMSIZE, 0444,
- "drivers", {Qdrivers}, 0, 0444,
- "hostdomain", {Qhostdomain}, DOMLEN, 0664,
- "hostowner", {Qhostowner}, 0, 0664,
- "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
- "null", {Qnull}, 0, 0666,
- "osversion", {Qosversion}, 0, 0444,
- "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
- "pid", {Qpid}, NUMSIZE, 0444,
- "ppid", {Qppid}, NUMSIZE, 0444,
- "random", {Qrandom}, 0, 0444,
- "reboot", {Qreboot}, 0, 0664,
- "secstore", {Qsecstore}, 0, 0666,
- "showfile", {Qshowfile}, 0, 0220,
- "snarf", {Qsnarf}, 0, 0666,
- "swap", {Qswap}, 0, 0664,
- "sysname", {Qsysname}, 0, 0664,
- "sysstat", {Qsysstat}, 0, 0666,
- "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
- "user", {Quser}, 0, 0666,
- "zero", {Qzero}, 0, 0444,
-};
-
-char secstorebuf[65536];
-Dirtab *secstoretab = &consdir[Qsecstore];
-Dirtab *snarftab = &consdir[Qsnarf];
-
-int
-readnum(ulong off, char *buf, ulong n, ulong val, int size)
-{
- char tmp[64];
-
- snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val);
- tmp[size-1] = ' ';
- if(off >= size)
- return 0;
- if(off+n > size)
- n = size-off;
- memmove(buf, tmp+off, n);
- return n;
-}
-
-int
-readstr(ulong off, char *buf, ulong n, char *str)
-{
- int size;
-
- size = strlen(str);
- if(off >= size)
- return 0;
- if(off+n > size)
- n = size-off;
- memmove(buf, str+off, n);
- return n;
-}
-
-static void
-consinit(void)
-{
- todinit();
- randominit();
- /*
- * at 115200 baud, the 1024 char buffer takes 56 ms to process,
- * processing it every 22 ms should be fine
- */
-/* addclock0link(kbdputcclock, 22); */
-}
-
-static Chan*
-consattach(char *spec)
-{
- return devattach('c', spec);
-}
-
-static Walkqid*
-conswalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
-}
-
-static int
-consstat(Chan *c, uchar *dp, int n)
-{
- return devstat(c, dp, n, consdir, nelem(consdir), devgen);
-}
-
-static Chan*
-consopen(Chan *c, int omode)
-{
- c->aux = nil;
- c = devopen(c, omode, consdir, nelem(consdir), devgen);
- switch((ulong)c->qid.path){
- case Qconsctl:
- qlock(&kbd.lk);
- kbd.ctl++;
- qunlock(&kbd.lk);
- break;
-
- case Qkprint:
- lock(&kprintlock);
- if(kprintinuse != 0){
- c->flag &= ~COPEN;
- unlock(&kprintlock);
- error(Einuse);
- }
- kprintinuse = 1;
- unlock(&kprintlock);
- if(kprintoq == nil){
- kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
- if(kprintoq == nil){
- c->flag &= ~COPEN;
- error(Enomem);
- }
- qnoblock(kprintoq, 1);
- }else
- qreopen(kprintoq);
- c->iounit = qiomaxatomic;
- break;
-
- case Qsecstore:
- if(omode == ORDWR)
- error(Eperm);
- if(omode != OREAD)
- memset(secstorebuf, 0, sizeof secstorebuf);
- break;
-
- case Qsnarf:
- if(omode == ORDWR)
- error(Eperm);
- if(omode == OREAD)
- c->aux = strdup("");
- else
- c->aux = mallocz(SnarfSize, 1);
- break;
- }
- return c;
-}
-
-static void
-consclose(Chan *c)
-{
- switch((ulong)c->qid.path){
- /* last close of control file turns off raw */
- case Qconsctl:
- if(c->flag&COPEN){
- qlock(&kbd.lk);
- if(--kbd.ctl == 0)
- kbd.raw = 0;
- qunlock(&kbd.lk);
- }
- break;
-
- /* close of kprint allows other opens */
- case Qkprint:
- if(c->flag & COPEN){
- kprintinuse = 0;
- qhangup(kprintoq, nil);
- }
- break;
-
- case Qsnarf:
- if(c->mode == OWRITE)
- clipwrite(c->aux);
- free(c->aux);
- break;
- }
-}
-
-static long
-consread(Chan *c, void *buf, long n, vlong off)
-{
- char *b;
- char tmp[128]; /* must be >= 6*NUMSIZE */
- char *cbuf = buf;
- int ch, i, eol;
- vlong offset = off;
-
- if(n <= 0)
- return n;
- switch((ulong)c->qid.path){
- case Qdir:
- return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
-
- case Qcons:
- qlock(&kbd.lk);
- if(waserror()) {
- qunlock(&kbd.lk);
- nexterror();
- }
- if(kbd.raw) {
- if(qcanread(lineq))
- n = qread(lineq, buf, n);
- else {
- /* read as much as possible */
- do {
- i = qread(kbdq, cbuf, n);
- cbuf += i;
- n -= i;
- } while (n>0 && qcanread(kbdq));
- n = cbuf - (char*)buf;
- }
- } else {
- while(!qcanread(lineq)) {
- qread(kbdq, &kbd.line[kbd.x], 1);
- ch = kbd.line[kbd.x];
- eol = 0;
- switch(ch){
- case '\b':
- if(kbd.x)
- kbd.x--;
- break;
- case 0x15:
- kbd.x = 0;
- break;
- case '\n':
- case 0x04:
- eol = 1;
- default:
- kbd.line[kbd.x++] = ch;
- break;
- }
- if(kbd.x == sizeof(kbd.line) || eol){
- if(ch == 0x04)
- kbd.x--;
- qwrite(lineq, kbd.line, kbd.x);
- kbd.x = 0;
- }
- }
- n = qread(lineq, buf, n);
- }
- qunlock(&kbd.lk);
- poperror();
- return n;
-
- case Qcpunote:
- sleep(&up->sleep, return0, nil);
-
- case Qcputime:
- return 0;
-
- case Qkprint:
- return qread(kprintoq, buf, n);
-
- case Qpgrpid:
- return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
-
- case Qpid:
- return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
-
- case Qppid:
- return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
-
- case Qtime:
- return readtime((ulong)offset, buf, n);
-
- case Qbintime:
- return readbintime(buf, n);
-
- case Qhostowner:
- return readstr((ulong)offset, buf, n, eve);
-
- case Qhostdomain:
- return readstr((ulong)offset, buf, n, hostdomain);
-
- case Quser:
- return readstr((ulong)offset, buf, n, up->user);
-
- case Qnull:
- return 0;
-
- case Qsnarf:
- if(offset == 0){
- free(c->aux);
- c->aux = clipread();
- }
- if(c->aux == nil)
- return 0;
- return readstr(offset, buf, n, c->aux);
-
- case Qsecstore:
- return readstr(offset, buf, n, secstorebuf);
-
- case Qsysstat:
- return 0;
-
- case Qswap:
- return 0;
-
- case Qsysname:
- if(sysname == nil)
- return 0;
- return readstr((ulong)offset, buf, n, sysname);
-
- case Qrandom:
- return randomread(buf, n);
-
- case Qdrivers:
- b = malloc(READSTR);
- if(b == nil)
- error(Enomem);
- n = 0;
- for(i = 0; devtab[i] != nil; i++)
- n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name);
- if(waserror()){
- free(b);
- nexterror();
- }
- n = readstr((ulong)offset, buf, n, b);
- free(b);
- poperror();
- return n;
-
- case Qzero:
- memset(buf, 0, n);
- return n;
-
- case Qosversion:
- snprint(tmp, sizeof tmp, "2000");
- n = readstr((ulong)offset, buf, n, tmp);
- return n;
-
- default:
- print("consread 0x%llux\n", c->qid.path);
- error(Egreg);
- }
- return -1; /* never reached */
-}
-
-static long
-conswrite(Chan *c, void *va, long n, vlong off)
-{
- char buf[256];
- long l, bp;
- char *a = va;
- int fd;
- Chan *swc;
- ulong offset = off;
- Cmdbuf *cb;
- Cmdtab *ct;
-
- switch((ulong)c->qid.path){
- case Qcons:
- /*
- * Can't page fault in putstrn, so copy the data locally.
- */
- l = n;
- while(l > 0){
- bp = l;
- if(bp > sizeof buf)
- bp = sizeof buf;
- memmove(buf, a, bp);
- putstrn0(buf, bp, 1);
- a += bp;
- l -= bp;
- }
- break;
-
- case Qconsctl:
- if(n >= sizeof(buf))
- n = sizeof(buf)-1;
- strncpy(buf, a, n);
- buf[n] = 0;
- for(a = buf; a;){
- if(strncmp(a, "rawon", 5) == 0){
- qlock(&kbd.lk);
- if(kbd.x){
- qwrite(kbdq, kbd.line, kbd.x);
- kbd.x = 0;
- }
- kbd.raw = 1;
- qunlock(&kbd.lk);
- } else if(strncmp(a, "rawoff", 6) == 0){
- qlock(&kbd.lk);
- kbd.raw = 0;
- kbd.x = 0;
- qunlock(&kbd.lk);
- } else if(strncmp(a, "ctlpon", 6) == 0){
- kbd.ctlpoff = 0;
- } else if(strncmp(a, "ctlpoff", 7) == 0){
- kbd.ctlpoff = 1;
- }
- if((a = strchr(a, ' ')))
- a++;
- }
- break;
-
- case Qtime:
- if(!iseve())
- error(Eperm);
- return writetime(a, n);
-
- case Qbintime:
- if(!iseve())
- error(Eperm);
- return writebintime(a, n);
-
- case Qhostowner:
- return hostownerwrite(a, n);
-
- case Qhostdomain:
- return hostdomainwrite(a, n);
-
- case Quser:
- return userwrite(a, n);
-
- case Qnull:
- break;
-
- case Qreboot:
- if(!iseve())
- error(Eperm);
- cb = parsecmd(a, n);
-
- if(waserror()) {
- free(cb);
- nexterror();
- }
- ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
- switch(ct->index) {
- case CMreboot:
- rebootcmd(cb->nf-1, cb->f+1);
- break;
- case CMpanic:
- panic("/dev/reboot");
- }
- poperror();
- free(cb);
- break;
-
- case Qsecstore:
- if(offset >= sizeof secstorebuf || offset+n+1 >= sizeof secstorebuf)
- error(Etoobig);
- secstoretab->qid.vers++;
- memmove(secstorebuf+offset, va, n);
- return n;
-
- case Qshowfile:
- return showfilewrite(a, n);
-
- case Qsnarf:
- if(offset >= SnarfSize || offset+n >= SnarfSize)
- error(Etoobig);
- snarftab->qid.vers++;
- memmove((uchar*)c->aux+offset, va, n);
- return n;
-
- case Qsysstat:
- n = 0;
- break;
-
- case Qswap:
- if(n >= sizeof buf)
- error(Egreg);
- memmove(buf, va, n); /* so we can NUL-terminate */
- buf[n] = 0;
- /* start a pager if not already started */
- if(strncmp(buf, "start", 5) == 0){
- kickpager();
- break;
- }
- if(cpuserver && !iseve())
- error(Eperm);
- if(buf[0]<'0' || '9'<buf[0])
- error(Ebadarg);
- fd = strtoul(buf, 0, 0);
- swc = fdtochan(fd, -1, 1, 1);
- setswapchan(swc);
- break;
-
- case Qsysname:
- if(offset != 0)
- error(Ebadarg);
- if(n <= 0 || n >= sizeof buf)
- error(Ebadarg);
- strncpy(buf, a, n);
- buf[n] = 0;
- if(buf[n-1] == '\n')
- buf[n-1] = 0;
- kstrdup(&sysname, buf);
- break;
-
- default:
- print("conswrite: 0x%llux\n", c->qid.path);
- error(Egreg);
- }
- return n;
-}
-
-Dev consdevtab = {
- 'c',
- "cons",
-
- devreset,
- consinit,
- devshutdown,
- consattach,
- conswalk,
- consstat,
- consopen,
- devcreate,
- consclose,
- consread,
- devbread,
- conswrite,
- devbwrite,
- devremove,
- devwstat,
-};
-
-static uvlong uvorder = (uvlong) 0x0001020304050607ULL;
-
-static uchar*
-le2vlong(vlong *to, uchar *f)
-{
- uchar *t, *o;
- int i;
-
- t = (uchar*)to;
- o = (uchar*)&uvorder;
- for(i = 0; i < sizeof(vlong); i++)
- t[o[i]] = f[i];
- return f+sizeof(vlong);
-}
-
-static uchar*
-vlong2le(uchar *t, vlong from)
-{
- uchar *f, *o;
- int i;
-
- f = (uchar*)&from;
- o = (uchar*)&uvorder;
- for(i = 0; i < sizeof(vlong); i++)
- t[i] = f[o[i]];
- return t+sizeof(vlong);
-}
-
-static long order = 0x00010203;
-
-static uchar*
-le2long(long *to, uchar *f)
-{
- uchar *t, *o;
- int i;
-
- t = (uchar*)to;
- o = (uchar*)&order;
- for(i = 0; i < sizeof(long); i++)
- t[o[i]] = f[i];
- return f+sizeof(long);
-}
-
-/*
-static uchar*
-long2le(uchar *t, long from)
-{
- uchar *f, *o;
- int i;
-
- f = (uchar*)&from;
- o = (uchar*)&order;
- for(i = 0; i < sizeof(long); i++)
- t[i] = f[o[i]];
- return t+sizeof(long);
-}
-*/
-
-char *Ebadtimectl = "bad time control";
-
-/*
- * like the old #c/time but with added info. Return
- *
- * secs nanosecs fastticks fasthz
- */
-static int
-readtime(ulong off, char *buf, int n)
-{
- vlong nsec, ticks;
- long sec;
- char str[7*NUMSIZE];
-
- nsec = todget(&ticks);
- if(fasthz == (vlong)0)
- fastticks((uvlong*)&fasthz);
- sec = nsec/((uvlong) 1000000000);
- snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ",
- NUMSIZE-1, sec,
- VLNUMSIZE-1, nsec,
- VLNUMSIZE-1, ticks,
- VLNUMSIZE-1, fasthz);
- return readstr(off, buf, n, str);
-}
-
-/*
- * set the time in seconds
- */
-static int
-writetime(char *buf, int n)
-{
- char b[13];
- long i;
- vlong now;
-
- if(n >= sizeof(b))
- error(Ebadtimectl);
- strncpy(b, buf, n);
- b[n] = 0;
- i = strtol(b, 0, 0);
- if(i <= 0)
- error(Ebadtimectl);
- now = i*((vlong) 1000000000);
- todset(now, 0, 0);
- return n;
-}
-
-/*
- * read binary time info. all numbers are little endian.
- * ticks and nsec are syncronized.
- */
-static int
-readbintime(char *buf, int n)
-{
- int i;
- vlong nsec, ticks;
- uchar *b = (uchar*)buf;
-
- i = 0;
- if(fasthz == (vlong)0)
- fastticks((uvlong*)&fasthz);
- nsec = todget(&ticks);
- if(n >= 3*sizeof(uvlong)){
- vlong2le(b+2*sizeof(uvlong), fasthz);
- i += sizeof(uvlong);
- }
- if(n >= 2*sizeof(uvlong)){
- vlong2le(b+sizeof(uvlong), ticks);
- i += sizeof(uvlong);
- }
- if(n >= 8){
- vlong2le(b, nsec);
- i += sizeof(vlong);
- }
- return i;
-}
-
-/*
- * set any of the following
- * - time in nsec
- * - nsec trim applied over some seconds
- * - clock frequency
- */
-static int
-writebintime(char *buf, int n)
-{
- uchar *p;
- vlong delta;
- long period;
-
- n--;
- p = (uchar*)buf + 1;
- switch(*buf){
- case 'n':
- if(n < sizeof(vlong))
- error(Ebadtimectl);
- le2vlong(&delta, p);
- todset(delta, 0, 0);
- break;
- case 'd':
- if(n < sizeof(vlong)+sizeof(long))
- error(Ebadtimectl);
- p = le2vlong(&delta, p);
- le2long(&period, p);
- todset(-1, delta, period);
- break;
- case 'f':
- if(n < sizeof(uvlong))
- error(Ebadtimectl);
- le2vlong(&fasthz, p);
- todsetfreq(fasthz);
- break;
- }
- return n;
-}
-
-
-int
-iprint(char *fmt, ...)
-{
- int n, s;
- va_list arg;
- char buf[PRINTSIZE];
-
- s = splhi();
- va_start(arg, fmt);
- n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
- va_end(arg);
- if(screenputs != 0 && iprintscreenputs)
- screenputs(buf, n);
-#undef write
- write(2, buf, n);
- splx(s);
-
- return n;
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/devdraw.c b/sys/src/cmd/unix/drawterm/kern/devdraw.c
deleted file mode 100644
index 8b6148e3c..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devdraw.c
+++ /dev/null
@@ -1,2148 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#define Image IMAGE
-#include <draw.h>
-#include <memdraw.h>
-#include <memlayer.h>
-#include <cursor.h>
-#include "screen.h"
-
-enum
-{
- Qtopdir = 0,
- Qnew,
- Q3rd,
- Q2nd,
- Qcolormap,
- Qctl,
- Qdata,
- Qrefresh,
-};
-
-/*
- * Qid path is:
- * 4 bits of file type (qids above)
- * 24 bits of mux slot number +1; 0 means not attached to client
- */
-#define QSHIFT 4 /* location in qid of client # */
-
-#define QID(q) ((((ulong)(q).path)&0x0000000F)>>0)
-#define CLIENTPATH(q) ((((ulong)q)&0x7FFFFFF0)>>QSHIFT)
-#define CLIENT(q) CLIENTPATH((q).path)
-
-#define NHASH (1<<5)
-#define HASHMASK (NHASH-1)
-#define IOUNIT (64*1024)
-
-typedef struct Client Client;
-typedef struct Draw Draw;
-typedef struct DImage DImage;
-typedef struct DScreen DScreen;
-typedef struct CScreen CScreen;
-typedef struct FChar FChar;
-typedef struct Refresh Refresh;
-typedef struct Refx Refx;
-typedef struct DName DName;
-
-ulong blanktime = 30; /* in minutes; a half hour */
-
-struct Draw
-{
- QLock lk;
- int clientid;
- int nclient;
- Client** client;
- int nname;
- DName* name;
- int vers;
- int softscreen;
- int blanked; /* screen turned off */
- ulong blanktime; /* time of last operation */
- ulong savemap[3*256];
-};
-
-struct Client
-{
- Ref r;
- DImage* dimage[NHASH];
- CScreen* cscreen;
- Refresh* refresh;
- Rendez refrend;
- uchar* readdata;
- int nreaddata;
- int busy;
- int clientid;
- int slot;
- int refreshme;
- int infoid;
- int op;
-};
-
-struct Refresh
-{
- DImage* dimage;
- Rectangle r;
- Refresh* next;
-};
-
-struct Refx
-{
- Client* client;
- DImage* dimage;
-};
-
-struct DName
-{
- char *name;
- Client *client;
- DImage* dimage;
- int vers;
-};
-
-struct FChar
-{
- int minx; /* left edge of bits */
- int maxx; /* right edge of bits */
- uchar miny; /* first non-zero scan-line */
- uchar maxy; /* last non-zero scan-line + 1 */
- schar left; /* offset of baseline */
- uchar width; /* width of baseline */
-};
-
-/*
- * Reference counts in DImages:
- * one per open by original client
- * one per screen image or fill
- * one per image derived from this one by name
- */
-struct DImage
-{
- int id;
- int ref;
- char *name;
- int vers;
- Memimage* image;
- int ascent;
- int nfchar;
- FChar* fchar;
- DScreen* dscreen; /* 0 if not a window */
- DImage* fromname; /* image this one is derived from, by name */
- DImage* next;
-};
-
-struct CScreen
-{
- DScreen* dscreen;
- CScreen* next;
-};
-
-struct DScreen
-{
- int id;
- int public;
- int ref;
- DImage *dimage;
- DImage *dfill;
- Memscreen* screen;
- Client* owner;
- DScreen* next;
-};
-
-static Draw sdraw;
-static Memimage *screenimage;
-static Memdata screendata;
-static Rectangle flushrect;
-static int waste;
-static DScreen* dscreen;
-extern void flushmemscreen(Rectangle);
- void drawmesg(Client*, void*, int);
- void drawuninstall(Client*, int);
- void drawfreedimage(DImage*);
- Client* drawclientofpath(ulong);
-
-static char Enodrawimage[] = "unknown id for draw image";
-static char Enodrawscreen[] = "unknown id for draw screen";
-static char Eshortdraw[] = "short draw message";
-static char Eshortread[] = "draw read too short";
-static char Eimageexists[] = "image id in use";
-static char Escreenexists[] = "screen id in use";
-static char Edrawmem[] = "image memory allocation failed";
-static char Ereadoutside[] = "readimage outside image";
-static char Ewriteoutside[] = "writeimage outside image";
-static char Enotfont[] = "image not a font";
-static char Eindex[] = "character index out of range";
-static char Enoclient[] = "no such draw client";
-/* static char Edepth[] = "image has bad depth"; */
-static char Enameused[] = "image name in use";
-static char Enoname[] = "no image with that name";
-static char Eoldname[] = "named image no longer valid";
-static char Enamed[] = "image already has name";
-static char Ewrongname[] = "wrong name for image";
-
-int
-drawcanqlock(void)
-{
- return canqlock(&sdraw.lk);
-}
-
-void
-drawqlock(void)
-{
- qlock(&sdraw.lk);
-}
-
-void
-drawqunlock(void)
-{
- qunlock(&sdraw.lk);
-}
-
-static int
-drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp)
-{
- int t;
- Qid q;
- ulong path;
- Client *cl;
-
- USED(name);
- USED(dt);
- USED(ndt);
-
- q.vers = 0;
-
- if(s == DEVDOTDOT){
- switch(QID(c->qid)){
- case Qtopdir:
- case Q2nd:
- mkqid(&q, Qtopdir, 0, QTDIR);
- devdir(c, q, "#i", 0, eve, 0500, dp);
- break;
- case Q3rd:
- cl = drawclientofpath(c->qid.path);
- if(cl == nil)
- strcpy(up->genbuf, "??");
- else
- sprint(up->genbuf, "%d", cl->clientid);
- mkqid(&q, Q2nd, 0, QTDIR);
- devdir(c, q, up->genbuf, 0, eve, 0500, dp);
- break;
- default:
- panic("drawwalk %llux", c->qid.path);
- }
- return 1;
- }
-
- /*
- * Top level directory contains the name of the device.
- */
- t = QID(c->qid);
- if(t == Qtopdir){
- switch(s){
- case 0:
- mkqid(&q, Q2nd, 0, QTDIR);
- devdir(c, q, "draw", 0, eve, 0555, dp);
- break;
- default:
- return -1;
- }
- return 1;
- }
-
- /*
- * Second level contains "new" plus all the clients.
- */
- if(t == Q2nd || t == Qnew){
- if(s == 0){
- mkqid(&q, Qnew, 0, QTFILE);
- devdir(c, q, "new", 0, eve, 0666, dp);
- }
- else if(s <= sdraw.nclient){
- cl = sdraw.client[s-1];
- if(cl == 0)
- return 0;
- sprint(up->genbuf, "%d", cl->clientid);
- mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR);
- devdir(c, q, up->genbuf, 0, eve, 0555, dp);
- return 1;
- }
- else
- return -1;
- return 1;
- }
-
- /*
- * Third level.
- */
- path = c->qid.path&~((1<<QSHIFT)-1); /* slot component */
- q.vers = c->qid.vers;
- q.type = QTFILE;
- switch(s){
- case 0:
- q.path = path|Qcolormap;
- devdir(c, q, "colormap", 0, eve, 0600, dp);
- break;
- case 1:
- q.path = path|Qctl;
- devdir(c, q, "ctl", 0, eve, 0600, dp);
- break;
- case 2:
- q.path = path|Qdata;
- devdir(c, q, "data", 0, eve, 0600, dp);
- break;
- case 3:
- q.path = path|Qrefresh;
- devdir(c, q, "refresh", 0, eve, 0400, dp);
- break;
- default:
- return -1;
- }
- return 1;
-}
-
-static
-int
-drawrefactive(void *a)
-{
- Client *c;
-
- c = a;
- return c->refreshme || c->refresh!=0;
-}
-
-static
-void
-drawrefreshscreen(DImage *l, Client *client)
-{
- while(l != nil && l->dscreen == nil)
- l = l->fromname;
- if(l != nil && l->dscreen->owner != client)
- l->dscreen->owner->refreshme = 1;
-}
-
-static
-void
-drawrefresh(Memimage *m, Rectangle r, void *v)
-{
- Refx *x;
- DImage *d;
- Client *c;
- Refresh *ref;
-
- USED(m);
-
- if(v == 0)
- return;
- x = v;
- c = x->client;
- d = x->dimage;
- for(ref=c->refresh; ref; ref=ref->next)
- if(ref->dimage == d){
- combinerect(&ref->r, r);
- return;
- }
- ref = malloc(sizeof(Refresh));
- if(ref){
- ref->dimage = d;
- ref->r = r;
- ref->next = c->refresh;
- c->refresh = ref;
- }
-}
-
-static void
-addflush(Rectangle r)
-{
- int abb, ar, anbb;
- Rectangle nbb;
-
- if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
- return;
-
- if(flushrect.min.x >= flushrect.max.x){
- flushrect = r;
- waste = 0;
- return;
- }
- nbb = flushrect;
- combinerect(&nbb, r);
- ar = Dx(r)*Dy(r);
- abb = Dx(flushrect)*Dy(flushrect);
- anbb = Dx(nbb)*Dy(nbb);
- /*
- * Area of new waste is area of new bb minus area of old bb,
- * less the area of the new segment, which we assume is not waste.
- * This could be negative, but that's OK.
- */
- waste += anbb-abb - ar;
- if(waste < 0)
- waste = 0;
- /*
- * absorb if:
- * total area is small
- * waste is less than half total area
- * rectangles touch
- */
- if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
- flushrect = nbb;
- return;
- }
- /* emit current state */
- if(flushrect.min.x < flushrect.max.x)
- flushmemscreen(flushrect);
- flushrect = r;
- waste = 0;
-}
-
-static
-void
-dstflush(int dstid, Memimage *dst, Rectangle r)
-{
- Memlayer *l;
-
- if(dstid == 0){
- combinerect(&flushrect, r);
- return;
- }
- /* how can this happen? -rsc, dec 12 2002 */
- if(dst == 0){
- print("nil dstflush\n");
- return;
- }
- l = dst->layer;
- if(l == nil)
- return;
- do{
- if(l->screen->image->data != screenimage->data)
- return;
- r = rectaddpt(r, l->delta);
- l = l->screen->image->layer;
- }while(l);
- addflush(r);
-}
-
-void
-drawflush(void)
-{
- if(flushrect.min.x < flushrect.max.x)
- flushmemscreen(flushrect);
- flushrect = Rect(10000, 10000, -10000, -10000);
-}
-
-void
-drawflushr(Rectangle r)
-{
- qlock(&sdraw.lk);
- flushmemscreen(r);
- qunlock(&sdraw.lk);
-}
-
-static
-int
-drawcmp(char *a, char *b, int n)
-{
- if(strlen(a) != n)
- return 1;
- return memcmp(a, b, n);
-}
-
-DName*
-drawlookupname(int n, char *str)
-{
- DName *name, *ename;
-
- name = sdraw.name;
- ename = &name[sdraw.nname];
- for(; name<ename; name++)
- if(drawcmp(name->name, str, n) == 0)
- return name;
- return 0;
-}
-
-int
-drawgoodname(DImage *d)
-{
- DName *n;
-
- /* if window, validate the screen's own images */
- if(d->dscreen)
- if(drawgoodname(d->dscreen->dimage) == 0
- || drawgoodname(d->dscreen->dfill) == 0)
- return 0;
- if(d->name == nil)
- return 1;
- n = drawlookupname(strlen(d->name), d->name);
- if(n==nil || n->vers!=d->vers)
- return 0;
- return 1;
-}
-
-DImage*
-drawlookup(Client *client, int id, int checkname)
-{
- DImage *d;
-
- d = client->dimage[id&HASHMASK];
- while(d){
- if(d->id == id){
- if(checkname && !drawgoodname(d))
- error(Eoldname);
- return d;
- }
- d = d->next;
- }
- return 0;
-}
-
-DScreen*
-drawlookupdscreen(int id)
-{
- DScreen *s;
-
- s = dscreen;
- while(s){
- if(s->id == id)
- return s;
- s = s->next;
- }
- return 0;
-}
-
-DScreen*
-drawlookupscreen(Client *client, int id, CScreen **cs)
-{
- CScreen *s;
-
- s = client->cscreen;
- while(s){
- if(s->dscreen->id == id){
- *cs = s;
- return s->dscreen;
- }
- s = s->next;
- }
- error(Enodrawscreen);
- return 0;
-}
-
-Memimage*
-drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
-{
- DImage *d;
-
- d = malloc(sizeof(DImage));
- if(d == 0)
- return 0;
- d->id = id;
- d->ref = 1;
- d->name = 0;
- d->vers = 0;
- d->image = i;
- d->nfchar = 0;
- d->fchar = 0;
- d->fromname = 0;
- d->dscreen = dscreen;
- d->next = client->dimage[id&HASHMASK];
- client->dimage[id&HASHMASK] = d;
- return i;
-}
-
-Memscreen*
-drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
-{
- Memscreen *s;
- CScreen *c;
-
- c = malloc(sizeof(CScreen));
- if(dimage && dimage->image && dimage->image->chan == 0)
- panic("bad image %p in drawinstallscreen", dimage->image);
-
- if(c == 0)
- return 0;
- if(d == 0){
- d = malloc(sizeof(DScreen));
- if(d == 0){
- free(c);
- return 0;
- }
- s = malloc(sizeof(Memscreen));
- if(s == 0){
- free(c);
- free(d);
- return 0;
- }
- s->frontmost = 0;
- s->rearmost = 0;
- d->dimage = dimage;
- if(dimage){
- s->image = dimage->image;
- dimage->ref++;
- }
- d->dfill = dfill;
- if(dfill){
- s->fill = dfill->image;
- dfill->ref++;
- }
- d->ref = 0;
- d->id = id;
- d->screen = s;
- d->public = public;
- d->next = dscreen;
- d->owner = client;
- dscreen = d;
- }
- c->dscreen = d;
- d->ref++;
- c->next = client->cscreen;
- client->cscreen = c;
- return d->screen;
-}
-
-void
-drawdelname(DName *name)
-{
- int i;
-
- i = name-sdraw.name;
- memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
- sdraw.nname--;
-}
-
-void
-drawfreedscreen(DScreen *this)
-{
- DScreen *ds, *next;
-
- this->ref--;
- if(this->ref < 0)
- print("negative ref in drawfreedscreen\n");
- if(this->ref > 0)
- return;
- ds = dscreen;
- if(ds == this){
- dscreen = this->next;
- goto Found;
- }
- while((next = ds->next)){ /* assign = */
- if(next == this){
- ds->next = this->next;
- goto Found;
- }
- ds = next;
- }
- error(Enodrawimage);
-
- Found:
- if(this->dimage)
- drawfreedimage(this->dimage);
- if(this->dfill)
- drawfreedimage(this->dfill);
- free(this->screen);
- free(this);
-}
-
-void
-drawfreedimage(DImage *dimage)
-{
- int i;
- Memimage *l;
- DScreen *ds;
-
- dimage->ref--;
- if(dimage->ref < 0)
- print("negative ref in drawfreedimage\n");
- if(dimage->ref > 0)
- return;
-
- /* any names? */
- for(i=0; i<sdraw.nname; )
- if(sdraw.name[i].dimage == dimage)
- drawdelname(sdraw.name+i);
- else
- i++;
- if(dimage->fromname){ /* acquired by name; owned by someone else*/
- drawfreedimage(dimage->fromname);
- goto Return;
- }
- if(dimage->image == screenimage) /* don't free the display */
- goto Return;
- ds = dimage->dscreen;
- if(ds){
- l = dimage->image;
- if(l->data == screenimage->data)
- addflush(l->layer->screenr);
- if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */
- free(l->layer->refreshptr);
- l->layer->refreshptr = nil;
- if(drawgoodname(dimage))
- memldelete(l);
- else
- memlfree(l);
- drawfreedscreen(ds);
- }else
- freememimage(dimage->image);
- Return:
- free(dimage->fchar);
- free(dimage);
-}
-
-void
-drawuninstallscreen(Client *client, CScreen *this)
-{
- CScreen *cs, *next;
-
- cs = client->cscreen;
- if(cs == this){
- client->cscreen = this->next;
- drawfreedscreen(this->dscreen);
- free(this);
- return;
- }
- while((next = cs->next)){ /* assign = */
- if(next == this){
- cs->next = this->next;
- drawfreedscreen(this->dscreen);
- free(this);
- return;
- }
- cs = next;
- }
-}
-
-void
-drawuninstall(Client *client, int id)
-{
- DImage *d, *next;
-
- d = client->dimage[id&HASHMASK];
- if(d == 0)
- error(Enodrawimage);
- if(d->id == id){
- client->dimage[id&HASHMASK] = d->next;
- drawfreedimage(d);
- return;
- }
- while((next = d->next)){ /* assign = */
- if(next->id == id){
- d->next = next->next;
- drawfreedimage(next);
- return;
- }
- d = next;
- }
- error(Enodrawimage);
-}
-
-void
-drawaddname(Client *client, DImage *di, int n, char *str)
-{
- DName *name, *ename, *new, *t;
-
- name = sdraw.name;
- ename = &name[sdraw.nname];
- for(; name<ename; name++)
- if(drawcmp(name->name, str, n) == 0)
- error(Enameused);
- t = smalloc((sdraw.nname+1)*sizeof(DName));
- memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
- free(sdraw.name);
- sdraw.name = t;
- new = &sdraw.name[sdraw.nname++];
- new->name = smalloc(n+1);
- memmove(new->name, str, n);
- new->name[n] = 0;
- new->dimage = di;
- new->client = client;
- new->vers = ++sdraw.vers;
-}
-
-Client*
-drawnewclient(void)
-{
- Client *cl, **cp;
- int i;
-
- for(i=0; i<sdraw.nclient; i++){
- cl = sdraw.client[i];
- if(cl == 0)
- break;
- }
- if(i == sdraw.nclient){
- cp = malloc((sdraw.nclient+1)*sizeof(Client*));
- if(cp == 0)
- return 0;
- memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
- free(sdraw.client);
- sdraw.client = cp;
- sdraw.nclient++;
- cp[i] = 0;
- }
- cl = malloc(sizeof(Client));
- if(cl == 0)
- return 0;
- memset(cl, 0, sizeof(Client));
- cl->slot = i;
- cl->clientid = ++sdraw.clientid;
- cl->op = SoverD;
- sdraw.client[i] = cl;
- return cl;
-}
-
-static int
-drawclientop(Client *cl)
-{
- int op;
-
- op = cl->op;
- cl->op = SoverD;
- return op;
-}
-
-int
-drawhasclients(void)
-{
- /*
- * if draw has ever been used, we can't resize the frame buffer,
- * even if all clients have exited (nclients is cumulative); it's too
- * hard to make work.
- */
- return sdraw.nclient != 0;
-}
-
-Client*
-drawclientofpath(ulong path)
-{
- Client *cl;
- int slot;
-
- slot = CLIENTPATH(path);
- if(slot == 0)
- return nil;
- cl = sdraw.client[slot-1];
- if(cl==0 || cl->clientid==0)
- return nil;
- return cl;
-}
-
-
-Client*
-drawclient(Chan *c)
-{
- Client *client;
-
- client = drawclientofpath(c->qid.path);
- if(client == nil)
- error(Enoclient);
- return client;
-}
-
-Memimage*
-drawimage(Client *client, uchar *a)
-{
- DImage *d;
-
- d = drawlookup(client, BGLONG(a), 1);
- if(d == nil)
- error(Enodrawimage);
- return d->image;
-}
-
-void
-drawrectangle(Rectangle *r, uchar *a)
-{
- r->min.x = BGLONG(a+0*4);
- r->min.y = BGLONG(a+1*4);
- r->max.x = BGLONG(a+2*4);
- r->max.y = BGLONG(a+3*4);
-}
-
-void
-drawpoint(Point *p, uchar *a)
-{
- p->x = BGLONG(a+0*4);
- p->y = BGLONG(a+1*4);
-}
-
-#define isvgascreen(dst) 1
-
-
-Point
-drawchar(Memimage *dst, Memimage *rdst, Point p,
- Memimage *src, Point *sp, DImage *font, int index, int op)
-{
- FChar *fc;
- Rectangle r;
- Point sp1;
- static Memimage *tmp;
-
- fc = &font->fchar[index];
- r.min.x = p.x+fc->left;
- r.min.y = p.y-(font->ascent-fc->miny);
- r.max.x = r.min.x+(fc->maxx-fc->minx);
- r.max.y = r.min.y+(fc->maxy-fc->miny);
- sp1.x = sp->x+fc->left;
- sp1.y = sp->y+fc->miny;
-
- /*
- * If we're drawing greyscale fonts onto a VGA screen,
- * it's very costly to read the screen memory to do the
- * alpha blending inside memdraw. If this is really a stringbg,
- * then rdst is the bg image (in main memory) which we can
- * refer to for the underlying dst pixels instead of reading dst
- * directly.
- */
- if(1 || (isvgascreen(dst) && !isvgascreen(rdst) /*&& font->image->depth > 1*/)){
- if(tmp == nil || tmp->chan != dst->chan || Dx(tmp->r) < Dx(r) || Dy(tmp->r) < Dy(r)){
- if(tmp)
- freememimage(tmp);
- tmp = allocmemimage(Rect(0,0,Dx(r),Dy(r)), dst->chan);
- if(tmp == nil)
- goto fallback;
- }
- memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), rdst, r.min, memopaque, ZP, S);
- memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), src, sp1, font->image, Pt(fc->minx, fc->miny), op);
- memdraw(dst, r, tmp, ZP, memopaque, ZP, S);
- }else{
- fallback:
- memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
- }
-
- p.x += fc->width;
- sp->x += fc->width;
- return p;
-}
-
-static int
-initscreenimage(void)
-{
- int width, depth;
- ulong chan;
- void *X;
- Rectangle r;
-
- if(screenimage != nil)
- return 1;
-
- screendata.base = nil;
- screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X);
- if(screendata.bdata == nil && X == nil)
- return 0;
- screendata.ref = 1;
-
- screenimage = allocmemimaged(r, chan, &screendata, X);
- if(screenimage == nil){
- /* RSC: BUG: detach screen */
- return 0;
- }
-
- screenimage->width = width;
- screenimage->clipr = r;
- return 1;
-}
-
-void
-deletescreenimage(void)
-{
- qlock(&sdraw.lk);
- /* RSC: BUG: detach screen */
- if(screenimage)
- freememimage(screenimage);
- screenimage = nil;
- qunlock(&sdraw.lk);
-}
-
-static Chan*
-drawattach(char *spec)
-{
- qlock(&sdraw.lk);
- if(!initscreenimage()){
- qunlock(&sdraw.lk);
- error("no frame buffer");
- }
- qunlock(&sdraw.lk);
- return devattach('i', spec);
-}
-
-static Walkqid*
-drawwalk(Chan *c, Chan *nc, char **name, int nname)
-{
- if(screendata.bdata == nil)
- error("no frame buffer");
- return devwalk(c, nc, name, nname, 0, 0, drawgen);
-}
-
-static int
-drawstat(Chan *c, uchar *db, int n)
-{
- return devstat(c, db, n, 0, 0, drawgen);
-}
-
-static Chan*
-drawopen(Chan *c, int omode)
-{
- Client *cl;
-
- if(c->qid.type & QTDIR){
- c = devopen(c, omode, 0, 0, drawgen);
- c->iounit = IOUNIT;
- }
-
- qlock(&sdraw.lk);
- if(waserror()){
- qunlock(&sdraw.lk);
- nexterror();
- }
-
- if(QID(c->qid) == Qnew){
- cl = drawnewclient();
- if(cl == 0)
- error(Enodev);
- c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);
- }
-
- switch(QID(c->qid)){
- case Qnew:
- break;
-
- case Qctl:
- cl = drawclient(c);
- if(cl->busy)
- error(Einuse);
- cl->busy = 1;
- flushrect = Rect(10000, 10000, -10000, -10000);
- drawinstall(cl, 0, screenimage, 0);
- incref(&cl->r);
- break;
- case Qcolormap:
- case Qdata:
- case Qrefresh:
- cl = drawclient(c);
- incref(&cl->r);
- break;
- }
- qunlock(&sdraw.lk);
- poperror();
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- c->iounit = IOUNIT;
- return c;
-}
-
-static void
-drawclose(Chan *c)
-{
- int i;
- DImage *d, **dp;
- Client *cl;
- Refresh *r;
-
- if(QID(c->qid) < Qcolormap) /* Qtopdir, Qnew, Q3rd, Q2nd have no client */
- return;
- qlock(&sdraw.lk);
- if(waserror()){
- qunlock(&sdraw.lk);
- nexterror();
- }
-
- cl = drawclient(c);
- if(QID(c->qid) == Qctl)
- cl->busy = 0;
- if((c->flag&COPEN) && (decref(&cl->r)==0)){
- while((r = cl->refresh)){ /* assign = */
- cl->refresh = r->next;
- free(r);
- }
- /* free names */
- for(i=0; i<sdraw.nname; )
- if(sdraw.name[i].client == cl)
- drawdelname(sdraw.name+i);
- else
- i++;
- while(cl->cscreen)
- drawuninstallscreen(cl, cl->cscreen);
- /* all screens are freed, so now we can free images */
- dp = cl->dimage;
- for(i=0; i<NHASH; i++){
- while((d = *dp) != nil){
- *dp = d->next;
- drawfreedimage(d);
- }
- dp++;
- }
- sdraw.client[cl->slot] = 0;
- drawflush(); /* to erase visible, now dead windows */
- free(cl);
- }
- qunlock(&sdraw.lk);
- poperror();
-}
-
-long
-drawread(Chan *c, void *a, long n, vlong off)
-{
- int index, m;
- ulong red, green, blue;
- Client *cl;
- uchar *p;
- Refresh *r;
- DImage *di;
- Memimage *i;
- ulong offset = off;
- char buf[16];
-
- if(c->qid.type & QTDIR)
- return devdirread(c, a, n, 0, 0, drawgen);
- cl = drawclient(c);
- qlock(&sdraw.lk);
- if(waserror()){
- qunlock(&sdraw.lk);
- nexterror();
- }
- switch(QID(c->qid)){
- case Qctl:
- if(n < 12*12)
- error(Eshortread);
- if(cl->infoid < 0)
- error(Enodrawimage);
- if(cl->infoid == 0){
- i = screenimage;
- if(i == nil)
- error(Enodrawimage);
- }else{
- di = drawlookup(cl, cl->infoid, 1);
- if(di == nil)
- error(Enodrawimage);
- i = di->image;
- }
- n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
- cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl,
- i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
- i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
- cl->infoid = -1;
- break;
-
- case Qcolormap:
- drawactive(1); /* to restore map from backup */
- p = malloc(4*12*256+1);
- if(p == 0)
- error(Enomem);
- m = 0;
- for(index = 0; index < 256; index++){
- getcolor(index, &red, &green, &blue);
- m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24);
- }
- n = readstr(offset, a, n, (char*)p);
- free(p);
- break;
-
- case Qdata:
- if(cl->readdata == nil)
- error("no draw data");
- if(n < cl->nreaddata)
- error(Eshortread);
- n = cl->nreaddata;
- memmove(a, cl->readdata, cl->nreaddata);
- free(cl->readdata);
- cl->readdata = nil;
- break;
-
- case Qrefresh:
- if(n < 5*4)
- error(Ebadarg);
- for(;;){
- if(cl->refreshme || cl->refresh)
- break;
- qunlock(&sdraw.lk);
- if(waserror()){
- qlock(&sdraw.lk); /* restore lock for waserror() above */
- nexterror();
- }
- sleep(&cl->refrend, drawrefactive, cl);
- poperror();
- qlock(&sdraw.lk);
- }
- p = a;
- while(cl->refresh && n>=5*4){
- r = cl->refresh;
- BPLONG(p+0*4, r->dimage->id);
- BPLONG(p+1*4, r->r.min.x);
- BPLONG(p+2*4, r->r.min.y);
- BPLONG(p+3*4, r->r.max.x);
- BPLONG(p+4*4, r->r.max.y);
- cl->refresh = r->next;
- free(r);
- p += 5*4;
- n -= 5*4;
- }
- cl->refreshme = 0;
- n = p-(uchar*)a;
- }
- qunlock(&sdraw.lk);
- poperror();
- return n;
-}
-
-void
-drawwakeall(void)
-{
- Client *cl;
- int i;
-
- for(i=0; i<sdraw.nclient; i++){
- cl = sdraw.client[i];
- if(cl && (cl->refreshme || cl->refresh))
- wakeup(&cl->refrend);
- }
-}
-
-static long
-drawwrite(Chan *c, void *a, long n, vlong offset)
-{
- char buf[128], *fields[4], *q;
- Client *cl;
- int i, m, red, green, blue, x;
-
- USED(offset);
-
- if(c->qid.type & QTDIR)
- error(Eisdir);
- cl = drawclient(c);
- qlock(&sdraw.lk);
- if(waserror()){
- drawwakeall();
- qunlock(&sdraw.lk);
- nexterror();
- }
- switch(QID(c->qid)){
- case Qctl:
- if(n != 4)
- error("unknown draw control request");
- cl->infoid = BGLONG((uchar*)a);
- break;
-
- case Qcolormap:
- drawactive(1); /* to restore map from backup */
- m = n;
- n = 0;
- while(m > 0){
- x = m;
- if(x > sizeof(buf)-1)
- x = sizeof(buf)-1;
- q = memccpy(buf, a, '\n', x);
- if(q == 0)
- break;
- i = q-buf;
- n += i;
- a = (char*)a + i;
- m -= i;
- *q = 0;
- if(tokenize(buf, fields, nelem(fields)) != 4)
- error(Ebadarg);
- i = strtoul(fields[0], 0, 0);
- red = strtoul(fields[1], 0, 0);
- green = strtoul(fields[2], 0, 0);
- blue = strtoul(fields[3], &q, 0);
- if(fields[3] == q)
- error(Ebadarg);
- if(red>255 || green>255 || blue>255 || i<0 || i>255)
- error(Ebadarg);
- red |= red<<8;
- red |= red<<16;
- green |= green<<8;
- green |= green<<16;
- blue |= blue<<8;
- blue |= blue<<16;
- setcolor(i, red, green, blue);
- }
- break;
-
- case Qdata:
- drawmesg(cl, a, n);
- drawwakeall();
- break;
-
- default:
- error(Ebadusefd);
- }
- qunlock(&sdraw.lk);
- poperror();
- return n;
-}
-
-uchar*
-drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
-{
- int b, x;
-
- if(p >= maxp)
- error(Eshortdraw);
- b = *p++;
- x = b & 0x7F;
- if(b & 0x80){
- if(p+1 >= maxp)
- error(Eshortdraw);
- x |= *p++ << 7;
- x |= *p++ << 15;
- if(x & (1<<22))
- x |= ~0<<23;
- }else{
- if(b & 0x40)
- x |= ~0<<7;
- x += oldx;
- }
- *newx = x;
- return p;
-}
-
-static void
-printmesg(char *fmt, uchar *a, int plsprnt)
-{
- char buf[256];
- char *p, *q;
- int s;
-
- if(1|| plsprnt==0){
- SET(s);
- SET(q);
- SET(p);
- USED(fmt);
- USED(a);
- p = buf;
- USED(p);
- USED(q);
- USED(s);
- return;
- }
- q = buf;
- *q++ = *a++;
- for(p=fmt; *p; p++){
- switch(*p){
- case 'l':
- q += sprint(q, " %ld", (long)BGLONG(a));
- a += 4;
- break;
- case 'L':
- q += sprint(q, " %.8lux", (ulong)BGLONG(a));
- a += 4;
- break;
- case 'R':
- q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));
- a += 16;
- break;
- case 'P':
- q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4));
- a += 8;
- break;
- case 'b':
- q += sprint(q, " %d", *a++);
- break;
- case 's':
- q += sprint(q, " %d", BGSHORT(a));
- a += 2;
- break;
- case 'S':
- q += sprint(q, " %.4ux", BGSHORT(a));
- a += 2;
- break;
- }
- }
- *q++ = '\n';
- *q = 0;
- iprint("%.*s", (int)(q-buf), buf);
-}
-
-void
-drawmesg(Client *client, void *av, int n)
-{
- int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
- uchar *u, *a, refresh;
- char *fmt;
- ulong value, chan;
- Rectangle r, clipr;
- Point p, q, *pp, sp;
- Memimage *i, *dst, *src, *mask;
- Memimage *l, **lp;
- Memscreen *scrn;
- DImage *font, *ll, *di, *ddst, *dsrc;
- DName *dn;
- DScreen *dscrn;
- FChar *fc;
- Refx *refx;
- CScreen *cs;
- Refreshfn reffn;
-
- a = av;
- m = 0;
- fmt = nil;
- if(waserror()){
- if(fmt) printmesg(fmt, a, 1);
- /* iprint("error: %s\n", up->errstr); */
- nexterror();
- }
- while((n-=m) > 0){
- USED(fmt);
- a += m;
- switch(*a){
- default:
- error("bad draw command");
- /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
- case 'b':
- printmesg(fmt="LLbLbRRL", a, 0);
- m = 1+4+4+1+4+1+4*4+4*4+4;
- if(n < m)
- error(Eshortdraw);
- dstid = BGLONG(a+1);
- scrnid = BGSHORT(a+5);
- refresh = a[9];
- chan = BGLONG(a+10);
- repl = a[14];
- drawrectangle(&r, a+15);
- drawrectangle(&clipr, a+31);
- value = BGLONG(a+47);
- if(drawlookup(client, dstid, 0))
- error(Eimageexists);
- if(scrnid){
- dscrn = drawlookupscreen(client, scrnid, &cs);
- scrn = dscrn->screen;
- if(repl || chan!=scrn->image->chan)
- error("image parameters incompatible with screen");
- reffn = 0;
- switch(refresh){
- case Refbackup:
- break;
- case Refnone:
- reffn = memlnorefresh;
- break;
- case Refmesg:
- reffn = drawrefresh;
- break;
- default:
- error("unknown refresh method");
- }
- l = memlalloc(scrn, r, reffn, 0, value);
- if(l == 0)
- error(Edrawmem);
- addflush(l->layer->screenr);
- l->clipr = clipr;
- rectclip(&l->clipr, r);
- if(drawinstall(client, dstid, l, dscrn) == 0){
- memldelete(l);
- error(Edrawmem);
- }
- dscrn->ref++;
- if(reffn){
- refx = nil;
- if(reffn == drawrefresh){
- refx = malloc(sizeof(Refx));
- if(refx == 0){
- drawuninstall(client, dstid);
- error(Edrawmem);
- }
- refx->client = client;
- refx->dimage = drawlookup(client, dstid, 1);
- }
- memlsetrefresh(l, reffn, refx);
- }
- continue;
- }
- i = allocmemimage(r, chan);
- if(i == 0)
- error(Edrawmem);
- if(repl)
- i->flags |= Frepl;
- i->clipr = clipr;
- if(!repl)
- rectclip(&i->clipr, r);
- if(drawinstall(client, dstid, i, 0) == 0){
- freememimage(i);
- error(Edrawmem);
- }
- memfillcolor(i, value);
- continue;
-
- /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
- case 'A':
- printmesg(fmt="LLLb", a, 1);
- m = 1+4+4+4+1;
- if(n < m)
- error(Eshortdraw);
- dstid = BGLONG(a+1);
- if(dstid == 0)
- error(Ebadarg);
- if(drawlookupdscreen(dstid))
- error(Escreenexists);
- ddst = drawlookup(client, BGLONG(a+5), 1);
- dsrc = drawlookup(client, BGLONG(a+9), 1);
- if(ddst==0 || dsrc==0)
- error(Enodrawimage);
- if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
- error(Edrawmem);
- continue;
-
- /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
- case 'c':
- printmesg(fmt="LbR", a, 0);
- m = 1+4+1+4*4;
- if(n < m)
- error(Eshortdraw);
- ddst = drawlookup(client, BGLONG(a+1), 1);
- if(ddst == nil)
- error(Enodrawimage);
- if(ddst->name)
- error("can't change repl/clipr of shared image");
- dst = ddst->image;
- if(a[5])
- dst->flags |= Frepl;
- drawrectangle(&dst->clipr, a+6);
- continue;
-
- /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
- case 'd':
- printmesg(fmt="LLLRPP", a, 0);
- m = 1+4+4+4+4*4+2*4+2*4;
- if(n < m)
- error(Eshortdraw);
- dst = drawimage(client, a+1);
- dstid = BGLONG(a+1);
- src = drawimage(client, a+5);
- mask = drawimage(client, a+9);
- drawrectangle(&r, a+13);
- drawpoint(&p, a+29);
- drawpoint(&q, a+37);
- op = drawclientop(client);
- memdraw(dst, r, src, p, mask, q, op);
- dstflush(dstid, dst, r);
- continue;
-
- /* toggle debugging: 'D' val[1] */
- case 'D':
- printmesg(fmt="b", a, 0);
- m = 1+1;
- if(n < m)
- error(Eshortdraw);
- drawdebug = a[1];
- continue;
-
- /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
- case 'e':
- case 'E':
- printmesg(fmt="LLPlllPll", a, 0);
- m = 1+4+4+2*4+4+4+4+2*4+2*4;
- if(n < m)
- error(Eshortdraw);
- dst = drawimage(client, a+1);
- dstid = BGLONG(a+1);
- src = drawimage(client, a+5);
- drawpoint(&p, a+9);
- e0 = BGLONG(a+17);
- e1 = BGLONG(a+21);
- if(e0<0 || e1<0)
- error("invalid ellipse semidiameter");
- j = BGLONG(a+25);
- if(j < 0)
- error("negative ellipse thickness");
- drawpoint(&sp, a+29);
- c = j;
- if(*a == 'E')
- c = -1;
- ox = BGLONG(a+37);
- oy = BGLONG(a+41);
- op = drawclientop(client);
- /* high bit indicates arc angles are present */
- if(ox & (1U<<31)){
- if((ox & (1<<30)) == 0)
- ox &= ~(1U<<31);
- memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
- }else
- memellipse(dst, p, e0, e1, c, src, sp, op);
- dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
- continue;
-
- /* free: 'f' id[4] */
- case 'f':
- printmesg(fmt="L", a, 1);
- m = 1+4;
- if(n < m)
- error(Eshortdraw);
- ll = drawlookup(client, BGLONG(a+1), 0);
- if(ll && ll->dscreen && ll->dscreen->owner != client)
- ll->dscreen->owner->refreshme = 1;
- drawuninstall(client, BGLONG(a+1));
- continue;
-
- /* free screen: 'F' id[4] */
- case 'F':
- printmesg(fmt="L", a, 1);
- m = 1+4;
- if(n < m)
- error(Eshortdraw);
- drawlookupscreen(client, BGLONG(a+1), &cs);
- drawuninstallscreen(client, cs);
- continue;
-
- /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
- case 'i':
- printmesg(fmt="Llb", a, 1);
- m = 1+4+4+1;
- if(n < m)
- error(Eshortdraw);
- dstid = BGLONG(a+1);
- if(dstid == 0)
- error("can't use display as font");
- font = drawlookup(client, dstid, 1);
- if(font == 0)
- error(Enodrawimage);
- if(font->image->layer)
- error("can't use window as font");
- ni = BGLONG(a+5);
- if(ni<=0 || ni>4096)
- error("bad font size (4096 chars max)");
- free(font->fchar); /* should we complain if non-zero? */
- font->fchar = malloc(ni*sizeof(FChar));
- if(font->fchar == 0)
- error("no memory for font");
- memset(font->fchar, 0, ni*sizeof(FChar));
- font->nfchar = ni;
- font->ascent = a[9];
- continue;
-
- /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
- case 'l':
- printmesg(fmt="LLSRPbb", a, 0);
- m = 1+4+4+2+4*4+2*4+1+1;
- if(n < m)
- error(Eshortdraw);
- font = drawlookup(client, BGLONG(a+1), 1);
- if(font == 0)
- error(Enodrawimage);
- if(font->nfchar == 0)
- error(Enotfont);
- src = drawimage(client, a+5);
- ci = BGSHORT(a+9);
- if(ci >= font->nfchar)
- error(Eindex);
- drawrectangle(&r, a+11);
- drawpoint(&p, a+27);
- memdraw(font->image, r, src, p, memopaque, p, S);
- fc = &font->fchar[ci];
- fc->minx = r.min.x;
- fc->maxx = r.max.x;
- fc->miny = r.min.y;
- fc->maxy = r.max.y;
- fc->left = a[35];
- fc->width = a[36];
- continue;
-
- /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
- case 'L':
- printmesg(fmt="LPPlllLP", a, 0);
- m = 1+4+2*4+2*4+4+4+4+4+2*4;
- if(n < m)
- error(Eshortdraw);
- dst = drawimage(client, a+1);
- dstid = BGLONG(a+1);
- drawpoint(&p, a+5);
- drawpoint(&q, a+13);
- e0 = BGLONG(a+21);
- e1 = BGLONG(a+25);
- j = BGLONG(a+29);
- if(j < 0)
- error("negative line width");
- src = drawimage(client, a+33);
- drawpoint(&sp, a+37);
- op = drawclientop(client);
- memline(dst, p, q, e0, e1, j, src, sp, op);
- /* avoid memlinebbox if possible */
- if(dstid==0 || dst->layer!=nil){
- /* BUG: this is terribly inefficient: update maximal containing rect*/
- r = memlinebbox(p, q, e0, e1, j);
- dstflush(dstid, dst, insetrect(r, -(1+1+j)));
- }
- continue;
-
- /* create image mask: 'm' newid[4] id[4] */
-/*
- *
- case 'm':
- printmesg("LL", a, 0);
- m = 4+4;
- if(n < m)
- error(Eshortdraw);
- break;
- *
- */
-
- /* attach to a named image: 'n' dstid[4] j[1] name[j] */
- case 'n':
- printmesg(fmt="Lz", a, 0);
- m = 1+4+1;
- if(n < m)
- error(Eshortdraw);
- j = a[5];
- if(j == 0) /* give me a non-empty name please */
- error(Eshortdraw);
- m += j;
- if(n < m)
- error(Eshortdraw);
- dstid = BGLONG(a+1);
- if(drawlookup(client, dstid, 0))
- error(Eimageexists);
- dn = drawlookupname(j, (char*)a+6);
- if(dn == nil)
- error(Enoname);
- if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
- error(Edrawmem);
- di = drawlookup(client, dstid, 0);
- if(di == 0)
- error("draw: can't happen");
- di->vers = dn->vers;
- di->name = smalloc(j+1);
- di->fromname = dn->dimage;
- di->fromname->ref++;
- memmove(di->name, a+6, j);
- di->name[j] = 0;
- client->infoid = dstid;
- continue;
-
- /* name an image: 'N' dstid[4] in[1] j[1] name[j] */
- case 'N':
- printmesg(fmt="Lbz", a, 0);
- m = 1+4+1+1;
- if(n < m)
- error(Eshortdraw);
- c = a[5];
- j = a[6];
- if(j == 0) /* give me a non-empty name please */
- error(Eshortdraw);
- m += j;
- if(n < m)
- error(Eshortdraw);
- di = drawlookup(client, BGLONG(a+1), 0);
- if(di == 0)
- error(Enodrawimage);
- if(di->name)
- error(Enamed);
- if(c)
- drawaddname(client, di, j, (char*)a+7);
- else{
- dn = drawlookupname(j, (char*)a+7);
- if(dn == nil)
- error(Enoname);
- if(dn->dimage != di)
- error(Ewrongname);
- drawdelname(dn);
- }
- continue;
-
- /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
- case 'o':
- printmesg(fmt="LPP", a, 0);
- m = 1+4+2*4+2*4;
- if(n < m)
- error(Eshortdraw);
- dst = drawimage(client, a+1);
- if(dst->layer){
- drawpoint(&p, a+5);
- drawpoint(&q, a+13);
- r = dst->layer->screenr;
- ni = memlorigin(dst, p, q);
- if(ni < 0)
- error("image origin failed");
- if(ni > 0){
- addflush(r);
- addflush(dst->layer->screenr);
- ll = drawlookup(client, BGLONG(a+1), 1);
- drawrefreshscreen(ll, client);
- }
- }
- continue;
-
- /* set compositing operator for next draw operation: 'O' op */
- case 'O':
- printmesg(fmt="b", a, 0);
- m = 1+1;
- if(n < m)
- error(Eshortdraw);
- client->op = a[1];
- continue;
-
- /* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
- /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
- case 'p':
- case 'P':
- printmesg(fmt="LslllLPP", a, 0);
- m = 1+4+2+4+4+4+4+2*4;
- if(n < m)
- error(Eshortdraw);
- dstid = BGLONG(a+1);
- dst = drawimage(client, a+1);
- ni = BGSHORT(a+5);
- if(ni < 0)
- error("negative count in polygon");
- e0 = BGLONG(a+7);
- e1 = BGLONG(a+11);
- j = 0;
- if(*a == 'p'){
- j = BGLONG(a+15);
- if(j < 0)
- error("negative polygon line width");
- }
- src = drawimage(client, a+19);
- drawpoint(&sp, a+23);
- drawpoint(&p, a+31);
- ni++;
- pp = malloc(ni*sizeof(Point));
- if(pp == nil)
- error(Enomem);
- doflush = 0;
- if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
- doflush = 1; /* simplify test in loop */
- ox = oy = 0;
- esize = 0;
- u = a+m;
- for(y=0; y<ni; y++){
- q = p;
- oesize = esize;
- u = drawcoord(u, a+n, ox, &p.x);
- u = drawcoord(u, a+n, oy, &p.y);
- ox = p.x;
- oy = p.y;
- if(doflush){
- esize = j;
- if(*a == 'p'){
- if(y == 0){
- c = memlineendsize(e0);
- if(c > esize)
- esize = c;
- }
- if(y == ni-1){
- c = memlineendsize(e1);
- if(c > esize)
- esize = c;
- }
- }
- if(*a=='P' && e0!=1 && e0 !=~0)
- r = dst->clipr;
- else if(y > 0){
- r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
- combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
- }
- if(rectclip(&r, dst->clipr)) /* should perhaps be an arg to dstflush */
- dstflush(dstid, dst, r);
- }
- pp[y] = p;
- }
- if(y == 1)
- dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
- op = drawclientop(client);
- if(*a == 'p')
- mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
- else
- memfillpoly(dst, pp, ni, e0, src, sp, op);
- free(pp);
- m = u-a;
- continue;
-
- /* read: 'r' id[4] R[4*4] */
- case 'r':
- printmesg(fmt="LR", a, 0);
- m = 1+4+4*4;
- if(n < m)
- error(Eshortdraw);
- i = drawimage(client, a+1);
- drawrectangle(&r, a+5);
- if(!rectinrect(r, i->r))
- error(Ereadoutside);
- c = bytesperline(r, i->depth);
- c *= Dy(r);
- free(client->readdata);
- client->readdata = mallocz(c, 0);
- if(client->readdata == nil)
- error("readimage malloc failed");
- client->nreaddata = memunload(i, r, client->readdata, c);
- if(client->nreaddata < 0){
- free(client->readdata);
- client->readdata = nil;
- error("bad readimage call");
- }
- continue;
-
- /* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
- /* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */
- case 's':
- case 'x':
- printmesg(fmt="LLLPRPs", a, 0);
- m = 1+4+4+4+2*4+4*4+2*4+2;
- if(*a == 'x')
- m += 4+2*4;
- if(n < m)
- error(Eshortdraw);
-
- dst = drawimage(client, a+1);
- dstid = BGLONG(a+1);
- src = drawimage(client, a+5);
- font = drawlookup(client, BGLONG(a+9), 1);
- if(font == 0)
- error(Enodrawimage);
- if(font->nfchar == 0)
- error(Enotfont);
- drawpoint(&p, a+13);
- drawrectangle(&r, a+21);
- drawpoint(&sp, a+37);
- ni = BGSHORT(a+45);
- u = a+m;
- m += ni*2;
- if(n < m)
- error(Eshortdraw);
- clipr = dst->clipr;
- dst->clipr = r;
- op = drawclientop(client);
- l = dst;
- if(*a == 'x'){
- /* paint background */
- l = drawimage(client, a+47);
- drawpoint(&q, a+51);
- r.min.x = p.x;
- r.min.y = p.y-font->ascent;
- r.max.x = p.x;
- r.max.y = r.min.y+Dy(font->image->r);
- j = ni;
- while(--j >= 0){
- ci = BGSHORT(u);
- if(ci<0 || ci>=font->nfchar){
- dst->clipr = clipr;
- error(Eindex);
- }
- r.max.x += font->fchar[ci].width;
- u += 2;
- }
- memdraw(dst, r, l, q, memopaque, ZP, op);
- u -= 2*ni;
- }
- q = p;
- while(--ni >= 0){
- ci = BGSHORT(u);
- if(ci<0 || ci>=font->nfchar){
- dst->clipr = clipr;
- error(Eindex);
- }
- q = drawchar(dst, l, q, src, &sp, font, ci, op);
- u += 2;
- }
- dst->clipr = clipr;
- p.y -= font->ascent;
- dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
- continue;
-
- /* use public screen: 'S' id[4] chan[4] */
- case 'S':
- printmesg(fmt="Ll", a, 0);
- m = 1+4+4;
- if(n < m)
- error(Eshortdraw);
- dstid = BGLONG(a+1);
- if(dstid == 0)
- error(Ebadarg);
- dscrn = drawlookupdscreen(dstid);
- if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
- error(Enodrawscreen);
- if(dscrn->screen->image->chan != BGLONG(a+5))
- error("inconsistent chan");
- if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
- error(Edrawmem);
- continue;
-
- /* top or bottom windows: 't' top[1] nw[2] n*id[4] */
- case 't':
- printmesg(fmt="bsL", a, 0);
- m = 1+1+2;
- if(n < m)
- error(Eshortdraw);
- nw = BGSHORT(a+2);
- if(nw < 0)
- error(Ebadarg);
- if(nw == 0)
- continue;
- m += nw*4;
- if(n < m)
- error(Eshortdraw);
- lp = malloc(nw*sizeof(Memimage*));
- if(lp == 0)
- error(Enomem);
- if(waserror()){
- free(lp);
- nexterror();
- }
- for(j=0; j<nw; j++)
- lp[j] = drawimage(client, a+1+1+2+j*4);
- if(lp[0]->layer == 0)
- error("images are not windows");
- for(j=1; j<nw; j++)
- if(lp[j]->layer->screen != lp[0]->layer->screen)
- error("images not on same screen");
- if(a[1])
- memltofrontn(lp, nw);
- else
- memltorearn(lp, nw);
- if(lp[0]->layer->screen->image->data == screenimage->data)
- for(j=0; j<nw; j++)
- addflush(lp[j]->layer->screenr);
- ll = drawlookup(client, BGLONG(a+1+1+2), 1);
- drawrefreshscreen(ll, client);
- poperror();
- free(lp);
- continue;
-
- /* visible: 'v' */
- case 'v':
- printmesg(fmt="", a, 0);
- m = 1;
- drawflush();
- continue;
-
- /* write: 'y' id[4] R[4*4] data[x*1] */
- /* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
- case 'y':
- case 'Y':
- printmesg(fmt="LR", a, 0);
- // iprint("load %c\n", *a);
- m = 1+4+4*4;
- if(n < m)
- error(Eshortdraw);
- dstid = BGLONG(a+1);
- dst = drawimage(client, a+1);
- drawrectangle(&r, a+5);
- if(!rectinrect(r, dst->r))
- error(Ewriteoutside);
- y = memload(dst, r, a+m, n-m, *a=='Y');
- if(y < 0)
- error("bad writeimage call");
- dstflush(dstid, dst, r);
- m += y;
- continue;
- }
- }
- poperror();
-}
-
-Dev drawdevtab = {
- 'i',
- "draw",
-
- devreset,
- devinit,
- devshutdown,
- drawattach,
- drawwalk,
- drawstat,
- drawopen,
- devcreate,
- drawclose,
- drawread,
- devbread,
- drawwrite,
- devbwrite,
- devremove,
- devwstat,
-};
-
-/*
- * On 8 bit displays, load the default color map
- */
-void
-drawcmap(void)
-{
- int r, g, b, cr, cg, cb, v;
- int num, den;
- int i, j;
-
- drawactive(1); /* to restore map from backup */
- for(r=0,i=0; r!=4; r++)
- for(v=0; v!=4; v++,i+=16){
- for(g=0,j=v-r; g!=4; g++)
- for(b=0;b!=4;b++,j++){
- den = r;
- if(g > den)
- den = g;
- if(b > den)
- den = b;
- if(den == 0) /* divide check -- pick grey shades */
- cr = cg = cb = v*17;
- else{
- num = 17*(4*den+v);
- cr = r*num/den;
- cg = g*num/den;
- cb = b*num/den;
- }
- setcolor(i+(j&15),
- cr*0x01010101, cg*0x01010101, cb*0x01010101);
- }
- }
-}
-
-void
-drawblankscreen(int blank)
-{
- int i, nc;
- ulong *p;
-
- if(blank == sdraw.blanked)
- return;
- if(!canqlock(&sdraw.lk))
- return;
- if(!initscreenimage()){
- qunlock(&sdraw.lk);
- return;
- }
- p = sdraw.savemap;
- nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
-
- /*
- * blankscreen uses the hardware to blank the screen
- * when possible. to help in cases when it is not possible,
- * we set the color map to be all black.
- */
- if(blank == 0){ /* turn screen on */
- for(i=0; i<nc; i++, p+=3)
- setcolor(i, p[0], p[1], p[2]);
- // blankscreen(0);
- }else{ /* turn screen off */
- // blankscreen(1);
- for(i=0; i<nc; i++, p+=3){
- getcolor(i, &p[0], &p[1], &p[2]);
- setcolor(i, 0, 0, 0);
- }
- }
- sdraw.blanked = blank;
- qunlock(&sdraw.lk);
-}
-
-/*
- * record activity on screen, changing blanking as appropriate
- */
-void
-drawactive(int active)
-{
-/*
- if(active){
- drawblankscreen(0);
- sdraw.blanktime = MACHP(0)->ticks;
- }else{
- if(blanktime && sdraw.blanktime && TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60 >= blanktime)
- drawblankscreen(1);
- }
-*/
-}
-
-int
-drawidletime(void)
-{
- return 0;
-/* return TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60; */
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/devfs-posix.c b/sys/src/cmd/unix/drawterm/kern/devfs-posix.c
deleted file mode 100644
index 23a7dbc4f..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devfs-posix.c
+++ /dev/null
@@ -1,635 +0,0 @@
-#include "u.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h> /* for remove, rename */
-#include <limits.h>
-
-#ifndef NAME_MAX
-# define NAME_MAX 256
-#endif
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-
-typedef struct Ufsinfo Ufsinfo;
-
-enum
-{
- NUID = 256,
- NGID = 256,
- MAXPATH = 1024,
- MAXCOMP = 128
-};
-
-struct Ufsinfo
-{
- int mode;
- int fd;
- int uid;
- int gid;
- DIR* dir;
- vlong offset;
- QLock oq;
- char nextname[NAME_MAX];
-};
-
-char *base = "/";
-
-static Qid fsqid(char*, struct stat *);
-static void fspath(Chan*, char*, char*);
-static ulong fsdirread(Chan*, uchar*, int, ulong);
-static int fsomode(int);
-
-/* clumsy hack, but not worse than the Path stuff in the last one */
-static char*
-uc2name(Chan *c)
-{
- char *s;
-
- if(c->name == nil)
- return "/";
- s = c2name(c);
- if(s[0]=='#' && s[1]=='U')
- return s+2;
- return s;
-}
-
-static char*
-lastelem(Chan *c)
-{
- char *s, *t;
-
- s = uc2name(c);
- if((t = strrchr(s, '/')) == nil)
- return s;
- if(t[1] == 0)
- return t;
- return t+1;
-}
-
-static Chan*
-fsattach(char *spec)
-{
- Chan *c;
- struct stat stbuf;
- static int devno;
- Ufsinfo *uif;
-
- if(stat(base, &stbuf) < 0)
- error(strerror(errno));
-
- c = devattach('U', spec);
-
- uif = mallocz(sizeof(Ufsinfo), 1);
- uif->mode = stbuf.st_mode;
- uif->uid = stbuf.st_uid;
- uif->gid = stbuf.st_gid;
-
- c->aux = uif;
- c->dev = devno++;
- c->qid.type = QTDIR;
-/*print("fsattach %s\n", c2name(c));*/
-
- return c;
-}
-
-static Chan*
-fsclone(Chan *c, Chan *nc)
-{
- Ufsinfo *uif;
-
- uif = mallocz(sizeof(Ufsinfo), 1);
- *uif = *(Ufsinfo*)c->aux;
- nc->aux = uif;
-
- return nc;
-}
-
-static int
-fswalk1(Chan *c, char *name)
-{
- struct stat stbuf;
- char path[MAXPATH];
- Ufsinfo *uif;
-
- fspath(c, name, path);
-
- /*print("** fs walk '%s' -> %s\n", path, name); */
-
- if(stat(path, &stbuf) < 0)
- return 0;
-
- uif = c->aux;
-
- uif->mode = stbuf.st_mode;
- uif->uid = stbuf.st_uid;
- uif->gid = stbuf.st_gid;
-
- c->qid = fsqid(path, &stbuf);
-
- return 1;
-}
-
-extern Cname* addelem(Cname*, char*);
-
-static Walkqid*
-fswalk(Chan *c, Chan *nc, char **name, int nname)
-{
- int i;
- Cname *cname;
- Walkqid *wq;
-
- if(nc != nil)
- panic("fswalk: nc != nil");
- wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
- nc = devclone(c);
- cname = c->name;
- incref(&cname->ref);
-
- fsclone(c, nc);
- wq->clone = nc;
- for(i=0; i<nname; i++){
- nc->name = cname;
- if(fswalk1(nc, name[i]) == 0)
- break;
- cname = addelem(cname, name[i]);
- wq->qid[i] = nc->qid;
- }
- nc->name = cname;
- if(i != nname){
- cclose(nc);
- wq->clone = nil;
- }
- wq->nqid = i;
- return wq;
-}
-
-static int
-fsstat(Chan *c, uchar *buf, int n)
-{
- Dir d;
- struct stat stbuf;
- char path[MAXPATH];
-
- if(n < BIT16SZ)
- error(Eshortstat);
-
- fspath(c, 0, path);
- if(stat(path, &stbuf) < 0)
- error(strerror(errno));
-
- d.name = lastelem(c);
- d.uid = "unknown";
- d.gid = "unknown";
- d.muid = "unknown";
- d.qid = c->qid;
- d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
- d.atime = stbuf.st_atime;
- d.mtime = stbuf.st_mtime;
- d.length = stbuf.st_size;
- d.type = 'U';
- d.dev = c->dev;
- return convD2M(&d, buf, n);
-}
-
-static Chan*
-fsopen(Chan *c, int mode)
-{
- char path[MAXPATH];
- int m, isdir;
- Ufsinfo *uif;
-
-/*print("fsopen %s\n", c2name(c));*/
- m = mode & (OTRUNC|3);
- switch(m) {
- case 0:
- break;
- case 1:
- case 1|16:
- break;
- case 2:
- case 0|16:
- case 2|16:
- break;
- case 3:
- break;
- default:
- error(Ebadarg);
- }
-
- isdir = c->qid.type & QTDIR;
-
- if(isdir && mode != OREAD)
- error(Eperm);
-
- m = fsomode(m & 3);
- c->mode = openmode(mode);
-
- uif = c->aux;
-
- fspath(c, 0, path);
- if(isdir) {
- uif->dir = opendir(path);
- if(uif->dir == 0)
- error(strerror(errno));
- }
- else {
- if(mode & OTRUNC)
- m |= O_TRUNC;
- uif->fd = open(path, m, 0666);
-
- if(uif->fd < 0)
- error(strerror(errno));
- }
- uif->offset = 0;
-
- c->offset = 0;
- c->flag |= COPEN;
- return c;
-}
-
-static void
-fscreate(Chan *c, char *name, int mode, ulong perm)
-{
- int fd, m;
- char path[MAXPATH];
- struct stat stbuf;
- Ufsinfo *uif;
-
- m = fsomode(mode&3);
-
- fspath(c, name, path);
-
- uif = c->aux;
-
- if(perm & DMDIR) {
- if(m)
- error(Eperm);
-
- if(mkdir(path, perm & 0777) < 0)
- error(strerror(errno));
-
- fd = open(path, 0);
- if(fd >= 0) {
- chmod(path, perm & 0777);
- chown(path, uif->uid, uif->uid);
- }
- close(fd);
-
- uif->dir = opendir(path);
- if(uif->dir == 0)
- error(strerror(errno));
- }
- else {
- fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
- if(fd >= 0) {
- if(m != 1) {
- close(fd);
- fd = open(path, m);
- }
- chmod(path, perm & 0777);
- chown(path, uif->uid, uif->gid);
- }
- if(fd < 0)
- error(strerror(errno));
- uif->fd = fd;
- }
-
- if(stat(path, &stbuf) < 0)
- error(strerror(errno));
- c->qid = fsqid(path, &stbuf);
- c->offset = 0;
- c->flag |= COPEN;
- c->mode = openmode(mode);
-}
-
-static void
-fsclose(Chan *c)
-{
- Ufsinfo *uif;
-
- uif = c->aux;
-
- if(c->flag & COPEN) {
- if(c->qid.type & QTDIR)
- closedir(uif->dir);
- else
- close(uif->fd);
- }
-
- free(uif);
-}
-
-static long
-fsread(Chan *c, void *va, long n, vlong offset)
-{
- int fd, r;
- Ufsinfo *uif;
-
-/*print("fsread %s\n", c2name(c));*/
- if(c->qid.type & QTDIR)
- return fsdirread(c, va, n, offset);
-
- uif = c->aux;
- qlock(&uif->oq);
- if(waserror()) {
- qunlock(&uif->oq);
- nexterror();
- }
- fd = uif->fd;
- if(uif->offset != offset) {
- r = lseek(fd, offset, 0);
- if(r < 0)
- error(strerror(errno));
- uif->offset = offset;
- }
-
- n = read(fd, va, n);
- if(n < 0)
- error(strerror(errno));
-
- uif->offset += n;
- qunlock(&uif->oq);
- poperror();
-
- return n;
-}
-
-static long
-fswrite(Chan *c, void *va, long n, vlong offset)
-{
- int fd, r;
- Ufsinfo *uif;
-
- uif = c->aux;
-
- qlock(&uif->oq);
- if(waserror()) {
- qunlock(&uif->oq);
- nexterror();
- }
- fd = uif->fd;
- if(uif->offset != offset) {
- r = lseek(fd, offset, 0);
- if(r < 0)
- error(strerror(errno));
- uif->offset = offset;
- }
-
- n = write(fd, va, n);
- if(n < 0)
- error(strerror(errno));
-
- uif->offset += n;
- qunlock(&uif->oq);
- poperror();
-
- return n;
-}
-
-static void
-fsremove(Chan *c)
-{
- int n;
- char path[MAXPATH];
-
- fspath(c, 0, path);
- if(c->qid.type & QTDIR)
- n = rmdir(path);
- else
- n = remove(path);
- if(n < 0)
- error(strerror(errno));
-}
-
-int
-fswstat(Chan *c, uchar *buf, int n)
-{
- Dir d;
- struct stat stbuf;
- char old[MAXPATH], new[MAXPATH];
- char strs[MAXPATH*3], *p;
- Ufsinfo *uif;
-
- if(convM2D(buf, n, &d, strs) != n)
- error(Ebadstat);
-
- fspath(c, 0, old);
- if(stat(old, &stbuf) < 0)
- error(strerror(errno));
-
- uif = c->aux;
-
- if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
- fspath(c, 0, old);
- strcpy(new, old);
- p = strrchr(new, '/');
- strcpy(p+1, d.name);
- if(rename(old, new) < 0)
- error(strerror(errno));
- }
-
- fspath(c, 0, old);
- if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
- if(chmod(old, d.mode&0777) < 0)
- error(strerror(errno));
- uif->mode &= ~0777;
- uif->mode |= d.mode&0777;
- }
-/*
- p = name2pass(gid, d.gid);
- if(p == 0)
- error(Eunknown);
-
- if(p->id != stbuf.st_gid) {
- if(chown(old, stbuf.st_uid, p->id) < 0)
- error(strerror(errno));
-
- uif->gid = p->id;
- }
-*/
- return n;
-}
-
-static Qid
-fsqid(char *p, struct stat *st)
-{
- Qid q;
- int dev;
- ulong h;
- static int nqdev;
- static uchar *qdev;
-
- if(qdev == 0)
- qdev = mallocz(65536U, 1);
-
- q.type = 0;
- if((st->st_mode&S_IFMT) == S_IFDIR)
- q.type = QTDIR;
-
- dev = st->st_dev & 0xFFFFUL;
- if(qdev[dev] == 0)
- qdev[dev] = ++nqdev;
-
- h = 0;
- while(*p != '\0')
- h += *p++ * 13;
-
- q.path = (vlong)qdev[dev]<<32;
- q.path |= h;
- q.vers = st->st_mtime;
-
- return q;
-}
-
-static void
-fspath(Chan *c, char *ext, char *path)
-{
- strcpy(path, base);
- strcat(path, "/");
- strcat(path, uc2name(c));
- if(ext){
- strcat(path, "/");
- strcat(path, ext);
- }
- cleanname(path);
-}
-
-static int
-isdots(char *name)
-{
- if(name[0] != '.')
- return 0;
- if(name[1] == '\0')
- return 1;
- if(name[1] != '.')
- return 0;
- if(name[2] == '\0')
- return 1;
- return 0;
-}
-
-static int
-p9readdir(char *name, Ufsinfo *uif)
-{
- struct dirent *de;
-
- if(uif->nextname[0]){
- strcpy(name, uif->nextname);
- uif->nextname[0] = 0;
- return 1;
- }
-
- de = readdir(uif->dir);
- if(de == NULL)
- return 0;
-
- strcpy(name, de->d_name);
- return 1;
-}
-
-static ulong
-fsdirread(Chan *c, uchar *va, int count, ulong offset)
-{
- int i;
- Dir d;
- long n;
- char de[NAME_MAX];
- struct stat stbuf;
- char path[MAXPATH], dirpath[MAXPATH];
- Ufsinfo *uif;
-
-/*print("fsdirread %s\n", c2name(c));*/
- i = 0;
- uif = c->aux;
-
- errno = 0;
- if(uif->offset != offset) {
- if(offset != 0)
- error("bad offset in fsdirread");
- uif->offset = offset; /* sync offset */
- uif->nextname[0] = 0;
- rewinddir(uif->dir);
- }
-
- fspath(c, 0, dirpath);
-
- while(i+BIT16SZ < count) {
- if(!p9readdir(de, uif))
- break;
-
- if(de[0]==0 || isdots(de))
- continue;
-
- d.name = de;
- sprint(path, "%s/%s", dirpath, de);
- memset(&stbuf, 0, sizeof stbuf);
-
- if(stat(path, &stbuf) < 0) {
- /* fprint(2, "dir: bad path %s\n", path); */
- /* but continue... probably a bad symlink */
- }
-
- d.uid = "unknown";
- d.gid = "unknown";
- d.muid = "unknown";
- d.qid = fsqid(path, &stbuf);
- d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
- d.atime = stbuf.st_atime;
- d.mtime = stbuf.st_mtime;
- d.length = stbuf.st_size;
- d.type = 'U';
- d.dev = c->dev;
- n = convD2M(&d, (uchar*)va+i, count-i);
- if(n == BIT16SZ){
- strcpy(uif->nextname, de);
- break;
- }
- i += n;
- }
-/*print("got %d\n", i);*/
- uif->offset += i;
- return i;
-}
-
-static int
-fsomode(int m)
-{
- switch(m) {
- case 0: /* OREAD */
- case 3: /* OEXEC */
- return 0;
- case 1: /* OWRITE */
- return 1;
- case 2: /* ORDWR */
- return 2;
- }
- error(Ebadarg);
- return 0;
-}
-
-Dev fsdevtab = {
- 'U',
- "fs",
-
- devreset,
- devinit,
- devshutdown,
- fsattach,
- fswalk,
- fsstat,
- fsopen,
- fscreate,
- fsclose,
- fsread,
- devbread,
- fswrite,
- devbwrite,
- fsremove,
- fswstat,
-};
diff --git a/sys/src/cmd/unix/drawterm/kern/devfs-win32.c b/sys/src/cmd/unix/drawterm/kern/devfs-win32.c
deleted file mode 100644
index 9997bd027..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devfs-win32.c
+++ /dev/null
@@ -1,707 +0,0 @@
-/*
- * Disable Unicode until the calls to FindFirstFile etc
- * are changed to use wide character strings.
- */
-#undef UNICODE
-#include <windows.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#ifndef NAME_MAX
-# define NAME_MAX 256
-#endif
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-typedef struct DIR DIR;
-typedef struct Ufsinfo Ufsinfo;
-
-enum
-{
- NUID = 256,
- NGID = 256,
- MAXPATH = 1024,
- MAXCOMP = 128
-};
-
-struct DIR
-{
- HANDLE handle;
- char* path;
- int index;
- WIN32_FIND_DATA wfd;
-};
-
-struct Ufsinfo
-{
- int mode;
- int fd;
- int uid;
- int gid;
- DIR* dir;
- ulong offset;
- QLock oq;
- char nextname[NAME_MAX];
-};
-
-DIR* opendir(char*);
-int readdir(char*, DIR*);
-void closedir(DIR*);
-void rewinddir(DIR*);
-
-char *base = "c:/.";
-
-static Qid fsqid(char*, struct stat *);
-static void fspath(Chan*, char*, char*);
-// static void fsperm(Chan*, int);
-static ulong fsdirread(Chan*, uchar*, int, ulong);
-static int fsomode(int);
-static int chown(char *path, int uid, int);
-
-/* clumsy hack, but not worse than the Path stuff in the last one */
-static char*
-uc2name(Chan *c)
-{
- char *s;
-
- if(c->name == nil)
- return "/";
- s = c2name(c);
- if(s[0]=='#' && s[1]=='U')
- return s+2;
- return s;
-}
-
-static char*
-lastelem(Chan *c)
-{
- char *s, *t;
-
- s = uc2name(c);
- if((t = strrchr(s, '/')) == nil)
- return s;
- if(t[1] == 0)
- return t;
- return t+1;
-}
-
-static Chan*
-fsattach(char *spec)
-{
- Chan *c;
- struct stat stbuf;
- static int devno;
- Ufsinfo *uif;
-
- if(stat(base, &stbuf) < 0)
- error(strerror(errno));
-
- c = devattach('U', spec);
-
- uif = mallocz(sizeof(Ufsinfo), 1);
- uif->gid = stbuf.st_gid;
- uif->uid = stbuf.st_uid;
- uif->mode = stbuf.st_mode;
-
- c->aux = uif;
- c->dev = devno++;
- c->qid.type = QTDIR;
-/*print("fsattach %s\n", c2name(c));*/
-
- return c;
-}
-
-static Chan*
-fsclone(Chan *c, Chan *nc)
-{
- Ufsinfo *uif;
-
- uif = mallocz(sizeof(Ufsinfo), 1);
- *uif = *(Ufsinfo*)c->aux;
- nc->aux = uif;
-
- return nc;
-}
-
-static int
-fswalk1(Chan *c, char *name)
-{
- struct stat stbuf;
- char path[MAXPATH];
- Ufsinfo *uif;
-
- fspath(c, name, path);
-
- /* print("** fs walk '%s' -> %s\n", path, name); */
-
- if(stat(path, &stbuf) < 0)
- return 0;
-
- uif = c->aux;
-
- uif->gid = stbuf.st_gid;
- uif->uid = stbuf.st_uid;
- uif->mode = stbuf.st_mode;
-
- c->qid = fsqid(path, &stbuf);
-
- return 1;
-}
-
-extern Cname* addelem(Cname*, char*);
-
-static Walkqid*
-fswalk(Chan *c, Chan *nc, char **name, int nname)
-{
- int i;
- Cname *cname;
- Walkqid *wq;
-
- if(nc != nil)
- panic("fswalk: nc != nil");
- wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
- nc = devclone(c);
- cname = c->name;
- incref(&cname->ref);
-
- fsclone(c, nc);
- wq->clone = nc;
- for(i=0; i<nname; i++){
- nc->name = cname;
- if(fswalk1(nc, name[i]) == 0)
- break;
- cname = addelem(cname, name[i]);
- wq->qid[i] = nc->qid;
- }
- nc->name = cname;
- if(i != nname){
- cclose(nc);
- wq->clone = nil;
- }
- wq->nqid = i;
- return wq;
-}
-
-static int
-fsstat(Chan *c, uchar *buf, int n)
-{
- Dir d;
- struct stat stbuf;
- char path[MAXPATH];
-
- if(n < BIT16SZ)
- error(Eshortstat);
-
- fspath(c, 0, path);
- if(stat(path, &stbuf) < 0)
- error(strerror(errno));
-
- d.name = lastelem(c);
- d.uid = "unknown";
- d.gid = "unknown";
- d.muid = "unknown";
- d.qid = c->qid;
- d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
- d.atime = stbuf.st_atime;
- d.mtime = stbuf.st_mtime;
- d.length = stbuf.st_size;
- d.type = 'U';
- d.dev = c->dev;
- return convD2M(&d, buf, n);
-}
-
-static Chan*
-fsopen(Chan *c, int mode)
-{
- char path[MAXPATH];
- int m, isdir;
- Ufsinfo *uif;
-
-/*print("fsopen %s\n", c2name(c));*/
- m = mode & (OTRUNC|3);
- switch(m) {
- case 0:
- break;
- case 1:
- case 1|16:
- break;
- case 2:
- case 0|16:
- case 2|16:
- break;
- case 3:
- break;
- default:
- error(Ebadarg);
- }
-
- isdir = c->qid.type & QTDIR;
-
- if(isdir && mode != OREAD)
- error(Eperm);
-
- m = fsomode(m & 3);
- c->mode = openmode(mode);
-
- uif = c->aux;
-
- fspath(c, 0, path);
- if(isdir) {
- uif->dir = opendir(path);
- if(uif->dir == 0)
- error(strerror(errno));
- }
- else {
- if(mode & OTRUNC)
- m |= O_TRUNC;
- uif->fd = open(path, m|_O_BINARY, 0666);
-
- if(uif->fd < 0)
- error(strerror(errno));
- }
- uif->offset = 0;
-
- c->offset = 0;
- c->flag |= COPEN;
- return c;
-}
-
-static void
-fscreate(Chan *c, char *name, int mode, ulong perm)
-{
- int fd, m;
- char path[MAXPATH];
- struct stat stbuf;
- Ufsinfo *uif;
-
- m = fsomode(mode&3);
-
- fspath(c, name, path);
-
- uif = c->aux;
-
- if(perm & DMDIR) {
- if(m)
- error(Eperm);
-
- if(mkdir(path) < 0)
- error(strerror(errno));
-
- fd = open(path, 0);
- if(fd >= 0) {
- chmod(path, perm & 0777);
- chown(path, uif->uid, uif->uid);
- }
- close(fd);
-
- uif->dir = opendir(path);
- if(uif->dir == 0)
- error(strerror(errno));
- }
- else {
- fd = open(path, _O_WRONLY|_O_BINARY|_O_CREAT|_O_TRUNC, 0666);
- if(fd >= 0) {
- if(m != 1) {
- close(fd);
- fd = open(path, m|_O_BINARY);
- }
- chmod(path, perm & 0777);
- chown(path, uif->uid, uif->gid);
- }
- if(fd < 0)
- error(strerror(errno));
- uif->fd = fd;
- }
-
- if(stat(path, &stbuf) < 0)
- error(strerror(errno));
- c->qid = fsqid(path, &stbuf);
- c->offset = 0;
- c->flag |= COPEN;
- c->mode = openmode(mode);
-}
-
-static void
-fsclose(Chan *c)
-{
- Ufsinfo *uif;
-
- uif = c->aux;
-
- if(c->flag & COPEN) {
- if(c->qid.type & QTDIR)
- closedir(uif->dir);
- else
- close(uif->fd);
- }
-
- free(uif);
-}
-
-static long
-fsread(Chan *c, void *va, long n, vlong offset)
-{
- int fd, r;
- Ufsinfo *uif;
-
-/*print("fsread %s\n", c2name(c));*/
- if(c->qid.type & QTDIR)
- return fsdirread(c, va, n, offset);
-
- uif = c->aux;
- qlock(&uif->oq);
- if(waserror()) {
- qunlock(&uif->oq);
- nexterror();
- }
- fd = uif->fd;
- if(uif->offset != offset) {
- r = lseek(fd, offset, 0);
- if(r < 0)
- error(strerror(errno));
- uif->offset = offset;
- }
-
- n = read(fd, va, n);
- if(n < 0)
- error(strerror(errno));
-
- uif->offset += n;
- qunlock(&uif->oq);
- poperror();
-
- return n;
-}
-
-static long
-fswrite(Chan *c, void *va, long n, vlong offset)
-{
- int fd, r;
- Ufsinfo *uif;
-
- uif = c->aux;
-
- qlock(&uif->oq);
- if(waserror()) {
- qunlock(&uif->oq);
- nexterror();
- }
- fd = uif->fd;
- if(uif->offset != offset) {
- r = lseek(fd, offset, 0);
- if(r < 0)
- error(strerror(errno));
- uif->offset = offset;
- }
-
- n = write(fd, va, n);
- if(n < 0)
- error(strerror(errno));
-
- uif->offset += n;
- qunlock(&uif->oq);
- poperror();
-
- return n;
-}
-
-static void
-fsremove(Chan *c)
-{
- int n;
- char path[MAXPATH];
-
- fspath(c, 0, path);
- if(c->qid.type & QTDIR)
- n = rmdir(path);
- else
- n = remove(path);
- if(n < 0)
- error(strerror(errno));
-}
-
-static int
-fswstat(Chan *c, uchar *buf, int n)
-{
- Dir d;
- struct stat stbuf;
- char old[MAXPATH], new[MAXPATH];
- char strs[MAXPATH*3], *p;
- Ufsinfo *uif;
-
- if (convM2D(buf, n, &d, strs) != n)
- error(Ebadstat);
-
- fspath(c, 0, old);
- if(stat(old, &stbuf) < 0)
- error(strerror(errno));
-
- uif = c->aux;
-
-// if(uif->uid != stbuf.st_uid)
-// error(Eowner);
-
- if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
- fspath(c, 0, old);
- strcpy(new, old);
- p = strrchr(new, '/');
- strcpy(p+1, d.name);
- if(rename(old, new) < 0)
- error(strerror(errno));
- }
-
- fspath(c, 0, old);
- if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
- if(chmod(old, d.mode&0777) < 0)
- error(strerror(errno));
- uif->mode &= ~0777;
- uif->mode |= d.mode&0777;
- }
-/*
- p = name2pass(gid, d.gid);
- if(p == 0)
- error(Eunknown);
-
- if(p->id != stbuf.st_gid) {
- if(chown(old, stbuf.st_uid, p->id) < 0)
- error(sys_errlist[errno]);
-
- uif->gid = p->id;
- }
-*/
- return n;
-}
-
-static Qid
-fsqid(char *p, struct stat *st)
-{
- Qid q;
- int dev;
- ulong h;
- static int nqdev;
- static uchar *qdev;
-
- if(qdev == 0)
- qdev = mallocz(65536U, 1);
-
- q.type = 0;
- if((st->st_mode&S_IFMT) == S_IFDIR)
- q.type = QTDIR;
-
- dev = st->st_dev & 0xFFFFUL;
- if(qdev[dev] == 0)
- qdev[dev] = ++nqdev;
-
- h = 0;
- while(*p != '\0')
- h += *p++ * 13;
-
- q.path = (vlong)qdev[dev]<<32;
- q.path |= h;
- q.vers = st->st_mtime;
-
- return q;
-}
-
-static void
-fspath(Chan *c, char *ext, char *path)
-{
- strcpy(path, base);
- strcat(path, "/");
- strcat(path, uc2name(c));
- if(ext) {
- strcat(path, "/");
- strcat(path, ext);
- }
- cleanname(path);
-}
-
-static int
-isdots(char *name)
-{
- if(name[0] != '.')
- return 0;
- if(name[1] == '\0')
- return 1;
- if(name[1] != '.')
- return 0;
- if(name[2] == '\0')
- return 1;
- return 0;
-}
-
-static int
-p9readdir(char *name, Ufsinfo *uif)
-{
- if(uif->nextname[0]){
- strcpy(name, uif->nextname);
- uif->nextname[0] = 0;
- return 1;
- }
-
- return readdir(name, uif->dir);
-}
-
-static ulong
-fsdirread(Chan *c, uchar *va, int count, ulong offset)
-{
- int i;
- Dir d;
- long n;
- char de[NAME_MAX];
- struct stat stbuf;
- char path[MAXPATH], dirpath[MAXPATH];
- Ufsinfo *uif;
-
-/*print("fsdirread %s\n", c2name(c));*/
- i = 0;
- uif = c->aux;
-
- errno = 0;
- if(uif->offset != offset) {
- if(offset != 0)
- error("bad offset in fsdirread");
- uif->offset = offset; /* sync offset */
- uif->nextname[0] = 0;
- rewinddir(uif->dir);
- }
-
- fspath(c, 0, dirpath);
-
- while(i+BIT16SZ < count) {
- if(!p9readdir(de, uif))
- break;
-
- if(de[0]==0 || isdots(de))
- continue;
-
- d.name = de;
- sprint(path, "%s/%s", dirpath, de);
- memset(&stbuf, 0, sizeof stbuf);
-
- if(stat(path, &stbuf) < 0) {
- print("dir: bad path %s\n", path);
- /* but continue... probably a bad symlink */
- }
-
- d.uid = "unknown";
- d.gid = "unknown";
- d.muid = "unknown";
- d.qid = fsqid(path, &stbuf);
- d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
- d.atime = stbuf.st_atime;
- d.mtime = stbuf.st_mtime;
- d.length = stbuf.st_size;
- d.type = 'U';
- d.dev = c->dev;
- n = convD2M(&d, (uchar*)va+i, count-i);
- if(n == BIT16SZ){
- strcpy(uif->nextname, de);
- break;
- }
- i += n;
- }
-/*print("got %d\n", i);*/
- uif->offset += i;
- return i;
-}
-
-static int
-fsomode(int m)
-{
- switch(m) {
- case 0: /* OREAD */
- case 3: /* OEXEC */
- return 0;
- case 1: /* OWRITE */
- return 1;
- case 2: /* ORDWR */
- return 2;
- }
- error(Ebadarg);
- return 0;
-}
-void
-closedir(DIR *d)
-{
- FindClose(d->handle);
- free(d->path);
-}
-
-int
-readdir(char *name, DIR *d)
-{
- if(d->index != 0) {
- if(FindNextFile(d->handle, &d->wfd) == FALSE)
- return 0;
- }
- strcpy(name, (char*)d->wfd.cFileName);
- d->index++;
-
- return 1;
-}
-
-void
-rewinddir(DIR *d)
-{
- FindClose(d->handle);
- d->handle = FindFirstFile(d->path, &d->wfd);
- d->index = 0;
-}
-
-static int
-chown(char *path, int uid, int perm)
-{
-/* panic("chown"); */
- return 0;
-}
-
-DIR*
-opendir(char *p)
-{
- DIR *d;
- char path[MAX_PATH];
-
-
- snprint(path, sizeof(path), "%s/*.*", p);
-
- d = mallocz(sizeof(DIR), 1);
- if(d == 0)
- return 0;
-
- d->index = 0;
-
- d->handle = FindFirstFile(path, &d->wfd);
- if(d->handle == INVALID_HANDLE_VALUE) {
- free(d);
- return 0;
- }
-
- d->path = strdup(path);
- return d;
-}
-
-Dev fsdevtab = {
- 'U',
- "fs",
-
- devreset,
- devinit,
- devshutdown,
- fsattach,
- fswalk,
- fsstat,
- fsopen,
- fscreate,
- fsclose,
- fsread,
- devbread,
- fswrite,
- devbwrite,
- fsremove,
- fswstat,
-};
diff --git a/sys/src/cmd/unix/drawterm/kern/devip-posix.c b/sys/src/cmd/unix/drawterm/kern/devip-posix.c
deleted file mode 100644
index 7f6171e4e..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devip-posix.c
+++ /dev/null
@@ -1,210 +0,0 @@
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netdb.h>
-
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "devip.h"
-
-#undef listen
-#undef accept
-#undef bind
-
-void
-osipinit(void)
-{
- char buf[1024];
- gethostname(buf, sizeof(buf));
- kstrdup(&sysname, buf);
-
-}
-
-int
-so_socket(int type)
-{
- int fd, one;
-
- switch(type) {
- default:
- error("bad protocol type");
- case S_TCP:
- type = SOCK_STREAM;
- break;
- case S_UDP:
- type = SOCK_DGRAM;
- break;
- }
-
- fd = socket(AF_INET, type, 0);
- if(fd < 0)
- oserror();
-
- one = 1;
- if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){
- oserrstr();
- print("setsockopt: %r");
- }
-
- return fd;
-}
-
-
-void
-so_connect(int fd, unsigned long raddr, unsigned short rport)
-{
- struct sockaddr_in sin;
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- hnputs(&sin.sin_port, rport);
- hnputl(&sin.sin_addr.s_addr, raddr);
-
- if(connect(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
- oserror();
-}
-
-void
-so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
-{
- socklen_t len;
- struct sockaddr_in sin;
-
- len = sizeof(sin);
- if(getsockname(fd, (struct sockaddr*)&sin, &len) < 0)
- oserror();
-
- if(sin.sin_family != AF_INET || len != sizeof(sin))
- error("not AF_INET");
-
- *laddr = nhgetl(&sin.sin_addr.s_addr);
- *lport = nhgets(&sin.sin_port);
-}
-
-void
-so_listen(int fd)
-{
- if(listen(fd, 5) < 0)
- oserror();
-}
-
-int
-so_accept(int fd, unsigned long *raddr, unsigned short *rport)
-{
- int nfd;
- socklen_t len;
- struct sockaddr_in sin;
-
- len = sizeof(sin);
- nfd = accept(fd, (struct sockaddr*)&sin, &len);
- if(nfd < 0)
- oserror();
-
- if(sin.sin_family != AF_INET || len != sizeof(sin))
- error("not AF_INET");
-
- *raddr = nhgetl(&sin.sin_addr.s_addr);
- *rport = nhgets(&sin.sin_port);
- return nfd;
-}
-
-void
-so_bind(int fd, int su, unsigned short port)
-{
- int i, one;
- struct sockaddr_in sin;
-
- one = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){
- oserrstr();
- print("setsockopt: %r");
- }
-
- if(su) {
- for(i = 600; i < 1024; i++) {
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = i;
-
- if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) >= 0)
- return;
- }
- oserror();
- }
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- hnputs(&sin.sin_port, port);
-
- if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
- oserror();
-}
-
-int
-so_gethostbyname(char *host, char**hostv, int n)
-{
- int i;
- char buf[32];
- unsigned char *p;
- struct hostent *hp;
-
- hp = gethostbyname(host);
- if(hp == 0)
- return 0;
-
- for(i = 0; hp->h_addr_list[i] && i < n; i++) {
- p = (unsigned char*)hp->h_addr_list[i];
- sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
- hostv[i] = strdup(buf);
- if(hostv[i] == 0)
- break;
- }
- return i;
-}
-
-char*
-hostlookup(char *host)
-{
- char buf[100];
- uchar *p;
- struct hostent *he;
-
- he = gethostbyname(host);
- if(he != 0 && he->h_addr_list[0]) {
- p = (uchar*)he->h_addr_list[0];
- sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]);
- } else
- strcpy(buf, host);
-
- return strdup(buf);
-}
-
-int
-so_getservbyname(char *service, char *net, char *port)
-{
- struct servent *s;
-
- s = getservbyname(service, net);
- if(s == 0)
- return -1;
-
- sprint(port, "%d", nhgets(&s->s_port));
- return 0;
-}
-
-int
-so_send(int fd, void *d, int n, int f)
-{
- return send(fd, d, n, f);
-}
-
-int
-so_recv(int fd, void *d, int n, int f)
-{
- return recv(fd, d, n, f);
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/devip-win32.c b/sys/src/cmd/unix/drawterm/kern/devip-win32.c
deleted file mode 100644
index 3caa67ad1..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devip-win32.c
+++ /dev/null
@@ -1,212 +0,0 @@
-#include <windows.h>
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "devip.h"
-
-#ifdef MSVC
-#pragma comment(lib, "wsock32.lib")
-#endif
-
-#undef listen
-#undef accept
-#undef bind
-
-void
-osipinit(void)
-{
- WSADATA wasdat;
- char buf[1024];
-
- if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0)
- panic("no winsock.dll");
-
- gethostname(buf, sizeof(buf));
- kstrdup(&sysname, buf);
-}
-
-int
-so_socket(int type)
-{
- int fd, one;
-
- switch(type) {
- default:
- error("bad protocol type");
- case S_TCP:
- type = SOCK_STREAM;
- break;
- case S_UDP:
- type = SOCK_DGRAM;
- break;
- }
-
- fd = socket(AF_INET, type, 0);
- if(fd < 0)
- oserror();
-
- one = 1;
- if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){
- oserrstr();
- print("setsockopt: %s\n", up->errstr);
- }
-
- return fd;
-}
-
-
-void
-so_connect(int fd, unsigned long raddr, unsigned short rport)
-{
- struct sockaddr_in sin;
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- hnputs(&sin.sin_port, rport);
- hnputl(&sin.sin_addr.s_addr, raddr);
-
- if(connect(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
- oserror();
-}
-
-void
-so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
-{
- int len;
- struct sockaddr_in sin;
-
- len = sizeof(sin);
- if(getsockname(fd, (struct sockaddr*)&sin, &len) < 0)
- oserror();
-
- if(sin.sin_family != AF_INET || len != sizeof(sin))
- error("not AF_INET");
-
- *laddr = nhgetl(&sin.sin_addr.s_addr);
- *lport = nhgets(&sin.sin_port);
-}
-
-void
-so_listen(int fd)
-{
- if(listen(fd, 5) < 0)
- oserror();
-}
-
-int
-so_accept(int fd, unsigned long *raddr, unsigned short *rport)
-{
- int nfd, len;
- struct sockaddr_in sin;
-
- len = sizeof(sin);
- nfd = accept(fd, (struct sockaddr*)&sin, &len);
- if(nfd < 0)
- oserror();
-
- if(sin.sin_family != AF_INET || len != sizeof(sin))
- error("not AF_INET");
-
- *raddr = nhgetl(&sin.sin_addr.s_addr);
- *rport = nhgets(&sin.sin_port);
- return nfd;
-}
-
-void
-so_bind(int fd, int su, unsigned short port)
-{
- int i, one;
- struct sockaddr_in sin;
-
- one = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){
- oserrstr();
- print("setsockopt: %s", up->errstr);
- }
-
- if(su) {
- for(i = 600; i < 1024; i++) {
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = i;
-
- if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) >= 0)
- return;
- }
- oserror();
- }
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- hnputs(&sin.sin_port, port);
-
- if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
- oserror();
-}
-
-int
-so_gethostbyname(char *host, char**hostv, int n)
-{
- int i;
- char buf[32];
- unsigned char *p;
- struct hostent *hp;
-
- hp = gethostbyname(host);
- if(hp == 0)
- return 0;
-
- for(i = 0; hp->h_addr_list[i] && i < n; i++) {
- p = (unsigned char*)hp->h_addr_list[i];
- sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
- hostv[i] = strdup(buf);
- if(hostv[i] == 0)
- break;
- }
- return i;
-}
-
-char*
-hostlookup(char *host)
-{
- char buf[100];
- uchar *p;
- HOSTENT *he;
-
- he = gethostbyname(host);
- if(he != 0 && he->h_addr_list[0]) {
- p = (uchar*)he->h_addr_list[0];
- sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]);
- } else
- strcpy(buf, host);
-
- return strdup(buf);
-}
-
-int
-so_getservbyname(char *service, char *net, char *port)
-{
- struct servent *s;
-
- s = getservbyname(service, net);
- if(s == 0)
- return -1;
-
- sprint(port, "%d", nhgets(&s->s_port));
- return 0;
-}
-
-int
-so_send(int fd, void *d, int n, int f)
-{
- return send(fd, d, n, f);
-}
-
-int
-so_recv(int fd, void *d, int n, int f)
-{
- return recv(fd, d, n, f);
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/devip.c b/sys/src/cmd/unix/drawterm/kern/devip.c
deleted file mode 100644
index f192aebcb..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devip.c
+++ /dev/null
@@ -1,938 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "devip.h"
-
-void hnputl(void *p, unsigned long v);
-void hnputs(void *p, unsigned short v);
-unsigned long nhgetl(void *p);
-unsigned short nhgets(void *p);
-unsigned long parseip(char *to, char *from);
-void csclose(Chan*);
-long csread(Chan*, void*, long, vlong);
-long cswrite(Chan*, void*, long, vlong);
-
-void osipinit(void);
-
-enum
-{
- Qtopdir = 1, /* top level directory */
- Qcs,
- Qprotodir, /* directory for a protocol */
- Qclonus,
- Qconvdir, /* directory for a conversation */
- Qdata,
- Qctl,
- Qstatus,
- Qremote,
- Qlocal,
- Qlisten,
-
- MAXPROTO = 4
-};
-#define TYPE(x) ((int)((x).path & 0xf))
-#define CONV(x) ((int)(((x).path >> 4)&0xfff))
-#define PROTO(x) ((int)(((x).path >> 16)&0xff))
-#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y))
-
-typedef struct Proto Proto;
-typedef struct Conv Conv;
-struct Conv
-{
- int x;
- Ref r;
- int sfd;
- int perm;
- char owner[KNAMELEN];
- char* state;
- ulong laddr;
- ushort lport;
- ulong raddr;
- ushort rport;
- int restricted;
- char cerr[KNAMELEN];
- Proto* p;
-};
-
-struct Proto
-{
- Lock l;
- int x;
- int stype;
- char name[KNAMELEN];
- int nc;
- int maxconv;
- Conv** conv;
- Qid qid;
-};
-
-static int np;
-static Proto proto[MAXPROTO];
-int eipfmt(Fmt*);
-
-static Conv* protoclone(Proto*, char*, int);
-static void setladdr(Conv*);
-
-int
-ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp)
-{
- Qid q;
- Conv *cv;
- char *p;
-
- USED(nname);
- q.vers = 0;
- q.type = 0;
- switch(TYPE(c->qid)) {
- case Qtopdir:
- if(s >= 1+np)
- return -1;
-
- if(s == 0){
- q.path = QID(s, 0, Qcs);
- devdir(c, q, "cs", 0, "network", 0666, dp);
- }else{
- s--;
- q.path = QID(s, 0, Qprotodir);
- q.type = QTDIR;
- devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp);
- }
- return 1;
- case Qprotodir:
- if(s < proto[PROTO(c->qid)].nc) {
- cv = proto[PROTO(c->qid)].conv[s];
- sprint(up->genbuf, "%d", s);
- q.path = QID(PROTO(c->qid), s, Qconvdir);
- q.type = QTDIR;
- devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
- return 1;
- }
- s -= proto[PROTO(c->qid)].nc;
- switch(s) {
- default:
- return -1;
- case 0:
- p = "clone";
- q.path = QID(PROTO(c->qid), 0, Qclonus);
- break;
- }
- devdir(c, q, p, 0, "network", 0555, dp);
- return 1;
- case Qconvdir:
- cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];
- switch(s) {
- default:
- return -1;
- case 0:
- q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata);
- devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
- return 1;
- case 1:
- q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl);
- devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
- return 1;
- case 2:
- p = "status";
- q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus);
- break;
- case 3:
- p = "remote";
- q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote);
- break;
- case 4:
- p = "local";
- q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal);
- break;
- case 5:
- p = "listen";
- q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten);
- break;
- }
- devdir(c, q, p, 0, cv->owner, 0444, dp);
- return 1;
- }
- return -1;
-}
-
-static void
-newproto(char *name, int type, int maxconv)
-{
- int l;
- Proto *p;
-
- if(np >= MAXPROTO) {
- print("no %s: increase MAXPROTO", name);
- return;
- }
-
- p = &proto[np];
- strcpy(p->name, name);
- p->stype = type;
- p->qid.path = QID(np, 0, Qprotodir);
- p->qid.type = QTDIR;
- p->x = np++;
- p->maxconv = maxconv;
- l = sizeof(Conv*)*(p->maxconv+1);
- p->conv = mallocz(l, 1);
- if(p->conv == 0)
- panic("no memory");
-}
-
-void
-ipinit(void)
-{
- osipinit();
-
- newproto("udp", S_UDP, 10);
- newproto("tcp", S_TCP, 30);
-
- fmtinstall('I', eipfmt);
- fmtinstall('E', eipfmt);
-
-}
-
-Chan *
-ipattach(char *spec)
-{
- Chan *c;
-
- c = devattach('I', spec);
- c->qid.path = QID(0, 0, Qtopdir);
- c->qid.type = QTDIR;
- c->qid.vers = 0;
- return c;
-}
-
-static Walkqid*
-ipwalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name, nname, 0, 0, ipgen);
-}
-
-int
-ipstat(Chan *c, uchar *dp, int n)
-{
- return devstat(c, dp, n, 0, 0, ipgen);
-}
-
-Chan *
-ipopen(Chan *c, int omode)
-{
- Proto *p;
- ulong raddr;
- ushort rport;
- int perm, sfd;
- Conv *cv, *lcv;
-
- omode &= 3;
- perm = 0;
- switch(omode) {
- case OREAD:
- perm = 4;
- break;
- case OWRITE:
- perm = 2;
- break;
- case ORDWR:
- perm = 6;
- break;
- }
-
- switch(TYPE(c->qid)) {
- default:
- break;
- case Qtopdir:
- case Qprotodir:
- case Qconvdir:
- case Qstatus:
- case Qremote:
- case Qlocal:
- if(omode != OREAD)
- error(Eperm);
- break;
- case Qclonus:
- p = &proto[PROTO(c->qid)];
- cv = protoclone(p, up->user, -1);
- if(cv == 0)
- error(Enodev);
- c->qid.path = QID(p->x, cv->x, Qctl);
- c->qid.vers = 0;
- break;
- case Qdata:
- case Qctl:
- p = &proto[PROTO(c->qid)];
- lock(&p->l);
- cv = p->conv[CONV(c->qid)];
- lock(&cv->r.lk);
- if((perm & (cv->perm>>6)) != perm) {
- if(strcmp(up->user, cv->owner) != 0 ||
- (perm & cv->perm) != perm) {
- unlock(&cv->r.lk);
- unlock(&p->l);
- error(Eperm);
- }
- }
- cv->r.ref++;
- if(cv->r.ref == 1) {
- memmove(cv->owner, up->user, KNAMELEN);
- cv->perm = 0660;
- }
- unlock(&cv->r.lk);
- unlock(&p->l);
- break;
- case Qlisten:
- p = &proto[PROTO(c->qid)];
- lcv = p->conv[CONV(c->qid)];
- sfd = so_accept(lcv->sfd, &raddr, &rport);
- cv = protoclone(p, up->user, sfd);
- if(cv == 0) {
- close(sfd);
- error(Enodev);
- }
- cv->raddr = raddr;
- cv->rport = rport;
- setladdr(cv);
- cv->state = "Established";
- c->qid.path = QID(p->x, cv->x, Qctl);
- break;
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
-}
-
-void
-ipclose(Chan *c)
-{
- Conv *cc;
-
- switch(TYPE(c->qid)) {
- case Qcs:
- csclose(c);
- break;
- case Qdata:
- case Qctl:
- if((c->flag & COPEN) == 0)
- break;
- cc = proto[PROTO(c->qid)].conv[CONV(c->qid)];
- if(decref(&cc->r) != 0)
- break;
- strcpy(cc->owner, "network");
- cc->perm = 0666;
- cc->state = "Closed";
- cc->laddr = 0;
- cc->raddr = 0;
- cc->lport = 0;
- cc->rport = 0;
- close(cc->sfd);
- break;
- }
-}
-
-long
-ipread(Chan *ch, void *a, long n, vlong offset)
-{
- int r;
- Conv *c;
- Proto *x;
- uchar ip[4];
- char buf[128], *p;
-
-/*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/
- p = a;
- switch(TYPE(ch->qid)) {
- default:
- error(Eperm);
- case Qcs:
- return csread(ch, a, n, offset);
- case Qprotodir:
- case Qtopdir:
- case Qconvdir:
- return devdirread(ch, a, n, 0, 0, ipgen);
- case Qctl:
- sprint(buf, "%d", CONV(ch->qid));
- return readstr(offset, p, n, buf);
- case Qremote:
- c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
- hnputl(ip, c->raddr);
- sprint(buf, "%I!%d\n", ip, c->rport);
- return readstr(offset, p, n, buf);
- case Qlocal:
- c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
- hnputl(ip, c->laddr);
- sprint(buf, "%I!%d\n", ip, c->lport);
- return readstr(offset, p, n, buf);
- case Qstatus:
- x = &proto[PROTO(ch->qid)];
- c = x->conv[CONV(ch->qid)];
- sprint(buf, "%s/%d %d %s \n",
- c->p->name, c->x, c->r.ref, c->state);
- return readstr(offset, p, n, buf);
- case Qdata:
- c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
- r = so_recv(c->sfd, a, n, 0);
- if(r < 0){
- oserrstr();
- nexterror();
- }
- return r;
- }
-}
-
-static void
-setladdr(Conv *c)
-{
- so_getsockname(c->sfd, &c->laddr, &c->lport);
-}
-
-static void
-setlport(Conv *c)
-{
- if(c->restricted == 0 && c->lport == 0)
- return;
-
- so_bind(c->sfd, c->restricted, c->lport);
-}
-
-static void
-setladdrport(Conv *c, char *str)
-{
- char *p, addr[4];
-
- p = strchr(str, '!');
- if(p == 0) {
- p = str;
- c->laddr = 0;
- }
- else {
- *p++ = 0;
- parseip(addr, str);
- c->laddr = nhgetl((uchar*)addr);
- }
- if(*p == '*')
- c->lport = 0;
- else
- c->lport = atoi(p);
-
- setlport(c);
-}
-
-static char*
-setraddrport(Conv *c, char *str)
-{
- char *p, addr[4];
-
- p = strchr(str, '!');
- if(p == 0)
- return "malformed address";
- *p++ = 0;
- parseip(addr, str);
- c->raddr = nhgetl((uchar*)addr);
- c->rport = atoi(p);
- p = strchr(p, '!');
- if(p) {
- if(strcmp(p, "!r") == 0)
- c->restricted = 1;
- }
- return 0;
-}
-
-long
-ipwrite(Chan *ch, void *a, long n, vlong offset)
-{
- Conv *c;
- Proto *x;
- int r, nf;
- char *p, *fields[3], buf[128];
-
- switch(TYPE(ch->qid)) {
- default:
- error(Eperm);
- case Qcs:
- return cswrite(ch, a, n, offset);
- case Qctl:
- x = &proto[PROTO(ch->qid)];
- c = x->conv[CONV(ch->qid)];
- if(n > sizeof(buf)-1)
- n = sizeof(buf)-1;
- memmove(buf, a, n);
- buf[n] = '\0';
-
- nf = tokenize(buf, fields, 3);
- if(strcmp(fields[0], "connect") == 0){
- switch(nf) {
- default:
- error("bad args to connect");
- case 2:
- p = setraddrport(c, fields[1]);
- if(p != 0)
- error(p);
- break;
- case 3:
- p = setraddrport(c, fields[1]);
- if(p != 0)
- error(p);
- c->lport = atoi(fields[2]);
- setlport(c);
- break;
- }
- so_connect(c->sfd, c->raddr, c->rport);
- setladdr(c);
- c->state = "Established";
- return n;
- }
- if(strcmp(fields[0], "announce") == 0) {
- switch(nf){
- default:
- error("bad args to announce");
- case 2:
- setladdrport(c, fields[1]);
- break;
- }
- so_listen(c->sfd);
- c->state = "Announced";
- return n;
- }
- if(strcmp(fields[0], "bind") == 0){
- switch(nf){
- default:
- error("bad args to bind");
- case 2:
- c->lport = atoi(fields[1]);
- break;
- }
- setlport(c);
- return n;
- }
- error("bad control message");
- case Qdata:
- x = &proto[PROTO(ch->qid)];
- c = x->conv[CONV(ch->qid)];
- r = so_send(c->sfd, a, n, 0);
- if(r < 0){
- oserrstr();
- nexterror();
- }
- return r;
- }
- return n;
-}
-
-static Conv*
-protoclone(Proto *p, char *user, int nfd)
-{
- Conv *c, **pp, **ep;
-
- c = 0;
- lock(&p->l);
- if(waserror()) {
- unlock(&p->l);
- nexterror();
- }
- ep = &p->conv[p->maxconv];
- for(pp = p->conv; pp < ep; pp++) {
- c = *pp;
- if(c == 0) {
- c = mallocz(sizeof(Conv), 1);
- if(c == 0)
- error(Enomem);
- lock(&c->r.lk);
- c->r.ref = 1;
- c->p = p;
- c->x = pp - p->conv;
- p->nc++;
- *pp = c;
- break;
- }
- lock(&c->r.lk);
- if(c->r.ref == 0) {
- c->r.ref++;
- break;
- }
- unlock(&c->r.lk);
- }
- if(pp >= ep) {
- unlock(&p->l);
- poperror();
- return 0;
- }
-
- strcpy(c->owner, user);
- c->perm = 0660;
- c->state = "Closed";
- c->restricted = 0;
- c->laddr = 0;
- c->raddr = 0;
- c->lport = 0;
- c->rport = 0;
- c->sfd = nfd;
- if(nfd == -1)
- c->sfd = so_socket(p->stype);
-
- unlock(&c->r.lk);
- unlock(&p->l);
- poperror();
- return c;
-}
-
-enum
-{
- Isprefix= 16,
-};
-
-uchar prefixvals[256] =
-{
-/*0x00*/ 0 | Isprefix,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x80*/ 1 | Isprefix,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0x90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0xA0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0xB0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0xC0*/ 2 | Isprefix,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0xD0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0xE0*/ 3 | Isprefix,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/*0xF0*/ 4 | Isprefix,
- 0, 0, 0, 0, 0, 0, 0,
-/*0xF8*/ 5 | Isprefix,
- 0, 0, 0,
-/*0xFC*/ 6 | Isprefix,
- 0,
-/*0xFE*/ 7 | Isprefix,
-/*0xFF*/ 8 | Isprefix,
-};
-
-int
-eipfmt(Fmt *f)
-{
- char buf[5*8];
- static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
- static char *ifmt = "%d.%d.%d.%d";
- uchar *p, ip[16];
- ulong ul;
-
- switch(f->r) {
- case 'E': /* Ethernet address */
- p = va_arg(f->args, uchar*);
- snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
- return fmtstrcpy(f, buf);
-
- case 'I':
- ul = va_arg(f->args, ulong);
- hnputl(ip, ul);
- snprint(buf, sizeof buf, ifmt, ip[0], ip[1], ip[2], ip[3]);
- return fmtstrcpy(f, buf);
- }
- return fmtstrcpy(f, "(eipfmt)");
-}
-
-void
-hnputl(void *p, unsigned long v)
-{
- unsigned char *a;
-
- a = p;
- a[0] = v>>24;
- a[1] = v>>16;
- a[2] = v>>8;
- a[3] = v;
-}
-
-void
-hnputs(void *p, unsigned short v)
-{
- unsigned char *a;
-
- a = p;
- a[0] = v>>8;
- a[1] = v;
-}
-
-unsigned long
-nhgetl(void *p)
-{
- unsigned char *a;
- a = p;
- return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
-}
-
-unsigned short
-nhgets(void *p)
-{
- unsigned char *a;
- a = p;
- return (a[0]<<8)|(a[1]<<0);
-}
-
-#define CLASS(p) ((*(unsigned char*)(p))>>6)
-
-unsigned long
-parseip(char *to, char *from)
-{
- int i;
- char *p;
-
- p = from;
- memset(to, 0, 4);
- for(i = 0; i < 4 && *p; i++){
- to[i] = strtoul(p, &p, 10);
- if(*p != '.' && *p != 0){
- memset(to, 0, 4);
- return 0;
- }
- if(*p == '.')
- p++;
- }
- switch(CLASS(to)){
- case 0: /* class A - 1 byte net */
- case 1:
- if(i == 3){
- to[3] = to[2];
- to[2] = to[1];
- to[1] = 0;
- } else if (i == 2){
- to[3] = to[1];
- to[1] = 0;
- }
- break;
- case 2: /* class B - 2 byte net */
- if(i == 3){
- to[3] = to[2];
- to[2] = 0;
- }
- break;
- }
- return nhgetl(to);
-}
-
-void
-csclose(Chan *c)
-{
- free(c->aux);
-}
-
-long
-csread(Chan *c, void *a, long n, vlong offset)
-{
- if(c->aux == nil)
- return 0;
- return readstr(offset, a, n, c->aux);
-}
-
-static struct
-{
- char *name;
- uint num;
-} tab[] = {
- "cs", 1,
- "echo", 7,
- "discard", 9,
- "systat", 11,
- "daytime", 13,
- "netstat", 15,
- "chargen", 19,
- "ftp-data", 20,
- "ftp", 21,
- "ssh", 22,
- "telnet", 23,
- "smtp", 25,
- "time", 37,
- "whois", 43,
- "dns", 53,
- "domain", 53,
- "uucp", 64,
- "gopher", 70,
- "rje", 77,
- "finger", 79,
- "http", 80,
- "link", 87,
- "supdup", 95,
- "hostnames", 101,
- "iso-tsap", 102,
- "x400", 103,
- "x400-snd", 104,
- "csnet-ns", 105,
- "pop-2", 109,
- "pop3", 110,
- "portmap", 111,
- "uucp-path", 117,
- "nntp", 119,
- "netbios", 139,
- "imap4", 143,
- "NeWS", 144,
- "print-srv", 170,
- "z39.50", 210,
- "fsb", 400,
- "sysmon", 401,
- "proxy", 402,
- "proxyd", 404,
- "https", 443,
- "cifs", 445,
- "ssmtp", 465,
- "rexec", 512,
- "login", 513,
- "shell", 514,
- "printer", 515,
- "courier", 530,
- "cscan", 531,
- "uucp", 540,
- "snntp", 563,
- "9fs", 564,
- "whoami", 565,
- "guard", 566,
- "ticket", 567,
- "dlsftp", 666,
- "fmclient", 729,
- "imaps", 993,
- "pop3s", 995,
- "ingreslock", 1524,
- "pptp", 1723,
- "nfs", 2049,
- "webster", 2627,
- "weather", 3000,
- "secstore", 5356,
- "Xdisplay", 6000,
- "styx", 6666,
- "mpeg", 6667,
- "rstyx", 6668,
- "infdb", 6669,
- "infsigner", 6671,
- "infcsigner", 6672,
- "inflogin", 6673,
- "bandt", 7330,
- "face", 32000,
- "dhashgate", 11978,
- "exportfs", 17007,
- "rexexec", 17009,
- "ncpu", 17010,
- "cpu", 17013,
- "glenglenda1", 17020,
- "glenglenda2", 17021,
- "glenglenda3", 17022,
- "glenglenda4", 17023,
- "glenglenda5", 17024,
- "glenglenda6", 17025,
- "glenglenda7", 17026,
- "glenglenda8", 17027,
- "glenglenda9", 17028,
- "glenglenda10", 17029,
- "flyboy", 17032,
- "dlsftp", 17033,
- "venti", 17034,
- "wiki", 17035,
- "vica", 17036,
- 0
-};
-
-static int
-lookupport(char *s)
-{
- int i;
- char buf[10], *p;
-
- i = strtol(s, &p, 0);
- if(*s && *p == 0)
- return i;
-
- i = so_getservbyname(s, "tcp", buf);
- if(i != -1)
- return atoi(buf);
- for(i=0; tab[i].name; i++)
- if(strcmp(s, tab[i].name) == 0)
- return tab[i].num;
- return 0;
-}
-
-static ulong
-lookuphost(char *s)
-{
- char to[4];
- ulong ip;
-
- memset(to, 0, sizeof to);
- parseip(to, s);
- ip = nhgetl(to);
- if(ip != 0)
- return ip;
- if((s = hostlookup(s)) == nil)
- return 0;
- parseip(to, s);
- ip = nhgetl(to);
- free(s);
- return ip;
-}
-
-long
-cswrite(Chan *c, void *a, long n, vlong offset)
-{
- char *f[4];
- char *s, *ns;
- ulong ip;
- int nf, port;
-
- s = malloc(n+1);
- if(s == nil)
- error(Enomem);
- if(waserror()){
- free(s);
- nexterror();
- }
- memmove(s, a, n);
- s[n] = 0;
- nf = getfields(s, f, nelem(f), 0, "!");
- if(nf != 3)
- error("can't translate");
-
- port = lookupport(f[2]);
- if(port <= 0)
- error("no translation for port found");
-
- ip = lookuphost(f[1]);
- if(ip == 0)
- error("no translation for host found");
-
- ns = smprint("/net/%s/clone %I!%d", f[0], ip, port);
- if(ns == nil)
- error(Enomem);
- free(c->aux);
- c->aux = ns;
- poperror();
- free(s);
- return n;
-}
-
-Dev ipdevtab =
-{
- 'I',
- "ip",
-
- devreset,
- ipinit,
- devshutdown,
- ipattach,
- ipwalk,
- ipstat,
- ipopen,
- devcreate,
- ipclose,
- ipread,
- devbread,
- ipwrite,
- devbwrite,
- devremove,
- devwstat,
-};
-
diff --git a/sys/src/cmd/unix/drawterm/kern/devip.h b/sys/src/cmd/unix/drawterm/kern/devip.h
deleted file mode 100644
index 950ad398d..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devip.h
+++ /dev/null
@@ -1,19 +0,0 @@
-enum
-{
- S_TCP,
- S_UDP
-};
-
-int so_socket(int type);
-void so_connect(int, unsigned long, unsigned short);
-void so_getsockname(int, unsigned long*, unsigned short*);
-void so_bind(int, int, unsigned short);
-void so_listen(int);
-int so_send(int, void*, int, int);
-int so_recv(int, void*, int, int);
-int so_accept(int, unsigned long*, unsigned short*);
-int so_getservbyname(char*, char*, char*);
-int so_gethostbyname(char*, char**, int);
-
-char* hostlookup(char*);
-
diff --git a/sys/src/cmd/unix/drawterm/kern/devlfd.c b/sys/src/cmd/unix/drawterm/kern/devlfd.c
deleted file mode 100644
index 7c61e0c1e..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devlfd.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#include "u.h"
-#include <errno.h>
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#undef pread
-#undef pwrite
-
-Chan*
-lfdchan(int fd)
-{
- Chan *c;
-
- c = newchan();
- c->type = devno('L', 0);
- c->aux = (void*)(uintptr)fd;
- c->name = newcname("fd");
- c->mode = ORDWR;
- c->qid.type = 0;
- c->qid.path = 0;
- c->qid.vers = 0;
- c->dev = 0;
- c->offset = 0;
- return c;
-}
-
-int
-lfdfd(int fd)
-{
- return newfd(lfdchan(fd));
-}
-
-static Chan*
-lfdattach(char *x)
-{
- USED(x);
-
- error(Egreg);
- return nil;
-}
-
-static Walkqid*
-lfdwalk(Chan *c, Chan *nc, char **name, int nname)
-{
- USED(c);
- USED(nc);
- USED(name);
- USED(nname);
-
- error(Egreg);
- return nil;
-}
-
-static int
-lfdstat(Chan *c, uchar *dp, int n)
-{
- USED(c);
- USED(dp);
- USED(n);
- error(Egreg);
- return -1;
-}
-
-static Chan*
-lfdopen(Chan *c, int omode)
-{
- USED(c);
- USED(omode);
-
- error(Egreg);
- return nil;
-}
-
-static void
-lfdclose(Chan *c)
-{
- close((int)(uintptr)c->aux);
-}
-
-static long
-lfdread(Chan *c, void *buf, long n, vlong off)
-{
- USED(off); /* can't pread on pipes */
- n = read((int)(uintptr)c->aux, buf, n);
- if(n < 0){
- iprint("error %d\n", errno);
- oserror();
- }
- return n;
-}
-
-static long
-lfdwrite(Chan *c, void *buf, long n, vlong off)
-{
- USED(off); /* can't pread on pipes */
-
- n = write((int)(uintptr)c->aux, buf, n);
- if(n < 0){
- iprint("error %d\n", errno);
- oserror();
- }
- return n;
-}
-
-Dev lfddevtab = {
- 'L',
- "lfd",
-
- devreset,
- devinit,
- devshutdown,
- lfdattach,
- lfdwalk,
- lfdstat,
- lfdopen,
- devcreate,
- lfdclose,
- lfdread,
- devbread,
- lfdwrite,
- devbwrite,
- devremove,
- devwstat,
-};
diff --git a/sys/src/cmd/unix/drawterm/kern/devmnt.c b/sys/src/cmd/unix/drawterm/kern/devmnt.c
deleted file mode 100644
index 9121bfdb4..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devmnt.c
+++ /dev/null
@@ -1,1216 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-/*
- * References are managed as follows:
- * The channel to the server - a network connection or pipe - has one
- * reference for every Chan open on the server. The server channel has
- * c->mux set to the Mnt used for muxing control to that server. Mnts
- * have no reference count; they go away when c goes away.
- * Each channel derived from the mount point has mchan set to c,
- * and increfs/decrefs mchan to manage references on the server
- * connection.
- */
-
-#define MAXRPC (IOHDRSZ+8192)
-
-struct Mntrpc
-{
- Chan* c; /* Channel for whom we are working */
- Mntrpc* list; /* Free/pending list */
- Fcall request; /* Outgoing file system protocol message */
- Fcall reply; /* Incoming reply */
- Mnt* m; /* Mount device during rpc */
- Rendez r; /* Place to hang out */
- uchar* rpc; /* I/O Data buffer */
- uint rpclen; /* len of buffer */
- Block *b; /* reply blocks */
- char done; /* Rpc completed */
- uvlong stime; /* start time for mnt statistics */
- ulong reqlen; /* request length for mnt statistics */
- ulong replen; /* reply length for mnt statistics */
- Mntrpc* flushed; /* message this one flushes */
-};
-
-enum
-{
- TAGSHIFT = 5, /* ulong has to be 32 bits */
- TAGMASK = (1<<TAGSHIFT)-1,
- NMASK = (64*1024)>>TAGSHIFT,
-};
-
-struct Mntalloc
-{
- Lock lk;
- Mnt* list; /* Mount devices in use */
- Mnt* mntfree; /* Free list */
- Mntrpc* rpcfree;
- int nrpcfree;
- int nrpcused;
- ulong id;
- ulong tagmask[NMASK];
-}mntalloc;
-
-void mattach(Mnt*, Chan*, char*);
-Mnt* mntchk(Chan*);
-void mntdirfix(uchar*, Chan*);
-Mntrpc* mntflushalloc(Mntrpc*, ulong);
-void mntflushfree(Mnt*, Mntrpc*);
-void mntfree(Mntrpc*);
-void mntgate(Mnt*);
-void mntpntfree(Mnt*);
-void mntqrm(Mnt*, Mntrpc*);
-Mntrpc* mntralloc(Chan*, ulong);
-long mntrdwr(int, Chan*, void*, long, vlong);
-int mntrpcread(Mnt*, Mntrpc*);
-void mountio(Mnt*, Mntrpc*);
-void mountmux(Mnt*, Mntrpc*);
-void mountrpc(Mnt*, Mntrpc*);
-int rpcattn(void*);
-Chan* mntchan(void);
-
-char Esbadstat[] = "invalid directory entry received from server";
-char Enoversion[] = "version not established for mount channel";
-
-
-void (*mntstats)(int, Chan*, uvlong, ulong);
-
-static void
-mntreset(void)
-{
- mntalloc.id = 1;
- mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */
- mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */
- fmtinstall('F', fcallfmt);
- fmtinstall('D', dirfmt);
-/* We can't install %M since eipfmt does and is used in the kernel [sape] */
-
- cinit();
-}
-
-/*
- * Version is not multiplexed: message sent only once per connection.
- */
-long
-mntversion(Chan *c, char *version, int msize, int returnlen)
-{
- Fcall f;
- uchar *msg;
- Mnt *m;
- char *v;
- long k, l;
- uvlong oo;
- char buf[128];
-
- qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
- if(waserror()){
- qunlock(&c->umqlock);
- nexterror();
- }
-
- /* defaults */
- if(msize == 0)
- msize = MAXRPC;
- if(msize > c->iounit && c->iounit != 0)
- msize = c->iounit;
- v = version;
- if(v == nil || v[0] == '\0')
- v = VERSION9P;
-
- /* validity */
- if(msize < 0)
- error("bad iounit in version call");
- if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
- error("bad 9P version specification");
-
- m = c->mux;
-
- if(m != nil){
- qunlock(&c->umqlock);
- poperror();
-
- strecpy(buf, buf+sizeof buf, m->version);
- k = strlen(buf);
- if(strncmp(buf, v, k) != 0){
- snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
- error(buf);
- }
- if(returnlen > 0){
- if(returnlen < k)
- error(Eshort);
- memmove(version, buf, k);
- }
- return k;
- }
-
- f.type = Tversion;
- f.tag = NOTAG;
- f.msize = msize;
- f.version = v;
- msg = malloc(8192+IOHDRSZ);
- if(msg == nil)
- exhausted("version memory");
- if(waserror()){
- free(msg);
- nexterror();
- }
- k = convS2M(&f, msg, 8192+IOHDRSZ);
- if(k == 0)
- error("bad fversion conversion on send");
-
- lock(&c->ref.lk);
- oo = c->offset;
- c->offset += k;
- unlock(&c->ref.lk);
-
- l = devtab[c->type]->write(c, msg, k, oo);
-
- if(l < k){
- lock(&c->ref.lk);
- c->offset -= k - l;
- unlock(&c->ref.lk);
- error("short write in fversion");
- }
-
- /* message sent; receive and decode reply */
- k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
- if(k <= 0)
- error("EOF receiving fversion reply");
-
- lock(&c->ref.lk);
- c->offset += k;
- unlock(&c->ref.lk);
-
- l = convM2S(msg, k, &f);
- if(l != k)
- error("bad fversion conversion on reply");
- if(f.type != Rversion){
- if(f.type == Rerror)
- error(f.ename);
- error("unexpected reply type in fversion");
- }
- if(f.msize > msize)
- error("server tries to increase msize in fversion");
- if(f.msize<256 || f.msize>1024*1024)
- error("nonsense value of msize in fversion");
- k = strlen(f.version);
- if(strncmp(f.version, v, k) != 0)
- error("bad 9P version returned from server");
-
- /* now build Mnt associated with this connection */
- lock(&mntalloc.lk);
- m = mntalloc.mntfree;
- if(m != 0)
- mntalloc.mntfree = m->list;
- else {
- m = malloc(sizeof(Mnt));
- if(m == 0) {
- unlock(&mntalloc.lk);
- exhausted("mount devices");
- }
- }
- m->list = mntalloc.list;
- mntalloc.list = m;
- m->version = nil;
- kstrdup(&m->version, f.version);
- m->id = mntalloc.id++;
- m->q = qopen(10*MAXRPC, 0, 0, nil);
- m->msize = f.msize;
- unlock(&mntalloc.lk);
-
- if(returnlen > 0){
- if(returnlen < k)
- error(Eshort);
- memmove(version, f.version, k);
- }
-
- poperror(); /* msg */
- free(msg);
-
- lock(&m->lk);
- m->queue = 0;
- m->rip = 0;
-
- c->flag |= CMSG;
- c->mux = m;
- m->c = c;
- unlock(&m->lk);
-
- poperror(); /* c */
- qunlock(&c->umqlock);
-
- return k;
-}
-
-Chan*
-mntauth(Chan *c, char *spec)
-{
- Mnt *m;
- Mntrpc *r;
-
- m = c->mux;
-
- if(m == nil){
- mntversion(c, VERSION9P, MAXRPC, 0);
- m = c->mux;
- if(m == nil)
- error(Enoversion);
- }
-
- c = mntchan();
- if(waserror()) {
- /* Close must not be called since it will
- * call mnt recursively
- */
- chanfree(c);
- nexterror();
- }
-
- r = mntralloc(0, m->msize);
-
- if(waserror()) {
- mntfree(r);
- nexterror();
- }
-
- r->request.type = Tauth;
- r->request.afid = c->fid;
- r->request.uname = up->user;
- r->request.aname = spec;
- mountrpc(m, r);
-
- c->qid = r->reply.aqid;
- c->mchan = m->c;
- incref(&m->c->ref);
- c->mqid = c->qid;
- c->mode = ORDWR;
-
- poperror(); /* r */
- mntfree(r);
-
- poperror(); /* c */
-
- return c;
-
-}
-
-static Chan*
-mntattach(char *muxattach)
-{
- Mnt *m;
- Chan *c;
- Mntrpc *r;
- struct bogus{
- Chan *chan;
- Chan *authchan;
- char *spec;
- int flags;
- }bogus;
-
- bogus = *((struct bogus *)muxattach);
- c = bogus.chan;
-
- m = c->mux;
-
- if(m == nil){
- mntversion(c, nil, 0, 0);
- m = c->mux;
- if(m == nil)
- error(Enoversion);
- }
-
- c = mntchan();
- if(waserror()) {
- /* Close must not be called since it will
- * call mnt recursively
- */
- chanfree(c);
- nexterror();
- }
-
- r = mntralloc(0, m->msize);
-
- if(waserror()) {
- mntfree(r);
- nexterror();
- }
-
- r->request.type = Tattach;
- r->request.fid = c->fid;
- if(bogus.authchan == nil)
- r->request.afid = NOFID;
- else
- r->request.afid = bogus.authchan->fid;
- r->request.uname = up->user;
- r->request.aname = bogus.spec;
- mountrpc(m, r);
-
- c->qid = r->reply.qid;
- c->mchan = m->c;
- incref(&m->c->ref);
- c->mqid = c->qid;
-
- poperror(); /* r */
- mntfree(r);
-
- poperror(); /* c */
-
- if(bogus.flags&MCACHE)
- c->flag |= CCACHE;
- return c;
-}
-
-Chan*
-mntchan(void)
-{
- Chan *c;
-
- c = devattach('M', 0);
- lock(&mntalloc.lk);
- c->dev = mntalloc.id++;
- unlock(&mntalloc.lk);
-
- if(c->mchan)
- panic("mntchan non-zero %p", c->mchan);
- return c;
-}
-
-static Walkqid*
-mntwalk(Chan *c, Chan *nc, char **name, int nname)
-{
- int i, alloc;
- Mnt *m;
- Mntrpc *r;
- Walkqid *wq;
-
- if(nc != nil)
- print("mntwalk: nc != nil\n");
- if(nname > MAXWELEM)
- error("devmnt: too many name elements");
- alloc = 0;
- wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
- if(waserror()){
- if(alloc && wq->clone!=nil)
- cclose(wq->clone);
- free(wq);
- return nil;
- }
-
- alloc = 0;
- m = mntchk(c);
- r = mntralloc(c, m->msize);
- if(nc == nil){
- nc = devclone(c);
- /*
- * Until the other side accepts this fid, we can't mntclose it.
- * Therefore set type to 0 for now; rootclose is known to be safe.
- */
- nc->type = 0;
- alloc = 1;
- }
- wq->clone = nc;
-
- if(waserror()) {
- mntfree(r);
- nexterror();
- }
- r->request.type = Twalk;
- r->request.fid = c->fid;
- r->request.newfid = nc->fid;
- r->request.nwname = nname;
- memmove(r->request.wname, name, nname*sizeof(char*));
-
- mountrpc(m, r);
-
- if(r->reply.nwqid > nname)
- error("too many QIDs returned by walk");
- if(r->reply.nwqid < nname){
- if(alloc)
- cclose(nc);
- wq->clone = nil;
- if(r->reply.nwqid == 0){
- free(wq);
- wq = nil;
- goto Return;
- }
- }
-
- /* move new fid onto mnt device and update its qid */
- if(wq->clone != nil){
- if(wq->clone != c){
- wq->clone->type = c->type;
- wq->clone->mchan = c->mchan;
- incref(&c->mchan->ref);
- }
- if(r->reply.nwqid > 0)
- wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
- }
- wq->nqid = r->reply.nwqid;
- for(i=0; i<wq->nqid; i++)
- wq->qid[i] = r->reply.wqid[i];
-
- Return:
- poperror();
- mntfree(r);
- poperror();
- return wq;
-}
-
-static int
-mntstat(Chan *c, uchar *dp, int n)
-{
- Mnt *m;
- Mntrpc *r;
-
- if(n < BIT16SZ)
- error(Eshortstat);
- m = mntchk(c);
- r = mntralloc(c, m->msize);
- if(waserror()) {
- mntfree(r);
- nexterror();
- }
- r->request.type = Tstat;
- r->request.fid = c->fid;
- mountrpc(m, r);
-
-/* r->reply.nstat is 16 bits
- if(r->reply.nstat >= 1<<16)
- error("returned stat buffer count too large");
-*/
-
- if(r->reply.nstat > n){
- /*
- * 12/31/2002 RSC
- *
- * This should be nstat-2, which is the first two
- * bytes of the stat buffer. But dirstat and dirfstat
- * depended on getting the full nstat (they didn't
- * add BIT16SZ themselves). I fixed dirstat and dirfstat
- * but am leaving this unchanged for now. After a
- * few months, once enough of the relevant binaries
- * have been recompiled for other reasons, we can
- * change this to nstat-2. Devstat gets this right
- * (via convD2M).
- */
- /* doesn't fit; just patch the count and return */
- PBIT16((uchar*)dp, r->reply.nstat);
- n = BIT16SZ;
- }else{
- n = r->reply.nstat;
- memmove(dp, r->reply.stat, n);
- validstat(dp, n);
- mntdirfix(dp, c);
- }
- poperror();
- mntfree(r);
- return n;
-}
-
-static Chan*
-mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
-{
- Mnt *m;
- Mntrpc *r;
-
- m = mntchk(c);
- r = mntralloc(c, m->msize);
- if(waserror()) {
- mntfree(r);
- nexterror();
- }
- r->request.type = type;
- r->request.fid = c->fid;
- r->request.mode = omode;
- if(type == Tcreate){
- r->request.perm = perm;
- r->request.name = name;
- }
- mountrpc(m, r);
-
- c->qid = r->reply.qid;
- c->offset = 0;
- c->mode = openmode(omode);
- c->iounit = r->reply.iounit;
- if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
- c->iounit = m->msize-IOHDRSZ;
- c->flag |= COPEN;
- poperror();
- mntfree(r);
-
- if(c->flag & CCACHE)
- copen(c);
-
- return c;
-}
-
-static Chan*
-mntopen(Chan *c, int omode)
-{
- return mntopencreate(Topen, c, nil, omode, 0);
-}
-
-static void
-mntcreate(Chan *c, char *name, int omode, ulong perm)
-{
- mntopencreate(Tcreate, c, name, omode, perm);
-}
-
-static void
-mntclunk(Chan *c, int t)
-{
- Mnt *m;
- Mntrpc *r;
-
- m = mntchk(c);
- r = mntralloc(c, m->msize);
- if(waserror()){
- mntfree(r);
- nexterror();
- }
-
- r->request.type = t;
- r->request.fid = c->fid;
- mountrpc(m, r);
- mntfree(r);
- poperror();
-}
-
-void
-muxclose(Mnt *m)
-{
- Mntrpc *q, *r;
-
- for(q = m->queue; q; q = r) {
- r = q->list;
- mntfree(q);
- }
- m->id = 0;
- free(m->version);
- m->version = nil;
- mntpntfree(m);
-}
-
-void
-mntpntfree(Mnt *m)
-{
- Mnt *f, **l;
- Queue *q;
-
- lock(&mntalloc.lk);
- l = &mntalloc.list;
- for(f = *l; f; f = f->list) {
- if(f == m) {
- *l = m->list;
- break;
- }
- l = &f->list;
- }
- m->list = mntalloc.mntfree;
- mntalloc.mntfree = m;
- q = m->q;
- unlock(&mntalloc.lk);
-
- qfree(q);
-}
-
-static void
-mntclose(Chan *c)
-{
- mntclunk(c, Tclunk);
-}
-
-static void
-mntremove(Chan *c)
-{
- mntclunk(c, Tremove);
-}
-
-static int
-mntwstat(Chan *c, uchar *dp, int n)
-{
- Mnt *m;
- Mntrpc *r;
-
- m = mntchk(c);
- r = mntralloc(c, m->msize);
- if(waserror()) {
- mntfree(r);
- nexterror();
- }
- r->request.type = Twstat;
- r->request.fid = c->fid;
- r->request.nstat = n;
- r->request.stat = dp;
- mountrpc(m, r);
- poperror();
- mntfree(r);
- return n;
-}
-
-static long
-mntread(Chan *c, void *buf, long n, vlong off)
-{
- uchar *p, *e;
- int nc, cache, isdir, dirlen;
-
- isdir = 0;
- cache = c->flag & CCACHE;
- if(c->qid.type & QTDIR) {
- cache = 0;
- isdir = 1;
- }
-
- p = buf;
- if(cache) {
- nc = cread(c, buf, n, off);
- if(nc > 0) {
- n -= nc;
- if(n == 0)
- return nc;
- p += nc;
- off += nc;
- }
- n = mntrdwr(Tread, c, p, n, off);
- cupdate(c, p, n, off);
- return n + nc;
- }
-
- n = mntrdwr(Tread, c, buf, n, off);
- if(isdir) {
- for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
- dirlen = BIT16SZ+GBIT16(p);
- if(p+dirlen > e)
- break;
- validstat(p, dirlen);
- mntdirfix(p, c);
- }
- if(p != e)
- error(Esbadstat);
- }
- return n;
-}
-
-static long
-mntwrite(Chan *c, void *buf, long n, vlong off)
-{
- return mntrdwr(Twrite, c, buf, n, off);
-}
-
-long
-mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
-{
- Mnt *m;
- Mntrpc *r;
- char *uba;
- int cache;
- ulong cnt, nr, nreq;
-
- m = mntchk(c);
- uba = buf;
- cnt = 0;
- cache = c->flag & CCACHE;
- if(c->qid.type & QTDIR)
- cache = 0;
- for(;;) {
- r = mntralloc(c, m->msize);
- if(waserror()) {
- mntfree(r);
- nexterror();
- }
- r->request.type = type;
- r->request.fid = c->fid;
- r->request.offset = off;
- r->request.data = uba;
- nr = n;
- if(nr > m->msize-IOHDRSZ)
- nr = m->msize-IOHDRSZ;
- r->request.count = nr;
- mountrpc(m, r);
- nreq = r->request.count;
- nr = r->reply.count;
- if(nr > nreq)
- nr = nreq;
-
- if(type == Tread)
- r->b = bl2mem((uchar*)uba, r->b, nr);
- else if(cache)
- cwrite(c, (uchar*)uba, nr, off);
-
- poperror();
- mntfree(r);
- off += nr;
- uba += nr;
- cnt += nr;
- n -= nr;
- if(nr != nreq || n == 0)
- break;
- }
- return cnt;
-}
-
-void
-mountrpc(Mnt *m, Mntrpc *r)
-{
- char *sn, *cn;
- int t;
-
- r->reply.tag = 0;
- r->reply.type = Tmax; /* can't ever be a valid message type */
-
- mountio(m, r);
-
- t = r->reply.type;
- switch(t) {
- case Rerror:
- error(r->reply.ename);
- case Rflush:
- error(Eintr);
- default:
- if(t == r->request.type+1)
- break;
- sn = "?";
- if(m->c->name != nil)
- sn = m->c->name->s;
- cn = "?";
- if(r->c != nil && r->c->name != nil)
- cn = r->c->name->s;
- print("mnt: proc %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n",
- up->pid, sn, cn,
- r, r->request.tag, r->request.fid, r->request.type,
- r->reply.type, r->reply.tag);
- error(Emountrpc);
- }
-}
-
-void
-mountio(Mnt *m, Mntrpc *r)
-{
- int n;
-
- while(waserror()) {
- if(m->rip == up)
- mntgate(m);
- if(strcmp(up->errstr, Eintr) != 0){
- mntflushfree(m, r);
- nexterror();
- }
- r = mntflushalloc(r, m->msize);
- }
-
- lock(&m->lk);
- r->m = m;
- r->list = m->queue;
- m->queue = r;
- unlock(&m->lk);
-
- /* Transmit a file system rpc */
- if(m->msize == 0)
- panic("msize");
- n = convS2M(&r->request, r->rpc, m->msize);
- if(n < 0)
- panic("bad message type in mountio");
- if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
- error(Emountrpc);
- r->stime = fastticks(nil);
- r->reqlen = n;
-
- /* Gate readers onto the mount point one at a time */
- for(;;) {
- lock(&m->lk);
- if(m->rip == 0)
- break;
- unlock(&m->lk);
- sleep(&r->r, rpcattn, r);
- if(r->done){
- poperror();
- mntflushfree(m, r);
- return;
- }
- }
- m->rip = up;
- unlock(&m->lk);
- while(r->done == 0) {
- if(mntrpcread(m, r) < 0)
- error(Emountrpc);
- mountmux(m, r);
- }
- mntgate(m);
- poperror();
- mntflushfree(m, r);
-}
-
-static int
-doread(Mnt *m, int len)
-{
- Block *b;
-
- while(qlen(m->q) < len){
- b = devtab[m->c->type]->bread(m->c, m->msize, 0);
- if(b == nil)
- return -1;
- if(BLEN(b) == 0){
- freeblist(b);
- return -1;
- }
- qaddlist(m->q, b);
- }
- return 0;
-}
-
-int
-mntrpcread(Mnt *m, Mntrpc *r)
-{
- int i, t, len, hlen;
- Block *b, **l, *nb;
-
- r->reply.type = 0;
- r->reply.tag = 0;
-
- /* read at least length, type, and tag and pullup to a single block */
- if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
- return -1;
- nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
-
- /* read in the rest of the message, avoid rediculous (for now) message sizes */
- len = GBIT32(nb->rp);
- if(len > m->msize){
- qdiscard(m->q, qlen(m->q));
- return -1;
- }
- if(doread(m, len) < 0)
- return -1;
-
- /* pullup the header (i.e. everything except data) */
- t = nb->rp[BIT32SZ];
- switch(t){
- case Rread:
- hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
- break;
- default:
- hlen = len;
- break;
- }
- nb = pullupqueue(m->q, hlen);
-
- if(convM2S(nb->rp, len, &r->reply) <= 0){
- /* bad message, dump it */
- print("mntrpcread: convM2S failed\n");
- qdiscard(m->q, len);
- return -1;
- }
-
- /* hang the data off of the fcall struct */
- l = &r->b;
- *l = nil;
- do {
- b = qremove(m->q);
- if(hlen > 0){
- b->rp += hlen;
- len -= hlen;
- hlen = 0;
- }
- i = BLEN(b);
- if(i <= len){
- len -= i;
- *l = b;
- l = &(b->next);
- } else {
- /* split block and put unused bit back */
- nb = allocb(i-len);
- memmove(nb->wp, b->rp+len, i-len);
- b->wp = b->rp+len;
- nb->wp += i-len;
- qputback(m->q, nb);
- *l = b;
- return 0;
- }
- }while(len > 0);
-
- return 0;
-}
-
-void
-mntgate(Mnt *m)
-{
- Mntrpc *q;
-
- lock(&m->lk);
- m->rip = 0;
- for(q = m->queue; q; q = q->list) {
- if(q->done == 0)
- if(wakeup(&q->r))
- break;
- }
- unlock(&m->lk);
-}
-
-void
-mountmux(Mnt *m, Mntrpc *r)
-{
- Mntrpc **l, *q;
-
- lock(&m->lk);
- l = &m->queue;
- for(q = *l; q; q = q->list) {
- /* look for a reply to a message */
- if(q->request.tag == r->reply.tag) {
- *l = q->list;
- if(q != r) {
- /*
- * Completed someone else.
- * Trade pointers to receive buffer.
- */
- q->reply = r->reply;
- q->b = r->b;
- r->b = nil;
- }
- q->done = 1;
- unlock(&m->lk);
- if(mntstats != 0)
- (*mntstats)(q->request.type,
- m->c, q->stime,
- q->reqlen + r->replen);
- if(q != r)
- wakeup(&q->r);
- return;
- }
- l = &q->list;
- }
- unlock(&m->lk);
- print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
-}
-
-/*
- * Create a new flush request and chain the previous
- * requests from it
- */
-Mntrpc*
-mntflushalloc(Mntrpc *r, ulong iounit)
-{
- Mntrpc *fr;
-
- fr = mntralloc(0, iounit);
-
- fr->request.type = Tflush;
- if(r->request.type == Tflush)
- fr->request.oldtag = r->request.oldtag;
- else
- fr->request.oldtag = r->request.tag;
- fr->flushed = r;
-
- return fr;
-}
-
-/*
- * Free a chain of flushes. Remove each unanswered
- * flush and the original message from the unanswered
- * request queue. Mark the original message as done
- * and if it hasn't been answered set the reply to to
- * Rflush.
- */
-void
-mntflushfree(Mnt *m, Mntrpc *r)
-{
- Mntrpc *fr;
-
- while(r){
- fr = r->flushed;
- if(!r->done){
- r->reply.type = Rflush;
- mntqrm(m, r);
- }
- if(fr)
- mntfree(r);
- r = fr;
- }
-}
-
-int
-alloctag(void)
-{
- int i, j;
- ulong v;
-
- for(i = 0; i < NMASK; i++){
- v = mntalloc.tagmask[i];
- if(v == ~0)
- continue;
- for(j = 0; j < 1<<TAGSHIFT; j++)
- if((v & (1<<j)) == 0){
- mntalloc.tagmask[i] |= 1<<j;
- return (i<<TAGSHIFT) + j;
- }
- }
- panic("no friggin tags left");
- return NOTAG;
-}
-
-void
-freetag(int t)
-{
- mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
-}
-
-Mntrpc*
-mntralloc(Chan *c, ulong msize)
-{
- Mntrpc *new;
-
- lock(&mntalloc.lk);
- new = mntalloc.rpcfree;
- if(new == nil){
- new = malloc(sizeof(Mntrpc));
- if(new == nil) {
- unlock(&mntalloc.lk);
- exhausted("mount rpc header");
- }
- /*
- * The header is split from the data buffer as
- * mountmux may swap the buffer with another header.
- */
- new->rpc = mallocz(msize, 0);
- if(new->rpc == nil){
- free(new);
- unlock(&mntalloc.lk);
- exhausted("mount rpc buffer");
- }
- new->rpclen = msize;
- new->request.tag = alloctag();
- }
- else {
- mntalloc.rpcfree = new->list;
- mntalloc.nrpcfree--;
- if(new->rpclen < msize){
- free(new->rpc);
- new->rpc = mallocz(msize, 0);
- if(new->rpc == nil){
- free(new);
- mntalloc.nrpcused--;
- unlock(&mntalloc.lk);
- exhausted("mount rpc buffer");
- }
- new->rpclen = msize;
- }
- }
- mntalloc.nrpcused++;
- unlock(&mntalloc.lk);
- new->c = c;
- new->done = 0;
- new->flushed = nil;
- new->b = nil;
- return new;
-}
-
-void
-mntfree(Mntrpc *r)
-{
- if(r->b != nil)
- freeblist(r->b);
- lock(&mntalloc.lk);
- if(mntalloc.nrpcfree >= 10){
- free(r->rpc);
- free(r);
- freetag(r->request.tag);
- }
- else{
- r->list = mntalloc.rpcfree;
- mntalloc.rpcfree = r;
- mntalloc.nrpcfree++;
- }
- mntalloc.nrpcused--;
- unlock(&mntalloc.lk);
-}
-
-void
-mntqrm(Mnt *m, Mntrpc *r)
-{
- Mntrpc **l, *f;
-
- lock(&m->lk);
- r->done = 1;
-
- l = &m->queue;
- for(f = *l; f; f = f->list) {
- if(f == r) {
- *l = r->list;
- break;
- }
- l = &f->list;
- }
- unlock(&m->lk);
-}
-
-Mnt*
-mntchk(Chan *c)
-{
- Mnt *m;
-
- /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
-
- if(c->mchan == nil)
- panic("mntchk 1: nil mchan c %s\n", c2name(c));
-
- m = c->mchan->mux;
-
- if(m == nil)
- print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan));
-
- /*
- * Was it closed and reused (was error(Eshutdown); now, it can't happen)
- */
- if(m->id == 0 || m->id >= c->dev)
- panic("mntchk 3: can't happen");
-
- return m;
-}
-
-/*
- * Rewrite channel type and dev for in-flight data to
- * reflect local values. These entries are known to be
- * the first two in the Dir encoding after the count.
- */
-void
-mntdirfix(uchar *dirbuf, Chan *c)
-{
- uint r;
-
- r = devtab[c->type]->dc;
- dirbuf += BIT16SZ; /* skip count */
- PBIT16(dirbuf, r);
- dirbuf += BIT16SZ;
- PBIT32(dirbuf, c->dev);
-}
-
-int
-rpcattn(void *v)
-{
- Mntrpc *r;
-
- r = v;
- return r->done || r->m->rip == 0;
-}
-
-Dev mntdevtab = {
- 'M',
- "mnt",
-
- mntreset,
- devinit,
- devshutdown,
- mntattach,
- mntwalk,
- mntstat,
- mntopen,
- mntcreate,
- mntclose,
- mntread,
- devbread,
- mntwrite,
- devbwrite,
- mntremove,
- mntwstat,
-};
diff --git a/sys/src/cmd/unix/drawterm/kern/devmouse.c b/sys/src/cmd/unix/drawterm/kern/devmouse.c
deleted file mode 100644
index 3ee0c8b6b..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devmouse.c
+++ /dev/null
@@ -1,237 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "draw.h"
-#include "memdraw.h"
-#include "screen.h"
-
-int mousequeue = 1;
-
-Mouseinfo mouse;
-Cursorinfo cursor;
-
-static int mousechanged(void*);
-
-enum{
- Qdir,
- Qcursor,
- Qmouse
-};
-
-Dirtab mousedir[]={
- ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
- "cursor", {Qcursor}, 0, 0666,
- "mouse", {Qmouse}, 0, 0666,
-};
-
-#define NMOUSE (sizeof(mousedir)/sizeof(Dirtab))
-
-static Chan*
-mouseattach(char *spec)
-{
- return devattach('m', spec);
-}
-
-static Walkqid*
-mousewalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name, nname, mousedir, NMOUSE, devgen);
-}
-
-static int
-mousestat(Chan *c, uchar *db, int n)
-{
- return devstat(c, db, n, mousedir, NMOUSE, devgen);
-}
-
-static Chan*
-mouseopen(Chan *c, int omode)
-{
- switch((long)c->qid.path){
- case Qdir:
- if(omode != OREAD)
- error(Eperm);
- break;
- case Qmouse:
- lock(&mouse.lk);
- if(mouse.open){
- unlock(&mouse.lk);
- error(Einuse);
- }
- mouse.open = 1;
- unlock(&mouse.lk);
- break;
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
-}
-
-void
-mouseclose(Chan *c)
-{
- if(!(c->flag&COPEN))
- return;
-
- switch((long)c->qid.path) {
- case Qmouse:
- lock(&mouse.lk);
- mouse.open = 0;
- unlock(&mouse.lk);
- cursorarrow();
- }
-}
-
-
-long
-mouseread(Chan *c, void *va, long n, vlong offset)
-{
- char buf[4*12+1];
- uchar *p;
- int i, nn;
- ulong msec;
-/* static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; */
-
- p = va;
- switch((long)c->qid.path){
- case Qdir:
- return devdirread(c, va, n, mousedir, NMOUSE, devgen);
-
- case Qcursor:
- if(offset != 0)
- return 0;
- if(n < 2*4+2*2*16)
- error(Eshort);
- n = 2*4+2*2*16;
- lock(&cursor.lk);
- BPLONG(p+0, cursor.offset.x);
- BPLONG(p+4, cursor.offset.y);
- memmove(p+8, cursor.clr, 2*16);
- memmove(p+40, cursor.set, 2*16);
- unlock(&cursor.lk);
- return n;
-
- case Qmouse:
- while(mousechanged(0) == 0)
- sleep(&mouse.r, mousechanged, 0);
-
- lock(&screen.lk);
- if(screen.reshaped) {
- screen.reshaped = 0;
- sprint(buf, "t%11d %11d", 0, ticks());
- if(n > 1+2*12)
- n = 1+2*12;
- memmove(va, buf, n);
- unlock(&screen.lk);
- return n;
- }
- unlock(&screen.lk);
-
- lock(&mouse.lk);
- i = mouse.ri;
- nn = (mouse.wi + Mousequeue - i) % Mousequeue;
- if(nn < 1)
- panic("empty mouse queue");
- msec = ticks();
- while(nn > 1) {
- if(mouse.queue[i].msec + Mousewindow > msec)
- break;
- i = (i+1)%Mousequeue;
- nn--;
- }
- sprint(buf, "m%11d %11d %11d %11d",
- mouse.queue[i].xy.x,
- mouse.queue[i].xy.y,
- mouse.queue[i].buttons,
- mouse.queue[i].msec);
- mouse.ri = (i+1)%Mousequeue;
- unlock(&mouse.lk);
- if(n > 1+4*12)
- n = 1+4*12;
- memmove(va, buf, n);
- return n;
- }
- return 0;
-}
-
-long
-mousewrite(Chan *c, void *va, long n, vlong offset)
-{
- char *p;
- Point pt;
- char buf[64];
-
- USED(offset);
-
- p = va;
- switch((long)c->qid.path){
- case Qdir:
- error(Eisdir);
-
- case Qcursor:
- if(n < 2*4+2*2*16){
- cursorarrow();
- }else{
- n = 2*4+2*2*16;
- lock(&cursor.lk);
- cursor.offset.x = BGLONG(p+0);
- cursor.offset.y = BGLONG(p+4);
- memmove(cursor.clr, p+8, 2*16);
- memmove(cursor.set, p+40, 2*16);
- unlock(&cursor.lk);
- setcursor();
- }
- return n;
-
- case Qmouse:
- if(n > sizeof buf-1)
- n = sizeof buf -1;
- memmove(buf, va, n);
- buf[n] = 0;
- p = 0;
- pt.x = strtoul(buf+1, &p, 0);
- if(p == 0)
- error(Eshort);
- pt.y = strtoul(p, 0, 0);
- if(ptinrect(pt, gscreen->r))
- mouseset(pt);
- return n;
- }
-
- error(Egreg);
- return -1;
-}
-
-int
-mousechanged(void *a)
-{
- USED(a);
-
- return mouse.ri != mouse.wi || screen.reshaped;
-}
-
-Dev mousedevtab = {
- 'm',
- "mouse",
-
- devreset,
- devinit,
- devshutdown,
- mouseattach,
- mousewalk,
- mousestat,
- mouseopen,
- devcreate,
- mouseclose,
- mouseread,
- devbread,
- mousewrite,
- devbwrite,
- devremove,
- devwstat,
-};
-
diff --git a/sys/src/cmd/unix/drawterm/kern/devpipe.c b/sys/src/cmd/unix/drawterm/kern/devpipe.c
deleted file mode 100644
index 73401f99f..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devpipe.c
+++ /dev/null
@@ -1,398 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "netif.h"
-
-typedef struct Pipe Pipe;
-struct Pipe
-{
- QLock lk;
- Pipe *next;
- int ref;
- ulong path;
- Queue *q[2];
- int qref[2];
-};
-
-struct
-{
- Lock lk;
- ulong path;
-} pipealloc;
-
-enum
-{
- Qdir,
- Qdata0,
- Qdata1,
-};
-
-Dirtab pipedir[] =
-{
- ".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
- "data", {Qdata0}, 0, 0600,
- "data1", {Qdata1}, 0, 0600,
-};
-#define NPIPEDIR 3
-
-static void
-pipeinit(void)
-{
- if(conf.pipeqsize == 0){
- if(conf.nmach > 1)
- conf.pipeqsize = 256*1024;
- else
- conf.pipeqsize = 32*1024;
- }
-}
-
-/*
- * create a pipe, no streams are created until an open
- */
-static Chan*
-pipeattach(char *spec)
-{
- Pipe *p;
- Chan *c;
-
- c = devattach('|', spec);
- p = malloc(sizeof(Pipe));
- if(p == 0)
- exhausted("memory");
- p->ref = 1;
-
- p->q[0] = qopen(conf.pipeqsize, 0, 0, 0);
- if(p->q[0] == 0){
- free(p);
- exhausted("memory");
- }
- p->q[1] = qopen(conf.pipeqsize, 0, 0, 0);
- if(p->q[1] == 0){
- free(p->q[0]);
- free(p);
- exhausted("memory");
- }
-
- lock(&pipealloc.lk);
- p->path = ++pipealloc.path;
- unlock(&pipealloc.lk);
-
- mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
- c->aux = p;
- c->dev = 0;
- return c;
-}
-
-static int
-pipegen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
-{
- Qid q;
- int len;
- Pipe *p;
-
- USED(name);
-
- if(i == DEVDOTDOT){
- devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp);
- return 1;
- }
- i++; /* skip . */
- if(tab==0 || i>=ntab)
- return -1;
-
- tab += i;
- p = c->aux;
- switch((ulong)tab->qid.path){
- case Qdata0:
- len = qlen(p->q[0]);
- break;
- case Qdata1:
- len = qlen(p->q[1]);
- break;
- default:
- len = tab->length;
- break;
- }
- mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
- devdir(c, q, tab->name, len, eve, tab->perm, dp);
- return 1;
-}
-
-
-static Walkqid*
-pipewalk(Chan *c, Chan *nc, char **name, int nname)
-{
- Walkqid *wq;
- Pipe *p;
-
- wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen);
- if(wq != nil && wq->clone != nil && wq->clone != c){
- p = c->aux;
- qlock(&p->lk);
- p->ref++;
- if(c->flag & COPEN){
- print("channel open in pipewalk\n");
- switch(NETTYPE(c->qid.path)){
- case Qdata0:
- p->qref[0]++;
- break;
- case Qdata1:
- p->qref[1]++;
- break;
- }
- }
- qunlock(&p->lk);
- }
- return wq;
-}
-
-static int
-pipestat(Chan *c, uchar *db, int n)
-{
- Pipe *p;
- Dir dir;
-
- p = c->aux;
-
- switch(NETTYPE(c->qid.path)){
- case Qdir:
- devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
- break;
- case Qdata0:
- devdir(c, c->qid, "data", qlen(p->q[0]), eve, 0600, &dir);
- break;
- case Qdata1:
- devdir(c, c->qid, "data1", qlen(p->q[1]), eve, 0600, &dir);
- break;
- default:
- panic("pipestat");
- }
- n = convD2M(&dir, db, n);
- if(n < BIT16SZ)
- error(Eshortstat);
- return n;
-}
-
-/*
- * if the stream doesn't exist, create it
- */
-static Chan*
-pipeopen(Chan *c, int omode)
-{
- Pipe *p;
-
- if(c->qid.type & QTDIR){
- if(omode != OREAD)
- error(Ebadarg);
- c->mode = omode;
- c->flag |= COPEN;
- c->offset = 0;
- return c;
- }
-
- p = c->aux;
- qlock(&p->lk);
- switch(NETTYPE(c->qid.path)){
- case Qdata0:
- p->qref[0]++;
- break;
- case Qdata1:
- p->qref[1]++;
- break;
- }
- qunlock(&p->lk);
-
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- c->iounit = qiomaxatomic;
- return c;
-}
-
-static void
-pipeclose(Chan *c)
-{
- Pipe *p;
-
- p = c->aux;
- qlock(&p->lk);
-
- if(c->flag & COPEN){
- /*
- * closing either side hangs up the stream
- */
- switch(NETTYPE(c->qid.path)){
- case Qdata0:
- p->qref[0]--;
- if(p->qref[0] == 0){
- qhangup(p->q[1], 0);
- qclose(p->q[0]);
- }
- break;
- case Qdata1:
- p->qref[1]--;
- if(p->qref[1] == 0){
- qhangup(p->q[0], 0);
- qclose(p->q[1]);
- }
- break;
- }
- }
-
-
- /*
- * if both sides are closed, they are reusable
- */
- if(p->qref[0] == 0 && p->qref[1] == 0){
- qreopen(p->q[0]);
- qreopen(p->q[1]);
- }
-
- /*
- * free the structure on last close
- */
- p->ref--;
- if(p->ref == 0){
- qunlock(&p->lk);
- free(p->q[0]);
- free(p->q[1]);
- free(p);
- } else
- qunlock(&p->lk);
-}
-
-static long
-piperead(Chan *c, void *va, long n, vlong offset)
-{
- Pipe *p;
-
- USED(offset);
-
- p = c->aux;
-
- switch(NETTYPE(c->qid.path)){
- case Qdir:
- return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
- case Qdata0:
- return qread(p->q[0], va, n);
- case Qdata1:
- return qread(p->q[1], va, n);
- default:
- panic("piperead");
- }
- return -1; /* not reached */
-}
-
-static Block*
-pipebread(Chan *c, long n, ulong offset)
-{
- Pipe *p;
-
- p = c->aux;
-
- switch(NETTYPE(c->qid.path)){
- case Qdata0:
- return qbread(p->q[0], n);
- case Qdata1:
- return qbread(p->q[1], n);
- }
-
- return devbread(c, n, offset);
-}
-
-/*
- * a write to a closed pipe causes a note to be sent to
- * the process.
- */
-static long
-pipewrite(Chan *c, void *va, long n, vlong offset)
-{
- Pipe *p;
-
- USED(offset);
- if(!islo())
- print("pipewrite hi %lux\n", getcallerpc(&c));
-
- if(waserror()) {
- /* avoid notes when pipe is a mounted queue */
- if((c->flag & CMSG) == 0)
- postnote(up, 1, "sys: write on closed pipe", NUser);
- nexterror();
- }
-
- p = c->aux;
-
- switch(NETTYPE(c->qid.path)){
- case Qdata0:
- n = qwrite(p->q[1], va, n);
- break;
-
- case Qdata1:
- n = qwrite(p->q[0], va, n);
- break;
-
- default:
- panic("pipewrite");
- }
-
- poperror();
- return n;
-}
-
-static long
-pipebwrite(Chan *c, Block *bp, ulong offset)
-{
- long n;
- Pipe *p;
-
- USED(offset);
-
- if(waserror()) {
- /* avoid notes when pipe is a mounted queue */
- if((c->flag & CMSG) == 0)
- postnote(up, 1, "sys: write on closed pipe", NUser);
- nexterror();
- }
-
- p = c->aux;
- switch(NETTYPE(c->qid.path)){
- case Qdata0:
- n = qbwrite(p->q[1], bp);
- break;
-
- case Qdata1:
- n = qbwrite(p->q[0], bp);
- break;
-
- default:
- n = 0;
- panic("pipebwrite");
- }
-
- poperror();
- return n;
-}
-
-Dev pipedevtab = {
- '|',
- "pipe",
-
- devreset,
- pipeinit,
- devshutdown,
- pipeattach,
- pipewalk,
- pipestat,
- pipeopen,
- devcreate,
- pipeclose,
- piperead,
- pipebread,
- pipewrite,
- pipebwrite,
- devremove,
- devwstat,
-};
diff --git a/sys/src/cmd/unix/drawterm/kern/devroot.c b/sys/src/cmd/unix/drawterm/kern/devroot.c
deleted file mode 100644
index db081ff1f..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devroot.c
+++ /dev/null
@@ -1,299 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-enum
-{
- Qdir = 0,
- Qboot = 0x1000,
- Qmnt = 0x2000,
- Qfactotum,
-
- Nrootfiles = 32,
- Nbootfiles = 32,
- Nmntfiles = 2,
-};
-
-typedef struct Dirlist Dirlist;
-struct Dirlist
-{
- uint base;
- Dirtab *dir;
- uchar **data;
- int ndir;
- int mdir;
-};
-
-static Dirtab rootdir[Nrootfiles] = {
- "#/", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
- "boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555,
- "mnt", {Qmnt, 0, QTDIR}, 0, DMDIR|0555,
-};
-static uchar *rootdata[Nrootfiles];
-static Dirlist rootlist =
-{
- 0,
- rootdir,
- rootdata,
- 3,
- Nrootfiles
-};
-
-static Dirtab bootdir[Nbootfiles] = {
- "boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555,
-};
-static uchar *bootdata[Nbootfiles];
-static Dirlist bootlist =
-{
- Qboot,
- bootdir,
- bootdata,
- 1,
- Nbootfiles
-};
-
-static uchar *mntdata[Nmntfiles];
-static Dirtab mntdir[Nmntfiles] = {
- "mnt", {Qmnt, 0, QTDIR}, 0, DMDIR|0555,
- "factotum", {Qfactotum, 0, QTDIR}, 0, DMDIR|0555,
-};
-static Dirlist mntlist =
-{
- Qmnt,
- mntdir,
- mntdata,
- 2,
- Nmntfiles
-};
-
-/*
- * add a file to the list
- */
-static void
-addlist(Dirlist *l, char *name, uchar *contents, ulong len, int perm)
-{
- Dirtab *d;
-
- if(l->ndir >= l->mdir)
- panic("too many root files");
- l->data[l->ndir] = contents;
- d = &l->dir[l->ndir];
- strcpy(d->name, name);
- d->length = len;
- d->perm = perm;
- d->qid.type = 0;
- d->qid.vers = 0;
- d->qid.path = ++l->ndir + l->base;
- if(perm & DMDIR)
- d->qid.type |= QTDIR;
-}
-
-/*
- * add a root file
- */
-void
-addbootfile(char *name, uchar *contents, ulong len)
-{
- addlist(&bootlist, name, contents, len, 0555);
-}
-
-/*
- * add a root directory
- */
-static void
-addrootdir(char *name)
-{
- addlist(&rootlist, name, nil, 0, DMDIR|0555);
-}
-
-static void
-rootreset(void)
-{
- addrootdir("bin");
- addrootdir("dev");
- addrootdir("env");
- addrootdir("fd");
- addrootdir("net");
- addrootdir("net.alt");
- addrootdir("proc");
- addrootdir("root");
- addrootdir("srv");
-}
-
-static Chan*
-rootattach(char *spec)
-{
- return devattach('/', spec);
-}
-
-static int
-rootgen(Chan *c, char *name, Dirtab *dirt, int ndirt, int s, Dir *dp)
-{
- int t;
- Dirtab *d;
- Dirlist *l;
-
- USED(dirt);
- USED(ndirt);
-
- switch((int)c->qid.path){
- case Qdir:
- if(s == DEVDOTDOT){
- Qid tqiddir = {Qdir, 0, QTDIR};
- devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
- return 1;
- }
- return devgen(c, name, rootlist.dir, rootlist.ndir, s, dp);
- case Qmnt:
- if(s == DEVDOTDOT){
- Qid tqiddir = {Qdir, 0, QTDIR};
- devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
- return 1;
- }
- return devgen(c, name, mntlist.dir, mntlist.ndir, s, dp);
- case Qboot:
- if(s == DEVDOTDOT){
- Qid tqiddir = {Qdir, 0, QTDIR};
- devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
- return 1;
- }
- return devgen(c, name, bootlist.dir, bootlist.ndir, s, dp);
- default:
- if(s == DEVDOTDOT){
- Qid tqiddir = {Qdir, 0, QTDIR};
- tqiddir.path = c->qid.path&0xF000;
- devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
- return 1;
- }
- if(s != 0)
- return -1;
- switch((int)c->qid.path & 0xF000){
- case Qdir:
- t = c->qid.path-1;
- l = &rootlist;
- break;
- case Qboot:
- t = c->qid.path - Qboot - 1;
- l = &bootlist;
- break;
- case Qmnt:
- t = c->qid.path - Qmnt - 1;
- l = &mntlist;
- break;
- default:
- return -1;
- }
- if(t >= l->ndir)
- return -1;
-if(t < 0){
-print("rootgen %llud %d %d\n", c->qid.path, s, t);
-panic("whoops");
-}
- d = &l->dir[t];
- devdir(c, d->qid, d->name, d->length, eve, d->perm, dp);
- return 1;
- }
- return -1;
-}
-
-static Walkqid*
-rootwalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name, nname, nil, 0, rootgen);
-}
-
-static int
-rootstat(Chan *c, uchar *dp, int n)
-{
- return devstat(c, dp, n, nil, 0, rootgen);
-}
-
-static Chan*
-rootopen(Chan *c, int omode)
-{
- return devopen(c, omode, nil, 0, devgen);
-}
-
-/*
- * sysremove() knows this is a nop
- */
-static void
-rootclose(Chan *c)
-{
- USED(c);
-}
-
-static long
-rootread(Chan *c, void *buf, long n, vlong off)
-{
- ulong t;
- Dirtab *d;
- Dirlist *l;
- uchar *data;
- ulong offset = off;
-
- t = c->qid.path;
- switch(t){
- case Qdir:
- case Qboot:
- case Qmnt:
- return devdirread(c, buf, n, nil, 0, rootgen);
- }
-
- if(t&Qboot)
- l = &bootlist;
- else if(t&Qmnt)
- l = &mntlist;
- else
- l = &bootlist;
- t &= 0xFFF;
- t--;
-
- if(t >= l->ndir)
- error(Egreg);
-
- d = &l->dir[t];
- data = l->data[t];
- if(offset >= d->length)
- return 0;
- if(offset+n > d->length)
- n = d->length - offset;
- memmove(buf, data+offset, n);
- return n;
-}
-
-static long
-rootwrite(Chan *c, void *v, long n, vlong o)
-{
- USED(c);
- USED(v);
- USED(n);
- USED(o);
-
- error(Egreg);
- return 0;
-}
-
-Dev rootdevtab = {
- '/',
- "root",
-
- rootreset,
- devinit,
- devshutdown,
- rootattach,
- rootwalk,
- rootstat,
- rootopen,
- devcreate,
- rootclose,
- rootread,
- devbread,
- rootwrite,
- devbwrite,
- devremove,
- devwstat,
-};
-
diff --git a/sys/src/cmd/unix/drawterm/kern/devssl.c b/sys/src/cmd/unix/drawterm/kern/devssl.c
deleted file mode 100644
index 3ad021f9f..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devssl.c
+++ /dev/null
@@ -1,1517 +0,0 @@
-/*
- * devssl - secure sockets layer
- */
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "libsec.h"
-
-#define NOSPOOKS 1
-
-typedef struct OneWay OneWay;
-struct OneWay
-{
- QLock q;
- QLock ctlq;
-
- void *state; /* encryption state */
- int slen; /* hash data length */
- uchar *secret; /* secret */
- ulong mid; /* message id */
-};
-
-enum
-{
- /* connection states */
- Sincomplete= 0,
- Sclear= 1,
- Sencrypting= 2,
- Sdigesting= 4,
- Sdigenc= Sencrypting|Sdigesting,
-
- /* encryption algorithms */
- Noencryption= 0,
- DESCBC= 1,
- DESECB= 2,
- RC4= 3
-};
-
-typedef struct Dstate Dstate;
-struct Dstate
-{
- Chan *c; /* io channel */
- uchar state; /* state of connection */
- int ref; /* serialized by dslock for atomic destroy */
-
- uchar encryptalg; /* encryption algorithm */
- ushort blocklen; /* blocking length */
-
- ushort diglen; /* length of digest */
- DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */
-
- /* for SSL format */
- int max; /* maximum unpadded data per msg */
- int maxpad; /* maximum padded data per msg */
-
- /* input side */
- OneWay in;
- Block *processed;
- Block *unprocessed;
-
- /* output side */
- OneWay out;
-
- /* protections */
- char *user;
- int perm;
-};
-
-enum
-{
- Maxdmsg= 1<<16,
- Maxdstate= 128, /* must be a power of 2 */
-};
-
-Lock dslock;
-int dshiwat;
-char *dsname[Maxdstate];
-Dstate *dstate[Maxdstate];
-char *encalgs;
-char *hashalgs;
-
-enum{
- Qtopdir = 1, /* top level directory */
- Qprotodir,
- Qclonus,
- Qconvdir, /* directory for a conversation */
- Qdata,
- Qctl,
- Qsecretin,
- Qsecretout,
- Qencalgs,
- Qhashalgs,
-};
-
-#define TYPE(x) ((x).path & 0xf)
-#define CONV(x) (((x).path >> 5)&(Maxdstate-1))
-#define QID(c, y) (((c)<<5) | (y))
-
-static void ensure(Dstate*, Block**, int);
-static void consume(Block**, uchar*, int);
-static void setsecret(OneWay*, uchar*, int);
-static Block* encryptb(Dstate*, Block*, int);
-static Block* decryptb(Dstate*, Block*);
-static Block* digestb(Dstate*, Block*, int);
-static void checkdigestb(Dstate*, Block*);
-static Chan* buftochan(char*);
-static void sslhangup(Dstate*);
-static Dstate* dsclone(Chan *c);
-static void dsnew(Chan *c, Dstate **);
-static long sslput(Dstate *s, Block * volatile b);
-
-char *sslnames[] = {
- /* unused */ 0,
- /* topdir */ 0,
- /* protodir */ 0,
- "clone",
- /* convdir */ 0,
- "data",
- "ctl",
- "secretin",
- "secretout",
- "encalgs",
- "hashalgs",
-};
-
-static int
-sslgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp)
-{
- Qid q;
- Dstate *ds;
- char name[16], *p, *nm;
- int ft;
-
- USED(n);
- USED(nd);
- USED(d);
-
- q.type = QTFILE;
- q.vers = 0;
-
- ft = TYPE(c->qid);
- switch(ft) {
- case Qtopdir:
- if(s == DEVDOTDOT){
- q.path = QID(0, Qtopdir);
- q.type = QTDIR;
- devdir(c, q, "#D", 0, eve, 0555, dp);
- return 1;
- }
- if(s > 0)
- return -1;
- q.path = QID(0, Qprotodir);
- q.type = QTDIR;
- devdir(c, q, "ssl", 0, eve, 0555, dp);
- return 1;
- case Qprotodir:
- if(s == DEVDOTDOT){
- q.path = QID(0, Qtopdir);
- q.type = QTDIR;
- devdir(c, q, ".", 0, eve, 0555, dp);
- return 1;
- }
- if(s < dshiwat) {
- q.path = QID(s, Qconvdir);
- q.type = QTDIR;
- ds = dstate[s];
- if(ds != 0)
- nm = ds->user;
- else
- nm = eve;
- if(dsname[s] == nil){
- sprint(name, "%d", s);
- kstrdup(&dsname[s], name);
- }
- devdir(c, q, dsname[s], 0, nm, 0555, dp);
- return 1;
- }
- if(s > dshiwat)
- return -1;
- q.path = QID(0, Qclonus);
- devdir(c, q, "clone", 0, eve, 0555, dp);
- return 1;
- case Qconvdir:
- if(s == DEVDOTDOT){
- q.path = QID(0, Qprotodir);
- q.type = QTDIR;
- devdir(c, q, "ssl", 0, eve, 0555, dp);
- return 1;
- }
- ds = dstate[CONV(c->qid)];
- if(ds != 0)
- nm = ds->user;
- else
- nm = eve;
- switch(s) {
- default:
- return -1;
- case 0:
- q.path = QID(CONV(c->qid), Qctl);
- p = "ctl";
- break;
- case 1:
- q.path = QID(CONV(c->qid), Qdata);
- p = "data";
- break;
- case 2:
- q.path = QID(CONV(c->qid), Qsecretin);
- p = "secretin";
- break;
- case 3:
- q.path = QID(CONV(c->qid), Qsecretout);
- p = "secretout";
- break;
- case 4:
- q.path = QID(CONV(c->qid), Qencalgs);
- p = "encalgs";
- break;
- case 5:
- q.path = QID(CONV(c->qid), Qhashalgs);
- p = "hashalgs";
- break;
- }
- devdir(c, q, p, 0, nm, 0660, dp);
- return 1;
- case Qclonus:
- devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
- return 1;
- default:
- ds = dstate[CONV(c->qid)];
- if(ds != 0)
- nm = ds->user;
- else
- nm = eve;
- devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
- return 1;
- }
- return -1;
-}
-
-static Chan*
-sslattach(char *spec)
-{
- Chan *c;
-
- c = devattach('D', spec);
- c->qid.path = QID(0, Qtopdir);
- c->qid.vers = 0;
- c->qid.type = QTDIR;
- return c;
-}
-
-static Walkqid*
-sslwalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name, nname, nil, 0, sslgen);
-}
-
-static int
-sslstat(Chan *c, uchar *db, int n)
-{
- return devstat(c, db, n, nil, 0, sslgen);
-}
-
-static Chan*
-sslopen(Chan *c, int omode)
-{
- Dstate *s, **pp;
- int perm;
- int ft;
-
- perm = 0;
- omode &= 3;
- switch(omode) {
- case OREAD:
- perm = 4;
- break;
- case OWRITE:
- perm = 2;
- break;
- case ORDWR:
- perm = 6;
- break;
- }
-
- ft = TYPE(c->qid);
- switch(ft) {
- default:
- panic("sslopen");
- case Qtopdir:
- case Qprotodir:
- case Qconvdir:
- if(omode != OREAD)
- error(Eperm);
- break;
- case Qclonus:
- s = dsclone(c);
- if(s == 0)
- error(Enodev);
- break;
- case Qctl:
- case Qdata:
- case Qsecretin:
- case Qsecretout:
- if(waserror()) {
- unlock(&dslock);
- nexterror();
- }
- lock(&dslock);
- pp = &dstate[CONV(c->qid)];
- s = *pp;
- if(s == 0)
- dsnew(c, pp);
- else {
- if((perm & (s->perm>>6)) != perm
- && (strcmp(up->user, s->user) != 0
- || (perm & s->perm) != perm))
- error(Eperm);
-
- s->ref++;
- }
- unlock(&dslock);
- poperror();
- break;
- case Qencalgs:
- case Qhashalgs:
- if(omode != OREAD)
- error(Eperm);
- break;
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
-}
-
-static int
-sslwstat(Chan *c, uchar *db, int n)
-{
- Dir *dir;
- Dstate *s;
- int m;
-
- s = dstate[CONV(c->qid)];
- if(s == 0)
- error(Ebadusefd);
- if(strcmp(s->user, up->user) != 0)
- error(Eperm);
-
- dir = smalloc(sizeof(Dir)+n);
- m = convM2D(db, n, &dir[0], (char*)&dir[1]);
- if(m == 0){
- free(dir);
- error(Eshortstat);
- }
-
- if(!emptystr(dir->uid))
- kstrdup(&s->user, dir->uid);
- if(dir->mode != ~0)
- s->perm = dir->mode;
-
- free(dir);
- return m;
-}
-
-static void
-sslclose(Chan *c)
-{
- Dstate *s;
- int ft;
-
- ft = TYPE(c->qid);
- switch(ft) {
- case Qctl:
- case Qdata:
- case Qsecretin:
- case Qsecretout:
- if((c->flag & COPEN) == 0)
- break;
-
- s = dstate[CONV(c->qid)];
- if(s == 0)
- break;
-
- lock(&dslock);
- if(--s->ref > 0) {
- unlock(&dslock);
- break;
- }
- dstate[CONV(c->qid)] = 0;
- unlock(&dslock);
-
- if(s->user != nil)
- free(s->user);
- sslhangup(s);
- if(s->c)
- cclose(s->c);
- if(s->in.secret)
- free(s->in.secret);
- if(s->out.secret)
- free(s->out.secret);
- if(s->in.state)
- free(s->in.state);
- if(s->out.state)
- free(s->out.state);
- free(s);
-
- }
-}
-
-/*
- * make sure we have at least 'n' bytes in list 'l'
- */
-static void
-ensure(Dstate *s, Block **l, int n)
-{
- int sofar, i;
- Block *b, *bl;
-
- sofar = 0;
- for(b = *l; b; b = b->next){
- sofar += BLEN(b);
- if(sofar >= n)
- return;
- l = &b->next;
- }
-
- while(sofar < n){
- bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
- if(bl == 0)
- nexterror();
- *l = bl;
- i = 0;
- for(b = bl; b; b = b->next){
- i += BLEN(b);
- l = &b->next;
- }
- if(i == 0)
- error(Ehungup);
- sofar += i;
- }
-}
-
-/*
- * copy 'n' bytes from 'l' into 'p' and free
- * the bytes in 'l'
- */
-static void
-consume(Block **l, uchar *p, int n)
-{
- Block *b;
- int i;
-
- for(; *l && n > 0; n -= i){
- b = *l;
- i = BLEN(b);
- if(i > n)
- i = n;
- memmove(p, b->rp, i);
- b->rp += i;
- p += i;
- if(BLEN(b) < 0)
- panic("consume");
- if(BLEN(b))
- break;
- *l = b->next;
- freeb(b);
- }
-}
-
-/*
- * give back n bytes
-static void
-regurgitate(Dstate *s, uchar *p, int n)
-{
- Block *b;
-
- if(n <= 0)
- return;
- b = s->unprocessed;
- if(s->unprocessed == nil || b->rp - b->base < n) {
- b = allocb(n);
- memmove(b->wp, p, n);
- b->wp += n;
- b->next = s->unprocessed;
- s->unprocessed = b;
- } else {
- b->rp -= n;
- memmove(b->rp, p, n);
- }
-}
- */
-
-/*
- * remove at most n bytes from the queue, if discard is set
- * dump the remainder
- */
-static Block*
-qtake(Block **l, int n, int discard)
-{
- Block *nb, *b, *first;
- int i;
-
- first = *l;
- for(b = first; b; b = b->next){
- i = BLEN(b);
- if(i == n){
- if(discard){
- freeblist(b->next);
- *l = 0;
- } else
- *l = b->next;
- b->next = 0;
- return first;
- } else if(i > n){
- i -= n;
- if(discard){
- freeblist(b->next);
- b->wp -= i;
- *l = 0;
- } else {
- nb = allocb(i);
- memmove(nb->wp, b->rp+n, i);
- nb->wp += i;
- b->wp -= i;
- nb->next = b->next;
- *l = nb;
- }
- b->next = 0;
- if(BLEN(b) < 0)
- panic("qtake");
- return first;
- } else
- n -= i;
- if(BLEN(b) < 0)
- panic("qtake");
- }
- *l = 0;
- return first;
-}
-
-/*
- * We can't let Eintr's lose data since the program
- * doing the read may be able to handle it. The only
- * places Eintr is possible is during the read's in consume.
- * Therefore, we make sure we can always put back the bytes
- * consumed before the last ensure.
- */
-static Block*
-sslbread(Chan *c, long n, ulong o)
-{
- Dstate * volatile s;
- Block *b;
- uchar consumed[3], *p;
- int toconsume;
- int len, pad;
-
- USED(o);
- s = dstate[CONV(c->qid)];
- if(s == 0)
- panic("sslbread");
- if(s->state == Sincomplete)
- error(Ebadusefd);
-
- qlock(&s->in.q);
- if(waserror()){
- qunlock(&s->in.q);
- nexterror();
- }
-
- if(s->processed == 0){
- /*
- * Read in the whole message. Until we've got it all,
- * it stays on s->unprocessed, so that if we get Eintr,
- * we'll pick up where we left off.
- */
- ensure(s, &s->unprocessed, 3);
- s->unprocessed = pullupblock(s->unprocessed, 2);
- p = s->unprocessed->rp;
- if(p[0] & 0x80){
- len = ((p[0] & 0x7f)<<8) | p[1];
- ensure(s, &s->unprocessed, len);
- pad = 0;
- toconsume = 2;
- } else {
- s->unprocessed = pullupblock(s->unprocessed, 3);
- len = ((p[0] & 0x3f)<<8) | p[1];
- pad = p[2];
- if(pad > len){
- print("pad %d buf len %d\n", pad, len);
- error("bad pad in ssl message");
- }
- toconsume = 3;
- }
- ensure(s, &s->unprocessed, toconsume+len);
-
- /* skip header */
- consume(&s->unprocessed, consumed, toconsume);
-
- /* grab the next message and decode/decrypt it */
- b = qtake(&s->unprocessed, len, 0);
-
- if(blocklen(b) != len)
- print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);
-
- if(waserror()){
- qunlock(&s->in.ctlq);
- if(b != nil)
- freeb(b);
- nexterror();
- }
- qlock(&s->in.ctlq);
- switch(s->state){
- case Sencrypting:
- if(b == nil)
- error("ssl message too short (encrypting)");
- b = decryptb(s, b);
- break;
- case Sdigesting:
- b = pullupblock(b, s->diglen);
- if(b == nil)
- error("ssl message too short (digesting)");
- checkdigestb(s, b);
- pullblock(&b, s->diglen);
- len -= s->diglen;
- break;
- case Sdigenc:
- b = decryptb(s, b);
- b = pullupblock(b, s->diglen);
- if(b == nil)
- error("ssl message too short (dig+enc)");
- checkdigestb(s, b);
- pullblock(&b, s->diglen);
- len -= s->diglen;
- break;
- }
-
- /* remove pad */
- if(pad)
- s->processed = qtake(&b, len - pad, 1);
- else
- s->processed = b;
- b = nil;
- s->in.mid++;
- qunlock(&s->in.ctlq);
- poperror();
- }
-
- /* return at most what was asked for */
- b = qtake(&s->processed, n, 0);
-
- qunlock(&s->in.q);
- poperror();
-
- return b;
-}
-
-static long
-sslread(Chan *c, void *a, long n, vlong off)
-{
- Block * volatile b;
- Block *nb;
- uchar *va;
- int i;
- char buf[128];
- ulong offset = off;
- int ft;
-
- if(c->qid.type & QTDIR)
- return devdirread(c, a, n, 0, 0, sslgen);
-
- ft = TYPE(c->qid);
- switch(ft) {
- default:
- error(Ebadusefd);
- case Qctl:
- ft = CONV(c->qid);
- sprint(buf, "%d", ft);
- return readstr(offset, a, n, buf);
- case Qdata:
- b = sslbread(c, n, offset);
- break;
- case Qencalgs:
- return readstr(offset, a, n, encalgs);
- break;
- case Qhashalgs:
- return readstr(offset, a, n, hashalgs);
- break;
- }
-
- if(waserror()){
- freeblist(b);
- nexterror();
- }
-
- n = 0;
- va = a;
- for(nb = b; nb; nb = nb->next){
- i = BLEN(nb);
- memmove(va+n, nb->rp, i);
- n += i;
- }
-
- freeblist(b);
- poperror();
-
- return n;
-}
-
-/*
- * this algorithm doesn't have to be great since we're just
- * trying to obscure the block fill
- */
-static void
-randfill(uchar *buf, int len)
-{
- while(len-- > 0)
- *buf++ = fastrand();
-}
-
-static long
-sslbwrite(Chan *c, Block *b, ulong o)
-{
- Dstate * volatile s;
- long rv;
-
- USED(o);
- s = dstate[CONV(c->qid)];
- if(s == nil)
- panic("sslbwrite");
-
- if(s->state == Sincomplete){
- freeb(b);
- error(Ebadusefd);
- }
-
- /* lock so split writes won't interleave */
- if(waserror()){
- qunlock(&s->out.q);
- nexterror();
- }
- qlock(&s->out.q);
-
- rv = sslput(s, b);
-
- poperror();
- qunlock(&s->out.q);
-
- return rv;
-}
-
-/*
- * use SSL record format, add in count, digest and/or encrypt.
- * the write is interruptable. if it is interrupted, we'll
- * get out of sync with the far side. not much we can do about
- * it since we don't know if any bytes have been written.
- */
-static long
-sslput(Dstate *s, Block * volatile b)
-{
- Block *nb;
- int h, n, m, pad, rv;
- uchar *p;
- int offset;
-
- if(waserror()){
-iprint("error: %s\n", up->errstr);
- if(b != nil)
- free(b);
- nexterror();
- }
-
- rv = 0;
- while(b != nil){
- m = n = BLEN(b);
- h = s->diglen + 2;
-
- /* trim to maximum block size */
- pad = 0;
- if(m > s->max){
- m = s->max;
- } else if(s->blocklen != 1){
- pad = (m + s->diglen)%s->blocklen;
- if(pad){
- if(m > s->maxpad){
- pad = 0;
- m = s->maxpad;
- } else {
- pad = s->blocklen - pad;
- h++;
- }
- }
- }
-
- rv += m;
- if(m != n){
- nb = allocb(m + h + pad);
- memmove(nb->wp + h, b->rp, m);
- nb->wp += m + h;
- b->rp += m;
- } else {
- /* add header space */
- nb = padblock(b, h);
- b = 0;
- }
- m += s->diglen;
-
- /* SSL style count */
- if(pad){
- nb = padblock(nb, -pad);
- randfill(nb->wp, pad);
- nb->wp += pad;
- m += pad;
-
- p = nb->rp;
- p[0] = (m>>8);
- p[1] = m;
- p[2] = pad;
- offset = 3;
- } else {
- p = nb->rp;
- p[0] = (m>>8) | 0x80;
- p[1] = m;
- offset = 2;
- }
-
- switch(s->state){
- case Sencrypting:
- nb = encryptb(s, nb, offset);
- break;
- case Sdigesting:
- nb = digestb(s, nb, offset);
- break;
- case Sdigenc:
- nb = digestb(s, nb, offset);
- nb = encryptb(s, nb, offset);
- break;
- }
-
- s->out.mid++;
-
- m = BLEN(nb);
- devtab[s->c->type]->bwrite(s->c, nb, s->c->offset);
- s->c->offset += m;
- }
-
- poperror();
- return rv;
-}
-
-static void
-setsecret(OneWay *w, uchar *secret, int n)
-{
- if(w->secret)
- free(w->secret);
-
- w->secret = smalloc(n);
- memmove(w->secret, secret, n);
- w->slen = n;
-}
-
-static void
-initDESkey(OneWay *w)
-{
- if(w->state){
- free(w->state);
- w->state = 0;
- }
-
- w->state = smalloc(sizeof(DESstate));
- if(w->slen >= 16)
- setupDESstate(w->state, w->secret, w->secret+8);
- else if(w->slen >= 8)
- setupDESstate(w->state, w->secret, 0);
- else
- error("secret too short");
-}
-
-/*
- * 40 bit DES is the same as 56 bit DES. However,
- * 16 bits of the key are masked to zero.
- */
-static void
-initDESkey_40(OneWay *w)
-{
- uchar key[8];
-
- if(w->state){
- free(w->state);
- w->state = 0;
- }
-
- if(w->slen >= 8){
- memmove(key, w->secret, 8);
- key[0] &= 0x0f;
- key[2] &= 0x0f;
- key[4] &= 0x0f;
- key[6] &= 0x0f;
- }
-
- w->state = malloc(sizeof(DESstate));
- if(w->slen >= 16)
- setupDESstate(w->state, key, w->secret+8);
- else if(w->slen >= 8)
- setupDESstate(w->state, key, 0);
- else
- error("secret too short");
-}
-
-static void
-initRC4key(OneWay *w)
-{
- if(w->state){
- free(w->state);
- w->state = 0;
- }
-
- w->state = smalloc(sizeof(RC4state));
- setupRC4state(w->state, w->secret, w->slen);
-}
-
-/*
- * 40 bit RC4 is the same as n-bit RC4. However,
- * we ignore all but the first 40 bits of the key.
- */
-static void
-initRC4key_40(OneWay *w)
-{
- if(w->state){
- free(w->state);
- w->state = 0;
- }
-
- if(w->slen > 5)
- w->slen = 5;
-
- w->state = malloc(sizeof(RC4state));
- setupRC4state(w->state, w->secret, w->slen);
-}
-
-/*
- * 128 bit RC4 is the same as n-bit RC4. However,
- * we ignore all but the first 128 bits of the key.
- */
-static void
-initRC4key_128(OneWay *w)
-{
- if(w->state){
- free(w->state);
- w->state = 0;
- }
-
- if(w->slen > 16)
- w->slen = 16;
-
- w->state = malloc(sizeof(RC4state));
- setupRC4state(w->state, w->secret, w->slen);
-}
-
-
-typedef struct Hashalg Hashalg;
-struct Hashalg
-{
- char *name;
- int diglen;
- DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
-};
-
-Hashalg hashtab[] =
-{
- { "md4", MD4dlen, md4, },
- { "md5", MD5dlen, md5, },
- { "sha1", SHA1dlen, sha1, },
- { "sha", SHA1dlen, sha1, },
- { 0 }
-};
-
-static int
-parsehashalg(char *p, Dstate *s)
-{
- Hashalg *ha;
-
- for(ha = hashtab; ha->name; ha++){
- if(strcmp(p, ha->name) == 0){
- s->hf = ha->hf;
- s->diglen = ha->diglen;
- s->state &= ~Sclear;
- s->state |= Sdigesting;
- return 0;
- }
- }
- return -1;
-}
-
-typedef struct Encalg Encalg;
-struct Encalg
-{
- char *name;
- int blocklen;
- int alg;
- void (*keyinit)(OneWay*);
-};
-
-#ifdef NOSPOOKS
-Encalg encrypttab[] =
-{
- { "descbc", 8, DESCBC, initDESkey, }, /* DEPRECATED -- use des_56_cbc */
- { "desecb", 8, DESECB, initDESkey, }, /* DEPRECATED -- use des_56_ecb */
- { "des_56_cbc", 8, DESCBC, initDESkey, },
- { "des_56_ecb", 8, DESECB, initDESkey, },
- { "des_40_cbc", 8, DESCBC, initDESkey_40, },
- { "des_40_ecb", 8, DESECB, initDESkey_40, },
- { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
- { "rc4_256", 1, RC4, initRC4key, },
- { "rc4_128", 1, RC4, initRC4key_128, },
- { "rc4_40", 1, RC4, initRC4key_40, },
- { 0 }
-};
-#else
-Encalg encrypttab[] =
-{
- { "des_40_cbc", 8, DESCBC, initDESkey_40, },
- { "des_40_ecb", 8, DESECB, initDESkey_40, },
- { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
- { "rc4_40", 1, RC4, initRC4key_40, },
- { 0 }
-};
-#endif /* NOSPOOKS */
-
-static int
-parseencryptalg(char *p, Dstate *s)
-{
- Encalg *ea;
-
- for(ea = encrypttab; ea->name; ea++){
- if(strcmp(p, ea->name) == 0){
- s->encryptalg = ea->alg;
- s->blocklen = ea->blocklen;
- (*ea->keyinit)(&s->in);
- (*ea->keyinit)(&s->out);
- s->state &= ~Sclear;
- s->state |= Sencrypting;
- return 0;
- }
- }
- return -1;
-}
-
-static long
-sslwrite(Chan *c, void *a, long n, vlong o)
-{
- Dstate * volatile s;
- Block * volatile b;
- int m, t;
- char *p, *np, *e, buf[128];
- uchar *x;
-
- USED(o);
- s = dstate[CONV(c->qid)];
- if(s == 0)
- panic("sslwrite");
-
- t = TYPE(c->qid);
- if(t == Qdata){
- if(s->state == Sincomplete)
- error(Ebadusefd);
-
- /* lock should a write gets split over multiple records */
- if(waserror()){
- qunlock(&s->out.q);
- nexterror();
- }
- qlock(&s->out.q);
- p = a;
-if(0) iprint("write %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n",
- n, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
- e = p + n;
- do {
- m = e - p;
- if(m > s->max)
- m = s->max;
-
- b = allocb(m);
- if(waserror()){
- freeb(b);
- nexterror();
- }
- memmove(b->wp, p, m);
- poperror();
- b->wp += m;
-
- sslput(s, b);
-
- p += m;
- } while(p < e);
- p = a;
-if(0) iprint("wrote %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n",
- n, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
- poperror();
- qunlock(&s->out.q);
- return n;
- }
-
- /* mutex with operations using what we're about to change */
- if(waserror()){
- qunlock(&s->in.ctlq);
- qunlock(&s->out.q);
- nexterror();
- }
- qlock(&s->in.ctlq);
- qlock(&s->out.q);
-
- switch(t){
- default:
- panic("sslwrite");
- case Qsecretin:
- setsecret(&s->in, a, n);
- goto out;
- case Qsecretout:
- setsecret(&s->out, a, n);
- goto out;
- case Qctl:
- break;
- }
-
- if(n >= sizeof(buf))
- error("arg too long");
- strncpy(buf, a, n);
- buf[n] = 0;
- p = strchr(buf, '\n');
- if(p)
- *p = 0;
- p = strchr(buf, ' ');
- if(p)
- *p++ = 0;
-
- if(strcmp(buf, "fd") == 0){
- s->c = buftochan(p);
-
- /* default is clear (msg delimiters only) */
- s->state = Sclear;
- s->blocklen = 1;
- s->diglen = 0;
- s->maxpad = s->max = (1<<15) - s->diglen - 1;
- s->in.mid = 0;
- s->out.mid = 0;
- } else if(strcmp(buf, "alg") == 0 && p != 0){
- s->blocklen = 1;
- s->diglen = 0;
-
- if(s->c == 0)
- error("must set fd before algorithm");
-
- s->state = Sclear;
- s->maxpad = s->max = (1<<15) - s->diglen - 1;
- if(strcmp(p, "clear") == 0){
- goto out;
- }
-
- if(s->in.secret && s->out.secret == 0)
- setsecret(&s->out, s->in.secret, s->in.slen);
- if(s->out.secret && s->in.secret == 0)
- setsecret(&s->in, s->out.secret, s->out.slen);
- if(s->in.secret == 0 || s->out.secret == 0)
- error("algorithm but no secret");
-
- s->hf = 0;
- s->encryptalg = Noencryption;
- s->blocklen = 1;
-
- for(;;){
- np = strchr(p, ' ');
- if(np)
- *np++ = 0;
-
- if(parsehashalg(p, s) < 0)
- if(parseencryptalg(p, s) < 0)
- error("bad algorithm");
-
- if(np == 0)
- break;
- p = np;
- }
-
- if(s->hf == 0 && s->encryptalg == Noencryption)
- error("bad algorithm");
-
- if(s->blocklen != 1){
- s->max = (1<<15) - s->diglen - 1;
- s->max -= s->max % s->blocklen;
- s->maxpad = (1<<14) - s->diglen - 1;
- s->maxpad -= s->maxpad % s->blocklen;
- } else
- s->maxpad = s->max = (1<<15) - s->diglen - 1;
- } else if(strcmp(buf, "secretin") == 0 && p != 0) {
- m = (strlen(p)*3)/2;
- x = smalloc(m);
- t = dec64(x, m, p, strlen(p));
- setsecret(&s->in, x, t);
- free(x);
- } else if(strcmp(buf, "secretout") == 0 && p != 0) {
- m = (strlen(p)*3)/2 + 1;
- x = smalloc(m);
- t = dec64(x, m, p, strlen(p));
- setsecret(&s->out, x, t);
- free(x);
- } else
- error(Ebadarg);
-
-out:
- qunlock(&s->in.ctlq);
- qunlock(&s->out.q);
- poperror();
- return n;
-}
-
-static void
-sslinit(void)
-{
- struct Encalg *e;
- struct Hashalg *h;
- int n;
- char *cp;
-
- n = 1;
- for(e = encrypttab; e->name != nil; e++)
- n += strlen(e->name) + 1;
- cp = encalgs = smalloc(n);
- for(e = encrypttab;;){
- strcpy(cp, e->name);
- cp += strlen(e->name);
- e++;
- if(e->name == nil)
- break;
- *cp++ = ' ';
- }
- *cp = 0;
-
- n = 1;
- for(h = hashtab; h->name != nil; h++)
- n += strlen(h->name) + 1;
- cp = hashalgs = smalloc(n);
- for(h = hashtab;;){
- strcpy(cp, h->name);
- cp += strlen(h->name);
- h++;
- if(h->name == nil)
- break;
- *cp++ = ' ';
- }
- *cp = 0;
-}
-
-Dev ssldevtab = {
- 'D',
- "ssl",
-
- devreset,
- sslinit,
- devshutdown,
- sslattach,
- sslwalk,
- sslstat,
- sslopen,
- devcreate,
- sslclose,
- sslread,
- sslbread,
- sslwrite,
- sslbwrite,
- devremove,
- sslwstat,
-};
-
-static Block*
-encryptb(Dstate *s, Block *b, int offset)
-{
- uchar *p, *ep, *p2, *ip, *eip;
- DESstate *ds;
-
- switch(s->encryptalg){
- case DESECB:
- ds = s->out.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp + offset; p < ep; p += 8)
- block_cipher(ds->expanded, p, 0);
- break;
- case DESCBC:
- ds = s->out.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp + offset; p < ep; p += 8){
- p2 = p;
- ip = ds->ivec;
- for(eip = ip+8; ip < eip; )
- *p2++ ^= *ip++;
- block_cipher(ds->expanded, p, 0);
- memmove(ds->ivec, p, 8);
- }
- break;
- case RC4:
- rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
- break;
- }
- return b;
-}
-
-static Block*
-decryptb(Dstate *s, Block *bin)
-{
- Block *b, **l;
- uchar *p, *ep, *tp, *ip, *eip;
- DESstate *ds;
- uchar tmp[8];
- int i;
-
- l = &bin;
- for(b = bin; b; b = b->next){
- /* make sure we have a multiple of s->blocklen */
- if(s->blocklen > 1){
- i = BLEN(b);
- if(i % s->blocklen){
- *l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
- if(b == 0)
- error("ssl encrypted message too short");
- }
- }
- l = &b->next;
-
- /* decrypt */
- switch(s->encryptalg){
- case DESECB:
- ds = s->in.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp; p < ep; p += 8)
- block_cipher(ds->expanded, p, 1);
- break;
- case DESCBC:
- ds = s->in.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp; p < ep;){
- memmove(tmp, p, 8);
- block_cipher(ds->expanded, p, 1);
- tp = tmp;
- ip = ds->ivec;
- for(eip = ip+8; ip < eip; ){
- *p++ ^= *ip;
- *ip++ = *tp++;
- }
- }
- break;
- case RC4:
- rc4(s->in.state, b->rp, BLEN(b));
- break;
- }
- }
- return bin;
-}
-
-static Block*
-digestb(Dstate *s, Block *b, int offset)
-{
- uchar *p;
- DigestState ss;
- uchar msgid[4];
- ulong n, h;
- OneWay *w;
-
- w = &s->out;
-
- memset(&ss, 0, sizeof(ss));
- h = s->diglen + offset;
- n = BLEN(b) - h;
-
- /* hash secret + message */
- (*s->hf)(w->secret, w->slen, 0, &ss);
- (*s->hf)(b->rp + h, n, 0, &ss);
-
- /* hash message id */
- p = msgid;
- n = w->mid;
- *p++ = n>>24;
- *p++ = n>>16;
- *p++ = n>>8;
- *p = n;
- (*s->hf)(msgid, 4, b->rp + offset, &ss);
-
- return b;
-}
-
-static void
-checkdigestb(Dstate *s, Block *bin)
-{
- uchar *p;
- DigestState ss;
- uchar msgid[4];
- int n, h;
- OneWay *w;
- uchar digest[128];
- Block *b;
-
- w = &s->in;
-
- memset(&ss, 0, sizeof(ss));
-
- /* hash secret */
- (*s->hf)(w->secret, w->slen, 0, &ss);
-
- /* hash message */
- h = s->diglen;
- for(b = bin; b; b = b->next){
- n = BLEN(b) - h;
- if(n < 0)
- panic("checkdigestb");
- (*s->hf)(b->rp + h, n, 0, &ss);
- h = 0;
- }
-
- /* hash message id */
- p = msgid;
- n = w->mid;
- *p++ = n>>24;
- *p++ = n>>16;
- *p++ = n>>8;
- *p = n;
- (*s->hf)(msgid, 4, digest, &ss);
-
- if(memcmp(digest, bin->rp, s->diglen) != 0)
- error("bad digest");
-}
-
-/* get channel associated with an fd */
-static Chan*
-buftochan(char *p)
-{
- Chan *c;
- int fd;
-
- if(p == 0)
- error(Ebadarg);
- fd = strtoul(p, 0, 0);
- if(fd < 0)
- error(Ebadarg);
- c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
- if(devtab[c->type] == &ssldevtab){
- cclose(c);
- error("cannot ssl encrypt devssl files");
- }
- return c;
-}
-
-/* hand up a digest connection */
-static void
-sslhangup(Dstate *s)
-{
- Block *b;
-
- qlock(&s->in.q);
- for(b = s->processed; b; b = s->processed){
- s->processed = b->next;
- freeb(b);
- }
- if(s->unprocessed){
- freeb(s->unprocessed);
- s->unprocessed = 0;
- }
- s->state = Sincomplete;
- qunlock(&s->in.q);
-}
-
-static Dstate*
-dsclone(Chan *ch)
-{
- int i;
- Dstate *ret;
-
- if(waserror()) {
- unlock(&dslock);
- nexterror();
- }
- lock(&dslock);
- ret = nil;
- for(i=0; i<Maxdstate; i++){
- if(dstate[i] == nil){
- dsnew(ch, &dstate[i]);
- ret = dstate[i];
- break;
- }
- }
- unlock(&dslock);
- poperror();
- return ret;
-}
-
-static void
-dsnew(Chan *ch, Dstate **pp)
-{
- Dstate *s;
- int t;
-
- *pp = s = malloc(sizeof(*s));
- if(!s)
- error(Enomem);
- if(pp - dstate >= dshiwat)
- dshiwat++;
- memset(s, 0, sizeof(*s));
- s->state = Sincomplete;
- s->ref = 1;
- kstrdup(&s->user, up->user);
- s->perm = 0660;
- t = TYPE(ch->qid);
- if(t == Qclonus)
- t = Qctl;
- ch->qid.path = QID(pp - dstate, t);
- ch->qid.vers = 0;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/devtab.c b/sys/src/cmd/unix/drawterm/kern/devtab.c
deleted file mode 100644
index e16a188fd..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devtab.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-extern Dev consdevtab;
-extern Dev rootdevtab;
-extern Dev pipedevtab;
-extern Dev ssldevtab;
-extern Dev tlsdevtab;
-extern Dev mousedevtab;
-extern Dev drawdevtab;
-extern Dev ipdevtab;
-extern Dev fsdevtab;
-extern Dev mntdevtab;
-extern Dev lfddevtab;
-extern Dev audiodevtab;
-
-Dev *devtab[] = {
- &rootdevtab,
- &consdevtab,
- &pipedevtab,
- &ssldevtab,
- &tlsdevtab,
- &mousedevtab,
- &drawdevtab,
- &ipdevtab,
- &fsdevtab,
- &mntdevtab,
- &lfddevtab,
- &audiodevtab,
- 0
-};
-
diff --git a/sys/src/cmd/unix/drawterm/kern/devtls.c b/sys/src/cmd/unix/drawterm/kern/devtls.c
deleted file mode 100644
index 6f439a241..000000000
--- a/sys/src/cmd/unix/drawterm/kern/devtls.c
+++ /dev/null
@@ -1,2185 +0,0 @@
-/*
- * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0
- */
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "libsec.h"
-
-typedef struct OneWay OneWay;
-typedef struct Secret Secret;
-typedef struct TlsRec TlsRec;
-typedef struct TlsErrs TlsErrs;
-
-enum {
- Statlen= 1024, /* max. length of status or stats message */
- /* buffer limits */
- MaxRecLen = 1<<14, /* max payload length of a record layer message */
- MaxCipherRecLen = MaxRecLen + 2048,
- RecHdrLen = 5,
- MaxMacLen = SHA1dlen,
-
- /* protocol versions we can accept */
- TLSVersion = 0x0301,
- SSL3Version = 0x0300,
- ProtocolVersion = 0x0301, /* maximum version we speak */
- MinProtoVersion = 0x0300, /* limits on version we accept */
- MaxProtoVersion = 0x03ff,
-
- /* connection states */
- SHandshake = 1 << 0, /* doing handshake */
- SOpen = 1 << 1, /* application data can be sent */
- SRClose = 1 << 2, /* remote side has closed down */
- SLClose = 1 << 3, /* sent a close notify alert */
- SAlert = 1 << 5, /* sending or sent a fatal alert */
- SError = 1 << 6, /* some sort of error has occured */
- SClosed = 1 << 7, /* it is all over */
-
- /* record types */
- RChangeCipherSpec = 20,
- RAlert,
- RHandshake,
- RApplication,
-
- SSL2ClientHello = 1,
- HSSL2ClientHello = 9, /* local convention; see tlshand.c */
-
- /* alerts */
- ECloseNotify = 0,
- EUnexpectedMessage = 10,
- EBadRecordMac = 20,
- EDecryptionFailed = 21,
- ERecordOverflow = 22,
- EDecompressionFailure = 30,
- EHandshakeFailure = 40,
- ENoCertificate = 41,
- EBadCertificate = 42,
- EUnsupportedCertificate = 43,
- ECertificateRevoked = 44,
- ECertificateExpired = 45,
- ECertificateUnknown = 46,
- EIllegalParameter = 47,
- EUnknownCa = 48,
- EAccessDenied = 49,
- EDecodeError = 50,
- EDecryptError = 51,
- EExportRestriction = 60,
- EProtocolVersion = 70,
- EInsufficientSecurity = 71,
- EInternalError = 80,
- EUserCanceled = 90,
- ENoRenegotiation = 100,
-
- EMAX = 256
-};
-
-struct Secret
-{
- char *encalg; /* name of encryption alg */
- char *hashalg; /* name of hash alg */
- int (*enc)(Secret*, uchar*, int);
- int (*dec)(Secret*, uchar*, int);
- int (*unpad)(uchar*, int, int);
- DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
- int block; /* encryption block len, 0 if none */
- int maclen;
- void *enckey;
- uchar mackey[MaxMacLen];
-};
-
-struct OneWay
-{
- QLock io; /* locks io access */
- QLock seclock; /* locks secret paramaters */
- ulong seq;
- Secret *sec; /* cipher in use */
- Secret *new; /* cipher waiting for enable */
-};
-
-struct TlsRec
-{
- Chan *c; /* io channel */
- int ref; /* serialized by tdlock for atomic destroy */
- int version; /* version of the protocol we are speaking */
- char verset; /* version has been set */
- char opened; /* opened command every issued? */
- char err[ERRMAX]; /* error message to return to handshake requests */
- vlong handin; /* bytes communicated by the record layer */
- vlong handout;
- vlong datain;
- vlong dataout;
-
- Lock statelk;
- int state;
- int debug;
-
- /* record layer mac functions for different protocol versions */
- void (*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*);
-
- /* input side -- protected by in.io */
- OneWay in;
- Block *processed; /* next bunch of application data */
- Block *unprocessed; /* data read from c but not parsed into records */
-
- /* handshake queue */
- Lock hqlock; /* protects hqref, alloc & free of handq, hprocessed */
- int hqref;
- Queue *handq; /* queue of handshake messages */
- Block *hprocessed; /* remainder of last block read from handq */
- QLock hqread; /* protects reads for hprocessed, handq */
-
- /* output side */
- OneWay out;
-
- /* protections */
- char *user;
- int perm;
-};
-
-struct TlsErrs{
- int err;
- int sslerr;
- int tlserr;
- int fatal;
- char *msg;
-};
-
-static TlsErrs tlserrs[] = {
- {ECloseNotify, ECloseNotify, ECloseNotify, 0, "close notify"},
- {EUnexpectedMessage, EUnexpectedMessage, EUnexpectedMessage, 1, "unexpected message"},
- {EBadRecordMac, EBadRecordMac, EBadRecordMac, 1, "bad record mac"},
- {EDecryptionFailed, EIllegalParameter, EDecryptionFailed, 1, "decryption failed"},
- {ERecordOverflow, EIllegalParameter, ERecordOverflow, 1, "record too long"},
- {EDecompressionFailure, EDecompressionFailure, EDecompressionFailure, 1, "decompression failed"},
- {EHandshakeFailure, EHandshakeFailure, EHandshakeFailure, 1, "could not negotiate acceptable security parameters"},
- {ENoCertificate, ENoCertificate, ECertificateUnknown, 1, "no appropriate certificate available"},
- {EBadCertificate, EBadCertificate, EBadCertificate, 1, "corrupted or invalid certificate"},
- {EUnsupportedCertificate, EUnsupportedCertificate, EUnsupportedCertificate, 1, "unsupported certificate type"},
- {ECertificateRevoked, ECertificateRevoked, ECertificateRevoked, 1, "revoked certificate"},
- {ECertificateExpired, ECertificateExpired, ECertificateExpired, 1, "expired certificate"},
- {ECertificateUnknown, ECertificateUnknown, ECertificateUnknown, 1, "unacceptable certificate"},
- {EIllegalParameter, EIllegalParameter, EIllegalParameter, 1, "illegal parameter"},
- {EUnknownCa, EHandshakeFailure, EUnknownCa, 1, "unknown certificate authority"},
- {EAccessDenied, EHandshakeFailure, EAccessDenied, 1, "access denied"},
- {EDecodeError, EIllegalParameter, EDecodeError, 1, "error decoding message"},
- {EDecryptError, EIllegalParameter, EDecryptError, 1, "error decrypting message"},
- {EExportRestriction, EHandshakeFailure, EExportRestriction, 1, "export restriction violated"},
- {EProtocolVersion, EIllegalParameter, EProtocolVersion, 1, "protocol version not supported"},
- {EInsufficientSecurity, EHandshakeFailure, EInsufficientSecurity, 1, "stronger security routines required"},
- {EInternalError, EHandshakeFailure, EInternalError, 1, "internal error"},
- {EUserCanceled, ECloseNotify, EUserCanceled, 0, "handshake canceled by user"},
- {ENoRenegotiation, EUnexpectedMessage, ENoRenegotiation, 0, "no renegotiation"},
-};
-
-enum
-{
- /* max. open tls connections */
- MaxTlsDevs = 1024
-};
-
-static Lock tdlock;
-static int tdhiwat;
-static int maxtlsdevs = 128;
-static TlsRec **tlsdevs;
-static char **trnames;
-static char *encalgs;
-static char *hashalgs;
-
-enum{
- Qtopdir = 1, /* top level directory */
- Qprotodir,
- Qclonus,
- Qencalgs,
- Qhashalgs,
- Qconvdir, /* directory for a conversation */
- Qdata,
- Qctl,
- Qhand,
- Qstatus,
- Qstats,
-};
-
-#define TYPE(x) ((x).path & 0xf)
-#define CONV(x) (((x).path >> 5)&(MaxTlsDevs-1))
-#define QID(c, y) (((c)<<5) | (y))
-
-static void checkstate(TlsRec *, int, int);
-static void ensure(TlsRec*, Block**, int);
-static void consume(Block**, uchar*, int);
-static Chan* buftochan(char*);
-static void tlshangup(TlsRec*);
-static void tlsError(TlsRec*, char *);
-static void alertHand(TlsRec*, char *);
-static TlsRec *newtls(Chan *c);
-static TlsRec *mktlsrec(void);
-static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
-static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
-static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
-static void sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);
-static void tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);
-static void put64(uchar *p, vlong x);
-static void put32(uchar *p, u32int);
-static void put24(uchar *p, int);
-static void put16(uchar *p, int);
-/* static u32int get32(uchar *p); */
-static int get16(uchar *p);
-static void tlsSetState(TlsRec *tr, int new, int old);
-static void rcvAlert(TlsRec *tr, int err);
-static void sendAlert(TlsRec *tr, int err);
-static void rcvError(TlsRec *tr, int err, char *msg, ...);
-static int rc4enc(Secret *sec, uchar *buf, int n);
-static int des3enc(Secret *sec, uchar *buf, int n);
-static int des3dec(Secret *sec, uchar *buf, int n);
-static int noenc(Secret *sec, uchar *buf, int n);
-static int sslunpad(uchar *buf, int n, int block);
-static int tlsunpad(uchar *buf, int n, int block);
-static void freeSec(Secret *sec);
-static char *tlsstate(int s);
-static void pdump(int, void*, char*);
-
-static char *tlsnames[] = {
- /* unused */ 0,
- /* topdir */ 0,
- /* protodir */ 0,
- "clone",
- "encalgs",
- "hashalgs",
- /* convdir */ 0,
- "data",
- "ctl",
- "hand",
- "status",
- "stats",
-};
-
-static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats };
-
-static int
-tlsgen(Chan *c, char*unused1, Dirtab *unused2, int unused3, int s, Dir *dp)
-{
- Qid q;
- TlsRec *tr;
- char *name, *nm;
- int perm, t;
-
- q.vers = 0;
- q.type = QTFILE;
-
- t = TYPE(c->qid);
- switch(t) {
- case Qtopdir:
- if(s == DEVDOTDOT){
- q.path = QID(0, Qtopdir);
- q.type = QTDIR;
- devdir(c, q, "#a", 0, eve, 0555, dp);
- return 1;
- }
- if(s > 0)
- return -1;
- q.path = QID(0, Qprotodir);
- q.type = QTDIR;
- devdir(c, q, "tls", 0, eve, 0555, dp);
- return 1;
- case Qprotodir:
- if(s == DEVDOTDOT){
- q.path = QID(0, Qtopdir);
- q.type = QTDIR;
- devdir(c, q, ".", 0, eve, 0555, dp);
- return 1;
- }
- if(s < 3){
- switch(s) {
- default:
- return -1;
- case 0:
- q.path = QID(0, Qclonus);
- break;
- case 1:
- q.path = QID(0, Qencalgs);
- break;
- case 2:
- q.path = QID(0, Qhashalgs);
- break;
- }
- perm = 0444;
- if(TYPE(q) == Qclonus)
- perm = 0555;
- devdir(c, q, tlsnames[TYPE(q)], 0, eve, perm, dp);
- return 1;
- }
- s -= 3;
- if(s >= tdhiwat)
- return -1;
- q.path = QID(s, Qconvdir);
- q.type = QTDIR;
- lock(&tdlock);
- tr = tlsdevs[s];
- if(tr != nil)
- nm = tr->user;
- else
- nm = eve;
- if((name = trnames[s]) == nil){
- name = trnames[s] = smalloc(16);
- sprint(name, "%d", s);
- }
- devdir(c, q, name, 0, nm, 0555, dp);
- unlock(&tdlock);
- return 1;
- case Qconvdir:
- if(s == DEVDOTDOT){
- q.path = QID(0, Qprotodir);
- q.type = QTDIR;
- devdir(c, q, "tls", 0, eve, 0555, dp);
- return 1;
- }
- if(s < 0 || s >= nelem(convdir))
- return -1;
- lock(&tdlock);
- tr = tlsdevs[CONV(c->qid)];
- if(tr != nil){
- nm = tr->user;
- perm = tr->perm;
- }else{
- perm = 0;
- nm = eve;
- }
- t = convdir[s];
- if(t == Qstatus || t == Qstats)
- perm &= 0444;
- q.path = QID(CONV(c->qid), t);
- devdir(c, q, tlsnames[t], 0, nm, perm, dp);
- unlock(&tdlock);
- return 1;
- case Qclonus:
- case Qencalgs:
- case Qhashalgs:
- perm = 0444;
- if(t == Qclonus)
- perm = 0555;
- devdir(c, c->qid, tlsnames[t], 0, eve, perm, dp);
- return 1;
- default:
- lock(&tdlock);
- tr = tlsdevs[CONV(c->qid)];
- if(tr != nil){
- nm = tr->user;
- perm = tr->perm;
- }else{
- perm = 0;
- nm = eve;
- }
- if(t == Qstatus || t == Qstats)
- perm &= 0444;
- devdir(c, c->qid, tlsnames[t], 0, nm, perm, dp);
- unlock(&tdlock);
- return 1;
- }
- return -1;
-}
-
-static Chan*
-tlsattach(char *spec)
-{
- Chan *c;
-
- c = devattach('a', spec);
- c->qid.path = QID(0, Qtopdir);
- c->qid.type = QTDIR;
- c->qid.vers = 0;
- return c;
-}
-
-static Walkqid*
-tlswalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name, nname, nil, 0, tlsgen);
-}
-
-static int
-tlsstat(Chan *c, uchar *db, int n)
-{
- return devstat(c, db, n, nil, 0, tlsgen);
-}
-
-static Chan*
-tlsopen(Chan *c, int omode)
-{
- TlsRec *tr, **pp;
- int t, perm;
-
- perm = 0;
- omode &= 3;
- switch(omode) {
- case OREAD:
- perm = 4;
- break;
- case OWRITE:
- perm = 2;
- break;
- case ORDWR:
- perm = 6;
- break;
- }
-
- t = TYPE(c->qid);
- switch(t) {
- default:
- panic("tlsopen");
- case Qtopdir:
- case Qprotodir:
- case Qconvdir:
- if(omode != OREAD)
- error(Eperm);
- break;
- case Qclonus:
- tr = newtls(c);
- if(tr == nil)
- error(Enodev);
- break;
- case Qctl:
- case Qdata:
- case Qhand:
- case Qstatus:
- case Qstats:
- if((t == Qstatus || t == Qstats) && omode != OREAD)
- error(Eperm);
- if(waserror()) {
- unlock(&tdlock);
- nexterror();
- }
- lock(&tdlock);
- pp = &tlsdevs[CONV(c->qid)];
- tr = *pp;
- if(tr == nil)
- error("must open connection using clone");
- if((perm & (tr->perm>>6)) != perm
- && (strcmp(up->user, tr->user) != 0
- || (perm & tr->perm) != perm))
- error(Eperm);
- if(t == Qhand){
- if(waserror()){
- unlock(&tr->hqlock);
- nexterror();
- }
- lock(&tr->hqlock);
- if(tr->handq != nil)
- error(Einuse);
- tr->handq = qopen(2 * MaxCipherRecLen, 0, 0, nil);
- if(tr->handq == nil)
- error("cannot allocate handshake queue");
- tr->hqref = 1;
- unlock(&tr->hqlock);
- poperror();
- }
- tr->ref++;
- unlock(&tdlock);
- poperror();
- break;
- case Qencalgs:
- case Qhashalgs:
- if(omode != OREAD)
- error(Eperm);
- break;
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- c->iounit = qiomaxatomic;
- return c;
-}
-
-static int
-tlswstat(Chan *c, uchar *dp, int n)
-{
- Dir *d;
- TlsRec *tr;
- int rv;
-
- d = nil;
- if(waserror()){
- free(d);
- unlock(&tdlock);
- nexterror();
- }
-
- lock(&tdlock);
- tr = tlsdevs[CONV(c->qid)];
- if(tr == nil)
- error(Ebadusefd);
- if(strcmp(tr->user, up->user) != 0)
- error(Eperm);
-
- d = smalloc(n + sizeof *d);
- rv = convM2D(dp, n, &d[0], (char*) &d[1]);
- if(rv == 0)
- error(Eshortstat);
- if(!emptystr(d->uid))
- kstrdup(&tr->user, d->uid);
- if(d->mode != ~0UL)
- tr->perm = d->mode;
-
- free(d);
- poperror();
- unlock(&tdlock);
-
- return rv;
-}
-
-static void
-dechandq(TlsRec *tr)
-{
- lock(&tr->hqlock);
- if(--tr->hqref == 0){
- if(tr->handq != nil){
- qfree(tr->handq);
- tr->handq = nil;
- }
- if(tr->hprocessed != nil){
- freeb(tr->hprocessed);
- tr->hprocessed = nil;
- }
- }
- unlock(&tr->hqlock);
-}
-
-static void
-tlsclose(Chan *c)
-{
- TlsRec *tr;
- int t;
-
- t = TYPE(c->qid);
- switch(t) {
- case Qctl:
- case Qdata:
- case Qhand:
- case Qstatus:
- case Qstats:
- if((c->flag & COPEN) == 0)
- break;
-
- tr = tlsdevs[CONV(c->qid)];
- if(tr == nil)
- break;
-
- if(t == Qhand)
- dechandq(tr);
-
- lock(&tdlock);
- if(--tr->ref > 0) {
- unlock(&tdlock);
- return;
- }
- tlsdevs[CONV(c->qid)] = nil;
- unlock(&tdlock);
-
- if(tr->c != nil && !waserror()){
- checkstate(tr, 0, SOpen|SHandshake|SRClose);
- sendAlert(tr, ECloseNotify);
- poperror();
- }
- tlshangup(tr);
- if(tr->c != nil)
- cclose(tr->c);
- freeSec(tr->in.sec);
- freeSec(tr->in.new);
- freeSec(tr->out.sec);
- freeSec(tr->out.new);
- free(tr->user);
- free(tr);
- break;
- }
-}
-
-/*
- * make sure we have at least 'n' bytes in list 'l'
- */
-static void
-ensure(TlsRec *s, Block **l, int n)
-{
- int sofar, i;
- Block *b, *bl;
-
- sofar = 0;
- for(b = *l; b; b = b->next){
- sofar += BLEN(b);
- if(sofar >= n)
- return;
- l = &b->next;
- }
-
- while(sofar < n){
- bl = devtab[s->c->type]->bread(s->c, MaxCipherRecLen + RecHdrLen, 0);
- if(bl == 0)
- error(Ehungup);
- *l = bl;
- i = 0;
- for(b = bl; b; b = b->next){
- i += BLEN(b);
- l = &b->next;
- }
- if(i == 0)
- error(Ehungup);
- sofar += i;
- }
-if(s->debug) pprint("ensure read %d\n", sofar);
-}
-
-/*
- * copy 'n' bytes from 'l' into 'p' and free
- * the bytes in 'l'
- */
-static void
-consume(Block **l, uchar *p, int n)
-{
- Block *b;
- int i;
-
- for(; *l && n > 0; n -= i){
- b = *l;
- i = BLEN(b);
- if(i > n)
- i = n;
- memmove(p, b->rp, i);
- b->rp += i;
- p += i;
- if(BLEN(b) < 0)
- panic("consume");
- if(BLEN(b))
- break;
- *l = b->next;
- freeb(b);
- }
-}
-
-/*
- * give back n bytes
- */
-static void
-regurgitate(TlsRec *s, uchar *p, int n)
-{
- Block *b;
-
- if(n <= 0)
- return;
- b = s->unprocessed;
- if(s->unprocessed == nil || b->rp - b->base < n) {
- b = allocb(n);
- memmove(b->wp, p, n);
- b->wp += n;
- b->next = s->unprocessed;
- s->unprocessed = b;
- } else {
- b->rp -= n;
- memmove(b->rp, p, n);
- }
-}
-
-/*
- * remove at most n bytes from the queue
- */
-static Block*
-qgrab(Block **l, int n)
-{
- Block *bb, *b;
- int i;
-
- b = *l;
- if(BLEN(b) == n){
- *l = b->next;
- b->next = nil;
- return b;
- }
-
- i = 0;
- for(bb = b; bb != nil && i < n; bb = bb->next)
- i += BLEN(bb);
- if(i > n)
- i = n;
-
- bb = allocb(i);
- consume(l, bb->wp, i);
- bb->wp += i;
- return bb;
-}
-
-static void
-tlsclosed(TlsRec *tr, int new)
-{
- lock(&tr->statelk);
- if(tr->state == SOpen || tr->state == SHandshake)
- tr->state = new;
- else if((new | tr->state) == (SRClose|SLClose))
- tr->state = SClosed;
- unlock(&tr->statelk);
- alertHand(tr, "close notify");
-}
-
-/*
- * read and process one tls record layer message
- * must be called with tr->in.io held
- * We can't let Eintrs lose data, since doing so will get
- * us out of sync with the sender and break the reliablity
- * of the channel. Eintr only happens during the reads in
- * consume. Therefore we put back any bytes consumed before
- * the last call to ensure.
- */
-static void
-tlsrecread(TlsRec *tr)
-{
- OneWay *volatile in;
- Block *volatile b;
- uchar *p, seq[8], header[RecHdrLen], hmac[MD5dlen];
- int volatile nconsumed;
- int len, type, ver, unpad_len;
-
- nconsumed = 0;
- if(waserror()){
- if(strcmp(up->errstr, Eintr) == 0 && !waserror()){
- regurgitate(tr, header, nconsumed);
- poperror();
- }else
- tlsError(tr, "channel error");
- nexterror();
- }
- ensure(tr, &tr->unprocessed, RecHdrLen);
- consume(&tr->unprocessed, header, RecHdrLen);
-if(tr->debug)pprint("consumed %d header\n", RecHdrLen);
- nconsumed = RecHdrLen;
-
- if((tr->handin == 0) && (header[0] & 0x80)){
- /* Cope with an SSL3 ClientHello expressed in SSL2 record format.
- This is sent by some clients that we must interoperate
- with, such as Java's JSSE and Microsoft's Internet Explorer. */
- len = (get16(header) & ~0x8000) - 3;
- type = header[2];
- ver = get16(header + 3);
- if(type != SSL2ClientHello || len < 22)
- rcvError(tr, EProtocolVersion, "invalid initial SSL2-like message");
- }else{ /* normal SSL3 record format */
- type = header[0];
- ver = get16(header+1);
- len = get16(header+3);
- }
- if(ver != tr->version && (tr->verset || ver < MinProtoVersion || ver > MaxProtoVersion))
- rcvError(tr, EProtocolVersion, "devtls expected ver=%x%s, saw (len=%d) type=%x ver=%x '%.12s'",
- tr->version, tr->verset?"/set":"", len, type, ver, (char*)header);
- if(len > MaxCipherRecLen || len < 0)
- rcvError(tr, ERecordOverflow, "record message too long %d", len);
- ensure(tr, &tr->unprocessed, len);
- nconsumed = 0;
- poperror();
-
- /*
- * If an Eintr happens after this, we'll get out of sync.
- * Make sure nothing we call can sleep.
- * Errors are ok, as they kill the connection.
- * Luckily, allocb won't sleep, it'll just error out.
- */
- b = nil;
- if(waserror()){
- if(b != nil)
- freeb(b);
- tlsError(tr, "channel error");
- nexterror();
- }
- b = qgrab(&tr->unprocessed, len);
-if(tr->debug) pprint("consumed unprocessed %d\n", len);
-
- in = &tr->in;
- if(waserror()){
- qunlock(&in->seclock);
- nexterror();
- }
- qlock(&in->seclock);
- p = b->rp;
- if(in->sec != nil) {
- /* to avoid Canvel-Hiltgen-Vaudenay-Vuagnoux attack, all errors here
- should look alike, including timing of the response. */
- unpad_len = (*in->sec->dec)(in->sec, p, len);
- if(unpad_len >= in->sec->maclen)
- len = unpad_len - in->sec->maclen;
-if(tr->debug) pprint("decrypted %d\n", unpad_len);
-if(tr->debug) pdump(unpad_len, p, "decrypted:");
-
- /* update length */
- put16(header+3, len);
- put64(seq, in->seq);
- in->seq++;
- (*tr->packMac)(in->sec, in->sec->mackey, seq, header, p, len, hmac);
- if(unpad_len < in->sec->maclen)
- rcvError(tr, EBadRecordMac, "short record mac");
- if(memcmp(hmac, p+len, in->sec->maclen) != 0)
- rcvError(tr, EBadRecordMac, "record mac mismatch");
- b->wp = b->rp + len;
- }
- qunlock(&in->seclock);
- poperror();
- if(len < 0)
- rcvError(tr, EDecodeError, "runt record message");
-
- switch(type) {
- default:
- rcvError(tr, EIllegalParameter, "invalid record message 0x%x", type);
- break;
- case RChangeCipherSpec:
- if(len != 1 || p[0] != 1)
- rcvError(tr, EDecodeError, "invalid change cipher spec");
- qlock(&in->seclock);
- if(in->new == nil){
- qunlock(&in->seclock);
- rcvError(tr, EUnexpectedMessage, "unexpected change cipher spec");
- }
- freeSec(in->sec);
- in->sec = in->new;
- in->new = nil;
- in->seq = 0;
- qunlock(&in->seclock);
- break;
- case RAlert:
- if(len != 2)
- rcvError(tr, EDecodeError, "invalid alert");
- if(p[0] == 2)
- rcvAlert(tr, p[1]);
- if(p[0] != 1)
- rcvError(tr, EIllegalParameter, "invalid alert fatal code");
-
- /*
- * propate non-fatal alerts to handshaker
- */
- if(p[1] == ECloseNotify) {
- tlsclosed(tr, SRClose);
- if(tr->opened)
- error("tls hungup");
- error("close notify");
- }
- if(p[1] == ENoRenegotiation)
- alertHand(tr, "no renegotiation");
- else if(p[1] == EUserCanceled)
- alertHand(tr, "handshake canceled by user");
- else
- rcvError(tr, EIllegalParameter, "invalid alert code");
- break;
- case RHandshake:
- /*
- * don't worry about dropping the block
- * qbwrite always queues even if flow controlled and interrupted.
- *
- * if there isn't any handshaker, ignore the request,
- * but notify the other side we are doing so.
- */
- lock(&tr->hqlock);
- if(tr->handq != nil){
- tr->hqref++;
- unlock(&tr->hqlock);
- if(waserror()){
- dechandq(tr);
- nexterror();
- }
- b = padblock(b, 1);
- *b->rp = RHandshake;
- qbwrite(tr->handq, b);
- b = nil;
- poperror();
- dechandq(tr);
- }else{
- unlock(&tr->hqlock);
- if(tr->verset && tr->version != SSL3Version && !waserror()){
- sendAlert(tr, ENoRenegotiation);
- poperror();
- }
- }
- break;
- case SSL2ClientHello:
- lock(&tr->hqlock);
- if(tr->handq != nil){
- tr->hqref++;
- unlock(&tr->hqlock);
- if(waserror()){
- dechandq(tr);
- nexterror();
- }
- /* Pass the SSL2 format data, so that the handshake code can compute
- the correct checksums. HSSL2ClientHello = HandshakeType 9 is
- unused in RFC2246. */
- b = padblock(b, 8);
- b->rp[0] = RHandshake;
- b->rp[1] = HSSL2ClientHello;
- put24(&b->rp[2], len+3);
- b->rp[5] = SSL2ClientHello;
- put16(&b->rp[6], ver);
- qbwrite(tr->handq, b);
- b = nil;
- poperror();
- dechandq(tr);
- }else{
- unlock(&tr->hqlock);
- if(tr->verset && tr->version != SSL3Version && !waserror()){
- sendAlert(tr, ENoRenegotiation);
- poperror();
- }
- }
- break;
- case RApplication:
- if(!tr->opened)
- rcvError(tr, EUnexpectedMessage, "application message received before handshake completed");
- if(BLEN(b) > 0){
- tr->processed = b;
- b = nil;
- }
- break;
- }
- if(b != nil)
- freeb(b);
- poperror();
-}
-
-/*
- * got a fatal alert message
- */
-static void
-rcvAlert(TlsRec *tr, int err)
-{
- char *s;
- int i;
-
- s = "unknown error";
- for(i=0; i < nelem(tlserrs); i++){
- if(tlserrs[i].err == err){
- s = tlserrs[i].msg;
- break;
- }
- }
-if(tr->debug) pprint("rcvAlert: %s\n", s);
-
- tlsError(tr, s);
- if(!tr->opened)
- error(s);
- error("tls error");
-}
-
-/*
- * found an error while decoding the input stream
- */
-static void
-rcvError(TlsRec *tr, int err, char *fmt, ...)
-{
- char msg[ERRMAX];
- va_list arg;
-
- va_start(arg, fmt);
- vseprint(msg, msg+sizeof(msg), fmt, arg);
- va_end(arg);
-if(tr->debug) pprint("rcvError: %s\n", msg);
-
- sendAlert(tr, err);
-
- if(!tr->opened)
- error(msg);
- error("tls error");
-}
-
-/*
- * make sure the next hand operation returns with a 'msg' error
- */
-static void
-alertHand(TlsRec *tr, char *msg)
-{
- Block *b;
- int n;
-
- lock(&tr->hqlock);
- if(tr->handq == nil){
- unlock(&tr->hqlock);
- return;
- }
- tr->hqref++;
- unlock(&tr->hqlock);
-
- n = strlen(msg);
- if(waserror()){
- dechandq(tr);
- nexterror();
- }
- b = allocb(n + 2);
- *b->wp++ = RAlert;
- memmove(b->wp, msg, n + 1);
- b->wp += n + 1;
-
- qbwrite(tr->handq, b);
-
- poperror();
- dechandq(tr);
-}
-
-static void
-checkstate(TlsRec *tr, int ishand, int ok)
-{
- int state;
-
- lock(&tr->statelk);
- state = tr->state;
- unlock(&tr->statelk);
- if(state & ok)
- return;
- switch(state){
- case SHandshake:
- case SOpen:
- break;
- case SError:
- case SAlert:
- if(ishand)
- error(tr->err);
- error("tls error");
- case SRClose:
- case SLClose:
- case SClosed:
- error("tls hungup");
- }
- error("tls improperly configured");
-}
-
-static Block*
-tlsbread(Chan *c, long n, ulong offset)
-{
- int ty;
- Block *b;
- TlsRec *volatile tr;
-
- ty = TYPE(c->qid);
- switch(ty) {
- default:
- return devbread(c, n, offset);
- case Qhand:
- case Qdata:
- break;
- }
-
- tr = tlsdevs[CONV(c->qid)];
- if(tr == nil)
- panic("tlsbread");
-
- if(waserror()){
- qunlock(&tr->in.io);
- nexterror();
- }
- qlock(&tr->in.io);
- if(ty == Qdata){
- checkstate(tr, 0, SOpen);
- while(tr->processed == nil)
- tlsrecread(tr);
-
- /* return at most what was asked for */
- b = qgrab(&tr->processed, n);
-if(tr->debug) pprint("consumed processed %d\n", BLEN(b));
-if(tr->debug) pdump(BLEN(b), b->rp, "consumed:");
- qunlock(&tr->in.io);
- poperror();
- tr->datain += BLEN(b);
- }else{
- checkstate(tr, 1, SOpen|SHandshake|SLClose);
-
- /*
- * it's ok to look at state without the lock
- * since it only protects reading records,
- * and we have that tr->in.io held.
- */
- while(!tr->opened && tr->hprocessed == nil && !qcanread(tr->handq))
- tlsrecread(tr);
-
- qunlock(&tr->in.io);
- poperror();
-
- if(waserror()){
- qunlock(&tr->hqread);
- nexterror();
- }
- qlock(&tr->hqread);
- if(tr->hprocessed == nil){
- b = qbread(tr->handq, MaxRecLen + 1);
- if(*b->rp++ == RAlert){
- kstrcpy(up->errstr, (char*)b->rp, ERRMAX);
- freeb(b);
- nexterror();
- }
- tr->hprocessed = b;
- }
- b = qgrab(&tr->hprocessed, n);
- poperror();
- qunlock(&tr->hqread);
- tr->handin += BLEN(b);
- }
-
- return b;
-}
-
-static long
-tlsread(Chan *c, void *a, long n, vlong off)
-{
- Block *volatile b;
- Block *nb;
- uchar *va;
- int i, ty;
- char *buf, *s, *e;
- ulong offset = off;
- TlsRec * tr;
-
- if(c->qid.type & QTDIR)
- return devdirread(c, a, n, 0, 0, tlsgen);
-
- tr = tlsdevs[CONV(c->qid)];
- ty = TYPE(c->qid);
- switch(ty) {
- default:
- error(Ebadusefd);
- case Qstatus:
- buf = smalloc(Statlen);
- qlock(&tr->in.seclock);
- qlock(&tr->out.seclock);
- s = buf;
- e = buf + Statlen;
- s = seprint(s, e, "State: %s\n", tlsstate(tr->state));
- s = seprint(s, e, "Version: 0x%x\n", tr->version);
- if(tr->in.sec != nil)
- s = seprint(s, e, "EncIn: %s\nHashIn: %s\n", tr->in.sec->encalg, tr->in.sec->hashalg);
- if(tr->in.new != nil)
- s = seprint(s, e, "NewEncIn: %s\nNewHashIn: %s\n", tr->in.new->encalg, tr->in.new->hashalg);
- if(tr->out.sec != nil)
- s = seprint(s, e, "EncOut: %s\nHashOut: %s\n", tr->out.sec->encalg, tr->out.sec->hashalg);
- if(tr->out.new != nil)
- seprint(s, e, "NewEncOut: %s\nNewHashOut: %s\n", tr->out.new->encalg, tr->out.new->hashalg);
- qunlock(&tr->in.seclock);
- qunlock(&tr->out.seclock);
- n = readstr(offset, a, n, buf);
- free(buf);
- return n;
- case Qstats:
- buf = smalloc(Statlen);
- s = buf;
- e = buf + Statlen;
- s = seprint(s, e, "DataIn: %lld\n", tr->datain);
- s = seprint(s, e, "DataOut: %lld\n", tr->dataout);
- s = seprint(s, e, "HandIn: %lld\n", tr->handin);
- seprint(s, e, "HandOut: %lld\n", tr->handout);
- n = readstr(offset, a, n, buf);
- free(buf);
- return n;
- case Qctl:
- buf = smalloc(Statlen);
- snprint(buf, Statlen, "%llud", CONV(c->qid));
- n = readstr(offset, a, n, buf);
- free(buf);
- return n;
- case Qdata:
- case Qhand:
- b = tlsbread(c, n, offset);
- break;
- case Qencalgs:
- return readstr(offset, a, n, encalgs);
- case Qhashalgs:
- return readstr(offset, a, n, hashalgs);
- }
-
- if(waserror()){
- freeblist(b);
- nexterror();
- }
-
- n = 0;
- va = a;
- for(nb = b; nb; nb = nb->next){
- i = BLEN(nb);
- memmove(va+n, nb->rp, i);
- n += i;
- }
-
- freeblist(b);
- poperror();
-
- return n;
-}
-
-/*
- * write a block in tls records
- */
-static void
-tlsrecwrite(TlsRec *tr, int type, Block *b)
-{
- Block *volatile bb;
- Block *nb;
- uchar *p, seq[8];
- OneWay *volatile out;
- int n, maclen, pad, ok;
-
- out = &tr->out;
- bb = b;
- if(waserror()){
- qunlock(&out->io);
- if(bb != nil)
- freeb(bb);
- nexterror();
- }
- qlock(&out->io);
-if(tr->debug)pprint("send %d\n", BLEN(b));
-if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
-
-
- ok = SHandshake|SOpen|SRClose;
- if(type == RAlert)
- ok |= SAlert;
- while(bb != nil){
- checkstate(tr, type != RApplication, ok);
-
- /*
- * get at most one maximal record's input,
- * with padding on the front for header and
- * back for mac and maximal block padding.
- */
- if(waserror()){
- qunlock(&out->seclock);
- nexterror();
- }
- qlock(&out->seclock);
- maclen = 0;
- pad = 0;
- if(out->sec != nil){
- maclen = out->sec->maclen;
- pad = maclen + out->sec->block;
- }
- n = BLEN(bb);
- if(n > MaxRecLen){
- n = MaxRecLen;
- nb = allocb(n + pad + RecHdrLen);
- memmove(nb->wp + RecHdrLen, bb->rp, n);
- bb->rp += n;
- }else{
- /*
- * carefully reuse bb so it will get freed if we're out of memory
- */
- bb = padblock(bb, RecHdrLen);
- if(pad)
- nb = padblock(bb, -pad);
- else
- nb = bb;
- bb = nil;
- }
-
- p = nb->rp;
- p[0] = type;
- put16(p+1, tr->version);
- put16(p+3, n);
-
- if(out->sec != nil){
- put64(seq, out->seq);
- out->seq++;
- (*tr->packMac)(out->sec, out->sec->mackey, seq, p, p + RecHdrLen, n, p + RecHdrLen + n);
- n += maclen;
-
- /* encrypt */
- n = (*out->sec->enc)(out->sec, p + RecHdrLen, n);
- nb->wp = p + RecHdrLen + n;
-
- /* update length */
- put16(p+3, n);
- }
- if(type == RChangeCipherSpec){
- if(out->new == nil)
- error("change cipher without a new cipher");
- freeSec(out->sec);
- out->sec = out->new;
- out->new = nil;
- out->seq = 0;
- }
- qunlock(&out->seclock);
- poperror();
-
- /*
- * if bwrite error's, we assume the block is queued.
- * if not, we're out of sync with the receiver and will not recover.
- */
- if(waserror()){
- if(strcmp(up->errstr, "interrupted") != 0)
- tlsError(tr, "channel error");
- nexterror();
- }
- devtab[tr->c->type]->bwrite(tr->c, nb, 0);
- poperror();
- }
- qunlock(&out->io);
- poperror();
-}
-
-static long
-tlsbwrite(Chan *c, Block *b, ulong offset)
-{
- int ty;
- ulong n;
- TlsRec *tr;
-
- n = BLEN(b);
-
- tr = tlsdevs[CONV(c->qid)];
- if(tr == nil)
- panic("tlsbread");
-
- ty = TYPE(c->qid);
- switch(ty) {
- default:
- return devbwrite(c, b, offset);
- case Qhand:
- tlsrecwrite(tr, RHandshake, b);
- tr->handout += n;
- break;
- case Qdata:
- checkstate(tr, 0, SOpen);
- tlsrecwrite(tr, RApplication, b);
- tr->dataout += n;
- break;
- }
-
- return n;
-}
-
-typedef struct Hashalg Hashalg;
-struct Hashalg
-{
- char *name;
- int maclen;
- void (*initkey)(Hashalg *, int, Secret *, uchar*);
-};
-
-static void
-initmd5key(Hashalg *ha, int version, Secret *s, uchar *p)
-{
- s->maclen = ha->maclen;
- if(version == SSL3Version)
- s->mac = sslmac_md5;
- else
- s->mac = hmac_md5;
- memmove(s->mackey, p, ha->maclen);
-}
-
-static void
-initclearmac(Hashalg *unused1, int unused2, Secret *s, uchar *unused3)
-{
- s->maclen = 0;
- s->mac = nomac;
-}
-
-static void
-initsha1key(Hashalg *ha, int version, Secret *s, uchar *p)
-{
- s->maclen = ha->maclen;
- if(version == SSL3Version)
- s->mac = sslmac_sha1;
- else
- s->mac = hmac_sha1;
- memmove(s->mackey, p, ha->maclen);
-}
-
-static Hashalg hashtab[] =
-{
- { "clear", 0, initclearmac, },
- { "md5", MD5dlen, initmd5key, },
- { "sha1", SHA1dlen, initsha1key, },
- { 0 }
-};
-
-static Hashalg*
-parsehashalg(char *p)
-{
- Hashalg *ha;
-
- for(ha = hashtab; ha->name; ha++)
- if(strcmp(p, ha->name) == 0)
- return ha;
- error("unsupported hash algorithm");
- return nil;
-}
-
-typedef struct Encalg Encalg;
-struct Encalg
-{
- char *name;
- int keylen;
- int ivlen;
- void (*initkey)(Encalg *ea, Secret *, uchar*, uchar*);
-};
-
-static void
-initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *unused1)
-{
- s->enckey = smalloc(sizeof(RC4state));
- s->enc = rc4enc;
- s->dec = rc4enc;
- s->block = 0;
- setupRC4state(s->enckey, p, ea->keylen);
-}
-
-static void
-initDES3key(Encalg *unused1, Secret *s, uchar *p, uchar *iv)
-{
- s->enckey = smalloc(sizeof(DES3state));
- s->enc = des3enc;
- s->dec = des3dec;
- s->block = 8;
- setupDES3state(s->enckey, (uchar(*)[8])p, iv);
-}
-
-static void
-initclearenc(Encalg *unused1, Secret *s, uchar *unused2, uchar *unused3)
-{
- s->enc = noenc;
- s->dec = noenc;
- s->block = 0;
-}
-
-static Encalg encrypttab[] =
-{
- { "clear", 0, 0, initclearenc },
- { "rc4_128", 128/8, 0, initRC4key },
- { "3des_ede_cbc", 3 * 8, 8, initDES3key },
- { 0 }
-};
-
-static Encalg*
-parseencalg(char *p)
-{
- Encalg *ea;
-
- for(ea = encrypttab; ea->name; ea++)
- if(strcmp(p, ea->name) == 0)
- return ea;
- error("unsupported encryption algorithm");
- return nil;
-}
-
-static long
-tlswrite(Chan *c, void *a, long n, vlong off)
-{
- Encalg *ea;
- Hashalg *ha;
- TlsRec *volatile tr;
- Secret *volatile tos, *volatile toc;
- Block *volatile b;
- Cmdbuf *volatile cb;
- int m, ty;
- char *p, *e;
- uchar *volatile x;
- ulong offset = off;
-
- tr = tlsdevs[CONV(c->qid)];
- if(tr == nil)
- panic("tlswrite");
-
- ty = TYPE(c->qid);
- switch(ty){
- case Qdata:
- case Qhand:
- p = a;
- e = p + n;
- do{
- m = e - p;
- if(m > MaxRecLen)
- m = MaxRecLen;
-
- b = allocb(m);
- if(waserror()){
- freeb(b);
- nexterror();
- }
- memmove(b->wp, p, m);
- poperror();
- b->wp += m;
-
- tlsbwrite(c, b, offset);
-
- p += m;
- }while(p < e);
- return n;
- case Qctl:
- break;
- default:
- error(Ebadusefd);
- return -1;
- }
-
- cb = parsecmd(a, n);
- if(waserror()){
- free(cb);
- nexterror();
- }
- if(cb->nf < 1)
- error("short control request");
-
- /* mutex with operations using what we're about to change */
- if(waserror()){
- qunlock(&tr->in.seclock);
- qunlock(&tr->out.seclock);
- nexterror();
- }
- qlock(&tr->in.seclock);
- qlock(&tr->out.seclock);
-
- if(strcmp(cb->f[0], "fd") == 0){
- if(cb->nf != 3)
- error("usage: fd open-fd version");
- if(tr->c != nil)
- error(Einuse);
- m = strtol(cb->f[2], nil, 0);
- if(m < MinProtoVersion || m > MaxProtoVersion)
- error("unsupported version");
- tr->c = buftochan(cb->f[1]);
- tr->version = m;
- tlsSetState(tr, SHandshake, SClosed);
- }else if(strcmp(cb->f[0], "version") == 0){
- if(cb->nf != 2)
- error("usage: version vers");
- if(tr->c == nil)
- error("must set fd before version");
- if(tr->verset)
- error("version already set");
- m = strtol(cb->f[1], nil, 0);
- if(m == SSL3Version)
- tr->packMac = sslPackMac;
- else if(m == TLSVersion)
- tr->packMac = tlsPackMac;
- else
- error("unsupported version");
- tr->verset = 1;
- tr->version = m;
- }else if(strcmp(cb->f[0], "secret") == 0){
- if(cb->nf != 5)
- error("usage: secret hashalg encalg isclient secretdata");
- if(tr->c == nil || !tr->verset)
- error("must set fd and version before secrets");
-
- if(tr->in.new != nil){
- freeSec(tr->in.new);
- tr->in.new = nil;
- }
- if(tr->out.new != nil){
- freeSec(tr->out.new);
- tr->out.new = nil;
- }
-
- ha = parsehashalg(cb->f[1]);
- ea = parseencalg(cb->f[2]);
-
- p = cb->f[4];
- m = (strlen(p)*3)/2;
- x = smalloc(m);
- tos = nil;
- toc = nil;
- if(waserror()){
- freeSec(tos);
- freeSec(toc);
- free(x);
- nexterror();
- }
- m = dec64(x, m, p, strlen(p));
- if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen)
- error("not enough secret data provided");
-
- tos = smalloc(sizeof(Secret));
- toc = smalloc(sizeof(Secret));
- if(!ha->initkey || !ea->initkey)
- error("misimplemented secret algorithm");
- (*ha->initkey)(ha, tr->version, tos, &x[0]);
- (*ha->initkey)(ha, tr->version, toc, &x[ha->maclen]);
- (*ea->initkey)(ea, tos, &x[2 * ha->maclen], &x[2 * ha->maclen + 2 * ea->keylen]);
- (*ea->initkey)(ea, toc, &x[2 * ha->maclen + ea->keylen], &x[2 * ha->maclen + 2 * ea->keylen + ea->ivlen]);
-
- if(!tos->mac || !tos->enc || !tos->dec
- || !toc->mac || !toc->enc || !toc->dec)
- error("missing algorithm implementations");
- if(strtol(cb->f[3], nil, 0) == 0){
- tr->in.new = tos;
- tr->out.new = toc;
- }else{
- tr->in.new = toc;
- tr->out.new = tos;
- }
- if(tr->version == SSL3Version){
- toc->unpad = sslunpad;
- tos->unpad = sslunpad;
- }else{
- toc->unpad = tlsunpad;
- tos->unpad = tlsunpad;
- }
- toc->encalg = ea->name;
- toc->hashalg = ha->name;
- tos->encalg = ea->name;
- tos->hashalg = ha->name;
-
- free(x);
- poperror();
- }else if(strcmp(cb->f[0], "changecipher") == 0){
- if(cb->nf != 1)
- error("usage: changecipher");
- if(tr->out.new == nil)
- error("cannot change cipher spec without setting secret");
-
- qunlock(&tr->in.seclock);
- qunlock(&tr->out.seclock);
- poperror();
- free(cb);
- poperror();
-
- /*
- * the real work is done as the message is written
- * so the stream is encrypted in sync.
- */
- b = allocb(1);
- *b->wp++ = 1;
- tlsrecwrite(tr, RChangeCipherSpec, b);
- return n;
- }else if(strcmp(cb->f[0], "opened") == 0){
- if(cb->nf != 1)
- error("usage: opened");
- if(tr->in.sec == nil || tr->out.sec == nil)
- error("cipher must be configured before enabling data messages");
- lock(&tr->statelk);
- if(tr->state != SHandshake && tr->state != SOpen){
- unlock(&tr->statelk);
- error("cannot enable data messages");
- }
- tr->state = SOpen;
- unlock(&tr->statelk);
- tr->opened = 1;
- }else if(strcmp(cb->f[0], "alert") == 0){
- if(cb->nf != 2)
- error("usage: alert n");
- if(tr->c == nil)
- error("must set fd before sending alerts");
- m = strtol(cb->f[1], nil, 0);
-
- qunlock(&tr->in.seclock);
- qunlock(&tr->out.seclock);
- poperror();
- free(cb);
- poperror();
-
- sendAlert(tr, m);
-
- if(m == ECloseNotify)
- tlsclosed(tr, SLClose);
-
- return n;
- } else if(strcmp(cb->f[0], "debug") == 0){
- if(cb->nf == 2){
- if(strcmp(cb->f[1], "on") == 0)
- tr->debug = 1;
- else
- tr->debug = 0;
- } else
- tr->debug = 1;
- } else
- error(Ebadarg);
-
- qunlock(&tr->in.seclock);
- qunlock(&tr->out.seclock);
- poperror();
- free(cb);
- poperror();
-
- return n;
-}
-
-static void
-tlsinit(void)
-{
- struct Encalg *e;
- struct Hashalg *h;
- int n;
- char *cp;
- static int already;
-
- if(!already){
- fmtinstall('H', encodefmt);
- already = 1;
- }
-
- tlsdevs = smalloc(sizeof(TlsRec*) * maxtlsdevs);
- trnames = smalloc((sizeof *trnames) * maxtlsdevs);
-
- n = 1;
- for(e = encrypttab; e->name != nil; e++)
- n += strlen(e->name) + 1;
- cp = encalgs = smalloc(n);
- for(e = encrypttab;;){
- strcpy(cp, e->name);
- cp += strlen(e->name);
- e++;
- if(e->name == nil)
- break;
- *cp++ = ' ';
- }
- *cp = 0;
-
- n = 1;
- for(h = hashtab; h->name != nil; h++)
- n += strlen(h->name) + 1;
- cp = hashalgs = smalloc(n);
- for(h = hashtab;;){
- strcpy(cp, h->name);
- cp += strlen(h->name);
- h++;
- if(h->name == nil)
- break;
- *cp++ = ' ';
- }
- *cp = 0;
-}
-
-Dev tlsdevtab = {
- 'a',
- "tls",
-
- devreset,
- tlsinit,
- devshutdown,
- tlsattach,
- tlswalk,
- tlsstat,
- tlsopen,
- devcreate,
- tlsclose,
- tlsread,
- tlsbread,
- tlswrite,
- tlsbwrite,
- devremove,
- tlswstat,
-};
-
-/* get channel associated with an fd */
-static Chan*
-buftochan(char *p)
-{
- Chan *c;
- int fd;
-
- if(p == 0)
- error(Ebadarg);
- fd = strtoul(p, 0, 0);
- if(fd < 0)
- error(Ebadarg);
- c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
- return c;
-}
-
-static void
-sendAlert(TlsRec *tr, int err)
-{
- Block *b;
- int i, fatal;
- char *msg;
-
-if(tr->debug)pprint("sendAlert %d\n", err);
- fatal = 1;
- msg = "tls unknown alert";
- for(i=0; i < nelem(tlserrs); i++) {
- if(tlserrs[i].err == err) {
- msg = tlserrs[i].msg;
- if(tr->version == SSL3Version)
- err = tlserrs[i].sslerr;
- else
- err = tlserrs[i].tlserr;
- fatal = tlserrs[i].fatal;
- break;
- }
- }
-
- if(!waserror()){
- b = allocb(2);
- *b->wp++ = fatal + 1;
- *b->wp++ = err;
- if(fatal)
- tlsSetState(tr, SAlert, SOpen|SHandshake|SRClose);
- tlsrecwrite(tr, RAlert, b);
- poperror();
- }
- if(fatal)
- tlsError(tr, msg);
-}
-
-static void
-tlsError(TlsRec *tr, char *msg)
-{
- int s;
-
-if(tr->debug)pprint("tleError %s\n", msg);
- lock(&tr->statelk);
- s = tr->state;
- tr->state = SError;
- if(s != SError){
- strncpy(tr->err, msg, ERRMAX - 1);
- tr->err[ERRMAX - 1] = '\0';
- }
- unlock(&tr->statelk);
- if(s != SError)
- alertHand(tr, msg);
-}
-
-static void
-tlsSetState(TlsRec *tr, int new, int old)
-{
- lock(&tr->statelk);
- if(tr->state & old)
- tr->state = new;
- unlock(&tr->statelk);
-}
-
-/* hand up a digest connection */
-static void
-tlshangup(TlsRec *tr)
-{
- Block *b;
-
- qlock(&tr->in.io);
- for(b = tr->processed; b; b = tr->processed){
- tr->processed = b->next;
- freeb(b);
- }
- if(tr->unprocessed != nil){
- freeb(tr->unprocessed);
- tr->unprocessed = nil;
- }
- qunlock(&tr->in.io);
-
- tlsSetState(tr, SClosed, ~0);
-}
-
-static TlsRec*
-newtls(Chan *ch)
-{
- TlsRec **pp, **ep, **np;
- char **nmp;
- int t, newmax;
-
- if(waserror()) {
- unlock(&tdlock);
- nexterror();
- }
- lock(&tdlock);
- ep = &tlsdevs[maxtlsdevs];
- for(pp = tlsdevs; pp < ep; pp++)
- if(*pp == nil)
- break;
- if(pp >= ep) {
- if(maxtlsdevs >= MaxTlsDevs) {
- unlock(&tdlock);
- poperror();
- return nil;
- }
- newmax = 2 * maxtlsdevs;
- if(newmax > MaxTlsDevs)
- newmax = MaxTlsDevs;
- np = smalloc(sizeof(TlsRec*) * newmax);
- memmove(np, tlsdevs, sizeof(TlsRec*) * maxtlsdevs);
- tlsdevs = np;
- pp = &tlsdevs[maxtlsdevs];
- memset(pp, 0, sizeof(TlsRec*)*(newmax - maxtlsdevs));
-
- nmp = smalloc(sizeof *nmp * newmax);
- memmove(nmp, trnames, sizeof *nmp * maxtlsdevs);
- trnames = nmp;
-
- maxtlsdevs = newmax;
- }
- *pp = mktlsrec();
- if(pp - tlsdevs >= tdhiwat)
- tdhiwat++;
- t = TYPE(ch->qid);
- if(t == Qclonus)
- t = Qctl;
- ch->qid.path = QID(pp - tlsdevs, t);
- ch->qid.vers = 0;
- unlock(&tdlock);
- poperror();
- return *pp;
-}
-
-static TlsRec *
-mktlsrec(void)
-{
- TlsRec *tr;
-
- tr = mallocz(sizeof(*tr), 1);
- if(tr == nil)
- error(Enomem);
- tr->state = SClosed;
- tr->ref = 1;
- kstrdup(&tr->user, up->user);
- tr->perm = 0660;
- return tr;
-}
-
-static char*
-tlsstate(int s)
-{
- switch(s){
- case SHandshake:
- return "Handshaking";
- case SOpen:
- return "Established";
- case SRClose:
- return "RemoteClosed";
- case SLClose:
- return "LocalClosed";
- case SAlert:
- return "Alerting";
- case SError:
- return "Errored";
- case SClosed:
- return "Closed";
- }
- return "Unknown";
-}
-
-static void
-freeSec(Secret *s)
-{
- if(s != nil){
- free(s->enckey);
- free(s);
- }
-}
-
-static int
-noenc(Secret *unused1, uchar *unused2, int n)
-{
- return n;
-}
-
-static int
-rc4enc(Secret *sec, uchar *buf, int n)
-{
- rc4(sec->enckey, buf, n);
- return n;
-}
-
-static int
-tlsunpad(uchar *buf, int n, int block)
-{
- int pad, nn;
-
- pad = buf[n - 1];
- nn = n - 1 - pad;
- if(nn <= 0 || n % block)
- return -1;
- while(--n > nn)
- if(pad != buf[n - 1])
- return -1;
- return nn;
-}
-
-static int
-sslunpad(uchar *buf, int n, int block)
-{
- int pad, nn;
-
- pad = buf[n - 1];
- nn = n - 1 - pad;
- if(nn <= 0 || n % block)
- return -1;
- return nn;
-}
-
-static int
-blockpad(uchar *buf, int n, int block)
-{
- int pad, nn;
-
- nn = n + block;
- nn -= nn % block;
- pad = nn - (n + 1);
- while(n < nn)
- buf[n++] = pad;
- return nn;
-}
-
-static int
-des3enc(Secret *sec, uchar *buf, int n)
-{
- n = blockpad(buf, n, 8);
- des3CBCencrypt(buf, n, sec->enckey);
- return n;
-}
-
-static int
-des3dec(Secret *sec, uchar *buf, int n)
-{
- des3CBCdecrypt(buf, n, sec->enckey);
- return (*sec->unpad)(buf, n, 8);
-}
-static DigestState*
-nomac(uchar *unused1, ulong unused2, uchar *unused3, ulong unused4,
- uchar *unused5, DigestState *unused6)
-{
- return nil;
-}
-
-/*
- * sslmac: mac calculations for ssl 3.0 only; tls 1.0 uses the standard hmac.
- */
-static DigestState*
-sslmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s,
- DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen, int padlen)
-{
- int i;
- uchar pad[48], innerdigest[20];
-
- if(xlen > sizeof(innerdigest)
- || padlen > sizeof(pad))
- return nil;
-
- if(klen>64)
- return nil;
-
- /* first time through */
- if(s == nil){
- for(i=0; i<padlen; i++)
- pad[i] = 0x36;
- s = (*x)(key, klen, nil, nil);
- s = (*x)(pad, padlen, nil, s);
- if(s == nil)
- return nil;
- }
-
- s = (*x)(p, len, nil, s);
- if(digest == nil)
- return s;
-
- /* last time through */
- for(i=0; i<padlen; i++)
- pad[i] = 0x5c;
- (*x)(nil, 0, innerdigest, s);
- s = (*x)(key, klen, nil, nil);
- s = (*x)(pad, padlen, nil, s);
- (*x)(innerdigest, xlen, digest, s);
- return nil;
-}
-
-static DigestState*
-sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
-{
- return sslmac_x(p, len, key, klen, digest, s, sha1, SHA1dlen, 40);
-}
-
-static DigestState*
-sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
-{
- return sslmac_x(p, len, key, klen, digest, s, md5, MD5dlen, 48);
-}
-
-static void
-sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac)
-{
- DigestState *s;
- uchar buf[11];
-
- memmove(buf, seq, 8);
- buf[8] = header[0];
- buf[9] = header[3];
- buf[10] = header[4];
-
- s = (*sec->mac)(buf, 11, mackey, sec->maclen, 0, 0);
- (*sec->mac)(body, len, mackey, sec->maclen, mac, s);
-}
-
-static void
-tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac)
-{
- DigestState *s;
- uchar buf[13];
-
- memmove(buf, seq, 8);
- memmove(&buf[8], header, 5);
-
- s = (*sec->mac)(buf, 13, mackey, sec->maclen, 0, 0);
- (*sec->mac)(body, len, mackey, sec->maclen, mac, s);
-}
-
-static void
-put32(uchar *p, u32int x)
-{
- p[0] = x>>24;
- p[1] = x>>16;
- p[2] = x>>8;
- p[3] = x;
-}
-
-static void
-put64(uchar *p, vlong x)
-{
- put32(p, (u32int)(x >> 32));
- put32(p+4, (u32int)x);
-}
-
-static void
-put24(uchar *p, int x)
-{
- p[0] = x>>16;
- p[1] = x>>8;
- p[2] = x;
-}
-
-static void
-put16(uchar *p, int x)
-{
- p[0] = x>>8;
- p[1] = x;
-}
-
-/*
-static u32int
-get32(uchar *p)
-{
- return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
-}
-*/
-
-static int
-get16(uchar *p)
-{
- return (p[0]<<8)|p[1];
-}
-
-static char *charmap = "0123456789abcdef";
-
-static void
-pdump(int len, void *a, char *tag)
-{
- uchar *p;
- int i;
- char buf[65+32];
- char *q;
-
- p = a;
- strcpy(buf, tag);
- while(len > 0){
- q = buf + strlen(tag);
- for(i = 0; len > 0 && i < 32; i++){
- if(*p >= ' ' && *p < 0x7f){
- *q++ = ' ';
- *q++ = *p;
- } else {
- *q++ = charmap[*p>>4];
- *q++ = charmap[*p & 0xf];
- }
- len--;
- p++;
- }
- *q = 0;
-
- if(len > 0)
- pprint("%s...\n", buf);
- else
- pprint("%s\n", buf);
- }
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/error.c b/sys/src/cmd/unix/drawterm/kern/error.c
deleted file mode 100644
index 465de475a..000000000
--- a/sys/src/cmd/unix/drawterm/kern/error.c
+++ /dev/null
@@ -1,50 +0,0 @@
-char Enoerror[] = "no error";
-char Emount[] = "inconsistent mount";
-char Eunmount[] = "not mounted";
-char Eunion[] = "not in union";
-char Emountrpc[] = "mount rpc error";
-char Eshutdown[] = "device shut down";
-char Enocreate[] = "mounted directory forbids creation";
-char Enonexist[] = "file does not exist";
-char Eexist[] = "file already exists";
-char Ebadsharp[] = "unknown device in # filename";
-char Enotdir[] = "not a directory";
-char Eisdir[] = "file is a directory";
-char Ebadchar[] = "bad character in file name";
-char Efilename[] = "file name syntax";
-char Eperm[] = "permission denied";
-char Ebadusefd[] = "inappropriate use of fd";
-char Ebadarg[] = "bad arg in system call";
-char Einuse[] = "device or object already in use";
-char Eio[] = "i/o error";
-char Etoobig[] = "read or write too large";
-char Etoosmall[] = "read or write too small";
-char Enoport[] = "network port not available";
-char Ehungup[] = "i/o on hungup channel";
-char Ebadctl[] = "bad process or channel control request";
-char Enodev[] = "no free devices";
-char Eprocdied[] = "process exited";
-char Enochild[] = "no living children";
-char Eioload[] = "i/o error in demand load";
-char Enovmem[] = "virtual memory allocation failed";
-char Ebadfd[] = "fd out of range or not open";
-char Enofd[] = "no free file descriptors";
-char Eisstream[] = "seek on a stream";
-char Ebadexec[] = "exec header invalid";
-char Etimedout[] = "connection timed out";
-char Econrefused[] = "connection refused";
-char Econinuse[] = "connection in use";
-char Eintr[] = "interrupted";
-char Enomem[] = "kernel allocate failed";
-char Enoswap[] = "swap space full";
-char Esoverlap[] = "segments overlap";
-char Emouseset[] = "mouse type already set";
-char Eshort[] = "i/o count too small";
-char Egreg[] = "ken has left the building";
-char Ebadspec[] = "bad attach specifier";
-char Enoreg[] = "process has no saved registers";
-char Enoattach[] = "mount/attach disallowed";
-char Eshortstat[] = "stat buffer too small";
-char Ebadstat[] = "malformed stat buffer";
-char Enegoff[] = "negative i/o offset";
-char Ecmdargs[] = "wrong #args in control message";
diff --git a/sys/src/cmd/unix/drawterm/kern/error.h b/sys/src/cmd/unix/drawterm/kern/error.h
deleted file mode 100644
index 6bb87622e..000000000
--- a/sys/src/cmd/unix/drawterm/kern/error.h
+++ /dev/null
@@ -1,50 +0,0 @@
-extern char Enoerror[]; /* no error */
-extern char Emount[]; /* inconsistent mount */
-extern char Eunmount[]; /* not mounted */
-extern char Eunion[]; /* not in union */
-extern char Emountrpc[]; /* mount rpc error */
-extern char Eshutdown[]; /* device shut down */
-extern char Enocreate[]; /* mounted directory forbids creation */
-extern char Enonexist[]; /* file does not exist */
-extern char Eexist[]; /* file already exists */
-extern char Ebadsharp[]; /* unknown device in # filename */
-extern char Enotdir[]; /* not a directory */
-extern char Eisdir[]; /* file is a directory */
-extern char Ebadchar[]; /* bad character in file name */
-extern char Efilename[]; /* file name syntax */
-extern char Eperm[]; /* permission denied */
-extern char Ebadusefd[]; /* inappropriate use of fd */
-extern char Ebadarg[]; /* bad arg in system call */
-extern char Einuse[]; /* device or object already in use */
-extern char Eio[]; /* i/o error */
-extern char Etoobig[]; /* read or write too large */
-extern char Etoosmall[]; /* read or write too small */
-extern char Enoport[]; /* network port not available */
-extern char Ehungup[]; /* i/o on hungup channel */
-extern char Ebadctl[]; /* bad process or channel control request */
-extern char Enodev[]; /* no free devices */
-extern char Eprocdied[]; /* process exited */
-extern char Enochild[]; /* no living children */
-extern char Eioload[]; /* i/o error in demand load */
-extern char Enovmem[]; /* virtual memory allocation failed */
-extern char Ebadfd[]; /* fd out of range or not open */
-extern char Enofd[]; /* no free file descriptors */
-extern char Eisstream[]; /* seek on a stream */
-extern char Ebadexec[]; /* exec header invalid */
-extern char Etimedout[]; /* connection timed out */
-extern char Econrefused[]; /* connection refused */
-extern char Econinuse[]; /* connection in use */
-extern char Eintr[]; /* interrupted */
-extern char Enomem[]; /* kernel allocate failed */
-extern char Enoswap[]; /* swap space full */
-extern char Esoverlap[]; /* segments overlap */
-extern char Emouseset[]; /* mouse type already set */
-extern char Eshort[]; /* i/o count too small */
-extern char Egreg[]; /* ken has left the building */
-extern char Ebadspec[]; /* bad attach specifier */
-extern char Enoreg[]; /* process has no saved registers */
-extern char Enoattach[]; /* mount/attach disallowed */
-extern char Eshortstat[]; /* stat buffer too small */
-extern char Ebadstat[]; /* malformed stat buffer */
-extern char Enegoff[]; /* negative i/o offset */
-extern char Ecmdargs[]; /* wrong #args in control message */
diff --git a/sys/src/cmd/unix/drawterm/kern/exportfs.c b/sys/src/cmd/unix/drawterm/kern/exportfs.c
deleted file mode 100644
index 46cb90d0c..000000000
--- a/sys/src/cmd/unix/drawterm/kern/exportfs.c
+++ /dev/null
@@ -1,821 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-typedef struct Fid Fid;
-typedef struct Export Export;
-typedef struct Exq Exq;
-
-#define nil ((void*)0)
-
-enum
-{
- Nfidhash = 1,
- MAXRPC = MAXMSG+MAXFDATA,
- MAXDIRREAD = (MAXFDATA/DIRLEN)*DIRLEN
-};
-
-struct Export
-{
- Ref r;
- Exq* work;
- Lock fidlock;
- Fid* fid[Nfidhash];
- Chan* root;
- Chan* io;
- Pgrp* pgrp;
- int npart;
- char part[MAXRPC];
-};
-
-struct Fid
-{
- Fid* next;
- Fid** last;
- Chan* chan;
- long offset;
- int fid;
- int ref; /* fcalls using the fid; locked by Export.Lock */
- int attached; /* fid attached or cloned but not clunked */
-};
-
-struct Exq
-{
- Lock lk;
- int nointr;
- int noresponse; /* don't respond to this one */
- Exq* next;
- int shut; /* has been noted for shutdown */
- Export* export;
- void* slave;
- Fcall rpc;
- char buf[MAXRPC];
-};
-
-struct
-{
- Lock l;
- Qlock qwait;
- Rendez rwait;
- Exq *head; /* work waiting for a slave */
- Exq *tail;
-}exq;
-
-static void exshutdown(Export*);
-static void exflush(Export*, int, int);
-static void exslave(void*);
-static void exfree(Export*);
-static void exportproc(Export*);
-
-static char* Exauth(Export*, Fcall*);
-static char* Exattach(Export*, Fcall*);
-static char* Exclunk(Export*, Fcall*);
-static char* Excreate(Export*, Fcall*);
-static char* Exopen(Export*, Fcall*);
-static char* Exread(Export*, Fcall*);
-static char* Exremove(Export*, Fcall*);
-static char* Exstat(Export*, Fcall*);
-static char* Exwalk(Export*, Fcall*);
-static char* Exwrite(Export*, Fcall*);
-static char* Exwstat(Export*, Fcall*);
-static char* Exversion(Export*, Fcall*);
-
-static char *(*fcalls[Tmax])(Export*, Fcall*);
-
-static char Enofid[] = "no such fid";
-static char Eseekdir[] = "can't seek on a directory";
-static char Ereaddir[] = "unaligned read of a directory";
-static int exdebug = 0;
-
-int
-sysexport(int fd)
-{
- Chan *c;
- Export *fs;
-
- if(waserror())
- return -1;
-
- c = fdtochan(fd, ORDWR, 1, 1);
- poperror();
- c->flag |= CMSG;
-
- fs = mallocz(sizeof(Export));
- fs->r.ref = 1;
- fs->pgrp = up->pgrp;
- refinc(&fs->pgrp->r);
- refinc(&up->slash->r);
- fs->root = up->slash;
- refinc(&fs->root->r);
- fs->root = domount(fs->root);
- fs->io = c;
-
- exportproc(fs);
-
- return 0;
-}
-
-static void
-exportinit(void)
-{
- lock(&exq.l);
- if(fcalls[Tversion] != nil) {
- unlock(&exq.l);
- return;
- }
-
- fmtinstall('F', fcallfmt);
- fmtinstall('D', dirfmt);
- fmtinstall('M', dirmodefmt);
- fcalls[Tversion] = Exversion;
- fcalls[Tauth] = Exauth;
- fcalls[Tattach] = Exattach;
- fcalls[Twalk] = Exwalk;
- fcalls[Topen] = Exopen;
- fcalls[Tcreate] = Excreate;
- fcalls[Tread] = Exread;
- fcalls[Twrite] = Exwrite;
- fcalls[Tclunk] = Exclunk;
- fcalls[Tremove] = Exremove;
- fcalls[Tstat] = Exstat;
- fcalls[Twstat] = Exwstat;
- unlock(&exq.l);
-}
-
-void
-exportproc(Export *fs)
-{
- Exq *q;
- char *buf;
- int n, cn, len;
-
- exportinit();
-
- for(;;){
- q = mallocz(sizeof(Exq));
- if(q == 0)
- panic("no memory");
-
- q->rpc.data = q->buf + MAXMSG;
-
- buf = q->buf;
- len = MAXRPC;
- if(fs->npart) {
- memmove(buf, fs->part, fs->npart);
- buf += fs->npart;
- len -= fs->npart;
- goto chk;
- }
- for(;;) {
- if(waserror())
- goto bad;
-
- n = (*devtab[fs->io->type].read)(fs->io, buf, len, 0);
- poperror();
-
- if(n <= 0)
- goto bad;
-
- buf += n;
- len -= n;
- chk:
- n = buf - q->buf;
-
- /* convM2S returns size of correctly decoded message */
- cn = convM2S(q->buf, &q->rpc, n);
- if(cn < 0){
- iprint("bad message type in devmnt\n");
- goto bad;
- }
- if(cn > 0) {
- n -= cn;
- if(n < 0){
- iprint("negative size in devmnt");
- goto bad;
- }
- fs->npart = n;
- if(n != 0)
- memmove(fs->part, q->buf+cn, n);
- break;
- }
- }
- if(exdebug)
- iprint("export %d <- %F\n", getpid(), &q->rpc);
-
- if(q->rpc.type == Tflush){
- exflush(fs, q->rpc.tag, q->rpc.oldtag);
- free(q);
- continue;
- }
-
- q->export = fs;
- refinc(&fs->r);
-
- lock(&exq.l);
- if(exq.head == nil)
- exq.head = q;
- else
- exq.tail->next = q;
- q->next = nil;
- exq.tail = q;
- unlock(&exq.l);
- if(exq.qwait.first == nil) {
- n = thread("exportfs", exslave, nil);
-/* iprint("launch export (pid=%ux)\n", n); */
- }
- rendwakeup(&exq.rwait);
- }
-bad:
- free(q);
- exshutdown(fs);
- exfree(fs);
-}
-
-void
-exflush(Export *fs, int flushtag, int tag)
-{
- Exq *q, **last;
- int n;
- Fcall fc;
- char buf[MAXMSG];
-
- /* hasn't been started? */
- lock(&exq.l);
- last = &exq.head;
- for(q = exq.head; q != nil; q = q->next){
- if(q->export == fs && q->rpc.tag == tag){
- *last = q->next;
- unlock(&exq.l);
- exfree(fs);
- free(q);
- goto Respond;
- }
- last = &q->next;
- }
- unlock(&exq.l);
-
- /* in progress? */
- lock(&fs->r.l);
- for(q = fs->work; q != nil; q = q->next){
- if(q->rpc.tag == tag && !q->noresponse){
- lock(&q->lk);
- q->noresponse = 1;
- if(!q->nointr)
- intr(q->slave);
- unlock(&q->lk);
- unlock(&fs->r.l);
- goto Respond;
- return;
- }
- }
- unlock(&fs->r.l);
-
-if(exdebug) iprint("exflush: did not find rpc: %d\n", tag);
-
-Respond:
- fc.type = Rflush;
- fc.tag = flushtag;
- n = convS2M(&fc, buf);
-if(exdebug) iprint("exflush -> %F\n", &fc);
- if(!waserror()){
- (*devtab[fs->io->type].write)(fs->io, buf, n, 0);
- poperror();
- }
-}
-
-void
-exshutdown(Export *fs)
-{
- Exq *q, **last;
-
- lock(&exq.l);
- last = &exq.head;
- for(q = exq.head; q != nil; q = *last){
- if(q->export == fs){
- *last = q->next;
- exfree(fs);
- free(q);
- continue;
- }
- last = &q->next;
- }
- unlock(&exq.l);
-
- lock(&fs->r.l);
- q = fs->work;
- while(q != nil){
- if(q->shut){
- q = q->next;
- continue;
- }
- q->shut = 1;
- unlock(&fs->r.l);
- /* postnote(q->slave, 1, "interrupted", NUser); */
- iprint("postnote 2!\n");
- lock(&fs->r.l);
- q = fs->work;
- }
- unlock(&fs->r.l);
-}
-
-void
-exfree(Export *fs)
-{
- Fid *f, *n;
- int i;
-
- if(refdec(&fs->r) != 0)
- return;
- closepgrp(fs->pgrp);
- cclose(fs->root);
- cclose(fs->io);
- for(i = 0; i < Nfidhash; i++){
- for(f = fs->fid[i]; f != nil; f = n){
- if(f->chan != nil)
- cclose(f->chan);
- n = f->next;
- free(f);
- }
- }
- free(fs);
-}
-
-int
-exwork(void *a)
-{
- return exq.head != nil;
-}
-
-void
-exslave(void *a)
-{
- Export *fs;
- Exq *q, *t, **last;
- char *err;
- int n;
-/*
- closepgrp(up->pgrp);
- up->pgrp = nil;
-*/
- for(;;){
- qlock(&exq.qwait);
- rendsleep(&exq.rwait, exwork, nil);
-
- lock(&exq.l);
- q = exq.head;
- if(q == nil) {
- unlock(&exq.l);
- qunlock(&exq.qwait);
- continue;
- }
- exq.head = q->next;
- q->slave = curthread();
- unlock(&exq.l);
-
- qunlock(&exq.qwait);
-
- q->noresponse = 0;
- q->nointr = 0;
- fs = q->export;
- lock(&fs->r.l);
- q->next = fs->work;
- fs->work = q;
- unlock(&fs->r.l);
-
- up->pgrp = q->export->pgrp;
-
- if(exdebug > 1)
- iprint("exslave dispatch %d %F\n", getpid(), &q->rpc);
-
- if(waserror()){
- iprint("exslave err %r\n");
- err = up->errstr;
- goto Err;
- }
- if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
- err = "bad fcall type";
- else
- err = (*fcalls[q->rpc.type])(fs, &q->rpc);
-
- poperror();
- Err:;
- q->rpc.type++;
- if(err){
- q->rpc.type = Rerror;
- strncpy(q->rpc.ename, err, ERRLEN);
- }
- n = convS2M(&q->rpc, q->buf);
-
- if(exdebug)
- iprint("exslve %d -> %F\n", getpid(), &q->rpc);
-
- lock(&q->lk);
- if(q->noresponse == 0){
- q->nointr = 1;
- clearintr();
- if(!waserror()){
- (*devtab[fs->io->type].write)(fs->io, q->buf, n, 0);
- poperror();
- }
- }
- unlock(&q->lk);
-
- /*
- * exflush might set noresponse at this point, but
- * setting noresponse means don't send a response now;
- * it's okay that we sent a response already.
- */
- if(exdebug > 1)
- iprint("exslave %d written %d\n", getpid(), q->rpc.tag);
-
- lock(&fs->r.l);
- last = &fs->work;
- for(t = fs->work; t != nil; t = t->next){
- if(t == q){
- *last = q->next;
- break;
- }
- last = &t->next;
- }
- unlock(&fs->r.l);
-
- exfree(q->export);
- free(q);
- }
- iprint("exslave shut down");
- threadexit();
-}
-
-Fid*
-Exmkfid(Export *fs, int fid)
-{
- ulong h;
- Fid *f, *nf;
-
- nf = mallocz(sizeof(Fid));
- if(nf == nil)
- return nil;
- lock(&fs->fidlock);
- h = fid % Nfidhash;
- for(f = fs->fid[h]; f != nil; f = f->next){
- if(f->fid == fid){
- unlock(&fs->fidlock);
- free(nf);
- return nil;
- }
- }
-
- nf->next = fs->fid[h];
- if(nf->next != nil)
- nf->next->last = &nf->next;
- nf->last = &fs->fid[h];
- fs->fid[h] = nf;
-
- nf->fid = fid;
- nf->ref = 1;
- nf->attached = 1;
- nf->offset = 0;
- nf->chan = nil;
- unlock(&fs->fidlock);
- return nf;
-}
-
-Fid*
-Exgetfid(Export *fs, int fid)
-{
- Fid *f;
- ulong h;
-
- lock(&fs->fidlock);
- h = fid % Nfidhash;
- for(f = fs->fid[h]; f; f = f->next) {
- if(f->fid == fid){
- if(f->attached == 0)
- break;
- f->ref++;
- unlock(&fs->fidlock);
- return f;
- }
- }
- unlock(&fs->fidlock);
- return nil;
-}
-
-void
-Exputfid(Export *fs, Fid *f)
-{
- lock(&fs->fidlock);
- f->ref--;
- if(f->ref == 0 && f->attached == 0){
- if(f->chan != nil)
- cclose(f->chan);
- f->chan = nil;
- *f->last = f->next;
- if(f->next != nil)
- f->next->last = f->last;
- unlock(&fs->fidlock);
- free(f);
- return;
- }
- unlock(&fs->fidlock);
-}
-
-char*
-Exsession(Export *e, Fcall *rpc)
-{
- memset(rpc->authid, 0, sizeof(rpc->authid));
- memset(rpc->authdom, 0, sizeof(rpc->authdom));
- memset(rpc->chal, 0, sizeof(rpc->chal));
- return nil;
-}
-
-char*
-Exauth(Export *e, Fcall *f)
-{
- return "authentication not required";
-}
-
-char*
-Exattach(Export *fs, Fcall *rpc)
-{
- Fid *f;
-
- f = Exmkfid(fs, rpc->fid);
- if(f == nil)
- return Einuse;
- if(waserror()){
- f->attached = 0;
- Exputfid(fs, f);
- return up->errstr;
- }
- f->chan = clone(fs->root, nil);
- poperror();
- rpc->qid = f->chan->qid;
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exclone(Export *fs, Fcall *rpc)
-{
- Fid *f, *nf;
-
- if(rpc->fid == rpc->newfid)
- return Einuse;
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- nf = Exmkfid(fs, rpc->newfid);
- if(nf == nil){
- Exputfid(fs, f);
- return Einuse;
- }
- if(waserror()){
- Exputfid(fs, f);
- Exputfid(fs, nf);
- return up->errstr;
- }
- nf->chan = clone(f->chan, nil);
- poperror();
- Exputfid(fs, f);
- Exputfid(fs, nf);
- return nil;
-}
-
-char*
-Exclunk(Export *fs, Fcall *rpc)
-{
- Fid *f;
-
- f = Exgetfid(fs, rpc->fid);
- if(f != nil){
- f->attached = 0;
- Exputfid(fs, f);
- }
- return nil;
-}
-
-char*
-Exwalk(Export *fs, Fcall *rpc)
-{
- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){
- Exputfid(fs, f);
- return up->errstr;
- }
- c = walk(f->chan, rpc->name, 1);
- if(c == nil)
- error(Enonexist);
- poperror();
-
- f->chan = c;
- rpc->qid = c->qid;
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exopen(Export *fs, Fcall *rpc)
-{
- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){
- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- c = (*devtab[c->type].open)(c, rpc->mode);
- poperror();
-
- f->chan = c;
- f->offset = 0;
- rpc->qid = f->chan->qid;
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Excreate(Export *fs, Fcall *rpc)
-{
- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){
- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- if(c->mnt && !(c->flag&CCREATE))
- c = createdir(c);
- (*devtab[c->type].create)(c, rpc->name, rpc->mode, rpc->perm);
- poperror();
-
- f->chan = c;
- rpc->qid = f->chan->qid;
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exread(Export *fs, Fcall *rpc)
-{
- Fid *f;
- Chan *c;
- long off;
- int dir, n, seek;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
-
- c = f->chan;
- dir = c->qid.path & CHDIR;
- if(dir){
- rpc->count -= rpc->count%DIRLEN;
- if(rpc->offset%DIRLEN || rpc->count==0){
- Exputfid(fs, f);
- return Ereaddir;
- }
- if(f->offset > rpc->offset){
- Exputfid(fs, f);
- return Eseekdir;
- }
- }
-
- if(waserror()) {
- Exputfid(fs, f);
- return up->errstr;
- }
-
- for(;;){
- n = rpc->count;
- seek = 0;
- off = rpc->offset;
- if(dir && f->offset != off){
- off = f->offset;
- n = rpc->offset - off;
- if(n > MAXDIRREAD)
- n = MAXDIRREAD;
- seek = 1;
- }
- if(dir && c->mnt != nil)
- n = unionread(c, rpc->data, n);
- else{
- c->offset = off;
- n = (*devtab[c->type].read)(c, rpc->data, n, off);
- }
- if(n == 0 || !seek)
- break;
- f->offset = off + n;
- c->offset += n;
- }
- rpc->count = n;
- poperror();
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exwrite(Export *fs, Fcall *rpc)
-{
- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){
- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- if(c->qid.path & CHDIR)
- error(Eisdir);
- rpc->count = (*devtab[c->type].write)(c, rpc->data, rpc->count, rpc->offset);
- poperror();
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exstat(Export *fs, Fcall *rpc)
-{
- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){
- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- (*devtab[c->type].stat)(c, rpc->stat);
- poperror();
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exwstat(Export *fs, Fcall *rpc)
-{
- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){
- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- (*devtab[c->type].wstat)(c, rpc->stat);
- poperror();
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exremove(Export *fs, Fcall *rpc)
-{
- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){
- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- (*devtab[c->type].remove)(c);
- poperror();
-
- /*
- * chan is already clunked by remove.
- * however, we need to recover the chan,
- * and follow sysremove's lead in making to point to root.
- */
- c->type = 0;
-
- f->attached = 0;
- Exputfid(fs, f);
- return nil;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/fns.h b/sys/src/cmd/unix/drawterm/kern/fns.h
deleted file mode 100644
index 97a935941..000000000
--- a/sys/src/cmd/unix/drawterm/kern/fns.h
+++ /dev/null
@@ -1,392 +0,0 @@
-#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1))
-
-void accounttime(void);
-void addclock0link(void (*)(void), int);
-int addphysseg(Physseg*);
-void addbootfile(char*, uchar*, ulong);
-Block* adjustblock(Block*, int);
-void alarmkproc(void*);
-Block* allocb(int);
-int anyhigher(void);
-int anyready(void);
-Page* auxpage(void);
-Block* bl2mem(uchar*, Block*, int);
-int blocklen(Block*);
-void callwithureg(void(*)(Ureg*));
-char* c2name(Chan*);
-int cangetc(void*);
-int canlock(Lock*);
-int canpage(Proc*);
-int canputc(void*);
-int canqlock(QLock*);
-int canrlock(RWlock*);
-void chandevinit(void);
-void chandevreset(void);
-void chandevshutdown(void);
-void chanfree(Chan*);
-void chanrec(Mnt*);
-void checkalarms(void);
-void checkb(Block*, char*);
-void cinit(void);
-Chan* cclone(Chan*);
-void cclose(Chan*);
-char* clipread(void);
-int clipwrite(char*);
-void closeegrp(Egrp*);
-void closefgrp(Fgrp*);
-void closemount(Mount*);
-void closepgrp(Pgrp*);
-void closergrp(Rgrp*);
-long clrfpintr(void);
-void cmderror(Cmdbuf*, char*);
-int cmount(Chan**, Chan*, int, char*);
-void cnameclose(Cname*);
-void confinit(void);
-void confinit1(int);
-int consactive(void);
-extern void (*consdebug)(void);
-void copen(Chan*);
-Block* concatblock(Block*);
-Block* copyblock(Block*, int);
-void copypage(Page*, Page*);
-int cread(Chan*, uchar*, int, vlong);
-void cunmount(Chan*, Chan*);
-void cupdate(Chan*, uchar*, int, vlong);
-void cwrite(Chan*, uchar*, int, vlong);
-ulong dbgpc(Proc*);
-int decref(Ref*);
-int decrypt(void*, void*, int);
-void delay(int);
-Chan* devattach(int, char*);
-Block* devbread(Chan*, long, ulong);
-long devbwrite(Chan*, Block*, ulong);
-Chan* devclone(Chan*);
-int devconfig(int, char *, DevConf *);
-void devcreate(Chan*, char*, int, ulong);
-void devdir(Chan*, Qid, char*, vlong, char*, long, Dir*);
-long devdirread(Chan*, char*, long, Dirtab*, int, Devgen*);
-Devgen devgen;
-void devinit(void);
-int devno(int, int);
-Chan* devopen(Chan*, int, Dirtab*, int, Devgen*);
-void devpermcheck(char*, ulong, int);
-void devpower(int);
-void devremove(Chan*);
-void devreset(void);
-void devshutdown(void);
-int devstat(Chan*, uchar*, int, Dirtab*, int, Devgen*);
-Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*);
-int devwstat(Chan*, uchar*, int);
-void drawactive(int);
-void drawcmap(void);
-int drawcanqlock(void);
-void drawqlock(void);
-void drawqunlock(void);
-void dumpaproc(Proc*);
-void dumpqueues(void);
-void dumpregs(Ureg*);
-void dumpstack(void);
-Fgrp* dupfgrp(Fgrp*);
-void duppage(Page*);
-void dupswap(Page*);
-int emptystr(char*);
-int encrypt(void*, void*, int);
-void envcpy(Egrp*, Egrp*);
-int eqchan(Chan*, Chan*, int);
-int eqqid(Qid, Qid);
-void error(char*);
-long execregs(ulong, ulong, ulong);
-void exhausted(char*);
-void exit(int);
-uvlong fastticks(uvlong*);
-int fault(ulong, int);
-void fdclose(int, int);
-Chan* fdtochan(int, int, int, int);
-int fixfault(Segment*, ulong, int, int);
-void flushmmu(void);
-void forkchild(Proc*, Ureg*);
-void forkret(void);
-void free(void*);
-void freeb(Block*);
-void freeblist(Block*);
-int freebroken(void);
-void freepte(Segment*, Pte*);
-void freesegs(int);
-void freesession(Session*);
-ulong getmalloctag(void*);
-ulong getrealloctag(void*);
-void gotolabel(Label*);
-char* getconfenv(void);
-int haswaitq(void*);
-long hostdomainwrite(char*, int);
-long hostownerwrite(char*, int);
-void hzsched(void);
-void iallocinit(void);
-Block* iallocb(int);
-void iallocsummary(void);
-long ibrk(ulong, int);
-void ilock(Lock*);
-void iunlock(Lock*);
-int incref(Ref*);
-void initseg(void);
-int iprint(char*, ...);
-void isdir(Chan*);
-int iseve(void);
-#define islo() (0)
-Segment* isoverlap(Proc*, ulong, int);
-int ispages(void*);
-int isphysseg(char*);
-void ixsummary(void);
-void kbdclock(void);
-int kbdcr2nl(Queue*, int);
-int kbdputc(Queue*, int);
-void kbdrepeat(int);
-long keyread(char*, int, long);
-void kickpager(void);
-void killbig(void);
-int kproc(char*, void(*)(void*), void*);
-void kprocchild(Proc*, void (*)(void*), void*);
-extern void (*kproftimer)(ulong);
-void ksetenv(char*, char*, int);
-void kstrcpy(char*, char*, int);
-void kstrdup(char**, char*);
-long latin1(Rune*, int);
-void lock(Lock*);
-void lockinit(void);
-void logopen(Log*);
-void logclose(Log*);
-char* logctl(Log*, int, char**, Logflag*);
-void logn(Log*, int, void*, int);
-long logread(Log*, void*, ulong, long);
-void log(Log*, int, char*, ...);
-Cmdtab* lookupcmd(Cmdbuf*, Cmdtab*, int);
-void machinit(void);
-void* mallocz(ulong, int);
-#define malloc kmalloc
-void* malloc(ulong);
-void mallocsummary(void);
-Block* mem2bl(uchar*, int);
-void mfreeseg(Segment*, ulong, int);
-void microdelay(int);
-void mkqid(Qid*, vlong, ulong, int);
-void mmurelease(Proc*);
-void mmuswitch(Proc*);
-Chan* mntauth(Chan*, char*);
-void mntdump(void);
-long mntversion(Chan*, char*, int, int);
-void mountfree(Mount*);
-ulong ms2tk(ulong);
-ulong msize(void*);
-ulong ms2tk(ulong);
-uvlong ms2fastticks(ulong);
-void muxclose(Mnt*);
-Chan* namec(char*, int, int, ulong);
-Chan* newchan(void);
-int newfd(Chan*);
-Mhead* newmhead(Chan*);
-Mount* newmount(Mhead*, Chan*, int, char*);
-Page* newpage(int, Segment **, ulong);
-Pgrp* newpgrp(void);
-Rgrp* newrgrp(void);
-Proc* newproc(void);
-char* nextelem(char*, char*);
-void nexterror(void);
-Cname* newcname(char*);
-int notify(Ureg*);
-int nrand(int);
-int okaddr(ulong, ulong, int);
-int openmode(ulong);
-void oserrstr(void);
-void oserror(void);
-Block* packblock(Block*);
-Block* padblock(Block*, int);
-void pagechainhead(Page*);
-void pageinit(void);
-void pagersummary(void);
-void panic(char*, ...);
-Cmdbuf* parsecmd(char *a, int n);
-ulong perfticks(void);
-void pexit(char*, int);
-int preempted(void);
-void printinit(void);
-int procindex(ulong);
-void pgrpcpy(Pgrp*, Pgrp*);
-void pgrpnote(ulong, char*, long, int);
-Pgrp* pgrptab(int);
-void pio(Segment *, ulong, ulong, Page **);
-#define poperror() up->nerrlab--
-void portclock(Ureg*);
-int postnote(Proc*, int, char*, int);
-int pprint(char*, ...);
-void prflush(void);
-ulong procalarm(ulong);
-int proccounter(char *name);
-void procctl(Proc*);
-void procdump(void);
-int procfdprint(Chan*, int, int, char*, int);
-void procinit0(void);
-void procflushseg(Segment*);
-void procpriority(Proc*, int, int);
-Proc* proctab(int);
-void procwired(Proc*, int);
-Pte* ptealloc(void);
-Pte* ptecpy(Pte*);
-int pullblock(Block**, int);
-Block* pullupblock(Block*, int);
-Block* pullupqueue(Queue*, int);
-void putmhead(Mhead*);
-void putmmu(ulong, ulong, Page*);
-void putpage(Page*);
-void putseg(Segment*);
-void putstr(char*);
-void putstrn(char*, int);
-void putswap(Page*);
-ulong pwait(Waitmsg*);
-Label* pwaserror(void);
-void qaddlist(Queue*, Block*);
-Block* qbread(Queue*, int);
-long qbwrite(Queue*, Block*);
-Queue* qbypass(void (*)(void*, Block*), void*);
-int qcanread(Queue*);
-void qclose(Queue*);
-int qconsume(Queue*, void*, int);
-Block* qcopy(Queue*, int, ulong);
-int qdiscard(Queue*, int);
-void qflush(Queue*);
-void qfree(Queue*);
-int qfull(Queue*);
-Block* qget(Queue*);
-void qhangup(Queue*, char*);
-int qisclosed(Queue*);
-void qinit(void);
-int qiwrite(Queue*, void*, int);
-int qlen(Queue*);
-void qlock(QLock*);
-Queue* qopen(int, int, void (*)(void*), void*);
-int qpass(Queue*, Block*);
-int qpassnolim(Queue*, Block*);
-int qproduce(Queue*, void*, int);
-void qputback(Queue*, Block*);
-long qread(Queue*, void*, int);
-Block* qremove(Queue*);
-void qreopen(Queue*);
-void qsetlimit(Queue*, int);
-void qunlock(QLock*);
-int qwindow(Queue*);
-int qwrite(Queue*, void*, int);
-void qnoblock(Queue*, int);
-int rand(void);
-void randominit(void);
-ulong randomread(void*, ulong);
-void rdb(void);
-int readnum(ulong, char*, ulong, ulong, int);
-int readstr(ulong, char*, ulong, char*);
-void ready(Proc*);
-void rebootcmd(int, char**);
-void reboot(void*, void*, ulong);
-void relocateseg(Segment*, ulong);
-void renameuser(char*, char*);
-void resched(char*);
-void resrcwait(char*);
-int return0(void*);
-void rlock(RWlock*);
-long rtctime(void);
-void runlock(RWlock*);
-Proc* runproc(void);
-void savefpregs(FPsave*);
-extern void (*saveintrts)(void);
-void sched(void);
-void scheddump(void);
-void schedinit(void);
-extern void (*screenputs)(char*, int);
-long seconds(void);
-ulong segattach(Proc*, ulong, char *, ulong, ulong);
-void segclock(ulong);
-void segpage(Segment*, Page*);
-void setkernur(Ureg*, Proc*);
-int setlabel(Label*);
-void setmalloctag(void*, uintptr);
-void setrealloctag(void*, ulong);
-void setregisters(Ureg*, char*, char*, int);
-void setswapchan(Chan*);
-long showfilewrite(char*, int);
-char* skipslash(char*);
-void sleep(Rendez*, int(*)(void*), void*);
-void* smalloc(ulong);
-int splhi(void);
-int spllo(void);
-void splx(int);
-void splxpc(int);
-char* srvname(Chan*);
-int swapcount(ulong);
-int swapfull(void);
-void swapinit(void);
-void timeradd(Timer*);
-void timerdel(Timer*);
-void timersinit(void);
-void timerintr(Ureg*, uvlong);
-void timerset(uvlong);
-ulong tk2ms(ulong);
-#define TK2MS(x) ((x)*(1000/HZ))
-vlong todget(vlong*);
-void todfix(void);
-void todsetfreq(vlong);
-void todinit(void);
-void todset(vlong, vlong, int);
-Block* trimblock(Block*, int, int);
-void tsleep(Rendez*, int (*)(void*), void*, int);
-int uartctl(Uart*, char*);
-int uartgetc(void);
-void uartkick(void*);
-void uartmouse(Uart*, int (*)(Queue*, int), int);
-void uartputc(int);
-void uartputs(char*, int);
-void uartrecv(Uart*, char);
-Uart* uartsetup(Uart*);
-int uartstageoutput(Uart*);
-void unbreak(Proc*);
-void uncachepage(Page*);
-long unionread(Chan*, void*, long);
-void unlock(Lock*);
-Proc** uploc(void);
-void userinit(void);
-ulong userpc(void);
-long userwrite(char*, int);
-#define validaddr(a, b, c)
-void validname(char*, int);
-void validstat(uchar*, int);
-void vcacheinval(Page*, ulong);
-void* vmemchr(void*, int, int);
-Proc* wakeup(Rendez*);
-int walk(Chan**, char**, int, int, int*);
-#define waserror() (setjmp(pwaserror()->buf))
-void wlock(RWlock*);
-void wunlock(RWlock*);
-void* xalloc(ulong);
-void* xallocz(ulong, int);
-void xfree(void*);
-void xhole(ulong, ulong);
-void xinit(void);
-int xmerge(void*, void*);
-void* xspanalloc(ulong, int, ulong);
-void xsummary(void);
-void yield(void);
-Segment* data2txt(Segment*);
-Segment* dupseg(Segment**, int, int);
-Segment* newseg(int, ulong, ulong);
-Segment* seg(Proc*, ulong, int);
-void hnputv(void*, vlong);
-void hnputl(void*, ulong);
-void hnputs(void*, ushort);
-vlong nhgetv(void*);
-ulong nhgetl(void*);
-ushort nhgets(void*);
-ulong ticks(void);
-void osproc(Proc*);
-void osnewproc(Proc*);
-void procsleep(void);
-void procwakeup(Proc*);
-void osinit(void);
-void screeninit(void);
-extern void terminit(void);
-
diff --git a/sys/src/cmd/unix/drawterm/kern/netif.h b/sys/src/cmd/unix/drawterm/kern/netif.h
deleted file mode 100644
index 06c42aec8..000000000
--- a/sys/src/cmd/unix/drawterm/kern/netif.h
+++ /dev/null
@@ -1,133 +0,0 @@
-typedef struct Etherpkt Etherpkt;
-typedef struct Netaddr Netaddr;
-typedef struct Netfile Netfile;
-typedef struct Netif Netif;
-
-enum
-{
- Nmaxaddr= 64,
- Nmhash= 31,
-
- Ncloneqid= 1,
- Naddrqid,
- N2ndqid,
- N3rdqid,
- Ndataqid,
- Nctlqid,
- Nstatqid,
- Ntypeqid,
- Nifstatqid,
-};
-
-/*
- * Macros to manage Qid's used for multiplexed devices
- */
-#define NETTYPE(x) (((ulong)x)&0x1f)
-#define NETID(x) ((((ulong)x))>>5)
-#define NETQID(i,t) ((((ulong)i)<<5)|(t))
-
-/*
- * one per multiplexed connection
- */
-struct Netfile
-{
- QLock lk;
-
- int inuse;
- ulong mode;
- char owner[KNAMELEN];
-
- int type; /* multiplexor type */
- int prom; /* promiscuous mode */
- int scan; /* base station scanning interval */
- int bridge; /* bridge mode */
- int headersonly; /* headers only - no data */
- uchar maddr[8]; /* bitmask of multicast addresses requested */
- int nmaddr; /* number of multicast addresses */
-
- Queue *in; /* input buffer */
-};
-
-/*
- * a network address
- */
-struct Netaddr
-{
- Netaddr *next; /* allocation chain */
- Netaddr *hnext;
- uchar addr[Nmaxaddr];
- int ref;
-};
-
-/*
- * a network interface
- */
-struct Netif
-{
- QLock lk;
-
- /* multiplexing */
- char name[KNAMELEN]; /* for top level directory */
- int nfile; /* max number of Netfiles */
- Netfile **f;
-
- /* about net */
- int limit; /* flow control */
- int alen; /* address length */
- int mbps; /* megabits per sec */
- uchar addr[Nmaxaddr];
- uchar bcast[Nmaxaddr];
- Netaddr *maddr; /* known multicast addresses */
- int nmaddr; /* number of known multicast addresses */
- Netaddr *mhash[Nmhash]; /* hash table of multicast addresses */
- int prom; /* number of promiscuous opens */
- int scan; /* number of base station scanners */
- int all; /* number of -1 multiplexors */
-
- /* statistics */
- int misses;
- int inpackets;
- int outpackets;
- int crcs; /* input crc errors */
- int oerrs; /* output errors */
- int frames; /* framing errors */
- int overflows; /* packet overflows */
- int buffs; /* buffering errors */
- int soverflows; /* software overflow */
-
- /* routines for touching the hardware */
- void *arg;
- void (*promiscuous)(void*, int);
- void (*multicast)(void*, uchar*, int);
- void (*scanbs)(void*, uint); /* scan for base stations */
-};
-
-void netifinit(Netif*, char*, int, ulong);
-Walkqid* netifwalk(Netif*, Chan*, Chan*, char **, int);
-Chan* netifopen(Netif*, Chan*, int);
-void netifclose(Netif*, Chan*);
-long netifread(Netif*, Chan*, void*, long, ulong);
-Block* netifbread(Netif*, Chan*, long, ulong);
-long netifwrite(Netif*, Chan*, void*, long);
-int netifwstat(Netif*, Chan*, uchar*, int);
-int netifstat(Netif*, Chan*, uchar*, int);
-int activemulti(Netif*, uchar*, int);
-
-/*
- * Ethernet specific
- */
-enum
-{
- Eaddrlen= 6,
- ETHERMINTU = 60, /* minimum transmit size */
- ETHERMAXTU = 1514, /* maximum transmit size */
- ETHERHDRSIZE = 14, /* size of an ethernet header */
-};
-
-struct Etherpkt
-{
- uchar d[Eaddrlen];
- uchar s[Eaddrlen];
- uchar type[2];
- uchar data[1500];
-};
diff --git a/sys/src/cmd/unix/drawterm/kern/parse.c b/sys/src/cmd/unix/drawterm/kern/parse.c
deleted file mode 100644
index 8c991f8dc..000000000
--- a/sys/src/cmd/unix/drawterm/kern/parse.c
+++ /dev/null
@@ -1,113 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-/*
- * Generous estimate of number of fields, including terminal nil pointer
- */
-static int
-ncmdfield(char *p, int n)
-{
- int white, nwhite;
- char *ep;
- int nf;
-
- if(p == nil)
- return 1;
-
- nf = 0;
- ep = p+n;
- white = 1; /* first text will start field */
- while(p < ep){
- nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */
- if(white && !nwhite) /* beginning of field */
- nf++;
- white = nwhite;
- }
- return nf+1; /* +1 for nil */
-}
-
-/*
- * parse a command written to a device
- */
-Cmdbuf*
-parsecmd(char *p, int n)
-{
- Cmdbuf *volatile cb;
- int nf;
- char *sp;
-
- nf = ncmdfield(p, n);
-
- /* allocate Cmdbuf plus string pointers plus copy of string including \0 */
- sp = smalloc(sizeof(*cb) + nf * sizeof(char*) + n + 1);
- cb = (Cmdbuf*)sp;
- cb->f = (char**)(&cb[1]);
- cb->buf = (char*)(&cb->f[nf]);
-
- if(up!=nil && waserror()){
- free(cb);
- nexterror();
- }
- memmove(cb->buf, p, n);
- if(up != nil)
- poperror();
-
- /* dump new line and null terminate */
- if(n > 0 && cb->buf[n-1] == '\n')
- n--;
- cb->buf[n] = '\0';
-
- cb->nf = tokenize(cb->buf, cb->f, nf-1);
- cb->f[cb->nf] = nil;
-
- return cb;
-}
-
-/*
- * Reconstruct original message, for error diagnostic
- */
-void
-cmderror(Cmdbuf *cb, char *s)
-{
- int i;
- char *p, *e;
-
- p = up->genbuf;
- e = p+ERRMAX-10;
- p = seprint(p, e, "%s \"", s);
- for(i=0; i<cb->nf; i++){
- if(i > 0)
- p = seprint(p, e, " ");
- p = seprint(p, e, "%q", cb->f[i]);
- }
- strcpy(p, "\"");
- error(up->genbuf);
-}
-
-/*
- * Look up entry in table
- */
-Cmdtab*
-lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
-{
- int i;
- Cmdtab *ct;
-
- if(cb->nf == 0)
- error("empty control message");
-
- for(ct = ctab, i=0; i<nctab; i++, ct++){
- if(strcmp(ct->cmd, "*") !=0) /* wildcard always matches */
- if(strcmp(ct->cmd, cb->f[0]) != 0)
- continue;
- if(ct->narg != 0 && ct->narg != cb->nf)
- cmderror(cb, Ecmdargs);
- return ct;
- }
-
- cmderror(cb, "unknown control message");
- return nil;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/pgrp.c b/sys/src/cmd/unix/drawterm/kern/pgrp.c
deleted file mode 100644
index 30b1f3e7b..000000000
--- a/sys/src/cmd/unix/drawterm/kern/pgrp.c
+++ /dev/null
@@ -1,272 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-static Ref pgrpid;
-static Ref mountid;
-
-#ifdef NOTDEF
-void
-pgrpnote(ulong noteid, char *a, long n, int flag)
-{
- Proc *p, *ep;
- char buf[ERRMAX];
-
- if(n >= ERRMAX-1)
- error(Etoobig);
-
- memmove(buf, a, n);
- buf[n] = 0;
- p = proctab(0);
- ep = p+conf.nproc;
- for(; p < ep; p++) {
- if(p->state == Dead)
- continue;
- if(up != p && p->noteid == noteid && p->kp == 0) {
- qlock(&p->debug);
- if(p->pid == 0 || p->noteid != noteid){
- qunlock(&p->debug);
- continue;
- }
- if(!waserror()) {
- postnote(p, 0, buf, flag);
- poperror();
- }
- qunlock(&p->debug);
- }
- }
-}
-#endif
-
-Pgrp*
-newpgrp(void)
-{
- Pgrp *p;
-
- p = smalloc(sizeof(Pgrp));
- p->ref.ref = 1;
- p->pgrpid = incref(&pgrpid);
- return p;
-}
-
-Rgrp*
-newrgrp(void)
-{
- Rgrp *r;
-
- r = smalloc(sizeof(Rgrp));
- r->ref.ref = 1;
- return r;
-}
-
-void
-closergrp(Rgrp *r)
-{
- if(decref(&r->ref) == 0)
- free(r);
-}
-
-void
-closepgrp(Pgrp *p)
-{
- Mhead **h, **e, *f, *next;
-
- if(decref(&p->ref) != 0)
- return;
-
- qlock(&p->debug);
- wlock(&p->ns);
- p->pgrpid = -1;
-
- e = &p->mnthash[MNTHASH];
- for(h = p->mnthash; h < e; h++) {
- for(f = *h; f; f = next) {
- wlock(&f->lock);
- cclose(f->from);
- mountfree(f->mount);
- f->mount = nil;
- next = f->hash;
- wunlock(&f->lock);
- putmhead(f);
- }
- }
- wunlock(&p->ns);
- qunlock(&p->debug);
- free(p);
-}
-
-void
-pgrpinsert(Mount **order, Mount *m)
-{
- Mount *f;
-
- m->order = 0;
- if(*order == 0) {
- *order = m;
- return;
- }
- for(f = *order; f; f = f->order) {
- if(m->mountid < f->mountid) {
- m->order = f;
- *order = m;
- return;
- }
- order = &f->order;
- }
- *order = m;
-}
-
-/*
- * pgrpcpy MUST preserve the mountid allocation order of the parent group
- */
-void
-pgrpcpy(Pgrp *to, Pgrp *from)
-{
- int i;
- Mount *n, *m, **link, *order;
- Mhead *f, **tom, **l, *mh;
-
- wlock(&from->ns);
- order = 0;
- tom = to->mnthash;
- for(i = 0; i < MNTHASH; i++) {
- l = tom++;
- for(f = from->mnthash[i]; f; f = f->hash) {
- rlock(&f->lock);
- mh = newmhead(f->from);
- *l = mh;
- l = &mh->hash;
- link = &mh->mount;
- for(m = f->mount; m; m = m->next) {
- n = newmount(mh, m->to, m->mflag, m->spec);
- m->copy = n;
- pgrpinsert(&order, m);
- *link = n;
- link = &n->next;
- }
- runlock(&f->lock);
- }
- }
- /*
- * Allocate mount ids in the same sequence as the parent group
- */
- lock(&mountid.lk);
- for(m = order; m; m = m->order)
- m->copy->mountid = mountid.ref++;
- unlock(&mountid.lk);
- wunlock(&from->ns);
-}
-
-Fgrp*
-dupfgrp(Fgrp *f)
-{
- Fgrp *new;
- Chan *c;
- int i;
-
- new = smalloc(sizeof(Fgrp));
- if(f == nil){
- new->fd = smalloc(DELTAFD*sizeof(Chan*));
- new->nfd = DELTAFD;
- new->ref.ref = 1;
- return new;
- }
-
- lock(&f->ref.lk);
- /* Make new fd list shorter if possible, preserving quantization */
- new->nfd = f->maxfd+1;
- i = new->nfd%DELTAFD;
- if(i != 0)
- new->nfd += DELTAFD - i;
- new->fd = malloc(new->nfd*sizeof(Chan*));
- if(new->fd == 0){
- unlock(&f->ref.lk);
- error("no memory for fgrp");
- }
- new->ref.ref = 1;
-
- new->maxfd = f->maxfd;
- for(i = 0; i <= f->maxfd; i++) {
- if((c = f->fd[i])){
- incref(&c->ref);
- new->fd[i] = c;
- }
- }
- unlock(&f->ref.lk);
-
- return new;
-}
-
-void
-closefgrp(Fgrp *f)
-{
- int i;
- Chan *c;
-
- if(f == 0)
- return;
-
- if(decref(&f->ref) != 0)
- return;
-
- for(i = 0; i <= f->maxfd; i++)
- if((c = f->fd[i]))
- cclose(c);
-
- free(f->fd);
- free(f);
-}
-
-Mount*
-newmount(Mhead *mh, Chan *to, int flag, char *spec)
-{
- Mount *m;
-
- m = smalloc(sizeof(Mount));
- m->to = to;
- m->head = mh;
- incref(&to->ref);
- m->mountid = incref(&mountid);
- m->mflag = flag;
- if(spec != 0)
- kstrdup(&m->spec, spec);
-
- return m;
-}
-
-void
-mountfree(Mount *m)
-{
- Mount *f;
-
- while(m) {
- f = m->next;
- cclose(m->to);
- m->mountid = 0;
- free(m->spec);
- free(m);
- m = f;
- }
-}
-
-#ifdef NOTDEF
-void
-resrcwait(char *reason)
-{
- char *p;
-
- if(up == 0)
- panic("resrcwait");
-
- p = up->psstate;
- if(reason) {
- up->psstate = reason;
- print("%s\n", reason);
- }
-
- tsleep(&up->sleep, return0, 0, 300);
- up->psstate = p;
-}
-#endif
diff --git a/sys/src/cmd/unix/drawterm/kern/posix.c b/sys/src/cmd/unix/drawterm/kern/posix.c
deleted file mode 100644
index 069d6531f..000000000
--- a/sys/src/cmd/unix/drawterm/kern/posix.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Posix generic OS implementation for drawterm.
- */
-
-#include "u.h"
-
-#ifndef _XOPEN_SOURCE /* for Apple and OpenBSD; not sure if needed */
-#define _XOPEN_SOURCE 500
-#endif
-
-#include <pthread.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/select.h>
-#include <signal.h>
-#include <pwd.h>
-#include <errno.h>
-
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-
-typedef struct Oproc Oproc;
-struct Oproc
-{
- int nsleep;
- int nwakeup;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-};
-
-static pthread_key_t prdakey;
-
-Proc*
-_getproc(void)
-{
- void *v;
-
- if((v = pthread_getspecific(prdakey)) == nil)
- panic("cannot getspecific");
- return v;
-}
-
-void
-_setproc(Proc *p)
-{
- if(pthread_setspecific(prdakey, p) != 0)
- panic("cannot setspecific");
-}
-
-void
-osinit(void)
-{
- if(pthread_key_create(&prdakey, 0))
- panic("cannot pthread_key_create");
-}
-
-#undef pipe
-void
-osnewproc(Proc *p)
-{
- Oproc *op;
- pthread_mutexattr_t attr;
-
- op = (Oproc*)p->oproc;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
- pthread_mutex_init(&op->mutex, &attr);
- pthread_mutexattr_destroy(&attr);
- pthread_cond_init(&op->cond, 0);
-}
-
-void
-osmsleep(int ms)
-{
- struct timeval tv;
-
- tv.tv_sec = ms / 1000;
- tv.tv_usec = (ms % 1000) * 1000; /* micro */
- if(select(0, NULL, NULL, NULL, &tv) < 0)
- panic("select");
-}
-
-void
-osyield(void)
-{
- sched_yield();
-}
-
-void
-oserrstr(void)
-{
- char *p;
-
- if((p = strerror(errno)) != nil)
- strecpy(up->errstr, up->errstr+ERRMAX, p);
- else
- snprint(up->errstr, ERRMAX, "unix error %d", errno);
-}
-
-void
-oserror(void)
-{
- oserrstr();
- nexterror();
-}
-
-static void* tramp(void*);
-
-void
-osproc(Proc *p)
-{
- pthread_t pid;
-
- if(pthread_create(&pid, nil, tramp, p)){
- oserrstr();
- panic("osproc: %r");
- }
- sched_yield();
-}
-
-static void*
-tramp(void *vp)
-{
- Proc *p;
-
- p = vp;
- if(pthread_setspecific(prdakey, p))
- panic("cannot setspecific");
- (*p->fn)(p->arg);
- /* BUG: leaks Proc */
- pthread_setspecific(prdakey, 0);
- pthread_exit(0);
- return 0;
-}
-
-void
-procsleep(void)
-{
- Proc *p;
- Oproc *op;
-
- p = up;
- op = (Oproc*)p->oproc;
- pthread_mutex_lock(&op->mutex);
- op->nsleep++;
- while(op->nsleep > op->nwakeup)
- pthread_cond_wait(&op->cond, &op->mutex);
- pthread_mutex_unlock(&op->mutex);
-}
-
-void
-procwakeup(Proc *p)
-{
- Oproc *op;
-
- op = (Oproc*)p->oproc;
- pthread_mutex_lock(&op->mutex);
- op->nwakeup++;
- if(op->nwakeup == op->nsleep)
- pthread_cond_signal(&op->cond);
- pthread_mutex_unlock(&op->mutex);
-}
-
-int randfd;
-#undef open
-void
-randominit(void)
-{
-#ifdef USE_RANDOM
- srandom(getpid()+fastticks(nil)+ticks());
-#else
- if((randfd = open("/dev/urandom", OREAD)) < 0)
- if((randfd = open("/dev/random", OREAD)) < 0)
- panic("open /dev/random: %r");
-#endif
-}
-
-#undef read
-ulong
-randomread(void *v, ulong n)
-{
-#ifdef USE_RANDOM
- int i;
-
- for(i=0; i<n; i++)
- ((uchar*)v)[i] = random();
- return n;
-#else
- int m;
-
- if((m = read(randfd, v, n)) != n)
- panic("short read from /dev/random: %d but %d", n, m);
- return m;
-#endif
-}
-
-#undef time
-long
-seconds(void)
-{
- return time(0);
-}
-
-ulong
-ticks(void)
-{
- static long sec0 = 0, usec0;
- struct timeval t;
-
- if(gettimeofday(&t, nil) < 0)
- return 0;
- if(sec0 == 0){
- sec0 = t.tv_sec;
- usec0 = t.tv_usec;
- }
- return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
-}
-
-long
-showfilewrite(char *a, int n)
-{
- error("not implemented");
- return -1;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/procinit.c b/sys/src/cmd/unix/drawterm/kern/procinit.c
deleted file mode 100644
index b2299d963..000000000
--- a/sys/src/cmd/unix/drawterm/kern/procinit.c
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-Rgrp *thergrp;
-
-void
-procinit0(void)
-{
- Proc *p;
-
- p = newproc();
- p->fgrp = dupfgrp(nil);
- p->rgrp = newrgrp();
- p->pgrp = newpgrp();
- _setproc(p);
-
- up->slash = namec("#/", Atodir, 0, 0);
- cnameclose(up->slash->name);
- up->slash->name = newcname("/");
- up->dot = cclone(up->slash);
-}
-
-Ref pidref;
-
-Proc*
-newproc(void)
-{
- Proc *p;
-
- p = mallocz(sizeof(Proc), 1);
- p->pid = incref(&pidref);
- strcpy(p->user, eve);
- p->syserrstr = p->errbuf0;
- p->errstr = p->errbuf1;
- strcpy(p->text, "drawterm");
- osnewproc(p);
- return p;
-}
-
-int
-kproc(char *name, void (*fn)(void*), void *arg)
-{
- Proc *p;
-
- p = newproc();
- p->fn = fn;
- p->arg = arg;
- p->slash = cclone(up->slash);
- p->dot = cclone(up->dot);
- p->rgrp = up->rgrp;
- if(p->rgrp)
- incref(&p->rgrp->ref);
- p->pgrp = up->pgrp;
- if(up->pgrp)
- incref(&up->pgrp->ref);
- p->fgrp = up->fgrp;
- if(p->fgrp)
- incref(&p->fgrp->ref);
- strecpy(p->text, p->text+sizeof p->text, name);
-
- osproc(p);
- return p->pid;
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/qio.c b/sys/src/cmd/unix/drawterm/kern/qio.c
deleted file mode 100644
index edee200be..000000000
--- a/sys/src/cmd/unix/drawterm/kern/qio.c
+++ /dev/null
@@ -1,1524 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-static ulong padblockcnt;
-static ulong concatblockcnt;
-static ulong pullupblockcnt;
-static ulong copyblockcnt;
-static ulong consumecnt;
-static ulong producecnt;
-static ulong qcopycnt;
-
-static int debugging;
-
-#define QDEBUG if(0)
-
-/*
- * IO queues
- */
-struct Queue
-{
- Lock lk;
-
- Block* bfirst; /* buffer */
- Block* blast;
-
- int len; /* bytes allocated to queue */
- int dlen; /* data bytes in queue */
- int limit; /* max bytes in queue */
- int inilim; /* initial limit */
- int state;
- int noblock; /* true if writes return immediately when q full */
- int eof; /* number of eofs read by user */
-
- void (*kick)(void*); /* restart output */
- void (*bypass)(void*, Block*); /* bypass queue altogether */
- void* arg; /* argument to kick */
-
- QLock rlock; /* mutex for reading processes */
- Rendez rr; /* process waiting to read */
- QLock wlock; /* mutex for writing processes */
- Rendez wr; /* process waiting to write */
-
- char err[ERRMAX];
-};
-
-enum
-{
- Maxatomic = 64*1024,
-};
-
-uint qiomaxatomic = Maxatomic;
-
-void
-ixsummary(void)
-{
- debugging ^= 1;
- iallocsummary();
- print("pad %lud, concat %lud, pullup %lud, copy %lud\n",
- padblockcnt, concatblockcnt, pullupblockcnt, copyblockcnt);
- print("consume %lud, produce %lud, qcopy %lud\n",
- consumecnt, producecnt, qcopycnt);
-}
-
-/*
- * free a list of blocks
- */
-void
-freeblist(Block *b)
-{
- Block *next;
-
- for(; b != 0; b = next){
- next = b->next;
- b->next = 0;
- freeb(b);
- }
-}
-
-/*
- * pad a block to the front (or the back if size is negative)
- */
-Block*
-padblock(Block *bp, int size)
-{
- int n;
- Block *nbp;
-
- QDEBUG checkb(bp, "padblock 1");
- if(size >= 0){
- if(bp->rp - bp->base >= size){
- bp->rp -= size;
- return bp;
- }
-
- if(bp->next)
- panic("padblock 0x%p", getcallerpc(&bp));
- n = BLEN(bp);
- padblockcnt++;
- nbp = allocb(size+n);
- nbp->rp += size;
- nbp->wp = nbp->rp;
- memmove(nbp->wp, bp->rp, n);
- nbp->wp += n;
- freeb(bp);
- nbp->rp -= size;
- } else {
- size = -size;
-
- if(bp->next)
- panic("padblock 0x%p", getcallerpc(&bp));
-
- if(bp->lim - bp->wp >= size)
- return bp;
-
- n = BLEN(bp);
- padblockcnt++;
- nbp = allocb(size+n);
- memmove(nbp->wp, bp->rp, n);
- nbp->wp += n;
- freeb(bp);
- }
- QDEBUG checkb(nbp, "padblock 1");
- return nbp;
-}
-
-/*
- * return count of bytes in a string of blocks
- */
-int
-blocklen(Block *bp)
-{
- int len;
-
- len = 0;
- while(bp) {
- len += BLEN(bp);
- bp = bp->next;
- }
- return len;
-}
-
-/*
- * return count of space in blocks
- */
-int
-blockalloclen(Block *bp)
-{
- int len;
-
- len = 0;
- while(bp) {
- len += BALLOC(bp);
- bp = bp->next;
- }
- return len;
-}
-
-/*
- * copy the string of blocks into
- * a single block and free the string
- */
-Block*
-concatblock(Block *bp)
-{
- int len;
- Block *nb, *f;
-
- if(bp->next == 0)
- return bp;
-
- nb = allocb(blocklen(bp));
- for(f = bp; f; f = f->next) {
- len = BLEN(f);
- memmove(nb->wp, f->rp, len);
- nb->wp += len;
- }
- concatblockcnt += BLEN(nb);
- freeblist(bp);
- QDEBUG checkb(nb, "concatblock 1");
- return nb;
-}
-
-/*
- * make sure the first block has at least n bytes
- */
-Block*
-pullupblock(Block *bp, int n)
-{
- int i;
- Block *nbp;
-
- /*
- * this should almost always be true, it's
- * just to avoid every caller checking.
- */
- if(BLEN(bp) >= n)
- return bp;
-
- /*
- * if not enough room in the first block,
- * add another to the front of the list.
- */
- if(bp->lim - bp->rp < n){
- nbp = allocb(n);
- nbp->next = bp;
- bp = nbp;
- }
-
- /*
- * copy bytes from the trailing blocks into the first
- */
- n -= BLEN(bp);
- while((nbp = bp->next)){
- i = BLEN(nbp);
- if(i > n) {
- memmove(bp->wp, nbp->rp, n);
- pullupblockcnt++;
- bp->wp += n;
- nbp->rp += n;
- QDEBUG checkb(bp, "pullupblock 1");
- return bp;
- } else {
- /* shouldn't happen but why crash if it does */
- if(i < 0){
- print("pullup negative length packet\n");
- i = 0;
- }
- memmove(bp->wp, nbp->rp, i);
- pullupblockcnt++;
- bp->wp += i;
- bp->next = nbp->next;
- nbp->next = 0;
- freeb(nbp);
- n -= i;
- if(n == 0){
- QDEBUG checkb(bp, "pullupblock 2");
- return bp;
- }
- }
- }
- freeb(bp);
- return 0;
-}
-
-/*
- * make sure the first block has at least n bytes
- */
-Block*
-pullupqueue(Queue *q, int n)
-{
- Block *b;
-
- if(BLEN(q->bfirst) >= n)
- return q->bfirst;
- q->bfirst = pullupblock(q->bfirst, n);
- for(b = q->bfirst; b != nil && b->next != nil; b = b->next)
- ;
- q->blast = b;
- return q->bfirst;
-}
-
-/*
- * trim to len bytes starting at offset
- */
-Block *
-trimblock(Block *bp, int offset, int len)
-{
- ulong l;
- Block *nb, *startb;
-
- QDEBUG checkb(bp, "trimblock 1");
- if(blocklen(bp) < offset+len) {
- freeblist(bp);
- return nil;
- }
-
- while((l = BLEN(bp)) < offset) {
- offset -= l;
- nb = bp->next;
- bp->next = nil;
- freeb(bp);
- bp = nb;
- }
-
- startb = bp;
- bp->rp += offset;
-
- while((l = BLEN(bp)) < len) {
- len -= l;
- bp = bp->next;
- }
-
- bp->wp -= (BLEN(bp) - len);
-
- if(bp->next) {
- freeblist(bp->next);
- bp->next = nil;
- }
-
- return startb;
-}
-
-/*
- * copy 'count' bytes into a new block
- */
-Block*
-copyblock(Block *bp, int count)
-{
- int l;
- Block *nbp;
-
- QDEBUG checkb(bp, "copyblock 0");
- nbp = allocb(count);
- for(; count > 0 && bp != 0; bp = bp->next){
- l = BLEN(bp);
- if(l > count)
- l = count;
- memmove(nbp->wp, bp->rp, l);
- nbp->wp += l;
- count -= l;
- }
- if(count > 0){
- memset(nbp->wp, 0, count);
- nbp->wp += count;
- }
- copyblockcnt++;
- QDEBUG checkb(nbp, "copyblock 1");
-
- return nbp;
-}
-
-Block*
-adjustblock(Block* bp, int len)
-{
- int n;
- Block *nbp;
-
- if(len < 0){
- freeb(bp);
- return nil;
- }
-
- if(bp->rp+len > bp->lim){
- nbp = copyblock(bp, len);
- freeblist(bp);
- QDEBUG checkb(nbp, "adjustblock 1");
-
- return nbp;
- }
-
- n = BLEN(bp);
- if(len > n)
- memset(bp->wp, 0, len-n);
- bp->wp = bp->rp+len;
- QDEBUG checkb(bp, "adjustblock 2");
-
- return bp;
-}
-
-
-/*
- * throw away up to count bytes from a
- * list of blocks. Return count of bytes
- * thrown away.
- */
-int
-pullblock(Block **bph, int count)
-{
- Block *bp;
- int n, bytes;
-
- bytes = 0;
- if(bph == nil)
- return 0;
-
- while(*bph != nil && count != 0) {
- bp = *bph;
- n = BLEN(bp);
- if(count < n)
- n = count;
- bytes += n;
- count -= n;
- bp->rp += n;
- QDEBUG checkb(bp, "pullblock ");
- if(BLEN(bp) == 0) {
- *bph = bp->next;
- bp->next = nil;
- freeb(bp);
- }
- }
- return bytes;
-}
-
-/*
- * get next block from a queue, return null if nothing there
- */
-Block*
-qget(Queue *q)
-{
- int dowakeup;
- Block *b;
-
- /* sync with qwrite */
- ilock(&q->lk);
-
- b = q->bfirst;
- if(b == nil){
- q->state |= Qstarve;
- iunlock(&q->lk);
- return nil;
- }
- q->bfirst = b->next;
- b->next = 0;
- q->len -= BALLOC(b);
- q->dlen -= BLEN(b);
- QDEBUG checkb(b, "qget");
-
- /* if writer flow controlled, restart */
- if((q->state & Qflow) && q->len < q->limit/2){
- q->state &= ~Qflow;
- dowakeup = 1;
- } else
- dowakeup = 0;
-
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->wr);
-
- return b;
-}
-
-/*
- * throw away the next 'len' bytes in the queue
- */
-int
-qdiscard(Queue *q, int len)
-{
- Block *b;
- int dowakeup, n, sofar;
-
- ilock(&q->lk);
- for(sofar = 0; sofar < len; sofar += n){
- b = q->bfirst;
- if(b == nil)
- break;
- QDEBUG checkb(b, "qdiscard");
- n = BLEN(b);
- if(n <= len - sofar){
- q->bfirst = b->next;
- b->next = 0;
- q->len -= BALLOC(b);
- q->dlen -= BLEN(b);
- freeb(b);
- } else {
- n = len - sofar;
- b->rp += n;
- q->dlen -= n;
- }
- }
-
- /*
- * if writer flow controlled, restart
- *
- * This used to be
- * q->len < q->limit/2
- * but it slows down tcp too much for certain write sizes.
- * I really don't understand it completely. It may be
- * due to the queue draining so fast that the transmission
- * stalls waiting for the app to produce more data. - presotto
- */
- if((q->state & Qflow) && q->len < q->limit){
- q->state &= ~Qflow;
- dowakeup = 1;
- } else
- dowakeup = 0;
-
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->wr);
-
- return sofar;
-}
-
-/*
- * Interrupt level copy out of a queue, return # bytes copied.
- */
-int
-qconsume(Queue *q, void *vp, int len)
-{
- Block *b;
- int n, dowakeup;
- uchar *p = vp;
- Block *tofree = nil;
-
- /* sync with qwrite */
- ilock(&q->lk);
-
- for(;;) {
- b = q->bfirst;
- if(b == 0){
- q->state |= Qstarve;
- iunlock(&q->lk);
- return -1;
- }
- QDEBUG checkb(b, "qconsume 1");
-
- n = BLEN(b);
- if(n > 0)
- break;
- q->bfirst = b->next;
- q->len -= BALLOC(b);
-
- /* remember to free this */
- b->next = tofree;
- tofree = b;
- };
-
- if(n < len)
- len = n;
- memmove(p, b->rp, len);
- consumecnt += n;
- b->rp += len;
- q->dlen -= len;
-
- /* discard the block if we're done with it */
- if((q->state & Qmsg) || len == n){
- q->bfirst = b->next;
- b->next = 0;
- q->len -= BALLOC(b);
- q->dlen -= BLEN(b);
-
- /* remember to free this */
- b->next = tofree;
- tofree = b;
- }
-
- /* if writer flow controlled, restart */
- if((q->state & Qflow) && q->len < q->limit/2){
- q->state &= ~Qflow;
- dowakeup = 1;
- } else
- dowakeup = 0;
-
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->wr);
-
- if(tofree != nil)
- freeblist(tofree);
-
- return len;
-}
-
-int
-qpass(Queue *q, Block *b)
-{
- int dlen, len, dowakeup;
-
- /* sync with qread */
- dowakeup = 0;
- ilock(&q->lk);
- if(q->len >= q->limit){
- freeblist(b);
- iunlock(&q->lk);
- return -1;
- }
- if(q->state & Qclosed){
- freeblist(b);
- iunlock(&q->lk);
- return BALLOC(b);
- }
-
- /* add buffer to queue */
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- len = BALLOC(b);
- dlen = BLEN(b);
- QDEBUG checkb(b, "qpass");
- while(b->next){
- b = b->next;
- QDEBUG checkb(b, "qpass");
- len += BALLOC(b);
- dlen += BLEN(b);
- }
- q->blast = b;
- q->len += len;
- q->dlen += dlen;
-
- if(q->len >= q->limit/2)
- q->state |= Qflow;
-
- if(q->state & Qstarve){
- q->state &= ~Qstarve;
- dowakeup = 1;
- }
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->rr);
-
- return len;
-}
-
-int
-qpassnolim(Queue *q, Block *b)
-{
- int dlen, len, dowakeup;
-
- /* sync with qread */
- dowakeup = 0;
- ilock(&q->lk);
-
- if(q->state & Qclosed){
- freeblist(b);
- iunlock(&q->lk);
- return BALLOC(b);
- }
-
- /* add buffer to queue */
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- len = BALLOC(b);
- dlen = BLEN(b);
- QDEBUG checkb(b, "qpass");
- while(b->next){
- b = b->next;
- QDEBUG checkb(b, "qpass");
- len += BALLOC(b);
- dlen += BLEN(b);
- }
- q->blast = b;
- q->len += len;
- q->dlen += dlen;
-
- if(q->len >= q->limit/2)
- q->state |= Qflow;
-
- if(q->state & Qstarve){
- q->state &= ~Qstarve;
- dowakeup = 1;
- }
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->rr);
-
- return len;
-}
-
-/*
- * if the allocated space is way out of line with the used
- * space, reallocate to a smaller block
- */
-Block*
-packblock(Block *bp)
-{
- Block **l, *nbp;
- int n;
-
- for(l = &bp; *l; l = &(*l)->next){
- nbp = *l;
- n = BLEN(nbp);
- if((n<<2) < BALLOC(nbp)){
- *l = allocb(n);
- memmove((*l)->wp, nbp->rp, n);
- (*l)->wp += n;
- (*l)->next = nbp->next;
- freeb(nbp);
- }
- }
-
- return bp;
-}
-
-int
-qproduce(Queue *q, void *vp, int len)
-{
- Block *b;
- int dowakeup;
- uchar *p = vp;
-
- /* sync with qread */
- dowakeup = 0;
- ilock(&q->lk);
-
- /* no waiting receivers, room in buffer? */
- if(q->len >= q->limit){
- q->state |= Qflow;
- iunlock(&q->lk);
- return -1;
- }
-
- /* save in buffer */
- b = iallocb(len);
- if(b == 0){
- iunlock(&q->lk);
- return 0;
- }
- memmove(b->wp, p, len);
- producecnt += len;
- b->wp += len;
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- q->blast = b;
- /* b->next = 0; done by iallocb() */
- q->len += BALLOC(b);
- q->dlen += BLEN(b);
- QDEBUG checkb(b, "qproduce");
-
- if(q->state & Qstarve){
- q->state &= ~Qstarve;
- dowakeup = 1;
- }
-
- if(q->len >= q->limit)
- q->state |= Qflow;
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->rr);
-
- return len;
-}
-
-/*
- * copy from offset in the queue
- */
-Block*
-qcopy(Queue *q, int len, ulong offset)
-{
- int sofar;
- int n;
- Block *b, *nb;
- uchar *p;
-
- nb = allocb(len);
-
- ilock(&q->lk);
-
- /* go to offset */
- b = q->bfirst;
- for(sofar = 0; ; sofar += n){
- if(b == nil){
- iunlock(&q->lk);
- return nb;
- }
- n = BLEN(b);
- if(sofar + n > offset){
- p = b->rp + offset - sofar;
- n -= offset - sofar;
- break;
- }
- QDEBUG checkb(b, "qcopy");
- b = b->next;
- }
-
- /* copy bytes from there */
- for(sofar = 0; sofar < len;){
- if(n > len - sofar)
- n = len - sofar;
- memmove(nb->wp, p, n);
- qcopycnt += n;
- sofar += n;
- nb->wp += n;
- b = b->next;
- if(b == nil)
- break;
- n = BLEN(b);
- p = b->rp;
- }
- iunlock(&q->lk);
-
- return nb;
-}
-
-/*
- * called by non-interrupt code
- */
-Queue*
-qopen(int limit, int msg, void (*kick)(void*), void *arg)
-{
- Queue *q;
-
- q = malloc(sizeof(Queue));
- if(q == 0)
- return 0;
-
- q->limit = q->inilim = limit;
- q->kick = kick;
- q->arg = arg;
- q->state = msg;
-
- q->state |= Qstarve;
- q->eof = 0;
- q->noblock = 0;
-
- return q;
-}
-
-/* open a queue to be bypassed */
-Queue*
-qbypass(void (*bypass)(void*, Block*), void *arg)
-{
- Queue *q;
-
- q = malloc(sizeof(Queue));
- if(q == 0)
- return 0;
-
- q->limit = 0;
- q->arg = arg;
- q->bypass = bypass;
- q->state = 0;
-
- return q;
-}
-
-static int
-notempty(void *a)
-{
- Queue *q = a;
-
- return (q->state & Qclosed) || q->bfirst != 0;
-}
-
-/*
- * wait for the queue to be non-empty or closed.
- * called with q ilocked.
- */
-static int
-qwait(Queue *q)
-{
- /* wait for data */
- for(;;){
- if(q->bfirst != nil)
- break;
-
- if(q->state & Qclosed){
- if(++q->eof > 3)
- return -1;
- if(*q->err && strcmp(q->err, Ehungup) != 0)
- return -1;
- return 0;
- }
-
- q->state |= Qstarve; /* flag requesting producer to wake me */
- iunlock(&q->lk);
- sleep(&q->rr, notempty, q);
- ilock(&q->lk);
- }
- return 1;
-}
-
-/*
- * add a block list to a queue
- */
-void
-qaddlist(Queue *q, Block *b)
-{
- /* queue the block */
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- q->len += blockalloclen(b);
- q->dlen += blocklen(b);
- while(b->next)
- b = b->next;
- q->blast = b;
-}
-
-/*
- * called with q ilocked
- */
-Block*
-qremove(Queue *q)
-{
- Block *b;
-
- b = q->bfirst;
- if(b == nil)
- return nil;
- q->bfirst = b->next;
- b->next = nil;
- q->dlen -= BLEN(b);
- q->len -= BALLOC(b);
- QDEBUG checkb(b, "qremove");
- return b;
-}
-
-/*
- * copy the contents of a string of blocks into
- * memory. emptied blocks are freed. return
- * pointer to first unconsumed block.
- */
-Block*
-bl2mem(uchar *p, Block *b, int n)
-{
- int i;
- Block *next;
-
- for(; b != nil; b = next){
- i = BLEN(b);
- if(i > n){
- memmove(p, b->rp, n);
- b->rp += n;
- return b;
- }
- memmove(p, b->rp, i);
- n -= i;
- p += i;
- b->rp += i;
- next = b->next;
- freeb(b);
- }
- return nil;
-}
-
-/*
- * copy the contents of memory into a string of blocks.
- * return nil on error.
- */
-Block*
-mem2bl(uchar *p, int len)
-{
- int n;
- Block *b, *first, **l;
-
- first = nil;
- l = &first;
- if(waserror()){
- freeblist(first);
- nexterror();
- }
- do {
- n = len;
- if(n > Maxatomic)
- n = Maxatomic;
-
- *l = b = allocb(n);
- /* setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]); */
- memmove(b->wp, p, n);
- b->wp += n;
- p += n;
- len -= n;
- l = &b->next;
- } while(len > 0);
- poperror();
-
- return first;
-}
-
-/*
- * put a block back to the front of the queue
- * called with q ilocked
- */
-void
-qputback(Queue *q, Block *b)
-{
- b->next = q->bfirst;
- if(q->bfirst == nil)
- q->blast = b;
- q->bfirst = b;
- q->len += BALLOC(b);
- q->dlen += BLEN(b);
-}
-
-/*
- * flow control, get producer going again
- * called with q ilocked
- */
-static void
-qwakeup_iunlock(Queue *q)
-{
- int dowakeup = 0;
-
- /* if writer flow controlled, restart */
- if((q->state & Qflow) && q->len < q->limit/2){
- q->state &= ~Qflow;
- dowakeup = 1;
- }
-
- iunlock(&q->lk);
-
- /* wakeup flow controlled writers */
- if(dowakeup){
- if(q->kick)
- q->kick(q->arg);
- wakeup(&q->wr);
- }
-}
-
-/*
- * get next block from a queue (up to a limit)
- */
-Block*
-qbread(Queue *q, int len)
-{
- Block *b, *nb;
- int n;
-
- qlock(&q->rlock);
- if(waserror()){
- qunlock(&q->rlock);
- nexterror();
- }
-
- ilock(&q->lk);
- switch(qwait(q)){
- case 0:
- /* queue closed */
- iunlock(&q->lk);
- qunlock(&q->rlock);
- poperror();
- return nil;
- case -1:
- /* multiple reads on a closed queue */
- iunlock(&q->lk);
- error(q->err);
- }
-
- /* if we get here, there's at least one block in the queue */
- b = qremove(q);
- n = BLEN(b);
-
- /* split block if it's too big and this is not a message queue */
- nb = b;
- if(n > len){
- if((q->state&Qmsg) == 0){
- n -= len;
- b = allocb(n);
- memmove(b->wp, nb->rp+len, n);
- b->wp += n;
- qputback(q, b);
- }
- nb->wp = nb->rp + len;
- }
-
- /* restart producer */
- qwakeup_iunlock(q);
-
- poperror();
- qunlock(&q->rlock);
- return nb;
-}
-
-/*
- * read a queue. if no data is queued, post a Block
- * and wait on its Rendez.
- */
-long
-qread(Queue *q, void *vp, int len)
-{
- Block *b, *first, **l;
- int m, n;
-
- qlock(&q->rlock);
- if(waserror()){
- qunlock(&q->rlock);
- nexterror();
- }
-
- ilock(&q->lk);
-again:
- switch(qwait(q)){
- case 0:
- /* queue closed */
- iunlock(&q->lk);
- qunlock(&q->rlock);
- poperror();
- return 0;
- case -1:
- /* multiple reads on a closed queue */
- iunlock(&q->lk);
- error(q->err);
- }
-
- /* if we get here, there's at least one block in the queue */
- if(q->state & Qcoalesce){
- /* when coalescing, 0 length blocks just go away */
- b = q->bfirst;
- if(BLEN(b) <= 0){
- freeb(qremove(q));
- goto again;
- }
-
- /* grab the first block plus as many
- * following blocks as will completely
- * fit in the read.
- */
- n = 0;
- l = &first;
- m = BLEN(b);
- for(;;) {
- *l = qremove(q);
- l = &b->next;
- n += m;
-
- b = q->bfirst;
- if(b == nil)
- break;
- m = BLEN(b);
- if(n+m > len)
- break;
- }
- } else {
- first = qremove(q);
- n = BLEN(first);
- }
-
- /* copy to user space outside of the ilock */
- iunlock(&q->lk);
- b = bl2mem(vp, first, len);
- ilock(&q->lk);
-
- /* take care of any left over partial block */
- if(b != nil){
- n -= BLEN(b);
- if(q->state & Qmsg)
- freeb(b);
- else
- qputback(q, b);
- }
-
- /* restart producer */
- qwakeup_iunlock(q);
-
- poperror();
- qunlock(&q->rlock);
- return n;
-}
-
-static int
-qnotfull(void *a)
-{
- Queue *q = a;
-
- return q->len < q->limit || (q->state & Qclosed);
-}
-
-ulong noblockcnt;
-
-/*
- * add a block to a queue obeying flow control
- */
-long
-qbwrite(Queue *q, Block *b)
-{
- int n, dowakeup;
-
- n = BLEN(b);
-
- if(q->bypass){
- (*q->bypass)(q->arg, b);
- return n;
- }
-
- dowakeup = 0;
- qlock(&q->wlock);
- if(waserror()){
- if(b != nil)
- freeb(b);
- qunlock(&q->wlock);
- nexterror();
- }
-
- ilock(&q->lk);
-
- /* give up if the queue is closed */
- if(q->state & Qclosed){
- iunlock(&q->lk);
- error(q->err);
- }
-
- /* if nonblocking, don't queue over the limit */
- if(q->len >= q->limit){
- if(q->noblock){
- iunlock(&q->lk);
- freeb(b);
- noblockcnt += n;
- qunlock(&q->wlock);
- poperror();
- return n;
- }
- }
-
- /* queue the block */
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- q->blast = b;
- b->next = 0;
- q->len += BALLOC(b);
- q->dlen += n;
- QDEBUG checkb(b, "qbwrite");
- b = nil;
-
- /* make sure other end gets awakened */
- if(q->state & Qstarve){
- q->state &= ~Qstarve;
- dowakeup = 1;
- }
- iunlock(&q->lk);
-
- /* get output going again */
- if(q->kick && (dowakeup || (q->state&Qkick)))
- q->kick(q->arg);
-
- /* wakeup anyone consuming at the other end */
- if(dowakeup){
- wakeup(&q->rr);
-
- /* if we just wokeup a higher priority process, let it run */
- /*
- p = wakeup(&q->rr);
- if(p != nil && p->priority > up->priority)
- sched();
- */
- }
-
- /*
- * flow control, wait for queue to get below the limit
- * before allowing the process to continue and queue
- * more. We do this here so that postnote can only
- * interrupt us after the data has been queued. This
- * means that things like 9p flushes and ssl messages
- * will not be disrupted by software interrupts.
- *
- * Note - this is moderately dangerous since a process
- * that keeps getting interrupted and rewriting will
- * queue infinite crud.
- */
- for(;;){
- if(q->noblock || qnotfull(q))
- break;
-
- ilock(&q->lk);
- q->state |= Qflow;
- iunlock(&q->lk);
- sleep(&q->wr, qnotfull, q);
- }
- USED(b);
-
- qunlock(&q->wlock);
- poperror();
- return n;
-}
-
-/*
- * write to a queue. only Maxatomic bytes at a time is atomic.
- */
-int
-qwrite(Queue *q, void *vp, int len)
-{
- int n, sofar;
- Block *b;
- uchar *p = vp;
-
- QDEBUG if(!islo())
- print("qwrite hi %p\n", getcallerpc(&q));
-
- sofar = 0;
- do {
- n = len-sofar;
- if(n > Maxatomic)
- n = Maxatomic;
-
- b = allocb(n);
- /* setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]); */
- if(waserror()){
- freeb(b);
- nexterror();
- }
- memmove(b->wp, p+sofar, n);
- poperror();
- b->wp += n;
-
- qbwrite(q, b);
-
- sofar += n;
- } while(sofar < len && (q->state & Qmsg) == 0);
-
- return len;
-}
-
-/*
- * used by print() to write to a queue. Since we may be splhi or not in
- * a process, don't qlock.
- */
-int
-qiwrite(Queue *q, void *vp, int len)
-{
- int n, sofar, dowakeup;
- Block *b;
- uchar *p = vp;
-
- dowakeup = 0;
-
- sofar = 0;
- do {
- n = len-sofar;
- if(n > Maxatomic)
- n = Maxatomic;
-
- b = iallocb(n);
- if(b == nil)
- break;
- memmove(b->wp, p+sofar, n);
- b->wp += n;
-
- ilock(&q->lk);
-
- QDEBUG checkb(b, "qiwrite");
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- q->blast = b;
- q->len += BALLOC(b);
- q->dlen += n;
-
- if(q->state & Qstarve){
- q->state &= ~Qstarve;
- dowakeup = 1;
- }
-
- iunlock(&q->lk);
-
- if(dowakeup){
- if(q->kick)
- q->kick(q->arg);
- wakeup(&q->rr);
- }
-
- sofar += n;
- } while(sofar < len && (q->state & Qmsg) == 0);
-
- return sofar;
-}
-
-/*
- * be extremely careful when calling this,
- * as there is no reference accounting
- */
-void
-qfree(Queue *q)
-{
- qclose(q);
- free(q);
-}
-
-/*
- * Mark a queue as closed. No further IO is permitted.
- * All blocks are released.
- */
-void
-qclose(Queue *q)
-{
- Block *bfirst;
-
- if(q == nil)
- return;
-
- /* mark it */
- ilock(&q->lk);
- q->state |= Qclosed;
- q->state &= ~(Qflow|Qstarve);
- strcpy(q->err, Ehungup);
- bfirst = q->bfirst;
- q->bfirst = 0;
- q->len = 0;
- q->dlen = 0;
- q->noblock = 0;
- iunlock(&q->lk);
-
- /* free queued blocks */
- freeblist(bfirst);
-
- /* wake up readers/writers */
- wakeup(&q->rr);
- wakeup(&q->wr);
-}
-
-/*
- * Mark a queue as closed. Wakeup any readers. Don't remove queued
- * blocks.
- */
-void
-qhangup(Queue *q, char *msg)
-{
- /* mark it */
- ilock(&q->lk);
- q->state |= Qclosed;
- if(msg == 0 || *msg == 0)
- strcpy(q->err, Ehungup);
- else
- strncpy(q->err, msg, ERRMAX-1);
- iunlock(&q->lk);
-
- /* wake up readers/writers */
- wakeup(&q->rr);
- wakeup(&q->wr);
-}
-
-/*
- * return non-zero if the q is hungup
- */
-int
-qisclosed(Queue *q)
-{
- return q->state & Qclosed;
-}
-
-/*
- * mark a queue as no longer hung up
- */
-void
-qreopen(Queue *q)
-{
- ilock(&q->lk);
- q->state &= ~Qclosed;
- q->state |= Qstarve;
- q->eof = 0;
- q->limit = q->inilim;
- iunlock(&q->lk);
-}
-
-/*
- * return bytes queued
- */
-int
-qlen(Queue *q)
-{
- return q->dlen;
-}
-
-/*
- * return space remaining before flow control
- */
-int
-qwindow(Queue *q)
-{
- int l;
-
- l = q->limit - q->len;
- if(l < 0)
- l = 0;
- return l;
-}
-
-/*
- * return true if we can read without blocking
- */
-int
-qcanread(Queue *q)
-{
- return q->bfirst!=0;
-}
-
-/*
- * change queue limit
- */
-void
-qsetlimit(Queue *q, int limit)
-{
- q->limit = limit;
-}
-
-/*
- * set blocking/nonblocking
- */
-void
-qnoblock(Queue *q, int onoff)
-{
- q->noblock = onoff;
-}
-
-/*
- * flush the output queue
- */
-void
-qflush(Queue *q)
-{
- Block *bfirst;
-
- /* mark it */
- ilock(&q->lk);
- bfirst = q->bfirst;
- q->bfirst = 0;
- q->len = 0;
- q->dlen = 0;
- iunlock(&q->lk);
-
- /* free queued blocks */
- freeblist(bfirst);
-
- /* wake up readers/writers */
- wakeup(&q->wr);
-}
-
-int
-qfull(Queue *q)
-{
- return q->state & Qflow;
-}
-
-int
-qstate(Queue *q)
-{
- return q->state;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/qlock.c b/sys/src/cmd/unix/drawterm/kern/qlock.c
deleted file mode 100644
index fdbeaeac3..000000000
--- a/sys/src/cmd/unix/drawterm/kern/qlock.c
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-
-static void
-queue(Proc **first, Proc **last)
-{
- Proc *t;
-
- t = *last;
- if(t == 0)
- *first = up;
- else
- t->qnext = up;
- *last = up;
- up->qnext = 0;
-}
-
-static Proc*
-dequeue(Proc **first, Proc **last)
-{
- Proc *t;
-
- t = *first;
- if(t == 0)
- return 0;
- *first = t->qnext;
- if(*first == 0)
- *last = 0;
- return t;
-}
-
-void
-qlock(QLock *q)
-{
- lock(&q->lk);
-
- if(q->hold == 0) {
- q->hold = up;
- unlock(&q->lk);
- return;
- }
-
- /*
- * Can't assert this because of RWLock
- assert(q->hold != up);
- */
-
- queue((Proc**)&q->first, (Proc**)&q->last);
- unlock(&q->lk);
- procsleep();
-}
-
-int
-canqlock(QLock *q)
-{
- lock(&q->lk);
- if(q->hold == 0) {
- q->hold = up;
- unlock(&q->lk);
- return 1;
- }
- unlock(&q->lk);
- return 0;
-}
-
-void
-qunlock(QLock *q)
-{
- Proc *p;
-
- lock(&q->lk);
- /*
- * Can't assert this because of RWlock
- assert(q->hold == CT);
- */
- p = dequeue((Proc**)&q->first, (Proc**)&q->last);
- if(p) {
- q->hold = p;
- unlock(&q->lk);
- procwakeup(p);
- } else {
- q->hold = 0;
- unlock(&q->lk);
- }
-}
-
-int
-holdqlock(QLock *q)
-{
- return q->hold == up;
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/rendez.c b/sys/src/cmd/unix/drawterm/kern/rendez.c
deleted file mode 100644
index 6a9ad174e..000000000
--- a/sys/src/cmd/unix/drawterm/kern/rendez.c
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-void
-sleep(Rendez *r, int (*f)(void*), void *arg)
-{
- int s;
-
- s = splhi();
-
- lock(&r->lk);
- lock(&up->rlock);
- if(r->p){
- print("double sleep %lud %lud\n", r->p->pid, up->pid);
- dumpstack();
- }
-
- /*
- * Wakeup only knows there may be something to do by testing
- * r->p in order to get something to lock on.
- * Flush that information out to memory in case the sleep is
- * committed.
- */
- r->p = up;
-
- if((*f)(arg) || up->notepending){
- /*
- * if condition happened or a note is pending
- * never mind
- */
- r->p = nil;
- unlock(&up->rlock);
- unlock(&r->lk);
- } else {
- /*
- * now we are committed to
- * change state and call scheduler
- */
- up->state = Wakeme;
- up->r = r;
-
- /* statistics */
- /* m->cs++; */
-
- unlock(&up->rlock);
- unlock(&r->lk);
-
- procsleep();
- }
-
- if(up->notepending) {
- up->notepending = 0;
- splx(s);
- error(Eintr);
- }
-
- splx(s);
-}
-
-Proc*
-wakeup(Rendez *r)
-{
- Proc *p;
- int s;
-
- s = splhi();
-
- lock(&r->lk);
- p = r->p;
-
- if(p != nil){
- lock(&p->rlock);
- if(p->state != Wakeme || p->r != r)
- panic("wakeup: state");
- r->p = nil;
- p->r = nil;
- p->state = Running;
- procwakeup(p);
- unlock(&p->rlock);
- }
- unlock(&r->lk);
-
- splx(s);
-
- return p;
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/rwlock.c b/sys/src/cmd/unix/drawterm/kern/rwlock.c
deleted file mode 100644
index 3381957a3..000000000
--- a/sys/src/cmd/unix/drawterm/kern/rwlock.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-void
-rlock(RWlock *l)
-{
- qlock(&l->x); /* wait here for writers and exclusion */
- lock(&l->lk);
- l->readers++;
- canqlock(&l->k); /* block writers if we are the first reader */
- unlock(&l->lk);
- qunlock(&l->x);
-}
-
-void
-runlock(RWlock *l)
-{
- lock(&l->lk);
- if(--l->readers == 0) /* last reader out allows writers */
- qunlock(&l->k);
- unlock(&l->lk);
-}
-
-void
-wlock(RWlock *l)
-{
- qlock(&l->x); /* wait here for writers and exclusion */
- qlock(&l->k); /* wait here for last reader */
-}
-
-void
-wunlock(RWlock *l)
-{
- qunlock(&l->k);
- qunlock(&l->x);
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/screen.h b/sys/src/cmd/unix/drawterm/kern/screen.h
deleted file mode 100644
index dfdc12de5..000000000
--- a/sys/src/cmd/unix/drawterm/kern/screen.h
+++ /dev/null
@@ -1,63 +0,0 @@
-typedef struct Mouseinfo Mouseinfo;
-typedef struct Mousestate Mousestate;
-typedef struct Cursorinfo Cursorinfo;
-typedef struct Screeninfo Screeninfo;
-
-#define Mousequeue 16 /* queue can only have Mousequeue-1 elements */
-#define Mousewindow 500 /* mouse event window in millisec */
-
-struct Mousestate {
- int buttons;
- Point xy;
- ulong msec;
-};
-
-struct Mouseinfo {
- Lock lk;
- Mousestate queue[Mousequeue];
- int ri, wi;
- int lastb;
- int trans;
- int open;
- Rendez r;
-};
-
-struct Cursorinfo {
- Lock lk;
- Point offset;
- uchar clr[2*16];
- uchar set[2*16];
-};
-
-struct Screeninfo {
- Lock lk;
- Memimage *newsoft;
- int reshaped;
- int depth;
- int dibtype;
-};
-
-extern Memimage *gscreen;
-extern Mouseinfo mouse;
-extern Cursorinfo cursor;
-extern Screeninfo screen;
-
-void screeninit(void);
-void screenload(Rectangle, int, uchar *, Point, int);
-
-void getcolor(ulong, ulong*, ulong*, ulong*);
-void setcolor(ulong, ulong, ulong, ulong);
-
-void refreshrect(Rectangle);
-
-void cursorarrow(void);
-void setcursor(void);
-void mouseset(Point);
-void drawflushr(Rectangle);
-void flushmemscreen(Rectangle);
-uchar *attachscreen(Rectangle*, ulong*, int*, int*, int*, void**);
-
-void drawqlock(void);
-void drawqunlock(void);
-int drawcanqlock(void);
-void terminit(void);
diff --git a/sys/src/cmd/unix/drawterm/kern/sleep.c b/sys/src/cmd/unix/drawterm/kern/sleep.c
deleted file mode 100644
index 6a9ad174e..000000000
--- a/sys/src/cmd/unix/drawterm/kern/sleep.c
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-void
-sleep(Rendez *r, int (*f)(void*), void *arg)
-{
- int s;
-
- s = splhi();
-
- lock(&r->lk);
- lock(&up->rlock);
- if(r->p){
- print("double sleep %lud %lud\n", r->p->pid, up->pid);
- dumpstack();
- }
-
- /*
- * Wakeup only knows there may be something to do by testing
- * r->p in order to get something to lock on.
- * Flush that information out to memory in case the sleep is
- * committed.
- */
- r->p = up;
-
- if((*f)(arg) || up->notepending){
- /*
- * if condition happened or a note is pending
- * never mind
- */
- r->p = nil;
- unlock(&up->rlock);
- unlock(&r->lk);
- } else {
- /*
- * now we are committed to
- * change state and call scheduler
- */
- up->state = Wakeme;
- up->r = r;
-
- /* statistics */
- /* m->cs++; */
-
- unlock(&up->rlock);
- unlock(&r->lk);
-
- procsleep();
- }
-
- if(up->notepending) {
- up->notepending = 0;
- splx(s);
- error(Eintr);
- }
-
- splx(s);
-}
-
-Proc*
-wakeup(Rendez *r)
-{
- Proc *p;
- int s;
-
- s = splhi();
-
- lock(&r->lk);
- p = r->p;
-
- if(p != nil){
- lock(&p->rlock);
- if(p->state != Wakeme || p->r != r)
- panic("wakeup: state");
- r->p = nil;
- p->r = nil;
- p->state = Running;
- procwakeup(p);
- unlock(&p->rlock);
- }
- unlock(&r->lk);
-
- splx(s);
-
- return p;
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/smalloc.c b/sys/src/cmd/unix/drawterm/kern/smalloc.c
deleted file mode 100644
index 314f3c850..000000000
--- a/sys/src/cmd/unix/drawterm/kern/smalloc.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-void*
-smalloc(ulong n)
-{
- return mallocz(n, 1);
-}
-
-void*
-malloc(ulong n)
-{
- return mallocz(n, 1);
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/stub.c b/sys/src/cmd/unix/drawterm/kern/stub.c
deleted file mode 100644
index d9c690638..000000000
--- a/sys/src/cmd/unix/drawterm/kern/stub.c
+++ /dev/null
@@ -1,171 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-void
-mallocsummary(void)
-{
-}
-
-void
-pagersummary(void)
-{
-}
-
-int
-iseve(void)
-{
- return 1;
-}
-
-void
-setswapchan(Chan *c)
-{
- USED(c);
-}
-
-void
-splx(int x)
-{
- USED(x);
-}
-
-int
-splhi(void)
-{
- return 0;
-}
-
-int
-spllo(void)
-{
- return 0;
-}
-
-void
-procdump(void)
-{
-}
-
-void
-scheddump(void)
-{
-}
-
-void
-killbig(void)
-{
-}
-
-void
-dumpstack(void)
-{
-}
-
-void
-xsummary(void)
-{
-}
-
-void
-rebootcmd(int argc, char **argv)
-{
- USED(argc);
- USED(argv);
-}
-
-void
-kickpager(void)
-{
-}
-
-int
-userwrite(char *a, int n)
-{
- error(Eperm);
- return 0;
-}
-
-vlong
-todget(vlong *p)
-{
- if(p)
- *p = 0;
- return 0;
-}
-
-void
-todset(vlong a, vlong b, int c)
-{
- USED(a);
- USED(b);
- USED(c);
-}
-
-void
-todsetfreq(vlong a)
-{
- USED(a);
-}
-
-long
-hostdomainwrite(char *a, int n)
-{
- USED(a);
- USED(n);
- error(Eperm);
- return 0;
-}
-
-long
-hostownerwrite(char *a, int n)
-{
- USED(a);
- USED(n);
- error(Eperm);
- return 0;
-}
-
-void
-todinit(void)
-{
-}
-
-void
-rdb(void)
-{
-}
-
-void
-setmalloctag(void *v, uintptr tag)
-{
- USED(v);
- USED(tag);
-}
-
-int
-postnote(Proc *p, int x, char *msg, int flag)
-{
- USED(p);
- USED(x);
- USED(msg);
- USED(flag);
- return 0;
-}
-
-void
-exhausted(char *s)
-{
- panic("out of %s", s);
-}
-
-uvlong
-fastticks(uvlong *v)
-{
- if(v)
- *v = 1;
- return 0;
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/sysfile.c b/sys/src/cmd/unix/drawterm/kern/sysfile.c
deleted file mode 100644
index 18dadbcda..000000000
--- a/sys/src/cmd/unix/drawterm/kern/sysfile.c
+++ /dev/null
@@ -1,1244 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include "user.h"
-#undef open
-#undef mount
-#undef read
-#undef write
-#undef seek
-#undef stat
-#undef wstat
-#undef remove
-#undef close
-#undef fstat
-#undef fwstat
-
-/*
- * The sys*() routines needn't poperror() as they return directly to syscall().
- */
-
-static void
-unlockfgrp(Fgrp *f)
-{
- int ex;
-
- ex = f->exceed;
- f->exceed = 0;
- unlock(&f->ref.lk);
- if(ex)
- pprint("warning: process exceeds %d file descriptors\n", ex);
-}
-
-int
-growfd(Fgrp *f, int fd) /* fd is always >= 0 */
-{
- Chan **newfd, **oldfd;
-
- if(fd < f->nfd)
- return 0;
- if(fd >= f->nfd+DELTAFD)
- return -1; /* out of range */
- /*
- * Unbounded allocation is unwise; besides, there are only 16 bits
- * of fid in 9P
- */
- if(f->nfd >= 5000){
- Exhausted:
- print("no free file descriptors\n");
- return -1;
- }
- newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
- if(newfd == 0)
- goto Exhausted;
- oldfd = f->fd;
- memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
- f->fd = newfd;
- free(oldfd);
- f->nfd += DELTAFD;
- if(fd > f->maxfd){
- if(fd/100 > f->maxfd/100)
- f->exceed = (fd/100)*100;
- f->maxfd = fd;
- }
- return 1;
-}
-
-/*
- * this assumes that the fgrp is locked
- */
-int
-findfreefd(Fgrp *f, int start)
-{
- int fd;
-
- for(fd=start; fd<f->nfd; fd++)
- if(f->fd[fd] == 0)
- break;
- if(fd >= f->nfd && growfd(f, fd) < 0)
- return -1;
- return fd;
-}
-
-int
-newfd(Chan *c)
-{
- int fd;
- Fgrp *f;
-
- f = up->fgrp;
- lock(&f->ref.lk);
- fd = findfreefd(f, 0);
- if(fd < 0){
- unlockfgrp(f);
- return -1;
- }
- if(fd > f->maxfd)
- f->maxfd = fd;
- f->fd[fd] = c;
- unlockfgrp(f);
- return fd;
-}
-
-int
-newfd2(int fd[2], Chan *c[2])
-{
- Fgrp *f;
-
- f = up->fgrp;
- lock(&f->ref.lk);
- fd[0] = findfreefd(f, 0);
- if(fd[0] < 0){
- unlockfgrp(f);
- return -1;
- }
- fd[1] = findfreefd(f, fd[0]+1);
- if(fd[1] < 0){
- unlockfgrp(f);
- return -1;
- }
- if(fd[1] > f->maxfd)
- f->maxfd = fd[1];
- f->fd[fd[0]] = c[0];
- f->fd[fd[1]] = c[1];
- unlockfgrp(f);
-
- return 0;
-}
-
-Chan*
-fdtochan(int fd, int mode, int chkmnt, int iref)
-{
- Chan *c;
- Fgrp *f;
-
- c = 0;
- f = up->fgrp;
-
- lock(&f->ref.lk);
- if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {
- unlock(&f->ref.lk);
- error(Ebadfd);
- }
- if(iref)
- incref(&c->ref);
- unlock(&f->ref.lk);
-
- if(chkmnt && (c->flag&CMSG)) {
- if(iref)
- cclose(c);
- error(Ebadusefd);
- }
-
- if(mode<0 || c->mode==ORDWR)
- return c;
-
- if((mode&OTRUNC) && c->mode==OREAD) {
- if(iref)
- cclose(c);
- error(Ebadusefd);
- }
-
- if((mode&~OTRUNC) != c->mode) {
- if(iref)
- cclose(c);
- error(Ebadusefd);
- }
-
- return c;
-}
-
-int
-openmode(ulong o)
-{
- o &= ~(OTRUNC|OCEXEC|ORCLOSE);
- if(o > OEXEC)
- error(Ebadarg);
- if(o == OEXEC)
- return OREAD;
- return o;
-}
-
-long
-_sysfd2path(int fd, char *buf, uint nbuf)
-{
- Chan *c;
-
- c = fdtochan(fd, -1, 0, 1);
-
- if(c->name == nil)
- snprint(buf, nbuf, "<null>");
- else
- snprint(buf, nbuf, "%s", c->name->s);
- cclose(c);
- return 0;
-}
-
-long
-_syspipe(int fd[2])
-{
- Chan *c[2];
- Dev *d;
- static char *datastr[] = {"data", "data1"};
-
- d = devtab[devno('|', 0)];
- c[0] = namec("#|", Atodir, 0, 0);
- c[1] = 0;
- fd[0] = -1;
- fd[1] = -1;
-
- if(waserror()){
- cclose(c[0]);
- if(c[1])
- cclose(c[1]);
- nexterror();
- }
- c[1] = cclone(c[0]);
- if(walk(&c[0], datastr+0, 1, 1, nil) < 0)
- error(Egreg);
- if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
- error(Egreg);
- c[0] = d->open(c[0], ORDWR);
- c[1] = d->open(c[1], ORDWR);
- if(newfd2(fd, c) < 0)
- error(Enofd);
- poperror();
-
- return 0;
-}
-
-long
-_sysdup(int fd0, int fd1)
-{
- int fd;
- Chan *c, *oc;
- Fgrp *f = up->fgrp;
-
- /*
- * Close after dup'ing, so date > #d/1 works
- */
- c = fdtochan(fd0, -1, 0, 1);
- fd = fd1;
- if(fd != -1){
- lock(&f->ref.lk);
- if(fd<0 || growfd(f, fd)<0) {
- unlockfgrp(f);
- cclose(c);
- error(Ebadfd);
- }
- if(fd > f->maxfd)
- f->maxfd = fd;
-
- oc = f->fd[fd];
- f->fd[fd] = c;
- unlockfgrp(f);
- if(oc)
- cclose(oc);
- }else{
- if(waserror()) {
- cclose(c);
- nexterror();
- }
- fd = newfd(c);
- if(fd < 0)
- error(Enofd);
- poperror();
- }
-
- return fd;
-}
-
-long
-_sysopen(char *name, int mode)
-{
- int fd;
- Chan *c = 0;
-
- openmode(mode); /* error check only */
- if(waserror()){
- if(c)
- cclose(c);
- nexterror();
- }
- c = namec(name, Aopen, mode, 0);
- fd = newfd(c);
- if(fd < 0)
- error(Enofd);
- poperror();
- return fd;
-}
-
-void
-fdclose(int fd, int flag)
-{
- int i;
- Chan *c;
- Fgrp *f = up->fgrp;
-
- lock(&f->ref.lk);
- c = f->fd[fd];
- if(c == 0){
- /* can happen for users with shared fd tables */
- unlock(&f->ref.lk);
- return;
- }
- if(flag){
- if(c==0 || !(c->flag&flag)){
- unlock(&f->ref.lk);
- return;
- }
- }
- f->fd[fd] = 0;
- if(fd == f->maxfd)
- for(i=fd; --i>=0 && f->fd[i]==0; )
- f->maxfd = i;
-
- unlock(&f->ref.lk);
- cclose(c);
-}
-
-long
-_sysclose(int fd)
-{
- fdtochan(fd, -1, 0, 0);
- fdclose(fd, 0);
-
- return 0;
-}
-
-long
-unionread(Chan *c, void *va, long n)
-{
- int i;
- long nr;
- Mhead *m;
- Mount *mount;
-
- qlock(&c->umqlock);
- m = c->umh;
- rlock(&m->lock);
- mount = m->mount;
- /* bring mount in sync with c->uri and c->umc */
- for(i = 0; mount != nil && i < c->uri; i++)
- mount = mount->next;
-
- nr = 0;
- while(mount != nil) {
- /* Error causes component of union to be skipped */
- if(mount->to && !waserror()) {
- if(c->umc == nil){
- c->umc = cclone(mount->to);
- c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
- }
-
- nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
- c->umc->offset += nr;
- poperror();
- }
- if(nr > 0)
- break;
-
- /* Advance to next element */
- c->uri++;
- if(c->umc) {
- cclose(c->umc);
- c->umc = nil;
- }
- mount = mount->next;
- }
- runlock(&m->lock);
- qunlock(&c->umqlock);
- return nr;
-}
-
-static long
-kread(int fd, void *buf, long n, vlong *offp)
-{
- int dir;
- Chan *c;
- vlong off;
-
- c = fdtochan(fd, OREAD, 1, 1);
-
- if(waserror()) {
- cclose(c);
- nexterror();
- }
-
- dir = c->qid.type&QTDIR;
- /*
- * The offset is passed through on directories, normally. sysseek complains but
- * pread is used by servers and e.g. exportfs that shouldn't need to worry about this issue.
- */
-
- if(offp == nil) /* use and maintain channel's offset */
- off = c->offset;
- else
- off = *offp;
-
- if(off < 0)
- error(Enegoff);
-
- if(dir && c->umh)
- n = unionread(c, buf, n);
- else
- n = devtab[c->type]->read(c, buf, n, off);
-
- if(offp == nil){
- lock(&c->ref.lk);
- c->offset += n;
- unlock(&c->ref.lk);
- }
-
- poperror();
- cclose(c);
-
- return n;
-}
-
-/* name conflicts with netbsd
-long
-_sys_read(int fd, void *buf, long n)
-{
- return kread(fd, buf, n, nil);
-}
-*/
-
-long
-_syspread(int fd, void *buf, long n, vlong off)
-{
- if(off == ((uvlong) ~0))
- return kread(fd, buf, n, nil);
- return kread(fd, buf, n, &off);
-}
-
-static long
-kwrite(int fd, void *buf, long nn, vlong *offp)
-{
- Chan *c;
- long m, n;
- vlong off;
-
- n = 0;
- c = fdtochan(fd, OWRITE, 1, 1);
- if(waserror()) {
- if(offp == nil){
- lock(&c->ref.lk);
- c->offset -= n;
- unlock(&c->ref.lk);
- }
- cclose(c);
- nexterror();
- }
-
- if(c->qid.type & QTDIR)
- error(Eisdir);
-
- n = nn;
-
- if(offp == nil){ /* use and maintain channel's offset */
- lock(&c->ref.lk);
- off = c->offset;
- c->offset += n;
- unlock(&c->ref.lk);
- }else
- off = *offp;
-
- if(off < 0)
- error(Enegoff);
-
- m = devtab[c->type]->write(c, buf, n, off);
-
- if(offp == nil && m < n){
- lock(&c->ref.lk);
- c->offset -= n - m;
- unlock(&c->ref.lk);
- }
-
- poperror();
- cclose(c);
-
- return m;
-}
-
-long
-sys_write(int fd, void *buf, long n)
-{
- return kwrite(fd, buf, n, nil);
-}
-
-long
-_syspwrite(int fd, void *buf, long n, vlong off)
-{
- if(off == ((uvlong) ~0))
- return kwrite(fd, buf, n, nil);
- return kwrite(fd, buf, n, &off);
-}
-
-static vlong
-_sysseek(int fd, vlong off, int whence)
-{
- Chan *c;
- uchar buf[sizeof(Dir)+100];
- Dir dir;
- int n;
-
- c = fdtochan(fd, -1, 1, 1);
- if(waserror()){
- cclose(c);
- nexterror();
- }
- if(devtab[c->type]->dc == '|')
- error(Eisstream);
-
- switch(whence){
- case 0:
- if((c->qid.type & QTDIR) && off != 0)
- error(Eisdir);
- if(off < 0)
- error(Enegoff);
- c->offset = off;
- break;
-
- case 1:
- if(c->qid.type & QTDIR)
- error(Eisdir);
- lock(&c->ref.lk); /* lock for read/write update */
- off = off + c->offset;
- if(off < 0)
- error(Enegoff);
- c->offset = off;
- unlock(&c->ref.lk);
- break;
-
- case 2:
- if(c->qid.type & QTDIR)
- error(Eisdir);
- n = devtab[c->type]->stat(c, buf, sizeof buf);
- if(convM2D(buf, n, &dir, nil) == 0)
- error("internal error: stat error in seek");
- off = dir.length + off;
- if(off < 0)
- error(Enegoff);
- c->offset = off;
- break;
-
- default:
- error(Ebadarg);
- }
- c->uri = 0;
- c->dri = 0;
- cclose(c);
- poperror();
- return off;
-}
-
-void
-validstat(uchar *s, int n)
-{
- int m;
- char buf[64];
-
- if(statcheck(s, n) < 0)
- error(Ebadstat);
- /* verify that name entry is acceptable */
- s += STATFIXLEN - 4*BIT16SZ; /* location of first string */
- /*
- * s now points at count for first string.
- * if it's too long, let the server decide; this is
- * only for his protection anyway. otherwise
- * we'd have to allocate and waserror.
- */
- m = GBIT16(s);
- s += BIT16SZ;
- if(m+1 > sizeof buf)
- return;
- memmove(buf, s, m);
- buf[m] = '\0';
- /* name could be '/' */
- if(strcmp(buf, "/") != 0)
- validname(buf, 0);
-}
-
-long
-_sysfstat(int fd, void *buf, long n)
-{
- Chan *c;
- uint l;
-
- l = n;
- validaddr(buf, l, 1);
- c = fdtochan(fd, -1, 0, 1);
- if(waserror()) {
- cclose(c);
- nexterror();
- }
- l = devtab[c->type]->stat(c, buf, l);
- poperror();
- cclose(c);
- return l;
-}
-
-long
-_sysstat(char *name, void *buf, long n)
-{
- Chan *c;
- uint l;
-
- l = n;
- validaddr(buf, l, 1);
- validaddr(name, 1, 0);
- c = namec(name, Aaccess, 0, 0);
- if(waserror()){
- cclose(c);
- nexterror();
- }
- l = devtab[c->type]->stat(c, buf, l);
- poperror();
- cclose(c);
- return l;
-}
-
-long
-_syschdir(char *name)
-{
- Chan *c;
-
- validaddr(name, 1, 0);
-
- c = namec(name, Atodir, 0, 0);
- cclose(up->dot);
- up->dot = c;
- return 0;
-}
-
-long
-bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec)
-{
- int ret;
- Chan *c0, *c1, *ac, *bc;
- struct{
- Chan *chan;
- Chan *authchan;
- char *spec;
- int flags;
- }bogus;
-
- if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
- error(Ebadarg);
-
- bogus.flags = flag & MCACHE;
-
- if(ismount){
- if(up->pgrp->noattach)
- error(Enoattach);
-
- ac = nil;
- bc = fdtochan(fd, ORDWR, 0, 1);
- if(waserror()) {
- if(ac)
- cclose(ac);
- cclose(bc);
- nexterror();
- }
-
- if(afd >= 0)
- ac = fdtochan(afd, ORDWR, 0, 1);
-
- bogus.chan = bc;
- bogus.authchan = ac;
-
- validaddr((ulong)spec, 1, 0);
- bogus.spec = spec;
- if(waserror())
- error(Ebadspec);
- validname(spec, 1);
- poperror();
-
- ret = devno('M', 0);
- c0 = devtab[ret]->attach((char*)&bogus);
-
- poperror();
- if(ac)
- cclose(ac);
- cclose(bc);
- }else{
- bogus.spec = 0;
- validaddr((ulong)arg0, 1, 0);
- c0 = namec(arg0, Abind, 0, 0);
- }
-
- if(waserror()){
- cclose(c0);
- nexterror();
- }
-
- validaddr((ulong)arg1, 1, 0);
- c1 = namec(arg1, Amount, 0, 0);
- if(waserror()){
- cclose(c1);
- nexterror();
- }
-
- ret = cmount(&c0, c1, flag, bogus.spec);
-
- poperror();
- cclose(c1);
- poperror();
- cclose(c0);
- if(ismount)
- fdclose(fd, 0);
-
- return ret;
-}
-
-long
-_sysbind(char *old, char *new, int flag)
-{
- return bindmount(0, -1, -1, old, new, flag, nil);
-}
-
-long
-_sysmount(int fd, int afd, char *new, int flag, char *spec)
-{
- return bindmount(1, fd, afd, nil, new, flag, spec);
-}
-
-long
-_sysunmount(char *old, char *new)
-{
- Chan *cmount, *cmounted;
-
- cmounted = 0;
-
- cmount = namec(new, Amount, 0, 0);
-
- if(old) {
- if(waserror()) {
- cclose(cmount);
- nexterror();
- }
- validaddr(old, 1, 0);
- /*
- * This has to be namec(..., Aopen, ...) because
- * if arg[0] is something like /srv/cs or /fd/0,
- * opening it is the only way to get at the real
- * Chan underneath.
- */
- cmounted = namec(old, Aopen, OREAD, 0);
- poperror();
- }
-
- if(waserror()) {
- cclose(cmount);
- if(cmounted)
- cclose(cmounted);
- nexterror();
- }
-
- cunmount(cmount, cmounted);
- cclose(cmount);
- if(cmounted)
- cclose(cmounted);
- poperror();
- return 0;
-}
-
-long
-_syscreate(char *name, int mode, ulong perm)
-{
- int fd;
- Chan *c = 0;
-
- openmode(mode&~OEXCL); /* error check only; OEXCL okay here */
- if(waserror()) {
- if(c)
- cclose(c);
- nexterror();
- }
- validaddr(name, 1, 0);
- c = namec(name, Acreate, mode, perm);
- fd = newfd(c);
- if(fd < 0)
- error(Enofd);
- poperror();
- return fd;
-}
-
-long
-_sysremove(char *name)
-{
- Chan *c;
-
- c = namec(name, Aremove, 0, 0);
- if(waserror()){
- c->type = 0; /* see below */
- cclose(c);
- nexterror();
- }
- devtab[c->type]->remove(c);
- /*
- * Remove clunks the fid, but we need to recover the Chan
- * so fake it up. rootclose() is known to be a nop.
- */
- c->type = 0;
- poperror();
- cclose(c);
- return 0;
-}
-
-long
-_syswstat(char *name, void *buf, long n)
-{
- Chan *c;
- uint l;
-
- l = n;
- validstat(buf, l);
- validaddr(name, 1, 0);
- c = namec(name, Aaccess, 0, 0);
- if(waserror()){
- cclose(c);
- nexterror();
- }
- l = devtab[c->type]->wstat(c, buf, l);
- poperror();
- cclose(c);
- return l;
-}
-
-long
-_sysfwstat(int fd, void *buf, long n)
-{
- Chan *c;
- uint l;
-
- l = n;
- validaddr(buf, l, 0);
- validstat(buf, l);
- c = fdtochan(fd, -1, 1, 1);
- if(waserror()) {
- cclose(c);
- nexterror();
- }
- l = devtab[c->type]->wstat(c, buf, l);
- poperror();
- cclose(c);
- return l;
-}
-
-
-static void
-starterror(void)
-{
- assert(up->nerrlab == 0);
-}
-
-static void
-_syserror(void)
-{
- char *p;
-
- p = up->syserrstr;
- up->syserrstr = up->errstr;
- up->errstr = p;
-}
-
-static void
-enderror(void)
-{
- assert(up->nerrlab == 1);
- poperror();
-}
-
-int
-sysbind(char *old, char *new, int flag)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysbind(old, new, flag);
- enderror();
- return n;
-}
-
-int
-syschdir(char *path)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _syschdir(path);
- enderror();
- return n;
-}
-
-int
-sysclose(int fd)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysclose(fd);
- enderror();
- return n;
-}
-
-int
-syscreate(char *name, int mode, ulong perm)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _syscreate(name, mode, perm);
- enderror();
- return n;
-}
-
-int
-sysdup(int fd0, int fd1)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysdup(fd0, fd1);
- enderror();
- return n;
-}
-
-int
-sysfstat(int fd, uchar *buf, int n)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysfstat(fd, buf, n);
- enderror();
- return n;
-}
-
-int
-sysfwstat(int fd, uchar *buf, int n)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysfwstat(fd, buf, n);
- enderror();
- return n;
-}
-
-int
-sysmount(int fd, int afd, char *new, int flag, char *spec)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysmount(fd, afd, new, flag, spec);
- enderror();
- return n;
-}
-
-int
-sysunmount(char *old, char *new)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysunmount(old, new);
- enderror();
- return n;
-}
-
-int
-sysopen(char *name, int mode)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysopen(name, mode);
- enderror();
- return n;
-}
-
-int
-syspipe(int *fd)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _syspipe(fd);
- enderror();
- return n;
-}
-
-long
-syspread(int fd, void *buf, long n, vlong off)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _syspread(fd, buf, n, off);
- enderror();
- return n;
-}
-
-long
-syspwrite(int fd, void *buf, long n, vlong off)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _syspwrite(fd, buf, n, off);
- enderror();
- return n;
-}
-
-long
-sysread(int fd, void *buf, long n)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _syspread(fd, buf, n, (uvlong) ~0);
- enderror();
- return n;
-}
-
-int
-sysremove(char *path)
-{
- int n;
-
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysremove(path);
- enderror();
- return n;
-}
-
-vlong
-sysseek(int fd, vlong off, int whence)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- off = _sysseek(fd, off, whence);
- enderror();
- return off;
-}
-
-int
-sysstat(char *name, uchar *buf, int n)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _sysstat(name, buf, n);
- enderror();
- return n;
-}
-
-long
-syswrite(int fd, void *buf, long n)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _syspwrite(fd, buf, n, (uvlong) ~0);
- enderror();
- return n;
-}
-
-int
-syswstat(char *name, uchar *buf, int n)
-{
- starterror();
- if(waserror()){
- _syserror();
- return -1;
- }
- n = _syswstat(name, buf, n);
- enderror();
- return n;
-}
-
-void
-werrstr(char *f, ...)
-{
- char buf[ERRMAX];
- va_list arg;
-
- va_start(arg, f);
- vsnprint(buf, sizeof buf, f, arg);
- va_end(arg);
-
- if(up->nerrlab)
- strecpy(up->errstr, up->errstr+ERRMAX, buf);
- else
- strecpy(up->syserrstr, up->syserrstr+ERRMAX, buf);
-}
-
-int
-__errfmt(Fmt *fmt)
-{
- if(up->nerrlab)
- return fmtstrcpy(fmt, up->errstr);
- else
- return fmtstrcpy(fmt, up->syserrstr);
-}
-
-int
-errstr(char *buf, uint n)
-{
- char tmp[ERRMAX];
- char *p;
-
- p = up->nerrlab ? up->errstr : up->syserrstr;
- memmove(tmp, p, ERRMAX);
- utfecpy(p, p+ERRMAX, buf);
- utfecpy(buf, buf+n, tmp);
- return strlen(buf);
-}
-
-int
-rerrstr(char *buf, uint n)
-{
- char *p;
-
- p = up->nerrlab ? up->errstr : up->syserrstr;
- utfecpy(buf, buf+n, p);
- return strlen(buf);
-}
-
-void*
-_sysrendezvous(void* arg0, void* arg1)
-{
- void *tag, *val;
- Proc *p, **l;
-
- tag = arg0;
- l = &REND(up->rgrp, (uintptr)tag);
- up->rendval = (void*)~0;
-
- lock(&up->rgrp->ref.lk);
- for(p = *l; p; p = p->rendhash) {
- if(p->rendtag == tag) {
- *l = p->rendhash;
- val = p->rendval;
- p->rendval = arg1;
-
- while(p->mach != 0)
- ;
- procwakeup(p);
- unlock(&up->rgrp->ref.lk);
- return val;
- }
- l = &p->rendhash;
- }
-
- /* Going to sleep here */
- up->rendtag = tag;
- up->rendval = arg1;
- up->rendhash = *l;
- *l = up;
- up->state = Rendezvous;
- unlock(&up->rgrp->ref.lk);
-
- procsleep();
-
- return up->rendval;
-}
-
-void*
-sysrendezvous(void *tag, void *val)
-{
- void *n;
-
- starterror();
- if(waserror()){
- _syserror();
- return (void*)~0;
- }
- n = _sysrendezvous(tag, val);
- enderror();
- return n;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/sysproc.c b/sys/src/cmd/unix/drawterm/kern/sysproc.c
deleted file mode 100644
index 11caeb773..000000000
--- a/sys/src/cmd/unix/drawterm/kern/sysproc.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-long
-sysexits(ulong *arg)
-{
- char *status;
- char *inval = "invalid exit string";
- char buf[ERRMAX];
-
- status = (char*)arg[0];
- if(status){
- if(waserror())
- status = inval;
- else{
- validaddr((ulong)status, 1, 0);
- if(vmemchr(status, 0, ERRMAX) == 0){
- memmove(buf, status, ERRMAX);
- buf[ERRMAX-1] = 0;
- status = buf;
- }
- }
- poperror();
-
- }
- pexit(status, 1);
- return 0; /* not reached */
-}
-
diff --git a/sys/src/cmd/unix/drawterm/kern/term.c b/sys/src/cmd/unix/drawterm/kern/term.c
deleted file mode 100644
index f8fa9cbbf..000000000
--- a/sys/src/cmd/unix/drawterm/kern/term.c
+++ /dev/null
@@ -1,205 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-#include <draw.h>
-#include <memdraw.h>
-#include "screen.h"
-
-#define MINX 8
-#define Backgnd 0xFF /* white */
-
- Memsubfont *memdefont;
-
-struct{
- Point pos;
- int bwid;
-}out;
-
-Lock screenlock;
-
-Memimage *conscol;
-Memimage *back;
-extern Memimage *gscreen;
-
-static Rectangle flushr;
-static Rectangle window;
-static Point curpos;
-static int h;
-static void termscreenputs(char*, int);
-
-
-static void
-screenflush(void)
-{
- drawflushr(flushr);
- flushr = Rect(10000, 10000, -10000, -10000);
-}
-
-static void
-addflush(Rectangle r)
-{
- if(flushr.min.x >= flushr.max.x)
- flushr = r;
- else
- combinerect(&flushr, r);
-}
-
-static void
-screenwin(void)
-{
- Point p;
- char *greet;
- Memimage *grey;
-
- drawqlock();
- back = memwhite;
- conscol = memblack;
- memfillcolor(gscreen, 0x444488FF);
-
- h = memdefont->height;
-
- window.min = addpt(gscreen->r.min, Pt(20,20));
- window.max.x = window.min.x + Dx(gscreen->r)*3/4-40;
- window.max.y = window.min.y + Dy(gscreen->r)*3/4-100;
-
- memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S);
- window = insetrect(window, 4);
- memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
-
- /* a lot of work to get a grey color */
- grey = allocmemimage(Rect(0,0,1,1), CMAP8);
- grey->flags |= Frepl;
- grey->clipr = gscreen->r;
- memfillcolor(grey, 0xAAAAAAFF);
- memimagedraw(gscreen, Rect(window.min.x, window.min.y,
- window.max.x, window.min.y+h+5+6), grey, ZP, nil, ZP, S);
- freememimage(grey);
- window = insetrect(window, 5);
-
- greet = " Plan 9 Console ";
- p = addpt(window.min, Pt(10, 0));
- memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
- window.min.y += h+6;
- curpos = window.min;
- window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
- flushmemscreen(gscreen->r);
- drawqunlock();
-}
-
-void
-terminit(void)
-{
- memdefont = getmemdefont();
- out.pos.x = MINX;
- out.pos.y = 0;
- out.bwid = memdefont->info[' '].width;
- screenwin();
- screenputs = termscreenputs;
-}
-
-static void
-scroll(void)
-{
- int o;
- Point p;
- Rectangle r;
-
- o = 8*h;
- r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
- p = Pt(window.min.x, window.min.y+o);
- memimagedraw(gscreen, r, gscreen, p, nil, p, S);
- r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
- memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
- flushmemscreen(gscreen->r);
- curpos.y -= o;
-}
-
-static void
-screenputc(char *buf)
-{
- Point p;
- int w, pos;
- Rectangle r;
- static int *xp;
- static int xbuf[256];
-
- if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
- xp = xbuf;
-
- switch(buf[0]) {
- case '\n':
- if(curpos.y+h >= window.max.y)
- scroll();
- curpos.y += h;
- screenputc("\r");
- break;
- case '\r':
- xp = xbuf;
- curpos.x = window.min.x;
- break;
- case '\t':
- p = memsubfontwidth(memdefont, " ");
- w = p.x;
- *xp++ = curpos.x;
- pos = (curpos.x-window.min.x)/w;
- pos = 8-(pos%8);
- r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
- memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
- addflush(r);
- curpos.x += pos*w;
- break;
- case '\b':
- if(xp <= xbuf)
- break;
- xp--;
- r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
- memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
- addflush(r);
- curpos.x = *xp;
- break;
- default:
- p = memsubfontwidth(memdefont, buf);
- w = p.x;
-
- if(curpos.x >= window.max.x-w)
- screenputc("\n");
-
- *xp++ = curpos.x;
- r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
- memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
- memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
- addflush(r);
- curpos.x += w;
- }
-}
-
-static void
-termscreenputs(char *s, int n)
-{
- int i, locked;
- Rune r;
- char buf[4];
-
- lock(&screenlock);
- locked = drawcanqlock();
- while(n > 0){
- i = chartorune(&r, s);
- if(i == 0){
- s++;
- --n;
- continue;
- }
- memmove(buf, s, i);
- buf[i] = 0;
- n -= i;
- s += i;
- screenputc(buf);
- }
- if(locked)
- drawqunlock();
- screenflush();
- unlock(&screenlock);
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/uart.c b/sys/src/cmd/unix/drawterm/kern/uart.c
deleted file mode 100644
index da6d93e3d..000000000
--- a/sys/src/cmd/unix/drawterm/kern/uart.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-extern int panicking;
-void
-uartputs(char *s, int n)
-{
- if(panicking)
- write(1, s, n);
-}
-
-
diff --git a/sys/src/cmd/unix/drawterm/kern/unused/syscall.c b/sys/src/cmd/unix/drawterm/kern/unused/syscall.c
deleted file mode 100644
index 1ae9a7cb2..000000000
--- a/sys/src/cmd/unix/drawterm/kern/unused/syscall.c
+++ /dev/null
@@ -1,837 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-Chan*
-fdtochan(int fd, int mode, int chkmnt, int iref)
-{
- Fgrp *f;
- Chan *c;
-
- c = 0;
- f = up->fgrp;
-
- lock(&f->ref.lk);
- if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) {
- unlock(&f->ref.lk);
- error(Ebadfd);
- }
- if(iref)
- refinc(&c->ref);
- unlock(&f->ref.lk);
-
- if(chkmnt && (c->flag&CMSG))
- goto bad;
- if(mode<0 || c->mode==ORDWR)
- return c;
- if((mode&OTRUNC) && c->mode==OREAD)
- goto bad;
- if((mode&~OTRUNC) != c->mode)
- goto bad;
- return c;
-bad:
- if(iref)
- cclose(c);
- error(Ebadusefd);
- return nil; /* shut up compiler */
-}
-
-static void
-fdclose(int fd, int flag)
-{
- int i;
- Chan *c;
- Fgrp *f;
-
- f = up->fgrp;
-
- lock(&f->ref.lk);
- c = f->fd[fd];
- if(c == 0) {
- unlock(&f->ref.lk);
- return;
- }
- if(flag) {
- if(c==0 || !(c->flag&flag)) {
- unlock(&f->ref.lk);
- return;
- }
- }
- f->fd[fd] = 0;
- if(fd == f->maxfd)
- for(i=fd; --i>=0 && f->fd[i]==0; )
- f->maxfd = i;
-
- unlock(&f->ref.lk);
- cclose(c);
-}
-
-static int
-newfd(Chan *c)
-{
- int i;
- Fgrp *f;
-
- f = up->fgrp;
- lock(&f->ref.lk);
- for(i=0; i<NFD; i++)
- if(f->fd[i] == 0){
- if(i > f->maxfd)
- f->maxfd = i;
- f->fd[i] = c;
- unlock(&f->ref.lk);
- return i;
- }
- unlock(&f->ref.lk);
- error("no file descriptors");
- return 0;
-}
-
-int
-sysclose(int fd)
-{
- if(waserror())
- return -1;
-
- fdtochan(fd, -1, 0, 0);
- fdclose(fd, 0);
- poperror();
- return 0;
-}
-
-int
-syscreate(char *path, int mode, ulong perm)
-{
- int fd;
- Chan *c = 0;
-
- if(waserror()) {
- cclose(c);
- return -1;
- }
-
- openmode(mode); /* error check only */
- c = namec(path, Acreate, mode, perm);
- fd = newfd((Chan*)c);
- poperror();
- return fd;
-}
-
-int
-sysdup(int old, int new)
-{
- Chan *oc;
- Fgrp *f = up->fgrp;
- Chan *c = 0;
-
- if(waserror())
- return -1;
-
- c = fdtochan(old, -1, 0, 1);
- if(new != -1) {
- if(new < 0 || NFD <= new) {
- cclose(c);
- error(Ebadfd);
- }
- lock(&f->ref.lk);
- if(new > f->maxfd)
- f->maxfd = new;
- oc = f->fd[new];
- f->fd[new] = (Chan*)c;
- unlock(&f->ref.lk);
- if(oc != 0)
- cclose(oc);
- }
- else {
- if(waserror()) {
- cclose(c);
- nexterror();
- }
- new = newfd((Chan*)c);
- poperror();
- }
- poperror();
- return new;
-}
-
-int
-sysfstat(int fd, char *buf)
-{
- Chan *c = 0;
-
- if(waserror()) {
- cclose(c);
- return -1;
- }
- c = fdtochan(fd, -1, 0, 1);
- devtab[c->type]->stat((Chan*)c, buf);
- poperror();
- cclose(c);
- return 0;
-}
-
-int
-sysfwstat(int fd, char *buf)
-{
- Chan *c = 0;
-
- if(waserror()) {
- cclose(c);
- return -1;
- }
- nameok(buf);
- c = fdtochan(fd, -1, 1, 1);
- devtab[c->type]->wstat((Chan*)c, buf);
- poperror();
- cclose(c);
- return 0;
-}
-
-int
-syschdir(char *dir)
-{
- return 0;
-}
-
-long
-bindmount(Chan *c0, char *old, int flag, char *spec)
-{
- int ret;
- Chan *c1 = 0;
-
- if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER))
- error(Ebadarg);
-
- c1 = namec(old, Amount, 0, 0);
- if(waserror()){
- cclose(c1);
- nexterror();
- }
-
- ret = cmount(c0, c1, flag, spec);
-
- poperror();
- cclose(c1);
- return ret;
-}
-
-int
-sysbind(char *new, char *old, int flags)
-{
- long r;
- Chan *c0 = 0;
-
- if(waserror()) {
- cclose(c0);
- return -1;
- }
- c0 = namec(new, Aaccess, 0, 0);
- r = bindmount(c0, old, flags, "");
- poperror();
- cclose(c0);
- return 0;
-}
-
-int
-sysmount(int fd, char *old, int flags, char *spec)
-{
- long r;
- Chan *c0 = 0, *bc = 0;
- struct {
- Chan* chan;
- char* spec;
- int flags;
- } mntparam;
-
- if(waserror()) {
- cclose(bc);
- cclose(c0);
- return -1;
- }
- bc = fdtochan(fd, ORDWR, 0, 1);
- mntparam.chan = (Chan*)bc;
- mntparam.spec = spec;
- mntparam.flags = flags;
- c0 = (*devtab[devno('M', 0)].attach)(&mntparam);
- cclose(bc);
- r = bindmount(c0, old, flags, spec);
- poperror();
- cclose(c0);
-
- return r;
-}
-
-int
-sysunmount(char *old, char *new)
-{
- Chan *cmount = 0, *cmounted = 0;
-
- if(waserror()) {
- cclose(cmount);
- cclose(cmounted);
- return -1;
- }
-
- cmount = namec(new, Amount, OREAD, 0);
- if(old != 0)
- cmounted = namec(old, Aopen, OREAD, 0);
-
- cunmount(cmount, cmounted);
- poperror();
- cclose(cmount);
- cclose(cmounted);
- return 0;
-}
-
-int
-sysopen(char *path, int mode)
-{
- int fd;
- Chan *c = 0;
-
- if(waserror()){
- cclose(c);
- return -1;
- }
- openmode(mode); /* error check only */
- c = namec(path, Aopen, mode, 0);
- fd = newfd((Chan*)c);
- poperror();
- return fd;
-}
-
-long
-unionread(Chan *c, void *va, long n)
-{
- long nr;
- Chan *nc = 0;
- Pgrp *pg = 0;
-
- pg = up->pgrp;
- rlock(&pg->ns);
-
- for(;;) {
- if(waserror()) {
- runlock(&pg->ns);
- nexterror();
- }
- nc = clone(c->mnt->to, 0);
- poperror();
-
- if(c->mountid != c->mnt->mountid) {
- runlock(&pg->ns);
- cclose(nc);
- return 0;
- }
-
- /* Error causes component of union to be skipped */
- if(waserror()) {
- cclose(nc);
- goto next;
- }
-
- nc = (*devtab[nc->type].open)((Chan*)nc, OREAD);
- nc->offset = c->offset;
- nr = (*devtab[nc->type].read)((Chan*)nc, va, n, nc->offset);
- /* devdirread e.g. changes it */
- c->offset = nc->offset;
- poperror();
-
- cclose(nc);
- if(nr > 0) {
- runlock(&pg->ns);
- return nr;
- }
- /* Advance to next element */
- next:
- c->mnt = c->mnt->next;
- if(c->mnt == 0)
- break;
- c->mountid = c->mnt->mountid;
- c->offset = 0;
- }
- runlock(&pg->ns);
- return 0;
-}
-
-long
-sysread(int fd, void *va, long n)
-{
- int dir;
- Lock *cl;
- Chan *c = 0;
-
- if(waserror()) {
- cclose(c);
- return -1;
- }
- c = fdtochan(fd, OREAD, 1, 1);
-
- dir = c->qid.path&CHDIR;
- if(dir) {
- n -= n%DIRLEN;
- if(c->offset%DIRLEN || n==0)
- error(Etoosmall);
- }
-
- if(dir && c->mnt)
- n = unionread((Chan*)c, va, n);
- else
- n = (*devtab[c->type].read)((Chan*)c, va, n, c->offset);
-
- cl = (Lock*)&c->r.l;
- lock(cl);
- c->offset += n;
- unlock(cl);
-
- poperror();
- cclose(c);
-
- return n;
-}
-
-int
-sysremove(char *path)
-{
- Chan *c = 0;
-
- if(waserror()) {
- if(c != 0)
- c->type = 0; /* see below */
- cclose(c);
- return -1;
- }
- c = namec(path, Aaccess, 0, 0);
- (*devtab[c->type].remove)((Chan*)c);
- /*
- * Remove clunks the fid, but we need to recover the Chan
- * so fake it up. rootclose() is known to be a nop.
- */
- c->type = 0;
- poperror();
- cclose(c);
- return 0;
-}
-
-long
-sysseek(int fd, long off, int whence)
-{
- Dir dir;
- Chan *c;
- char buf[DIRLEN];
-
- if(waserror())
- return -1;
-
- c = fdtochan(fd, -1, 1, 0);
- if(c->qid.path & CHDIR)
- error(Eisdir);
-
- switch(whence) {
- case 0:
- c->offset = off;
- break;
-
- case 1:
- lock(&c->r.l); /* lock for read/write update */
- c->offset += off;
- off = c->offset;
- unlock(&c->r.l);
- break;
-
- case 2:
- (*devtab[c->type].stat)(c, buf);
- convM2D(buf, &dir);
- c->offset = dir.length + off;
- off = c->offset;
- break;
- }
- poperror();
- return off;
-}
-
-int
-sysstat(char *path, char *buf)
-{
- Chan *c = 0;
-
- if(waserror()){
- cclose(c);
- return -1;
- }
- c = namec(path, Aaccess, 0, 0);
- (*devtab[c->type].stat)((Chan*)c, buf);
- poperror();
- cclose(c);
- return 0;
-}
-
-long
-syswrite(int fd, void *va, long n)
-{
- Lock *cl;
- Chan *c = 0;
-
- if(waserror()) {
- cclose(c);
- return -1;
- }
- c = fdtochan(fd, OWRITE, 1, 1);
- if(c->qid.path & CHDIR)
- error(Eisdir);
-
- n = (*devtab[c->type].write)((Chan*)c, va, n, c->offset);
-
- cl = (Lock*)&c->r.l;
- lock(cl);
- c->offset += n;
- unlock(cl);
-
- poperror();
- cclose(c);
-
- return n;
-}
-
-int
-syswstat(char *path, char *buf)
-{
- Chan *c = 0;
-
- if(waserror()) {
- cclose(c);
- return -1;
- }
-
- nameok(buf);
- c = namec(path, Aaccess, 0, 0);
- (*devtab[c->type].wstat)((Chan*)c, buf);
- poperror();
- cclose(c);
- return 0;
-}
-
-int
-sysdirstat(char *name, Dir *dir)
-{
- char buf[DIRLEN];
-
- if(sysstat(name, buf) == -1)
- return -1;
- convM2D(buf, dir);
- return 0;
-}
-
-int
-sysdirfstat(int fd, Dir *dir)
-{
- char buf[DIRLEN];
-
- if(sysfstat(fd, buf) == -1)
- return -1;
-
- convM2D(buf, dir);
- return 0;
-}
-
-int
-sysdirwstat(char *name, Dir *dir)
-{
- char buf[DIRLEN];
-
- convD2M(dir, buf);
- return syswstat(name, buf);
-}
-
-int
-sysdirfwstat(int fd, Dir *dir)
-{
- char buf[DIRLEN];
-
- convD2M(dir, buf);
- return sysfwstat(fd, buf);
-}
-
-long
-sysdirread(int fd, Dir *dbuf, long count)
-{
- int c, n, i, r;
- char buf[DIRLEN*50];
-
- n = 0;
- count = (count/sizeof(Dir)) * DIRLEN;
- while(n < count) {
- c = count - n;
- if(c > sizeof(buf))
- c = sizeof(buf);
- r = sysread(fd, buf, c);
- if(r == 0)
- break;
- if(r < 0 || r % DIRLEN)
- return -1;
- for(i=0; i<r; i+=DIRLEN) {
- convM2D(buf+i, dbuf);
- dbuf++;
- }
- n += r;
- if(r != c)
- break;
- }
-
- return (n/DIRLEN) * sizeof(Dir);
-}
-
-static int
-call(char *clone, char *dest, int *cfdp, char *dir, char *local)
-{
- int fd, cfd, n;
- char *p, name[3*NAMELEN+5], data[3*NAMELEN+10];
-
- cfd = sysopen(clone, ORDWR);
- if(cfd < 0){
- werrstr("%s: %r", clone);
- return -1;
- }
-
- /* get directory name */
- n = sysread(cfd, name, sizeof(name)-1);
- if(n < 0) {
- sysclose(cfd);
- return -1;
- }
- name[n] = 0;
- sprint(name, "%d", strtoul(name, 0, 0));
- p = strrchr(clone, '/');
- *p = 0;
- if(dir)
- snprint(dir, 2*NAMELEN, "%s/%s", clone, name);
- snprint(data, sizeof(data), "%s/%s/data", clone, name);
-
- /* connect */
- /* set local side (port number, for example) if we need to */
- if(local)
- snprint(name, sizeof(name), "connect %s %s", dest, local);
- else
- snprint(name, sizeof(name), "connect %s", dest);
- if(syswrite(cfd, name, strlen(name)) < 0){
- werrstr("%s failed: %r", name);
- sysclose(cfd);
- return -1;
- }
-
- /* open data connection */
- fd = sysopen(data, ORDWR);
- if(fd < 0){
- werrstr("can't open %s: %r", data);
- sysclose(cfd);
- return -1;
- }
- if(cfdp)
- *cfdp = cfd;
- else
- sysclose(cfd);
- return fd;
-}
-
-int
-sysdial(char *dest, char *local, char *dir, int *cfdp)
-{
- int n, fd, rv;
- char *p, net[128], clone[NAMELEN+12];
-
- /* go for a standard form net!... */
- p = strchr(dest, '!');
- if(p == 0){
- snprint(net, sizeof(net), "net!%s", dest);
- } else {
- strncpy(net, dest, sizeof(net)-1);
- net[sizeof(net)-1] = 0;
- }
-
- /* call the connection server */
- fd = sysopen("/net/cs", ORDWR);
- if(fd < 0){
- /* no connection server, don't translate */
- p = strchr(net, '!');
- *p++ = 0;
- snprint(clone, sizeof(clone), "/net/%s/clone", net);
- return call(clone, p, cfdp, dir, local);
- }
-
- /*
- * send dest to connection to translate
- */
- if(syswrite(fd, net, strlen(net)) < 0){
- werrstr("%s: %r", net);
- sysclose(fd);
- return -1;
- }
-
- /*
- * loop through each address from the connection server till
- * we get one that works.
- */
- rv = -1;
- sysseek(fd, 0, 0);
- while((n = sysread(fd, net, sizeof(net) - 1)) > 0){
- net[n] = 0;
- p = strchr(net, ' ');
- if(p == 0)
- continue;
- *p++ = 0;
- rv = call(net, p, cfdp, dir, local);
- if(rv >= 0)
- break;
- }
- sysclose(fd);
- return rv;
-}
-
-static int
-identtrans(char *addr, char *naddr, int na, char *file, int nf)
-{
- char *p;
- char reply[4*NAMELEN];
-
- /* parse the network */
- strncpy(reply, addr, sizeof(reply));
- reply[sizeof(reply)-1] = 0;
- p = strchr(reply, '!');
- if(p)
- *p++ = 0;
-
- sprint(file, "/net/%.*s/clone", na - sizeof("/net//clone"), reply);
- strncpy(naddr, p, na);
- naddr[na-1] = 0;
- return 1;
-}
-
-static int
-nettrans(char *addr, char *naddr, int na, char *file, int nf)
-{
- long n;
- int fd;
- char *cp;
- char reply[4*NAMELEN];
-
- /*
- * ask the connection server
- */
- fd = sysopen("/net/cs", ORDWR);
- if(fd < 0)
- return identtrans(addr, naddr, na, file, nf);
- if(syswrite(fd, addr, strlen(addr)) < 0){
- sysclose(fd);
- return -1;
- }
- sysseek(fd, 0, 0);
- n = sysread(fd, reply, sizeof(reply)-1);
- sysclose(fd);
- if(n <= 0)
- return -1;
- reply[n] = '\0';
-
- /*
- * parse the reply
- */
- cp = strchr(reply, ' ');
- if(cp == 0)
- return -1;
- *cp++ = 0;
- strncpy(naddr, cp, na);
- naddr[na-1] = 0;
- strncpy(file, reply, nf);
- file[nf-1] = 0;
- return 0;
-}
-
-int
-sysannounce(char *addr, char *dir)
-{
- char *cp;
- int ctl, n, m;
- char buf[3*NAMELEN];
- char buf2[3*NAMELEN];
- char netdir[2*NAMELEN];
- char naddr[3*NAMELEN];
-
- /*
- * translate the address
- */
- if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0){
- werrstr("can't translate address");
- return -1;
- }
-
- /*
- * get a control channel
- */
- ctl = sysopen(netdir, ORDWR);
- if(ctl<0){
- werrstr("can't open control channel");
- return -1;
- }
- cp = strrchr(netdir, '/');
- *cp = 0;
-
- /*
- * find out which line we have
- */
- n = sprint(buf, "%.*s/", 2*NAMELEN+1, netdir);
- m = sysread(ctl, &buf[n], sizeof(buf)-n-1);
- if(m <= 0) {
- sysclose(ctl);
- werrstr("can't read control file");
- return -1;
- }
- buf[n+m] = 0;
-
- /*
- * make the call
- */
- n = sprint(buf2, "announce %.*s", 2*NAMELEN, naddr);
- if(syswrite(ctl, buf2, n) != n) {
- sysclose(ctl);
- werrstr("announcement fails");
- return -1;
- }
-
- strcpy(dir, buf);
-
- return ctl;
-}
-
-int
-syslisten(char *dir, char *newdir)
-{
- char *cp;
- int ctl, n, m;
- char buf[3*NAMELEN];
-
- /*
- * open listen, wait for a call
- */
- sprint(buf, "%.*s/listen", 2*NAMELEN+1, dir);
- ctl = sysopen(buf, ORDWR);
- if(ctl < 0)
- return -1;
-
- /*
- * find out which line we have
- */
- strcpy(buf, dir);
- cp = strrchr(buf, '/');
- *++cp = 0;
- n = cp-buf;
- m = sysread(ctl, cp, sizeof(buf) - n - 1);
- if(n<=0){
- sysclose(ctl);
- return -1;
- }
- buf[n+m] = 0;
-
- strcpy(newdir, buf);
- return ctl;
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/waserror.c b/sys/src/cmd/unix/drawterm/kern/waserror.c
deleted file mode 100644
index 3a07bc928..000000000
--- a/sys/src/cmd/unix/drawterm/kern/waserror.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-Label*
-pwaserror(void)
-{
- if(up->nerrlab == NERR)
- panic("error stack overflow");
- return &up->errlab[up->nerrlab++];
-}
-
-void
-nexterror(void)
-{
- longjmp(up->errlab[--up->nerrlab].buf, 1);
-}
-
-void
-error(char *e)
-{
- kstrcpy(up->errstr, e, ERRMAX);
- setjmp(up->errlab[NERR-1].buf);
- nexterror();
-}
diff --git a/sys/src/cmd/unix/drawterm/kern/win32.c b/sys/src/cmd/unix/drawterm/kern/win32.c
deleted file mode 100644
index fa79c1d54..000000000
--- a/sys/src/cmd/unix/drawterm/kern/win32.c
+++ /dev/null
@@ -1,470 +0,0 @@
-#include <windows.h>
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include <libsec.h>
-
-typedef struct Oproc Oproc;
-struct Oproc {
- int tid;
- HANDLE *sema;
-};
-
-static int tlsx = TLS_OUT_OF_INDEXES;
-
-char *argv0;
-
-Proc*
-_getproc(void)
-{
- if(tlsx == TLS_OUT_OF_INDEXES)
- return nil;
- return TlsGetValue(tlsx);
-}
-
-void
-_setproc(Proc *p)
-{
- if(tlsx == TLS_OUT_OF_INDEXES){
- tlsx = TlsAlloc();
- if(tlsx == TLS_OUT_OF_INDEXES)
- panic("out of indexes");
- }
- TlsSetValue(tlsx, p);
-}
-
-void
-oserror(void)
-{
- oserrstr();
- nexterror();
-}
-
-void
-osinit(void)
-{
- Oproc *t;
- static Proc firstprocCTstore;
-
- _setproc(&firstprocCTstore);
- t = (Oproc*)firstprocCTstore.oproc;
- assert(t != 0);
-
- t->tid = GetCurrentThreadId();
- t->sema = CreateSemaphore(0, 0, 1000, 0);
- if(t->sema == 0) {
- oserror();
- panic("could not create semaphore: %r");
- }
-}
-
-void
-osnewproc(Proc *p)
-{
- Oproc *op;
-
- op = (Oproc*)p->oproc;
- op->sema = CreateSemaphore(0, 0, 1000, 0);
- if (op->sema == 0) {
- oserror();
- panic("could not create semaphore: %r");
- }
-}
-
-void
-osmsleep(int ms)
-{
- Sleep((DWORD) ms);
-}
-
-void
-osyield(void)
-{
- Sleep(0);
-}
-
-static DWORD WINAPI tramp(LPVOID vp);
-
-void
-osproc(Proc *p)
-{
- DWORD tid;
-
- if(CreateThread(0, 0, tramp, p, 0, &tid) == 0) {
- oserror();
- panic("osproc: %r");
- }
-
- Sleep(0);
-}
-
-static DWORD WINAPI
-tramp(LPVOID vp)
-{
- Proc *p = (Proc *) vp;
- Oproc *op = (Oproc*) p->oproc;
-
- _setproc(p);
- op->tid = GetCurrentThreadId();
- op->sema = CreateSemaphore(0, 0, 1000, 0);
- if(op->sema == 0) {
- oserror();
- panic("could not create semaphore: %r");
- }
-
- (*p->fn)(p->arg);
- ExitThread(0);
- return 0;
-}
-
-void
-procsleep(void)
-{
- Proc *p;
- Oproc *op;
-
- p = up;
- op = (Oproc*)p->oproc;
- WaitForSingleObject(op->sema, INFINITE);}
-
-void
-procwakeup(Proc *p)
-{
- Oproc *op;
-
- op = (Oproc*)p->oproc;
- ReleaseSemaphore(op->sema, 1, 0);
-}
-
-void
-random20(uchar *p)
-{
- LARGE_INTEGER ti;
- int i, j;
- FILETIME ft;
- DigestState ds;
- vlong tsc;
-
- GetSystemTimeAsFileTime(&ft);
- memset(&ds, 0, sizeof ds);
- sha1((uchar*)&ft, sizeof(ft), 0, &ds);
- for(i=0; i<50; i++) {
- for(j=0; j<10; j++) {
- QueryPerformanceCounter(&ti);
- sha1((uchar*)&ti, sizeof(ti), 0, &ds);
- tsc = GetTickCount();
- sha1((uchar*)&tsc, sizeof(tsc), 0, &ds);
- }
- Sleep(10);
- }
- sha1(0, 0, p, &ds);
-}
-
-void
-randominit(void)
-{
-}
-
-ulong
-randomread(void *v, ulong n)
-{
- int i;
- uchar p[20];
-
- for(i=0; i<n; i+=20){
- random20(p);
- if(i+20 <= n)
- memmove((char*)v+i, p, 20);
- else
- memmove((char*)v+i, p, n-i);
- }
- return n;
-}
-
-long
-seconds(void)
-{
- return time(0);
-}
-
-ulong
-ticks(void)
-{
- return GetTickCount();
-}
-
-#if 0
-uvlong
-fastticks(uvlong *v)
-{
- uvlong n;
-
- n = GetTickCount() * 1000 * 1000;
- if(v)
- *v = n;
- return n;
-}
-#endif
-
-extern int main(int, char*[]);
-
-
-int
-wstrutflen(Rune *s)
-{
- int n;
-
- for(n=0; *s; n+=runelen(*s),s++)
- ;
- return n;
-}
-
-int
-wstrtoutf(char *s, Rune *t, int n)
-{
- int i;
- char *s0;
-
- s0 = s;
- if(n <= 0)
- return wstrutflen(t)+1;
- while(*t) {
- if(n < UTFmax+1 && n < runelen(*t)+1) {
- *s = 0;
- return s-s0+wstrutflen(t)+1;
- }
- i = runetochar(s, t);
- s += i;
- n -= i;
- t++;
- }
- *s = 0;
- return s-s0;
-}
-
-int
-win_hasunicode(void)
-{
- OSVERSIONINFOA osinfo;
- int r;
-
- osinfo.dwOSVersionInfoSize = sizeof(osinfo);
- if(!GetVersionExA(&osinfo))
- panic("GetVersionEx failed");
- switch(osinfo.dwPlatformId) {
- default:
- panic("unknown PlatformId");
- case VER_PLATFORM_WIN32s:
- panic("Win32s not supported");
- case VER_PLATFORM_WIN32_WINDOWS:
- r = 0;
- break;
- case VER_PLATFORM_WIN32_NT:
- r = 1;
- break;
- }
-
- return r;
-}
-
-int
-wstrlen(Rune *s)
-{
- int n;
-
- for(n=0; *s; s++,n++)
- ;
- return n;
-}
-static int args(char *argv[], int n, char *p);
-
-int APIENTRY
-WinMain(HINSTANCE x, HINSTANCE y, LPSTR z, int w)
-{
- int argc, n;
- char *arg, *p, **argv;
- Rune *warg;
-
- if(0 && win_hasunicode()){
- warg = GetCommandLineW();
- n = (wstrlen(warg)+1)*UTFmax;
- arg = malloc(n);
- wstrtoutf(arg, warg, n);
- }else
- arg = GetCommandLineA();
-
- /* conservative guess at the number of args */
- for(argc=4,p=arg; *p; p++)
- if(*p == ' ' || *p == '\t')
- argc++;
- argv = malloc(argc*sizeof(char*));
- argc = args(argv, argc, arg);
-
- mymain(argc, argv);
- ExitThread(0);
- return 0;
-}
-
-/*
- * Break the command line into arguments
- * The rules for this are not documented but appear to be the following
- * according to the source for the microsoft C library.
- * Words are seperated by space or tab
- * Words containing a space or tab can be quoted using "
- * 2N backslashes + " ==> N backslashes and end quote
- * 2N+1 backslashes + " ==> N backslashes + literal "
- * N backslashes not followed by " ==> N backslashes
- */
-static int
-args(char *argv[], int n, char *p)
-{
- char *p2;
- int i, j, quote, nbs;
-
- for(i=0; *p && i<n-1; i++) {
- while(*p == ' ' || *p == '\t')
- p++;
- quote = 0;
- argv[i] = p2 = p;
- for(;*p; p++) {
- if(!quote && (*p == ' ' || *p == '\t'))
- break;
- for(nbs=0; *p == '\\'; p++,nbs++)
- ;
- if(*p == '"') {
- for(j=0; j<(nbs>>1); j++)
- *p2++ = '\\';
- if(nbs&1)
- *p2++ = *p;
- else
- quote = !quote;
- } else {
- for(j=0; j<nbs; j++)
- *p2++ = '\\';
- *p2++ = *p;
- }
- }
- /* move p up one to avoid pointing to null at end of p2 */
- if(*p)
- p++;
- *p2 = 0;
- }
- argv[i] = 0;
-
- return i;
-}
-/*
- * Windows socket error messages
- * There must be a way to get these strings out of the library.
- * This table is derived from the MSDN online help.
- */
-static struct {
- int e;
- char *s;
-} tab[] = {
- { 10004, "interrupted function call" },
- { 10013, "permission denied" },
- { 10014, "bad address" },
- { 10022, "invalid argument" },
- { 10024, "too many open files" },
- { 10035, "resource temporarily unavailable" },
- { 10036, "operation now in progress" },
- { 10037, "operation already in progress" },
- { 10038, "socket operation on nonsocket" },
- { 10039, "destination address required" },
- { 10040, "message too long" },
- { 10041, "protocol wrong type for socket" },
- { 10042, "bad protocol option" },
- { 10043, "protocol not supported" },
- { 10044, "socket type not supported" },
- { 10045, "operation not supported" },
- { 10046, "protocol family not supported" },
- { 10047, "address family not supported by protocol family" },
- { 10048, "address already in use" },
- { 10049, "cannot assign requested address" },
- { 10050, "network is down" },
- { 10051, "network is unreachable" },
- { 10052, "network dropped connection on reset" },
- { 10053, "software caused connection abort" },
- { 10054, "connection reset by peer" },
- { 10055, "no buffer space available" },
- { 10056, "socket is already connected" },
- { 10057, "socket is not connected" },
- { 10058, "cannot send after socket shutdown" },
- { 10060, "connection timed out" },
- { 10061, "connection refused" },
- { 10064, "host is down" },
- { 10065, "no route to host" },
- { 10067, "too many processes" },
- { 10091, "network subsystem is unavailable" },
- { 10092, "winsock.dll version out of range" },
- { 10093, "wsastartup not called" },
- { 10101, "graceful shutdown in progress" },
- { 10109, "class type not found" },
- { 11001, "host name not found" },
- { 11002, "host not found (non-authoritative)" },
- { 11003, "nonrecoverable error" },
- { 11004, "valid name, but no data record of requested type" },
-};
-
-void
-osrerrstr(char *buf, uint nbuf)
-{
- char *p, *q;
- int e, i, r;
-
- e = GetLastError();
- r = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
- 0, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- buf, nbuf, 0);
- if(r == 0){
- for(i=0; i<nelem(tab); i++)
- if(tab[i].e == e){
- strecpy(buf, buf+nbuf, tab[i].s);
- break;
- }
- if(i==nelem(tab))
- snprint(buf, nbuf, "windows error %d", e);
- }
-
- for(p=q=buf; *p; p++) {
- if(*p == '\r')
- continue;
- if(*p == '\n')
- *q++ = ' ';
- else
- *q++ = *p;
- }
- *q = '\0';
-}
-
-void
-oserrstr(void)
-{
- osrerrstr(up->errstr, ERRMAX);
-}
-
-long
-showfilewrite(char *a, int n)
-{
- Rune *action, *arg, *cmd;
- static Rune Lopen[] = { 'o', 'p', 'e', 'n', 0 };
-
- cmd = runesmprint("%.*s", n, a);
- if(cmd == nil)
- error("out of memory");
- if(cmd[runestrlen(cmd)-1] == '\n')
- cmd[runestrlen(cmd)] = 0;
- p = runestrchr(cmd, ' ');
- if(p){
- action = cmd;
- *p++ = 0;
- arg = p;
- }else{
- action = Lopen;
- arg = cmd;
- }
- ShellExecute(0, 0, action, arg, 0, SW_SHOWNORMAL);
- return n;
-}