Provide a `--pidfile' option in `fw'.
[fwd] / fattr.c
CommitLineData
3b7defab 1/* -*-c-*-
2 *
7481fc9c 3 * $Id: fattr.c,v 1.4 2004/04/08 01:36:25 mdw Exp $
3b7defab 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
3b7defab 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
52fattr 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
65void 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
84int 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
9b699b28 95 conf_undelim(sc, 0, ",=+-");
3b7defab 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");
9b699b28 102 conf_undelim(sc, 0, 0);
3b7defab 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;
e73034b0 113 unsigned mask = 04700;
114 unsigned state = 0;
3b7defab 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
e73034b0 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;
3b7defab 139
e73034b0 140 case '=': mode &= ~mask; /* Drop through */
141 case '+': state = 0; or = 1; break;
142 case '-': state = 0; or = 0; break;
3b7defab 143
144#define APPLY(m) if (or) mode |= ((m) & mask); else mode &= ~((m) & mask);
e73034b0 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;
3b7defab 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
223int 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 -------------------------------------------------*/