+#
+#define isdir(a) ((a.flags & 060000) == 040000)
+/*
+ * chownall [ - ] [ -nname ] [ -a ] [ -g# ] [ -u# ] directory ...
+ *
+ * Author: Bill Joy (UCB) Oct 13, 1976
+ */
+char progname[] "chownall";
+char usagestr[] "usage: %s [ - ] [ -nname ] [ -a ] [ -g# ] [ -u# ] directory ...\n";
+
+struct dbuff {
+ int ino;
+ char name[14];
+};
+struct stbuff {
+ int dev;
+ int inumber;
+ int flags;
+ char nlinks;
+ char uid;
+ char gid;
+ char size0;
+ int size1;
+ int addr[8];
+ int actime[2];
+ int modtime[2];
+};
+char *concat();
+int status;
+int terse;
+int lev;
+int all;
+int chggrp;
+int newuser;
+int newgid;
+char *newname;
+int chgusr;
+int newuid;
+int srcuid;
+int srcgid;
+
+char **xargv;
+
+main(argc,argv)
+char *argv[];
+{
+ register char *argp;
+ int *num;
+
+/*
+ if (getuid())
+ panic("NOT super-user");
+*/
+ argv++;
+ argc--;
+ while (argc && *(argp = *argv) == '-')
+ {
+ if (!*++argp)
+ terse++;
+ else
+ {
+ do
+ {
+ switch(*argp++)
+ {
+ case 'a':
+ all++;
+ break;
+ case 'g':
+ if (chggrp)
+ goto usage;
+ chggrp++;
+ num = &newgid;
+ goto getnum;
+ case 'u':
+ if (chgusr)
+ goto usage;
+ chgusr++;
+ num = &newuid;
+getnum:
+ *num = 0;
+ if (!(*argp >= '0' && *argp <= '9'))
+ panic("bad user/group number");
+ do
+ *num = *num * 10 + *argp++ - '0';
+ while (*argp >= '0' && *argp <= '9');
+ if (*num > 255)
+ panic("group/user number too large (%d > 255)", *num);
+ break;
+ case 'n':
+ if (chgusr || chggrp)
+ panic("Can't specify -n with -g or -a");
+ chgusr++;
+ chggrp++;
+ newuser = findname(argp);
+ newuid = newuser & 0377;
+ newgid = (newuser >> 8) & 0377;
+ newname = argp;
+ all++;
+ while (*argp) ++argp;
+ break;
+ default:
+ goto usage;
+ }
+ } while(*argp);
+ }
+ argc--;
+ argv++;
+ }
+ if (argc == 0)
+usage:
+ {
+ printf(usagestr, progname);
+ exit(1);
+ }
+ else
+ {
+ if (!chgusr && !chggrp)
+ panic("no changes specified");
+ else if (all && (!chgusr || !chggrp))
+ panic("all option requires both user and group to be specified");
+ while(argc)
+ {
+ xargv = argv;
+ if (all && !terse)
+ {
+ printf("last chance before scribbling uid %d and gid %d",
+ newuid, newgid);
+ if (newname) printf(" (%s)",newname);
+ printf(" all over \"%s\"\n", argv[0]);
+ cani();
+ }
+ chtree(argv[0]);
+ argv++;
+ argc--;
+ }
+ }
+ exit(0);
+}
+
+int old;
+int new;
+
+owner(xgid, xuid)
+{
+ old = ((xgid & 0377) << 8) | (xuid & 0377);
+ if (all)
+ goto spankingnew;
+ else if (chgusr)
+ if (xuid != srcuid || xgid != srcgid)
+ new = old;
+ else
+spankingnew:
+ new = (((chggrp ? newgid : srcgid) & 0377) << 8) | (newuid & 0377);
+ else if (chggrp && xgid == srcgid)
+ new = ((newgid & 0377) << 8) | (xuid & 0377);
+ else
+ new = old;
+ return(new);
+}
+
+chtree(spth)
+char *spth;
+{
+ char nspth[120];
+ struct dbuff sdbuff;
+ struct stbuff source;
+ int sunit, i;
+
+ if (stat(spth, &source) < 0)
+ panic("\"%s\": cannot stat", spth);
+ else if (!isdir(source))
+ panic("\"%s\": not a directory", spth);
+ else if ((sunit = open(spth, 0)) < 0)
+ panic("\"%s\": cannot open directory", spth);
+ else
+ {
+ if (lev == 0)
+ {
+ srcuid = source.uid;
+ srcgid = source.gid;
+ if (!srcuid && !srcgid && !chgusr)
+ {
+ printf("\"%s\" is owned by the root\n.", spth);
+ printf("I don't think I should change all group 0's to group %d's there.\n", newgid);
+ printf("Sorry.\n");
+ exit(1);
+ }
+ if (chgusr && !chggrp && source.uid == 0)
+ panic("owner of \"%s\" is uid 0 in his group !?!", spth);
+ else if (!chgusr && chggrp && source.uid != 0)
+ panic("owner of \"%s\" is not uid 0 of his group !?!", spth);
+ }
+ lev++;
+ while ((i = read(sunit, &sdbuff, 16) == 16))
+ {
+ concat(nspth, spth, sdbuff.name);
+ if (sdbuff.ino == 0)
+ continue;
+ else if (stat(nspth, &source) < 0)
+ panic("\"%s\": cannot stat", nspth);
+ else if (isdir(source))
+ if (equal(sdbuff.name, ".."))
+ continue; /* Whew ! */
+ else if (!equal(sdbuff.name, "."))
+ chtree(nspth);
+ if (owner(source.gid, source.uid) != old)
+ if (chown(nspth, new) == -1)
+ panic("can't chown \"%s\" to %o !?!", nspth, new);
+ }
+ if (i == -1)
+ panic("error reading \"%s\":", spth);
+ else if (i && i != 16)
+ panic("panic: bad directory structure: \"%s\"", spth);
+ }
+ close(sunit);
+ if (!--lev)
+ if (chgusr && !chggrp || chggrp && !chgusr)
+ if (chown(spth, owner(srcgid, srcuid)) == -1)
+ panic("can't chown \"%s\" to %o !?!", spth, new);
+}
+
+
+char *concat(a, b, c)
+char *a, *b, *c;
+{
+ register char *ra, *rb;
+ register cnt;
+
+ cnt = 14;
+ rb = c;
+ while (*rb++)
+ if (!--cnt)
+ break;
+ cnt = 14 - cnt;
+ rb = b;
+ while (*rb++)
+ cnt++;
+ if (cnt >= 100)
+ panic("path name too long: \"%s/%s\"", b, c);
+ ra = a;
+ rb = b;
+ while (*ra++ = *rb++)
+ continue;
+ *(ra-1) = '/';
+ rb = c;
+ cnt = 14;
+ while (*ra++ = *rb++)
+ if (!--cnt)
+ {
+ *ra++ = 0;
+ break;
+ }
+ return(a);
+}
+
+panic(a1, a2, a3, a4)
+{
+ printf("%s: ", progname);
+ printf(a1, a2, a3, a4);
+ putchar('\n');
+ exit(1);
+}
+
+equal(a, b)
+char *a, *b;
+{
+ register char *ra, *rb;
+
+ ra = a;
+ rb = b;
+ while (*ra == *rb++)
+ if (*ra)
+ ra++;
+ else
+ return(!*--rb);
+ return(0);
+}
+
+cani()
+{
+ register char c, ch;
+
+ printf("ok ? ");
+ ch = c = getchar();
+ while (ch != '\n' && ch)
+ ch = getchar();
+ if (c != 'y')
+ exit(1);
+}
+
+putchar(c)
+{
+ write(2, &c, 1);
+}
+
+findname(user)
+ char *user;
+{
+ int pbuf[259];
+ char *p,c,*pfile;
+ int u,v;
+ pfile = "/etc/passwd";
+ pbuf[0] = open(pfile, 0);
+ if(pbuf[0] < 0) {
+ write(2, "Cannot open /etc/passwd\n", 25);
+ exit(9);
+ }
+ goto l1;
+
+/*
+ * skip to beginning of next line
+ */
+
+skip:
+ while(c != '\n') {
+ if(c < 0)
+ goto ill;
+ c = getc(pbuf);
+ }
+
+/*
+ * compare user names
+ */
+
+l1:
+ c = getc(pbuf);
+ if(c < 0) {
+ write(2, "User name not found in password file\n", 37);
+ exit(9);
+ }
+ p = user;
+ while(c != ':') {
+ if(*p++ != c)
+ goto skip;
+ c = getc(pbuf);
+ }
+ if(*p)
+ goto skip;
+/*
+ * skip old password
+ */
+ do {
+ c = getc(pbuf);
+ if(c < 0)
+ goto ill;
+ } while(c != ':');
+
+
+/*
+ * validate uid and gid
+ */
+
+ u = 0;
+ do {
+ c = getc(pbuf);
+ if(c >= '0' && c <= '9')
+ u = u*10 + c-'0';
+ if(c < 0)
+ goto ill;
+ } while(c != ':');
+ v = 0;
+ do {
+ c = getc(pbuf);
+ if(c >= '0' && c <= '9')
+ v = v*10 + c-'0';
+ if(c < 0)
+ goto ill;
+ } while(c != ':');
+ return ((v<<8) | u);
+ill: write(2,"Password file illformed\n",24);
+ exit(9);
+}