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/libc/9sys |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libc/9sys')
51 files changed, 4283 insertions, 0 deletions
diff --git a/sys/src/libc/9sys/abort.c b/sys/src/libc/9sys/abort.c new file mode 100755 index 000000000..b0fd74cd5 --- /dev/null +++ b/sys/src/libc/9sys/abort.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> +void +abort(void) +{ + while(*(int*)0) + ; +} diff --git a/sys/src/libc/9sys/access.c b/sys/src/libc/9sys/access.c new file mode 100755 index 000000000..c9fee3432 --- /dev/null +++ b/sys/src/libc/9sys/access.c @@ -0,0 +1,33 @@ +#include <u.h> +#include <libc.h> + +int +access(char *name, int mode) +{ + int fd; + Dir *db; + static char omode[] = { + 0, + OEXEC, + OWRITE, + ORDWR, + OREAD, + OEXEC, /* only approximate */ + ORDWR, + ORDWR /* only approximate */ + }; + + if(mode == AEXIST){ + db = dirstat(name); + free(db); + if(db != nil) + return 0; + return -1; + } + fd = open(name, omode[mode&7]); + if(fd >= 0){ + close(fd); + return 0; + } + return -1; +} diff --git a/sys/src/libc/9sys/announce.c b/sys/src/libc/9sys/announce.c new file mode 100755 index 000000000..b2252ed21 --- /dev/null +++ b/sys/src/libc/9sys/announce.c @@ -0,0 +1,274 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> + +static int nettrans(char*, char*, int na, char*, int); + +enum +{ + Maxpath= 256, +}; + +/* + * announce a network service. + */ +int +announce(char *addr, char *dir) +{ + int ctl, n, m; + char buf[Maxpath]; + char buf2[Maxpath]; + char netdir[Maxpath]; + char naddr[Maxpath]; + char *cp; + + /* + * translate the address + */ + if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0) + return -1; + + /* + * get a control channel + */ + ctl = open(netdir, ORDWR); + if(ctl<0){ + werrstr("announce opening %s: %r", netdir); + return -1; + } + cp = strrchr(netdir, '/'); + if(cp == nil){ + werrstr("announce arg format %s", netdir); + close(ctl); + return -1; + } + *cp = 0; + + /* + * find out which line we have + */ + n = snprint(buf, sizeof(buf), "%s/", netdir); + m = read(ctl, &buf[n], sizeof(buf)-n-1); + if(m <= 0){ + werrstr("announce reading %s: %r", netdir); + close(ctl); + return -1; + } + buf[n+m] = 0; + + /* + * make the call + */ + n = snprint(buf2, sizeof(buf2), "announce %s", naddr); + if(write(ctl, buf2, n)!=n){ + werrstr("announce writing %s: %r", netdir); + close(ctl); + return -1; + } + + /* + * return directory etc. + */ + if(dir){ + strncpy(dir, buf, NETPATHLEN); + dir[NETPATHLEN-1] = 0; + } + return ctl; +} + +/* + * listen for an incoming call + */ +int +listen(char *dir, char *newdir) +{ + int ctl, n, m; + char buf[Maxpath]; + char *cp; + + /* + * open listen, wait for a call + */ + snprint(buf, sizeof(buf), "%s/listen", dir); + ctl = open(buf, ORDWR); + if(ctl < 0){ + werrstr("listen opening %s: %r", buf); + return -1; + } + + /* + * find out which line we have + */ + strncpy(buf, dir, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; + cp = strrchr(buf, '/'); + if(cp == nil){ + close(ctl); + werrstr("listen arg format %s", dir); + return -1; + } + *++cp = 0; + n = cp-buf; + m = read(ctl, cp, sizeof(buf) - n - 1); + if(m <= 0){ + close(ctl); + werrstr("listen reading %s/listen: %r", dir); + return -1; + } + buf[n+m] = 0; + + /* + * return directory etc. + */ + if(newdir){ + strncpy(newdir, buf, NETPATHLEN); + newdir[NETPATHLEN-1] = 0; + } + return ctl; + +} + +/* + * accept a call, return an fd to the open data file + */ +int +accept(int ctl, char *dir) +{ + char buf[Maxpath]; + char *num; + long n; + + num = strrchr(dir, '/'); + if(num == nil) + num = dir; + else + num++; + + n = snprint(buf, sizeof(buf), "accept %s", num); + write(ctl, buf, n); /* ignore return value, network might not need accepts */ + + snprint(buf, sizeof(buf), "%s/data", dir); + return open(buf, ORDWR); +} + +/* + * reject a call, tell device the reason for the rejection + */ +int +reject(int ctl, char *dir, char *cause) +{ + char buf[Maxpath]; + char *num; + long n; + + num = strrchr(dir, '/'); + if(num == 0) + num = dir; + else + num++; + snprint(buf, sizeof(buf), "reject %s %s", num, cause); + n = strlen(buf); + if(write(ctl, buf, n) != n) + return -1; + return 0; +} + +/* + * perform the identity translation (in case we can't reach cs) + */ +static int +identtrans(char *netdir, char *addr, char *naddr, int na, char *file, int nf) +{ + char proto[Maxpath]; + char *p; + + USED(nf); + + /* parse the protocol */ + strncpy(proto, addr, sizeof(proto)); + proto[sizeof(proto)-1] = 0; + p = strchr(proto, '!'); + if(p) + *p++ = 0; + + snprint(file, nf, "%s/%s/clone", netdir, proto); + strncpy(naddr, p, na); + naddr[na-1] = 0; + + return 1; +} + +/* + * call up the connection server and get a translation + */ +static int +nettrans(char *addr, char *naddr, int na, char *file, int nf) +{ + int i, fd; + char buf[Maxpath]; + char netdir[Maxpath]; + char *p, *p2; + long n; + + /* + * parse, get network directory + */ + p = strchr(addr, '!'); + if(p == 0){ + werrstr("bad dial string: %s", addr); + return -1; + } + if(*addr != '/'){ + strncpy(netdir, "/net", sizeof(netdir)); + netdir[sizeof(netdir) - 1] = 0; + } else { + for(p2 = p; *p2 != '/'; p2--) + ; + i = p2 - addr; + if(i == 0 || i >= sizeof(netdir)){ + werrstr("bad dial string: %s", addr); + return -1; + } + strncpy(netdir, addr, i); + netdir[i] = 0; + addr = p2 + 1; + } + + /* + * ask the connection server + */ + snprint(buf, sizeof(buf), "%s/cs", netdir); + fd = open(buf, ORDWR); + if(fd < 0) + return identtrans(netdir, addr, naddr, na, file, nf); + if(write(fd, addr, strlen(addr)) < 0){ + close(fd); + return -1; + } + seek(fd, 0, 0); + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if(n <= 0) + return -1; + buf[n] = 0; + + /* + * parse the reply + */ + p = strchr(buf, ' '); + if(p == 0) + return -1; + *p++ = 0; + strncpy(naddr, p, na); + naddr[na-1] = 0; + + if(buf[0] == '/'){ + p = strchr(buf+1, '/'); + if(p == nil) + p = buf; + else + p++; + } + snprint(file, nf, "%s/%s", netdir, p); + return 0; +} diff --git a/sys/src/libc/9sys/convD2M.c b/sys/src/libc/9sys/convD2M.c new file mode 100755 index 000000000..dfc0e5d79 --- /dev/null +++ b/sys/src/libc/9sys/convD2M.c @@ -0,0 +1,95 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +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; +} + +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++){ + if(sv[i]) + nsv[i] = strlen(sv[i]); + else + nsv[i] = 0; + ns += nsv[i]; + } + + ss = STATFIXLEN + ns; + + /* set size before 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; + if(ns) + memmove(p, sv[i], ns); + p += ns; + } + + if(ss != p - buf) + return 0; + + return p - buf; +} diff --git a/sys/src/libc/9sys/convM2D.c b/sys/src/libc/9sys/convM2D.c new file mode 100755 index 000000000..6f4b4bd93 --- /dev/null +++ b/sys/src/libc/9sys/convM2D.c @@ -0,0 +1,94 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +int +statcheck(uchar *buf, uint nbuf) +{ + uchar *ebuf; + int i; + + ebuf = buf + nbuf; + + if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)) + return -1; + + 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 char nullstring[] = ""; + +uint +convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns; + + if(nbuf < STATFIXLEN) + return 0; + + 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; + + 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){ + 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/libc/9sys/convM2S.c b/sys/src/libc/9sys/convM2S.c new file mode 100755 index 000000000..fcdcd42d6 --- /dev/null +++ b/sys/src/libc/9sys/convM2S.c @@ -0,0 +1,315 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static +uchar* +gstring(uchar *p, uchar *ep, char **s) +{ + uint n; + + if(p+BIT16SZ > ep) + return nil; + n = GBIT16(p); + p += BIT16SZ - 1; + if(p+n+1 > ep) + return nil; + /* move it down, on top of count, to make room for '\0' */ + memmove(p, p + 1, n); + p[n] = '\0'; + *s = (char*)p; + p += n+1; + return p; +} + +static +uchar* +gqid(uchar *p, uchar *ep, Qid *q) +{ + if(p+QIDSZ > ep) + return nil; + q->type = GBIT8(p); + p += BIT8SZ; + q->vers = GBIT32(p); + p += BIT32SZ; + q->path = GBIT64(p); + p += BIT64SZ; + return p; +} + +/* + * no syntactic checks. + * three causes for error: + * 1. message size field is incorrect + * 2. input buffer too short for its own data (counts too long, etc.) + * 3. too many names or qids + * gqid() and gstring() return nil if they would reach beyond buffer. + * main switch statement checks range and also can fall through + * to test at end of routine. + */ +uint +convM2S(uchar *ap, uint nap, Fcall *f) +{ + uchar *p, *ep; + uint i, size; + + p = ap; + ep = p + nap; + + if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) + return 0; + size = GBIT32(p); + p += BIT32SZ; + + if(size < BIT32SZ+BIT8SZ+BIT16SZ) + return 0; + + f->type = GBIT8(p); + p += BIT8SZ; + f->tag = GBIT16(p); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Tflush: + if(p+BIT16SZ > ep) + return 0; + f->oldtag = GBIT16(p); + p += BIT16SZ; + break; + + case Tauth: + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Tattach: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Twalk: + if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->newfid = GBIT32(p); + p += BIT32SZ; + f->nwname = GBIT16(p); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; i<f->nwname; i++){ + p = gstring(p, ep, &f->wname[i]); + if(p == nil) + break; + } + break; + + case Topen: + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tcreate: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->name); + if(p == nil) + break; + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->perm = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tread: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Twrite: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Tclunk: + case Tremove: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Tstat: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Twstat: + if(p+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + +/* + */ + case Rversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Rerror: + p = gstring(p, ep, &f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = gqid(p, ep, &f->aqid); + if(p == nil) + break; + break; + + case Rattach: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + break; + + case Rwalk: + if(p+BIT16SZ > ep) + return 0; + f->nwqid = GBIT16(p); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; i<f->nwqid; i++){ + p = gqid(p, ep, &f->wqid[i]); + if(p == nil) + break; + } + break; + + case Ropen: + case Rcreate: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + if(p+BIT32SZ > ep) + return 0; + f->iounit = GBIT32(p); + p += BIT32SZ; + break; + + case Rread: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Rwrite: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Rclunk: + case Rremove: + break; + + case Rstat: + if(p+BIT16SZ > ep) + return 0; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + + case Rwstat: + break; + } + + if(p==nil || p>ep) + return 0; + if(ap+size == p) + return size; + return 0; +} diff --git a/sys/src/libc/9sys/convS2M.c b/sys/src/libc/9sys/convS2M.c new file mode 100755 index 000000000..fb5f596ce --- /dev/null +++ b/sys/src/libc/9sys/convS2M.c @@ -0,0 +1,389 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static +uchar* +pstring(uchar *p, char *s) +{ + uint n; + + if(s == nil){ + PBIT16(p, 0); + p += BIT16SZ; + return p; + } + + n = strlen(s); + /* + * We are moving the string before the length, + * so you can S2M a struct into an existing message + */ + memmove(p + BIT16SZ, s, n); + PBIT16(p, n); + p += n + BIT16SZ; + return p; +} + +static +uchar* +pqid(uchar *p, Qid *q) +{ + PBIT8(p, q->type); + p += BIT8SZ; + PBIT32(p, q->vers); + p += BIT32SZ; + PBIT64(p, q->path); + p += BIT64SZ; + return p; +} + +static +uint +stringsz(char *s) +{ + if(s == nil) + return BIT16SZ; + + return BIT16SZ+strlen(s); +} + +uint +sizeS2M(Fcall *f) +{ + uint n; + int i; + + n = 0; + n += BIT32SZ; /* size */ + n += BIT8SZ; /* type */ + n += BIT16SZ; /* tag */ + + switch(f->type) + { + default: + return 0; + + case Tversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Tflush: + n += BIT16SZ; + break; + + case Tauth: + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Tattach: + n += BIT32SZ; + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Twalk: + n += BIT32SZ; + n += BIT32SZ; + n += BIT16SZ; + for(i=0; i<f->nwname; i++) + n += stringsz(f->wname[i]); + break; + + case Topen: + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tcreate: + n += BIT32SZ; + n += stringsz(f->name); + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tread: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + break; + + case Twrite: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + n += f->count; + break; + + case Tclunk: + case Tremove: + n += BIT32SZ; + break; + + case Tstat: + n += BIT32SZ; + break; + + case Twstat: + n += BIT32SZ; + n += BIT16SZ; + n += f->nstat; + break; +/* + */ + + case Rversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Rerror: + n += stringsz(f->ename); + break; + + case Rflush: + break; + + case Rauth: + n += QIDSZ; + break; + + case Rattach: + n += QIDSZ; + break; + + case Rwalk: + n += BIT16SZ; + n += f->nwqid*QIDSZ; + break; + + case Ropen: + case Rcreate: + n += QIDSZ; + n += BIT32SZ; + break; + + case Rread: + n += BIT32SZ; + n += f->count; + break; + + case Rwrite: + n += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + n += BIT16SZ; + n += f->nstat; + break; + + case Rwstat: + break; + } + return n; +} + +uint +convS2M(Fcall *f, uchar *ap, uint nap) +{ + uchar *p; + uint i, size; + + size = sizeS2M(f); + if(size == 0) + return 0; + if(size > nap) + return 0; + + p = (uchar*)ap; + + PBIT32(p, size); + p += BIT32SZ; + PBIT8(p, f->type); + p += BIT8SZ; + PBIT16(p, f->tag); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Tflush: + PBIT16(p, f->oldtag); + p += BIT16SZ; + break; + + case Tauth: + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Tattach: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Twalk: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->newfid); + p += BIT32SZ; + PBIT16(p, f->nwname); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; i<f->nwname; i++) + p = pstring(p, f->wname[i]); + break; + + case Topen: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tcreate: + PBIT32(p, f->fid); + p += BIT32SZ; + p = pstring(p, f->name); + PBIT32(p, f->perm); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tread: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Twrite: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Tclunk: + case Tremove: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Tstat: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Twstat: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; +/* + */ + + case Rversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Rerror: + p = pstring(p, f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = pqid(p, &f->aqid); + break; + + case Rattach: + p = pqid(p, &f->qid); + break; + + case Rwalk: + PBIT16(p, f->nwqid); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; i<f->nwqid; i++) + p = pqid(p, &f->wqid[i]); + break; + + case Ropen: + case Rcreate: + p = pqid(p, &f->qid); + PBIT32(p, f->iounit); + p += BIT32SZ; + break; + + case Rread: + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Rwrite: + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; + + case Rwstat: + break; + } + if(size != p-ap) + return 0; + return size; +} diff --git a/sys/src/libc/9sys/cputime.c b/sys/src/libc/9sys/cputime.c new file mode 100755 index 000000000..1e05634aa --- /dev/null +++ b/sys/src/libc/9sys/cputime.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +#define HZ 1000 + +double +cputime(void) +{ + long t[4]; + long times(long*); + int i; + + times(t); + for(i=1; i<4; i++) + t[0] += t[i]; + return t[0] / (double)HZ; +} diff --git a/sys/src/libc/9sys/ctime.c b/sys/src/libc/9sys/ctime.c new file mode 100755 index 000000000..d841b64e9 --- /dev/null +++ b/sys/src/libc/9sys/ctime.c @@ -0,0 +1,304 @@ +/* + * 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 GMT 1970n0 + * 012345678901234567890123456789 + * 0 1 2 + * + * ctime(t) just calls localtime, then asctime. + */ + +#include <u.h> +#include <libc.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); + +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, long*); +static +struct +{ + char stname[4]; + char dlname[4]; + long stdiff; + long dldiff; + long dlpairs[TZSIZE]; +} timezone; + +char* +ctime(long t) +{ + return asctime(localtime(t)); +} + +Tm* +localtime(long tim) +{ + Tm *ct; + long t, *p; + int dlflag; + + 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(t); + if(dlflag){ + strcpy(ct->zone, timezone.dlname); + ct->tzoff = timezone.dldiff; + } else { + strcpy(ct->zone, timezone.stname); + ct->tzoff = timezone.stdiff; + } + return ct; +} + +Tm* +gmtime(long tim) +{ + int d0, d1; + long hms, day; + static Tm xtime; + + /* + * break initial number into days + */ + hms = tim % 86400L; + day = tim / 86400L; + if(hms < 0) { + hms += 86400L; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + xtime.sec = hms % 60; + d1 = hms / 60; + xtime.min = d1 % 60; + d1 /= 60; + xtime.hour = d1; + + /* + * day is the day number. + * generate day of the week. + * The addend is 4 mod 7 (1/1/1970 was Thursday) + */ + + xtime.wday = (day + 7340036L) % 7; + + /* + * year number + */ + if(day >= 0) + for(d1 = 1970; day >= dysize(d1); d1++) + day -= dysize(d1); + else + for (d1 = 1970; day < 0; d1--) + day += dysize(d1-1); + xtime.year = d1-1900; + xtime.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; + xtime.mday = d0 + 1; + xtime.mon = d1; + strcpy(xtime.zone, "GMT"); + return &xtime; +} + +char* +asctime(Tm *t) +{ + char *ncp; + static char cbuf[30]; + + strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n"); + ncp = &"SunMonTueWedThuFriSat"[t->wday*3]; + cbuf[0] = *ncp++; + cbuf[1] = *ncp++; + cbuf[2] = *ncp; + ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3]; + cbuf[4] = *ncp++; + cbuf[5] = *ncp++; + cbuf[6] = *ncp; + ct_numb(cbuf+8, t->mday); + ct_numb(cbuf+11, t->hour+100); + ct_numb(cbuf+14, t->min+100); + ct_numb(cbuf+17, t->sec+100); + ncp = t->zone; + cbuf[20] = *ncp++; + cbuf[21] = *ncp++; + cbuf[22] = *ncp; + if(t->year >= 100) { + cbuf[24] = '2'; + cbuf[25] = '0'; + } + ct_numb(cbuf+26, t->year+100); + return cbuf; +} + +static +dysize(int y) +{ + + if(y%4 == 0 && (y%100 != 0 || y%400 == 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)){ + close(i); + 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/libc/9sys/dial.c b/sys/src/libc/9sys/dial.c new file mode 100755 index 000000000..74fc6e6ae --- /dev/null +++ b/sys/src/libc/9sys/dial.c @@ -0,0 +1,492 @@ +/* + * dial - connect to a service (parallel version) + */ +#include <u.h> +#include <libc.h> + +typedef struct Conn Conn; +typedef struct Dest Dest; +typedef struct DS DS; + +enum +{ + Maxstring = 128, + Maxpath = 256, + + Maxcsreply = 64*80, /* this is probably overly generous */ + /* + * this should be a plausible slight overestimate for non-interactive + * use even if it's ridiculously long for interactive use. + */ + Maxconnms = 20*60*1000, /* 20 minutes */ +}; + +struct DS { + /* dist string */ + char buf[Maxstring]; + char *netdir; + char *proto; + char *rem; + + /* other args */ + char *local; + char *dir; + int *cfdp; +}; + +/* + * malloc these; they need to be writable by this proc & all children. + * the stack is private to each proc, and static allocation in the data + * segment would not permit concurrent dials within a multi-process program. + */ +struct Conn { + int pid; + int dead; + + int dfd; + int cfd; + char dir[NETPATHLEN]; + char err[ERRMAX]; +}; +struct Dest { + Conn *conn; /* allocated array */ + Conn *connend; + int nkid; + + QLock winlck; + int winner; /* index into conn[] */ + + char *nextaddr; + char addrlist[Maxcsreply]; +}; + +static int call(char*, char*, DS*, Dest*, Conn*); +static int csdial(DS*); +static void _dial_string_parse(char*, DS*); + + +/* + * the dialstring is of the form '[/net/]proto!dest' + */ +static int +dialimpl(char *dest, char *local, char *dir, int *cfdp) +{ + DS ds; + int rv; + char err[ERRMAX], alterr[ERRMAX]; + + ds.local = local; + ds.dir = dir; + ds.cfdp = cfdp; + + _dial_string_parse(dest, &ds); + if(ds.netdir) + return csdial(&ds); + + ds.netdir = "/net"; + rv = csdial(&ds); + if(rv >= 0) + return rv; + err[0] = '\0'; + errstr(err, sizeof err); + if(strstr(err, "refused") != 0){ + werrstr("%s", err); + return rv; + } + ds.netdir = "/net.alt"; + rv = csdial(&ds); + if(rv >= 0) + return rv; + + alterr[0] = 0; + errstr(alterr, sizeof alterr); + if(strstr(alterr, "translate") || strstr(alterr, "does not exist")) + werrstr("%s", err); + else + werrstr("%s", alterr); + return rv; +} + +/* + * the thread library can't cope with rfork(RFMEM|RFPROC), + * so it must override this with a private version of dial. + */ +int (*_dial)(char *, char *, char *, int *) = dialimpl; + +int +dial(char *dest, char *local, char *dir, int *cfdp) +{ + return (*_dial)(dest, local, dir, cfdp); +} + +static int +connsalloc(Dest *dp, int addrs) +{ + free(dp->conn); + dp->connend = nil; + assert(addrs > 0); + + dp->conn = mallocz(addrs * sizeof *dp->conn, 1); + if(dp->conn == nil) + return -1; + dp->connend = dp->conn + addrs; + return 0; +} + +static void +freedest(Dest *dp) +{ + if (dp != nil) { + free(dp->conn); + free(dp); + } +} + +static void +closeopenfd(int *fdp) +{ + if (*fdp > 0) { + close(*fdp); + *fdp = -1; + } +} + +static void +notedeath(Dest *dp, char *exitsts) +{ + int i, n, pid; + char *fields[5]; /* pid + 3 times + error */ + Conn *conn; + + for (i = 0; i < nelem(fields); i++) + fields[i] = ""; + n = tokenize(exitsts, fields, nelem(fields)); + if (n < 4) + return; + pid = atoi(fields[0]); + if (pid <= 0) + return; + for (conn = dp->conn; conn < dp->connend; conn++) + if (conn->pid == pid && !conn->dead) { /* it's one we know? */ + if (conn - dp->conn != dp->winner) { + closeopenfd(&conn->dfd); + closeopenfd(&conn->cfd); + } + strncpy(conn->err, fields[4], sizeof conn->err); + conn->dead = 1; + return; + } + /* not a proc that we forked */ +} + +static int +outstandingprocs(Dest *dp) +{ + Conn *conn; + + for (conn = dp->conn; conn < dp->connend; conn++) + if (!conn->dead) + return 1; + return 0; +} + +static int +reap(Dest *dp) +{ + char exitsts[2*ERRMAX]; + + if (outstandingprocs(dp) && await(exitsts, sizeof exitsts) >= 0) { + notedeath(dp, exitsts); + return 0; + } + return -1; +} + +static int +fillinds(DS *ds, Dest *dp) +{ + Conn *conn; + + if (dp->winner < 0) + return -1; + conn = &dp->conn[dp->winner]; + if (ds->cfdp) + *ds->cfdp = conn->cfd; + if (ds->dir) + strncpy(ds->dir, conn->dir, NETPATHLEN); + return conn->dfd; +} + +static int +connectwait(Dest *dp, char *besterr) +{ + Conn *conn; + + /* wait for a winner or all attempts to time out */ + while (dp->winner < 0 && reap(dp) >= 0) + ; + + /* kill all of our still-live kids & reap them */ + for (conn = dp->conn; conn < dp->connend; conn++) + if (!conn->dead) + postnote(PNPROC, conn->pid, "die"); + while (reap(dp) >= 0) + ; + + /* rummage about and report some error string */ + for (conn = dp->conn; conn < dp->connend; conn++) + if (conn - dp->conn != dp->winner && conn->dead && + conn->err[0]) { + strncpy(besterr, conn->err, ERRMAX); + break; + } + return dp->winner; +} + +static int +parsecs(Dest *dp, char **clonep, char **destp) +{ + char *dest, *p; + + dest = strchr(dp->nextaddr, ' '); + if(dest == nil) + return -1; + *dest++ = '\0'; + p = strchr(dest, '\n'); + if(p == nil) + return -1; + *p++ = '\0'; + *clonep = dp->nextaddr; + *destp = dest; + dp->nextaddr = p; /* advance to next line */ + return 0; +} + +static void +pickuperr(char *besterr, char *err) +{ + err[0] = '\0'; + errstr(err, ERRMAX); + if(strstr(err, "does not exist") == 0) + strcpy(besterr, err); +} + +/* + * try all addresses in parallel and take the first one that answers; + * this helps when systems have ip v4 and v6 addresses but are + * only reachable from here on one (or some) of them. + */ +static int +dialmulti(DS *ds, Dest *dp) +{ + int rv, kid, kidme; + char *clone, *dest; + char err[ERRMAX], besterr[ERRMAX]; + + dp->winner = -1; + dp->nkid = 0; + while(dp->winner < 0 && *dp->nextaddr != '\0' && + parsecs(dp, &clone, &dest) >= 0) { + kidme = dp->nkid++; /* make private copy on stack */ + kid = rfork(RFPROC|RFMEM); /* spin off a call attempt */ + if (kid < 0) + --dp->nkid; + else if (kid == 0) { + alarm(Maxconnms); + *besterr = '\0'; + rv = call(clone, dest, ds, dp, &dp->conn[kidme]); + if(rv < 0) + pickuperr(besterr, err); + _exits(besterr); /* avoid atexit callbacks */ + } + } + rv = connectwait(dp, besterr); + if(rv < 0 && *besterr) + werrstr("%s", besterr); + else + werrstr("%s", err); + return rv; +} + +static int +csdial(DS *ds) +{ + int n, fd, rv, addrs, bleft; + char c; + char *addrp, *clone2, *dest; + char buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX]; + Dest *dp; + + dp = mallocz(sizeof *dp, 1); + if(dp == nil) + return -1; + dp->winner = -1; + if (connsalloc(dp, 1) < 0) { /* room for a single conn. */ + freedest(dp); + return -1; + } + + /* + * open connection server + */ + snprint(buf, sizeof(buf), "%s/cs", ds->netdir); + fd = open(buf, ORDWR); + if(fd < 0){ + /* no connection server, don't translate */ + snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto); + rv = call(clone, ds->rem, ds, dp, &dp->conn[0]); + fillinds(ds, dp); + freedest(dp); + return rv; + } + + /* + * ask connection server to translate + */ + snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem); + if(write(fd, buf, strlen(buf)) < 0){ + close(fd); + freedest(dp); + return -1; + } + + /* + * read all addresses from the connection server. + */ + seek(fd, 0, 0); + addrs = 0; + addrp = dp->nextaddr = dp->addrlist; + bleft = sizeof dp->addrlist - 2; /* 2 is room for \n\0 */ + while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) { + if (addrp[n-1] != '\n') + addrp[n++] = '\n'; + addrs++; + addrp += n; + bleft -= n; + } + /* + * if we haven't read all of cs's output, assume the last line might + * have been truncated and ignore it. we really don't expect this + * to happen. + */ + if (addrs > 0 && bleft <= 0 && read(fd, &c, 1) == 1) + addrs--; + close(fd); + + *besterr = 0; + rv = -1; /* pessimistic default */ + if (addrs == 0) + werrstr("no address to dial"); + else if (addrs == 1) { + /* common case: dial one address without forking */ + if (parsecs(dp, &clone2, &dest) >= 0 && + (rv = call(clone2, dest, ds, dp, &dp->conn[0])) < 0) { + pickuperr(besterr, err); + werrstr("%s", besterr); + } + } else if (connsalloc(dp, addrs) >= 0) + rv = dialmulti(ds, dp); + + /* fill in results */ + if (rv >= 0 && dp->winner >= 0) + rv = fillinds(ds, dp); + + freedest(dp); + return rv; +} + +static int +call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn) +{ + int fd, cfd, n; + char cname[Maxpath], name[Maxpath], data[Maxpath], *p; + + /* because cs is in a different name space, replace the mount point */ + if(*clone == '/'){ + p = strchr(clone+1, '/'); + if(p == nil) + p = clone; + else + p++; + } else + p = clone; + snprint(cname, sizeof cname, "%s/%s", ds->netdir, p); + + conn->pid = getpid(); + conn->cfd = cfd = open(cname, ORDWR); + if(cfd < 0) + return -1; + + /* get directory name */ + n = read(cfd, name, sizeof(name)-1); + if(n < 0){ + closeopenfd(&conn->cfd); + return -1; + } + name[n] = 0; + for(p = name; *p == ' '; p++) + ; + snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0)); + p = strrchr(cname, '/'); + *p = 0; + if(ds->dir) + snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name); + snprint(data, sizeof(data), "%s/%s/data", cname, name); + + /* connect */ + if(ds->local) + snprint(name, sizeof(name), "connect %s %s", dest, ds->local); + else + snprint(name, sizeof(name), "connect %s", dest); + if(write(cfd, name, strlen(name)) < 0){ + closeopenfd(&conn->cfd); + return -1; + } + + /* open data connection */ + conn->dfd = fd = open(data, ORDWR); + if(fd < 0){ + closeopenfd(&conn->cfd); + return -1; + } + if(ds->cfdp == nil) + closeopenfd(&conn->cfd); + + qlock(&dp->winlck); + if (dp->winner < 0 && conn < dp->connend) + dp->winner = conn - dp->conn; + qunlock(&dp->winlck); + return fd; +} + +/* + * parse a dial string + */ +static void +_dial_string_parse(char *str, DS *ds) +{ + char *p, *p2; + + strncpy(ds->buf, str, Maxstring); + ds->buf[Maxstring-1] = 0; + + p = strchr(ds->buf, '!'); + if(p == 0) { + ds->netdir = 0; + ds->proto = "net"; + ds->rem = ds->buf; + } else { + if(*ds->buf != '/' && *ds->buf != '#'){ + ds->netdir = 0; + ds->proto = ds->buf; + } else { + for(p2 = p; *p2 != '/'; p2--) + ; + *p2++ = 0; + ds->netdir = ds->buf; + ds->proto = p2; + } + *p = 0; + ds->rem = p + 1; + } +} diff --git a/sys/src/libc/9sys/dirfstat.c b/sys/src/libc/9sys/dirfstat.c new file mode 100755 index 000000000..0534a2278 --- /dev/null +++ b/sys/src/libc/9sys/dirfstat.c @@ -0,0 +1,37 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +enum +{ + DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */ +}; + +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) + BIT16SZ + nd); + if(d == nil) + return nil; + buf = (uchar*)&d[1]; + n = fstat(fd, buf, BIT16SZ+nd); + if(n < BIT16SZ){ + free(d); + return nil; + } + nd = GBIT16(buf); /* upper bound on size of Dir + strings */ + if(nd <= n){ + convM2D(buf, n, d, (char*)&d[1]); + return d; + } + /* else sizeof(Dir)+BIT16SZ+nd is plenty */ + free(d); + } + return nil; +} diff --git a/sys/src/libc/9sys/dirfwstat.c b/sys/src/libc/9sys/dirfwstat.c new file mode 100755 index 000000000..85803ff4c --- /dev/null +++ b/sys/src/libc/9sys/dirfwstat.c @@ -0,0 +1,19 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +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; +} diff --git a/sys/src/libc/9sys/dirmodefmt.c b/sys/src/libc/9sys/dirmodefmt.c new file mode 100755 index 000000000..82eb5a308 --- /dev/null +++ b/sys/src/libc/9sys/dirmodefmt.c @@ -0,0 +1,48 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static char *modes[] = +{ + "---", + "--x", + "-w-", + "-wx", + "r--", + "r-x", + "rw-", + "rwx", +}; + +static void +rwx(long m, char *s) +{ + strncpy(s, modes[m], 3); +} + +int +dirmodefmt(Fmt *f) +{ + static char buf[16]; + ulong m; + + m = va_arg(f->args, ulong); + + if(m & DMDIR) + buf[0]='d'; + else if(m & DMAPPEND) + buf[0]='a'; + else if(m & DMAUTH) + buf[0]='A'; + else + buf[0]='-'; + if(m & DMEXCL) + buf[1]='l'; + else + buf[1]='-'; + rwx((m>>6)&7, buf+2); + rwx((m>>3)&7, buf+5); + rwx((m>>0)&7, buf+8); + buf[11] = 0; + return fmtstrcpy(f, buf); +} diff --git a/sys/src/libc/9sys/dirread.c b/sys/src/libc/9sys/dirread.c new file mode 100755 index 000000000..0efd2f954 --- /dev/null +++ b/sys/src/libc/9sys/dirread.c @@ -0,0 +1,97 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static +long +dirpackage(uchar *buf, long ts, Dir **d) +{ + char *s; + long ss, i, n, nn, m; + + *d = nil; + if(ts <= 0) + 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); + *d = nil; + 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); + if(ts == 0 && n < 0) + return -1; + return ts; +} diff --git a/sys/src/libc/9sys/dirstat.c b/sys/src/libc/9sys/dirstat.c new file mode 100755 index 000000000..eb5171d2a --- /dev/null +++ b/sys/src/libc/9sys/dirstat.c @@ -0,0 +1,37 @@ +#include <u.h> +#include <libc.h> +#include <fcall.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); /* upper bound on size of Dir + strings */ + if(nd <= n){ + convM2D(buf, n, d, (char*)&d[1]); + return d; + } + /* else sizeof(Dir)+BIT16SZ+nd is plenty */ + free(d); + } + return nil; +} diff --git a/sys/src/libc/9sys/dirwstat.c b/sys/src/libc/9sys/dirwstat.c new file mode 100755 index 000000000..cb62e3fc4 --- /dev/null +++ b/sys/src/libc/9sys/dirwstat.c @@ -0,0 +1,19 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +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; +} diff --git a/sys/src/libc/9sys/fcallfmt.c b/sys/src/libc/9sys/fcallfmt.c new file mode 100755 index 000000000..c5a8af614 --- /dev/null +++ b/sys/src/libc/9sys/fcallfmt.c @@ -0,0 +1,234 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static uint dumpsome(char*, char*, char*, long); +static void fdirconv(char*, char*, Dir*); +static char *qidtype(char*, uchar); + +#define QIDFMT "(%.16llux %lud %s)" + +int +fcallfmt(Fmt *fmt) +{ + Fcall *f; + int fid, type, tag, i; + char buf[512], tmp[200]; + char *p, *e; + Dir *d; + Qid *q; + + e = buf+sizeof(buf); + f = va_arg(fmt->args, Fcall*); + type = f->type; + fid = f->fid; + tag = f->tag; + switch(type){ + case Tversion: /* 100 */ + seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Rversion: + seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Tauth: /* 102 */ + seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag, + f->afid, f->uname, f->aname); + break; + case Rauth: + seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag, + f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type)); + break; + case Tattach: /* 104 */ + seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag, + fid, f->afid, f->uname, f->aname); + break; + case Rattach: + seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type)); + break; + case Rerror: /* 107; 106 (Terror) illegal */ + seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename); + break; + case Tflush: /* 108 */ + seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag); + break; + case Rflush: + seprint(buf, e, "Rflush tag %ud", tag); + break; + case Twalk: /* 110 */ + p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname); + if(f->nwname <= MAXWELEM) + for(i=0; i<f->nwname; i++) + p = seprint(p, e, "%d:%s ", i, f->wname[i]); + break; + case Rwalk: + p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid); + if(f->nwqid <= MAXWELEM) + for(i=0; i<f->nwqid; i++){ + q = &f->wqid[i]; + p = seprint(p, e, "%d:" QIDFMT " ", i, + q->path, q->vers, qidtype(tmp, q->type)); + } + break; + case Topen: /* 112 */ + seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode); + break; + case Ropen: + seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tcreate: /* 114 */ + seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode); + break; + case Rcreate: + seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tread: /* 116 */ + seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud", + tag, fid, f->offset, f->count); + break; + case Rread: + p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Twrite: /* 118 */ + p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ", + tag, fid, f->offset, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Rwrite: + seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count); + break; + case Tclunk: /* 120 */ + seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid); + break; + case Rclunk: + seprint(buf, e, "Rclunk tag %ud", tag); + break; + case Tremove: /* 122 */ + seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid); + break; + case Rremove: + seprint(buf, e, "Rremove tag %ud", tag); + break; + case Tstat: /* 124 */ + seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid); + break; + case Rstat: + p = seprint(buf, e, "Rstat tag %ud ", tag); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Twstat: /* 126 */ + p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Rwstat: + seprint(buf, e, "Rwstat tag %ud", tag); + break; + default: + seprint(buf, e, "unknown type %d", type); + } + return fmtstrcpy(fmt, buf); +} + +static char* +qidtype(char *s, uchar t) +{ + char *p; + + p = s; + if(t & QTDIR) + *p++ = 'd'; + if(t & QTAPPEND) + *p++ = 'a'; + if(t & QTEXCL) + *p++ = 'l'; + if(t & QTAUTH) + *p++ = 'A'; + *p = '\0'; + return s; +} + +int +dirfmt(Fmt *fmt) +{ + char buf[160]; + + fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*)); + return fmtstrcpy(fmt, buf); +} + +static void +fdirconv(char *buf, char *e, Dir *d) +{ + char tmp[16]; + + seprint(buf, e, "'%s' '%s' '%s' '%s' " + "q " QIDFMT " m %#luo " + "at %ld mt %ld l %lld " + "t %d d %d", + d->name, d->uid, d->gid, d->muid, + d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode, + d->atime, d->mtime, d->length, + d->type, d->dev); +} + +/* + * dump out count (or DUMPL, if count is bigger) bytes from + * buf to ans, as a string if they are all printable, + * else as a series of hex bytes + */ +#define DUMPL 64 + +static uint +dumpsome(char *ans, char *e, char *buf, long count) +{ + int i, printable; + char *p; + + if(buf == nil){ + seprint(ans, e, "<no data>"); + return strlen(ans); + } + printable = 1; + if(count > DUMPL) + count = DUMPL; + for(i=0; i<count && printable; i++) + if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127) + printable = 0; + p = ans; + *p++ = '\''; + if(printable){ + if(count > e-p-2) + count = e-p-2; + memmove(p, buf, count); + p += count; + }else{ + if(2*count > e-p-2) + count = (e-p-2)/2; + for(i=0; i<count; i++){ + if(i>0 && i%4==0) + *p++ = ' '; + sprint(p, "%2.2ux", (uchar)buf[i]); + p += 2; + } + } + *p++ = '\''; + *p = 0; + return p - ans; +} diff --git a/sys/src/libc/9sys/fork.c b/sys/src/libc/9sys/fork.c new file mode 100755 index 000000000..46296ed5d --- /dev/null +++ b/sys/src/libc/9sys/fork.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +int +fork(void) +{ + return rfork(RFPROC|RFFDG|RFREND); +} diff --git a/sys/src/libc/9sys/getenv.c b/sys/src/libc/9sys/getenv.c new file mode 100755 index 000000000..146b35b62 --- /dev/null +++ b/sys/src/libc/9sys/getenv.c @@ -0,0 +1,36 @@ +#include <u.h> +#include <libc.h> + +char* +getenv(char *name) +{ + int r, f; + long s; + char *ans; + char *p, *ep, ename[100]; + + if(strchr(name, '/') != nil) + return nil; + snprint(ename, sizeof ename, "/env/%s", name); + if(strcmp(ename+5, name) != 0) + return nil; + f = open(ename, OREAD); + if(f < 0) + return 0; + s = seek(f, 0, 2); + ans = malloc(s+1); + if(ans) { + setmalloctag(ans, getcallerpc(&name)); + seek(f, 0, 0); + r = read(f, ans, s); + if(r >= 0) { + ep = ans + s - 1; + for(p = ans; p < ep; p++) + if(*p == '\0') + *p = ' '; + ans[s] = '\0'; + } + } + close(f); + return ans; +} diff --git a/sys/src/libc/9sys/getnetconninfo.c b/sys/src/libc/9sys/getnetconninfo.c new file mode 100755 index 000000000..8dbb95f89 --- /dev/null +++ b/sys/src/libc/9sys/getnetconninfo.c @@ -0,0 +1,133 @@ +#include <u.h> +#include <libc.h> + +static char *unknown = "???"; + +static void +getendpoint(char *dir, char *file, char **sysp, char **servp) +{ + int fd, n; + char buf[128]; + char *sys, *serv; + + sys = serv = 0; + + snprint(buf, sizeof buf, "%s/%s", dir, file); + fd = open(buf, OREAD); + if(fd >= 0){ + n = read(fd, buf, sizeof(buf)-1); + if(n>0){ + buf[n-1] = 0; + serv = strchr(buf, '!'); + if(serv){ + *serv++ = 0; + serv = strdup(serv); + } + sys = strdup(buf); + } + close(fd); + } + if(serv == 0) + serv = unknown; + if(sys == 0) + sys = unknown; + *servp = serv; + *sysp = sys; +} + +NetConnInfo* +getnetconninfo(char *dir, int fd) +{ + NetConnInfo *nci; + char *cp; + Dir *d; + char spec[10]; + char path[128]; + char netname[128], *p; + + /* get a directory address via fd */ + if(dir == nil || *dir == 0){ + if(fd2path(fd, path, sizeof(path)) < 0) + return nil; + cp = strrchr(path, '/'); + if(cp == nil) + return nil; + *cp = 0; + dir = path; + } + + nci = mallocz(sizeof *nci, 1); + if(nci == nil) + return nil; + + /* copy connection directory */ + nci->dir = strdup(dir); + if(nci->dir == nil) + goto err; + + /* get netroot */ + nci->root = strdup(dir); + if(nci->root == nil) + goto err; + cp = strchr(nci->root+1, '/'); + if(cp == nil) + goto err; + *cp = 0; + + /* figure out bind spec */ + d = dirstat(nci->dir); + if(d != nil){ + sprint(spec, "#%C%d", d->type, d->dev); + nci->spec = strdup(spec); + } + if(nci->spec == nil) + nci->spec = unknown; + free(d); + + /* get the two end points */ + getendpoint(nci->dir, "local", &nci->lsys, &nci->lserv); + if(nci->lsys == nil || nci->lserv == nil) + goto err; + getendpoint(nci->dir, "remote", &nci->rsys, &nci->rserv); + if(nci->rsys == nil || nci->rserv == nil) + goto err; + + strecpy(netname, netname+sizeof netname, nci->dir); + if((p = strrchr(netname, '/')) != nil) + *p = 0; + if(strncmp(netname, "/net/", 5) == 0) + memmove(netname, netname+5, strlen(netname+5)+1); + nci->laddr = smprint("%s!%s!%s", netname, nci->lsys, nci->lserv); + nci->raddr = smprint("%s!%s!%s", netname, nci->rsys, nci->rserv); + if(nci->laddr == nil || nci->raddr == nil) + goto err; + return nci; +err: + freenetconninfo(nci); + return nil; +} + +static void +xfree(char *x) +{ + if(x == nil || x == unknown) + return; + free(x); +} + +void +freenetconninfo(NetConnInfo *nci) +{ + if(nci == nil) + return; + xfree(nci->root); + xfree(nci->dir); + xfree(nci->spec); + xfree(nci->lsys); + xfree(nci->lserv); + xfree(nci->rsys); + xfree(nci->rserv); + xfree(nci->laddr); + xfree(nci->raddr); + free(nci); +} diff --git a/sys/src/libc/9sys/getpid.c b/sys/src/libc/9sys/getpid.c new file mode 100755 index 000000000..9a9c86c13 --- /dev/null +++ b/sys/src/libc/9sys/getpid.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +int +getpid(void) +{ + char b[20]; + int f; + + memset(b, 0, sizeof(b)); + f = open("#c/pid", 0); + if(f >= 0) { + read(f, b, sizeof(b)); + close(f); + } + return atol(b); +} diff --git a/sys/src/libc/9sys/getppid.c b/sys/src/libc/9sys/getppid.c new file mode 100755 index 000000000..b90b57ee5 --- /dev/null +++ b/sys/src/libc/9sys/getppid.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +int +getppid(void) +{ + char b[20]; + int f; + + memset(b, 0, sizeof(b)); + f = open("/dev/ppid", 0); + if(f >= 0) { + read(f, b, sizeof(b)); + close(f); + } + return atol(b); +} diff --git a/sys/src/libc/9sys/getwd.c b/sys/src/libc/9sys/getwd.c new file mode 100755 index 000000000..ed73cb775 --- /dev/null +++ b/sys/src/libc/9sys/getwd.c @@ -0,0 +1,19 @@ +#include <u.h> +#include <libc.h> + +static char *nsgetwd(char*, int); + +char* +getwd(char *buf, int nbuf) +{ + int n, fd; + + fd = open(".", OREAD); + if(fd < 0) + return nil; + n = fd2path(fd, buf, nbuf); + close(fd); + if(n < 0) + return nil; + return buf; +} diff --git a/sys/src/libc/9sys/iounit.c b/sys/src/libc/9sys/iounit.c new file mode 100755 index 000000000..194b17173 --- /dev/null +++ b/sys/src/libc/9sys/iounit.c @@ -0,0 +1,27 @@ +#include <u.h> +#include <libc.h> + +/* + * Format: + 3 r M 4 (0000000000457def 11 00) 8192 512 /rc/lib/rcmain + */ + +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(tokenize(buf, args, nelem(args)) != nelem(args)) + return 0; + return atoi(args[7]); +} diff --git a/sys/src/libc/9sys/mkfile b/sys/src/libc/9sys/mkfile new file mode 100755 index 000000000..3b7d95e8e --- /dev/null +++ b/sys/src/libc/9sys/mkfile @@ -0,0 +1,64 @@ +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a +OFILES=\ + abort.$O\ + access.$O\ + announce.$O\ + convD2M.$O\ + convM2D.$O\ + convM2S.$O\ + convS2M.$O\ + cputime.$O\ + ctime.$O\ + dial.$O\ + dirfstat.$O\ + dirfwstat.$O\ + dirmodefmt.$O\ + dirread.$O\ + dirstat.$O\ + dirwstat.$O\ + fcallfmt.$O\ + fork.$O\ + getnetconninfo.$O\ + getenv.$O\ + getpid.$O\ + getppid.$O\ + getwd.$O\ + iounit.$O\ + nsec.$O\ + nulldir.$O\ + postnote.$O\ + privalloc.$O\ + pushssl.$O\ + pushtls.$O\ + putenv.$O\ + qlock.$O\ + read.$O\ + read9pmsg.$O\ + readv.$O\ + rerrstr.$O\ + sbrk.$O\ + setnetmtpt.$O\ + sysfatal.$O\ + syslog.$O\ + sysname.$O\ + time.$O\ + times.$O\ + tm2sec.$O\ + truerand.$O\ + wait.$O\ + waitpid.$O\ + werrstr.$O\ + write.$O\ + writev.$O\ + +HFILES=/sys/include/libc.h + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + +</sys/src/cmd/mksyslib + diff --git a/sys/src/libc/9sys/nsec.c b/sys/src/libc/9sys/nsec.c new file mode 100755 index 000000000..f0e981d04 --- /dev/null +++ b/sys/src/libc/9sys/nsec.c @@ -0,0 +1,75 @@ +#include <u.h> +#include <libc.h> +#include <tos.h> + +static uvlong order = 0x0001020304050607ULL; + +static void +be2vlong(vlong *to, uchar *f) +{ + uchar *t, *o; + int i; + + t = (uchar*)to; + o = (uchar*)ℴ + for(i = 0; i < sizeof order; i++) + t[o[i]] = f[i]; +} + +static int fd = -1; +static struct { + int pid; + int fd; +} fds[64]; + +vlong +nsec(void) +{ + uchar b[8]; + vlong t; + int pid, i, f, tries; + + /* + * Threaded programs may have multiple procs + * with different fd tables, so we may need to open + * /dev/bintime on a per-pid basis + */ + + /* First, look if we've opened it for this particular pid */ + pid = _tos->pid; + do{ + f = -1; + for(i = 0; i < nelem(fds); i++) + if(fds[i].pid == pid){ + f = fds[i].fd; + break; + } + tries = 0; + if(f < 0){ + /* If it's not open for this pid, try the global pid */ + if(fd >= 0) + f = fd; + else{ + /* must open */ + if((f = open("/dev/bintime", OREAD|OCEXEC)) < 0) + return 0; + fd = f; + for(i = 0; i < nelem(fds); i++) + if(fds[i].pid == pid || fds[i].pid == 0){ + fds[i].pid = pid; + fds[i].fd = f; + break; + } + } + } + if(pread(f, b, sizeof b, 0) == sizeof b){ + be2vlong(&t, b); + return t; + } + close(f); + if(i < nelem(fds)) + fds[i].fd = -1; + }while(tries++ == 0); /* retry once */ + USED(tries); + return 0; +} diff --git a/sys/src/libc/9sys/nulldir.c b/sys/src/libc/9sys/nulldir.c new file mode 100755 index 000000000..612725d81 --- /dev/null +++ b/sys/src/libc/9sys/nulldir.c @@ -0,0 +1,9 @@ +#include <u.h> +#include <libc.h> + +void +nulldir(Dir *d) +{ + memset(d, ~0, sizeof(Dir)); + d->name = d->uid = d->gid = d->muid = ""; +} diff --git a/sys/src/libc/9sys/postnote.c b/sys/src/libc/9sys/postnote.c new file mode 100755 index 000000000..46564e9ea --- /dev/null +++ b/sys/src/libc/9sys/postnote.c @@ -0,0 +1,32 @@ +#include <u.h> +#include <libc.h> + +int +postnote(int group, int pid, char *note) +{ + char file[128]; + int f, r; + + switch(group) { + case PNPROC: + sprint(file, "/proc/%d/note", pid); + break; + case PNGROUP: + sprint(file, "/proc/%d/notepg", pid); + break; + default: + return -1; + } + + f = open(file, OWRITE); + if(f < 0) + return -1; + + r = strlen(note); + if(write(f, note, r) != r) { + close(f); + return -1; + } + close(f); + return 0; +} diff --git a/sys/src/libc/9sys/privalloc.c b/sys/src/libc/9sys/privalloc.c new file mode 100755 index 000000000..907485e2f --- /dev/null +++ b/sys/src/libc/9sys/privalloc.c @@ -0,0 +1,45 @@ +#include <u.h> +#include <libc.h> + +static Lock privlock; +static int privinit; +static void **privs; + +extern void **_privates; +extern int _nprivates; + +void ** +privalloc(void) +{ + void **p; + int i; + + lock(&privlock); + if(!privinit){ + privinit = 1; + if(_nprivates){ + _privates[0] = 0; + for(i = 1; i < _nprivates; i++) + _privates[i] = &_privates[i - 1]; + privs = &_privates[i - 1]; + } + } + p = privs; + if(p != nil){ + privs = *p; + *p = nil; + } + unlock(&privlock); + return p; +} + +void +privfree(void **p) +{ + lock(&privlock); + if(p != nil && privinit){ + *p = privs; + privs = p; + } + unlock(&privlock); +} diff --git a/sys/src/libc/9sys/pushssl.c b/sys/src/libc/9sys/pushssl.c new file mode 100755 index 000000000..8817dd1c3 --- /dev/null +++ b/sys/src/libc/9sys/pushssl.c @@ -0,0 +1,44 @@ +#include <u.h> +#include <libc.h> + +/* + * Since the SSL device uses decimal file descriptors to name channels, + * it is impossible for a user-level file server to stand in for the kernel device. + * Thus we hard-code #D rather than use /net/ssl. + */ + +int +pushssl(int fd, char *alg, char *secin, char *secout, int *cfd) +{ + char buf[8]; + char dname[64]; + int n, data, ctl; + + ctl = open("#D/ssl/clone", ORDWR); + if(ctl < 0) + return -1; + n = read(ctl, buf, sizeof(buf)-1); + if(n < 0) + goto error; + buf[n] = 0; + sprint(dname, "#D/ssl/%s/data", buf); + data = open(dname, ORDWR); + if(data < 0) + goto error; + if(fprint(ctl, "fd %d", fd) < 0 || + fprint(ctl, "secretin %s", secin) < 0 || + fprint(ctl, "secretout %s", secout) < 0 || + fprint(ctl, "alg %s", alg) < 0){ + close(data); + goto error; + } + close(fd); + if(cfd != 0) + *cfd = ctl; + else + close(ctl); + return data; +error: + close(ctl); + return -1; +} diff --git a/sys/src/libc/9sys/pushtls.c b/sys/src/libc/9sys/pushtls.c new file mode 100755 index 000000000..038aad748 --- /dev/null +++ b/sys/src/libc/9sys/pushtls.c @@ -0,0 +1,99 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <mp.h> +#include <libsec.h> + +enum { + TLSFinishedLen = 12, + HFinished = 20, +}; + +static int +finished(int hand, int isclient) +{ + int i, n; + uchar buf[500], buf2[500]; + + buf[0] = HFinished; + buf[1] = TLSFinishedLen>>16; + buf[2] = TLSFinishedLen>>8; + buf[3] = TLSFinishedLen; + n = TLSFinishedLen+4; + + for(i=0; i<2; i++){ + if(i==0) + memmove(buf+4, "client finished", TLSFinishedLen); + else + memmove(buf+4, "server finished", TLSFinishedLen); + if(isclient == 1-i){ + if(write(hand, buf, n) != n) + return -1; + }else{ + if(readn(hand, buf2, n) != n || memcmp(buf,buf2,n) != 0) + return -1; + } + } + return 1; +} + + +// given a plain fd and secrets established beforehand, return encrypted connection +int +pushtls(int fd, char *hashalg, char *encalg, int isclient, char *secret, char *dir) +{ + char buf[8]; + char dname[64]; + int n, data, ctl, hand; + + // open a new filter; get ctl fd + data = hand = -1; + // /net/tls uses decimal file descriptors to name channels, hence a + // user-level file server can't stand in for #a; may as well hard-code it. + ctl = open("#a/tls/clone", ORDWR); + if(ctl < 0) + goto error; + n = read(ctl, buf, sizeof(buf)-1); + if(n < 0) + goto error; + buf[n] = 0; + if(dir) + sprint(dir, "#a/tls/%s", buf); + + // get application fd + sprint(dname, "#a/tls/%s/data", buf); + data = open(dname, ORDWR); + if(data < 0) + goto error; + + // get handshake fd + sprint(dname, "#a/tls/%s/hand", buf); + hand = open(dname, ORDWR); + if(hand < 0) + goto error; + + // speak a minimal handshake + if(fprint(ctl, "fd %d 0x301", fd) < 0 || + fprint(ctl, "version 0x301") < 0 || + fprint(ctl, "secret %s %s %d %s", hashalg, encalg, isclient, secret) < 0 || + fprint(ctl, "changecipher") < 0 || + finished(hand, isclient) < 0 || + fprint(ctl, "opened") < 0){ + close(hand); + hand = -1; + goto error; + } + close(ctl); + close(hand); + close(fd); + return data; + +error: + if(data>=0) + close(data); + if(ctl>=0) + close(ctl); + if(hand>=0) + close(hand); + return -1; +} diff --git a/sys/src/libc/9sys/putenv.c b/sys/src/libc/9sys/putenv.c new file mode 100755 index 000000000..de2389482 --- /dev/null +++ b/sys/src/libc/9sys/putenv.c @@ -0,0 +1,26 @@ +#include <u.h> +#include <libc.h> + +int +putenv(char *name, char *val) +{ + int f; + char ename[100]; + long s; + + if(strchr(name, '/') != nil) + return -1; + snprint(ename, sizeof ename, "/env/%s", name); + if(strcmp(ename+5, name) != 0) + return -1; + f = create(ename, OWRITE, 0664); + if(f < 0) + return -1; + s = strlen(val); + if(write(f, val, s) != s){ + close(f); + return -1; + } + close(f); + return 0; +} diff --git a/sys/src/libc/9sys/qlock.c b/sys/src/libc/9sys/qlock.c new file mode 100755 index 000000000..fb2d80238 --- /dev/null +++ b/sys/src/libc/9sys/qlock.c @@ -0,0 +1,363 @@ +#include <u.h> +#include <libc.h> + +static struct { + QLp *p; + QLp x[1024]; +} ql = { + ql.x +}; + +enum +{ + Queuing, + QueuingR, + QueuingW, + Sleeping, +}; + +static void* (*_rendezvousp)(void*, void*) = rendezvous; + +/* this gets called by the thread library ONLY to get us to use its rendezvous */ +void +_qlockinit(void* (*r)(void*, void*)) +{ + _rendezvousp = r; +} + +/* 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)(mp, (void*)1) == (void*)~0) + ; + mp->inuse = 0; +} + +void +qunlock(QLock *q) +{ + QLp *p; + + lock(&q->lock); + if (q->locked == 0) + fprint(2, "qunlock called with qlock not held, from %#p\n", + getcallerpc(&q)); + 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)(p, (void*)0x12345) == (void*)~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; +} + +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)(mp, (void*)1) == (void*)~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)(p, 0) == (void*)~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)(mp, (void*)1) == (void*)~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)(p, 0) == (void*)~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)(p, 0) == (void*)~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)(t, (void*)0x12345) == (void*)~0) + ; + }else{ + r->l->locked = 0; + unlock(&r->l->lock); + } + + /* wait for a wakeup */ + while((*_rendezvousp)(me, (void*)1) == (void*)~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; +} + diff --git a/sys/src/libc/9sys/read.c b/sys/src/libc/9sys/read.c new file mode 100755 index 000000000..2119ab2ac --- /dev/null +++ b/sys/src/libc/9sys/read.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +long +read(int fd, void *buf, long n) +{ + return pread(fd, buf, n, -1LL); +} diff --git a/sys/src/libc/9sys/read9pmsg.c b/sys/src/libc/9sys/read9pmsg.c new file mode 100755 index 000000000..9e90ec5d6 --- /dev/null +++ b/sys/src/libc/9sys/read9pmsg.c @@ -0,0 +1,31 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +int +read9pmsg(int fd, void *abuf, uint n) +{ + int m, len; + uchar *buf; + + buf = abuf; + + /* read count */ + m = readn(fd, buf, BIT32SZ); + if(m != BIT32SZ){ + if(m < 0) + return -1; + return 0; + } + + len = GBIT32(buf); + if(len <= BIT32SZ || len > n){ + werrstr("bad length in 9P2000 message header"); + return -1; + } + len -= BIT32SZ; + m = readn(fd, buf+BIT32SZ, len); + if(m < len) + return 0; + return BIT32SZ+m; +} diff --git a/sys/src/libc/9sys/readv.c b/sys/src/libc/9sys/readv.c new file mode 100755 index 000000000..a0dc10aaf --- /dev/null +++ b/sys/src/libc/9sys/readv.c @@ -0,0 +1,49 @@ +#include <u.h> +#include <libc.h> + +static +long +ioreadv(int fd, IOchunk *io, int nio, vlong offset) +{ + int i; + long m, n, tot; + char *buf, *p; + + tot = 0; + for(i=0; i<nio; i++) + tot += io[i].len; + buf = malloc(tot); + if(buf == nil) + return -1; + + tot = pread(fd, buf, tot, offset); + + p = buf; + n = tot; + for(i=0; i<nio; i++){ + if(n <= 0) + break; + m = io->len; + if(m > n) + m = n; + memmove(io->addr, p, m); + n -= m; + p += m; + io++; + } + + free(buf); + return tot; +} + +long +readv(int fd, IOchunk *io, int nio) +{ + return ioreadv(fd, io, nio, -1LL); +} + +long +preadv(int fd, IOchunk *io, int nio, vlong off) +{ + return ioreadv(fd, io, nio, off); +} diff --git a/sys/src/libc/9sys/rerrstr.c b/sys/src/libc/9sys/rerrstr.c new file mode 100755 index 000000000..c64cd4940 --- /dev/null +++ b/sys/src/libc/9sys/rerrstr.c @@ -0,0 +1,13 @@ +#include <u.h> +#include <libc.h> + +void +rerrstr(char *buf, uint nbuf) +{ + char tmp[ERRMAX]; + + tmp[0] = 0; + errstr(tmp, sizeof tmp); + utfecpy(buf, buf+nbuf, tmp); + errstr(tmp, sizeof tmp); +} diff --git a/sys/src/libc/9sys/sbrk.c b/sys/src/libc/9sys/sbrk.c new file mode 100755 index 000000000..88b593e11 --- /dev/null +++ b/sys/src/libc/9sys/sbrk.c @@ -0,0 +1,35 @@ +#include <u.h> +#include <libc.h> + +extern char end[]; +static char *bloc = { end }; +extern int brk_(void*); + +enum +{ + Round = 7 +}; + +int +brk(void *p) +{ + uintptr bl; + + bl = ((uintptr)p + Round) & ~Round; + if(brk_((void*)bl) < 0) + return -1; + bloc = (char*)bl; + return 0; +} + +void* +sbrk(ulong n) +{ + uintptr bl; + + bl = ((uintptr)bloc + Round) & ~Round; + if(brk_((void*)(bl+n)) < 0) + return (void*)-1; + bloc = (char*)bl + n; + return (void*)bl; +} diff --git a/sys/src/libc/9sys/setnetmtpt.c b/sys/src/libc/9sys/setnetmtpt.c new file mode 100755 index 000000000..3d984f08f --- /dev/null +++ b/sys/src/libc/9sys/setnetmtpt.c @@ -0,0 +1,16 @@ +#include <u.h> +#include <libc.h> + +void +setnetmtpt(char *net, int n, char *x) +{ + if(x == nil) + x = "/net"; + + if(*x == '/'){ + strncpy(net, x, n); + net[n-1] = 0; + } else { + snprint(net, n, "/net%s", x); + } +} diff --git a/sys/src/libc/9sys/sysfatal.c b/sys/src/libc/9sys/sysfatal.c new file mode 100755 index 000000000..e2cef6c48 --- /dev/null +++ b/sys/src/libc/9sys/sysfatal.c @@ -0,0 +1,28 @@ +#include <u.h> +#include <libc.h> + + +static void +_sysfatalimpl(char *fmt, va_list arg) +{ + char buf[1024]; + + vseprint(buf, buf+sizeof(buf), fmt, arg); + if(argv0) + fprint(2, "%s: %s\n", argv0, buf); + else + fprint(2, "%s\n", buf); + exits(buf); +} + +void (*_sysfatal)(char *fmt, va_list arg) = _sysfatalimpl; + +void +sysfatal(char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + (*_sysfatal)(fmt, arg); + va_end(arg); +} diff --git a/sys/src/libc/9sys/syslog.c b/sys/src/libc/9sys/syslog.c new file mode 100755 index 000000000..828ad04a7 --- /dev/null +++ b/sys/src/libc/9sys/syslog.c @@ -0,0 +1,117 @@ +#include <u.h> +#include <libc.h> + +static struct +{ + int fd; + int consfd; + char *name; + Dir *d; + Dir *consd; + Lock; +} sl = +{ + -1, -1, +}; + +static void +_syslogopen(void) +{ + char buf[1024]; + + if(sl.fd >= 0) + close(sl.fd); + snprint(buf, sizeof(buf), "/sys/log/%s", sl.name); + sl.fd = open(buf, OWRITE|OCEXEC); +} + +/* + * Print + * sysname: time: mesg + * on /sys/log/logname. + * If cons or log file can't be opened, print on the system console, too. + */ +void +syslog(int cons, char *logname, char *fmt, ...) +{ + char buf[1024]; + char *ctim, *p; + va_list arg; + int n; + Dir *d; + char err[ERRMAX]; + + err[0] = '\0'; + errstr(err, sizeof err); + lock(&sl); + + /* + * paranoia makes us stat to make sure a fork+close + * hasn't broken our fd's + */ + d = dirfstat(sl.fd); + if(sl.fd < 0 + || sl.name == nil + || strcmp(sl.name, logname)!=0 + || sl.d == nil + || d == nil + || d->dev != sl.d->dev + || d->type != sl.d->type + || d->qid.path != sl.d->qid.path){ + free(sl.name); + sl.name = strdup(logname); + if(sl.name == nil) + cons = 1; + else{ + _syslogopen(); + if(sl.fd < 0) + cons = 1; + free(sl.d); + sl.d = d; + d = nil; /* don't free it */ + } + } + free(d); + if(cons){ + d = dirfstat(sl.consfd); + if(sl.consfd < 0 + || d == nil + || sl.consd == nil + || d->dev != sl.consd->dev + || d->type != sl.consd->type + || d->qid.path != sl.consd->qid.path){ + sl.consfd = open("#c/cons", OWRITE|OCEXEC); + free(sl.consd); + sl.consd = d; + d = nil; /* don't free it */ + } + free(d); + } + + if(fmt == nil){ + unlock(&sl); + return; + } + + ctim = ctime(time(0)); + werrstr(err); + p = buf + snprint(buf, sizeof(buf)-1, "%s ", sysname()); + strncpy(p, ctim+4, 15); + p += 15; + *p++ = ' '; + va_start(arg, fmt); + p = vseprint(p, buf+sizeof(buf)-1, fmt, arg); + va_end(arg); + *p++ = '\n'; + n = p - buf; + + if(sl.fd >= 0){ + seek(sl.fd, 0, 2); + write(sl.fd, buf, n); + } + + if(cons && sl.consfd >=0) + write(sl.consfd, buf, n); + + unlock(&sl); +} diff --git a/sys/src/libc/9sys/sysname.c b/sys/src/libc/9sys/sysname.c new file mode 100755 index 000000000..1854ddceb --- /dev/null +++ b/sys/src/libc/9sys/sysname.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> + +char* +sysname(void) +{ + int f, n; + static char b[128]; + + if(b[0]) + return b; + + f = open("#c/sysname", 0); + if(f >= 0) { + n = read(f, b, sizeof(b)-1); + if(n > 0) + b[n] = 0; + close(f); + } + return b; +} diff --git a/sys/src/libc/9sys/time.c b/sys/src/libc/9sys/time.c new file mode 100755 index 000000000..3e5f83b04 --- /dev/null +++ b/sys/src/libc/9sys/time.c @@ -0,0 +1,51 @@ +#include <u.h> +#include <libc.h> + + +/* + * After a fork with fd's copied, both fd's are pointing to + * the same Chan structure. Since the offset is kept in the Chan + * structure, the seek's and read's in the two processes can + * compete at moving the offset around. Hence the unusual loop + * in the middle of this routine. + */ +static long +oldtime(long *tp) +{ + char b[20]; + static int f = -1; + int i, retries; + long t; + + memset(b, 0, sizeof(b)); + for(retries = 0; retries < 100; retries++){ + if(f < 0) + f = open("/dev/time", OREAD|OCEXEC); + if(f < 0) + break; + if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){ + close(f); + f = -1; + } else { + if(i != 0) + break; + } + } + t = atol(b); + if(tp) + *tp = t; + return t; +} + +long +time(long *tp) +{ + vlong t; + + t = nsec()/1000000000LL; + if(t == 0) + t = oldtime(0); + if(tp != nil) + *tp = t; + return t; +} diff --git a/sys/src/libc/9sys/times.c b/sys/src/libc/9sys/times.c new file mode 100755 index 000000000..b8303474f --- /dev/null +++ b/sys/src/libc/9sys/times.c @@ -0,0 +1,60 @@ +#include <u.h> +#include <libc.h> + +static +char* +skip(char *p) +{ + + while(*p == ' ') + p++; + while(*p != ' ' && *p != 0) + p++; + return p; +} + +/* + * after a fork with fd's copied, both fd's are pointing to + * the same Chan structure. Since the offset is kept in the Chan + * structure, the seek's and read's in the two processes can be + * are competing moving the offset around. Hence the unusual loop + * in the middle of this routine. + */ +long +times(long *t) +{ + char b[200], *p; + static int f = -1; + int i, retries; + ulong r; + + memset(b, 0, sizeof(b)); + for(retries = 0; retries < 100; retries++){ + if(f < 0) + f = open("/dev/cputime", OREAD|OCEXEC); + if(f < 0) + break; + if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){ + close(f); + f = -1; + } else { + if(i != 0) + break; + } + } + p = b; + if(t) + t[0] = atol(p); + p = skip(p); + if(t) + t[1] = atol(p); + p = skip(p); + r = atol(p); + if(t){ + p = skip(p); + t[2] = atol(p); + p = skip(p); + t[3] = atol(p); + } + return r; +} diff --git a/sys/src/libc/9sys/tm2sec.c b/sys/src/libc/9sys/tm2sec.c new file mode 100755 index 000000000..223d3f1d9 --- /dev/null +++ b/sys/src/libc/9sys/tm2sec.c @@ -0,0 +1,194 @@ +#include <u.h> +#include <libc.h> + +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, long*); +static +struct +{ + char stname[4]; + char dlname[4]; + long stdiff; + long dldiff; + long dlpairs[TZSIZE]; +} timezone; + +#define SEC2MIN 60L +#define SEC2HOUR (60L*SEC2MIN) +#define SEC2DAY (24L*SEC2HOUR) + +/* + * days per month plus days/year + */ +static int dmsize[] = +{ + 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; +static int ldmsize[] = +{ + 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * return the days/month for the given year + */ +static int * +yrsize(int y) +{ + if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0)) + return ldmsize; + else + return dmsize; +} + +/* + * compute seconds since Jan 1 1970 GMT + * and convert to our timezone. + */ +long +tm2sec(Tm *tm) +{ + long secs; + int i, yday, year, *d2m; + + if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0) + readtimezone(); + secs = 0; + + /* + * seconds per year + */ + year = tm->year + 1900; + for(i = 1970; i < year; i++){ + d2m = yrsize(i); + secs += d2m[0] * SEC2DAY; + } + + /* + * if mday is set, use mon and mday to compute yday + */ + if(tm->mday){ + yday = 0; + d2m = yrsize(year); + for(i=0; i<tm->mon; i++) + yday += d2m[i+1]; + yday += tm->mday-1; + }else{ + yday = tm->yday; + } + secs += yday * SEC2DAY; + + /* + * hours, minutes, seconds + */ + secs += tm->hour * SEC2HOUR; + secs += tm->min * SEC2MIN; + secs += tm->sec; + + /* + * Only handles zones mentioned in /env/timezone, + * but things get too ambiguous otherwise. + */ + if(strcmp(tm->zone, timezone.stname) == 0) + secs -= timezone.stdiff; + else if(strcmp(tm->zone, timezone.dlname) == 0) + secs -= timezone.dldiff; + if(secs < 0) + secs = 0; + return secs; +} + +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 int +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 int +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/libc/9sys/truerand.c b/sys/src/libc/9sys/truerand.c new file mode 100755 index 000000000..10a0f14de --- /dev/null +++ b/sys/src/libc/9sys/truerand.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +ulong +truerand(void) +{ + ulong x; + static int randfd = -1; + + if(randfd < 0) + randfd = open("/dev/random", OREAD|OCEXEC); + if(randfd < 0) + sysfatal("can't open /dev/random"); + if(read(randfd, &x, sizeof(x)) != sizeof(x)) + sysfatal("can't read /dev/random"); + return x; +} diff --git a/sys/src/libc/9sys/wait.c b/sys/src/libc/9sys/wait.c new file mode 100755 index 000000000..e2ac817ea --- /dev/null +++ b/sys/src/libc/9sys/wait.c @@ -0,0 +1,32 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +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, nelem(fld)) != nelem(fld)){ + werrstr("couldn't parse wait message"); + 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/libc/9sys/waitpid.c b/sys/src/libc/9sys/waitpid.c new file mode 100755 index 000000000..098c428cf --- /dev/null +++ b/sys/src/libc/9sys/waitpid.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +int +waitpid(void) +{ + int n; + char buf[512], *fld[5]; + + n = await(buf, sizeof buf-1); + if(n <= 0) + return -1; + buf[n] = '\0'; + if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){ + werrstr("couldn't parse wait message"); + return -1; + } + return atoi(fld[0]); +} + diff --git a/sys/src/libc/9sys/werrstr.c b/sys/src/libc/9sys/werrstr.c new file mode 100755 index 000000000..da542aa17 --- /dev/null +++ b/sys/src/libc/9sys/werrstr.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +void +werrstr(char *fmt, ...) +{ + va_list arg; + char buf[ERRMAX]; + + va_start(arg, fmt); + vseprint(buf, buf+ERRMAX, fmt, arg); + va_end(arg); + errstr(buf, ERRMAX); +} diff --git a/sys/src/libc/9sys/write.c b/sys/src/libc/9sys/write.c new file mode 100755 index 000000000..5bbd3064e --- /dev/null +++ b/sys/src/libc/9sys/write.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +long +write(int fd, void *buf, long n) +{ + return pwrite(fd, buf, n, -1LL); +} diff --git a/sys/src/libc/9sys/writev.c b/sys/src/libc/9sys/writev.c new file mode 100755 index 000000000..e3692db27 --- /dev/null +++ b/sys/src/libc/9sys/writev.c @@ -0,0 +1,42 @@ +#include <u.h> +#include <libc.h> + +static +long +iowritev(int fd, IOchunk *io, int nio, vlong offset) +{ + int i; + long tot; + char *buf, *p; + + tot = 0; + for(i=0; i<nio; i++) + tot += io[i].len; + buf = malloc(tot); + if(buf == nil) + return -1; + + p = buf; + for(i=0; i<nio; i++){ + memmove(p, io->addr, io->len); + p += io->len; + io++; + } + + tot = pwrite(fd, buf, tot, offset); + + free(buf); + return tot; +} + +long +writev(int fd, IOchunk *io, int nio) +{ + return iowritev(fd, io, nio, -1LL); +} + +long +pwritev(int fd, IOchunk *io, int nio, vlong off) +{ + return iowritev(fd, io, nio, off); +} |