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