139978Sbostic /* 239978Sbostic * Copyright (c) 1989 The Regents of the University of California. 339978Sbostic * All rights reserved. 439978Sbostic * 5*42626Sbostic * %sccs.include.redist.c% 639978Sbostic */ 739978Sbostic 839978Sbostic #if defined(LIBC_SCCS) && !defined(lint) 9*42626Sbostic static char sccsid[] = "@(#)setmode.c 5.3 (Berkeley) 06/01/90"; 1039978Sbostic #endif /* LIBC_SCCS and not lint */ 1139978Sbostic 1239978Sbostic #include <sys/types.h> 1339978Sbostic #include <sys/stat.h> 1441579Sbostic #include <errno.h> 1541579Sbostic #include <stdio.h> 1639978Sbostic 1741579Sbostic #define setbits set[0] 1841579Sbostic #define clrbits set[1] 1941579Sbostic #define Xbits set[2] 2039978Sbostic 2139978Sbostic mode_t 2241579Sbostic getmode(set, omode) 2341579Sbostic mode_t *set, omode; 2439978Sbostic { 2539978Sbostic register mode_t newmode; 2639978Sbostic 2739978Sbostic newmode = omode & clrbits; 2839978Sbostic newmode |= setbits; 2939978Sbostic if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) 3039978Sbostic newmode |= Xbits; 3139978Sbostic return(newmode); 3239978Sbostic } 3339978Sbostic 3439978Sbostic #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 3539978Sbostic #define CLR(a) { clrbits |= a; setbits &= ~(a); Xbits &= ~(a); } 3639978Sbostic 3741579Sbostic mode_t * 3839978Sbostic setmode(p) 3939978Sbostic register char *p; 4039978Sbostic { 4141579Sbostic extern int errno; 4239978Sbostic register int perm, who; 4339978Sbostic register char op; 4441579Sbostic mode_t mask, *set; 4539978Sbostic int permXbits; 4641579Sbostic char *malloc(); 4739978Sbostic 4839978Sbostic /* 4939978Sbostic * get a copy of the mask for the permissions that are mask 5039978Sbostic * relative. Flip the bits, we want what's not set. 5139978Sbostic */ 5239978Sbostic (void)umask(mask = umask(0)); 5339978Sbostic mask = ~mask; 5439978Sbostic 5541579Sbostic if (!(set = (mode_t *)malloc((u_int)(sizeof(mode_t) * 3)))) { 5641579Sbostic errno = ENOMEM; 5741579Sbostic return(NULL); 5841579Sbostic } 5941579Sbostic 6039978Sbostic setbits = clrbits = Xbits = 0; 6139978Sbostic 6239978Sbostic /* 6339978Sbostic * if an absolute number, get it and return; disallow non-octal 6439978Sbostic * digits or illegal bits. 6539978Sbostic */ 6639978Sbostic if (isdigit(*p)) { 6739978Sbostic setbits = (mode_t)strtol(p, (char **)0, 8); 6839978Sbostic clrbits = ~(STANDARD_BITS|S_ISTXT); 6939978Sbostic Xbits = 0; 7039978Sbostic while (*++p) 7139978Sbostic if (*p < '0' || *p > '7') 7241579Sbostic return(NULL); 7339978Sbostic if (setbits & clrbits) 7441579Sbostic return(NULL); 7541579Sbostic return(set); 7639978Sbostic } 7739978Sbostic 7839978Sbostic if (!*p) 7941579Sbostic return(NULL); 8039978Sbostic /* 8139978Sbostic * accumulate bits to add and subtract from each clause of 8239978Sbostic * the symbolic mode 8339978Sbostic */ 8439978Sbostic for (;;) { 8539978Sbostic for (who = 0;; ++p) 8639978Sbostic switch (*p) { 8739978Sbostic case 'a': 8839978Sbostic who |= STANDARD_BITS; 8939978Sbostic break; 9039978Sbostic case 'u': 9139978Sbostic who |= S_ISUID|S_IRWXU; 9239978Sbostic break; 9339978Sbostic case 'g': 9439978Sbostic who |= S_ISGID|S_IRWXG; 9539978Sbostic break; 9639978Sbostic case 'o': 9739978Sbostic who |= S_IRWXO; 9839978Sbostic break; 9939978Sbostic default: 10039978Sbostic goto getop; 10139978Sbostic } 10239978Sbostic 10339978Sbostic getop: if ((op = *p++) != '+' && op != '-' && op != '=') 10441579Sbostic return(NULL); 10539978Sbostic 10639978Sbostic who &= ~S_ISTXT; 10739978Sbostic for (perm = 0;; ++p) 10839978Sbostic switch (*p) { 10939978Sbostic case 'r': 11039978Sbostic perm |= S_IRUSR|S_IRGRP|S_IROTH; 11139978Sbostic break; 11239978Sbostic case 's': 11339978Sbostic /* if only "other" bits ignore set-id */ 11439978Sbostic if (who & ~S_IRWXO) 11539978Sbostic perm |= S_ISUID|S_ISGID; 11639978Sbostic break; 11739978Sbostic case 't': 11839978Sbostic /* if only "other" bits ignore sticky */ 11939978Sbostic if (who & ~S_IRWXO) { 12039978Sbostic who |= S_ISTXT; 12139978Sbostic perm |= S_ISTXT; 12239978Sbostic } 12339978Sbostic break; 12439978Sbostic case 'w': 12539978Sbostic perm |= S_IWUSR|S_IWGRP|S_IWOTH; 12639978Sbostic break; 12739978Sbostic case 'X': 12839978Sbostic permXbits = S_IXUSR|S_IXGRP|S_IXOTH; 12939978Sbostic break; 13039978Sbostic case 'x': 13139978Sbostic perm |= S_IXUSR|S_IXGRP|S_IXOTH; 13239978Sbostic break; 13339978Sbostic default: 13439978Sbostic goto apply; 13539978Sbostic } 13639978Sbostic 13739978Sbostic apply: switch(op) { 13839978Sbostic case '+': 13939978Sbostic /* 14039978Sbostic * If no perm value, skip. If no who value, use umask 14139978Sbostic * bits. Don't bother clearing any bits, getmode 14239978Sbostic * clears first, then sets. 14339978Sbostic */ 14439978Sbostic if (perm || permXbits) { 14539978Sbostic if (!who) 14639978Sbostic who = mask; 14739978Sbostic if (permXbits) 14839978Sbostic Xbits |= who & permXbits; 14939978Sbostic setbits |= who & perm; 15039978Sbostic } 15139978Sbostic break; 15239978Sbostic case '-': 15339978Sbostic /* 15439978Sbostic * If no perm value, skip. If no who value, use 15539978Sbostic * owner, group, and other. 15639978Sbostic */ 15739978Sbostic if (perm) { 15839978Sbostic if (!who) 15939978Sbostic who = S_IRWXU|S_IRWXG|S_IRWXO; 16039978Sbostic CLR(who & perm); 16139978Sbostic } 16239978Sbostic break; 16339978Sbostic case '=': 16439978Sbostic /* 16539978Sbostic * If no who value, clear all the bits. Otherwise, 16639978Sbostic * clear the bits specified by who. 16739978Sbostic */ 16839978Sbostic if (!who) { 16939978Sbostic CLR(STANDARD_BITS); 17039978Sbostic who = mask; 17139978Sbostic } else 17239978Sbostic CLR(who); 17339978Sbostic if (perm) 17439978Sbostic setbits |= who & perm; 17539978Sbostic break; 17639978Sbostic } 17739978Sbostic 17839978Sbostic if (!*p) 17939978Sbostic break; 18039978Sbostic if (*p != ',') 18139978Sbostic goto getop; 18239978Sbostic ++p; 18339978Sbostic } 18439978Sbostic clrbits = ~clrbits; 18541579Sbostic return(set); 18639978Sbostic } 187