xref: /freebsd-src/usr.sbin/bsdconfig/share/common.subr (revision c36b3dbc99d1e6dfc658e9c20382abc75749af82)
1ab2043b8SDevin Teskeif [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1
2ab2043b8SDevin Teske#
3ab2043b8SDevin Teske# Copyright (c) 2012 Ron McDowell
4d1eef61dSDevin Teske# Copyright (c) 2012-2016 Devin Teske
5ab2043b8SDevin Teske# All rights reserved.
6ab2043b8SDevin Teske#
7ab2043b8SDevin Teske# Redistribution and use in source and binary forms, with or without
8ab2043b8SDevin Teske# modification, are permitted provided that the following conditions
9ab2043b8SDevin Teske# are met:
10ab2043b8SDevin Teske# 1. Redistributions of source code must retain the above copyright
11ab2043b8SDevin Teske#    notice, this list of conditions and the following disclaimer.
12ab2043b8SDevin Teske# 2. Redistributions in binary form must reproduce the above copyright
13ab2043b8SDevin Teske#    notice, this list of conditions and the following disclaimer in the
14ab2043b8SDevin Teske#    documentation and/or other materials provided with the distribution.
15ab2043b8SDevin Teske#
16ab2043b8SDevin Teske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17ab2043b8SDevin Teske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ab2043b8SDevin Teske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ab2043b8SDevin Teske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20ab2043b8SDevin Teske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ab2043b8SDevin Teske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ab2043b8SDevin Teske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ab2043b8SDevin Teske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ab2043b8SDevin Teske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ab2043b8SDevin Teske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ab2043b8SDevin Teske# SUCH DAMAGE.
27ab2043b8SDevin Teske#
28ab2043b8SDevin Teske#
29526e1dc1SDevin Teske############################################################ CONFIGURATION
30526e1dc1SDevin Teske
31526e1dc1SDevin Teske#
32526e1dc1SDevin Teske# Default file descriptors to link to stdout/stderr for passthru allowing
33526e1dc1SDevin Teske# redirection within a sub-shell to bypass directly to the terminal.
34526e1dc1SDevin Teske#
35dc68c8b3SDevin Teske: ${TERMINAL_STDOUT_PASSTHRU:=3}
36dc68c8b3SDevin Teske: ${TERMINAL_STDERR_PASSTHRU:=4}
37526e1dc1SDevin Teske
38cc42ef53SBrad Davis#
39cc42ef53SBrad Davis# Default OSNAME shown in the installer
40cc42ef53SBrad Davis#
41cc42ef53SBrad Davis: ${OSNAME:=FreeBSD}
42cc42ef53SBrad Davis: ${EFI_LABEL_NAME:=FreeBSD}
43cc42ef53SBrad Davis
44ab2043b8SDevin Teske############################################################ GLOBALS
45ab2043b8SDevin Teske
46ab2043b8SDevin Teske#
47ab2043b8SDevin Teske# Program name
48ab2043b8SDevin Teske#
49ab2043b8SDevin Teskepgm="${0##*/}"
50ab2043b8SDevin Teske
51ab2043b8SDevin Teske#
52ab2043b8SDevin Teske# Program arguments
53ab2043b8SDevin Teske#
54ab2043b8SDevin TeskeARGC="$#"
55ab2043b8SDevin TeskeARGV="$@"
56ab2043b8SDevin Teske
57ab2043b8SDevin Teske#
58ab2043b8SDevin Teske# Global exit status variables
59ab2043b8SDevin Teske#
60ab2043b8SDevin TeskeSUCCESS=0
61ab2043b8SDevin TeskeFAILURE=1
62ab2043b8SDevin Teske
6356961fd7SDevin Teske#
6456961fd7SDevin Teske# Operating environment details
6556961fd7SDevin Teske#
6656961fd7SDevin Teskeexport UNAME_S="$( uname -s )" # Operating System (i.e. FreeBSD)
6756961fd7SDevin Teskeexport UNAME_P="$( uname -p )" # Processor Architecture (i.e. i386)
68632d9a08SDevin Teskeexport UNAME_M="$( uname -m )" # Machine platform (i.e. i386)
6956961fd7SDevin Teskeexport UNAME_R="$( uname -r )" # Release Level (i.e. X.Y-RELEASE)
7056961fd7SDevin Teske
71e14ddd1fSDevin Teske#
72e14ddd1fSDevin Teske# Default behavior is to call f_debug_init() automatically when loaded.
73e14ddd1fSDevin Teske#
74e14ddd1fSDevin Teske: ${DEBUG_SELF_INITIALIZE=1}
75e14ddd1fSDevin Teske
76c3755aa3SDevin Teske#
7757f3f6eeSDevin Teske# Default behavior of f_debug_init() is to truncate $debugFile (set to NULL to
7857f3f6eeSDevin Teske# disable truncating the debug file when initializing). To get child processes
7957f3f6eeSDevin Teske# to append to the same log file, export this variarable (with a NULL value)
8057f3f6eeSDevin Teske# and also export debugFile with the desired value.
8157f3f6eeSDevin Teske#
8257f3f6eeSDevin Teske: ${DEBUG_INITIALIZE_FILE=1}
8357f3f6eeSDevin Teske
8457f3f6eeSDevin Teske#
85c3755aa3SDevin Teske# Define standard optstring arguments that should be supported by all programs
86c3755aa3SDevin Teske# using this include (unless DEBUG_SELF_INITIALIZE is set to NULL to prevent
87c3755aa3SDevin Teske# f_debug_init() from autamatically processing "$@" for the below arguments):
88c3755aa3SDevin Teske#
89c3755aa3SDevin Teske# 	d	Sets $debug to 1
90c3755aa3SDevin Teske# 	D:	Sets $debugFile to $OPTARG
91c3755aa3SDevin Teske#
92c3755aa3SDevin TeskeGETOPTS_STDARGS="dD:"
93c3755aa3SDevin Teske
945b4765c3SDevin Teske#
955b4765c3SDevin Teske# The getopts builtin will return 1 either when the end of "$@" or the first
965b4765c3SDevin Teske# invalid flag is reached. This makes it impossible to determine if you've
975b4765c3SDevin Teske# processed all the arguments or simply have hit an invalid flag. In the cases
985b4765c3SDevin Teske# where we want to tolerate invalid flags (f_debug_init() for example), the
995b4765c3SDevin Teske# following variable can be appended to your optstring argument to getopts,
1005b4765c3SDevin Teske# preventing it from prematurely returning 1 before the end of the arguments.
1015b4765c3SDevin Teske#
1025b4765c3SDevin Teske# NOTE: This assumes that all unknown flags are argument-less.
1035b4765c3SDevin Teske#
1045b4765c3SDevin TeskeGETOPTS_ALLFLAGS="abcdefghijklmnopqrstuvwxyz"
1055b4765c3SDevin TeskeGETOPTS_ALLFLAGS="${GETOPTS_ALLFLAGS}ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1065b4765c3SDevin TeskeGETOPTS_ALLFLAGS="${GETOPTS_ALLFLAGS}0123456789"
1075b4765c3SDevin Teske
1085b4765c3SDevin Teske#
1095b4765c3SDevin Teske# When we get included, f_debug_init() will fire (unless $DEBUG_SELF_INITIALIZE
1105b4765c3SDevin Teske# is set to disable automatic initialization) and process "$@" for a few global
1115b4765c3SDevin Teske# options such as `-d' and/or `-D file'. However, if your program takes custom
1125b4765c3SDevin Teske# flags that take arguments, this automatic processing may fail unexpectedly.
1135b4765c3SDevin Teske#
1145b4765c3SDevin Teske# The solution to this problem is to pre-define (before including this file)
1155b4765c3SDevin Teske# the following variable (which defaults to NULL) to indicate that there are
1165b4765c3SDevin Teske# extra flags that should be considered when performing automatic processing of
1175b4765c3SDevin Teske# globally persistent flags.
1185b4765c3SDevin Teske#
1195b4765c3SDevin Teske: ${GETOPTS_EXTRA:=}
1205b4765c3SDevin Teske
121ab2043b8SDevin Teske############################################################ FUNCTIONS
122ab2043b8SDevin Teske
1233e8cb79dSDevin Teske# f_dprintf $format [$arguments ...]
124ab2043b8SDevin Teske#
12556961fd7SDevin Teske# Sensible debug function. Override in ~/.bsdconfigrc if desired.
12656961fd7SDevin Teske# See /usr/share/examples/bsdconfig/bsdconfigrc for example.
127ab2043b8SDevin Teske#
128450f13a4SDevin Teske# If $debug is set and non-NULL, prints DEBUG info using printf(1) syntax:
129450f13a4SDevin Teske# 	+ To $debugFile, if set and non-NULL
130450f13a4SDevin Teske# 	+ To standard output if $debugFile is either NULL or unset
131450f13a4SDevin Teske# 	+ To both if $debugFile begins with a single plus-sign (`+')
132450f13a4SDevin Teske#
133ab2043b8SDevin Teskef_dprintf()
134ab2043b8SDevin Teske{
13556961fd7SDevin Teske	[ "$debug" ] || return $SUCCESS
13656961fd7SDevin Teske	local fmt="$1"; shift
1379c83db2dSDevin Teske	case "$debugFile" in ""|+*)
13856961fd7SDevin Teske	printf "DEBUG: $fmt${fmt:+\n}" "$@" >&${TERMINAL_STDOUT_PASSTHRU:-1}
1399c83db2dSDevin Teske	esac
1409c83db2dSDevin Teske	[ "${debugFile#+}" ] &&
1419c83db2dSDevin Teske		printf "DEBUG: $fmt${fmt:+\n}" "$@" >> "${debugFile#+}"
1429c83db2dSDevin Teske	return $SUCCESS
143ab2043b8SDevin Teske}
144ab2043b8SDevin Teske
145e14ddd1fSDevin Teske# f_debug_init
146e14ddd1fSDevin Teske#
147e14ddd1fSDevin Teske# Initialize debugging. Truncates $debugFile to zero bytes if set.
148e14ddd1fSDevin Teske#
149e14ddd1fSDevin Teskef_debug_init()
150e14ddd1fSDevin Teske{
151e14ddd1fSDevin Teske	#
152e14ddd1fSDevin Teske	# Process stored command-line arguments
153e14ddd1fSDevin Teske	#
1548c944ff5SDevin Teske	set -- $ARGV
1559ecd54f2SDevin Teske	local OPTIND OPTARG flag
156c3755aa3SDevin Teske	f_dprintf "f_debug_init: ARGV=[%s] GETOPTS_STDARGS=[%s]" \
157c3755aa3SDevin Teske	          "$ARGV" "$GETOPTS_STDARGS"
1585b4765c3SDevin Teske	while getopts "$GETOPTS_STDARGS$GETOPTS_EXTRA$GETOPTS_ALLFLAGS" flag \
1595b4765c3SDevin Teske	> /dev/null; do
160e14ddd1fSDevin Teske		case "$flag" in
1618c944ff5SDevin Teske		d) debug=1 ;;
1628c944ff5SDevin Teske		D) debugFile="$OPTARG" ;;
163e14ddd1fSDevin Teske		esac
164e14ddd1fSDevin Teske	done
1658c944ff5SDevin Teske	shift $(( $OPTIND - 1 ))
166c3755aa3SDevin Teske	f_dprintf "f_debug_init: debug=[%s] debugFile=[%s]" \
167c3755aa3SDevin Teske	          "$debug" "$debugFile"
1688c944ff5SDevin Teske
1698c944ff5SDevin Teske	#
1708c944ff5SDevin Teske	# Automagically enable debugging if debugFile is set (and non-NULL)
1718c944ff5SDevin Teske	#
1728c944ff5SDevin Teske	[ "$debugFile" ] && { [ "${debug+set}" ] || debug=1; }
173e14ddd1fSDevin Teske
174e14ddd1fSDevin Teske	#
175ec65e4f8SPedro F. Giffuni	# Make debugging persistent if set
176e14ddd1fSDevin Teske	#
177e14ddd1fSDevin Teske	[ "$debug" ] && export debug
178dcfa0eb3SDevin Teske	[ "$debugFile" ] && export debugFile
179e14ddd1fSDevin Teske
180e14ddd1fSDevin Teske	#
18157f3f6eeSDevin Teske	# Truncate debug file unless requested otherwise. Note that we will
18257f3f6eeSDevin Teske	# trim a leading plus (`+') from the value of debugFile to support
183ec65e4f8SPedro F. Giffuni	# persistent meaning that f_dprintf() should print both to standard
18457f3f6eeSDevin Teske	# output and $debugFile (minus the leading plus, of course).
185e14ddd1fSDevin Teske	#
186e14ddd1fSDevin Teske	local _debug_file="${debugFile#+}"
18757f3f6eeSDevin Teske	if [ "$_debug_file" -a "$DEBUG_INITIALIZE_FILE" ]; then
188e14ddd1fSDevin Teske		if ( umask 022 && :> "$_debug_file" ); then
189e14ddd1fSDevin Teske			f_dprintf "Successfully initialized debugFile \`%s'" \
190e14ddd1fSDevin Teske			          "$_debug_file"
1913e8cb79dSDevin Teske			f_isset debug || debug=1 # turn debugging on if not set
192e14ddd1fSDevin Teske		else
193e14ddd1fSDevin Teske			unset debugFile
194e14ddd1fSDevin Teske			f_dprintf "Unable to initialize debugFile \`%s'" \
195e14ddd1fSDevin Teske			          "$_debug_file"
196e14ddd1fSDevin Teske		fi
197e14ddd1fSDevin Teske	fi
198e14ddd1fSDevin Teske}
199e14ddd1fSDevin Teske
2003e8cb79dSDevin Teske# f_err $format [$arguments ...]
201ab2043b8SDevin Teske#
202ab2043b8SDevin Teske# Print a message to stderr (fd=2).
203ab2043b8SDevin Teske#
204ab2043b8SDevin Teskef_err()
205ab2043b8SDevin Teske{
206d4ae33f0SDevin Teske	printf "$@" >&2
207ab2043b8SDevin Teske}
208ab2043b8SDevin Teske
209ab2043b8SDevin Teske# f_quietly $command [$arguments ...]
210ab2043b8SDevin Teske#
2112d49f165SDevin Teske# Run a command quietly (quell any output to stdout or stderr)
212ab2043b8SDevin Teske#
213ab2043b8SDevin Teskef_quietly()
214ab2043b8SDevin Teske{
215fb7d723eSDevin Teske	"$@" > /dev/null 2>&1
216ab2043b8SDevin Teske}
217ab2043b8SDevin Teske
218ab2043b8SDevin Teske# f_have $anything ...
219ab2043b8SDevin Teske#
220ab2043b8SDevin Teske# A wrapper to the `type' built-in. Returns true if argument is a valid shell
221ab2043b8SDevin Teske# built-in, keyword, or externally-tracked binary, otherwise false.
222ab2043b8SDevin Teske#
223ab2043b8SDevin Teskef_have()
224ab2043b8SDevin Teske{
225ab2043b8SDevin Teske	f_quietly type "$@"
226ab2043b8SDevin Teske}
227ab2043b8SDevin Teske
2284d5a468dSDevin Teske# setvar $var_to_set [$value]
2294d5a468dSDevin Teske#
2307729d5e3SDevin Teske# Implement setvar for shells unlike FreeBSD sh(1).
2314d5a468dSDevin Teske#
2324d5a468dSDevin Teskeif ! f_have setvar; then
2334d5a468dSDevin Teskesetvar()
2344d5a468dSDevin Teske{
2354d5a468dSDevin Teske	[ $# -gt 0 ] || return $SUCCESS
2364d5a468dSDevin Teske	local __setvar_var_to_set="$1" __setvar_right="$2" __setvar_left=
2374d5a468dSDevin Teske	case $# in
2384d5a468dSDevin Teske	1) unset "$__setvar_var_to_set"
2394d5a468dSDevin Teske	   return $? ;;
2404d5a468dSDevin Teske	2) : fall through ;;
2414d5a468dSDevin Teske	*) f_err "setvar: too many arguments\n"
2424d5a468dSDevin Teske	   return $FAILURE
2434d5a468dSDevin Teske	esac
2447729d5e3SDevin Teske	case "$__setvar_var_to_set" in *[!0-9A-Za-z_]*)
2457729d5e3SDevin Teske		f_err "setvar: %s: bad variable name\n" "$__setvar_var_to_set"
2467729d5e3SDevin Teske		return 2
2477729d5e3SDevin Teske	esac
2484d5a468dSDevin Teske	while case "$__setvar_r" in *\'*) : ;; *) false ; esac
2494d5a468dSDevin Teske	do
2504d5a468dSDevin Teske		__setvar_left="$__setvar_left${__setvar_right%%\'*}'\\''"
2514d5a468dSDevin Teske		__setvar_right="${__setvar_right#*\'}"
2524d5a468dSDevin Teske	done
2534d5a468dSDevin Teske	__setvar_left="$__setvar_left${__setvar_right#*\'}"
2544d5a468dSDevin Teske	eval "$__setvar_var_to_set='$__setvar_left'"
2554d5a468dSDevin Teske}
2564d5a468dSDevin Teskefi
2574d5a468dSDevin Teske
258c0adcdb9SDevin Teske# f_which $anything [$var_to_set]
259c0adcdb9SDevin Teske#
260c0adcdb9SDevin Teske# A fast built-in replacement for syntaxes such as foo=$( which bar ). In a
261c0adcdb9SDevin Teske# comparison of 10,000 runs of this function versus which, this function
262c0adcdb9SDevin Teske# completed in under 3 seconds, while `which' took almost a full minute.
263c0adcdb9SDevin Teske#
264c0adcdb9SDevin Teske# If $var_to_set is missing or NULL, output is (like which) to standard out.
265c0adcdb9SDevin Teske# Returns success if a match was found, failure otherwise.
266c0adcdb9SDevin Teske#
267c0adcdb9SDevin Teskef_which()
268c0adcdb9SDevin Teske{
269c0adcdb9SDevin Teske	local __name="$1" __var_to_set="$2"
270c0adcdb9SDevin Teske	case "$__name" in */*|'') return $FAILURE; esac
27136fb8bfcSDevin Teske	local __p __exec IFS=":" __found=
272c0adcdb9SDevin Teske	for __p in $PATH; do
27336fb8bfcSDevin Teske		__exec="$__p/$__name"
27436fb8bfcSDevin Teske		[ -f "$__exec" -a -x "$__exec" ] && __found=1 break
275c0adcdb9SDevin Teske	done
276c0adcdb9SDevin Teske	if [ "$__found" ]; then
277c0adcdb9SDevin Teske		if [ "$__var_to_set" ]; then
278c0adcdb9SDevin Teske			setvar "$__var_to_set" "$__exec"
279c0adcdb9SDevin Teske		else
280c0adcdb9SDevin Teske			echo "$__exec"
281c0adcdb9SDevin Teske		fi
282c0adcdb9SDevin Teske		return $SUCCESS
283c0adcdb9SDevin Teske	fi
284c0adcdb9SDevin Teske	return $FAILURE
285c0adcdb9SDevin Teske}
286c0adcdb9SDevin Teske
28799bc932eSDevin Teske# f_getvar $var_to_get [$var_to_set]
28899bc932eSDevin Teske#
28999bc932eSDevin Teske# Utility function designed to go along with the already-builtin setvar.
29099bc932eSDevin Teske# Allows clean variable name indirection without forking or sub-shells.
29199bc932eSDevin Teske#
29299bc932eSDevin Teske# Returns error status if the requested variable ($var_to_get) is not set.
29399bc932eSDevin Teske#
29499bc932eSDevin Teske# If $var_to_set is missing or NULL, the value of $var_to_get is printed to
29599bc932eSDevin Teske# standard output for capturing in a sub-shell (which is less-recommended
29699bc932eSDevin Teske# because of performance degredation; for example, when called in a loop).
29799bc932eSDevin Teske#
29899bc932eSDevin Teskef_getvar()
29999bc932eSDevin Teske{
3007323adacSDevin Teske	local __var_to_get="$1" __var_to_set="$2"
3017323adacSDevin Teske	[ "$__var_to_set" ] || local value
3027323adacSDevin Teske	eval [ \"\${$__var_to_get+set}\" ]
3037323adacSDevin Teske	local __retval=$?
3042a267449SDevin Teske	eval ${__var_to_set:-value}=\"\${$__var_to_get}\"
30599bc932eSDevin Teske	eval f_dprintf '"f_getvar: var=[%s] value=[%s] r=%u"' \
3067323adacSDevin Teske		\"\$__var_to_get\" \"\$${__var_to_set:-value}\" \$__retval
3077323adacSDevin Teske	[ "$__var_to_set" ] || { [ "$value" ] && echo "$value"; }
3087323adacSDevin Teske	return $__retval
30999bc932eSDevin Teske}
31099bc932eSDevin Teske
3111d17434bSDevin Teske# f_isset $var
3121d17434bSDevin Teske#
3131d17434bSDevin Teske# Check if variable $var is set. Returns success if variable is set, otherwise
3141d17434bSDevin Teske# returns failure.
3151d17434bSDevin Teske#
3161d17434bSDevin Teskef_isset()
3171d17434bSDevin Teske{
3181d17434bSDevin Teske	eval [ \"\${${1%%[$IFS]*}+set}\" ]
3191d17434bSDevin Teske}
3201d17434bSDevin Teske
3213e8cb79dSDevin Teske# f_die [$status [$format [$arguments ...]]]
322ab2043b8SDevin Teske#
323ab2043b8SDevin Teske# Abruptly terminate due to an error optionally displaying a message in a
324ab2043b8SDevin Teske# dialog box using printf(1) syntax.
325ab2043b8SDevin Teske#
326ab2043b8SDevin Teskef_die()
327ab2043b8SDevin Teske{
328ab2043b8SDevin Teske	local status=$FAILURE
329ab2043b8SDevin Teske
330ab2043b8SDevin Teske	# If there is at least one argument, take it as the status
331ab2043b8SDevin Teske	if [ $# -gt 0 ]; then
332ab2043b8SDevin Teske		status=$1
333ab2043b8SDevin Teske		shift 1 # status
334ab2043b8SDevin Teske	fi
335ab2043b8SDevin Teske
336ab2043b8SDevin Teske	# If there are still arguments left, pass them to f_show_msg
337ab2043b8SDevin Teske	[ $# -gt 0 ] && f_show_msg "$@"
338ab2043b8SDevin Teske
339ab2043b8SDevin Teske	# Optionally call f_clean_up() function if it exists
340ab2043b8SDevin Teske	f_have f_clean_up && f_clean_up
341ab2043b8SDevin Teske
342ab2043b8SDevin Teske	exit $status
343ab2043b8SDevin Teske}
344ab2043b8SDevin Teske
345ab2043b8SDevin Teske# f_interrupt
346ab2043b8SDevin Teske#
347ab2043b8SDevin Teske# Interrupt handler.
348ab2043b8SDevin Teske#
349ab2043b8SDevin Teskef_interrupt()
350ab2043b8SDevin Teske{
351ab2043b8SDevin Teske	exec 2>&1 # fix sh(1) bug where stderr gets lost within async-trap
352ab2043b8SDevin Teske	f_die
353ab2043b8SDevin Teske}
354ab2043b8SDevin Teske
3553e8cb79dSDevin Teske# f_show_info $format [$arguments ...]
35613aadd84SDevin Teske#
35713aadd84SDevin Teske# Display a message in a dialog infobox using printf(1) syntax.
35813aadd84SDevin Teske#
35913aadd84SDevin Teskef_show_info()
36013aadd84SDevin Teske{
36113aadd84SDevin Teske	local msg
36213aadd84SDevin Teske	msg=$( printf "$@" )
36313aadd84SDevin Teske
36413aadd84SDevin Teske	#
36513aadd84SDevin Teske	# Use f_dialog_infobox from dialog.subr if possible, otherwise fall
36613aadd84SDevin Teske	# back to dialog(1) (without options, making it obvious when using
36713aadd84SDevin Teske	# un-aided system dialog).
36813aadd84SDevin Teske	#
36913aadd84SDevin Teske	if f_have f_dialog_info; then
37013aadd84SDevin Teske		f_dialog_info "$msg"
37113aadd84SDevin Teske	else
372*c36b3dbcSAlfonso S. Siciliano		bsddialog --infobox "$msg" 0 0
37313aadd84SDevin Teske	fi
37413aadd84SDevin Teske}
37513aadd84SDevin Teske
3763e8cb79dSDevin Teske# f_show_msg $format [$arguments ...]
377ab2043b8SDevin Teske#
378ab2043b8SDevin Teske# Display a message in a dialog box using printf(1) syntax.
379ab2043b8SDevin Teske#
380ab2043b8SDevin Teskef_show_msg()
381ab2043b8SDevin Teske{
382ab2043b8SDevin Teske	local msg
383ab2043b8SDevin Teske	msg=$( printf "$@" )
384ab2043b8SDevin Teske
385ab2043b8SDevin Teske	#
386ab2043b8SDevin Teske	# Use f_dialog_msgbox from dialog.subr if possible, otherwise fall
387ab2043b8SDevin Teske	# back to dialog(1) (without options, making it obvious when using
388ab2043b8SDevin Teske	# un-aided system dialog).
389ab2043b8SDevin Teske	#
390ab2043b8SDevin Teske	if f_have f_dialog_msgbox; then
391ab2043b8SDevin Teske		f_dialog_msgbox "$msg"
392ab2043b8SDevin Teske	else
393*c36b3dbcSAlfonso S. Siciliano		bsddialog --msgbox "$msg" 0 0
394ab2043b8SDevin Teske	fi
395ab2043b8SDevin Teske}
396ab2043b8SDevin Teske
3978a316c00SDevin Teske# f_show_err $format [$arguments ...]
3988a316c00SDevin Teske#
3998a316c00SDevin Teske# Display a message in a dialog box with ``Error'' i18n title (overridden by
40067602532SDevin Teske# setting msg_error) using printf(1) syntax.
4018a316c00SDevin Teske#
4028a316c00SDevin Teskef_show_err()
4038a316c00SDevin Teske{
4048a316c00SDevin Teske	local msg
4058a316c00SDevin Teske	msg=$( printf "$@" )
4068a316c00SDevin Teske
4078a316c00SDevin Teske	: ${msg:=${msg_an_unknown_error_occurred:-An unknown error occurred}}
4088a316c00SDevin Teske
4098a316c00SDevin Teske	if [ "$_DIALOG_SUBR" ]; then
4108a316c00SDevin Teske		f_dialog_title "${msg_error:-Error}"
4118a316c00SDevin Teske		f_dialog_msgbox "$msg"
4128a316c00SDevin Teske		f_dialog_title_restore
4138a316c00SDevin Teske	else
4148a316c00SDevin Teske		dialog --title "${msg_error:-Error}" --msgbox "$msg" 0 0
4158a316c00SDevin Teske	fi
4168a316c00SDevin Teske	return $SUCCESS
4178a316c00SDevin Teske}
41827ff90aaSDevin Teske
4193e8cb79dSDevin Teske# f_yesno $format [$arguments ...]
42027ff90aaSDevin Teske#
42127ff90aaSDevin Teske# Display a message in a dialog yes/no box using printf(1) syntax.
42227ff90aaSDevin Teske#
42327ff90aaSDevin Teskef_yesno()
42427ff90aaSDevin Teske{
42527ff90aaSDevin Teske	local msg
42627ff90aaSDevin Teske	msg=$( printf "$@" )
42727ff90aaSDevin Teske
42827ff90aaSDevin Teske	#
42927ff90aaSDevin Teske	# Use f_dialog_yesno from dialog.subr if possible, otherwise fall
43027ff90aaSDevin Teske	# back to dialog(1) (without options, making it obvious when using
43127ff90aaSDevin Teske	# un-aided system dialog).
43227ff90aaSDevin Teske	#
43327ff90aaSDevin Teske	if f_have f_dialog_yesno; then
43427ff90aaSDevin Teske		f_dialog_yesno "$msg"
43527ff90aaSDevin Teske	else
436*c36b3dbcSAlfonso S. Siciliano		bsddialog --yesno "$msg" 0 0
43727ff90aaSDevin Teske	fi
43827ff90aaSDevin Teske}
43927ff90aaSDevin Teske
4403e8cb79dSDevin Teske# f_noyes $format [$arguments ...]
44127ff90aaSDevin Teske#
44227ff90aaSDevin Teske# Display a message in a dialog yes/no box using printf(1) syntax.
44327ff90aaSDevin Teske# NOTE: THis is just like the f_yesno function except "No" is default.
44427ff90aaSDevin Teske#
44527ff90aaSDevin Teskef_noyes()
44627ff90aaSDevin Teske{
44727ff90aaSDevin Teske	local msg
44827ff90aaSDevin Teske	msg=$( printf "$@" )
44927ff90aaSDevin Teske
45027ff90aaSDevin Teske	#
45127ff90aaSDevin Teske	# Use f_dialog_noyes from dialog.subr if possible, otherwise fall
45227ff90aaSDevin Teske	# back to dialog(1) (without options, making it obvious when using
45327ff90aaSDevin Teske	# un-aided system dialog).
45427ff90aaSDevin Teske	#
45527ff90aaSDevin Teske	if f_have f_dialog_noyes; then
45627ff90aaSDevin Teske		f_dialog_noyes "$msg"
45727ff90aaSDevin Teske	else
458*c36b3dbcSAlfonso S. Siciliano		bsddialog --defaultno --yesno "$msg" 0 0
45927ff90aaSDevin Teske	fi
46027ff90aaSDevin Teske}
46127ff90aaSDevin Teske
46240dfc82dSDevin Teske# f_show_help $file
46340dfc82dSDevin Teske#
46440dfc82dSDevin Teske# Display a language help-file. Automatically takes $LANG and $LC_ALL into
46540dfc82dSDevin Teske# consideration when displaying $file (suffix ".$LC_ALL" or ".$LANG" will
46640dfc82dSDevin Teske# automatically be added prior to loading the language help-file).
46740dfc82dSDevin Teske#
46840dfc82dSDevin Teske# If a language has been requested by setting either $LANG or $LC_ALL in the
46940dfc82dSDevin Teske# environment and the language-specific help-file does not exist we will fall
47040dfc82dSDevin Teske# back to $file without-suffix.
47140dfc82dSDevin Teske#
47240dfc82dSDevin Teske# If the language help-file does not exist, an error is displayed instead.
47340dfc82dSDevin Teske#
47440dfc82dSDevin Teskef_show_help()
47540dfc82dSDevin Teske{
47640dfc82dSDevin Teske	local file="$1"
47740dfc82dSDevin Teske	local lang="${LANG:-$LC_ALL}"
47840dfc82dSDevin Teske
47940dfc82dSDevin Teske	[ -f "$file.$lang" ] && file="$file.$lang"
48040dfc82dSDevin Teske
48140dfc82dSDevin Teske	#
48240dfc82dSDevin Teske	# Use f_dialog_textbox from dialog.subr if possible, otherwise fall
48340dfc82dSDevin Teske	# back to dialog(1) (without options, making it obvious when using
48440dfc82dSDevin Teske	# un-aided system dialog).
48540dfc82dSDevin Teske	#
48640dfc82dSDevin Teske	if f_have f_dialog_textbox; then
48740dfc82dSDevin Teske		f_dialog_textbox "$file"
48840dfc82dSDevin Teske	else
489*c36b3dbcSAlfonso S. Siciliano		bsddialog --msgbox "$( cat "$file" 2>&1 )" 0 0
49040dfc82dSDevin Teske	fi
49140dfc82dSDevin Teske}
49240dfc82dSDevin Teske
493ab2043b8SDevin Teske# f_include $file
494ab2043b8SDevin Teske#
495ab2043b8SDevin Teske# Include a shell subroutine file.
496ab2043b8SDevin Teske#
497ab2043b8SDevin Teske# If the subroutine file exists but returns error status during loading, exit
498ab2043b8SDevin Teske# is called and execution is prematurely terminated with the same error status.
499ab2043b8SDevin Teske#
500ab2043b8SDevin Teskef_include()
501ab2043b8SDevin Teske{
502ab2043b8SDevin Teske	local file="$1"
503526e1dc1SDevin Teske	f_dprintf "f_include: file=[%s]" "$file"
504ab2043b8SDevin Teske	. "$file" || exit $?
505ab2043b8SDevin Teske}
506ab2043b8SDevin Teske
507ab2043b8SDevin Teske# f_include_lang $file
508ab2043b8SDevin Teske#
509ab2043b8SDevin Teske# Include a language file. Automatically takes $LANG and $LC_ALL into
5107f72bb44SDevin Teske# consideration when including $file (suffix ".$LC_ALL" or ".$LANG" will
511ab2043b8SDevin Teske# automatically by added prior to loading the language file).
512ab2043b8SDevin Teske#
513ab2043b8SDevin Teske# No error is produced if (a) a language has been requested (by setting either
514ab2043b8SDevin Teske# $LANG or $LC_ALL in the environment) and (b) the language file does not
515ab2043b8SDevin Teske# exist -- in which case we will fall back to loading $file without-suffix.
516ab2043b8SDevin Teske#
517ab2043b8SDevin Teske# If the language file exists but returns error status during loading, exit
518ab2043b8SDevin Teske# is called and execution is prematurely terminated with the same error status.
519ab2043b8SDevin Teske#
520ab2043b8SDevin Teskef_include_lang()
521ab2043b8SDevin Teske{
522ab2043b8SDevin Teske	local file="$1"
523ab2043b8SDevin Teske	local lang="${LANG:-$LC_ALL}"
524ab2043b8SDevin Teske
525526e1dc1SDevin Teske	f_dprintf "f_include_lang: file=[%s] lang=[%s]" "$file" "$lang"
526ab2043b8SDevin Teske	if [ -f "$file.$lang" ]; then
527ab2043b8SDevin Teske		. "$file.$lang" || exit $?
528ab2043b8SDevin Teske	else
529ab2043b8SDevin Teske		. "$file" || exit $?
530ab2043b8SDevin Teske	fi
531ab2043b8SDevin Teske}
532ab2043b8SDevin Teske
533ab2043b8SDevin Teske# f_usage $file [$key1 $value1 ...]
534ab2043b8SDevin Teske#
535ab2043b8SDevin Teske# Display USAGE file with optional pre-processor macro definitions. The first
536ab2043b8SDevin Teske# argument is the template file containing the usage text to be displayed. If
537ab2043b8SDevin Teske# $LANG or $LC_ALL (in order of preference, respectively) is set, ".encoding"
538ab2043b8SDevin Teske# will automatically be appended as a suffix to the provided $file pathname.
539ab2043b8SDevin Teske#
540ab2043b8SDevin Teske# When processing $file, output begins at the first line containing that is
541ab2043b8SDevin Teske# (a) not a comment, (b) not empty, and (c) is not pure-whitespace. All lines
542ab2043b8SDevin Teske# appearing after this first-line are output, including (a) comments (b) empty
543ab2043b8SDevin Teske# lines, and (c) lines that are purely whitespace-only.
544ab2043b8SDevin Teske#
545ab2043b8SDevin Teske# If additional arguments appear after $file, substitutions are made while
546ab2043b8SDevin Teske# printing the contents of the USAGE file. The pre-processor macro syntax is in
547ab2043b8SDevin Teske# the style of autoconf(1), for example:
548ab2043b8SDevin Teske#
549ab2043b8SDevin Teske# 	f_usage $file "FOO" "BAR"
550ab2043b8SDevin Teske#
551ab2043b8SDevin Teske# Will cause instances of "@FOO@" appearing in $file to be replaced with the
5529680f649SDevin Teske# text "BAR" before being printed to the screen.
553ab2043b8SDevin Teske#
554ab2043b8SDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
555ab2043b8SDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
556ab2043b8SDevin Teske#
557ab2043b8SDevin Teskef_usage_awk='
558ab2043b8SDevin TeskeBEGIN { found = 0 }
559ab2043b8SDevin Teske{
560ab2043b8SDevin Teske	if ( !found && $0 ~ /^[[:space:]]*($|#)/ ) next
561ab2043b8SDevin Teske	found = 1
562ab2043b8SDevin Teske	print
563ab2043b8SDevin Teske}
564ab2043b8SDevin Teske'
565ab2043b8SDevin Teskef_usage()
566ab2043b8SDevin Teske{
567ab2043b8SDevin Teske	local file="$1"
568ab2043b8SDevin Teske	local lang="${LANG:-$LC_ALL}"
569ab2043b8SDevin Teske
570526e1dc1SDevin Teske	f_dprintf "f_usage: file=[%s] lang=[%s]" "$file" "$lang"
571ab2043b8SDevin Teske
572ab2043b8SDevin Teske	shift 1 # file
573ab2043b8SDevin Teske
574ab2043b8SDevin Teske	local usage
575ab2043b8SDevin Teske	if [ -f "$file.$lang" ]; then
576ab2043b8SDevin Teske		usage=$( awk "$f_usage_awk" "$file.$lang" ) || exit $FAILURE
577ab2043b8SDevin Teske	else
578ab2043b8SDevin Teske		usage=$( awk "$f_usage_awk" "$file" ) || exit $FAILURE
579ab2043b8SDevin Teske	fi
580ab2043b8SDevin Teske
581ab2043b8SDevin Teske	while [ $# -gt 0 ]; do
582ab2043b8SDevin Teske		local key="$1"
583ab2043b8SDevin Teske		export value="$2"
584ab2043b8SDevin Teske		usage=$( echo "$usage" | awk \
585ab2043b8SDevin Teske			"{ gsub(/@$key@/, ENVIRON[\"value\"]); print }" )
586ab2043b8SDevin Teske		shift 2
587ab2043b8SDevin Teske	done
588ab2043b8SDevin Teske
589ab2043b8SDevin Teske	f_err "%s\n" "$usage"
590ab2043b8SDevin Teske
591ab2043b8SDevin Teske	exit $FAILURE
592ab2043b8SDevin Teske}
593ab2043b8SDevin Teske
594d4ae33f0SDevin Teske# f_index_file $keyword [$var_to_set]
595ab2043b8SDevin Teske#
59648c5129fSDevin Teske# Process all INDEX files known to bsdconfig and return the path to first file
59748c5129fSDevin Teske# containing a menu_selection line with a keyword portion matching $keyword.
598ab2043b8SDevin Teske#
59948c5129fSDevin Teske# If $LANG or $LC_ALL (in order of preference, respectively) is set,
60048c5129fSDevin Teske# "INDEX.encoding" files will be searched first.
601ab2043b8SDevin Teske#
60248c5129fSDevin Teske# If no file is found, error status is returned along with the NULL string.
603ab2043b8SDevin Teske#
604d4ae33f0SDevin Teske# If $var_to_set is NULL or missing, output is printed to stdout (which is less
605d4ae33f0SDevin Teske# recommended due to performance degradation; in a loop for example).
606d4ae33f0SDevin Teske#
607ab2043b8SDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
608ab2043b8SDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
609ab2043b8SDevin Teske#
61048c5129fSDevin Teskef_index_file_awk='
611ab2043b8SDevin Teske# Variables that should be defined on the invocation line:
61248c5129fSDevin Teske# 	-v keyword="keyword"
61348c5129fSDevin TeskeBEGIN { found = 0 }
61448c5129fSDevin Teske( $0 ~ "^menu_selection=\"" keyword "\\|" ) {
61548c5129fSDevin Teske	print FILENAME
61648c5129fSDevin Teske	found++
617ab2043b8SDevin Teske	exit
618ab2043b8SDevin Teske}
61948c5129fSDevin TeskeEND { exit ! found }
620ab2043b8SDevin Teske'
62148c5129fSDevin Teskef_index_file()
622ab2043b8SDevin Teske{
623d4ae33f0SDevin Teske	local __keyword="$1" __var_to_set="$2"
624d4ae33f0SDevin Teske	local __lang="${LANG:-$LC_ALL}"
625d4ae33f0SDevin Teske	local __indexes="$BSDCFG_LIBE${BSDCFG_LIBE:+/}*/INDEX"
626ab2043b8SDevin Teske
627d4ae33f0SDevin Teske	f_dprintf "f_index_file: keyword=[%s] lang=[%s]" "$__keyword" "$__lang"
628ab2043b8SDevin Teske
629d4ae33f0SDevin Teske	if [ "$__lang" ]; then
630d4ae33f0SDevin Teske		if [ "$__var_to_set" ]; then
631d4ae33f0SDevin Teske			eval "$__var_to_set"='"$( awk -v keyword="$__keyword" \
632d4ae33f0SDevin Teske				"$f_index_file_awk" $__indexes.$__lang
633d4ae33f0SDevin Teske			)"' && return $SUCCESS
634d4ae33f0SDevin Teske		else
635d4ae33f0SDevin Teske			awk -v keyword="$__keyword" "$f_index_file_awk" \
636d4ae33f0SDevin Teske				$__indexes.$__lang && return $SUCCESS
637d4ae33f0SDevin Teske		fi
63848c5129fSDevin Teske		# No match, fall-thru to non-i18n sources
63948c5129fSDevin Teske	fi
640d4ae33f0SDevin Teske	if [ "$__var_to_set" ]; then
641d4ae33f0SDevin Teske		eval "$__var_to_set"='"$( awk -v keyword="$__keyword" \
642d4ae33f0SDevin Teske			"$f_index_file_awk" $__indexes )"' && return $SUCCESS
643d4ae33f0SDevin Teske	else
644d4ae33f0SDevin Teske		awk -v keyword="$__keyword" "$f_index_file_awk" $__indexes &&
645d4ae33f0SDevin Teske			return $SUCCESS
646d4ae33f0SDevin Teske	fi
6471da51566SDevin Teske
6481da51566SDevin Teske	# No match? Fall-thru to `local' libexec sources (add-on modules)
6491da51566SDevin Teske
6501da51566SDevin Teske	[ "$BSDCFG_LOCAL_LIBE" ] || return $FAILURE
651d4ae33f0SDevin Teske	__indexes="$BSDCFG_LOCAL_LIBE/*/INDEX"
652d4ae33f0SDevin Teske	if [ "$__lang" ]; then
653d4ae33f0SDevin Teske		if [ "$__var_to_set" ]; then
654d4ae33f0SDevin Teske			eval "$__var_to_set"='"$( awk -v keyword="$__keyword" \
655d4ae33f0SDevin Teske				"$f_index_file_awk" $__indexes.$__lang
656d4ae33f0SDevin Teske			)"' && return $SUCCESS
657d4ae33f0SDevin Teske		else
658d4ae33f0SDevin Teske			awk -v keyword="$__keyword" "$f_index_file_awk" \
659d4ae33f0SDevin Teske				$__indexes.$__lang && return $SUCCESS
660d4ae33f0SDevin Teske		fi
6611da51566SDevin Teske		# No match, fall-thru to non-i18n sources
6621da51566SDevin Teske	fi
663d4ae33f0SDevin Teske	if [ "$__var_to_set" ]; then
664d4ae33f0SDevin Teske		eval "$__var_to_set"='$( awk -v keyword="$__keyword" \
665d4ae33f0SDevin Teske			"$f_index_file_awk" $__indexes )"'
666d4ae33f0SDevin Teske	else
667d4ae33f0SDevin Teske		awk -v keyword="$__keyword" "$f_index_file_awk" $__indexes
668d4ae33f0SDevin Teske	fi
66948c5129fSDevin Teske}
67048c5129fSDevin Teske
671d4ae33f0SDevin Teske# f_index_menusel_keyword $indexfile $pgm [$var_to_set]
67248c5129fSDevin Teske#
67348c5129fSDevin Teske# Process $indexfile and return only the keyword portion of the menu_selection
67448c5129fSDevin Teske# line with a command portion matching $pgm.
67548c5129fSDevin Teske#
67648c5129fSDevin Teske# This function is for internationalization (i18n) mapping of the on-disk
67748c5129fSDevin Teske# scriptname ($pgm) into the localized language (given language-specific
67848c5129fSDevin Teske# $indexfile). If $LANG or $LC_ALL (in orderder of preference, respectively) is
67948c5129fSDevin Teske# set, ".encoding" will automatically be appended as a suffix to the provided
68048c5129fSDevin Teske# $indexfile pathname.
68148c5129fSDevin Teske#
68248c5129fSDevin Teske# If, within $indexfile, multiple $menu_selection values map to $pgm, only the
68348c5129fSDevin Teske# first one will be returned. If no mapping can be made, the NULL string is
68448c5129fSDevin Teske# returned.
68548c5129fSDevin Teske#
68648c5129fSDevin Teske# If $indexfile does not exist, error status is returned with NULL.
68748c5129fSDevin Teske#
688d4ae33f0SDevin Teske# If $var_to_set is NULL or missing, output is printed to stdout (which is less
689d4ae33f0SDevin Teske# recommended due to performance degradation; in a loop for example).
690d4ae33f0SDevin Teske#
69148c5129fSDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
69248c5129fSDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
69348c5129fSDevin Teske#
69448c5129fSDevin Teskef_index_menusel_keyword_awk='
69548c5129fSDevin Teske# Variables that should be defined on the invocation line:
69648c5129fSDevin Teske# 	-v pgm="program_name"
69748c5129fSDevin Teske#
69848c5129fSDevin TeskeBEGIN {
69948c5129fSDevin Teske	prefix = "menu_selection=\""
70048c5129fSDevin Teske	plen = length(prefix)
70148c5129fSDevin Teske	found = 0
70248c5129fSDevin Teske}
70348c5129fSDevin Teske{
70448c5129fSDevin Teske	if (!match($0, "^" prefix ".*\\|.*\"")) next
70548c5129fSDevin Teske
70648c5129fSDevin Teske	keyword = command = substr($0, plen + 1, RLENGTH - plen - 1)
70748c5129fSDevin Teske	sub(/^.*\|/, "", command)
70848c5129fSDevin Teske	sub(/\|.*$/, "", keyword)
70948c5129fSDevin Teske
71048c5129fSDevin Teske	if ( command == pgm )
71148c5129fSDevin Teske	{
71248c5129fSDevin Teske		print keyword
71348c5129fSDevin Teske		found++
71448c5129fSDevin Teske		exit
71548c5129fSDevin Teske	}
71648c5129fSDevin Teske}
71748c5129fSDevin TeskeEND { exit ! found }
71848c5129fSDevin Teske'
71948c5129fSDevin Teskef_index_menusel_keyword()
72048c5129fSDevin Teske{
721d4ae33f0SDevin Teske	local __indexfile="$1" __pgm="$2" __var_to_set="$3"
722d4ae33f0SDevin Teske	local __lang="${LANG:-$LC_ALL}" __file="$__indexfile"
72348c5129fSDevin Teske
724d4ae33f0SDevin Teske	[ -f "$__indexfile.$__lang" ] && __file="$__indexfile.$__lang"
725526e1dc1SDevin Teske	f_dprintf "f_index_menusel_keyword: index=[%s] pgm=[%s] lang=[%s]" \
726d4ae33f0SDevin Teske	          "$__file" "$__pgm" "$__lang"
72748c5129fSDevin Teske
728d4ae33f0SDevin Teske	if [ "$__var_to_set" ]; then
729d4ae33f0SDevin Teske		setvar "$__var_to_set" "$( awk \
730d4ae33f0SDevin Teske		    -v pgm="$__pgm" "$f_index_menusel_keyword_awk" "$__file"
731d4ae33f0SDevin Teske		)"
732d4ae33f0SDevin Teske	else
733d4ae33f0SDevin Teske		awk -v pgm="$__pgm" "$f_index_menusel_keyword_awk" "$__file"
73448c5129fSDevin Teske	fi
73548c5129fSDevin Teske}
73648c5129fSDevin Teske
737d4ae33f0SDevin Teske# f_index_menusel_command $indexfile $keyword [$var_to_set]
73848c5129fSDevin Teske#
73948c5129fSDevin Teske# Process $indexfile and return only the command portion of the menu_selection
74048c5129fSDevin Teske# line with a keyword portion matching $keyword.
74148c5129fSDevin Teske#
74248c5129fSDevin Teske# This function is for mapping [possibly international] keywords into the
74348c5129fSDevin Teske# command to be executed. If $LANG or $LC_ALL (order of preference) is set,
74448c5129fSDevin Teske# ".encoding" will automatically be appended as a suffix to the provided
74548c5129fSDevin Teske# $indexfile pathname.
74648c5129fSDevin Teske#
74748c5129fSDevin Teske# If, within $indexfile, multiple $menu_selection values map to $keyword, only
74848c5129fSDevin Teske# the first one will be returned. If no mapping can be made, the NULL string is
74948c5129fSDevin Teske# returned.
75048c5129fSDevin Teske#
75148c5129fSDevin Teske# If $indexfile doesn't exist, error status is returned with NULL.
75248c5129fSDevin Teske#
753d4ae33f0SDevin Teske# If $var_to_set is NULL or missing, output is printed to stdout (which is less
754d4ae33f0SDevin Teske# recommended due to performance degradation; in a loop for example).
755d4ae33f0SDevin Teske#
75648c5129fSDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
75748c5129fSDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
75848c5129fSDevin Teske#
75948c5129fSDevin Teskef_index_menusel_command_awk='
76048c5129fSDevin Teske# Variables that should be defined on the invocation line:
76148c5129fSDevin Teske# 	-v key="keyword"
76248c5129fSDevin Teske#
76348c5129fSDevin TeskeBEGIN {
76448c5129fSDevin Teske	prefix = "menu_selection=\""
76548c5129fSDevin Teske	plen = length(prefix)
76648c5129fSDevin Teske	found = 0
76748c5129fSDevin Teske}
76848c5129fSDevin Teske{
76948c5129fSDevin Teske	if (!match($0, "^" prefix ".*\\|.*\"")) next
77048c5129fSDevin Teske
77148c5129fSDevin Teske	keyword = command = substr($0, plen + 1, RLENGTH - plen - 1)
77248c5129fSDevin Teske	sub(/^.*\|/, "", command)
77348c5129fSDevin Teske	sub(/\|.*$/, "", keyword)
77448c5129fSDevin Teske
77548c5129fSDevin Teske	if ( keyword == key )
77648c5129fSDevin Teske	{
77748c5129fSDevin Teske		print command
77848c5129fSDevin Teske		found++
77948c5129fSDevin Teske		exit
78048c5129fSDevin Teske	}
78148c5129fSDevin Teske}
78248c5129fSDevin TeskeEND { exit ! found }
78348c5129fSDevin Teske'
78448c5129fSDevin Teskef_index_menusel_command()
78548c5129fSDevin Teske{
786d4ae33f0SDevin Teske	local __indexfile="$1" __keyword="$2" __var_to_set="$3" __command
787d4ae33f0SDevin Teske	local __lang="${LANG:-$LC_ALL}" __file="$__indexfile"
78848c5129fSDevin Teske
789d4ae33f0SDevin Teske	[ -f "$__indexfile.$__lang" ] && __file="$__indexfile.$__lang"
790526e1dc1SDevin Teske	f_dprintf "f_index_menusel_command: index=[%s] key=[%s] lang=[%s]" \
791d4ae33f0SDevin Teske	          "$__file" "$__keyword" "$__lang"
79248c5129fSDevin Teske
793d4ae33f0SDevin Teske	[ -f "$__file" ] || return $FAILURE
794d4ae33f0SDevin Teske	__command=$( awk -v key="$__keyword" \
795d4ae33f0SDevin Teske		"$f_index_menusel_command_awk" "$__file" ) || return $FAILURE
79648c5129fSDevin Teske
79748c5129fSDevin Teske	#
79848c5129fSDevin Teske	# If the command pathname is not fully qualified fix-up/force to be
79948c5129fSDevin Teske	# relative to the $indexfile directory.
80048c5129fSDevin Teske	#
801d4ae33f0SDevin Teske	case "$__command" in
80248c5129fSDevin Teske	/*) : already fully qualified ;;
80348c5129fSDevin Teske	*)
804d4ae33f0SDevin Teske		local __indexdir="${__indexfile%/*}"
805d4ae33f0SDevin Teske		[ "$__indexdir" != "$__indexfile" ] || __indexdir="."
806d4ae33f0SDevin Teske		__command="$__indexdir/$__command"
80748c5129fSDevin Teske	esac
80848c5129fSDevin Teske
809d4ae33f0SDevin Teske	if [ "$__var_to_set" ]; then
810d4ae33f0SDevin Teske		setvar "$__var_to_set" "$__command"
811d4ae33f0SDevin Teske	else
812d4ae33f0SDevin Teske		echo "$__command"
813d4ae33f0SDevin Teske	fi
814ab2043b8SDevin Teske}
815ab2043b8SDevin Teske
8167323adacSDevin Teske# f_running_as_init
8177323adacSDevin Teske#
8187323adacSDevin Teske# Returns true if running as init(1).
8197323adacSDevin Teske#
8207323adacSDevin Teskef_running_as_init()
8217323adacSDevin Teske{
8227323adacSDevin Teske	#
8237323adacSDevin Teske	# When a custom init(8) performs an exec(3) to invoke a shell script,
8247323adacSDevin Teske	# PID 1 becomes sh(1) and $PPID is set to 1 in the executed script.
8257323adacSDevin Teske	#
8267323adacSDevin Teske	[ ${PPID:-0} -eq 1 ] # Return status
8277323adacSDevin Teske}
8287323adacSDevin Teske
8297323adacSDevin Teske# f_mounted $local_directory
8309ecd54f2SDevin Teske# f_mounted -b $device
8317323adacSDevin Teske#
8329ecd54f2SDevin Teske# Return success if a filesystem is mounted on a particular directory. If `-b'
8339ecd54f2SDevin Teske# is present, instead check that the block device (or a partition thereof) is
8349ecd54f2SDevin Teske# mounted.
8357323adacSDevin Teske#
8367323adacSDevin Teskef_mounted()
8377323adacSDevin Teske{
8389ecd54f2SDevin Teske	local OPTIND OPTARG flag use_device=
8399ecd54f2SDevin Teske	while getopts b flag; do
8409ecd54f2SDevin Teske		case "$flag" in
8419ecd54f2SDevin Teske		b) use_device=1 ;;
8429ecd54f2SDevin Teske		esac
8439ecd54f2SDevin Teske	done
8449ecd54f2SDevin Teske	shift $(( $OPTIND - 1 ))
8459ecd54f2SDevin Teske	if [ "$use_device" ]; then
8469ecd54f2SDevin Teske		local device="$1"
8479ecd54f2SDevin Teske		mount | grep -Eq \
8489ecd54f2SDevin Teske			"^$device([[:space:]]|p[0-9]|s[0-9]|\.nop|\.eli)"
8499ecd54f2SDevin Teske	else
8507323adacSDevin Teske		[ -d "$dir" ] || return $FAILURE
8517323adacSDevin Teske		mount | grep -Eq " on $dir \([^)]+\)$"
8529ecd54f2SDevin Teske	fi
8539ecd54f2SDevin Teske	# Return status is that of last grep(1)
8547323adacSDevin Teske}
8557323adacSDevin Teske
856d4ae33f0SDevin Teske# f_eval_catch [-de] [-k $var_to_set] $funcname $utility \
857d4ae33f0SDevin Teske#              $format [$arguments ...]
858bdf4b176SDevin Teske#
859bdf4b176SDevin Teske# Silently evaluate a command in a sub-shell and test for error. If debugging
860bdf4b176SDevin Teske# is enabled a copy of the command and its output is sent to debug (either
861bdf4b176SDevin Teske# stdout or file depending on environment). If an error occurs, output of the
862bdf4b176SDevin Teske# command is displayed in a dialog(1) msgbox using the [above] f_show_err()
863d4ae33f0SDevin Teske# function (unless optional `-d' flag is given, then no dialog).
864d4ae33f0SDevin Teske#
865bdf4b176SDevin Teske# The $funcname argument is sent to debugging while the $utility argument is
866d4ae33f0SDevin Teske# used in the title of the dialog box. The command that is executed as well as
867d4ae33f0SDevin Teske# sent to debugging with $funcname is the product of the printf(1) syntax
868d4ae33f0SDevin Teske# produced by $format with optional $arguments.
869d4ae33f0SDevin Teske#
870d4ae33f0SDevin Teske# The following options are supported:
871d4ae33f0SDevin Teske#
872d4ae33f0SDevin Teske# 	-d	Do not use dialog(1).
873d4ae33f0SDevin Teske# 	-e	Produce error text from failed command on stderr.
874d4ae33f0SDevin Teske# 	-k var	Save output from the command in var.
875bdf4b176SDevin Teske#
876bdf4b176SDevin Teske# Example 1:
877bdf4b176SDevin Teske#
878bdf4b176SDevin Teske# 	debug=1
879bdf4b176SDevin Teske# 	f_eval_catch myfunc echo 'echo "%s"' "Hello, World!"
880bdf4b176SDevin Teske#
881bdf4b176SDevin Teske# 	Produces the following debug output:
882bdf4b176SDevin Teske#
883bdf4b176SDevin Teske# 		DEBUG: myfunc: echo "Hello, World!"
884bdf4b176SDevin Teske# 		DEBUG: myfunc: retval=0 <output below>
885bdf4b176SDevin Teske# 		Hello, World!
886bdf4b176SDevin Teske#
887d4ae33f0SDevin Teske# Example 2:
888d4ae33f0SDevin Teske#
889d4ae33f0SDevin Teske# 	debug=1
890d4ae33f0SDevin Teske# 	f_eval_catch -k contents myfunc cat 'cat "%s"' /some/file
891d4ae33f0SDevin Teske# 	# dialog(1) Error ``cat: /some/file: No such file or directory''
892d4ae33f0SDevin Teske# 	# contents=[cat: /some/file: No such file or directory]
893d4ae33f0SDevin Teske#
894d4ae33f0SDevin Teske# 	Produces the following debug output:
895d4ae33f0SDevin Teske#
896d4ae33f0SDevin Teske# 		DEBUG: myfunc: cat "/some/file"
897d4ae33f0SDevin Teske# 		DEBUG: myfunc: retval=1 <output below>
898d4ae33f0SDevin Teske# 		cat: /some/file: No such file or directory
899d4ae33f0SDevin Teske#
900bdf4b176SDevin Teske# Example 3:
901bdf4b176SDevin Teske#
902bdf4b176SDevin Teske# 	debug=1
903bdf4b176SDevin Teske# 	echo 123 | f_eval_catch myfunc rev rev
904bdf4b176SDevin Teske#
905bdf4b176SDevin Teske# 	Produces the following debug output:
906bdf4b176SDevin Teske#
907bdf4b176SDevin Teske# 		DEBUG: myfunc: rev
908bdf4b176SDevin Teske# 		DEBUG: myfunc: retval=0 <output below>
909bdf4b176SDevin Teske# 		321
910bdf4b176SDevin Teske#
911bdf4b176SDevin Teske# Example 4:
912bdf4b176SDevin Teske#
913bdf4b176SDevin Teske# 	debug=1
914bdf4b176SDevin Teske# 	f_eval_catch myfunc true true
915bdf4b176SDevin Teske#
916bdf4b176SDevin Teske# 	Produces the following debug output:
917bdf4b176SDevin Teske#
918bdf4b176SDevin Teske# 		DEBUG: myfunc: true
919bdf4b176SDevin Teske# 		DEBUG: myfunc: retval=0 <no output>
920bdf4b176SDevin Teske#
921d4ae33f0SDevin Teske# Example 5:
922d4ae33f0SDevin Teske#
923d4ae33f0SDevin Teske# 	f_eval_catch -de myfunc ls 'ls "%s"' /some/dir
924d4ae33f0SDevin Teske# 	# Output on stderr ``ls: /some/dir: No such file or directory''
925d4ae33f0SDevin Teske#
926d4ae33f0SDevin Teske# Example 6:
927d4ae33f0SDevin Teske#
928d4ae33f0SDevin Teske# 	f_eval_catch -dek contents myfunc ls 'ls "%s"' /etc
929d4ae33f0SDevin Teske# 	# Output from `ls' sent to stderr and also saved in $contents
930d4ae33f0SDevin Teske#
931bdf4b176SDevin Teskef_eval_catch()
932bdf4b176SDevin Teske{
933d4ae33f0SDevin Teske	local __no_dialog= __show_err= __var_to_set=
934d4ae33f0SDevin Teske
935d4ae33f0SDevin Teske	#
936d4ae33f0SDevin Teske	# Process local function arguments
937d4ae33f0SDevin Teske	#
9389ecd54f2SDevin Teske	local OPTIND OPTARG __flag
939d4ae33f0SDevin Teske	while getopts "dek:" __flag > /dev/null; do
940d4ae33f0SDevin Teske		case "$__flag" in
941d4ae33f0SDevin Teske		d) __no_dialog=1 ;;
942d4ae33f0SDevin Teske		e) __show_err=1 ;;
943d4ae33f0SDevin Teske		k) __var_to_set="$OPTARG" ;;
944d4ae33f0SDevin Teske		esac
945d4ae33f0SDevin Teske	done
946d4ae33f0SDevin Teske	shift $(( $OPTIND - 1 ))
947d4ae33f0SDevin Teske
948d4ae33f0SDevin Teske	local __funcname="$1" __utility="$2"; shift 2
949d4ae33f0SDevin Teske	local __cmd __output __retval
950d4ae33f0SDevin Teske
951d4ae33f0SDevin Teske	__cmd=$( printf -- "$@" )
952d4ae33f0SDevin Teske	f_dprintf "%s: %s" "$__funcname" "$__cmd" # Log command *before* eval
953d4ae33f0SDevin Teske	__output=$( exec 2>&1; eval "$__cmd" )
954d4ae33f0SDevin Teske	__retval=$?
955d4ae33f0SDevin Teske	if [ "$__output" ]; then
956d4ae33f0SDevin Teske		[ "$__show_err" ] && echo "$__output" >&2
957d4ae33f0SDevin Teske		f_dprintf "%s: retval=%i <output below>\n%s" "$__funcname" \
958d4ae33f0SDevin Teske		          $__retval "$__output"
959bdf4b176SDevin Teske	else
960d4ae33f0SDevin Teske		f_dprintf "%s: retval=%i <no output>" "$__funcname" $__retval
961bdf4b176SDevin Teske	fi
962d4ae33f0SDevin Teske
963d4ae33f0SDevin Teske	! [ "$__no_dialog" -o "$nonInteractive" -o $__retval -eq $SUCCESS ] &&
964d4ae33f0SDevin Teske		msg_error="${msg_error:-Error}${__utility:+: $__utility}" \
965d4ae33f0SDevin Teske			f_show_err "%s" "$__output"
966bdf4b176SDevin Teske		# NB: f_show_err will handle NULL output appropriately
967d4ae33f0SDevin Teske
968d4ae33f0SDevin Teske	[ "$__var_to_set" ] && setvar "$__var_to_set" "$__output"
969d4ae33f0SDevin Teske
970d4ae33f0SDevin Teske	return $__retval
971d4ae33f0SDevin Teske}
972d4ae33f0SDevin Teske
973d4ae33f0SDevin Teske# f_count $var_to_set arguments ...
974d4ae33f0SDevin Teske#
975d4ae33f0SDevin Teske# Sets $var_to_set to the number of arguments minus one (the effective number
976d4ae33f0SDevin Teske# of arguments following $var_to_set).
977d4ae33f0SDevin Teske#
978d4ae33f0SDevin Teske# Example:
979d4ae33f0SDevin Teske# 	f_count count dog house # count=[2]
980d4ae33f0SDevin Teske#
981d4ae33f0SDevin Teskef_count()
982d4ae33f0SDevin Teske{
983d4ae33f0SDevin Teske	setvar "$1" $(( $# - 1 ))
984d4ae33f0SDevin Teske}
985d4ae33f0SDevin Teske
986d4ae33f0SDevin Teske# f_count_ifs $var_to_set string ...
987d4ae33f0SDevin Teske#
988d4ae33f0SDevin Teske# Sets $var_to_set to the number of words (split by the internal field
989d4ae33f0SDevin Teske# separator, IFS) following $var_to_set.
990d4ae33f0SDevin Teske#
991d4ae33f0SDevin Teske# Example 1:
992d4ae33f0SDevin Teske#
993d4ae33f0SDevin Teske# 	string="word1   word2   word3"
994d4ae33f0SDevin Teske# 	f_count_ifs count "$string" # count=[3]
995d4ae33f0SDevin Teske# 	f_count_ifs count $string # count=[3]
996d4ae33f0SDevin Teske#
997d4ae33f0SDevin Teske# Example 2:
998d4ae33f0SDevin Teske#
999d4ae33f0SDevin Teske# 	IFS=. f_count_ifs count www.freebsd.org # count=[3]
1000d4ae33f0SDevin Teske#
1001d4ae33f0SDevin Teske# NB: Make sure to use double-quotes if you are using a custom value for IFS
1002d4ae33f0SDevin Teske# and you don't want the current value to effect the result. See example 3.
1003d4ae33f0SDevin Teske#
1004d4ae33f0SDevin Teske# Example 3:
1005d4ae33f0SDevin Teske#
1006d4ae33f0SDevin Teske# 	string="a-b c-d"
1007d4ae33f0SDevin Teske# 	IFS=- f_count_ifs count "$string" # count=[3]
1008d4ae33f0SDevin Teske# 	IFS=- f_count_ifs count $string # count=[4]
1009d4ae33f0SDevin Teske#
1010d4ae33f0SDevin Teskef_count_ifs()
1011d4ae33f0SDevin Teske{
1012d4ae33f0SDevin Teske	local __var_to_set="$1"
1013d4ae33f0SDevin Teske	shift 1
1014d4ae33f0SDevin Teske	set -- $*
1015d4ae33f0SDevin Teske	setvar "$__var_to_set" $#
1016bdf4b176SDevin Teske}
1017bdf4b176SDevin Teske
1018ab2043b8SDevin Teske############################################################ MAIN
1019ab2043b8SDevin Teske
1020ab2043b8SDevin Teske#
1021ab2043b8SDevin Teske# Trap signals so we can recover gracefully
1022ab2043b8SDevin Teske#
1023d1eef61dSDevin Tesketrap 'f_interrupt' INT
1024d1eef61dSDevin Tesketrap 'f_die' TERM PIPE XCPU XFSZ FPE TRAP ABRT SEGV
1025d1eef61dSDevin Tesketrap '' ALRM PROF USR1 USR2 HUP VTALRM
1026ab2043b8SDevin Teske
1027526e1dc1SDevin Teske#
1028526e1dc1SDevin Teske# Clone terminal stdout/stderr so we can redirect to it from within sub-shells
1029526e1dc1SDevin Teske#
1030526e1dc1SDevin Teskeeval exec $TERMINAL_STDOUT_PASSTHRU\>\&1
1031526e1dc1SDevin Teskeeval exec $TERMINAL_STDERR_PASSTHRU\>\&2
1032526e1dc1SDevin Teske
103356961fd7SDevin Teske#
1034e14ddd1fSDevin Teske# Self-initialize unless requested otherwise
103556961fd7SDevin Teske#
1036e14ddd1fSDevin Teskef_dprintf "%s: DEBUG_SELF_INITIALIZE=[%s]" \
1037e14ddd1fSDevin Teske          dialog.subr "$DEBUG_SELF_INITIALIZE"
1038e14ddd1fSDevin Teskecase "$DEBUG_SELF_INITIALIZE" in
1039e14ddd1fSDevin Teske""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
1040e14ddd1fSDevin Teske*) f_debug_init
1041e14ddd1fSDevin Teskeesac
10429c83db2dSDevin Teske
10439c83db2dSDevin Teske#
104456961fd7SDevin Teske# Log our operating environment for debugging purposes
104556961fd7SDevin Teske#
104656961fd7SDevin Teskef_dprintf "UNAME_S=[%s] UNAME_P=[%s] UNAME_R=[%s]" \
104756961fd7SDevin Teske          "$UNAME_S" "$UNAME_P" "$UNAME_R"
104856961fd7SDevin Teske
104956961fd7SDevin Teskef_dprintf "%s: Successfully loaded." common.subr
105056961fd7SDevin Teske
1051ab2043b8SDevin Teskefi # ! $_COMMON_SUBR
1052