xref: /csrg-svn/bin/chmod/chmod.c (revision 28353)
119840Sdist /*
219840Sdist  * Copyright (c) 1980 Regents of the University of California.
319840Sdist  * All rights reserved.  The Berkeley software License Agreement
419840Sdist  * specifies the terms and conditions for redistribution.
519840Sdist  */
616242Slayer 
719840Sdist #ifndef lint
8*28353Smckusick static char sccsid[] = "@(#)chmod.c	5.5 (Berkeley) 05/22/86";
924503Ssam #endif
1019840Sdist 
1116242Slayer /*
1216242Slayer  * chmod options mode files
1316242Slayer  * where
1424503Ssam  *	mode is [ugoa][+-=][rwxXstugo] or an octal number
1524503Ssam  *	options are -Rf
1616242Slayer  */
1716242Slayer #include <stdio.h>
1816242Slayer #include <sys/types.h>
1916242Slayer #include <sys/stat.h>
2016242Slayer #include <sys/dir.h>
2116242Slayer 
2216242Slayer char	*modestring, *ms;
2316242Slayer int	um;
2416242Slayer int	status;
2524503Ssam int	fflag;
2624503Ssam int	rflag;
2716242Slayer 
2824503Ssam main(argc, argv)
2924503Ssam 	char *argv[];
3016242Slayer {
3116270Slayer 	register char *p, *flags;
3224503Ssam 	register int i;
3324503Ssam 	struct stat st;
3416242Slayer 
3516242Slayer 	if (argc < 3) {
3624503Ssam 		fprintf(stderr,
3724503Ssam 		    "Usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n");
3816242Slayer 		exit(-1);
3916242Slayer 	}
4024503Ssam 	argv++, --argc;
4124503Ssam 	while (argc > 0 && argv[0][0] == '-') {
4224503Ssam 		for (p = &argv[0][1]; *p; p++) switch (*p) {
4316270Slayer 
4424503Ssam 		case 'R':
4523482Smckusick 			rflag++;
4624503Ssam 			break;
4724503Ssam 
4824503Ssam 		case 'f':
4924503Ssam 			fflag++;
5024503Ssam 			break;
5124503Ssam 
5224503Ssam 		default:
5324503Ssam 			goto done;
5423482Smckusick 		}
5524503Ssam 		argc--, argv++;
5616242Slayer 	}
5724503Ssam done:
5816242Slayer 	modestring = argv[0];
5916242Slayer 	um = umask(0);
6016242Slayer 	(void) newmode(0);
6116242Slayer 	for (i = 1; i < argc; i++) {
6216242Slayer 		p = argv[i];
6324503Ssam 		/* do stat for directory arguments */
64*28353Smckusick 		if (lstat(p, &st) < 0) {
65*28353Smckusick 			status += Perror(p);
6616242Slayer 			continue;
6716242Slayer 		}
68*28353Smckusick 		if (rflag && (st.st_mode&S_IFMT) == S_IFDIR) {
6916242Slayer 			status += chmodr(p, newmode(st.st_mode));
7016242Slayer 			continue;
7116242Slayer 		}
72*28353Smckusick 		if ((st.st_mode&S_IFMT) == S_IFLNK && stat(p, &st) < 0) {
73*28353Smckusick 			status += Perror(p);
74*28353Smckusick 			continue;
75*28353Smckusick 		}
7624503Ssam 		if (chmod(p, newmode(st.st_mode)) < 0) {
77*28353Smckusick 			status += Perror(p);
7824503Ssam 			continue;
7924503Ssam 		}
8016242Slayer 	}
8116242Slayer 	exit(status);
8216242Slayer }
8316242Slayer 
8416242Slayer chmodr(dir, mode)
8524503Ssam 	char *dir;
8616242Slayer {
8724503Ssam 	register DIR *dirp;
8824503Ssam 	register struct direct *dp;
8924503Ssam 	register struct stat st;
9024503Ssam 	char savedir[1024];
9124503Ssam 	int ecode;
9216242Slayer 
9324503Ssam 	if (getwd(savedir) == 0)
9424503Ssam 		fatal(255, "%s", savedir);
9516242Slayer 	/*
9624503Ssam 	 * Change what we are given before doing it's contents
9724503Ssam 	 */
98*28353Smckusick 	if (chmod(dir, newmode(mode)) < 0 && Perror(dir))
9924503Ssam 		return (1);
100*28353Smckusick 	if (chdir(dir) < 0) {
101*28353Smckusick 		Perror(dir);
102*28353Smckusick 		return (1);
103*28353Smckusick 	}
104*28353Smckusick 	if ((dirp = opendir(".")) == NULL) {
105*28353Smckusick 		Perror(dir);
106*28353Smckusick 		return (1);
107*28353Smckusick 	}
10816242Slayer 	dp = readdir(dirp);
10916242Slayer 	dp = readdir(dirp); /* read "." and ".." */
11024503Ssam 	ecode = 0;
11116242Slayer 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
11224503Ssam 		if (lstat(dp->d_name, &st) < 0) {
113*28353Smckusick 			ecode = Perror(dp->d_name);
11424503Ssam 			if (ecode)
11524503Ssam 				break;
11624503Ssam 			continue;
11718473Smckusick 		}
118*28353Smckusick 		if ((st.st_mode&S_IFMT) == S_IFDIR) {
11924503Ssam 			ecode = chmodr(dp->d_name, newmode(st.st_mode));
12024503Ssam 			if (ecode)
12124503Ssam 				break;
12224503Ssam 			continue;
12324503Ssam 		}
124*28353Smckusick 		if ((st.st_mode&S_IFMT) == S_IFLNK)
125*28353Smckusick 			continue;
12624503Ssam 		if (chmod(dp->d_name, newmode(st.st_mode)) < 0 &&
127*28353Smckusick 		    (ecode = Perror(dp->d_name)))
12824503Ssam 			break;
12916242Slayer 	}
13016242Slayer 	closedir(dirp);
13124503Ssam 	if (chdir(savedir) < 0)
13224503Ssam 		fatal(255, "can't change back to %s", savedir);
13324503Ssam 	return (ecode);
13416242Slayer }
13516242Slayer 
13624503Ssam error(fmt, a)
13724503Ssam 	char *fmt, *a;
13824503Ssam {
13924503Ssam 
14024503Ssam 	if (!fflag) {
14124503Ssam 		fprintf(stderr, "chmod: ");
14224503Ssam 		fprintf(stderr, fmt, a);
14324503Ssam 		putc('\n', stderr);
14424503Ssam 	}
14524503Ssam 	return (!fflag);
14624503Ssam }
14724503Ssam 
14824503Ssam fatal(status, fmt, a)
14924503Ssam 	int status;
15024503Ssam 	char *fmt, *a;
15124503Ssam {
15224503Ssam 
15324503Ssam 	fflag = 0;
15424503Ssam 	(void) error(fmt, a);
15524503Ssam 	exit(status);
15624503Ssam }
15724503Ssam 
15824503Ssam Perror(s)
15924503Ssam 	char *s;
16024503Ssam {
16124503Ssam 
162*28353Smckusick 	if (!fflag) {
163*28353Smckusick 		fprintf(stderr, "chmod: ");
164*28353Smckusick 		perror(s);
165*28353Smckusick 	}
166*28353Smckusick 	return (!fflag);
16724503Ssam }
16824503Ssam 
16916242Slayer newmode(nm)
17024503Ssam 	unsigned nm;
17116242Slayer {
17216242Slayer 	register o, m, b;
17316242Slayer 	int savem;
17416242Slayer 
17516242Slayer 	ms = modestring;
17616242Slayer 	savem = nm;
17716242Slayer 	m = abs();
17824503Ssam 	if (*ms == '\0')
17924503Ssam 		return (m);
18016242Slayer 	do {
18116242Slayer 		m = who();
18216242Slayer 		while (o = what()) {
18316242Slayer 			b = where(nm);
18416242Slayer 			switch (o) {
18516242Slayer 			case '+':
18616242Slayer 				nm |= b & m;
18716242Slayer 				break;
18816242Slayer 			case '-':
18916242Slayer 				nm &= ~(b & m);
19016242Slayer 				break;
19116242Slayer 			case '=':
19216242Slayer 				nm &= ~m;
19316242Slayer 				nm |= b & m;
19416242Slayer 				break;
19516242Slayer 			}
19616242Slayer 		}
19716242Slayer 	} while (*ms++ == ',');
19824503Ssam 	if (*--ms)
19924503Ssam 		fatal(255, "invalid mode");
20024503Ssam 	return (nm);
20116242Slayer }
20216242Slayer 
20316242Slayer abs()
20416242Slayer {
20516242Slayer 	register c, i;
20616242Slayer 
20716242Slayer 	i = 0;
20816242Slayer 	while ((c = *ms++) >= '0' && c <= '7')
20916242Slayer 		i = (i << 3) + (c - '0');
21016242Slayer 	ms--;
21124503Ssam 	return (i);
21216242Slayer }
21316242Slayer 
21424503Ssam #define	USER	05700	/* user's bits */
21524503Ssam #define	GROUP	02070	/* group's bits */
21624503Ssam #define	OTHER	00007	/* other's bits */
21724503Ssam #define	ALL	01777	/* all (note absence of setuid, etc) */
21824503Ssam 
21924503Ssam #define	READ	00444	/* read permit */
22024503Ssam #define	WRITE	00222	/* write permit */
22124503Ssam #define	EXEC	00111	/* exec permit */
22224503Ssam #define	SETID	06000	/* set[ug]id */
22324503Ssam #define	STICKY	01000	/* sticky bit */
22424503Ssam 
22516242Slayer who()
22616242Slayer {
22716242Slayer 	register m;
22816242Slayer 
22916242Slayer 	m = 0;
23016242Slayer 	for (;;) switch (*ms++) {
23116242Slayer 	case 'u':
23216242Slayer 		m |= USER;
23316242Slayer 		continue;
23416242Slayer 	case 'g':
23516242Slayer 		m |= GROUP;
23616242Slayer 		continue;
23716242Slayer 	case 'o':
23816242Slayer 		m |= OTHER;
23916242Slayer 		continue;
24016242Slayer 	case 'a':
24116242Slayer 		m |= ALL;
24216242Slayer 		continue;
24316242Slayer 	default:
24416242Slayer 		ms--;
24516242Slayer 		if (m == 0)
24616242Slayer 			m = ALL & ~um;
24724503Ssam 		return (m);
24816242Slayer 	}
24916242Slayer }
25016242Slayer 
25116242Slayer what()
25216242Slayer {
25316242Slayer 
25416242Slayer 	switch (*ms) {
25516242Slayer 	case '+':
25616242Slayer 	case '-':
25716242Slayer 	case '=':
25824503Ssam 		return (*ms++);
25916242Slayer 	}
26024503Ssam 	return (0);
26116242Slayer }
26216242Slayer 
26316242Slayer where(om)
26424503Ssam 	register om;
26516242Slayer {
26616242Slayer 	register m;
26716242Slayer 
26816242Slayer  	m = 0;
26916242Slayer 	switch (*ms) {
27016242Slayer 	case 'u':
27116242Slayer 		m = (om & USER) >> 6;
27216242Slayer 		goto dup;
27316242Slayer 	case 'g':
27416242Slayer 		m = (om & GROUP) >> 3;
27516242Slayer 		goto dup;
27616242Slayer 	case 'o':
27716242Slayer 		m = (om & OTHER);
27816242Slayer 	dup:
27916242Slayer 		m &= (READ|WRITE|EXEC);
28016242Slayer 		m |= (m << 3) | (m << 6);
28116242Slayer 		++ms;
28224503Ssam 		return (m);
28316242Slayer 	}
28416242Slayer 	for (;;) switch (*ms++) {
28516242Slayer 	case 'r':
28616242Slayer 		m |= READ;
28716242Slayer 		continue;
28816242Slayer 	case 'w':
28916242Slayer 		m |= WRITE;
29016242Slayer 		continue;
29116242Slayer 	case 'x':
29216242Slayer 		m |= EXEC;
29316242Slayer 		continue;
29416594Sralph 	case 'X':
29518473Smckusick 		if ((om & S_IFDIR) || (om & EXEC))
29618473Smckusick 			m |= EXEC;
29716594Sralph 		continue;
29816242Slayer 	case 's':
29916242Slayer 		m |= SETID;
30016242Slayer 		continue;
30116242Slayer 	case 't':
30216242Slayer 		m |= STICKY;
30316242Slayer 		continue;
30416242Slayer 	default:
30516242Slayer 		ms--;
30624503Ssam 		return (m);
30716242Slayer 	}
30816242Slayer }
309