make error messages a little better, use constants in unistd.h
[unix-history] / usr / src / lib / libc / gen / setmode.c
CommitLineData
0dfc069b
KB
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
269a7923 5 * %sccs.include.redist.c%
0dfc069b
KB
6 */
7
8#if defined(LIBC_SCCS) && !defined(lint)
269a7923 9static char sccsid[] = "@(#)setmode.c 5.3 (Berkeley) %G%";
0dfc069b
KB
10#endif /* LIBC_SCCS and not lint */
11
12#include <sys/types.h>
13#include <sys/stat.h>
840c650e
KB
14#include <errno.h>
15#include <stdio.h>
0dfc069b 16
840c650e
KB
17#define setbits set[0]
18#define clrbits set[1]
19#define Xbits set[2]
0dfc069b
KB
20
21mode_t
840c650e
KB
22getmode(set, omode)
23 mode_t *set, omode;
0dfc069b
KB
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
840c650e 37mode_t *
0dfc069b
KB
38setmode(p)
39 register char *p;
40{
840c650e 41 extern int errno;
0dfc069b
KB
42 register int perm, who;
43 register char op;
840c650e 44 mode_t mask, *set;
0dfc069b 45 int permXbits;
840c650e 46 char *malloc();
0dfc069b
KB
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
840c650e
KB
55 if (!(set = (mode_t *)malloc((u_int)(sizeof(mode_t) * 3)))) {
56 errno = ENOMEM;
57 return(NULL);
58 }
59
0dfc069b
KB
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')
840c650e 72 return(NULL);
0dfc069b 73 if (setbits & clrbits)
840c650e
KB
74 return(NULL);
75 return(set);
0dfc069b
KB
76 }
77
78 if (!*p)
840c650e 79 return(NULL);
0dfc069b
KB
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
103getop: if ((op = *p++) != '+' && op != '-' && op != '=')
840c650e 104 return(NULL);
0dfc069b
KB
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
137apply: 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;
840c650e 185 return(set);
0dfc069b 186}