xref: /csrg-svn/lib/libc/gen/setmode.c (revision 41579)
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.2 (Berkeley) 05/10/90";
20 #endif /* LIBC_SCCS and not lint */
21 
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <errno.h>
25 #include <stdio.h>
26 
27 #define	setbits	set[0]
28 #define	clrbits	set[1]
29 #define	Xbits	set[2]
30 
31 mode_t
32 getmode(set, omode)
33 	mode_t *set, omode;
34 {
35 	register mode_t newmode;
36 
37 	newmode = omode & clrbits;
38 	newmode |= setbits;
39 	if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
40 		newmode |= Xbits;
41 	return(newmode);
42 }
43 
44 #define	STANDARD_BITS	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
45 #define	CLR(a)		{ clrbits |= a; setbits &= ~(a); Xbits &= ~(a); }
46 
47 mode_t *
48 setmode(p)
49 	register char *p;
50 {
51 	extern int errno;
52 	register int perm, who;
53 	register char op;
54 	mode_t mask, *set;
55 	int permXbits;
56 	char *malloc();
57 
58 	/*
59 	 * get a copy of the mask for the permissions that are mask
60 	 * relative.  Flip the bits, we want what's not set.
61 	 */
62 	(void)umask(mask = umask(0));
63 	mask = ~mask;
64 
65 	if (!(set = (mode_t *)malloc((u_int)(sizeof(mode_t) * 3)))) {
66 		errno = ENOMEM;
67 		return(NULL);
68 	}
69 
70 	setbits = clrbits = Xbits = 0;
71 
72 	/*
73 	 * if an absolute number, get it and return; disallow non-octal
74 	 * digits or illegal bits.
75 	 */
76 	if (isdigit(*p)) {
77 		setbits = (mode_t)strtol(p, (char **)0, 8);
78 		clrbits = ~(STANDARD_BITS|S_ISTXT);
79 		Xbits = 0;
80 		while (*++p)
81 			if (*p < '0' || *p > '7')
82 				return(NULL);
83 		if (setbits & clrbits)
84 			return(NULL);
85 		return(set);
86 	}
87 
88 	if (!*p)
89 		return(NULL);
90 	/*
91 	 * accumulate bits to add and subtract from each clause of
92 	 * the symbolic mode
93 	 */
94 	for (;;) {
95 		for (who = 0;; ++p)
96 			switch (*p) {
97 			case 'a':
98 				who |= STANDARD_BITS;
99 				break;
100 			case 'u':
101 				who |= S_ISUID|S_IRWXU;
102 				break;
103 			case 'g':
104 				who |= S_ISGID|S_IRWXG;
105 				break;
106 			case 'o':
107 				who |= S_IRWXO;
108 				break;
109 			default:
110 				goto getop;
111 			}
112 
113 getop:		if ((op = *p++) != '+' && op != '-' && op != '=')
114 			return(NULL);
115 
116 		who &= ~S_ISTXT;
117 		for (perm = 0;; ++p)
118 			switch (*p) {
119 			case 'r':
120 				perm |= S_IRUSR|S_IRGRP|S_IROTH;
121 				break;
122 			case 's':
123 				/* if only "other" bits ignore set-id */
124 				if (who & ~S_IRWXO)
125 					perm |= S_ISUID|S_ISGID;
126 				break;
127 			case 't':
128 				/* if only "other" bits ignore sticky */
129 				if (who & ~S_IRWXO) {
130 					who |= S_ISTXT;
131 					perm |= S_ISTXT;
132 				}
133 				break;
134 			case 'w':
135 				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
136 				break;
137 			case 'X':
138 				permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
139 				break;
140 			case 'x':
141 				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
142 				break;
143 			default:
144 				goto apply;
145 			}
146 
147 apply:		switch(op) {
148 		case '+':
149 			/*
150 			 * If no perm value, skip.  If no who value, use umask
151 			 * bits.  Don't bother clearing any bits, getmode
152 			 * clears first, then sets.
153 			 */
154 			if (perm || permXbits) {
155 				if (!who)
156 					who = mask;
157 				if (permXbits)
158 					Xbits |= who & permXbits;
159 				setbits |= who & perm;
160 			}
161 			break;
162 		case '-':
163 			/*
164 			 * If no perm value, skip.  If no who value, use
165 			 * owner, group, and other.
166 			 */
167 			if (perm) {
168 				if (!who)
169 					who = S_IRWXU|S_IRWXG|S_IRWXO;
170 				CLR(who & perm);
171 			}
172 			break;
173 		case '=':
174 			/*
175 			 * If no who value, clear all the bits.  Otherwise,
176 			 * clear the bits specified by who.
177 			 */
178 			if (!who) {
179 				CLR(STANDARD_BITS);
180 				who = mask;
181 			} else
182 				CLR(who);
183 			if (perm)
184 				setbits |= who & perm;
185 			break;
186 		}
187 
188 		if (!*p)
189 			break;
190 		if (*p != ',')
191 			goto getop;
192 		++p;
193 	}
194 	clrbits = ~clrbits;
195 	return(set);
196 }
197