[comp.os.minix] symbolic chmod

ferry@htsa.uucp (Ferry Rietveld) (01/24/89)

	When I received my Minix (1.2) from P-H (about 1 year after ordering !!)suprisingly it did not support a symbolic chmod , which I find more appealing 
then using octal [ 8-( ] numbers . So i decided to write one myself.

And here it is !!!


	      
	o /  cut here 
---------x----------------------------------------------------------------
	o \
/*
**  usage : chmod mode files ... 
**  mode   -> OctalInt | Symbolic .
**  Symbolic -> [who] op perm {[op] perm} { ',' [who] op perm {[op] perm} } 
**  who      -> 'u' | 'g' | 'o' .
**  op       -> '+' | '-' | '=' .
**  perm     -> 'r' | 'w' | 'x' | 's' | 't' .
**
**  Written by Ferry Rietveld
**  date 01-15-89 . 
*/

#ifdef unix
#include <sys/types.h>
#include <sys/stat.h>
#define prints(x,y) printf(x,y) 
#else
#include <stat.h>
#endif
#include <stdio.h>
#include <ctype.h>

#define AND 	'-'
#define OR	'+'
#define IS	'='
#define rwx(q)  in(q,"rwx")
#define rwxst(q)  in(q,"rwxst")

int OrMode = 0 , AndMode = 07777 ;

main (argc, argv)
int   argc;
char  **argv;
{
        int  i, fiddle = 0, count = 0 , step, Mode ;
        struct stat fstat ;

        if (argc < 3) Usage ();

        if( isdigit(argv[1][0]) ) Mode = intmode (argv[1]);
        else fiddle = 1 ; /* fool around with | and & & flags */

        for (i = 2; i < argc; i++) {
		OrMode = 0 , AndMode = 07777 ;
                if (stat(argv[i],&fstat) < 0) {
                        prints("Chmod : can't stat %s\n",argv[i]);
                        count++;
                }
                else {
		      step = 0 ;
                      if (fiddle) {
			     do { /* Here there is no way back, 
				  ** change the old mode.
				  */
				OrMode = 0 ; AndMode = 07777 ;
				step=Set_flags(argv[1],step) ;
				fstat.st_mode = fstat.st_mode & AndMode ;
                                fstat.st_mode |= OrMode ;
			     } while (step!=0) ;
                      	     Mode = fstat.st_mode ;
		      }
                      if (chmod (argv[i], Mode) < 0) {
                            prints("Chmod : can't change %s\n",argv[i]);
                            count++;
                      }
               }
        }
        exit (count);
}

/* 
** Parse the flag string and set the apropriate bits 
*/
Set_flags(mode,i)
char *mode;
int i ;
{
   int usr= -1, grp= -1, otr= -1, flag = 1, op;
   while (mode[i]) {
      switch (mode[i++]) { /* First char */
	  case 'a' : break ; 
          case 'u' : usr = 6 ; flag=0 ; break ;
	  case 'g' : grp = 3 ; flag=0 ; break ;
          case 'o' : otr = 0 ; flag=0 ; break ;
	  case '+' : /* Same as - */ ;
	  case '-' : /* Same as = */ ;
	  case '=' : if (flag) { usr=6;grp=3;otr=0; } ;
		     i-- ; /* miner designer fault */
		     while (in(mode[i],"+-=")) { 
			     op = mode[i++] ; 
			     while (rwxst(mode[i])) { 
					Bit_rwx(mode[i],usr,op) ;
					Bit_rwx(mode[i],grp,op) ;
					Bit_rwx(mode[i++],otr,op) ;
			     }
                     }
                     usr = grp = otr = -1 ;
		     flag = 1 ;
	   	     break ;
          case ',' : return ( i ) ;
	  default  : Usage() ;
     }
  }
  return ( 0 ) ;
} /* Set_flags */

/*
** Set up the mask for setting or clearing a single bit 
*/
Bit_rwx(c,shift,UpDown)
char c;
int shift, UpDown;
{
	if (shift==-1) return ;
	if (UpDown==OR) {
      		switch(c) {
                     case 'r': shift++ ; 
                     case 'w': shift++ ; 
                     case 'x': OrMode |= (001<<shift) ; break;
                     case 's': if (shift) OrMode |=(01000<<shift/3);
			       else Usage() ;
			       break;
               	     case 't': if (!shift) OrMode |=(01000<<shift/3);
			       else Usage() ;
			       break;
                }
		return ;
	}
	if (UpDown==AND) { 
                switch(c) {
                     case 'r': shift++ ; 
                     case 'w': shift++ ;
                     case 'x': AndMode &= ~(0001<<shift) ; break;
                     case 's': if (shift) AndMode &= ~(01000<<shift/3);
			       else Usage() ;
			       break;
                     case 't': if (!shift) AndMode &= ~(01000<<shift/3);
			       else Usage() ;
			       break;
                } /* switch */
		return ;
	}
	/* 
	** For securety reasons UMASK should be taken into account 
	** for the next setting of a bit 
	*/
        switch(c) {
                case 'r': OrMode |= (0004<<shift) ; break;
                case 'w': OrMode |= (0002<<shift) ; break;
                case 'x': OrMode |= (0001<<shift) ; break;
        }
	AndMode &= ~(0007<<shift) ;
}

int intmode (Octs)
char   *Octs;
{
        int c, i=0;
        while ((c = *Octs++) >= '0' && c <= '7')
                i = (i<<3) + (c - '0');
        if (c != '\0') Usage ();
        return (i);
}

Usage () {
#ifdef unix
        prints ("Usage: Chmod [ugoa] [+-=] [rwxst] file ...\n","");
#else
        prints ("Usage: Chmod [ugoa] [+-=] [rwxst] file ...\n");
#endif
        exit (255); 
}

/*
** A simple IN set test 
*/
int in(c,str)
char c, *str;
{
	while ( *str ) if (*str++==c) return (1) ;
	return (0) ;
}

__________________________________________________________________________
Ferry Rietveld.			AHA - TMF
mail : ...hp4nl!htsa!ferry	Europaboulevard 23
tel : 020 -446586 		1079 PC Amsterdam.
--------------------------------------------------------------------------