URI: 
       tVarious additions and fixes. - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit fd04aacee17b348da206c13a550dc1029669805f
   DIR parent 74f990ad84deb1591ddb91be4fc8152ec0c46222
  HTML Author: rsc <devnull@localhost>
       Date:   Sun, 23 Nov 2003 18:12:54 +0000
       
       Various additions and fixes.
       
       Diffstat:
         A src/lib9/9proc.h                    |      23 +++++++++++++++++++++++
         D src/lib9/Makefile                   |      38 -------------------------------
         M src/lib9/_exits.c                   |       6 +++++-
         A src/lib9/_p9dialparse.c             |     151 +++++++++++++++++++++++++++++++
         A src/lib9/_p9dir.c                   |     121 +++++++++++++++++++++++++++++++
         A src/lib9/_p9proc.c                  |      73 +++++++++++++++++++++++++++++++
         A src/lib9/announce.c                 |     137 +++++++++++++++++++++++++++++++
         A src/lib9/atexit.c                   |      54 +++++++++++++++++++++++++++++++
         A src/lib9/atnotify.c                 |      58 ++++++++++++++++++++++++++++++
         M src/lib9/await.c                    |      24 +++++++++---------------
         A src/lib9/cistrcmp.c                 |      26 ++++++++++++++++++++++++++
         A src/lib9/cistrncmp.c                |      28 ++++++++++++++++++++++++++++
         A src/lib9/cistrstr.c                 |      23 +++++++++++++++++++++++
         A src/lib9/create.c                   |       8 ++++++++
         A src/lib9/ctime.c                    |      51 +++++++++++++++++++++++++++++++
         A src/lib9/date.c                     |      77 +++++++++++++++++++++++++++++++
         A src/lib9/dial.c                     |      92 +++++++++++++++++++++++++++++++
         A src/lib9/dirfstat.c                 |      29 +++++++++++++++++++++++++++++
         A src/lib9/dirfwstat.c                |      21 +++++++++++++++++++++
         A src/lib9/dirmodefmt.c               |      47 +++++++++++++++++++++++++++++++
         A src/lib9/dirread.c                  |     155 +++++++++++++++++++++++++++++++
         M src/lib9/dirstat.c                  |      99 +++++++------------------------
         A src/lib9/dirwstat.c                 |      21 +++++++++++++++++++++
         A src/lib9/dup.c                      |      12 ++++++++++++
         M src/lib9/errstr.c                   |      13 +++++++++++++
         A src/lib9/exec.c                     |       9 +++++++++
         M src/lib9/exits.c                    |      14 +++++++++++++-
         M src/lib9/ffork-Darwin.c             |      27 +--------------------------
         A src/lib9/ffork-SunOS.c              |       1 +
         C src/lib9/ffork-Darwin.c -> src/lib… |       0 
         A src/lib9/getcallerpc-sun4u.s        |       5 +++++
         A src/lib9/getenv.c                   |      15 +++++++++++++++
         A src/lib9/getuser.c                  |      17 +++++++++++++++++
         A src/lib9/getwd.c                    |      10 ++++++++++
         A src/lib9/jmp-FreeBSD.s              |       3 +++
         A src/lib9/jmp.c                      |      17 +++++++++++++++++
         A src/lib9/main.c                     |      13 +++++++++++++
         A src/lib9/mkfile                     |      73 +++++++++++++++++++++++++++++++
         A src/lib9/needsrcquote.c             |      12 ++++++++++++
         A src/lib9/netmkaddr.c                |      52 +++++++++++++++++++++++++++++++
         A src/lib9/notify.c                   |      83 +++++++++++++++++++++++++++++++
         A src/lib9/nulldir.c                  |       9 +++++++++
         A src/lib9/postnote.c                 |      34 +++++++++++++++++++++++++++++++
         A src/lib9/priv.c                     |      32 +++++++++++++++++++++++++++++++
         A src/lib9/quote.c                    |     136 +++++++++++++++++++++++++++++++
         A src/lib9/rendez-SunOS.c             |       1 +
         M src/lib9/rendez-pthread.c           |       1 +
         A src/lib9/rendez.c                   |      42 +++++++++++++++++++++++++++++++
         A src/lib9/rfork.c                    |      20 ++++++++++++++++++++
         A src/lib9/seek.c                     |       8 ++++++++
         A src/lib9/sleep.c                    |      35 +++++++++++++++++++++++++++++++
         A src/lib9/stat2dir.c                 |     116 ++++++++++++++++++++++++++++++
         A src/lib9/tas-sun4u.s                |       4 ++++
         A src/lib9/time.c                     |      58 ++++++++++++++++++++++++++++++
         A src/lib9/udp.c                      |      52 +++++++++++++++++++++++++++++++
         M src/lib9/wait.c                     |       3 ++-
         A src/lib9/waitpid.c                  |      20 ++++++++++++++++++++
       
       57 files changed, 2150 insertions(+), 159 deletions(-)
       ---
   DIR diff --git a/src/lib9/9proc.h b/src/lib9/9proc.h
       t@@ -0,0 +1,23 @@
       +enum
       +{
       +        NPRIV = 16,
       +        RENDHASH = 33,
       +        PIDHASH = 33,
       +};
       +
       +typedef struct Uproc Uproc;
       +struct Uproc
       +{
       +        Uproc *next;
       +        int pid;
       +        int pipe[2];
       +        int state;
       +        void *priv[NPRIV];
       +        ulong rendval;
       +        ulong rendtag;
       +        Uproc *rendhash;
       +        p9jmp_buf notejb;
       +};
       +
       +extern Uproc *_p9uproc(void);
       +extern void _p9uprocdie(void);
   DIR diff --git a/src/lib9/Makefile b/src/lib9/Makefile
       t@@ -1,38 +0,0 @@
       -PLAN9=../..
       -include $(PLAN9)/src/Makehdr
       -
       -LIB=lib9.a
       -
       -OFILES=\
       -        _exits.$O\
       -        argv0.$O\
       -        await.$O\
       -        cleanname.$O\
       -        dirstat.$O\
       -        encodefmt.$O\
       -        errstr.$O\
       -        exits.$O\
       -        ffork-$(SYSNAME).$O\
       -        getcallerpc-$(OBJTYPE).$O\
       -        getfields.$O\
       -        lock.$O\
       -        malloctag.$O\
       -        mallocz.$O\
       -        nrand.$O\
       -        qlock.$O\
       -        readn.$O\
       -        rendez-$(SYSNAME).$O\
       -        strecpy.$O\
       -        sysfatal.$O\
       -        tas-$(OBJTYPE).$O\
       -        tokenize.$O\
       -        u16.$O\
       -        u32.$O\
       -        u64.$O\
       -        wait.$O\
       -
       -HFILES=\
       -        $(PLAN9)/include/lib9.h\
       -
       -include $(PLAN9)/src/Makesyslib
       -
   DIR diff --git a/src/lib9/_exits.c b/src/lib9/_exits.c
       t@@ -1,8 +1,12 @@
       -#include <lib9.h>
       +#include <u.h>
       +#include <libc.h>
       +#include "9proc.h"
        
        void
        _exits(char *s)
        {
       +        _p9uprocdie();
       +
                if(s && *s)
                        _exit(1);
                _exit(0);
   DIR diff --git a/src/lib9/_p9dialparse.c b/src/lib9/_p9dialparse.c
       t@@ -0,0 +1,151 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#include <netdb.h>
       +#include <sys/un.h>
       +
       +static char *nets[] = { "tcp", "udp", nil };
       +#define CLASS(p) ((*(uchar*)(p))>>6)
       +
       +static int
       +parseip(char *host, u32int *pip)
       +{
       +        uchar addr[4];
       +        int x, i;
       +        char *p;
       +
       +        p = host;
       +        for(i=0; i<4 && *p; i++){
       +                x = strtoul(p, &p, 0);
       +                if(x < 0 || x >= 256)
       +                        return -1;
       +                if(*p != '.' && *p != 0)
       +                        return -1;
       +                if(*p == '.')
       +                        p++;
       +                addr[i] = x;
       +        }
       +
       +        switch(CLASS(addr)){
       +        case 0:
       +        case 1:
       +                if(i == 3){
       +                        addr[3] = addr[2];
       +                        addr[2] = addr[1];
       +                        addr[1] = 0;
       +                }else if(i == 2){
       +                        addr[3] = addr[1];
       +                        addr[2] = 0;
       +                        addr[1] = 0;
       +                }else if(i != 4)
       +                        return -1;
       +                break;
       +        case 2:
       +                if(i == 3){
       +                        addr[3] = addr[2];
       +                        addr[2] = 0;
       +                }else if(i != 4)
       +                        return -1;
       +                break;
       +        }
       +        *pip = *(u32int*)addr;
       +        return 0;
       +}
       +
       +int
       +_p9dialparse(char *addr, char **pnet, char **punix, u32int *phost, int *pport)
       +{
       +        char *net, *host, *port, *e;
       +        int i;
       +        struct servent *se;
       +        struct hostent *he;
       +        struct sockaddr_un *sun;
       +
       +        if(strncmp(addr, "/net/", 5) == 0)
       +                addr += 5;
       +
       +        net = addr;
       +        if((host = strchr(net, '!')) == nil){
       +                werrstr("malformed address");
       +                return -1;
       +        }
       +        *host++ = 0;
       +        if((port = strchr(host, '!')) == nil){
       +                if(strcmp(net, "unix")==0 || strcmp(net, "net")==0){
       +                Unix:
       +                        if(strlen(host)+1 > sizeof sun->sun_path){
       +                                werrstr("unix socket name too long");
       +                                return -1;
       +                        }
       +                        *punix = host;
       +                        *pnet = "unix";
       +                        *phost = 0;
       +                        *pport = 0;
       +                        return 0;
       +                }
       +                werrstr("malformed address");
       +                return -1;
       +        }
       +        *port++ = 0;
       +
       +        if(*host == 0){
       +                werrstr("malformed address (empty host)");
       +                return -1;
       +        }
       +        if(*port == 0){
       +                werrstr("malformed address (empty port)");
       +                return -1;
       +        }
       +
       +        if(strcmp(net, "unix") == 0)
       +                goto Unix;
       +
       +        if(strcmp(net, "tcp")!=0 && strcmp(net, "udp")!=0){
       +                werrstr("bad network %s!%s!%s", net, host, port);
       +                return -1;
       +        }
       +
       +        /* translate host */
       +        if(strcmp(host, "*") == 0)
       +                *phost = 0;
       +        else if(parseip(host, phost) == 0)
       +                {}
       +        else if((he = gethostbyname(host)) != nil)
       +                *phost = *(u32int*)(he->h_addr);
       +        else{
       +                werrstr("unknown host %s", host);
       +                return -1;
       +        }
       +
       +        /* translate network and port; should return list rather than first */
       +        if(strcmp(net, "net") == 0){
       +                for(i=0; nets[i]; i++){
       +                        if((se = getservbyname(port, nets[i])) != nil){
       +                                *pnet = nets[i];
       +                                *pport = ntohs(se->s_port);
       +                                return 0;
       +                        }
       +                }
       +                werrstr("unknown service %s", port);
       +                return -1;
       +        }
       +
       +        if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){
       +                werrstr("unknown network %s", net);
       +                return -1;
       +        }
       +
       +        *pnet = net;
       +        i = strtol(port, &e, 0);
       +        if(*e == 0){
       +                *pport = i;
       +                return 0;
       +        }
       +
       +        if((se = getservbyname(port, net)) != nil){
       +                *pport = ntohs(se->s_port);
       +                return 0;
       +        }
       +        werrstr("unknown service %s", port);
       +        return -1;
       +}
   DIR diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
       t@@ -0,0 +1,121 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +#include <sys/stat.h>
       +#include <sys/disklabel.h>
       +#include <dirent.h>
       +#include <pwd.h>
       +#include <grp.h>
       +
       +int
       +_p9dir(struct stat *st, char *name, Dir *d, char **str, char *estr)
       +{
       +        char *s;
       +        char tmp[20];
       +        struct group *g;
       +        struct passwd *p;
       +        int sz;
       +
       +        sz = 0;
       +        if(d)
       +                memset(d, 0, sizeof *d);
       +
       +        /* name */
       +        s = strrchr(name, '/');
       +        if(s)
       +                s++;
       +        if(!s || !*s)
       +                s = name;
       +        if(*s == '/')
       +                s++;
       +        if(*s == 0)
       +                s = "/";
       +        if(d){
       +                if(*str + strlen(s)+1 > estr)
       +                        d->name = "oops";
       +                else{
       +                        strcpy(*str, s);
       +                        d->name = *str;
       +                        *str += strlen(*str)+1;
       +                }
       +        }
       +        sz += strlen(s)+1;
       +
       +        /* user */
       +        p = getpwuid(st->st_uid);
       +        if(p == nil){
       +                snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
       +                s = tmp;
       +        }else
       +                s = p->pw_name;
       +        sz += strlen(s)+1;
       +        if(d){
       +                if(*str+strlen(s)+1 > estr)
       +                        d->uid = "oops";        
       +                else{
       +                        strcpy(*str, s);
       +                        d->uid = *str;
       +                        *str += strlen(*str)+1;
       +                }
       +        }
       +
       +        /* group */
       +        g = getgrgid(st->st_gid);
       +        if(g == nil){
       +                snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
       +                s = tmp;
       +        }else
       +                s = g->gr_name;
       +        sz += strlen(s)+1;
       +        if(d){
       +                if(*str + strlen(s)+1 > estr)
       +                        d->gid = "oops";        
       +                else{
       +                        strcpy(*str, s);
       +                        d->gid = *str;
       +                        *str += strlen(*str)+1;
       +                }
       +        }
       +
       +        if(d){
       +                d->type = 'M';
       +
       +                d->muid = "";
       +                d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
       +                d->qid.vers = st->st_gen;
       +                d->mode = st->st_mode&0777;
       +                d->atime = st->st_atime;
       +                d->mtime = st->st_mtime;
       +                d->length = st->st_size;
       +
       +                if(S_ISDIR(st->st_mode)){
       +                        d->length = 0;
       +                        d->mode |= DMDIR;
       +                        d->qid.type = QTDIR;
       +                }
       +
       +                /* fetch real size for disks */
       +                if(S_ISCHR(st->st_mode)){
       +                        int fd, n;
       +                        struct disklabel lab;
       +
       +                        if((fd = open(name, O_RDONLY)) < 0)
       +                                goto nosize;
       +                        if(ioctl(fd, DIOCGDINFO, &lab) < 0)
       +                                goto nosize;
       +                        n = minor(st->st_rdev)&7;
       +                        if(n >= lab.d_npartitions)
       +                                goto nosize;
       +
       +                        d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
       +
       +                nosize:
       +                        if(fd >= 0)
       +                                close(fd);
       +                }
       +        }
       +
       +        return sz;
       +}
       +
   DIR diff --git a/src/lib9/_p9proc.c b/src/lib9/_p9proc.c
       t@@ -0,0 +1,73 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "9proc.h"
       +
       +static Lock uproclock;
       +static Uproc *phash[PIDHASH];
       +
       +Uproc*
       +_p9uproc(void)
       +{
       +        /* for now, assume getpid is fast or cached */
       +        int pid;
       +        Uproc *up;
       +
       +        pid = getpid();
       +again:
       +if(0)print("find %d\n", pid);
       +        lock(&uproclock);
       +        for(up=phash[pid%PIDHASH]; up; up=up->next){
       +                if(up->pid == pid){
       +if(0)print("found %d\n", pid);
       +                        unlock(&uproclock);
       +                        return up;
       +                }
       +        }
       +
       +        up = mallocz(sizeof(Uproc), 1);
       +        if(up == nil){
       +if(0)print("again %d\n", pid);
       +                unlock(&uproclock);
       +                sleep(1000);
       +                goto again;
       +        }
       +
       +againpipe:
       +        if(pipe(up->pipe) < 0){
       +if(0)print("againpipe %d\n", pid);
       +                sleep(1000);
       +                goto againpipe;
       +        }
       +
       +        up->pid = pid;
       +        up->next = phash[pid%PIDHASH];
       +        phash[pid%PIDHASH] = up;
       +if(0)print("link %d\n", pid);
       +        unlock(&uproclock);
       +        return up;
       +}
       +
       +void
       +_p9uprocdie(void)
       +{
       +        Uproc **l, *up;
       +        int pid;
       +
       +        pid = getpid();
       +if(0)print("die %d\n", pid);
       +        lock(&uproclock);
       +        for(l=&phash[pid%33]; *l; l=&(*l)->next){
       +                if((*l)->pid == pid){
       +                        up = *l;
       +                        *l = up->next;
       +if(0)print("died %d\n", pid);
       +                        unlock(&uproclock);
       +                        close(up->pipe[0]);
       +                        close(up->pipe[1]);
       +                        free(up);
       +                        return;
       +                }
       +        }
       +if(0)print("not started %d\n", pid);
       +        unlock(&uproclock);
       +}
   DIR diff --git a/src/lib9/announce.c b/src/lib9/announce.c
       t@@ -0,0 +1,137 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +#include <sys/socket.h>
       +#include <netinet/in.h>
       +#include <sys/un.h>
       +
       +extern int _p9dialparse(char*, char**, char**, u32int*, int*);
       +
       +static int
       +getfd(char *dir)
       +{
       +        int fd;
       +
       +        if(strncmp(dir, "/dev/fd/", 8) != 0)
       +                return -1;
       +        fd = strtol(dir+8, &dir, 0);
       +        if(*dir != 0)
       +                return -1;
       +        return fd;
       +}
       +
       +static void
       +putfd(char *dir, int fd)
       +{
       +        snprint(dir, NETPATHLEN, "/dev/fd/%d", fd);
       +}
       +
       +#undef unix
       +
       +int
       +p9announce(char *addr, char *dir)
       +{
       +        int proto;
       +        char *buf, *unix;
       +        char *net;
       +        u32int host;
       +        int port, s;
       +        int n, sn;
       +        struct sockaddr_in sa;
       +        struct sockaddr_un sun;
       +
       +        buf = strdup(addr);
       +        if(buf == nil)
       +                return -1;
       +
       +        if(_p9dialparse(buf, &net, &unix, &host, &port) < 0){
       +                free(buf);
       +                return -1;
       +        }
       +        if(strcmp(net, "tcp") == 0)
       +                proto = SOCK_STREAM;
       +        else if(strcmp(net, "udp") == 0)
       +                proto = SOCK_DGRAM;
       +        else if(strcmp(net, "unix") == 0)
       +                goto Unix;
       +        else{
       +                werrstr("can only handle tcp, udp, and unix: not %s", net);
       +                free(buf);
       +                return -1;
       +        }
       +        free(buf);
       +
       +        memset(&sa, 0, sizeof sa);
       +        memmove(&sa.sin_addr, &host, 4);
       +        sa.sin_family = AF_INET;
       +        sa.sin_port = htons(port);
       +        if((s = socket(AF_INET, proto, 0)) < 0)
       +                return -1;
       +        sn = sizeof n;
       +        if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&n, &sn) >= 0
       +        && n == SOCK_STREAM){
       +                n = 1;
       +                setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
       +        }
       +        if(bind(s, (struct sockaddr*)&sa, sizeof sa) < 0){
       +                close(s);
       +                return -1;
       +        }
       +        if(proto == SOCK_STREAM){
       +                listen(s, 8);
       +                putfd(dir, s);
       +print("announce dir: %s\n", dir);
       +        }
       +        return s;
       +
       +Unix:
       +        memset(&sun, 0, sizeof sun);
       +        sun.sun_family = AF_UNIX;
       +        sun.sun_len = sizeof sun;
       +        strcpy(sun.sun_path, unix);
       +        if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
       +                return -1;
       +        sn = sizeof sun;
       +        if(bind(s, (struct sockaddr*)&sun, sizeof sun) < 0){
       +                close(s);
       +                return -1;
       +        }
       +        listen(s, 8);
       +        putfd(dir, s);
       +        return s;
       +}
       +
       +int
       +p9listen(char *dir, char *newdir)
       +{
       +        int fd;
       +
       +        if((fd = getfd(dir)) < 0){
       +                werrstr("bad 'directory' in listen: %s", dir);
       +                return -1;
       +        }
       +
       +print("accept %d", fd);
       +        if((fd = accept(fd, nil, nil)) < 0)
       +                return -1;
       +print(" -> %d\n", fd);
       +
       +        putfd(newdir, fd);
       +print("listen dir: %s\n", newdir);
       +        return fd;
       +}
       +
       +int
       +p9accept(int cfd, char *dir)
       +{
       +        int fd;
       +
       +        if((fd = getfd(dir)) < 0){
       +                werrstr("bad 'directory' in accept");
       +                return -1;
       +        }
       +        /* need to dup because the listen fd will be closed */
       +        return dup(fd);
       +}
       +
   DIR diff --git a/src/lib9/atexit.c b/src/lib9/atexit.c
       t@@ -0,0 +1,54 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#define        NEXIT        33
       +
       +static Lock onexlock;
       +static struct
       +{
       +        void        (*f)(void);
       +        int        pid;
       +}onex[NEXIT];
       +
       +int
       +atexit(void (*f)(void))
       +{
       +        int i;
       +
       +        lock(&onexlock);
       +        for(i=0; i<NEXIT; i++)
       +                if(onex[i].f == 0) {
       +                        onex[i].pid = getpid();
       +                        onex[i].f = f;
       +                        unlock(&onexlock);
       +                        return 1;
       +                }
       +        unlock(&onexlock);
       +        return 0;
       +}
       +
       +void
       +atexitdont(void (*f)(void))
       +{
       +        int i, pid;
       +
       +        pid = getpid();
       +        for(i=0; i<NEXIT; i++)
       +                if(onex[i].f == f && onex[i].pid == pid)
       +                        onex[i].f = 0;
       +}
       +
       +void
       +exits(char *s)
       +{
       +        int i, pid;
       +        void (*f)(void);
       +
       +        pid = getpid();
       +        for(i = NEXIT-1; i >= 0; i--)
       +                if((f = onex[i].f) && pid == onex[i].pid) {
       +                        onex[i].f = 0;
       +                        (*f)();
       +                }
       +        _exits(s);
       +}
   DIR diff --git a/src/lib9/atnotify.c b/src/lib9/atnotify.c
       t@@ -0,0 +1,58 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#define        NFN        33
       +static        int        (*onnot[NFN])(void*, char*);
       +static        Lock        onnotlock;
       +
       +static
       +void
       +notifier(void *v, char *s)
       +{
       +        int i;
       +
       +        for(i=0; i<NFN; i++)
       +                if(onnot[i] && ((*onnot[i])(v, s))){
       +                        noted(NCONT);
       +                        return;
       +                }
       +        noted(NDFLT);
       +}
       +
       +int
       +atnotify(int (*f)(void*, char*), int in)
       +{
       +        int i, n, ret;
       +        static int init;
       +
       +        if(!init){
       +                notify(notifier);
       +                init = 1;                /* assign = */
       +        }
       +        ret = 0;
       +        lock(&onnotlock);
       +        if(in){
       +                for(i=0; i<NFN; i++)
       +                        if(onnot[i] == 0) {
       +                                onnot[i] = f;
       +                                ret = 1;
       +                                break;
       +                        }
       +        }else{
       +                n = 0;
       +                for(i=0; i<NFN; i++)
       +                        if(onnot[i]){
       +                                if(ret==0 && onnot[i]==f){
       +                                        onnot[i] = 0;
       +                                        ret = 1;
       +                                }else
       +                                        n++;
       +                        }
       +                if(n == 0){
       +                        init = 0;
       +                        notify(0);
       +                }
       +        }
       +        unlock(&onnotlock);
       +        return ret;
       +}
   DIR diff --git a/src/lib9/await.c b/src/lib9/await.c
       t@@ -1,12 +1,12 @@
       +#define NOPLAN9DEFINES
       +#include <u.h>
       +#include <libc.h>
       +
        #include <signal.h>
        #include <sys/types.h>
       -#include <sys/time.h>
        #include <sys/resource.h>
        #include <sys/wait.h>
        #include <sys/time.h>
       -#include <string.h>
       -#include <errno.h>
       -#include <lib9.h>
        
        static struct {
                int sig;
       t@@ -18,9 +18,7 @@ static struct {
                SIGILL,                "sys: trap: illegal instruction",
                SIGTRAP,                "sys: trace trap",
                SIGABRT,                "sys: abort",
       -#ifdef SIGEMT
                SIGEMT,                "sys: emulate instruction executed",
       -#endif
                SIGFPE,                "sys: fp: trap",
                SIGKILL,                "sys: kill",
                SIGBUS,                "sys: bus error",
       t@@ -40,14 +38,12 @@ static struct {
                SIGVTALRM,        "sys: virtual time alarm",
                SIGPROF,                "sys: profiling timer alarm",
                SIGWINCH,        "sys: window size change",
       -#ifdef SIGINFO
                SIGINFO,                "sys: status request",
       -#endif
                SIGUSR1,                "sys: usr1",
                SIGUSR2,                "sys: usr2",
        };
                
       -static char*
       +char*
        _p9sigstr(int sig, char *tmp)
        {
                int i;
       t@@ -59,8 +55,7 @@ _p9sigstr(int sig, char *tmp)
                return tmp;
        }
        
       -/*
       -static int
       +int
        _p9strsig(char *s)
        {
                int i;
       t@@ -70,7 +65,6 @@ _p9strsig(char *s)
                                return tab[i].sig;
                return 0;
        }
       -*/
        
        int
        await(char *str, int n)
       t@@ -89,16 +83,16 @@ await(char *str, int n)
                        if(WIFEXITED(status)){
                                status = WEXITSTATUS(status);
                                if(status)
       -                                snprint(buf, sizeof buf, "%d %lu %lu %lu %d", pid, u, s, u+s, status);
       +                                snprint(buf, sizeof buf, "%d %lud %lud %lud %d", pid, u, s, u+s, status);
                                else
       -                                snprint(buf, sizeof buf, "%d %lu %lu %lu ''", pid, u, s, u+s);
       +                                snprint(buf, sizeof buf, "%d %lud %lud %lud ''", pid, u, s, u+s, status);
                                strecpy(str, str+n, buf);
                                return strlen(str);
                        }
                        if(WIFSIGNALED(status)){
                                cd = WCOREDUMP(status);
                                USED(cd);
       -                        snprint(buf, sizeof buf, "%d %lu %lu %lu '%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp));
       +                        snprint(buf, sizeof buf, "%d %lud %lud %lud '%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp));
                                strecpy(str, str+n, buf);
                                return strlen(str);
                        }
   DIR diff --git a/src/lib9/cistrcmp.c b/src/lib9/cistrcmp.c
       t@@ -0,0 +1,26 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +cistrcmp(char *s1, char *s2)
       +{
       +        int c1, c2;
       +
       +        while(*s1){
       +                c1 = *(uchar*)s1++;
       +                c2 = *(uchar*)s2++;
       +
       +                if(c1 == c2)
       +                        continue;
       +
       +                if(c1 >= 'A' && c1 <= 'Z')
       +                        c1 -= 'A' - 'a';
       +
       +                if(c2 >= 'A' && c2 <= 'Z')
       +                        c2 -= 'A' - 'a';
       +
       +                if(c1 != c2)
       +                        return c1 - c2;
       +        }
       +        return -*s2;
       +}
   DIR diff --git a/src/lib9/cistrncmp.c b/src/lib9/cistrncmp.c
       t@@ -0,0 +1,28 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +cistrncmp(char *s1, char *s2, int n)
       +{
       +        int c1, c2;
       +
       +        while(*s1 && n-- > 0){
       +                c1 = *(uchar*)s1++;
       +                c2 = *(uchar*)s2++;
       +
       +                if(c1 == c2)
       +                        continue;
       +
       +                if(c1 >= 'A' && c1 <= 'Z')
       +                        c1 -= 'A' - 'a';
       +
       +                if(c2 >= 'A' && c2 <= 'Z')
       +                        c2 -= 'A' - 'a';
       +
       +                if(c1 != c2)
       +                        return c1 - c2;
       +        }
       +        if(n <= 0)
       +                return 0;
       +        return -*s2;
       +}
   DIR diff --git a/src/lib9/cistrstr.c b/src/lib9/cistrstr.c
       t@@ -0,0 +1,23 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +char*
       +cistrstr(char *s, char *sub)
       +{
       +        int c, csub, n;
       +
       +        csub = *sub;
       +        if(csub == '\0')
       +                return s;
       +        if(csub >= 'A' && csub <= 'Z')
       +                csub -= 'A' - 'a';
       +        sub++;
       +        n = strlen(sub);
       +        for(; c = *s; s++){
       +                if(c >= 'A' && c <= 'Z')
       +                        c -= 'A' - 'a';
       +                if(c == csub && cistrncmp(s+1, sub, n) == 0)
       +                        return s;
       +        }
       +        return nil;
       +}
   DIR diff --git a/src/lib9/create.c b/src/lib9/create.c
       t@@ -0,0 +1,8 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +create(char *path, int mode, ulong perm)
       +{
       +        return open(path, mode|O_CREAT|O_TRUNC, perm);
       +}
   DIR diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
       t@@ -0,0 +1,51 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +static
       +void
       +ct_numb(char *cp, int n)
       +{
       +
       +        cp[0] = ' ';
       +        if(n >= 10)
       +                cp[0] = (n/10)%10 + '0';
       +        cp[1] = n%10 + '0';
       +}
       +
       +char*
       +asctime(Tm *t)
       +{
       +        char *ncp;
       +        static char cbuf[30];
       +
       +        strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
       +        ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
       +        cbuf[0] = *ncp++;
       +        cbuf[1] = *ncp++;
       +        cbuf[2] = *ncp;
       +        ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
       +        cbuf[4] = *ncp++;
       +        cbuf[5] = *ncp++;
       +        cbuf[6] = *ncp;
       +        ct_numb(cbuf+8, t->mday);
       +        ct_numb(cbuf+11, t->hour+100);
       +        ct_numb(cbuf+14, t->min+100);
       +        ct_numb(cbuf+17, t->sec+100);
       +        ncp = t->zone;
       +        cbuf[20] = *ncp++;
       +        cbuf[21] = *ncp++;
       +        cbuf[22] = *ncp;
       +        if(t->year >= 100) {
       +                cbuf[24] = '2';
       +                cbuf[25] = '0';
       +        }
       +        ct_numb(cbuf+26, t->year+100);
       +        return cbuf;
       +}
       +
       +char*
       +ctime(long t)
       +{
       +        return asctime(localtime(t));
       +}
       +
   DIR diff --git a/src/lib9/date.c b/src/lib9/date.c
       t@@ -0,0 +1,77 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#undef gmtime
       +#undef localtime
       +#undef asctime
       +#undef ctime
       +#undef cputime
       +#undef times
       +#undef tm2sec
       +#undef nsec
       +
       +#include <time.h>
       +
       +static Tm bigtm;
       +
       +static void
       +tm2Tm(struct tm *tm, Tm *bigtm)
       +{
       +        memset(bigtm, 0, sizeof *bigtm);
       +        bigtm->sec = tm->tm_sec;
       +        bigtm->min = tm->tm_min;
       +        bigtm->hour = tm->tm_hour;
       +        bigtm->mday = tm->tm_mday;
       +        bigtm->mon = tm->tm_mon;
       +        bigtm->year = tm->tm_year;
       +        bigtm->wday = tm->tm_wday;
       +        strecpy(bigtm->zone, bigtm->zone+4, tm->tm_zone);
       +        bigtm->tzoff = tm->tm_gmtoff;
       +}
       +
       +static void
       +Tm2tm(Tm *bigtm, struct tm *tm)
       +{
       +        memset(tm, 0, sizeof *tm);
       +        tm->tm_sec = bigtm->sec;
       +        tm->tm_min = bigtm->min;
       +        tm->tm_hour = bigtm->hour;
       +        tm->tm_mday = bigtm->mday;
       +        tm->tm_mon = bigtm->mon;
       +        tm->tm_year = bigtm->year;
       +        tm->tm_wday = bigtm->wday;
       +        tm->tm_zone = bigtm->zone;
       +        tm->tm_gmtoff = bigtm->tzoff;
       +}
       +
       +Tm*
       +p9gmtime(long t)
       +{
       +        struct tm tm;
       +
       +        tm = *gmtime(&t);
       +        tm2Tm(&tm, &bigtm);
       +        return &bigtm;
       +}
       +
       +Tm*
       +p9localtime(long t)
       +{
       +        struct tm tm;
       +
       +        tm = *localtime(&t);
       +        tm2Tm(&tm, &bigtm);
       +        return &bigtm;
       +}
       +
       +long
       +p9tm2sec(Tm *bigtm)
       +{
       +        struct tm tm;
       +
       +        Tm2tm(bigtm, &tm);
       +        if(strcmp(bigtm->zone, "GMT") == 0 || strcmp(bigtm->zone, "UCT") == 0)
       +                return timegm(&tm);
       +        return mktime(&tm);        /* local time zone */
       +}
       +
   DIR diff --git a/src/lib9/dial.c b/src/lib9/dial.c
       t@@ -0,0 +1,92 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#undef        accept
       +#undef        announce
       +#undef        dial
       +#undef        setnetmtpt
       +#undef        hangup
       +#undef        listen
       +#undef        netmkaddr
       +#undef        reject
       +
       +#include <sys/socket.h>
       +#include <netinet/in.h>
       +#include <sys/un.h>
       +#include <netdb.h>
       +
       +
       +extern int _p9dialparse(char*, char**, char**, u32int*, int*);
       +#undef unix
       +
       +int
       +p9dial(char *addr, char *dummy1, char *dummy2, int *dummy3)
       +{
       +        char *buf;
       +        char *net, *unix;
       +        u32int host;
       +        int port;
       +        int proto;
       +        struct sockaddr_in sa;        
       +        struct sockaddr_un su;
       +        int s;
       +
       +        if(dummy1 || dummy2 || dummy3){
       +                werrstr("cannot handle extra arguments in dial");
       +                return -1;
       +        }
       +
       +        buf = strdup(addr);
       +        if(buf == nil)
       +                return -1;
       +
       +        if(_p9dialparse(buf, &net, &unix, &host, &port) < 0){
       +                free(buf);
       +                return -1;
       +        }
       +
       +        if(strcmp(net, "tcp") == 0)
       +                proto = SOCK_STREAM;
       +        else if(strcmp(net, "udp") == 0)
       +                proto = SOCK_DGRAM;
       +        else if(strcmp(net, "unix") == 0)
       +                goto Unix;
       +        else{
       +                werrstr("can only handle tcp, udp, and unix: not %s", net);
       +                free(buf);
       +                return -1;
       +        }
       +        free(buf);
       +
       +        memset(&sa, 0, sizeof sa);
       +        memmove(&sa.sin_addr, &host, 4);
       +        sa.sin_family = AF_INET;
       +        sa.sin_port = htons(port);
       +        if((s = socket(AF_INET, proto, 0)) < 0)
       +                return -1;
       +        if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
       +                close(s);
       +                return -1;
       +        }
       +        return s;
       +
       +Unix:
       +        memset(&su, 0, sizeof su);
       +        su.sun_len = sizeof su;
       +        su.sun_family = AF_UNIX;
       +        if(strlen(unix)+1 > sizeof su.sun_path){
       +                werrstr("unix socket name too long");
       +                free(buf);
       +                return -1;
       +        }
       +        strcpy(su.sun_path, unix);
       +        free(buf);
       +        if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
       +                return -1;
       +        if(connect(s, (struct sockaddr*)&su, sizeof su) < 0){
       +                close(s);
       +                return -1;
       +        }
       +        return s;
       +}
       +
   DIR diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
       t@@ -0,0 +1,29 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +#include <sys/stat.h>
       +
       +extern int _p9dir(struct stat*, char*, Dir*, char**, char*);
       +
       +Dir*
       +dirfstat(int fd)
       +{
       +        struct stat st;
       +        int nstr;
       +        Dir *d;
       +        char *str, tmp[100];
       +
       +        if(fstat(fd, &st) < 0)
       +                return nil;
       +
       +        snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
       +        nstr = _p9dir(&st, tmp, nil, nil, nil);
       +        d = mallocz(sizeof(Dir)+nstr, 1);
       +        if(d == nil)
       +                return nil;
       +        str = (char*)&d[1];
       +        _p9dir(&st, tmp, d, &str, str+nstr);
       +        return d;
       +}
       +
   DIR diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
       t@@ -0,0 +1,21 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +#include <sys/time.h>
       +
       +int
       +dirfwstat(int fd, Dir *dir)
       +{
       +        struct timeval tv[2];
       +
       +        /* BUG handle more */
       +        if(dir->mtime == ~0ULL)
       +                return 0;
       +
       +        tv[0].tv_sec = dir->mtime;
       +        tv[0].tv_usec = 0;
       +        tv[1].tv_sec = dir->mtime;
       +        tv[1].tv_usec = 0;
       +        return futimes(fd, tv);
       +}
   DIR diff --git a/src/lib9/dirmodefmt.c b/src/lib9/dirmodefmt.c
       t@@ -0,0 +1,47 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +static char *modes[] =
       +{
       +        "---",
       +        "--x",
       +        "-w-",
       +        "-wx",
       +        "r--",
       +        "r-x",
       +        "rw-",
       +        "rwx",
       +};
       +
       +static void
       +rwx(long m, char *s)
       +{
       +        strncpy(s, modes[m], 3);
       +}
       +
       +int
       +dirmodefmt(Fmt *f)
       +{
       +        static char buf[16];
       +        ulong m;
       +
       +        m = va_arg(f->args, ulong);
       +
       +        if(m & DMDIR)
       +                buf[0]='d';
       +        else if(m & DMAPPEND)
       +                buf[0]='a';
       +        else if(m & DMAUTH)
       +                buf[0]='A';
       +        else
       +                buf[0]='-';
       +        if(m & DMEXCL)
       +                buf[1]='l';
       +        else
       +                buf[1]='-';
       +        rwx((m>>6)&7, buf+2);
       +        rwx((m>>3)&7, buf+5);
       +        rwx((m>>0)&7, buf+8);
       +        buf[11] = 0;
       +        return fmtstrcpy(f, buf);
       +}
   DIR diff --git a/src/lib9/dirread.c b/src/lib9/dirread.c
       t@@ -0,0 +1,155 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#undef asctime
       +#undef ctime
       +#undef gmtime
       +#undef localtime
       +
       +#include <sys/stat.h>
       +#include <dirent.h>
       +
       +extern int _p9dir(struct stat*, char*, Dir*, char**, char*);
       +
       +static int
       +countde(char *p, int n)
       +{
       +        char *e;
       +        int m;
       +        struct dirent *de;
       +
       +        e = p+n;
       +        m = 0;
       +        while(p < e){
       +                de = (struct dirent*)p;
       +                if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
       +                        break;
       +                if(de->d_namlen == 1 && de->d_name[0]=='.')
       +                        de->d_namlen = 0;
       +                else if(de->d_namlen == 2 && de->d_name[0]=='.' && de->d_name[1]=='.')
       +                        de->d_namlen = 0;
       +                else
       +                        m++;
       +                p += de->d_reclen;
       +        }
       +        return m;
       +}
       +
       +static int
       +dirpackage(int fd, char *buf, int n, Dir **dp)
       +{
       +        int oldwd;
       +        char *p, *str, *estr;
       +        int i, nstr, m;
       +        struct dirent *de;
       +        struct stat st;
       +        Dir *d;
       +
       +        n = countde(buf, n);
       +        if(n <= 0)
       +                return n;
       +
       +        if((oldwd = open(".", O_RDONLY)) < 0)
       +                return -1;
       +        if(fchdir(fd) < 0)
       +                return -1;
       +                
       +        p = buf;
       +        nstr = 0;
       +        for(i=0; i<n; i++){
       +                de = (struct dirent*)p;
       +                if(stat(de->d_name, &st) < 0)
       +                        de->d_namlen = 0;
       +                else
       +                        nstr += _p9dir(&st, de->d_name, nil, nil, nil);
       +                p += de->d_reclen;
       +        }
       +
       +        d = malloc(sizeof(Dir)*n+nstr);
       +        if(d == nil){
       +                fchdir(oldwd);
       +                close(oldwd);
       +                return -1;
       +        }
       +        str = (char*)&d[n];
       +        estr = str+nstr;
       +
       +        p = buf;
       +        m = 0;
       +        for(i=0; i<n; i++){
       +                de = (struct dirent*)p;
       +                if(de->d_namlen != 0 && stat(de->d_name, &st) >= 0)
       +                        _p9dir(&st, de->d_name, &d[m++], &str, estr);
       +                p += de->d_reclen;
       +        }
       +
       +        fchdir(oldwd);
       +        close(oldwd);
       +        *dp = d;
       +        return m;
       +}
       +
       +long
       +dirread(int fd, Dir **dp)
       +{
       +        char *buf;
       +        struct stat st;
       +        int n;
       +
       +        *dp = 0;
       +
       +        if(fstat(fd, &st) < 0)
       +                return -1;
       +
       +        if(st.st_blksize < 8192)
       +                st.st_blksize = 8192;
       +
       +        buf = malloc(st.st_blksize);
       +        if(buf == nil)
       +                return -1;
       +
       +        n = getdents(fd, buf, st.st_blksize);
       +        if(n < 0){
       +                free(buf);
       +                return -1;
       +        }
       +        n = dirpackage(fd, buf, n, dp);
       +        free(buf);
       +        return n;
       +}
       +
       +
       +long
       +dirreadall(int fd, Dir **d)
       +{
       +        uchar *buf, *nbuf;
       +        long n, ts;
       +        struct stat st;
       +
       +        if(fstat(fd, &st) < 0)
       +                return -1;
       +
       +        if(st.st_blksize < 8192)
       +                st.st_blksize = 8192;
       +
       +        buf = nil;
       +        ts = 0;
       +        for(;;){
       +                nbuf = realloc(buf, ts+st.st_blksize);
       +                if(nbuf == nil){
       +                        free(buf);
       +                        return -1;
       +                }
       +                buf = nbuf;
       +                n = getdents(fd, buf+ts, st.st_blksize);
       +                if(n <= 0)
       +                        break;
       +                ts += n;
       +        }
       +        if(ts >= 0)
       +                ts = dirpackage(fd, buf, ts, d);
       +        free(buf);
       +        if(ts == 0 && n < 0)
       +                return -1;
       +        return ts;
       +}
   DIR diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
       t@@ -1,83 +1,28 @@
       -#include "u.h"
       -#include "libc.h"
       -#include <sys/types.h>
       -#include <sys/stat.h>
       -#include <pwd.h>
       -#include <grp.h>
       -
       -static void
       -statconv(Dir *dir, struct stat *s)
       -{
       -        struct passwd *p;
       -        struct group *g;
       -        ulong q;
       -
       -        p = getpwuid(s->st_uid);
       -        if (p)
       -                strncpy(dir->uid, p->pw_name, NAMELEN);
       -        g = getgrgid(s->st_gid);
       -        if (g)
       -                strncpy(dir->gid, g->gr_name, NAMELEN);
       -        q = 0;
       -        if(S_ISDIR(s->st_mode))
       -                q = CHDIR;
       -        q |= s->st_ino & 0x00FFFFFFUL;
       -        dir->qid.path = q;
       -        dir->qid.vers = s->st_mtime;
       -        dir->mode = (dir->qid.path&CHDIR)|(s->st_mode&0777);
       -        dir->atime = s->st_atime;
       -        dir->mtime = s->st_mtime;
       -        dir->length = s->st_size;
       -        dir->dev = s->st_dev;
       -        dir->type = 'M';
       -        if(S_ISFIFO(s->st_mode))
       -                dir->type = '|';
       -}
       -
       -int
       -dirfstat(int fd, Dir *d)
       -{
       -        struct stat sbuf;
       -
       -        if(fstat(fd, &sbuf) < 0)
       -                return -1;
       -        statconv(d, &sbuf);
       -        return 0;
       -}
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
        
       -static char *
       -lelem(char *path)
       -{        
       -        char *pr;
       -
       -        pr = utfrrune(path, '/');
       -        if(pr)
       -                pr++;
       -        else
       -                pr = path;
       -        return pr;
       -}
       -
       -int
       -dirstat(char *f, Dir *d)
       -{
       -        struct stat sbuf;
       +#include <sys/stat.h>
        
       -        if(stat(f, &sbuf) < 0)
       -                return -1;
       -        statconv(d, &sbuf);
       -        strncpy(d->name, lelem(f), NAMELEN);
       -        return 0;
       -}
       +extern int _p9dir(struct stat*, char*, Dir*, char**, char*);
        
       -int
       -dirfwstat(int fd, Dir *d)
       +Dir*
       +dirstat(char *file)
        {
       -        return -1;
       +        struct stat st;
       +        int nstr;
       +        Dir *d;
       +        char *str;
       +
       +        if(stat(file, &st) < 0)
       +                return nil;
       +
       +        nstr = _p9dir(&st, file, nil, nil, nil);
       +        d = mallocz(sizeof(Dir)+nstr, 1);
       +        if(d == nil)
       +                return nil;
       +        str = (char*)&d[1];
       +        _p9dir(&st, file, d, &str, str+nstr);
       +        return d;
        }
        
       -int
       -dirwstat(char *name, Dir *d)
       -{
       -        return -1;
       -}
   DIR diff --git a/src/lib9/dirwstat.c b/src/lib9/dirwstat.c
       t@@ -0,0 +1,21 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +#include <sys/time.h>
       +
       +int
       +dirwstat(char *file, Dir *dir)
       +{
       +        struct timeval tv[2];
       +
       +        /* BUG handle more */
       +        if(dir->mtime == ~0ULL)
       +                return 0;
       +
       +        tv[0].tv_sec = dir->mtime;
       +        tv[0].tv_usec = 0;
       +        tv[1].tv_sec = dir->mtime;
       +        tv[1].tv_usec = 0;
       +        return utimes(file, tv);
       +}
   DIR diff --git a/src/lib9/dup.c b/src/lib9/dup.c
       t@@ -0,0 +1,12 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#undef dup
       +
       +int
       +p9dup(int old, int new)
       +{
       +        if(new == -1)
       +                return dup(old);
       +        return dup2(old, new);
       +}
   DIR diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
       t@@ -78,3 +78,16 @@ werrstr(char *fmt, ...)
                va_end(arg);
                errstr(buf, ERRMAX);
        }
       +
       +char*
       +gerrstr(void)
       +{
       +        char *s;
       +
       +        s = getsyserr();
       +        if(errno != EPLAN9)
       +                strcpy(s, strerror(errno));
       +        return s;
       +}
       +
       +
   DIR diff --git a/src/lib9/exec.c b/src/lib9/exec.c
       t@@ -0,0 +1,9 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +exec(char *prog, char *argv[])
       +{
       +        /* to mimic plan 9 should be just exec, but execvp is a better fit for unix */
       +        return execvp(prog, argv);
       +}
   DIR diff --git a/src/lib9/exits.c b/src/lib9/exits.c
       t@@ -1,10 +1,22 @@
       -#include <lib9.h>
       +#include <u.h>
       +#include <libc.h>
       +
       +extern void _privdie(void);
        
        void
        exits(char *s)
        {
       +        _privdie();
                if(s && *s)
                        exit(1);
                exit(0);
        }
        
       +void
       +_exits(char *s)
       +{
       +        _privdie();
       +        if(s && *s)
       +                _exit(1);
       +        _exit(0);
       +}
   DIR diff --git a/src/lib9/ffork-Darwin.c b/src/lib9/ffork-Darwin.c
       t@@ -1,26 +1 @@
       -#include <lib9.h>
       -#include <pthread.h>
       -
       -extern int __isthreaded;
       -int
       -ffork(int flags, void(*fn)(void*), void *arg)
       -{
       -        void *p;
       -        pthread_t tid;
       -
       -        if(flags != (RFMEM|RFNOWAIT)){
       -                werrstr("ffork unsupported");
       -                return -1;
       -        }
       -
       -        if(pthread_create(&tid, NULL, (void*(*)(void*))fn, arg) < 0)
       -                return -1;
       -        return (int)tid;
       -}
       -
       -int
       -getfforkid(void)
       -{
       -        return (int)pthread_self();
       -}
       -
       +#include "ffork-pthread.c"
   DIR diff --git a/src/lib9/ffork-SunOS.c b/src/lib9/ffork-SunOS.c
       t@@ -0,0 +1 @@
       +#include "ffork-pthread.c"
   DIR diff --git a/src/lib9/ffork-Darwin.c b/src/lib9/ffork-pthread.c
   DIR diff --git a/src/lib9/getcallerpc-sun4u.s b/src/lib9/getcallerpc-sun4u.s
       t@@ -0,0 +1,5 @@
       +.text
       +.globl getcallerpc
       +getcallerpc:
       +        retl
       +        or %o7, %r0, %o0
   DIR diff --git a/src/lib9/getenv.c b/src/lib9/getenv.c
       t@@ -0,0 +1,15 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +char*
       +p9getenv(char *s)
       +{
       +        char *t;
       +
       +        t = getenv(s);
       +        if(t == 0)
       +                return 0;
       +        return strdup(t);
       +}
       +
   DIR diff --git a/src/lib9/getuser.c b/src/lib9/getuser.c
       t@@ -0,0 +1,17 @@
       +#include <pwd.h>
       +
       +#include <u.h>
       +#include <libc.h>
       +
       +char*
       +getuser(void)
       +{
       +        static char user[64];
       +        struct passwd *pw;
       +
       +        pw = getpwuid(getuid());
       +        if(pw == nil)
       +                return "none";
       +        strecpy(user, user+sizeof user, pw->pw_name);
       +        return user;
       +}
   DIR diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
       t@@ -0,0 +1,10 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#undef getwd
       +
       +char*
       +p9getwd(char *s, int ns)
       +{
       +        return getcwd(s, ns);
       +}
   DIR diff --git a/src/lib9/jmp-FreeBSD.s b/src/lib9/jmp-FreeBSD.s
       t@@ -0,0 +1,3 @@
       +.globl sigsetjmp, p9setjmp
       +p9setjmp:
       +        jmp sigsetjmp
   DIR diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
       t@@ -0,0 +1,17 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +void
       +p9longjmp(p9jmp_buf buf, int val)
       +{
       +        siglongjmp((void*)buf, val);
       +}
       +
       +void
       +p9notejmp(void *x, p9jmp_buf buf, int val)
       +{
       +        USED(x);
       +        siglongjmp((void*)buf, val);
       +}
       +
   DIR diff --git a/src/lib9/main.c b/src/lib9/main.c
       t@@ -0,0 +1,13 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +extern void p9main(int, char**);
       +
       +int
       +main(int argc, char **argv)
       +{
       +        p9main(argc, argv);
       +        exits("main");
       +        return 99;
       +}
   DIR diff --git a/src/lib9/mkfile b/src/lib9/mkfile
       t@@ -0,0 +1,73 @@
       +PLAN9=../..
       +<$PLAN9/src/mkhdr
       +
       +LIB=lib9.a
       +
       +OFILES=\
       +        _exits.$O\
       +        _p9dialparse.$O\
       +        _p9dir.$O\
       +        _p9proc.$O\
       +        announce.$O\
       +        argv0.$O\
       +        atexit.$O\
       +        atnotify.$O\
       +        await.$O\
       +        cistrcmp.$O\
       +        cistrncmp.$O\
       +        cistrstr.$O\
       +        cleanname.$O\
       +        create.$O\
       +        ctime.$O\
       +        date.$O\
       +        dial.$O\
       +        dirfstat.$O\
       +        dirfwstat.$O\
       +        dirmodefmt.$O\
       +        dirread.$O\
       +        dirstat.$O\
       +        dirwstat.$O\
       +        dup.$O\
       +        encodefmt.$O\
       +        errstr.$O\
       +        exec.$O\
       +        ffork-$SYSNAME.$O\
       +        getcallerpc-$OBJTYPE.$O\
       +        getenv.$O\
       +        getfields.$O\
       +        getuser.$O\
       +        getwd.$O\
       +        jmp.$O\
       +        jmp-FreeBSD.$O\
       +        lock.$O\
       +        main.$O\
       +        malloctag.$O\
       +        mallocz.$O\
       +        needsrcquote.$O\
       +        netmkaddr.$O\
       +        notify.$O\
       +        nrand.$O\
       +        nulldir.$O\
       +        postnote.$O\
       +        qlock.$O\
       +        quote.$O\
       +        readn.$O\
       +        rendez-$SYSNAME.$O\
       +        rfork.$O\
       +        seek.$O\
       +        sleep.$O\
       +        strecpy.$O\
       +        sysfatal.$O\
       +        tas-$OBJTYPE.$O\
       +        time.$O\
       +        tokenize.$O\
       +        u16.$O\
       +        u32.$O\
       +        u64.$O\
       +        wait.$O\
       +        waitpid.$O\
       +
       +HFILES=\
       +        $PLAN9/include/lib9.h\
       +
       +<$PLAN9/src/mksyslib
   DIR diff --git a/src/lib9/needsrcquote.c b/src/lib9/needsrcquote.c
       t@@ -0,0 +1,12 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +needsrcquote(int c)
       +{
       +        if(c <= ' ')
       +                return 1;
       +        if(strchr("`^#*[]=|\\?${}()'<>&;", c))
       +                return 1;
       +        return 0;
       +}
   DIR diff --git a/src/lib9/netmkaddr.c b/src/lib9/netmkaddr.c
       t@@ -0,0 +1,52 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ctype.h>
       +
       +/*
       + *  make an address, add the defaults
       + */
       +char *
       +netmkaddr(char *linear, char *defnet, char *defsrv)
       +{
       +        static char addr[256];
       +        char *cp;
       +
       +        /*
       +         *  dump network name
       +         */
       +        cp = strchr(linear, '!');
       +        if(cp == 0){
       +                if(defnet==0){
       +                        if(defsrv)
       +                                snprint(addr, sizeof(addr), "net!%s!%s",
       +                                        linear, defsrv);
       +                        else
       +                                snprint(addr, sizeof(addr), "net!%s", linear);
       +                }
       +                else {
       +                        if(defsrv)
       +                                snprint(addr, sizeof(addr), "%s!%s!%s", defnet,
       +                                        linear, defsrv);
       +                        else
       +                                snprint(addr, sizeof(addr), "%s!%s", defnet,
       +                                        linear);
       +                }
       +                return addr;
       +        }
       +
       +        /*
       +         *  if there is already a service, use it
       +         */
       +        cp = strchr(cp+1, '!');
       +        if(cp)
       +                return linear;
       +
       +        /*
       +         *  add default service
       +         */
       +        if(defsrv == 0)
       +                return linear;
       +        snprint(addr, sizeof(addr), "%s!%s", linear, defsrv);
       +
       +        return addr;
       +}
   DIR diff --git a/src/lib9/notify.c b/src/lib9/notify.c
       t@@ -0,0 +1,83 @@
       +#include <signal.h>
       +
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +#include "9proc.h"
       +
       +extern char *_p9sigstr(int, char*);
       +
       +static int sigs[] = {
       +        SIGHUP,
       +        SIGINT,
       +        SIGQUIT,
       +        SIGILL,
       +        SIGTRAP,
       +        SIGABRT,
       +        SIGEMT,
       +        SIGFPE,
       +        SIGBUS,
       +        SIGSEGV,
       +        SIGSYS,
       +        SIGPIPE,
       +        SIGALRM,
       +        SIGTERM,
       +        SIGTSTP,
       +        SIGTTIN,
       +        SIGTTOU,
       +        SIGXCPU,
       +        SIGXFSZ,
       +        SIGVTALRM,
       +        SIGUSR1,
       +        SIGUSR2,
       +};
       +
       +static void (*notifyf)(void*, char*);
       +
       +static void
       +notifysigf(int sig)
       +{
       +        int v;
       +        char tmp[64];
       +        Uproc *up;
       +
       +        up = _p9uproc();
       +        v = p9setjmp(up->notejb);
       +        if(v == 0 && notifyf)
       +                (*notifyf)(nil, _p9sigstr(sig, tmp));
       +        else if(v == 2){
       +if(0)print("HANDLED %d\n", sig);
       +                return;
       +        }
       +if(0)print("DEFAULT %d\n", sig);
       +        signal(sig, SIG_DFL);
       +        kill(getpid(), sig);
       +}
       +        
       +int
       +notify(void (*f)(void*, char*))
       +{
       +        int i;
       +        void (*sf)(int);
       +
       +        if(f == nil)
       +                sf = SIG_DFL;
       +        else{
       +                notifyf = f;
       +                sf = notifysigf;
       +        }
       +        for(i=0; i<nelem(sigs); i++)
       +                signal(sigs[i], sf);
       +        return 0;
       +}
       +
       +int
       +noted(int v)
       +{
       +        Uproc *up;
       +
       +        up = _p9uproc();
       +        p9longjmp(up->notejb, v==NCONT ? 2 : 1);
       +        abort();
       +        return 0;
       +}
   DIR diff --git a/src/lib9/nulldir.c b/src/lib9/nulldir.c
       t@@ -0,0 +1,9 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +void
       +nulldir(Dir *d)
       +{
       +        memset(d, ~0, sizeof(Dir));
       +        d->name = d->uid = d->gid = d->muid = "";
       +}
   DIR diff --git a/src/lib9/postnote.c b/src/lib9/postnote.c
       t@@ -0,0 +1,34 @@
       +#include <signal.h>
       +
       +#include <u.h>
       +#define _NO9DEFINES_
       +#include <libc.h>
       +
       +
       +extern int _p9strsig(char*);
       +
       +int
       +postnote(int who, int pid, char *msg)
       +{
       +        int sig;
       +
       +        sig = _p9strsig(msg);
       +        if(sig == 0){
       +                werrstr("unknown note");
       +                return -1;
       +        }
       +
       +        switch(who){
       +        default:
       +                werrstr("bad who in postnote");
       +                return -1;
       +        case PNPROC:
       +                return kill(pid, sig);
       +        case PNGROUP:
       +                if((pid = getpgid(pid)) < 0)
       +                        return -1;
       +                return killpg(pid, sig);
       +        }
       +}
       +
       +                
   DIR diff --git a/src/lib9/priv.c b/src/lib9/priv.c
       t@@ -0,0 +1,32 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "9proc.h"
       +
       +static Lock privlock;
       +static ulong privmap;
       +
       +int
       +privalloc(void)
       +{
       +        int i;
       +
       +        lock(&privlock);
       +        for(i=0; i<NPRIV; i++)
       +                if((privmap&(1<<i)) == 0){
       +                        privmap |= (1<<i);
       +                        unlock(&privlock);
       +                        return i;
       +                }
       +        unlock(&privlock);
       +        return -1;
       +}
       +
       +void**
       +privmem(int i)
       +{
       +        Uproc *up;
       +
       +        up = _p9uproc();
       +        return &up->priv[i];
       +}
       +
   DIR diff --git a/src/lib9/quote.c b/src/lib9/quote.c
       t@@ -0,0 +1,136 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int        (*doquote)(int);
       +
       +/* in libfmt */
       +extern int __needsquotes(char*, int*);
       +extern int __runeneedsquotes(Rune*, int*);
       +
       +char*
       +unquotestrdup(char *s)
       +{
       +        char *t, *ret;
       +        int quoting;
       +
       +        ret = s = strdup(s);        /* return unquoted copy */
       +        if(ret == nil)
       +                return ret;
       +        quoting = 0;
       +        t = s;        /* s is output string, t is input string */
       +        while(*t!='\0' && (quoting || (*t!=' ' && *t!='\t'))){
       +                if(*t != '\''){
       +                        *s++ = *t++;
       +                        continue;
       +                }
       +                /* *t is a quote */
       +                if(!quoting){
       +                        quoting = 1;
       +                        t++;
       +                        continue;
       +                }
       +                /* quoting and we're on a quote */
       +                if(t[1] != '\''){
       +                        /* end of quoted section; absorb closing quote */
       +                        t++;
       +                        quoting = 0;
       +                        continue;
       +                }
       +                /* doubled quote; fold one quote into two */
       +                t++;
       +                *s++ = *t++;
       +        }
       +        if(t != s)
       +                memmove(s, t, strlen(t)+1);
       +        return ret;
       +}
       +
       +Rune*
       +unquoterunestrdup(Rune *s)
       +{
       +        Rune *t, *ret;
       +        int quoting;
       +
       +        ret = s = runestrdup(s);        /* return unquoted copy */
       +        if(ret == nil)
       +                return ret;
       +        quoting = 0;
       +        t = s;        /* s is output string, t is input string */
       +        while(*t!='\0' && (quoting || (*t!=' ' && *t!='\t'))){
       +                if(*t != '\''){
       +                        *s++ = *t++;
       +                        continue;
       +                }
       +                /* *t is a quote */
       +                if(!quoting){
       +                        quoting = 1;
       +                        t++;
       +                        continue;
       +                }
       +                /* quoting and we're on a quote */
       +                if(t[1] != '\''){
       +                        /* end of quoted section; absorb closing quote */
       +                        t++;
       +                        quoting = 0;
       +                        continue;
       +                }
       +                /* doubled quote; fold one quote into two */
       +                t++;
       +                *s++ = *t++;
       +        }
       +        if(t != s)
       +                memmove(s, t, (runestrlen(t)+1)*sizeof(Rune));
       +        return ret;
       +}
       +
       +char*
       +quotestrdup(char *s)
       +{
       +        char *t, *u, *ret;
       +        int quotelen;
       +        Rune r;
       +
       +        if(__needsquotes(s, &quotelen) == 0)
       +                return strdup(s);
       +        
       +        ret = malloc(quotelen+1);
       +        if(ret == nil)
       +                return nil;
       +        u = ret;
       +        *u++ = '\'';
       +        for(t=s; *t; t++){
       +                r = *t;
       +                if(r == L'\'')
       +                        *u++ = r;        /* double the quote */
       +                *u++ = r;
       +        }
       +        *u++ = '\'';
       +        *u = '\0';
       +        return ret;
       +}
       +
       +Rune*
       +quoterunestrdup(Rune *s)
       +{
       +        Rune *t, *u, *ret;
       +        int quotelen;
       +        Rune r;
       +
       +        if(__runeneedsquotes(s, &quotelen) == 0)
       +                return runestrdup(s);
       +        
       +        ret = malloc((quotelen+1)*sizeof(Rune));
       +        if(ret == nil)
       +                return nil;
       +        u = ret;
       +        *u++ = '\'';
       +        for(t=s; *t; t++){
       +                r = *t;
       +                if(r == L'\'')
       +                        *u++ = r;        /* double the quote */
       +                *u++ = r;
       +        }
       +        *u++ = '\'';
       +        *u = '\0';
       +        return ret;
       +}
   DIR diff --git a/src/lib9/rendez-SunOS.c b/src/lib9/rendez-SunOS.c
       t@@ -0,0 +1 @@
       +#include "rendez-pthread.c"
   DIR diff --git a/src/lib9/rendez-pthread.c b/src/lib9/rendez-pthread.c
       t@@ -33,6 +33,7 @@
         */
        
        #include <pthread.h>
       +#include <signal.h>
        #include <lib9.h>
        
        enum
   DIR diff --git a/src/lib9/rendez.c b/src/lib9/rendez.c
       t@@ -0,0 +1,42 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "9proc.h"
       +
       +static Lock rendlock;
       +static Uproc *rendhash[RENDHASH];
       +
       +ulong
       +rendezvous(ulong tag, ulong val)
       +{
       +        char c;
       +        ulong ret;
       +        Uproc *t, *self, **l;
       +
       +        self = _p9uproc();
       +        lock(&rendlock);
       +        l = &rendhash[tag%RENDHASH];
       +        for(t=*l; t; l=&t->rendhash, t=*l){
       +                if(t->rendtag==tag){
       +                        *l = t->rendhash;
       +                        ret = t->rendval;
       +                        t->rendval = val;
       +                        t->rendtag++;
       +                        c = 0;
       +                        unlock(&rendlock);
       +                        write(t->pipe[1], &c, 1);
       +                        return ret;
       +                }
       +        }
       +
       +        /* Going to sleep here. */
       +        t = self;
       +        t->rendtag = tag;
       +        t->rendval = val;
       +        t->rendhash = *l;
       +        *l = t;
       +        unlock(&rendlock);
       +        do
       +                read(t->pipe[0], &c, 1);
       +        while(t->rendtag == tag);
       +        return t->rendval;
       +}
   DIR diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
       t@@ -0,0 +1,20 @@
       +#define NOPLAN9DEFINES
       +#include <lib9.h>
       +
       +int
       +p9rfork(int flags)
       +{
       +        if(flags&RFPROC){
       +                werrstr("cannot use rfork to fork -- use ffork");
       +                return -1;
       +        }
       +        if(flags&RFNOTEG){
       +                setpgrp(0, 0);
       +                flags &= ~RFNOTEG;
       +        }
       +        if(flags){
       +                werrstr("unknown flags %08ux in rfork", flags);
       +                return -1;
       +        }
       +        return 0;
       +}
   DIR diff --git a/src/lib9/seek.c b/src/lib9/seek.c
       t@@ -0,0 +1,8 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +vlong
       +seek(int fd, vlong offset, int whence)
       +{
       +        return lseek(fd, offset, whence);
       +}
   DIR diff --git a/src/lib9/sleep.c b/src/lib9/sleep.c
       t@@ -0,0 +1,35 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +#include <sys/time.h>
       +#include <sched.h>
       +
       +int
       +p9sleep(long milli)
       +{
       +        struct timeval tv;
       +
       +        if(milli == 0){
       +                sched_yield();
       +                return 0;
       +        }
       +
       +        tv.tv_sec = milli/1000;
       +        tv.tv_usec = (milli%1000)*1000;
       +        return select(0, 0, 0, 0, &tv);
       +}
       +
       +long
       +p9alarm(ulong milli)
       +{
       +        struct itimerval itv;
       +        struct itimerval oitv;
       +
       +        itv.it_interval.tv_sec = 0;
       +        itv.it_interval.tv_usec = 0;
       +        itv.it_value.tv_sec = milli/1000;
       +        itv.it_value.tv_usec = (milli%1000)*1000;
       +        if(setitimer(ITIMER_REAL, &itv, &oitv) < 0)
       +                return -1;
       +        return oitv.it_value.tv_sec*1000+oitv.it_value.tv_usec/1000;
       +}
   DIR diff --git a/src/lib9/stat2dir.c b/src/lib9/stat2dir.c
       t@@ -0,0 +1,116 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +#include <sys/stat.h>
       +#include <sys/disklabel.h>
       +#include <dirent.h>
       +#include <pwd.h>
       +#include <grp.h>
       +
       +int
       +_p9dir(struct stat *st, char *name, Dir *d, char **str, char *estr)
       +{
       +        char *s;
       +        char tmp[20];
       +        struct group *g;
       +        struct pwd *p;
       +        int sz;
       +
       +        sz = 0;
       +
       +        /* name */
       +        s = strrchr(name, '/');
       +        if(s && s[1])
       +                s++;
       +        else
       +                s = "/";
       +        if(d){
       +                if(*str + strlen(s)+1 > estr)
       +                        d->name = "oops";
       +                else{
       +                        strcpy(*str, s);
       +                        d->name = *str;
       +                        *str += strlen(*str)+1;
       +                }
       +        }
       +        sz += strlen(s)+1;
       +
       +        /* user */
       +        p = getpwuid(st->st_uid);
       +        if(p == nil){
       +                snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
       +                s = tmp;
       +        }else
       +                s = p->pw_name;
       +        sz += strlen(s)+1;
       +        if(d){
       +                if(*str+strlen(s)+1 > estr)
       +                        d->uid = "oops";        
       +                else{
       +                        strcpy(*str, s);
       +                        d->uid = *str;
       +                        *str += strlen(*str)+1;
       +                }
       +        }
       +
       +        /* group */
       +        g = getgrgid(st->st_gid);
       +        if(g == nil){
       +                snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
       +                s = tmp;
       +        }else
       +                s = g->gr_name;
       +        sz += strlen(s)+1;
       +        if(d){
       +                if(*str + strlen(s)+1 > estr){
       +                        d->gid = "oops";        
       +                else{
       +                        strcpy(*str, s);
       +                        d->gid = *str;
       +                        *str += strlen(*str)+1;
       +                }
       +        }
       +
       +        if(d){
       +                d->muid = "";
       +                d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
       +                d->qid.vers = st->st_gen;
       +                d->mode = st->st_mode&0777;
       +                if(S_ISDIR(st->st_mode)){
       +                        d->mode |= DMDIR;
       +                        d->qid.type = QTDIR;
       +                }
       +                d->atime = st->st_atime;
       +                d->mtime = st->st_mtime;
       +                d->length = st->st_size;
       +
       +                /* fetch real size for disks */
       +                if(S_ISCHR(st->st_mode)){
       +                        int fd, n;
       +                        struct disklabel lab;
       +
       +                        if((fd = open(name, O_RDONLY)) < 0)
       +                                goto nosize;
       +                        if(ioctl(fd, DIOCGDINFO, &lab) < 0)
       +                                goto nosize;
       +                        n = minor(st->st_rdev)&0xFFFF;
       +                        if(n >= lab.d_npartitions)
       +                                goto nosize;
       +                        d->length = (vlong)lab.d_npartitions[n].p_size * lab.d_secsize;
       +                nosize:
       +                        if(fd >= 0)
       +                                close(fd);
       +                }
       +        }
       +
       +        return sz;
       +}
       +
       +Dir*
       +_dirfstat(char *name, int fd)
       +{
       +        Dir *d;
       +        int size;
       +
       +        
       +}
   DIR diff --git a/src/lib9/tas-sun4u.s b/src/lib9/tas-sun4u.s
       t@@ -0,0 +1,4 @@
       +.globl _tas
       +_tas:
       +        retl
       +        ldstub [%o0], %o0
   DIR diff --git a/src/lib9/time.c b/src/lib9/time.c
       t@@ -0,0 +1,58 @@
       +#include <sys/time.h>
       +#include <sys/resource.h>
       +
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +
       +long
       +p9times(long *t)
       +{
       +        struct rusage ru, cru;
       +
       +        if(getrusage(0, &ru) < 0 || getrusage(-1, &cru) < 0)
       +                return -1;
       +
       +        t[0] = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
       +        t[1] = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
       +        t[2] = cru.ru_utime.tv_sec*1000 + cru.ru_utime.tv_usec/1000;
       +        t[3] = cru.ru_stime.tv_sec*1000 + cru.ru_stime.tv_usec/1000;
       +
       +        /* BUG */
       +        return t[0]+t[1]+t[2]+t[3];
       +}
       +
       +double
       +p9cputime(void)
       +{
       +        long t[4];
       +        double d;
       +
       +        if(p9times(t) < 0)
       +                return -1.0;
       +
       +        d = (double)t[0]+(double)t[1]+(double)t[2]+(double)t[3];
       +        return d/1000.0;
       +}
       +
       +vlong
       +p9nsec(void)
       +{
       +        struct timeval tv;
       +
       +        if(gettimeofday(&tv, 0) < 0)
       +                return -1;
       +
       +        return (vlong)tv.tv_sec*1000*1000*1000 + tv.tv_usec*1000;
       +}
       +
       +long
       +p9time(long *tt)
       +{
       +        long t;
       +        t = time(0);
       +        if(tt)
       +                *tt = t;
       +        return t;
       +}
       +
   DIR diff --git a/src/lib9/udp.c b/src/lib9/udp.c
       t@@ -0,0 +1,52 @@
       +#include <u.h>
       +#define NOPLAN9DEFINES
       +#include <libc.h>
       +#include <ip.h>
       +
       +#include <sys/socket.h>
       +#include <netinet/in.h>
       +
       +/*
       + *  prefix of all v4 addresses
       + *  copied from libip because libc cannot depend on libip
       + */
       +static uchar v4prefix[IPaddrlen] = {
       +        0, 0, 0, 0,
       +        0, 0, 0, 0,
       +        0, 0, 0xff, 0xff,
       +        0, 0, 0, 0
       +};
       +
       +long
       +udpread(int fd, Udphdr *hdr, void *buf, long n)
       +{
       +        struct sockaddr_in sin;
       +        socklen_t len;
       +
       +        len = sizeof sin;
       +        n = recvfrom(fd, buf, n, 0, (struct sockaddr*)&sin, &len);
       +        if(len != sizeof sin){
       +                werrstr("recvfrom acting weird");
       +                return -1;
       +        }
       +        if(n < 0)
       +                return -1;
       +        memset(hdr, 0, sizeof *hdr);
       +        memmove(hdr->raddr, v4prefix, IPaddrlen);
       +        *(u32int*)(hdr->raddr+12) = *(u32int*)&sin.sin_addr;
       +        *(u16int*)hdr->rport = *(u16int*)&sin.sin_port;
       +        return n;
       +}
       +
       +long
       +udpwrite(int fd, Udphdr *hdr, void *buf, long n)
       +{
       +        struct sockaddr_in sin;
       +
       +        memset(&sin, 0, sizeof sin);
       +        sin.sin_family = AF_INET;
       +        *(u32int*)&sin.sin_addr = *(u32int*)(hdr->raddr+12);
       +        *(u16int*)&sin.sin_port = *(u16int*)hdr->rport;
       +        return sendto(fd, buf, n, 0, (struct sockaddr*)&sin, sizeof sin);
       +}
       +
   DIR diff --git a/src/lib9/wait.c b/src/lib9/wait.c
       t@@ -1,4 +1,5 @@
       -#include <lib9.h>
       +#include <u.h>
       +#include <libc.h>
        
        Waitmsg*
        wait(void)
   DIR diff --git a/src/lib9/waitpid.c b/src/lib9/waitpid.c
       t@@ -0,0 +1,20 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +waitpid(void)
       +{
       +        int n;
       +        char buf[512], *fld[5];
       +
       +        n = await(buf, sizeof buf-1);
       +        if(n <= 0)
       +                return -1;
       +        buf[n] = '\0';
       +        if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
       +                werrstr("couldn't parse wait message");
       +                return -1;
       +        }
       +        return atoi(fld[0]);
       +}
       +