]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/config/mkoptions.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / usr.sbin / config / mkoptions.c
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  * 3. 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
35 static char sccsid[] = "@(#)mkheaders.c 8.1 (Berkeley) 6/6/93";
36 #endif
37 static const char rcsid[] =
38   "$FreeBSD$";
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
53 static  struct users {
54         int     u_default;
55         int     u_min;
56         int     u_max;
57 } users = { 8, 2, 512 };
58
59 static char *lower(char *);
60 static void read_options(void);
61 static void do_option(char *);
62 static char *tooption(char *);
63
64 void
65 options(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
141 static void
142 do_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  */
292 static char *
293 tooption(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         
314 static void
315 check_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
328 static void
329 insert_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
343 static void
344 update_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
363 static int
364 read_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  */
410 static void
411 read_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
426 static char *
427 lower(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 }