1BSD/s6/chownall.c

Compare this file to the similar file:
Show the results in this format:

#
#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);
}