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/cmd/srvold9p |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/srvold9p')
-rwxr-xr-x | sys/src/cmd/srvold9p/9p1.h | 127 | ||||
-rwxr-xr-x | sys/src/cmd/srvold9p/9p1lib.c | 627 | ||||
-rwxr-xr-x | sys/src/cmd/srvold9p/fcall.c | 150 | ||||
-rwxr-xr-x | sys/src/cmd/srvold9p/mkfile | 11 | ||||
-rwxr-xr-x | sys/src/cmd/srvold9p/srvold9p.c | 1123 |
5 files changed, 2038 insertions, 0 deletions
diff --git a/sys/src/cmd/srvold9p/9p1.h b/sys/src/cmd/srvold9p/9p1.h new file mode 100755 index 000000000..d783647a4 --- /dev/null +++ b/sys/src/cmd/srvold9p/9p1.h @@ -0,0 +1,127 @@ +#include <authsrv.h> + +#define DIRREC 116 /* size of a directory ascii record */ +#define ERRREC 64 /* size of a error record */ +#define NAMEREC 28 + +typedef struct Fcall9p1 Fcall9p1; +typedef struct Qid9p1 Qid9p1; + +struct Qid9p1 +{ + long path; + long version; +}; + +struct Fcall9p1 +{ + char type; + ushort fid; + short err; + short tag; + union + { + struct + { + short uid; /* T-Userstr */ + short oldtag; /* T-nFlush */ + Qid9p1 qid; /* R-Attach, R-Clwalk, R-Walk, + * R-Open, R-Create */ + char rauth[AUTHENTLEN]; /* R-attach */ + }; + struct + { + char uname[NAMEREC]; /* T-nAttach */ + char aname[NAMEREC]; /* T-nAttach */ + char ticket[TICKETLEN]; /* T-attach */ + char auth[AUTHENTLEN]; /* T-attach */ + }; + struct + { + char ename[ERRREC]; /* R-nError */ + char chal[CHALLEN]; /* T-session, R-session */ + char authid[NAMEREC]; /* R-session */ + char authdom[DOMLEN]; /* R-session */ + }; + struct + { + char name[NAMEREC]; /* T-Walk, T-Clwalk, T-Create, T-Remove */ + long perm; /* T-Create */ + ushort newfid; /* T-Clone, T-Clwalk */ + 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[DIRREC]; /* T-Wstat, R-Stat */ + }; + }; +}; + +/* + * P9 protocol message types + */ +enum +{ + Tnop9p1 = 50, + Rnop9p1, + Tosession9p1 = 52, + Rosession9p1, + Terror9p1 = 54, /* illegal */ + Rerror9p1, + Tflush9p1 = 56, + Rflush9p1, + Toattach9p1 = 58, + Roattach9p1, + Tclone9p1 = 60, + Rclone9p1, + Twalk9p1 = 62, + Rwalk9p1, + Topen9p1 = 64, + Ropen9p1, + Tcreate9p1 = 66, + Rcreate9p1, + Tread9p1 = 68, + Rread9p1, + Twrite9p1 = 70, + Rwrite9p1, + Tclunk9p1 = 72, + Rclunk9p1, + Tremove9p1 = 74, + Rremove9p1, + Tstat9p1 = 76, + Rstat9p1, + Twstat9p1 = 78, + Rwstat9p1, + Tclwalk9p1 = 80, + Rclwalk9p1, + Tauth9p1 = 82, /* illegal */ + Rauth9p1, /* illegal */ + Tsession9p1 = 84, + Rsession9p1, + Tattach9p1 = 86, + Rattach9p1, + + MAXSYSCALL +}; + +int convA2M9p1(Authenticator*, char*, char*); +void convM2A9p1(char*, Authenticator*, char*); +void convM2T9p1(char*, Ticket*, char*); +int convD2M9p1(Dir*, char*); +int convM2D9p1(char*, Dir*); +int convM2S9p1(char*, Fcall9p1*, int); +int convS2M9p1(Fcall9p1*, char*); +int fcallfmt9p1(Fmt*); +int fcall(int); + +#pragma varargck type "F" Fcall* +#pragma varargck type "G" Fcall9p1* +#pragma varargck type "D" Dir* + +void fatal(char*, ...); diff --git a/sys/src/cmd/srvold9p/9p1lib.c b/sys/src/cmd/srvold9p/9p1lib.c new file mode 100755 index 000000000..df68ef5ba --- /dev/null +++ b/sys/src/cmd/srvold9p/9p1lib.c @@ -0,0 +1,627 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include "9p1.h" +#pragma varargck type "D" Dir* /* from fcall.h */ + +static void dumpsome(char*, char*, long); + +int +fcallfmt9p1(Fmt *f1) +{ + Fcall9p1 *f; + int fid, type, tag, n; + char buf[512]; + Dir d; + + f = va_arg(f1->args, Fcall9p1*); + type = f->type; + fid = f->fid; + tag = f->tag; + switch(type){ + case Tnop9p1: /* 50 */ + sprint(buf, "old Tnop tag %ud", tag); + break; + case Rnop9p1: + sprint(buf, "old Rnop tag %ud", tag); + break; + case Tsession9p1: /* 52 */ + sprint(buf, "old Tsession tag %ud", tag); + break; + case Rsession9p1: + sprint(buf, "old Rsession tag %ud", tag); + break; + case Rerror9p1: /* 55 */ + sprint(buf, "old Rerror tag %ud error %.64s", tag, f->ename); + break; + case Tflush9p1: /* 56 */ + sprint(buf, "old Tflush tag %ud oldtag %d", tag, f->oldtag); + break; + case Rflush9p1: + sprint(buf, "old Rflush tag %ud", tag); + break; + case Tattach9p1: /* 58 */ + sprint(buf, "old Tattach tag %ud fid %d uname %.28s aname %.28s auth %.28s", + tag, f->fid, f->uname, f->aname, f->auth); + break; + case Rattach9p1: + sprint(buf, "old Rattach tag %ud fid %d qid 0x%lux|0x%lux", + tag, fid, f->qid.path, f->qid.version); + break; + case Tclone9p1: /* 60 */ + sprint(buf, "old Tclone tag %ud fid %d newfid %d", tag, fid, f->newfid); + break; + case Rclone9p1: + sprint(buf, "old Rclone tag %ud fid %d", tag, fid); + break; + case Twalk9p1: /* 62 */ + sprint(buf, "old Twalk tag %ud fid %d name %.28s", tag, fid, f->name); + break; + case Rwalk9p1: + sprint(buf, "old Rwalk tag %ud fid %d qid 0x%lux|0x%lux", + tag, fid, f->qid.path, f->qid.version); + break; + case Topen9p1: /* 64 */ + sprint(buf, "old Topen tag %ud fid %d mode %d", tag, fid, f->mode); + break; + case Ropen9p1: + sprint(buf, "old Ropen tag %ud fid %d qid 0x%lux|0x%lux", + tag, fid, f->qid.path, f->qid.version); + break; + case Tcreate9p1: /* 66 */ + sprint(buf, "old Tcreate tag %ud fid %d name %.28s perm 0x%lux mode %d", + tag, fid, f->name, f->perm, f->mode); + break; + case Rcreate9p1: + sprint(buf, "old Rcreate tag %ud fid %d qid 0x%lux|0x%lux", + tag, fid, f->qid.path, f->qid.version); + break; + case Tread9p1: /* 68 */ + sprint(buf, "old Tread tag %ud fid %d offset %ld count %ld", + tag, fid, f->offset, f->count); + break; + case Rread9p1: + n = sprint(buf, "old Rread tag %ud fid %d count %ld ", tag, fid, f->count); + dumpsome(buf+n, f->data, f->count); + break; + case Twrite9p1: /* 70 */ + n = sprint(buf, "old Twrite tag %ud fid %d offset %ld count %ld ", + tag, fid, f->offset, f->count); + dumpsome(buf+n, f->data, f->count); + break; + case Rwrite9p1: + sprint(buf, "old Rwrite tag %ud fid %d count %ld", tag, fid, f->count); + break; + case Tclunk9p1: /* 72 */ + sprint(buf, "old Tclunk tag %ud fid %d", tag, fid); + break; + case Rclunk9p1: + sprint(buf, "old Rclunk tag %ud fid %d", tag, fid); + break; + case Tremove9p1: /* 74 */ + sprint(buf, "old Tremove tag %ud fid %d", tag, fid); + break; + case Rremove9p1: + sprint(buf, "old Rremove tag %ud fid %d", tag, fid); + break; + case Tstat9p1: /* 76 */ + sprint(buf, "old Tstat tag %ud fid %d", tag, fid); + break; + case Rstat9p1: + convM2D9p1(f->stat, &d); + sprint(buf, "old Rstat tag %ud fid %d stat %D", tag, fid, &d); + break; + case Twstat9p1: /* 78 */ + convM2D9p1(f->stat, &d); + sprint(buf, "old Twstat tag %ud fid %d stat %D", tag, fid, &d); + break; + case Rwstat9p1: + sprint(buf, "old Rwstat tag %ud fid %d", tag, fid); + break; + case Tclwalk9p1: /* 81 */ + sprint(buf, "old Tclwalk tag %ud fid %d newfid %d name %.28s", + tag, fid, f->newfid, f->name); + break; + case Rclwalk9p1: + sprint(buf, "old Rclwalk tag %ud fid %d qid 0x%lux|0x%lux", + tag, fid, f->qid.path, f->qid.version); + break; + default: + sprint(buf, "unknown type %d", type); + } + return fmtstrcpy(f1, buf); +} + +/* + * 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 void +dumpsome(char *ans, char *buf, long count) +{ + int i, printable; + char *p; + + 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){ + memmove(p, buf, count); + p += count; + }else{ + for(i=0; i<count; i++){ + if(i>0 && i%4==0) + *p++ = ' '; + sprint(p, "%2.2ux", buf[i]); + p += 2; + } + } + *p++ = '\''; + *p = 0; +} + +#define CHAR(x) *p++ = f->x +#define SHORT(x) { ulong vvv = f->x; p[0] = vvv; p[1] = vvv>>8; p += 2; } +#define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4 +#define LONG(x) { ulong vvv = f->x; VLONG(vvv); } +#define BYTES(x,n) memmove(p, f->x, n); p += n +#define STRING(x,n) strncpy((char*)p, f->x, n); p += n + +int +convS2M9p1(Fcall9p1 *f, char *ap) +{ + uchar *p; + int t; + + p = (uchar*)ap; + CHAR(type); + t = f->type; + SHORT(tag); + switch(t) + { + default: + fprint(2, "convS2M9p1: bad type: %d\n", t); + return 0; + + case Tnop9p1: + case Tosession9p1: + break; + + case Tsession9p1: + BYTES(chal, sizeof(f->chal)); + break; + + case Tflush9p1: + SHORT(oldtag); + break; + + case Tattach9p1: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + BYTES(ticket, sizeof(f->ticket)); + BYTES(auth, sizeof(f->auth)); + break; + + case Toattach9p1: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + BYTES(ticket, NAMEREC); + break; + + case Tclone9p1: + SHORT(fid); + SHORT(newfid); + break; + + case Twalk9p1: + SHORT(fid); + STRING(name, sizeof(f->name)); + break; + + case Tclwalk9p1: + SHORT(fid); + SHORT(newfid); + STRING(name, sizeof(f->name)); + break; + + case Topen9p1: + SHORT(fid); + CHAR(mode); + break; + + case Tcreate9p1: + SHORT(fid); + STRING(name, sizeof(f->name)); + LONG(perm); + CHAR(mode); + break; + + case Tread9p1: + SHORT(fid); + LONG(offset); VLONG(0); + SHORT(count); + break; + + case Twrite9p1: + SHORT(fid); + LONG(offset); VLONG(0); + SHORT(count); + p++; + if((uchar*)p == (uchar*)f->data) { + p += f->count; + break; + } + BYTES(data, f->count); + break; + + case Tclunk9p1: + case Tremove9p1: + case Tstat9p1: + SHORT(fid); + break; + + case Twstat9p1: + SHORT(fid); + BYTES(stat, sizeof(f->stat)); + break; +/* + */ + case Rnop9p1: + case Rosession9p1: + case Rflush9p1: + break; + + case Rsession9p1: + BYTES(chal, sizeof(f->chal)); + BYTES(authid, sizeof(f->authid)); + BYTES(authdom, sizeof(f->authdom)); + break; + + case Rerror9p1: + STRING(ename, sizeof(f->ename)); + break; + + case Rclone9p1: + case Rclunk9p1: + case Rremove9p1: + case Rwstat9p1: + SHORT(fid); + break; + + case Rwalk9p1: + case Ropen9p1: + case Rcreate9p1: + case Rclwalk9p1: + SHORT(fid); + LONG(qid.path); + LONG(qid.version); + break; + + case Rattach9p1: + SHORT(fid); + LONG(qid.path); + LONG(qid.version); + BYTES(rauth, sizeof(f->rauth)); + break; + + case Roattach9p1: + SHORT(fid); + LONG(qid.path); + LONG(qid.version); + break; + + case Rread9p1: + SHORT(fid); + SHORT(count); + p++; + if((uchar*)p == (uchar*)f->data) { + p += f->count; + break; + } + BYTES(data, f->count); + break; + + case Rwrite9p1: + SHORT(fid); + SHORT(count); + break; + + case Rstat9p1: + SHORT(fid); + BYTES(stat, sizeof(f->stat)); + break; + } + return p - (uchar*)ap; +} + +int +convD2M9p1(Dir *f, char *ap) +{ + uchar *p; + ulong q; + + p = (uchar*)ap; + STRING(name, NAMEREC); + STRING(uid, NAMEREC); + STRING(gid, NAMEREC); + + q = f->qid.path & ~0x80000000; + if(f->qid.type & QTDIR) + q |= 0x80000000; + VLONG(q); + LONG(qid.vers); + LONG(mode); + LONG(atime); + LONG(mtime); + LONG(length); VLONG(0); + VLONG(0); + return p - (uchar*)ap; +} + +int +convA2M9p1(Authenticator *f, char *ap, char *key) +{ + int n; + uchar *p; + + p = (uchar*)ap; + CHAR(num); + STRING(chal, CHALLEN); + LONG(id); + n = p - (uchar*)ap; + if(key) + encrypt(key, ap, n); + return n; +} + +#undef CHAR +#undef SHORT +#undef LONG +#undef VLONG +#undef BYTES +#undef STRING + +#define CHAR(x) f->x = *p++ +#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 +#define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4 +#define LONG(x) VLONG(f->x) +#define BYTES(x,n) memmove(f->x, p, n); p += n +#define STRING(x,n) memmove(f->x, p, n); p += n + +int +convM2S9p1(char *ap, Fcall9p1 *f, int n) +{ + uchar *p; + int t; + + p = (uchar*)ap; + CHAR(type); + t = f->type; + SHORT(tag); + switch(t) + { + default: + fprint(2, "convM2S9p1: bad type: %d\n", f->type); + return 0; + + case Tnop9p1: + case Tosession9p1: + break; + + case Tsession9p1: + BYTES(chal, sizeof(f->chal)); + break; + + case Tflush9p1: + SHORT(oldtag); + break; + + case Tattach9p1: + SHORT(fid); + BYTES(uname, sizeof(f->uname)); + BYTES(aname, sizeof(f->aname)); + BYTES(ticket, sizeof(f->ticket)); + BYTES(auth, sizeof(f->auth)); + break; + + case Toattach9p1: + SHORT(fid); + BYTES(uname, sizeof(f->uname)); + BYTES(aname, sizeof(f->aname)); + BYTES(ticket, NAMEREC); + break; + + case Tclone9p1: + SHORT(fid); + SHORT(newfid); + break; + + case Twalk9p1: + SHORT(fid); + BYTES(name, sizeof(f->name)); + break; + + case Tclwalk9p1: + SHORT(fid); + SHORT(newfid); + BYTES(name, sizeof(f->name)); + break; + + case Tremove9p1: + SHORT(fid); + break; + + case Topen9p1: + SHORT(fid); + CHAR(mode); + break; + + case Tcreate9p1: + SHORT(fid); + BYTES(name, sizeof(f->name)); + LONG(perm); + CHAR(mode); + break; + + case Tread9p1: + SHORT(fid); + LONG(offset); p += 4; + SHORT(count); + break; + + case Twrite9p1: + SHORT(fid); + LONG(offset); p += 4; + SHORT(count); + p++; + f->data = (char*)p; p += f->count; + break; + + case Tclunk9p1: + case Tstat9p1: + SHORT(fid); + break; + + case Twstat9p1: + SHORT(fid); + BYTES(stat, sizeof(f->stat)); + break; + +/* + */ + case Rnop9p1: + case Rosession9p1: + break; + + case Rsession9p1: + BYTES(chal, sizeof(f->chal)); + BYTES(authid, sizeof(f->authid)); + BYTES(authdom, sizeof(f->authdom)); + break; + + case Rerror9p1: + BYTES(ename, sizeof(f->ename)); + break; + + case Rflush9p1: + break; + + case Rclone9p1: + case Rclunk9p1: + case Rremove9p1: + case Rwstat9p1: + SHORT(fid); + break; + + case Rwalk9p1: + case Rclwalk9p1: + case Ropen9p1: + case Rcreate9p1: + SHORT(fid); + LONG(qid.path); + LONG(qid.version); + break; + + case Rattach9p1: + SHORT(fid); + LONG(qid.path); + LONG(qid.version); + BYTES(rauth, sizeof(f->rauth)); + break; + + case Roattach9p1: + SHORT(fid); + LONG(qid.path); + LONG(qid.version); + break; + + case Rread9p1: + SHORT(fid); + SHORT(count); + p++; + f->data = (char*)p; p += f->count; + break; + + case Rwrite9p1: + SHORT(fid); + SHORT(count); + break; + + case Rstat9p1: + SHORT(fid); + BYTES(stat, sizeof(f->stat)); + break; + } + if((uchar*)ap+n == p) + return n; + return 0; +} + +int +convM2D9p1(char *ap, Dir *f) +{ + uchar *p; + + p = (uchar*)ap; + f->name = (char*)p; + p += NAMEREC; + f->uid = (char*)p; + f->muid = (char*)p; + p += NAMEREC; + f->gid = (char*)p; + p += NAMEREC; + + LONG(qid.path); + f->qid.path &= ~0x80000000; + + LONG(qid.vers); + LONG(mode); + f->qid.type = f->mode >> 24; + LONG(atime); + LONG(mtime); + LONG(length); p += 4; + p += 4; + return p - (uchar*)ap; +} + +void +convM2A9p1(char *ap, Authenticator *f, char *key) +{ + uchar *p; + + if(key) + decrypt(key, ap, AUTHENTLEN); + p = (uchar*)ap; + CHAR(num); + STRING(chal, CHALLEN); + LONG(id); + USED(p); +} + +void +convM2T9p1(char *ap, Ticket *f, char *key) +{ + uchar *p; + + if(key) + decrypt(key, ap, TICKETLEN); + p = (uchar*)ap; + CHAR(num); + STRING(chal, CHALLEN); + STRING(cuid, NAMEREC); + f->cuid[NAMEREC-1] = 0; + STRING(suid, NAMEREC); + f->suid[NAMEREC-1] = 0; + STRING(key, DESKEYLEN); + USED(p); +}; diff --git a/sys/src/cmd/srvold9p/fcall.c b/sys/src/cmd/srvold9p/fcall.c new file mode 100755 index 000000000..a3e007330 --- /dev/null +++ b/sys/src/cmd/srvold9p/fcall.c @@ -0,0 +1,150 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <fcall.h> +#include "9p1.h" + +#define MAXFDATA (8*1024) +#define MAXRPC (MAXFDATA+160) + +/* + * reassemble 9P messages for stream based protocols + * interposed between devmnt and the network by srv for tcp connections + * fcall expects devmnt on fd0, network fd1 + */ +uchar msglen[256] = +{ + [Tnop9p1] 3, + [Rnop9p1] 3, + [Tsession9p1] 3+CHALLEN, + [Rsession9p1] 3+NAMEREC+DOMLEN+CHALLEN, + [Terror9p1] 0, + [Rerror9p1] 67, + [Tflush9p1] 5, + [Rflush9p1] 3, + [Tattach9p1] 5+2*NAMEREC+TICKETLEN+AUTHENTLEN, + [Rattach9p1] 13+AUTHENTLEN, + [Tclone9p1] 7, + [Rclone9p1] 5, + [Twalk9p1] 33, + [Rwalk9p1] 13, + [Topen9p1] 6, + [Ropen9p1] 13, + [Tcreate9p1] 38, + [Rcreate9p1] 13, + [Tread9p1] 15, + [Rread9p1] 8, + [Twrite9p1] 16, + [Rwrite9p1] 7, + [Tclunk9p1] 5, + [Rclunk9p1] 5, + [Tremove9p1] 5, + [Rremove9p1] 5, + [Tstat9p1] 5, + [Rstat9p1] 121, + [Twstat9p1] 121, + [Rwstat9p1] 5, + [Tclwalk9p1] 35, + [Rclwalk9p1] 13, +}; + +enum +{ + Twritehdr = 16, /* Min bytes for Twrite */ + Rreadhdr = 8, /* Min bytes for Rread */ + Twritecnt = 13, /* Offset in byte stream of write count */ + Rreadcnt = 5, /* Offset for Readcnt */ +}; + +int +mntrpclen(uchar *d, int n) +{ + uchar t; + int len, off; + + if(n < 1) + return 0; + + t = d[0]; + switch(t) { /* This is the type */ + default: + len = msglen[t]; + if(len == 0) /* Illegal type so consume */ + return n; + if(n < len) + return 0; + return len; + case Twrite9p1: /* Fmt: TGGFFOOOOOOOOCC */ + len = Twritehdr; /* T = type, G = tag, F = fid */ + off = Twritecnt; /* O = offset, C = count */ + break; + case Rread9p1: /* Fmt: TGGFFCC */ + len = Rreadhdr; + off = Rreadcnt; + break; + } + if(n < off+2) + return 0; + + len += d[off]|(d[off+1]<<8); + if(n < len) + return 0; + + return len; +} + +int +fcall(int fd) +{ + int i, r, n, l; + uchar *p, *buf; + int pipefd[2]; + + if(pipe(pipefd) < 0) + fatal("fcall pipe: %r"); + + buf = malloc(MAXRPC); + if(buf == nil) + fatal("fcall malloc"); + + switch(rfork(RFPROC|RFMEM|RFFDG|RFCNAMEG)){ + default: + return pipefd[0]; /* parent returns fd */ + case 0: + break; /* child builds buffers */ + case -1: + fatal("fcall fork: %r"); + } + + /* close file descriptors */ + for(i=0; i<20; i++) + if(i!=fd && i!=pipefd[1]) + close(i); + + l = MAXRPC; + p = buf; + for(;;) { + n = read(fd, p, l); + if(n < 0) + break; + p += n; + l -= n; + + for(;;) { + r = mntrpclen(buf, p - buf); + if(r == 0) + break; + + if(write(pipefd[1], buf, r) < 0) + break; + + n = (p - buf) - r; + memmove(buf, buf+r, n); + p = buf+n; + l = MAXRPC - n; + } + } + close(pipefd[1]); + fatal(nil); + return -1; +} diff --git a/sys/src/cmd/srvold9p/mkfile b/sys/src/cmd/srvold9p/mkfile new file mode 100755 index 000000000..41e6ceb71 --- /dev/null +++ b/sys/src/cmd/srvold9p/mkfile @@ -0,0 +1,11 @@ +</$objtype/mkfile +BIN=/$objtype/bin + +TARG=srvold9p +OFILES=srvold9p.$O\ + 9p1lib.$O\ + fcall.$O\ + +</sys/src/cmd/mkone + +install: $O.out diff --git a/sys/src/cmd/srvold9p/srvold9p.c b/sys/src/cmd/srvold9p/srvold9p.c new file mode 100755 index 000000000..32f6b0bf0 --- /dev/null +++ b/sys/src/cmd/srvold9p/srvold9p.c @@ -0,0 +1,1123 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <fcall.h> +#include <libsec.h> +#include "9p1.h" + +char *user; +int newfd; +int roldfd; +int woldfd; +int debug; +int dofcall; +QLock servelock; +QLock fidlock; +QLock taglock; +int mainpid; +int ntag; +int nfork; +char FLUSHED[] = "FLUSHED"; + +enum{ + Maxfdata = 8192 +}; + +enum{ + Command, + Network, + File, + Stdio, +}; + +typedef struct Tag Tag; +struct Tag +{ + int tag; + int flushed; + int received; + int ref; + Tag *next; +}; + +typedef struct Message Message; +struct Message +{ + char *data; + int n; +}; + +typedef struct Fid Fid; + +struct Fid +{ + short busy; + short allocated; + int fid; + Qid qid; + ulong newoffset; + ulong oldoffset; + Fid *next; +}; + +Fid *fids; +Tag *tags; + +char *rflush(Fcall*, Fcall*, char*), + *rversion(Fcall*, Fcall*, char*), + *rauth(Fcall*, Fcall*, char*), + *rattach(Fcall*, Fcall*, char*), + *rwalk(Fcall*, Fcall*, char*), + *ropen(Fcall*, Fcall*, char*), + *rcreate(Fcall*, Fcall*, char*), + *rread(Fcall*, Fcall*, char*), + *rwrite(Fcall*, Fcall*, char*), + *rclunk(Fcall*, Fcall*, char*), + *rremove(Fcall*, Fcall*, char*), + *rstat(Fcall*, Fcall*, char*), + *rwstat(Fcall*, Fcall*, char*); + +char *(*fcalls[])(Fcall*, Fcall*, char*) = { + [Tversion] rversion, + [Tflush] rflush, + [Tauth] rauth, + [Tattach] rattach, + [Twalk] rwalk, + [Topen] ropen, + [Tcreate] rcreate, + [Tread] rread, + [Twrite] rwrite, + [Tclunk] rclunk, + [Tremove] rremove, + [Tstat] rstat, + [Twstat] rwstat, +}; + +char Etoolong[] = "name too long"; + +void connect(int, char*); +void post(int, char*); +void serve(void); +void demux(void); +void* emalloc(ulong); +char* transact9p1(Fcall9p1*, Fcall9p1*, char*); +Fid* newfid(int); + +struct +{ + char chal[CHALLEN]; /* my challenge */ + char rchal[CHALLEN]; /* his challenge */ + char authid[NAMEREC]; + char authdom[DOMLEN]; + int id; +} ai; + +void +usage(void) +{ + fprint(2, "usage: srvold9p [-abcCd] [-u user] [-s | [-m mountpoint]] [-x 'command' | -n network-addr | -f file] [-F] [-p servicename]\n"); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + int method; + char *oldstring; + char *mountpoint, *postname; + int mountflag, mountfd; + int p[2]; +int i; + + fmtinstall('F', fcallfmt); + fmtinstall('G', fcallfmt9p1); + fmtinstall('D', dirfmt); + + user = getuser(); + mountpoint = nil; + mountflag = 0; + postname = nil; + oldstring = nil; + method = -1; + mountfd = -1; + + ARGBEGIN{ + case 'a': + mountflag |= MAFTER; + break; + case 'b': + mountflag |= MBEFORE; + break; + case 'c': + mountflag |= MCREATE; + break; + case 'C': + mountflag |= MCACHE; + break; + case 'd': + debug++; + break; + case 'f': + method = File; + oldstring = ARGF(); + break; + case 'F': + dofcall++; + break; + case 'm': + mountpoint = EARGF(usage()); + break; + case 'n': + method = Network; + oldstring = ARGF(); + break; + case 'p': + postname = ARGF(); + if(postname == nil) + usage(); + break; + case 's': + method = Stdio; + break; + case 'u': + user = EARGF(usage()); + break; + case 'x': + method = Command; + oldstring = ARGF(); + break; + default: + usage(); + }ARGEND; + + if(method == Stdio){ + if(mountpoint!=nil || argc!=0) + usage(); + }else{ + if(oldstring == nil || argc != 0 || (mountflag!=0 && mountpoint==nil)) + usage(); + } + + rfork(RFNOTEG|RFREND); + + connect(method, oldstring); + + if(method == Stdio) + newfd = 0; + else{ + if(pipe(p) < 0) + fatal("pipe: %r"); + if(postname != nil) + post(p[0], postname); + mountfd = p[0]; + newfd = p[1]; + } + if(debug) + fprint(2, "connected and posted\n"); + + switch(rfork(RFPROC|RFMEM|RFNAMEG|RFFDG)){ + case 0: + mainpid = getpid(); + /* child does all the work */ + if(mountfd >= 0) + close(mountfd); + switch(rfork(RFPROC|RFMEM|RFFDG)){ + case 0: + for(i = 0; i < 20; i++) + if (i != roldfd) close(i); + demux(); + return; + case -1: + fatal("fork error: %r"); + break; + } + for(i = 0; i < 20; i++) + if (i != newfd && i != woldfd && (debug == 0 || i != 2)) close(i); + serve(); + break; + case -1: + fatal("fork error: %r"); + break; + default: + /* parent mounts if required, then exits */ + if(mountpoint){ + if(mount(mountfd, -1, mountpoint, mountflag, "") < 0) + fatal("can't mount: %r"); + } + break; + } + exits(nil); +} + +void +connect(int method, char *oldstring) +{ + char *s; + char dir[256]; + + switch(method){ + default: + roldfd = -1; + woldfd = -1; + fatal("can't handle method type %d", method); + break; + case Network: + s = netmkaddr(oldstring, 0, "9fs"); + roldfd = dial(s, 0, dir, 0); + if(roldfd < 0) + fatal("dial %s: %r", s); + woldfd = roldfd; + if(dofcall) + roldfd = fcall(woldfd); + break; + case File: + roldfd = open(oldstring, ORDWR); + if(roldfd < 0) + fatal("can't open %s: %r", oldstring); + woldfd = roldfd; + if(dofcall) + roldfd = fcall(woldfd); + break; + case Stdio: + roldfd = fcall(1); + woldfd = 1; + break; + } +} + +void +post(int fd, char *srv) +{ + int f; + char buf[128]; + + snprint(buf, sizeof buf, "/srv/%s", srv); + f = create(buf, OWRITE, 0666); + if(f < 0) + fatal("can't create %s: %r", buf); + sprint(buf, "%d", fd); + if(write(f, buf, strlen(buf)) != strlen(buf)) + fatal("post write: %r"); + close(f); +} + +Fid * +newfid(int fid) +{ + Fid *f, *ff; + + ff = 0; + qlock(&fidlock); + for(f = fids; f; f = f->next) + if(f->fid == fid){ + f->allocated = 1; + qunlock(&fidlock); + return f; + } + else if(!ff && !f->allocated) + ff = f; + if(ff){ + ff->fid = fid; + ff->allocated = 1; + qunlock(&fidlock); + return ff; + } + f = emalloc(sizeof *f); + f->fid = fid; + f->next = fids; + f->allocated = 1; + fids = f; + qunlock(&fidlock); + return f; +} + +/* + * Reads returning 9P1 messages and demultiplexes them. + * BUG: assumes one read per message. + */ +void +demux(void) +{ + int m, n; + char *data; + Fcall9p1 r; + Message *msg; + Tag *t; + + for(;;){ + data = malloc(IOHDRSZ+Maxfdata); /* no need to clear memory */ + if(data == nil) + fatal("demux malloc: %r"); + m = read(roldfd, data, IOHDRSZ+Maxfdata); + if(m <= 0) + fatal("read error talking to old system: %r"); + n = convM2S9p1(data, &r, m); + if(n == 0) + fatal("bad conversion receiving from old system"); + if(debug) + fprint(2, "srvold9p:<=%G\n", &r); + qlock(&taglock); + for(t=tags; t!=nil; t=t->next) + if(t->tag == r.tag){ + t->received = 1; + break; + } + qunlock(&taglock); + /* + * Fcall9p1 tag is used to rendezvous. + * Recipient converts message a second time, but that's OK. + */ + msg = emalloc(sizeof(Message)); + msg->data = data; + msg->n = n; + rendezvous((void*)r.tag, msg); + } +} + +Tag* +newtag(int tag) +{ + Tag *t; + + t = emalloc(sizeof(Tag)); + t->tag = tag; + t->flushed = 0; + t->received = 0; + t->ref = 1; + qlock(&taglock); + t->next = tags; + tags = t; + qunlock(&taglock); + return t; +} + +void +freetag(Tag *tag) /* called with taglock set */ +{ + Tag *t, *prev; + + if(tag->ref-- == 1){ + prev = nil; + for(t=tags; t!=nil; t=t->next){ + if(t == tag){ + if(prev == nil) + tags = t->next; + else + prev->next = t->next; + break; + } + prev = t; + } + if(t == nil) + sysfatal("freetag"); + free(tag); + } +} + +void +serve(void) +{ + char *err; + int n; + Fcall thdr; + Fcall rhdr; + uchar mdata[IOHDRSZ+Maxfdata]; + char mdata9p1[IOHDRSZ+Maxfdata]; + Tag *tag; + + for(;;){ + qlock(&servelock); + for(;;){ + n = read9pmsg(newfd, mdata, sizeof mdata); + + if(n == 0) + continue; + if(n < 0) + break; + if(n > 0 && convM2S(mdata, n, &thdr) > 0) + break; + } + if(n>0 && servelock.head==nil) /* no other processes waiting to read */ + switch(rfork(RFPROC|RFMEM)){ + case 0: + /* child starts serving */ + continue; + break; + case -1: + fatal("fork error: %r"); + break; + default: + break; + } + qunlock(&servelock); + + if(n < 0) + fatal(nil); /* exit quietly; remote end has just hung up */ + + if(debug) + fprint(2, "srvold9p:<-%F\n", &thdr); + + tag = newtag(thdr.tag); + + if(!fcalls[thdr.type]) + err = "bad fcall type"; + else + err = (*fcalls[thdr.type])(&thdr, &rhdr, mdata9p1); + + qlock(&taglock); + if(tag->flushed){ + freetag(tag); + qunlock(&taglock); + continue; + } + qunlock(&taglock); + + if(err){ + rhdr.type = Rerror; + rhdr.ename = err; + }else{ + rhdr.type = thdr.type + 1; + rhdr.fid = thdr.fid; + } + rhdr.tag = thdr.tag; + if(debug) + fprint(2, "srvold9p:->%F\n", &rhdr);/**/ + n = convS2M(&rhdr, mdata, sizeof mdata); + if(n == 0) + fatal("convS2M error on write"); + if(write(newfd, mdata, n) != n) + fatal("mount write"); + + qlock(&taglock); + freetag(tag); + qunlock(&taglock); + } +} + +void +send9p1(Fcall9p1 *t, char *data) +{ + int m, n; + + if(debug) + fprint(2, "srvold9p:=>%G\n", t); + n = convS2M9p1(t, data); + if(n == 0) + fatal("bad conversion sending to old system"); + m = write(woldfd, data, n); + if(m != n) + fatal("wrote %d to old system; should be %d", m, n); +} + +int +recv9p1(Fcall9p1 *r, int tag, char *data) +{ + int n; + Message *msg; + + msg = rendezvous((void*)tag, 0); + if(msg == (void*)~0) + fatal("rendezvous: %r"); + if(msg == nil){ + if(debug) + fprint(2, "recv flushed\n"); + return -1; + } + /* copy data to local buffer */ + memmove(data, msg->data, msg->n); + n = convM2S9p1(data, r, msg->n); + if(n == 0) + fatal("bad conversion receiving from old system"); + free(msg->data); + free(msg); + return 1; +} + +char* +transact9p1(Fcall9p1 *t, Fcall9p1 *r, char *mdata9p1) +{ + send9p1(t, mdata9p1); + if(recv9p1(r, t->tag, mdata9p1) < 0) + return FLUSHED; + if(r->type == Rerror9p1) + return r->ename; + if(r->type != t->type+1) + fatal("bad message type; expected %d got %d", t->type+1, r->type); + return nil; +} + +char* +rflush(Fcall *t, Fcall *, char *mdata9p1) +{ + Fcall9p1 t9, r9; + Tag *oldt; + + t9.type = Tflush9p1; + t9.tag = t->tag; + t9.oldtag = t->oldtag; + qlock(&taglock); + for(oldt=tags; oldt!=nil; oldt=oldt->next) + if(oldt->tag == t->oldtag){ + oldt->flushed = 1; + oldt->ref++; + break; + } + qunlock(&taglock); + + if(oldt == nil){ /* nothing to flush */ + if(debug) + fprint(2, "no such tag to flush\n"); + return 0; + } + + transact9p1(&t9, &r9, mdata9p1); /* can't error */ + + qlock(&taglock); + if(oldt->received == 0){ /* wake up receiver */ + if(debug) + fprint(2, "wake up receiver\n"); + oldt->received = 1; + rendezvous((void*)t->oldtag, 0); + } + freetag(oldt); + qunlock(&taglock); + return 0; +} + +char* +rversion(Fcall *t, Fcall *r, char*) +{ + Fid *f; + + /* just ack; this one doesn't go to old service */ + if(t->msize > IOHDRSZ+Maxfdata) + r->msize = IOHDRSZ+Maxfdata; + else + r->msize = t->msize; + if(strncmp(t->version, "9P2000", 6) != 0) + return "unknown 9P version"; + r->version = "9P2000"; + + qlock(&fidlock); + for(f = fids; f; f = f->next){ + f->busy = 0; + f->allocated = 0; + } + qunlock(&fidlock); + + return 0; +} + +char* +rauth(Fcall *, Fcall *, char *) +{ + return "srvold9p: authentication not supported"; +} + +#ifdef asdf + +void +memrandom(void *p, int n) +{ + ulong *lp; + uchar *cp; + + for(lp = p; n >= sizeof(ulong); n -= sizeof(ulong)) + *lp++ = fastrand(); + for(cp = (uchar*)lp; n > 0; n--) + *cp++ = fastrand(); +} + +char* +rsession(Fcall *t, Fcall *r, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + Fid *f; + + t9.type = Tsession9p1; + t9.tag = t->tag; + if(doauth) + memrandom(t9.chal, sizeof t9.chal); + else + memset(t9.chal, 0, sizeof t9.chal); + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + + qlock(&fidlock); + for(f = fids; f; f = f->next){ + f->busy = 0; + f->allocated = 0; + } + qunlock(&fidlock); + + if(doauth){ + memmove(ai.authid, r9.authid, sizeof ai.authid); + memmove(ai.authdom, r9.authdom, sizeof ai.authid); + memmove(ai.rchal, r9.chal, sizeof ai.rchal); + memmove(ai.chal, t9.chal, sizeof ai.chal); + r->authid = ai.authid; + r->authdom = ai.authdom; + r->chal = (uchar*)ai.rchal; + r->nchal = CHALLEN; + } else { + r->authid = ""; + r->authdom = ""; + r->nchal = 0; + r->chal = nil; + } + return 0; +} +#endif + +char* +rattach(Fcall *t, Fcall *r, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + Fid *f; + + f = newfid(t->fid); + if(f->busy) + return "attach: fid in use"; + /* no authentication! */ + t9.type = Tattach9p1; + t9.tag = t->tag; + t9.fid = t->fid; + strncpy(t9.uname, t->uname, NAMEREC); + if(strcmp(user, "none") == 0) + strncpy(t9.uname, user, NAMEREC); + strncpy(t9.aname, t->aname, NAMEREC); + memset(t9.ticket, 0, sizeof t9.ticket); + memset(t9.auth, 0, sizeof t9.auth); + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + + r->qid.path = r9.qid.path & ~0x80000000; + r->qid.vers = r9.qid.version; + r->qid.type = QTDIR; + f->busy = 1; + f->qid = r->qid; + return 0; +} + +char* +rwalk(Fcall *t, Fcall *r, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + int i, fid; + Qid *q; + Fid *f, *nf; + + f = newfid(t->fid); + if(!f->busy) + return "walk: bad fid"; + + fid = t->fid; + nf = nil; + if(t->fid != t->newfid){ + nf = newfid(t->newfid); + if(nf->busy) + return "walk: newfid in use"; + t9.type = Tclone9p1; + t9.tag = t->tag; + t9.fid = t->fid; + t9.newfid = t->newfid; + err = transact9p1(&t9, &r9, mdata9p1); + if(err){ + nf->busy = 0; + nf->allocated = 0; + return err; + } + fid = t->newfid; + nf->busy = 1; + } + + err = nil; + r->nwqid = 0; + for(i=0; i<t->nwname && err==nil; i++){ + if(i > MAXWELEM) + break; + t9.type = Twalk9p1; + t9.tag = t->tag; + t9.fid = fid; + strncpy(t9.name, t->wname[i], NAMEREC); + err = transact9p1(&t9, &r9, mdata9p1); + if(err == FLUSHED){ + i = -1; /* guarantee cleanup */ + break; + } + if(err == nil){ + q = &r->wqid[r->nwqid++]; + q->type = QTFILE; + if(r9.qid.path & 0x80000000) + q->type = QTDIR; + q->vers = r9.qid.version; + q->path = r9.qid.path & ~0x80000000; + } + } + + if(nf!=nil && (err!=nil || i<t->nwname)){ + /* clunk the new fid */ + t9.type = Tclunk9p1; + t9.tag = t->tag; + t9.fid = t->newfid; + transact9p1(&t9, &r9, mdata9p1); + /* ignore more errors */ + nf->busy = 0; + nf->allocated = 0; + } + + if(i>0 && i==t->nwname && err==nil) + f->qid = r->wqid[r->nwqid-1]; + if(i > 0) + return 0; + return err; +} + +char* +ropen(Fcall *t, Fcall *r, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + Fid *f; + + f = newfid(t->fid); + if(!f->busy) + return "open: bad fid"; + + t9.type = Topen9p1; + t9.tag = t->tag; + t9.fid = t->fid; + t9.mode = t->mode; + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + + r->qid.path = r9.qid.path & ~0x80000000; + r->qid.vers = r9.qid.version; + r->qid.type = QTFILE; + if(r9.qid.path & 0x80000000) + r->qid.type = QTDIR; + f->qid = r->qid; + f->newoffset = 0; + f->oldoffset = 0; + r->iounit = 0; + return 0; +} + +char* +rcreate(Fcall *t, Fcall *r, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + Fid *f; + + f = newfid(t->fid); + if(!f->busy) + return "create: bad fid"; + + t9.type = Tcreate9p1; + t9.tag = t->tag; + t9.fid = t->fid; + if(strlen(t->name)+1 >= NAMEREC) + return "file name element too long"; + strncpy(t9.name, t->name, NAMEREC); + t9.perm = t->perm; + t9.mode = t->mode; + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + + r->qid.path = r9.qid.path & ~0x80000000; + r->qid.vers = r9.qid.version; + r->qid.type = QTFILE; + if(r9.qid.path & 0x80000000) + r->qid.type = QTDIR; + if(r9.qid.path & 0x40000000) + r->qid.type |= QTAPPEND; + if(r9.qid.path & 0x20000000) + r->qid.type |= QTEXCL; + f->qid = r->qid; + r->iounit = 0; + return 0; +} + +char* +dirrread(Fcall *t, Fcall *r, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + Fid *f; + int i, ndir, n, count; + Dir d; + uchar buf[Maxfdata]; + char *old; + + f = newfid(t->fid); + if(!f->busy) + return "dirread: bad fid"; + + if(f->newoffset != t->offset) + return "seek in directory disallowed"; + + t9.type = Tread9p1; + t9.tag = t->tag; + t9.fid = t->fid; + t9.offset = f->oldoffset; + t9.count = t->count; /* new directories tend to be smaller, so this may overshoot */ + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + + ndir = r9.count/DIRREC; + old = r9.data; + count = 0; + for(i=0; i<ndir; i++){ + if(convM2D9p1(old, &d) != DIRREC) + return "bad dir conversion in read"; + n = convD2M(&d, buf+count, sizeof buf-count); + if(n<=BIT16SZ || count+n>t->count) + break; + old += DIRREC; + f->oldoffset += DIRREC; + f->newoffset += n; + count += n; + } + memmove(r9.data, buf, count); /* put it back in stable storage */ + r->data = r9.data; + r->count = count; + return 0; +} + +char* +rread(Fcall *t, Fcall *r, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + Fid *f; + + f = newfid(t->fid); + if(!f->busy) + return "read: bad fid"; + + if(f->qid.type & QTDIR) + return dirrread(t, r, mdata9p1); + + t9.type = Tread9p1; + t9.tag = t->tag; + t9.fid = t->fid; + t9.offset = t->offset; + t9.count = t->count; + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + + r->count = r9.count; + r->data = r9.data; /* points to stable storage */ + return 0; +} + +char* +rwrite(Fcall *t, Fcall *r, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + Fid *f; + + f = newfid(t->fid); + if(!f->busy) + return "write: bad fid"; + + t9.type = Twrite9p1; + t9.tag = t->tag; + t9.fid = t->fid; + t9.offset = t->offset; + t9.count = t->count; + t9.data = t->data; + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + + r->count = r9.count; + return 0; +} + +char* +rclunk(Fcall *t, Fcall *, char *mdata9p1) +{ + Fcall9p1 t9, r9; + Fid *f; + + f = newfid(t->fid); + if(!f->busy) + return "clunk: bad fid"; + t9.type = Tclunk9p1; + t9.tag = t->tag; + t9.fid = t->fid; + transact9p1(&t9, &r9, mdata9p1); + f->busy = 0; + f->allocated = 0; + /* disregard error */ + return 0; +} + +char* +rremove(Fcall *t, Fcall*, char *mdata9p1) +{ + char *err; + Fcall9p1 t9, r9; + Fid *f; + + f = newfid(t->fid); + if(!f->busy) + return "remove: bad fid"; + t9.type = Tremove9p1; + t9.tag = t->tag; + t9.fid = t->fid; + err = transact9p1(&t9, &r9, mdata9p1); + f->busy = 0; + f->allocated = 0; + return err; +} + +char* +rstat(Fcall *t, Fcall *r, char *mdata9p1) +{ + Fcall9p1 t9, r9; + char *err; + Fid *f; + Dir d; + uchar buf[256]; /* big enough; there's no long names */ + + f = newfid(t->fid); + if(!f->busy) + return "stat: bad fid"; + + t9.type = Tstat9p1; + t9.tag = t->tag; + t9.fid = t->fid; + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + + if(convM2D9p1(r9.stat, &d) != DIRREC) + return "bad conversion in stat"; + r->stat = buf; + r->nstat = convD2M(&d, buf, sizeof buf); + return 0; +} + +int +anydefault(Dir *d) +{ + if(d->name[0] == '\0') + return 1; + if(d->uid[0] == '\0') + return 1; + if(d->gid[0] == '\0') + return 1; + if(d->mode == ~0) + return 1; + if(d->mtime == ~0) + return 1; + return 0; +} + +char* +rwstat(Fcall *t, Fcall *, char *mdata9p1) +{ + Fcall9p1 t9, r9; + char strs[DIRREC]; + char *err; + Fid *f; + Dir d, cd; + + f = newfid(t->fid); + if(!f->busy) + return "wstat: bad fid"; + + convM2D(t->stat, t->nstat, &d, strs); + cd = d; + if(anydefault(&d)){ + /* must first stat file so we can copy current values */ + t9.type = Tstat9p1; + t9.tag = t->tag; + t9.fid = t->fid; + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + if(convM2D9p1(r9.stat, &cd) != DIRREC) + return "bad in conversion in wstat"; + + /* fill in default values */ + if(d.name[0] != '\0'){ + if(strlen(d.name) >= NAMEREC) + return Etoolong; + cd.name = d.name; + } + if(d.uid[0] != '\0'){ + if(strlen(d.uid) >= NAMEREC) + return Etoolong; + cd.uid = d.uid; + } + if(d.gid[0] != '\0'){ + if(strlen(d.gid) >= NAMEREC) + return Etoolong; + cd.gid = d.gid; + } + if(d.mode != ~0) + cd.mode = d.mode; + if(d.mtime != ~0) + cd.mtime = d.mtime; + if(d.length != ~0LL) + cd.length = d.length; + } + + if(convD2M9p1(&cd, t9.stat) != DIRREC) + return "bad out conversion in wstat"; + + t9.type = Twstat9p1; + t9.tag = t->tag; + t9.fid = t->fid; + err = transact9p1(&t9, &r9, mdata9p1); + if(err) + return err; + return 0; +} + +void * +emalloc(ulong n) +{ + void *p; + + p = malloc(n); + if(!p) + fatal("out of memory: %r"); + memset(p, 0, n); + return p; +} + +void +fatal(char *fmt, ...) +{ + char buf[1024]; + va_list arg; + + if(fmt){ + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s: (pid %d) %s\n", argv0, getpid(), buf); + }else + buf[0] = '\0'; + if(mainpid){ + /* two hits are sometimes needed */ + postnote(PNGROUP, mainpid, "die1 - from srvold9p"); + postnote(PNGROUP, mainpid, "die2 - from srvold9p"); + } + exits(buf); +} |