119840Sdist /* 2*34043Sbostic * Copyright (c) 1980, 1988 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*34043Sbostic char copyright[] = 9*34043Sbostic "@(#) Copyright (c) 1980, 1988 Regents of the University of California.\n\ 10*34043Sbostic All rights reserved.\n"; 11*34043Sbostic #endif /* not lint */ 1219840Sdist 13*34043Sbostic #ifndef lint 14*34043Sbostic static char sccsid[] = "@(#)chmod.c 5.7 (Berkeley) 04/21/88"; 15*34043Sbostic #endif /* not lint */ 16*34043Sbostic 1716242Slayer /* 1816242Slayer * chmod options mode files 1916242Slayer * where 2024503Ssam * mode is [ugoa][+-=][rwxXstugo] or an octal number 2124503Ssam * options are -Rf 2216242Slayer */ 2316242Slayer #include <stdio.h> 2416242Slayer #include <sys/types.h> 2516242Slayer #include <sys/stat.h> 2616242Slayer #include <sys/dir.h> 2716242Slayer 28*34043Sbostic static int fflag, rflag, retval, um; 29*34043Sbostic static char *modestring, *ms; 3016242Slayer 3124503Ssam main(argc, argv) 32*34043Sbostic int argc; 33*34043Sbostic char **argv; 3416242Slayer { 35*34043Sbostic extern char *optarg; 36*34043Sbostic extern int optind, opterr; 37*34043Sbostic int ch; 3816242Slayer 39*34043Sbostic /* 40*34043Sbostic * since "-[rwx]" etc. are valid file modes, we don't let getopt(3) 41*34043Sbostic * print error messages, and we mess around with optind as necessary. 42*34043Sbostic */ 43*34043Sbostic opterr = 0; 44*34043Sbostic while ((ch = getopt(argc, argv, "Rf")) != EOF) 45*34043Sbostic switch((char)ch) { 4624503Ssam case 'R': 4723482Smckusick rflag++; 4824503Ssam break; 4924503Ssam case 'f': 5024503Ssam fflag++; 5124503Ssam break; 52*34043Sbostic case '?': 5324503Ssam default: 54*34043Sbostic --optind; 5524503Ssam goto done; 5623482Smckusick } 57*34043Sbostic done: argv += optind; 58*34043Sbostic argc -= optind; 59*34043Sbostic 60*34043Sbostic if (argc < 2) { 61*34043Sbostic fputs("usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n", 62*34043Sbostic stderr); 63*34043Sbostic exit(-1); 6416242Slayer } 65*34043Sbostic 66*34043Sbostic modestring = *argv; 6716242Slayer um = umask(0); 68*34043Sbostic (void)newmode((u_short)0); 69*34043Sbostic 70*34043Sbostic while (*++argv) 71*34043Sbostic change(*argv); 72*34043Sbostic exit(retval); 7316242Slayer } 7416242Slayer 75*34043Sbostic change(file) 76*34043Sbostic char *file; 7716242Slayer { 7824503Ssam register DIR *dirp; 7924503Ssam register struct direct *dp; 80*34043Sbostic struct stat buf; 8116242Slayer 82*34043Sbostic if (lstat(file, &buf) || chmod(file, newmode(buf.st_mode))) { 83*34043Sbostic err(file); 84*34043Sbostic return; 8528353Smckusick } 86*34043Sbostic if (rflag && ((buf.st_mode & S_IFMT) == S_IFDIR)) { 87*34043Sbostic if (chdir(file) < 0 || !(dirp = opendir("."))) { 88*34043Sbostic err(file); 89*34043Sbostic return; 9018473Smckusick } 91*34043Sbostic for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 92*34043Sbostic if (dp->d_name[0] == '.' && (!dp->d_name[1] || 93*34043Sbostic dp->d_name[1] == '.' && !dp->d_name[2])) 94*34043Sbostic continue; 95*34043Sbostic change(dp->d_name); 9624503Ssam } 97*34043Sbostic closedir(dirp); 98*34043Sbostic if (chdir("..")) { 99*34043Sbostic err(".."); 100*34043Sbostic exit(fflag ? 0 : -1); 101*34043Sbostic } 10216242Slayer } 10316242Slayer } 10416242Slayer 105*34043Sbostic err(s) 10624503Ssam char *s; 10724503Ssam { 108*34043Sbostic if (fflag) 109*34043Sbostic return; 110*34043Sbostic fputs("chmod: ", stderr); 111*34043Sbostic perror(s); 112*34043Sbostic retval = -1; 11324503Ssam } 11424503Ssam 11516242Slayer newmode(nm) 116*34043Sbostic u_short nm; 11716242Slayer { 118*34043Sbostic register int o, m, b; 11916242Slayer 12016242Slayer ms = modestring; 12116242Slayer m = abs(); 12224503Ssam if (*ms == '\0') 12324503Ssam return (m); 12416242Slayer do { 12516242Slayer m = who(); 12616242Slayer while (o = what()) { 127*34043Sbostic b = where((int)nm); 12816242Slayer switch (o) { 12916242Slayer case '+': 13016242Slayer nm |= b & m; 13116242Slayer break; 13216242Slayer case '-': 13316242Slayer nm &= ~(b & m); 13416242Slayer break; 13516242Slayer case '=': 13616242Slayer nm &= ~m; 13716242Slayer nm |= b & m; 13816242Slayer break; 13916242Slayer } 14016242Slayer } 14116242Slayer } while (*ms++ == ','); 142*34043Sbostic if (*--ms) { 143*34043Sbostic fputs("chmod: invalid mode.\n", stderr); 144*34043Sbostic exit(-1); 145*34043Sbostic } 146*34043Sbostic return ((int)nm); 14716242Slayer } 14816242Slayer 14916242Slayer abs() 15016242Slayer { 151*34043Sbostic register int c, i; 15216242Slayer 15316242Slayer i = 0; 15416242Slayer while ((c = *ms++) >= '0' && c <= '7') 15516242Slayer i = (i << 3) + (c - '0'); 15616242Slayer ms--; 15724503Ssam return (i); 15816242Slayer } 15916242Slayer 16024503Ssam #define USER 05700 /* user's bits */ 16124503Ssam #define GROUP 02070 /* group's bits */ 16224503Ssam #define OTHER 00007 /* other's bits */ 16324503Ssam #define ALL 01777 /* all (note absence of setuid, etc) */ 16424503Ssam 16524503Ssam #define READ 00444 /* read permit */ 16624503Ssam #define WRITE 00222 /* write permit */ 16724503Ssam #define EXEC 00111 /* exec permit */ 16824503Ssam #define SETID 06000 /* set[ug]id */ 16924503Ssam #define STICKY 01000 /* sticky bit */ 17024503Ssam 17116242Slayer who() 17216242Slayer { 173*34043Sbostic register int m; 17416242Slayer 17516242Slayer m = 0; 17616242Slayer for (;;) switch (*ms++) { 17716242Slayer case 'u': 17816242Slayer m |= USER; 17916242Slayer continue; 18016242Slayer case 'g': 18116242Slayer m |= GROUP; 18216242Slayer continue; 18316242Slayer case 'o': 18416242Slayer m |= OTHER; 18516242Slayer continue; 18616242Slayer case 'a': 18716242Slayer m |= ALL; 18816242Slayer continue; 18916242Slayer default: 19016242Slayer ms--; 19116242Slayer if (m == 0) 19216242Slayer m = ALL & ~um; 19324503Ssam return (m); 19416242Slayer } 19516242Slayer } 19616242Slayer 19716242Slayer what() 19816242Slayer { 19916242Slayer switch (*ms) { 20016242Slayer case '+': 20116242Slayer case '-': 20216242Slayer case '=': 20324503Ssam return (*ms++); 20416242Slayer } 20524503Ssam return (0); 20616242Slayer } 20716242Slayer 20816242Slayer where(om) 209*34043Sbostic register int om; 21016242Slayer { 211*34043Sbostic register int m; 21216242Slayer 21316242Slayer m = 0; 21416242Slayer switch (*ms) { 21516242Slayer case 'u': 21616242Slayer m = (om & USER) >> 6; 21716242Slayer goto dup; 21816242Slayer case 'g': 21916242Slayer m = (om & GROUP) >> 3; 22016242Slayer goto dup; 22116242Slayer case 'o': 22216242Slayer m = (om & OTHER); 22316242Slayer dup: 22416242Slayer m &= (READ|WRITE|EXEC); 22516242Slayer m |= (m << 3) | (m << 6); 22616242Slayer ++ms; 22724503Ssam return (m); 22816242Slayer } 22916242Slayer for (;;) switch (*ms++) { 23016242Slayer case 'r': 23116242Slayer m |= READ; 23216242Slayer continue; 23316242Slayer case 'w': 23416242Slayer m |= WRITE; 23516242Slayer continue; 23616242Slayer case 'x': 23716242Slayer m |= EXEC; 23816242Slayer continue; 23916594Sralph case 'X': 24018473Smckusick if ((om & S_IFDIR) || (om & EXEC)) 24118473Smckusick m |= EXEC; 24216594Sralph continue; 24316242Slayer case 's': 24416242Slayer m |= SETID; 24516242Slayer continue; 24616242Slayer case 't': 24716242Slayer m |= STICKY; 24816242Slayer continue; 24916242Slayer default: 25016242Slayer ms--; 25124503Ssam return (m); 25216242Slayer } 25316242Slayer } 254