xref: /csrg-svn/bin/chmod/chmod.c (revision 16242)
1*16242Slayer static char *sccsid = "@(#)chmod.c	4.1 03/26/84";
2*16242Slayer 
3*16242Slayer /*
4*16242Slayer  * chmod options mode files
5*16242Slayer  * where
6*16242Slayer  *	mode	is [ugoa][+-=][rwxstugo] or a octal number
7*16242Slayer  *	options are -R
8*16242Slayer  */
9*16242Slayer #include <stdio.h>
10*16242Slayer #include <sys/types.h>
11*16242Slayer #include <sys/stat.h>
12*16242Slayer #include <sys/dir.h>
13*16242Slayer 
14*16242Slayer #define	USER	05700	/* user's bits */
15*16242Slayer #define	GROUP	02070	/* group's bits */
16*16242Slayer #define	OTHER	00007	/* other's bits */
17*16242Slayer #define	ALL	01777	/* all (note absence of setuid, etc) */
18*16242Slayer 
19*16242Slayer #define	READ	00444	/* read permit */
20*16242Slayer #define	WRITE	00222	/* write permit */
21*16242Slayer #define	EXEC	00111	/* exec permit */
22*16242Slayer #define	SETID	06000	/* set[ug]id */
23*16242Slayer #define	STICKY	01000	/* sticky bit */
24*16242Slayer 
25*16242Slayer char	*modestring, *ms;
26*16242Slayer int	um;
27*16242Slayer int	status;
28*16242Slayer int	rflag = 0, debug = 0;
29*16242Slayer 
30*16242Slayer main(argc,argv)
31*16242Slayer char **argv;
32*16242Slayer {
33*16242Slayer 	register i;
34*16242Slayer 	register char *p;
35*16242Slayer 	struct	stat st;
36*16242Slayer 
37*16242Slayer 	if (argc < 3) {
38*16242Slayer 		fprintf(stderr
39*16242Slayer 			,"Usage: chmod [-R] [ugoa][+-=][rwxstugo] file ...\n");
40*16242Slayer 		exit(-1);
41*16242Slayer 	}
42*16242Slayer 	argv++, --argc;
43*16242Slayer 	if (strcmp(argv[0], "-R") == 0) {
44*16242Slayer 		rflag++;
45*16242Slayer 		argv++, --argc;
46*16242Slayer 	}
47*16242Slayer 	modestring = argv[0];
48*16242Slayer 
49*16242Slayer 	um = umask(0);
50*16242Slayer 	(void) newmode(0);
51*16242Slayer 	for (i = 1; i < argc; i++) {
52*16242Slayer 		p = argv[i];
53*16242Slayer 		if (lstat(p, &st) < 0) {
54*16242Slayer 			fprintf(stderr, "chmod: can't access %s\n", p);
55*16242Slayer 			++status;
56*16242Slayer 			continue;
57*16242Slayer 		}
58*16242Slayer 		if (rflag && st.st_mode & S_IFDIR) {
59*16242Slayer 			status += chmodr(p, newmode(st.st_mode));
60*16242Slayer 		} else if (chmod(p, newmode(st.st_mode)) < 0) {
61*16242Slayer 			fprintf(stderr, "chmod: can't change %s\n", p);
62*16242Slayer 			++status;
63*16242Slayer 			continue;
64*16242Slayer 		}
65*16242Slayer 	}
66*16242Slayer 	exit(status);
67*16242Slayer }
68*16242Slayer 
69*16242Slayer chmodr(dir, mode)
70*16242Slayer 	char	*dir;
71*16242Slayer {
72*16242Slayer #define CHECK(name,sbuf)\
73*16242Slayer 	if (lstat(name, sbuf) < 0) {\
74*16242Slayer 		fprintf(stderr, "chmod: can't access %s\n", dp->d_name);\
75*16242Slayer 		return(1);\
76*16242Slayer 	}
77*16242Slayer 
78*16242Slayer 	register DIR		*dirp;
79*16242Slayer 	register struct direct	*dp;
80*16242Slayer 	register struct stat	st;
81*16242Slayer 	char			savedir[1024];
82*16242Slayer 
83*16242Slayer 	if (getwd(savedir) == 0) {
84*16242Slayer 		fprintf(stderr, "chmod: %s\n", savedir);
85*16242Slayer 		exit(255);
86*16242Slayer 	}
87*16242Slayer 
88*16242Slayer 	/*
89*16242Slayer 	** chmod what we are given before doing it's contents
90*16242Slayer 	*/
91*16242Slayer 	chmod(dir, newmode(mode));
92*16242Slayer 
93*16242Slayer 	chdir(dir);
94*16242Slayer 	if ((dirp = opendir(".")) == NULL) {
95*16242Slayer 		perror(dir);
96*16242Slayer 		return(1);
97*16242Slayer 	}
98*16242Slayer 	dp = readdir(dirp);
99*16242Slayer 	dp = readdir(dirp); /* read "." and ".." */
100*16242Slayer 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
101*16242Slayer 		CHECK(dp->d_name, &st);
102*16242Slayer 		chmod(dp->d_name, newmode(st.st_mode));
103*16242Slayer 		if (st.st_mode & S_IFDIR)
104*16242Slayer 			chmodr(dp->d_name, mode);
105*16242Slayer 	}
106*16242Slayer 	closedir(dirp);
107*16242Slayer 	chdir(savedir);
108*16242Slayer 	return(0);
109*16242Slayer }
110*16242Slayer 
111*16242Slayer newmode(nm)
112*16242Slayer unsigned nm;
113*16242Slayer {
114*16242Slayer 	register o, m, b;
115*16242Slayer 	int savem;
116*16242Slayer 
117*16242Slayer 	ms = modestring;
118*16242Slayer 	savem = nm;
119*16242Slayer 	m = abs();
120*16242Slayer 	if (!*ms) {
121*16242Slayer 		nm = m;
122*16242Slayer 		goto ret;
123*16242Slayer 	}
124*16242Slayer 	do {
125*16242Slayer 		m = who();
126*16242Slayer 		while (o = what()) {
127*16242Slayer 			b = where(nm);
128*16242Slayer 			switch (o) {
129*16242Slayer 			case '+':
130*16242Slayer 				nm |= b & m;
131*16242Slayer 				break;
132*16242Slayer 			case '-':
133*16242Slayer 				nm &= ~(b & m);
134*16242Slayer 				break;
135*16242Slayer 			case '=':
136*16242Slayer 				nm &= ~m;
137*16242Slayer 				nm |= b & m;
138*16242Slayer 				break;
139*16242Slayer 			}
140*16242Slayer 		}
141*16242Slayer 	} while (*ms++ == ',');
142*16242Slayer 	if (*--ms) {
143*16242Slayer 		fprintf(stderr, "chmod: invalid mode\n");
144*16242Slayer 		exit(255);
145*16242Slayer 	}
146*16242Slayer ret:
147*16242Slayer 	if ((savem & S_IFDIR) || (savem & S_IEXEC))
148*16242Slayer 		nm = nm | ((nm & 0444) >> 2);
149*16242Slayer 	return(nm);
150*16242Slayer }
151*16242Slayer 
152*16242Slayer abs()
153*16242Slayer {
154*16242Slayer 	register c, i;
155*16242Slayer 
156*16242Slayer 	i = 0;
157*16242Slayer 	while ((c = *ms++) >= '0' && c <= '7')
158*16242Slayer 		i = (i << 3) + (c - '0');
159*16242Slayer 	ms--;
160*16242Slayer 	return(i);
161*16242Slayer }
162*16242Slayer 
163*16242Slayer who()
164*16242Slayer {
165*16242Slayer 	register m;
166*16242Slayer 
167*16242Slayer 	m = 0;
168*16242Slayer 	for (;;) switch (*ms++) {
169*16242Slayer 	case 'u':
170*16242Slayer 		m |= USER;
171*16242Slayer 		continue;
172*16242Slayer 	case 'g':
173*16242Slayer 		m |= GROUP;
174*16242Slayer 		continue;
175*16242Slayer 	case 'o':
176*16242Slayer 		m |= OTHER;
177*16242Slayer 		continue;
178*16242Slayer 	case 'a':
179*16242Slayer 		m |= ALL;
180*16242Slayer 		continue;
181*16242Slayer 	default:
182*16242Slayer 		ms--;
183*16242Slayer 		if (m == 0)
184*16242Slayer 			m = ALL & ~um;
185*16242Slayer 		return m;
186*16242Slayer 	}
187*16242Slayer }
188*16242Slayer 
189*16242Slayer what()
190*16242Slayer {
191*16242Slayer 
192*16242Slayer 	switch (*ms) {
193*16242Slayer 	case '+':
194*16242Slayer 	case '-':
195*16242Slayer 	case '=':
196*16242Slayer 		return *ms++;
197*16242Slayer 	}
198*16242Slayer 	return(0);
199*16242Slayer }
200*16242Slayer 
201*16242Slayer where(om)
202*16242Slayer register om;
203*16242Slayer {
204*16242Slayer 	register m;
205*16242Slayer 
206*16242Slayer  	m = 0;
207*16242Slayer 	switch (*ms) {
208*16242Slayer 	case 'u':
209*16242Slayer 		m = (om & USER) >> 6;
210*16242Slayer 		goto dup;
211*16242Slayer 	case 'g':
212*16242Slayer 		m = (om & GROUP) >> 3;
213*16242Slayer 		goto dup;
214*16242Slayer 	case 'o':
215*16242Slayer 		m = (om & OTHER);
216*16242Slayer 	dup:
217*16242Slayer 		m &= (READ|WRITE|EXEC);
218*16242Slayer 		m |= (m << 3) | (m << 6);
219*16242Slayer 		++ms;
220*16242Slayer 		return m;
221*16242Slayer 	}
222*16242Slayer 	for (;;) switch (*ms++) {
223*16242Slayer 	case 'r':
224*16242Slayer 		m |= READ;
225*16242Slayer 		continue;
226*16242Slayer 	case 'w':
227*16242Slayer 		m |= WRITE;
228*16242Slayer 		continue;
229*16242Slayer 	case 'x':
230*16242Slayer 		m |= EXEC;
231*16242Slayer 		continue;
232*16242Slayer 	case 's':
233*16242Slayer 		m |= SETID;
234*16242Slayer 		continue;
235*16242Slayer 	case 't':
236*16242Slayer 		m |= STICKY;
237*16242Slayer 		continue;
238*16242Slayer 	default:
239*16242Slayer 		ms--;
240*16242Slayer 		return m;
241*16242Slayer 	}
242*16242Slayer }
243