xref: /csrg-svn/lib/libc/gen/setmode.c (revision 41579)
139978Sbostic /*
239978Sbostic  * Copyright (c) 1989 The Regents of the University of California.
339978Sbostic  * All rights reserved.
439978Sbostic  *
539978Sbostic  * Redistribution and use in source and binary forms are permitted
639978Sbostic  * provided that the above copyright notice and this paragraph are
739978Sbostic  * duplicated in all such forms and that any documentation,
839978Sbostic  * advertising materials, and other materials related to such
939978Sbostic  * distribution and use acknowledge that the software was developed
1039978Sbostic  * by the University of California, Berkeley.  The name of the
1139978Sbostic  * University may not be used to endorse or promote products derived
1239978Sbostic  * from this software without specific prior written permission.
1339978Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1439978Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1539978Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1639978Sbostic  */
1739978Sbostic 
1839978Sbostic #if defined(LIBC_SCCS) && !defined(lint)
19*41579Sbostic static char sccsid[] = "@(#)setmode.c	5.2 (Berkeley) 05/10/90";
2039978Sbostic #endif /* LIBC_SCCS and not lint */
2139978Sbostic 
2239978Sbostic #include <sys/types.h>
2339978Sbostic #include <sys/stat.h>
24*41579Sbostic #include <errno.h>
25*41579Sbostic #include <stdio.h>
2639978Sbostic 
27*41579Sbostic #define	setbits	set[0]
28*41579Sbostic #define	clrbits	set[1]
29*41579Sbostic #define	Xbits	set[2]
3039978Sbostic 
3139978Sbostic mode_t
32*41579Sbostic getmode(set, omode)
33*41579Sbostic 	mode_t *set, omode;
3439978Sbostic {
3539978Sbostic 	register mode_t newmode;
3639978Sbostic 
3739978Sbostic 	newmode = omode & clrbits;
3839978Sbostic 	newmode |= setbits;
3939978Sbostic 	if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
4039978Sbostic 		newmode |= Xbits;
4139978Sbostic 	return(newmode);
4239978Sbostic }
4339978Sbostic 
4439978Sbostic #define	STANDARD_BITS	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
4539978Sbostic #define	CLR(a)		{ clrbits |= a; setbits &= ~(a); Xbits &= ~(a); }
4639978Sbostic 
47*41579Sbostic mode_t *
4839978Sbostic setmode(p)
4939978Sbostic 	register char *p;
5039978Sbostic {
51*41579Sbostic 	extern int errno;
5239978Sbostic 	register int perm, who;
5339978Sbostic 	register char op;
54*41579Sbostic 	mode_t mask, *set;
5539978Sbostic 	int permXbits;
56*41579Sbostic 	char *malloc();
5739978Sbostic 
5839978Sbostic 	/*
5939978Sbostic 	 * get a copy of the mask for the permissions that are mask
6039978Sbostic 	 * relative.  Flip the bits, we want what's not set.
6139978Sbostic 	 */
6239978Sbostic 	(void)umask(mask = umask(0));
6339978Sbostic 	mask = ~mask;
6439978Sbostic 
65*41579Sbostic 	if (!(set = (mode_t *)malloc((u_int)(sizeof(mode_t) * 3)))) {
66*41579Sbostic 		errno = ENOMEM;
67*41579Sbostic 		return(NULL);
68*41579Sbostic 	}
69*41579Sbostic 
7039978Sbostic 	setbits = clrbits = Xbits = 0;
7139978Sbostic 
7239978Sbostic 	/*
7339978Sbostic 	 * if an absolute number, get it and return; disallow non-octal
7439978Sbostic 	 * digits or illegal bits.
7539978Sbostic 	 */
7639978Sbostic 	if (isdigit(*p)) {
7739978Sbostic 		setbits = (mode_t)strtol(p, (char **)0, 8);
7839978Sbostic 		clrbits = ~(STANDARD_BITS|S_ISTXT);
7939978Sbostic 		Xbits = 0;
8039978Sbostic 		while (*++p)
8139978Sbostic 			if (*p < '0' || *p > '7')
82*41579Sbostic 				return(NULL);
8339978Sbostic 		if (setbits & clrbits)
84*41579Sbostic 			return(NULL);
85*41579Sbostic 		return(set);
8639978Sbostic 	}
8739978Sbostic 
8839978Sbostic 	if (!*p)
89*41579Sbostic 		return(NULL);
9039978Sbostic 	/*
9139978Sbostic 	 * accumulate bits to add and subtract from each clause of
9239978Sbostic 	 * the symbolic mode
9339978Sbostic 	 */
9439978Sbostic 	for (;;) {
9539978Sbostic 		for (who = 0;; ++p)
9639978Sbostic 			switch (*p) {
9739978Sbostic 			case 'a':
9839978Sbostic 				who |= STANDARD_BITS;
9939978Sbostic 				break;
10039978Sbostic 			case 'u':
10139978Sbostic 				who |= S_ISUID|S_IRWXU;
10239978Sbostic 				break;
10339978Sbostic 			case 'g':
10439978Sbostic 				who |= S_ISGID|S_IRWXG;
10539978Sbostic 				break;
10639978Sbostic 			case 'o':
10739978Sbostic 				who |= S_IRWXO;
10839978Sbostic 				break;
10939978Sbostic 			default:
11039978Sbostic 				goto getop;
11139978Sbostic 			}
11239978Sbostic 
11339978Sbostic getop:		if ((op = *p++) != '+' && op != '-' && op != '=')
114*41579Sbostic 			return(NULL);
11539978Sbostic 
11639978Sbostic 		who &= ~S_ISTXT;
11739978Sbostic 		for (perm = 0;; ++p)
11839978Sbostic 			switch (*p) {
11939978Sbostic 			case 'r':
12039978Sbostic 				perm |= S_IRUSR|S_IRGRP|S_IROTH;
12139978Sbostic 				break;
12239978Sbostic 			case 's':
12339978Sbostic 				/* if only "other" bits ignore set-id */
12439978Sbostic 				if (who & ~S_IRWXO)
12539978Sbostic 					perm |= S_ISUID|S_ISGID;
12639978Sbostic 				break;
12739978Sbostic 			case 't':
12839978Sbostic 				/* if only "other" bits ignore sticky */
12939978Sbostic 				if (who & ~S_IRWXO) {
13039978Sbostic 					who |= S_ISTXT;
13139978Sbostic 					perm |= S_ISTXT;
13239978Sbostic 				}
13339978Sbostic 				break;
13439978Sbostic 			case 'w':
13539978Sbostic 				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
13639978Sbostic 				break;
13739978Sbostic 			case 'X':
13839978Sbostic 				permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
13939978Sbostic 				break;
14039978Sbostic 			case 'x':
14139978Sbostic 				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
14239978Sbostic 				break;
14339978Sbostic 			default:
14439978Sbostic 				goto apply;
14539978Sbostic 			}
14639978Sbostic 
14739978Sbostic apply:		switch(op) {
14839978Sbostic 		case '+':
14939978Sbostic 			/*
15039978Sbostic 			 * If no perm value, skip.  If no who value, use umask
15139978Sbostic 			 * bits.  Don't bother clearing any bits, getmode
15239978Sbostic 			 * clears first, then sets.
15339978Sbostic 			 */
15439978Sbostic 			if (perm || permXbits) {
15539978Sbostic 				if (!who)
15639978Sbostic 					who = mask;
15739978Sbostic 				if (permXbits)
15839978Sbostic 					Xbits |= who & permXbits;
15939978Sbostic 				setbits |= who & perm;
16039978Sbostic 			}
16139978Sbostic 			break;
16239978Sbostic 		case '-':
16339978Sbostic 			/*
16439978Sbostic 			 * If no perm value, skip.  If no who value, use
16539978Sbostic 			 * owner, group, and other.
16639978Sbostic 			 */
16739978Sbostic 			if (perm) {
16839978Sbostic 				if (!who)
16939978Sbostic 					who = S_IRWXU|S_IRWXG|S_IRWXO;
17039978Sbostic 				CLR(who & perm);
17139978Sbostic 			}
17239978Sbostic 			break;
17339978Sbostic 		case '=':
17439978Sbostic 			/*
17539978Sbostic 			 * If no who value, clear all the bits.  Otherwise,
17639978Sbostic 			 * clear the bits specified by who.
17739978Sbostic 			 */
17839978Sbostic 			if (!who) {
17939978Sbostic 				CLR(STANDARD_BITS);
18039978Sbostic 				who = mask;
18139978Sbostic 			} else
18239978Sbostic 				CLR(who);
18339978Sbostic 			if (perm)
18439978Sbostic 				setbits |= who & perm;
18539978Sbostic 			break;
18639978Sbostic 		}
18739978Sbostic 
18839978Sbostic 		if (!*p)
18939978Sbostic 			break;
19039978Sbostic 		if (*p != ',')
19139978Sbostic 			goto getop;
19239978Sbostic 		++p;
19339978Sbostic 	}
19439978Sbostic 	clrbits = ~clrbits;
195*41579Sbostic 	return(set);
19639978Sbostic }
197