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