mkoptions.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1995  Peter Wemm
5 * Copyright (c) 1980, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)mkheaders.c	8.1 (Berkeley) 6/6/93";
36#endif
37static const char rcsid[] =
38  "$FreeBSD: stable/11/usr.sbin/config/mkoptions.c 330897 2018-03-14 03:19:51Z eadler $";
39#endif /* not lint */
40
41/*
42 * Make all the .h files for the optional entries
43 */
44
45#include <ctype.h>
46#include <err.h>
47#include <stdio.h>
48#include <string.h>
49#include <sys/param.h>
50#include "config.h"
51#include "y.tab.h"
52
53static	struct users {
54	int	u_default;
55	int	u_min;
56	int	u_max;
57} users = { 8, 2, 512 };
58
59static char *lower(char *);
60static void read_options(void);
61static void do_option(char *);
62static char *tooption(char *);
63
64void
65options(void)
66{
67	char buf[40];
68	struct cputype *cp;
69	struct opt_list *ol;
70	struct opt *op;
71
72	/* Fake the cpu types as options. */
73	SLIST_FOREACH(cp, &cputype, cpu_next) {
74		op = (struct opt *)calloc(1, sizeof(*op));
75		if (op == NULL)
76			err(EXIT_FAILURE, "calloc");
77		op->op_name = ns(cp->cpu_name);
78		SLIST_INSERT_HEAD(&opt, op, op_next);
79	}
80
81	if (maxusers == 0) {
82		/* fprintf(stderr, "maxusers not specified; will auto-size\n"); */
83	} else if (maxusers < users.u_min) {
84		fprintf(stderr, "minimum of %d maxusers assumed\n",
85		    users.u_min);
86		maxusers = users.u_min;
87	} else if (maxusers > users.u_max)
88		fprintf(stderr, "warning: maxusers > %d (%d)\n",
89		    users.u_max, maxusers);
90
91	/* Fake MAXUSERS as an option. */
92	op = (struct opt *)calloc(1, sizeof(*op));
93	if (op == NULL)
94		err(EXIT_FAILURE, "calloc");
95	op->op_name = ns("MAXUSERS");
96	snprintf(buf, sizeof(buf), "%d", maxusers);
97	op->op_value = ns(buf);
98	SLIST_INSERT_HEAD(&opt, op, op_next);
99
100	read_options();
101
102	/* Fake the value of MACHINE_ARCH as an option if necessary */
103	SLIST_FOREACH(ol, &otab, o_next) {
104		if (strcasecmp(ol->o_name, machinearch) != 0)
105			continue;
106
107		op = (struct opt *)calloc(1, sizeof(*op));
108		if (op == NULL)
109			err(EXIT_FAILURE, "calloc");
110		op->op_name = ns(ol->o_name);
111		SLIST_INSERT_HEAD(&opt, op, op_next);
112		break;
113	}
114
115	SLIST_FOREACH(op, &opt, op_next) {
116		SLIST_FOREACH(ol, &otab, o_next) {
117			if (eq(op->op_name, ol->o_name) &&
118			    (ol->o_flags & OL_ALIAS)) {
119				fprintf(stderr, "Mapping option %s to %s.\n",
120				    op->op_name, ol->o_file);
121				op->op_name = ol->o_file;
122				break;
123			}
124		}
125	}
126	SLIST_FOREACH(ol, &otab, o_next)
127		do_option(ol->o_name);
128	SLIST_FOREACH(op, &opt, op_next) {
129		if (!op->op_ownfile && strncmp(op->op_name, "DEV_", 4)) {
130			fprintf(stderr, "%s: unknown option \"%s\"\n",
131			       PREFIX, op->op_name);
132			exit(1);
133		}
134	}
135}
136
137/*
138 * Generate an <options>.h file
139 */
140
141static void
142do_option(char *name)
143{
144	char *file, *inw;
145	const char *basefile;
146	struct opt_list *ol;
147	struct opt *op;
148	struct opt_head op_head;
149	FILE *inf, *outf;
150	char *value;
151	char *oldvalue;
152	int seen;
153	int tidy;
154
155	file = tooption(name);
156	/*
157	 * Check to see if the option was specified..
158	 */
159	value = NULL;
160	SLIST_FOREACH(op, &opt, op_next) {
161		if (eq(name, op->op_name)) {
162			oldvalue = value;
163			value = op->op_value;
164			if (value == NULL)
165				value = ns("1");
166			if (oldvalue != NULL && !eq(value, oldvalue))
167				fprintf(stderr,
168			    "%s: option \"%s\" redefined from %s to %s\n",
169				   PREFIX, op->op_name, oldvalue,
170				   value);
171			op->op_ownfile++;
172		}
173	}
174
175	remember(file);
176	inf = fopen(file, "r");
177	if (inf == NULL) {
178		outf = fopen(file, "w");
179		if (outf == NULL)
180			err(1, "%s", file);
181
182		/* was the option in the config file? */
183		if (value) {
184			fprintf(outf, "#define %s %s\n", name, value);
185		} /* else empty file */
186
187		(void)fclose(outf);
188		return;
189	}
190	basefile = "";
191	SLIST_FOREACH(ol, &otab, o_next)
192		if (eq(name, ol->o_name)) {
193			basefile = ol->o_file;
194			break;
195		}
196	oldvalue = NULL;
197	SLIST_INIT(&op_head);
198	seen = 0;
199	tidy = 0;
200	for (;;) {
201		char *cp;
202		char *invalue;
203
204		/* get the #define */
205		if ((inw = get_word(inf)) == NULL || inw == (char *)EOF)
206			break;
207		/* get the option name */
208		if ((inw = get_word(inf)) == NULL || inw == (char *)EOF)
209			break;
210		inw = ns(inw);
211		/* get the option value */
212		if ((cp = get_word(inf)) == NULL || cp == (char *)EOF)
213			break;
214		/* option value */
215		invalue = ns(cp); /* malloced */
216		if (eq(inw, name)) {
217			oldvalue = invalue;
218			invalue = value;
219			seen++;
220		}
221		SLIST_FOREACH(ol, &otab, o_next)
222			if (eq(inw, ol->o_name))
223				break;
224		if (!eq(inw, name) && !ol) {
225			fprintf(stderr,
226			    "WARNING: unknown option `%s' removed from %s\n",
227			    inw, file);
228			tidy++;
229		} else if (ol != NULL && !eq(basefile, ol->o_file)) {
230			fprintf(stderr,
231			    "WARNING: option `%s' moved from %s to %s\n",
232			    inw, basefile, ol->o_file);
233			tidy++;
234		} else {
235			op = (struct opt *) calloc(1, sizeof *op);
236			if (op == NULL)
237				err(EXIT_FAILURE, "calloc");
238			op->op_name = inw;
239			op->op_value = invalue;
240			SLIST_INSERT_HEAD(&op_head, op, op_next);
241		}
242
243		/* EOL? */
244		cp = get_word(inf);
245		if (cp == (char *)EOF)
246			break;
247	}
248	(void)fclose(inf);
249	if (!tidy && ((value == NULL && oldvalue == NULL) ||
250	    (value && oldvalue && eq(value, oldvalue)))) {
251		while (!SLIST_EMPTY(&op_head)) {
252			op = SLIST_FIRST(&op_head);
253			SLIST_REMOVE_HEAD(&op_head, op_next);
254			free(op->op_name);
255			free(op->op_value);
256			free(op);
257		}
258		return;
259	}
260
261	if (value && !seen) {
262		/* New option appears */
263		op = (struct opt *) calloc(1, sizeof *op);
264		if (op == NULL)
265			err(EXIT_FAILURE, "calloc");
266		op->op_name = ns(name);
267		op->op_value = value ? ns(value) : NULL;
268		SLIST_INSERT_HEAD(&op_head, op, op_next);
269	}
270
271	outf = fopen(file, "w");
272	if (outf == NULL)
273		err(1, "%s", file);
274	while (!SLIST_EMPTY(&op_head)) {
275		op = SLIST_FIRST(&op_head);
276		/* was the option in the config file? */
277		if (op->op_value) {
278			fprintf(outf, "#define %s %s\n",
279				op->op_name, op->op_value);
280		}
281		SLIST_REMOVE_HEAD(&op_head, op_next);
282		free(op->op_name);
283		free(op->op_value);
284		free(op);
285	}
286	(void)fclose(outf);
287}
288
289/*
290 * Find the filename to store the option spec into.
291 */
292static char *
293tooption(char *name)
294{
295	static char hbuf[MAXPATHLEN];
296	char nbuf[MAXPATHLEN];
297	struct opt_list *po;
298
299	/* "cannot happen"?  the otab list should be complete.. */
300	(void)strlcpy(nbuf, "options.h", sizeof(nbuf));
301
302	SLIST_FOREACH(po, &otab, o_next) {
303		if (eq(po->o_name, name)) {
304			strlcpy(nbuf, po->o_file, sizeof(nbuf));
305			break;
306		}
307	}
308
309	(void)strlcpy(hbuf, path(nbuf), sizeof(hbuf));
310	return (hbuf);
311}
312
313
314static void
315check_duplicate(const char *fname, const char *this)
316{
317	struct opt_list *po;
318
319	SLIST_FOREACH(po, &otab, o_next) {
320		if (eq(po->o_name, this)) {
321			fprintf(stderr, "%s: Duplicate option %s.\n",
322			    fname, this);
323			exit(1);
324		}
325	}
326}
327
328static void
329insert_option(const char *fname, char *this, char *val)
330{
331	struct opt_list *po;
332
333	check_duplicate(fname, this);
334	po = (struct opt_list *) calloc(1, sizeof *po);
335	if (po == NULL)
336		err(EXIT_FAILURE, "calloc");
337	po->o_name = this;
338	po->o_file = val;
339	po->o_flags = 0;
340	SLIST_INSERT_HEAD(&otab, po, o_next);
341}
342
343static void
344update_option(const char *this, char *val, int flags)
345{
346	struct opt_list *po;
347
348	SLIST_FOREACH(po, &otab, o_next) {
349		if (eq(po->o_name, this)) {
350			free(po->o_file);
351			po->o_file = val;
352			po->o_flags = flags;
353			return;
354		}
355	}
356	/*
357	 * Option not found, but that's OK, we just ignore it since it
358	 * may be for another arch.
359	 */
360	return;
361}
362
363static int
364read_option_file(const char *fname, int flags)
365{
366	FILE *fp;
367	char *wd, *this, *val;
368	char genopt[MAXPATHLEN];
369
370	fp = fopen(fname, "r");
371	if (fp == NULL)
372		return (0);
373	while ((wd = get_word(fp)) != (char *)EOF) {
374		if (wd == NULL)
375			continue;
376		if (wd[0] == '#') {
377			while (((wd = get_word(fp)) != (char *)EOF) && wd)
378				continue;
379			continue;
380		}
381		this = ns(wd);
382		val = get_word(fp);
383		if (val == (char *)EOF)
384			return (1);
385		if (val == NULL) {
386			if (flags) {
387				fprintf(stderr, "%s: compat file requires two"
388				    " words per line at %s\n", fname, this);
389				exit(1);
390			}
391			char *s = ns(this);
392			(void)snprintf(genopt, sizeof(genopt), "opt_%s.h",
393			    lower(s));
394			val = genopt;
395			free(s);
396		}
397		val = ns(val);
398		if (flags == 0)
399			insert_option(fname, this, val);
400		else
401			update_option(this, val, flags);
402	}
403	(void)fclose(fp);
404	return (1);
405}
406
407/*
408 * read the options and options.<machine> files
409 */
410static void
411read_options(void)
412{
413	char fname[MAXPATHLEN];
414
415	SLIST_INIT(&otab);
416	read_option_file("../../conf/options", 0);
417	(void)snprintf(fname, sizeof fname, "../../conf/options.%s",
418	    machinename);
419	if (!read_option_file(fname, 0)) {
420		(void)snprintf(fname, sizeof fname, "options.%s", machinename);
421		read_option_file(fname, 0);
422	}
423	read_option_file("../../conf/options-compat", OL_ALIAS);
424}
425
426static char *
427lower(char *str)
428{
429	char *cp = str;
430
431	while (*str) {
432		if (isupper(*str))
433			*str = tolower(*str);
434		str++;
435	}
436	return (cp);
437}
438