mkoptions.c revision 153888
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 153888 2005-12-30 15:29:50Z ru $";
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 *)malloc(sizeof(*op));
73		memset(op, 0, sizeof(*op));
74		op->op_name = ns(cp->cpu_name);
75		SLIST_INSERT_HEAD(&opt, op, op_next);
76	}
77
78	if (maxusers == 0) {
79		/* printf("maxusers not specified; will auto-size\n"); */
80	} else if (maxusers < users.u_min) {
81		printf("minimum of %d maxusers assumed\n", users.u_min);
82		maxusers = users.u_min;
83	} else if (maxusers > users.u_max)
84		printf("warning: maxusers > %d (%d)\n", users.u_max, maxusers);
85
86	/* Fake MAXUSERS as an option. */
87	op = (struct opt *)malloc(sizeof(*op));
88	memset(op, 0, sizeof(*op));
89	op->op_name = ns("MAXUSERS");
90	snprintf(buf, sizeof(buf), "%d", maxusers);
91	op->op_value = ns(buf);
92	SLIST_INSERT_HEAD(&opt, op, op_next);
93
94	read_options();
95	SLIST_FOREACH(ol, &otab, o_next)
96		do_option(ol->o_name);
97	SLIST_FOREACH(op, &opt, op_next) {
98		if (!op->op_ownfile && strncmp(op->op_name, "DEV_", 4)) {
99			printf("%s: unknown option \"%s\"\n",
100			       PREFIX, op->op_name);
101			exit(1);
102		}
103	}
104}
105
106/*
107 * Generate an <options>.h file
108 */
109
110static void
111do_option(char *name)
112{
113	char *file, *inw;
114	const char *basefile;
115	struct opt_list *ol;
116	struct opt *op;
117	struct opt_head op_head;
118	FILE *inf, *outf;
119	char *value;
120	char *oldvalue;
121	int seen;
122	int tidy;
123
124	file = tooption(name);
125
126	/*
127	 * Check to see if the option was specified..
128	 */
129	value = NULL;
130	SLIST_FOREACH(op, &opt, op_next) {
131		if (eq(name, op->op_name)) {
132			oldvalue = value;
133			value = op->op_value;
134			if (value == NULL)
135				value = ns("1");
136			if (oldvalue != NULL && !eq(value, oldvalue))
137				printf(
138			    "%s: option \"%s\" redefined from %s to %s\n",
139				   PREFIX, op->op_name, oldvalue,
140				   value);
141			op->op_ownfile++;
142		}
143	}
144
145	remember(file);
146	inf = fopen(file, "r");
147	if (inf == 0) {
148		outf = fopen(file, "w");
149		if (outf == 0)
150			err(1, "%s", file);
151
152		/* was the option in the config file? */
153		if (value) {
154			fprintf(outf, "#define %s %s\n", name, value);
155		} /* else empty file */
156
157		(void) fclose(outf);
158		return;
159	}
160	basefile = "";
161	SLIST_FOREACH(ol, &otab, o_next)
162		if (eq(name, ol->o_name)) {
163			basefile = ol->o_file;
164			break;
165		}
166	oldvalue = NULL;
167	SLIST_INIT(&op_head);
168	seen = 0;
169	tidy = 0;
170	for (;;) {
171		char *cp;
172		char *invalue;
173
174		/* get the #define */
175		if ((inw = get_word(inf)) == 0 || inw == (char *)EOF)
176			break;
177		/* get the option name */
178		if ((inw = get_word(inf)) == 0 || inw == (char *)EOF)
179			break;
180		inw = ns(inw);
181		/* get the option value */
182		if ((cp = get_word(inf)) == 0 || cp == (char *)EOF)
183			break;
184		/* option value */
185		invalue = ns(cp); /* malloced */
186		if (eq(inw, name)) {
187			oldvalue = invalue;
188			invalue = value;
189			seen++;
190		}
191		SLIST_FOREACH(ol, &otab, o_next)
192			if (eq(inw, ol->o_name))
193				break;
194		if (!eq(inw, name) && !ol) {
195			printf("WARNING: unknown option `%s' removed from %s\n",
196				inw, file);
197			tidy++;
198		} else if (ol != NULL && !eq(basefile, ol->o_file)) {
199			printf("WARNING: option `%s' moved from %s to %s\n",
200				inw, basefile, ol->o_file);
201			tidy++;
202		} else {
203			op = (struct opt *) malloc(sizeof *op);
204			bzero(op, sizeof(*op));
205			op->op_name = inw;
206			op->op_value = invalue;
207			SLIST_INSERT_HEAD(&op_head, op, op_next);
208		}
209
210		/* EOL? */
211		cp = get_word(inf);
212		if (cp == (char *)EOF)
213			break;
214	}
215	(void) fclose(inf);
216	if (!tidy && ((value == NULL && oldvalue == NULL) ||
217	    (value && oldvalue && eq(value, oldvalue)))) {
218		while (!SLIST_EMPTY(&op_head)) {
219			op = SLIST_FIRST(&op_head);
220			SLIST_REMOVE_HEAD(&op_head, op_next);
221			free(op->op_name);
222			free(op->op_value);
223			free(op);
224		}
225		return;
226	}
227
228	if (value && !seen) {
229		/* New option appears */
230		op = (struct opt *) malloc(sizeof *op);
231		bzero(op, sizeof(*op));
232		op->op_name = ns(name);
233		op->op_value = value ? ns(value) : NULL;
234		SLIST_INSERT_HEAD(&op_head, op, op_next);
235	}
236
237	outf = fopen(file, "w");
238	if (outf == 0)
239		err(1, "%s", file);
240	while (!SLIST_EMPTY(&op_head)) {
241		op = SLIST_FIRST(&op_head);
242		/* was the option in the config file? */
243		if (op->op_value) {
244			fprintf(outf, "#define %s %s\n",
245				op->op_name, op->op_value);
246		}
247		SLIST_REMOVE_HEAD(&op_head, op_next);
248		free(op->op_name);
249		free(op->op_value);
250		free(op);
251	}
252	(void) fclose(outf);
253}
254
255/*
256 * Find the filename to store the option spec into.
257 */
258static char *
259tooption(char *name)
260{
261	static char hbuf[MAXPATHLEN];
262	char nbuf[MAXPATHLEN];
263	struct opt_list *po;
264
265	/* "cannot happen"?  the otab list should be complete.. */
266	(void) strlcpy(nbuf, "options.h", sizeof(nbuf));
267
268	SLIST_FOREACH(po, &otab, o_next) {
269		if (eq(po->o_name, name)) {
270			strlcpy(nbuf, po->o_file, sizeof(nbuf));
271			break;
272		}
273	}
274
275	(void) strlcpy(hbuf, path(nbuf), sizeof(hbuf));
276	return (hbuf);
277}
278
279/*
280 * read the options and options.<machine> files
281 */
282static void
283read_options(void)
284{
285	FILE *fp;
286	char fname[MAXPATHLEN];
287	char *wd, *this, *val;
288	struct opt_list *po;
289	int first = 1;
290	char genopt[MAXPATHLEN];
291
292	SLIST_INIT(&otab);
293	(void) snprintf(fname, sizeof(fname), "../../conf/options");
294openit:
295	fp = fopen(fname, "r");
296	if (fp == 0) {
297		return;
298	}
299next:
300	wd = get_word(fp);
301	if (wd == (char *)EOF) {
302		(void) fclose(fp);
303		if (first == 1) {
304			first++;
305			(void) snprintf(fname, sizeof fname, "../../conf/options.%s", machinename);
306			fp = fopen(fname, "r");
307			if (fp != 0)
308				goto next;
309			(void) snprintf(fname, sizeof fname, "options.%s", machinename);
310			goto openit;
311		}
312		return;
313	}
314	if (wd == 0)
315		goto next;
316	if (wd[0] == '#')
317	{
318		while (((wd = get_word(fp)) != (char *)EOF) && wd)
319		;
320		goto next;
321	}
322	this = ns(wd);
323	val = get_word(fp);
324	if (val == (char *)EOF)
325		return;
326	if (val == 0) {
327		char *s = ns(this);
328		(void) snprintf(genopt, sizeof(genopt), "opt_%s.h", lower(s));
329		val = genopt;
330		free(s);
331	}
332	val = ns(val);
333
334	SLIST_FOREACH(po, &otab, o_next) {
335		if (eq(po->o_name, this)) {
336			printf("%s: Duplicate option %s.\n",
337			       fname, this);
338			exit(1);
339		}
340	}
341
342	po = (struct opt_list *) malloc(sizeof *po);
343	bzero(po, sizeof(*po));
344	po->o_name = this;
345	po->o_file = val;
346	SLIST_INSERT_HEAD(&otab, po, o_next);
347
348	goto next;
349}
350
351static char *
352lower(char *str)
353{
354	char *cp = str;
355
356	while (*str) {
357		if (isupper(*str))
358			*str = tolower(*str);
359		str++;
360	}
361	return (cp);
362}
363