1241149Sdteske#!/bin/sh
2241149Sdteske#-
3280390Sdteske# Copyright (c) 2010-2015 Devin Teske
4241149Sdteske# All rights reserved.
5241149Sdteske#
6241149Sdteske# Redistribution and use in source and binary forms, with or without
7241149Sdteske# modification, are permitted provided that the following conditions
8241149Sdteske# are met:
9241149Sdteske# 1. Redistributions of source code must retain the above copyright
10241149Sdteske#    notice, this list of conditions and the following disclaimer.
11241149Sdteske# 2. Redistributions in binary form must reproduce the above copyright
12241149Sdteske#    notice, this list of conditions and the following disclaimer in the
13241149Sdteske#    documentation and/or other materials provided with the distribution.
14241149Sdteske#
15241149Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16252987Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17241149Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18241149Sdteske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19241149Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20241149Sdteske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21241149Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22241149Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23241149Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24241149Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25241149Sdteske# SUCH DAMAGE.
26241149Sdteske#
27241149Sdteske# $FreeBSD: stable/10/usr.sbin/sysrc/sysrc 337588 2018-08-10 20:07:59Z dteske $
28241149Sdteske#
29241149Sdteske############################################################ INCLUDES
30241149Sdteske
31260679Sdteske# Prevent `-d' from being interpreted as a debug flag by common.subr
32260679SdteskeDEBUG_SELF_INITIALIZE=
33260679Sdteske
34241149SdteskeBSDCFG_SHARE="/usr/share/bsdconfig"
35241149Sdteske[ "$_COMMON_SUBR" ] || . $BSDCFG_SHARE/common.subr || exit 1
36241149Sdteske[ "$_SYSRC_SUBR"  ] || f_include $BSDCFG_SHARE/sysrc.subr
37241149Sdteske
38241149Sdteske############################################################ GLOBALS
39241149Sdteske
40241149Sdteske#
41260679Sdteske# Version information
42260679Sdteske#
43292833SdteskeSYSRC_VERSION="7.0 Sep-13,2015"
44260679Sdteske
45260679Sdteske#
46241149Sdteske# Options
47241149Sdteske#
48260679SdteskeCHECK_ONLY=
49292833SdteskeDEFAULT=
50241149SdteskeDELETE=
51241149SdteskeDESCRIBE=
52292833SdteskeEXISTING_ONLY=
53241149SdteskeIGNORE_UNKNOWNS=
54241149SdteskeJAIL=
55292833SdteskeLIST_SERVICE_CONFS=
56292833SdteskeLIST_CONFS=
57241149SdteskeQUIET=
58241149SdteskeROOTDIR=
59292833SdteskeSERVICE=
60241149SdteskeSHOW_ALL=
61241149SdteskeSHOW_EQUALS=
62241149SdteskeSHOW_FILE=
63241149SdteskeSHOW_NAME=1
64241149SdteskeSHOW_VALUE=1
65290301SdteskeVERBOSE=
66241149Sdteske
67241149Sdteske############################################################ FUNCTIONS
68241149Sdteske
69290307Sdteske# die [$fmt [$opts ...]]
70241149Sdteske#
71241149Sdteske# Optionally print a message to stderr before exiting with failure status.
72241149Sdteske#
73241149Sdteskedie()
74241149Sdteske{
75241149Sdteske	local fmt="$1"
76241149Sdteske	[ $# -gt 0 ] && shift 1
77241149Sdteske	[  "$fmt"  ] && f_err "$fmt\n" "$@"
78241149Sdteske
79241149Sdteske	exit $FAILURE
80241149Sdteske}
81241149Sdteske
82241149Sdteske# usage
83241149Sdteske#
84241149Sdteske# Prints a short syntax statement and exits.
85241149Sdteske#
86241149Sdteskeusage()
87241149Sdteske{
88292833Sdteske	f_err "Usage: %s [OPTIONS] %s\n" "$pgm" \
89292833Sdteske		"{name[[+|-]=value] ... | -a | -A | -l | -L [name ...]}"
90241149Sdteske	f_err "Try \`%s --help' for more information.\n" "$pgm"
91241149Sdteske	die
92241149Sdteske}
93241149Sdteske
94241149Sdteske# help
95241149Sdteske#
96241149Sdteske# Prints a full syntax statement and exits.
97241149Sdteske#
98241149Sdteskehelp()
99241149Sdteske{
100241149Sdteske	local optfmt="\t%-11s%s\n"
101241149Sdteske	local envfmt="\t%-17s%s\n"
102241149Sdteske
103280390Sdteske	f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm"
104292833Sdteske	f_err "Usage: %s [OPTIONS] -a | -A\n" "$pgm"
105292833Sdteske	f_err "Usage: %s [OPTIONS] -l | -L [name ...]\n" "$pgm"
106241149Sdteske
107241149Sdteske	f_err "OPTIONS:\n"
108241149Sdteske	f_err "$optfmt" "-a" \
109241149Sdteske	      "Dump a list of all non-default configuration variables."
110241149Sdteske	f_err "$optfmt" "-A" \
111241149Sdteske	      "Dump a list of all configuration variables (incl. defaults)."
112260679Sdteske	f_err "$optfmt" "-c" \
113272191Sdteske	      "Check. Return success if set or no changes, else error."
114241149Sdteske	f_err "$optfmt" "-d" \
115241149Sdteske	      "Print a description of the given variable."
116241149Sdteske	f_err "$optfmt" "-D" \
117241149Sdteske	      "Show default value(s) only (this is the same as setting"
118241149Sdteske	f_err "$optfmt" "" \
119241149Sdteske	      "RC_CONFS to NULL or passing \`-f' with a NULL file-argument)."
120241149Sdteske	f_err "$optfmt" "-e" \
121241149Sdteske	      "Print query results as \`var=value' (useful for producing"
122241149Sdteske	f_err "$optfmt" "" \
123241149Sdteske	      "output to be fed back in). Ignored if \`-n' is specified."
124292833Sdteske	f_err "$optfmt" "-E" \
125292833Sdteske	      "Existing files only with \`-[lL]' or when changing a setting."
126241149Sdteske	f_err "$optfmt" "-f file" \
127241149Sdteske	      "Operate on the specified file(s) instead of rc_conf_files."
128241149Sdteske	f_err "$optfmt" "" \
129241149Sdteske	      "Can be specified multiple times for additional files."
130241149Sdteske	f_err "$optfmt" "-F" \
131241149Sdteske	      "Show only the last rc.conf(5) file each directive is in."
132241149Sdteske	f_err "$optfmt" "-h" \
133241149Sdteske	      "Print a short usage statement to stderr and exit."
134241149Sdteske	f_err "$optfmt" "--help" \
135241149Sdteske	      "Print this message to stderr and exit."
136241149Sdteske	f_err "$optfmt" "-i" \
137241149Sdteske	      "Ignore unknown variables."
138241149Sdteske	f_err "$optfmt" "-j jail" \
139241149Sdteske	      "The jid or name of the jail to operate within (overrides"
140241149Sdteske	f_err "$optfmt" "" \
141241149Sdteske	      "\`-R dir'; requires jexec(8))."
142292833Sdteske	f_err "$optfmt" "-l" \
143292833Sdteske	      "List configuration files used at startup on stdout and exit."
144292833Sdteske	f_err "$optfmt" "-L" \
145292833Sdteske	      "List all configuration files including rc.conf.d entries."
146241149Sdteske	f_err "$optfmt" "-n" \
147241149Sdteske	      "Show only variable values, not their names."
148241149Sdteske	f_err "$optfmt" "-N" \
149241149Sdteske	      "Show only variable names, not their values."
150241149Sdteske	f_err "$optfmt" "-q" \
151272191Sdteske	      "Quiet. Disable verbose and hide certain errors."
152292833Sdteske	f_err "$optfmt" "-s name" \
153292833Sdteske	      "Process additional \`rc.conf.d' entries for service name."
154292833Sdteske	f_err "$optfmt" "" \
155292833Sdteske	      "Ignored if \`-f file' is given."
156241149Sdteske	f_err "$optfmt" "-R dir" \
157241149Sdteske	      "Operate within the root directory \`dir' rather than \`/'."
158241149Sdteske	f_err "$optfmt" "-v" \
159241149Sdteske	      "Verbose. Print the pathname of the specific rc.conf(5)"
160241149Sdteske	f_err "$optfmt" "" \
161241149Sdteske	      "file where the directive was found."
162260679Sdteske	f_err "$optfmt" "--version" \
163260679Sdteske	      "Print version information to stdout and exit."
164241149Sdteske	f_err "$optfmt" "-x" \
165241149Sdteske	      "Remove variable(s) from specified file(s)."
166241149Sdteske	f_err "\n"
167241149Sdteske
168241149Sdteske	f_err "ENVIRONMENT:\n"
169241149Sdteske	f_err "$envfmt" "RC_CONFS" \
170241149Sdteske	      "Override default rc_conf_files (even if set to NULL)."
171241149Sdteske	f_err "$envfmt" "RC_DEFAULTS" \
172241149Sdteske	      "Location of \`/etc/defaults/rc.conf' file."
173241149Sdteske
174241149Sdteske	die
175241149Sdteske}
176241149Sdteske
177241149Sdteske# jail_depend
178241149Sdteske#
179241149Sdteske# Dump dependencies such as language-file variables and include files to stdout
180241149Sdteske# to be piped-into sh(1) running via jexec(8)/chroot(8). As a security measure,
181241149Sdteske# this prevents existing language files and library files from being loaded in
182241149Sdteske# the jail. This also relaxes the requirement to have these files in every jail
183241149Sdteske# before sysrc can be used on said jail.
184241149Sdteske#
185241149Sdteskejail_depend()
186241149Sdteske{
187241149Sdteske	#
188241149Sdteske	# Indicate that we are jailed
189241149Sdteske	#
190241149Sdteske	echo export _SYSRC_JAILED=1
191241149Sdteske
192241149Sdteske	#
193241149Sdteske	# Print i18n language variables (their current values are sanitized
194241149Sdteske	# and re-printed for interpretation so that the i18n language files
195241149Sdteske	# do not need to exist within the jail).
196241149Sdteske	#
197241149Sdteske	local var val
198241149Sdteske	for var in \
199241149Sdteske		msg_cannot_create_permission_denied \
200241149Sdteske		msg_permission_denied \
201241149Sdteske		msg_previous_syntax_errors \
202241149Sdteske	; do
203241149Sdteske		val=$( eval echo \"\$$var\" |
204241149Sdteske			awk '{ gsub(/'\''/, "'\''\\'\'\''"); print }' )
205241149Sdteske		echo $var="'$val'"
206241149Sdteske	done
207241149Sdteske
208241149Sdteske	#
209241149Sdteske	# Print include dependencies
210241149Sdteske	#
211260679Sdteske	echo DEBUG_SELF_INITIALIZE=
212241149Sdteske	cat $BSDCFG_SHARE/common.subr
213241149Sdteske	cat $BSDCFG_SHARE/sysrc.subr
214241149Sdteske}
215241149Sdteske
216290306Sdteske# escape $string [$var_to_set]
217290306Sdteske#
218290306Sdteske# Escape $string contents so that the contents can be properly encapsulated in
219290306Sdteske# single-quotes (making for safe evaluation).
220290306Sdteske#
221290306Sdteske# NB: See `bsdconfig includes -dF escape' for relevant information/discussion.
222290306Sdteske# NB: Abridged version of `f_shell_escape()' from bsdconfig(8) `strings.subr'.
223290306Sdteske#
224290304Sdteskeescape()
225290304Sdteske{
226290304Sdteske	local __start="$1" __var_to_set="$2" __string=
227290304Sdteske	while [ "$__start" ]; do
228290304Sdteske		case "$__start" in *\'*)
229290304Sdteske			__string="$__string${__start%%\'*}'\\''"
230290304Sdteske			__start="${__start#*\'}" continue
231290304Sdteske		esac
232290304Sdteske		break
233290304Sdteske	done
234290304Sdteske	__string="$__string$__start"
235290304Sdteske	if [ "$__var_to_set" ]; then
236290304Sdteske		setvar "$__var_to_set" "$__string"
237290304Sdteske	else
238290304Sdteske		echo "$__string"
239290304Sdteske	fi
240290304Sdteske}
241290304Sdteske
242241149Sdteske############################################################ MAIN SOURCE
243241149Sdteske
244241149Sdteske#
245241149Sdteske# Perform sanity checks
246241149Sdteske#
247290303Sdteske[ $# -gt 0 ] || usage # NOTREACHED
248241149Sdteske
249241149Sdteske#
250260679Sdteske# Check for `--help' and `--version' command-line option
251241149Sdteske#
252290310Sdteskefor arg in "$@"; do
253290310Sdteske	case "$arg" in
254290310Sdteske	--) break ;;
255290310Sdteske	--help) help ;; # NOTREACHED
256290310Sdteske	--version) # see GLOBALS
257290310Sdteske		echo "$SYSRC_VERSION"
258290310Sdteske		exit $FAILURE ;;
259290310Sdteske	esac
260290310Sdteskedone
261290310Sdteskeunset arg
262241149Sdteske
263241149Sdteske#
264241149Sdteske# Process command-line flags
265241149Sdteske#
266292833Sdteskewhile getopts aAcdDeEf:Fhij:lLnNqR:s:vxX flag; do
267241149Sdteske	case "$flag" in
268290302Sdteske	a) SHOW_ALL=${SHOW_ALL:-1} ;;
269290302Sdteske	A) SHOW_ALL=2 ;;
270290302Sdteske	c) CHECK_ONLY=1 ;;
271290302Sdteske	d) DESCRIBE=1 ;;
272292833Sdteske	D) DEFAULT=1 RC_CONFS= ;;
273290302Sdteske	e) SHOW_EQUALS=1 ;;
274292833Sdteske	E) EXISTING_ONLY=1 ;;
275292833Sdteske	f) DEFAULT= RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;;
276290302Sdteske	F) SHOW_FILE=1 ;;
277290303Sdteske	h) usage ;; # NOTREACHED
278290302Sdteske	i) IGNORE_UNKNOWNS=1 ;;
279290312Sdteske	j) [ "$OPTARG" ] ||
280290312Sdteske		die "%s: Missing or null argument to \`-j' flag" "$pgm"
281290302Sdteske	   JAIL="$OPTARG" ;;
282292833Sdteske	l) LIST_CONFS=1 ;;
283292833Sdteske	L) LIST_SERVICE_CONFS=1 ;;
284290302Sdteske	n) SHOW_NAME= ;;
285290302Sdteske	N) SHOW_VALUE= ;;
286290302Sdteske	q) QUIET=1 VERBOSE= ;;
287290312Sdteske	R) [ "$OPTARG" ] ||
288290312Sdteske		die "%s: Missing or null argument to \`-R' flag" "$pgm"
289290302Sdteske	   ROOTDIR="$OPTARG" ;;
290292833Sdteske	s) [ "$OPTARG" ] ||
291292833Sdteske		die "%s: Missing or null argument to \`-s' flag" "$pgm"
292292833Sdteske	   SERVICE="$OPTARG" ;;
293290302Sdteske	v) VERBOSE=1 QUIET= ;;
294290302Sdteske	x) DELETE=${DELETE:-1} ;;
295290302Sdteske	X) DELETE=2 ;;
296290303Sdteske	\?) usage ;; # NOTREACHED
297241149Sdteske	esac
298241149Sdteskedone
299241149Sdteskeshift $(( $OPTIND - 1 ))
300241149Sdteske
301241149Sdteske#
302292833Sdteske# Process `-L' flag
303292833Sdteske#
304292833Sdteskeif [ "$LIST_SERVICE_CONFS" ]; then
305292833Sdteske	list= 
306292833Sdteske
307292833Sdteske	#
308292833Sdteske	# List rc_conf_files if no service names given
309292833Sdteske	#
310292833Sdteske	files=
311292833Sdteske	[ $# -eq 0 ] && files=$( f_sysrc_get rc_conf_files )
312292833Sdteske	for file in $files; do
313292833Sdteske		if [ "$EXISTING_ONLY" ]; then
314292833Sdteske			[ -e "$file" -a ! -d "$file" ] || continue
315292833Sdteske		fi
316292833Sdteske		case "$list" in
317292833Sdteske		"$file"|*" $file"|"$file "*|*" $file "*) continue ;;
318292833Sdteske		esac
319292833Sdteske		list="$list $file"
320292833Sdteske	done
321292833Sdteske	list="${list# }"
322292833Sdteske	if [ $# -eq 0 ]; then
323292833Sdteske		if [ "$VERBOSE" ]; then
324292833Sdteske			echo rc_conf_files: $list
325292833Sdteske		elif [ "$SHOW_EQUALS" ]; then
326292833Sdteske			echo "rc_conf_files=\"$list\""
327292833Sdteske		fi
328292833Sdteske	fi
329292833Sdteske
330292833Sdteske	#
331292833Sdteske	# List rc.conf.d entries
332292833Sdteske	#
333292833Sdteske	retval=$SUCCESS
334292833Sdteske	for service in ${*:-$( service -l )}; do
335292833Sdteske		slist=
336292833Sdteske		f_sysrc_service_configs $service files || retval=$? continue
337292833Sdteske		for file in $files; do
338292833Sdteske			if [ "$EXISTING_ONLY" ]; then
339292833Sdteske				[ -e "$file" -a ! -d "$file" ] || continue
340292833Sdteske			fi
341292833Sdteske			if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then
342292833Sdteske				case "$list" in
343292833Sdteske				"$file"|*" $file"|"$file "*|*" $file "*)
344292833Sdteske					continue ;;
345292833Sdteske				esac
346292833Sdteske			fi
347292833Sdteske			slist="$slist $file"
348292833Sdteske		done
349292833Sdteske		slist="${slist# }"
350292833Sdteske		if [ $# -gt 0 ]; then
351292833Sdteske			[ "$slist" ] || retval=$?
352292833Sdteske		fi
353292833Sdteske		if [ "$VERBOSE" ]; then
354292833Sdteske			[ "$slist" ] && echo "$service: $slist"
355292833Sdteske			continue
356292833Sdteske		elif [ "$SHOW_EQUALS" ]; then
357292833Sdteske			[ "$slist" ] && echo "$service=\"$slist\""
358292833Sdteske			continue
359292833Sdteske		fi
360292833Sdteske		list="$list${slist:+ }$slist"
361292833Sdteske	done
362292833Sdteske	if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then
363292833Sdteske		if [ $# -eq 0 -o ! "$QUIET" ]; then
364292833Sdteske			list="${list# }"
365292833Sdteske			[ "$list" ] && echo $list
366292833Sdteske		fi
367292833Sdteske	fi
368292833Sdteske
369292833Sdteske	exit $retval
370292833Sdteskefi
371292833Sdteske
372292833Sdteske#
373292833Sdteske# Process `-s name' argument
374292833Sdteske#
375292833Sdteskeif [ "$SERVICE" -a ! "${RC_CONFS+set}" ]; then
376292833Sdteske	if f_sysrc_service_configs "$SERVICE" RC_CONFS; then
377292833Sdteske		rc_conf_files=$( f_sysrc_get rc_conf_files )
378292833Sdteske		RC_CONFS="$rc_conf_files${RC_CONFS:+ }$RC_CONFS"
379292833Sdteske		unset rc_conf_files
380292833Sdteske	else
381292833Sdteske		unset RC_CONFS
382292833Sdteske	fi
383292833Sdteskefi
384292833Sdteske
385292833Sdteske#
386292833Sdteske# Process `-E' option flag
387292833Sdteske#
388292833Sdteskeif [ "$EXISTING_ONLY" ]; then
389292833Sdteske	#
390292833Sdteske	# To get f_sysrc_*() to ignore missing rc_conf_files, we have to use
391292833Sdteske	# RC_CONFS to override the unpreened value. If RC_CONFS already has a
392292833Sdteske	# value (`-D', `-f file', `-s name', or inherited from parent), use it.
393292833Sdteske	# Otherwise, include filtered contents of rc_conf_files.
394292833Sdteske	# 
395292833Sdteske	RC_CONFS=$(
396292833Sdteske		if [ "${RC_CONFS+set}" ]; then
397292833Sdteske			set -- $RC_CONFS
398292833Sdteske		else
399292833Sdteske			set -- $( f_sysrc_get rc_conf_files )
400292833Sdteske		fi
401292833Sdteske		while [ $# -gt 0 ]; do
402292833Sdteske			[ -f "$1" ] && echo -n " $1"
403292833Sdteske			shift
404292833Sdteske		done
405292833Sdteske	)
406292833Sdteske	RC_CONFS="${RC_CONFS# }"
407292833Sdteskefi
408292833Sdteske
409292833Sdteske#
410292833Sdteske# Process `-l' option flag
411292833Sdteske#
412292833Sdteskeif [ "$LIST_CONFS" ]; then
413292833Sdteske	[ $# -eq 0 ] || usage
414292833Sdteske	if [ "$DEFAULT" ]; then
415292833Sdteske		echo "$RC_DEFAULTS"
416292833Sdteske	elif [ "${RC_CONFS+set}" ]; then
417292833Sdteske		echo "$RC_CONFS"
418292833Sdteske	else
419292833Sdteske		f_sysrc_get rc_conf_files
420292833Sdteske	fi
421292833Sdteske	exit $SUCCESS
422292833Sdteskefi
423292833Sdteske
424292833Sdteske#
425241149Sdteske# [More] Sanity checks (e.g., "sysrc --")
426241149Sdteske#
427290303Sdteske[ $# -eq 0 -a ! "$SHOW_ALL" ] && usage # NOTREACHED
428241149Sdteske
429241149Sdteske#
430241149Sdteske# Taint-check all rc.conf(5) files
431241149Sdteske#
432241149Sdteskeerrmsg="$pgm: Exiting due to previous syntax errors"
433241565Sdteskeif [ "${RC_CONFS+set}" ]; then
434241149Sdteske	( for i in $RC_CONFS; do
435241149Sdteske	  	[ -e "$i" ] || continue
436241149Sdteske	  	/bin/sh -n "$i" || exit $FAILURE
437241149Sdteske	  done
438241149Sdteske	  exit $SUCCESS
439241149Sdteske	) || die "$errmsg"
440241149Sdteskeelse
441241149Sdteske	/bin/sh -n "$RC_DEFAULTS" || die "$errmsg"
442241149Sdteske	( . "$RC_DEFAULTS"
443241149Sdteske	  for i in $rc_conf_files; do
444241149Sdteske	  	[ -e "$i" ] || continue
445241149Sdteske	  	/bin/sh -n "$i" || exit $FAILURE
446241149Sdteske	  done
447241149Sdteske	  exit $SUCCESS
448241149Sdteske	) || die "$errmsg"
449241149Sdteskefi
450241149Sdteske
451241149Sdteske#
452241149Sdteske# Process `-x' (and secret `-X') command-line options
453241149Sdteske#
454241149Sdteskeerrmsg="$pgm: \`-x' option incompatible with \`-a'/\`-A' options"
455241149Sdteskeerrmsg="$errmsg (use \`-X' to override)"
456241149Sdteskeif [ "$DELETE" -a "$SHOW_ALL" ]; then
457241149Sdteske	[ "$DELETE" = "2" ] || die "$errmsg"
458241149Sdteskefi
459241149Sdteske
460241149Sdteske#
461260679Sdteske# Pre-flight for `-c' command-line option
462260679Sdteske#
463260679Sdteske[ "$CHECK_ONLY" -a "$SHOW_ALL" ] &&
464260679Sdteske	die "$pgm: \`-c' option incompatible with \`-a'/\`-A' options"
465260679Sdteske
466260679Sdteske#
467241149Sdteske# Process `-e', `-n', and `-N' command-line options
468241149Sdteske#
469241149SdteskeSEP=': '
470260679Sdteske[ "$SHOW_FILE" ] && SHOW_EQUALS=
471241149Sdteske[ "$SHOW_NAME" ] || SHOW_EQUALS=
472290301Sdteske[ "$VERBOSE" = "0" ] && VERBOSE=
473241149Sdteskeif [ ! "$SHOW_VALUE" ]; then
474241149Sdteske	SHOW_NAME=1
475241149Sdteske	SHOW_EQUALS=
476241149Sdteskefi
477260679Sdteske[ "$SHOW_EQUALS" ] && SEP='="'
478241149Sdteske
479241149Sdteske#
480241149Sdteske# Process `-j jail' and `-R dir' command-line options
481241149Sdteske#
482241149Sdteskeif [ "$JAIL" -o "$ROOTDIR" ]; then
483241149Sdteske	#
484241149Sdteske	# Reconstruct the arguments that we want to carry-over
485241149Sdteske	#
486241149Sdteske	args="
487290301Sdteske		${VERBOSE:+-v}
488241149Sdteske		${QUIET:+-q}
489241149Sdteske		$( [ "$DELETE" = "1" ] && echo \ -x )
490241149Sdteske		$( [ "$DELETE" = "2" ] && echo \ -X )
491241149Sdteske		$( [ "$SHOW_ALL" = "1" ] && echo \ -a )
492241149Sdteske		$( [ "$SHOW_ALL" = "2" ] && echo \ -A )
493260679Sdteske		${CHECK_ONLY:+-c}
494292833Sdteske		${DEFAULT:+-D}
495292833Sdteske		${EXISTING_ONLY:+-E}
496292833Sdteske		${LIST_CONFS:+-l}
497292833Sdteske		${LIST_SERVICE_CONFS:+-L}
498241149Sdteske		${DESCRIBE:+-d}
499241149Sdteske		${SHOW_EQUALS:+-e}
500241149Sdteske		${IGNORE_UNKNOWNS:+-i}
501241149Sdteske		$( [ "$SHOW_NAME"  ] || echo \ -n )
502241149Sdteske		$( [ "$SHOW_VALUE" ] || echo \ -N )
503241149Sdteske		$( [ "$SHOW_FILE"  ] && echo \ -F )
504241149Sdteske	"
505292833Sdteske	if [ "$SERVICE" ]; then
506292833Sdteske		escape "$SERVICE" _SERVICE
507292833Sdteske		args="$args -s '$_SERVICE'"
508292833Sdteske		unset _SERVICE
509292833Sdteske	fi
510241565Sdteske	if [ "${RC_CONFS+set}" ]; then
511290304Sdteske		escape "$RC_CONFS" _RC_CONFS
512290304Sdteske		args="$args -f '$_RC_CONFS'"
513290304Sdteske		unset _RC_CONFS
514241149Sdteske	fi
515241149Sdteske	for arg in "$@"; do
516290304Sdteske		escape "$arg" arg
517241149Sdteske		args="$args '$arg'"
518241149Sdteske	done
519241149Sdteske
520241149Sdteske	#
521241149Sdteske	# If both are supplied, `-j jail' supercedes `-R dir'
522241149Sdteske	#
523241149Sdteske	if [ "$JAIL" ]; then
524241149Sdteske		#
525241149Sdteske		# Re-execute ourselves with sh(1) via jexec(8)
526241149Sdteske		#
527241149Sdteske		( echo set -- $args
528241149Sdteske		  jail_depend
529241149Sdteske		  cat $0
530241149Sdteske		) | env - RC_DEFAULTS="$RC_DEFAULTS" \
531241149Sdteske		    	/usr/sbin/jexec "$JAIL" /bin/sh
532241149Sdteske		exit $?
533241149Sdteske	elif [ "$ROOTDIR" ]; then
534241149Sdteske		#
535241149Sdteske		# Make sure that the root directory specified is not to any
536241149Sdteske		# running jails.
537241149Sdteske		#
538241149Sdteske		# NOTE: To maintain backward compatibility with older jails on
539241149Sdteske		# older systems, we will not perform this check if either the
540241149Sdteske		# jls(1) or jexec(8) utilities are missing.
541241149Sdteske		#
542241149Sdteske		if f_have jexec && f_have jls; then
543290312Sdteske			jid=$( jls jid path |
544241149Sdteske				while read JID JROOT; do
545241149Sdteske					[ "$JROOT" = "$ROOTDIR" ] || continue
546241149Sdteske					echo $JID
547241149Sdteske				done
548290312Sdteske			)
549241149Sdteske
550241149Sdteske			#
551241149Sdteske			# If multiple running jails match the specified root
552241149Sdteske			# directory, exit with error.
553241149Sdteske			#
554241149Sdteske			if [ "$jid" -a "${jid%[$IFS]*}" != "$jid" ]; then
555241149Sdteske				die "%s: %s: %s" "$pgm" "$ROOTDIR" \
556241149Sdteske				    "$( echo "Multiple jails claim this" \
557241149Sdteske				             "directory as their root." \
558241149Sdteske				             "(use \`-j jail' instead)" )"
559241149Sdteske			fi
560241149Sdteske
561241149Sdteske			#
562241149Sdteske			# If only a single running jail matches the specified
563241149Sdteske			# root directory, implicitly use `-j jail'.
564241149Sdteske			#
565241149Sdteske			if [ "$jid" ]; then
566241149Sdteske				#
567241149Sdteske				# Re-execute outselves with sh(1) via jexec(8)
568241149Sdteske				#
569241149Sdteske				( echo set -- $args
570241149Sdteske				  jail_depend
571241149Sdteske				  cat $0
572241149Sdteske				) | env - RC_DEFAULTS="$RC_DEFAULTS" \
573241149Sdteske					/usr/sbin/jexec "$jid" /bin/sh
574241149Sdteske				exit $?
575241149Sdteske			fi
576241149Sdteske
577241149Sdteske			# Otherwise, fall through and allow chroot(8)
578241149Sdteske		fi
579241149Sdteske
580241149Sdteske		#
581241149Sdteske		# Re-execute ourselves with sh(1) via chroot(8)
582241149Sdteske		#
583241149Sdteske		( echo set -- $args
584241149Sdteske		  jail_depend
585241149Sdteske		  cat $0
586241149Sdteske		) | env - RC_DEFAULTS="$RC_DEFAULTS" \
587241149Sdteske		    	/usr/sbin/chroot "$ROOTDIR" /bin/sh
588241149Sdteske		exit $?
589241149Sdteske	fi
590241149Sdteskefi
591241149Sdteske
592241149Sdteske#
593241149Sdteske# Process `-a' or `-A' command-line options
594241149Sdteske#
595241149Sdteskeif [ "$SHOW_ALL" ]; then
596241149Sdteske	#
597241149Sdteske	# Get a list of variables that are currently set in the rc.conf(5)
598241149Sdteske	# files (included `/etc/defaults/rc.conf') by performing a call to
599241149Sdteske	# source_rc_confs() in a clean environment.
600241149Sdteske	#
601241149Sdteske	( # Operate in a sub-shell to protect the parent environment
602241149Sdteske		#
603241149Sdteske		# Set which variables we want to preserve in the environment.
604241149Sdteske		# Append the pipe-character (|) to the list of internal field
605241149Sdteske		# separation (IFS) characters, allowing us to use the below
606241149Sdteske		# list both as an extended grep (-E) pattern and argument list
607241149Sdteske		# (required to first get f_clean_env() to preserve these in the
608241149Sdteske		# environment and then later to prune them from the list of
609241149Sdteske		# variables produced by set(1)).
610241149Sdteske		#
611241149Sdteske		IFS="$IFS|"
612241149Sdteske		EXCEPT="IFS|EXCEPT|PATH|RC_DEFAULTS|OPTIND|DESCRIBE|SEP"
613292833Sdteske		EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME|DEFAULT"
614292833Sdteske		EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS|SERVICE"
615292833Sdteske		EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY|EXISTING_ONLY"
616292833Sdteske		EXCEPT="$EXCEPT|LIST_CONFS|LIST_SERVICE_CONFS"
617241149Sdteske		EXCEPT="$EXCEPT|f_sysrc_desc_awk|f_sysrc_delete_awk"
618241149Sdteske
619241149Sdteske		#
620241149Sdteske		# Clean the environment (except for our required variables)
621241149Sdteske		# and then source the required files.
622241149Sdteske		#
623241149Sdteske		f_clean_env --except $EXCEPT
624241149Sdteske		if [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ]; then
625241149Sdteske			. "$RC_DEFAULTS"
626241149Sdteske
627241149Sdteske			#
628241149Sdteske			# If passed `-a' (rather than `-A'), re-purge the
629241149Sdteske			# environment, removing the rc.conf(5) defaults.
630241149Sdteske			#
631290312Sdteske			[ "$SHOW_ALL" = "1" ] &&
632290312Sdteske				f_clean_env --except rc_conf_files $EXCEPT
633241149Sdteske
634241149Sdteske			#
635241149Sdteske			# If `-f file' was passed, set $rc_conf_files to an
636241149Sdteske			# explicit value, modifying the default behavior of
637241149Sdteske			# source_rc_confs().
638241149Sdteske			#
639292833Sdteske			if [ "${RC_CONFS+set}" ]; then
640292833Sdteske				[ "$SHOW_ALL" = "1" -a "$SERVICE" -a \
641292833Sdteske					! "$DEFAULT" ] || rc_conf_files=
642292833Sdteske				rc_conf_files="$rc_conf_files $RC_CONFS"
643292833Sdteske				rc_conf_files="${rc_conf_files# }"
644292833Sdteske				rc_conf_files="${rc_conf_files% }"
645292833Sdteske			fi
646241149Sdteske
647241149Sdteske			source_rc_confs
648241149Sdteske
649241149Sdteske			#
650241149Sdteske			# If passed `-a' (rather than `-A'), remove
651241149Sdteske			# `rc_conf_files' unless it was defined somewhere
652241149Sdteske			# other than rc.conf(5) defaults.
653241149Sdteske			#
654241149Sdteske			[ "$SHOW_ALL" = "1" -a \
655241149Sdteske			  "$( f_sysrc_find rc_conf_files )" = "$RC_DEFAULTS" \
656290312Sdteske			] && unset rc_conf_files
657241149Sdteske		fi
658241149Sdteske
659241149Sdteske		for NAME in $( set |
660241149Sdteske			awk -F= '/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' |
661241149Sdteske			grep -Ev "^($EXCEPT)$"
662241149Sdteske		); do
663241149Sdteske			#
664241149Sdteske			# If enabled, describe rather than expand value
665241149Sdteske			#
666241149Sdteske			if [ "$DESCRIBE" ]; then
667241149Sdteske				echo "$NAME: $( f_sysrc_desc "$NAME" )"
668241149Sdteske				continue
669241149Sdteske			fi
670241149Sdteske
671241149Sdteske			#
672241149Sdteske			# If `-F' is passed, find it and move on
673241149Sdteske			#
674241149Sdteske			if [ "$SHOW_FILE" ]; then
675241149Sdteske				[ "$SHOW_NAME" ] && echo -n "$NAME: "
676241149Sdteske				f_sysrc_find "$NAME"
677241149Sdteske				continue
678241149Sdteske			fi
679241149Sdteske
680241149Sdteske			#
681241149Sdteske			# If `-X' is passed, delete the variables
682241149Sdteske			#
683241149Sdteske			if [ "$DELETE" = "2" ]; then
684241149Sdteske				f_sysrc_delete "$NAME"
685241149Sdteske				continue
686241149Sdteske			fi
687241149Sdteske
688290312Sdteske			[ "$VERBOSE" ] &&
689241149Sdteske				echo -n "$( f_sysrc_find "$NAME" ): "
690241149Sdteske
691241149Sdteske			#
692241149Sdteske			# If `-N' is passed, simplify the output
693241149Sdteske			#
694241149Sdteske			if [ ! "$SHOW_VALUE" ]; then
695241149Sdteske				echo "$NAME"
696241149Sdteske				continue
697241149Sdteske			fi
698241149Sdteske
699241149Sdteske			echo "${SHOW_NAME:+$NAME$SEP}$(
700241149Sdteske			      f_sysrc_get "$NAME" )${SHOW_EQUALS:+\"}"
701241149Sdteske
702241149Sdteske		done
703241149Sdteske	)
704241149Sdteske
705241149Sdteske	#
706241149Sdteske	# Ignore the remainder of positional arguments.
707241149Sdteske	#
708241149Sdteske	exit $SUCCESS
709241149Sdteskefi
710241149Sdteske
711241149Sdteske#
712241149Sdteske# Process command-line arguments
713241149Sdteske#
714272191Sdteskestatus=$SUCCESS
715241149Sdteskewhile [ $# -gt 0 ]; do
716241149Sdteske	NAME="${1%%=*}"
717241149Sdteske
718280390Sdteske	case "$NAME" in
719280390Sdteske	*+) mode=APPEND NAME="${NAME%+}" ;;
720280390Sdteske	*-) mode=REMOVE NAME="${NAME%-}" ;;
721280390Sdteske	 *) mode=ASSIGN
722280390Sdteske	esac
723280390Sdteske
724290312Sdteske	[ "$DESCRIBE" ] &&
725241149Sdteske		echo "$NAME: $( f_sysrc_desc "$NAME" )"
726241149Sdteske
727241149Sdteske	case "$1" in
728241149Sdteske	*=*)
729241149Sdteske		#
730241149Sdteske		# Like sysctl(8), if both `-d' AND "name=value" is passed,
731260679Sdteske		# first describe (done above), then attempt to set
732241149Sdteske		#
733241149Sdteske
734260679Sdteske		# If verbose, prefix line with where the directive lives
735290301Sdteske		if [ "$VERBOSE" -a ! "$CHECK_ONLY" ]; then
736241149Sdteske			file=$( f_sysrc_find "$NAME" )
737290312Sdteske			[ "$file" = "$RC_DEFAULTS" -o ! "$file" ] &&
738241149Sdteske				file=$( f_sysrc_get 'rc_conf_files%%[$IFS]*' )
739260679Sdteske			if [ "$SHOW_EQUALS" ]; then
740260679Sdteske				echo -n ": $file; "
741260679Sdteske			else
742260679Sdteske				echo -n "$file: "
743260679Sdteske			fi
744241149Sdteske		fi
745241149Sdteske
746241149Sdteske		#
747241149Sdteske		# If `-x' or `-X' is passed, delete the variable and ignore the
748241149Sdteske		# desire to set some value
749241149Sdteske		#
750241149Sdteske		if [ "$DELETE" ]; then
751272191Sdteske			f_sysrc_delete "$NAME" || status=$FAILURE
752241149Sdteske			shift 1
753241149Sdteske			continue
754241149Sdteske		fi
755241149Sdteske
756241149Sdteske		#
757260679Sdteske		# If `-c' is passed, simply compare and move on
758260679Sdteske		#
759260679Sdteske		if [ "$CHECK_ONLY" ]; then
760260679Sdteske			if ! IGNORED=$( f_sysrc_get "$NAME?" ); then
761272191Sdteske				status=$FAILURE
762290301Sdteske				[ "$VERBOSE" ] &&
763272191Sdteske					echo "$NAME: not currently set"
764272191Sdteske				shift 1
765272191Sdteske				continue
766260679Sdteske			fi
767272191Sdteske			value=$( f_sysrc_get "$NAME" )
768272191Sdteske			if [ "$value" != "${1#*=}" ]; then
769272191Sdteske				status=$FAILURE
770290301Sdteske				if [ "$VERBOSE" ]; then
771272191Sdteske					echo -n "$( f_sysrc_find "$NAME" ): "
772272191Sdteske					echo -n "$NAME: would change from "
773272191Sdteske					echo "\`$value' to \`${1#*=}'"
774272191Sdteske				fi
775290301Sdteske			elif [ "$VERBOSE" ]; then
776272191Sdteske				echo -n "$( f_sysrc_find "$NAME" ): "
777272191Sdteske				echo "$NAME: already set to \`$value'"
778272191Sdteske			fi
779260679Sdteske			shift 1
780260679Sdteske			continue
781260679Sdteske		fi
782260679Sdteske
783260679Sdteske		#
784280390Sdteske		# Determine both `before' value and appropriate `new' value
785241149Sdteske		#
786280390Sdteske		case "$mode" in
787280390Sdteske		APPEND)
788280390Sdteske			before=$( f_sysrc_get "$NAME" )
789280390Sdteske			add="${1#*=}"
790280390Sdteske			delim="${add%"${add#?}"}" # first character
791280390Sdteske			oldIFS="$IFS"
792280390Sdteske			case "$delim" in
793280390Sdteske			""|[$IFS]|[a-zA-Z0-9]) delim=" " ;;
794280390Sdteske			*) IFS="$delim"
795280390Sdteske			esac
796280390Sdteske			new="$before"
797280390Sdteske			for a in $add; do
798280390Sdteske				[ "$a" ] || continue
799280390Sdteske				skip=
800280390Sdteske				for b in $before; do
801280390Sdteske					[ "$b" = "$a" ] && skip=1 break
802280390Sdteske				done
803280390Sdteske				[ "$skip" ] || new="$new$delim$a"
804280390Sdteske			done
805280390Sdteske			new="${new#"$delim"}" IFS="$oldIFS"
806280390Sdteske			unset add delim oldIFS a skip b
807280390Sdteske			[ "$SHOW_FILE" ] && before=$( f_sysrc_find "$NAME" )
808280390Sdteske			;;
809280390Sdteske		REMOVE)
810280390Sdteske			before=$( f_sysrc_get "$NAME" )
811280390Sdteske			remove="${1#*=}"
812280390Sdteske			delim="${remove%"${remove#?}"}" # first character
813280390Sdteske			oldIFS="$IFS"
814280390Sdteske			case "$delim" in
815280390Sdteske			""|[$IFS]|[a-zA-Z0-9]) delim=" " ;;
816280390Sdteske			*) IFS="$delim"
817280390Sdteske			esac
818280390Sdteske			new=
819280390Sdteske			for b in $before; do
820280390Sdteske				[ "$b" ] || continue
821280390Sdteske				add=1
822280390Sdteske				for r in $remove; do
823280390Sdteske					[ "$r" = "$b" ] && add= break
824280390Sdteske				done
825280390Sdteske				[ "$add" ] && new="$new$delim$b"
826280390Sdteske			done
827280390Sdteske			new="${new#"$delim"}" IFS="$oldIFS"
828280390Sdteske			unset remove delim oldIFS b add r
829280390Sdteske			[ "$SHOW_FILE" ] && before=$( f_sysrc_find "$NAME" )
830280390Sdteske			;;
831290305Sdteske		*) # ASSIGN
832241149Sdteske			if [ "$SHOW_FILE" ]; then
833241149Sdteske				before=$( f_sysrc_find "$NAME" )
834241149Sdteske			else
835241149Sdteske				before=$( f_sysrc_get "$NAME" )
836241149Sdteske			fi
837280390Sdteske			new="${1#*=}"
838280390Sdteske		esac
839280390Sdteske
840280390Sdteske		#
841280390Sdteske		# If `-N' is passed, simplify the output
842280390Sdteske		#
843280390Sdteske		if [ ! "$SHOW_VALUE" ]; then
844280390Sdteske			echo "$NAME"
845280390Sdteske			f_sysrc_set "$NAME" "$new"
846280390Sdteske		else
847280390Sdteske			if f_sysrc_set "$NAME" "$new"; then
848241149Sdteske				if [ "$SHOW_FILE" ]; then
849241149Sdteske					after=$( f_sysrc_find "$NAME" )
850241149Sdteske				else
851241149Sdteske					after=$( f_sysrc_get "$NAME" )
852241149Sdteske				fi
853260679Sdteske				echo -n "${SHOW_NAME:+$NAME$SEP}"
854260679Sdteske				echo -n "$before${SHOW_EQUALS:+\" #}"
855260679Sdteske				echo -n " -> ${SHOW_EQUALS:+\"}$after"
856260679Sdteske				echo "${SHOW_EQUALS:+\"}"
857241149Sdteske			fi
858241149Sdteske		fi
859241149Sdteske		;;
860241149Sdteske	*)
861260679Sdteske		if ! IGNORED=$( f_sysrc_get "$NAME?" ); then
862272191Sdteske			[ "$IGNORE_UNKNOWNS" -o "$QUIET" ] ||
863337588Sdteske				f_err "%s: unknown variable '%s'\n" \
864337588Sdteske					"$pgm" "$NAME"
865241149Sdteske			shift 1
866272191Sdteske			status=$FAILURE
867241149Sdteske			continue
868241149Sdteske		fi
869241149Sdteske
870260679Sdteske		# The above check told us what we needed for `-c'
871260679Sdteske		if [ "$CHECK_ONLY" ]; then
872260679Sdteske			shift 1
873260679Sdteske			continue
874260679Sdteske		fi
875260679Sdteske
876241149Sdteske		#
877260679Sdteske		# Like sysctl(8), when `-d' is passed, desribe it
878260679Sdteske		# (already done above) rather than expanding it
879241149Sdteske		#
880241149Sdteske
881241149Sdteske		if [ "$DESCRIBE" ]; then
882241149Sdteske			shift 1
883241149Sdteske			continue
884241149Sdteske		fi
885241149Sdteske
886241149Sdteske		#
887241149Sdteske		# If `-x' or `-X' is passed, delete the variable
888241149Sdteske		#
889241149Sdteske		if [ "$DELETE" ]; then
890272191Sdteske			f_sysrc_delete "$NAME" || status=$FAILURE
891241149Sdteske			shift 1
892241149Sdteske			continue
893241149Sdteske		fi
894241149Sdteske
895241149Sdteske		#
896241149Sdteske		# If `-F' is passed, find it and move on
897241149Sdteske		#
898241149Sdteske		if [ "$SHOW_FILE" ]; then
899241149Sdteske			[ "$SHOW_NAME" ] && echo -n "$NAME: "
900241149Sdteske			f_sysrc_find "$NAME"
901241149Sdteske			shift 1
902241149Sdteske			continue
903241149Sdteske		fi
904241149Sdteske
905290301Sdteske		if [ "$VERBOSE" ]; then
906260679Sdteske			if [ "$SHOW_EQUALS" ]; then
907260679Sdteske				echo -n ": $( f_sysrc_find "$NAME" ); "
908260679Sdteske			else
909260679Sdteske				echo -n "$( f_sysrc_find "$NAME" ): "
910260679Sdteske			fi
911260679Sdteske		fi
912241149Sdteske
913241149Sdteske		#
914241149Sdteske		# If `-N' is passed, simplify the output
915241149Sdteske		#
916241149Sdteske		if [ ! "$SHOW_VALUE" ]; then
917241149Sdteske			echo "$NAME"
918241149Sdteske		else
919241149Sdteske			echo "${SHOW_NAME:+$NAME$SEP}$(
920241149Sdteske			      f_sysrc_get "$NAME" )${SHOW_EQUALS:+\"}"
921241149Sdteske		fi
922241149Sdteske	esac
923241149Sdteske	shift 1
924241149Sdteskedone
925260679Sdteske
926272191Sdteskeexit $status # $SUCCESS unless error occurred with either `-c' or `-x'
927260679Sdteske
928260679Sdteske################################################################################
929260679Sdteske# END
930260679Sdteske################################################################################
931