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