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*23482Smckusick static char sccsid[] = "@(#)chmod.c 5.2 (Berkeley) 06/09/85"; 919840Sdist #endif not lint 1019840Sdist 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] == '-') { 54*23482Smckusick if (strcmp(argv[0], "-R") == 0) { 55*23482Smckusick rflag++; 56*23482Smckusick argv++, argc--; 57*23482Smckusick } 5816242Slayer } 5916270Slayer 6016242Slayer modestring = argv[0]; 6116242Slayer 6216242Slayer um = umask(0); 6316242Slayer (void) newmode(0); 6416242Slayer for (i = 1; i < argc; i++) { 6516242Slayer p = argv[i]; 6616594Sralph if (stat(p, &st) < 0) { 6716242Slayer fprintf(stderr, "chmod: can't access %s\n", p); 6816242Slayer ++status; 6916242Slayer continue; 7016242Slayer } 7116242Slayer if (rflag && st.st_mode & S_IFDIR) { 7216242Slayer status += chmodr(p, newmode(st.st_mode)); 7316242Slayer } else if (chmod(p, newmode(st.st_mode)) < 0) { 7416242Slayer fprintf(stderr, "chmod: can't change %s\n", p); 7516242Slayer ++status; 7616242Slayer continue; 7716242Slayer } 7816242Slayer } 7916242Slayer exit(status); 8016242Slayer } 8116242Slayer 8216242Slayer chmodr(dir, mode) 8316242Slayer char *dir; 8416242Slayer { 8516242Slayer register DIR *dirp; 8616242Slayer register struct direct *dp; 8716242Slayer register struct stat st; 8816242Slayer char savedir[1024]; 8916242Slayer 9016242Slayer if (getwd(savedir) == 0) { 9116242Slayer fprintf(stderr, "chmod: %s\n", savedir); 9216242Slayer exit(255); 9316242Slayer } 9416242Slayer 9516242Slayer /* 9616242Slayer ** chmod what we are given before doing it's contents 9716242Slayer */ 9816242Slayer chmod(dir, newmode(mode)); 9916242Slayer 10016242Slayer chdir(dir); 10116242Slayer if ((dirp = opendir(".")) == NULL) { 10216242Slayer perror(dir); 10316242Slayer return(1); 10416242Slayer } 10516242Slayer dp = readdir(dirp); 10616242Slayer dp = readdir(dirp); /* read "." and ".." */ 10716242Slayer for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { 10818473Smckusick if (stat(dp->d_name, &st) < 0) { 10918473Smckusick fprintf(stderr, "chmod: can't access %s\n", dp->d_name); 11018473Smckusick return(1); 11118473Smckusick } 11216242Slayer chmod(dp->d_name, newmode(st.st_mode)); 11316242Slayer if (st.st_mode & S_IFDIR) 11416242Slayer chmodr(dp->d_name, mode); 11516242Slayer } 11616242Slayer closedir(dirp); 11716242Slayer chdir(savedir); 11816242Slayer return(0); 11916242Slayer } 12016242Slayer 12116242Slayer newmode(nm) 12216242Slayer unsigned nm; 12316242Slayer { 12416242Slayer register o, m, b; 12516242Slayer int savem; 12616242Slayer 12716242Slayer ms = modestring; 12816242Slayer savem = nm; 12916242Slayer m = abs(); 13018473Smckusick if (!*ms) 13118473Smckusick return(m); 13216242Slayer do { 13316242Slayer m = who(); 13416242Slayer while (o = what()) { 13516242Slayer b = where(nm); 13616242Slayer switch (o) { 13716242Slayer case '+': 13816242Slayer nm |= b & m; 13916242Slayer break; 14016242Slayer case '-': 14116242Slayer nm &= ~(b & m); 14216242Slayer break; 14316242Slayer case '=': 14416242Slayer nm &= ~m; 14516242Slayer nm |= b & m; 14616242Slayer break; 14716242Slayer } 14816242Slayer } 14916242Slayer } while (*ms++ == ','); 15016242Slayer if (*--ms) { 15116242Slayer fprintf(stderr, "chmod: invalid mode\n"); 15216242Slayer exit(255); 15316242Slayer } 15416242Slayer return(nm); 15516242Slayer } 15616242Slayer 15716242Slayer abs() 15816242Slayer { 15916242Slayer register c, i; 16016242Slayer 16116242Slayer i = 0; 16216242Slayer while ((c = *ms++) >= '0' && c <= '7') 16316242Slayer i = (i << 3) + (c - '0'); 16416242Slayer ms--; 16516242Slayer return(i); 16616242Slayer } 16716242Slayer 16816242Slayer who() 16916242Slayer { 17016242Slayer register m; 17116242Slayer 17216242Slayer m = 0; 17316242Slayer for (;;) switch (*ms++) { 17416242Slayer case 'u': 17516242Slayer m |= USER; 17616242Slayer continue; 17716242Slayer case 'g': 17816242Slayer m |= GROUP; 17916242Slayer continue; 18016242Slayer case 'o': 18116242Slayer m |= OTHER; 18216242Slayer continue; 18316242Slayer case 'a': 18416242Slayer m |= ALL; 18516242Slayer continue; 18616242Slayer default: 18716242Slayer ms--; 18816242Slayer if (m == 0) 18916242Slayer m = ALL & ~um; 19016242Slayer return m; 19116242Slayer } 19216242Slayer } 19316242Slayer 19416242Slayer what() 19516242Slayer { 19616242Slayer 19716242Slayer switch (*ms) { 19816242Slayer case '+': 19916242Slayer case '-': 20016242Slayer case '=': 20116242Slayer return *ms++; 20216242Slayer } 20316242Slayer return(0); 20416242Slayer } 20516242Slayer 20616242Slayer where(om) 20716242Slayer register om; 20816242Slayer { 20916242Slayer register m; 21016242Slayer 21116242Slayer m = 0; 21216242Slayer switch (*ms) { 21316242Slayer case 'u': 21416242Slayer m = (om & USER) >> 6; 21516242Slayer goto dup; 21616242Slayer case 'g': 21716242Slayer m = (om & GROUP) >> 3; 21816242Slayer goto dup; 21916242Slayer case 'o': 22016242Slayer m = (om & OTHER); 22116242Slayer dup: 22216242Slayer m &= (READ|WRITE|EXEC); 22316242Slayer m |= (m << 3) | (m << 6); 22416242Slayer ++ms; 22516242Slayer return m; 22616242Slayer } 22716242Slayer for (;;) switch (*ms++) { 22816242Slayer case 'r': 22916242Slayer m |= READ; 23016242Slayer continue; 23116242Slayer case 'w': 23216242Slayer m |= WRITE; 23316242Slayer continue; 23416242Slayer case 'x': 23516242Slayer m |= EXEC; 23616242Slayer continue; 23716594Sralph case 'X': 23818473Smckusick if ((om & S_IFDIR) || (om & EXEC)) 23918473Smckusick m |= EXEC; 24016594Sralph continue; 24116242Slayer case 's': 24216242Slayer m |= SETID; 24316242Slayer continue; 24416242Slayer case 't': 24516242Slayer m |= STICKY; 24616242Slayer continue; 24716242Slayer default: 24816242Slayer ms--; 24916242Slayer return m; 25016242Slayer } 25116242Slayer } 252