|
|
1.1 root 1: /*
2: * Copyright (c) 1980, 1988 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1980, 1988 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif /* not lint */
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)chmod.c 5.7 (Berkeley) 4/21/88";
15: #endif /* not lint */
16:
17: /*
18: * chmod options mode files
19: * where
20: * mode is [ugoa][+-=][rwxXstugo] or an octal number
21: * options are -Rf
22: */
23: #include <stdio.h>
24: #include <sys/types.h>
25: #include <sys/stat.h>
26: #include <sys/dir.h>
27:
28: static int fflag, rflag, retval, um;
29: static char *modestring, *ms;
30:
31: main(argc, argv)
32: int argc;
33: char **argv;
34: {
35: extern char *optarg;
36: extern int optind, opterr;
37: int ch;
38:
39: /*
40: * since "-[rwx]" etc. are valid file modes, we don't let getopt(3)
41: * print error messages, and we mess around with optind as necessary.
42: */
43: opterr = 0;
44: while ((ch = getopt(argc, argv, "Rf")) != EOF)
45: switch((char)ch) {
46: case 'R':
47: rflag++;
48: break;
49: case 'f':
50: fflag++;
51: break;
52: case '?':
53: default:
54: --optind;
55: goto done;
56: }
57: done: argv += optind;
58: argc -= optind;
59:
60: if (argc < 2) {
61: fputs("usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n",
62: stderr);
63: exit(-1);
64: }
65:
66: modestring = *argv;
67: um = umask(0);
68: (void)newmode((u_short)0);
69:
70: while (*++argv)
71: change(*argv);
72: exit(retval);
73: }
74:
75: change(file)
76: char *file;
77: {
78: register DIR *dirp;
79: register struct direct *dp;
80: struct stat buf;
81:
82: if (lstat(file, &buf) || chmod(file, newmode(buf.st_mode))) {
83: err(file);
84: return;
85: }
86: if (rflag && ((buf.st_mode & S_IFMT) == S_IFDIR)) {
87: if (chdir(file) < 0 || !(dirp = opendir("."))) {
88: err(file);
89: return;
90: }
91: for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
92: if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
93: dp->d_name[1] == '.' && !dp->d_name[2]))
94: continue;
95: change(dp->d_name);
96: }
97: closedir(dirp);
98: if (chdir("..")) {
99: err("..");
100: exit(fflag ? 0 : -1);
101: }
102: }
103: }
104:
105: err(s)
106: char *s;
107: {
108: if (fflag)
109: return;
110: fputs("chmod: ", stderr);
111: perror(s);
112: retval = -1;
113: }
114:
115: newmode(nm)
116: u_short nm;
117: {
118: register int o, m, b;
119:
120: ms = modestring;
121: m = abs();
122: if (*ms == '\0')
123: return (m);
124: do {
125: m = who();
126: while (o = what()) {
127: b = where((int)nm);
128: switch (o) {
129: case '+':
130: nm |= b & m;
131: break;
132: case '-':
133: nm &= ~(b & m);
134: break;
135: case '=':
136: nm &= ~m;
137: nm |= b & m;
138: break;
139: }
140: }
141: } while (*ms++ == ',');
142: if (*--ms) {
143: fputs("chmod: invalid mode.\n", stderr);
144: exit(-1);
145: }
146: return ((int)nm);
147: }
148:
149: abs()
150: {
151: register int c, i;
152:
153: i = 0;
154: while ((c = *ms++) >= '0' && c <= '7')
155: i = (i << 3) + (c - '0');
156: ms--;
157: return (i);
158: }
159:
160: #define USER 05700 /* user's bits */
161: #define GROUP 02070 /* group's bits */
162: #define OTHER 00007 /* other's bits */
163: #define ALL 01777 /* all (note absence of setuid, etc) */
164:
165: #define READ 00444 /* read permit */
166: #define WRITE 00222 /* write permit */
167: #define EXEC 00111 /* exec permit */
168: #define SETID 06000 /* set[ug]id */
169: #define STICKY 01000 /* sticky bit */
170:
171: who()
172: {
173: register int m;
174:
175: m = 0;
176: for (;;) switch (*ms++) {
177: case 'u':
178: m |= USER;
179: continue;
180: case 'g':
181: m |= GROUP;
182: continue;
183: case 'o':
184: m |= OTHER;
185: continue;
186: case 'a':
187: m |= ALL;
188: continue;
189: default:
190: ms--;
191: if (m == 0)
192: m = ALL & ~um;
193: return (m);
194: }
195: }
196:
197: what()
198: {
199: switch (*ms) {
200: case '+':
201: case '-':
202: case '=':
203: return (*ms++);
204: }
205: return (0);
206: }
207:
208: where(om)
209: register int om;
210: {
211: register int m;
212:
213: m = 0;
214: switch (*ms) {
215: case 'u':
216: m = (om & USER) >> 6;
217: goto dup;
218: case 'g':
219: m = (om & GROUP) >> 3;
220: goto dup;
221: case 'o':
222: m = (om & OTHER);
223: dup:
224: m &= (READ|WRITE|EXEC);
225: m |= (m << 3) | (m << 6);
226: ++ms;
227: return (m);
228: }
229: for (;;) switch (*ms++) {
230: case 'r':
231: m |= READ;
232: continue;
233: case 'w':
234: m |= WRITE;
235: continue;
236: case 'x':
237: m |= EXEC;
238: continue;
239: case 'X':
240: if ((om & S_IFDIR) || (om & EXEC))
241: m |= EXEC;
242: continue;
243: case 's':
244: m |= SETID;
245: continue;
246: case 't':
247: m |= STICKY;
248: continue;
249: default:
250: ms--;
251: return (m);
252: }
253: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.