1 /*
2 * Copyright (c) 2013-2026 Devin Teske <dteske@FreeBSD.org>
3 * Copyright (c) 2021-2026 Faraz Vahedi <kfv@FreeBSD.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8 /*
9 * sysconf(8): CLI entry, option parsing, and program state.
10 */
11
12 #include "sysconf_priv.h"
13
14 /* Requests to process (one per name argument) */
15 struct request *reqs; /* set by main() */
16 unsigned int nreqs; /* set by main() */
17
18 /* Union of all directives, for `-a' against multi-file targets */
19 struct dumpent *dumps; /* set by scan_cb() */
20 size_t ndumps; /* set by scan_cb() */
21 size_t dumpsize; /* set by scan_cb() */
22
23 /* Resolved target state */
24 char **conf_files; /* ordered backing files */
25 size_t nconf_files;
26 size_t conf_scanidx; /* file being parsed (scan_pass) */
27 size_t write_idx; /* default write target index */
28 int defaults_idx = -1; /* defaults file index in conf_files
29 * (read-only, never listed); -1 if none */
30 enum bsdconf_format format = BSDCONF_FORMAT_GENERIC;
31
32 /* Extra display information */
33 const char *pgm; /* set to getprogname() by main() */
34 bool check = false; /* `-c' */
35 bool defaults_only = false; /* `-D' */
36 bool dump_all = false; /* `-a' */
37 bool existing_only = false; /* `-E' */
38 bool ignore_unknown = false; /* `-i' */
39 bool list_all = false; /* `-L' */
40 bool list_files = false; /* `-l' */
41 bool name_only = false; /* `-N' */
42 bool quiet = false; /* `-q' */
43 bool remove_mode = false; /* `-x' */
44 bool set_knobs = false; /* `-s' WITH_/WITHOUT_ presence */
45 bool show_desc = false; /* `-d' */
46 bool show_equals = false; /* `-e' */
47 bool show_file = false; /* `-F' */
48 bool value_only = false; /* `-n' */
49 bool verbose = false; /* `-v' */
50 bool verbose_trail = false; /* `-V' */
51 bool with_defaults = false; /* `-A' */
52
53 /* Option arguments */
54 const char *file = NULL; /* `-f file' */
55 bool file_stdin = false; /* `-f -' given */
56 const char *jailname = NULL; /* `-j jail' */
57 const char *module = NULL; /* `-k module' */
58 const char *rootdir = ""; /* `-R dir' */
59
60 /*
61 * Locate the target keyword in `argv' without consuming or validating
62 * anything: the first argument that is neither an option cluster nor the
63 * argument of one (per OPTSTRING; an unknown option letter is assumed to
64 * take no argument). A `--' ends option scanning as usual. Returns the
65 * argv index of the target, or -1 when there is none. Used before any
66 * getopt(3) processing so that the `rc' pass-through target (see
67 * exec_sysrc() below) can be detected while the command line is still
68 * pristine.
69 *
70 * Attached arguments (`-fPATH', `-R/altroot') are self-contained: the rest
71 * of the cluster is the option's argument, so the following argv element is
72 * not consumed. Only a trailing option letter that takes an argument and
73 * has nothing after it in the cluster (`-f PATH') skips the next element.
74 */
75 static int
find_target(int argc,char * argv[])76 find_target(int argc, char *argv[])
77 {
78 int n;
79 const char *o;
80 const char *p;
81
82 for (n = 1; n < argc; n++) {
83 if (strcmp(argv[n], "--") == 0)
84 return (n + 1 < argc ? n + 1 : -1);
85 if (argv[n][0] == '-' && argv[n][1] != '\0') {
86 for (p = argv[n] + 1; *p != '\0'; p++) {
87 o = strchr(OPTSTRING, *p);
88 if (o != NULL && o[1] == ':') {
89 /* Takes an argument */
90 if (p[1] != '\0') {
91 ;
92 /* attached: rest of argv[n] */
93 } else if (n + 1 < argc) {
94 n++;
95 /* separate argv */
96 }
97 break;
98 }
99 }
100 continue;
101 }
102 return (n);
103 }
104
105 return (-1);
106 }
107
108 /*
109 * The `rc' pass-through: rc.conf(5) is sysrc(8)'s domain, and its feature
110 * set is a superset of ours, so no option or argument is validated,
111 * interpreted, or reordered here -- every argument except the target
112 * keyword itself (at argv index `skip') is handed to sysrc(8) verbatim.
113 * Never returns.
114 */
115 static void
exec_sysrc(int argc,char * argv[],int skip)116 exec_sysrc(int argc, char *argv[], int skip)
117 {
118 int n;
119 int nargc = 0;
120 char **nargv;
121
122 if ((nargv = calloc((size_t)argc + 1, sizeof(*nargv))) == NULL)
123 err(EXIT_FAILURE, NULL);
124 nargv[nargc++] = (char *)(uintptr_t)"sysrc";
125 for (n = 1; n < argc; n++) {
126 if (n == skip)
127 continue;
128 nargv[nargc++] = argv[n];
129 }
130 nargv[nargc] = NULL;
131
132 execvp("sysrc", nargv);
133 err(EXIT_FAILURE, "sysrc");
134 }
135
136 /*
137 * Run the getopt(3) loop over `argv', setting the option globals. Called
138 * once for the options preceding the target keyword and once for those
139 * following it. Returns the number of arguments consumed (optind).
140 */
141 static int
parse_options(int argc,char * argv[])142 parse_options(int argc, char *argv[])
143 {
144 int ch;
145
146 while ((ch = getopt(argc, argv, OPTSTRING)) != -1) {
147 switch (ch) {
148 case 'A': /* dump all directives, defaults included */
149 with_defaults = 1;
150 break;
151 case 'a': /* dump all directives */
152 dump_all = 1;
153 break;
154 case 'c': /* check only; do not modify */
155 check = 1;
156 break;
157 case 'd': /* show directive descriptions */
158 show_desc = 1;
159 break;
160 case 'D': /* consult the defaults file only */
161 defaults_only = 1;
162 break;
163 case 'E': /* list existing files only (with -l/-L) */
164 existing_only = 1;
165 break;
166 case 'e': /* show name=value */
167 show_equals = 1;
168 break;
169 case 'F': /* show authoritative file, not value */
170 show_file = 1;
171 break;
172 case 'f': /* explicit file (`-' is standard input) */
173 if (strcmp(optarg, "-") == 0) {
174 file = "/dev/stdin";
175 file_stdin = 1;
176 } else {
177 file = optarg;
178 file_stdin = 0;
179 }
180 break;
181 case 'h': /* help/usage */
182 usage();
183 break;
184 case 'i': /* ignore unknown names */
185 ignore_unknown = 1;
186 break;
187 case 'j': /* jail name or id */
188 jailname = optarg;
189 break;
190 case 'k': /* kernel module drop-in */
191 module = optarg;
192 break;
193 case 'l': /* list backing files */
194 list_files = 1;
195 break;
196 case 'L': /* list all candidate files */
197 list_all = 1;
198 break;
199 case 'n': /* value only */
200 value_only = 1;
201 break;
202 case 'N': /* name only */
203 name_only = 1;
204 break;
205 case 'q': /* quiet */
206 quiet = 1;
207 break;
208 case 'R': /* root dir */
209 rootdir = optarg;
210 break;
211 case 's': /* set empty WITH_/WITHOUT_ knobs (make/src) */
212 set_knobs = 1;
213 break;
214 case 'v': /* verbose (last file + final value) */
215 verbose = 1;
216 break;
217 case 'V': /* verbose trail (every assignment step) */
218 verbose_trail = 1;
219 break;
220 case 'x': /* remove */
221 remove_mode = 1;
222 break;
223 case '?': /* unknown argument (based on optstring) */
224 default: /* unhandled argument (based on switch) */
225 usage();
226 }
227 }
228
229 return (optind);
230 }
231
232 /*
233 * The native configuration trinity's third member: read and modify
234 * loader.conf(5), sysctl.conf(5), make.conf(5), and arbitrary configuration
235 * files with sysctl(8) assignment syntax.
236 */
237 int
main(int argc,char * argv[])238 main(int argc, char *argv[])
239 {
240 int have_reads = 0;
241 int have_writes = 0;
242 int n;
243 int rv = EXIT_SUCCESS;
244 const char *target = NULL;
245
246 pgm = getprogname();
247
248 /*
249 * The `rc' target is a pure pass-through to sysrc(8), detected
250 * while the command line is still pristine so that nothing --
251 * `--help' and `--version' included -- is intercepted on its way
252 * there (see exec_sysrc()).
253 */
254 n = find_target(argc, argv);
255 if (n > 0 && strcmp(argv[n], "rc") == 0)
256 exec_sysrc(argc, argv, n); /* never returns */
257
258 /*
259 * Honor `--help' and `--version' wherever they appear (getopt(3)
260 * knows nothing of long options and would reject them as illegal
261 * short options). A bare `--' ends option processing as usual.
262 */
263 for (n = 1; n < argc; n++) {
264 if (strcmp(argv[n], "--") == 0)
265 break;
266 if (strcmp(argv[n], "--help") == 0)
267 help();
268 if (strcmp(argv[n], "--version") == 0) {
269 printf("%s (libbsdconf %s)\n", SYSCONF_VERSION,
270 BSDCONF_VERSION);
271 exit(EXIT_SUCCESS);
272 }
273 }
274
275 /*
276 * Process command-line options
277 */
278 n = parse_options(argc, argv);
279 argc -= n;
280 argv += n;
281
282 /*
283 * Consume the (required) target keyword and allow further options
284 * to follow it, mirroring the option placement freedom of
285 * sysctl(8) (e.g., `sysconf sysctl -L'). getopt(3) skips over its
286 * first argument, so hand it the target keyword's slot as the
287 * program name.
288 */
289 if (argc > 0) {
290 target = argv[0];
291 argc--;
292 argv++;
293 #ifdef __FreeBSD__
294 optreset = 1;
295 optind = 1;
296 #else
297 optind = 0; /* glibc and musl re-initialize at zero */
298 #endif
299 n = parse_options(argc + 1, argv - 1) - 1;
300 argc -= n;
301 argv += n;
302 }
303
304 if (jailname != NULL && *rootdir != '\0') {
305 warnx("-j and -R are mutually exclusive");
306 usage();
307 }
308 if (file != NULL && module != NULL) {
309 warnx("-f and -k are mutually exclusive");
310 usage();
311 }
312 if (existing_only && !list_files && !list_all) {
313 warnx("-E requires -l or -L");
314 usage();
315 }
316 if (set_knobs && remove_mode) {
317 warnx("-s and -x are mutually exclusive");
318 usage();
319 }
320
321 #ifdef __FreeBSD__
322 if (jailname != NULL) {
323 int jid;
324
325 if ((jid = jail_getid(jailname)) < 0)
326 errx(EXIT_FAILURE, "%s", jail_errmsg);
327 if (jail_attach(jid) != 0)
328 err(EXIT_FAILURE, "jail_attach(%d)", jid);
329 }
330 #else
331 if (jailname != NULL)
332 errx(EXIT_FAILURE, "-j is not supported on this platform");
333 #endif
334
335 /* Resolve the target format and its backing files */
336 resolve_target(target);
337
338 /* `-k' requires a target with a module drop-in directory */
339 if (module != NULL) {
340 const struct bsdconf_format_def *def;
341 const struct bsdconf_source *source;
342 int has_moddir = 0;
343
344 def = bsdconf_format_lookup(format);
345 if (def != NULL && def->sources != NULL)
346 for (source = def->sources; source->path != NULL;
347 source++)
348 if (source->type == BSDCONF_SOURCE_MODDIR)
349 has_moddir = 1;
350 if (!has_moddir) {
351 warnx("target does not support -k");
352 usage();
353 }
354 }
355
356 /*
357 * `-d', `-D', and `-A' consult a body of defaults; only targets
358 * that have one support them (make.conf and friends have no
359 * defaults file, and no directive descriptions to give). The
360 * exception is `sysctl -d', whose descriptions come from the
361 * running kernel rather than any file.
362 */
363 {
364 const struct bsdconf_format_def *def;
365 int has_defaults;
366
367 def = bsdconf_format_lookup(format);
368 has_defaults = def != NULL && def->defaults != NULL;
369
370 if (show_desc) {
371 if (format != BSDCONF_FORMAT_SYSCTL &&
372 !has_defaults) {
373 warnx("target does not support -d");
374 usage();
375 }
376 if (file != NULL) {
377 warnx("-d and -f are mutually exclusive");
378 usage();
379 }
380 if (list_files || list_all || remove_mode || check ||
381 set_knobs) {
382 warnx("-d cannot be combined with "
383 "-c/-l/-L/-s/-x");
384 usage();
385 }
386 #ifdef __FreeBSD__
387 if (format == BSDCONF_FORMAT_SYSCTL &&
388 *rootdir != '\0')
389 errx(EXIT_FAILURE, "sysctl descriptions "
390 "come from the running kernel; "
391 "-R does not apply");
392 #endif
393 }
394 if ((defaults_only || with_defaults) && !has_defaults) {
395 warnx("target does not support -%c",
396 defaults_only ? 'D' : 'A');
397 usage();
398 }
399 if ((defaults_only || with_defaults) && file != NULL) {
400 warnx("-%c and -f are mutually exclusive",
401 defaults_only ? 'D' : 'A');
402 usage();
403 }
404 }
405
406 /* File listings take no names and perform no other work */
407 if (list_files || list_all) {
408 if (argc != 0 || dump_all) {
409 warnx("-l/-L take no names");
410 usage();
411 }
412 exit(do_list());
413 }
414
415 /* `-A' with no names dumps everything, defaults included */
416 if (with_defaults && argc == 0)
417 dump_all = 1;
418
419 /* Display usage and exit if not given at least one name */
420 if (argc == 0 && !dump_all) {
421 warnx("no names provided");
422 usage();
423 }
424 if (argc != 0 && dump_all) {
425 warnx("-a does not take names");
426 usage();
427 }
428
429 /* Classify the remaining arguments */
430 nreqs = (unsigned int)argc;
431 if (nreqs > 0 &&
432 (reqs = calloc(nreqs, sizeof(*reqs))) == NULL)
433 err(EXIT_FAILURE, NULL);
434 if (set_knobs) {
435 if (format != BSDCONF_FORMAT_MAKE &&
436 format != BSDCONF_FORMAT_SRC) {
437 warnx("-s is only valid for make and src");
438 usage();
439 }
440 if (argc == 0) {
441 warnx("-s requires at least one WITH_/WITHOUT_ name");
442 usage();
443 }
444 }
445 for (n = 0; n < argc; n++) {
446 split_request(argv[n], &reqs[n], remove_mode);
447 if (set_knobs) {
448 if (reqs[n].newvalue != NULL) {
449 warnx("-s does not take a value "
450 "('%s')", argv[n]);
451 usage();
452 }
453 if (!make_knob_name_p(reqs[n].name)) {
454 if (strcmp(reqs[n].name,
455 "WITHOUT_MODULES") == 0)
456 warnx("WITHOUT_MODULES takes a "
457 "module list; use "
458 "WITHOUT_MODULES=...");
459 else
460 warnx("-s requires a WITH_ or "
461 "WITHOUT_ name ('%s')",
462 reqs[n].name);
463 usage();
464 }
465 reqs[n].newvalue = "";
466 }
467 if (reqs[n].newvalue != NULL && !reqs[n].remove)
468 warn_with_equals_no(reqs[n].name,
469 reqs[n].newvalue, NULL, 0);
470 if (reqs[n].remove || reqs[n].newvalue != NULL)
471 have_writes = 1;
472 else
473 have_reads = 1;
474 }
475 if (check && !have_writes) {
476 warnx("-c requires at least one name=value or -s name");
477 usage();
478 }
479
480 /* Descriptions are read-only */
481 if (show_desc) {
482 if (have_writes) {
483 warnx("-d does not take values");
484 usage();
485 }
486 #ifndef __FreeBSD__
487 if (format == BSDCONF_FORMAT_SYSCTL)
488 errx(EXIT_FAILURE,
489 "sysctl descriptions require FreeBSD");
490 #endif
491 /* Explicit names need no file scan at all */
492 if (!dump_all) {
493 #ifdef __FreeBSD__
494 if (format == BSDCONF_FORMAT_SYSCTL)
495 exit(describe_sysctl());
496 #endif
497 exit(describe_defaults());
498 }
499
500 /*
501 * Dumps (-ad, -Ad, -aDd) pair each scanned directive with
502 * its description; harvest the descriptions before the
503 * read sandbox slams shut.
504 */
505 if (format != BSDCONF_FORMAT_SYSCTL)
506 load_descriptions();
507 }
508
509 /* Defaults can be read and checked against, never rewritten */
510 if ((defaults_only || with_defaults) && have_writes && !check)
511 errx(EXIT_FAILURE, "defaults are read-only");
512
513 /* Standard input can be read and checked, never rewritten */
514 if (file_stdin && have_writes && !check)
515 errx(EXIT_FAILURE, "cannot write to standard input");
516
517 #if defined(__FreeBSD__)
518 /*
519 * Refuse up front to set sysctl OIDs that can never take effect
520 * from sysctl.conf(5) (non-leaf, read-only, loader-only tunables)
521 * or whose values cannot fit the OID's CTLTYPE (so an overflowing
522 * assignment cannot surprise sysctl(8) at boot). Unknown OIDs are
523 * warned about but still written -- the module may not be loaded
524 * yet, matching init(8)'s handling of sysctl.conf(5). Only
525 * meaningful against the running system's sysctl tree, so skipped
526 * under -R. -i/-q quiet the unknown-OID warning; -k remains the
527 * module drop-in selector.
528 */
529 if (format == BSDCONF_FORMAT_SYSCTL && have_writes && !check &&
530 *rootdir == '\0') {
531 int quiet_unknown = ignore_unknown || quiet;
532 unsigned int u;
533
534 for (u = 0; u < nreqs; u++) {
535 if (reqs[u].newvalue == NULL)
536 continue;
537 if (sysctl_writable(reqs[u].name, reqs[u].newvalue,
538 quiet_unknown) != 0) {
539 /* Convert to a no-op; count the failure */
540 reqs[u].newvalue = NULL;
541 reqs[u].remove = 0;
542 reqs[u].name = "";
543 rv = EXIT_FAILURE;
544 }
545 }
546 have_writes = 0;
547 have_reads = 0;
548 for (u = 0; u < nreqs; u++) {
549 if (reqs[u].remove || reqs[u].newvalue != NULL)
550 have_writes = 1;
551 else if (reqs[u].name[0] != '\0')
552 have_reads = 1;
553 }
554 if (rv != EXIT_SUCCESS && !have_writes && !have_reads)
555 exit(rv); /* nothing settable remains */
556 }
557 #endif
558
559 /*
560 * Scan the backing files to locate each request's authoritative
561 * definition. Pure reads and -c checks (do_checks() never calls
562 * put) run the scan inside a Capsicum sandbox -- except a sysctl
563 * description dump, whose kernel queries the sandbox would deny.
564 * Classify by whether we will actually write, not by whether the
565 * argv looked like name=value (`-c' sets have_writes for checks).
566 */
567 scan_pass((check || !have_writes) &&
568 !(show_desc && format == BSDCONF_FORMAT_SYSCTL));
569
570 /* Materialize list edits now that effective values are known */
571 if (merge_list_requests() != EXIT_SUCCESS)
572 rv = EXIT_FAILURE;
573
574 if (check) {
575 if (do_make_strikes(1) != EXIT_SUCCESS)
576 rv = EXIT_FAILURE;
577 if (do_checks() != EXIT_SUCCESS)
578 rv = EXIT_FAILURE;
579 exit(rv);
580 }
581
582 /* Apply writes first so that subsequent reads see the result */
583 if (have_writes) {
584 int wrv;
585
586 if ((wrv = do_make_strikes(0)) != EXIT_SUCCESS)
587 rv = wrv;
588 if ((wrv = do_writes()) != EXIT_SUCCESS)
589 rv = wrv;
590
591 /* Refresh the scan for any trailing read requests */
592 if (have_reads || dump_all) {
593 for (n = 0; (unsigned int)n < nreqs; n++) {
594 size_t ai;
595
596 trail_free(reqs[n].trail, reqs[n].ntrail);
597 reqs[n].trail = NULL;
598 reqs[n].ntrail = 0;
599 for (ai = 0; ai < reqs[n].nassigns; ai++)
600 free(reqs[n].assigns[ai].piece);
601 free(reqs[n].assigns);
602 reqs[n].assigns = NULL;
603 reqs[n].nassigns = 0;
604 reqs[n].found = 0;
605 reqs[n].append_present = 0;
606 reqs[n].srcidx = -1;
607 reqs[n].line = 0;
608 memset(reqs[n].infile, 0, nconf_files);
609 }
610 scan_pass(0);
611 }
612 }
613
614 if (have_reads || dump_all) {
615 int rrv;
616
617 if ((rrv = do_reads()) != EXIT_SUCCESS)
618 rv = rrv;
619 }
620
621 exit(rv);
622 }
623
624 /*
625 * Print short usage statement to stderr and exit with error status.
626 */
627 void
usage(void)628 usage(void)
629 {
630
631 fprintf(stderr,
632 "usage: %s target [-AcDeFinNqsvVx] [-j jail | -R dir]"
633 " [-f file | -k module]\n"
634 " name[[+|-]=value] ...\n", pgm);
635 fprintf(stderr,
636 " %s target [-ADeFnNqvV] [-j jail | -R dir]"
637 " [-f file | -k module] -a\n", pgm);
638 fprintf(stderr,
639 " %s target [-AaDinNq] [-j jail | -R dir]"
640 " -d [name ...]\n", pgm);
641 fprintf(stderr,
642 " %s target [-E] [-j jail | -R dir] [-k module]"
643 " -l | -L\n", pgm);
644 fprintf(stderr,
645 " %s rc [sysrc(8) argument ...]\n", pgm);
646 fprintf(stderr, "Try `%s --help' for more information.\n", pgm);
647 exit(EXIT_FAILURE);
648 }
649
650 /*
651 * Print long usage statement to stderr and exit with error status.
652 */
653 void
help(void)654 help(void)
655 {
656
657 fprintf(stderr,
658 "usage: %s target [-AcDeFinNqsvVx] [-j jail | -R dir]"
659 " [-f file | -k module] name[[+|-]=value] ...\n", pgm);
660 fprintf(stderr, "TARGETS:\n");
661 #define TGTFMT "\t%-9s %s\n"
662 fprintf(stderr, TGTFMT, "loader",
663 "files named by loader_conf_files et al. in");
664 fprintf(stderr, TGTFMT, "",
665 "/boot/defaults/loader.conf (typically /boot/loader.conf,");
666 fprintf(stderr, TGTFMT, "",
667 "loader.conf.d/*.conf, loader.conf.local)");
668 fprintf(stderr, TGTFMT, "sysctl",
669 "/etc/sysctl.conf, sysctl.conf.local, sysctl.kld.d/*.conf");
670 fprintf(stderr, TGTFMT, "make",
671 "/etc/make.conf (or -f for any make-syntax file)");
672 fprintf(stderr, TGTFMT, "src",
673 "/usr/src build triad: src-env.conf, make.conf, src.conf");
674 fprintf(stderr, TGTFMT, "",
675 "(new writes prefer src.conf; env: SRC_ENV_CONF,");
676 fprintf(stderr, TGTFMT, "",
677 "__MAKE_CONF, SRCCONF)");
678 fprintf(stderr, TGTFMT, "rc",
679 "pass-through: all other arguments go to sysrc(8) verbatim");
680 fprintf(stderr, TGTFMT, "generic",
681 "no default files; requires -f file");
682 fprintf(stderr, "OPTIONS:\n");
683 #define OPTFMT "\t%-9s %s\n"
684 fprintf(stderr, OPTFMT, "-A",
685 "Include the target's defaults file in the sourcing order");
686 fprintf(stderr, OPTFMT, "",
687 "(alone, dumps everything, defaults included).");
688 fprintf(stderr, OPTFMT, "-a",
689 "Dump the union of all directives from the target's files.");
690 fprintf(stderr, OPTFMT, "-c",
691 "Check. Return success if no changes needed, else error.");
692 fprintf(stderr, OPTFMT, "-D",
693 "Consult only the target's defaults file.");
694 fprintf(stderr, OPTFMT, "-d",
695 "Show directive descriptions (from the defaults file's");
696 fprintf(stderr, OPTFMT, "",
697 "comments; for sysctl, from the running kernel). With");
698 fprintf(stderr, OPTFMT, "",
699 "-a, -A, or -D, describe every directive in scope.");
700 fprintf(stderr, OPTFMT, "-E",
701 "With -l or -L, list only files that exist on disk.");
702 fprintf(stderr, OPTFMT, "-e",
703 "Separate name and value with `=' (reads and write echoes).");
704 fprintf(stderr, OPTFMT, "-F",
705 "Show the file holding each directive's effective value.");
706 fprintf(stderr, OPTFMT, "-f file",
707 "Operate on file, in the target's format, instead of the");
708 fprintf(stderr, OPTFMT, "",
709 "target's standard files (`-' means standard input).");
710 fprintf(stderr, OPTFMT, "-h",
711 "Print a short usage statement to stderr and exit.");
712 fprintf(stderr, OPTFMT, "--help",
713 "Print this message to stderr and exit.");
714 fprintf(stderr, OPTFMT, "--version",
715 "Print the utility and library versions and exit.");
716 fprintf(stderr, OPTFMT, "-i",
717 "Ignore unknown names (and quiet unknown sysctl OID warnings).");
718 fprintf(stderr, OPTFMT, "-j jail",
719 "Operate within the jail `jail' (name or numeric id).");
720 fprintf(stderr, OPTFMT, "-k module",
721 "Include the kernel module drop-in file for `module'.");
722 fprintf(stderr, OPTFMT, "-l",
723 "List the pathnames of the target's backing files.");
724 fprintf(stderr, OPTFMT, "-L",
725 "List all candidate files, including module drop-ins.");
726 fprintf(stderr, OPTFMT, "-n",
727 "Show only directive values, not their names.");
728 fprintf(stderr, OPTFMT, "-N",
729 "Show only directive names, not their values.");
730 fprintf(stderr, OPTFMT, "-q",
731 "Quiet. Suppress unknown-directive warnings and the");
732 fprintf(stderr, OPTFMT, "",
733 "`old -> new' echo of writes.");
734 fprintf(stderr, OPTFMT, "-R dir",
735 "Operate within the root directory `dir' rather than `/'.");
736 fprintf(stderr, OPTFMT, "-s",
737 "Set empty WITH_/WITHOUT_ knobs (make and src only).");
738 fprintf(stderr, OPTFMT, "-v",
739 "Verbose. Print the pathname of the configuration file");
740 fprintf(stderr, OPTFMT, "",
741 "holding the final effective value.");
742 fprintf(stderr, OPTFMT, "-V",
743 "Trail. Reads: each assignment step (file:line, operator,");
744 fprintf(stderr, OPTFMT, "",
745 "fragment, running effective). Writes: file:line:");
746 fprintf(stderr, OPTFMT, "",
747 "name=old -> name=new (or name=value (unchanged)).");
748 fprintf(stderr, OPTFMT, "-x",
749 "Remove name(s) from the target's files.");
750 fprintf(stderr, "ENVIRONMENT:\n");
751 fprintf(stderr, OPTFMT, "LOADER_DEFAULTS",
752 "Defaults file for the loader target (in place of");
753 fprintf(stderr, OPTFMT, "",
754 "/boot/defaults/loader.conf).");
755 fprintf(stderr, OPTFMT, "SRC_ENV_CONF",
756 "src-env.conf for the src target (default /etc/src-env.conf).");
757 fprintf(stderr, OPTFMT, "__MAKE_CONF",
758 "make.conf for the src target (default /etc/make.conf).");
759 fprintf(stderr, OPTFMT, "SRCCONF",
760 "src.conf for the src target (default /etc/src.conf).");
761 exit(EXIT_FAILURE);
762 }
763