diff options
author | Russ Cox <rsc@swtch.com> | 2012-07-17 19:10:45 -0400 |
---|---|---|
committer | Russ Cox <rsc@swtch.com> | 2012-07-17 19:10:45 -0400 |
commit | d2173bb552d308d60a4e4a53cd3b8e0949b38dbc (patch) | |
tree | 196b3078e732ff170019734fb6990ceab2f80b01 /src/cmd/disk | |
parent | f0add8ef24f83cb2085ef1c7534d16c57881e3f3 (diff) | |
download | plan9port-d2173bb552d308d60a4e4a53cd3b8e0949b38dbc.tar.gz plan9port-d2173bb552d308d60a4e4a53cd3b8e0949b38dbc.tar.bz2 plan9port-d2173bb552d308d60a4e4a53cd3b8e0949b38dbc.zip |
disk/mkfs, disk/mkext: add from Plan 9
R=rsc, rsc
http://codereview.appspot.com/6405057
Diffstat (limited to 'src/cmd/disk')
-rw-r--r-- | src/cmd/disk/mkext.c | 318 | ||||
-rw-r--r-- | src/cmd/disk/mkfile | 11 | ||||
-rw-r--r-- | src/cmd/disk/mkfs.c | 840 |
3 files changed, 1169 insertions, 0 deletions
diff --git a/src/cmd/disk/mkext.c b/src/cmd/disk/mkext.c new file mode 100644 index 00000000..05190d04 --- /dev/null +++ b/src/cmd/disk/mkext.c @@ -0,0 +1,318 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +enum{ + LEN = 8*1024, + NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */ +}; + +int selected(char*, int, char*[]); +void mkdirs(char*, char*); +void mkdir(char*, ulong, ulong, char*, char*); +void extract(char*, ulong, ulong, char*, char*, uvlong); +void seekpast(uvlong); +void error(char*, ...); +void warn(char*, ...); +void usage(void); +#pragma varargck argpos warn 1 +#pragma varargck argpos error 1 + +Biobuf bin; +uchar binbuf[2*LEN]; +char linebuf[LEN]; +int uflag; +int hflag; +int vflag; +int Tflag; + +void +main(int argc, char **argv) +{ + Biobuf bout; + char *fields[NFLDS], name[2*LEN], *p, *namep; + char *uid, *gid; + ulong mode, mtime; + uvlong bytes; + + quotefmtinstall(); + namep = name; + ARGBEGIN{ + case 'd': + p = ARGF(); + if(strlen(p) >= LEN) + error("destination fs name too long\n"); + strcpy(name, p); + namep = name + strlen(name); + break; + case 'h': + hflag = 1; + Binit(&bout, 1, OWRITE); + break; + case 'u': + uflag = 1; + Tflag = 1; + break; + case 'T': + Tflag = 1; + break; + case 'v': + vflag = 1; + break; + default: + usage(); + }ARGEND + + Binits(&bin, 0, OREAD, binbuf, sizeof binbuf); + while(p = Brdline(&bin, '\n')){ + p[Blinelen(&bin)-1] = '\0'; + strcpy(linebuf, p); + p = linebuf; + if(strcmp(p, "end of archive") == 0){ + Bterm(&bout); + fprint(2, "done\n"); + exits(0); + } + if (gettokens(p, fields, NFLDS, " \t") != NFLDS){ + warn("too few fields in file header"); + continue; + } + p = unquotestrdup(fields[0]); + strcpy(namep, p); + free(p); + mode = strtoul(fields[1], 0, 8); + uid = fields[2]; + gid = fields[3]; + mtime = strtoul(fields[4], 0, 10); + bytes = strtoull(fields[5], 0, 10); + if(argc){ + if(!selected(namep, argc, argv)){ + if(bytes) + seekpast(bytes); + continue; + } + mkdirs(name, namep); + } + if(hflag){ + Bprint(&bout, "%q %luo %q %q %lud %llud\n", + name, mode, uid, gid, mtime, bytes); + if(bytes) + seekpast(bytes); + continue; + } + if(mode & DMDIR) + mkdir(name, mode, mtime, uid, gid); + else + extract(name, mode, mtime, uid, gid, bytes); + } + fprint(2, "premature end of archive\n"); + exits("premature end of archive"); +} + +int +fileprefix(char *prefix, char *s) +{ + while(*prefix) + if(*prefix++ != *s++) + return 0; + if(*s && *s != '/') + return 0; + return 1; +} + +int +selected(char *s, int argc, char *argv[]) +{ + int i; + + for(i=0; i<argc; i++) + if(fileprefix(argv[i], s)) + return 1; + return 0; +} + +void +mkdirs(char *name, char *namep) +{ + char buf[2*LEN], *p; + int fd; + + strcpy(buf, name); + for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){ + if(p[1] == '\0') + return; + *p = 0; + fd = create(buf, OREAD, 0775|DMDIR); + close(fd); + *p = '/'; + } +} + +void +mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid) +{ + Dir *d, xd; + int fd; + char *p; + char olderr[256]; + + fd = create(name, OREAD, mode); + if(fd < 0){ + rerrstr(olderr, sizeof(olderr)); + if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){ + free(d); + warn("can't make directory %q, mode %luo: %s", name, mode, olderr); + return; + } + free(d); + } + close(fd); + + d = &xd; + nulldir(d); + p = utfrrune(name, L'/'); + if(p) + p++; + else + p = name; + d->name = p; + if(uflag){ + d->uid = uid; + d->gid = gid; + } + if(Tflag) + d->mtime = mtime; + d->mode = mode; + if(dirwstat(name, d) < 0) + warn("can't set modes for %q: %r", name); + + if(uflag||Tflag){ + if((d = dirstat(name)) == nil){ + warn("can't reread modes for %q: %r", name); + return; + } + if(Tflag && d->mtime != mtime) + warn("%q: time mismatch %lud %lud\n", name, mtime, d->mtime); + if(uflag && strcmp(uid, d->uid)) + warn("%q: uid mismatch %q %q", name, uid, d->uid); + if(uflag && strcmp(gid, d->gid)) + warn("%q: gid mismatch %q %q", name, gid, d->gid); + } +} + +void +extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, uvlong bytes) +{ + Dir d, *nd; + Biobuf *b; + char buf[LEN]; + char *p; + ulong n; + uvlong tot; + + if(vflag) + print("x %q %llud bytes\n", name, bytes); + + b = Bopen(name, OWRITE); + if(!b){ + warn("can't make file %q: %r", name); + seekpast(bytes); + return; + } + for(tot = 0; tot < bytes; tot += n){ + n = sizeof buf; + if(tot + n > bytes) + n = bytes - tot; + n = Bread(&bin, buf, n); + if(n <= 0) + error("premature eof reading %q", name); + if(Bwrite(b, buf, n) != n) + warn("error writing %q: %r", name); + } + + nulldir(&d); + p = utfrrune(name, '/'); + if(p) + p++; + else + p = name; + d.name = p; + if(uflag){ + d.uid = uid; + d.gid = gid; + } + if(Tflag) + d.mtime = mtime; + d.mode = mode; + Bflush(b); + if(dirfwstat(Bfildes(b), &d) < 0) + warn("can't set modes for %q: %r", name); + if(uflag||Tflag){ + if((nd = dirfstat(Bfildes(b))) == nil) + warn("can't reread modes for %q: %r", name); + else{ + if(Tflag && nd->mtime != mtime) + warn("%q: time mismatch %lud %lud\n", + name, mtime, nd->mtime); + if(uflag && strcmp(uid, nd->uid)) + warn("%q: uid mismatch %q %q", + name, uid, nd->uid); + if(uflag && strcmp(gid, nd->gid)) + warn("%q: gid mismatch %q %q", + name, gid, nd->gid); + free(nd); + } + } + Bterm(b); +} + +void +seekpast(uvlong bytes) +{ + char buf[LEN]; + long n; + uvlong tot; + + for(tot = 0; tot < bytes; tot += n){ + n = sizeof buf; + if(tot + n > bytes) + n = bytes - tot; + n = Bread(&bin, buf, n); + if(n < 0) + error("premature eof"); + } +} + +void +error(char *fmt, ...) +{ + char buf[1024]; + va_list arg; + + sprint(buf, "%q: ", argv0); + va_start(arg, fmt); + vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s\n", buf); + exits(0); +} + +void +warn(char *fmt, ...) +{ + char buf[1024]; + va_list arg; + + sprint(buf, "%q: ", argv0); + va_start(arg, fmt); + vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s\n", buf); +} + +void +usage(void) +{ + fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n"); + exits("usage"); +} diff --git a/src/cmd/disk/mkfile b/src/cmd/disk/mkfile new file mode 100644 index 00000000..d702a890 --- /dev/null +++ b/src/cmd/disk/mkfile @@ -0,0 +1,11 @@ +<$PLAN9/src/mkhdr + +TARG=\ + mkext\ + mkfs\ + +BIN=$BIN/disk + +<$PLAN9/src/mkmany + + diff --git a/src/cmd/disk/mkfs.c b/src/cmd/disk/mkfs.c new file mode 100644 index 00000000..1e70ab76 --- /dev/null +++ b/src/cmd/disk/mkfs.c @@ -0,0 +1,840 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <bio.h> + +#define getmode plan9_getmode +#define setuid plan9_setuid + +enum{ + LEN = 8*1024, + HUNKS = 128, + + /* + * types of destination file sytems + */ + Kfs = 0, + Fs, + Archive, +}; + +typedef struct File File; + +struct File{ + char *new; + char *elem; + char *old; + char *uid; + char *gid; + ulong mode; +}; + +void arch(Dir*); +void copy(Dir*); +int copyfile(File*, Dir*, int); +void* emalloc(ulong); +void error(char *, ...); +void freefile(File*); +File* getfile(File*); +char* getmode(char*, ulong*); +char* getname(char*, char**); +char* getpath(char*); +void kfscmd(char *); +void mkdir(Dir*); +int mkfile(File*); +void mkfs(File*, int); +char* mkpath(char*, char*); +void mktree(File*, int); +void mountkfs(char*); +void printfile(File*); +void setnames(File*); +void setusers(void); +void skipdir(void); +char* strdup(char*); +int uptodate(Dir*, char*); +void usage(void); +void warn(char *, ...); + +Biobuf *b; +Biobuf bout; /* stdout when writing archive */ +uchar boutbuf[2*LEN]; +char newfile[LEN]; +char oldfile[LEN]; +char *proto; +char *cputype; +char *users; +char *oldroot; +char *newroot; +char *prog = "mkfs"; +int lineno; +char *buf; +char *zbuf; +int buflen = 1024-8; +int indent; +int verb; +int modes; +int ream; +int debug; +int xflag; +int sfd; +int fskind; /* Kfs, Fs, Archive */ +int setuid; /* on Fs: set uid and gid? */ +char *user; + +void +main(int argc, char **argv) +{ + File file; + char *name; + int i, errs; + + quotefmtinstall(); + user = getuser(); + name = ""; + memset(&file, 0, sizeof file); + file.new = ""; + file.old = 0; + oldroot = ""; + newroot = "/n/kfs"; + users = 0; + fskind = Kfs; + ARGBEGIN{ + case 'a': + if(fskind != Kfs) { + fprint(2, "cannot use -a with -d\n"); + usage(); + } + fskind = Archive; + newroot = ""; + Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf); + break; + case 'd': + if(fskind != Kfs) { + fprint(2, "cannot use -d with -a\n"); + usage(); + } + fskind = Fs; + newroot = ARGF(); + break; + case 'D': + debug = 1; + break; + case 'n': + name = EARGF(usage()); + break; + case 'p': + modes = 1; + break; + case 'r': + ream = 1; + break; + case 's': + oldroot = ARGF(); + break; + case 'u': + users = ARGF(); + break; + case 'U': + setuid = 1; + break; + case 'v': + verb = 1; + break; + case 'x': + xflag = 1; + break; + case 'z': + buflen = atoi(ARGF())-8; + break; + default: + usage(); + }ARGEND + + if(!argc) + usage(); + + buf = emalloc(buflen); + zbuf = emalloc(buflen); + memset(zbuf, 0, buflen); + + mountkfs(name); + kfscmd("allow"); + proto = "users"; + setusers(); + cputype = getenv("cputype"); + if(cputype == 0) + cputype = "68020"; + + errs = 0; + for(i = 0; i < argc; i++){ + proto = argv[i]; + fprint(2, "processing %q\n", proto); + + b = Bopen(proto, OREAD); + if(!b){ + fprint(2, "%q: can't open %q: skipping\n", prog, proto); + errs++; + continue; + } + + lineno = 0; + indent = 0; + mkfs(&file, -1); + Bterm(b); + } + fprint(2, "file system made\n"); + kfscmd("disallow"); + kfscmd("sync"); + if(errs) + exits("skipped protos"); + if(fskind == Archive){ + Bprint(&bout, "end of archive\n"); + Bterm(&bout); + } + exits(0); +} + +void +mkfs(File *me, int level) +{ + File *child; + int rec; + + child = getfile(me); + if(!child) + return; + if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){ + rec = child->elem[0] == '+'; + free(child->new); + child->new = strdup(me->new); + setnames(child); + mktree(child, rec); + freefile(child); + child = getfile(me); + } + while(child && indent > level){ + if(mkfile(child)) + mkfs(child, indent); + freefile(child); + child = getfile(me); + } + if(child){ + freefile(child); + Bseek(b, -Blinelen(b), 1); + lineno--; + } +} + +void +mktree(File *me, int rec) +{ + File child; + Dir *d; + int i, n, fd; + + fd = open(oldfile, OREAD); + if(fd < 0){ + warn("can't open %q: %r", oldfile); + return; + } + + child = *me; + while((n = dirread(fd, &d)) > 0){ + for(i = 0; i < n; i++){ + child.new = mkpath(me->new, d[i].name); + if(me->old) + child.old = mkpath(me->old, d[i].name); + child.elem = d[i].name; + setnames(&child); + if(copyfile(&child, &d[i], 1) && rec) + mktree(&child, rec); + free(child.new); + if(child.old) + free(child.old); + } + } + close(fd); +} + +int +mkfile(File *f) +{ + Dir *dir; + + if((dir = dirstat(oldfile)) == nil){ + warn("can't stat file %q: %r", oldfile); + skipdir(); + return 0; + } + return copyfile(f, dir, 0); +} + +int +copyfile(File *f, Dir *d, int permonly) +{ + ulong mode; + Dir nd; + + if(xflag){ + Bprint(&bout, "%q\t%ld\t%lld\n", f->new, d->mtime, d->length); + return (d->mode & DMDIR) != 0; + } + if(verb && (fskind == Archive || ream)) + fprint(2, "%q\n", f->new); + d->name = f->elem; + if(d->type != 'M' && d->type != 'Z'){ + d->uid = "sys"; + d->gid = "sys"; + mode = (d->mode >> 6) & 7; + d->mode |= mode | (mode << 3); + } + if(strcmp(f->uid, "-") != 0) + d->uid = f->uid; + if(strcmp(f->gid, "-") != 0) + d->gid = f->gid; + if(fskind == Fs && !setuid){ + d->uid = ""; + d->gid = ""; + } + if(f->mode != ~0){ + if(permonly) + d->mode = (d->mode & ~0666) | (f->mode & 0666); + else if((d->mode&DMDIR) != (f->mode&DMDIR)) + warn("inconsistent mode for %q", f->new); + else + d->mode = f->mode; + } + if(!uptodate(d, newfile)){ + if(verb && (fskind != Archive && ream == 0)) + fprint(2, "%q\n", f->new); + if(d->mode & DMDIR) + mkdir(d); + else + copy(d); + }else if(modes){ + nulldir(&nd); + nd.mode = d->mode; + nd.gid = d->gid; + nd.mtime = d->mtime; + if(verb && (fskind != Archive && ream == 0)) + fprint(2, "%q\n", f->new); + if(dirwstat(newfile, &nd) < 0) + warn("can't set modes for %q: %r", f->new); + nulldir(&nd); + nd.uid = d->uid; + dirwstat(newfile, &nd); + } + return (d->mode & DMDIR) != 0; +} + +/* + * check if file to is up to date with + * respect to the file represented by df + */ +int +uptodate(Dir *df, char *to) +{ + int ret; + Dir *dt; + + if(fskind == Archive || ream || (dt = dirstat(to)) == nil) + return 0; + ret = dt->mtime >= df->mtime; + free(dt); + return ret; +} + +void +copy(Dir *d) +{ + char cptmp[LEN], *p; + int f, t, n, needwrite, nowarnyet = 1; + vlong tot, len; + Dir nd; + + f = open(oldfile, OREAD); + if(f < 0){ + warn("can't open %q: %r", oldfile); + return; + } + t = -1; + if(fskind == Archive) + arch(d); + else{ + strcpy(cptmp, newfile); + p = utfrrune(cptmp, L'/'); + if(!p) + error("internal temporary file error"); + strcpy(p+1, "__mkfstmp"); + t = create(cptmp, OWRITE, 0666); + if(t < 0){ + warn("can't create %q: %r", newfile); + close(f); + return; + } + } + + needwrite = 0; + for(tot = 0; tot < d->length; tot += n){ + len = d->length - tot; + /* don't read beyond d->length */ + if (len > buflen) + len = buflen; + n = read(f, buf, len); + if(n <= 0) { + if(n < 0 && nowarnyet) { + warn("can't read %q: %r", oldfile); + nowarnyet = 0; + } + /* + * don't quit: pad to d->length (in pieces) to agree + * with the length in the header, already emitted. + */ + memset(buf, 0, len); + n = len; + } + if(fskind == Archive){ + if(Bwrite(&bout, buf, n) != n) + error("write error: %r"); + }else if(memcmp(buf, zbuf, n) == 0){ + if(seek(t, n, 1) < 0) + error("can't write zeros to %q: %r", newfile); + needwrite = 1; + }else{ + if(write(t, buf, n) < n) + error("can't write %q: %r", newfile); + needwrite = 0; + } + } + close(f); + if(needwrite){ + if(seek(t, -1, 1) < 0 || write(t, zbuf, 1) != 1) + error("can't write zero at end of %q: %r", newfile); + } + if(tot != d->length){ + /* this should no longer happen */ + warn("wrong number of bytes written to %q (was %lld should be %lld)\n", + newfile, tot, d->length); + if(fskind == Archive){ + warn("seeking to proper position\n"); + /* does no good if stdout is a pipe */ + Bseek(&bout, d->length - tot, 1); + } + } + if(fskind == Archive) + return; + remove(newfile); + nulldir(&nd); + nd.mode = d->mode; + nd.gid = d->gid; + nd.mtime = d->mtime; + nd.name = d->name; + if(dirfwstat(t, &nd) < 0) + error("can't move tmp file to %q: %r", newfile); + nulldir(&nd); + nd.uid = d->uid; + dirfwstat(t, &nd); + close(t); +} + +void +mkdir(Dir *d) +{ + Dir *d1; + Dir nd; + int fd; + + if(fskind == Archive){ + arch(d); + return; + } + fd = create(newfile, OREAD, d->mode); + nulldir(&nd); + nd.mode = d->mode; + nd.gid = d->gid; + nd.mtime = d->mtime; + if(fd < 0){ + if((d1 = dirstat(newfile)) == nil || !(d1->mode & DMDIR)){ + free(d1); + error("can't create %q", newfile); + } + free(d1); + if(dirwstat(newfile, &nd) < 0) + warn("can't set modes for %q: %r", newfile); + nulldir(&nd); + nd.uid = d->uid; + dirwstat(newfile, &nd); + return; + } + if(dirfwstat(fd, &nd) < 0) + warn("can't set modes for %q: %r", newfile); + nulldir(&nd); + nd.uid = d->uid; + dirfwstat(fd, &nd); + close(fd); +} + +void +arch(Dir *d) +{ + Bprint(&bout, "%q %luo %q %q %lud %lld\n", + newfile, d->mode, d->uid, d->gid, d->mtime, d->length); +} + +char * +mkpath(char *prefix, char *elem) +{ + char *p; + int n; + + n = strlen(prefix) + strlen(elem) + 2; + p = emalloc(n); + sprint(p, "%s/%s", prefix, elem); + return p; +} + +char * +strdup(char *s) +{ + char *t; + + t = emalloc(strlen(s) + 1); + return strcpy(t, s); +} + +void +setnames(File *f) +{ + sprint(newfile, "%s%s", newroot, f->new); + if(f->old){ + if(f->old[0] == '/') + sprint(oldfile, "%s%s", oldroot, f->old); + else + strcpy(oldfile, f->old); + }else + sprint(oldfile, "%s%s", oldroot, f->new); + if(strlen(newfile) >= sizeof newfile + || strlen(oldfile) >= sizeof oldfile) + error("name overfile"); +} + +void +freefile(File *f) +{ + if(f->old) + free(f->old); + if(f->new) + free(f->new); + free(f); +} + +/* + * skip all files in the proto that + * could be in the current dir + */ +void +skipdir(void) +{ + char *p, c; + int level; + + if(indent < 0 || b == nil) /* b is nil when copying adm/users */ + return; + level = indent; + for(;;){ + indent = 0; + p = Brdline(b, '\n'); + lineno++; + if(!p){ + indent = -1; + return; + } + while((c = *p++) != '\n') + if(c == ' ') + indent++; + else if(c == '\t') + indent += 8; + else + break; + if(indent <= level){ + Bseek(b, -Blinelen(b), 1); + lineno--; + return; + } + } +} + +File* +getfile(File *old) +{ + File *f; + char *elem; + char *p; + int c; + + if(indent < 0) + return 0; +loop: + indent = 0; + p = Brdline(b, '\n'); + lineno++; + if(!p){ + indent = -1; + return 0; + } + while((c = *p++) != '\n') + if(c == ' ') + indent++; + else if(c == '\t') + indent += 8; + else + break; + if(c == '\n' || c == '#') + goto loop; + p--; + f = emalloc(sizeof *f); + p = getname(p, &elem); + if(debug) + fprint(2, "getfile: %q root %q\n", elem, old->new); + f->new = mkpath(old->new, elem); + f->elem = utfrrune(f->new, L'/') + 1; + p = getmode(p, &f->mode); + p = getname(p, &f->uid); + if(!*f->uid) + f->uid = "-"; + p = getname(p, &f->gid); + if(!*f->gid) + f->gid = "-"; + f->old = getpath(p); + if(f->old && strcmp(f->old, "-") == 0){ + free(f->old); + f->old = 0; + } + setnames(f); + + if(debug) + printfile(f); + + return f; +} + +char* +getpath(char *p) +{ + char *q, *new; + int c, n; + + while((c = *p) == ' ' || c == '\t') + p++; + q = p; + while((c = *q) != '\n' && c != ' ' && c != '\t') + q++; + if(q == p) + return 0; + n = q - p; + new = emalloc(n + 1); + memcpy(new, p, n); + new[n] = 0; + return new; +} + +char* +getname(char *p, char **buf) +{ + char *s, *start; + int c; + + while((c = *p) == ' ' || c == '\t') + p++; + + start = p; + while((c = *p) != '\n' && c != ' ' && c != '\t' && c != '\0') + p++; + + *buf = malloc(p+1-start); + if(*buf == nil) + return nil; + memmove(*buf, start, p-start); + (*buf)[p-start] = '\0'; + + if(**buf == '$'){ + s = getenv(*buf+1); + if(s == 0){ + warn("can't read environment variable %q", *buf+1); + skipdir(); + free(*buf); + return nil; + } + free(*buf); + *buf = s; + } + return p; +} + +char* +getmode(char *p, ulong *xmode) +{ + char *buf, *s; + ulong m; + + *xmode = ~0; + p = getname(p, &buf); + if(p == nil) + return nil; + + s = buf; + if(!*s || strcmp(s, "-") == 0) + return p; + m = 0; + if(*s == 'd'){ + m |= DMDIR; + s++; + } + if(*s == 'a'){ + m |= DMAPPEND; + s++; + } + if(*s == 'l'){ + m |= DMEXCL; + s++; + } + if(s[0] < '0' || s[0] > '7' + || s[1] < '0' || s[1] > '7' + || s[2] < '0' || s[2] > '7' + || s[3]){ + warn("bad mode specification %q", buf); + free(buf); + return p; + } + *xmode = m | strtoul(s, 0, 8); + free(buf); + return p; +} + +void +setusers(void) +{ + File file; + int m; + + if(fskind != Kfs) + return; + m = modes; + modes = 1; + file.uid = "adm"; + file.gid = "adm"; + file.mode = DMDIR|0775; + file.new = "/adm"; + file.elem = "adm"; + file.old = 0; + setnames(&file); + strcpy(oldfile, file.new); /* Don't use root for /adm */ + mkfile(&file); + file.new = "/adm/users"; + file.old = users; + file.elem = "users"; + file.mode = 0664; + setnames(&file); + if (file.old) + strcpy(oldfile, file.old); /* Don't use root for /adm/users */ + mkfile(&file); + kfscmd("user"); + mkfile(&file); + file.mode = DMDIR|0775; + file.new = "/adm"; + file.old = "/adm"; + file.elem = "adm"; + setnames(&file); + strcpy(oldfile, file.old); /* Don't use root for /adm */ + mkfile(&file); + modes = m; +} + +void +mountkfs(char *name) +{ + if(fskind != Kfs) + return; + sysfatal("no kfs: use -a or -d"); +} + +void +kfscmd(char *cmd) +{ + char buf[4*1024]; + int n; + + if(fskind != Kfs) + return; + if(write(sfd, cmd, strlen(cmd)) != strlen(cmd)){ + fprint(2, "%q: error writing %q: %r", prog, cmd); + return; + } + for(;;){ + n = read(sfd, buf, sizeof buf - 1); + if(n <= 0) + return; + buf[n] = '\0'; + if(strcmp(buf, "done") == 0 || strcmp(buf, "success") == 0) + return; + if(strcmp(buf, "unknown command") == 0){ + fprint(2, "%q: command %q not recognized\n", prog, cmd); + return; + } + } +} + +void * +emalloc(ulong n) +{ + void *p; + + if((p = malloc(n)) == 0) + error("out of memory"); + return p; +} + +void +error(char *fmt, ...) +{ + char buf[1024]; + va_list arg; + + sprint(buf, "%q: %q:%d: ", prog, proto, lineno); + va_start(arg, fmt); + vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s\n", buf); + kfscmd("disallow"); + kfscmd("sync"); + exits(0); +} + +void +warn(char *fmt, ...) +{ + char buf[1024]; + va_list arg; + + sprint(buf, "%q: %q:%d: ", prog, proto, lineno); + va_start(arg, fmt); + vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s\n", buf); +} + +void +printfile(File *f) +{ + if(f->old) + fprint(2, "%q from %q %q %q %lo\n", f->new, f->old, f->uid, f->gid, f->mode); + else + fprint(2, "%q %q %q %lo\n", f->new, f->uid, f->gid, f->mode); +} + +void +usage(void) +{ + fprint(2, "usage: %q [-aprvx] [-d root] [-n name] [-s source] [-u users] [-z n] proto ...\n", prog); + exits("usage"); +} |