Index: head/usr.sbin/sysrc/sysrc =================================================================== --- head/usr.sbin/sysrc/sysrc (revision 279623) +++ head/usr.sbin/sysrc/sysrc (revision 279624) @@ -1,701 +1,743 @@ #!/bin/sh #- -# Copyright (c) 2010-2014 Devin Teske +# Copyright (c) 2010-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # ############################################################ INCLUDES # Prevent `-d' from being interpreted as a debug flag by common.subr DEBUG_SELF_INITIALIZE= BSDCFG_SHARE="/usr/share/bsdconfig" [ "$_COMMON_SUBR" ] || . $BSDCFG_SHARE/common.subr || exit 1 [ "$_SYSRC_SUBR" ] || f_include $BSDCFG_SHARE/sysrc.subr ############################################################ GLOBALS # # Version information # -SYSRC_VERSION="6.2 Nov-3,2014" +SYSRC_VERSION="6.3 Mar-4,2015" # # Options # CHECK_ONLY= DELETE= DESCRIBE= IGNORE_UNKNOWNS= JAIL= QUIET= ROOTDIR= SHOW_ALL= SHOW_EQUALS= SHOW_FILE= SHOW_NAME=1 SHOW_VALUE=1 SYSRC_VERBOSE= ############################################################ FUNCTIONS # die [ $fmt [ $opts ... ]] # # Optionally print a message to stderr before exiting with failure status. # die() { local fmt="$1" [ $# -gt 0 ] && shift 1 [ "$fmt" ] && f_err "$fmt\n" "$@" exit $FAILURE } # usage # # Prints a short syntax statement and exits. # usage() { f_err "Usage: %s [OPTIONS] name[[+]=value] ...\n" "$pgm" f_err "Try \`%s --help' for more information.\n" "$pgm" die } # help # # Prints a full syntax statement and exits. # help() { local optfmt="\t%-11s%s\n" local envfmt="\t%-17s%s\n" - f_err "Usage: %s [OPTIONS] name[[+]=value] ...\n" "$pgm" + f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm" f_err "OPTIONS:\n" f_err "$optfmt" "-a" \ "Dump a list of all non-default configuration variables." f_err "$optfmt" "-A" \ "Dump a list of all configuration variables (incl. defaults)." f_err "$optfmt" "-c" \ "Check. Return success if set or no changes, else error." f_err "$optfmt" "-d" \ "Print a description of the given variable." f_err "$optfmt" "-D" \ "Show default value(s) only (this is the same as setting" f_err "$optfmt" "" \ "RC_CONFS to NULL or passing \`-f' with a NULL file-argument)." f_err "$optfmt" "-e" \ "Print query results as \`var=value' (useful for producing" f_err "$optfmt" "" \ "output to be fed back in). Ignored if \`-n' is specified." f_err "$optfmt" "-f file" \ "Operate on the specified file(s) instead of rc_conf_files." f_err "$optfmt" "" \ "Can be specified multiple times for additional files." f_err "$optfmt" "-F" \ "Show only the last rc.conf(5) file each directive is in." f_err "$optfmt" "-h" \ "Print a short usage statement to stderr and exit." f_err "$optfmt" "--help" \ "Print this message to stderr and exit." f_err "$optfmt" "-i" \ "Ignore unknown variables." f_err "$optfmt" "-j jail" \ "The jid or name of the jail to operate within (overrides" f_err "$optfmt" "" \ "\`-R dir'; requires jexec(8))." f_err "$optfmt" "-n" \ "Show only variable values, not their names." f_err "$optfmt" "-N" \ "Show only variable names, not their values." f_err "$optfmt" "-q" \ "Quiet. Disable verbose and hide certain errors." f_err "$optfmt" "-R dir" \ "Operate within the root directory \`dir' rather than \`/'." f_err "$optfmt" "-v" \ "Verbose. Print the pathname of the specific rc.conf(5)" f_err "$optfmt" "" \ "file where the directive was found." f_err "$optfmt" "--version" \ "Print version information to stdout and exit." f_err "$optfmt" "-x" \ "Remove variable(s) from specified file(s)." f_err "\n" f_err "ENVIRONMENT:\n" f_err "$envfmt" "RC_CONFS" \ "Override default rc_conf_files (even if set to NULL)." f_err "$envfmt" "RC_DEFAULTS" \ "Location of \`/etc/defaults/rc.conf' file." die } # jail_depend # # Dump dependencies such as language-file variables and include files to stdout # to be piped-into sh(1) running via jexec(8)/chroot(8). As a security measure, # this prevents existing language files and library files from being loaded in # the jail. This also relaxes the requirement to have these files in every jail # before sysrc can be used on said jail. # jail_depend() { # # Indicate that we are jailed # echo export _SYSRC_JAILED=1 # # Print i18n language variables (their current values are sanitized # and re-printed for interpretation so that the i18n language files # do not need to exist within the jail). # local var val for var in \ msg_cannot_create_permission_denied \ msg_permission_denied \ msg_previous_syntax_errors \ ; do val=$( eval echo \"\$$var\" | awk '{ gsub(/'\''/, "'\''\\'\'\''"); print }' ) echo $var="'$val'" done # # Print include dependencies # echo DEBUG_SELF_INITIALIZE= cat $BSDCFG_SHARE/common.subr cat $BSDCFG_SHARE/sysrc.subr } ############################################################ MAIN SOURCE # # Perform sanity checks # [ $# -gt 0 ] || usage # # Check for `--help' and `--version' command-line option # ( # Operate in sub-shell to protect $@ in parent while [ $# -gt 0 ]; do case "$1" in --help) help ;; --version) # see GLOBALS echo "$SYSRC_VERSION" exit 1 ;; -[fRj]) # These flags take an argument shift 1 ;; esac shift 1 done exit 0 ) || die # # Process command-line flags # while getopts aAcdDef:Fhij:nNqR:vxX flag; do case "$flag" in a) SHOW_ALL=${SHOW_ALL:-1};; A) SHOW_ALL=2;; c) CHECK_ONLY=1;; d) DESCRIBE=1;; D) RC_CONFS=;; e) SHOW_EQUALS=1;; f) RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG";; F) SHOW_FILE=1;; h) usage;; i) IGNORE_UNKNOWNS=1;; j) [ "$OPTARG" ] || die \ "%s: Missing or null argument to \`-j' flag" "$pgm" JAIL="$OPTARG";; n) SHOW_NAME=;; N) SHOW_VALUE=;; q) QUIET=1 SYSRC_VERBOSE=;; R) [ "$OPTARG" ] || die \ "%s: Missing or null argument to \`-R' flag" "$pgm" ROOTDIR="$OPTARG";; v) SYSRC_VERBOSE=1 QUIET=;; x) DELETE=${DELETE:-1};; X) DELETE=2;; \?) usage;; esac done shift $(( $OPTIND - 1 )) # # [More] Sanity checks (e.g., "sysrc --") # [ $# -eq 0 -a ! "$SHOW_ALL" ] && usage # # Taint-check all rc.conf(5) files # errmsg="$pgm: Exiting due to previous syntax errors" if [ "${RC_CONFS+set}" ]; then ( for i in $RC_CONFS; do [ -e "$i" ] || continue /bin/sh -n "$i" || exit $FAILURE done exit $SUCCESS ) || die "$errmsg" else /bin/sh -n "$RC_DEFAULTS" || die "$errmsg" ( . "$RC_DEFAULTS" for i in $rc_conf_files; do [ -e "$i" ] || continue /bin/sh -n "$i" || exit $FAILURE done exit $SUCCESS ) || die "$errmsg" fi # # Process `-x' (and secret `-X') command-line options # errmsg="$pgm: \`-x' option incompatible with \`-a'/\`-A' options" errmsg="$errmsg (use \`-X' to override)" if [ "$DELETE" -a "$SHOW_ALL" ]; then [ "$DELETE" = "2" ] || die "$errmsg" fi # # Pre-flight for `-c' command-line option # [ "$CHECK_ONLY" -a "$SHOW_ALL" ] && die "$pgm: \`-c' option incompatible with \`-a'/\`-A' options" # # Process `-e', `-n', and `-N' command-line options # SEP=': ' [ "$SHOW_FILE" ] && SHOW_EQUALS= [ "$SHOW_NAME" ] || SHOW_EQUALS= [ "$SYSRC_VERBOSE" = "0" ] && SYSRC_VERBOSE= if [ ! "$SHOW_VALUE" ]; then SHOW_NAME=1 SHOW_EQUALS= fi [ "$SHOW_EQUALS" ] && SEP='="' # # Process `-j jail' and `-R dir' command-line options # if [ "$JAIL" -o "$ROOTDIR" ]; then # # Reconstruct the arguments that we want to carry-over # args=" ${SYSRC_VERBOSE:+-v} ${QUIET:+-q} $( [ "$DELETE" = "1" ] && echo \ -x ) $( [ "$DELETE" = "2" ] && echo \ -X ) $( [ "$SHOW_ALL" = "1" ] && echo \ -a ) $( [ "$SHOW_ALL" = "2" ] && echo \ -A ) ${CHECK_ONLY:+-c} ${DESCRIBE:+-d} ${SHOW_EQUALS:+-e} ${IGNORE_UNKNOWNS:+-i} $( [ "$SHOW_NAME" ] || echo \ -n ) $( [ "$SHOW_VALUE" ] || echo \ -N ) $( [ "$SHOW_FILE" ] && echo \ -F ) " if [ "${RC_CONFS+set}" ]; then args="$args -f '$RC_CONFS'" fi for arg in "$@"; do args="$args '$arg'" done # # If both are supplied, `-j jail' supercedes `-R dir' # if [ "$JAIL" ]; then # # Re-execute ourselves with sh(1) via jexec(8) # ( echo set -- $args jail_depend cat $0 ) | env - RC_DEFAULTS="$RC_DEFAULTS" \ /usr/sbin/jexec "$JAIL" /bin/sh exit $? elif [ "$ROOTDIR" ]; then # # Make sure that the root directory specified is not to any # running jails. # # NOTE: To maintain backward compatibility with older jails on # older systems, we will not perform this check if either the # jls(1) or jexec(8) utilities are missing. # if f_have jexec && f_have jls; then jid="`jls jid path | \ ( while read JID JROOT; do [ "$JROOT" = "$ROOTDIR" ] || continue echo $JID done )`" # # If multiple running jails match the specified root # directory, exit with error. # if [ "$jid" -a "${jid%[$IFS]*}" != "$jid" ]; then die "%s: %s: %s" "$pgm" "$ROOTDIR" \ "$( echo "Multiple jails claim this" \ "directory as their root." \ "(use \`-j jail' instead)" )" fi # # If only a single running jail matches the specified # root directory, implicitly use `-j jail'. # if [ "$jid" ]; then # # Re-execute outselves with sh(1) via jexec(8) # ( echo set -- $args jail_depend cat $0 ) | env - RC_DEFAULTS="$RC_DEFAULTS" \ /usr/sbin/jexec "$jid" /bin/sh exit $? fi # Otherwise, fall through and allow chroot(8) fi # # Re-execute ourselves with sh(1) via chroot(8) # ( echo set -- $args jail_depend cat $0 ) | env - RC_DEFAULTS="$RC_DEFAULTS" \ /usr/sbin/chroot "$ROOTDIR" /bin/sh exit $? fi fi # # Process `-a' or `-A' command-line options # if [ "$SHOW_ALL" ]; then # # Get a list of variables that are currently set in the rc.conf(5) # files (included `/etc/defaults/rc.conf') by performing a call to # source_rc_confs() in a clean environment. # ( # Operate in a sub-shell to protect the parent environment # # Set which variables we want to preserve in the environment. # Append the pipe-character (|) to the list of internal field # separation (IFS) characters, allowing us to use the below # list both as an extended grep (-E) pattern and argument list # (required to first get f_clean_env() to preserve these in the # environment and then later to prune them from the list of # variables produced by set(1)). # IFS="$IFS|" EXCEPT="IFS|EXCEPT|PATH|RC_DEFAULTS|OPTIND|DESCRIBE|SEP" EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME" EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|SYSRC_VERBOSE|RC_CONFS" EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY" EXCEPT="$EXCEPT|f_sysrc_desc_awk|f_sysrc_delete_awk" # # Clean the environment (except for our required variables) # and then source the required files. # f_clean_env --except $EXCEPT if [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ]; then . "$RC_DEFAULTS" # # If passed `-a' (rather than `-A'), re-purge the # environment, removing the rc.conf(5) defaults. # [ "$SHOW_ALL" = "1" ] \ && f_clean_env --except rc_conf_files $EXCEPT # # If `-f file' was passed, set $rc_conf_files to an # explicit value, modifying the default behavior of # source_rc_confs(). # [ "${RC_CONFS+set}" ] && rc_conf_files="$RC_CONFS" source_rc_confs # # If passed `-a' (rather than `-A'), remove # `rc_conf_files' unless it was defined somewhere # other than rc.conf(5) defaults. # [ "$SHOW_ALL" = "1" -a \ "$( f_sysrc_find rc_conf_files )" = "$RC_DEFAULTS" \ ] \ && unset rc_conf_files fi for NAME in $( set | awk -F= '/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' | grep -Ev "^($EXCEPT)$" ); do # # If enabled, describe rather than expand value # if [ "$DESCRIBE" ]; then echo "$NAME: $( f_sysrc_desc "$NAME" )" continue fi # # If `-F' is passed, find it and move on # if [ "$SHOW_FILE" ]; then [ "$SHOW_NAME" ] && echo -n "$NAME: " f_sysrc_find "$NAME" continue fi # # If `-X' is passed, delete the variables # if [ "$DELETE" = "2" ]; then f_sysrc_delete "$NAME" continue fi [ "$SYSRC_VERBOSE" ] && \ echo -n "$( f_sysrc_find "$NAME" ): " # # If `-N' is passed, simplify the output # if [ ! "$SHOW_VALUE" ]; then echo "$NAME" continue fi echo "${SHOW_NAME:+$NAME$SEP}$( f_sysrc_get "$NAME" )${SHOW_EQUALS:+\"}" done ) # # Ignore the remainder of positional arguments. # exit $SUCCESS fi # # Process command-line arguments # status=$SUCCESS while [ $# -gt 0 ]; do NAME="${1%%=*}" case "$NAME" in *+) mode=APPEND NAME="${NAME%+}" ;; + *-) mode=REMOVE NAME="${NAME%-}" ;; *) mode=ASSIGN esac [ "$DESCRIBE" ] && \ echo "$NAME: $( f_sysrc_desc "$NAME" )" case "$1" in *=*) # # Like sysctl(8), if both `-d' AND "name=value" is passed, # first describe (done above), then attempt to set # # If verbose, prefix line with where the directive lives if [ "$SYSRC_VERBOSE" -a ! "$CHECK_ONLY" ]; then file=$( f_sysrc_find "$NAME" ) [ "$file" = "$RC_DEFAULTS" -o ! "$file" ] && \ file=$( f_sysrc_get 'rc_conf_files%%[$IFS]*' ) if [ "$SHOW_EQUALS" ]; then echo -n ": $file; " else echo -n "$file: " fi fi # # If `-x' or `-X' is passed, delete the variable and ignore the # desire to set some value # if [ "$DELETE" ]; then f_sysrc_delete "$NAME" || status=$FAILURE shift 1 continue fi # # If `-c' is passed, simply compare and move on # if [ "$CHECK_ONLY" ]; then if ! IGNORED=$( f_sysrc_get "$NAME?" ); then status=$FAILURE [ "$SYSRC_VERBOSE" ] && echo "$NAME: not currently set" shift 1 continue fi value=$( f_sysrc_get "$NAME" ) if [ "$value" != "${1#*=}" ]; then status=$FAILURE if [ "$SYSRC_VERBOSE" ]; then echo -n "$( f_sysrc_find "$NAME" ): " echo -n "$NAME: would change from " echo "\`$value' to \`${1#*=}'" fi elif [ "$SYSRC_VERBOSE" ]; then echo -n "$( f_sysrc_find "$NAME" ): " echo "$NAME: already set to \`$value'" fi shift 1 continue fi # - # If `-N' is passed, simplify the output + # Determine both `before' value and appropriate `new' value # - if [ ! "$SHOW_VALUE" ]; then - echo "$NAME" - case "$mode" in - APPEND) - before=$( f_sysrc_get "$NAME" ) - f_sysrc_set "$NAME" "$before${1#*=}" - ;; - *) - f_sysrc_set "$NAME" "${1#*=}" + case "$mode" in + APPEND) + before=$( f_sysrc_get "$NAME" ) + add="${1#*=}" + delim="${add%"${add#?}"}" # first character + oldIFS="$IFS" + case "$delim" in + ""|[$IFS]|[a-zA-Z0-9]) delim=" " ;; + *) IFS="$delim" esac - else + new="$before" + for a in $add; do + [ "$a" ] || continue + skip= + for b in $before; do + [ "$b" = "$a" ] && skip=1 break + done + [ "$skip" ] || new="$new$delim$a" + done + new="${new#"$delim"}" IFS="$oldIFS" + unset add delim oldIFS a skip b + [ "$SHOW_FILE" ] && before=$( f_sysrc_find "$NAME" ) + ;; + REMOVE) + before=$( f_sysrc_get "$NAME" ) + remove="${1#*=}" + delim="${remove%"${remove#?}"}" # first character + oldIFS="$IFS" + case "$delim" in + ""|[$IFS]|[a-zA-Z0-9]) delim=" " ;; + *) IFS="$delim" + esac + new= + for b in $before; do + [ "$b" ] || continue + add=1 + for r in $remove; do + [ "$r" = "$b" ] && add= break + done + [ "$add" ] && new="$new$delim$b" + done + new="${new#"$delim"}" IFS="$oldIFS" + unset remove delim oldIFS b add r + [ "$SHOW_FILE" ] && before=$( f_sysrc_find "$NAME" ) + ;; + *) if [ "$SHOW_FILE" ]; then before=$( f_sysrc_find "$NAME" ) else before=$( f_sysrc_get "$NAME" ) fi - if case "$mode" in - APPEND) f_sysrc_set "$NAME" "$before${1#*=}" ;; - *) f_sysrc_set "$NAME" "${1#*=}" - esac - then + new="${1#*=}" + esac + + # + # If `-N' is passed, simplify the output + # + if [ ! "$SHOW_VALUE" ]; then + echo "$NAME" + f_sysrc_set "$NAME" "$new" + else + if f_sysrc_set "$NAME" "$new"; then if [ "$SHOW_FILE" ]; then after=$( f_sysrc_find "$NAME" ) else after=$( f_sysrc_get "$NAME" ) fi echo -n "${SHOW_NAME:+$NAME$SEP}" echo -n "$before${SHOW_EQUALS:+\" #}" echo -n " -> ${SHOW_EQUALS:+\"}$after" echo "${SHOW_EQUALS:+\"}" fi fi ;; *) if ! IGNORED=$( f_sysrc_get "$NAME?" ); then [ "$IGNORE_UNKNOWNS" -o "$QUIET" ] || echo "$pgm: unknown variable '$NAME'" shift 1 status=$FAILURE continue fi # The above check told us what we needed for `-c' if [ "$CHECK_ONLY" ]; then shift 1 continue fi # # Like sysctl(8), when `-d' is passed, desribe it # (already done above) rather than expanding it # if [ "$DESCRIBE" ]; then shift 1 continue fi # # If `-x' or `-X' is passed, delete the variable # if [ "$DELETE" ]; then f_sysrc_delete "$NAME" || status=$FAILURE shift 1 continue fi # # If `-F' is passed, find it and move on # if [ "$SHOW_FILE" ]; then [ "$SHOW_NAME" ] && echo -n "$NAME: " f_sysrc_find "$NAME" shift 1 continue fi if [ "$SYSRC_VERBOSE" ]; then if [ "$SHOW_EQUALS" ]; then echo -n ": $( f_sysrc_find "$NAME" ); " else echo -n "$( f_sysrc_find "$NAME" ): " fi fi # # If `-N' is passed, simplify the output # if [ ! "$SHOW_VALUE" ]; then echo "$NAME" else echo "${SHOW_NAME:+$NAME$SEP}$( f_sysrc_get "$NAME" )${SHOW_EQUALS:+\"}" fi esac shift 1 done exit $status # $SUCCESS unless error occurred with either `-c' or `-x' ################################################################################ # END ################################################################################ Index: head/usr.sbin/sysrc/sysrc.8 =================================================================== --- head/usr.sbin/sysrc/sysrc.8 (revision 279623) +++ head/usr.sbin/sysrc/sysrc.8 (revision 279624) @@ -1,319 +1,437 @@ -.\" Copyright (c) 2011-2014 Devin Teske +.\" Copyright (c) 2011-2015 Devin Teske .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd November 4, 2014 +.Dd March 4, 2015 .Dt SYSRC 8 .Os .Sh NAME .Nm sysrc .Nd safely edit system rc files .Sh SYNOPSIS .Nm .Op Fl cdDeFhinNqvx .Op Fl f Ar file .Op Fl j Ar jail | Fl R Ar dir -.Ar name Ns Op Ns Oo + Oc Ns = Ns Ar value +.Ar name Ns Op Ns Oo +|- Oc Ns = Ns Ar value .Ar ... .Nm .Op Fl cdDeFhinNqvx .Op Fl f Ar file .Op Fl j Ar jail | Fl R Ar dir .Fl a | A .Sh DESCRIPTION The .Nm utility retrieves .Xr rc.conf 5 variables from the collection of system rc files and allows processes with appropriate privilege to change values in a safe and effective manner. .Pp The following options are available: .Bl -tag -width indent+ .It Fl a Dump a list of all non-default configuration variables. .It Fl A Dump a list of all configuration variables .Pq incl. defaults . .It Fl c Check only. For querying, return success if all requested variables are set .Pq even if NULL , otherwise return error status. For assignments, return success if no changes are required, otherwise failure. If verbose .Pq see Dq Fl v prints a message stating whether variables are set and/or changes are required. .It Fl d Print a description of the given variable. .It Fl D Show default value(s) only (this is the same as setting RC_CONFS to NULL or passing `-f' with a NULL file-argument). .It Fl e Print query results as .Xr sh 1 compatible syntax .Pq for example, Ql var=value . Ignored if either .Ql Fl n or .Ql Fl F is specified. .It Fl f Ar file Operate on the specified file(s) instead of the files obtained by reading the .Sq rc_conf_files entry in the .Ev RC_DEFAULTS file. This option can be specified multiple times for additional files. .It Fl F Show only the last .Xr rc.conf 5 file each directive is in. .It Fl h Print a short usage message to stderr and exit. .It Fl -help Print a full usage statement to stderr and exit. .It Fl i Ignore unknown variables. .It Fl j Ar jail The .Ar jid or name of the .Ar jail to operate within .Pq overrides So Fl R Ar dir Sc ; requires Xr jexec 8 . .It Fl n Show only variable values, not their names. .It Fl N Show only variable names, not their values. .It Fl q Quiet. Disable verbose and hide certain errors. .It Fl R Ar dir Operate within the root directory .Sq Ar dir rather than .Sq / . .It Fl v Verbose. Print the pathname of the specific .Xr rc.conf 5 file where the directive was found. .It Fl -version Print version information to stdout and exit. .It Fl x Remove variable(s) from specified file(s). .El .Pp This utility has a similar syntax to .Xr sysctl 8 . It shares the `-e' and `-n' options .Pq detailed above and also has the same .Ql name[=value] syntax for making queries/assignments. In addition -.Pq unlike Xr sysctl 8 , +.Pq but unlike Xr sysctl 8 , .Ql name+=value -is supported for appending values. +is supported for adding items to values +.Pq see APPENDING VALUES +and +.Ql name-=value +is supported for removing items from values +.Pq see SUBTRACTING VALUES . .Pp However, while .Xr sysctl 8 serves to query/modify MIBs in the entrant kernel, .Nm instead works on values in the system .Xr rc.conf 5 configuration files. .Pp The list of system configuration files is configured in the file .Ql /etc/defaults/rc.conf within the variable .Ql rc_conf_files , which by-default contains a space-separated list of pathnames. On all FreeBSD systems, this defaults to the value "/etc/rc.conf /etc/rc.conf.local". Each pathname is sourced in-order upon startup. It is in the same fashion that .Nm sources the configuration files before returning the value of the given variable. .Pp When supplied a variable name, .Nm will return the value of the variable. If the variable does not appear in any of the configured .Ql rc_conf_files , an error is printed and error status is returned. .Pp When changing values of a given variable, it does not matter if the variable appears in any of the .Ql rc_conf_files or not. If the variable does not appear in any of the files, it is appended to the end of the first pathname in the .Ql rc_conf_files variable. Otherwise, .Nm will replace only the last-occurrence in the last-file found to contain the variable. This gets the value to take effect next boot without heavily modifying these integral files (yet taking care not to allow the file to grow unwieldy should .Nm be called repeatedly). +.Sh APPENDING VALUES +When using the +.Ql key+=value +syntax to add items to existing values, +the first character of the value is taken as the delimiter separating items +.Pq usually Qo \ Qc or Qo , Qc . +For example, in the following statement: +.Bl -tag -width indent+ +.It \ +.Nm +cloned_interfaces+=" gif0" +.El +.Pp +the first character is a space, informing +.Nm +that existing values are to be considered separated by whitespace. +If +.Ql gif0 +is not found in the existing value for +.Va cloned_interfaces , +it is added +.Pq with delimiter only if existing value is non-NULL . +.Pp +For convenience, if the first character is alpha-numeric +.Pq letters A-Z, a-z, or numbers 0-9 , +.Nm +uses the default setting of whitespace as separator. +For example, the above and below statements are equivalent since +.Dq gif0 +starts with an alpha-numeric character +.Pq the letter Li g : +.Pp +.Bl -tag -width indent+ +.It \ +.Nm +cloned_interfaces+=gif0 +.El +.Pp +Take the following sequence for example: +.Bl -tag -width indent+ +.It \ +.Nm +cloned_interfaces= # start with NULL +.It \ +.Nm +cloned_interfaces+=gif0 +.Dl # NULL -> `gif0' Pq NB: no preceding delimiter +.It \ +.Nm +cloned_interfaces+=gif0 # no change +.It \ +.Nm +cloned_interfaces+="tun0 gif0" +.Dl # `gif0' -> `gif0 tun0' Pq NB: no duplication +.El +.Pp +.Nm +prevents the same value from being added if already there. +.Sh SUBTRACTING VALUES +When using the +.Ql key-=value +syntax to remove items from existing values, +the first character of the value is taken as the delimiter separating items +.Pq usually Qo \ Qc or Qo , Qc . +For example, in the following statement: +.Pp +.Dl Nm cloned_interfaces-=" gif0" +.Pp +the first character is a space, informing +.Nm +that existing values are to be considered separated by whitespace. +If +.Ql gif0 +is found in the existing value for +.Va cloned_interfaces , +it is removed +.Pq extra delimiters removed . +.Pp +For convenience, if the first character is alpha-numeric +.Pq letters A-Z, a-z, or numbers 0-9 , +.Nm +uses the default setting of whitespace as separator. +For example, the above and below statements are equivalent since +.Dq gif0 +starts with an alpha-numeric character +.Pq the letter Li g : +.Pp +.Bl -tag -width indent+ +.It \ +.Nm +cloned_interfaces-=gif0 +.El +.Pp +Take the following sequence for example: +.Bl -tag -width indent+ +.It \ +.Nm +foo="bar baz" # start +.It \ +.Nm +foo-=bar # `bar baz' -> `baz' +.It \ +.Nm +foo-=baz # `baz' -> NULL +.El +.Pp +.Nm +removes all occurrences of all items provided +and collapses extra delimiters between items. .Sh ENVIRONMENT The following environment variables are referenced by .Nm : .Bl -tag -width ".Ev RC_DEFAULTS" .It Ev RC_CONFS Override default .Ql rc_conf_files .Pq even if set to NULL . .It Ev RC_DEFAULTS Location of .Ql /etc/defaults/rc.conf file. .El .Sh DEPENDENCIES The following standard commands are required by .Nm : .Pp .Xr awk 1 , .Xr cat 1 , .Xr chmod 1 , .Xr env 1 , .Xr grep 1 , .Xr jls 1 , .Xr mktemp 1 , .Xr mv 1 , .Xr rm 1 , .Xr sh 1 , .Xr stat 1 , .Xr tail 1 , .Xr chown 8 and .Xr jexec 8 . .Sh FILES .Bl -tag -width ".Pa /etc/defaults/rc.conf" -compact .It Pa /etc/defaults/rc.conf .It Pa /etc/rc.conf .It Pa /etc/rc.conf.local .El .Sh EXAMPLES Below are some simple examples of how .Nm can be used to query certain values from the .Xr rc.conf 5 collection of system configuration files: .Pp .Nm sshd_enable .Dl returns the value of $sshd_enable, usually YES or NO . .Pp .Nm defaultrouter .Dl returns IP address of default router Pq if configured . .Pp Working on other files, such as .Xr crontab 5 : .Pp .Nm -f /etc/crontab MAILTO .Dl returns the value of the MAILTO setting Pq if configured . .Pp Appending to existing values: .Pp .Nm -\&cloned_interfaces+=" gif0" -.Dl appends Qo \ gif0 Qc to $cloned_interfaces . +\&cloned_interfaces+=gif0 +.Dl appends Qo gif0 Qc to $cloned_interfaces Pq see APPENDING VALUES . +.Pp +.Nm +\&cloned_interfaces-=gif0 +.Dl removes Qo gif0 Qc from $cloned_interfaces Pq see SUBTRACTING VALUES . .Pp In addition to the above syntax, .Nm also supports inline .Xr sh 1 PARAMETER expansion for changing the way values are reported, shown below: .Pp .Nm \&'hostname%%.*' .Dl returns $hostname up to (but not including) first `.' . .Pp .Nm \&'network_interfaces%%[$IFS]*' .Dl returns first word of $network_interfaces . .Pp .Nm \&'ntpdate_flags##*[$IFS]' .Dl returns last word of $ntpdate_flags (time server address) . .Pp .Nm usbd_flags-"default" .Dl returns $usbd_flags or "default" if unset or NULL . .Pp .Nm cloned_interfaces+"alternate" .Dl returns "alternate" if $cloned_interfaces is set . .Pp .Nm \&'#kern_securelevel' .Dl returns length in characters of $kern_securelevel . .Pp .Nm \&'hostname?' .Dl returns NULL and error status 2 if $hostname is unset Pq or if set, returns the value of $hostname with no error status . .Pp .Nm \&'hostname:?' .Dl returns NULL and error status 2 if $hostname is unset or NULL Pq or if set and non-NULL, returns value without error status . .Sh LIMITATIONS The .Nm utility presently does not support the .Ql rc.conf.d collection of system configuration files .Pq which requires a service name to be known during execution . .Pp This will be corrected by a future enhancement. .Sh SEE ALSO .Xr jls 1 , .Xr rc.conf 5 , .Xr jail 8 , .Xr jexec 8 , .Xr rc 8 , .Xr sysctl 8 .Sh HISTORY A .Nm utility first appeared in .Fx 9.2 . .Sh AUTHORS .An Devin Teske Aq Mt dteske@FreeBSD.org .Sh THANKS TO Brandon Gooch, Garrett Cooper, Julian Elischer, Pawel Jakub Dawidek, Cyrille Lefevre, Ross West, Stefan Esser, Marco Steinbach, Jilles Tjoelker, Allan Jude, and Lars Engels for suggestions, help, and testing.