xref: /csrg-svn/lib/libc/gen/setmode.c (revision 39978)
1*39978Sbostic /*
2*39978Sbostic  * Copyright (c) 1989 The Regents of the University of California.
3*39978Sbostic  * All rights reserved.
4*39978Sbostic  *
5*39978Sbostic  * Redistribution and use in source and binary forms are permitted
6*39978Sbostic  * provided that the above copyright notice and this paragraph are
7*39978Sbostic  * duplicated in all such forms and that any documentation,
8*39978Sbostic  * advertising materials, and other materials related to such
9*39978Sbostic  * distribution and use acknowledge that the software was developed
10*39978Sbostic  * by the University of California, Berkeley.  The name of the
11*39978Sbostic  * University may not be used to endorse or promote products derived
12*39978Sbostic  * from this software without specific prior written permission.
13*39978Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*39978Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*39978Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*39978Sbostic  */
17*39978Sbostic 
18*39978Sbostic #if defined(LIBC_SCCS) && !defined(lint)
19*39978Sbostic static char sccsid[] = "@(#)setmode.c	5.1 (Berkeley) 02/01/90";
20*39978Sbostic #endif /* LIBC_SCCS and not lint */
21*39978Sbostic 
22*39978Sbostic #include <sys/types.h>
23*39978Sbostic #include <sys/stat.h>
24*39978Sbostic 
25*39978Sbostic static mode_t setbits, clrbits, Xbits;
26*39978Sbostic 
27*39978Sbostic mode_t
28*39978Sbostic getmode(omode)
29*39978Sbostic 	mode_t omode;
30*39978Sbostic {
31*39978Sbostic 	register mode_t newmode;
32*39978Sbostic 
33*39978Sbostic 	newmode = omode & clrbits;
34*39978Sbostic 	newmode |= setbits;
35*39978Sbostic 	if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
36*39978Sbostic 		newmode |= Xbits;
37*39978Sbostic 	return(newmode);
38*39978Sbostic }
39*39978Sbostic 
40*39978Sbostic #define	STANDARD_BITS	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
41*39978Sbostic #define	CLR(a)		{ clrbits |= a; setbits &= ~(a); Xbits &= ~(a); }
42*39978Sbostic 
43*39978Sbostic setmode(p)
44*39978Sbostic 	register char *p;
45*39978Sbostic {
46*39978Sbostic 	register int perm, who;
47*39978Sbostic 	register char op;
48*39978Sbostic 	mode_t mask;
49*39978Sbostic 	int permXbits;
50*39978Sbostic 
51*39978Sbostic 	/*
52*39978Sbostic 	 * get a copy of the mask for the permissions that are mask
53*39978Sbostic 	 * relative.  Flip the bits, we want what's not set.
54*39978Sbostic 	 */
55*39978Sbostic 	(void)umask(mask = umask(0));
56*39978Sbostic 	mask = ~mask;
57*39978Sbostic 
58*39978Sbostic 	setbits = clrbits = Xbits = 0;
59*39978Sbostic 
60*39978Sbostic 	/*
61*39978Sbostic 	 * if an absolute number, get it and return; disallow non-octal
62*39978Sbostic 	 * digits or illegal bits.
63*39978Sbostic 	 */
64*39978Sbostic 	if (isdigit(*p)) {
65*39978Sbostic 		setbits = (mode_t)strtol(p, (char **)0, 8);
66*39978Sbostic 		clrbits = ~(STANDARD_BITS|S_ISTXT);
67*39978Sbostic 		Xbits = 0;
68*39978Sbostic 		while (*++p)
69*39978Sbostic 			if (*p < '0' || *p > '7')
70*39978Sbostic 				return(-1);
71*39978Sbostic 		if (setbits & clrbits)
72*39978Sbostic 			return(-1);
73*39978Sbostic 		return(0);
74*39978Sbostic 	}
75*39978Sbostic 
76*39978Sbostic 	if (!*p)
77*39978Sbostic 		return(-1);
78*39978Sbostic 	/*
79*39978Sbostic 	 * accumulate bits to add and subtract from each clause of
80*39978Sbostic 	 * the symbolic mode
81*39978Sbostic 	 */
82*39978Sbostic 	for (;;) {
83*39978Sbostic 		for (who = 0;; ++p)
84*39978Sbostic 			switch (*p) {
85*39978Sbostic 			case 'a':
86*39978Sbostic 				who |= STANDARD_BITS;
87*39978Sbostic 				break;
88*39978Sbostic 			case 'u':
89*39978Sbostic 				who |= S_ISUID|S_IRWXU;
90*39978Sbostic 				break;
91*39978Sbostic 			case 'g':
92*39978Sbostic 				who |= S_ISGID|S_IRWXG;
93*39978Sbostic 				break;
94*39978Sbostic 			case 'o':
95*39978Sbostic 				who |= S_IRWXO;
96*39978Sbostic 				break;
97*39978Sbostic 			default:
98*39978Sbostic 				goto getop;
99*39978Sbostic 			}
100*39978Sbostic 
101*39978Sbostic getop:		if ((op = *p++) != '+' && op != '-' && op != '=')
102*39978Sbostic 			return(-1);
103*39978Sbostic 
104*39978Sbostic 		who &= ~S_ISTXT;
105*39978Sbostic 		for (perm = 0;; ++p)
106*39978Sbostic 			switch (*p) {
107*39978Sbostic 			case 'r':
108*39978Sbostic 				perm |= S_IRUSR|S_IRGRP|S_IROTH;
109*39978Sbostic 				break;
110*39978Sbostic 			case 's':
111*39978Sbostic 				/* if only "other" bits ignore set-id */
112*39978Sbostic 				if (who & ~S_IRWXO)
113*39978Sbostic 					perm |= S_ISUID|S_ISGID;
114*39978Sbostic 				break;
115*39978Sbostic 			case 't':
116*39978Sbostic 				/* if only "other" bits ignore sticky */
117*39978Sbostic 				if (who & ~S_IRWXO) {
118*39978Sbostic 					who |= S_ISTXT;
119*39978Sbostic 					perm |= S_ISTXT;
120*39978Sbostic 				}
121*39978Sbostic 				break;
122*39978Sbostic 			case 'w':
123*39978Sbostic 				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
124*39978Sbostic 				break;
125*39978Sbostic 			case 'X':
126*39978Sbostic 				permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
127*39978Sbostic 				break;
128*39978Sbostic 			case 'x':
129*39978Sbostic 				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
130*39978Sbostic 				break;
131*39978Sbostic 			default:
132*39978Sbostic 				goto apply;
133*39978Sbostic 			}
134*39978Sbostic 
135*39978Sbostic apply:		switch(op) {
136*39978Sbostic 		case '+':
137*39978Sbostic 			/*
138*39978Sbostic 			 * If no perm value, skip.  If no who value, use umask
139*39978Sbostic 			 * bits.  Don't bother clearing any bits, getmode
140*39978Sbostic 			 * clears first, then sets.
141*39978Sbostic 			 */
142*39978Sbostic 			if (perm || permXbits) {
143*39978Sbostic 				if (!who)
144*39978Sbostic 					who = mask;
145*39978Sbostic 				if (permXbits)
146*39978Sbostic 					Xbits |= who & permXbits;
147*39978Sbostic 				setbits |= who & perm;
148*39978Sbostic 			}
149*39978Sbostic 			break;
150*39978Sbostic 		case '-':
151*39978Sbostic 			/*
152*39978Sbostic 			 * If no perm value, skip.  If no who value, use
153*39978Sbostic 			 * owner, group, and other.
154*39978Sbostic 			 */
155*39978Sbostic 			if (perm) {
156*39978Sbostic 				if (!who)
157*39978Sbostic 					who = S_IRWXU|S_IRWXG|S_IRWXO;
158*39978Sbostic 				CLR(who & perm);
159*39978Sbostic 			}
160*39978Sbostic 			break;
161*39978Sbostic 		case '=':
162*39978Sbostic 			/*
163*39978Sbostic 			 * If no who value, clear all the bits.  Otherwise,
164*39978Sbostic 			 * clear the bits specified by who.
165*39978Sbostic 			 */
166*39978Sbostic 			if (!who) {
167*39978Sbostic 				CLR(STANDARD_BITS);
168*39978Sbostic 				who = mask;
169*39978Sbostic 			} else
170*39978Sbostic 				CLR(who);
171*39978Sbostic 			if (perm)
172*39978Sbostic 				setbits |= who & perm;
173*39978Sbostic 			break;
174*39978Sbostic 		}
175*39978Sbostic 
176*39978Sbostic 		if (!*p)
177*39978Sbostic 			break;
178*39978Sbostic 		if (*p != ',')
179*39978Sbostic 			goto getop;
180*39978Sbostic 		++p;
181*39978Sbostic 	}
182*39978Sbostic 	clrbits = ~clrbits;
183*39978Sbostic 	return(0);
184*39978Sbostic }
185