]> git.saurik.com Git - apple/libc.git/blobdiff - gen/setmode-fbsd.c
Libc-583.tar.gz
[apple/libc.git] / gen / setmode-fbsd.c
deleted file mode 120000 (symlink)
index cb65fef7d0f929ca816c1a44285c3cfd3dffd76d..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-./setmode.c
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..6d06c821e8ed0f040fbb610ad044edbbca572601
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Dave Borman at Cray Research, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setmode.c  8.2 (Berkeley) 3/25/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/gen/setmode.c,v 1.9 2003/02/23 00:24:03 mikeh Exp $");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef SETMODE_DEBUG
+#include <stdio.h>
+#endif
+#include "un-namespace.h"
+
+#define        SET_LEN 6               /* initial # of bitcmd struct to malloc */
+#define        SET_LEN_INCR 4          /* # of bitcmd structs to add as needed */
+
+typedef struct bitcmd {
+       char    cmd;
+       char    cmd2;
+       mode_t  bits;
+} BITCMD;
+
+#define        CMD2_CLR        0x01
+#define        CMD2_SET        0x02
+#define        CMD2_GBITS      0x04
+#define        CMD2_OBITS      0x08
+#define        CMD2_UBITS      0x10
+
+#define        compress_mode   _sm_compress_mode
+
+static BITCMD  *addcmd(BITCMD *, int, int, int, u_int);
+__private_extern__ void                compress_mode(BITCMD *);
+#ifdef SETMODE_DEBUG
+static void     dumpmode(BITCMD *);
+#endif
+
+#ifndef BUILDING_VARIANT
+/*
+ * Given the old mode and an array of bitcmd structures, apply the operations
+ * described in the bitcmd structures to the old mode, and return the new mode.
+ * Note that there is no '=' command; a strict assignment is just a '-' (clear
+ * bits) followed by a '+' (set bits).
+ */
+mode_t
+getmode(bbox, omode)
+       const void *bbox;
+       mode_t omode;
+{
+       const BITCMD *set;
+       mode_t clrval, newmode, value;
+
+       set = (const BITCMD *)bbox;
+       newmode = omode;
+       for (value = 0;; set++)
+               switch(set->cmd) {
+               /*
+                * When copying the user, group or other bits around, we "know"
+                * where the bits are in the mode so that we can do shifts to
+                * copy them around.  If we don't use shifts, it gets real
+                * grundgy with lots of single bit checks and bit sets.
+                */
+               case 'u':
+                       value = (newmode & S_IRWXU) >> 6;
+                       goto common;
+
+               case 'g':
+                       value = (newmode & S_IRWXG) >> 3;
+                       goto common;
+
+               case 'o':
+                       value = newmode & S_IRWXO;
+common:                        if (set->cmd2 & CMD2_CLR) {
+                               clrval =
+                                   (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
+                               if (set->cmd2 & CMD2_UBITS)
+                                       newmode &= ~((clrval<<6) & set->bits);
+                               if (set->cmd2 & CMD2_GBITS)
+                                       newmode &= ~((clrval<<3) & set->bits);
+                               if (set->cmd2 & CMD2_OBITS)
+                                       newmode &= ~(clrval & set->bits);
+                       }
+                       if (set->cmd2 & CMD2_SET) {
+                               if (set->cmd2 & CMD2_UBITS)
+                                       newmode |= (value<<6) & set->bits;
+                               if (set->cmd2 & CMD2_GBITS)
+                                       newmode |= (value<<3) & set->bits;
+                               if (set->cmd2 & CMD2_OBITS)
+                                       newmode |= value & set->bits;
+                       }
+                       break;
+
+               case '+':
+                       newmode |= set->bits;
+                       break;
+
+               case '-':
+                       newmode &= ~set->bits;
+                       break;
+
+               case 'X':
+                       if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
+                               newmode |= set->bits;
+                       break;
+
+               case '\0':
+               default:
+#ifdef SETMODE_DEBUG
+                       (void)printf("getmode:%04o -> %04o\n", omode, newmode);
+#endif
+                       return (newmode);
+               }
+}
+#endif /* BUILDING_VARIANT */
+
+#define        ADDCMD(a, b, c, d)                                              \
+       if (set >= endset) {                                            \
+               BITCMD *newset;                                         \
+               setlen += SET_LEN_INCR;                                 \
+               newset = realloc(saveset, sizeof(BITCMD) * setlen);     \
+               if (!newset) {                                          \
+                       if (saveset)                                    \
+                               free(saveset);                          \
+                       saveset = NULL;                                 \
+                       return (NULL);                                  \
+               }                                                       \
+               set = newset + (set - saveset);                         \
+               saveset = newset;                                       \
+               endset = newset + (setlen - 2);                         \
+       }                                                               \
+       set = addcmd(set, (a), (b), (c), (d))
+
+#ifndef VARIANT_LEGACY
+#define        STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO|S_ISTXT)
+#else /* VARIANT_LEGACY */
+#define        STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
+#endif /* !VARIANT_LEGACY */
+
+void *
+setmode(p)
+       const char *p;
+{
+       int perm, who;
+       char op, *ep;
+       BITCMD *set, *saveset, *endset;
+       sigset_t sigset, sigoset;
+       mode_t mask;
+       int equalopdone=0, permXbits, setlen;
+       long perml;
+
+       if (!*p)
+               return (NULL);
+
+       /*
+        * Get a copy of the mask for the permissions that are mask relative.
+        * Flip the bits, we want what's not set.  Since it's possible that
+        * the caller is opening files inside a signal handler, protect them
+        * as best we can.
+        */
+       sigfillset(&sigset);
+        (void)_sigprocmask(SIG_BLOCK, &sigset, &sigoset);
+       (void)umask(mask = umask(0));
+       mask = ~mask;
+        (void)_sigprocmask(SIG_SETMASK, &sigoset, NULL);
+
+       setlen = SET_LEN + 2;
+
+       if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
+               return (NULL);
+       saveset = set;
+       endset = set + (setlen - 2);
+
+       /*
+        * If an absolute number, get it and return; disallow non-octal digits
+        * or illegal bits.
+        */
+       if (isdigit((unsigned char)*p)) {
+               perml = strtol(p, &ep, 8);
+#ifndef VARIANT_LEGACY
+               if (*ep || perml < 0 || perml & ~STANDARD_BITS)
+#else /* VARIANT_LEGACY */
+               if (*ep || perml < 0 || perml & ~(STANDARD_BITS|S_ISTXT))
+#endif /* !VARIANT_LEGACY */
+               {
+                       free(saveset);
+                       return (NULL);
+               }
+               perm = (mode_t)perml;
+#ifndef VARIANT_LEGACY
+               ADDCMD('=', STANDARD_BITS, perm, mask);
+#else /* VARIANT_LEGACY */
+               ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
+#endif /* !VARIANT_LEGACY */
+               set->cmd = 0;
+               return (saveset);
+       }
+
+       /*
+        * Build list of structures to set/clear/copy bits as described by
+        * each clause of the symbolic mode.
+        */
+       for (;;) {
+               /* First, find out which bits might be modified. */
+               for (who = 0;; ++p) {
+                       switch (*p) {
+                       case 'a':
+                               who |= STANDARD_BITS;
+                               break;
+                       case 'u':
+                               who |= S_ISUID|S_IRWXU;
+                               break;
+                       case 'g':
+                               who |= S_ISGID|S_IRWXG;
+                               break;
+                       case 'o':
+                               who |= S_IRWXO;
+                               break;
+                       default:
+                               goto getop;
+                       }
+               }
+
+getop:         if ((op = *p++) != '+' && op != '-' && op != '=') {
+                       free(saveset);
+                       return (NULL);
+               }
+               if (op == '=')
+                       equalopdone = 0;
+
+#ifdef VARIANT_LEGACY
+               who &= ~S_ISTXT;
+#endif /* VARIANT_LEGACY */
+               for (perm = 0, permXbits = 0;; ++p) {
+                       switch (*p) {
+                       case 'r':
+                               perm |= S_IRUSR|S_IRGRP|S_IROTH;
+                               break;
+                       case 's':
+                               /* If only "other" bits ignore set-id. */
+                               if (!who || who & ~S_IRWXO)
+                                       perm |= S_ISUID|S_ISGID;
+                               break;
+                       case 't':
+                               /* If only "other" bits ignore sticky. */
+                               if (!who || who & ~S_IRWXO) {
+#ifdef VARIANT_LEGACY
+                                       who |= S_ISTXT;
+#endif /* VARIANT_LEGACY */
+                                       perm |= S_ISTXT;
+                               }
+                               break;
+                       case 'w':
+                               perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+                               break;
+                       case 'X':
+                               permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
+                               break;
+                       case 'x':
+                               perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+                               break;
+                       case 'u':
+                       case 'g':
+                       case 'o':
+                               /*
+                                * When ever we hit 'u', 'g', or 'o', we have
+                                * to flush out any partial mode that we have,
+                                * and then do the copying of the mode bits.
+                                */
+                               if (perm) {
+                                       ADDCMD(op, who, perm, mask);
+                                       perm = 0;
+                               }
+                               if (op == '=')
+                                       equalopdone = 1;
+                               if (op == '+' && permXbits) {
+                                       ADDCMD('X', who, permXbits, mask);
+                                       permXbits = 0;
+                               }
+                               ADDCMD(*p, who, op, mask);
+                               break;
+
+                       default:
+                               /*
+                                * Add any permissions that we haven't already
+                                * done.
+                                */
+                               if (perm || (op == '=' && !equalopdone)) {
+                                       if (op == '=')
+                                               equalopdone = 1;
+                                       ADDCMD(op, who, perm, mask);
+                                       perm = 0;
+                               }
+                               if (permXbits) {
+                                       ADDCMD('X', who, permXbits, mask);
+                                       permXbits = 0;
+                               }
+                               goto apply;
+                       }
+               }
+
+apply:         if (!*p)
+                       break;
+               if (*p != ',')
+                       goto getop;
+               ++p;
+       }
+       set->cmd = 0;
+#ifdef SETMODE_DEBUG
+       (void)printf("Before compress_mode()\n");
+       dumpmode(saveset);
+#endif
+       compress_mode(saveset);
+#ifdef SETMODE_DEBUG
+       (void)printf("After compress_mode()\n");
+       dumpmode(saveset);
+#endif
+       return (saveset);
+}
+
+static BITCMD *
+addcmd(set, op, who, oparg, mask)
+       BITCMD *set;
+       int oparg, who;
+       int op;
+       u_int mask;
+{
+       switch (op) {
+       case '=':
+               set->cmd = '-';
+               set->bits = who ? who : STANDARD_BITS;
+               set++;
+
+               op = '+';
+               /* FALLTHROUGH */
+       case '+':
+       case '-':
+       case 'X':
+               set->cmd = op;
+               set->bits = (who ? who : mask) & oparg;
+               break;
+
+       case 'u':
+       case 'g':
+       case 'o':
+               set->cmd = op;
+               if (who) {
+                       set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
+                                   ((who & S_IRGRP) ? CMD2_GBITS : 0) |
+                                   ((who & S_IROTH) ? CMD2_OBITS : 0);
+                       set->bits = (mode_t)~0;
+               } else {
+                       set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
+                       set->bits = mask;
+               }
+
+               if (oparg == '+')
+                       set->cmd2 |= CMD2_SET;
+               else if (oparg == '-')
+                       set->cmd2 |= CMD2_CLR;
+               else if (oparg == '=')
+                       set->cmd2 |= CMD2_SET|CMD2_CLR;
+               break;
+       }
+       return (set + 1);
+}
+
+#ifdef SETMODE_DEBUG
+static void
+dumpmode(set)
+       BITCMD *set;
+{
+       for (; set->cmd; ++set)
+               (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
+                   set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
+                   set->cmd2 & CMD2_CLR ? " CLR" : "",
+                   set->cmd2 & CMD2_SET ? " SET" : "",
+                   set->cmd2 & CMD2_UBITS ? " UBITS" : "",
+                   set->cmd2 & CMD2_GBITS ? " GBITS" : "",
+                   set->cmd2 & CMD2_OBITS ? " OBITS" : "");
+}
+#endif
+
+#ifndef BUILDING_VARIANT
+/*
+ * Given an array of bitcmd structures, compress by compacting consecutive
+ * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
+ * 'g' and 'o' commands continue to be separate.  They could probably be
+ * compacted, but it's not worth the effort.
+ */
+__private_extern__ void
+compress_mode(set)
+       BITCMD *set;
+{
+       BITCMD *nset;
+       int setbits, clrbits, Xbits, op;
+
+       for (nset = set;;) {
+               /* Copy over any 'u', 'g' and 'o' commands. */
+               while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
+                       *set++ = *nset++;
+                       if (!op)
+                               return;
+               }
+
+               for (setbits = clrbits = Xbits = 0;; nset++) {
+                       if ((op = nset->cmd) == '-') {
+                               clrbits |= nset->bits;
+                               setbits &= ~nset->bits;
+                               Xbits &= ~nset->bits;
+                       } else if (op == '+') {
+                               setbits |= nset->bits;
+                               clrbits &= ~nset->bits;
+                               Xbits &= ~nset->bits;
+                       } else if (op == 'X')
+                               Xbits |= nset->bits & ~setbits;
+                       else
+                               break;
+               }
+               if (clrbits) {
+                       set->cmd = '-';
+                       set->cmd2 = 0;
+                       set->bits = clrbits;
+                       set++;
+               }
+               if (setbits) {
+                       set->cmd = '+';
+                       set->cmd2 = 0;
+                       set->bits = setbits;
+                       set++;
+               }
+               if (Xbits) {
+                       set->cmd = 'X';
+                       set->cmd2 = 0;
+                       set->bits = Xbits;
+                       set++;
+               }
+       }
+}
+#endif /* BUILDING_VARIANT */