Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/config/mkoptions.cc
103062 views
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
/*
34
* Make all the .h files for the optional entries
35
*/
36
37
#include <ctype.h>
38
#include <err.h>
39
#include <stdio.h>
40
#include <string.h>
41
#include <unistd.h>
42
#include <sys/param.h>
43
#include "config.h"
44
#include "y.tab.h"
45
46
static struct users {
47
int u_default;
48
int u_min;
49
int u_max;
50
} users = { 8, 2, 512 };
51
52
static char *lower(char *);
53
static void read_options(void);
54
static void do_option(char *);
55
static char *tooption(char *);
56
57
void
58
options(void)
59
{
60
char buf[40];
61
struct cputype *cp;
62
struct opt_list *ol;
63
struct opt *op;
64
65
/* Fake the cpu types as options. */
66
SLIST_FOREACH(cp, &cputype, cpu_next) {
67
op = (struct opt *)calloc(1, sizeof(*op));
68
if (op == NULL)
69
err(EXIT_FAILURE, "calloc");
70
op->op_name = ns(cp->cpu_name);
71
SLIST_INSERT_HEAD(&opt, op, op_next);
72
}
73
74
if (maxusers == 0) {
75
if (verbose)
76
fprintf(stderr,
77
"maxusers not specified; will auto-size\n");
78
} else if (maxusers < users.u_min) {
79
fprintf(stderr, "minimum of %d maxusers assumed\n",
80
users.u_min);
81
maxusers = users.u_min;
82
} else if (maxusers > users.u_max)
83
fprintf(stderr, "warning: maxusers > %d (%d)\n",
84
users.u_max, maxusers);
85
86
/* Fake MAXUSERS as an option. */
87
op = (struct opt *)calloc(1, sizeof(*op));
88
if (op == NULL)
89
err(EXIT_FAILURE, "calloc");
90
op->op_name = ns("MAXUSERS");
91
snprintf(buf, sizeof(buf), "%d", maxusers);
92
op->op_value = ns(buf);
93
SLIST_INSERT_HEAD(&opt, op, op_next);
94
95
read_options();
96
97
/* Fake the value of MACHINE_ARCH as an option if necessary */
98
SLIST_FOREACH(ol, &otab, o_next) {
99
if (strcasecmp(ol->o_name, machinearch) != 0)
100
continue;
101
102
op = (struct opt *)calloc(1, sizeof(*op));
103
if (op == NULL)
104
err(EXIT_FAILURE, "calloc");
105
op->op_name = ns(ol->o_name);
106
SLIST_INSERT_HEAD(&opt, op, op_next);
107
break;
108
}
109
110
SLIST_FOREACH(op, &opt, op_next) {
111
SLIST_FOREACH(ol, &otab, o_next) {
112
if (eq(op->op_name, ol->o_name) &&
113
(ol->o_flags & OL_ALIAS)) {
114
fprintf(stderr, "Mapping option %s to %s.\n",
115
op->op_name, ol->o_file);
116
op->op_name = ol->o_file;
117
break;
118
}
119
}
120
}
121
SLIST_FOREACH(ol, &otab, o_next)
122
do_option(ol->o_name);
123
SLIST_FOREACH(op, &opt, op_next) {
124
if (!op->op_ownfile && strncmp(op->op_name, "DEV_", 4)) {
125
fprintf(stderr, "%s: unknown option \"%s\"\n",
126
PREFIX, op->op_name);
127
exit(1);
128
}
129
}
130
}
131
132
/*
133
* Generate an <options>.h file
134
*/
135
136
static void
137
do_option(char *name)
138
{
139
char *file;
140
const char *basefile;
141
struct opt_list *ol;
142
struct opt *op;
143
struct opt_head op_head;
144
FILE *inf, *outf;
145
char *value;
146
char *oldvalue;
147
int seen;
148
int tidy;
149
150
file = tooption(name);
151
/*
152
* Check to see if the option was specified..
153
*/
154
value = NULL;
155
SLIST_FOREACH(op, &opt, op_next) {
156
if (eq(name, op->op_name)) {
157
oldvalue = value;
158
value = op->op_value;
159
if (value == NULL)
160
value = ns("1");
161
if (oldvalue != NULL && !eq(value, oldvalue))
162
fprintf(stderr,
163
"%s: option \"%s\" redefined from %s to %s\n",
164
PREFIX, op->op_name, oldvalue,
165
value);
166
op->op_ownfile++;
167
}
168
}
169
170
remember(file);
171
inf = fopen(file, "r");
172
if (inf == NULL) {
173
outf = fopen(file, "w");
174
if (outf == NULL)
175
err(1, "%s", file);
176
177
/* was the option in the config file? */
178
if (value) {
179
fprintf(outf, "#define %s %s\n", name, value);
180
} /* else empty file */
181
182
(void)fclose(outf);
183
return;
184
}
185
basefile = "";
186
SLIST_FOREACH(ol, &otab, o_next)
187
if (eq(name, ol->o_name)) {
188
basefile = ol->o_file;
189
break;
190
}
191
oldvalue = NULL;
192
SLIST_INIT(&op_head);
193
seen = 0;
194
tidy = 0;
195
for (;;) {
196
configword cp, inw;
197
char *invalue;
198
199
/* get the #define */
200
if ((inw = get_word(inf)).eol() || inw.eof())
201
break;
202
/* get the option name */
203
if ((inw = get_word(inf)).eol() || inw.eof())
204
break;
205
/* get the option value */
206
if ((cp = get_word(inf)).eol() || cp.eof())
207
break;
208
/* option value */
209
invalue = ns(cp); /* malloced */
210
if (eq(inw, name)) {
211
oldvalue = invalue;
212
invalue = value;
213
seen++;
214
}
215
SLIST_FOREACH(ol, &otab, o_next)
216
if (eq(inw, ol->o_name))
217
break;
218
if (!eq(inw, name) && !ol) {
219
fprintf(stderr,
220
"WARNING: unknown option `%s' removed from %s\n",
221
inw->c_str(), file);
222
tidy++;
223
} else if (ol != NULL && !eq(basefile, ol->o_file)) {
224
fprintf(stderr,
225
"WARNING: option `%s' moved from %s to %s\n",
226
inw->c_str(), 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 = ns(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.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 = ns(value);
262
SLIST_INSERT_HEAD(&op_head, op, op_next);
263
}
264
265
outf = fopen(file, "w");
266
if (outf == NULL)
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
*/
286
static char *
287
tooption(char *name)
288
{
289
static char hbuf[MAXPATHLEN];
290
char nbuf[MAXPATHLEN];
291
struct opt_list *po;
292
char *fpath;
293
294
/* "cannot happen"? the otab list should be complete.. */
295
(void)strlcpy(nbuf, "options.h", sizeof(nbuf));
296
297
SLIST_FOREACH(po, &otab, o_next) {
298
if (eq(po->o_name, name)) {
299
strlcpy(nbuf, po->o_file, sizeof(nbuf));
300
break;
301
}
302
}
303
304
fpath = path(nbuf);
305
(void)strlcpy(hbuf, fpath, sizeof(hbuf));
306
free(fpath);
307
return (hbuf);
308
}
309
310
311
static void
312
check_duplicate(const char *fname, const char *chkopt)
313
{
314
struct opt_list *po;
315
316
SLIST_FOREACH(po, &otab, o_next) {
317
if (eq(po->o_name, chkopt)) {
318
fprintf(stderr, "%s: Duplicate option %s.\n",
319
fname, chkopt);
320
exit(1);
321
}
322
}
323
}
324
325
static void
326
insert_option(const char *fname, char *optname, char *val)
327
{
328
struct opt_list *po;
329
330
check_duplicate(fname, optname);
331
po = (struct opt_list *) calloc(1, sizeof *po);
332
if (po == NULL)
333
err(EXIT_FAILURE, "calloc");
334
po->o_name = optname;
335
po->o_file = val;
336
po->o_flags = 0;
337
SLIST_INSERT_HEAD(&otab, po, o_next);
338
}
339
340
static void
341
update_option(const char *optname, char *val, int flags)
342
{
343
struct opt_list *po;
344
345
SLIST_FOREACH(po, &otab, o_next) {
346
if (eq(po->o_name, optname)) {
347
free(po->o_file);
348
po->o_file = val;
349
po->o_flags = flags;
350
return;
351
}
352
}
353
/*
354
* Option not found, but that's OK, we just ignore it since it
355
* may be for another arch.
356
*/
357
return;
358
}
359
360
static int
361
read_option_file(const char *fname, int flags)
362
{
363
FILE *fp;
364
configword wd;
365
char *optname, *val;
366
char genopt[MAXPATHLEN];
367
368
fp = fopen(fname, "r");
369
if (fp == NULL) {
370
if (verbose) {
371
getcwd(genopt, sizeof(genopt));
372
fprintf(stderr, "Unable to open options file: %s\n",
373
fname);
374
fprintf(stderr, "CWD: %s\n", genopt);
375
}
376
return (0);
377
}
378
while (!(wd = get_word(fp)).eof()) {
379
if (wd.eol())
380
continue;
381
if (wd[0] == '#') {
382
while (!(wd = get_word(fp)).eof() && !wd.eol())
383
continue;
384
continue;
385
}
386
optname = ns(wd);
387
wd = get_word(fp);
388
if (wd.eof()) {
389
free(optname);
390
break;
391
}
392
if (wd.eol()) {
393
if (flags) {
394
fprintf(stderr, "%s: compat file requires two"
395
" words per line at %s\n", fname, optname);
396
exit(1);
397
}
398
char *s = ns(optname);
399
(void)snprintf(genopt, sizeof(genopt), "opt_%s.h",
400
lower(s));
401
val = ns(genopt);
402
free(s);
403
} else {
404
val = ns(wd);
405
}
406
407
if (flags == 0) {
408
/*
409
* insert_option takes possession of `optname` in the
410
* new option instead of making yet another copy.
411
*/
412
insert_option(fname, optname, val);
413
} else {
414
update_option(optname, val, flags);
415
free(optname);
416
optname = NULL;
417
}
418
}
419
(void)fclose(fp);
420
return (1);
421
}
422
423
/*
424
* read the options and options.<machine> files
425
*/
426
static void
427
read_options(void)
428
{
429
char fname[MAXPATHLEN];
430
struct files_name *nl, *tnl;
431
432
SLIST_INIT(&otab);
433
read_option_file("../../conf/options", 0);
434
(void)snprintf(fname, sizeof fname, "../../conf/options.%s",
435
machinename);
436
if (!read_option_file(fname, 0)) {
437
(void)snprintf(fname, sizeof fname, "options.%s", machinename);
438
read_option_file(fname, 0);
439
}
440
for (nl = STAILQ_FIRST(&optfntab); nl != NULL; nl = tnl) {
441
read_option_file(nl->f_name, 0);
442
tnl = STAILQ_NEXT(nl, f_next);
443
free(nl->f_name);
444
free(nl);
445
}
446
read_option_file("../../conf/options-compat", OL_ALIAS);
447
}
448
449
static char *
450
lower(char *str)
451
{
452
char *cp = str;
453
454
while (*str) {
455
if (isupper(*str))
456
*str = tolower(*str);
457
str++;
458
}
459
return (cp);
460
}
461
462