119840Sdist /* 219840Sdist * Copyright (c) 1980 Regents of the University of California. 319840Sdist * All rights reserved. The Berkeley software License Agreement 419840Sdist * specifies the terms and conditions for redistribution. 519840Sdist */ 616242Slayer 719840Sdist #ifndef lint 8*24503Ssam static char sccsid[] = "@(#)chmod.c 5.4 (Berkeley) 08/31/85"; 9*24503Ssam #endif 1019840Sdist 1116242Slayer /* 1216242Slayer * chmod options mode files 1316242Slayer * where 14*24503Ssam * mode is [ugoa][+-=][rwxXstugo] or an octal number 15*24503Ssam * options are -Rf 1616242Slayer */ 1716242Slayer #include <stdio.h> 1816242Slayer #include <sys/types.h> 1916242Slayer #include <sys/stat.h> 2016242Slayer #include <sys/dir.h> 2116242Slayer 2216242Slayer char *modestring, *ms; 2316242Slayer int um; 2416242Slayer int status; 25*24503Ssam int fflag; 26*24503Ssam int rflag; 2716242Slayer 28*24503Ssam main(argc, argv) 29*24503Ssam char *argv[]; 3016242Slayer { 3116270Slayer register char *p, *flags; 32*24503Ssam register int i; 33*24503Ssam struct stat st; 3416242Slayer 3516242Slayer if (argc < 3) { 36*24503Ssam fprintf(stderr, 37*24503Ssam "Usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n"); 3816242Slayer exit(-1); 3916242Slayer } 40*24503Ssam argv++, --argc; 41*24503Ssam while (argc > 0 && argv[0][0] == '-') { 42*24503Ssam for (p = &argv[0][1]; *p; p++) switch (*p) { 4316270Slayer 44*24503Ssam case 'R': 4523482Smckusick rflag++; 46*24503Ssam break; 47*24503Ssam 48*24503Ssam case 'f': 49*24503Ssam fflag++; 50*24503Ssam break; 51*24503Ssam 52*24503Ssam default: 53*24503Ssam goto done; 5423482Smckusick } 55*24503Ssam argc--, argv++; 5616242Slayer } 57*24503Ssam done: 5816242Slayer modestring = argv[0]; 5916242Slayer um = umask(0); 6016242Slayer (void) newmode(0); 6116242Slayer for (i = 1; i < argc; i++) { 6216242Slayer p = argv[i]; 63*24503Ssam /* do stat for directory arguments */ 6416594Sralph if (stat(p, &st) < 0) { 65*24503Ssam status += error("can't access %s", p); 6616242Slayer continue; 6716242Slayer } 68*24503Ssam if (rflag && st.st_mode&S_IFDIR) { 6916242Slayer status += chmodr(p, newmode(st.st_mode)); 7016242Slayer continue; 7116242Slayer } 72*24503Ssam if (chmod(p, newmode(st.st_mode)) < 0) { 73*24503Ssam status += error("can't change %s", p); 74*24503Ssam continue; 75*24503Ssam } 7616242Slayer } 7716242Slayer exit(status); 7816242Slayer } 7916242Slayer 8016242Slayer chmodr(dir, mode) 81*24503Ssam char *dir; 8216242Slayer { 83*24503Ssam register DIR *dirp; 84*24503Ssam register struct direct *dp; 85*24503Ssam register struct stat st; 86*24503Ssam char savedir[1024]; 87*24503Ssam int ecode; 8816242Slayer 89*24503Ssam if (getwd(savedir) == 0) 90*24503Ssam fatal(255, "%s", savedir); 9116242Slayer /* 92*24503Ssam * Change what we are given before doing it's contents 93*24503Ssam */ 94*24503Ssam if (chmod(dir, newmode(mode)) < 0 && error("can't change %s", dir)) 95*24503Ssam return (1); 96*24503Ssam if (chdir(dir) < 0) 97*24503Ssam return (Perror(dir)); 98*24503Ssam if ((dirp = opendir(".")) == NULL) 99*24503Ssam return (Perror(dir)); 10016242Slayer dp = readdir(dirp); 10116242Slayer dp = readdir(dirp); /* read "." and ".." */ 102*24503Ssam ecode = 0; 10316242Slayer for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { 104*24503Ssam if (lstat(dp->d_name, &st) < 0) { 105*24503Ssam ecode = error("can't access %s", dp->d_name); 106*24503Ssam if (ecode) 107*24503Ssam break; 108*24503Ssam continue; 10918473Smckusick } 110*24503Ssam if (st.st_mode&S_IFDIR) { 111*24503Ssam ecode = chmodr(dp->d_name, newmode(st.st_mode)); 112*24503Ssam if (ecode) 113*24503Ssam break; 114*24503Ssam continue; 115*24503Ssam } 116*24503Ssam if (chmod(dp->d_name, newmode(st.st_mode)) < 0 && 117*24503Ssam (ecode = error("can't change %s", dp->d_name))) 118*24503Ssam break; 11916242Slayer } 12016242Slayer closedir(dirp); 121*24503Ssam if (chdir(savedir) < 0) 122*24503Ssam fatal(255, "can't change back to %s", savedir); 123*24503Ssam return (ecode); 12416242Slayer } 12516242Slayer 126*24503Ssam error(fmt, a) 127*24503Ssam char *fmt, *a; 128*24503Ssam { 129*24503Ssam 130*24503Ssam if (!fflag) { 131*24503Ssam fprintf(stderr, "chmod: "); 132*24503Ssam fprintf(stderr, fmt, a); 133*24503Ssam putc('\n', stderr); 134*24503Ssam } 135*24503Ssam return (!fflag); 136*24503Ssam } 137*24503Ssam 138*24503Ssam fatal(status, fmt, a) 139*24503Ssam int status; 140*24503Ssam char *fmt, *a; 141*24503Ssam { 142*24503Ssam 143*24503Ssam fflag = 0; 144*24503Ssam (void) error(fmt, a); 145*24503Ssam exit(status); 146*24503Ssam } 147*24503Ssam 148*24503Ssam Perror(s) 149*24503Ssam char *s; 150*24503Ssam { 151*24503Ssam 152*24503Ssam fprintf(stderr, "chmod: "); 153*24503Ssam perror(s); 154*24503Ssam return (1); 155*24503Ssam } 156*24503Ssam 15716242Slayer newmode(nm) 158*24503Ssam unsigned nm; 15916242Slayer { 16016242Slayer register o, m, b; 16116242Slayer int savem; 16216242Slayer 16316242Slayer ms = modestring; 16416242Slayer savem = nm; 16516242Slayer m = abs(); 166*24503Ssam if (*ms == '\0') 167*24503Ssam return (m); 16816242Slayer do { 16916242Slayer m = who(); 17016242Slayer while (o = what()) { 17116242Slayer b = where(nm); 17216242Slayer switch (o) { 17316242Slayer case '+': 17416242Slayer nm |= b & m; 17516242Slayer break; 17616242Slayer case '-': 17716242Slayer nm &= ~(b & m); 17816242Slayer break; 17916242Slayer case '=': 18016242Slayer nm &= ~m; 18116242Slayer nm |= b & m; 18216242Slayer break; 18316242Slayer } 18416242Slayer } 18516242Slayer } while (*ms++ == ','); 186*24503Ssam if (*--ms) 187*24503Ssam fatal(255, "invalid mode"); 188*24503Ssam return (nm); 18916242Slayer } 19016242Slayer 19116242Slayer abs() 19216242Slayer { 19316242Slayer register c, i; 19416242Slayer 19516242Slayer i = 0; 19616242Slayer while ((c = *ms++) >= '0' && c <= '7') 19716242Slayer i = (i << 3) + (c - '0'); 19816242Slayer ms--; 199*24503Ssam return (i); 20016242Slayer } 20116242Slayer 202*24503Ssam #define USER 05700 /* user's bits */ 203*24503Ssam #define GROUP 02070 /* group's bits */ 204*24503Ssam #define OTHER 00007 /* other's bits */ 205*24503Ssam #define ALL 01777 /* all (note absence of setuid, etc) */ 206*24503Ssam 207*24503Ssam #define READ 00444 /* read permit */ 208*24503Ssam #define WRITE 00222 /* write permit */ 209*24503Ssam #define EXEC 00111 /* exec permit */ 210*24503Ssam #define SETID 06000 /* set[ug]id */ 211*24503Ssam #define STICKY 01000 /* sticky bit */ 212*24503Ssam 21316242Slayer who() 21416242Slayer { 21516242Slayer register m; 21616242Slayer 21716242Slayer m = 0; 21816242Slayer for (;;) switch (*ms++) { 21916242Slayer case 'u': 22016242Slayer m |= USER; 22116242Slayer continue; 22216242Slayer case 'g': 22316242Slayer m |= GROUP; 22416242Slayer continue; 22516242Slayer case 'o': 22616242Slayer m |= OTHER; 22716242Slayer continue; 22816242Slayer case 'a': 22916242Slayer m |= ALL; 23016242Slayer continue; 23116242Slayer default: 23216242Slayer ms--; 23316242Slayer if (m == 0) 23416242Slayer m = ALL & ~um; 235*24503Ssam return (m); 23616242Slayer } 23716242Slayer } 23816242Slayer 23916242Slayer what() 24016242Slayer { 24116242Slayer 24216242Slayer switch (*ms) { 24316242Slayer case '+': 24416242Slayer case '-': 24516242Slayer case '=': 246*24503Ssam return (*ms++); 24716242Slayer } 248*24503Ssam return (0); 24916242Slayer } 25016242Slayer 25116242Slayer where(om) 252*24503Ssam register om; 25316242Slayer { 25416242Slayer register m; 25516242Slayer 25616242Slayer m = 0; 25716242Slayer switch (*ms) { 25816242Slayer case 'u': 25916242Slayer m = (om & USER) >> 6; 26016242Slayer goto dup; 26116242Slayer case 'g': 26216242Slayer m = (om & GROUP) >> 3; 26316242Slayer goto dup; 26416242Slayer case 'o': 26516242Slayer m = (om & OTHER); 26616242Slayer dup: 26716242Slayer m &= (READ|WRITE|EXEC); 26816242Slayer m |= (m << 3) | (m << 6); 26916242Slayer ++ms; 270*24503Ssam return (m); 27116242Slayer } 27216242Slayer for (;;) switch (*ms++) { 27316242Slayer case 'r': 27416242Slayer m |= READ; 27516242Slayer continue; 27616242Slayer case 'w': 27716242Slayer m |= WRITE; 27816242Slayer continue; 27916242Slayer case 'x': 28016242Slayer m |= EXEC; 28116242Slayer continue; 28216594Sralph case 'X': 28318473Smckusick if ((om & S_IFDIR) || (om & EXEC)) 28418473Smckusick m |= EXEC; 28516594Sralph continue; 28616242Slayer case 's': 28716242Slayer m |= SETID; 28816242Slayer continue; 28916242Slayer case 't': 29016242Slayer m |= STICKY; 29116242Slayer continue; 29216242Slayer default: 29316242Slayer ms--; 294*24503Ssam return (m); 29516242Slayer } 29616242Slayer } 297