xref: /csrg-svn/bin/chmod/chmod.c (revision 24503)
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*24503Ssam static char sccsid[] = "@(#)chmod.c	5.4 (Berkeley) 08/31/85";
9*24503Ssam #endif
1019840Sdist 
1116242Slayer /*
1216242Slayer  * chmod options mode files
1316242Slayer  * where
14*24503Ssam  *	mode is [ugoa][+-=][rwxXstugo] or an octal number
15*24503Ssam  *	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;
25*24503Ssam int	fflag;
26*24503Ssam int	rflag;
2716242Slayer 
28*24503Ssam main(argc, argv)
29*24503Ssam 	char *argv[];
3016242Slayer {
3116270Slayer 	register char *p, *flags;
32*24503Ssam 	register int i;
33*24503Ssam 	struct stat st;
3416242Slayer 
3516242Slayer 	if (argc < 3) {
36*24503Ssam 		fprintf(stderr,
37*24503Ssam 		    "Usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n");
3816242Slayer 		exit(-1);
3916242Slayer 	}
40*24503Ssam 	argv++, --argc;
41*24503Ssam 	while (argc > 0 && argv[0][0] == '-') {
42*24503Ssam 		for (p = &argv[0][1]; *p; p++) switch (*p) {
4316270Slayer 
44*24503Ssam 		case 'R':
4523482Smckusick 			rflag++;
46*24503Ssam 			break;
47*24503Ssam 
48*24503Ssam 		case 'f':
49*24503Ssam 			fflag++;
50*24503Ssam 			break;
51*24503Ssam 
52*24503Ssam 		default:
53*24503Ssam 			goto done;
5423482Smckusick 		}
55*24503Ssam 		argc--, argv++;
5616242Slayer 	}
57*24503Ssam done:
5816242Slayer 	modestring = argv[0];
5916242Slayer 	um = umask(0);
6016242Slayer 	(void) newmode(0);
6116242Slayer 	for (i = 1; i < argc; i++) {
6216242Slayer 		p = argv[i];
63*24503Ssam 		/* do stat for directory arguments */
6416594Sralph 		if (stat(p, &st) < 0) {
65*24503Ssam 			status += error("can't access %s", p);
6616242Slayer 			continue;
6716242Slayer 		}
68*24503Ssam 		if (rflag && st.st_mode&S_IFDIR) {
6916242Slayer 			status += chmodr(p, newmode(st.st_mode));
7016242Slayer 			continue;
7116242Slayer 		}
72*24503Ssam 		if (chmod(p, newmode(st.st_mode)) < 0) {
73*24503Ssam 			status += error("can't change %s", p);
74*24503Ssam 			continue;
75*24503Ssam 		}
7616242Slayer 	}
7716242Slayer 	exit(status);
7816242Slayer }
7916242Slayer 
8016242Slayer chmodr(dir, mode)
81*24503Ssam 	char *dir;
8216242Slayer {
83*24503Ssam 	register DIR *dirp;
84*24503Ssam 	register struct direct *dp;
85*24503Ssam 	register struct stat st;
86*24503Ssam 	char savedir[1024];
87*24503Ssam 	int ecode;
8816242Slayer 
89*24503Ssam 	if (getwd(savedir) == 0)
90*24503Ssam 		fatal(255, "%s", savedir);
9116242Slayer 	/*
92*24503Ssam 	 * Change what we are given before doing it's contents
93*24503Ssam 	 */
94*24503Ssam 	if (chmod(dir, newmode(mode)) < 0 && error("can't change %s", dir))
95*24503Ssam 		return (1);
96*24503Ssam 	if (chdir(dir) < 0)
97*24503Ssam 		return (Perror(dir));
98*24503Ssam 	if ((dirp = opendir(".")) == NULL)
99*24503Ssam 		return (Perror(dir));
10016242Slayer 	dp = readdir(dirp);
10116242Slayer 	dp = readdir(dirp); /* read "." and ".." */
102*24503Ssam 	ecode = 0;
10316242Slayer 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
104*24503Ssam 		if (lstat(dp->d_name, &st) < 0) {
105*24503Ssam 			ecode = error("can't access %s", dp->d_name);
106*24503Ssam 			if (ecode)
107*24503Ssam 				break;
108*24503Ssam 			continue;
10918473Smckusick 		}
110*24503Ssam 		if (st.st_mode&S_IFDIR) {
111*24503Ssam 			ecode = chmodr(dp->d_name, newmode(st.st_mode));
112*24503Ssam 			if (ecode)
113*24503Ssam 				break;
114*24503Ssam 			continue;
115*24503Ssam 		}
116*24503Ssam 		if (chmod(dp->d_name, newmode(st.st_mode)) < 0 &&
117*24503Ssam 		    (ecode = error("can't change %s", dp->d_name)))
118*24503Ssam 			break;
11916242Slayer 	}
12016242Slayer 	closedir(dirp);
121*24503Ssam 	if (chdir(savedir) < 0)
122*24503Ssam 		fatal(255, "can't change back to %s", savedir);
123*24503Ssam 	return (ecode);
12416242Slayer }
12516242Slayer 
126*24503Ssam error(fmt, a)
127*24503Ssam 	char *fmt, *a;
128*24503Ssam {
129*24503Ssam 
130*24503Ssam 	if (!fflag) {
131*24503Ssam 		fprintf(stderr, "chmod: ");
132*24503Ssam 		fprintf(stderr, fmt, a);
133*24503Ssam 		putc('\n', stderr);
134*24503Ssam 	}
135*24503Ssam 	return (!fflag);
136*24503Ssam }
137*24503Ssam 
138*24503Ssam fatal(status, fmt, a)
139*24503Ssam 	int status;
140*24503Ssam 	char *fmt, *a;
141*24503Ssam {
142*24503Ssam 
143*24503Ssam 	fflag = 0;
144*24503Ssam 	(void) error(fmt, a);
145*24503Ssam 	exit(status);
146*24503Ssam }
147*24503Ssam 
148*24503Ssam Perror(s)
149*24503Ssam 	char *s;
150*24503Ssam {
151*24503Ssam 
152*24503Ssam 	fprintf(stderr, "chmod: ");
153*24503Ssam 	perror(s);
154*24503Ssam 	return (1);
155*24503Ssam }
156*24503Ssam 
15716242Slayer newmode(nm)
158*24503Ssam 	unsigned nm;
15916242Slayer {
16016242Slayer 	register o, m, b;
16116242Slayer 	int savem;
16216242Slayer 
16316242Slayer 	ms = modestring;
16416242Slayer 	savem = nm;
16516242Slayer 	m = abs();
166*24503Ssam 	if (*ms == '\0')
167*24503Ssam 		return (m);
16816242Slayer 	do {
16916242Slayer 		m = who();
17016242Slayer 		while (o = what()) {
17116242Slayer 			b = where(nm);
17216242Slayer 			switch (o) {
17316242Slayer 			case '+':
17416242Slayer 				nm |= b & m;
17516242Slayer 				break;
17616242Slayer 			case '-':
17716242Slayer 				nm &= ~(b & m);
17816242Slayer 				break;
17916242Slayer 			case '=':
18016242Slayer 				nm &= ~m;
18116242Slayer 				nm |= b & m;
18216242Slayer 				break;
18316242Slayer 			}
18416242Slayer 		}
18516242Slayer 	} while (*ms++ == ',');
186*24503Ssam 	if (*--ms)
187*24503Ssam 		fatal(255, "invalid mode");
188*24503Ssam 	return (nm);
18916242Slayer }
19016242Slayer 
19116242Slayer abs()
19216242Slayer {
19316242Slayer 	register c, i;
19416242Slayer 
19516242Slayer 	i = 0;
19616242Slayer 	while ((c = *ms++) >= '0' && c <= '7')
19716242Slayer 		i = (i << 3) + (c - '0');
19816242Slayer 	ms--;
199*24503Ssam 	return (i);
20016242Slayer }
20116242Slayer 
202*24503Ssam #define	USER	05700	/* user's bits */
203*24503Ssam #define	GROUP	02070	/* group's bits */
204*24503Ssam #define	OTHER	00007	/* other's bits */
205*24503Ssam #define	ALL	01777	/* all (note absence of setuid, etc) */
206*24503Ssam 
207*24503Ssam #define	READ	00444	/* read permit */
208*24503Ssam #define	WRITE	00222	/* write permit */
209*24503Ssam #define	EXEC	00111	/* exec permit */
210*24503Ssam #define	SETID	06000	/* set[ug]id */
211*24503Ssam #define	STICKY	01000	/* sticky bit */
212*24503Ssam 
21316242Slayer who()
21416242Slayer {
21516242Slayer 	register m;
21616242Slayer 
21716242Slayer 	m = 0;
21816242Slayer 	for (;;) switch (*ms++) {
21916242Slayer 	case 'u':
22016242Slayer 		m |= USER;
22116242Slayer 		continue;
22216242Slayer 	case 'g':
22316242Slayer 		m |= GROUP;
22416242Slayer 		continue;
22516242Slayer 	case 'o':
22616242Slayer 		m |= OTHER;
22716242Slayer 		continue;
22816242Slayer 	case 'a':
22916242Slayer 		m |= ALL;
23016242Slayer 		continue;
23116242Slayer 	default:
23216242Slayer 		ms--;
23316242Slayer 		if (m == 0)
23416242Slayer 			m = ALL & ~um;
235*24503Ssam 		return (m);
23616242Slayer 	}
23716242Slayer }
23816242Slayer 
23916242Slayer what()
24016242Slayer {
24116242Slayer 
24216242Slayer 	switch (*ms) {
24316242Slayer 	case '+':
24416242Slayer 	case '-':
24516242Slayer 	case '=':
246*24503Ssam 		return (*ms++);
24716242Slayer 	}
248*24503Ssam 	return (0);
24916242Slayer }
25016242Slayer 
25116242Slayer where(om)
252*24503Ssam 	register om;
25316242Slayer {
25416242Slayer 	register m;
25516242Slayer 
25616242Slayer  	m = 0;
25716242Slayer 	switch (*ms) {
25816242Slayer 	case 'u':
25916242Slayer 		m = (om & USER) >> 6;
26016242Slayer 		goto dup;
26116242Slayer 	case 'g':
26216242Slayer 		m = (om & GROUP) >> 3;
26316242Slayer 		goto dup;
26416242Slayer 	case 'o':
26516242Slayer 		m = (om & OTHER);
26616242Slayer 	dup:
26716242Slayer 		m &= (READ|WRITE|EXEC);
26816242Slayer 		m |= (m << 3) | (m << 6);
26916242Slayer 		++ms;
270*24503Ssam 		return (m);
27116242Slayer 	}
27216242Slayer 	for (;;) switch (*ms++) {
27316242Slayer 	case 'r':
27416242Slayer 		m |= READ;
27516242Slayer 		continue;
27616242Slayer 	case 'w':
27716242Slayer 		m |= WRITE;
27816242Slayer 		continue;
27916242Slayer 	case 'x':
28016242Slayer 		m |= EXEC;
28116242Slayer 		continue;
28216594Sralph 	case 'X':
28318473Smckusick 		if ((om & S_IFDIR) || (om & EXEC))
28418473Smckusick 			m |= EXEC;
28516594Sralph 		continue;
28616242Slayer 	case 's':
28716242Slayer 		m |= SETID;
28816242Slayer 		continue;
28916242Slayer 	case 't':
29016242Slayer 		m |= STICKY;
29116242Slayer 		continue;
29216242Slayer 	default:
29316242Slayer 		ms--;
294*24503Ssam 		return (m);
29516242Slayer 	}
29616242Slayer }
297