diff options
Diffstat (limited to 'usr.sbin/sysrc')
-rw-r--r-- | usr.sbin/sysrc/Makefile | 7 | ||||
-rw-r--r-- | usr.sbin/sysrc/Makefile.depend | 11 | ||||
-rw-r--r-- | usr.sbin/sysrc/sysrc | 929 | ||||
-rw-r--r-- | usr.sbin/sysrc/sysrc.8 | 477 |
4 files changed, 1424 insertions, 0 deletions
diff --git a/usr.sbin/sysrc/Makefile b/usr.sbin/sysrc/Makefile new file mode 100644 index 0000000..1ace38a --- /dev/null +++ b/usr.sbin/sysrc/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +SCRIPTS= sysrc + +MAN= sysrc.8 + +.include <bsd.prog.mk> diff --git a/usr.sbin/sysrc/Makefile.depend b/usr.sbin/sysrc/Makefile.depend new file mode 100644 index 0000000..f80275d --- /dev/null +++ b/usr.sbin/sysrc/Makefile.depend @@ -0,0 +1,11 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/sysrc/sysrc b/usr.sbin/sysrc/sysrc new file mode 100644 index 0000000..e384dff --- /dev/null +++ b/usr.sbin/sysrc/sysrc @@ -0,0 +1,929 @@ +#!/bin/sh +#- +# 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="7.0 Sep-13,2015" + +# +# Options +# +CHECK_ONLY= +DEFAULT= +DELETE= +DESCRIBE= +EXISTING_ONLY= +IGNORE_UNKNOWNS= +JAIL= +LIST_SERVICE_CONFS= +LIST_CONFS= +QUIET= +ROOTDIR= +SERVICE= +SHOW_ALL= +SHOW_EQUALS= +SHOW_FILE= +SHOW_NAME=1 +SHOW_VALUE=1 +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] %s\n" "$pgm" \ + "{name[[+|-]=value] ... | -a | -A | -l | -L [name ...]}" + 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] -a | -A\n" "$pgm" + f_err "Usage: %s [OPTIONS] -l | -L [name ...]\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" "-E" \ + "Existing files only with \`-[lL]' or when changing a setting." + 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" "-l" \ + "List configuration files used at startup on stdout and exit." + f_err "$optfmt" "-L" \ + "List all configuration files including rc.conf.d entries." + 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" "-s name" \ + "Process additional \`rc.conf.d' entries for service name." + f_err "$optfmt" "" \ + "Ignored if \`-f file' is given." + 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 +} + +# escape $string [$var_to_set] +# +# Escape $string contents so that the contents can be properly encapsulated in +# single-quotes (making for safe evaluation). +# +# NB: See `bsdconfig includes -dF escape' for relevant information/discussion. +# NB: Abridged version of `f_shell_escape()' from bsdconfig(8) `strings.subr'. +# +escape() +{ + local __start="$1" __var_to_set="$2" __string= + while [ "$__start" ]; do + case "$__start" in *\'*) + __string="$__string${__start%%\'*}'\\''" + __start="${__start#*\'}" continue + esac + break + done + __string="$__string$__start" + if [ "$__var_to_set" ]; then + setvar "$__var_to_set" "$__string" + else + echo "$__string" + fi +} + +############################################################ MAIN SOURCE + +# +# Perform sanity checks +# +[ $# -gt 0 ] || usage # NOTREACHED + +# +# Check for `--help' and `--version' command-line option +# +for arg in "$@"; do + case "$arg" in + --) break ;; + --help) help ;; # NOTREACHED + --version) # see GLOBALS + echo "$SYSRC_VERSION" + exit $FAILURE ;; + esac +done +unset arg + +# +# Process command-line flags +# +while getopts aAcdDeEf:Fhij:lLnNqR:s:vxX flag; do + case "$flag" in + a) SHOW_ALL=${SHOW_ALL:-1} ;; + A) SHOW_ALL=2 ;; + c) CHECK_ONLY=1 ;; + d) DESCRIBE=1 ;; + D) DEFAULT=1 RC_CONFS= ;; + e) SHOW_EQUALS=1 ;; + E) EXISTING_ONLY=1 ;; + f) DEFAULT= RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;; + F) SHOW_FILE=1 ;; + h) usage ;; # NOTREACHED + i) IGNORE_UNKNOWNS=1 ;; + j) [ "$OPTARG" ] || + die "%s: Missing or null argument to \`-j' flag" "$pgm" + JAIL="$OPTARG" ;; + l) LIST_CONFS=1 ;; + L) LIST_SERVICE_CONFS=1 ;; + n) SHOW_NAME= ;; + N) SHOW_VALUE= ;; + q) QUIET=1 VERBOSE= ;; + R) [ "$OPTARG" ] || + die "%s: Missing or null argument to \`-R' flag" "$pgm" + ROOTDIR="$OPTARG" ;; + s) [ "$OPTARG" ] || + die "%s: Missing or null argument to \`-s' flag" "$pgm" + SERVICE="$OPTARG" ;; + v) VERBOSE=1 QUIET= ;; + x) DELETE=${DELETE:-1} ;; + X) DELETE=2 ;; + \?) usage ;; # NOTREACHED + esac +done +shift $(( $OPTIND - 1 )) + +# +# Process `-L' flag +# +if [ "$LIST_SERVICE_CONFS" ]; then + list= + + # + # List rc_conf_files if no service names given + # + files= + [ $# -eq 0 ] && files=$( f_sysrc_get rc_conf_files ) + for file in $files; do + if [ "$EXISTING_ONLY" ]; then + [ -e "$file" -a ! -d "$file" ] || continue + fi + case "$list" in + "$file"|*" $file"|"$file "*|*" $file "*) continue ;; + esac + list="$list $file" + done + list="${list# }" + if [ $# -eq 0 ]; then + if [ "$VERBOSE" ]; then + echo rc_conf_files: $list + elif [ "$SHOW_EQUALS" ]; then + echo "rc_conf_files=\"$list\"" + fi + fi + + # + # List rc.conf.d entries + # + retval=$SUCCESS + for service in ${*:-$( service -l )}; do + slist= + f_sysrc_service_configs $service files || retval=$? continue + for file in $files; do + if [ "$EXISTING_ONLY" ]; then + [ -e "$file" -a ! -d "$file" ] || continue + fi + if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then + case "$list" in + "$file"|*" $file"|"$file "*|*" $file "*) + continue ;; + esac + fi + slist="$slist $file" + done + slist="${slist# }" + if [ $# -gt 0 ]; then + [ "$slist" ] || retval=$? + fi + if [ "$VERBOSE" ]; then + [ "$slist" ] && echo "$service: $slist" + continue + elif [ "$SHOW_EQUALS" ]; then + [ "$slist" ] && echo "$service=\"$slist\"" + continue + fi + list="$list${slist:+ }$slist" + done + if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then + if [ $# -eq 0 -o ! "$QUIET" ]; then + list="${list# }" + [ "$list" ] && echo $list + fi + fi + + exit $retval +fi + +# +# Process `-s name' argument +# +if [ "$SERVICE" -a ! "${RC_CONFS+set}" ]; then + if f_sysrc_service_configs "$SERVICE" RC_CONFS; then + rc_conf_files=$( f_sysrc_get rc_conf_files ) + RC_CONFS="$rc_conf_files${RC_CONFS:+ }$RC_CONFS" + unset rc_conf_files + else + unset RC_CONFS + fi +fi + +# +# Process `-E' option flag +# +if [ "$EXISTING_ONLY" ]; then + # + # To get f_sysrc_*() to ignore missing rc_conf_files, we have to use + # RC_CONFS to override the unpreened value. If RC_CONFS already has a + # value (`-D', `-f file', `-s name', or inherited from parent), use it. + # Otherwise, include filtered contents of rc_conf_files. + # + RC_CONFS=$( + if [ "${RC_CONFS+set}" ]; then + set -- $RC_CONFS + else + set -- $( f_sysrc_get rc_conf_files ) + fi + while [ $# -gt 0 ]; do + [ -f "$1" ] && echo -n " $1" + shift + done + ) + RC_CONFS="${RC_CONFS# }" +fi + +# +# Process `-l' option flag +# +if [ "$LIST_CONFS" ]; then + [ $# -eq 0 ] || usage + if [ "$DEFAULT" ]; then + echo "$RC_DEFAULTS" + elif [ "${RC_CONFS+set}" ]; then + echo "$RC_CONFS" + else + f_sysrc_get rc_conf_files + fi + exit $SUCCESS +fi + +# +# [More] Sanity checks (e.g., "sysrc --") +# +[ $# -eq 0 -a ! "$SHOW_ALL" ] && usage # NOTREACHED + +# +# 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= +[ "$VERBOSE" = "0" ] && 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=" + ${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} + ${DEFAULT:+-D} + ${EXISTING_ONLY:+-E} + ${LIST_CONFS:+-l} + ${LIST_SERVICE_CONFS:+-L} + ${DESCRIBE:+-d} + ${SHOW_EQUALS:+-e} + ${IGNORE_UNKNOWNS:+-i} + $( [ "$SHOW_NAME" ] || echo \ -n ) + $( [ "$SHOW_VALUE" ] || echo \ -N ) + $( [ "$SHOW_FILE" ] && echo \ -F ) + " + if [ "$SERVICE" ]; then + escape "$SERVICE" _SERVICE + args="$args -s '$_SERVICE'" + unset _SERVICE + fi + if [ "${RC_CONFS+set}" ]; then + escape "$RC_CONFS" _RC_CONFS + args="$args -f '$_RC_CONFS'" + unset _RC_CONFS + fi + for arg in "$@"; do + escape "$arg" arg + 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|DEFAULT" + EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS|SERVICE" + EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY|EXISTING_ONLY" + EXCEPT="$EXCEPT|LIST_CONFS|LIST_SERVICE_CONFS" + 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(). + # + if [ "${RC_CONFS+set}" ]; then + [ "$SHOW_ALL" = "1" -a "$SERVICE" -a \ + ! "$DEFAULT" ] || rc_conf_files= + rc_conf_files="$rc_conf_files $RC_CONFS" + rc_conf_files="${rc_conf_files# }" + rc_conf_files="${rc_conf_files% }" + fi + + 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 + + [ "$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 [ "$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 + [ "$VERBOSE" ] && + echo "$NAME: not currently set" + shift 1 + continue + fi + value=$( f_sysrc_get "$NAME" ) + if [ "$value" != "${1#*=}" ]; then + status=$FAILURE + if [ "$VERBOSE" ]; then + echo -n "$( f_sysrc_find "$NAME" ): " + echo -n "$NAME: would change from " + echo "\`$value' to \`${1#*=}'" + fi + elif [ "$VERBOSE" ]; then + echo -n "$( f_sysrc_find "$NAME" ): " + echo "$NAME: already set to \`$value'" + fi + shift 1 + continue + fi + + # + # Determine both `before' value and appropriate `new' value + # + 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 + 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" ) + ;; + *) # ASSIGN + if [ "$SHOW_FILE" ]; then + before=$( f_sysrc_find "$NAME" ) + else + before=$( f_sysrc_get "$NAME" ) + fi + 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 [ "$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 +################################################################################ diff --git a/usr.sbin/sysrc/sysrc.8 b/usr.sbin/sysrc/sysrc.8 new file mode 100644 index 0000000..dbd0e4b --- /dev/null +++ b/usr.sbin/sysrc/sysrc.8 @@ -0,0 +1,477 @@ +.\" 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 September 12, 2015 +.Dt SYSRC 8 +.Os +.Sh NAME +.Nm sysrc +.Nd safely edit system rc files +.Sh SYNOPSIS +.Nm +.Op Fl cdDeEFhinNqvx +.Op Fl s Ar name +.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 ... +.Nm +.Op Fl cdDeEFhinNqvx +.Op Fl s Ar name +.Op Fl f Ar file +.Op Fl j Ar jail | Fl R Ar dir +.Fl a | A +.Nm +.Op Fl E +.Op Fl s Ar name +.Op Fl f Ar file +.Fl l +.Nm +.Op Fl eEqv +.Fl L +.Op Ar name ... +.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 E +When given +.Sq Fl l +or +.Sq Fl L +to list configuration files, only list those that exist. +When changing a setting, prefer to modify existing files. +.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 l +List configuration files used at startup on stdout and exit. +.It Fl L +List all configuration files including rc.conf.d entries on stdout and exit. +Can be combined with +.Sq Fl v +or +.Sq Fl e +to show service names. +.Nm +exits with success if all named services are installed, failure otherwise. +.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. +When combined with +.Sq Fl L +and one or more +.Li Ar name +arguments, provide only exit status and no output. +.It Fl R Ar dir +Operate within the root directory +.Sq Ar dir +rather than +.Sq / . +.It Fl s Ar name +If an +.Li rc.d +script of +.Ar name +exists +.Po +in +.Dq /etc/rc.d +or +.Li local_startup +directories +.Pc , +process its +.Dq rc.conf.d +entries as potential overrides to +.Sq rc_conf_files . +See +.Xr rc.subr 8 +for additional information on +.Dq rc.conf.d . +Can be combined with +.Sq Fl l +to list configuration files used by service at startup. +.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 but unlike Xr sysctl 8 , +.Ql name+=value +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 -item -offset 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 : +.Bl -item -offset indent +.It +.Nm +cloned_interfaces+=gif0 +.El +.Pp +Take the following sequence for example: +.Bl -item -offset 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 : +.Bl -item -offset indent +.It +.Nm +cloned_interfaces-=gif0 +.El +.Pp +Take the following sequence for example: +.Bl -item -offset 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 +.It Pa /etc/rc.conf.d/name +.It Pa /etc/rc.conf.d/name/* +.It Pa /usr/local/etc/rc.conf.d/name +.It Pa /usr/local/etc/rc.conf.d/name/* +.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 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 . +.Sh SEE ALSO +.Xr jls 1 , +.Xr rc.conf 5 , +.Xr rc.subr 8 , +.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. |