]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/sysrc/sysrc
MFC r287383: Comment for escape() function.
[FreeBSD/stable/10.git] / usr.sbin / sysrc / sysrc
1 #!/bin/sh
2 #-
3 # Copyright (c) 2010-2015 Devin Teske
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 # SUCH DAMAGE.
26 #
27 # $FreeBSD$
28 #
29 ############################################################ INCLUDES
30
31 # Prevent `-d' from being interpreted as a debug flag by common.subr
32 DEBUG_SELF_INITIALIZE=
33
34 BSDCFG_SHARE="/usr/share/bsdconfig"
35 [ "$_COMMON_SUBR" ] || . $BSDCFG_SHARE/common.subr || exit 1
36 [ "$_SYSRC_SUBR"  ] || f_include $BSDCFG_SHARE/sysrc.subr
37
38 ############################################################ GLOBALS
39
40 #
41 # Version information
42 #
43 SYSRC_VERSION="6.3 Mar-4,2015"
44
45 #
46 # Options
47 #
48 CHECK_ONLY=
49 DELETE=
50 DESCRIBE=
51 IGNORE_UNKNOWNS=
52 JAIL=
53 QUIET=
54 ROOTDIR=
55 SHOW_ALL=
56 SHOW_EQUALS=
57 SHOW_FILE=
58 SHOW_NAME=1
59 SHOW_VALUE=1
60 VERBOSE=
61
62 ############################################################ FUNCTIONS
63
64 # die [ $fmt [ $opts ... ]]
65 #
66 # Optionally print a message to stderr before exiting with failure status.
67 #
68 die()
69 {
70         local fmt="$1"
71         [ $# -gt 0 ] && shift 1
72         [  "$fmt"  ] && f_err "$fmt\n" "$@"
73
74         exit $FAILURE
75 }
76
77 # usage
78 #
79 # Prints a short syntax statement and exits.
80 #
81 usage()
82 {
83         f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm"
84         f_err "Try \`%s --help' for more information.\n" "$pgm"
85         die
86 }
87
88 # help
89 #
90 # Prints a full syntax statement and exits.
91 #
92 help()
93 {
94         local optfmt="\t%-11s%s\n"
95         local envfmt="\t%-17s%s\n"
96
97         f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm"
98
99         f_err "OPTIONS:\n"
100         f_err "$optfmt" "-a" \
101               "Dump a list of all non-default configuration variables."
102         f_err "$optfmt" "-A" \
103               "Dump a list of all configuration variables (incl. defaults)."
104         f_err "$optfmt" "-c" \
105               "Check. Return success if set or no changes, else error."
106         f_err "$optfmt" "-d" \
107               "Print a description of the given variable."
108         f_err "$optfmt" "-D" \
109               "Show default value(s) only (this is the same as setting"
110         f_err "$optfmt" "" \
111               "RC_CONFS to NULL or passing \`-f' with a NULL file-argument)."
112         f_err "$optfmt" "-e" \
113               "Print query results as \`var=value' (useful for producing"
114         f_err "$optfmt" "" \
115               "output to be fed back in). Ignored if \`-n' is specified."
116         f_err "$optfmt" "-f file" \
117               "Operate on the specified file(s) instead of rc_conf_files."
118         f_err "$optfmt" "" \
119               "Can be specified multiple times for additional files."
120         f_err "$optfmt" "-F" \
121               "Show only the last rc.conf(5) file each directive is in."
122         f_err "$optfmt" "-h" \
123               "Print a short usage statement to stderr and exit."
124         f_err "$optfmt" "--help" \
125               "Print this message to stderr and exit."
126         f_err "$optfmt" "-i" \
127               "Ignore unknown variables."
128         f_err "$optfmt" "-j jail" \
129               "The jid or name of the jail to operate within (overrides"
130         f_err "$optfmt" "" \
131               "\`-R dir'; requires jexec(8))."
132         f_err "$optfmt" "-n" \
133               "Show only variable values, not their names."
134         f_err "$optfmt" "-N" \
135               "Show only variable names, not their values."
136         f_err "$optfmt" "-q" \
137               "Quiet. Disable verbose and hide certain errors."
138         f_err "$optfmt" "-R dir" \
139               "Operate within the root directory \`dir' rather than \`/'."
140         f_err "$optfmt" "-v" \
141               "Verbose. Print the pathname of the specific rc.conf(5)"
142         f_err "$optfmt" "" \
143               "file where the directive was found."
144         f_err "$optfmt" "--version" \
145               "Print version information to stdout and exit."
146         f_err "$optfmt" "-x" \
147               "Remove variable(s) from specified file(s)."
148         f_err "\n"
149
150         f_err "ENVIRONMENT:\n"
151         f_err "$envfmt" "RC_CONFS" \
152               "Override default rc_conf_files (even if set to NULL)."
153         f_err "$envfmt" "RC_DEFAULTS" \
154               "Location of \`/etc/defaults/rc.conf' file."
155
156         die
157 }
158
159 # jail_depend
160 #
161 # Dump dependencies such as language-file variables and include files to stdout
162 # to be piped-into sh(1) running via jexec(8)/chroot(8). As a security measure,
163 # this prevents existing language files and library files from being loaded in
164 # the jail. This also relaxes the requirement to have these files in every jail
165 # before sysrc can be used on said jail.
166 #
167 jail_depend()
168 {
169         #
170         # Indicate that we are jailed
171         #
172         echo export _SYSRC_JAILED=1
173
174         #
175         # Print i18n language variables (their current values are sanitized
176         # and re-printed for interpretation so that the i18n language files
177         # do not need to exist within the jail).
178         #
179         local var val
180         for var in \
181                 msg_cannot_create_permission_denied \
182                 msg_permission_denied \
183                 msg_previous_syntax_errors \
184         ; do
185                 val=$( eval echo \"\$$var\" |
186                         awk '{ gsub(/'\''/, "'\''\\'\'\''"); print }' )
187                 echo $var="'$val'"
188         done
189
190         #
191         # Print include dependencies
192         #
193         echo DEBUG_SELF_INITIALIZE=
194         cat $BSDCFG_SHARE/common.subr
195         cat $BSDCFG_SHARE/sysrc.subr
196 }
197
198 # escape $string [$var_to_set]
199 #
200 # Escape $string contents so that the contents can be properly encapsulated in
201 # single-quotes (making for safe evaluation).
202 #
203 # NB: See `bsdconfig includes -dF escape' for relevant information/discussion.
204 # NB: Abridged version of `f_shell_escape()' from bsdconfig(8) `strings.subr'.
205 #
206 escape()
207 {
208         local __start="$1" __var_to_set="$2" __string=
209         while [ "$__start" ]; do
210                 case "$__start" in *\'*)
211                         __string="$__string${__start%%\'*}'\\''"
212                         __start="${__start#*\'}" continue
213                 esac
214                 break
215         done
216         __string="$__string$__start"
217         if [ "$__var_to_set" ]; then
218                 setvar "$__var_to_set" "$__string"
219         else
220                 echo "$__string"
221         fi
222 }
223
224 ############################################################ MAIN SOURCE
225
226 #
227 # Perform sanity checks
228 #
229 [ $# -gt 0 ] || usage # NOTREACHED
230
231 #
232 # Check for `--help' and `--version' command-line option
233 #
234 ( # Operate in sub-shell to protect $@ in parent
235         while [ $# -gt 0 ]; do
236                 case "$1" in
237                 --help) help ;;
238                 --version) # see GLOBALS
239                         echo "$SYSRC_VERSION"
240                         exit 1 ;;
241                 -[fRj]) # These flags take an argument
242                         shift 1 ;;
243                 esac
244                 shift 1
245         done
246         exit 0
247 ) || die
248
249 #
250 # Process command-line flags
251 #
252 while getopts aAcdDef:Fhij:nNqR:vxX flag; do
253         case "$flag" in
254         a) SHOW_ALL=${SHOW_ALL:-1} ;;
255         A) SHOW_ALL=2 ;;
256         c) CHECK_ONLY=1 ;;
257         d) DESCRIBE=1 ;;
258         D) RC_CONFS= ;;
259         e) SHOW_EQUALS=1 ;;
260         f) RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;;
261         F) SHOW_FILE=1 ;;
262         h) usage ;; # NOTREACHED
263         i) IGNORE_UNKNOWNS=1 ;;
264         j) [ "$OPTARG" ] || die \
265                 "%s: Missing or null argument to \`-j' flag" "$pgm"
266            JAIL="$OPTARG" ;;
267         n) SHOW_NAME= ;;
268         N) SHOW_VALUE= ;;
269         q) QUIET=1 VERBOSE= ;;
270         R) [ "$OPTARG" ] || die \
271                 "%s: Missing or null argument to \`-R' flag" "$pgm"
272            ROOTDIR="$OPTARG" ;;
273         v) VERBOSE=1 QUIET= ;;
274         x) DELETE=${DELETE:-1} ;;
275         X) DELETE=2 ;;
276         \?) usage ;; # NOTREACHED
277         esac
278 done
279 shift $(( $OPTIND - 1 ))
280
281 #
282 # [More] Sanity checks (e.g., "sysrc --")
283 #
284 [ $# -eq 0 -a ! "$SHOW_ALL" ] && usage # NOTREACHED
285
286 #
287 # Taint-check all rc.conf(5) files
288 #
289 errmsg="$pgm: Exiting due to previous syntax errors"
290 if [ "${RC_CONFS+set}" ]; then
291         ( for i in $RC_CONFS; do
292                 [ -e "$i" ] || continue
293                 /bin/sh -n "$i" || exit $FAILURE
294           done
295           exit $SUCCESS
296         ) || die "$errmsg"
297 else
298         /bin/sh -n "$RC_DEFAULTS" || die "$errmsg"
299         ( . "$RC_DEFAULTS"
300           for i in $rc_conf_files; do
301                 [ -e "$i" ] || continue
302                 /bin/sh -n "$i" || exit $FAILURE
303           done
304           exit $SUCCESS
305         ) || die "$errmsg"
306 fi
307
308 #
309 # Process `-x' (and secret `-X') command-line options
310 #
311 errmsg="$pgm: \`-x' option incompatible with \`-a'/\`-A' options"
312 errmsg="$errmsg (use \`-X' to override)"
313 if [ "$DELETE" -a "$SHOW_ALL" ]; then
314         [ "$DELETE" = "2" ] || die "$errmsg"
315 fi
316
317 #
318 # Pre-flight for `-c' command-line option
319 #
320 [ "$CHECK_ONLY" -a "$SHOW_ALL" ] &&
321         die "$pgm: \`-c' option incompatible with \`-a'/\`-A' options"
322
323 #
324 # Process `-e', `-n', and `-N' command-line options
325 #
326 SEP=': '
327 [ "$SHOW_FILE" ] && SHOW_EQUALS=
328 [ "$SHOW_NAME" ] || SHOW_EQUALS=
329 [ "$VERBOSE" = "0" ] && VERBOSE=
330 if [ ! "$SHOW_VALUE" ]; then
331         SHOW_NAME=1
332         SHOW_EQUALS=
333 fi
334 [ "$SHOW_EQUALS" ] && SEP='="'
335
336 #
337 # Process `-j jail' and `-R dir' command-line options
338 #
339 if [ "$JAIL" -o "$ROOTDIR" ]; then
340         #
341         # Reconstruct the arguments that we want to carry-over
342         #
343         args="
344                 ${VERBOSE:+-v}
345                 ${QUIET:+-q}
346                 $( [ "$DELETE" = "1" ] && echo \ -x )
347                 $( [ "$DELETE" = "2" ] && echo \ -X )
348                 $( [ "$SHOW_ALL" = "1" ] && echo \ -a )
349                 $( [ "$SHOW_ALL" = "2" ] && echo \ -A )
350                 ${CHECK_ONLY:+-c}
351                 ${DESCRIBE:+-d}
352                 ${SHOW_EQUALS:+-e}
353                 ${IGNORE_UNKNOWNS:+-i}
354                 $( [ "$SHOW_NAME"  ] || echo \ -n )
355                 $( [ "$SHOW_VALUE" ] || echo \ -N )
356                 $( [ "$SHOW_FILE"  ] && echo \ -F )
357         "
358         if [ "${RC_CONFS+set}" ]; then
359                 escape "$RC_CONFS" _RC_CONFS
360                 args="$args -f '$_RC_CONFS'"
361                 unset _RC_CONFS
362         fi
363         for arg in "$@"; do
364                 escape "$arg" arg
365                 args="$args '$arg'"
366         done
367
368         #
369         # If both are supplied, `-j jail' supercedes `-R dir'
370         #
371         if [ "$JAIL" ]; then
372                 #
373                 # Re-execute ourselves with sh(1) via jexec(8)
374                 #
375                 ( echo set -- $args
376                   jail_depend
377                   cat $0
378                 ) | env - RC_DEFAULTS="$RC_DEFAULTS" \
379                         /usr/sbin/jexec "$JAIL" /bin/sh
380                 exit $?
381         elif [ "$ROOTDIR" ]; then
382                 #
383                 # Make sure that the root directory specified is not to any
384                 # running jails.
385                 #
386                 # NOTE: To maintain backward compatibility with older jails on
387                 # older systems, we will not perform this check if either the
388                 # jls(1) or jexec(8) utilities are missing.
389                 #
390                 if f_have jexec && f_have jls; then
391                         jid="`jls jid path | \
392                         (
393                                 while read JID JROOT; do
394                                         [ "$JROOT" = "$ROOTDIR" ] || continue
395                                         echo $JID
396                                 done
397                         )`"
398
399                         #
400                         # If multiple running jails match the specified root
401                         # directory, exit with error.
402                         #
403                         if [ "$jid" -a "${jid%[$IFS]*}" != "$jid" ]; then
404                                 die "%s: %s: %s" "$pgm" "$ROOTDIR" \
405                                     "$( echo "Multiple jails claim this" \
406                                              "directory as their root." \
407                                              "(use \`-j jail' instead)" )"
408                         fi
409
410                         #
411                         # If only a single running jail matches the specified
412                         # root directory, implicitly use `-j jail'.
413                         #
414                         if [ "$jid" ]; then
415                                 #
416                                 # Re-execute outselves with sh(1) via jexec(8)
417                                 #
418                                 ( echo set -- $args
419                                   jail_depend
420                                   cat $0
421                                 ) | env - RC_DEFAULTS="$RC_DEFAULTS" \
422                                         /usr/sbin/jexec "$jid" /bin/sh
423                                 exit $?
424                         fi
425
426                         # Otherwise, fall through and allow chroot(8)
427                 fi
428
429                 #
430                 # Re-execute ourselves with sh(1) via chroot(8)
431                 #
432                 ( echo set -- $args
433                   jail_depend
434                   cat $0
435                 ) | env - RC_DEFAULTS="$RC_DEFAULTS" \
436                         /usr/sbin/chroot "$ROOTDIR" /bin/sh
437                 exit $?
438         fi
439 fi
440
441 #
442 # Process `-a' or `-A' command-line options
443 #
444 if [ "$SHOW_ALL" ]; then
445         #
446         # Get a list of variables that are currently set in the rc.conf(5)
447         # files (included `/etc/defaults/rc.conf') by performing a call to
448         # source_rc_confs() in a clean environment.
449         #
450         ( # Operate in a sub-shell to protect the parent environment
451                 #
452                 # Set which variables we want to preserve in the environment.
453                 # Append the pipe-character (|) to the list of internal field
454                 # separation (IFS) characters, allowing us to use the below
455                 # list both as an extended grep (-E) pattern and argument list
456                 # (required to first get f_clean_env() to preserve these in the
457                 # environment and then later to prune them from the list of
458                 # variables produced by set(1)).
459                 #
460                 IFS="$IFS|"
461                 EXCEPT="IFS|EXCEPT|PATH|RC_DEFAULTS|OPTIND|DESCRIBE|SEP"
462                 EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME"
463                 EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS"
464                 EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY"
465                 EXCEPT="$EXCEPT|f_sysrc_desc_awk|f_sysrc_delete_awk"
466
467                 #
468                 # Clean the environment (except for our required variables)
469                 # and then source the required files.
470                 #
471                 f_clean_env --except $EXCEPT
472                 if [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ]; then
473                         . "$RC_DEFAULTS"
474
475                         #
476                         # If passed `-a' (rather than `-A'), re-purge the
477                         # environment, removing the rc.conf(5) defaults.
478                         #
479                         [ "$SHOW_ALL" = "1" ] \
480                                 && f_clean_env --except rc_conf_files $EXCEPT
481
482                         #
483                         # If `-f file' was passed, set $rc_conf_files to an
484                         # explicit value, modifying the default behavior of
485                         # source_rc_confs().
486                         #
487                         [ "${RC_CONFS+set}" ] && rc_conf_files="$RC_CONFS"
488
489                         source_rc_confs
490
491                         #
492                         # If passed `-a' (rather than `-A'), remove
493                         # `rc_conf_files' unless it was defined somewhere
494                         # other than rc.conf(5) defaults.
495                         #
496                         [ "$SHOW_ALL" = "1" -a \
497                           "$( f_sysrc_find rc_conf_files )" = "$RC_DEFAULTS" \
498                         ] \
499                         && unset rc_conf_files
500                 fi
501
502                 for NAME in $( set |
503                         awk -F= '/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' |
504                         grep -Ev "^($EXCEPT)$"
505                 ); do
506                         #
507                         # If enabled, describe rather than expand value
508                         #
509                         if [ "$DESCRIBE" ]; then
510                                 echo "$NAME: $( f_sysrc_desc "$NAME" )"
511                                 continue
512                         fi
513
514                         #
515                         # If `-F' is passed, find it and move on
516                         #
517                         if [ "$SHOW_FILE" ]; then
518                                 [ "$SHOW_NAME" ] && echo -n "$NAME: "
519                                 f_sysrc_find "$NAME"
520                                 continue
521                         fi
522
523                         #
524                         # If `-X' is passed, delete the variables
525                         #
526                         if [ "$DELETE" = "2" ]; then
527                                 f_sysrc_delete "$NAME"
528                                 continue
529                         fi
530
531                         [ "$VERBOSE" ] && \
532                                 echo -n "$( f_sysrc_find "$NAME" ): "
533
534                         #
535                         # If `-N' is passed, simplify the output
536                         #
537                         if [ ! "$SHOW_VALUE" ]; then
538                                 echo "$NAME"
539                                 continue
540                         fi
541
542                         echo "${SHOW_NAME:+$NAME$SEP}$(
543                               f_sysrc_get "$NAME" )${SHOW_EQUALS:+\"}"
544
545                 done
546         )
547
548         #
549         # Ignore the remainder of positional arguments.
550         #
551         exit $SUCCESS
552 fi
553
554 #
555 # Process command-line arguments
556 #
557 status=$SUCCESS
558 while [ $# -gt 0 ]; do
559         NAME="${1%%=*}"
560
561         case "$NAME" in
562         *+) mode=APPEND NAME="${NAME%+}" ;;
563         *-) mode=REMOVE NAME="${NAME%-}" ;;
564          *) mode=ASSIGN
565         esac
566
567         [ "$DESCRIBE" ] && \
568                 echo "$NAME: $( f_sysrc_desc "$NAME" )"
569
570         case "$1" in
571         *=*)
572                 #
573                 # Like sysctl(8), if both `-d' AND "name=value" is passed,
574                 # first describe (done above), then attempt to set
575                 #
576
577                 # If verbose, prefix line with where the directive lives
578                 if [ "$VERBOSE" -a ! "$CHECK_ONLY" ]; then
579                         file=$( f_sysrc_find "$NAME" )
580                         [ "$file" = "$RC_DEFAULTS" -o ! "$file" ] && \
581                                 file=$( f_sysrc_get 'rc_conf_files%%[$IFS]*' )
582                         if [ "$SHOW_EQUALS" ]; then
583                                 echo -n ": $file; "
584                         else
585                                 echo -n "$file: "
586                         fi
587                 fi
588
589                 #
590                 # If `-x' or `-X' is passed, delete the variable and ignore the
591                 # desire to set some value
592                 #
593                 if [ "$DELETE" ]; then
594                         f_sysrc_delete "$NAME" || status=$FAILURE
595                         shift 1
596                         continue
597                 fi
598
599                 #
600                 # If `-c' is passed, simply compare and move on
601                 #
602                 if [ "$CHECK_ONLY" ]; then
603                         if ! IGNORED=$( f_sysrc_get "$NAME?" ); then
604                                 status=$FAILURE
605                                 [ "$VERBOSE" ] &&
606                                         echo "$NAME: not currently set"
607                                 shift 1
608                                 continue
609                         fi
610                         value=$( f_sysrc_get "$NAME" )
611                         if [ "$value" != "${1#*=}" ]; then
612                                 status=$FAILURE
613                                 if [ "$VERBOSE" ]; then
614                                         echo -n "$( f_sysrc_find "$NAME" ): "
615                                         echo -n "$NAME: would change from "
616                                         echo "\`$value' to \`${1#*=}'"
617                                 fi
618                         elif [ "$VERBOSE" ]; then
619                                 echo -n "$( f_sysrc_find "$NAME" ): "
620                                 echo "$NAME: already set to \`$value'"
621                         fi
622                         shift 1
623                         continue
624                 fi
625
626                 #
627                 # Determine both `before' value and appropriate `new' value
628                 #
629                 case "$mode" in
630                 APPEND)
631                         before=$( f_sysrc_get "$NAME" )
632                         add="${1#*=}"
633                         delim="${add%"${add#?}"}" # first character
634                         oldIFS="$IFS"
635                         case "$delim" in
636                         ""|[$IFS]|[a-zA-Z0-9]) delim=" " ;;
637                         *) IFS="$delim"
638                         esac
639                         new="$before"
640                         for a in $add; do
641                                 [ "$a" ] || continue
642                                 skip=
643                                 for b in $before; do
644                                         [ "$b" = "$a" ] && skip=1 break
645                                 done
646                                 [ "$skip" ] || new="$new$delim$a"
647                         done
648                         new="${new#"$delim"}" IFS="$oldIFS"
649                         unset add delim oldIFS a skip b
650                         [ "$SHOW_FILE" ] && before=$( f_sysrc_find "$NAME" )
651                         ;;
652                 REMOVE)
653                         before=$( f_sysrc_get "$NAME" )
654                         remove="${1#*=}"
655                         delim="${remove%"${remove#?}"}" # first character
656                         oldIFS="$IFS"
657                         case "$delim" in
658                         ""|[$IFS]|[a-zA-Z0-9]) delim=" " ;;
659                         *) IFS="$delim"
660                         esac
661                         new=
662                         for b in $before; do
663                                 [ "$b" ] || continue
664                                 add=1
665                                 for r in $remove; do
666                                         [ "$r" = "$b" ] && add= break
667                                 done
668                                 [ "$add" ] && new="$new$delim$b"
669                         done
670                         new="${new#"$delim"}" IFS="$oldIFS"
671                         unset remove delim oldIFS b add r
672                         [ "$SHOW_FILE" ] && before=$( f_sysrc_find "$NAME" )
673                         ;;
674                 *) # ASSIGN
675                         if [ "$SHOW_FILE" ]; then
676                                 before=$( f_sysrc_find "$NAME" )
677                         else
678                                 before=$( f_sysrc_get "$NAME" )
679                         fi
680                         new="${1#*=}"
681                 esac
682
683                 #
684                 # If `-N' is passed, simplify the output
685                 #
686                 if [ ! "$SHOW_VALUE" ]; then
687                         echo "$NAME"
688                         f_sysrc_set "$NAME" "$new"
689                 else
690                         if f_sysrc_set "$NAME" "$new"; then
691                                 if [ "$SHOW_FILE" ]; then
692                                         after=$( f_sysrc_find "$NAME" )
693                                 else
694                                         after=$( f_sysrc_get "$NAME" )
695                                 fi
696                                 echo -n "${SHOW_NAME:+$NAME$SEP}"
697                                 echo -n "$before${SHOW_EQUALS:+\" #}"
698                                 echo -n " -> ${SHOW_EQUALS:+\"}$after"
699                                 echo "${SHOW_EQUALS:+\"}"
700                         fi
701                 fi
702                 ;;
703         *)
704                 if ! IGNORED=$( f_sysrc_get "$NAME?" ); then
705                         [ "$IGNORE_UNKNOWNS" -o "$QUIET" ] ||
706                                 echo "$pgm: unknown variable '$NAME'"
707                         shift 1
708                         status=$FAILURE
709                         continue
710                 fi
711
712                 # The above check told us what we needed for `-c'
713                 if [ "$CHECK_ONLY" ]; then
714                         shift 1
715                         continue
716                 fi
717
718                 #
719                 # Like sysctl(8), when `-d' is passed, desribe it
720                 # (already done above) rather than expanding it
721                 #
722
723                 if [ "$DESCRIBE" ]; then
724                         shift 1
725                         continue
726                 fi
727
728                 #
729                 # If `-x' or `-X' is passed, delete the variable
730                 #
731                 if [ "$DELETE" ]; then
732                         f_sysrc_delete "$NAME" || status=$FAILURE
733                         shift 1
734                         continue
735                 fi
736
737                 #
738                 # If `-F' is passed, find it and move on
739                 #
740                 if [ "$SHOW_FILE" ]; then
741                         [ "$SHOW_NAME" ] && echo -n "$NAME: "
742                         f_sysrc_find "$NAME"
743                         shift 1
744                         continue
745                 fi
746
747                 if [ "$VERBOSE" ]; then
748                         if [ "$SHOW_EQUALS" ]; then
749                                 echo -n ": $( f_sysrc_find "$NAME" ); "
750                         else
751                                 echo -n "$( f_sysrc_find "$NAME" ): "
752                         fi
753                 fi
754
755                 #
756                 # If `-N' is passed, simplify the output
757                 #
758                 if [ ! "$SHOW_VALUE" ]; then
759                         echo "$NAME"
760                 else
761                         echo "${SHOW_NAME:+$NAME$SEP}$(
762                               f_sysrc_get "$NAME" )${SHOW_EQUALS:+\"}"
763                 fi
764         esac
765         shift 1
766 done
767
768 exit $status # $SUCCESS unless error occurred with either `-c' or `-x'
769
770 ################################################################################
771 # END
772 ################################################################################