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