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