aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2003-11-23 18:12:54 +0000
committerrsc <devnull@localhost>2003-11-23 18:12:54 +0000
commitfd04aacee17b348da206c13a550dc1029669805f (patch)
tree9bdd35a25ff6e3d6e9a0171b06240a76723f922c
parent74f990ad84deb1591ddb91be4fc8152ec0c46222 (diff)
downloadplan9port-fd04aacee17b348da206c13a550dc1029669805f.tar.gz
plan9port-fd04aacee17b348da206c13a550dc1029669805f.tar.bz2
plan9port-fd04aacee17b348da206c13a550dc1029669805f.zip
Various additions and fixes.
-rw-r--r--src/lib9/9proc.h23
-rw-r--r--src/lib9/Makefile38
-rw-r--r--src/lib9/_exits.c6
-rw-r--r--src/lib9/_p9dialparse.c151
-rw-r--r--src/lib9/_p9dir.c121
-rw-r--r--src/lib9/_p9proc.c73
-rw-r--r--src/lib9/announce.c137
-rw-r--r--src/lib9/atexit.c54
-rw-r--r--src/lib9/atnotify.c58
-rw-r--r--src/lib9/await.c24
-rw-r--r--src/lib9/cistrcmp.c26
-rw-r--r--src/lib9/cistrncmp.c28
-rw-r--r--src/lib9/cistrstr.c23
-rw-r--r--src/lib9/create.c8
-rw-r--r--src/lib9/ctime.c51
-rw-r--r--src/lib9/date.c77
-rw-r--r--src/lib9/dial.c92
-rw-r--r--src/lib9/dirfstat.c29
-rw-r--r--src/lib9/dirfwstat.c21
-rw-r--r--src/lib9/dirmodefmt.c47
-rw-r--r--src/lib9/dirread.c155
-rw-r--r--src/lib9/dirstat.c99
-rw-r--r--src/lib9/dirwstat.c21
-rw-r--r--src/lib9/dup.c12
-rw-r--r--src/lib9/errstr.c13
-rw-r--r--src/lib9/exec.c9
-rw-r--r--src/lib9/exits.c14
-rw-r--r--src/lib9/ffork-Darwin.c27
-rw-r--r--src/lib9/ffork-SunOS.c1
-rw-r--r--src/lib9/ffork-pthread.c26
-rw-r--r--src/lib9/getcallerpc-sun4u.s5
-rw-r--r--src/lib9/getenv.c15
-rw-r--r--src/lib9/getuser.c17
-rw-r--r--src/lib9/getwd.c10
-rw-r--r--src/lib9/jmp-FreeBSD.s3
-rw-r--r--src/lib9/jmp.c17
-rw-r--r--src/lib9/main.c13
-rw-r--r--src/lib9/mkfile73
-rw-r--r--src/lib9/needsrcquote.c12
-rw-r--r--src/lib9/netmkaddr.c52
-rw-r--r--src/lib9/notify.c83
-rw-r--r--src/lib9/nulldir.c9
-rw-r--r--src/lib9/postnote.c34
-rw-r--r--src/lib9/priv.c32
-rw-r--r--src/lib9/quote.c136
-rw-r--r--src/lib9/rendez-SunOS.c1
-rw-r--r--src/lib9/rendez-pthread.c1
-rw-r--r--src/lib9/rendez.c42
-rw-r--r--src/lib9/rfork.c20
-rw-r--r--src/lib9/seek.c8
-rw-r--r--src/lib9/sleep.c35
-rw-r--r--src/lib9/stat2dir.c116
-rw-r--r--src/lib9/tas-sun4u.s4
-rw-r--r--src/lib9/time.c58
-rw-r--r--src/lib9/udp.c52
-rw-r--r--src/lib9/wait.c3
-rw-r--r--src/lib9/waitpid.c20
57 files changed, 2176 insertions, 159 deletions
diff --git a/src/lib9/9proc.h b/src/lib9/9proc.h
new file mode 100644
index 00000000..713b9558
--- /dev/null
+++ b/src/lib9/9proc.h
@@ -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);
diff --git a/src/lib9/Makefile b/src/lib9/Makefile
deleted file mode 100644
index 5411bd92..00000000
--- a/src/lib9/Makefile
+++ /dev/null
@@ -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
-
diff --git a/src/lib9/_exits.c b/src/lib9/_exits.c
index 35ff4e67..9affe948 100644
--- a/src/lib9/_exits.c
+++ b/src/lib9/_exits.c
@@ -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);
diff --git a/src/lib9/_p9dialparse.c b/src/lib9/_p9dialparse.c
new file mode 100644
index 00000000..93c98425
--- /dev/null
+++ b/src/lib9/_p9dialparse.c
@@ -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;
+}
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
new file mode 100644
index 00000000..459bd157
--- /dev/null
+++ b/src/lib9/_p9dir.c
@@ -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;
+}
+
diff --git a/src/lib9/_p9proc.c b/src/lib9/_p9proc.c
new file mode 100644
index 00000000..6e4010cd
--- /dev/null
+++ b/src/lib9/_p9proc.c
@@ -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);
+}
diff --git a/src/lib9/announce.c b/src/lib9/announce.c
new file mode 100644
index 00000000..dc8cbbbf
--- /dev/null
+++ b/src/lib9/announce.c
@@ -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);
+}
+
diff --git a/src/lib9/atexit.c b/src/lib9/atexit.c
new file mode 100644
index 00000000..b1d8b977
--- /dev/null
+++ b/src/lib9/atexit.c
@@ -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);
+}
diff --git a/src/lib9/atnotify.c b/src/lib9/atnotify.c
new file mode 100644
index 00000000..60e8ad0c
--- /dev/null
+++ b/src/lib9/atnotify.c
@@ -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;
+}
diff --git a/src/lib9/await.c b/src/lib9/await.c
index 49160e76..67e99b82 100644
--- a/src/lib9/await.c
+++ b/src/lib9/await.c
@@ -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;
@@ -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",
@@ -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;
@@ -59,8 +55,7 @@ _p9sigstr(int sig, char *tmp)
return tmp;
}
-/*
-static int
+int
_p9strsig(char *s)
{
int i;
@@ -70,7 +65,6 @@ _p9strsig(char *s)
return tab[i].sig;
return 0;
}
-*/
int
await(char *str, int n)
@@ -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);
}
diff --git a/src/lib9/cistrcmp.c b/src/lib9/cistrcmp.c
new file mode 100644
index 00000000..a545615b
--- /dev/null
+++ b/src/lib9/cistrcmp.c
@@ -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;
+}
diff --git a/src/lib9/cistrncmp.c b/src/lib9/cistrncmp.c
new file mode 100644
index 00000000..8f24d411
--- /dev/null
+++ b/src/lib9/cistrncmp.c
@@ -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;
+}
diff --git a/src/lib9/cistrstr.c b/src/lib9/cistrstr.c
new file mode 100644
index 00000000..0a113226
--- /dev/null
+++ b/src/lib9/cistrstr.c
@@ -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;
+}
diff --git a/src/lib9/create.c b/src/lib9/create.c
new file mode 100644
index 00000000..abef0c35
--- /dev/null
+++ b/src/lib9/create.c
@@ -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);
+}
diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
new file mode 100644
index 00000000..e9d971bf
--- /dev/null
+++ b/src/lib9/ctime.c
@@ -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));
+}
+
diff --git a/src/lib9/date.c b/src/lib9/date.c
new file mode 100644
index 00000000..2e84fd0a
--- /dev/null
+++ b/src/lib9/date.c
@@ -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 */
+}
+
diff --git a/src/lib9/dial.c b/src/lib9/dial.c
new file mode 100644
index 00000000..1d961b4c
--- /dev/null
+++ b/src/lib9/dial.c
@@ -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;
+}
+
diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
new file mode 100644
index 00000000..e617bc2f
--- /dev/null
+++ b/src/lib9/dirfstat.c
@@ -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;
+}
+
diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
new file mode 100644
index 00000000..7f6c54aa
--- /dev/null
+++ b/src/lib9/dirfwstat.c
@@ -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);
+}
diff --git a/src/lib9/dirmodefmt.c b/src/lib9/dirmodefmt.c
new file mode 100644
index 00000000..8d796354
--- /dev/null
+++ b/src/lib9/dirmodefmt.c
@@ -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);
+}
diff --git a/src/lib9/dirread.c b/src/lib9/dirread.c
new file mode 100644
index 00000000..f4610f68
--- /dev/null
+++ b/src/lib9/dirread.c
@@ -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;
+}
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
index fb9cd0ac..253a9056 100644
--- a/src/lib9/dirstat.c
+++ b/src/lib9/dirstat.c
@@ -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;
-}
diff --git a/src/lib9/dirwstat.c b/src/lib9/dirwstat.c
new file mode 100644
index 00000000..573dd376
--- /dev/null
+++ b/src/lib9/dirwstat.c
@@ -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);
+}
diff --git a/src/lib9/dup.c b/src/lib9/dup.c
new file mode 100644
index 00000000..feec1b77
--- /dev/null
+++ b/src/lib9/dup.c
@@ -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);
+}
diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
index 504ec6ec..0c6ab315 100644
--- a/src/lib9/errstr.c
+++ b/src/lib9/errstr.c
@@ -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;
+}
+
+
diff --git a/src/lib9/exec.c b/src/lib9/exec.c
new file mode 100644
index 00000000..ffe81343
--- /dev/null
+++ b/src/lib9/exec.c
@@ -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);
+}
diff --git a/src/lib9/exits.c b/src/lib9/exits.c
index a449f68e..f4206e9a 100644
--- a/src/lib9/exits.c
+++ b/src/lib9/exits.c
@@ -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);
+}
diff --git a/src/lib9/ffork-Darwin.c b/src/lib9/ffork-Darwin.c
index 189ac94f..5e677f72 100644
--- a/src/lib9/ffork-Darwin.c
+++ b/src/lib9/ffork-Darwin.c
@@ -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"
diff --git a/src/lib9/ffork-SunOS.c b/src/lib9/ffork-SunOS.c
new file mode 100644
index 00000000..5e677f72
--- /dev/null
+++ b/src/lib9/ffork-SunOS.c
@@ -0,0 +1 @@
+#include "ffork-pthread.c"
diff --git a/src/lib9/ffork-pthread.c b/src/lib9/ffork-pthread.c
new file mode 100644
index 00000000..189ac94f
--- /dev/null
+++ b/src/lib9/ffork-pthread.c
@@ -0,0 +1,26 @@
+#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();
+}
+
diff --git a/src/lib9/getcallerpc-sun4u.s b/src/lib9/getcallerpc-sun4u.s
new file mode 100644
index 00000000..f28e57f1
--- /dev/null
+++ b/src/lib9/getcallerpc-sun4u.s
@@ -0,0 +1,5 @@
+.text
+.globl getcallerpc
+getcallerpc:
+ retl
+ or %o7, %r0, %o0
diff --git a/src/lib9/getenv.c b/src/lib9/getenv.c
new file mode 100644
index 00000000..c6ff7160
--- /dev/null
+++ b/src/lib9/getenv.c
@@ -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);
+}
+
diff --git a/src/lib9/getuser.c b/src/lib9/getuser.c
new file mode 100644
index 00000000..b53a3892
--- /dev/null
+++ b/src/lib9/getuser.c
@@ -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;
+}
diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
new file mode 100644
index 00000000..d6f7a131
--- /dev/null
+++ b/src/lib9/getwd.c
@@ -0,0 +1,10 @@
+#include <u.h>
+#include <libc.h>
+
+#undef getwd
+
+char*
+p9getwd(char *s, int ns)
+{
+ return getcwd(s, ns);
+}
diff --git a/src/lib9/jmp-FreeBSD.s b/src/lib9/jmp-FreeBSD.s
new file mode 100644
index 00000000..6e52b686
--- /dev/null
+++ b/src/lib9/jmp-FreeBSD.s
@@ -0,0 +1,3 @@
+.globl sigsetjmp, p9setjmp
+p9setjmp:
+ jmp sigsetjmp
diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
new file mode 100644
index 00000000..6f928bab
--- /dev/null
+++ b/src/lib9/jmp.c
@@ -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);
+}
+
diff --git a/src/lib9/main.c b/src/lib9/main.c
new file mode 100644
index 00000000..4a429054
--- /dev/null
+++ b/src/lib9/main.c
@@ -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;
+}
diff --git a/src/lib9/mkfile b/src/lib9/mkfile
new file mode 100644
index 00000000..9f5971ab
--- /dev/null
+++ b/src/lib9/mkfile
@@ -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
diff --git a/src/lib9/needsrcquote.c b/src/lib9/needsrcquote.c
new file mode 100644
index 00000000..f4cf460c
--- /dev/null
+++ b/src/lib9/needsrcquote.c
@@ -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;
+}
diff --git a/src/lib9/netmkaddr.c b/src/lib9/netmkaddr.c
new file mode 100644
index 00000000..fd53f468
--- /dev/null
+++ b/src/lib9/netmkaddr.c
@@ -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;
+}
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
new file mode 100644
index 00000000..095a3f54
--- /dev/null
+++ b/src/lib9/notify.c
@@ -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;
+}
diff --git a/src/lib9/nulldir.c b/src/lib9/nulldir.c
new file mode 100644
index 00000000..612725d8
--- /dev/null
+++ b/src/lib9/nulldir.c
@@ -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 = "";
+}
diff --git a/src/lib9/postnote.c b/src/lib9/postnote.c
new file mode 100644
index 00000000..9124bd5c
--- /dev/null
+++ b/src/lib9/postnote.c
@@ -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);
+ }
+}
+
+
diff --git a/src/lib9/priv.c b/src/lib9/priv.c
new file mode 100644
index 00000000..651c48c1
--- /dev/null
+++ b/src/lib9/priv.c
@@ -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];
+}
+
diff --git a/src/lib9/quote.c b/src/lib9/quote.c
new file mode 100644
index 00000000..4467377a
--- /dev/null
+++ b/src/lib9/quote.c
@@ -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;
+}
diff --git a/src/lib9/rendez-SunOS.c b/src/lib9/rendez-SunOS.c
new file mode 100644
index 00000000..eabb9a75
--- /dev/null
+++ b/src/lib9/rendez-SunOS.c
@@ -0,0 +1 @@
+#include "rendez-pthread.c"
diff --git a/src/lib9/rendez-pthread.c b/src/lib9/rendez-pthread.c
index 9b5d4342..b4b95f21 100644
--- a/src/lib9/rendez-pthread.c
+++ b/src/lib9/rendez-pthread.c
@@ -33,6 +33,7 @@
*/
#include <pthread.h>
+#include <signal.h>
#include <lib9.h>
enum
diff --git a/src/lib9/rendez.c b/src/lib9/rendez.c
new file mode 100644
index 00000000..cf23a4e5
--- /dev/null
+++ b/src/lib9/rendez.c
@@ -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;
+}
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
new file mode 100644
index 00000000..e248cd78
--- /dev/null
+++ b/src/lib9/rfork.c
@@ -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;
+}
diff --git a/src/lib9/seek.c b/src/lib9/seek.c
new file mode 100644
index 00000000..b626355f
--- /dev/null
+++ b/src/lib9/seek.c
@@ -0,0 +1,8 @@
+#include <u.h>
+#include <libc.h>
+
+vlong
+seek(int fd, vlong offset, int whence)
+{
+ return lseek(fd, offset, whence);
+}
diff --git a/src/lib9/sleep.c b/src/lib9/sleep.c
new file mode 100644
index 00000000..9cafdcf6
--- /dev/null
+++ b/src/lib9/sleep.c
@@ -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;
+}
diff --git a/src/lib9/stat2dir.c b/src/lib9/stat2dir.c
new file mode 100644
index 00000000..51f5bf28
--- /dev/null
+++ b/src/lib9/stat2dir.c
@@ -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;
+
+
+}
diff --git a/src/lib9/tas-sun4u.s b/src/lib9/tas-sun4u.s
new file mode 100644
index 00000000..b960a26a
--- /dev/null
+++ b/src/lib9/tas-sun4u.s
@@ -0,0 +1,4 @@
+.globl _tas
+_tas:
+ retl
+ ldstub [%o0], %o0
diff --git a/src/lib9/time.c b/src/lib9/time.c
new file mode 100644
index 00000000..169a82f5
--- /dev/null
+++ b/src/lib9/time.c
@@ -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;
+}
+
diff --git a/src/lib9/udp.c b/src/lib9/udp.c
new file mode 100644
index 00000000..a1164723
--- /dev/null
+++ b/src/lib9/udp.c
@@ -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);
+}
+
diff --git a/src/lib9/wait.c b/src/lib9/wait.c
index 14af7156..6dc137b1 100644
--- a/src/lib9/wait.c
+++ b/src/lib9/wait.c
@@ -1,4 +1,5 @@
-#include <lib9.h>
+#include <u.h>
+#include <libc.h>
Waitmsg*
wait(void)
diff --git a/src/lib9/waitpid.c b/src/lib9/waitpid.c
new file mode 100644
index 00000000..3df8ef89
--- /dev/null
+++ b/src/lib9/waitpid.c
@@ -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]);
+}
+