13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 3*219b2ee8SDavid du Colombier #include <auth.h> 43e12c5d1SDavid du Colombier #include <bio.h> 53e12c5d1SDavid du Colombier 63e12c5d1SDavid du Colombier enum{ 73e12c5d1SDavid du Colombier LEN = 8*1024, 83e12c5d1SDavid du Colombier HUNKS = 128, 93e12c5d1SDavid du Colombier 103e12c5d1SDavid du Colombier /* 113e12c5d1SDavid du Colombier * types of destination file sytems 123e12c5d1SDavid du Colombier */ 133e12c5d1SDavid du Colombier Kfs = 0, 143e12c5d1SDavid du Colombier Fs, 153e12c5d1SDavid du Colombier Archive, 163e12c5d1SDavid du Colombier }; 173e12c5d1SDavid du Colombier 183e12c5d1SDavid du Colombier typedef struct File File; 193e12c5d1SDavid du Colombier 203e12c5d1SDavid du Colombier struct File{ 213e12c5d1SDavid du Colombier char *new; 223e12c5d1SDavid du Colombier char *elem; 233e12c5d1SDavid du Colombier char *old; 243e12c5d1SDavid du Colombier char uid[NAMELEN]; 253e12c5d1SDavid du Colombier char gid[NAMELEN]; 263e12c5d1SDavid du Colombier ulong mode; 273e12c5d1SDavid du Colombier }; 283e12c5d1SDavid du Colombier 293e12c5d1SDavid du Colombier void arch(Dir*); 30*219b2ee8SDavid du Colombier void copy(Dir*); 31*219b2ee8SDavid du Colombier int copyfile(File*, Dir*, int); 323e12c5d1SDavid du Colombier void* emalloc(ulong); 333e12c5d1SDavid du Colombier void error(char *, ...); 34*219b2ee8SDavid du Colombier void freefile(File*); 35*219b2ee8SDavid du Colombier File* getfile(File*); 36*219b2ee8SDavid du Colombier char* getmode(char*, ulong*); 37*219b2ee8SDavid du Colombier char* getname(char*, char*, int); 38*219b2ee8SDavid du Colombier char* getpath(char*); 39*219b2ee8SDavid du Colombier void kfscmd(char *); 40*219b2ee8SDavid du Colombier void mkdir(Dir*); 41*219b2ee8SDavid du Colombier int mkfile(File*); 42*219b2ee8SDavid du Colombier void mkfs(File*, int); 43*219b2ee8SDavid du Colombier char* mkpath(char*, char*); 44*219b2ee8SDavid du Colombier void mktree(File*, int); 45*219b2ee8SDavid du Colombier void mountkfs(char*); 46*219b2ee8SDavid du Colombier void printfile(File*); 47*219b2ee8SDavid du Colombier void setnames(File*); 48*219b2ee8SDavid du Colombier void setusers(void); 49*219b2ee8SDavid du Colombier void skipdir(void); 50*219b2ee8SDavid du Colombier char* strdup(char*); 51*219b2ee8SDavid du Colombier int uptodate(Dir*, char*); 523e12c5d1SDavid du Colombier void usage(void); 53*219b2ee8SDavid du Colombier void warn(char *, ...); 543e12c5d1SDavid du Colombier 553e12c5d1SDavid du Colombier Biobuf *b; 563e12c5d1SDavid du Colombier Biobufhdr bout; /* stdout when writing archive */ 573e12c5d1SDavid du Colombier uchar boutbuf[2*LEN]; 583e12c5d1SDavid du Colombier char newfile[LEN]; 593e12c5d1SDavid du Colombier char oldfile[LEN]; 603e12c5d1SDavid du Colombier char *proto; 613e12c5d1SDavid du Colombier char *cputype; 623e12c5d1SDavid du Colombier char *users; 633e12c5d1SDavid du Colombier char *oldroot; 643e12c5d1SDavid du Colombier char *newroot; 653e12c5d1SDavid du Colombier char *prog = "mkfs"; 663e12c5d1SDavid du Colombier int lineno; 673e12c5d1SDavid du Colombier char *buf; 683e12c5d1SDavid du Colombier char *zbuf; 693e12c5d1SDavid du Colombier int buflen = 1024-8; 703e12c5d1SDavid du Colombier int indent; 713e12c5d1SDavid du Colombier int verb; 723e12c5d1SDavid du Colombier int modes; 733e12c5d1SDavid du Colombier int ream; 74*219b2ee8SDavid du Colombier int debug; 753e12c5d1SDavid du Colombier int xflag; 763e12c5d1SDavid du Colombier int sfd; 773e12c5d1SDavid du Colombier int fskind; /* Kfs, Fs, Archive */ 783e12c5d1SDavid du Colombier char *user; 793e12c5d1SDavid du Colombier 803e12c5d1SDavid du Colombier void 813e12c5d1SDavid du Colombier main(int argc, char **argv) 823e12c5d1SDavid du Colombier { 833e12c5d1SDavid du Colombier File file; 843e12c5d1SDavid du Colombier char name[NAMELEN]; 853e12c5d1SDavid du Colombier int i, errs; 863e12c5d1SDavid du Colombier 873e12c5d1SDavid du Colombier user = getuser(); 883e12c5d1SDavid du Colombier name[0] = '\0'; 893e12c5d1SDavid du Colombier memset(&file, 0, sizeof file); 903e12c5d1SDavid du Colombier file.new = ""; 913e12c5d1SDavid du Colombier file.old = 0; 923e12c5d1SDavid du Colombier oldroot = ""; 933e12c5d1SDavid du Colombier newroot = "/n/kfs"; 943e12c5d1SDavid du Colombier users = 0; 953e12c5d1SDavid du Colombier fskind = Kfs; 963e12c5d1SDavid du Colombier ARGBEGIN{ 973e12c5d1SDavid du Colombier case 'a': 983e12c5d1SDavid du Colombier fskind = Archive; 993e12c5d1SDavid du Colombier newroot = ""; 1003e12c5d1SDavid du Colombier Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf); 1013e12c5d1SDavid du Colombier break; 1023e12c5d1SDavid du Colombier case 'd': 1033e12c5d1SDavid du Colombier fskind = Fs; 1043e12c5d1SDavid du Colombier newroot = ARGF(); 1053e12c5d1SDavid du Colombier break; 106*219b2ee8SDavid du Colombier case 'D': 107*219b2ee8SDavid du Colombier debug = 1; 108*219b2ee8SDavid du Colombier break; 1093e12c5d1SDavid du Colombier case 'n': 1103e12c5d1SDavid du Colombier strncpy(name, ARGF(), NAMELEN - 1); 1113e12c5d1SDavid du Colombier name[NAMELEN - 1] = '\0'; 1123e12c5d1SDavid du Colombier break; 1133e12c5d1SDavid du Colombier case 'p': 1143e12c5d1SDavid du Colombier modes = 1; 1153e12c5d1SDavid du Colombier break; 1163e12c5d1SDavid du Colombier case 'r': 1173e12c5d1SDavid du Colombier ream = 1; 1183e12c5d1SDavid du Colombier break; 1193e12c5d1SDavid du Colombier case 's': 1203e12c5d1SDavid du Colombier oldroot = ARGF(); 1213e12c5d1SDavid du Colombier break; 1223e12c5d1SDavid du Colombier case 'u': 1233e12c5d1SDavid du Colombier users = ARGF(); 1243e12c5d1SDavid du Colombier break; 1253e12c5d1SDavid du Colombier case 'v': 1263e12c5d1SDavid du Colombier verb = 1; 1273e12c5d1SDavid du Colombier break; 1283e12c5d1SDavid du Colombier case 'x': 1293e12c5d1SDavid du Colombier xflag = 1; 1303e12c5d1SDavid du Colombier break; 1313e12c5d1SDavid du Colombier case 'z': 1323e12c5d1SDavid du Colombier buflen = atoi(ARGF())-8; 1333e12c5d1SDavid du Colombier break; 1343e12c5d1SDavid du Colombier default: 1353e12c5d1SDavid du Colombier usage(); 1363e12c5d1SDavid du Colombier }ARGEND 1373e12c5d1SDavid du Colombier 1383e12c5d1SDavid du Colombier if(!argc) 1393e12c5d1SDavid du Colombier usage(); 1403e12c5d1SDavid du Colombier 1413e12c5d1SDavid du Colombier buf = emalloc(buflen); 1423e12c5d1SDavid du Colombier zbuf = emalloc(buflen); 1433e12c5d1SDavid du Colombier memset(zbuf, 0, buflen); 1443e12c5d1SDavid du Colombier 1453e12c5d1SDavid du Colombier mountkfs(name); 1463e12c5d1SDavid du Colombier kfscmd("allow"); 1473e12c5d1SDavid du Colombier proto = "users"; 1483e12c5d1SDavid du Colombier setusers(); 1493e12c5d1SDavid du Colombier cputype = getenv("cputype"); 1503e12c5d1SDavid du Colombier if(cputype == 0) 1513e12c5d1SDavid du Colombier cputype = "68020"; 1523e12c5d1SDavid du Colombier 1533e12c5d1SDavid du Colombier errs = 0; 1543e12c5d1SDavid du Colombier for(i = 0; i < argc; i++){ 1553e12c5d1SDavid du Colombier proto = argv[i]; 1563e12c5d1SDavid du Colombier fprint(2, "processing %s\n", proto); 1573e12c5d1SDavid du Colombier 1583e12c5d1SDavid du Colombier b = Bopen(proto, OREAD); 1593e12c5d1SDavid du Colombier if(!b){ 1603e12c5d1SDavid du Colombier fprint(2, "%s: can't open %s: skipping\n", prog, proto); 1613e12c5d1SDavid du Colombier errs++; 1623e12c5d1SDavid du Colombier continue; 1633e12c5d1SDavid du Colombier } 1643e12c5d1SDavid du Colombier 1653e12c5d1SDavid du Colombier lineno = 0; 166*219b2ee8SDavid du Colombier indent = 0; 1673e12c5d1SDavid du Colombier mkfs(&file, -1); 168*219b2ee8SDavid du Colombier Bterm(b); 1693e12c5d1SDavid du Colombier } 1703e12c5d1SDavid du Colombier fprint(2, "file system made\n"); 1713e12c5d1SDavid du Colombier kfscmd("disallow"); 1723e12c5d1SDavid du Colombier kfscmd("sync"); 1733e12c5d1SDavid du Colombier if(errs) 1743e12c5d1SDavid du Colombier exits("skipped protos"); 1753e12c5d1SDavid du Colombier if(fskind == Archive){ 1763e12c5d1SDavid du Colombier Bprint(&bout, "end of archive\n"); 177*219b2ee8SDavid du Colombier Bterm(&bout); 1783e12c5d1SDavid du Colombier } 1793e12c5d1SDavid du Colombier exits(0); 1803e12c5d1SDavid du Colombier } 1813e12c5d1SDavid du Colombier 1823e12c5d1SDavid du Colombier void 1833e12c5d1SDavid du Colombier mkfs(File *me, int level) 1843e12c5d1SDavid du Colombier { 1853e12c5d1SDavid du Colombier File *child; 1863e12c5d1SDavid du Colombier int rec; 1873e12c5d1SDavid du Colombier 1883e12c5d1SDavid du Colombier child = getfile(me); 1893e12c5d1SDavid du Colombier if(!child) 1903e12c5d1SDavid du Colombier return; 1913e12c5d1SDavid du Colombier if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){ 1923e12c5d1SDavid du Colombier rec = child->elem[0] == '+'; 1933e12c5d1SDavid du Colombier free(child->new); 1943e12c5d1SDavid du Colombier child->new = strdup(me->new); 1953e12c5d1SDavid du Colombier setnames(child); 1963e12c5d1SDavid du Colombier mktree(child, rec); 1973e12c5d1SDavid du Colombier freefile(child); 1983e12c5d1SDavid du Colombier child = getfile(me); 1993e12c5d1SDavid du Colombier } 2003e12c5d1SDavid du Colombier while(child && indent > level){ 2013e12c5d1SDavid du Colombier if(mkfile(child)) 2023e12c5d1SDavid du Colombier mkfs(child, indent); 2033e12c5d1SDavid du Colombier freefile(child); 2043e12c5d1SDavid du Colombier child = getfile(me); 2053e12c5d1SDavid du Colombier } 2063e12c5d1SDavid du Colombier if(child){ 2073e12c5d1SDavid du Colombier freefile(child); 2083e12c5d1SDavid du Colombier Bseek(b, -Blinelen(b), 1); 2093e12c5d1SDavid du Colombier lineno--; 2103e12c5d1SDavid du Colombier } 2113e12c5d1SDavid du Colombier } 2123e12c5d1SDavid du Colombier 2133e12c5d1SDavid du Colombier void 2143e12c5d1SDavid du Colombier mktree(File *me, int rec) 2153e12c5d1SDavid du Colombier { 2163e12c5d1SDavid du Colombier File child; 2173e12c5d1SDavid du Colombier Dir d[HUNKS]; 2183e12c5d1SDavid du Colombier int i, n, fd; 2193e12c5d1SDavid du Colombier 2203e12c5d1SDavid du Colombier fd = open(oldfile, OREAD); 2213e12c5d1SDavid du Colombier if(fd < 0){ 2223e12c5d1SDavid du Colombier warn("can't open %s: %r", oldfile); 2233e12c5d1SDavid du Colombier return; 2243e12c5d1SDavid du Colombier } 2253e12c5d1SDavid du Colombier 2263e12c5d1SDavid du Colombier child = *me; 2273e12c5d1SDavid du Colombier while((n = dirread(fd, d, sizeof d)) > 0){ 2283e12c5d1SDavid du Colombier n /= DIRLEN; 2293e12c5d1SDavid du Colombier for(i = 0; i < n; i++){ 2303e12c5d1SDavid du Colombier child.new = mkpath(me->new, d[i].name); 2313e12c5d1SDavid du Colombier if(me->old) 2323e12c5d1SDavid du Colombier child.old = mkpath(me->old, d[i].name); 2333e12c5d1SDavid du Colombier child.elem = d[i].name; 2343e12c5d1SDavid du Colombier setnames(&child); 2353e12c5d1SDavid du Colombier if(copyfile(&child, &d[i], 1) && rec) 2363e12c5d1SDavid du Colombier mktree(&child, rec); 2373e12c5d1SDavid du Colombier free(child.new); 2383e12c5d1SDavid du Colombier if(child.old) 2393e12c5d1SDavid du Colombier free(child.old); 2403e12c5d1SDavid du Colombier } 2413e12c5d1SDavid du Colombier } 2423e12c5d1SDavid du Colombier close(fd); 2433e12c5d1SDavid du Colombier } 2443e12c5d1SDavid du Colombier 2453e12c5d1SDavid du Colombier int 2463e12c5d1SDavid du Colombier mkfile(File *f) 2473e12c5d1SDavid du Colombier { 2483e12c5d1SDavid du Colombier Dir dir; 2493e12c5d1SDavid du Colombier 2503e12c5d1SDavid du Colombier if(dirstat(oldfile, &dir) < 0){ 2513e12c5d1SDavid du Colombier warn("can't stat file %s: %r", oldfile); 252*219b2ee8SDavid du Colombier skipdir(); 2533e12c5d1SDavid du Colombier return 0; 2543e12c5d1SDavid du Colombier } 2553e12c5d1SDavid du Colombier return copyfile(f, &dir, 0); 2563e12c5d1SDavid du Colombier } 2573e12c5d1SDavid du Colombier 2583e12c5d1SDavid du Colombier int 2593e12c5d1SDavid du Colombier copyfile(File *f, Dir *d, int permonly) 2603e12c5d1SDavid du Colombier { 2613e12c5d1SDavid du Colombier ulong mode; 2623e12c5d1SDavid du Colombier 2633e12c5d1SDavid du Colombier if(xflag){ 2643e12c5d1SDavid du Colombier Bprint(&bout, "%s\t%ld\t%d\n", f->new, d->mtime, d->length); 2653e12c5d1SDavid du Colombier return (d->mode & CHDIR) != 0; 2663e12c5d1SDavid du Colombier } 2673e12c5d1SDavid du Colombier if(verb) 2683e12c5d1SDavid du Colombier fprint(2, "%s\n", f->new); 2693e12c5d1SDavid du Colombier memmove(d->name, f->elem, NAMELEN); 2703e12c5d1SDavid du Colombier if(d->type != 'M'){ 2713e12c5d1SDavid du Colombier strncpy(d->uid, "sys", NAMELEN); 2723e12c5d1SDavid du Colombier strncpy(d->gid, "sys", NAMELEN); 2733e12c5d1SDavid du Colombier mode = (d->mode >> 6) & 7; 2743e12c5d1SDavid du Colombier d->mode |= mode | (mode << 3); 2753e12c5d1SDavid du Colombier } 2763e12c5d1SDavid du Colombier if(strcmp(f->uid, "-") != 0) 2773e12c5d1SDavid du Colombier strncpy(d->uid, f->uid, NAMELEN); 2783e12c5d1SDavid du Colombier if(strcmp(f->gid, "-") != 0) 2793e12c5d1SDavid du Colombier strncpy(d->gid, f->gid, NAMELEN); 2803e12c5d1SDavid du Colombier if(fskind == Fs){ 2813e12c5d1SDavid du Colombier strncpy(d->uid, user, NAMELEN); 2823e12c5d1SDavid du Colombier strncpy(d->gid, user, NAMELEN); 2833e12c5d1SDavid du Colombier } 2843e12c5d1SDavid du Colombier if(f->mode != ~0){ 2853e12c5d1SDavid du Colombier if(permonly) 2863e12c5d1SDavid du Colombier d->mode = (d->mode & ~0666) | (f->mode & 0666); 2873e12c5d1SDavid du Colombier else if((d->mode&CHDIR) != (f->mode&CHDIR)) 2883e12c5d1SDavid du Colombier warn("inconsistent mode for %s", f->new); 2893e12c5d1SDavid du Colombier else 2903e12c5d1SDavid du Colombier d->mode = f->mode; 2913e12c5d1SDavid du Colombier } 2923e12c5d1SDavid du Colombier if(!uptodate(d, newfile)){ 2933e12c5d1SDavid du Colombier if(d->mode & CHDIR) 2943e12c5d1SDavid du Colombier mkdir(d); 2953e12c5d1SDavid du Colombier else 2963e12c5d1SDavid du Colombier copy(d); 2973e12c5d1SDavid du Colombier }else if(modes && dirwstat(newfile, d) < 0) 2983e12c5d1SDavid du Colombier warn("can't set modes for %s: %r", f->new); 2993e12c5d1SDavid du Colombier return (d->mode & CHDIR) != 0; 3003e12c5d1SDavid du Colombier } 3013e12c5d1SDavid du Colombier 3023e12c5d1SDavid du Colombier /* 3033e12c5d1SDavid du Colombier * check if file to is up to date with 3043e12c5d1SDavid du Colombier * respect to the file represented by df 3053e12c5d1SDavid du Colombier */ 3063e12c5d1SDavid du Colombier int 3073e12c5d1SDavid du Colombier uptodate(Dir *df, char *to) 3083e12c5d1SDavid du Colombier { 3093e12c5d1SDavid du Colombier Dir dt; 3103e12c5d1SDavid du Colombier 3113e12c5d1SDavid du Colombier if(fskind == Archive || ream || dirstat(to, &dt) < 0) 3123e12c5d1SDavid du Colombier return 0; 3133e12c5d1SDavid du Colombier return dt.mtime >= df->mtime; 3143e12c5d1SDavid du Colombier } 3153e12c5d1SDavid du Colombier 3163e12c5d1SDavid du Colombier void 3173e12c5d1SDavid du Colombier copy(Dir *d) 3183e12c5d1SDavid du Colombier { 3193e12c5d1SDavid du Colombier char cptmp[LEN], *p; 3203e12c5d1SDavid du Colombier long tot; 3213e12c5d1SDavid du Colombier int f, t, n; 3223e12c5d1SDavid du Colombier 3233e12c5d1SDavid du Colombier f = open(oldfile, OREAD); 3243e12c5d1SDavid du Colombier if(f < 0){ 3253e12c5d1SDavid du Colombier warn("can't open %s: %r", oldfile); 3263e12c5d1SDavid du Colombier return; 3273e12c5d1SDavid du Colombier } 3283e12c5d1SDavid du Colombier t = -1; 3293e12c5d1SDavid du Colombier if(fskind == Archive) 3303e12c5d1SDavid du Colombier arch(d); 3313e12c5d1SDavid du Colombier else{ 3323e12c5d1SDavid du Colombier strcpy(cptmp, newfile); 3333e12c5d1SDavid du Colombier p = utfrrune(cptmp, L'/'); 3343e12c5d1SDavid du Colombier if(!p) 3353e12c5d1SDavid du Colombier error("internal temporary file error"); 3363e12c5d1SDavid du Colombier strcpy(p+1, "__mkfstmp"); 3373e12c5d1SDavid du Colombier t = create(cptmp, OWRITE, 0666); 3383e12c5d1SDavid du Colombier if(t < 0){ 3393e12c5d1SDavid du Colombier warn("can't create %s: %r", newfile); 3403e12c5d1SDavid du Colombier close(f); 3413e12c5d1SDavid du Colombier return; 3423e12c5d1SDavid du Colombier } 3433e12c5d1SDavid du Colombier } 3443e12c5d1SDavid du Colombier 3453e12c5d1SDavid du Colombier for(tot = 0;; tot += n){ 3463e12c5d1SDavid du Colombier n = read(f, buf, buflen); 3473e12c5d1SDavid du Colombier if(n < 0){ 3483e12c5d1SDavid du Colombier warn("can't read %s: %r", oldfile); 3493e12c5d1SDavid du Colombier break; 3503e12c5d1SDavid du Colombier } 3513e12c5d1SDavid du Colombier if(n == 0) 3523e12c5d1SDavid du Colombier break; 3533e12c5d1SDavid du Colombier if(fskind == Archive){ 3543e12c5d1SDavid du Colombier if(Bwrite(&bout, buf, n) != n) 3553e12c5d1SDavid du Colombier error("write error: %r"); 3563e12c5d1SDavid du Colombier }else if(memcmp(buf, zbuf, buflen) == 0){ 3573e12c5d1SDavid du Colombier if(seek(t, buflen, 1) < 0) 3583e12c5d1SDavid du Colombier error("can't write zeros to %s: %r", newfile); 3593e12c5d1SDavid du Colombier }else if(write(t, buf, n) < n) 3603e12c5d1SDavid du Colombier error("can't write %s: %r", newfile); 3613e12c5d1SDavid du Colombier } 3623e12c5d1SDavid du Colombier close(f); 3633e12c5d1SDavid du Colombier if(tot != d->length){ 3643e12c5d1SDavid du Colombier warn("wrong number bytes written to %s (was %d should be %d)\n", 3653e12c5d1SDavid du Colombier newfile, tot, d->length); 3663e12c5d1SDavid du Colombier if(fskind == Archive){ 3673e12c5d1SDavid du Colombier warn("seeking to proper position\n"); 3683e12c5d1SDavid du Colombier Bseek(&bout, d->length - tot, 1); 3693e12c5d1SDavid du Colombier } 3703e12c5d1SDavid du Colombier } 3713e12c5d1SDavid du Colombier if(fskind == Archive) 3723e12c5d1SDavid du Colombier return; 3733e12c5d1SDavid du Colombier remove(newfile); 3743e12c5d1SDavid du Colombier if(dirfwstat(t, d) < 0) 3753e12c5d1SDavid du Colombier error("can't move tmp file to %s: %r", newfile); 3763e12c5d1SDavid du Colombier close(t); 3773e12c5d1SDavid du Colombier } 3783e12c5d1SDavid du Colombier 3793e12c5d1SDavid du Colombier void 3803e12c5d1SDavid du Colombier mkdir(Dir *d) 3813e12c5d1SDavid du Colombier { 3823e12c5d1SDavid du Colombier Dir d1; 3833e12c5d1SDavid du Colombier int fd; 3843e12c5d1SDavid du Colombier 3853e12c5d1SDavid du Colombier if(fskind == Archive){ 3863e12c5d1SDavid du Colombier arch(d); 3873e12c5d1SDavid du Colombier return; 3883e12c5d1SDavid du Colombier } 3893e12c5d1SDavid du Colombier fd = create(newfile, OREAD, d->mode); 3903e12c5d1SDavid du Colombier if(fd < 0){ 3913e12c5d1SDavid du Colombier if(dirstat(newfile, &d1) < 0 || !(d1.mode & CHDIR)) 3923e12c5d1SDavid du Colombier error("can't create %s", newfile); 3933e12c5d1SDavid du Colombier if(dirwstat(newfile, d) < 0) 3943e12c5d1SDavid du Colombier warn("can't set modes for %s: %r", newfile); 3953e12c5d1SDavid du Colombier return; 3963e12c5d1SDavid du Colombier } 3973e12c5d1SDavid du Colombier if(dirfwstat(fd, d) < 0) 3983e12c5d1SDavid du Colombier warn("can't set modes for %s: %r", newfile); 3993e12c5d1SDavid du Colombier close(fd); 4003e12c5d1SDavid du Colombier } 4013e12c5d1SDavid du Colombier 4023e12c5d1SDavid du Colombier void 4033e12c5d1SDavid du Colombier arch(Dir *d) 4043e12c5d1SDavid du Colombier { 405*219b2ee8SDavid du Colombier Bprint(&bout, "%s %luo %s %s %lud %d\n", 406*219b2ee8SDavid du Colombier newfile, d->mode, d->uid, d->gid, d->mtime, d->length); 4073e12c5d1SDavid du Colombier } 4083e12c5d1SDavid du Colombier 4093e12c5d1SDavid du Colombier char * 4103e12c5d1SDavid du Colombier mkpath(char *prefix, char *elem) 4113e12c5d1SDavid du Colombier { 4123e12c5d1SDavid du Colombier char *p; 4133e12c5d1SDavid du Colombier int n; 4143e12c5d1SDavid du Colombier 4153e12c5d1SDavid du Colombier n = strlen(prefix) + strlen(elem) + 2; 4163e12c5d1SDavid du Colombier p = emalloc(n); 4173e12c5d1SDavid du Colombier sprint(p, "%s/%s", prefix, elem); 4183e12c5d1SDavid du Colombier return p; 4193e12c5d1SDavid du Colombier } 4203e12c5d1SDavid du Colombier 4213e12c5d1SDavid du Colombier char * 4223e12c5d1SDavid du Colombier strdup(char *s) 4233e12c5d1SDavid du Colombier { 4243e12c5d1SDavid du Colombier char *t; 4253e12c5d1SDavid du Colombier 4263e12c5d1SDavid du Colombier t = emalloc(strlen(s) + 1); 4273e12c5d1SDavid du Colombier return strcpy(t, s); 4283e12c5d1SDavid du Colombier } 4293e12c5d1SDavid du Colombier 4303e12c5d1SDavid du Colombier void 4313e12c5d1SDavid du Colombier setnames(File *f) 4323e12c5d1SDavid du Colombier { 4333e12c5d1SDavid du Colombier sprint(newfile, "%s%s", newroot, f->new); 4343e12c5d1SDavid du Colombier if(f->old){ 4353e12c5d1SDavid du Colombier if(f->old[0] == '/') 4363e12c5d1SDavid du Colombier sprint(oldfile, "%s%s", oldroot, f->old); 4373e12c5d1SDavid du Colombier else 4383e12c5d1SDavid du Colombier strcpy(oldfile, f->old); 4393e12c5d1SDavid du Colombier }else 4403e12c5d1SDavid du Colombier sprint(oldfile, "%s%s", oldroot, f->new); 4413e12c5d1SDavid du Colombier if(strlen(newfile) >= sizeof newfile 4423e12c5d1SDavid du Colombier || strlen(oldfile) >= sizeof oldfile) 4433e12c5d1SDavid du Colombier error("name overfile"); 4443e12c5d1SDavid du Colombier } 4453e12c5d1SDavid du Colombier 4463e12c5d1SDavid du Colombier void 4473e12c5d1SDavid du Colombier freefile(File *f) 4483e12c5d1SDavid du Colombier { 4493e12c5d1SDavid du Colombier if(f->old) 4503e12c5d1SDavid du Colombier free(f->old); 4513e12c5d1SDavid du Colombier if(f->new) 4523e12c5d1SDavid du Colombier free(f->new); 4533e12c5d1SDavid du Colombier free(f); 4543e12c5d1SDavid du Colombier } 4553e12c5d1SDavid du Colombier 456*219b2ee8SDavid du Colombier /* 457*219b2ee8SDavid du Colombier * skip all files in the proto that 458*219b2ee8SDavid du Colombier * could be in the current dir 459*219b2ee8SDavid du Colombier */ 460*219b2ee8SDavid du Colombier void 461*219b2ee8SDavid du Colombier skipdir(void) 462*219b2ee8SDavid du Colombier { 463*219b2ee8SDavid du Colombier char *p, c; 464*219b2ee8SDavid du Colombier int level; 465*219b2ee8SDavid du Colombier 466*219b2ee8SDavid du Colombier if(indent < 0) 467*219b2ee8SDavid du Colombier return; 468*219b2ee8SDavid du Colombier level = indent; 469*219b2ee8SDavid du Colombier for(;;){ 470*219b2ee8SDavid du Colombier indent = 0; 471*219b2ee8SDavid du Colombier p = Brdline(b, '\n'); 472*219b2ee8SDavid du Colombier lineno++; 473*219b2ee8SDavid du Colombier if(!p){ 474*219b2ee8SDavid du Colombier indent = -1; 475*219b2ee8SDavid du Colombier return; 476*219b2ee8SDavid du Colombier } 477*219b2ee8SDavid du Colombier while((c = *p++) != '\n') 478*219b2ee8SDavid du Colombier if(c == ' ') 479*219b2ee8SDavid du Colombier indent++; 480*219b2ee8SDavid du Colombier else if(c == '\t') 481*219b2ee8SDavid du Colombier indent += 8; 482*219b2ee8SDavid du Colombier else 483*219b2ee8SDavid du Colombier break; 484*219b2ee8SDavid du Colombier if(indent <= level){ 485*219b2ee8SDavid du Colombier Bseek(b, -Blinelen(b), 1); 486*219b2ee8SDavid du Colombier lineno--; 487*219b2ee8SDavid du Colombier return; 488*219b2ee8SDavid du Colombier } 489*219b2ee8SDavid du Colombier } 490*219b2ee8SDavid du Colombier } 491*219b2ee8SDavid du Colombier 4923e12c5d1SDavid du Colombier File* 4933e12c5d1SDavid du Colombier getfile(File *old) 4943e12c5d1SDavid du Colombier { 4953e12c5d1SDavid du Colombier File *f; 4963e12c5d1SDavid du Colombier char elem[NAMELEN]; 4973e12c5d1SDavid du Colombier char *p; 4983e12c5d1SDavid du Colombier int c; 4993e12c5d1SDavid du Colombier 500*219b2ee8SDavid du Colombier if(indent < 0) 501*219b2ee8SDavid du Colombier return 0; 5023e12c5d1SDavid du Colombier loop: 5033e12c5d1SDavid du Colombier indent = 0; 5043e12c5d1SDavid du Colombier p = Brdline(b, '\n'); 5053e12c5d1SDavid du Colombier lineno++; 5063e12c5d1SDavid du Colombier if(!p){ 5073e12c5d1SDavid du Colombier indent = -1; 5083e12c5d1SDavid du Colombier return 0; 5093e12c5d1SDavid du Colombier } 510*219b2ee8SDavid du Colombier while((c = *p++) != '\n') 5113e12c5d1SDavid du Colombier if(c == ' ') 5123e12c5d1SDavid du Colombier indent++; 5133e12c5d1SDavid du Colombier else if(c == '\t') 5143e12c5d1SDavid du Colombier indent += 8; 5153e12c5d1SDavid du Colombier else 5163e12c5d1SDavid du Colombier break; 517*219b2ee8SDavid du Colombier if(c == '\n' || c == '#') 5183e12c5d1SDavid du Colombier goto loop; 5193e12c5d1SDavid du Colombier p--; 5203e12c5d1SDavid du Colombier f = emalloc(sizeof *f); 5213e12c5d1SDavid du Colombier p = getname(p, elem, sizeof elem); 522*219b2ee8SDavid du Colombier if(debug) 523*219b2ee8SDavid du Colombier fprint(2, "getfile: %s root %s\n", elem, old->new); 5243e12c5d1SDavid du Colombier f->new = mkpath(old->new, elem); 5253e12c5d1SDavid du Colombier f->elem = utfrrune(f->new, L'/') + 1; 5263e12c5d1SDavid du Colombier p = getmode(p, &f->mode); 5273e12c5d1SDavid du Colombier p = getname(p, f->uid, sizeof f->uid); 5283e12c5d1SDavid du Colombier if(!*f->uid) 5293e12c5d1SDavid du Colombier strcpy(f->uid, "-"); 5303e12c5d1SDavid du Colombier p = getname(p, f->gid, sizeof f->gid); 5313e12c5d1SDavid du Colombier if(!*f->gid) 5323e12c5d1SDavid du Colombier strcpy(f->gid, "-"); 5333e12c5d1SDavid du Colombier f->old = getpath(p); 5343e12c5d1SDavid du Colombier if(f->old && strcmp(f->old, "-") == 0){ 5353e12c5d1SDavid du Colombier free(f->old); 5363e12c5d1SDavid du Colombier f->old = 0; 5373e12c5d1SDavid du Colombier } 5383e12c5d1SDavid du Colombier setnames(f); 539*219b2ee8SDavid du Colombier 540*219b2ee8SDavid du Colombier if(debug) 541*219b2ee8SDavid du Colombier printfile(f); 542*219b2ee8SDavid du Colombier 5433e12c5d1SDavid du Colombier return f; 5443e12c5d1SDavid du Colombier } 5453e12c5d1SDavid du Colombier 5463e12c5d1SDavid du Colombier char* 5473e12c5d1SDavid du Colombier getpath(char *p) 5483e12c5d1SDavid du Colombier { 549*219b2ee8SDavid du Colombier char *q, *new; 550*219b2ee8SDavid du Colombier int c, n; 5513e12c5d1SDavid du Colombier 5523e12c5d1SDavid du Colombier while((c = *p) == ' ' || c == '\t') 5533e12c5d1SDavid du Colombier p++; 5543e12c5d1SDavid du Colombier q = p; 555*219b2ee8SDavid du Colombier while((c = *q) != '\n' && c != ' ' && c != '\t') 5563e12c5d1SDavid du Colombier q++; 557*219b2ee8SDavid du Colombier if(q == p) 5583e12c5d1SDavid du Colombier return 0; 559*219b2ee8SDavid du Colombier n = q - p; 560*219b2ee8SDavid du Colombier new = emalloc(n + 1); 561*219b2ee8SDavid du Colombier memcpy(new, p, n); 562*219b2ee8SDavid du Colombier new[n] = 0; 563*219b2ee8SDavid du Colombier return new; 5643e12c5d1SDavid du Colombier } 5653e12c5d1SDavid du Colombier 5663e12c5d1SDavid du Colombier char* 5673e12c5d1SDavid du Colombier getname(char *p, char *buf, int len) 5683e12c5d1SDavid du Colombier { 5693e12c5d1SDavid du Colombier char *s; 5703e12c5d1SDavid du Colombier int i, c; 5713e12c5d1SDavid du Colombier 5723e12c5d1SDavid du Colombier while((c = *p) == ' ' || c == '\t') 5733e12c5d1SDavid du Colombier p++; 5743e12c5d1SDavid du Colombier i = 0; 575*219b2ee8SDavid du Colombier while((c = *p) != '\n' && c != ' ' && c != '\t'){ 5763e12c5d1SDavid du Colombier if(i < len) 5773e12c5d1SDavid du Colombier buf[i++] = c; 5783e12c5d1SDavid du Colombier p++; 5793e12c5d1SDavid du Colombier } 5803e12c5d1SDavid du Colombier if(i == len){ 5813e12c5d1SDavid du Colombier buf[len-1] = '\0'; 5823e12c5d1SDavid du Colombier warn("name %s too long; truncated", buf); 5833e12c5d1SDavid du Colombier }else 5843e12c5d1SDavid du Colombier buf[i] = '\0'; 5853e12c5d1SDavid du Colombier 5863e12c5d1SDavid du Colombier if(strcmp(buf, "$cputype") == 0) 5873e12c5d1SDavid du Colombier strcpy(buf, cputype); 5883e12c5d1SDavid du Colombier else if(buf[0] == '$'){ 5893e12c5d1SDavid du Colombier s = getenv(buf+1); 5903e12c5d1SDavid du Colombier if(s == 0) 5913e12c5d1SDavid du Colombier error("can't read environment variable %s", buf+1); 5923e12c5d1SDavid du Colombier strncpy(buf, s, NAMELEN-1); 5933e12c5d1SDavid du Colombier buf[NAMELEN-1] = '\0'; 5943e12c5d1SDavid du Colombier free(s); 5953e12c5d1SDavid du Colombier } 5963e12c5d1SDavid du Colombier return p; 5973e12c5d1SDavid du Colombier } 5983e12c5d1SDavid du Colombier 5993e12c5d1SDavid du Colombier char* 6003e12c5d1SDavid du Colombier getmode(char *p, ulong *mode) 6013e12c5d1SDavid du Colombier { 6023e12c5d1SDavid du Colombier char buf[7], *s; 6033e12c5d1SDavid du Colombier ulong m; 6043e12c5d1SDavid du Colombier 6053e12c5d1SDavid du Colombier *mode = ~0; 6063e12c5d1SDavid du Colombier p = getname(p, buf, sizeof buf); 6073e12c5d1SDavid du Colombier s = buf; 6083e12c5d1SDavid du Colombier if(!*s || strcmp(s, "-") == 0) 6093e12c5d1SDavid du Colombier return p; 6103e12c5d1SDavid du Colombier m = 0; 6113e12c5d1SDavid du Colombier if(*s == 'd'){ 6123e12c5d1SDavid du Colombier m |= CHDIR; 6133e12c5d1SDavid du Colombier s++; 6143e12c5d1SDavid du Colombier } 6153e12c5d1SDavid du Colombier if(*s == 'a'){ 6163e12c5d1SDavid du Colombier m |= CHAPPEND; 6173e12c5d1SDavid du Colombier s++; 6183e12c5d1SDavid du Colombier } 6193e12c5d1SDavid du Colombier if(*s == 'l'){ 6203e12c5d1SDavid du Colombier m |= CHEXCL; 6213e12c5d1SDavid du Colombier s++; 6223e12c5d1SDavid du Colombier } 6233e12c5d1SDavid du Colombier if(s[0] < '0' || s[0] > '7' 6243e12c5d1SDavid du Colombier || s[1] < '0' || s[1] > '7' 6253e12c5d1SDavid du Colombier || s[2] < '0' || s[2] > '7' 6263e12c5d1SDavid du Colombier || s[3]){ 6273e12c5d1SDavid du Colombier warn("bad mode specification %s", buf); 6283e12c5d1SDavid du Colombier return p; 6293e12c5d1SDavid du Colombier } 6303e12c5d1SDavid du Colombier *mode = m | strtoul(s, 0, 8); 6313e12c5d1SDavid du Colombier return p; 6323e12c5d1SDavid du Colombier } 6333e12c5d1SDavid du Colombier 6343e12c5d1SDavid du Colombier void 6353e12c5d1SDavid du Colombier setusers(void) 6363e12c5d1SDavid du Colombier { 6373e12c5d1SDavid du Colombier File file; 6383e12c5d1SDavid du Colombier int m; 6393e12c5d1SDavid du Colombier 6403e12c5d1SDavid du Colombier if(fskind != Kfs) 6413e12c5d1SDavid du Colombier return; 6423e12c5d1SDavid du Colombier m = modes; 6433e12c5d1SDavid du Colombier modes = 1; 6443e12c5d1SDavid du Colombier strcpy(file.uid, "adm"); 6453e12c5d1SDavid du Colombier strcpy(file.gid, "adm"); 6463e12c5d1SDavid du Colombier file.mode = CHDIR|0775; 6473e12c5d1SDavid du Colombier file.new = "/adm"; 6483e12c5d1SDavid du Colombier file.elem = "adm"; 6493e12c5d1SDavid du Colombier file.old = 0; 6503e12c5d1SDavid du Colombier setnames(&file); 6513e12c5d1SDavid du Colombier mkfile(&file); 6523e12c5d1SDavid du Colombier file.new = "/adm/users"; 6533e12c5d1SDavid du Colombier file.old = users; 6543e12c5d1SDavid du Colombier file.elem = "users"; 6553e12c5d1SDavid du Colombier file.mode = 0664; 6563e12c5d1SDavid du Colombier setnames(&file); 6573e12c5d1SDavid du Colombier mkfile(&file); 6583e12c5d1SDavid du Colombier kfscmd("user"); 6593e12c5d1SDavid du Colombier mkfile(&file); 6603e12c5d1SDavid du Colombier file.mode = CHDIR|0775; 6613e12c5d1SDavid du Colombier file.new = "/adm"; 6623e12c5d1SDavid du Colombier file.old = "/adm"; 6633e12c5d1SDavid du Colombier file.elem = "adm"; 6643e12c5d1SDavid du Colombier setnames(&file); 6653e12c5d1SDavid du Colombier mkfile(&file); 6663e12c5d1SDavid du Colombier modes = m; 6673e12c5d1SDavid du Colombier } 6683e12c5d1SDavid du Colombier 6693e12c5d1SDavid du Colombier void 6703e12c5d1SDavid du Colombier mountkfs(char *name) 6713e12c5d1SDavid du Colombier { 6723e12c5d1SDavid du Colombier char kname[2*NAMELEN]; 6733e12c5d1SDavid du Colombier 6743e12c5d1SDavid du Colombier if(fskind != Kfs) 6753e12c5d1SDavid du Colombier return; 6763e12c5d1SDavid du Colombier if(name[0]) 6773e12c5d1SDavid du Colombier sprint(kname, "/srv/kfs.%s", name); 6783e12c5d1SDavid du Colombier else 6793e12c5d1SDavid du Colombier strcpy(kname, "/srv/kfs"); 6803e12c5d1SDavid du Colombier sfd = open(kname, ORDWR); 6813e12c5d1SDavid du Colombier if(sfd < 0){ 6823e12c5d1SDavid du Colombier fprint(2, "can't open %s\n", kname); 6833e12c5d1SDavid du Colombier exits("open /srv/kfs"); 6843e12c5d1SDavid du Colombier } 685*219b2ee8SDavid du Colombier if(amount(sfd, "/n/kfs", MREPL|MCREATE, "") < 0){ 6863e12c5d1SDavid du Colombier fprint(2, "can't mount kfs on /n/kfs\n"); 6873e12c5d1SDavid du Colombier exits("mount kfs"); 6883e12c5d1SDavid du Colombier } 6893e12c5d1SDavid du Colombier close(sfd); 6903e12c5d1SDavid du Colombier strcat(kname, ".cmd"); 6913e12c5d1SDavid du Colombier sfd = open(kname, ORDWR); 6923e12c5d1SDavid du Colombier if(sfd < 0){ 6933e12c5d1SDavid du Colombier fprint(2, "can't open %s\n", kname); 6943e12c5d1SDavid du Colombier exits("open /srv/kfs"); 6953e12c5d1SDavid du Colombier } 6963e12c5d1SDavid du Colombier } 6973e12c5d1SDavid du Colombier 6983e12c5d1SDavid du Colombier void 6993e12c5d1SDavid du Colombier kfscmd(char *cmd) 7003e12c5d1SDavid du Colombier { 7013e12c5d1SDavid du Colombier char buf[4*1024]; 7023e12c5d1SDavid du Colombier int n; 7033e12c5d1SDavid du Colombier 7043e12c5d1SDavid du Colombier if(fskind != Kfs) 7053e12c5d1SDavid du Colombier return; 7063e12c5d1SDavid du Colombier if(write(sfd, cmd, strlen(cmd)) != strlen(cmd)){ 7073e12c5d1SDavid du Colombier fprint(2, "%s: error writing %s: %r", prog, cmd); 7083e12c5d1SDavid du Colombier return; 7093e12c5d1SDavid du Colombier } 7103e12c5d1SDavid du Colombier for(;;){ 7113e12c5d1SDavid du Colombier n = read(sfd, buf, sizeof buf - 1); 7123e12c5d1SDavid du Colombier if(n <= 0) 7133e12c5d1SDavid du Colombier return; 7143e12c5d1SDavid du Colombier buf[n] = '\0'; 7153e12c5d1SDavid du Colombier if(strcmp(buf, "done") == 0 || strcmp(buf, "success") == 0) 7163e12c5d1SDavid du Colombier return; 7173e12c5d1SDavid du Colombier if(strcmp(buf, "unknown command") == 0){ 7183e12c5d1SDavid du Colombier fprint(2, "%s: command %s not recognized\n", prog, cmd); 7193e12c5d1SDavid du Colombier return; 7203e12c5d1SDavid du Colombier } 7213e12c5d1SDavid du Colombier } 7223e12c5d1SDavid du Colombier } 7233e12c5d1SDavid du Colombier 7243e12c5d1SDavid du Colombier void * 7253e12c5d1SDavid du Colombier emalloc(ulong n) 7263e12c5d1SDavid du Colombier { 7273e12c5d1SDavid du Colombier void *p; 7283e12c5d1SDavid du Colombier 7293e12c5d1SDavid du Colombier if((p = malloc(n)) == 0) 7303e12c5d1SDavid du Colombier error("out of memory"); 7313e12c5d1SDavid du Colombier return p; 7323e12c5d1SDavid du Colombier } 7333e12c5d1SDavid du Colombier 7343e12c5d1SDavid du Colombier void 7353e12c5d1SDavid du Colombier error(char *fmt, ...) 7363e12c5d1SDavid du Colombier { 7373e12c5d1SDavid du Colombier char buf[1024]; 7383e12c5d1SDavid du Colombier 7393e12c5d1SDavid du Colombier sprint(buf, "%s: %s: %d: ", prog, proto, lineno); 7403e12c5d1SDavid du Colombier doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)); 7413e12c5d1SDavid du Colombier fprint(2, "%s\n", buf); 7423e12c5d1SDavid du Colombier kfscmd("disallow"); 7433e12c5d1SDavid du Colombier kfscmd("sync"); 7443e12c5d1SDavid du Colombier exits(0); 7453e12c5d1SDavid du Colombier } 7463e12c5d1SDavid du Colombier 7473e12c5d1SDavid du Colombier void 7483e12c5d1SDavid du Colombier warn(char *fmt, ...) 7493e12c5d1SDavid du Colombier { 7503e12c5d1SDavid du Colombier char buf[1024]; 7513e12c5d1SDavid du Colombier 7523e12c5d1SDavid du Colombier sprint(buf, "%s: %s: %d: ", prog, proto, lineno); 7533e12c5d1SDavid du Colombier doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)); 7543e12c5d1SDavid du Colombier fprint(2, "%s\n", buf); 7553e12c5d1SDavid du Colombier } 7563e12c5d1SDavid du Colombier 7573e12c5d1SDavid du Colombier void 758*219b2ee8SDavid du Colombier printfile(File *f) 759*219b2ee8SDavid du Colombier { 760*219b2ee8SDavid du Colombier if(f->old) 761*219b2ee8SDavid du Colombier fprint(2, "%s from %s %s %s %o\n", f->new, f->old, f->uid, f->gid, f->mode); 762*219b2ee8SDavid du Colombier else 763*219b2ee8SDavid du Colombier fprint(2, "%s %s %s %o\n", f->new, f->uid, f->gid, f->mode); 764*219b2ee8SDavid du Colombier } 765*219b2ee8SDavid du Colombier 766*219b2ee8SDavid du Colombier void 7673e12c5d1SDavid du Colombier usage(void) 7683e12c5d1SDavid du Colombier { 7693e12c5d1SDavid du Colombier fprint(2, "usage: %s [-aprv] [-z n] [-n kfsname] [-u userfile] [-s src-fs] proto ...\n", prog); 7703e12c5d1SDavid du Colombier exits("usage"); 7713e12c5d1SDavid du Colombier } 772