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*28353Smckusick static char sccsid[] = "@(#)chmod.c 5.5 (Berkeley) 05/22/86"; 924503Ssam #endif 1019840Sdist 1116242Slayer /* 1216242Slayer * chmod options mode files 1316242Slayer * where 1424503Ssam * mode is [ugoa][+-=][rwxXstugo] or an octal number 1524503Ssam * 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; 2524503Ssam int fflag; 2624503Ssam int rflag; 2716242Slayer 2824503Ssam main(argc, argv) 2924503Ssam char *argv[]; 3016242Slayer { 3116270Slayer register char *p, *flags; 3224503Ssam register int i; 3324503Ssam struct stat st; 3416242Slayer 3516242Slayer if (argc < 3) { 3624503Ssam fprintf(stderr, 3724503Ssam "Usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n"); 3816242Slayer exit(-1); 3916242Slayer } 4024503Ssam argv++, --argc; 4124503Ssam while (argc > 0 && argv[0][0] == '-') { 4224503Ssam for (p = &argv[0][1]; *p; p++) switch (*p) { 4316270Slayer 4424503Ssam case 'R': 4523482Smckusick rflag++; 4624503Ssam break; 4724503Ssam 4824503Ssam case 'f': 4924503Ssam fflag++; 5024503Ssam break; 5124503Ssam 5224503Ssam default: 5324503Ssam goto done; 5423482Smckusick } 5524503Ssam argc--, argv++; 5616242Slayer } 5724503Ssam done: 5816242Slayer modestring = argv[0]; 5916242Slayer um = umask(0); 6016242Slayer (void) newmode(0); 6116242Slayer for (i = 1; i < argc; i++) { 6216242Slayer p = argv[i]; 6324503Ssam /* do stat for directory arguments */ 64*28353Smckusick if (lstat(p, &st) < 0) { 65*28353Smckusick status += Perror(p); 6616242Slayer continue; 6716242Slayer } 68*28353Smckusick if (rflag && (st.st_mode&S_IFMT) == S_IFDIR) { 6916242Slayer status += chmodr(p, newmode(st.st_mode)); 7016242Slayer continue; 7116242Slayer } 72*28353Smckusick if ((st.st_mode&S_IFMT) == S_IFLNK && stat(p, &st) < 0) { 73*28353Smckusick status += Perror(p); 74*28353Smckusick continue; 75*28353Smckusick } 7624503Ssam if (chmod(p, newmode(st.st_mode)) < 0) { 77*28353Smckusick status += Perror(p); 7824503Ssam continue; 7924503Ssam } 8016242Slayer } 8116242Slayer exit(status); 8216242Slayer } 8316242Slayer 8416242Slayer chmodr(dir, mode) 8524503Ssam char *dir; 8616242Slayer { 8724503Ssam register DIR *dirp; 8824503Ssam register struct direct *dp; 8924503Ssam register struct stat st; 9024503Ssam char savedir[1024]; 9124503Ssam int ecode; 9216242Slayer 9324503Ssam if (getwd(savedir) == 0) 9424503Ssam fatal(255, "%s", savedir); 9516242Slayer /* 9624503Ssam * Change what we are given before doing it's contents 9724503Ssam */ 98*28353Smckusick if (chmod(dir, newmode(mode)) < 0 && Perror(dir)) 9924503Ssam return (1); 100*28353Smckusick if (chdir(dir) < 0) { 101*28353Smckusick Perror(dir); 102*28353Smckusick return (1); 103*28353Smckusick } 104*28353Smckusick if ((dirp = opendir(".")) == NULL) { 105*28353Smckusick Perror(dir); 106*28353Smckusick return (1); 107*28353Smckusick } 10816242Slayer dp = readdir(dirp); 10916242Slayer dp = readdir(dirp); /* read "." and ".." */ 11024503Ssam ecode = 0; 11116242Slayer for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { 11224503Ssam if (lstat(dp->d_name, &st) < 0) { 113*28353Smckusick ecode = Perror(dp->d_name); 11424503Ssam if (ecode) 11524503Ssam break; 11624503Ssam continue; 11718473Smckusick } 118*28353Smckusick if ((st.st_mode&S_IFMT) == S_IFDIR) { 11924503Ssam ecode = chmodr(dp->d_name, newmode(st.st_mode)); 12024503Ssam if (ecode) 12124503Ssam break; 12224503Ssam continue; 12324503Ssam } 124*28353Smckusick if ((st.st_mode&S_IFMT) == S_IFLNK) 125*28353Smckusick continue; 12624503Ssam if (chmod(dp->d_name, newmode(st.st_mode)) < 0 && 127*28353Smckusick (ecode = Perror(dp->d_name))) 12824503Ssam break; 12916242Slayer } 13016242Slayer closedir(dirp); 13124503Ssam if (chdir(savedir) < 0) 13224503Ssam fatal(255, "can't change back to %s", savedir); 13324503Ssam return (ecode); 13416242Slayer } 13516242Slayer 13624503Ssam error(fmt, a) 13724503Ssam char *fmt, *a; 13824503Ssam { 13924503Ssam 14024503Ssam if (!fflag) { 14124503Ssam fprintf(stderr, "chmod: "); 14224503Ssam fprintf(stderr, fmt, a); 14324503Ssam putc('\n', stderr); 14424503Ssam } 14524503Ssam return (!fflag); 14624503Ssam } 14724503Ssam 14824503Ssam fatal(status, fmt, a) 14924503Ssam int status; 15024503Ssam char *fmt, *a; 15124503Ssam { 15224503Ssam 15324503Ssam fflag = 0; 15424503Ssam (void) error(fmt, a); 15524503Ssam exit(status); 15624503Ssam } 15724503Ssam 15824503Ssam Perror(s) 15924503Ssam char *s; 16024503Ssam { 16124503Ssam 162*28353Smckusick if (!fflag) { 163*28353Smckusick fprintf(stderr, "chmod: "); 164*28353Smckusick perror(s); 165*28353Smckusick } 166*28353Smckusick return (!fflag); 16724503Ssam } 16824503Ssam 16916242Slayer newmode(nm) 17024503Ssam unsigned nm; 17116242Slayer { 17216242Slayer register o, m, b; 17316242Slayer int savem; 17416242Slayer 17516242Slayer ms = modestring; 17616242Slayer savem = nm; 17716242Slayer m = abs(); 17824503Ssam if (*ms == '\0') 17924503Ssam return (m); 18016242Slayer do { 18116242Slayer m = who(); 18216242Slayer while (o = what()) { 18316242Slayer b = where(nm); 18416242Slayer switch (o) { 18516242Slayer case '+': 18616242Slayer nm |= b & m; 18716242Slayer break; 18816242Slayer case '-': 18916242Slayer nm &= ~(b & m); 19016242Slayer break; 19116242Slayer case '=': 19216242Slayer nm &= ~m; 19316242Slayer nm |= b & m; 19416242Slayer break; 19516242Slayer } 19616242Slayer } 19716242Slayer } while (*ms++ == ','); 19824503Ssam if (*--ms) 19924503Ssam fatal(255, "invalid mode"); 20024503Ssam return (nm); 20116242Slayer } 20216242Slayer 20316242Slayer abs() 20416242Slayer { 20516242Slayer register c, i; 20616242Slayer 20716242Slayer i = 0; 20816242Slayer while ((c = *ms++) >= '0' && c <= '7') 20916242Slayer i = (i << 3) + (c - '0'); 21016242Slayer ms--; 21124503Ssam return (i); 21216242Slayer } 21316242Slayer 21424503Ssam #define USER 05700 /* user's bits */ 21524503Ssam #define GROUP 02070 /* group's bits */ 21624503Ssam #define OTHER 00007 /* other's bits */ 21724503Ssam #define ALL 01777 /* all (note absence of setuid, etc) */ 21824503Ssam 21924503Ssam #define READ 00444 /* read permit */ 22024503Ssam #define WRITE 00222 /* write permit */ 22124503Ssam #define EXEC 00111 /* exec permit */ 22224503Ssam #define SETID 06000 /* set[ug]id */ 22324503Ssam #define STICKY 01000 /* sticky bit */ 22424503Ssam 22516242Slayer who() 22616242Slayer { 22716242Slayer register m; 22816242Slayer 22916242Slayer m = 0; 23016242Slayer for (;;) switch (*ms++) { 23116242Slayer case 'u': 23216242Slayer m |= USER; 23316242Slayer continue; 23416242Slayer case 'g': 23516242Slayer m |= GROUP; 23616242Slayer continue; 23716242Slayer case 'o': 23816242Slayer m |= OTHER; 23916242Slayer continue; 24016242Slayer case 'a': 24116242Slayer m |= ALL; 24216242Slayer continue; 24316242Slayer default: 24416242Slayer ms--; 24516242Slayer if (m == 0) 24616242Slayer m = ALL & ~um; 24724503Ssam return (m); 24816242Slayer } 24916242Slayer } 25016242Slayer 25116242Slayer what() 25216242Slayer { 25316242Slayer 25416242Slayer switch (*ms) { 25516242Slayer case '+': 25616242Slayer case '-': 25716242Slayer case '=': 25824503Ssam return (*ms++); 25916242Slayer } 26024503Ssam return (0); 26116242Slayer } 26216242Slayer 26316242Slayer where(om) 26424503Ssam register om; 26516242Slayer { 26616242Slayer register m; 26716242Slayer 26816242Slayer m = 0; 26916242Slayer switch (*ms) { 27016242Slayer case 'u': 27116242Slayer m = (om & USER) >> 6; 27216242Slayer goto dup; 27316242Slayer case 'g': 27416242Slayer m = (om & GROUP) >> 3; 27516242Slayer goto dup; 27616242Slayer case 'o': 27716242Slayer m = (om & OTHER); 27816242Slayer dup: 27916242Slayer m &= (READ|WRITE|EXEC); 28016242Slayer m |= (m << 3) | (m << 6); 28116242Slayer ++ms; 28224503Ssam return (m); 28316242Slayer } 28416242Slayer for (;;) switch (*ms++) { 28516242Slayer case 'r': 28616242Slayer m |= READ; 28716242Slayer continue; 28816242Slayer case 'w': 28916242Slayer m |= WRITE; 29016242Slayer continue; 29116242Slayer case 'x': 29216242Slayer m |= EXEC; 29316242Slayer continue; 29416594Sralph case 'X': 29518473Smckusick if ((om & S_IFDIR) || (om & EXEC)) 29618473Smckusick m |= EXEC; 29716594Sralph continue; 29816242Slayer case 's': 29916242Slayer m |= SETID; 30016242Slayer continue; 30116242Slayer case 't': 30216242Slayer m |= STICKY; 30316242Slayer continue; 30416242Slayer default: 30516242Slayer ms--; 30624503Ssam return (m); 30716242Slayer } 30816242Slayer } 309