This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sbin / chkconfig / chkconfig.c
CommitLineData
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
28const 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
40static int testvalue(const char *);
9adaa3bd 41static int printflags(const char *);
1029ba56
GW
42static int setvalue(const char *, int);
43static int printvalues(void);
44static void usage(void);
45static void die(const char *);
67be5a28 46static int is_on(const char *, size_t);
1029ba56
GW
47
48const char *whoami;
49static const char *configdir = _PATH_CONFIG;
50static int sortbystate = 0;
ef1bbcbc 51static int doflags = 0;
1029ba56
GW
52static int force = 0;
53static int verbose = 0;
54
55int 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
113static 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
120static void chat(const char *str, int state) {
121 if(verbose)
122 printf("`%s' is %s.\n", str, state ? "ON" : "OFF");
123}
124
ef1bbcbc
GW
125static 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
141static 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 163static 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
201static 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
211static 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 */
252struct q {
253 struct q *next;
254 int state;
255 char *name;
9adaa3bd 256 char *flags;
1029ba56
GW
257};
258
259static struct q *onhead;
260static struct q *offhead; /* only used for sortbystate == 1 */
261
262static 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
290static 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
356static void die(const char *why) {
357 fprintf(stderr, "%s: %s: %s\n", whoami, why, strerror(errno));
358 exit(-1);
359}
360
361static 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}