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