1BSD/s6/chownall.c
#
#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);
}