xref: /plan9/sys/src/cmd/chmod.c (revision b7327ca21ed3e4a9e0de5a7574d158a22b9e1024)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier #define U(x) (x<<6)
53e12c5d1SDavid du Colombier #define G(x) (x<<3)
63e12c5d1SDavid du Colombier #define O(x) (x)
73e12c5d1SDavid du Colombier #define A(x) (U(x)|G(x)|O(x))
83e12c5d1SDavid du Colombier 
99a747e4fSDavid du Colombier #define DMRWE (DMREAD|DMWRITE|DMEXEC)
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier int parsemode(char *, ulong *, ulong *);
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier void
main(int argc,char * argv[])143e12c5d1SDavid du Colombier main(int argc, char *argv[])
153e12c5d1SDavid du Colombier {
163e12c5d1SDavid du Colombier 	int i;
179a747e4fSDavid du Colombier 	Dir *dir, ndir;
183e12c5d1SDavid du Colombier 	ulong mode, mask;
193e12c5d1SDavid du Colombier 	char *p;
203e12c5d1SDavid du Colombier 
217dd7cddfSDavid du Colombier 	if(argc < 3){
22*b7327ca2SDavid du Colombier 		fprint(2, "usage: chmod 0777 file ... or chmod [who]op[rwxalt] file ...\n");
233e12c5d1SDavid du Colombier 		exits("usage");
243e12c5d1SDavid du Colombier 	}
253e12c5d1SDavid du Colombier 	mode = strtol(argv[1], &p, 8);
263e12c5d1SDavid du Colombier 	if(*p == 0)
279a747e4fSDavid du Colombier 		mask = A(DMRWE);
283e12c5d1SDavid du Colombier 	else if(!parsemode(argv[1], &mask, &mode)){
293e12c5d1SDavid du Colombier 		fprint(2, "chmod: bad mode: %s\n", argv[1]);
303e12c5d1SDavid du Colombier 		exits("mode");
313e12c5d1SDavid du Colombier 	}
329a747e4fSDavid du Colombier 	nulldir(&ndir);
333e12c5d1SDavid du Colombier 	for(i=2; i<argc; i++){
349a747e4fSDavid du Colombier 		dir = dirstat(argv[i]);
359a747e4fSDavid du Colombier 		if(dir == nil){
369a747e4fSDavid du Colombier 			fprint(2, "chmod: can't stat %s: %r\n", argv[i]);
373e12c5d1SDavid du Colombier 			continue;
383e12c5d1SDavid du Colombier 		}
399a747e4fSDavid du Colombier 		ndir.mode = (dir->mode & ~mask) | (mode & mask);
409a747e4fSDavid du Colombier 		free(dir);
419a747e4fSDavid du Colombier 		if(dirwstat(argv[i], &ndir)==-1){
429a747e4fSDavid du Colombier 			fprint(2, "chmod: can't wstat %s: %r\n", argv[i]);
433e12c5d1SDavid du Colombier 			continue;
443e12c5d1SDavid du Colombier 		}
453e12c5d1SDavid du Colombier 	}
463e12c5d1SDavid du Colombier 	exits(0);
473e12c5d1SDavid du Colombier }
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier int
parsemode(char * spec,ulong * pmask,ulong * pmode)503e12c5d1SDavid du Colombier parsemode(char *spec, ulong *pmask, ulong *pmode)
513e12c5d1SDavid du Colombier {
523e12c5d1SDavid du Colombier 	ulong mode, mask;
533e12c5d1SDavid du Colombier 	int done, op;
543e12c5d1SDavid du Colombier 	char *s;
553e12c5d1SDavid du Colombier 
563e12c5d1SDavid du Colombier 	s = spec;
57e44fe4caSDavid du Colombier 	mask = DMAPPEND | DMEXCL | DMTMP;
583e12c5d1SDavid du Colombier 	for(done=0; !done; ){
593e12c5d1SDavid du Colombier 		switch(*s){
603e12c5d1SDavid du Colombier 		case 'u':
619a747e4fSDavid du Colombier 			mask |= U(DMRWE); break;
623e12c5d1SDavid du Colombier 		case 'g':
639a747e4fSDavid du Colombier 			mask |= G(DMRWE); break;
643e12c5d1SDavid du Colombier 		case 'o':
659a747e4fSDavid du Colombier 			mask |= O(DMRWE); break;
663e12c5d1SDavid du Colombier 		case 'a':
679a747e4fSDavid du Colombier 			mask |= A(DMRWE); break;
683e12c5d1SDavid du Colombier 		case 0:
693e12c5d1SDavid du Colombier 			return 0;
703e12c5d1SDavid du Colombier 		default:
713e12c5d1SDavid du Colombier 			done = 1;
723e12c5d1SDavid du Colombier 		}
733e12c5d1SDavid du Colombier 		if(!done)
743e12c5d1SDavid du Colombier 			s++;
753e12c5d1SDavid du Colombier 	}
763e12c5d1SDavid du Colombier 	if(s == spec)
779a747e4fSDavid du Colombier 		mask |= A(DMRWE);
783e12c5d1SDavid du Colombier 	op = *s++;
793e12c5d1SDavid du Colombier 	if(op != '+' && op != '-' && op != '=')
803e12c5d1SDavid du Colombier 		return 0;
813e12c5d1SDavid du Colombier 	mode = 0;
823e12c5d1SDavid du Colombier 	for(; *s ; s++){
833e12c5d1SDavid du Colombier 		switch(*s){
843e12c5d1SDavid du Colombier 		case 'r':
859a747e4fSDavid du Colombier 			mode |= A(DMREAD); break;
863e12c5d1SDavid du Colombier 		case 'w':
879a747e4fSDavid du Colombier 			mode |= A(DMWRITE); break;
883e12c5d1SDavid du Colombier 		case 'x':
899a747e4fSDavid du Colombier 			mode |= A(DMEXEC); break;
903e12c5d1SDavid du Colombier 		case 'a':
919a747e4fSDavid du Colombier 			mode |= DMAPPEND; break;
923e12c5d1SDavid du Colombier 		case 'l':
939a747e4fSDavid du Colombier 			mode |= DMEXCL; break;
94e44fe4caSDavid du Colombier 		case 't':
95e44fe4caSDavid du Colombier 			mode |= DMTMP; break;
963e12c5d1SDavid du Colombier 		default:
973e12c5d1SDavid du Colombier 			return 0;
983e12c5d1SDavid du Colombier 		}
993e12c5d1SDavid du Colombier 	}
1003e12c5d1SDavid du Colombier 	if(*s != 0)
1013e12c5d1SDavid du Colombier 		return 0;
1023e12c5d1SDavid du Colombier 	if(op == '+' || op == '-')
1033e12c5d1SDavid du Colombier 		mask &= mode;
1043e12c5d1SDavid du Colombier 	if(op == '-')
1053e12c5d1SDavid du Colombier 		mode = ~mode;
1063e12c5d1SDavid du Colombier 	*pmask = mask;
1073e12c5d1SDavid du Colombier 	*pmode = mode;
1083e12c5d1SDavid du Colombier 	return 1;
1093e12c5d1SDavid du Colombier }
110