diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/ape/lib/ap/plan9 |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/ape/lib/ap/plan9')
105 files changed, 7690 insertions, 0 deletions
diff --git a/sys/src/ape/lib/ap/plan9/9errstr.c b/sys/src/ape/lib/ap/plan9/9errstr.c new file mode 100755 index 000000000..31226c18b --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/9errstr.c @@ -0,0 +1,4 @@ +#include "sys9.h" + +int +_ERRSTR(
\ No newline at end of file diff --git a/sys/src/ape/lib/ap/plan9/9iounit.c b/sys/src/ape/lib/ap/plan9/9iounit.c new file mode 100755 index 000000000..7117a9fe0 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/9iounit.c @@ -0,0 +1,65 @@ +#include "lib.h" +#include <string.h> +#include <stdlib.h> +#include <fmt.h> +#include "sys9.h" +#include "dir.h" + +/* + * Format: + 3 r M 4 (0000000000457def 11 00) 8192 512 /rc/lib/rcmain + */ + +static int +getfields(char *str, char **args, int max, int mflag) +{ + char r; + int nr, intok, narg; + + if(max <= 0) + return 0; + + narg = 0; + args[narg] = str; + if(!mflag) + narg++; + intok = 0; + for(;;) { + r = *str++; + if(r == 0) + break; + if(r == ' ' || r == '\t'){ + if(narg >= max) + break; + *str = 0; + intok = 0; + args[narg] = str + nr; + if(!mflag) + narg++; + } else { + if(!intok && mflag) + narg++; + intok = 1; + } + } + return narg; +} +int +_IOUNIT(int fd) +{ + int i, cfd; + char buf[128], *args[10]; + + snprint(buf, sizeof buf, "#d/%dctl", fd); + cfd = _OPEN(buf, OREAD); + if(cfd < 0) + return 0; + i = _READ(cfd, buf, sizeof buf-1); + _CLOSE(cfd); + if(i <= 0) + return 0; + buf[i] = '\0'; + if(getfields(buf, args, 10, 1) != 10) + return 0; + return atoi(args[7]); +} diff --git a/sys/src/ape/lib/ap/plan9/9mallocz.c b/sys/src/ape/lib/ap/plan9/9mallocz.c new file mode 100755 index 000000000..de5edb266 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/9mallocz.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <string.h> + +void* +_MALLOCZ(int n, int clr) +{ + void *v; + + v = malloc(n); + if(v && clr) + memset(v, 0, n); + return v; +} + diff --git a/sys/src/ape/lib/ap/plan9/9read.c b/sys/src/ape/lib/ap/plan9/9read.c new file mode 100755 index 000000000..ce38b3908 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/9read.c @@ -0,0 +1,11 @@ +#include "lib.h" +#include <string.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +long +_READ(int fd, void *buf, long n) +{ + return _PREAD(fd, buf, n, -1LL); +} diff --git a/sys/src/ape/lib/ap/plan9/9readn.c b/sys/src/ape/lib/ap/plan9/9readn.c new file mode 100755 index 000000000..8a0f5615c --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/9readn.c @@ -0,0 +1,21 @@ +#include "sys9.h" + +long +_READN(int f, void *av, long n) +{ + char *a; + long m, t; + + a = av; + t = 0; + while(t < n){ + m = _READ(f, a+t, n-t); + if(m <= 0){ + if(t == 0) + return m; + break; + } + t += m; + } + return t; +} diff --git a/sys/src/ape/lib/ap/plan9/9wait.c b/sys/src/ape/lib/ap/plan9/9wait.c new file mode 100755 index 000000000..71771df0b --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/9wait.c @@ -0,0 +1,93 @@ +#include "lib.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +static char qsep[] = " \t\r\n"; + +static char* +qtoken(char *s) +{ + int quoting; + char *t; + + quoting = 0; + t = s; /* s is output string, t is input string */ + while(*t!='\0' && (quoting || strchr(qsep, *t)==nil)){ + 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(*s != '\0'){ + *s = '\0'; + if(t == s) + t++; + } + return t; +} + +static int +tokenize(char *s, char **args, int maxargs) +{ + int nargs; + + for(nargs=0; nargs<maxargs; nargs++){ + while(*s!='\0' && strchr(qsep, *s)!=nil) + s++; + if(*s == '\0') + break; + args[nargs] = s; + s = qtoken(s); + } + + return nargs; +} + +Waitmsg* +_WAIT(void) +{ + int n, l; + char buf[512], *fld[5]; + Waitmsg *w; + + n = _AWAIT(buf, sizeof buf-1); + if(n < 0) + return nil; + buf[n] = '\0'; + if(tokenize(buf, fld, 5) != 5){ + strcpy(buf, "couldn't parse wait message"); + _ERRSTR(buf, sizeof buf); + return nil; + } + l = strlen(fld[4])+1; + w = malloc(sizeof(Waitmsg)+l); + if(w == nil) + return nil; + w->pid = atoi(fld[0]); + w->time[0] = atoi(fld[1]); + w->time[1] = atoi(fld[2]); + w->time[2] = atoi(fld[3]); + w->msg = (char*)&w[1]; + memmove(w->msg, fld[4], l); + return w; +} + diff --git a/sys/src/ape/lib/ap/plan9/9write.c b/sys/src/ape/lib/ap/plan9/9write.c new file mode 100755 index 000000000..e87a45ade --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/9write.c @@ -0,0 +1,11 @@ +#include "lib.h" +#include <string.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +long +_WRITE(int fd, void *buf, long n) +{ + return _PWRITE(fd, buf, n, -1LL); +} diff --git a/sys/src/ape/lib/ap/plan9/_buf.c b/sys/src/ape/lib/ap/plan9/_buf.c new file mode 100755 index 000000000..21fe282bb --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_buf.c @@ -0,0 +1,472 @@ +#define _BSDTIME_EXTENSION +#define _LOCK_EXTENSION +#include "lib.h" +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdio.h> +#include <lock.h> +#include <sys/time.h> +#include <sys/select.h> +#include <unistd.h> +#include "sys9.h" + +typedef struct Muxseg { + Lock lock; /* for mutual exclusion access to buffer variables */ + int curfds; /* number of fds currently buffered */ + int selwait; /* true if selecting process is waiting */ + int waittime; /* time for timer process to wait */ + fd_set rwant; /* fd's that select wants to read */ + fd_set ewant; /* fd's that select wants to know eof info on */ + Muxbuf bufs[INITBUFS]; /* can grow, via segbrk() */ +} Muxseg; + +#define MUXADDR ((void*)0x6000000) +static Muxseg *mux = 0; /* shared memory segment */ + +/* _muxsid and _killmuxsid are known in libbsd's listen.c */ +int _muxsid = -1; /* group id of copy processes */ +static int _mainpid = -1; +static int timerpid = -1; /* pid of a timer process */ + +void _killmuxsid(void); +static void _copyproc(int, Muxbuf*); +static void _timerproc(void); +static void _resettimer(void); + +static int copynotehandler(void *, char *); + +/* assume FD_SETSIZE is 96 */ +#define FD_ANYSET(p) ((p)->fds_bits[0] || (p)->fds_bits[1] || (p)->fds_bits[2]) + +/* + * Start making fd read-buffered: make the shared segment, if necessary, + * allocate a slot (index into mux->bufs), and fork a child to read the fd + * and write into the slot-indexed buffer. + * Return -1 if we can't do it. + */ +int +_startbuf(int fd) +{ + long i, n, slot; + int pid, sid; + Fdinfo *f; + Muxbuf *b; + + if(mux == 0){ + _RFORK(RFREND); + mux = (Muxseg*)_SEGATTACH(0, "shared", MUXADDR, sizeof(Muxseg)); + if((long)mux == -1){ + _syserrno(); + return -1; + } + /* segattach has returned zeroed memory */ + atexit(_killmuxsid); + } + + if(fd == -1) + return 0; + + lock(&mux->lock); + slot = mux->curfds++; + if(mux->curfds > INITBUFS) { + if(_SEGBRK(mux, mux->bufs+mux->curfds) < 0){ + _syserrno(); + unlock(&mux->lock); + return -1; + } + } + + f = &_fdinfo[fd]; + b = &mux->bufs[slot]; + b->n = 0; + b->putnext = b->data; + b->getnext = b->data; + b->eof = 0; + b->fd = fd; + if(_mainpid == -1) + _mainpid = getpid(); + if((pid = _RFORK(RFFDG|RFPROC|RFNOWAIT)) == 0){ + /* copy process ... */ + if(_muxsid == -1) { + _RFORK(RFNOTEG); + _muxsid = getpgrp(); + } else + setpgid(getpid(), _muxsid); + _NOTIFY(copynotehandler); + for(i=0; i<OPEN_MAX; i++) + if(i!=fd && (_fdinfo[i].flags&FD_ISOPEN)) + _CLOSE(i); + _RENDEZVOUS(0, _muxsid); + _copyproc(fd, b); + } + + /* parent process continues ... */ + b->copypid = pid; + f->buf = b; + f->flags |= FD_BUFFERED; + unlock(&mux->lock); + _muxsid = _RENDEZVOUS(0, 0); + /* leave fd open in parent so system doesn't reuse it */ + return 0; +} + +/* + * The given buffered fd is being closed. + * Set the fd field in the shared buffer to -1 to tell copyproc + * to exit, and kill the copyproc. + */ +void +_closebuf(int fd) +{ + Muxbuf *b; + + b = _fdinfo[fd].buf; + if(!b) + return; + lock(&mux->lock); + b->fd = -1; + unlock(&mux->lock); + kill(b->copypid, SIGKILL); +} + +/* child copy procs execute this until eof */ +static void +_copyproc(int fd, Muxbuf *b) +{ + unsigned char *e; + int n; + int nzeros; + + e = &b->data[PERFDMAX]; + for(;;) { + /* make sure there's room */ + lock(&mux->lock); + if(e - b->putnext < READMAX) { + if(b->getnext == b->putnext) { + b->getnext = b->putnext = b->data; + unlock(&mux->lock); + } else { + /* sleep until there's room */ + b->roomwait = 1; + unlock(&mux->lock); + _RENDEZVOUS((unsigned long)&b->roomwait, 0); + } + } else + unlock(&mux->lock); + /* + * A Zero-length _READ might mean a zero-length write + * happened, or it might mean eof; try several times to + * disambiguate (posix read() discards 0-length messages) + */ + nzeros = 0; + do { + n = _READ(fd, b->putnext, READMAX); + if(b->fd == -1) { + _exit(0); /* we've been closed */ + } + } while(n == 0 && ++nzeros < 3); + lock(&mux->lock); + if(n <= 0) { + b->eof = 1; + if(mux->selwait && FD_ISSET(fd, &mux->ewant)) { + mux->selwait = 0; + unlock(&mux->lock); + _RENDEZVOUS((unsigned long)&mux->selwait, fd); + } else if(b->datawait) { + b->datawait = 0; + unlock(&mux->lock); + _RENDEZVOUS((unsigned long)&b->datawait, 0); + } else if(mux->selwait && FD_ISSET(fd, &mux->rwant)) { + mux->selwait = 0; + unlock(&mux->lock); + _RENDEZVOUS((unsigned long)&mux->selwait, fd); + } else + unlock(&mux->lock); + _exit(0); + } else { + b->putnext += n; + b->n += n; + if(b->n > 0) { + /* parent process cannot be both in datawait and selwait */ + if(b->datawait) { + b->datawait = 0; + unlock(&mux->lock); + /* wake up _bufreading process */ + _RENDEZVOUS((unsigned long)&b->datawait, 0); + } else if(mux->selwait && FD_ISSET(fd, &mux->rwant)) { + mux->selwait = 0; + unlock(&mux->lock); + /* wake up selecting process */ + _RENDEZVOUS((unsigned long)&mux->selwait, fd); + } else + unlock(&mux->lock); + } else + unlock(&mux->lock); + } + } +} + +/* like read(), for a buffered fd; extra arg noblock says don't wait for data if true */ +int +_readbuf(int fd, void *addr, int nwant, int noblock) +{ + Muxbuf *b; + int ngot; + + b = _fdinfo[fd].buf; + if(b->eof && b->n == 0) { +goteof: + return 0; + } + if(b->n == 0 && noblock) { + errno = EAGAIN; + return -1; + } + /* make sure there's data */ + lock(&mux->lock); + ngot = b->putnext - b->getnext; + if(ngot == 0) { + /* maybe EOF just happened */ + if(b->eof) { + unlock(&mux->lock); + goto goteof; + } + /* sleep until there's data */ + b->datawait = 1; + unlock(&mux->lock); + _RENDEZVOUS((unsigned long)&b->datawait, 0); + lock(&mux->lock); + ngot = b->putnext - b->getnext; + } + if(ngot == 0) { + unlock(&mux->lock); + goto goteof; + } + if(ngot > nwant) + ngot = nwant; + memcpy(addr, b->getnext, ngot); + b->getnext += ngot; + b->n -= ngot; + if(b->getnext == b->putnext && b->roomwait) { + b->getnext = b->putnext = b->data; + b->roomwait = 0; + unlock(&mux->lock); + /* wake up copy process */ + _RENDEZVOUS((unsigned long)&b->roomwait, 0); + } else + unlock(&mux->lock); + return ngot; +} + +int +select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) +{ + int n, i, tmp, t, slots, fd, err; + Fdinfo *f; + Muxbuf *b; + + if(timeout) + t = timeout->tv_sec*1000 + (timeout->tv_usec+999)/1000; + else + t = -1; + if(!((rfds && FD_ANYSET(rfds)) || (wfds && FD_ANYSET(wfds)) + || (efds && FD_ANYSET(efds)))) { + /* no requested fds */ + if(t > 0) + _SLEEP(t); + return 0; + } + + _startbuf(-1); + + /* make sure all requested rfds and efds are buffered */ + if(nfds >= OPEN_MAX) + nfds = OPEN_MAX; + for(i = 0; i < nfds; i++) + if((rfds && FD_ISSET(i, rfds)) || (efds && FD_ISSET(i, efds))){ + f = &_fdinfo[i]; + if(!(f->flags&FD_BUFFERED)) + if(_startbuf(i) != 0) { + return -1; + } + b = f->buf; + if(rfds && FD_ISSET(i,rfds) && b->eof && b->n == 0) + if(efds == 0 || !FD_ISSET(i,efds)) { + errno = EBADF; /* how X tells a client is gone */ + return -1; + } + } + + /* check wfds; for now, we'll say they are all ready */ + n = 0; + if(wfds && FD_ANYSET(wfds)){ + for(i = 0; i<nfds; i++) + if(FD_ISSET(i, wfds)) { + n++; + } + } + + lock(&mux->lock); + + slots = mux->curfds; + FD_ZERO(&mux->rwant); + FD_ZERO(&mux->ewant); + + for(i = 0; i<slots; i++) { + b = &mux->bufs[i]; + fd = b->fd; + if(fd == -1) + continue; + err = 0; + if(efds && FD_ISSET(fd, efds)) { + if(b->eof && b->n == 0){ + err = 1; + n++; + }else{ + FD_CLR(fd, efds); + FD_SET(fd, &mux->ewant); + } + } + if(rfds && FD_ISSET(fd, rfds)) { + if(!err && (b->n > 0 || b->eof)) + n++; + else{ + FD_CLR(fd, rfds); + FD_SET(fd, &mux->rwant); + } + } + } + if(n || !(FD_ANYSET(&mux->rwant) || FD_ANYSET(&mux->ewant)) || t == 0) { + FD_ZERO(&mux->rwant); + FD_ZERO(&mux->ewant); + unlock(&mux->lock); + return n; + } + + if(timeout) { + mux->waittime = t; + if(timerpid == -1) + _timerproc(); + else + _resettimer(); + } + mux->selwait = 1; + unlock(&mux->lock); + fd = _RENDEZVOUS((unsigned long)&mux->selwait, 0); + if(fd >= 0) { + b = _fdinfo[fd].buf; + if(FD_ISSET(fd, &mux->rwant)) { + FD_SET(fd, rfds); + n = 1; + } else if(FD_ISSET(fd, &mux->ewant) && b->eof && b->n == 0) { + FD_SET(fd, efds); + n = 1; + } + } + FD_ZERO(&mux->rwant); + FD_ZERO(&mux->ewant); + return n; +} + +static int timerreset; +static int timerpid; + +static void +alarmed(int v) +{ + timerreset = 1; +} + +/* a little over an hour */ +#define LONGWAIT 4000001 + +static void +_killtimerproc(void) +{ + if(timerpid > 0) + kill(timerpid, SIGKILL); +} + +static void +_timerproc(void) +{ + int i; + + if((timerpid = _RFORK(RFFDG|RFPROC|RFNOWAIT)) == 0){ + /* timer process */ + setpgid(getpid(), _muxsid); + signal(SIGALRM, alarmed); + for(i=0; i<OPEN_MAX; i++) + _CLOSE(i); + _RENDEZVOUS(1, 0); + for(;;) { + _SLEEP(mux->waittime); + if(timerreset) { + timerreset = 0; + } else { + lock(&mux->lock); + if(mux->selwait && mux->waittime != LONGWAIT) { + mux->selwait = 0; + mux->waittime = LONGWAIT; + unlock(&mux->lock); + _RENDEZVOUS((unsigned long)&mux->selwait, -2); + } else { + mux->waittime = LONGWAIT; + unlock(&mux->lock); + } + } + } + } + atexit(_killtimerproc); + /* parent process continues */ + _RENDEZVOUS(1, 0); +} + +static void +_resettimer(void) +{ + kill(timerpid, SIGALRM); +} + +void +_killmuxsid(void) +{ + if(_muxsid != -1 && (_mainpid == getpid() || _mainpid == -1)) + kill(-_muxsid,SIGTERM); +} + +/* call this on fork(), because reading a BUFFERED fd won't work in child */ +void +_detachbuf(void) +{ + int i; + Fdinfo *f; + + if(mux == 0) + return; + _SEGDETACH(mux); + for(i = 0; i < OPEN_MAX; i++){ + f = &_fdinfo[i]; + if(f->flags&FD_BUFFERED) + f->flags = (f->flags&~FD_BUFFERED) | FD_BUFFEREDX; + /* mark 'poisoned' */ + } + mux = 0; + _muxsid = -1; + _mainpid = -1; + timerpid = -1; +} + +static int +copynotehandler(void *u, char *msg) +{ + int i; + void(*f)(int); + + if(_finishing) + _finish(0, 0); + _NOTED(1); +} diff --git a/sys/src/ape/lib/ap/plan9/_dirconv.c b/sys/src/ape/lib/ap/plan9/_dirconv.c new file mode 100755 index 000000000..3889c2ee2 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_dirconv.c @@ -0,0 +1,65 @@ +#include "lib.h" +#include <string.h> +#include "sys9.h" +#include "dir.h" + +#define CHAR(x) *p++ = f->x +#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 +#define LONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24; p += 4 +#define VLONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24;\ + p[4] = 0; p[5] = 0; p[6] = 0; p[7] = 0; p += 8 +#define STRING(x,n) memcpy(p, f->x, n); p += n + +int +convD2M(Dir *f, char *ap) +{ + unsigned char *p; + + p = (unsigned char*)ap; + STRING(name, sizeof(f->name)); + STRING(uid, sizeof(f->uid)); + STRING(gid, sizeof(f->gid)); + LONG(qid.path); + LONG(qid.vers); + LONG(mode); + LONG(atime); + LONG(mtime); + VLONG(length); + SHORT(type); + SHORT(dev); + return p - (unsigned char*)ap; +} + +#undef CHAR +#undef SHORT +#undef LONG +#undef VLONG +#undef STRING + +#define CHAR(x) f->x = *p++ +#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 +#define LONG(x) f->x = (p[0] | (p[1]<<8) |\ + (p[2]<<16) | (p[3]<<24)); p += 4 +#define VLONG(x) f->x = (p[0] | (p[1]<<8) |\ + (p[2]<<16) | (p[3]<<24)); p += 8 +#define STRING(x,n) memcpy(f->x, p, n); p += n + +int +convM2D(char *ap, Dir *f) +{ + unsigned char *p; + + p = (unsigned char*)ap; + STRING(name, sizeof(f->name)); + STRING(uid, sizeof(f->uid)); + STRING(gid, sizeof(f->gid)); + LONG(qid.path); + LONG(qid.vers); + LONG(mode); + LONG(atime); + LONG(mtime); + VLONG(length); + SHORT(type); + SHORT(dev); + return p - (unsigned char*)ap; +} diff --git a/sys/src/ape/lib/ap/plan9/_envsetup.c b/sys/src/ape/lib/ap/plan9/_envsetup.c new file mode 100755 index 000000000..55cf33b85 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_envsetup.c @@ -0,0 +1,123 @@ +#include "lib.h" +#include <stdlib.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include "sys9.h" +#include "dir.h" + +/* + * Called before main to initialize environ. + * Some plan9 environment variables + * have 0 bytes in them (notably $path); + * we change them to 1's (and execve changes back) + * + * Also, register the note handler. + */ + +char **environ; +int errno; +unsigned long _clock; +static char name[NAME_MAX+5] = "#e"; +static void fdsetup(char *, char *); +static void sigsetup(char *, char *); + +enum { + Envhunk=7000, +}; + +void +_envsetup(void) +{ + int dfd; + struct dirent *de; + int n, nd, m, i, j, f; + int psize, cnt; + int nohandle; + int fdinited; + char *ps, *p; + char **pp; + Dir *d9, *d9a; + + nohandle = 0; + fdinited = 0; + cnt = 0; + dfd = _OPEN(name, 0); + if(dfd < 0) { + static char **emptyenvp = 0; + environ = emptyenvp; + return; + } + name[2] = '/'; + ps = p = malloc(Envhunk); + psize = Envhunk; + nd = _dirreadall(dfd, &d9a); + _CLOSE(dfd); + for(j=0; j<nd; j++){ + d9 = &d9a[j]; + n = strlen(d9->name); + m = d9->length; + i = p - ps; + if(i+n+1+m+1 > psize) { + psize += (n+m+2 < Envhunk)? Envhunk : n+m+2; + ps = realloc(ps, psize); + p = ps + i; + } + memcpy(p, d9->name, n); + p[n] = '='; + strcpy(name+3, d9->name); + f = _OPEN(name, O_RDONLY); + if(f < 0 || _READ(f, p+n+1, m) != m) + m = 0; + _CLOSE(f); + if(p[n+m] == 0) + m--; + for(i=0; i<m; i++) + if(p[n+1+i] == 0) + p[n+1+i] = 1; + p[n+1+m] = 0; + if(strcmp(d9->name, "_fdinfo") == 0) { + _fdinit(p+n+1, p+n+1+m); + fdinited = 1; + } else if(strcmp(d9->name, "_sighdlr") == 0) + sigsetup(p+n+1, p+n+1+m); + else if(strcmp(d9->name, "nohandle") == 0) + nohandle = 1; + p += n+m+2; + cnt++; + } + free(d9a); + if(!fdinited) + _fdinit(0, 0); + environ = pp = malloc((1+cnt)*sizeof(char *)); + p = ps; + for(i = 0; i < cnt; i++) { + *pp++ = p; + p = memchr(p, 0, ps+psize-p); + if (!p) + break; + p++; + } + *pp = 0; + if(!nohandle) + _NOTIFY(_notehandler); +} + +static void +sigsetup(char *s, char *se) +{ + int i, sig; + char *e; + + while(s < se){ + sig = strtoul(s, &e, 10); + if(s == e) + break; + s = e; + if(sig <= MAXSIG) + _sighdlr[sig] = SIG_IGN; + } +} diff --git a/sys/src/ape/lib/ap/plan9/_errno.c b/sys/src/ape/lib/ap/plan9/_errno.c new file mode 100755 index 000000000..8e5caad7d --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_errno.c @@ -0,0 +1,124 @@ +#include "lib.h" +#include "sys9.h" +#include <string.h> +#include <errno.h> + +/* make this global, so programs can look at it if errno is unilluminating */ + +/* see also: ../stdio/strerror.c, with errno-> string mapping */ + +char _plan9err[ERRMAX]; + +static struct errmap { + int errno; + char *ename; +} map[] = { + /* from /sys/src/9/port/errstr.h */ + {EINVAL, "inconsistent mount"}, + {EINVAL, "not mounted"}, + {EINVAL, "not in union"}, + {EIO, "mount rpc error"}, + {EIO, "mounted device shut down"}, + {EPERM, "mounted directory forbids creation"}, + {ENOENT, "does not exist"}, + {ENXIO, "unknown device in # filename"}, + {ENOTDIR, "not a directory"}, + {EISDIR, "file is a directory"}, + {EINVAL, "bad character in file name"}, + {EINVAL, "file name syntax"}, + {EPERM, "permission denied"}, + {EPERM, "inappropriate use of fd"}, + {EINVAL, "bad arg in system call"}, + {EBUSY, "device or object already in use"}, + {EIO, "i/o error"}, + {EIO, "read or write too large"}, + {EIO, "read or write too small"}, + {EADDRINUSE, "network port not available"}, + {ESHUTDOWN, "write to hungup stream"}, + {ESHUTDOWN, "i/o on hungup channel"}, + {EINVAL, "bad process or channel control request"}, + {EBUSY, "no free devices"}, + {ESRCH, "process exited"}, + {ECHILD, "no living children"}, + {EIO, "i/o error in demand load"}, + {ENOMEM, "virtual memory allocation failed"}, + {EBADF, "fd out of range or not open"}, + {EMFILE, "no free file descriptors"}, + {ESPIPE, "seek on a stream"}, + {ENOEXEC, "exec header invalid"}, + {ETIMEDOUT, "connection timed out"}, + {ECONNREFUSED, "connection refused"}, + {ECONNREFUSED, "connection in use"}, + {EINTR, "interrupted"}, + {ENOMEM, "kernel allocate failed"}, + {EINVAL, "segments overlap"}, + {EIO, "i/o count too small"}, + {EGREG, "ken has left the building"}, + {EINVAL, "bad attach specifier"}, + + /* from exhausted() calls in kernel */ + {ENFILE, "no free file descriptors"}, + {EBUSY, "no free mount devices"}, + {EBUSY, "no free mount rpc buffer"}, + {EBUSY, "no free segments"}, + {ENOMEM, "no free memory"}, + {ENOBUFS, "no free Blocks"}, + {EBUSY, "no free routes"}, + + /* from ken */ + {EINVAL, "attach -- bad specifier"}, + {EBADF, "unknown fid"}, + {EINVAL, "bad character in directory name"}, + {EBADF, "read/write -- on non open fid"}, + {EIO, "read/write -- count too big"}, + {EIO, "phase error -- directory entry not allocated"}, + {EIO, "phase error -- qid does not match"}, + {EACCES, "access permission denied"}, + {ENOENT, "directory entry not found"}, + {EINVAL, "open/create -- unknown mode"}, + {ENOTDIR, "walk -- in a non-directory"}, + {ENOTDIR, "create -- in a non-directory"}, + {EIO, "phase error -- cannot happen"}, + {EEXIST, "create -- file exists"}, + {EINVAL, "create -- . and .. illegal names"}, + {ENOTEMPTY, "directory not empty"}, + {EINVAL, "attach -- privileged user"}, + {EPERM, "wstat -- not owner"}, + {EPERM, "wstat -- not in group"}, + {EINVAL, "create/wstat -- bad character in file name"}, + {EBUSY, "walk -- too many (system wide)"}, + {EROFS, "file system read only"}, + {ENOSPC, "file system full"}, + {EINVAL, "read/write -- offset negative"}, + {EBUSY, "open/create -- file is locked"}, + {EBUSY, "close/read/write -- lock is broken"}, + + /* from sockets */ + {ENOTSOCK, "not a socket"}, + {EPROTONOSUPPORT, "protocol not supported"}, + {ECONNREFUSED, "connection refused"}, + {EAFNOSUPPORT, "address family not supported"}, + {ENOBUFS, "insufficient buffer space"}, + {EOPNOTSUPP, "operation not supported"}, + {EADDRINUSE, "address in use"}, + {EGREG, "unnamed error message"}, +}; + +#define NERRMAP (sizeof(map)/sizeof(struct errmap)) + +/* convert last system call error to an errno */ +void +_syserrno(void) +{ + int i; + + if(_ERRSTR(_plan9err, sizeof _plan9err) < 0) + errno = EINVAL; + else{ + for(i = 0; i < NERRMAP; i++) + if(strstr(_plan9err, map[i].ename) != 0) + break; + _ERRSTR(_plan9err, sizeof _plan9err); + errno = (i < NERRMAP)? map[i].errno : EINVAL; + } +} diff --git a/sys/src/ape/lib/ap/plan9/_exit.c b/sys/src/ape/lib/ap/plan9/_exit.c new file mode 100755 index 000000000..e3886ff18 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_exit.c @@ -0,0 +1,58 @@ +#include "lib.h" +#include "sys9.h" +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> + +int _finishing = 0; +int _sessleader = 0; + +static char exitstatus[ERRMAX]; + +void +_exit(int status) +{ + _finish(status, 0); +} + +void +_finish(int status, char *term) +{ + int i, nalive; + char *cp; + + if(_finishing) + _EXITS(exitstatus); + _finishing = 1; + if(status){ + cp = _ultoa(exitstatus, status & 0xFF); + *cp = 0; + }else if(term){ + strncpy(exitstatus, term, ERRMAX); + exitstatus[ERRMAX-1] = '\0'; + } + if(_sessleader) + kill(0, SIGTERM); + _EXITS(exitstatus); +} + +/* emulate: return p+sprintf(p, "%uld", v) */ +#define IDIGIT 15 +char * +_ultoa(char *p, unsigned long v) +{ + char s[IDIGIT]; + int n, i; + + s[IDIGIT-1] = 0; + for(i = IDIGIT-2; i; i--){ + n = v % 10; + s[i] = n + '0'; + v = v / 10; + if(v == 0) + break; + } + strcpy(p, s+i); + return p + (IDIGIT-1-i); +} diff --git a/sys/src/ape/lib/ap/plan9/_fcall.c b/sys/src/ape/lib/ap/plan9/_fcall.c new file mode 100755 index 000000000..394f4cc08 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_fcall.c @@ -0,0 +1,422 @@ +#include <string.h> +#include "sys9.h" +#include "lib.h" +#include "dir.h" +#include "fcall.h" + +typedef unsigned char uchar; + +#define CHAR(x) *p++ = f->x +#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 +#define LONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24; p += 4 +#define VLONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24;\ + p[4] = 0; p[5] = 0; p[6] = 0; p[7] = 0; p += 8 +#define STRING(x,n) memcpy(p, f->x, n); p += n + +int +convS2M(Fcall *f, char *ap) +{ + uchar *p; + + p = (uchar*)ap; + CHAR(type); + SHORT(tag); + switch(f->type) + { + default: + return 0; + + case Tosession: + case Tnop: + break; + + case Tsession: + STRING(chal, sizeof(f->chal)); + break; + + case Tflush: + SHORT(oldtag); + break; + + case Tattach: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + STRING(ticket, sizeof(f->ticket)); + STRING(auth, sizeof(f->auth)); + break; + + case Toattach: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + STRING(ticket, NAMELEN); + break; + + case Tauth: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(ticket, 8+NAMELEN); + break; + + case Tclone: + SHORT(fid); + SHORT(newfid); + break; + + case Twalk: + SHORT(fid); + STRING(name, sizeof(f->name)); + break; + + case Topen: + SHORT(fid); + CHAR(mode); + break; + + case Tcreate: + SHORT(fid); + STRING(name, sizeof(f->name)); + LONG(perm); + CHAR(mode); + break; + + case Tread: + SHORT(fid); + VLONG(offset); + SHORT(count); + break; + + case Twrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + p++; /* pad(1) */ + STRING(data, f->count); + break; + + case Tclunk: + SHORT(fid); + break; + + case Tremove: + SHORT(fid); + break; + + case Tstat: + SHORT(fid); + break; + + case Twstat: + SHORT(fid); + STRING(stat, sizeof(f->stat)); + break; + + case Tclwalk: + SHORT(fid); + SHORT(newfid); + STRING(name, sizeof(f->name)); + break; +/* + */ + case Rosession: + case Rnop: + break; + + case Rsession: + STRING(chal, sizeof(f->chal)); + STRING(authid, sizeof(f->authid)); + STRING(authdom, sizeof(f->authdom)); + break; + + case Rerror: + STRING(ename, sizeof(f->ename)); + break; + + case Rflush: + break; + + case Rattach: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + STRING(rauth, sizeof(f->rauth)); + break; + + case Roattach: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + break; + + case Rauth: + SHORT(fid); + STRING(ticket, 8+8+7+7); + break; + + case Rclone: + SHORT(fid); + break; + + case Rwalk: + case Rclwalk: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + break; + + case Ropen: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + break; + + case Rcreate: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + break; + + case Rread: + SHORT(fid); + SHORT(count); + p++; /* pad(1) */ + STRING(data, f->count); + break; + + case Rwrite: + SHORT(fid); + SHORT(count); + break; + + case Rclunk: + SHORT(fid); + break; + + case Rremove: + SHORT(fid); + break; + + case Rstat: + SHORT(fid); + STRING(stat, sizeof(f->stat)); + break; + + case Rwstat: + SHORT(fid); + break; + } + return p - (uchar*)ap; +} + +#undef CHAR +#undef SHORT +#undef LONG +#undef VLONG +#undef STRING + +#define CHAR(x) f->x = *p++ +#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 +#define LONG(x) f->x = (p[0] | (p[1]<<8) |\ + (p[2]<<16) | (p[3]<<24)); p += 4 +#define VLONG(x) f->x = (p[0] | (p[1]<<8) |\ + (p[2]<<16) | (p[3]<<24)); p += 8 +#define STRING(x,n) memcpy(f->x, p, n); p += n + +int +convM2S(char *ap, Fcall *f, int n) +{ + uchar *p; + + p = (uchar*)ap; + CHAR(type); + SHORT(tag); + switch(f->type) + { + default: + return 0; + + case Tnop: + case Tosession: + break; + + case Tsession: + STRING(chal, sizeof(f->chal)); + break; + + case Tflush: + SHORT(oldtag); + break; + + case Tattach: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + STRING(ticket, sizeof(f->ticket)); + STRING(auth, sizeof(f->auth)); + break; + + case Toattach: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + STRING(ticket, NAMELEN); + break; + + case Tauth: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(ticket, 8+NAMELEN); + break; + + case Tclone: + SHORT(fid); + SHORT(newfid); + break; + + case Twalk: + SHORT(fid); + STRING(name, sizeof(f->name)); + break; + + case Topen: + SHORT(fid); + CHAR(mode); + break; + + case Tcreate: + SHORT(fid); + STRING(name, sizeof(f->name)); + LONG(perm); + CHAR(mode); + break; + + case Tread: + SHORT(fid); + VLONG(offset); + SHORT(count); + break; + + case Twrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + p++; /* pad(1) */ + f->data = (char*)p; p += f->count; + break; + + case Tclunk: + SHORT(fid); + break; + + case Tremove: + SHORT(fid); + break; + + case Tstat: + SHORT(fid); + break; + + case Twstat: + SHORT(fid); + STRING(stat, sizeof(f->stat)); + break; + + case Tclwalk: + SHORT(fid); + SHORT(newfid); + STRING(name, sizeof(f->name)); + break; +/* + */ + case Rnop: + case Rosession: + break; + + case Rsession: + STRING(chal, sizeof(f->chal)); + STRING(authid, sizeof(f->authid)); + STRING(authdom, sizeof(f->authdom)); + break; + + case Rerror: + STRING(ename, sizeof(f->ename)); + break; + + case Rflush: + break; + + case Rattach: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + STRING(rauth, sizeof(f->rauth)); + break; + + case Roattach: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + break; + + case Rauth: + SHORT(fid); + STRING(ticket, 8+8+7+7); + break; + + case Rclone: + SHORT(fid); + break; + + case Rwalk: + case Rclwalk: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + break; + + case Ropen: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + break; + + case Rcreate: + SHORT(fid); + LONG(qid.path); + LONG(qid.vers); + break; + + case Rread: + SHORT(fid); + SHORT(count); + p++; /* pad(1) */ + f->data = (char*)p; p += f->count; + break; + + case Rwrite: + SHORT(fid); + SHORT(count); + break; + + case Rclunk: + SHORT(fid); + break; + + case Rremove: + SHORT(fid); + break; + + case Rstat: + SHORT(fid); + STRING(stat, sizeof(f->stat)); + break; + + case Rwstat: + SHORT(fid); + break; + } + if((uchar*)ap+n == p) + return n; + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/_fdinfo.c b/sys/src/ape/lib/ap/plan9/_fdinfo.c new file mode 100755 index 000000000..85bbeca95 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_fdinfo.c @@ -0,0 +1,169 @@ +#define _BSDTIME_EXTENSION +#include "lib.h" +#include <sys/stat.h> +#include <stdlib.h> +#include "sys9.h" +#include <string.h> + +extern int errno; +Fdinfo _fdinfo[OPEN_MAX]; + +/* + called from _envsetup, either with the value of the environment + variable _fdinfo (from s to se-1), or with s==0 if there was no _fdinfo +*/ +static void +defaultfdinit(void) +{ + int i; + Fdinfo *fi; + + for(i = 0; i <= 2; i++) { + fi = &_fdinfo[i]; + fi->flags = FD_ISOPEN; + fi->oflags = (i == 0)? O_RDONLY : O_WRONLY; + if(_isatty(i)) + fi->flags |= FD_ISTTY; + } +} + +static int +readprocfdinit(void) +{ + /* construct info from /proc/$pid/fd */ + char buf[8192]; + Fdinfo *fi; + int fd, pfd, pid, n, tot, m; + char *s, *nexts; + + memset(buf, 0, sizeof buf); + pfd = _OPEN("#c/pid", 0); + if(pfd < 0) + return -1; + if(_PREAD(pfd, buf, 100, 0) < 0){ + _CLOSE(pfd); + return -1; + } + _CLOSE(pfd); + pid = strtoul(buf, 0, 10); + strcpy(buf, "#p/"); + _ultoa(buf+3, pid); + strcat(buf, "/fd"); + pfd = _OPEN(buf, 0); + if(pfd < 0) + return -1; + memset(buf, 0, sizeof buf); + tot = 0; + for(;;){ + n = _PREAD(pfd, buf+tot, sizeof buf-tot, tot); + if(n <= 0) + break; + tot += n; + } + _CLOSE(pfd); + if(n < 0) + return -1; + buf[sizeof buf-1] = '\0'; + s = strchr(buf, '\n'); /* skip current directory */ + if(s == 0) + return -1; + s++; + m = 0; + for(; s && *s; s=nexts){ + nexts = strchr(s, '\n'); + if(nexts) + *nexts++ = '\0'; + errno = 0; + fd = strtoul(s, &s, 10); + if(errno != 0) + return -1; + if(fd >= OPEN_MAX) + continue; + if(fd == pfd) + continue; + fi = &_fdinfo[fd]; + fi->flags = FD_ISOPEN; + while(*s == ' ' || *s == '\t') + s++; + if(*s == 'r'){ + m |= 1; + s++; + } + if(*s == 'w'){ + m |= 2; + } + if(m==1) + fi->oflags = O_RDONLY; + else if(m==2) + fi->oflags = O_WRONLY; + else + fi->oflags = O_RDWR; + if(strlen(s) >= 9 && strcmp(s+strlen(s)-9, "/dev/cons") == 0) + fi->flags |= FD_ISTTY; + } + return 0; +} + +static void +sfdinit(int usedproc, char *s, char *se) +{ + int i; + Fdinfo *fi; + unsigned long fd, fl, ofl; + char *e; + struct stat sbuf; + + while(s < se){ + fd = strtoul(s, &e, 10); + if(s == e) + break; + s = e; + fl = strtoul(s, &e, 10); + if(s == e) + break; + s = e; + ofl = strtoul(s, &e, 10); + if(s == e) + break; + s = e; + if(fd < OPEN_MAX){ + fi = &_fdinfo[fd]; + if(usedproc && !(fi->flags&FD_ISOPEN)) + continue; /* should probably ignore all of $_fdinit */ + fi->flags = fl; + fi->oflags = ofl; + if(_isatty(fd)) + fi->flags |= FD_ISTTY; + } + } + +} + +void +_fdinit(char *s, char *se) +{ + int i, usedproc; + Fdinfo *fi; + struct stat sbuf; + + usedproc = 0; + if(readprocfdinit() == 0) + usedproc = 1; +else +_WRITE(2, "FAILED\n", 7); + if(s) + sfdinit(usedproc, s, se); + if(!s && !usedproc) + defaultfdinit(); + + for(i = 0; i < OPEN_MAX; i++) { + fi = &_fdinfo[i]; + if(fi->flags&FD_ISOPEN){ + if(fstat(i, &sbuf) >= 0) { + fi->uid = sbuf.st_uid; + fi->gid = sbuf.st_gid; + } + } + } +} + diff --git a/sys/src/ape/lib/ap/plan9/_getpw.c b/sys/src/ape/lib/ap/plan9/_getpw.c new file mode 100755 index 000000000..151d7f3c8 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_getpw.c @@ -0,0 +1,174 @@ +#include "lib.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "sys9.h" +#include "dir.h" + +/* + * Search /adm/users for line with second field == *pname (if + * not NULL), else with first field == *pnum. Return non-zero + * if found, and fill in *pnum, *pname, and *plist to fields + * 1, 2, and 4 + */ + +enum {NAMEMAX = 20, MEMOMAX = 40 }; + +static char *admusers = "/adm/users"; + +/* we hold a fixed-length memo list of past lookups, and use a move-to-front + strategy to organize the list +*/ +typedef struct Memo { + char name[NAMEMAX]; + int num; + char *glist; +} Memo; + +static Memo *memo[MEMOMAX]; +static int nmemo = 0; + +int +_getpw(int *pnum, char **pname, char **plist) +{ + Dir *d; + int f, n, i, j, matchnum, m, matched; + char *eline, *f1, *f2, *f3, *f4; + Memo *mem; + static char *au = NULL; + vlong length; + + if(!pname) + return 0; + if(au == NULL){ + d = _dirstat(admusers); + if(d == nil) + return 0; + length = d->length; + free(d); + if((au = (char *)malloc(length+2)) == NULL) + return 0; + f = open(admusers, O_RDONLY); + if(f < 0) + return 0; + n = read(f, au, length); + if(n < 0) + return 0; + au[n] = 0; + } + matchnum = (*pname == NULL); + matched = 0; + /* try using memo */ + for(i = 0; i<nmemo; i++) { + mem = memo[i]; + if(matchnum) + matched = (mem->num == *pnum); + else + matched = (strcmp(mem->name, *pname) == 0); + if(matched) { + break; + } + } + if(!matched) + for(f1 = au, eline = au; !matched && *eline; f1 = eline+1){ + eline = strchr(f1, '\n'); + if(!eline) + eline = strchr(f1, 0); + if(*f1 == '#' || *f1 == '\n') + continue; + n = eline-f1; + f2 = memchr(f1, ':', n); + if(!f2) + continue; + f2++; + f3 = memchr(f2, ':', n-(f2-f1)); + if(!f3) + continue; + f3++; + f4 = memchr(f3, ':', n-(f3-f1)); + if(!f4) + continue; + f4++; + if(matchnum) + matched = (atoi(f1) == *pnum); + else{ + int length; + + length = f3-f2-1; + matched = length==strlen(*pname) && memcmp(*pname, f2, length)==0; + } + if(matched){ + /* allocate and fill in a Memo structure */ + mem = (Memo*)malloc(sizeof(struct Memo)); + if(!mem) + return 0; + m = (f3-f2)-1; + if(m > NAMEMAX-1) + m = NAMEMAX-1; + memcpy(mem->name, f2, m); + mem->name[m] = 0; + mem->num = atoi(f1); + m = n-(f4-f1); + if(m > 0){ + mem->glist = (char*)malloc(m+1); + if(mem->glist) { + memcpy(mem->glist, f4, m); + mem->glist[m] = 0; + } + } else + mem->glist = 0; + /* prepare for following move-to-front */ + if(nmemo == MEMOMAX) { + free(memo[nmemo-1]); + i = nmemo-1; + } else { + i = nmemo++; + } + } + } + if(matched) { + if(matchnum) + *pname = mem->name; + else + *pnum = mem->num; + if(plist) + *plist = mem->glist; + if(i > 0) { + /* make room at front */ + for(j = i; j > 0; j--) + memo[j] = memo[j-1]; + } + memo[0] = mem; + return 1; + } + return 0; +} + +char ** +_grpmems(char *list) +{ + char **v; + char *p; + static char *holdvec[200]; + static char holdlist[1000]; + + p = list; + v = holdvec; + if(p) { + strncpy(holdlist, list, sizeof(holdlist)); + while(v< &holdvec[sizeof(holdvec)]-1 && *p){ + *v++ = p; + p = strchr(p, ','); + if(p){ + p++; + *p = 0; + }else + break; + } + } + *v = 0; + return holdvec; +} diff --git a/sys/src/ape/lib/ap/plan9/_nap.c b/sys/src/ape/lib/ap/plan9/_nap.c new file mode 100755 index 000000000..d21eff79c --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/_nap.c @@ -0,0 +1,20 @@ +#include "lib.h" +#include <unistd.h> +#include <time.h> +#include "sys9.h" + +/* + * This is an extension to POSIX + */ +unsigned int +_nap(unsigned int millisecs) +{ + time_t t0, t1; + + t0 = time(0); + if(_SLEEP(millisecs) < 0){ + t1 = time(0); + return t1-t0; + } + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/access.c b/sys/src/ape/lib/ap/plan9/access.c new file mode 100755 index 000000000..c51b37d6c --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/access.c @@ -0,0 +1,62 @@ +#include "lib.h" +#include <string.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +int +access(const char *name, int mode) +{ + int fd, n; + Dir *db; + struct stat st; + static char omode[] = { + 0, + 3, + 1, + 2, + 0, + 2, + 2, + 2 + }; + char tname[1024]; + + if(mode == 0){ + db = _dirstat(name); + if(db == nil){ + _syserrno(); + return -1; + } + free(db); + return 0; + } + fd = open(name, omode[mode&7]); + if(fd >= 0){ + close(fd); + return 0; + } + else if(stat(name, &st)==0 && S_ISDIR(st.st_mode)){ + if(mode & (R_OK|X_OK)){ + fd = open(name, O_RDONLY); + if(fd < 0) + return -1; + close(fd); + } + if(mode & W_OK){ + strncpy(tname, name, sizeof(tname)-9); + strcat(tname, "/_AcChAcK"); + fd = creat(tname, 0666); + if(fd < 0) + return -1; + close(fd); + _REMOVE(tname); + } + return 0; + } + return -1; +} diff --git a/sys/src/ape/lib/ap/plan9/acid.c b/sys/src/ape/lib/ap/plan9/acid.c new file mode 100755 index 000000000..5109a215e --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/acid.c @@ -0,0 +1,31 @@ +/* include struct defs to get acid library + cpp -I/sys/include/ape -I/$objtype/include/ape -I./include acid.c > t.c + vc -a t.c > acidlib +*/ +#define _POSIX_SOURCE 1 +#define _BSD_EXTENSION 1 +#define _LOCK_EXTENSION +#include <stddef.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdio.h> +#include <lock.h> +#include <sys/time.h> +#include <sys/select.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <termios.h> +#include <stdarg.h> +#include <math.h> +#include <float.h> +#include <sys/utsname.h> +/* #include "lib.h" buf.c below */ +/* #include "sys9.h" buf.c below */ +#include "_buf.c" +#include "dir.h" +#include "fcall.h" diff --git a/sys/src/ape/lib/ap/plan9/acidlib b/sys/src/ape/lib/ap/plan9/acidlib new file mode 100755 index 000000000..a4f14503f --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/acidlib @@ -0,0 +1,706 @@ +sizeof_1_ = 8; +aggr _1_ +{ + 'D' 0 quot; + 'D' 4 rem; +}; + +defn +_1_(addr) { + complex _1_ addr; + print(" quot ", addr.quot, "\n"); + print(" rem ", addr.rem, "\n"); +}; + +sizeof_2_ = 8; +aggr _2_ +{ + 'D' 0 quot; + 'D' 4 rem; +}; + +defn +_2_(addr) { + complex _2_ addr; + print(" quot ", addr.quot, "\n"); + print(" rem ", addr.rem, "\n"); +}; + +sizeofsigaction = 12; +aggr sigaction +{ + 'X' 0 sa_handler; + 'D' 4 sa_mask; + 'D' 8 sa_flags; +}; + +defn +sigaction(addr) { + complex sigaction addr; + print(" sa_handler ", addr.sa_handler\X, "\n"); + print(" sa_mask ", addr.sa_mask, "\n"); + print(" sa_flags ", addr.sa_flags, "\n"); +}; + +sizeof_3_ = 32; +aggr _3_ +{ + 'D' 0 fd; + 'C' 4 flags; + 'C' 5 state; + 'X' 8 buf; + 'X' 12 rp; + 'X' 16 wp; + 'X' 20 lp; + 'U' 24 bufl; + 'a' 28 unbuf; +}; + +defn +_3_(addr) { + complex _3_ addr; + print(" fd ", addr.fd, "\n"); + print(" flags ", addr.flags, "\n"); + print(" state ", addr.state, "\n"); + print(" buf ", addr.buf\X, "\n"); + print(" rp ", addr.rp\X, "\n"); + print(" wp ", addr.wp\X, "\n"); + print(" lp ", addr.lp\X, "\n"); + print(" bufl ", addr.bufl, "\n"); + print(" unbuf ", addr.unbuf, "\n"); +}; + +sizeof_4_ = 4; +aggr _4_ +{ + 'D' 0 val; +}; + +defn +_4_(addr) { + complex _4_ addr; + print(" val ", addr.val, "\n"); +}; + +sizeoftimeval = 8; +aggr timeval +{ + 'D' 0 tv_sec; + 'D' 4 tv_usec; +}; + +defn +timeval(addr) { + complex timeval addr; + print(" tv_sec ", addr.tv_sec, "\n"); + print(" tv_usec ", addr.tv_usec, "\n"); +}; + +sizeoftimezone = 8; +aggr timezone +{ + 'D' 0 tz_minuteswest; + 'D' 4 tz_dsttime; +}; + +defn +timezone(addr) { + complex timezone addr; + print(" tz_minuteswest ", addr.tz_minuteswest, "\n"); + print(" tz_dsttime ", addr.tz_dsttime, "\n"); +}; + +sizeoffd_set = 12; +aggr fd_set +{ + 'a' 0 fds_bits; +}; + +defn +fd_set(addr) { + complex fd_set addr; + mem(addr, "3X"); +}; + +sizeofstat = 28; +aggr stat +{ + 'u' 0 st_dev; + 'u' 2 st_ino; + 'u' 4 st_mode; + 'd' 6 st_nlink; + 'd' 8 st_uid; + 'd' 10 st_gid; + 'D' 12 st_size; + 'D' 16 st_atime; + 'D' 20 st_mtime; + 'D' 24 st_ctime; +}; + +defn +stat(addr) { + complex stat addr; + print(" st_dev ", addr.st_dev, "\n"); + print(" st_ino ", addr.st_ino, "\n"); + print(" st_mode ", addr.st_mode, "\n"); + print(" st_nlink ", addr.st_nlink, "\n"); + print(" st_uid ", addr.st_uid, "\n"); + print(" st_gid ", addr.st_gid, "\n"); + print(" st_size ", addr.st_size, "\n"); + print(" st_atime ", addr.st_atime, "\n"); + print(" st_mtime ", addr.st_mtime, "\n"); + print(" st_ctime ", addr.st_ctime, "\n"); +}; + +sizeofflock = 16; +aggr flock +{ + 'd' 0 l_type; + 'd' 2 l_whence; + 'D' 4 l_start; + 'D' 8 l_len; + 'D' 12 l_pid; +}; + +defn +flock(addr) { + complex flock addr; + print(" l_type ", addr.l_type, "\n"); + print(" l_whence ", addr.l_whence, "\n"); + print(" l_start ", addr.l_start, "\n"); + print(" l_len ", addr.l_len, "\n"); + print(" l_pid ", addr.l_pid, "\n"); +}; + +sizeofdirent = 28; +aggr dirent +{ + 'a' 0 d_name; +}; + +defn +dirent(addr) { + complex dirent addr; + print(" d_name ", addr.d_name, "\n"); +}; + +sizeof_dirdesc = 16; +aggr _dirdesc +{ + 'D' 0 dd_fd; + 'D' 4 dd_loc; + 'D' 8 dd_size; + 'X' 12 dd_buf; +}; + +defn +_dirdesc(addr) { + complex _dirdesc addr; + print(" dd_fd ", addr.dd_fd, "\n"); + print(" dd_loc ", addr.dd_loc, "\n"); + print(" dd_size ", addr.dd_size, "\n"); + print(" dd_buf ", addr.dd_buf\X, "\n"); +}; + +sizeoftermios = 28; +aggr termios +{ + 'U' 0 c_iflag; + 'U' 4 c_oflag; + 'U' 8 c_cflag; + 'U' 12 c_lflag; + 'a' 16 c_cc; +}; + +defn +termios(addr) { + complex termios addr; + print(" c_iflag ", addr.c_iflag, "\n"); + print(" c_oflag ", addr.c_oflag, "\n"); + print(" c_cflag ", addr.c_cflag, "\n"); + print(" c_lflag ", addr.c_lflag, "\n"); + print(" c_cc ", addr.c_cc, "\n"); +}; + +sizeofutsname = 20; +aggr utsname +{ + 'X' 0 sysname; + 'X' 4 nodename; + 'X' 8 release; + 'X' 12 version; + 'X' 16 machine; +}; + +defn +utsname(addr) { + complex utsname addr; + print(" sysname ", addr.sysname\X, "\n"); + print(" nodename ", addr.nodename\X, "\n"); + print(" release ", addr.release\X, "\n"); + print(" version ", addr.version\X, "\n"); + print(" machine ", addr.machine\X, "\n"); +}; + +sizeofMuxbuf = 16400; +aggr Muxbuf +{ + 'D' 0 n; + 'X' 4 putnext; + 'X' 8 getnext; + 'b' 12 fd; + 'b' 13 eof; + 'b' 14 roomwait; + 'b' 15 datawait; + 'a' 16 data; +}; + +defn +Muxbuf(addr) { + complex Muxbuf addr; + print(" n ", addr.n, "\n"); + print(" putnext ", addr.putnext\X, "\n"); + print(" getnext ", addr.getnext\X, "\n"); + print(" fd ", addr.fd, "\n"); + print(" eof ", addr.eof, "\n"); + print(" roomwait ", addr.roomwait, "\n"); + print(" datawait ", addr.datawait, "\n"); + print(" data ", addr.data, "\n"); +}; + +sizeofFdinfo = 16; +aggr Fdinfo +{ + 'U' 0 flags; + 'U' 4 oflags; + 'X' 8 name; + 'A' Muxbuf 12 buf; +}; + +defn +Fdinfo(addr) { + complex Fdinfo addr; + print(" flags ", addr.flags, "\n"); + print(" oflags ", addr.oflags, "\n"); + print(" name ", addr.name\X, "\n"); + print(" buf ", addr.buf\X, "\n"); +}; + +sizeofWaitmsg = 112; +aggr Waitmsg +{ + 'a' 0 pid; + 'a' 12 time; + 'a' 48 msg; +}; + +defn +Waitmsg(addr) { + complex Waitmsg addr; + print(" pid ", addr.pid, "\n"); + print(" time ", addr.time, "\n"); + print(" msg ", addr.msg, "\n"); +}; + +sizeof_5_ = 8; +aggr _5_ +{ + 'D' 0 hlength; + 'D' 4 length; +}; + +defn +_5_(addr) { + complex _5_ addr; + print(" hlength ", addr.hlength, "\n"); + print(" length ", addr.length, "\n"); +}; + +sizeof_6_ = 8; +aggr _6_ +{ + 'a' 0 clength; + 'D' 0 vlength; + { + 'D' 0 hlength; + 'D' 4 length; + }; +}; + +defn +_6_(addr) { + complex _6_ addr; + print(" clength ", addr.clength, "\n"); + print(" vlength ", addr.vlength, "\n"); + print("_5_ {\n"); + _5_(addr+0); + print("}\n"); +}; + +sizeofQid = 8; +aggr Qid +{ + 'U' 0 path; + 'U' 4 vers; +}; + +defn +Qid(addr) { + complex Qid addr; + print(" path ", addr.path, "\n"); + print(" vers ", addr.vers, "\n"); +}; + +sizeofDir = 116; +aggr Dir +{ + 'a' 0 name; + 'a' 28 uid; + 'a' 56 gid; + Qid 84 qid; + 'U' 92 mode; + 'D' 96 atime; + 'D' 100 mtime; + { + 'a' 104 clength; + 'D' 104 vlength; + { + 'D' 104 hlength; + 'D' 108 length; + }; + }; + 'd' 112 type; + 'd' 114 dev; +}; + +defn +Dir(addr) { + complex Dir addr; + print(" name ", addr.name, "\n"); + print(" uid ", addr.uid, "\n"); + print(" gid ", addr.gid, "\n"); + print("Qid qid {\n"); + Qid(addr.qid); + print("}\n"); + print(" mode ", addr.mode, "\n"); + print(" atime ", addr.atime, "\n"); + print(" mtime ", addr.mtime, "\n"); + print("_6_ {\n"); + _6_(addr+104); + print("}\n"); + print(" type ", addr.type, "\n"); + print(" dev ", addr.dev, "\n"); +}; + +sizeof_7_ = 28; +aggr _7_ +{ + 'u' 0 oldtag; + Qid 4 qid; + 'a' 12 rauth; +}; + +defn +_7_(addr) { + complex _7_ addr; + print(" oldtag ", addr.oldtag, "\n"); + print("Qid qid {\n"); + Qid(addr.qid); + print("}\n"); + print(" rauth ", addr.rauth, "\n"); +}; + +sizeof_8_ = 144; +aggr _8_ +{ + 'a' 0 uname; + 'a' 28 aname; + 'a' 56 ticket; + 'a' 128 auth; +}; + +defn +_8_(addr) { + complex _8_ addr; + print(" uname ", addr.uname, "\n"); + print(" aname ", addr.aname, "\n"); + print(" ticket ", addr.ticket, "\n"); + print(" auth ", addr.auth, "\n"); +}; + +sizeof_9_ = 148; +aggr _9_ +{ + 'a' 0 ename; + 'a' 64 authid; + 'a' 92 authdom; + 'a' 140 chal; +}; + +defn +_9_(addr) { + complex _9_ addr; + print(" ename ", addr.ename, "\n"); + print(" authid ", addr.authid, "\n"); + print(" authdom ", addr.authdom, "\n"); + print(" chal ", addr.chal, "\n"); +}; + +sizeof_10_ = 36; +aggr _10_ +{ + 'D' 0 perm; + 'd' 4 newfid; + 'a' 6 name; + 'C' 34 mode; +}; + +defn +_10_(addr) { + complex _10_ addr; + print(" perm ", addr.perm, "\n"); + print(" newfid ", addr.newfid, "\n"); + print(" name ", addr.name, "\n"); + print(" mode ", addr.mode, "\n"); +}; + +sizeof_11_ = 12; +aggr _11_ +{ + 'D' 0 offset; + 'D' 4 count; + 'X' 8 data; +}; + +defn +_11_(addr) { + complex _11_ addr; + print(" offset ", addr.offset, "\n"); + print(" count ", addr.count, "\n"); + print(" data ", addr.data\X, "\n"); +}; + +sizeof_12_ = 116; +aggr _12_ +{ + 'a' 0 stat; +}; + +defn +_12_(addr) { + complex _12_ addr; + print(" stat ", addr.stat, "\n"); +}; + +sizeof_13_ = 148; +aggr _13_ +{ + { + 'u' 0 oldtag; + Qid 4 qid; + 'a' 12 rauth; + }; + { + 'a' 0 uname; + 'a' 28 aname; + 'a' 56 ticket; + 'a' 128 auth; + }; + { + 'a' 0 ename; + 'a' 64 authid; + 'a' 92 authdom; + 'a' 140 chal; + }; + { + 'D' 0 perm; + 'd' 4 newfid; + 'a' 6 name; + 'C' 34 mode; + }; + { + 'D' 0 offset; + 'D' 4 count; + 'X' 8 data; + }; + { + 'a' 0 stat; + }; +}; + +defn +_13_(addr) { + complex _13_ addr; + print("_7_ {\n"); + _7_(addr+0); + print("}\n"); + print("_8_ {\n"); + _8_(addr+0); + print("}\n"); + print("_9_ {\n"); + _9_(addr+0); + print("}\n"); + print("_10_ {\n"); + _10_(addr+0); + print("}\n"); + print("_11_ {\n"); + _11_(addr+0); + print("}\n"); + print("_12_ {\n"); + _12_(addr+0); + print("}\n"); +}; + +sizeofFcall = 156; +aggr Fcall +{ + 'C' 0 type; + 'd' 2 fid; + 'u' 4 tag; + { + { + 'u' 8 oldtag; + Qid 12 qid; + 'a' 20 rauth; + }; + { + 'a' 8 uname; + 'a' 36 aname; + 'a' 64 ticket; + 'a' 136 auth; + }; + { + 'a' 8 ename; + 'a' 72 authid; + 'a' 100 authdom; + 'a' 148 chal; + }; + { + 'D' 8 perm; + 'd' 12 newfid; + 'a' 14 name; + 'C' 42 mode; + }; + { + 'D' 8 offset; + 'D' 12 count; + 'X' 16 data; + }; + { + 'a' 8 stat; + }; + }; +}; + +defn +Fcall(addr) { + complex Fcall addr; + print(" type ", addr.type, "\n"); + print(" fid ", addr.fid, "\n"); + print(" tag ", addr.tag, "\n"); + print("_13_ {\n"); + _13_(addr+8); + print("}\n"); +}; + +sizeofMuxbuf = 16400; +aggr Muxbuf +{ + 'D' 0 n; + 'X' 4 putnext; + 'X' 8 getnext; + 'b' 12 fd; + 'b' 13 eof; + 'b' 14 roomwait; + 'b' 15 datawait; + 'a' 16 data; +}; + +defn +Muxbuf(addr) { + complex Muxbuf addr; + print(" n ", addr.n, "\n"); + print(" putnext ", addr.putnext\X, "\n"); + print(" getnext ", addr.getnext\X, "\n"); + print(" fd ", addr.fd, "\n"); + print(" eof ", addr.eof, "\n"); + print(" roomwait ", addr.roomwait, "\n"); + print(" datawait ", addr.datawait, "\n"); + print(" data ", addr.data, "\n"); +}; + +sizeofFdinfo = 16; +aggr Fdinfo +{ + 'U' 0 flags; + 'U' 4 oflags; + 'X' 8 name; + 'A' Muxbuf 12 buf; +}; + +defn +Fdinfo(addr) { + complex Fdinfo addr; + print(" flags ", addr.flags, "\n"); + print(" oflags ", addr.oflags, "\n"); + print(" name ", addr.name\X, "\n"); + print(" buf ", addr.buf\X, "\n"); +}; + +sizeofWaitmsg = 112; +aggr Waitmsg +{ + 'a' 0 pid; + 'a' 12 time; + 'a' 48 msg; +}; + +defn +Waitmsg(addr) { + complex Waitmsg addr; + print(" pid ", addr.pid, "\n"); + print(" time ", addr.time, "\n"); + print(" msg ", addr.msg, "\n"); +}; + +sizeofMuxseg = 65640; +aggr Muxseg +{ + _4_ 0 lock; + 'D' 4 curfds; + 'D' 8 selwait; + 'D' 12 waittime; + fd_set 16 rwant; + fd_set 28 ewant; + 'a' 40 bufs; +}; + +defn +Muxseg(addr) { + complex Muxseg addr; + print("_4_ lock {\n"); + _4_(addr.lock); + print("}\n"); + print(" curfds ", addr.curfds, "\n"); + print(" selwait ", addr.selwait, "\n"); + print(" waittime ", addr.waittime, "\n"); + print("fd_set rwant {\n"); + fd_set(addr.rwant); + print("}\n"); + print("fd_set ewant {\n"); + fd_set(addr.ewant); + print("}\n"); + print(" bufs ", addr.bufs, "\n"); +}; + +complex Muxseg mux; +complex Fdinfo _startbuf:f; +complex Muxbuf _startbuf:b; +complex Muxbuf _copyproc:b; +complex Muxbuf _readbuf:b; +complex fd_set select:rfds; +complex fd_set select:wfds; +complex fd_set select:efds; +complex timeval select:timeout; +complex Fdinfo select:f; +complex Muxbuf select:b; diff --git a/sys/src/ape/lib/ap/plan9/alarm.c b/sys/src/ape/lib/ap/plan9/alarm.c new file mode 100755 index 000000000..f8a24aa65 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/alarm.c @@ -0,0 +1,9 @@ +#include "lib.h" +#include <unistd.h> +#include "sys9.h" + +unsigned int +alarm(unsigned seconds) +{ + return _ALARM(seconds*1000); +} diff --git a/sys/src/ape/lib/ap/plan9/brk.c b/sys/src/ape/lib/ap/plan9/brk.c new file mode 100755 index 000000000..0b3240377 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/brk.c @@ -0,0 +1,36 @@ +#include "lib.h" +#include <errno.h> +#include "sys9.h" + +char end[]; +static char *bloc = { end }; +extern int _BRK_(void*); + +char * +brk(char *p) +{ + unsigned long n; + + n = (unsigned long)p; + n += 3; + n &= ~3; + if(_BRK_((void*)n) < 0){ + errno = ENOMEM; + return (char *)-1; + } + bloc = (char *)n; + return 0; +} + +void * +sbrk(unsigned long n) +{ + n += 3; + n &= ~3; + if(_BRK_((void *)(bloc+n)) < 0){ + errno = ENOMEM; + return (void *)-1; + } + bloc += n; + return (void *)(bloc-n); +} diff --git a/sys/src/ape/lib/ap/plan9/buf.prom b/sys/src/ape/lib/ap/plan9/buf.prom new file mode 100755 index 000000000..e8751dadd --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/buf.prom @@ -0,0 +1,360 @@ +#define NBUFS 2 +#define READMAX 2 +#define BUFSIZ 2*READMAX +#define EOF 255 +#define TIMEOUT 254 +#define FILEMAXLEN 20 + +byte n[NBUFS]; +byte ntotal[NBUFS]; +byte putnext[NBUFS]; +byte getnext[NBUFS]; +bool eof[NBUFS]; +bool roomwait[NBUFS]; +bool datawait[NBUFS]; +byte rwant; + +/* use one big data array to simulate 2-d array */ +#define bufstart(slot) (slot*BUFSIZ) +#define bufend(slot) ((slot+1)*BUFSIZ) +/* bit data[BUFSIZ*NBUFS]; */ + +bool selwait; +/* bool hastimeout; */ + +#define get 0 +#define release 1 + +chan lock = [0] of { bit }; +chan lockkill = [0] of { bit }; +chan sel = [0] of { byte }; +chan selcall = [0] of { byte }; +chan selans = [0] of { byte, byte }; +chan selkill = [0] of { bit }; +chan readcall = [0] of { byte, byte }; +chan readans = [0] of { byte }; +chan readkill = [0] of { bit }; +chan croom[NBUFS] = [0] of { bit }; +chan cdata[NBUFS] = [0] of { bit }; + +proctype Lockrendez() +{ + do + :: lock!get -> lock?release + :: lockkill?release -> break + od +} + +proctype Copy(byte fd) +{ + byte num; + bit b; + + do :: 1 -> + /* make sure there's room */ + lock?get; + if + :: (BUFSIZ-putnext[fd]) < READMAX -> + if + :: getnext[fd] == putnext[fd] -> + getnext[fd] = 0; + putnext[fd] = 0; + lock!release + :: getnext[fd] != putnext[fd] -> + roomwait[fd] = 1; + lock!release; + croom[fd]?b + fi + :: (BUFSIZ-putnext[fd]) >= READMAX -> + lock!release + fi; + /* simulate read into data buf at putnext */ + if + :: ntotal[fd] > FILEMAXLEN -> + num = EOF + :: ntotal[fd] <= FILEMAXLEN -> + if + :: num = 1 + :: num = READMAX + :: num = EOF + fi + fi; + /* here is where data transfer would happen */ + lock?get; + if + :: num == EOF -> + eof[fd] = 1; +/* printf("Copy %d got eof\n", fd);/**/ + if + :: datawait[fd] -> + datawait[fd] = 0; + lock!release; + cdata[fd]!1 + :: !datawait[fd] && (rwant & (1<<fd)) && selwait -> + selwait = 0; + lock!release; + sel!fd + :: !datawait[fd] && !((rwant & (1<<fd)) && selwait) -> + lock!release + fi; + break + :: num != EOF -> +/* printf("Copy %d putting %d in; old putnext=%d, old n=%d\n", fd, num, putnext[fd], n[fd]); /* */ + putnext[fd] = putnext[fd] + num; + n[fd] = n[fd] + num; + ntotal[fd] = ntotal[fd] + num; + assert(n[fd] > 0); + if + :: datawait[fd] -> + datawait[fd] = 0; + lock!release; + cdata[fd]!1 + :: !datawait[fd] && (rwant & (1<<fd)) && selwait -> + selwait = 0; + lock!release; + sel!fd + :: !datawait[fd] && !((rwant & (1<<fd)) && selwait) -> + lock!release + fi + fi; + od +} + +proctype Read() +{ + byte ngot; + byte fd; + byte nwant; + bit b; + + do + :: readcall?fd,nwant -> + if + :: eof[fd] && n[fd] == 0 -> + readans!EOF + :: !(eof[fd] && n[fd] == 0) -> + lock?get; + ngot = putnext[fd] - getnext[fd]; +/* printf("Reading %d, want %d: ngot = %d - %d, n = %d\n", fd, nwant, putnext[fd], getnext[fd], n[fd]); /* */ + if + :: ngot == 0 -> + if + :: eof[fd] -> + skip + :: !eof[fd] -> + /* sleep until there's data */ + datawait[fd] = 1; +/* printf("Read sleeping\n"); /* */ + lock!release; + cdata[fd]?b; + lock?get; + ngot = putnext[fd] - getnext[fd]; +/* printf("Read awoke, ngot = %d\n", ngot); /**/ + fi + :: ngot != 0 -> skip + fi; + if + :: ngot > nwant -> ngot = nwant + :: ngot <= nwant -> skip + fi; + /* here would take ngot elements from data, from getnext[fd] ... */ + getnext[fd] = getnext[fd] + ngot; + assert(n[fd] >= ngot); + n[fd] = n[fd] - ngot; + if + :: ngot == 0 -> + assert(eof[fd]); + ngot = EOF + :: ngot != 0 -> skip + fi; + if + :: getnext[fd] == putnext[fd] && roomwait[fd] -> + getnext[fd] = 0; + putnext[fd] = 0; + roomwait[fd] = 0; + lock!release; + croom[fd]!0 + :: getnext[fd] != putnext[fd] || !roomwait[fd] -> + lock!release + fi; + readans!ngot + fi + :: readkill?b -> break + od +} + +proctype Select() +{ + byte num; + byte i; + byte fd; + byte r; + bit b; + + do + :: selcall?r -> +/* printf("Select called, r=%d\n", r); /**/ + i = 0; + do + :: i < NBUFS -> + if + :: r & (1<<i) -> + if + :: eof[i] && n[i] == 0 -> +/* printf("Select got eof on %d\n", i);/**/ + num = EOF; + r = i; + goto donesel + :: !eof[i] || n[i] != 0 -> skip + fi + :: !(r & (1<<i)) -> skip + fi; + i = i+1 + :: i >= NBUFS -> break + od; + num = 0; + lock?get; + rwant = 0; + i = 0; + do + :: i < NBUFS -> + if + :: r & (1<<i) -> + if + :: n[i] > 0 || eof[i] -> +/* printf("Select found %d has n==%d\n", i, n[i]); /**/ + num = num+1 + :: n[i] == 0 && !eof[i] -> +/* printf("Select asks to wait for %d\n", i); /**/ + r = r &(~(1<<i)); + rwant = rwant | (1<<i) + fi + :: !(r & (1<<i)) -> skip + fi; + i = i+1 + :: i >= NBUFS -> break + od; + if + :: num > 0 || rwant == 0 -> + rwant = 0; + lock!release; + :: num == 0 && rwant != 0 -> + selwait = 1; + lock!release; +/* printf("Select sleeps\n"); /**/ + sel?fd; +/* printf("Select wakes up, fd=%d\n", fd); /**/ + if + :: fd != TIMEOUT -> + if + :: (rwant & (1<<fd)) && (n[fd] > 0) -> + r = r | (1<<fd); + num = 1 + :: !(rwant & (1<<fd)) || (n[fd] == 0) -> + num = 0 + fi + :: fd == TIMEOUT -> skip + fi; + rwant = 0 + fi; + donesel: + selans!num,r + :: selkill?b -> break + od +} + +/* This routine is written knowing NBUFS == 2 in several places */ +proctype User() +{ + byte ndone; + byte i; + byte rw; + byte num; + byte nwant; + byte fd; + bool goteof[NBUFS]; + + ndone = 0; + do + :: ndone == NBUFS -> break + :: ndone < NBUFS -> + if + :: 1-> + /* maybe use Read */ +/* printf("User trying to read. Current goteofs: %d %d\n", goteof[0], goteof[1]); /**/ + /* randomly pick fd 0 or 1 from non-eof ones */ + if + :: !goteof[0] -> fd = 0 + :: !goteof[1] -> fd = 1 + fi; + if + :: nwant = 1 + :: nwant = READMAX + fi; + readcall!fd,nwant; + readans?num; + if + :: num == EOF -> + goteof[fd] = 1; + ndone = ndone + 1 + :: num != EOF -> assert(num != 0) + fi + :: 1-> +/* printf("User trying to select. Current goteofs: %d %d\n", goteof[0], goteof[1]); /**/ + /* maybe use Select, then Read */ + /* randomly set the "i want" bit for non-eof fds */ + if + :: !goteof[0] && !goteof[1] -> rw = (1<<0) | (1<<1) + :: !goteof[0] -> rw = (1<<0) + :: !goteof[1] -> rw = (1<<1) + fi; + selcall!rw; + selans?i,rw; + if + :: i == EOF -> + goteof[rw] = 1; + ndone = ndone + 1 + :: i != EOF -> + /* this next statement knows NBUFS == 2 ! */ + if + :: rw & (1<<0) -> fd = 0 + :: rw & (1<<1) -> fd = 1 + :: rw == 0 -> fd = EOF + fi; + if + :: nwant = 1 + :: nwant = READMAX + fi; + if + :: fd != EOF -> + readcall!fd,nwant; + readans?num; + assert(num != 0) + :: fd == EOF -> skip + fi + fi + fi + od; + lockkill!release; + selkill!release; + readkill!release +} + +init +{ + byte i; + + atomic { + run Lockrendez(); + i = 0; + do + :: i < NBUFS -> + run Copy(i); + i = i+1 + :: i >= NBUFS -> break + od; + run Select(); + run Read(); + run User() + } +} diff --git a/sys/src/ape/lib/ap/plan9/cfgetospeed.c b/sys/src/ape/lib/ap/plan9/cfgetospeed.c new file mode 100755 index 000000000..cc89f4a86 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/cfgetospeed.c @@ -0,0 +1,26 @@ +#include <termios.h> + +speed_t +cfgetospeed(const struct termios *p) +{ + return B0; +} + +int +cfsetospeed(struct termios *p, speed_t s) +{ + return 0; +} + +speed_t +cfgetispeed(const struct termios *p) +{ + return B0; +} + +int +cfsetispeed(struct termios *p, speed_t s) +{ + return 0; +} + diff --git a/sys/src/ape/lib/ap/plan9/chdir.c b/sys/src/ape/lib/ap/plan9/chdir.c new file mode 100755 index 000000000..245f116d0 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/chdir.c @@ -0,0 +1,14 @@ +#include "lib.h" +#include <unistd.h> +#include "sys9.h" + +int +chdir(const char *f) +{ + int n; + + n = _CHDIR(f); + if(n < 0) + _syserrno(); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/chmod.c b/sys/src/ape/lib/ap/plan9/chmod.c new file mode 100755 index 000000000..8b6daad22 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/chmod.c @@ -0,0 +1,33 @@ +#include "lib.h" +#include <errno.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +int +chmod(const char *path, mode_t mode) +{ + Dir d; + + _nulldir(&d); + d.mode = mode & 0777; + if(_dirwstat(path, &d) < 0){ + _syserrno(); + return -1; + } + return 0; +} + +int +fchmod(int fd, mode_t mode) +{ + Dir d; + + _nulldir(&d); + d.mode = mode & 0777; + if(_dirfwstat(fd, &d) < 0){ + _syserrno(); + return -1; + } + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/chown.c b/sys/src/ape/lib/ap/plan9/chown.c new file mode 100755 index 000000000..22b651d14 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/chown.c @@ -0,0 +1,39 @@ +#include "lib.h" +#include "sys9.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include "dir.h" + +int +chown(const char *path, uid_t owner, gid_t group) +{ + int num; + Dir d; + + _nulldir(&d); + + /* find owner, group */ + d.uid = nil; + num = owner; + if(!_getpw(&num, &d.uid, 0)) { + errno = EINVAL; + return -1; + } + + d.gid = nil; + num = group; + if(!_getpw(&num, &d.gid, 0)) { + errno = EINVAL; + return -1; + } + + if(_dirwstat(path, &d) < 0){ + _syserrno(); + return -1; + } + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/close.c b/sys/src/ape/lib/ap/plan9/close.c new file mode 100755 index 000000000..258788a39 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/close.c @@ -0,0 +1,34 @@ +#include "lib.h" +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "sys9.h" + +int +close(int d) +{ + int n; + Fdinfo *f; + + n = -1; + f = &_fdinfo[d]; + if(d<0 || d>=OPEN_MAX || !(f->flags&FD_ISOPEN)) + errno = EBADF; + else{ + if(f->flags&(FD_BUFFERED|FD_BUFFEREDX)) { + if(f->flags&FD_BUFFERED) + _closebuf(d); + f->flags &= ~FD_BUFFERED; + } + n = _CLOSE(d); + if(n < 0) + _syserrno(); + _fdinfo[d].flags = 0; + _fdinfo[d].oflags = 0; + if(_fdinfo[d].name){ + free(_fdinfo[d].name); + _fdinfo[d].name = 0; + } + } + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/convD2M.c b/sys/src/ape/lib/ap/plan9/convD2M.c new file mode 100755 index 000000000..fc1ade5c5 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/convD2M.c @@ -0,0 +1,93 @@ +#include "lib.h" +#include <string.h> +#include "sys9.h" +#include "dir.h" + +uint +_convD2M(Dir *d, uchar *buf, uint nbuf) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns, nsv[4], ss; + + if(nbuf < BIT16SZ) + return 0; + + p = buf; + ebuf = buf + nbuf; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++){ + nsv[i] = strlen(sv[i]); + ns += nsv[i]; + } + + ss = STATFIXLEN + ns; + + /* set size befor erroring, so user can know how much is needed */ + /* note that length excludes count field itself */ + PBIT16(p, ss-BIT16SZ); + p += BIT16SZ; + + if(ss > nbuf) + return BIT16SZ; + + PBIT16(p, d->type); + p += BIT16SZ; + PBIT32(p, d->dev); + p += BIT32SZ; + PBIT8(p, d->qid.type); + p += BIT8SZ; + PBIT32(p, d->qid.vers); + p += BIT32SZ; + PBIT64(p, d->qid.path); + p += BIT64SZ; + PBIT32(p, d->mode); + p += BIT32SZ; + PBIT32(p, d->atime); + p += BIT32SZ; + PBIT32(p, d->mtime); + p += BIT32SZ; + PBIT64(p, d->length); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + ns = nsv[i]; + if(p + ns + BIT16SZ > ebuf) + return 0; + PBIT16(p, ns); + p += BIT16SZ; + memmove(p, sv[i], ns); + p += ns; + } + + if(ss != p - buf) + return 0; + + return p - buf; +} + +uint +_sizeD2M(Dir *d) +{ + char *sv[4]; + int i, ns; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++) + if(sv[i]) + ns += strlen(sv[i]); + + return STATFIXLEN + ns; +} + diff --git a/sys/src/ape/lib/ap/plan9/convM2D.c b/sys/src/ape/lib/ap/plan9/convM2D.c new file mode 100755 index 000000000..222e88927 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/convM2D.c @@ -0,0 +1,74 @@ +#include "lib.h" +#include <string.h> +#include "sys9.h" +#include "dir.h" +#define nil ((void*)0) + +static char nullstring[] = ""; + +uint +_convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns, nsv[4]; + + p = buf; + ebuf = buf + nbuf; + + p += BIT16SZ; /* ignore size */ + d->type = GBIT16(p); + p += BIT16SZ; + d->dev = GBIT32(p); + p += BIT32SZ; + d->qid.type = GBIT8(p); + p += BIT8SZ; + d->qid.vers = GBIT32(p); + p += BIT32SZ; + d->qid.path = GBIT64(p); + p += BIT64SZ; + d->mode = GBIT32(p); + p += BIT32SZ; + d->atime = GBIT32(p); + p += BIT32SZ; + d->mtime = GBIT32(p); + p += BIT32SZ; + d->length = GBIT64(p); + p += BIT64SZ; + + d->name = nil; + d->uid = nil; + d->gid = nil; + d->muid = nil; + + for(i = 0; i < 4; i++){ + if(p + BIT16SZ > ebuf) + return 0; + ns = GBIT16(p); + p += BIT16SZ; + if(p + ns > ebuf) + return 0; + if(strs){ + nsv[i] = ns; + sv[i] = strs; + memmove(strs, p, ns); + strs += ns; + *strs++ = '\0'; + } + p += ns; + } + + if(strs){ + d->name = sv[0]; + d->uid = sv[1]; + d->gid = sv[2]; + d->muid = sv[3]; + }else{ + d->name = nullstring; + d->uid = nullstring; + d->gid = nullstring; + d->muid = nullstring; + } + + return p - buf; +} diff --git a/sys/src/ape/lib/ap/plan9/creat.c b/sys/src/ape/lib/ap/plan9/creat.c new file mode 100755 index 000000000..a0f917a62 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/creat.c @@ -0,0 +1,13 @@ +#include "lib.h" +#include <sys/stat.h> +#include <fcntl.h> + +int +creat(const char *name, mode_t mode) +{ + int n; + + n = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode); + /* no need to _syserrno; open did it already */ + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/ctermid.c b/sys/src/ape/lib/ap/plan9/ctermid.c new file mode 100755 index 000000000..a8689a71f --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/ctermid.c @@ -0,0 +1,20 @@ +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +char * +ctermid(char *s) +{ + static char buf[L_ctermid]; + + if(s == 0) + s = buf; + strncpy(s, "/dev/cons", sizeof buf); + return(s); +} + +char * +ctermid_r(char *s) +{ + return s ? ctermid(s) : NULL; +} diff --git a/sys/src/ape/lib/ap/plan9/ctime.c b/sys/src/ape/lib/ap/plan9/ctime.c new file mode 100755 index 000000000..34a0b12a5 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/ctime.c @@ -0,0 +1,321 @@ +/* + * This routine converts time as follows. + * The epoch is 0000 Jan 1 1970 GMT. + * The argument time is in seconds since then. + * The localtime(t) entry returns a pointer to an array + * containing + * + * seconds (0-59) + * minutes (0-59) + * hours (0-23) + * day of month (1-31) + * month (0-11) + * year-1970 + * weekday (0-6, Sun is 0) + * day of the year + * daylight savings flag + * + * The routine gets the daylight savings time from the environment. + * + * asctime(tvec)) + * where tvec is produced by localtime + * returns a ptr to a character string + * that has the ascii time in the form + * + * \\ + * Thu Jan 01 00:00:00 1970n0 + * 01234567890123456789012345 + * 0 1 2 + * + * ctime(t) just calls localtime, then asctime. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <unistd.h> +#include <string.h> + +static char dmsize[12] = +{ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * The following table is used for 1974 and 1975 and + * gives the day number of the first day after the Sunday of the + * change. + */ + +static int dysize(int); +static void ct_numb(char*, int); +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, long*); + +#define TZSIZE 150 + +static +struct +{ + char stname[4]; + char dlname[4]; + long stdiff; + long dldiff; + long dlpairs[TZSIZE]; +} timezone; + +char* +ctime(const time_t *t) +{ + return asctime(localtime(t)); +} + +struct tm* +gmtime_r(const time_t *timp, struct tm *result) +{ + int d0, d1; + long hms, day; + time_t tim; + + tim = *timp; + /* + * break initial number into days + */ + hms = tim % 86400L; + day = tim / 86400L; + if(hms < 0) { + hms += 86400L; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + result->tm_sec = hms % 60; + d1 = hms / 60; + result->tm_min = d1 % 60; + d1 /= 60; + result->tm_hour = d1; + + /* + * day is the day number. + * generate day of the week. + * The addend is 4 mod 7 (1/1/1970 was Thursday) + */ + + result->tm_wday = (day + 7340036L) % 7; + + /* + * year number + */ + if(day >= 0) + for(d1 = 70; day >= dysize(d1); d1++) + day -= dysize(d1); + else + for (d1 = 70; day < 0; d1--) + day += dysize(d1-1); + result->tm_year = d1; + result->tm_yday = d0 = day; + + /* + * generate month + */ + + if(dysize(d1) == 366) + dmsize[1] = 29; + for(d1 = 0; d0 >= dmsize[d1]; d1++) + d0 -= dmsize[d1]; + dmsize[1] = 28; + result->tm_mday = d0 + 1; + result->tm_mon = d1; + result->tm_isdst = 0; + return result; +} + +struct tm* +gmtime(const time_t *timp) +{ + static struct tm xtime; + + return gmtime_r(timp, &xtime); +} + +struct tm* +localtime_r(const time_t *timp, struct tm *result) +{ + struct tm *ct; + time_t t, tim; + long *p; + int i, dlflag; + + tim = *timp; + if(timezone.stname[0] == 0) + readtimezone(); + t = tim + timezone.stdiff; + dlflag = 0; + for(p = timezone.dlpairs; *p; p += 2) + if(t >= p[0]) + if(t < p[1]) { + t = tim + timezone.dldiff; + dlflag++; + break; + } + ct = gmtime_r(&t, result); + ct->tm_isdst = dlflag; + return ct; +} + +struct tm* +localtime(const time_t *timp) +{ + static struct tm xtime; + + return localtime_r(timp, &xtime); +} + +char* +asctime_r(const struct tm *t, char *buf) +{ + char *ncp; + + strcpy(buf, "Thu Jan 01 00:00:00 1970\n"); + ncp = &"SunMonTueWedThuFriSat"[t->tm_wday*3]; + buf[0] = *ncp++; + buf[1] = *ncp++; + buf[2] = *ncp; + ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->tm_mon*3]; + buf[4] = *ncp++; + buf[5] = *ncp++; + buf[6] = *ncp; + ct_numb(buf+8, t->tm_mday); + ct_numb(buf+11, t->tm_hour+100); + ct_numb(buf+14, t->tm_min+100); + ct_numb(buf+17, t->tm_sec+100); + if(t->tm_year >= 100) { + buf[20] = '2'; + buf[21] = '0'; + } + ct_numb(buf+22, t->tm_year+100); + return buf; +} + +char* +asctime(const struct tm *t) +{ + static char cbuf[30]; + + return asctime_r(t, cbuf); +} + +static +dysize(int y) +{ + if((y%4) == 0) + return 366; + return 365; +} + +static +void +ct_numb(char *cp, int n) +{ + cp[0] = ' '; + if(n >= 10) + cp[0] = (n/10)%10 + '0'; + cp[1] = n%10 + '0'; +} + +static +void +readtimezone(void) +{ + char buf[TZSIZE*11+30], *p; + int i; + + memset(buf, 0, sizeof(buf)); + i = open("/env/timezone", 0); + if(i < 0) + goto error; + if(read(i, buf, sizeof(buf)) >= sizeof(buf)) + goto error; + close(i); + p = buf; + if(rd_name(&p, timezone.stname)) + goto error; + if(rd_long(&p, &timezone.stdiff)) + goto error; + if(rd_name(&p, timezone.dlname)) + goto error; + if(rd_long(&p, &timezone.dldiff)) + goto error; + for(i=0; i<TZSIZE; i++) { + if(rd_long(&p, &timezone.dlpairs[i])) + goto error; + if(timezone.dlpairs[i] == 0) + return; + } + +error: + timezone.stdiff = 0; + strcpy(timezone.stname, "GMT"); + timezone.dlpairs[0] = 0; +} + +static +rd_name(char **f, char *p) +{ + int c, i; + + for(;;) { + c = *(*f)++; + if(c != ' ' && c != '\n') + break; + } + for(i=0; i<3; i++) { + if(c == ' ' || c == '\n') + return 1; + *p++ = c; + c = *(*f)++; + } + if(c != ' ' && c != '\n') + return 1; + *p = 0; + return 0; +} + +static +rd_long(char **f, long *p) +{ + int c, s; + long l; + + s = 0; + for(;;) { + c = *(*f)++; + if(c == '-') { + s++; + continue; + } + if(c != ' ' && c != '\n') + break; + } + if(c == 0) { + *p = 0; + return 0; + } + l = 0; + for(;;) { + if(c == ' ' || c == '\n') + break; + if(c < '0' || c > '9') + return 1; + l = l*10 + c-'0'; + c = *(*f)++; + } + if(s) + l = -l; + *p = l; + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/cuserid.c b/sys/src/ape/lib/ap/plan9/cuserid.c new file mode 100755 index 000000000..bf78bb3d2 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/cuserid.c @@ -0,0 +1,21 @@ +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +/* + * BUG: supposed to be for effective uid, + * but plan9 doesn't have that concept + */ +char * +cuserid(char *s) +{ + char *logname; + static char buf[L_cuserid]; + + if((logname = getlogin()) == NULL) + return(NULL); + if(s == 0) + s = buf; + strncpy(s, logname, sizeof buf); + return(s); +} diff --git a/sys/src/ape/lib/ap/plan9/dir.h b/sys/src/ape/lib/ap/plan9/dir.h new file mode 100755 index 000000000..2af4f3e96 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/dir.h @@ -0,0 +1,80 @@ +typedef long long vlong; +typedef unsigned long long uvlong; +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +#define GBIT8(p) ((p)[0]) +#define GBIT16(p) ((p)[0]|((p)[1]<<8)) +#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) +#define GBIT64(p) ((vlong)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\ + ((vlong)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32)) + +#define PBIT8(p,v) (p)[0]=(v) +#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8 +#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24 +#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\ + (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56 + +#define BIT8SZ 1 +#define BIT16SZ 2 +#define BIT32SZ 4 +#define BIT64SZ 8 +#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ) + +/* STATFIXLEN includes leading 16-bit count */ +/* The count, however, excludes itself; total size is BIT16SZ+count */ +#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */ + +typedef union +{ + char clength[8]; + vlong vlength; + struct + { + long hlength; + long length; + }; +} Length; + +typedef +struct Qid +{ + uvlong path; + ulong vers; + uchar type; +} Qid; + +typedef +struct Dir { + /* system-modified data */ + ushort type; /* server type */ + uint dev; /* server subtype */ + /* file data */ + Qid qid; /* unique id from server */ + ulong mode; /* permissions */ + ulong atime; /* last read time */ + ulong mtime; /* last write time */ + vlong length; /* file length: see <u.h> */ + char *name; /* last element of path */ + char *uid; /* owner name */ + char *gid; /* group name */ + char *muid; /* last modifier name */ +} Dir; + +void _dirtostat(struct stat *, Dir*, Fdinfo*); +uint _convM2D(uchar*, uint, Dir*, char*); +uint _convD2M(Dir*, uchar*, uint); +Dir *_dirstat(char*); +int _dirwstat(char*, Dir*); +Dir *_dirfstat(int); +int _dirfwstat(int, Dir*); +long _dirread(int, Dir**); +long _dirreadall(int, Dir**); +void _nulldir(Dir*); +uint _sizeD2M(Dir*); + +#ifndef nil +#define nil ((void*)0) +#endif diff --git a/sys/src/ape/lib/ap/plan9/dirread.c b/sys/src/ape/lib/ap/plan9/dirread.c new file mode 100755 index 000000000..e03d32d77 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/dirread.c @@ -0,0 +1,119 @@ +#include "lib.h" +#include <string.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +static int +statcheck(uchar *buf, uint nbuf) +{ + uchar *ebuf; + int i; + + ebuf = buf + nbuf; + + buf += STATFIXLEN - 4 * BIT16SZ; + + for(i = 0; i < 4; i++){ + if(buf + BIT16SZ > ebuf) + return -1; + buf += BIT16SZ + GBIT16(buf); + } + + if(buf != ebuf) + return -1; + + return 0; +} + +static +long +dirpackage(uchar *buf, long ts, Dir **d) +{ + char *s; + long ss, i, n, nn, m; + + if(ts == 0){ + *d = nil; + return 0; + } + + /* + * first find number of all stats, check they look like stats, & size all associated strings + */ + ss = 0; + n = 0; + for(i = 0; i < ts; i += m){ + m = BIT16SZ + GBIT16(&buf[i]); + if(statcheck(&buf[i], m) < 0) + break; + ss += m; + n++; + } + + if(i != ts) + return -1; + + *d = malloc(n * sizeof(Dir) + ss); + if(*d == nil) + return -1; + + /* + * then convert all buffers + */ + s = (char*)*d + n * sizeof(Dir); + nn = 0; + for(i = 0; i < ts; i += m){ + m = BIT16SZ + GBIT16((uchar*)&buf[i]); + if(nn >= n || _convM2D(&buf[i], m, *d + nn, s) != m){ + free(*d); + return -1; + } + nn++; + s += m; + } + + return nn; +} + +long +_dirread(int fd, Dir **d) +{ + uchar *buf; + long ts; + + buf = malloc(DIRMAX); + if(buf == nil) + return -1; + ts = _READ(fd, buf, DIRMAX); + if(ts >= 0) + ts = dirpackage(buf, ts, d); + free(buf); + return ts; +} + +long +_dirreadall(int fd, Dir **d) +{ + uchar *buf, *nbuf; + long n, ts; + + buf = nil; + ts = 0; + for(;;){ + nbuf = realloc(buf, ts+DIRMAX); + if(nbuf == nil){ + free(buf); + return -1; + } + buf = nbuf; + n = _READ(fd, buf+ts, DIRMAX); + if(n <= 0) + break; + ts += n; + } + if(ts >= 0) + ts = dirpackage(buf, ts, d); + free(buf); + return ts; +} diff --git a/sys/src/ape/lib/ap/plan9/dirstat.c b/sys/src/ape/lib/ap/plan9/dirstat.c new file mode 100755 index 000000000..f054b4f6e --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/dirstat.c @@ -0,0 +1,107 @@ +#include "lib.h" +#include <string.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +enum +{ + DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */ +}; + +Dir* +_dirstat(char *name) +{ + Dir *d; + uchar *buf; + int n, nd, i; + + nd = DIRSIZE; + for(i=0; i<2; i++){ /* should work by the second try */ + d = malloc(sizeof(Dir) + BIT16SZ +nd); + if(d == nil) + return nil; + buf = (uchar*)&d[1]; + n = _STAT(name, buf, BIT16SZ+nd); + if(n < BIT16SZ){ + free(d); + return nil; + } + nd = GBIT16((uchar*)buf); /* size needed to store whole stat buffer */ + if(nd <= n){ + _convM2D(buf, n, d, (char*)&d[1]); + return d; + } + /* else sizeof(Dir)+BIT16SZ+nd is plenty */ + free(d); + } + return nil; +} + +int +_dirwstat(char *name, Dir *d) +{ + uchar *buf; + int r; + + r = _sizeD2M(d); + buf = malloc(r); + if(buf == nil) + return -1; + _convD2M(d, buf, r); + r = _WSTAT(name, buf, r); + free(buf); + return r; +} + +Dir* +_dirfstat(int fd) +{ + Dir *d; + uchar *buf; + int n, nd, i; + + nd = DIRSIZE; + for(i=0; i<2; i++){ /* should work by the second try */ + d = malloc(sizeof(Dir) + nd); + if(d == nil) + return nil; + buf = (uchar*)&d[1]; + n = _FSTAT(fd, buf, nd); + if(n < BIT16SZ){ + free(d); + return nil; + } + nd = GBIT16(buf); /* size needed to store whole stat buffer */ + if(nd <= n){ + _convM2D(buf, n, d, (char*)&d[1]); + return d; + } + /* else sizeof(Dir)+nd is plenty */ + free(d); + } + return nil; +} + +int +_dirfwstat(int fd, Dir *d) +{ + uchar *buf; + int r; + + r = _sizeD2M(d); + buf = malloc(r); + if(buf == nil) + return -1; + _convD2M(d, buf, r); + r = _FWSTAT(fd, buf, r); + free(buf); + return r; +} + +void +_nulldir(Dir *d) +{ + memset(d, ~0, sizeof(Dir)); + d->name = d->uid = d->gid = d->muid = ""; +} diff --git a/sys/src/ape/lib/ap/plan9/dirtostat.c b/sys/src/ape/lib/ap/plan9/dirtostat.c new file mode 100755 index 000000000..6abc6dfa7 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/dirtostat.c @@ -0,0 +1,52 @@ +#include "lib.h" +#include <sys/stat.h> +#include <errno.h> +#include "sys9.h" +#include "dir.h" + +/* fi is non-null if there is an fd associated with s */ +void +_dirtostat(struct stat *s, Dir *d, Fdinfo *fi) +{ + int num; + char *nam; + + s->st_dev = (d->type<<8)|(d->dev&0xFF); + s->st_ino = d->qid.path; + s->st_mode = d->mode&0777; + if(fi && (fi->flags&FD_ISTTY)) + s->st_mode |= S_IFCHR; + else if(d->mode & 0x80000000) + s->st_mode |= S_IFDIR; + else if(d->type == '|' || d->type == 's') + s->st_mode |= S_IFIFO; + else if(d->type != 'M') + s->st_mode |= S_IFCHR; + else + s->st_mode |= S_IFREG; + s->st_nlink = 1; + s->st_uid = 1; + s->st_gid = 1; + if(fi && (fi->flags&FD_BUFFERED)) + s->st_size = fi->buf->n; + else + s->st_size = d->length; + s->st_atime = d->atime; + s->st_mtime = d->mtime; + s->st_ctime = d->mtime; + if(fi && fi->uid != -2){ + s->st_uid = fi->uid; + s->st_gid = fi->gid; + } else { + nam = d->uid; + if(_getpw(&num, &nam, 0)) + s->st_uid = num; + nam = d->gid; + if(_getpw(&num, &nam, 0)) + s->st_gid = num; + if(fi){ + fi->uid = s->st_uid; + fi->gid = s->st_gid; + } + } +} diff --git a/sys/src/ape/lib/ap/plan9/dup.c b/sys/src/ape/lib/ap/plan9/dup.c new file mode 100755 index 000000000..37883be52 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/dup.c @@ -0,0 +1,24 @@ +#include "lib.h" +#include <unistd.h> +#include <errno.h> + +int +dup(int oldd) +{ + return fcntl(oldd, F_DUPFD, 0); +} + +int +dup2(int oldd, int newd) +{ + int n; + + if(newd < 0 || newd >= OPEN_MAX){ + errno = EBADF; + return -1; + } + if(oldd == newd && _fdinfo[newd].flags&FD_ISOPEN) + return newd; + close(newd); + return fcntl(oldd, F_DUPFD, newd); +} diff --git a/sys/src/ape/lib/ap/plan9/execl.c b/sys/src/ape/lib/ap/plan9/execl.c new file mode 100755 index 000000000..79ffa44c3 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/execl.c @@ -0,0 +1,9 @@ +#include <unistd.h> + +extern char **environ; + +int +execl(const char *name, const char *arg0, ...) +{ + return execve(name, &arg0, environ); +} diff --git a/sys/src/ape/lib/ap/plan9/execle.c b/sys/src/ape/lib/ap/plan9/execle.c new file mode 100755 index 000000000..f607c4914 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/execle.c @@ -0,0 +1,11 @@ +#include <unistd.h> + +int +execle(const char *name, const char *arg0, const char *aore, ...) +{ + char *p; + + for(p=(char *)(&name)+1; *p; ) + p++; + return execve(name, &arg0, (char **)p+1); +} diff --git a/sys/src/ape/lib/ap/plan9/execlp.c b/sys/src/ape/lib/ap/plan9/execlp.c new file mode 100755 index 000000000..ff5d71761 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/execlp.c @@ -0,0 +1,24 @@ +#include <unistd.h> +#include <string.h> +#include <sys/limits.h> + +/* + * BUG: instead of looking at PATH env variable, + * just try prepending /bin/ if name fails... + */ + +extern char **environ; + +int +execlp(const char *name, const char *arg0, ...) +{ + int n; + char buf[PATH_MAX]; + + if((n=execve(name, &arg0, environ)) < 0){ + strcpy(buf, "/bin/"); + strcpy(buf+5, name); + n = execve(buf, &name+1, environ); + } + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/execv.c b/sys/src/ape/lib/ap/plan9/execv.c new file mode 100755 index 000000000..409e96003 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/execv.c @@ -0,0 +1,9 @@ +#include <unistd.h> + +extern char **environ; + +int +execv(const char *name, const char *argv[]) +{ + return execve(name, argv, environ); +} diff --git a/sys/src/ape/lib/ap/plan9/execve.c b/sys/src/ape/lib/ap/plan9/execve.c new file mode 100755 index 000000000..1d5c3c2fe --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/execve.c @@ -0,0 +1,103 @@ +#include "lib.h" +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include "sys9.h" + +extern char **environ; + +int +execve(const char *name, const char *argv[], const char *envp[]) +{ + int n, f, i; + char **e, *ss, *se; + Fdinfo *fi; + unsigned long flags; + char nam[256+5]; + char buf[1000]; + + _RFORK(RFCENVG); + /* + * To pass _fdinfo[] across exec, put lines like + * fd flags oflags + * in $_fdinfo (for open fd's) + */ + + f = _CREATE("#e/_fdinfo", OWRITE, 0666); + ss = buf; + for(n = 0; n<OPEN_MAX; n++){ + fi = &_fdinfo[n]; + flags = fi->flags; + if(flags&FD_CLOEXEC){ + _CLOSE(n); + fi->flags = 0; + fi->oflags = 0; + }else if(flags&FD_ISOPEN){ + ss = _ultoa(ss, n); + *ss++ = ' '; + ss = _ultoa(ss, flags); + *ss++ = ' '; + ss = _ultoa(ss, fi->oflags); + *ss++ = '\n'; + if(ss-buf < sizeof(buf)-50){ + _WRITE(f, buf, ss-buf); + ss = buf; + } + } + } + if(ss > buf) + _WRITE(f, buf, ss-buf); + _CLOSE(f); + /* + * To pass _sighdlr[] across exec, set $_sighdlr + * to list of blank separated fd's that have + * SIG_IGN (the rest will be SIG_DFL). + * We write the variable, even if no signals + * are ignored, in case the current value of the + * variable ignored some. + */ + f = _CREATE("#e/_sighdlr", OWRITE, 0666); + if(f >= 0){ + ss = buf; + for(i = 0, n=0; i <=MAXSIG && ss < &buf[sizeof(buf)]-5; i++) { + if(_sighdlr[i] == SIG_IGN) { + ss = _ultoa(ss, i); + *ss++ = ' '; + } + } + _WRITE(f, buf, ss-buf); + _CLOSE(f); + } + if(envp){ + strcpy(nam, "#e/"); + for(e = envp; (ss = *e); e++) { + se = strchr(ss, '='); + if(!se || ss==se) + continue; /* what is name? value? */ + n = se-ss; + if(n >= sizeof(nam)-3) + n = sizeof(nam)-3-1; + memcpy(nam+3, ss, n); + nam[3+n] = 0; + f = _CREATE(nam, OWRITE, 0666); + if(f < 0) + continue; + se++; /* past = */ + n = strlen(se); + /* temporarily decode nulls (see _envsetup()) */ + for(i=0; i < n; i++) + if(se[i] == 1) + se[i] = 0; + _WRITE(f, se, n); + /* put nulls back */ + for(i=0; i < n; i++) + if(se[i] == 0) + se[i] = 1; + _CLOSE(f); + } + } + n = _EXEC(name, argv); + _syserrno(); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/execvp.c b/sys/src/ape/lib/ap/plan9/execvp.c new file mode 100755 index 000000000..f2ed53d1d --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/execvp.c @@ -0,0 +1,24 @@ +#include <unistd.h> +#include <sys/limits.h> +#include <string.h> + +extern char **environ; + +/* + * BUG: instead of looking at PATH env variable, + * just try prepending /bin/ if name fails... + */ + +int +execvp(const char *name, const char **argv) +{ + int n; + char buf[PATH_MAX]; + + if((n=execve(name, argv, environ)) < 0){ + strcpy(buf, "/bin/"); + strcpy(buf+5, name); + n = execve(buf, argv, environ); + } + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/fcall.h b/sys/src/ape/lib/ap/plan9/fcall.h new file mode 100755 index 000000000..8090a19a4 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/fcall.h @@ -0,0 +1,118 @@ +typedef struct Fcall Fcall; + +/* see /sys/include/auth.h */ +enum +{ + DOMLEN= 48, /* length of an authentication domain name */ + DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */ + CHALLEN= 8, /* length of a challenge */ + NETCHLEN= 16, /* max network challenge length */ + CONFIGLEN= 14, + + KEYDBLEN= NAMELEN+DESKEYLEN+4+2 +}; +#define TICKETLEN (CHALLEN+2*NAMELEN+DESKEYLEN+1) +#define AUTHENTLEN (CHALLEN+4+1) + +struct Fcall +{ + char type; + short fid; + unsigned short tag; + union + { + struct + { + unsigned short oldtag; /* T-Flush */ + Qid qid; /* R-Attach, R-Walk, R-Open, R-Create */ + char rauth[AUTHENTLEN]; /* Rattach */ + }; + struct + { + char uname[NAMELEN]; /* T-Attach */ + char aname[NAMELEN]; /* T-Attach */ + char ticket[TICKETLEN]; /* T-Attach */ + char auth[AUTHENTLEN];/* T-Attach */ + }; + struct + { + char ename[ERRLEN]; /* R-Error */ + char authid[NAMELEN]; /* R-session */ + char authdom[DOMLEN]; /* R-session */ + char chal[CHALLEN]; /* T-session/R-session */ + }; + struct + { + long perm; /* T-Create */ + short newfid; /* T-Clone, T-Clwalk */ + char name[NAMELEN]; /* T-Walk, T-Clwalk, T-Create */ + char mode; /* T-Create, T-Open */ + }; + struct + { + long offset; /* T-Read, T-Write */ + long count; /* T-Read, T-Write, R-Read */ + char *data; /* T-Write, R-Read */ + }; + struct + { + char stat[DIRLEN]; /* T-Wstat, R-Stat */ + }; + }; +}; + +#define MAXFDATA 8192 +#define MAXMSG 160 /* max header sans data */ +#define NOTAG 0xFFFF /* Dummy tag */ + +enum +{ + Tmux = 48, + Rmux, /* illegal */ + Tnop = 50, + Rnop, + Tosession = 52, /* illegal */ + Rosession, /* illegal */ + Terror = 54, /* illegal */ + Rerror, + Tflush = 56, + Rflush, + Toattach = 58, /* illegal */ + Roattach, /* illegal */ + Tclone = 60, + Rclone, + Twalk = 62, + Rwalk, + Topen = 64, + Ropen, + Tcreate = 66, + Rcreate, + Tread = 68, + Rread, + Twrite = 70, + Rwrite, + Tclunk = 72, + Rclunk, + Tremove = 74, + Rremove, + Tstat = 76, + Rstat, + Twstat = 78, + Rwstat, + Tclwalk = 80, + Rclwalk, + Tauth = 82, /* illegal */ + Rauth, /* illegal */ + Tsession = 84, + Rsession, + Tattach = 86, + Rattach, +}; + +int convM2S(char*, Fcall*, int); +int convS2M(Fcall*, char*); + +int convM2D(char*, Dir*); +int convD2M(Dir*, char*); + +char* getS(int, char*, Fcall*, long*); diff --git a/sys/src/ape/lib/ap/plan9/fcntl.c b/sys/src/ape/lib/ap/plan9/fcntl.c new file mode 100755 index 000000000..053e38ec3 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/fcntl.c @@ -0,0 +1,81 @@ +#include "lib.h" +#include <unistd.h> +#include <errno.h> +#include <stdarg.h> +#include "sys9.h" + +/* + * BUG: advisory locking not implemented + */ + +#define OFL (O_ACCMODE|O_NONBLOCK|O_APPEND) + +int +fcntl(int fd, int cmd, ...) +{ + int arg, i, ans, err; + Fdinfo *fi, *fans; + va_list va; + unsigned long oflags; + + err = 0; + ans = 0; + va_start(va, cmd); + arg = va_arg(va, int); + va_end(va); + fi = &_fdinfo[fd]; + if(fd<0 || fd>=OPEN_MAX || !(fi->flags&FD_ISOPEN)) + err = EBADF; + else switch(cmd){ + case F_DUPFD: + if(fi->flags&(FD_BUFFERED|FD_BUFFEREDX)){ + err = EGREG; /* dup of buffered fd not implemented */ + break; + } + oflags = fi->oflags; + for(i = (arg>0)? arg : 0; i<OPEN_MAX; i++) + if(!(_fdinfo[i].flags&FD_ISOPEN)) + break; + if(i == OPEN_MAX) + err = EMFILE; + else { + ans = _DUP(fd, i); + if(ans != i){ + if(ans < 0){ + _syserrno(); + err = errno; + }else + err = EBADF; + }else{ + fans = &_fdinfo[ans]; + fans->flags = fi->flags&~FD_CLOEXEC; + fans->oflags = oflags; + fans->uid = fi->uid; + fans->gid = fi->gid; + } + } + break; + case F_GETFD: + ans = fi->flags&FD_CLOEXEC; + break; + case F_SETFD: + fi->flags = (fi->flags&~FD_CLOEXEC)|(arg&FD_CLOEXEC); + break; + case F_GETFL: + ans = fi->oflags&OFL; + break; + case F_SETFL: + fi->oflags = (fi->oflags&~OFL)|(arg&OFL); + break; + case F_GETLK: + case F_SETLK: + case F_SETLKW: + err = EINVAL; + break; + } + if(err){ + errno = err; + ans = -1; + } + return ans; +} diff --git a/sys/src/ape/lib/ap/plan9/fork.c b/sys/src/ape/lib/ap/plan9/fork.c new file mode 100755 index 000000000..8137bc688 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/fork.c @@ -0,0 +1,19 @@ +#include "lib.h" +#include <errno.h> +#include <unistd.h> +#include "sys9.h" + +pid_t +fork(void) +{ + int n; + + n = _RFORK(RFENVG|RFFDG|RFPROC); + if(n < 0) + _syserrno(); + if(n == 0) { + _detachbuf(); + _sessleader = 0; + } + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/frexp.c b/sys/src/ape/lib/ap/plan9/frexp.c new file mode 100755 index 000000000..588f90cee --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/frexp.c @@ -0,0 +1,89 @@ +#include <math.h> +#include <errno.h> +#define _RESEARCH_SOURCE +#include <float.h> + +#define MASK 0x7ffL +#define SHIFT 20 +#define BIAS 1022L + +typedef union +{ + double d; + struct + { +#ifdef IEEE_8087 + long ls; + long ms; +#else + long ms; + long ls; +#endif + }; +} Cheat; + +double +frexp(double d, int *ep) +{ + Cheat x; + + if(d == 0) { + *ep = 0; + return 0; + } + x.d = d; + *ep = ((x.ms >> SHIFT) & MASK) - BIAS; + x.ms &= ~(MASK << SHIFT); + x.ms |= BIAS << SHIFT; + return x.d; +} + +double +ldexp(double d, int e) +{ + Cheat x; + + if(d == 0) + return 0; + x.d = d; + e += (x.ms >> SHIFT) & MASK; + if(e <= 0) + return 0; + if(e >= MASK){ + errno = ERANGE; + if(d < 0) + return -HUGE_VAL; + return HUGE_VAL; + } + x.ms &= ~(MASK << SHIFT); + x.ms |= (long)e << SHIFT; + return x.d; +} + +double +modf(double d, double *ip) +{ + double f; + Cheat x; + int e; + + if(d < 1) { + if(d < 0) { + f = modf(-d, ip); + *ip = -*ip; + return -f; + } + *ip = 0; + return d; + } + x.d = d; + e = ((x.ms >> SHIFT) & MASK) - BIAS; + if(e <= SHIFT+1) { + x.ms &= ~(0x1fffffL >> e); + x.ls = 0; + } else + if(e <= SHIFT+33) + x.ls &= ~(0x7fffffffL >> (e-SHIFT-2)); + *ip = x.d; + return d - x.d; +} diff --git a/sys/src/ape/lib/ap/plan9/fstat.c b/sys/src/ape/lib/ap/plan9/fstat.c new file mode 100755 index 000000000..62e6c653a --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/fstat.c @@ -0,0 +1,20 @@ +#include "lib.h" +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +int +fstat(int fd, struct stat *buf) +{ + Dir *d; + + if((d = _dirfstat(fd)) == nil){ + _syserrno(); + return -1; + } + _dirtostat(buf, d, &_fdinfo[fd]); + free(d); + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/fsync.c b/sys/src/ape/lib/ap/plan9/fsync.c new file mode 100755 index 000000000..f37d35c04 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/fsync.c @@ -0,0 +1,10 @@ +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +int +fsync(int fd) +{ + errno = EINVAL; + return -1; +} diff --git a/sys/src/ape/lib/ap/plan9/ftruncate.c b/sys/src/ape/lib/ap/plan9/ftruncate.c new file mode 100755 index 000000000..aa867488c --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/ftruncate.c @@ -0,0 +1,23 @@ +#include "lib.h" +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include "dir.h" + +int +ftruncate(int fd, off_t length) +{ + Dir d; + + if(length < 0){ + errno = EINVAL; + return -1; + } + _nulldir(&d); + d.length = length; + if(_dirfwstat(fd, &d) < 0){ + _syserrno(); + return -1; + } + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/getcwd.c b/sys/src/ape/lib/ap/plan9/getcwd.c new file mode 100755 index 000000000..db6936b56 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getcwd.c @@ -0,0 +1,32 @@ +#include "lib.h" +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include "sys9.h" +#include "dir.h" + +char* +getcwd(char *buf, size_t len) +{ + int fd; + + fd = _OPEN(".", OREAD); + if(fd < 0) { + errno = EACCES; + return 0; + } + if(_FD2PATH(fd, buf, len) < 0) { + errno = EIO; + _CLOSE(fd); + return 0; + } + _CLOSE(fd); + +/* RSC: is this necessary? */ + if(buf[0] == '\0') + strcpy(buf, "/"); + return buf; +} diff --git a/sys/src/ape/lib/ap/plan9/getgid.c b/sys/src/ape/lib/ap/plan9/getgid.c new file mode 100755 index 000000000..e1f5fc39b --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getgid.c @@ -0,0 +1,21 @@ +#include <sys/types.h> +#include <grp.h> +#include <unistd.h> + +/* + * BUG: assumes group that is same as user name + * is the one wanted (plan 9 has no "current group") + */ +gid_t +getgid(void) +{ + struct group *g; + g = getgrnam(getlogin()); + return g? g->gr_gid : 1; +} + +gid_t +getegid(void) +{ + return getgid(); +} diff --git a/sys/src/ape/lib/ap/plan9/getgrgid.c b/sys/src/ape/lib/ap/plan9/getgrgid.c new file mode 100755 index 000000000..77e2997fa --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getgrgid.c @@ -0,0 +1,25 @@ +#include <stddef.h> +#include <grp.h> + +extern int _getpw(int *, char **, char **); +extern char **_grpmems(char *); + +static struct group holdgroup; + +struct group * +getgrgid(gid_t gid) +{ + int num; + char *nam, *mem; + + num = gid; + nam = 0; + mem = 0; + if(_getpw(&num, &nam, &mem)){ + holdgroup.gr_name = nam; + holdgroup.gr_gid = num; + holdgroup.gr_mem = _grpmems(mem); + return &holdgroup; + } + return NULL; +} diff --git a/sys/src/ape/lib/ap/plan9/getgrnam.c b/sys/src/ape/lib/ap/plan9/getgrnam.c new file mode 100755 index 000000000..7033120e4 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getgrnam.c @@ -0,0 +1,25 @@ +#include <stddef.h> +#include <grp.h> + +extern int _getpw(int *, char **, char **); +extern char **_grpmems(char *); + +static struct group holdgroup; + +struct group * +getgrnam(const char *name) +{ + int num; + char *nam, *mem; + + num = 0; + nam = name; + mem = 0; + if(_getpw(&num, &nam, &mem)){ + holdgroup.gr_name = nam; + holdgroup.gr_gid = num; + holdgroup.gr_mem = _grpmems(mem); + return &holdgroup; + } + return NULL; +} diff --git a/sys/src/ape/lib/ap/plan9/getgroups.c b/sys/src/ape/lib/ap/plan9/getgroups.c new file mode 100755 index 000000000..e226a65b4 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getgroups.c @@ -0,0 +1,10 @@ +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +int +getgroups(int gidsize, gid_t grouplist[]) +{ + errno = EINVAL; + return -1; +} diff --git a/sys/src/ape/lib/ap/plan9/getlogin.c b/sys/src/ape/lib/ap/plan9/getlogin.c new file mode 100755 index 000000000..8d2d51ce0 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getlogin.c @@ -0,0 +1,27 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/limits.h> + +char * +getlogin_r(char *buf, int len) +{ + int f, n; + + f = open("/dev/user", O_RDONLY); + if(f < 0) + return 0; + n = read(f, buf, len); + buf[len-1] = 0; + close(f); + return (n>=0)? buf : 0; +} + +char * +getlogin(void) +{ + static char buf[NAME_MAX+1]; + + return getlogin_r(buf, sizeof buf); +} diff --git a/sys/src/ape/lib/ap/plan9/getpgrp.c b/sys/src/ape/lib/ap/plan9/getpgrp.c new file mode 100755 index 000000000..310028784 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getpgrp.c @@ -0,0 +1,27 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include "sys9.h" +#include "lib.h" + +pid_t +getpgrp(void) +{ + int n, f, pid; + char pgrpbuf[15], fname[30]; + + pid = getpid(); + sprintf(fname, "/proc/%d/noteid", pid); + f = open(fname, 0); + n = read(f, pgrpbuf, sizeof pgrpbuf); + if(n < 0) + _syserrno(); + else + n = atoi(pgrpbuf); + close(f); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/getpid.c b/sys/src/ape/lib/ap/plan9/getpid.c new file mode 100755 index 000000000..66eaaae8d --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getpid.c @@ -0,0 +1,22 @@ +#include "lib.h" +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "sys9.h" + +pid_t +getpid(void) +{ + int n, f; + char pidbuf[15]; + + f = _OPEN("#c/pid", 0); + n = _READ(f, pidbuf, sizeof pidbuf); + if(n < 0) + _syserrno(); + else + n = atoi(pidbuf); + _CLOSE(f); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/getppid.c b/sys/src/ape/lib/ap/plan9/getppid.c new file mode 100755 index 000000000..01759221b --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getppid.c @@ -0,0 +1,23 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "sys9.h" + +pid_t +getppid(void) +{ + int n, f; + char ppidbuf[15]; + + f = open("#c/ppid", 0); + n = read(f, ppidbuf, sizeof ppidbuf); + if(n < 0) + errno = EINVAL; + else + n = atoi(ppidbuf); + close(f); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/getpwnam.c b/sys/src/ape/lib/ap/plan9/getpwnam.c new file mode 100755 index 000000000..e9d1c5b4e --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getpwnam.c @@ -0,0 +1,29 @@ +#include "lib.h" +#include <stddef.h> +#include <pwd.h> +#include <string.h> + +static struct passwd holdpw; +static char dirbuf[40] = "/usr/"; +static char *rc = "/bin/rc"; + +struct passwd * +getpwnam(const char *name) +{ + int num; + char *nam, *mem; + + num = 0; + nam = name; + mem = 0; + if(_getpw(&num, &nam, &mem)){ + holdpw.pw_name = nam; + holdpw.pw_uid = num; + holdpw.pw_gid = num; + strncpy(dirbuf+5, nam, sizeof(dirbuf)-6); + holdpw.pw_dir = dirbuf; + holdpw.pw_shell = rc; + return &holdpw; + } + return NULL; +} diff --git a/sys/src/ape/lib/ap/plan9/getpwuid.c b/sys/src/ape/lib/ap/plan9/getpwuid.c new file mode 100755 index 000000000..e2983765b --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getpwuid.c @@ -0,0 +1,30 @@ +#include <stddef.h> +#include <pwd.h> +#include <string.h> + +extern int _getpw(int *, char **, char **); + +static struct passwd holdpw; +static char dirbuf[40] = "/usr/"; +static char *rc = "/bin/rc"; + +struct passwd * +getpwuid(uid_t uid) +{ + int num; + char *nam, *mem; + + num = uid; + nam = 0; + mem = 0; + if(_getpw(&num, &nam, &mem)){ + holdpw.pw_name = nam; + holdpw.pw_uid = num; + holdpw.pw_gid = num; + strncpy(dirbuf+5, nam, sizeof(dirbuf)-6); + holdpw.pw_dir = dirbuf; + holdpw.pw_shell = rc; + return &holdpw; + } + return NULL; +} diff --git a/sys/src/ape/lib/ap/plan9/getuid.c b/sys/src/ape/lib/ap/plan9/getuid.c new file mode 100755 index 000000000..05d4c0832 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/getuid.c @@ -0,0 +1,17 @@ +#include <sys/types.h> +#include <pwd.h> +#include <unistd.h> + +uid_t +getuid(void) +{ + struct passwd *p; + p = getpwnam(getlogin()); + return p? p->pw_uid : 1; +} + +uid_t +geteuid(void) +{ + return getuid(); +} diff --git a/sys/src/ape/lib/ap/plan9/isatty.c b/sys/src/ape/lib/ap/plan9/isatty.c new file mode 100755 index 000000000..e04cd891d --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/isatty.c @@ -0,0 +1,29 @@ +#include "lib.h" +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "sys9.h" +#include "dir.h" + +int +_isatty(int fd) +{ + int t; + char buf[64]; + + if(_FD2PATH(fd, buf, sizeof buf) < 0) + return 0; + + /* might be /mnt/term/dev/cons */ + return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0; +} + +/* The FD_ISTTY flag is set via _isatty in _fdsetup or open */ +int +isatty(fd) +{ + if(_fdinfo[fd].flags&FD_ISTTY) + return 1; + else + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/kill.c b/sys/src/ape/lib/ap/plan9/kill.c new file mode 100755 index 000000000..95bbbdcc7 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/kill.c @@ -0,0 +1,60 @@ +#include "lib.h" +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +static int +note(int pid, char *msg, char *fmt) +{ + int f; + char pname[50]; + + sprintf(pname, fmt, pid); + f = open(pname, O_WRONLY); + if(f < 0){ + errno = ESRCH; + return -1; + } + if(msg != 0 && write(f, msg, strlen(msg)) < 0){ + close(f); + errno = EPERM; + return -1; + } + close(f); + return 0; +} + +int +kill(pid_t pid, int sig) +{ + char *msg; + int sid, r, mpid; + + if(sig == 0) + msg = 0; + else { + msg = _sigstring(sig); + if(msg == 0) { + errno = EINVAL; + return -1; + } + } + + if(pid < 0) { + sid = getpgrp(); + mpid = getpid(); + if(setpgid(mpid, -pid) == 0) { + r = note(mpid, msg, "/proc/%d/notepg"); + setpgid(mpid, sid); + } else { + r = -1; + } + } else if(pid == 0) + r = note(getpid(), msg, "/proc/%d/notepg"); + else + r = note(pid, msg, "/proc/%d/note"); + return r; +} diff --git a/sys/src/ape/lib/ap/plan9/lib.h b/sys/src/ape/lib/ap/plan9/lib.h new file mode 100755 index 000000000..91a51d5d3 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/lib.h @@ -0,0 +1,72 @@ +#include <sys/types.h> +#include <sys/limits.h> +#include <fcntl.h> +#include <ureg.h> + +typedef struct Ureg Ureg; + +/* mux buf for selecting (see _buf.c) */ +enum { + READMAX = 8192, /* read at most this much with _READ */ + PERFDMAX = 2*READMAX, /* stop _READing an fd when it has this much */ + INITBUFS = 4, /* allow enough room for this many PERFDMAX */ +}; + +typedef struct Muxbuf { + int n; /* # unprocessed chars in buf */ + unsigned char* putnext; /* place for copy process to put next data */ + unsigned char* getnext; /* place for parent process to get next data */ + char fd; /* fd for which this is a buffer */ + unsigned char eof; /* true if eof after current data exhausted */ + unsigned char roomwait; /* true if copy process is waiting for room */ + unsigned char datawait; /* true if parent process is waiting for data */ + int copypid; /* pid of copyproc */ + unsigned char data[PERFDMAX]; +} Muxbuf; + +/* be sure to change _fdinfo[] init in _fdinfo if you change this */ +typedef struct Fdinfo{ + unsigned long flags; + unsigned long oflags; + uid_t uid; + gid_t gid; + char *name; + /* + * the following is used if flags&FD_BUFFERED + */ + Muxbuf *buf; /* holds buffered data and state */ +} Fdinfo; + +/* #define FD_CLOEXEC 1 is in fcntl.h */ + +#define FD_ISOPEN 0x2 +#define FD_BUFFERED 0x4 +#define FD_BUFFEREDX 0x8 +#define FD_ISTTY 0x20 + +#define MAXSIG SIGUSR2 + +extern Fdinfo _fdinfo[]; + +extern int _finishing; +extern int _sessleader; +extern void (*_sighdlr[])(int, char*, Ureg*); +extern char *_sigstring(int); +extern int _stringsig(char *); +extern long _psigblocked; +extern int _startbuf(int); +extern int _selbuf(int); +extern void _closebuf(int); +extern int _readbuf(int, void*, int, int); +extern void _detachbuf(void); +extern void _finish(int, char *); +extern char *_ultoa(char *, unsigned long); +extern int _notehandler(void *, char *); +extern void _notetramp(int, void (*)(int, char*, Ureg*), Ureg*); +extern void _syserrno(void); +extern int _getpw(int *, char **, char **); +extern int _isatty(int); +extern void _fdinit(char*, char*); + + +void checkbug(char *, int); diff --git a/sys/src/ape/lib/ap/plan9/link.c b/sys/src/ape/lib/ap/plan9/link.c new file mode 100755 index 000000000..9bf3755fb --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/link.c @@ -0,0 +1,12 @@ +#include <unistd.h> +#include <errno.h> + +/* + * BUG: LINK_MAX==1 isn't really allowed + */ +int +link(const char *name1, const char *name2) +{ + errno = EMLINK; + return -1; +} diff --git a/sys/src/ape/lib/ap/plan9/lseek.c b/sys/src/ape/lib/ap/plan9/lseek.c new file mode 100755 index 000000000..8c4eba39d --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/lseek.c @@ -0,0 +1,24 @@ +#include "lib.h" +#include <unistd.h> +#include <errno.h> +#include "sys9.h" + +/* + * BUG: errno mapping + */ +off_t +lseek(int d, off_t offset, int whence) +{ + long long n; + int flags; + + flags = _fdinfo[d].flags; + if(flags&(FD_BUFFERED|FD_BUFFEREDX|FD_ISTTY)) { + errno = ESPIPE; + return -1; + } + n = _SEEK(d, offset, whence); + if(n < 0) + _syserrno(); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/malloc.c b/sys/src/ape/lib/ap/plan9/malloc.c new file mode 100755 index 000000000..09f3c178e --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/malloc.c @@ -0,0 +1,142 @@ +#include <stdlib.h> +#include <string.h> + +typedef unsigned int uint; + +enum +{ + MAGIC = 0xbada110c, + MAX2SIZE = 32, + CUTOFF = 12, +}; + +typedef struct Bucket Bucket; +struct Bucket +{ + int size; + int magic; + Bucket *next; + int pad; + char data[1]; +}; + +typedef struct Arena Arena; +struct Arena +{ + Bucket *btab[MAX2SIZE]; +}; +static Arena arena; + +#define datoff ((int)((Bucket*)0)->data) +#define nil ((void*)0) + +extern void *sbrk(unsigned long); + +void* +malloc(size_t size) +{ + uint next; + int pow, n; + Bucket *bp, *nbp; + + for(pow = 1; pow < MAX2SIZE; pow++) { + if(size <= (1<<pow)) + goto good; + } + + return nil; +good: + /* Allocate off this list */ + bp = arena.btab[pow]; + if(bp) { + arena.btab[pow] = bp->next; + + if(bp->magic != 0) + abort(); + + bp->magic = MAGIC; + return bp->data; + } + size = sizeof(Bucket)+(1<<pow); + size += 7; + size &= ~7; + + if(pow < CUTOFF) { + n = (CUTOFF-pow)+2; + bp = sbrk(size*n); + if((int)bp < 0) + return nil; + + next = (uint)bp+size; + nbp = (Bucket*)next; + arena.btab[pow] = nbp; + for(n -= 2; n; n--) { + next = (uint)nbp+size; + nbp->next = (Bucket*)next; + nbp->size = pow; + nbp = nbp->next; + } + nbp->size = pow; + } + else { + bp = sbrk(size); + if((int)bp < 0) + return nil; + } + + bp->size = pow; + bp->magic = MAGIC; + + return bp->data; +} + +void +free(void *ptr) +{ + Bucket *bp, **l; + + if(ptr == nil) + return; + + /* Find the start of the structure */ + bp = (Bucket*)((uint)ptr - datoff); + + if(bp->magic != MAGIC) + abort(); + + bp->magic = 0; + l = &arena.btab[bp->size]; + bp->next = *l; + *l = bp; +} + +void* +realloc(void *ptr, size_t n) +{ + void *new; + uint osize; + Bucket *bp; + + if(ptr == nil) + return malloc(n); + + /* Find the start of the structure */ + bp = (Bucket*)((uint)ptr - datoff); + + if(bp->magic != MAGIC) + abort(); + + /* enough space in this bucket */ + osize = 1<<bp->size; + if(osize >= n) + return ptr; + + new = malloc(n); + if(new == nil) + return nil; + + memmove(new, ptr, osize); + free(ptr); + + return new; +} diff --git a/sys/src/ape/lib/ap/plan9/mkdir.c b/sys/src/ape/lib/ap/plan9/mkdir.c new file mode 100755 index 000000000..1773150b5 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/mkdir.c @@ -0,0 +1,27 @@ +#include "lib.h" +#include <sys/stat.h> +#include <errno.h> +#include "sys9.h" + +/* + * BUG: errno mapping + */ +int +mkdir(const char *name, mode_t mode) +{ + int n; + struct stat st; + + if(stat(name, &st)==0) { + errno = EEXIST; + return -1; + } + n = _CREATE(name, 0, 0x80000000|(mode&0777)); + if(n < 0) + _syserrno(); + else{ + _CLOSE(n); + n = 0; + } + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/mkfile b/sys/src/ape/lib/ap/plan9/mkfile new file mode 100755 index 000000000..502d00f8b --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/mkfile @@ -0,0 +1,110 @@ +APE=/sys/src/ape +<$APE/config +LIB=/$objtype/lib/ape/libap.a +OFILES=\ + _buf.$O\ + _dirconv.$O\ + _envsetup.$O\ + _errno.$O\ + _exit.$O\ + _fdinfo.$O\ + _getpw.$O\ + _nap.$O\ + 9mallocz.$O\ + 9iounit.$O\ + 9read.$O\ + 9readn.$O\ + 9wait.$O\ + 9write.$O\ + access.$O\ + alarm.$O\ + brk.$O\ + cfgetospeed.$O\ + chdir.$O\ + chmod.$O\ + chown.$O\ + close.$O\ + convM2D.$O\ + convD2M.$O\ + creat.$O\ + ctermid.$O\ + ctime.$O\ + cuserid.$O\ + dirread.$O\ + dirstat.$O\ + dirtostat.$O\ + dup.$O\ + execl.$O\ + execle.$O\ + execlp.$O\ + execv.$O\ + execve.$O\ + execvp.$O\ + fcntl.$O\ + fork.$O\ + frexp.$O\ + fstat.$O\ + fsync.$O\ + ftruncate.$O\ + getcwd.$O\ + getgid.$O\ + getgrgid.$O\ + getgrnam.$O\ + getgroups.$O\ + getlogin.$O\ + getpgrp.$O\ + getpid.$O\ + getppid.$O\ + getpwnam.$O\ + getpwuid.$O\ + getuid.$O\ + isatty.$O\ + kill.$O\ + link.$O\ + lseek.$O\ + malloc.$O\ + mkdir.$O\ + nan.$O\ + open.$O\ + opendir.$O\ + pause.$O\ + pipe.$O\ + profile.$O\ + qlock.$O\ + read.$O\ + rename.$O\ + rmdir.$O\ + setgid.$O\ + setpgid.$O\ + setsid.$O\ + setuid.$O\ + signal.$O\ + sigpending.$O\ + sigprocmask.$O\ + sigsuspend.$O\ + sleep.$O\ + sqrt.$O\ + stat.$O\ + system.$O\ + tcgetattr.$O\ + time.$O\ + times.$O\ + tmpfile.$O\ + ttyname.$O\ + umask.$O\ + uname.$O\ + unlink.$O\ + utime.$O\ + wait.$O\ + write.$O\ + +UPDATE=\ + mkfile\ + /386/lib/ape/libap.a\ + ${OFILES:%.$O=%.c}\ + +</sys/src/cmd/mksyslib + +CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE -D_BSD_EXTENSION + +$OFILES: lib.h diff --git a/sys/src/ape/lib/ap/plan9/nan.c b/sys/src/ape/lib/ap/plan9/nan.c new file mode 100755 index 000000000..db7c13fe8 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/nan.c @@ -0,0 +1,54 @@ +#include <float.h> +#include <math.h> + +#define NANEXP (2047<<20) +#define NANMASK (2047<<20) +#define NANSIGN (1<<31) + +double +NaN(void) +{ + FPdbleword a; + + a.hi = NANEXP; + a.lo = 1; + return a.x; +} + +int +isNaN(double d) +{ + FPdbleword a; + + a.x = d; + if((a.hi & NANMASK) != NANEXP) + return 0; + return !isInf(d, 0); +} + +double +Inf(int sign) +{ + FPdbleword a; + + a.hi = NANEXP; + a.lo = 0; + if(sign < 0) + a.hi |= NANSIGN; + return a.x; +} + +int +isInf(double d, int sign) +{ + FPdbleword a; + + a.x = d; + if(a.lo != 0) + return 0; + if(a.hi == NANEXP) + return sign >= 0; + if(a.hi == (NANEXP|NANSIGN)) + return sign <= 0; + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/open.c b/sys/src/ape/lib/ap/plan9/open.c new file mode 100755 index 000000000..1cfe0d6b5 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/open.c @@ -0,0 +1,62 @@ +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include "lib.h" +#include <sys/stat.h> +#include "sys9.h" + +/* + * O_NOCTTY has no effect + */ +int +open(const char *path, int flags, ...) +{ + int n; + long f; + int mode; + Fdinfo *fi; + va_list va; + struct stat sbuf; + + f = flags&O_ACCMODE; + if(flags&O_CREAT){ + if(access(path, 0) >= 0){ + if(flags&O_EXCL){ + errno = EEXIST; + return -1; + }else{ + if((flags&O_TRUNC)&&(flags&(O_RDWR|O_WRONLY))) + f |= 16; + n = _OPEN(path, f); + } + }else{ + va_start(va, flags); + mode = va_arg(va, int); + va_end(va); + n = _CREATE(path, f, mode&0777); + } + if(n < 0) + _syserrno(); + }else{ + if((flags&O_TRUNC)&&(flags&(O_RDWR|O_WRONLY))) + f |= 16; + n = _OPEN(path, f); + if(n < 0) + _syserrno(); + } + if(n >= 0){ + fi = &_fdinfo[n]; + fi->flags = FD_ISOPEN; + fi->oflags = flags&(O_ACCMODE|O_NONBLOCK|O_APPEND); + fi->uid = -2; + fi->gid = -2; + fi->name = malloc(strlen(path)+1); + if(fi->name) + strcpy(fi->name, path); + if(fi->oflags&O_APPEND) + _SEEK(n, 0, 2); + } + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/opendir.c b/sys/src/ape/lib/ap/plan9/opendir.c new file mode 100755 index 000000000..ebc22dbf6 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/opendir.c @@ -0,0 +1,121 @@ +#include "lib.h" +#include <stdlib.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include "sys9.h" +#include "dir.h" + +#define DBLOCKSIZE 20 + +DIR * +opendir(const char *filename) +{ + int f; + DIR *d; + struct stat sb; + Dir *d9; + + if((d9 = _dirstat(filename)) == nil){ + _syserrno(); + return NULL; + } + _dirtostat(&sb, d9, 0); + free(d9); + if(S_ISDIR(sb.st_mode) == 0) { + errno = ENOTDIR; + return NULL; + } + + f = open(filename, O_RDONLY); + if(f < 0){ + _syserrno(); + return NULL; + } + _fdinfo[f].flags |= FD_CLOEXEC; + d = (DIR *)malloc(sizeof(DIR) + DBLOCKSIZE*sizeof(struct dirent)); + if(!d){ + errno = ENOMEM; + return NULL; + } + d->dd_buf = (char *)d + sizeof(DIR); + d->dd_fd = f; + d->dd_loc = 0; + d->dd_size = 0; + d->dirs = nil; + d->dirsize = 0; + d->dirloc = 0; + return d; +} + +int +closedir(DIR *d) +{ + if(!d){ + errno = EBADF; + return -1; + } + if(close(d->dd_fd) < 0) + return -1; + free(d->dirs); + free(d); + return 0; +} + +void +rewinddir(DIR *d) +{ + if(!d) + return; + d->dd_loc = 0; + d->dd_size = 0; + d->dirsize = 0; + d->dirloc = 0; + free(d->dirs); + d->dirs = nil; + if(_SEEK(d->dd_fd, 0, 0) < 0){ + _syserrno(); + return; + } +} + +struct dirent * +readdir(DIR *d) +{ + int i, n; + struct dirent *dr; + Dir *dirs; + + if(!d){ + errno = EBADF; + return NULL; + } + if(d->dd_loc >= d->dd_size){ + if(d->dirloc >= d->dirsize){ + free(d->dirs); + d->dirs = NULL; + d->dirsize = _dirread(d->dd_fd, &d->dirs); + d->dirloc = 0; + } + if(d->dirsize < 0) { /* malloc or read failed in _dirread? */ + free(d->dirs); + d->dirs = NULL; + } + if(d->dirs == NULL) + return NULL; + + dr = (struct dirent *)d->dd_buf; + dirs = d->dirs; + for(i=0; i<DBLOCKSIZE && d->dirloc < d->dirsize; i++){ + strncpy(dr[i].d_name, dirs[d->dirloc++].name, MAXNAMLEN); + dr[i].d_name[MAXNAMLEN] = 0; + } + d->dd_loc = 0; + d->dd_size = i*sizeof(struct dirent); + } + dr = (struct dirent*)(d->dd_buf+d->dd_loc); + d->dd_loc += sizeof(struct dirent); + return dr; +} diff --git a/sys/src/ape/lib/ap/plan9/pause.c b/sys/src/ape/lib/ap/plan9/pause.c new file mode 100755 index 000000000..38fd96162 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/pause.c @@ -0,0 +1,11 @@ +#include "lib.h" +#include <unistd.h> +#include "sys9.h" + +int +pause(void) +{ + for(;;) + if(_SLEEP(1000*1000) < 0) + return; +} diff --git a/sys/src/ape/lib/ap/plan9/pipe.c b/sys/src/ape/lib/ap/plan9/pipe.c new file mode 100755 index 000000000..edc2372e8 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/pipe.c @@ -0,0 +1,31 @@ +#include <errno.h> +#include "lib.h" +#include "sys9.h" + +int +pipe(int fildes[2]) +{ + Fdinfo *fi; + int i; + + if(!fildes){ + errno = EFAULT; + return -1; + } + if(_PIPE(fildes) < 0) + _syserrno(); + else + if(fildes[0] < 0 || fildes[0]>=OPEN_MAX || + fildes[1] < 0 || fildes[1]>=OPEN_MAX) { + errno = EMFILE; + return -1; + } + for(i = 0; i <=1; i++) { + fi = &_fdinfo[fildes[i]]; + fi->flags = FD_ISOPEN; + fi->oflags = O_RDWR; + fi->uid = 0; /* none */ + fi->gid = 0; + } + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/profile.c b/sys/src/ape/lib/ap/plan9/profile.c new file mode 100755 index 000000000..a69e65f2b --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/profile.c @@ -0,0 +1,324 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <fcntl.h> +#include "sys9.h" + +enum { + Profoff, /* No profiling */ + Profuser, /* Measure user time only (default) */ + Profkernel, /* Measure user + kernel time */ + Proftime, /* Measure total time */ + Profsample, /* Use clock interrupt to sample (default when there is no cycle counter) */ +}; /* what */ + +typedef long long vlong; +typedef unsigned long ulong; +typedef unsigned long long uvlong; + +#include "/sys/include/tos.h" + +extern void* sbrk(ulong); +extern long _callpc(void**); +extern long _savearg(void); +extern void _cycles(uvlong*); /* 64-bit value of the cycle counter if there is one, 0 if there isn't */ + +static ulong khz; +static ulong perr; +static int havecycles; + +typedef struct Plink Plink; +struct Plink +{ + Plink *old; + Plink *down; + Plink *link; + long pc; + long count; + vlong time; +}; + +#pragma profile off + +ulong +_profin(void) +{ + void *dummy; + long pc; + Plink *pp, *p; + ulong arg; + vlong t; + + arg = _savearg(); + pc = _callpc(&dummy); + pp = _tos->prof.pp; + if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid)) + return arg; + + for(p=pp->down; p; p=p->link) + if(p->pc == pc) + goto out; + p = _tos->prof.next + 1; + if(p >= _tos->prof.last){ + _tos->prof.pp = 0; + perr++; + return arg; + } + _tos->prof.next = p; + p->link = pp->down; + pp->down = p; + p->pc = pc; + p->old = pp; + p->down = 0; + p->count = 0; + p->time = 0LL; + +out: + _tos->prof.pp = p; + p->count++; + switch(_tos->prof.what){ + case Profkernel: + p->time = p->time - _tos->pcycles; + goto proftime; + case Profuser: + /* Add kernel cycles on proc entry */ + p->time = p->time + _tos->kcycles; + /* fall through */ + case Proftime: + proftime: /* Subtract cycle counter on proc entry */ + _cycles((uvlong*)&t); + p->time = p->time - t; + break; + case Profsample: + p->time = p->time - _tos->clock; + break; + } + return arg; /* disgusting linkage */ +} + +ulong +_profout(void) +{ + Plink *p; + ulong arg; + vlong t; + + arg = _savearg(); + p = _tos->prof.pp; + if (p == NULL || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)) + return arg; /* Not our process */ + switch(_tos->prof.what){ + case Profkernel: /* Add proc cycles on proc entry */ + p->time = p->time + _tos->pcycles; + goto proftime; + case Profuser: /* Subtract kernel cycles on proc entry */ + p->time = p->time - _tos->kcycles; + /* fall through */ + case Proftime: + proftime: /* Add cycle counter on proc entry */ + _cycles((uvlong*)&t); + p->time = p->time + t; + break; + case Profsample: + p->time = p->time + _tos->clock; + break; + } + _tos->prof.pp = p->old; + return arg; +} + +/* stdio may not be ready for us yet */ +static void +err(char *fmt, ...) +{ + int fd; + va_list arg; + char buf[128]; + + if((fd = open("/dev/cons", OWRITE)) == -1) + return; + va_start(arg, fmt); + /* + * C99 now requires *snprintf to return the number of characters + * that *would* have been emitted, had there been room for them, + * or a negative value on an `encoding error'. Arrgh! + */ + vsnprintf(buf, sizeof buf, fmt, arg); + va_end(arg); + write(fd, buf, strlen(buf)); + close(fd); +} + +void +_profdump(void) +{ + int f; + long n; + Plink *p; + char *vp; + char filename[64]; + + if (_tos->prof.what == 0) + return; /* No profiling */ + if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid) + return; /* Not our process */ + if(perr) + err("%lud Prof errors\n", perr); + _tos->prof.pp = NULL; + if (_tos->prof.pid) + snprintf(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid); + else + snprintf(filename, sizeof filename - 1, "prof.out"); + f = creat(filename, 0666); + if(f < 0) { + err("%s: cannot create - %s\n", filename, strerror(errno)); + return; + } + _tos->prof.pid = ~0; /* make sure data gets dumped once */ + switch(_tos->prof.what){ + case Profkernel: + _cycles((uvlong*)&_tos->prof.first->time); + _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles; + break; + case Profuser: + _cycles((uvlong*)&_tos->prof.first->time); + _tos->prof.first->time = _tos->prof.first->time - _tos->kcycles; + break; + case Proftime: + _cycles((uvlong*)&_tos->prof.first->time); + break; + case Profsample: + _tos->prof.first->time = _tos->clock; + break; + } + vp = (char*)_tos->prof.first; + + for(p = _tos->prof.first; p <= _tos->prof.next; p++) { + + /* + * short down + */ + n = 0xffff; + if(p->down) + n = p->down - _tos->prof.first; + vp[0] = n>>8; + vp[1] = n; + + /* + * short right + */ + n = 0xffff; + if(p->link) + n = p->link - _tos->prof.first; + vp[2] = n>>8; + vp[3] = n; + vp += 4; + + /* + * long pc + */ + n = p->pc; + vp[0] = n>>24; + vp[1] = n>>16; + vp[2] = n>>8; + vp[3] = n; + vp += 4; + + /* + * long count + */ + n = p->count; + vp[0] = n>>24; + vp[1] = n>>16; + vp[2] = n>>8; + vp[3] = n; + vp += 4; + + /* + * vlong time + */ + if (havecycles){ + n = (vlong)(p->time / (vlong)khz); + }else + n = p->time; + + vp[0] = n>>24; + vp[1] = n>>16; + vp[2] = n>>8; + vp[3] = n; + vp += 4; + } + write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first); + close(f); + +} + +void +_profinit(int entries, int what) +{ + if (_tos->prof.what == 0) + return; /* Profiling not linked in */ + _tos->prof.pp = NULL; + _tos->prof.first = calloc(entries*sizeof(Plink),1); + _tos->prof.last = _tos->prof.first + entries; + _tos->prof.next = _tos->prof.first; + _tos->prof.pid = _tos->pid; + _tos->prof.what = what; + _tos->clock = 1; +} + +void +_profmain(void) +{ + char ename[50]; + int n, f; + + n = 2000; + if (_tos->cyclefreq != 0LL){ + khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */ + havecycles = 1; + } + f = open("/env/profsize", OREAD); + if(f >= 0) { + memset(ename, 0, sizeof(ename)); + read(f, ename, sizeof(ename)-1); + close(f); + n = atol(ename); + } + _tos->prof.what = Profuser; + f = open("/env/proftype", OREAD); + if(f >= 0) { + memset(ename, 0, sizeof(ename)); + read(f, ename, sizeof(ename)-1); + close(f); + if (strcmp(ename, "user") == 0) + _tos->prof.what = Profuser; + else if (strcmp(ename, "kernel") == 0) + _tos->prof.what = Profkernel; + else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0) + _tos->prof.what = Proftime; + else if (strcmp(ename, "sample") == 0) + _tos->prof.what = Profsample; + } + _tos->prof.first = sbrk(n*sizeof(Plink)); + _tos->prof.last = sbrk(0); + _tos->prof.next = _tos->prof.first; + _tos->prof.pp = NULL; + _tos->prof.pid = _tos->pid; + atexit(_profdump); + _tos->clock = 1; +} + +void prof(void (*fn)(void*), void *arg, int entries, int what) +{ + _profinit(entries, what); + _tos->prof.pp = _tos->prof.next; + fn(arg); + _profdump(); +} + +#pragma profile on + diff --git a/sys/src/ape/lib/ap/plan9/qlock.c b/sys/src/ape/lib/ap/plan9/qlock.c new file mode 100755 index 000000000..b0882f789 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/qlock.c @@ -0,0 +1,365 @@ +#define _LOCK_EXTENSION +#define _QLOCK_EXTENSION +#define _RESEARCH_SOURCE +#include <u.h> +#include <lock.h> +#include <qlock.h> +#include <stdlib.h> +#include "sys9.h" + +#define rendezvous _RENDEZVOUS +#define _rendezvousp rendezvous +#define _tas tas +#define nelem(x) (sizeof(x)/sizeof((x)[0])) + +static struct { + QLp *p; + QLp x[1024]; +} ql = { + ql.x +}; + +enum +{ + Queuing, + QueuingR, + QueuingW, + Sleeping, +}; + +/* find a free shared memory location to queue ourselves in */ +static QLp* +getqlp(void) +{ + QLp *p, *op; + + op = ql.p; + for(p = op+1; ; p++){ + if(p == &ql.x[nelem(ql.x)]) + p = ql.x; + if(p == op) + abort(); + if(_tas(&(p->inuse)) == 0){ + ql.p = p; + p->next = nil; + break; + } + } + return p; +} + +void +qlock(QLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(!q->locked){ + q->locked = 1; + unlock(&q->lock); + return; + } + + + /* chain into waiting list */ + mp = getqlp(); + p = q->tail; + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->state = Queuing; + unlock(&q->lock); + + /* wait */ + while((*_rendezvousp)((ulong)mp, 1) == ~0) + ; + mp->inuse = 0; +} + +void +qunlock(QLock *q) +{ + QLp *p; + + lock(&q->lock); + p = q->head; + if(p != nil){ + /* wakeup head waiting process */ + q->head = p->next; + if(q->head == nil) + q->tail = nil; + unlock(&q->lock); + while((*_rendezvousp)((ulong)p, 0x12345) == ~0) + ; + return; + } + q->locked = 0; + unlock(&q->lock); +} + +int +canqlock(QLock *q) +{ + if(!canlock(&q->lock)) + return 0; + if(!q->locked){ + q->locked = 1; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +#if 0 + +void +rlock(RWLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(q->writer == 0 && q->head == nil){ + /* no writer, go for it */ + q->readers++; + unlock(&q->lock); + return; + } + + mp = getqlp(); + p = q->tail; + if(p == 0) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingR; + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)((ulong)mp, 1) == ~0) + ; + mp->inuse = 0; +} + +int +canrlock(RWLock *q) +{ + lock(&q->lock); + if (q->writer == 0 && q->head == nil) { + /* no writer; go for it */ + q->readers++; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +runlock(RWLock *q) +{ + QLp *p; + + lock(&q->lock); + if(q->readers <= 0) + abort(); + p = q->head; + if(--(q->readers) > 0 || p == nil){ + unlock(&q->lock); + return; + } + + /* start waiting writer */ + if(p->state != QueuingW) + abort(); + q->head = p->next; + if(q->head == 0) + q->tail = 0; + q->writer = 1; + unlock(&q->lock); + + /* wakeup waiter */ + while((*_rendezvousp)((ulong)p, 0) == ~0) + ; +} + +void +wlock(RWLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(q->readers == 0 && q->writer == 0){ + /* noone waiting, go for it */ + q->writer = 1; + unlock(&q->lock); + return; + } + + /* wait */ + p = q->tail; + mp = getqlp(); + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingW; + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)((ulong)mp, 1) == ~0) + ; + mp->inuse = 0; +} + +int +canwlock(RWLock *q) +{ + lock(&q->lock); + if (q->readers == 0 && q->writer == 0) { + /* no one waiting; go for it */ + q->writer = 1; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +wunlock(RWLock *q) +{ + QLp *p; + + lock(&q->lock); + if(q->writer == 0) + abort(); + p = q->head; + if(p == nil){ + q->writer = 0; + unlock(&q->lock); + return; + } + if(p->state == QueuingW){ + /* start waiting writer */ + q->head = p->next; + if(q->head == nil) + q->tail = nil; + unlock(&q->lock); + while((*_rendezvousp)((ulong)p, 0) == ~0) + ; + return; + } + + if(p->state != QueuingR) + abort(); + + /* wake waiting readers */ + while(q->head != nil && q->head->state == QueuingR){ + p = q->head; + q->head = p->next; + q->readers++; + while((*_rendezvousp)((ulong)p, 0) == ~0) + ; + } + if(q->head == nil) + q->tail = nil; + q->writer = 0; + unlock(&q->lock); +} + +void +rsleep(Rendez *r) +{ + QLp *t, *me; + + if(!r->l) + abort(); + lock(&r->l->lock); + /* we should hold the qlock */ + if(!r->l->locked) + abort(); + + /* add ourselves to the wait list */ + me = getqlp(); + me->state = Sleeping; + if(r->head == nil) + r->head = me; + else + r->tail->next = me; + me->next = nil; + r->tail = me; + + /* pass the qlock to the next guy */ + t = r->l->head; + if(t){ + r->l->head = t->next; + if(r->l->head == nil) + r->l->tail = nil; + unlock(&r->l->lock); + while((*_rendezvousp)((ulong)t, 0x12345) == ~0) + ; + }else{ + r->l->locked = 0; + unlock(&r->l->lock); + } + + /* wait for a wakeup */ + while((*_rendezvousp)((ulong)me, 1) == ~0) + ; + me->inuse = 0; +} + +int +rwakeup(Rendez *r) +{ + QLp *t; + + /* + * take off wait and put on front of queue + * put on front so guys that have been waiting will not get starved + */ + + if(!r->l) + abort(); + lock(&r->l->lock); + if(!r->l->locked) + abort(); + + t = r->head; + if(t == nil){ + unlock(&r->l->lock); + return 0; + } + + r->head = t->next; + if(r->head == nil) + r->tail = nil; + + t->next = r->l->head; + r->l->head = t; + if(r->l->tail == nil) + r->l->tail = t; + + t->state = Queuing; + unlock(&r->l->lock); + return 1; +} + +int +rwakeupall(Rendez *r) +{ + int i; + + for(i=0; rwakeup(r); i++) + ; + return i; +} + +#endif diff --git a/sys/src/ape/lib/ap/plan9/read.c b/sys/src/ape/lib/ap/plan9/read.c new file mode 100755 index 000000000..471ab7e33 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/read.c @@ -0,0 +1,46 @@ +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include "lib.h" +#include "sys9.h" + +#include <stdio.h> + +ssize_t +read(int d, void *buf, size_t nbytes) +{ + int n, noblock, isbuf; + Fdinfo *f; + + if(d<0 || d>=OPEN_MAX || !((f = &_fdinfo[d])->flags&FD_ISOPEN)){ + errno = EBADF; + return -1; + } + if(nbytes <= 0) + return 0; + if(buf == 0){ + errno = EFAULT; + return -1; + } + f = &_fdinfo[d]; + noblock = f->oflags&O_NONBLOCK; + isbuf = f->flags&(FD_BUFFERED|FD_BUFFEREDX); + if(noblock || isbuf){ + if(f->flags&FD_BUFFEREDX) { + errno = EIO; + return -1; + } + if(!isbuf) { + if(_startbuf(d) != 0) { + errno = EIO; + return -1; + } + } + n = _readbuf(d, buf, nbytes, noblock); + }else{ + n = _READ(d, buf, nbytes); + if(n < 0) + _syserrno(); + } + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/rename.c b/sys/src/ape/lib/ap/plan9/rename.c new file mode 100755 index 000000000..dddfea328 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/rename.c @@ -0,0 +1,76 @@ +#include "lib.h" +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +int +rename(const char *from, const char *to) +{ + int n, i; + char *f, *t; + Dir *d, nd; + long mode; + + if(access(to, 0) >= 0){ + if(_REMOVE(to) < 0){ + _syserrno(); + return -1; + } + } + if((d = _dirstat(to)) != nil){ + free(d); + errno = EEXIST; + return -1; + } + if((d = _dirstat(from)) == nil){ + _syserrno(); + return -1; + } + f = strrchr(from, '/'); + t = strrchr(to, '/'); + f = f? f+1 : from; + t = t? t+1 : to; + n = 0; + if(f-from==t-to && strncmp(from, to, f-from)==0){ + /* from and to are in same directory (we miss some cases) */ + i = strlen(t); + _nulldir(&nd); + nd.name = t; + if(_dirwstat(from, &nd) < 0){ + _syserrno(); + n = -1; + } + }else{ + /* different directories: have to copy */ + int ffd, tfd; + char buf[8192]; + + if((ffd = _OPEN(from, 0)) < 0 || + (tfd = _CREATE(to, 1, d->mode)) < 0){ + _CLOSE(ffd); + _syserrno(); + n = -1; + } + while(n>=0 && (n = _READ(ffd, buf, 8192)) > 0) + if(_WRITE(tfd, buf, n) != n){ + _syserrno(); + n = -1; + } + _CLOSE(ffd); + _CLOSE(tfd); + if(n>0) + n = 0; + if(n == 0) { + if(_REMOVE(from) < 0){ + _syserrno(); + return -1; + } + } + } + free(d); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/rmdir.c b/sys/src/ape/lib/ap/plan9/rmdir.c new file mode 100755 index 000000000..a799bc00b --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/rmdir.c @@ -0,0 +1,17 @@ +#include "lib.h" +#include <errno.h> +#include <unistd.h> +#include "sys9.h" + +int +rmdir(const char *path) +{ + int n; + + n = 0; + if(_REMOVE(path) < 0) { + _syserrno(); + n = -1; + } + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/setgid.c b/sys/src/ape/lib/ap/plan9/setgid.c new file mode 100755 index 000000000..7c9075c3f --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/setgid.c @@ -0,0 +1,14 @@ +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +/* + * BUG: never works + */ + +int +setgid(gid_t gid) +{ + errno = EPERM; + return -1; +} diff --git a/sys/src/ape/lib/ap/plan9/setpgid.c b/sys/src/ape/lib/ap/plan9/setpgid.c new file mode 100755 index 000000000..dd5445085 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/setpgid.c @@ -0,0 +1,31 @@ +#include "lib.h" +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include "sys9.h" + +int +setpgid(pid_t pid, pid_t pgid) +{ + int n, f; + char buf[50], fname[30]; + + if(pid == 0) + pid = getpid(); + if(pgid == 0) + pgid = getpgrp(); + sprintf(fname, "/proc/%d/noteid", pid); + f = open(fname, 1); + if(f < 0) { + errno = ESRCH; + return -1; + } + n = sprintf(buf, "%d", pgid); + n = write(f, buf, n); + if(n < 0) + _syserrno(); + else + n = 0; + close(f); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/setsid.c b/sys/src/ape/lib/ap/plan9/setsid.c new file mode 100755 index 000000000..f53f8f2f3 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/setsid.c @@ -0,0 +1,14 @@ +#include "lib.h" +#include <unistd.h> +#include "sys9.h" + +pid_t +setsid(void) +{ + if(_RFORK(RFNAMEG|RFNOTEG) < 0){ + _syserrno(); + return -1; + } + _sessleader = 1; + return getpgrp(); +} diff --git a/sys/src/ape/lib/ap/plan9/setuid.c b/sys/src/ape/lib/ap/plan9/setuid.c new file mode 100755 index 000000000..a34f2de6f --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/setuid.c @@ -0,0 +1,14 @@ +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +/* + * BUG: never works + */ + +int +setuid(uid_t uid) +{ + errno = EPERM; + return -1; +} diff --git a/sys/src/ape/lib/ap/plan9/signal.c b/sys/src/ape/lib/ap/plan9/signal.c new file mode 100755 index 000000000..cf8a823ef --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/signal.c @@ -0,0 +1,136 @@ +#include "lib.h" +#include "sys9.h" +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <setjmp.h> + +extern sigset_t _psigblocked; + +static struct { + char *msg; /* just check prefix */ + int num; +} sigtab[] = { + {"hangup", SIGHUP}, + {"interrupt", SIGINT}, + {"quit", SIGQUIT}, + {"alarm", SIGALRM}, + {"sys: trap: illegal instruction", SIGILL}, + {"sys: trap: reserved instruction", SIGILL}, + {"sys: trap: reserved", SIGILL}, + {"sys: trap: arithmetic overflow", SIGFPE}, + {"abort", SIGABRT}, + {"sys: fp:", SIGFPE}, + {"exit", SIGKILL}, + {"die", SIGKILL}, + {"kill", SIGKILL}, + {"sys: trap: bus error", SIGSEGV}, + {"sys: trap: address error", SIGSEGV}, + {"sys: trap: TLB", SIGSEGV}, + {"sys: write on closed pipe", SIGPIPE}, + {"alarm", SIGALRM}, + {"term", SIGTERM}, + {"usr1", SIGUSR1}, + {"usr2", SIGUSR2}, +}; +#define NSIGTAB ((sizeof sigtab)/(sizeof (sigtab[0]))) + +void (*_sighdlr[MAXSIG+1])(int, char*, Ureg*); /* 0 initialized: SIG_DFL */ + +void +(*signal(int sig, void (*func)(int, char*, Ureg*)))(int, char*, Ureg*) +{ + void(*oldf)(int, char*, Ureg*); + + if(sig <= 0 || sig > MAXSIG){ + errno = EINVAL; + return SIG_ERR; + } + oldf = _sighdlr[sig]; + if(sig == SIGKILL) + return oldf; /* can't catch or ignore SIGKILL */ + _sighdlr[sig] = func; + return oldf; +} + +/* BAD CODE - see /sys/src/ape/lib/ap/$objtype/setjmp.s for real code +int +sigsetjmp(sigjmp_buf buf, int savemask) +{ + int r; + + buf[0] = savemask; + buf[1] = _psigblocked; + return setjmp(&buf[2]); +} +*/ + +/* + * BUG: improper handling of process signal mask + */ +int +sigaction(int sig, struct sigaction *act, struct sigaction *oact) +{ + if(sig <= 0 || sig > MAXSIG || sig == SIGKILL){ + errno = EINVAL; + return -1; + } + if(oact){ + oact->sa_handler = _sighdlr[sig]; + oact->sa_mask = _psigblocked; + oact->sa_flags = 0; + } + if(act){ + _sighdlr[sig] = act->sa_handler; + } + return 0; +} + +/* this is registered in _envsetup */ +int +_notehandler(Ureg *u, char *msg) +{ + int i; + void(*f)(int, char*, Ureg*); + extern void _doatexits(void); /* in stdio/exit.c */ + + if(_finishing) + _finish(0, 0); + for(i = 0; i<NSIGTAB; i++){ + if(strncmp(msg, sigtab[i].msg, strlen(sigtab[i].msg)) == 0){ + f = _sighdlr[sigtab[i].num]; + if(f == SIG_DFL || f == SIG_ERR) + break; + if(f != SIG_IGN) { + _notetramp(sigtab[i].num, f, u); + /* notetramp is machine-dependent; doesn't return to here */ + } + _NOTED(0); /* NCONT */ + return; + } + } + _doatexits(); + _NOTED(1); /* NDFLT */ +} + +int +_stringsig(char *nam) +{ + int i; + + for(i = 0; i<NSIGTAB; i++) + if(strncmp(nam, sigtab[i].msg, strlen(sigtab[i].msg)) == 0) + return sigtab[i].num; + return 0; +} + +char * +_sigstring(int sig) +{ + int i; + + for(i=0; i<NSIGTAB; i++) + if(sigtab[i].num == sig) + return sigtab[i].msg; + return "unknown signal"; +} diff --git a/sys/src/ape/lib/ap/plan9/sigpending.c b/sys/src/ape/lib/ap/plan9/sigpending.c new file mode 100755 index 000000000..8b5eb2eda --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/sigpending.c @@ -0,0 +1,11 @@ +#include <signal.h> + +/* + * BUG: don't keep track of these + */ +int +sigpending(sigset_t *set) +{ + *set = 0; + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/sigprocmask.c b/sys/src/ape/lib/ap/plan9/sigprocmask.c new file mode 100755 index 000000000..84b94f987 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/sigprocmask.c @@ -0,0 +1,23 @@ +#include "lib.h" +#include <signal.h> +#include <errno.h> + +sigset_t _psigblocked; + +int +sigprocmask(int how, sigset_t *set, sigset_t *oset) +{ + if(oset) + *oset = _psigblocked; + if(how==SIG_BLOCK) + _psigblocked |= *set; + else if(how==SIG_UNBLOCK) + _psigblocked &= ~*set; + else if(how==SIG_SETMASK) + _psigblocked = *set; + else{ + errno = EINVAL; + return -1; + } + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/sigsuspend.c b/sys/src/ape/lib/ap/plan9/sigsuspend.c new file mode 100755 index 000000000..290c15d0f --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/sigsuspend.c @@ -0,0 +1,13 @@ +#include <signal.h> +#include <errno.h> + +/* + * BUG: doesn't work + */ + +int +sigsuspend(sigset_t *set) +{ + errno = EINVAL; + return -1; +} diff --git a/sys/src/ape/lib/ap/plan9/sleep.c b/sys/src/ape/lib/ap/plan9/sleep.c new file mode 100755 index 000000000..a6fcf19a9 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/sleep.c @@ -0,0 +1,17 @@ +#include "lib.h" +#include <unistd.h> +#include <time.h> +#include "sys9.h" + +unsigned int +sleep(unsigned int secs) +{ + time_t t0, t1; + + t0 = time(0); + if(_SLEEP(secs*1000) < 0){ + t1 = time(0); + return t1-t0; + } + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/sqrt.c b/sys/src/ape/lib/ap/plan9/sqrt.c new file mode 100755 index 000000000..98974360d --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/sqrt.c @@ -0,0 +1,56 @@ +/* + sqrt returns the square root of its floating + point argument. Newton's method. + + calls frexp +*/ + +#include <math.h> +#include <errno.h> +#define _RESEARCH_SOURCE +#include <float.h> + +double +sqrt(double arg) +{ + double x, temp; + int exp, i; + + if(isInf(arg, 1)) + return arg; + if(arg <= 0) { + if(arg < 0) + errno = EDOM; + return 0; + } + x = frexp(arg, &exp); + while(x < 0.5) { + x *= 2; + exp--; + } + /* + * NOTE + * this wont work on 1's comp + */ + if(exp & 1) { + x *= 2; + exp--; + } + temp = 0.5 * (1.0+x); + + while(exp > 60) { + temp *= (1L<<30); + exp -= 60; + } + while(exp < -60) { + temp /= (1L<<30); + exp += 60; + } + if(exp >= 0) + temp *= 1L << (exp/2); + else + temp /= 1L << (-exp/2); + for(i=0; i<=4; i++) + temp = 0.5*(temp + arg/temp); + return temp; +} diff --git a/sys/src/ape/lib/ap/plan9/stat.c b/sys/src/ape/lib/ap/plan9/stat.c new file mode 100755 index 000000000..be0d7c484 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/stat.c @@ -0,0 +1,21 @@ +#include "lib.h" +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +int +stat(const char *path, struct stat *buf) +{ + Dir *d; + + if((d = _dirstat(path)) == nil){ + _syserrno(); + return -1; + } + _dirtostat(buf, d, 0); + free(d); + + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/sys9.h b/sys/src/ape/lib/ap/plan9/sys9.h new file mode 100755 index 000000000..b289273cb --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/sys9.h @@ -0,0 +1,121 @@ +typedef +struct Waitmsg +{ + int pid; /* of loved one */ + unsigned long time[3]; /* of loved one & descendants */ + char *msg; +} Waitmsg; + +#define STATMAX 65535U /* max length of machine-independent stat structure */ +#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */ +#define ERRMAX 128 /* max length of error string */ + +#define MORDER 0x0003 /* mask for bits defining order of mounting */ +#define MREPL 0x0000 /* mount replaces object */ +#define MBEFORE 0x0001 /* mount goes before others in union directory */ +#define MAFTER 0x0002 /* mount goes after others in union directory */ +#define MCREATE 0x0004 /* permit creation in mounted directory */ +#define MCACHE 0x0010 /* cache some data */ +#define MMASK 0x0007 /* all bits on */ + +#define OREAD 0 /* open for read */ +#define OWRITE 1 /* write */ +#define ORDWR 2 /* read and write */ +#define OEXEC 3 /* execute, == read but check execute permission */ +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ +#define OCEXEC 32 /* or'ed in, close on exec */ +#define ORCLOSE 64 /* or'ed in, remove on close */ +#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */ + +#define AEXIST 0 /* accessible: exists */ +#define AEXEC 1 /* execute access */ +#define AWRITE 2 /* write access */ +#define AREAD 4 /* read access */ + +/* Segattch */ +#define SG_RONLY 0040 /* read only */ +#define SG_CEXEC 0100 /* detach on exec */ + +#define NCONT 0 /* continue after note */ +#define NDFLT 1 /* terminate after note */ +#define NSAVE 2 /* clear note but hold state */ +#define NRSTR 3 /* restore saved state */ + +/* bits in Qid.type */ +#define QTDIR 0x80 /* type bit for directories */ +#define QTAPPEND 0x40 /* type bit for append only files */ +#define QTEXCL 0x20 /* type bit for exclusive use files */ +#define QTMOUNT 0x10 /* type bit for mounted channel */ +#define QTFILE 0x00 /* plain file */ + +/* bits in Dir.mode */ +#define DMDIR 0x80000000 /* mode bit for directories */ +#define DMAPPEND 0x40000000 /* mode bit for append only files */ +#define DMEXCL 0x20000000 /* mode bit for exclusive use files */ +#define DMMOUNT 0x10000000 /* mode bit for mounted channel */ +#define DMREAD 0x4 /* mode bit for read permission */ +#define DMWRITE 0x2 /* mode bit for write permission */ +#define DMEXEC 0x1 /* mode bit for execute permission */ + +/* rfork */ +enum +{ + RFNAMEG = (1<<0), + RFENVG = (1<<1), + RFFDG = (1<<2), + RFNOTEG = (1<<3), + RFPROC = (1<<4), + RFMEM = (1<<5), + RFNOWAIT = (1<<6), + RFCNAMEG = (1<<10), + RFCENVG = (1<<11), + RFCFDG = (1<<12), + RFREND = (1<<13), + RFNOMNT = (1<<14) +}; + +extern int _AWAIT(char*, int); +extern int _ALARM(unsigned long); +extern int _BIND(const char*, const char*, int); +extern int _CHDIR(const char*); +extern int _CLOSE(int); +extern int _CREATE(char*, int, unsigned long); +extern int _DUP(int, int); +extern int _ERRSTR(char*, unsigned int); +extern int _EXEC(char*, char*[]); +extern void _EXITS(char *); +extern int _FD2PATH(int, char*, int); +extern int _FAUTH(int, char*); +extern int _FSESSION(int, char*, int); +extern int _FSTAT(int, unsigned char*, int); +extern int _FWSTAT(int, unsigned char*, int); +extern int _MOUNT(int, int, const char*, int, const char*); +extern int _NOTED(int); +extern int _NOTIFY(int(*)(void*, char*)); +extern int _OPEN(const char*, int); +extern int _PIPE(int*); +extern long _PREAD(int, void*, long, long long); +extern long _PWRITE(int, void*, long, long long); +extern long _READ(int, void*, long); +extern int _REMOVE(const char*); +extern int _RENDEZVOUS(unsigned long, unsigned long); +extern int _RFORK(int); +extern int _SEGATTACH(int, char*, void*, unsigned long); +extern int _SEGBRK(void*, void*); +extern int _SEGDETACH(void*); +extern int _SEGFLUSH(void*, unsigned long); +extern int _SEGFREE(void*, unsigned long); +extern long long _SEEK(int, long long, int); +extern int _SLEEP(long); +extern int _STAT(const char*, unsigned char*, int); +extern Waitmsg* _WAIT(void); +extern long _WRITE(int, const void*, long); +extern int _WSTAT(const char*, unsigned char*, int); + +extern int __open(char *, int, ...); +extern int __access(char *, int); +extern int __chdir(char *); +extern int __creat(char *, int); +extern int __link(char *, int); +extern int __stat(char *, struct stat *); +extern int __unlink(char *); diff --git a/sys/src/ape/lib/ap/plan9/system.c b/sys/src/ape/lib/ap/plan9/system.c new file mode 100755 index 000000000..497b0e1f1 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/system.c @@ -0,0 +1,40 @@ +#include "lib.h" +#include <stdlib.h> +#include <stdio.h> +#include <sys/wait.h> +#include <unistd.h> + +int +system(const char *s) +{ + int w, status; + pid_t pid; + char cmd[30], *oty; + + oty = getenv("cputype"); + if(!oty) + return -1; + if(!s) + return 1; /* a command interpreter is available */ + pid = fork(); + snprintf(cmd, sizeof cmd, "/%s/bin/ape/sh", oty); + if(pid == 0) { + execl(cmd, "sh", "-c", s, NULL); + _exit(1); + } + if(pid < 0){ + _syserrno(); + return -1; + } + for(;;) { + w = wait(&status); + if(w == -1 || w == pid) + break; + } + + if(w == -1){ + _syserrno(); + return w; + } + return status; +} diff --git a/sys/src/ape/lib/ap/plan9/tcgetattr.c b/sys/src/ape/lib/ap/plan9/tcgetattr.c new file mode 100755 index 000000000..8a7d3e608 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/tcgetattr.c @@ -0,0 +1,201 @@ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <termios.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include "sys9.h" +#include "lib.h" +#include "dir.h" + +#define CESC '\\' +#define CINTR 0177 /* DEL */ +#define CQUIT 034 /* FS, cntl | */ +#define CERASE 010 /* BS */ +#define CKILL 025 /* cntl u */ +#define CEOF 04 /* cntl d */ +#define CSTART 021 /* cntl q */ +#define CSTOP 023 /* cntl s */ +#define CSWTCH 032 /* cntl z */ +#define CEOL 000 +#define CNSWTCH 0 + +static int +isptty(int fd) +{ + Dir *d; + int rv; + + if((d = _dirfstat(fd)) == nil) + return 0; + rv = (strncmp(d->name, "ptty", 4) == 0); + free(d); + return rv; +} + +int +tcgetattr(int fd, struct termios *t) +{ + int n; + char buf[60]; + + if(!isptty(fd)) { + if(isatty(fd)) { + /* If there is no emulation return sensible defaults */ + t->c_iflag = ISTRIP|ICRNL|IXON|IXOFF; + t->c_oflag = OPOST|TAB3|ONLCR; + t->c_cflag = B9600; + t->c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; + t->c_cc[VINTR] = CINTR; + t->c_cc[VQUIT] = CQUIT; + t->c_cc[VERASE] = CERASE; + t->c_cc[VKILL] = CKILL; + t->c_cc[VEOF] = CEOF; + t->c_cc[VEOL] = CEOL; + t->c_cc[VSTART] = CSTART; + t->c_cc[VSTOP] = CSTOP; + return 0; + } else { + errno = ENOTTY; + return -1; + } + } + if(_SEEK(fd, -2, 0) != -2) { + _syserrno(); + return -1; + } + + n = _READ(fd, buf, 57); + if(n < 0) { + _syserrno(); + return -1; + } + + t->c_iflag = strtoul(buf+4, 0, 16); + t->c_oflag = strtoul(buf+9, 0, 16); + t->c_cflag = strtoul(buf+14, 0, 16); + t->c_lflag = strtoul(buf+19, 0, 16); + + for(n = 0; n < NCCS; n++) + t->c_cc[n] = strtoul(buf+24+(n*3), 0, 16); + + return 0; +} + +/* BUG: ignores optional actions */ + +int +tcsetattr(int fd, int optactions, const struct termios *t) +{ + int n, i; + char buf[100]; + + if(!isptty(fd)) { + if(!isatty(fd)) { + errno = ENOTTY; + return -1; + } else + return 0; + } + n = sprintf(buf, "IOW %4.4x %4.4x %4.4x %4.4x ", + t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag); + + for(i = 0; i < NCCS; i++) + n += sprintf(buf+n, "%2.2x ", t->c_cc[i]); + + if(_SEEK(fd, -2, 0) != -2) { + _syserrno(); + return -1; + } + + n = _WRITE(fd, buf, n); + if(n < 0) { + _syserrno(); + return -1; + } + + return 0; +} + +int +tcsetpgrp(int fd, pid_t pgrpid) +{ + int n; + char buf[30]; + + if(!isptty(fd)) { + if(!isatty(fd)) { + errno = ENOTTY; + return -1; + } else + return 0; + } + n = sprintf(buf, "IOW note %d", pgrpid); + + if(_SEEK(fd, -2, 0) != -2) { + _syserrno(); + return -1; + } + + n = _WRITE(fd, buf, n); + if(n < 0) { + _syserrno(); + return -1; + } +} + +pid_t +tcgetpgrp(int fd) +{ + int n; + pid_t pgrp; + char buf[100]; + + if(!isptty(fd)) { + errno = ENOTTY; + return -1; + } + if(_SEEK(fd, -2, 0) != -2) { + _syserrno(); + return -1; + } + n = _READ(fd, buf, sizeof(buf)); + if(n < 0) { + _syserrno(); + return -1; + } + pgrp = atoi(buf+24+(NCCS*3)); + return pgrp; +} + +/* should do a better job here */ + +int +tcdrain(int) +{ + errno = ENOTTY; + return -1; +} + +int +tcflush(int, int) +{ + errno = ENOTTY; + return -1; +} + +int +tcflow(int, int) +{ + errno = ENOTTY; + return -1; +} + +int +tcsendbreak(int) +{ + errno = ENOTTY; + return -1; +} diff --git a/sys/src/ape/lib/ap/plan9/time.c b/sys/src/ape/lib/ap/plan9/time.c new file mode 100755 index 000000000..85a1e72b2 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/time.c @@ -0,0 +1,27 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include "sys9.h" + +time_t +time(time_t *tp) +{ + char b[20]; + int f; + time_t t; + + memset(b, 0, sizeof(b)); + f = _OPEN("/dev/time", 0); + if(f >= 0) { + _PREAD(f, b, sizeof(b), 0); + _CLOSE(f); + } + t = atol(b); + if(tp) + *tp = t; + return t; +} diff --git a/sys/src/ape/lib/ap/plan9/times.c b/sys/src/ape/lib/ap/plan9/times.c new file mode 100755 index 000000000..2d1e95c8c --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/times.c @@ -0,0 +1,51 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/times.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +static +char* +skip(char *p) +{ + + while(*p == ' ') + p++; + while(*p != ' ' && *p != 0) + p++; + return p; +} + +clock_t +times(struct tms *buf) +{ + char b[200], *p; + int f; + unsigned long r; + + memset(b, 0, sizeof(b)); + f = open("/dev/cputime", O_RDONLY); + if(f >= 0) { + lseek(f, SEEK_SET, 0); + read(f, b, sizeof(b)); + close(f); + } + p = b; + if(buf) + buf->tms_utime = atol(p); + p = skip(p); + if(buf) + buf->tms_stime = atol(p); + p = skip(p); + r = atol(p); + if(buf){ + p = skip(p); + buf->tms_cutime = atol(p); + p = skip(p); + buf->tms_cstime = atol(p); + } + return r; +} diff --git a/sys/src/ape/lib/ap/plan9/tmpfile.c b/sys/src/ape/lib/ap/plan9/tmpfile.c new file mode 100755 index 000000000..c3ab5fd88 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/tmpfile.c @@ -0,0 +1,44 @@ +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include "sys9.h" +#undef OPEN +#include "../stdio/iolib.h" +#include "lib.h" +#include "dir.h" + +FILE * +tmpfile(void){ + FILE *f; + static char name[]="/tmp/tf0000000000000"; + char *p; + int n; + for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++) + if(f->state==CLOSED) + break; + if(f==&_IO_stream[FOPEN_MAX]) + return NULL; + while(access(name, 0) >= 0){ + p = name+7; + while(*p == '9') + *p++ = '0'; + if(*p == '\0') + return NULL; + ++*p; + } + n = _CREATE(name, 64|2, 0777); /* remove-on-close */ + if(n==-1){ + _syserrno(); + return NULL; + } + _fdinfo[n].flags = FD_ISOPEN; + _fdinfo[n].oflags = 2; + f->fd=n; + f->flags=0; + f->state=OPEN; + f->buf=0; + f->rp=0; + f->wp=0; + f->lp=0; + return f; +} diff --git a/sys/src/ape/lib/ap/plan9/ttyname.c b/sys/src/ape/lib/ap/plan9/ttyname.c new file mode 100755 index 000000000..980186a81 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/ttyname.c @@ -0,0 +1,11 @@ +#include <unistd.h> +#include <stdio.h> + +char * +ttyname(int fd) +{ + static char buf[100]; + + sprintf(buf, "/fd/%d", fd); + return buf; +} diff --git a/sys/src/ape/lib/ap/plan9/umask.c b/sys/src/ape/lib/ap/plan9/umask.c new file mode 100755 index 000000000..b45b7576c --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/umask.c @@ -0,0 +1,13 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +/* + * No such concept in plan9, but supposed to be always successful + */ + +mode_t +umask(mode_t numask) +{ + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/uname.c b/sys/src/ape/lib/ap/plan9/uname.c new file mode 100755 index 000000000..1df2a941f --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/uname.c @@ -0,0 +1,25 @@ +#include <stdlib.h> +#include <string.h> +#include <sys/utsname.h> + +int +uname(struct utsname *n) +{ + n->sysname = getenv("osname"); + if(!n->sysname) + n->sysname = "Plan9"; + n->nodename = getenv("sysname"); + if(!n->nodename){ + n->nodename = getenv("site"); + if(!n->nodename) + n->nodename = "?"; + } + n->release = "4"; /* edition */ + n->version = "0"; + n->machine = getenv("cputype"); + if(!n->machine) + n->machine = "?"; + if(strcmp(n->machine, "386") == 0) + n->machine = "i386"; /* for gnu configure */ + return 0; +} diff --git a/sys/src/ape/lib/ap/plan9/unlink.c b/sys/src/ape/lib/ap/plan9/unlink.c new file mode 100755 index 000000000..a015c782f --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/unlink.c @@ -0,0 +1,75 @@ +#include "lib.h" +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + + +/* + * BUG: errno mapping + */ + +int +unlink(const char *path) +{ + int n, i, fd; + long long nn; + Dir *db1, *db2, nd; + Fdinfo *f; + char *p, newname[PATH_MAX], newelem[32]; + + /* if the file is already open, make it close-on-exec (and rename to qid) */ + if((db1 = _dirstat(path)) == nil) { + _syserrno(); + return -1; + } + fd = -1; + for(i=0, f = _fdinfo;i < OPEN_MAX; i++, f++) { + if((f->flags&FD_ISOPEN) && (db2=_dirfstat(i)) != nil) { + if(db1->qid.path == db2->qid.path && + db1->qid.vers == db2->qid.vers && + db1->type == db2->type && + db1->dev == db2->dev) { + sprintf(newelem, "%8.8lx%8.8lx", (ulong)(db2->qid.path>>32), (ulong)db2->qid.path); + _nulldir(&nd); + nd.name = newelem; + if(_dirfwstat(i, &nd) < 0) + p = (char*)path; + else { + p = strrchr(path, '/'); + if(p == 0) + p = newelem; + else { + memmove(newname, path, p-path); + newname[p-path] = '/'; + strcpy(newname+(p-path)+1, newelem); + p = newname; + } + } + /* reopen remove on close */ + fd = _OPEN(p, 64|(f->oflags)); + if(fd < 0){ + free(db2); + continue; + } + nn = _SEEK(i, 0, 1); + if(nn < 0) + nn = 0; + _SEEK(fd, nn, 0); + _DUP(fd, i); + _CLOSE(fd); + free(db1); + return 0; + } + free(db2); + } + } + if(fd == -1) + if((n=_REMOVE(path)) < 0) + _syserrno(); + free(db1); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/utime.c b/sys/src/ape/lib/ap/plan9/utime.c new file mode 100755 index 000000000..52eeb34e2 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/utime.c @@ -0,0 +1,30 @@ +#include "lib.h" +#include <sys/types.h> +#include <time.h> +#include <utime.h> +#include <errno.h> +#include <stdlib.h> +#include "sys9.h" +#include "dir.h" + +int +utime(const char *path, const struct utimbuf *times) +{ + int n; + Dir nd; + time_t curt; + + _nulldir(&nd); + if(times == 0) { + curt = time(0); + nd.atime = curt; + nd.mtime = curt; + } else { + nd.atime = times->actime; + nd.mtime = times->modtime; + } + n = _dirwstat(path, &nd); + if(n < 0) + _syserrno(); + return n; +} diff --git a/sys/src/ape/lib/ap/plan9/wait.c b/sys/src/ape/lib/ap/plan9/wait.c new file mode 100755 index 000000000..ac1ab13da --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/wait.c @@ -0,0 +1,150 @@ +#include "lib.h" +#include <stdlib.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include "sys9.h" +#include "dir.h" + +/* + * status not yet collected for processes that have exited + */ +typedef struct Waited Waited; +struct Waited { + Waitmsg* msg; + Waited* next; +}; +static Waited *wd; + +static Waitmsg * +lookpid(int pid) +{ + Waited **wl, *w; + Waitmsg *msg; + + for(wl = &wd; (w = *wl) != nil; wl = &w->next) + if(pid <= 0 || w->msg->pid == pid){ + msg = w->msg; + *wl = w->next; + free(w); + return msg; + } + return 0; +} + +static void +addpid(Waitmsg *msg) +{ + Waited *w; + + w = malloc(sizeof(*w)); + if(w == nil){ + /* lost it; what can we do? */ + free(msg); + return; + } + w->msg = msg; + w->next = wd; + wd = w; +} + +static int +waitstatus(Waitmsg *w) +{ + int r, t; + char *bp, *ep; + + r = 0; + t = 0; + if(w->msg[0]){ + /* message is 'prog pid:string' */ + bp = w->msg; + while(*bp){ + if(*bp++ == ':') + break; + } + if(*bp == 0) + bp = w->msg; + r = strtol(bp, &ep, 10); + if(*ep == 0){ + if(r < 0 || r >= 256) + r = 1; + }else{ + t = _stringsig(bp); + if(t == 0) + r = 1; + } + } + return (r<<8) | t; +} + +static void +waitresource(struct rusage *ru, Waitmsg *w) +{ + memset(ru, 0, sizeof(*ru)); + ru->ru_utime.tv_sec = w->time[0]/1000; + ru->ru_utime.tv_usec = (w->time[0]%1000)*1000; + ru->ru_stime.tv_sec = w->time[1]/1000; + ru->ru_stime.tv_usec = (w->time[1]%1000)*1000; +} + +pid_t +wait(int *status) +{ + return wait4(-1, status, 0, nil); +} + +pid_t +waitpid(pid_t wpid, int *status, int options) +{ + return wait4(wpid, status, options, nil); +} + +pid_t +wait3(int *status, int options, struct rusage *res) +{ + return wait4(-1, status, options, res); +} + +pid_t +wait4(pid_t wpid, int *status, int options, struct rusage *res) +{ + char pname[50]; + Dir *d; + Waitmsg *w; + + w = lookpid(wpid); + if(w == nil){ + if(options & WNOHANG){ + snprintf(pname, sizeof(pname), "/proc/%d/wait", getpid()); + d = _dirstat(pname); + if(d != nil && d->length == 0){ + free(d); + return 0; + } + free(d); + } + for(;;){ + w = _WAIT(); + if(w == nil){ + _syserrno(); + return -1; + } + if(wpid <= 0 || w->pid == wpid) + break; + addpid(w); + } + } + if(res != nil) + waitresource(res, w); + if(status != nil) + *status = waitstatus(w); + wpid = w->pid; + free(w); + return wpid; +} diff --git a/sys/src/ape/lib/ap/plan9/write.c b/sys/src/ape/lib/ap/plan9/write.c new file mode 100755 index 000000000..6795bbc92 --- /dev/null +++ b/sys/src/ape/lib/ap/plan9/write.c @@ -0,0 +1,21 @@ +#include <errno.h> +#include <unistd.h> +#include "lib.h" +#include "sys9.h" + +ssize_t +write(int d, const void *buf, size_t nbytes) +{ + int n; + + if(d<0 || d>=OPEN_MAX || !(_fdinfo[d].flags&FD_ISOPEN)){ + errno = EBADF; + return -1; + } + if(_fdinfo[d].oflags&O_APPEND) + _SEEK(d, 0, 2); + n = _WRITE(d, buf, nbytes); + if(n < 0) + _syserrno(); + return n; +} |