mkoptions.c revision 159362
1/*
2 * Copyright (c) 1995  Peter Wemm
3 * Copyright (c) 1980, 1993
4 *	The Regents of the University of California.  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 * 4. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#ifndef lint
32#if 0
33static char sccsid[] = "@(#)mkheaders.c	8.1 (Berkeley) 6/6/93";
34#endif
35static const char rcsid[] =
36  "$FreeBSD: head/usr.sbin/config/mkoptions.c 159362 2006-06-07 01:43:26Z delphij $";
37#endif /* not lint */
38
39/*
40 * Make all the .h files for the optional entries
41 */
42
43#include <ctype.h>
44#include <err.h>
45#include <stdio.h>
46#include <string.h>
47#include <sys/param.h>
48#include "config.h"
49#include "y.tab.h"
50
51static	struct users {
52	int	u_default;
53	int	u_min;
54	int	u_max;
55} users = { 8, 2, 512 };
56
57static char *lower(char *);
58static void read_options(void);
59static void do_option(char *);
60static char *tooption(char *);
61
62void
63options(void)
64{
65	char buf[40];
66	struct cputype *cp;
67	struct opt_list *ol;
68	struct opt *op;
69
70	/* Fake the cpu types as options. */
71	SLIST_FOREACH(cp, &cputype, cpu_next) {
72		op = (struct opt *)calloc(1, sizeof(*op));
73		op->op_name = ns(cp->cpu_name);
74		SLIST_INSERT_HEAD(&opt, op, op_next);
75	}
76
77	if (maxusers == 0) {
78		/* printf("maxusers not specified; will auto-size\n"); */
79	} else if (maxusers < users.u_min) {
80		printf("minimum of %d maxusers assumed\n", users.u_min);
81		maxusers = users.u_min;
82	} else if (maxusers > users.u_max)
83		printf("warning: maxusers > %d (%d)\n", users.u_max, maxusers);
84
85	/* Fake MAXUSERS as an option. */
86	op = (struct opt *)calloc(1, sizeof(*op));
87	op->op_name = ns("MAXUSERS");
88	snprintf(buf, sizeof(buf), "%d", maxusers);
89	op->op_value = ns(buf);
90	SLIST_INSERT_HEAD(&opt, op, op_next);
91
92	read_options();
93	SLIST_FOREACH(ol, &otab, o_next)
94		do_option(ol->o_name);
95	SLIST_FOREACH(op, &opt, op_next) {
96		if (!op->op_ownfile && strncmp(op->op_name, "DEV_", 4)) {
97			printf("%s: unknown option \"%s\"\n",
98			       PREFIX, op->op_name);
99			exit(1);
100		}
101	}
102}
103
104/*
105 * Generate an <options>.h file
106 */
107
108static void
109do_option(char *name)
110{
111	char *file, *inw;
112	const char *basefile;
113	struct opt_list *ol;
114	struct opt *op;
115	struct opt_head op_head;
116	FILE *inf, *outf;
117	char *value;
118	char *oldvalue;
119	int seen;
120	int tidy;
121
122	file = tooption(name);
123
124	/*
125	 * Check to see if the option was specified..
126	 */
127	value = NULL;
128	SLIST_FOREACH(op, &opt, op_next) {
129		if (eq(name, op->op_name)) {
130			oldvalue = value;
131			value = op->op_value;
132			if (value == NULL)
133				value = ns("1");
134			if (oldvalue != NULL && !eq(value, oldvalue))
135				printf(
136			    "%s: option \"%s\" redefined from %s to %s\n",
137				   PREFIX, op->op_name, oldvalue,
138				   value);
139			op->op_ownfile++;
140		}
141	}
142
143	remember(file);
144	inf = fopen(file, "r");
145	if (inf == 0) {
146		outf = fopen(file, "w");
147		if (outf == 0)
148			err(1, "%s", file);
149
150		/* was the option in the config file? */
151		if (value) {
152			fprintf(outf, "#define %s %s\n", name, value);
153		} /* else empty file */
154
155		(void) fclose(outf);
156		return;
157	}
158	basefile = "";
159	SLIST_FOREACH(ol, &otab, o_next)
160		if (eq(name, ol->o_name)) {
161			basefile = ol->o_file;
162			break;
163		}
164	oldvalue = NULL;
165	SLIST_INIT(&op_head);
166	seen = 0;
167	tidy = 0;
168	for (;;) {
169		char *cp;
170		char *invalue;
171
172		/* get the #define */
173		if ((inw = get_word(inf)) == 0 || inw == (char *)EOF)
174			break;
175		/* get the option name */
176		if ((inw = get_word(inf)) == 0 || inw == (char *)EOF)
177			break;
178		inw = ns(inw);
179		/* get the option value */
180		if ((cp = get_word(inf)) == 0 || cp == (char *)EOF)
181			break;
182		/* option value */
183		invalue = ns(cp); /* malloced */
184		if (eq(inw, name)) {
185			oldvalue = invalue;
186			invalue = value;
187			seen++;
188		}
189		SLIST_FOREACH(ol, &otab, o_next)
190			if (eq(inw, ol->o_name))
191				break;
192		if (!eq(inw, name) && !ol) {
193			printf("WARNING: unknown option `%s' removed from %s\n",
194				inw, file);
195			tidy++;
196		} else if (ol != NULL && !eq(basefile, ol->o_file)) {
197			printf("WARNING: option `%s' moved from %s to %s\n",
198				inw, basefile, ol->o_file);
199			tidy++;
200		} else {
201			op = (struct opt *) calloc(1, sizeof *op);
202			op->op_name = inw;
203			op->op_value = invalue;
204			SLIST_INSERT_HEAD(&op_head, op, op_next);
205		}
206
207		/* EOL? */
208		cp = get_word(inf);
209		if (cp == (char *)EOF)
210			break;
211	}
212	(void) fclose(inf);
213	if (!tidy && ((value == NULL && oldvalue == NULL) ||
214	    (value && oldvalue && eq(value, oldvalue)))) {
215		while (!SLIST_EMPTY(&op_head)) {
216			op = SLIST_FIRST(&op_head);
217			SLIST_REMOVE_HEAD(&op_head, op_next);
218			free(op->op_name);
219			free(op->op_value);
220			free(op);
221		}
222		return;
223	}
224
225	if (value && !seen) {
226		/* New option appears */
227		op = (struct opt *) calloc(1, sizeof *op);
228		op->op_name = ns(name);
229		op->op_value = value ? ns(value) : NULL;
230		SLIST_INSERT_HEAD(&op_head, op, op_next);
231	}
232
233	outf = fopen(file, "w");
234	if (outf == 0)
235		err(1, "%s", file);
236	while (!SLIST_EMPTY(&op_head)) {
237		op = SLIST_FIRST(&op_head);
238		/* was the option in the config file? */
239		if (op->op_value) {
240			fprintf(outf, "#define %s %s\n",
241				op->op_name, op->op_value);
242		}
243		SLIST_REMOVE_HEAD(&op_head, op_next);
244		free(op->op_name);
245		free(op->op_value);
246		free(op);
247	}
248	(void) fclose(outf);
249}
250
251/*
252 * Find the filename to store the option spec into.
253 */
254static char *
255tooption(char *name)
256{
257	static char hbuf[MAXPATHLEN];
258	char nbuf[MAXPATHLEN];
259	struct opt_list *po;
260
261	/* "cannot happen"?  the otab list should be complete.. */
262	(void) strlcpy(nbuf, "options.h", sizeof(nbuf));
263
264	SLIST_FOREACH(po, &otab, o_next) {
265		if (eq(po->o_name, name)) {
266			strlcpy(nbuf, po->o_file, sizeof(nbuf));
267			break;
268		}
269	}
270
271	(void) strlcpy(hbuf, path(nbuf), sizeof(hbuf));
272	return (hbuf);
273}
274
275/*
276 * read the options and options.<machine> files
277 */
278static void
279read_options(void)
280{
281	FILE *fp;
282	char fname[MAXPATHLEN];
283	char *wd, *this, *val;
284	struct opt_list *po;
285	int first = 1;
286	char genopt[MAXPATHLEN];
287
288	SLIST_INIT(&otab);
289	(void) snprintf(fname, sizeof(fname), "../../conf/options");
290openit:
291	fp = fopen(fname, "r");
292	if (fp == 0) {
293		return;
294	}
295next:
296	wd = get_word(fp);
297	if (wd == (char *)EOF) {
298		(void) fclose(fp);
299		if (first == 1) {
300			first++;
301			(void) snprintf(fname, sizeof fname, "../../conf/options.%s", machinename);
302			fp = fopen(fname, "r");
303			if (fp != 0)
304				goto next;
305			(void) snprintf(fname, sizeof fname, "options.%s", machinename);
306			goto openit;
307		}
308		return;
309	}
310	if (wd == 0)
311		goto next;
312	if (wd[0] == '#')
313	{
314		while (((wd = get_word(fp)) != (char *)EOF) && wd)
315		;
316		goto next;
317	}
318	this = ns(wd);
319	val = get_word(fp);
320	if (val == (char *)EOF)
321		return;
322	if (val == 0) {
323		char *s = ns(this);
324		(void) snprintf(genopt, sizeof(genopt), "opt_%s.h", lower(s));
325		val = genopt;
326		free(s);
327	}
328	val = ns(val);
329
330	SLIST_FOREACH(po, &otab, o_next) {
331		if (eq(po->o_name, this)) {
332			printf("%s: Duplicate option %s.\n",
333			       fname, this);
334			exit(1);
335		}
336	}
337
338	po = (struct opt_list *) calloc(1, sizeof *po);
339	po->o_name = this;
340	po->o_file = val;
341	SLIST_INSERT_HEAD(&otab, po, o_next);
342
343	goto next;
344}
345
346static char *
347lower(char *str)
348{
349	char *cp = str;
350
351	while (*str) {
352		if (isupper(*str))
353			*str = tolower(*str);
354		str++;
355	}
356	return (cp);
357}
358