jehanne/sys/src/cmd/chmod.c

119 lines
2.3 KiB
C

/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <lib9.h>
#define U(x) (x<<6)
#define G(x) (x<<3)
#define O(x) (x)
#define A(x) (U(x)|G(x)|O(x))
#define DMRWE (DMREAD|DMWRITE|DMEXEC)
int parsemode(char *, uint32_t *, uint32_t *);
void
main(int argc, char *argv[])
{
int i;
Dir *dir, ndir;
uint32_t mode, mask;
char *p;
if(argc < 3){
fprint(2, "usage: chmod 0777 file ... or chmod [who]op[rwxalt] file ...\n");
exits("usage");
}
mode = strtol(argv[1], &p, 8);
if(*p == 0)
mask = A(DMRWE);
else if(!parsemode(argv[1], &mask, &mode)){
fprint(2, "chmod: bad mode: %s\n", argv[1]);
exits("mode");
}
nulldir(&ndir);
for(i=2; i<argc; i++){
dir = dirstat(argv[i]);
if(dir == nil){
fprint(2, "chmod: can't stat %s: %r\n", argv[i]);
continue;
}
ndir.mode = (dir->mode & ~mask) | (mode & mask);
free(dir);
if(dirwstat(argv[i], &ndir)==-1){
fprint(2, "chmod: can't wstat %s: %r\n", argv[i]);
continue;
}
}
exits(0);
}
int
parsemode(char *spec, uint32_t *pmask, uint32_t *pmode)
{
uint32_t mode, mask;
int done, op;
char *s;
s = spec;
mask = DMAPPEND | DMEXCL | DMTMP;
for(done=0; !done; ){
switch(*s){
case 'u':
mask |= U(DMRWE); break;
case 'g':
mask |= G(DMRWE); break;
case 'o':
mask |= O(DMRWE); break;
case 'a':
mask |= A(DMRWE); break;
case 0:
return 0;
default:
done = 1;
}
if(!done)
s++;
}
if(s == spec)
mask |= A(DMRWE);
op = *s++;
if(op != '+' && op != '-' && op != '=')
return 0;
mode = 0;
for(; *s ; s++){
switch(*s){
case 'r':
mode |= A(DMREAD); break;
case 'w':
mode |= A(DMWRITE); break;
case 'x':
mode |= A(DMEXEC); break;
case 'a':
mode |= DMAPPEND; break;
case 'l':
mode |= DMEXCL; break;
case 't':
mode |= DMTMP; break;
default:
return 0;
}
}
if(*s != 0)
return 0;
if(op == '+' || op == '-')
mask &= mode;
if(op == '-')
mode = ~mode;
*pmask = mask;
*pmode = mode;
return 1;
}