regoli@silver.bacs.indiana.edu (michael regoli) (06/02/89)
In article <1771@papaya.bbn.com> rsalz@bbn.com (Rich Salz) writes: | [ Note the follow-ups.] | | Why hasn't anyone written a chmod(1) that takes a bloody "rwsr-xr-x" string? | /r$ | -- | Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. ][ here's something i found lying around that does exactly that (well, almost--but it's a start). if an industrious soul wants to make improvements to allow more than any combination of "rwxrwxrwx" (e.g., "rwsr-xr-x") the patches would be most appreciated. please post your patches here. or rewrite the whole damn thing. -- michael regoli regoli@iubacs.bitnet regoli@sivler.bacs.indiana.edu ...rutgers!iuvax!silver!regoli -- /* * * CHMODE.C * * New version of the chmod program: accepts inputs of the * same format as given by the ls -l command, ie it can * be invoked like 'chmode rwxrw-r-- *' to make the modes * of each file specified match the template! * * If automatic aggregate initialization is available, * compile with: * * cc -Dauto chmode.c -o chmode * * otherwise use: * * cc chmode.c -o chmode * */ #include <whoami.h> #include <stdio.h> #define ERROR -1 #define O_RD 256 /** 400 octal **/ #define O_WR 128 /** 200 octal **/ #define O_EX 64 /** 100 octal **/ #define G_RD 32 /** 40 octal **/ #define G_WR 16 /** 20 octal **/ #define G_EX 8 /** 10 octal **/ #define E_RD 4 #define E_WR 2 #define E_EX 1 main(argc, argv) int argc; char *argv[]; { register int newmode; register int j; char buffer[16]; if (argc < 3) exit(printf("Usage: %s <graphic mode> <file(s)>\n",argv[0])); --argc; newmode = 0; j = 1; strncpy(buffer,argv[j++], 9); if (strlen(buffer) != 9) exit(printf("Usage: %s <9 char graphic mode> <file(s)>\n",argv[0])); /** lets figure out the graphic mode translation! **/ if ((newmode = translate(buffer)) == ERROR) { printf("Bad graphic mode designator! Please use 'rwxrwxrwx' as a template, \n"); printf("indicating those accesses that you desire to prevent with a dash\n"); printf(" For example: 'chmode rw-r--r-- test.c'\n"); exit(1); } while (--argc > 0) chmod(argv[j++], newmode); } int translate(buffer) char buffer[]; { /** translate a graphic representation of file access to an equivalent number as defined in CHMOD(2) **/ register int loc = 0, sum = 0, val; #ifdef auto char type[] = "rwxrwxrwx"; int mode[] = { O_RD, O_WR, O_EX, G_RD, G_WR, G_EX, E_RD, E_WR, E_EX }; #else char type[9]; int mode[9]; mode[0] = O_RD; mode[1] = O_WR; mode[2] = O_EX; mode[3] = G_RD; mode[4] = G_WR; mode[5] = G_EX; mode[6] = E_RD; mode[7] = E_WR; mode[8] = E_EX; strcpy(type,"rwxrwxrwx"); #endif for (loc = 0; loc < 9; loc++) if ((val = check(buffer[loc], type[loc], mode[loc])) == ERROR) return(ERROR); else sum += val; return(sum); } int check(ch, type, mask) char ch; int mask; { /** check to see if ch is either type or '-', returning either mask or ERROR **/ if (ch == type) return(mask); else if (ch == '-') return(0); else return(ERROR); } /* * CHMODE.C: Finis. */
gis@datlog.co.uk ( Ian Stewartson ) (06/08/89)
In article <21508@iuvax.cs.indiana.edu> regoli@silver.bacs.indiana.edu (michael regoli) writes: >In article <1771@papaya.bbn.com> rsalz@bbn.com (Rich Salz) writes: >| Why hasn't anyone written a chmod(1) that takes a bloody "rwsr-xr-x" string? > >if an industrious soul wants to make improvements to allow more than >any combination of "rwxrwxrwx" (e.g., "rwsr-xr-x") the patches would >be most appreciated. Attached is a modified version of some source which came over in comp.os.minix (I think) which supports Sys Vr2 absolute and symbolic modes and the new string mode all in one. I've tested it as far as I can. The only problem one may have with it are the include files which were based on POSIX on Unix SysVr2 so one may have to hack about. Hope it is of some interest. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: chmod.c # Wrapped by gis@dlvax2 on Wed Jun 7 18:44:50 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'chmod.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'chmod.c'\" else echo shar: Extracting \"'chmod.c'\" \(8300 characters\) sed "s/^X//" >'chmod.c' <<'END_OF_FILE' X/* X * chmod.c Author: James da Silva (ihnp4!killer!jaime) X * X * A Version of chmod up to Sys Vr2 with ls string mode enchancement X * Updated by Ian Stewartson (gis@datlog.co.uk) X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include <stdlib.h> X#include <ctype.h> X#include <string.h> X X#define WHO_USER 1 /* Set user */ X#define WHO_GROUP 2 /* Set group */ X#define WHO_OTHER 4 /* Set others */ X#define WHO_ALL 7 /* Set all */ X Xstruct stat st; /* structure returned by stat() */ Xchar *u_mode; /* New mode argument */ Xchar *pname; Xmode_t newmode; Xmode_t num_absolute (); Xmode_t str_absolute (); Xmode_t symbolic (); Xmode_t applyop (); Xvoid usage (); Xvoid badmode (); Xint isabsolute = 0; X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X int i; X int error = 0; X X pname = *(argv++); X X if (argc < 3) X usage (); X X u_mode = *argv; /* save pointer to mode arg */ X X/* check for octal mode */ X X if (isabsolute = (isdigit(*u_mode) && (*u_mode <= '7')) ) X newmode = num_absolute (); X X else if ((strlen (u_mode) == 9) && ((*u_mode == 'r') || (*u_mode == '-'))) X { X isabsolute = 1; X newmode = str_absolute (); X } X X/* apply the mode to all files listed */ X X for (i = 2; i < argc; i++) X { X if (stat (*(++argv), &st)) /* get current file mode */ X { X fprintf (stderr, "%s: cannot find `%s'\n", pname, *argv); X ++error; X continue; X } X X/* calculate new mode for this file */ X X if (!isabsolute) X newmode = symbolic (st.st_mode); X X if (chmod (*argv, newmode)) /* change the mode */ X { X fprintf (stderr, "%s: cannot chmod `%s'\n", pname, *argv); X ++error; X } X } X X exit (error); X} X X X/* X * num_absolute - Interprets an octal mode. The file modes will be set to X * this value. X */ X Xmode_t num_absolute () X{ X mode_t m = 0; X char *s = u_mode; X X/* convert octal string to integer */ X X while (isdigit(*s) && (*s <= '7')) X m = m * 8 + (*(s++) - '0'); X X/* if something else is there, choke */ X X if (*s) X badmode (s); X X return m; X} X X X/* X * symbolic X * X * Processes symbolic mode of the form (in EBNF): X * <symbolic> ::= <pgroup> { ',' <pgroup> }. X * <pgroup> ::= [ <who> ] <op> <permissions> { <op> <permissions> }. X * X * <who> ::= <whoch> { <whoch> }. X * <whoch> ::= 'a' | 'u' | 'g' | 'o'. X * X * <op> ::= '+' | '-' | '='. X * X * <permissions> ::= <permch> { <permch> }. X * <permch> ::= 'r' | 'w' | 'x' | 's' | 't' | 'u' | 'g' | 'o'. X * X * If <who> is omitted, 'a' is assumed, BUT umask()ed bits are uneffected. X * If <op> is '=', all unspecified permissions are turned off for this <who>. X * For permissions 'u', 'g', and 'o', the permissions are taken from the X * specified set. i.e. o=g sets the permissions for other the same as for X * group. X */ X Xmode_t symbolic(mode) Xmode_t mode; X{ X int haspcopy; X int who; X mode_t u_mask = umask (0); /* get the umasked bits */ X mode_t emask; X mode_t partial; /* RXW flags */ X mode_t other; /* sst flags */ X char *s = u_mode; X char op; X X do /* pgroup */ X { X who = 0; X X/* Process until we reach an operator (get the who) */ X X while (strchr ("+-=", *s) == (char *)NULL) X { X switch (*s) X { X case 'a': who |= WHO_ALL; break; X case 'u': who |= WHO_USER; break; X case 'g': who |= WHO_GROUP; break; X case 'o': who |= WHO_OTHER; break; X X default: X badmode (s); X } X X s++; X } X X/* If who is not defined - set all */ X X if (!who) X { X who = WHO_ALL; X emask = ~u_mask; /* effective umask */ X } X X else X emask = ~0; X X X/* process each given operator */ X X while (*s && (strchr ("+-=", *s) != (char *)NULL)) X { X op = *(s++); X partial = 0; X other = 0; X haspcopy = 0; X X /* collect the specified permissions */ X X while (*s && (strchr ("rwxstugo", *s) != (char *)NULL)) X { X X/* Berkeley only allows one of 'u' 'g' or 'o' as permissions */ X X if ((*s && (strchr ("ugo", *s) != (char *)NULL)) && X (haspcopy++)) X badmode (s); X X/* Process the permissions */ X X switch (*s) X { X case 'r': X partial |= S_IROTH; X break; X X case 'w': X partial |= S_IWOTH; X break; X X case 'x': X partial |= S_IXOTH; X break; X X case 't': X other |= S_ISVTX; X break; X X case 'u': X partial |= (mode & S_IRWXU) >> 6; X other |= mode & S_ISUID; X break; X X case 'g': X partial |= (mode & S_IRWXG) >> 3; X other |= mode & S_ISGID; X break; X X case 'o': X partial |= (mode & S_IRWXO); X break; X X case 's': X if (who & WHO_USER) X other |= S_ISUID; X X if (who & WHO_GROUP) X other |= S_ISGID; X X break; X X default: X badmode (s); X } X X s++; X } X X/* apply the op using the affected bits and masks */ X X if (who & WHO_USER) X mode = applyop (mode, op, (other | (partial << 6)), emask, X (S_IRWXU | S_ISUID)); X X if (who & WHO_GROUP) X mode = applyop (mode, op, (other | (partial << 3)), emask, X (S_IRWXG | S_ISGID)); X X if (who & WHO_OTHER) X mode = applyop (mode, op, (other | partial), emask, X S_IRWXO); X } X X } while (*(s++) == ','); X X/* not at end - choke */ X X if (*(--s)) X badmode(s); X X return mode; X} X X X/* X * applyop X * X * applies the operator to the current mode using the specified bitset X * and mask. 'bits' will contain 1's in every bit affected by the X * operator '+', '-', or '='. In the case of '=', msk is used to X * determine which bits will be forced off. 'emask' is the effective X * umask. X */ X Xmode_t applyop (mode, op, bits, emask, msk) Xchar op; Xmode_t mode, bits, emask, msk; X{ X if (op == '+') X return mode | bits & emask; /* turn these bits on */ X X if (op == '-') X return mode & ~(bits & emask); /* turn these off */ X X if (op == '=') X { X mode |= bits & emask; /* turn these bits on */ X return mode & ~(~bits & msk & emask); /* others off */ X } X X/* should never get here (famous last words) */ X X fprintf (stderr, "%s: panic: bad op `%c' passed\n", pname, op); X return mode; X} X X X/* X * usage - Prints a terse usage message and exits. X */ X Xvoid usage () X{ X fprintf (stderr, "Usage: %s [absolute-mode | symbolic-mode | string-mode] files\n", pname); X exit(1); X} X X X/* X * badmode X * X * Called when the parser chokes on the given mode. X * Prints a message showing the offending character and exits. X */ X Xvoid badmode (s) Xchar *s; X{ X int sp; X char buffer[80]; X X sp = s - u_mode + strlen (pname) + 21; X sp = sp > 79 ? 79 : sp; /* check for buffer overflow */ X X memset (buffer, ' ', 80); X buffer[sp] = 0; X X fprintf (stderr, "%s: badly formed mode `%s'\n", pname, u_mode); X fprintf (stderr, "%s^\n", buffer); X exit (1); X} X X/* X * str_absolute - Interprets an ls string mode. The file modes will be set to X * this value. X */ X Xmode_t str_absolute () X{ X mode_t m = 0; /* New mode */ X char *s = u_mode; X int i; X X for (i = 0; i < 9; ++i, ++s) X { X if (*s == '-') X continue; X X switch (i % 3) X { X case 0: X if (*s != 'r') X badmode (s); X X m |= (S_IRUSR >> ((i / 3) * 3)); X break; X X case 1: X if (*s != 'w') X badmode (s); X X m |= (S_IWUSR >> ((i / 3) * 3)); X break; X X/* For x flag, there are a number of options x, s, S, t, T depending on X * mulitple values so we need the position in the string as well X */ X X case 2: X if (islower(*s)) X m |= (S_IXUSR >> ((i / 3) * 3)); X X switch (*s) X { X default: X badmode (s); X X case 't': X case 'T': X m |= S_ISVTX; X break; X X X case 'S': X case 's': X if (!(i / 3)) X m |= S_ISUID; X X else if ((i / 3) == 1) X m |= S_ISGID; X X else X badmode (s); X break; X X case 'x': X break; X } X X break; X X } X } X X return m; X} END_OF_FILE if test 8300 -ne `wc -c <'chmod.c'`; then echo shar: \"'chmod.c'\" unpacked with wrong size! fi # end of 'chmod.c' fi echo shar: End of shell archive. exit 0 Regards, Ian Stewartson Data Logic Ltd, Queens House, Greenhill Way, Harrow, Middlesex, HA1 1YR, UK. (Phone) +44 1 863 0383 (Telex) 888103 (Fax) +44 1 861 2010 (Network) gis@datlog.co.uk or ukc!datlog!gis
brianb@marque.mu.edu (Brian Bebeau) (06/08/89)
In article <21508@iuvax.cs.indiana.edu> regoli@silver.bacs.indiana.edu (michael regoli) writes: > >if an industrious soul wants to make improvements to allow more than >any combination of "rwxrwxrwx" (e.g., "rwsr-xr-x") the patches would >be most appreciated. > >please post your patches here. or rewrite the whole damn thing. > >-- >michael regoli >regoli@iubacs.bitnet >regoli@sivler.bacs.indiana.edu >...rutgers!iuvax!silver!regoli Ok, I did. I rewrote it basically from translate() on keeping the main() stuff. ADDITIONS: accepts setuid, setgid accepts sticky bit accepts file/record locking complains if chmod fails It also lints clean. This should be fine on a SYSV machine, I don't know about Berkeley, I can't try it. There are two problems. 1) Although it will catch errors like "rwz" it will silently accept "rww". 2) If you try to set the sticky bit and you don't have permission, it won't complain. ---cut------cut------cut------cut------cut------cut------cut------cut--- /* * * CHMOD2.C * * Based on the chmode program by: * michael regoli regoli@sivler.bacs.indiana.edu * Modified by: * Brian Bebeau brianb@marque.mu.edu * * New version of the chmod program: accepts inputs of the * same format as given by the ls -l command, ie it can * be invoked like 'chmode rwxrw-r-- *' to make the modes * of each file specified match the template! * * cc -O chmod2.c -o chmod2 * */ #include <stdio.h> #include <errno.h> #define ERROR -1 #define SUID 04000 /* set user id */ #define SGID 02000 /* set group id */ #define STKY 01000 /* sticky bit */ #define ROWN 00400 /* owner read permission */ #define WOWN 00200 /* owner write permission */ #define XOWN 00100 /* owner execute permissin */ #define RGRP 00040 /* group read permission */ #define WGRP 00020 /* group write permission */ #define XGRP 00010 /* group execute permission */ #define ROTH 00004 /* other read permission */ #define WOTH 00002 /* other write permission */ #define XOTH 00001 /* other execute permission */ void exit(), perror(); char *strcpy(), *strncpy(); main(argc, argv) int argc; char *argv[]; { register int newmode; register int j; char buffer[16]; if (argc < 3) { (void) fprintf(stderr, "Usage: %s <graphic mode> file(s)\n",argv[0]); exit(1); } --argc; newmode = 0; j = 1; (void) strncpy(buffer,argv[j++], 9); /** lets figure out the graphic mode translation! **/ if ((newmode = translate(buffer)) == ERROR) { (void) fprintf(stderr, "Bad graphic mode designator! Please use 'rwxrwxrwx' as a template, \n"); (void) fprintf(stderr, "indicating those accesses that you desire to prevent with a dash\n"); (void) fprintf(stderr, " For example: 'chmode rw-r--r-- test.c'\n"); exit(2); } while (--argc > 0) if (chmod(argv[j++], newmode) < 0) { perror("chmod failed"); exit(3); } exit(0); /*NOTREACHED*/ } translate(buffer) char buffer[]; { /** translate a graphic representation of file access to an equivalent number as defined in CHMOD(2) **/ register int mode=0, i; for (i=0; i < 9; i++) { switch(buffer[i]) { case 'r': if (i == 0) mode |= ROWN; if (i == 3) mode |= RGRP; if (i == 6) mode |= ROTH; break; case 'w': if (i == 1) mode |= WOWN; if (i == 4) mode |= WGRP; if (i == 7) mode |= WOTH; break; case 'x': if (i == 2) mode |= XOWN; if (i == 5) mode |= XGRP; if (i == 8) mode |= XOTH; break; case 's': if (i == 2){ mode |= SUID; mode |= XOWN; } if (i == 5) { mode |= SGID; mode |= XGRP; } break; case 't': if (i == 8) { mode |= STKY; mode |= XOTH; } break; case 'l': if (i == 5) { mode |= SGID; mode &= ~XGRP; } break; case '-': break; default: return (ERROR); } /* end switch */ } /* end for */ return (mode); } /* end routine */ /* end program chmod2.c */ ---cut------cut------cut------cut------cut------cut------cut------cut--- --------------------------------------------------------------------------- Brian Bebeau Marquette University DOMAIN: brianb@marque.mu.edu UUCP: {uwvax,uunet}!marque!brianb ARPA: brianb%marque.uucp@csd1.milw.wisc.edu BITNET: 6877BEBE@MUCSD ---------------------------------------------------------------------------