Version bump.
[fwd] / fattr.c
1 /* -*-c-*-
2 *
3 * $Id: fattr.c,v 1.3 2002/01/13 14:50:22 mdw Exp $
4 *
5 * Handling of file attributes
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the `fw' port forwarder.
13 *
14 * `fw' is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * `fw' is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with `fw'; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29 /*----- Revision history --------------------------------------------------*
30 *
31 * $Log: fattr.c,v $
32 * Revision 1.3 2002/01/13 14:50:22 mdw
33 * Delimiter-setting function names change.
34 *
35 * Revision 1.2 1999/08/19 18:32:48 mdw
36 * Improve lexical analysis. In particular, `chmod' patterns don't have to
37 * be quoted any more.
38 *
39 * Revision 1.1 1999/07/26 23:33:56 mdw
40 * Support code for new design.
41 *
42 */
43
44 /*----- Header files ------------------------------------------------------*/
45
46 #include "config.h"
47
48 #include <ctype.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <unistd.h>
57
58 #include <pwd.h>
59 #include <grp.h>
60
61 #include "conf.h"
62 #include "fattr.h"
63 #include "scan.h"
64
65 /*----- Global variables --------------------------------------------------*/
66
67 fattr fattr_global;
68
69 /*----- Main code ---------------------------------------------------------*/
70
71 /* --- @fattr_init@ --- *
72 *
73 * Arguments: @fattr *f@ = pointer to file attributes
74 *
75 * Returns: ---
76 *
77 * Use: Initializes a set of file attributes to default values.
78 */
79
80 void fattr_init(fattr *f)
81 {
82 unsigned um = umask(0);
83 umask(um);
84 f->mode = 0666 & ~um;
85 f->uid = -1;
86 f->gid = -1;
87 }
88
89 /* --- @fattr_option@ --- *
90 *
91 * Arguments: @scanner *sc@ = pointer to scanner to read
92 * @fattr *f@ = pointer to file attributes to set
93 *
94 * Returns: Whether the option was claimed.
95 *
96 * Use: Reads file attributes from a scanner.
97 */
98
99 int fattr_option(scanner *sc, fattr *f)
100 {
101 CONF_BEGIN(sc, "fattr", "file attribute")
102
103 /* --- Read a file mode specification --- */
104
105 if (strcmp(sc->d.buf, "mode") == 0) {
106 unsigned mode = 0;
107
108 /* --- Gobble an optional `=' sign --- */
109
110 conf_undelim(sc, 0, ",=+-");
111 token(sc);
112 if (sc->t == '=')
113 token(sc);
114
115 if (sc->t != CTOK_WORD)
116 error(sc, "parse error, expected file mode");
117 conf_undelim(sc, 0, 0);
118
119 /* --- If it looks digitlike, read as octal --- */
120
121 if (isdigit((unsigned char)*sc->d.buf))
122 mode = strtoul(sc->d.buf, 0, 8) & 07777;
123
124 /* --- Otherise read as chmod-like characters --- */
125
126 else {
127 const char *p;
128 unsigned mask = 04700;
129 unsigned state = 0;
130 unsigned or = 1;
131
132 /* --- Set the default from the umask --- */
133
134 {
135 unsigned um = umask(0);
136 umask(um);
137 mode = 0666 & ~um;
138 }
139
140 /* --- Parse the characters --- *
141 *
142 * This is a particularly lenient implementation of the usual chmod-
143 * style mode language.
144 */
145
146 for (p = sc->d.buf; *p; p++) {
147 switch (*p) {
148 case ',': break;
149
150 case 'a': mask = (mask & state) | 07777; state = 07777; break;
151 case 'u': mask = (mask & state) | 04700; state = 07777; break;
152 case 'g': mask = (mask & state) | 02070; state = 07777; break;
153 case 'o': mask = (mask & state) | 01007; state = 07777; break;
154
155 case '=': mode &= ~mask; /* Drop through */
156 case '+': state = 0; or = 1; break;
157 case '-': state = 0; or = 0; break;
158
159 #define APPLY(m) if (or) mode |= ((m) & mask); else mode &= ~((m) & mask);
160 case 'r': state = 0; APPLY(00444); break;
161 case 'w': state = 0; APPLY(00222); break;
162 case 'x': state = 0; APPLY(00111); break;
163 case 's': state = 0; APPLY(06000); break;
164 case 't': state = 0; APPLY(01000); break;
165 #undef APPLY
166
167 default: error(sc, "unknown mode character `%c'", *p);
168 }
169 }
170 }
171
172 token(sc);
173 f->mode = mode;
174 CONF_ACCEPT;
175 }
176
177 /* --- Read a file uid specification --- */
178
179 if (strcmp(sc->d.buf, "uid") == 0 ||
180 strcmp(sc->d.buf, "user") == 0 ||
181 strcmp(sc->d.buf, "owner") == 0) {
182 token(sc);
183 if (sc->t == '=')
184 token(sc);
185 if (sc->t != CTOK_WORD)
186 error(sc, "parse error, expected user name or uid");
187 if (isdigit((unsigned char)*sc->d.buf))
188 f->uid = atoi(sc->d.buf);
189 else {
190 struct passwd *pw = getpwnam(sc->d.buf);
191 if (!pw)
192 error(sc, "unknown user name `%s'", sc->d.buf);
193 f->uid = pw->pw_uid;
194 }
195 token(sc);
196 CONF_ACCEPT;
197 }
198
199 /* --- Read a file gid specification --- */
200
201 if (strcmp(sc->d.buf, "gid") == 0 ||
202 strcmp(sc->d.buf, "group") == 0) {
203 token(sc);
204 if (sc->t == '=')
205 token(sc);
206 if (sc->t != CTOK_WORD)
207 error(sc, "parse error, expected group name or gid");
208 if (isdigit((unsigned char)*sc->d.buf))
209 f->gid = atoi(sc->d.buf);
210 else {
211 struct group *gr = getgrnam(sc->d.buf);
212 if (!gr)
213 error(sc, "unknown user name `%s'", sc->d.buf);
214 f->gid = gr->gr_gid;
215 }
216 token(sc);
217 CONF_ACCEPT;
218 }
219
220 /* --- Nothing here for me --- */
221
222 CONF_END;
223 }
224
225 /* --- @fattr_apply@ --- *
226 *
227 * Arguments: @const char *file@ = pointer to filename
228 * @fattr *f@ = pointer to attribute set
229 *
230 * Returns: @-1@ if it failed.
231 *
232 * Use: Applies file attributes to a file. For best results, try to
233 * create the file with the right permissions and so on. This
234 * call will fix everything up, but there are potential races
235 * which might catch you out if you're not careful.
236 */
237
238 int fattr_apply(const char *file, fattr *f)
239 {
240 if (chown(file, f->uid, f->gid) == -1 ||
241 chmod(file, f->mode) == -1)
242 return (-1);
243 return (0);
244 }
245
246 /*----- That's all, folks -------------------------------------------------*/