xref: /plan9/sys/src/cmd/chmod.c (revision b7327ca21ed3e4a9e0de5a7574d158a22b9e1024)
1 #include <u.h>
2 #include <libc.h>
3 
4 #define U(x) (x<<6)
5 #define G(x) (x<<3)
6 #define O(x) (x)
7 #define A(x) (U(x)|G(x)|O(x))
8 
9 #define DMRWE (DMREAD|DMWRITE|DMEXEC)
10 
11 int parsemode(char *, ulong *, ulong *);
12 
13 void
main(int argc,char * argv[])14 main(int argc, char *argv[])
15 {
16 	int i;
17 	Dir *dir, ndir;
18 	ulong mode, mask;
19 	char *p;
20 
21 	if(argc < 3){
22 		fprint(2, "usage: chmod 0777 file ... or chmod [who]op[rwxalt] file ...\n");
23 		exits("usage");
24 	}
25 	mode = strtol(argv[1], &p, 8);
26 	if(*p == 0)
27 		mask = A(DMRWE);
28 	else if(!parsemode(argv[1], &mask, &mode)){
29 		fprint(2, "chmod: bad mode: %s\n", argv[1]);
30 		exits("mode");
31 	}
32 	nulldir(&ndir);
33 	for(i=2; i<argc; i++){
34 		dir = dirstat(argv[i]);
35 		if(dir == nil){
36 			fprint(2, "chmod: can't stat %s: %r\n", argv[i]);
37 			continue;
38 		}
39 		ndir.mode = (dir->mode & ~mask) | (mode & mask);
40 		free(dir);
41 		if(dirwstat(argv[i], &ndir)==-1){
42 			fprint(2, "chmod: can't wstat %s: %r\n", argv[i]);
43 			continue;
44 		}
45 	}
46 	exits(0);
47 }
48 
49 int
parsemode(char * spec,ulong * pmask,ulong * pmode)50 parsemode(char *spec, ulong *pmask, ulong *pmode)
51 {
52 	ulong mode, mask;
53 	int done, op;
54 	char *s;
55 
56 	s = spec;
57 	mask = DMAPPEND | DMEXCL | DMTMP;
58 	for(done=0; !done; ){
59 		switch(*s){
60 		case 'u':
61 			mask |= U(DMRWE); break;
62 		case 'g':
63 			mask |= G(DMRWE); break;
64 		case 'o':
65 			mask |= O(DMRWE); break;
66 		case 'a':
67 			mask |= A(DMRWE); break;
68 		case 0:
69 			return 0;
70 		default:
71 			done = 1;
72 		}
73 		if(!done)
74 			s++;
75 	}
76 	if(s == spec)
77 		mask |= A(DMRWE);
78 	op = *s++;
79 	if(op != '+' && op != '-' && op != '=')
80 		return 0;
81 	mode = 0;
82 	for(; *s ; s++){
83 		switch(*s){
84 		case 'r':
85 			mode |= A(DMREAD); break;
86 		case 'w':
87 			mode |= A(DMWRITE); break;
88 		case 'x':
89 			mode |= A(DMEXEC); break;
90 		case 'a':
91 			mode |= DMAPPEND; break;
92 		case 'l':
93 			mode |= DMEXCL; break;
94 		case 't':
95 			mode |= DMTMP; break;
96 		default:
97 			return 0;
98 		}
99 	}
100 	if(*s != 0)
101 		return 0;
102 	if(op == '+' || op == '-')
103 		mask &= mode;
104 	if(op == '-')
105 		mode = ~mode;
106 	*pmask = mask;
107 	*pmode = mode;
108 	return 1;
109 }
110