xref: /csrg-svn/lib/libc/gen/setmode.c (revision 42626)
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