1*19840Sdist /* 2*19840Sdist * Copyright (c) 1980 Regents of the University of California. 3*19840Sdist * All rights reserved. The Berkeley software License Agreement 4*19840Sdist * specifies the terms and conditions for redistribution. 5*19840Sdist */ 616242Slayer 7*19840Sdist #ifndef lint 8*19840Sdist static char sccsid[] = "@(#)chmod.c 5.1 (Berkeley) 04/30/85"; 9*19840Sdist #endif not lint 10*19840Sdist 1116242Slayer /* 1216242Slayer * chmod options mode files 1316242Slayer * where 1418473Smckusick * mode is [ugoa][+-=][rwxXstugo] or a octal number 1516242Slayer * options are -R 1616242Slayer */ 1716242Slayer #include <stdio.h> 1816242Slayer #include <sys/types.h> 1916242Slayer #include <sys/stat.h> 2016242Slayer #include <sys/dir.h> 2116242Slayer 2216242Slayer #define USER 05700 /* user's bits */ 2316242Slayer #define GROUP 02070 /* group's bits */ 2416242Slayer #define OTHER 00007 /* other's bits */ 2516242Slayer #define ALL 01777 /* all (note absence of setuid, etc) */ 2616242Slayer 2716242Slayer #define READ 00444 /* read permit */ 2816242Slayer #define WRITE 00222 /* write permit */ 2916242Slayer #define EXEC 00111 /* exec permit */ 3016242Slayer #define SETID 06000 /* set[ug]id */ 3116242Slayer #define STICKY 01000 /* sticky bit */ 3216242Slayer 3316242Slayer char *modestring, *ms; 3416242Slayer int um; 3516242Slayer int status; 3618473Smckusick int rflag, debug; 3716242Slayer 3816242Slayer main(argc,argv) 3916242Slayer char **argv; 4016242Slayer { 4116242Slayer register i; 4216270Slayer register char *p, *flags; 4316242Slayer struct stat st; 4416242Slayer 4518473Smckusick usage: 4616242Slayer if (argc < 3) { 4716242Slayer fprintf(stderr 4818473Smckusick ,"Usage: chmod [-R] [ugoa][+-=][rwxXstugo] file ...\n"); 4916242Slayer exit(-1); 5016242Slayer } 5116270Slayer 5216242Slayer argv++, --argc; 5316270Slayer if (*argv[0] == '-') { 5416270Slayer for (flags = argv[0]; *flags; ++flags) 5516270Slayer switch (*flags) { 5616270Slayer case '-': break; 5716270Slayer case 'R': rflag++; break; 5818473Smckusick default: argc = 0; goto usage; 5916270Slayer } 6016270Slayer argv++, argc--; 6116242Slayer } 6216270Slayer 6316242Slayer modestring = argv[0]; 6416242Slayer 6516242Slayer um = umask(0); 6616242Slayer (void) newmode(0); 6716242Slayer for (i = 1; i < argc; i++) { 6816242Slayer p = argv[i]; 6916594Sralph if (stat(p, &st) < 0) { 7016242Slayer fprintf(stderr, "chmod: can't access %s\n", p); 7116242Slayer ++status; 7216242Slayer continue; 7316242Slayer } 7416242Slayer if (rflag && st.st_mode & S_IFDIR) { 7516242Slayer status += chmodr(p, newmode(st.st_mode)); 7616242Slayer } else if (chmod(p, newmode(st.st_mode)) < 0) { 7716242Slayer fprintf(stderr, "chmod: can't change %s\n", p); 7816242Slayer ++status; 7916242Slayer continue; 8016242Slayer } 8116242Slayer } 8216242Slayer exit(status); 8316242Slayer } 8416242Slayer 8516242Slayer chmodr(dir, mode) 8616242Slayer char *dir; 8716242Slayer { 8816242Slayer register DIR *dirp; 8916242Slayer register struct direct *dp; 9016242Slayer register struct stat st; 9116242Slayer char savedir[1024]; 9216242Slayer 9316242Slayer if (getwd(savedir) == 0) { 9416242Slayer fprintf(stderr, "chmod: %s\n", savedir); 9516242Slayer exit(255); 9616242Slayer } 9716242Slayer 9816242Slayer /* 9916242Slayer ** chmod what we are given before doing it's contents 10016242Slayer */ 10116242Slayer chmod(dir, newmode(mode)); 10216242Slayer 10316242Slayer chdir(dir); 10416242Slayer if ((dirp = opendir(".")) == NULL) { 10516242Slayer perror(dir); 10616242Slayer return(1); 10716242Slayer } 10816242Slayer dp = readdir(dirp); 10916242Slayer dp = readdir(dirp); /* read "." and ".." */ 11016242Slayer for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { 11118473Smckusick if (stat(dp->d_name, &st) < 0) { 11218473Smckusick fprintf(stderr, "chmod: can't access %s\n", dp->d_name); 11318473Smckusick return(1); 11418473Smckusick } 11516242Slayer chmod(dp->d_name, newmode(st.st_mode)); 11616242Slayer if (st.st_mode & S_IFDIR) 11716242Slayer chmodr(dp->d_name, mode); 11816242Slayer } 11916242Slayer closedir(dirp); 12016242Slayer chdir(savedir); 12116242Slayer return(0); 12216242Slayer } 12316242Slayer 12416242Slayer newmode(nm) 12516242Slayer unsigned nm; 12616242Slayer { 12716242Slayer register o, m, b; 12816242Slayer int savem; 12916242Slayer 13016242Slayer ms = modestring; 13116242Slayer savem = nm; 13216242Slayer m = abs(); 13318473Smckusick if (!*ms) 13418473Smckusick return(m); 13516242Slayer do { 13616242Slayer m = who(); 13716242Slayer while (o = what()) { 13816242Slayer b = where(nm); 13916242Slayer switch (o) { 14016242Slayer case '+': 14116242Slayer nm |= b & m; 14216242Slayer break; 14316242Slayer case '-': 14416242Slayer nm &= ~(b & m); 14516242Slayer break; 14616242Slayer case '=': 14716242Slayer nm &= ~m; 14816242Slayer nm |= b & m; 14916242Slayer break; 15016242Slayer } 15116242Slayer } 15216242Slayer } while (*ms++ == ','); 15316242Slayer if (*--ms) { 15416242Slayer fprintf(stderr, "chmod: invalid mode\n"); 15516242Slayer exit(255); 15616242Slayer } 15716242Slayer return(nm); 15816242Slayer } 15916242Slayer 16016242Slayer abs() 16116242Slayer { 16216242Slayer register c, i; 16316242Slayer 16416242Slayer i = 0; 16516242Slayer while ((c = *ms++) >= '0' && c <= '7') 16616242Slayer i = (i << 3) + (c - '0'); 16716242Slayer ms--; 16816242Slayer return(i); 16916242Slayer } 17016242Slayer 17116242Slayer who() 17216242Slayer { 17316242Slayer register 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; 19316242Slayer return m; 19416242Slayer } 19516242Slayer } 19616242Slayer 19716242Slayer what() 19816242Slayer { 19916242Slayer 20016242Slayer switch (*ms) { 20116242Slayer case '+': 20216242Slayer case '-': 20316242Slayer case '=': 20416242Slayer return *ms++; 20516242Slayer } 20616242Slayer return(0); 20716242Slayer } 20816242Slayer 20916242Slayer where(om) 21016242Slayer register om; 21116242Slayer { 21216242Slayer register m; 21316242Slayer 21416242Slayer m = 0; 21516242Slayer switch (*ms) { 21616242Slayer case 'u': 21716242Slayer m = (om & USER) >> 6; 21816242Slayer goto dup; 21916242Slayer case 'g': 22016242Slayer m = (om & GROUP) >> 3; 22116242Slayer goto dup; 22216242Slayer case 'o': 22316242Slayer m = (om & OTHER); 22416242Slayer dup: 22516242Slayer m &= (READ|WRITE|EXEC); 22616242Slayer m |= (m << 3) | (m << 6); 22716242Slayer ++ms; 22816242Slayer return m; 22916242Slayer } 23016242Slayer for (;;) switch (*ms++) { 23116242Slayer case 'r': 23216242Slayer m |= READ; 23316242Slayer continue; 23416242Slayer case 'w': 23516242Slayer m |= WRITE; 23616242Slayer continue; 23716242Slayer case 'x': 23816242Slayer m |= EXEC; 23916242Slayer continue; 24016594Sralph case 'X': 24118473Smckusick if ((om & S_IFDIR) || (om & EXEC)) 24218473Smckusick m |= EXEC; 24316594Sralph continue; 24416242Slayer case 's': 24516242Slayer m |= SETID; 24616242Slayer continue; 24716242Slayer case 't': 24816242Slayer m |= STICKY; 24916242Slayer continue; 25016242Slayer default: 25116242Slayer ms--; 25216242Slayer return m; 25316242Slayer } 25416242Slayer } 255