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