Commit | Line | Data |
---|---|---|
1029ba56 GW |
1 | /* |
2 | * Copyright 1993, Garrett A. Wollman. | |
3 | * Copyright 1993, University of Vermont and State Agricultural College. | |
4 | * All Rights Reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND AUTHOR ``AS IS'' AND | |
16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHOR BE LIABLE | |
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
25 | * SUCH DAMAGE. | |
26 | */ | |
27 | ||
28 | const char chkconfig_c_rcsid[] = | |
67be5a28 | 29 | "$Id: chkconfig.c,v 1.4 1993/11/12 03:54:24 wollman Exp $"; |
1029ba56 GW |
30 | |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <sys/types.h> | |
34 | #include <sys/stat.h> | |
35 | #include <dirent.h> | |
36 | #include <errno.h> | |
37 | #include <string.h> | |
38 | #include "paths.h" | |
39 | ||
40 | static int testvalue(const char *); | |
9adaa3bd | 41 | static int printflags(const char *); |
1029ba56 GW |
42 | static int setvalue(const char *, int); |
43 | static int printvalues(void); | |
44 | static void usage(void); | |
45 | static void die(const char *); | |
67be5a28 | 46 | static int is_on(const char *, size_t); |
1029ba56 GW |
47 | |
48 | const char *whoami; | |
49 | static const char *configdir = _PATH_CONFIG; | |
50 | static int sortbystate = 0; | |
ef1bbcbc | 51 | static int doflags = 0; |
1029ba56 GW |
52 | static int force = 0; |
53 | static int verbose = 0; | |
54 | ||
55 | int main(int argc, char **argv) { | |
56 | int opt; | |
57 | ||
58 | whoami = argv[0]; | |
59 | ||
ef1bbcbc | 60 | while((opt = getopt(argc, argv, "osfd:v")) != EOF) { |
1029ba56 | 61 | switch(opt) { |
ef1bbcbc GW |
62 | case 'o': |
63 | doflags = 1; | |
64 | break; | |
1029ba56 GW |
65 | case 's': |
66 | sortbystate = 1; | |
67 | break; | |
68 | case 'f': | |
69 | force = 1; | |
70 | break; | |
71 | case 'd': | |
72 | configdir = optarg; | |
73 | break; | |
74 | case 'v': | |
75 | verbose = 1; | |
76 | break; | |
77 | case '?': | |
78 | default: | |
79 | usage(); | |
80 | return -1; | |
81 | } | |
82 | } | |
83 | ||
84 | if(sortbystate && optind != argc) { | |
85 | fprintf(stderr, "%s: -s: too many arguments\n", whoami); | |
86 | usage(); | |
87 | return -1; | |
88 | } | |
89 | ||
90 | if(force && optind == argc) { | |
91 | fprintf(stderr, "%s: -f: too few arguments\n", whoami); | |
92 | usage(); | |
93 | return -1; | |
94 | } | |
95 | ||
96 | switch(argc - optind) { | |
97 | case 0: | |
98 | return printvalues(); | |
99 | ||
100 | case 1: | |
9adaa3bd | 101 | return doflags ? printflags(argv[optind]) : testvalue(argv[optind]); |
1029ba56 GW |
102 | |
103 | case 2: | |
67be5a28 AM |
104 | return setvalue(argv[optind], is_on(argv[optind + 1], |
105 | strlen(argv[optind + 1]))); | |
1029ba56 GW |
106 | |
107 | default: | |
108 | usage(); | |
109 | return -1; | |
110 | } | |
111 | } | |
112 | ||
67be5a28 AM |
113 | static int is_on(const char *str, size_t len) { |
114 | if(!str || len < 2) return 0; | |
1029ba56 GW |
115 | return ( ((str[0] == 'o') || (str[0] == 'O')) |
116 | && ((str[1] == 'n') || (str[1] == 'N')) | |
67be5a28 | 117 | && ((len == 2) || (str[2] == '\n'))); |
1029ba56 GW |
118 | } |
119 | ||
120 | static void chat(const char *str, int state) { | |
121 | if(verbose) | |
122 | printf("`%s' is %s.\n", str, state ? "ON" : "OFF"); | |
123 | } | |
124 | ||
ef1bbcbc GW |
125 | static const char *confname(const char *str, const char *str2) { |
126 | int len = strlen(configdir) + strlen(str) + strlen(str2) + 2; | |
1029ba56 GW |
127 | char *rv = malloc(len); |
128 | ||
129 | if(!rv) { | |
130 | errno = ENOMEM; | |
131 | die("confname: malloc"); | |
132 | } | |
133 | ||
134 | strcpy(rv, configdir); | |
135 | strcat(rv, "/"); | |
136 | strcat(rv, str); | |
ef1bbcbc | 137 | strcat(rv, str2); |
1029ba56 GW |
138 | return rv; |
139 | } | |
140 | ||
141 | static int testvalue(const char *str) { | |
142 | FILE *fp; | |
143 | char *line; | |
144 | const char *fname; | |
67be5a28 | 145 | size_t len = 0; |
1029ba56 GW |
146 | int rv = 1; /* NB: shell's convention is opposite C's */ |
147 | ||
ef1bbcbc | 148 | fname = confname(str, ""); |
1029ba56 GW |
149 | fp = fopen(fname, "r"); |
150 | if(fp) { | |
ef1bbcbc | 151 | do { |
67be5a28 | 152 | line = fgetln(fp, &len); |
ef1bbcbc | 153 | } while(line && line[0] == '#'); |
67be5a28 | 154 | rv = !is_on(line, len); /* shell's convention is opposite C's */ |
1029ba56 GW |
155 | fclose(fp); |
156 | } | |
157 | ||
158 | free((void *)fname); /* cast away `const' to avoid warning */ | |
159 | chat(str, !rv); /* tell the user about it if verbose */ | |
160 | return rv; | |
161 | } | |
162 | ||
9adaa3bd | 163 | static char *getflags(const char *str) { |
ef1bbcbc GW |
164 | FILE *fp; |
165 | char *line; | |
166 | const char *fname; | |
9adaa3bd | 167 | char *rv = strdup(""); |
67be5a28 | 168 | size_t len = 0; |
9adaa3bd GW |
169 | |
170 | if(!rv) { | |
171 | errno = ENOMEM; | |
172 | die("getflags: strdup"); | |
173 | } | |
ef1bbcbc GW |
174 | |
175 | fname = confname(str, ".flags"); | |
176 | fp = fopen(fname, "r"); | |
177 | if(fp) { | |
178 | do { | |
67be5a28 | 179 | line = fgetln(fp, &len); |
ef1bbcbc GW |
180 | } while(line && line[0] == '#'); |
181 | ||
182 | if(line) { | |
9adaa3bd | 183 | free(rv); |
67be5a28 AM |
184 | if(line[len - 1] == '\n') --len; |
185 | if((rv = (char *) malloc(len + 1)) == NULL) { | |
9adaa3bd | 186 | errno = ENOMEM; |
67be5a28 | 187 | die("getflags: malloc"); |
9adaa3bd | 188 | } |
67be5a28 AM |
189 | bcopy(line, rv, len); |
190 | rv[len] = '\0'; | |
ef1bbcbc GW |
191 | } |
192 | ||
193 | fclose(fp); | |
194 | } | |
195 | free((void *)fname); | |
9adaa3bd GW |
196 | |
197 | return rv; | |
198 | } | |
199 | ||
200 | ||
201 | static int printflags(const char *str) { | |
202 | int rv = 0; | |
203 | char *flags; | |
204 | ||
205 | flags = getflags(str); | |
206 | if(flags[0]) printf("%s\n", flags); | |
207 | free(flags); | |
ef1bbcbc GW |
208 | return 0; |
209 | } | |
210 | ||
1029ba56 GW |
211 | static int setvalue(const char *str, int state) { |
212 | FILE *fp; | |
213 | const char *fname; | |
214 | ||
ef1bbcbc | 215 | fname = confname(str, ""); |
1029ba56 GW |
216 | errno = 0; |
217 | fp = fopen(fname, "r"); | |
218 | if(!fp && !force) { | |
219 | /* | |
220 | * Yes, I know this is bogus, but SGI must have had some sort of | |
221 | * reason... | |
222 | */ | |
223 | if(errno == ENOENT) { | |
224 | fprintf(stderr, | |
225 | "%s: configuration file does not exist;" | |
226 | " use `-f' flag to create it.\n", whoami); | |
227 | return -1; | |
228 | } else { | |
229 | die(fname); | |
230 | } | |
231 | } | |
232 | ||
233 | if(fp) | |
234 | fclose(fp); | |
235 | ||
236 | errno = 0; | |
237 | fp = fopen(fname, "w"); | |
238 | if(!fp) | |
239 | die(fname); | |
240 | ||
241 | fprintf(fp, "%s\n", state ? "on" : "off"); | |
242 | ||
243 | fclose(fp); | |
244 | ||
245 | chat(str, state); | |
246 | return 0; | |
247 | } | |
248 | ||
249 | /* | |
250 | * From here down is the code for listing the value of every option. | |
251 | */ | |
252 | struct q { | |
253 | struct q *next; | |
254 | int state; | |
255 | char *name; | |
9adaa3bd | 256 | char *flags; |
1029ba56 GW |
257 | }; |
258 | ||
259 | static struct q *onhead; | |
260 | static struct q *offhead; /* only used for sortbystate == 1 */ | |
261 | ||
262 | static void insert(const char *fname) { | |
263 | struct q *q; | |
264 | struct q **headp; | |
265 | int state; | |
266 | ||
267 | q = malloc(sizeof *q); | |
268 | if(!q) { | |
269 | errno = ENOMEM; | |
270 | die("insert: malloc"); | |
271 | } | |
272 | ||
273 | q->name = strdup(fname); | |
274 | q->state = state = !testvalue(fname); | |
9adaa3bd | 275 | q->flags = getflags(fname); |
1029ba56 GW |
276 | |
277 | if(state || !sortbystate) | |
278 | headp = &onhead; | |
279 | else | |
280 | headp = &offhead; | |
281 | ||
52c309c0 | 282 | while(*headp && strcmp(q->name, (**headp).name) > 0) { |
1029ba56 GW |
283 | headp = &(**headp).next; |
284 | } | |
285 | ||
286 | q->next = *headp; | |
287 | *headp = q; | |
288 | } | |
289 | ||
290 | static int printvalues(void) { | |
291 | struct q *temp; | |
292 | DIR *dir; | |
293 | struct dirent *entry; | |
294 | struct stat stab; | |
295 | int doneheader = 0; | |
296 | ||
297 | verbose = 0; /* we're already verbose enough */ | |
298 | ||
299 | errno = 0; | |
300 | dir = opendir(configdir); | |
301 | if(!dir) | |
302 | die(configdir); | |
303 | ||
304 | while((entry = readdir(dir))) { | |
305 | if(stat(entry->d_name, &stab) < 0) { | |
306 | die(entry->d_name); | |
307 | } | |
308 | ||
309 | if(S_ISREG(stab.st_mode) && !strchr(entry->d_name, '.')) { | |
310 | insert(entry->d_name); | |
311 | } | |
312 | } | |
313 | ||
314 | closedir(dir); | |
315 | ||
316 | /* | |
317 | * Now we're done reading the file names, so we can print them out. | |
318 | * Thanks to insert(), everything is already in ASCII order. | |
319 | */ | |
9adaa3bd | 320 | #define FORMAT "%15s %-5s %s\n" |
1029ba56 GW |
321 | |
322 | if(sortbystate) { | |
9adaa3bd GW |
323 | printf("%15s %s %s\n", |
324 | "Option", "State", "Flags"); | |
325 | printf("%15s %s %s\n", | |
326 | "===============", "=====", "===================="); | |
1029ba56 GW |
327 | doneheader = 1; |
328 | ||
329 | while((temp = offhead)) { | |
9adaa3bd | 330 | printf(FORMAT, temp->name, "off", temp->flags); |
1029ba56 | 331 | free(temp->name); |
9adaa3bd | 332 | free(temp->flags); |
1029ba56 GW |
333 | offhead = temp->next; |
334 | free(temp); | |
335 | } | |
336 | } | |
337 | ||
338 | if(!doneheader) { | |
9adaa3bd GW |
339 | printf("%15s %s %s\n", "Option", "State", "Flags"); |
340 | printf("%15s %s %s\n", | |
341 | "===============", "=====", "===================="); | |
1029ba56 GW |
342 | } |
343 | ||
344 | while((temp = onhead)) { | |
9adaa3bd | 345 | printf(FORMAT, temp->name, temp->state ? "on" : "off", temp->flags); |
1029ba56 | 346 | free(temp->name); |
9adaa3bd | 347 | free(temp->flags); |
1029ba56 GW |
348 | onhead = temp->next; |
349 | free(temp); | |
350 | } | |
351 | ||
352 | return 0; | |
353 | } | |
354 | ||
355 | ||
356 | static void die(const char *why) { | |
357 | fprintf(stderr, "%s: %s: %s\n", whoami, why, strerror(errno)); | |
358 | exit(-1); | |
359 | } | |
360 | ||
361 | static void usage(void) { | |
362 | fprintf(stderr, "%s: usage:\n" | |
363 | "%s [ -d configdir ] [ -s ]\n" | |
364 | "%s [ -d configdir ] option\n" | |
365 | "%s [ -d configdir ] [ -f ] option [ on | off ]\n", | |
366 | whoami, whoami, whoami, whoami); | |
367 | } |