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