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