home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / LIBSRC.ZOO / libsrc / gen / setmode.c < prev    next >
C/C++ Source or Header  |  1992-02-01  |  10KB  |  441 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #if defined(LIBC_SCCS) && !defined(lint)
  35. static char sccsid[] = "@(#)setmode.c    5.6 (Berkeley) 5/27/91";
  36. #endif /* LIBC_SCCS and not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/stat.h>
  40. #include <sys/errno.h>
  41. #ifdef SETMODE_DEBUG
  42. #include <stdio.h>
  43. #endif
  44. #include <stdlib.h>
  45. #include <ctype.h>
  46.  
  47. #define    SET_LEN    6        /* initial # of bitcmd struct to malloc */
  48. #define    SET_LEN_INCR 4        /* # of bitcmd structs to add as needed */
  49.  
  50. struct bitcmd {
  51.     char    cmd;
  52.     char    cmd2;
  53.     mode_t    bits;
  54. };
  55.  
  56. #define    CMD2_CLR    0x01
  57. #define    CMD2_SET    0x02
  58. #define    CMD2_GBITS    0x04
  59. #define    CMD2_OBITS    0x08
  60. #define    CMD2_UBITS    0x10
  61.  
  62. /*
  63.  * Given the old mode and an array of bitcmd structures, apply the operations
  64.  * described in the bitcmd structures to the old mode, and return the new mode.
  65.  * Note that there is no '=' command; a strict assignment is just a '-' (clear
  66.  * bits) followed by a '+' (set bits).
  67.  */
  68. mode_t
  69. getmode(bbox, omode)
  70.     void *bbox;
  71.     mode_t omode;
  72. {
  73.     register struct bitcmd *set;
  74.     register mode_t newmode, value;
  75.  
  76.     set = (struct bitcmd *)bbox;
  77.     newmode = omode;
  78.     for (value = 0;; set++)
  79.         switch(set->cmd) {
  80.         /*
  81.          * When copying the user, group or other bits around, we "know"
  82.          * where the bit are in the mode so that we can do shifts to
  83.          * copy them around.  If we don't use shifts, it gets real
  84.          * grundgy with lots of single bit checks and bit sets.
  85.          */
  86.         case 'u':
  87.             value = (newmode & S_IRWXU) >> 6;
  88.             goto common;
  89.  
  90.         case 'g':
  91.             value = (newmode & S_IRWXG) >> 3;
  92.             goto common;
  93.  
  94.         case 'o':
  95.             value = newmode & S_IRWXO;
  96.         common:
  97.             if (set->cmd2 & CMD2_CLR) {
  98.                 if (set->cmd2 & CMD2_UBITS)
  99.                     newmode &= ~(S_IRWXU & set->bits);
  100.                 if (set->cmd2 & CMD2_GBITS)
  101.                     newmode &= ~(S_IRWXG & set->bits);
  102.                 if (set->cmd2 & CMD2_OBITS)
  103.                     newmode &= ~(S_IRWXO & set->bits);
  104.             }
  105.             if (set->cmd2 & CMD2_SET) {
  106.                 if (set->cmd2 & CMD2_UBITS)
  107.                     newmode |= (value<<6) & set->bits;
  108.                 if (set->cmd2 & CMD2_GBITS)
  109.                     newmode |= (value<<3) & set->bits;
  110.                 if (set->cmd2 & CMD2_OBITS)
  111.                     newmode |= value & set->bits;
  112.             }
  113.             break;
  114.  
  115.         case '+':
  116.             newmode |= set->bits;
  117.             break;
  118.  
  119.         case '-':
  120.             newmode &= ~set->bits;
  121.             break;
  122.  
  123.         case 'X':
  124.             if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
  125.                 newmode |= set->bits;
  126.             break;
  127.  
  128.         case '\0':
  129.         default:
  130. #ifdef SETMODE_DEBUG
  131.             (void)printf("getmode(, %04o) -> %04o\n",
  132.                 omode, newmode);
  133. #endif
  134.             return(newmode);
  135.         }
  136. }
  137.  
  138. #define    STANDARD_BITS    (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
  139.  
  140. static struct bitcmd *
  141. addcmd(set, op, who, oparg, mask)
  142.     struct bitcmd *set;
  143.     register int oparg, who;
  144.     register int op;
  145.     mode_t mask;
  146. {
  147.     switch (op) {
  148.     case '+':
  149.     case 'X':
  150.         set->cmd = op;
  151.         set->bits = (who ? who : mask) & oparg;
  152.         break;
  153.  
  154.     case '-':
  155.         set->cmd = '-';
  156.         set->bits = (who ? who : (S_IRWXU|S_IRWXG|S_IRWXO)) & oparg;
  157.         break;
  158.  
  159.     case '=':
  160.         set->cmd = '-';
  161.         if (!who) {
  162.             set->bits = STANDARD_BITS;
  163.             who = mask;
  164.         } else
  165.             set->bits = who;
  166.         set++;
  167.  
  168.         set->cmd = '+';
  169.         set->bits = who & oparg;
  170.         break;
  171.     case 'u':
  172.     case 'g':
  173.     case 'o':
  174.         set->cmd = op;
  175.         if (who) {
  176.             set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
  177.                     ((who & S_IRGRP) ? CMD2_GBITS : 0) |
  178.                     ((who & S_IROTH) ? CMD2_OBITS : 0);
  179.             set->bits = ~0;
  180.         } else {
  181.             set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
  182.             set->bits = mask;
  183.         }
  184.     
  185.         if (oparg == '+')
  186.             set->cmd2 |= CMD2_SET;
  187.         else if (oparg == '-')
  188.             set->cmd2 |= CMD2_CLR;
  189.         else if (oparg == '=')
  190.             set->cmd2 |= CMD2_SET|CMD2_CLR;
  191.         break;
  192.     }
  193.     return(set+1);
  194. }
  195.  
  196. #define    ADDCMD(a, b, c, d) \
  197.     if (set >= endset) { \
  198.         register struct bitcmd *newset; \
  199.         setlen += SET_LEN_INCR; \
  200.         newset = realloc(saveset, sizeof(struct bitcmd) * setlen); \
  201.         if (!saveset) \
  202.             return(NULL); \
  203.         set = newset + (set - saveset); \
  204.         saveset = newset; \
  205.         endset = newset + (setlen - 2); \
  206.     } \
  207.     set = addcmd(set, (a), (b), (c), (d))
  208.  
  209. void *
  210. setmode(p)
  211.     register char *p;
  212. {
  213.     register int perm, who;
  214.     register char op;
  215.     mode_t mask;
  216.     struct bitcmd *set, *saveset, *endset;
  217.     int permXbits, setlen;
  218.     static int compress_mode();
  219.  
  220.     /*
  221.      * Get a copy of the mask for the permissions that are mask relative.
  222.      * Flip the bits, we want what's not set.
  223.      */
  224.     (void)umask(mask = umask(0));
  225.     mask = ~mask;
  226.  
  227.     setlen = SET_LEN + 2;
  228.     
  229.     set = (struct bitcmd *)malloc((u_int)(sizeof(struct bitcmd) * setlen));
  230.     if (!set)
  231.         return(NULL);
  232.     saveset = set;
  233.     endset = set + (setlen - 2);
  234.  
  235.     /*
  236.      * If an absolute number, get it and return; disallow non-octal digits
  237.      * or illegal bits.
  238.      */
  239.     if (isdigit(*p)) {
  240.         perm = (mode_t)strtol(p, (char **)0, 8);
  241.         if (perm & ~(STANDARD_BITS|S_ISTXT)) {
  242.             free(saveset);
  243.             return(NULL);
  244.         }
  245.         while (*++p)
  246.             if (*p < '0' || *p > '7') {
  247.                 free(saveset);
  248.                 return(NULL);
  249.             }
  250.         ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
  251.         return((void *)saveset);
  252.     }
  253.  
  254.     if (!*p) {
  255.         free(saveset);
  256.         return(NULL);
  257.     }
  258.     /*
  259.      * Build list of structures to set/clear/copy bits as described by
  260.      * each clause of the symbolic mode.
  261.      */
  262.     for (;;) {
  263.         /* First, find out which bits might be modified. */
  264.         for (who = 0;; ++p) {
  265.             switch (*p) {
  266.             case 'a':
  267.                 who |= STANDARD_BITS;
  268.                 break;
  269.             case 'u':
  270.                 who |= S_ISUID|S_IRWXU;
  271.                 break;
  272.             case 'g':
  273.                 who |= S_ISGID|S_IRWXG;
  274.                 break;
  275.             case 'o':
  276.                 who |= S_IRWXO;
  277.                 break;
  278.             default:
  279.                 goto getop;
  280.             }
  281.         }
  282.     getop:        
  283.  
  284.         if ((op = *p++) != '+' && op != '-' && op != '=') {
  285.             free(saveset);
  286.             return(NULL);
  287.         }
  288.  
  289.         who &= ~S_ISTXT;
  290.         for (perm = 0, permXbits = 0;; ++p) {
  291.             switch (*p) {
  292.             case 'r':
  293.                 perm |= S_IRUSR|S_IRGRP|S_IROTH;
  294.                 break;
  295.             case 's':
  296.                 /* If only "other" bits ignore set-id. */
  297.                 if (who & ~S_IRWXO)
  298.                     perm |= S_ISUID|S_ISGID;
  299.                 break;
  300.             case 't':
  301.                 /* If only "other" bits ignore sticky. */
  302.                 if (who & ~S_IRWXO) {
  303.                     who |= S_ISTXT;
  304.                     perm |= S_ISTXT;
  305.                 }
  306.                 break;
  307.             case 'w':
  308.                 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
  309.                 break;
  310.             case 'X':
  311.                 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
  312.                 break;
  313.             case 'x':
  314.                 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
  315.                 break;
  316.             case 'u':
  317.             case 'g':
  318.             case 'o':
  319.                 /*
  320.                  * When ever we hit 'u', 'g', or 'o', we have
  321.                  * to flush out any partial mode that we have,
  322.                  * and then do the copying of the mode bits.
  323.                  */
  324.                 if (perm) {
  325.                     ADDCMD(op, who, perm, mask);
  326.                     perm = 0;
  327.                 }
  328.                 if (op == '+' && permXbits) {
  329.                     ADDCMD('X', who, permXbits, mask);
  330.                     permXbits = 0;
  331.                 }
  332.                 ADDCMD(*p, who, op, mask);
  333.                 break;
  334.  
  335.             default:
  336.                 /*
  337.                  * Add any permissions that we haven't already
  338.                  * done.
  339.                  */
  340.                 if (perm) {
  341.                     ADDCMD(op, who, perm, mask);
  342.                     perm = 0;
  343.                 }
  344.                 if (permXbits) {
  345.                     ADDCMD('X', who, permXbits, mask);
  346.                     permXbits = 0;
  347.                 }
  348.                 goto apply;
  349.             }
  350.         }
  351.  
  352. apply:        if (!*p)
  353.             break;
  354.         if (*p != ',')
  355.             goto getop;
  356.         ++p;
  357.     }
  358.     set->cmd = 0;
  359. #ifdef SETMODE_DEBUG
  360.     (void)printf("Before compress_mode()\n");
  361.     dumpmode(saveset);
  362. #endif
  363.     compress_mode(saveset);
  364. #ifdef SETMODE_DEBUG
  365.     (void)printf("After compress_mode()\n");
  366.     dumpmode(saveset);
  367. #endif
  368.     return((void *)saveset);
  369. }
  370.  
  371. #ifdef SETMODE_DEBUG
  372. dumpmode(set)
  373.     register struct bitcmd *set;
  374. {
  375.     for (; set->cmd; ++set)
  376.         (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
  377.             set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
  378.             set->cmd2 & CMD2_CLR ? " CLR" : "",
  379.             set->cmd2 & CMD2_SET ? " SET" : "",
  380.             set->cmd2 & CMD2_UBITS ? " UBITS" : "",
  381.             set->cmd2 & CMD2_GBITS ? " GBITS" : "",
  382.             set->cmd2 & CMD2_OBITS ? " OBITS" : "");
  383. }
  384. #endif
  385.  
  386. /*
  387.  * Given an array of bitcmd structures, compress by compacting consecutive
  388.  * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
  389.  * 'g' and 'o' commands continue to be separate.  They could probably be 
  390.  * compacted, but it's not worth the effort.
  391.  */
  392. static
  393. compress_mode(set)
  394.     register struct bitcmd *set;
  395. {
  396.     register struct bitcmd *nset;
  397.     register int setbits, clrbits, Xbits, op;
  398.  
  399.     for (nset = set;;) {
  400.         /* Copy over any 'u', 'g' and 'o' commands. */
  401.         while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
  402.             *set++ = *nset++;
  403.             if (!op)
  404.                 return;
  405.         }
  406.  
  407.         for (setbits = clrbits = Xbits = 0;; nset++) {
  408.             if ((op = nset->cmd) == '-') {
  409.                 clrbits |= nset->bits;
  410.                 setbits &= ~nset->bits;
  411.                 Xbits &= ~nset->bits;
  412.             } else if (op == '+') {
  413.                 setbits |= nset->bits;
  414.                 clrbits &= ~nset->bits;
  415.                 Xbits &= ~nset->bits;
  416.             } else if (op == 'X')
  417.                 Xbits |= nset->bits & ~setbits;
  418.             else
  419.                 break;
  420.         }
  421.         if (clrbits) {
  422.             set->cmd = '-';
  423.             set->cmd2 = 0;
  424.             set->bits = clrbits;
  425.             set++;
  426.         }
  427.         if (setbits) {
  428.             set->cmd = '+';
  429.             set->cmd2 = 0;
  430.             set->bits = setbits;
  431.             set++;
  432.         }
  433.         if (Xbits) {
  434.             set->cmd = 'X';
  435.             set->cmd2 = 0;
  436.             set->bits = Xbits;
  437.             set++;
  438.         }
  439.     }
  440. }
  441.