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