summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsdconfig
diff options
context:
space:
mode:
authordteske <dteske@FreeBSD.org>2012-07-14 03:16:57 +0000
committerdteske <dteske@FreeBSD.org>2012-07-14 03:16:57 +0000
commit3981b9b76aa0266598ee7b724e5981627d8ac129 (patch)
tree8b439d31cf63b5d5c97b653a3cd721fd9961baa5 /usr.sbin/bsdconfig
parent5d2a55de5070f6d3a8e4b9762a397596e7b308ae (diff)
downloadFreeBSD-src-3981b9b76aa0266598ee7b724e5981627d8ac129.zip
FreeBSD-src-3981b9b76aa0266598ee7b724e5981627d8ac129.tar.gz
Import bsdconfig(8) as a replacement for the post-install abilities of
deprecated sysinstall(8). NOTE: WITH_BSDCONFIG is currently required. Submitted by: Devin Teske (dteske), Ron McDowell <rcm@fuzzwad.org> Reviewed by: Ron McDowell <rcm@fuzzwad.org> Approved by: Ed Maste (emaste)
Diffstat (limited to 'usr.sbin/bsdconfig')
-rw-r--r--usr.sbin/bsdconfig/Makefile32
-rw-r--r--usr.sbin/bsdconfig/USAGE40
-rwxr-xr-xusr.sbin/bsdconfig/bsdconfig313
-rw-r--r--usr.sbin/bsdconfig/bsdconfig.8240
-rw-r--r--usr.sbin/bsdconfig/console/INDEX59
-rw-r--r--usr.sbin/bsdconfig/console/Makefile16
-rw-r--r--usr.sbin/bsdconfig/console/USAGE33
-rwxr-xr-xusr.sbin/bsdconfig/console/console137
-rwxr-xr-xusr.sbin/bsdconfig/console/font205
-rw-r--r--usr.sbin/bsdconfig/console/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/console/include/messages.subr264
-rwxr-xr-xusr.sbin/bsdconfig/console/keymap365
-rwxr-xr-xusr.sbin/bsdconfig/console/repeat134
-rwxr-xr-xusr.sbin/bsdconfig/console/saver198
-rwxr-xr-xusr.sbin/bsdconfig/console/screenmap142
-rwxr-xr-xusr.sbin/bsdconfig/console/ttys197
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/INDEX53
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/Makefile16
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/USAGE33
-rwxr-xr-xusr.sbin/bsdconfig/diskmgmt/diskmgmt85
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/include/messages.subr27
-rw-r--r--usr.sbin/bsdconfig/docsinstall/INDEX53
-rw-r--r--usr.sbin/bsdconfig/docsinstall/Makefile16
-rw-r--r--usr.sbin/bsdconfig/docsinstall/USAGE33
-rwxr-xr-xusr.sbin/bsdconfig/docsinstall/docsinstall97
-rw-r--r--usr.sbin/bsdconfig/docsinstall/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/docsinstall/include/messages.subr28
-rw-r--r--usr.sbin/bsdconfig/dot/INDEX53
-rw-r--r--usr.sbin/bsdconfig/dot/Makefile16
-rw-r--r--usr.sbin/bsdconfig/dot/USAGE143
-rwxr-xr-xusr.sbin/bsdconfig/dot/dot646
-rw-r--r--usr.sbin/bsdconfig/dot/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/dot/include/messages.subr30
-rw-r--r--usr.sbin/bsdconfig/examples/Makefile11
-rw-r--r--usr.sbin/bsdconfig/examples/bsdconfigrc35
-rw-r--r--usr.sbin/bsdconfig/include/Makefile12
-rw-r--r--usr.sbin/bsdconfig/include/common.subr299
-rw-r--r--usr.sbin/bsdconfig/include/dialog.subr1441
-rw-r--r--usr.sbin/bsdconfig/include/messages.subr56
-rw-r--r--usr.sbin/bsdconfig/include/mustberoot.subr360
-rw-r--r--usr.sbin/bsdconfig/include/strings.subr104
-rw-r--r--usr.sbin/bsdconfig/include/sysrc.subr616
-rw-r--r--usr.sbin/bsdconfig/mouse/INDEX58
-rw-r--r--usr.sbin/bsdconfig/mouse/Makefile16
-rw-r--r--usr.sbin/bsdconfig/mouse/USAGE33
-rwxr-xr-xusr.sbin/bsdconfig/mouse/disable104
-rwxr-xr-xusr.sbin/bsdconfig/mouse/enable118
-rwxr-xr-xusr.sbin/bsdconfig/mouse/flags116
-rw-r--r--usr.sbin/bsdconfig/mouse/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/mouse/include/messages.subr90
-rwxr-xr-xusr.sbin/bsdconfig/mouse/mouse134
-rwxr-xr-xusr.sbin/bsdconfig/mouse/port142
-rwxr-xr-xusr.sbin/bsdconfig/mouse/type158
-rw-r--r--usr.sbin/bsdconfig/networking/INDEX57
-rw-r--r--usr.sbin/bsdconfig/networking/Makefile16
-rw-r--r--usr.sbin/bsdconfig/networking/USAGE33
-rwxr-xr-xusr.sbin/bsdconfig/networking/defaultrouter73
-rwxr-xr-xusr.sbin/bsdconfig/networking/devices158
-rwxr-xr-xusr.sbin/bsdconfig/networking/hostname73
-rw-r--r--usr.sbin/bsdconfig/networking/include/Makefile12
-rw-r--r--usr.sbin/bsdconfig/networking/include/common.subr65
-rw-r--r--usr.sbin/bsdconfig/networking/include/device.subr489
-rw-r--r--usr.sbin/bsdconfig/networking/include/hostname.subr211
-rw-r--r--usr.sbin/bsdconfig/networking/include/ipaddr.subr236
-rw-r--r--usr.sbin/bsdconfig/networking/include/media.subr235
-rw-r--r--usr.sbin/bsdconfig/networking/include/messages.subr100
-rw-r--r--usr.sbin/bsdconfig/networking/include/netmask.subr215
-rw-r--r--usr.sbin/bsdconfig/networking/include/resolv.subr509
-rw-r--r--usr.sbin/bsdconfig/networking/include/routing.subr168
-rwxr-xr-xusr.sbin/bsdconfig/networking/nameservers73
-rwxr-xr-xusr.sbin/bsdconfig/networking/networking146
-rw-r--r--usr.sbin/bsdconfig/password/INDEX53
-rw-r--r--usr.sbin/bsdconfig/password/Makefile16
-rw-r--r--usr.sbin/bsdconfig/password/USAGE33
-rw-r--r--usr.sbin/bsdconfig/password/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/password/include/messages.subr35
-rw-r--r--usr.sbin/bsdconfig/password/include/password.subr122
-rwxr-xr-xusr.sbin/bsdconfig/password/password82
-rw-r--r--usr.sbin/bsdconfig/security/INDEX54
-rw-r--r--usr.sbin/bsdconfig/security/Makefile16
-rw-r--r--usr.sbin/bsdconfig/security/USAGE33
-rw-r--r--usr.sbin/bsdconfig/security/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/security/include/messages.subr48
-rwxr-xr-xusr.sbin/bsdconfig/security/kern_securelevel135
-rwxr-xr-xusr.sbin/bsdconfig/security/security149
-rw-r--r--usr.sbin/bsdconfig/startup/INDEX58
-rw-r--r--usr.sbin/bsdconfig/startup/Makefile16
-rw-r--r--usr.sbin/bsdconfig/startup/USAGE33
-rw-r--r--usr.sbin/bsdconfig/startup/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/startup/include/messages.subr112
-rw-r--r--usr.sbin/bsdconfig/startup/include/rcconf.subr466
-rw-r--r--usr.sbin/bsdconfig/startup/include/rcedit.subr106
-rw-r--r--usr.sbin/bsdconfig/startup/include/rcvar.subr206
-rwxr-xr-xusr.sbin/bsdconfig/startup/misc406
-rwxr-xr-xusr.sbin/bsdconfig/startup/rcadd153
-rwxr-xr-xusr.sbin/bsdconfig/startup/rcconf246
-rwxr-xr-xusr.sbin/bsdconfig/startup/rcdelete355
-rwxr-xr-xusr.sbin/bsdconfig/startup/rcedit69
-rwxr-xr-xusr.sbin/bsdconfig/startup/rcvar200
-rwxr-xr-xusr.sbin/bsdconfig/startup/startup128
-rw-r--r--usr.sbin/bsdconfig/timezone/INDEX53
-rw-r--r--usr.sbin/bsdconfig/timezone/Makefile16
-rw-r--r--usr.sbin/bsdconfig/timezone/USAGE42
-rw-r--r--usr.sbin/bsdconfig/timezone/include/Makefile12
-rw-r--r--usr.sbin/bsdconfig/timezone/include/continents.subr138
-rw-r--r--usr.sbin/bsdconfig/timezone/include/countries.subr78
-rw-r--r--usr.sbin/bsdconfig/timezone/include/iso3166.subr197
-rw-r--r--usr.sbin/bsdconfig/timezone/include/menus.subr220
-rw-r--r--usr.sbin/bsdconfig/timezone/include/messages.subr78
-rw-r--r--usr.sbin/bsdconfig/timezone/include/zones.subr670
-rwxr-xr-xusr.sbin/bsdconfig/timezone/timezone448
-rw-r--r--usr.sbin/bsdconfig/ttys/INDEX53
-rw-r--r--usr.sbin/bsdconfig/ttys/Makefile16
-rw-r--r--usr.sbin/bsdconfig/ttys/USAGE33
-rw-r--r--usr.sbin/bsdconfig/ttys/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/ttys/include/messages.subr31
-rwxr-xr-xusr.sbin/bsdconfig/ttys/ttys128
-rw-r--r--usr.sbin/bsdconfig/usermgmt/INDEX60
-rw-r--r--usr.sbin/bsdconfig/usermgmt/Makefile17
-rw-r--r--usr.sbin/bsdconfig/usermgmt/USAGE33
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupadd64
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupdel93
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupedit93
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupinput295
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/group_input.subr437
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/messages.subr111
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/user_input.subr1180
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/useradd64
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/userdel93
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/useredit93
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/userinput515
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/usermgmt150
134 files changed, 19427 insertions, 0 deletions
diff --git a/usr.sbin/bsdconfig/Makefile b/usr.sbin/bsdconfig/Makefile
new file mode 100644
index 0000000..1ce8d9c
--- /dev/null
+++ b/usr.sbin/bsdconfig/Makefile
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= console \
+ diskmgmt \
+ docsinstall \
+ dot \
+ examples \
+ include \
+ mouse \
+ networking \
+ password \
+ security \
+ startup \
+ timezone \
+ ttys \
+ usermgmt
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig
+FILES= USAGE
+
+SCRIPTS= bsdconfig
+
+MAN= bsdconfig.8
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+ mkdir -p ${DESTDIR}${SCRIPTSDIR}
+ mkdir -p ${DESTDIR}${MANDIR}8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/USAGE b/usr.sbin/bsdconfig/USAGE
new file mode 100644
index 0000000..86355b0
--- /dev/null
+++ b/usr.sbin/bsdconfig/USAGE
@@ -0,0 +1,40 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage:
+ @PROGRAM_NAME@ [-h]
+ @PROGRAM_NAME@ command [-h]
+ @PROGRAM_NAME@ [OPTIONS] [command [OPTIONS]]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
+
+COMMANDS:
+@COMMAND_LIST@
diff --git a/usr.sbin/bsdconfig/bsdconfig b/usr.sbin/bsdconfig/bsdconfig
new file mode 100755
index 0000000..2e8eaae
--- /dev/null
+++ b/usr.sbin/bsdconfig/bsdconfig
@@ -0,0 +1,313 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# usage
+#
+# display usage and exit
+#
+usage()
+{
+ local index="INDEX" cmd_list=""
+
+ cd $BSDCFG_LIBE
+
+ # Test for language-specific indices
+ f_quietly ls */"$index.${LANG:-$LC_ALL}" &&
+ index="$index.${LANG:-$LC_ALL}"
+
+ cmd_list=$(
+ awk '/^menu_selection="/ {
+ sub(/\|.*/, "")
+ sub(/^menu_selection="/, "")
+ print
+ }' */$index | sort
+ )
+
+ #
+ # Determine the longest command-length (in characters)
+ #
+ local longest_cmd
+ longest_cmd=$( echo "$cmd_list" | f_longest_line_length )
+ f_dprintf "longest_cmd=[$longest_cmd]"
+
+ #
+ # Determine the maximum width of terminal/console
+ #
+ local max_size max_width
+ max_size=$( stty size 2> /dev/null )
+ : ${max_size:="24 80"}
+ max_width="${max_size#*[$IFS]}"
+ f_dprintf "max_width=[$max_width]"
+
+ #
+ # Using the longest command-length as the width of a single column,
+ # determine if we can use more than one column to display commands.
+ #
+ local x=$longest_cmd ncols=1
+ x=$(( $x + 8 )) # Accomodate leading tab character
+ x=$(( $x + 3 + $longest_cmd )) # Preload end of next column
+ while [ $x -lt $max_width ]; do
+ ncols=$(( $ncols + 1 ))
+ x=$(( $x + 3 + $longest_cmd ))
+ done
+ f_dprintf "ncols=[$ncols] x=[$x]"
+
+ #
+ # Re-format the command-list into multiple columns
+ #
+ cmd_list=$( eval "$( echo "$cmd_list" |
+ awk -v ncols=$ncols -v size=$longest_cmd '
+ BEGIN {
+ n = 0
+ row_item[1] = ""
+ }
+ function print_row()
+ {
+ fmt = "printf \"\\t%-" size "s"
+ for (i = 1; i < cur_col; i++)
+ fmt = fmt " %-" size "s"
+ fmt = fmt "\\n\""
+ printf "%s", fmt
+ for (i = 1; i <= cur_col; i++)
+ printf " \"%s\"", row_item[i]
+ print ""
+ }
+ {
+ n++
+ cur_col = (( n - 1 ) % ncols ) + 1
+ printf "f_dprintf \"row_item[%u]=[%s]\"\n", cur_col, $0
+ row_item[cur_col] = $0
+ if ( cur_col == ncols ) print_row()
+ }
+ END {
+ if ( cur_col < ncols ) print_row()
+ }' )"
+ )
+
+ f_usage $BSDCFG_LIBE/USAGE \
+ "PROGRAM_NAME" "$pgm" \
+ "COMMAND_LIST" "$cmd_list"
+}
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local title="$DIALOG_TITLE"
+ local btitle="$DIALOG_BACKTITLE"
+ local prompt="$msg_menu_text"
+ local menu_list size
+
+ menu_list="
+ 'X' '$msg_exit' '$msg_exit_bsdconfig'
+ " # END-QUOTE
+
+ local sanitize_awk="{ gsub(/'/, \"'\\\\''\"); print }"
+
+ local menuitem menu_title menu_help menu_selection index=1
+ for menuitem in $( ls -d [0-9][0-9][0-9].* ); do
+ [ $index -lt ${#DIALOG_MENU_TAGS} ] || break
+ tag=$( f_substr "$DIALOG_MENU_TAGS" $index 1 )
+
+ menu_program=
+ menu_title=
+ menu_help=
+ f_include_lang $menuitem/INDEX
+ [ "$menu_program" ] || continue
+
+ case "$menu_program" in
+ /*) : already fully qualified ;;
+ *)
+ menu_program="$menuitem/$menu_program"
+ esac
+
+ menu_title=$( echo "$menu_title" | awk "$sanitize_awk" )
+ menu_help=$( echo "$menu_help" | awk "$sanitize_awk" )
+ setvar "menu_program$tag" "$menu_program"
+ menu_list="$menu_list '$tag' '$menu_title' '$menu_help'"
+
+ index=$(( $index + 1 ))
+ done
+
+ size=$( eval f_dialog_menu_with_help_size \
+ \"\$title\" \
+ \"\$btitle\" \
+ \"\$prompt\" \
+ \"\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --item-help \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_exit_bsdconfig\" \
+ --menu \"\$prompt\" $size $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) usage;;
+ esac
+done
+shift $(( $OPTIND -1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_main_menu"
+
+[ "$SECURE" ] && f_mustberoot_init
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Log our operating environment for debugging purposes
+#
+export UNAME_S="$(uname -s)" # Operating System (i.e. FreeBSD)
+export UNAME_P="$(uname -p)" # Processor Architecture (i.e. i386)
+export UNAME_R="$(uname -r)" # Release Level (i.e. X.Y-RELEASE)
+f_dprintf "UNAME_S=[$UNAME_S] UNAME_P=[$UNAME_P] UNAME_R=[$UNAME_R]"
+
+cd $BSDCFG_LIBE || f_die 1 "$msg_directory_not_found" "$BSDCFG_LIBE"
+
+#
+# If a non-option argument was passed, process it as a menuitem selection...
+#
+if [ "$1" ]; then
+ #
+ # ...unless it's a long-option for usage.
+ #
+ case "$1" in
+ -help|--help|-\?) usage;;
+ esac
+
+ #
+ # Find the INDEX (possibly i18n) claiming this keyword
+ #
+ lang="${LANG:-$LC_ALL}"
+ if [ "$lang" ]; then
+ sel=$( grep "^menu_selection=\"$1|" */INDEX.$lang \
+ 2> /dev/null | tail -1 )
+
+ # Fall-back to non-i18n sources if nothing was found
+ [ "$sel" ] ||
+ sel=$( grep "^menu_selection=\"$1|" */INDEX | tail -1 )
+ else
+ sel=$( grep "^menu_selection=\"$1|" */INDEX | tail -1 )
+ fi
+
+ #
+ # If no matches, display usage (which shows valid keywords)
+ #
+ if [ ! "$sel" ]; then
+ f_err "%s: %s: $msg_not_found\n" "$pgm" "$1"
+ usage
+ fi
+
+ #
+ # The command to execute is after the pipe-character (|) in the
+ # menu_selection property of the INDEX file for the menuitem.
+ #
+ cmd="${sel#*|}"
+ cmd="${cmd%\"}"
+ if [ ! "$cmd" ]; then
+ echo "$pgm: $1: $msg_not_found"
+ usage
+ fi
+ shift
+
+ #
+ # If the command pathname is not fully qualified fix-up/force to be
+ # relative to the menuitem directory.
+ #
+ case "$cmd" in
+ /*) : already fully qualified ;;
+ *)
+ dir="${sel%%/*}"
+ cmd="$dir/$cmd"
+ esac
+
+ exec $cmd ${USE_XDIALOG:+-X} "$@" || exit 1
+fi
+
+[ -f "$HOME/.bsdconfigrc" ] || f_dialog_msgbox "$msg_help_text"
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ X) # Exit
+ break
+ ;;
+
+ *) # Dynamically loaded menuitem
+ cmd=$( eval echo \"\$menu_program$mtag\" )
+ f_dprintf "cmd=[$cmd]"
+ $cmd ${USE_XDIALOG:+-X}
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/bsdconfig.8 b/usr.sbin/bsdconfig/bsdconfig.8
new file mode 100644
index 0000000..58cfe00
--- /dev/null
+++ b/usr.sbin/bsdconfig/bsdconfig.8
@@ -0,0 +1,240 @@
+.\" Copyright (c) 2012 Ron McDowell
+.\" Copyright (c) 2012 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 ``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 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.
+.\"
+.\" docsinstall
+.\" password
+.\" diskmgmt
+.\" usermgmt
+.\" useradd
+.\" useredit
+.\" userdel
+.\" groupmgmt
+.\" groupadd
+.\" groupedit
+.\" groupdel
+.\" console
+.\" syscons_font
+.\" syscons_keymap
+.\" syscons_repeat
+.\" syscons_saver
+.\" syscons_screenmap
+.\" syscons_ttys
+.\" timezone
+.\" mouse
+.\" mouse_enable
+.\" mouse_type
+.\" mouse_port
+.\" mouse_flags
+.\" mouse_disable
+.\" networking
+.\" defaultrouter
+.\" hostname
+.\" nameservers
+.\" netdev
+.\" security
+.\" ttys
+.\" [dot]
+.\"
+.\" $FreeBSD$
+.\"
+.Dd Mar 20, 2012
+.Dt BSDCONFIG 8
+.Os
+.Sh NAME
+.Nm bsdconfig
+.Nd system configuration utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl h
+.Nm
+.Ar command
+.Op Fl h
+.Nm
+.Op OPTIONS
+.Op command Op OPTIONS
+.Sh DESCRIPTION
+.Nm
+is used to set up many system configuration settings, both for new systems, as
+well as changing configuration settings of existing systems.
+.Pp
+.Nm
+takes a command as an argument. If invoked with no arguments, it will bring up
+a master menu listing the available commands.
+.Pp
+The following options are available:
+.Bl -tag -width indent+
+.It Fl h
+Print usage statement and exit.
+.It Fl S
+Secure X11 mode
+.Pq implies Fl X .
+As root, always prompt-for and validate
+.Xr sudo 8
+username/password before starting.
+.It Fl X
+Use
+.Xr Xdialog 1
+in place of
+.Xr dialog 1 .
+
+.Sh COMMANDS
+The following commands
+.Pq sorted alphabetically
+are currently included in the base
+.Nm
+program, with more to be added soon. Other commands can be added, as detailed
+below in the
+.Cm ADDING COMMANDS
+section, and once added, will appear in the master menu as well as in the
+.Cm -h
+listing.
+.Bl -tag -width ".Cm syscons_screenmap"
+.It Cm console
+Utilities to customize the behavior of the system console.
+.It Cm defaultrouter
+Shortcut to the Default Router/Gateway menu under networking.
+.It Cm diskmgmt
+Manage disk partitions and/or labels. Executes
+.Xr sade 8 .
+.It Cm docsinstall
+Executes the
+.Cm bsdinstall docsinstall
+sub-utility to allow installation/re-installation of the FreeBSD Documentation
+set(s).
+.It Cm dot
+Generate a graphviz
+.Xr dot 1
+language file
+.Pq printed on stdout
+visualizing the
+.Xr bsdconfig 8
+menu, include, and shortcut structure and relationships. See
+.Dq bsdconfig dot -h
+for more details.
+.It Cm groupadd
+Shortcut to the Add Groups menu under groupmgmt.
+.It Cm groupdel
+Shortcut to the Delete Groups menu under groupmgmt.
+.It Cm groupedit
+Shortcut to the Edit/View Groups menu under groupmgmt.
+.It Cm groupmgmt
+Utilities to Add/Change/View/Delete Group Accounts.
+.It Cm hostname
+Shortcut to the Hostname/Domain menu under networking.
+.It Cm mouse
+Utilities for configuring, exploring, and enabling console mouse support.
+.It Cm mouse_disable
+Shortcut to the Disable menu under mouse.
+.It Cm mouse_enable
+Shortcut to the Enable menu under mouse.
+.It Cm mouse_flags
+Shortcut to the Flags menu under mouse.
+.It Cm mouse_port
+Shortcut to the Port menu under mouse.
+.It Cm mouse_type
+Shortcut to the Type menu under mouse.
+.It Cm nameservers
+Shortcut to the DNS Nameservers menu under networking.
+.It Cm netdev
+Shortcut to the Network Interfaces menu under networking.
+.It Cm networking
+Utilities to set/change Hostname/Domain, Network Interfaces, Default
+Router/Gateway, and DNS Nameservers.
+.It Cm password
+Set the system administrator
+.Pq root
+password.
+.It Cm security
+Configure various system security settings.
+.It Cm syscons_font
+Shortcut to the Font menu under console.
+.It Cm syscons_keymap
+Shortcut to the Keymap menu under console.
+.It Cm syscons_repeat
+Shortcut to the Repeat menu under console.
+.It Cm syscons_saver
+Shortcut to the Saver menu under console.
+.It Cm syscons_screenmap
+Shortcut to the Screenmap menu under console.
+.It Cm syscons_ttys
+Shortcut to the Ttys menu under console.
+.It Cm timezone
+Set the regional timezone of the local machine.
+.It Cm useradd
+Shortcut to the Add Users menu under usermgmt.
+.It Cm userdel
+Shortcut to the Delete Users menu under usermgmt.
+.It Cm useredit
+Shortcut to the Edit/View Users menu under usermgmt.
+.It Cm usermgmt
+Utilities to Add/Edit/View/Delete User Accounts.
+
+.Sh INTERNATIONALIZATION
+i18n features are built into
+.Nm
+and language-specific translation files will be added as they become available.
+In the absence of language-specific translation files, the default
+.Pq en_US.ISO8859-1
+files will be used.
+
+.Sh ADDING COMMANDS
+To be documented later. Document menu_selection="command|*" syntax of INDEX
+files.
+
+.Sh ENVIRONMENT VARIABLES
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width ".Ev LC_ALL"
+.It Ev LANG
+If LANG is set, messages and index information will be read from files named
+messages.$LANG and INDEX.$LANG and fall back to files named messages and INDEX if
+messages.$LANG and INDEX.$LANG do not exist. LANG takes precedence over LC_ALL.
+.It Ev LC_ALL
+If LC_ALL is set, messages and index information will be read from files named
+messages.$LC_ALL and INDEX.$LC_ALL and fall back to files named messages and INDEX if
+messages.$LC_ALL and INDEX.$LC_ALL do not exist.
+
+.Sh FILES
+/usr/share/examples/bsdconfig/bsdconfigrc can be copied to $HOME/.bsdconfigrc and
+customized as needed.
+
+.Sh EXIT STATUS
+.Ex -std
+
+.Sh SEE ALSO
+.Xr host-setup 8
+
+.Sh HISTORY
+.Nm
+first appeared in
+.Fx 10.0 .
+
+.Sh AUTHORS
+.\" An -nosplit
+.An Ron McDowell Aq rcm@FuzzWad.ORG
+.An Devin Teske Aq devinteske@hotmail.com
+
+.Sh BUGS
+Undoubtedly.
diff --git a/usr.sbin/bsdconfig/console/INDEX b/usr.sbin/bsdconfig/console/INDEX
new file mode 100644
index 0000000..30ebcf8
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/INDEX
@@ -0,0 +1,59 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Console"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Customize system console behavior"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="console|console"
+menu_selection="syscons_font|font"
+menu_selection="syscons_keymap|keymap"
+menu_selection="syscons_repeat|repeat"
+menu_selection="syscons_saver|saver"
+menu_selection="syscons_screenmap|screenmap"
+menu_selection="syscons_ttys|ttys"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="console"
diff --git a/usr.sbin/bsdconfig/console/Makefile b/usr.sbin/bsdconfig/console/Makefile
new file mode 100644
index 0000000..aa6c6f1
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/080.console
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= console font keymap repeat saver screenmap ttys
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/console/USAGE b/usr.sbin/bsdconfig/console/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/console/console b/usr.sbin/bsdconfig/console/console
new file mode 100755
index 0000000..d4eeec8
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/console
@@ -0,0 +1,137 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="080.console"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_configure_system_console_settings"
+ local prompt="$msg_console_menu_text"
+
+ menu_list="
+ 'X $msg_exit' '$msg_exit_this_menu'
+ '2 $msg_font' '$msg_choose_alternate_screen_font'
+ '3 $msg_keymap' '$msg_choose_alternate_keyboard_map'
+ '4 $msg_repeat' '$msg_set_repeat_rate'
+ '5 $msg_saver' '$msg_configure_screen_saver'
+ '6 $msg_screenmap' '$msg_choose_alternate_screenmap'
+ '7 $msg_ttys' '$msg_choose_console_terminal_type'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_system_console_configuration"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+ "2 $msg_font") # Choose an alternate screen font
+ $BSDCFG_LIBE/$APP_DIR/font ${USE_XDIALOG:+-X} ;;
+ "3 $msg_keymap") # Choose an alternate keyboard map
+ $BSDCFG_LIBE/$APP_DIR/keymap ${USE_XDIALOG:+-X} ;;
+ "4 $msg_repeat") # Set the rate at which keys repeat
+ $BSDCFG_LIBE/$APP_DIR/repeat ${USE_XDIALOG:+-X} ;;
+ "5 $msg_saver") # Configure the screen saver
+ $BSDCFG_LIBE/$APP_DIR/saver ${USE_XDIALOG:+-X} ;;
+ "6 $msg_screenmap") # Choose an alternate screenmap
+ $BSDCFG_LIBE/$APP_DIR/screenmap ${USE_XDIALOG:+-X} ;;
+ "7 $msg_ttys") # Choose console terminal type
+ $BSDCFG_LIBE/$APP_DIR/ttys ${USE_XDIALOG:+-X} ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/console/font b/usr.sbin/bsdconfig/console/font
new file mode 100755
index 0000000..5ea3e2d
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/font
@@ -0,0 +1,205 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="080.console"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_choose_a_font"
+ local prompt="$msg_font_menu_text"
+
+ menu_list="
+ '1 $msg_none' '$msg_use_hardware_default_font'
+ '2 $msg_ibm_437' '$msg_ibm_437_desc'
+ '3 $msg_ibm_850' '$msg_ibm_850_desc'
+ '4 $msg_ibm_865' '$msg_ibm_865_desc'
+ '5 $msg_ibm_866' '$msg_ibm_866_desc'
+ '6 $msg_ibm_866u' '$msg_ibm_866u_desc'
+ '7 $msg_ibm_1251' '$msg_ibm_1251_desc'
+ '8 $msg_iso_8859_1' '$msg_iso_8859_1_desc'
+ '9 $msg_iso_8859_2' '$msg_iso_8859_2_desc'
+ 'a $msg_iso_8859_4' '$msg_iso_8859_4_desc'
+ 'b $msg_iso_8859_7' '$msg_iso_8859_7_desc'
+ 'c $msg_iso_8859_8' '$msg_iso_8859_8_desc'
+ 'd $msg_iso_8859_15' '$msg_iso_8859_15_desc'
+ 'e $msg_swiss' '$msg_swiss_desc'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_system_console_font"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "1 $msg_none") # Use hardware default font
+ f_sysrc_set font8x8 "NO" || f_die
+ f_sysrc_set font8x14 "NO" || f_die
+ f_sysrc_set font8x16 "NO" || f_die
+ break ;;
+ "2 $msg_ibm_437") # English and others, VGA default
+ f_sysrc_set font8x8 "cp437-8x8" || f_die
+ f_sysrc_set font8x14 "cp437-8x14" || f_die
+ f_sysrc_set font8x16 "cp437-8x16" || f_die
+ break ;;
+ "3 $msg_ibm_850") # Western Europe, IBM encoding
+ f_sysrc_set font8x8 "cp850-8x8" || f_die
+ f_sysrc_set font8x14 "cp850-8x14" || f_die
+ f_sysrc_set font8x16 "cp850-8x16" || f_die
+ break ;;
+ "4 $msg_ibm_865") # Norwegian, IBM encoding
+ f_sysrc_set font8x8 "cp865-8x8" || f_die
+ f_sysrc_set font8x14 "cp865-8x14" || f_die
+ f_sysrc_set font8x16 "cp865-8x16" || f_die
+ break ;;
+ "5 $msg_ibm_866") # Russian, IBM encoding (use with KOI8-R screenmap)
+ f_sysrc_set font8x8 "cp866-8x8" || f_die
+ f_sysrc_set font8x14 "cp866-8x14" || f_die
+ f_sysrc_set font8x16 "cp866b-8x16" || f_die
+ f_sysrc_set mousechar_start 3 || f_die
+ break ;;
+ "6 $msg_ibm_866u") # Ukrainian, IBM encoding (use w/ KOI8-U screenmap)
+ f_sysrc_set font8x8 "cp866u-8x8" || f_die
+ f_sysrc_set font8x14 "cp866u-8x14" || f_die
+ f_sysrc_set font8x16 "cp866u-8x16" || f_die
+ f_sysrc_set mousechar_start 3 || f_die
+ break ;;
+ "7 $msg_ibm_1251") # Cyrillic, MS Windows encoding
+ f_sysrc_set font8x8 "cp1251-8x8" || f_die
+ f_sysrc_set font8x14 "cp1251-8x14" || f_die
+ f_sysrc_set font8x16 "cp1251-8x16" || f_die
+ f_sysrc_set mousechar_start 3 || f_die
+ break ;;
+ "8 $msg_iso_8859_1") # Western Europe, ISO encoding
+ f_sysrc_set font8x8 "iso-8x8" || f_die
+ f_sysrc_set font8x14 "iso-8x14" || f_die
+ f_sysrc_set font8x16 "iso-8x16" || f_die
+ break ;;
+ "9 $msg_iso_8859_2") # Eastern Europe, ISO encoding
+ f_sysrc_set font8x8 "iso02-8x8" || f_die
+ f_sysrc_set font8x14 "iso02-8x14" || f_die
+ f_sysrc_set font8x16 "iso02-8x16" || f_die
+ break ;;
+ "a $msg_iso_8859_4") # Baltic, ISO encoding
+ f_sysrc_set font8x8 "iso04-8x8" || f_die
+ f_sysrc_set font8x14 "iso04-8x14" || f_die
+ f_sysrc_set font8x16 "iso04-8x16" || f_die
+ break ;;
+ "b $msg_iso_8859_7") # Greek, ISO encoding
+ f_sysrc_set font8x8 "iso07-8x8" || f_die
+ f_sysrc_set font8x14 "iso07-8x14" || f_die
+ f_sysrc_set font8x16 "iso07-8x16" || f_die
+ break ;;
+ "c $msg_iso_8859_8") # Hebrew, ISO encoding
+ f_sysrc_set font8x8 "iso08-8x8" || f_die
+ f_sysrc_set font8x14 "iso08-8x14" || f_die
+ f_sysrc_set font8x16 "iso08-8x16" || f_die
+ break ;;
+ "d $msg_iso_8859_15") # Europe, ISO encoding
+ f_sysrc_set font8x8 "iso15-8x8" || f_die
+ f_sysrc_set font8x14 "iso15-8x14" || f_die
+ f_sysrc_set font8x16 "iso15-8x16" || f_die
+ break ;;
+ "e $msg_swiss") # English, better resolution
+ f_sysrc_set font8x8 "swiss-8x8" || f_die
+ f_sysrc_set font8x14 "NO" || f_die
+ f_sysrc_set font8x16 "swiss-8x16" || f_die
+ break ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/console/include/Makefile b/usr.sbin/bsdconfig/console/include/Makefile
new file mode 100644
index 0000000..e915751
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/080.console/include
+FILES= messages.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/console/include/messages.subr b/usr.sbin/bsdconfig/console/include/messages.subr
new file mode 100644
index 0000000..ffc9084
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/include/messages.subr
@@ -0,0 +1,264 @@
+# Copyright (c) 2012 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$
+
+hline_choose_a_font="Choose a font"
+hline_choose_a_keyboard_map="Choose a keyboard map"
+hline_choose_a_keyboard_repeat_rate="Choose a keyboard repeat rate"
+hline_choose_a_screen_map="Choose a screen map"
+hline_choose_a_screen_saver="Choose a nifty-looking screen saver"
+hline_choose_a_terminal_type="Choose a terminal type"
+hline_configure_system_console_settings="Configure your system console settings"
+msg_beastie="Beastie"
+msg_beastie_desc="\"BSD Daemon\" animated screen saver (graphics)"
+msg_belgian="Belgian"
+msg_belgian_desc="Belgian ISO keymap"
+msg_blank="Blank"
+msg_blank_desc="Simply blank the screen"
+msg_brazil_cp850="Brazil CP850"
+msg_brazil_cp850_desc="Brazil CP850 keymap"
+msg_brazil_iso="Brazil ISO"
+msg_brazil_iso_accent="Brazil ISO (accent)"
+msg_brazil_iso_accent_desc="Brazil ISO keymap (accent keys)"
+msg_brazil_iso_desc="Brazil ISO keymap"
+msg_bulgarian_bds="Bulgarian BDS"
+msg_bulgarian_bds_desc="Bulgarian BDS keymap"
+msg_bulgarian_phonetic="Bulgarian Phonetic"
+msg_bulgarian_phonetic_desc="Bulgarian Phonetic keymap"
+msg_cancel="Cancel"
+msg_central_european_iso="Central European ISO"
+msg_central_european_iso_desc="Central European ISO keymap"
+msg_choose_alternate_keyboard_map="Choose an alternate keyboard map"
+msg_choose_alternate_screenmap="Choose an alternate screenmap"
+msg_choose_alternate_screen_font="Choose an alternate screen font"
+msg_choose_console_terminal_type="Choose console terminal type"
+msg_configure_screen_saver="Configure the screen saver"
+msg_console_menu_text="The system console driver for FreeBSD has a number of configuration\noptions which may be set according to your preference.\n\nWhen you are done setting configuration options, select Cancel."
+msg_croatian_iso="Croation ISO"
+msg_croatian_iso_desc="Croation ISO keymap"
+msg_czech_iso_accent="Czech ISO (accent)"
+msg_czech_iso_accent_desc="Czech ISO keymap (accent keys)"
+msg_daemon="Daemon"
+msg_daemon_desc="\"BSD Daemon\" animated screen saver (text)"
+msg_danish_cp865="Danish CP865"
+msg_danish_cp865_desc="Danish Code Page 865 keymap"
+msg_danish_iso="Danish ISO"
+msg_danish_iso_desc="Danish ISO keymap"
+msg_default="Default"
+msg_default_desc="Use default keyboard repeat rate"
+msg_dragon="Dragon"
+msg_dragon_desc="Dragon screensaver (graphics)"
+msg_enter_timeout_period="Enter time-out period in seconds for screen saver"
+msg_estonian_cp850="Estonian CP850"
+msg_estonian_cp850_desc="Estonian Code Page 850 keymap"
+msg_estonian_iso="Estonian ISO"
+msg_estonian_iso_desc="Estonian ISO keymap"
+msg_estonian_iso_15="Estonian ISO 15"
+msg_estonian_iso_15_desc="Estonian ISO 8859-15 keymap"
+msg_exit="Exit"
+msg_exit_this_menu="Exit this menu (returning to previous)"
+msg_fade="Fade"
+msg_fade_desc="Fade out effect screen saver"
+msg_fast="Fast"
+msg_fast_desc="Fast keyboard repeat rate"
+msg_finnish_cp850="Finnish CP850"
+msg_finnish_cp850_desc="Finnish Code Page 850 keymap"
+msg_finnish_iso="Finnish ISO"
+msg_finnish_iso_desc="Finnish ISO keymap"
+msg_fire="Fire"
+msg_fire_desc="Flames effect screen saver"
+msg_font="Font"
+msg_font_menu_text="Most PC hardware defaults to displaying characters in the\nIBM 437 character set. However, in the Unix world, this\ncharacter set is very rarely used. Most Western European\ncountries, for example, prefer ISO 8859-1.\nAmerican users won't notice the difference since the bottom half\nof all these charactersets is ANSI anyway. However, they might\nwant to load a font anyway to use the 30- or 50-line displays.\nIf your hardware is capable of downloading a new display font,\nyou can select the appropriate font below."
+msg_french_iso="French ISO"
+msg_french_iso_accent="French ISO (accent)"
+msg_french_iso_accent_desc="French ISO keymap (accent keys)"
+msg_french_iso_desc="French ISO keymap"
+msg_french_iso_macbook="French ISO/Macbook"
+msg_french_iso_macbook_desc="French ISO keymap on macbook"
+msg_green="Green"
+msg_green_desc="\"Green\" power saving mode (if supported by monitor)"
+msg_german_cp850="German CP850"
+msg_german_cp850_desc="German Code Page 850 keymap"
+msg_german_iso="German ISO"
+msg_german_iso_desc="German ISO keymap"
+msg_greek_101="Greek 101"
+msg_greek_101_desc="Greek ISO keymap (101 keys)"
+msg_greek_104="Greek 104"
+msg_greek_104_desc="Greek ISO keymap (104 keys)"
+msg_greek_elot="Greek ELOT"
+msg_greek_elot_desc="Greek ISO keymap (ELOT 1000)"
+msg_hungarian_101="Hungarian 101"
+msg_hungarian_101_desc="Hungarian ISO keymap (101 key)"
+msg_hungarian_102="Hungarian 102"
+msg_hungarian_102_desc="Hungarian ISO keymap (102 key)"
+msg_ibm_437="IBM 437"
+msg_ibm_437_desc="English and others, VGA default"
+msg_ibm_437_vga_default="IBM437 (VGA default)"
+msg_ibm_850="IBM 850"
+msg_ibm_850_desc="Western Europe, IBM encoding"
+msg_ibm_865="IBM 865"
+msg_ibm_865_desc="Norwegian, IBM encoding"
+msg_ibm_866="IBM 866"
+msg_ibm_866_desc="Russian, IBM encoding (use with KOI8-R screenmap)"
+msg_ibm_866u="IBM 866u"
+msg_ibm_866u_desc="Ukrainian, IBM encoding (use with KOI8-U screenmap)"
+msg_ibm_1251="IBM 1251"
+msg_ibm_1251_desc="Cyrillic, MS Windows encoding"
+msg_icelandic="Icelandic"
+msg_icelandic_accent="Icelandic (accent)"
+msg_icelandic_accent_desc="Icelandic ISO keymap (accent keys)"
+msg_icelandic_desc="Icelandic ISO keymap"
+msg_iso_8859_1="ISO 8859-1"
+msg_iso_8859_1_desc="Western Europe, ISO encoding"
+msg_iso_8859_1_to_ibm437="ISO 8859-1 to IBM437"
+msg_iso_8859_1_to_ibm437_desc="W-Europe ISO 8859-1 to IBM 437 screenmap"
+msg_iso_8859_2="ISO 8859-2"
+msg_iso_8859_2_desc="Eastern Europe, ISO encoding"
+msg_iso_8859_4="ISO 8859-4"
+msg_iso_8859_4_desc="Baltic, ISO encoding"
+msg_iso_8859_7="ISO 8859-7"
+msg_iso_8859_7_desc="Greek, ISO encoding"
+msg_iso_8859_7_to_ibm437="ISO 8859-7 to IBM437"
+msg_iso_8859_7_to_ibm437_desc="Greek ISO 8859-1 to IBM 437 screenmap"
+msg_iso_8859_8="ISO 8859-8"
+msg_iso_8859_8_desc="Hebrew, ISO encoding"
+msg_iso_8859_15="ISO 8859-15"
+msg_iso_8859_15_desc="Europe, ISO encoding"
+msg_italian="Italian"
+msg_italian_desc="Italian ISO keymap"
+msg_japanese_106="Japanese 106"
+msg_japanese_106_desc="Japanese 106 keymap"
+msg_keymap="Keymap"
+msg_keymap_menu_text="The system console driver for FreeBSD defaults to a standard\n\"US\" keyboard map. Users may wish to choose one of the\nother keymaps below."
+msg_koi8_r="KOI8-R"
+msg_koi8_u="KOI8-U"
+msg_koi8_r_to_ibm866="KOI8-R to IBM866"
+msg_koi8_r_to_ibm866_desc="Russian KOI8-R to IBM 866 screenmap"
+msg_koi8_u_to_ibm866u="KOI8-U to IBM866u"
+msg_koi8_u_to_ibm866u_desc="Ukrainian KOI8-U to IBM 866u screenmap"
+msg_latin_american="Latin American"
+msg_latin_american_accent="Latin American (accent)"
+msg_latin_american_accent_desc="Latin American ISO keymap (accent keys)"
+msg_latin_american_desc="Latin American ISO keymap"
+msg_logo="Logo"
+msg_logo_desc="FreeBSD \"logo\" animated screen saver (graphics)"
+msg_none="None"
+msg_none_saver_desc="Disable the screensaver"
+msg_none_screenmap_desc="No screenmap, don'\''t touch font"
+msg_none_ttys_desc="Don'\''t touch anything"
+msg_normal="Normal"
+msg_normal_desc="\"Normal\" keyboard repeat rate"
+msg_norway_iso="Norway ISO"
+msg_norway_iso_desc="Norwegian ISO keymap"
+msg_ok="OK"
+msg_polish_iso="Polish ISO"
+msg_polish_iso_desc="Polish ISO keymap"
+msg_portuguese="Portuguese"
+msg_portuguese_accent="Portuguese (accent)"
+msg_portuguese_accent_desc="Portuguese ISO keymap (accent keys)"
+msg_portuguese_desc="Portuguese ISO keymap"
+msg_rain="Rain"
+msg_rain_desc="Rain drops screen saver"
+msg_repeat="Repeat"
+msg_repeat_menu_text="This menu allows you to set the speed at which keys repeat\nwhen held down."
+msg_russia_koi8_r="Russia KOI8-R"
+msg_russia_koi8_r_desc="Russia KOI8-R keymap"
+msg_saver="Saver"
+msg_saver_menu_text="By default, the console driver will not attempt to do anything\nspecial with your screen when it's idle. If you expect to leave your\nmonitor switched on and idle for long periods of time then you should\nprobably enable one of these screen savers to prevent burn-in."
+msg_screenmap="Screenmap"
+msg_screenmap_menu_text="Unless you load a specific font, most PC hardware defaults to\ndisplaying characters in the IBM 437 character set. However,\nin the Unix world, this character set is very rarely used. Most\nWestern European countries, for example, prefer ISO 8859-1.\nAmerican users won't notice the difference since the bottom half\nof all these character sets is ANSI anyway.\nIf your hardware is capable of downloading a new display font,\nyou should probably choose that option. However, for hardware\nwhere this is not possible (e.g. monochrome adapters), a screen\nmap will give you the best approximation that your hardware can\ndisplay at all."
+msg_set_repeat_rate="Set the rate at which keys repeat"
+msg_slovak="Slovak"
+msg_slovak_desc="Slovak ISO keymap"
+msg_slovenian="Slovenian"
+msg_slovenian_desc="Slovenian ISO keymap"
+msg_slow="Slow"
+msg_slow_desc="Slow keyboard repeat rate"
+msg_snake="Snake"
+msg_snake_desc="Draw a FreeBSD \"snake\" on your screen"
+msg_spanish="Spanish"
+msg_spanish_accent="Spanish (accent)"
+msg_spanish_accent_desc="Spanish ISO keymap (accent keys)"
+msg_spanish_desc="Spanish ISO keymap"
+msg_star="Star"
+msg_star_desc="A \"twinkling stars\" effect"
+msg_swedish_cp850="Swedish CP850"
+msg_swedish_cp850_desc="Swedish Code Page 850 keymap"
+msg_swedish_iso="Swedish ISO"
+msg_swedish_iso_desc="Swedish ISO keymap"
+msg_swiss="SWISS"
+msg_swiss_desc="English, better resolution"
+msg_swiss_french_cp850="Swiss French CP850"
+msg_swiss_french_cp850_desc="Swiss French Code Page 850 keymap"
+msg_swiss_french_iso="Swiss French ISO"
+msg_swiss_french_iso_accent="Swiss French ISO (accent)"
+msg_swiss_french_iso_accent_desc="Swiss French ISO keymap (accent keys)"
+msg_swiss_french_iso_desc="Swiss French ISO keymap"
+msg_swiss_german_cp850="Swiss German CP850"
+msg_swiss_german_cp850_desc="Swiss German Code Page 850 keymap"
+msg_swiss_german_iso="Swiss German ISO"
+msg_swiss_german_iso_accent="Swiss German ISO (accent)"
+msg_swiss_german_iso_accent_desc="Swiss German ISO keymap (accent keys)"
+msg_swiss_german_iso_desc="Swiss German ISO keymap"
+msg_system_console_configuration="System Console Configuration"
+msg_system_console_font="System Console Font"
+msg_system_console_keymap="System Console Keymap"
+msg_system_console_keyboard_repeat_rate="System Console Keyboard Repeat Rate"
+msg_system_console_screen_saver="System Console Screen Saver"
+msg_system_console_screenmap="System Console Screenmap"
+msg_system_console_terminal_type="System Console Terminal Type"
+msg_timeout="Timeout"
+msg_timeout_desc="Set the screen saver timeout interval"
+msg_ttys="Ttys"
+msg_ttys_menu_text="For various console encodings, a corresponding terminal type\nmust be chosen in /etc/ttys.\n\nWARNING: For compatibility reasons, only entries starting with\nttyv and terminal types starting with cons[0-9] can be changed\nvia this menu."
+msg_uk_cp850="UK CP850"
+msg_uk_cp850_desc="UK Code Page 850 keymap"
+msg_uk_iso="UK ISO"
+msg_uk_iso_desc="UK ISO keymap"
+msg_ukrainian_koi8_u="Ukranian KOI8-U"
+msg_ukrainian_koi8_u_desc="Ukranian KOI8-U keymap"
+msg_ukrainian_koi8_u_koi8_r="Ukranian KOI8-U+KOI8-R"
+msg_ukrainian_koi8_u_koi8_r_desc="Ukranian KOI8-U+KOI8-R keymap (alter)"
+msg_us_ascii="US-ASCII"
+msg_us_ascii_to_ibm327="US-ASCII to IBM437"
+msg_us_ascii_to_ibm327_desc="US-ASCII to IBM 437 screenmap"
+msg_usa_capslock_ctrl="USA CapsLock->Ctrl"
+msg_usa_capslock_ctrl_desc="US standard (Caps as L-Control)"
+msg_usa_dvorak="USA Dvorak"
+msg_usa_dvorak_desc="US Dvorak keymap"
+msg_usa_dvorak_left="USA Dvorak (left)"
+msg_usa_dvorak_left_desc="US left handed Dvorak keymap"
+msg_usa_dvorak_right="USA Dvorak (right)"
+msg_usa_dvorak_right_desc="US right handed Dvorak keymap"
+msg_usa_emacs="USA Emacs"
+msg_usa_emacs_desc="US standard optimized for EMACS"
+msg_usa_iso="USA ISO"
+msg_usa_iso_desc="US ISO keymap"
+msg_usa_unix="USA UNIX"
+msg_usa_unix_desc="US traditional UNIX-workstation"
+msg_use_hardware_default_font="Use hardware default font"
+msg_value_required="Value Required"
+msg_warp="Warp"
+msg_warp_desc="A \"stars warping\" effect"
diff --git a/usr.sbin/bsdconfig/console/keymap b/usr.sbin/bsdconfig/console/keymap
new file mode 100755
index 0000000..63592e7
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/keymap
@@ -0,0 +1,365 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="080.console"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# List of keymap names
+#
+KEYMAP_NAMES="
+ belgian brazil_cp850 brazil_iso
+ brazil_iso_accent bulgarian_bds bulgarian_phonetic
+ central_european_iso croatian_iso czech_iso_accent
+ danish_cp865 danish_iso estonian_cp850
+ estonian_iso estonian_iso_15 finnish_cp850
+ finnish_iso french_iso french_iso_accent
+ french_iso_macbook german_cp850 german_iso
+ greek_101 greek_104 greek_elot
+ hungarian_101 hungarian_102 icelandic
+ icelandic_accent italian japanese_106
+ latin_american latin_american_accent norway_iso
+ polish_iso portuguese portuguese_accent
+ russia_koi8_r slovak slovenian
+ spanish spanish_accent swedish_cp850
+ swedish_iso swiss_french_cp850 swiss_french_iso
+ swiss_french_iso_accent swiss_german_cp850 swiss_german_iso
+ swiss_german_iso_accent uk_cp850 uk_iso
+ ukrainian_koi8_u ukrainian_koi8_u_koi8_r usa_capslock_ctrl
+ usa_dvorak usa_dvorak_left usa_dvorak_right
+ usa_emacs usa_iso usa_unix
+" # END-QUOTE
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_choose_a_keyboard_map"
+ local prompt="$msg_keymap_menu_text"
+
+ #
+ # Export variables for awk(1) ENVIRON visibility
+ #
+ local name
+ for name in $KEYMAP_NAMES; do
+ export msg_$name msg_${name}_desc
+ done
+
+ #
+ # Generate a sorted list of keymaps. If the first letter of the keymap
+ # name is unique (case-insensitive) then it is used as the tag to allow
+ # the user to jump to that entry.
+ #
+ menu_list=$(
+ for name in $KEYMAP_NAMES; do
+ eval echo \"\$msg_$name\" msg_$name
+ done | sort | awk 'BEGIN { prefix = "" }
+ {
+ cur_prefix = tolower(substr(ENVIRON[$NF], 1, 1))
+ printf "'\''"
+ if ( prefix != cur_prefix )
+ prefix = cur_prefix
+ else
+ printf " "
+ printf "%s'\'' '\''%s'\''\n",
+ ENVIRON[$NF], ENVIRON[$NF"_desc"]
+ }'
+ )
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_system_console_keymap"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ #
+ # Reverse the users choice into the variable name
+ #
+ keymap_name=
+ mtag="${mtag# }" # remove single leading-space if-present
+ for name in $KEYMAP_NAMES; do
+ if [ "$( eval echo \"\$msg_$name\" )" = "$mtag" ]; then
+ keymap_name="$name"
+ break
+ fi
+ done
+
+ [ "$keymap_name" ] || continue
+
+ case "$keymap_name" in
+ belgian)
+ f_sysrc_set keymap "be.iso" || f_die
+ break ;;
+ brazil_cp850)
+ f_sysrc_set keymap "br275.cp850" || f_die
+ break ;;
+ brazil_iso)
+ f_sysrc_set keymap "br275.iso" || f_die
+ break ;;
+ brazil_iso_accent)
+ f_sysrc_set keymap "br275.iso.acc" || f_die
+ break ;;
+ bulgarian_bds)
+ f_sysrc_set keymap "bg.bds.ctrlcaps" || f_die
+ break ;;
+ bulgarian_phonetic)
+ f_sysrc_set keymap "bg.phonetic.ctrlcaps" || f_die
+ break ;;
+ central_european_iso)
+ f_sysrc_set keymap "ce.iso2" || f_die
+ break ;;
+ croatian_iso)
+ f_sysrc_set keymap "hr.iso" || f_die
+ break ;;
+ czech_iso_accent)
+ f_sysrc_set keymap "cs.latin2.qwertz" || f_die
+ break ;;
+ danish_cp865)
+ f_sysrc_set keymap "danish.cp865" || f_die
+ break ;;
+ danish_iso)
+ f_sysrc_set keymap "danish.iso" || f_die
+ break ;;
+ estonian_cp850)
+ f_sysrc_set keymap "estonian.cp850" || f_die
+ break ;;
+ estonian_iso)
+ f_sysrc_set keymap "estonian.iso" || f_die
+ break ;;
+ estonian_iso_15)
+ f_sysrc_set keymap "estonian.iso15" || f_die
+ break ;;
+ finnish_cp850)
+ f_sysrc_set keymap "finnish.cp850" || f_die
+ break ;;
+ finnish_iso)
+ f_sysrc_set keymap "finnish.iso" || f_die
+ break ;;
+ french_iso)
+ f_sysrc_set keymap "fr.iso" || f_die
+ break ;;
+ french_iso_accent)
+ f_sysrc_set keymap "fr.iso.acc" || f_die
+ break ;;
+ french_iso_macbook)
+ f_sysrc_set keymap "fr.macbook.acc" || f_die
+ break ;;
+ german_cp850)
+ f_sysrc_set keymap "german.cp850" || f_die
+ break ;;
+ german_iso)
+ f_sysrc_set keymap "german.iso" || f_die
+ break ;;
+ greek_101)
+ f_sysrc_set keymap "gr.us101.acc" || f_die
+ break ;;
+ greek_104)
+ f_sysrc_set keymap "el.iso07" || f_die
+ break ;;
+ greek_elot)
+ f_sysrc_set keymap "gr.elot.acc" || f_die
+ break ;;
+ hungarian_101)
+ f_sysrc_set keymap "hu.iso2.101keys" || f_die
+ break ;;
+ hungarian_102)
+ f_sysrc_set keymap "hu.iso2.102keys" || f_die
+ break ;;
+ icelandic)
+ f_sysrc_set keymap "icelandic.iso" || f_die
+ break ;;
+ icelandic_accent)
+ f_sysrc_set keymap "icelandic.iso.acc" || f_die
+ break ;;
+ italian)
+ f_sysrc_set keymap "it.iso" || f_die
+ break ;;
+ japanese_106)
+ f_sysrc_set keymap "jp.106" || f_die
+ break ;;
+ latin_american)
+ f_sysrc_set keymap "latinamerican" || f_die
+ break ;;
+ latin_american_accent)
+ f_sysrc_set keymap "latinamerican.iso.acc" || f_die
+ break ;;
+ norway_iso)
+ f_sysrc_set keymap "norwegian.iso" || f_die
+ break ;;
+ polish_iso)
+ f_sysrc_set keymap "pl_PL.ISO8859-2" || f_die
+ break ;;
+ portuguese)
+ f_sysrc_set keymap "pt.iso" || f_die
+ break ;;
+ portuguese_accent)
+ f_sysrc_set keymap "pt.iso.acc" || f_die
+ break ;;
+ russia_koi8_r)
+ f_sysrc_set keymap "ru.koi8-r" || f_die
+ break ;;
+ slovak)
+ f_sysrc_set keymap "sk.iso2" || f_die
+ break ;;
+ slovenian)
+ f_sysrc_set keymap "si.iso" || f_die
+ break ;;
+ spanish)
+ f_sysrc_set keymap "spanish.iso" || f_die
+ break ;;
+ spanish_accent)
+ f_sysrc_set keymap "spanish.iso.acc" || f_die
+ break ;;
+ swedish_cp850)
+ f_sysrc_set keymap "swedish.cp850" || f_die
+ break ;;
+ swedish_iso)
+ f_sysrc_set keymap "swedish.iso" || f_die
+ break ;;
+ swiss_french_cp850)
+ f_sysrc_set keymap "swissfrench.cp850" || f_die
+ break ;;
+ swiss_french_iso)
+ f_sysrc_set keymap "swissfrench.iso" || f_die
+ break ;;
+ swiss_french_iso_accent)
+ f_sysrc_set keymap "swissfrench.iso.acc" || f_die
+ break ;;
+ swiss_german_cp850)
+ f_sysrc_set keymap "swissgerman.cp850" || f_die
+ break ;;
+ swiss_german_iso)
+ f_sysrc_set keymap "swissgerman.iso" || f_die
+ break ;;
+ swiss_german_iso_accent)
+ f_sysrc_set keymap "swissgerman.iso.acc" || f_die
+ break ;;
+ uk_cp850)
+ f_sysrc_set keymap "uk.cp850" || f_die
+ break ;;
+ uk_iso)
+ f_sysrc_set keymap "uk.iso" || f_die
+ break ;;
+ ukrainian_koi8_u)
+ f_sysrc_set keymap "ua.koi8-u" || f_die
+ break ;;
+ ukrainian_koi8_u_koi8_r)
+ f_sysrc_set keymap "ua.koi8-u.shift.alt" || f_die
+ break ;;
+ usa_capslock_ctrl)
+ f_sysrc_set keymap "us.pc-ctrl" || f_die
+ break ;;
+ usa_dvorak)
+ f_sysrc_set keymap "us.dvorak" || f_die
+ break ;;
+ usa_dvorak_left)
+ f_sysrc_set keymap "us.dvorakl" || f_die
+ break ;;
+ usa_dvorak_right)
+ f_sysrc_set keymap "us.dvorakr" || f_die
+ break ;;
+ usa_emacs)
+ f_sysrc_set keymap "us.emacs" || f_die
+ break ;;
+ usa_iso)
+ f_sysrc_set keymap "us.iso" || f_die
+ break ;;
+ usa_unix)
+ f_sysrc_set keymap "us.unix" || f_die
+ break ;;
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/console/repeat b/usr.sbin/bsdconfig/console/repeat
new file mode 100755
index 0000000..8f968fd
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/repeat
@@ -0,0 +1,134 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="080.console"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_choose_a_keyboard_repeat_rate"
+ local prompt="$msg_repeat_menu_text"
+
+ menu_list="
+ '$msg_slow' '$msg_slow_desc'
+ '$msg_normal' '$msg_normal_desc'
+ '$msg_fast' '$msg_fast_desc'
+ '$msg_default' '$msg_default_desc'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_system_console_keyboard_repeat_rate"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "$msg_slow") # Slow keyboard repeat rate
+ f_sysrc_set keyrate "slow" || f_die
+ break ;;
+ "$msg_normal") # "Normal" keyboard repeat rate
+ f_sysrc_set keyrate "normal" || f_die
+ break ;;
+ "$msg_fast") # Fast keyboard repeat rate
+ f_sysrc_set keyrate "fast" || f_die
+ break ;;
+ "$msg_default") # Use default keyboard repeat rate
+ f_sysrc_set keyrate "NO" || f_die
+ break ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/console/saver b/usr.sbin/bsdconfig/console/saver
new file mode 100755
index 0000000..8e803d2
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/saver
@@ -0,0 +1,198 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="080.console"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_choose_a_screen_saver"
+ local prompt="$msg_saver_menu_text"
+
+ menu_list="
+ '1 $msg_blank' '$msg_blank_desc'
+ '2 $msg_beastie' '$msg_beastie_desc'
+ '3 $msg_daemon' '$msg_daemon_desc'
+ '4 $msg_dragon' '$msg_dragon_desc'
+ '5 $msg_fade' '$msg_fade_desc'
+ '6 $msg_fire' '$msg_fire_desc'
+ '7 $msg_green' '$msg_green_desc'
+ '8 $msg_logo' '$msg_logo_desc'
+ '9 $msg_rain' '$msg_rain_desc'
+ 'a $msg_snake' '$msg_snake_desc'
+ 'b $msg_star' '$msg_star_desc'
+ 'c $msg_warp' '$msg_warp_desc'
+ 'd $msg_none' '$msg_none_saver_desc'
+ '$msg_timeout' '$msg_timeout_desc'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_system_console_screen_saver"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "1 $msg_blank") # Simply blank the screen
+ f_sysrc_set saver "blank" || f_die
+ break ;;
+ "2 $msg_beastie") # "BSD Daemon" animated screen saver (graphics)
+ f_sysrc_set saver "beastie" || f_die
+ break ;;
+ "3 $msg_daemon") # "BSD Daemon" animated screen saver (text)
+ f_sysrc_set saver "daemon" || f_die
+ break ;;
+ "4 $msg_dragon") # Dragon screensaver (graphics)
+ f_sysrc_set saver "dragon" || f_die
+ break ;;
+ "5 $msg_fade") # Fade out effect screen saver
+ f_sysrc_set saver "fade" || f_die
+ break ;;
+ "6 $msg_fire") # Flames effect screen saver
+ f_sysrc_set saver "fire" || f_die
+ break ;;
+ "7 $msg_green") # "Green" power saving mode (if supported by monitor)
+ f_sysrc_set saver "green" || f_die
+ break ;;
+ "8 $msg_logo") # FreeBSD "logo" animated screen saver (graphics)
+ f_sysrc_set saver "logo" || f_die
+ break ;;
+ "9 $msg_rain") # Rain drops screen saver
+ f_sysrc_set saver "rain" || f_die
+ break ;;
+ "a $msg_snake") # Draw a FreeBSD "snake" on your screen
+ f_sysrc_set saver "snake" || f_die
+ break ;;
+ "b $msg_star") # A "twinkling stars" effect
+ f_sysrc_set saver "star" || f_die
+ break ;;
+ "c $msg_warp") # A "stars warping" effect
+ f_sysrc_set saver "warp" || f_die
+ break ;;
+ "d $msg_none") # Disable the screensaver
+ f_sysrc_set saver "NO" || f_die
+ break ;;
+ "$msg_timeout") # Set the screen saver timeout interval
+ f_dialog_title "$msg_value_required"
+ title="$DIALOG_TITLE"
+ btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ prompt="$msg_enter_timeout_period"
+ blanktime=$( f_sysrc_get blanktime )
+ hline=""
+ size=$( f_dialog_inputbox_size \
+ "$title" \
+ "$btitle" \
+ "$prompt" \
+ "$blanktime" \
+ "$hline" )
+ $DIALOG \
+ --title "$title" \
+ --backtitle "$btitle" \
+ --hline "$hline" \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --inputbox "$prompt" $size \
+ "$blanktime" \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+ retval=$?
+ blanktime=$( f_dialog_inputstr )
+ [ $retval -eq $SUCCESS ] &&
+ f_sysrc_set blanktime "$blanktime"
+ ;;
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/console/screenmap b/usr.sbin/bsdconfig/console/screenmap
new file mode 100755
index 0000000..9e10c9f
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/screenmap
@@ -0,0 +1,142 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="080.console"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_choose_a_screen_map"
+ local prompt="$msg_screenmap_menu_text"
+
+ menu_list="
+ '1 $msg_none' '$msg_none_screenmap_desc'
+ '2 $msg_iso_8859_1_to_ibm437' '$msg_iso_8859_1_to_ibm437_desc'
+ '3 $msg_iso_8859_7_to_ibm437' '$msg_iso_8859_7_to_ibm437_desc'
+ '4 $msg_us_ascii_to_ibm327' '$msg_us_ascii_to_ibm327_desc'
+ '5 $msg_koi8_r_to_ibm866' '$msg_koi8_r_to_ibm866_desc'
+ '6 $msg_koi8_u_to_ibm866u' '$msg_koi8_u_to_ibm866u_desc'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_system_console_screenmap"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "1 $msg_none") # No screenmap, don't touch font
+ f_sysrc_set scrnmap "NO" || f_die
+ break ;;
+ "2 $msg_iso_8859_1_to_ibm437") # W-Europe ISO 8859-1 to IBM 437 scrnmap
+ f_sysrc_set scrnmap "iso-8859-1_to_cp437" || f_die
+ break ;;
+ "3 $msg_iso_8859_7_to_ibm437") # Greek ISO 8859-7 to IBM 437 screenmap
+ f_sysrc_set scrnmap "iso-8859-7_to_cp437" || f_die
+ break ;;
+ "4 $msg_us_ascii_to_ibm327") # US-ASCII to IBM 437 screenmap
+ f_sysrc_set scrnmap "us-ascii_to_cp437" || f_die
+ break ;;
+ "5 $msg_koi8_r_to_ibm866") # Russian KOI8-R to IBM 866 screenmap
+ f_sysrc_set scrnmap "koi8-r2cp866" || f_die
+ break ;;
+ "6 $msg_koi8_u_to_ibm866u") # Ukrainian KOI8-U to IBM 866u screenmap
+ f_sysrc_set scrnmap "koi8-u2cp866u" || f_die
+ break ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/console/ttys b/usr.sbin/bsdconfig/console/ttys
new file mode 100755
index 0000000..7502bec
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/ttys
@@ -0,0 +1,197 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="080.console"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# Location of ttys(5)
+#
+ETC_TTYS=/etc/ttys
+
+############################################################ GLOBALS
+
+#
+# Terminal-type map/menu-item list
+#
+TTY_MENU_LIST="
+ '1 $msg_none' '$msg_none_ttys_desc'
+ '2 $msg_ibm_437_vga_default' 'cons25'
+ '3 $msg_iso_8859_1' 'cons25l1'
+ '4 $msg_iso_8859_2' 'cons25l2'
+ '5 $msg_iso_8859_7' 'cons25l7'
+ '6 $msg_koi8_r' 'cons25r'
+ '7 $msg_koi8_u' 'cons25u'
+ '8 $msg_us_ascii' 'cons25w'
+" # END-QUOTE
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local size
+ local hline="$hline_choose_a_terminal_type"
+ local prompt="$msg_ttys_menu_text"
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $TTY_MENU_LIST )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $TTY_MENU_LIST \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# ttys_set_type $consterm
+#
+# Set terminal type of `ttyv*' and `cons[0-9]' entries in ttys(5) to $consterm.
+#
+ttys_set_type()
+{
+ local consterm="$1"
+
+ #
+ # Create new temporary file to write our ttys(5) update with new types.
+ #
+ local tmpfile="$( mktemp -t "pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ #
+ # Fixup permissions and ownership (mktemp(1) creates the temporary file
+ # with 0600 permissions -- change the permissions and ownership to
+ # match ttys(5) before we write it out and mv(1) it into place).
+ #
+ local mode="$( stat -f '%#Lp' "$ETC_TTYS" 2> /dev/null )"
+ local owner="$( stat -f '%u:%g' "$ETC_TTYS" 2> /dev/null )"
+ f_quietly chmod "${mode:-0644}" "$tmpfile"
+ f_quietly chown "${owner:-root:wheel}" "$tmpfile"
+
+ #
+ # Operate on ttys(5), replacing only the types of `ttyv*' and
+ # `cons[0-9]' terminals with the new type.
+ #
+ awk -v consterm="$consterm" '
+ BEGIN {
+ }
+ {
+ # "Skip" blank-lines, lines containing only whitespace, and
+ # lines containing only a comment or whitespace-then-comment.
+ #
+ if ( $0 ~ /^[[:space:]]*(#|$)/ ) { print; next }
+
+ # "Skip" terminal types other than those supported
+ #
+ if ( $1 !~ /^(ttyv.*|cons[0-9])$/ ) { print; next }
+
+ # Change the terminal type to the new value
+ #
+ match($0, /[[:alnum:]\.\+-_]+[[:space:]]+(on|off).*$/)
+ if ( ! RSTART ) { print; next }
+ left = substr($0, 0, RSTART - 1)
+ match($0, /[[:space:]]+(on|off).*$/)
+ right = substr($0, RSTART)
+ printf "%s%s%s\n", left, consterm, right
+ }
+ ' "$ETC_TTYS" > "$tmpfile" || return $FAILURE
+ f_quietly mv "$tmpfile" "$ETC_TTYS" || return $FAILURE
+
+ return $SUCCESS
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_system_console_terminal_type"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+ [ "$mtag" = "1 $msg_none" ] && break
+
+ consterm=$( eval f_dialog_menutag2item \"\$mtag\" $TTY_MENU_LIST )
+ err=$( ttys_set_type "$consterm" 2>&1 )
+ [ "$err" ] || break
+
+ f_show_msg "%s" "$err"
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/diskmgmt/INDEX b/usr.sbin/bsdconfig/diskmgmt/INDEX
new file mode 100644
index 0000000..2d03af8
--- /dev/null
+++ b/usr.sbin/bsdconfig/diskmgmt/INDEX
@@ -0,0 +1,53 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Disk Management"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Manage disk partitions and/or labels"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="diskmgmt|diskmgmt"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="diskmgmt"
diff --git a/usr.sbin/bsdconfig/diskmgmt/Makefile b/usr.sbin/bsdconfig/diskmgmt/Makefile
new file mode 100644
index 0000000..894c62c
--- /dev/null
+++ b/usr.sbin/bsdconfig/diskmgmt/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/050.diskmgmt
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= diskmgmt
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/diskmgmt/USAGE b/usr.sbin/bsdconfig/diskmgmt/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/diskmgmt/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/diskmgmt/diskmgmt b/usr.sbin/bsdconfig/diskmgmt/diskmgmt
new file mode 100755
index 0000000..6d3fbf0
--- /dev/null
+++ b/usr.sbin/bsdconfig/diskmgmt/diskmgmt
@@ -0,0 +1,85 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="050.diskmgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# If X11 is requested, which terminal and what options should we use?
+#
+X11TERM=xterm
+X11TERM_OPTS=
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_mustberoot_init
+
+#
+# If Xdialog(1) is requested, we'll need to wrap bsdinstall(8) into xterm(1)
+#
+if [ "$USE_XDIALOG" ]; then
+ f_have "$X11TERM" || f_die 1 \
+ "$msg_no_such_file_or_directory" "$pgm" "$X11TERM"
+
+ exec $X11TERM $X11TERM_OPTS -e /usr/sbin/sade
+else
+ exec /usr/sbin/sade
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/diskmgmt/include/Makefile b/usr.sbin/bsdconfig/diskmgmt/include/Makefile
new file mode 100644
index 0000000..9c94c0e
--- /dev/null
+++ b/usr.sbin/bsdconfig/diskmgmt/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/050.diskmgmt/include
+FILES= messages.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/diskmgmt/include/messages.subr b/usr.sbin/bsdconfig/diskmgmt/include/messages.subr
new file mode 100644
index 0000000..f0b563f
--- /dev/null
+++ b/usr.sbin/bsdconfig/diskmgmt/include/messages.subr
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 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$
+
+msg_no_such_file_or_directory="%s: %s: No such file or directory"
diff --git a/usr.sbin/bsdconfig/docsinstall/INDEX b/usr.sbin/bsdconfig/docsinstall/INDEX
new file mode 100644
index 0000000..c61e221
--- /dev/null
+++ b/usr.sbin/bsdconfig/docsinstall/INDEX
@@ -0,0 +1,53 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Documentation installation"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Install FreeBSD Documentation set"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="docsinstall|docsinstall"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="docsinstall"
diff --git a/usr.sbin/bsdconfig/docsinstall/Makefile b/usr.sbin/bsdconfig/docsinstall/Makefile
new file mode 100644
index 0000000..de03d7d
--- /dev/null
+++ b/usr.sbin/bsdconfig/docsinstall/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/020.docsinstall
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= docsinstall
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/docsinstall/USAGE b/usr.sbin/bsdconfig/docsinstall/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/docsinstall/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/docsinstall/docsinstall b/usr.sbin/bsdconfig/docsinstall/docsinstall
new file mode 100755
index 0000000..c0e11b6
--- /dev/null
+++ b/usr.sbin/bsdconfig/docsinstall/docsinstall
@@ -0,0 +1,97 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="020.docsinstall"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# If X11 is requested, which terminal and what options should we use?
+#
+X11TERM=xterm
+X11TERM_OPTS=
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_mustberoot_init
+
+#
+# If Xdialog(1) is requested, we'll need to wrap bsdinstall(8) into xterm(1)
+#
+if [ "$USE_XDIALOG" ]; then
+ #
+ # Make sure $X11TERM exists and is executable
+ #
+ case "$X11TERM" in
+ */*)
+ [ -e "$X11TERM" ] || f_die 1 \
+ "$msg_no_such_file_or_directory" "$pgm" "$X11TERM"
+ [ -x "$X11TERM" ] || f_die 1 \
+ "$msg_permission_denied" "$pgm" "$X11TERM"
+ ;;
+ *)
+ f_have "$X11TERM" || f_die 1 \
+ "$msg_no_such_file_or_directory" "$pgm" "$X11TERM"
+ esac
+
+ exec $X11TERM $X11TERM_OPTS -e /usr/sbin/bsdinstall docsinstall
+else
+ exec /usr/sbin/bsdinstall docsinstall
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/docsinstall/include/Makefile b/usr.sbin/bsdconfig/docsinstall/include/Makefile
new file mode 100644
index 0000000..9f75f7d
--- /dev/null
+++ b/usr.sbin/bsdconfig/docsinstall/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/020.docsinstall/include
+FILES= messages.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/docsinstall/include/messages.subr b/usr.sbin/bsdconfig/docsinstall/include/messages.subr
new file mode 100644
index 0000000..4c55f0f
--- /dev/null
+++ b/usr.sbin/bsdconfig/docsinstall/include/messages.subr
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 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$
+
+msg_no_such_file_or_directory="%s: %s: No such file or directory"
+msg_permission_denied="%s: %s: permission denied"
diff --git a/usr.sbin/bsdconfig/dot/INDEX b/usr.sbin/bsdconfig/dot/INDEX
new file mode 100644
index 0000000..96b0c87
--- /dev/null
+++ b/usr.sbin/bsdconfig/dot/INDEX
@@ -0,0 +1,53 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title=""
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help=""
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="dot|dot"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program=""
diff --git a/usr.sbin/bsdconfig/dot/Makefile b/usr.sbin/bsdconfig/dot/Makefile
new file mode 100644
index 0000000..5a87282
--- /dev/null
+++ b/usr.sbin/bsdconfig/dot/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/dot
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= dot
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/dot/USAGE b/usr.sbin/bsdconfig/dot/USAGE
new file mode 100644
index 0000000..c1c0dc3
--- /dev/null
+++ b/usr.sbin/bsdconfig/dot/USAGE
@@ -0,0 +1,143 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -c Don't show command-line shortcut relationships.
+ -d Don't show the date in the graph label.
+ -i Don't show include relationships.
+
+EXAMPLES:
+ View dot(1) language output describing bsdconfig(8) layout/make-up:
+
+ bsdconfig @PROGRAM_NAME@ | less
+
+ Render dot(1) output in SVG format (displays in most modern browsers):
+
+ bsdconfig @PROGRAM_NAME@ | dot -Tsvg -o bsdconfig.svg
+
+ NOTE: Requires `graphics/graphviz' from ports/packages.
+
+ View the above-rendered SVG file using your favorite X11-based viewer:
+
+ gimmage bsdconfig.svg
+
+ NOTE: Requires `graphics/gimmage' from ports/packages.
+
+ or
+
+ gthumb bsdconfig.svg
+
+ NOTE: Image is scaled to fit window on launch.
+ NOTE: Requires `graphics/gthumb' from ports/packages.
+
+ or
+
+ gqview bsdconfig.svg
+
+ NOTE: Requires `graphics/gqview' from ports/packages.
+
+ or
+
+ gx bsdconfig.svg
+
+ NOTE: Image is scaled to fit window on launch.
+ NOTE: Requires `graphics/gx' from ports/packages.
+
+ or
+
+ eog bsdconfig.svg
+
+ NOTE: Requires `graphics/eog' from ports/packages.
+
+ Render dot(1) output as PostScript print output consisting of multiple
+ US-Letter sized pages that can be assembled into a large poster (using
+ traditional tools such as scissors and tape):
+
+ bsdconfig @PROGRAM_NAME@ | dot -Teps -o bsdconfig.eps
+ poster -v -mLet -s1 -o bsdconfig.ps bsdconfig.eps
+
+ NOTE: Change "-s1" above to "-s0.5" to halve the size of the
+ poster or "-s2", for example, to double the poster size.
+
+ NOTE: Requires both `graphics/graphviz' and `print/poster' from
+ ports/packages.
+
+ Render dot(1) output as PostScript scaled to fit on a poster consisting
+ of 2x-wide and 4x-tall US-Letter sized pages:
+
+ bsdconfig @PROGRAM_NAME@ | dot -Teps -o bsdconfig.eps
+ poster -v -mLet -p2x4Letter -o bsdconfig.ps bsdconfig.eps
+
+ NOTE: Requires both `graphics/graphviz' and `print/poster' from
+ ports/packages.
+
+ View the above-rendered PostScript poster using X11:
+
+ gsview bsdconfig.ps
+
+ NOTE: Requires `print/gsview' from ports/packages.
+
+ or
+
+ convert bsdconfig.ps bsdconfig.pdf
+ xpdf bsdconfig.pdf
+
+ NOTE: Requires both `graphics/ImageMagick' and
+ `graphics/xdpf' from ports/packages.
+
+ NOTE: The converted PDF file is not suitable for
+ printing due to loss of quality during the
+ conversion process.
+
+ Print the above-rendered PostScript poster:
+
+ lpr -h bsdconfig.ps
+
+ NOTE: Requires configuration of a printer in `/etc/printcap'.
+
+ Extract each page of the poster into a separate PNG file:
+
+ gs -q -dNOPAUSE -dBATCH -sPAPERSIZE=letter \
+ -dTextAlphaBits=4 -dGraphicsAlphaBits=4 \
+ -sDEVICE=png16m -sOutputFile=bsdconfig%03d.png \
+ bsdconfig.ps
+
+ NOTE: Requires `print/ghostscript9' from ports/packages.
+
+ NOTE: The converted PNG files are not suitable for printing
+ due to loss of quality during the conversion process.
+
+ Extract a single page of the poster into a separate PostScript file for
+ printing individual pages from the command-line:
+
+ psselect 1 bsdconfig.ps bsdconfig-page1.ps
+ lpr -h bsdconfig-page1.ps
+
+ NOTE: Change "1" to "2" for the second page, ad-infinitum.
+ NOTE: Requires `print/psutils-letter' from ports/packages.
diff --git a/usr.sbin/bsdconfig/dot/dot b/usr.sbin/bsdconfig/dot/dot
new file mode 100755
index 0000000..e1f0e1b
--- /dev/null
+++ b/usr.sbin/bsdconfig/dot/dot
@@ -0,0 +1,646 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+APP_DIR="dot"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# Locataion of bsdconfig(8)
+#
+BSDCONFIG=/usr/sbin/bsdconfig
+
+############################################################ GLOBALS
+
+#
+# Options
+#
+SHOW_GRAPH_LABEL_DATE=1
+SHOW_INCLUDES=1
+SHOW_CMDLINE=1
+
+############################################################ FUNCTIONS
+
+# begin_nodelist $shape $color $fillcolor $style
+#
+# Create a new multi-node list rendering nodes in a specific style described by
+# the arguments passed.
+#
+begin_nodelist()
+{
+ local shape="$1" color="$2" fillcolor="$3" style="$4"
+
+ printf "\tnode [\n"
+ [ "$shape" ] &&
+ printf '\t\tshape = "%s",\n' "$shape"
+ [ "$color" ] &&
+ printf '\t\tcolor = "%s",\n' "$color"
+ [ "$fillcolor" ] &&
+ printf '\t\tfillcolor = "%s",\n' "$fillcolor"
+ [ "$style" ] &&
+ printf '\t\tstyle = "%s",\n' "$style"
+ printf "\t] {\n"
+}
+
+# print_node $node [$attributes ...]
+#
+# Print a node within a multi-node list.
+#
+print_node()
+{
+ local node="$1"
+
+ shift 1 # node
+
+ case "$node" in
+ edge) printf '\t\t%s' "$node";;
+ *) printf '\t\t"%s"' "$node";;
+ esac
+
+ if [ $# -gt 0 ]; then
+ echo -n ' ['
+ while [ $# -gt 0 ]; do
+ printf " %s" "$1"
+ shift 1
+ [ $# -gt 0 ] && echo -n ","
+ done
+ echo -n " ]"
+ fi
+
+ echo ";"
+}
+
+# print_node2 $node $node [$attributes ...]
+#
+# Print a directed node-node connection within a multi-node list.
+#
+print_node2()
+{
+ local node1="$1" node2="$2"
+
+ shift 2 # node1 node2
+
+ printf '\t\t"%s" -> "%s"' "$node1" "$node2"
+
+ if [ $# -gt 0 ]; then
+ echo -n ' ['
+ while [ $# -gt 0 ]; do
+ printf " %s" "$1"
+ shift 1
+ [ $# -gt 0 ] && echo -n ","
+ done
+ echo -n " ]"
+ fi
+
+ echo ";"
+}
+
+# end_nodelist
+#
+# Close a multi-node list.
+#
+end_nodelist()
+{
+ printf "\t};\n"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts cdhi flag; do
+ case "$flag" in
+ i) SHOW_INCLUDES=;;
+ d) SHOW_GRAPH_LABEL_DATE=;;
+ c) SHOW_CMDLINE=;;
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+cd $BSDCFG_LIBE || f_die 1 "$msg_directory_not_found" "$BSDCFG_LIB"
+
+#
+# Get a list of menu programs
+#
+menu_program_list=
+for file in [0-9][0-9][0-9].*/INDEX; do
+ menu_program_list="$menu_program_list $(
+ tail -r "$file" | awk -v item="${file%%/*}" '
+ /^[[:space:]]*menu_program="/ {
+ sub(/^.*="/, "")
+ sub(/"$/, "")
+ if ( ! $0 ) next
+ if ( $0 !~ "^/" ) sub(/^/, item "/")
+ print; exit
+ }'
+ )"
+done
+
+#
+# Get a list of submenu programs
+#
+submenu_program_list=
+for menu_program in $menu_program_list; do
+ case "$menu_program" in
+ [0-9][0-9][0-9].*/*) : fall-through ;;
+ *) continue # No sub-menus we can process
+ esac
+
+ submenu_program_list="$submenu_program_list $(
+ awk -v menu_program="$menu_program" \
+ -v item="${menu_program%%/*}" \
+ '
+ /^menu_selection="/ {
+ sub(/.*\|/, "")
+ sub(/"$/, "")
+ if ( ! $0 ) next
+ if ( $0 !~ "^/" )
+ sub(/^/, item "/")
+ if ( $0 == menu_program ) next
+ print
+ }
+ ' "${menu_program%%/*}/INDEX"
+ )"
+done
+
+#
+# Get a list of command-line programs
+#
+cmd_program_list=
+for file in */INDEX; do
+ cmd_program_list="$cmd_program_list $(
+ awk -v item="${file%%/*}" '
+ /^menu_selection="/ {
+ sub(/.*\|/, "")
+ sub(/"$/, "")
+
+ if ( ! $0 ) next
+
+ if ( $0 !~ "^/" )
+ sub(/^/, item "/")
+
+ print
+ }
+ ' $file
+ )"
+done
+
+#
+# [Optionally] Calculate list of include files
+#
+if [ "$SHOW_INCLUDES" ]; then
+ #
+ # Build list of files in which to search for includes
+ #
+ file_list=$(
+ for file in \
+ $BSDCONFIG \
+ $menu_program_list \
+ $submenu_program_list \
+ $cmd_program_list \
+ ; do
+ [ -e "$file" ] && echo $file
+ done | sort -u
+ )
+
+ #
+ # Build list of includes used by the above files
+ #
+ include_file_list=
+ for file in $file_list; do
+ include_file_list="$include_file_list $(
+ awk -v file="$file" -v item="${file%%/*}" '
+ BEGIN { regex = "^f_include \\$BSDCFG_LIBE/" }
+ ( $0 ~ regex "include/" ) {
+ sub(regex, "")
+ print
+ }
+ ( $0 ~ regex "\\$APP_DIR/include/" ) {
+ sub(regex "\\$APP_DIR", item)
+ print
+ }
+ ' $file
+ )"
+ done
+
+ #
+ # Sort the list of includes and remove duplicate entries
+ #
+ include_file_list=$(
+ for include_file in $include_file_list; do
+ echo "$include_file"
+ done | sort -u
+ )
+
+ #
+ # Search previously-discovered include files for further includes
+ #
+ for file in $include_file_list; do
+ include_file_list="$include_file_list $(
+ awk -v file="$file" -v item="${file%%/*}" '
+ BEGIN { regex = "^f_include \\$BSDCFG_LIBE/" }
+ ( $0 ~ regex "include/" ) {
+ sub(regex, "")
+ print
+ }
+ ( $0 ~ regex "\\$APP_DIR/include/" ) {
+ sub(regex "\\$APP_DIR", item)
+ print
+ }
+ ' $file
+ )"
+ done
+
+ #
+ # Sort the list of includes and remove duplicate entries [again]
+ #
+ include_file_list=$(
+ for include_file in $include_file_list; do
+ echo "$include_file"
+ done | sort -u
+ )
+fi
+
+#
+# Start the directional-graph (digraph) output
+#
+printf 'strict digraph "" { // Empty name to prevent SVG Auto-Tooltip\n'
+label_format="$msg_graph_label_with_command"
+[ "$SHOW_GRAPH_LABEL_DATE" ] &&
+ label_format="$msg_graph_label_with_command_and_date"
+lang="${LANG:-$LC_ALL}"
+printf "\n\tlabel = \"$label_format\"\n" \
+ "${lang:+LANG=${lang%%[$IFS]*} }bsdconfig $pgm${ARGV:+ $ARGV}" \
+ "$( date +"%c %Z" )"
+
+#
+# Print graph-specific properties
+#
+printf '\n\t/*\n\t * Graph setup and orientation\n\t */\n'
+printf '\tlabelloc = top;\t\t// display above label at top of graph\n'
+printf '\trankdir = LR;\t\t// create ranks left-to-right\n'
+printf '\torientation = portrait;\t// default\n'
+printf '\tratio = fill;\t\t// approximate aspect ratio\n'
+printf '\tcenter = 1;\t\t// center drawing on page\n'
+
+#
+# Perform edge-concentration when displaying a lot of information
+#
+# NOTE: This is disabled because dot version 2.28.0 (current) and older have a
+# bug that causes a crash when rankdir = LR and concentrate = true
+#
+# NOTE: Do not re-enable until said bug is fixed in some future revision.
+#
+#[ "$SHOW_INCLUDES" -a "$SHOW_CMDLINE" ] &&
+# printf '\tconcentrate = true;\t// enable edge concentrators\n'
+
+#
+# Print font details for graph/cluster label(s)
+#
+printf '\n\t/*\n\t * Font details for graph/cluster label(s)\n\t */\n'
+printf '\tfontname = "Times-Italic";\n'
+printf '\tfontsize = 14;\n'
+
+#
+# Print default node attributes
+#
+printf '\n\t/*\n\t * Default node attributes\n\t */\n'
+printf '\tnode [\n'
+printf '\t\tfontname = "Times-Roman",\n'
+printf '\t\tfontsize = 12,\n'
+printf '\t\twidth = 2.5, // arbitrary minimum width for all nodes\n'
+printf '\t\tfixedsize, // turn minimum width into exact width\n'
+printf '\t];\n'
+
+#
+# Print top-level item(s)
+#
+printf '\n\t/*\n\t * bsdconfig(8)\n\t */\n'
+shape=circle color=black fillcolor=yellow style=filled
+begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+print_node "bsdconfig" "fontname = \"Times-Bold\"" "fontsize = 16"
+end_nodelist
+
+#
+# Print menus
+#
+printf '\n\t/*\n\t * Menu items\n\t */\n'
+shape=box color=black fillcolor=lightblue style=filled
+begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+for menu_program in $menu_program_list; do
+ print_node "$menu_program" "label = \"${menu_program#*/}\""
+done
+end_nodelist
+
+#
+# Print sub-menus
+#
+printf '\n\t/*\n\t * Sub-menu items\n\t */\n'
+shape=box color=black fillcolor=lightblue style=filled
+begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+for submenu_program in $submenu_program_list; do
+ print_node "$submenu_program" "label = \"${submenu_program#*/}\""
+done
+end_nodelist
+
+#
+# Print menu relationships
+#
+printf '\n\t/*\n\t * Menu item relationships\n\t */\n'
+shape=box color=black fillcolor=lightblue style=filled edge_color=blue
+begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+print_node edge "penwidth = 5.0" "style = bold" "color = $edge_color"
+for menu_program in $menu_program_list; do
+ print_node2 "bsdconfig" "$menu_program"
+done
+end_nodelist
+
+#
+# Print sub-menu relationships
+#
+printf '\n\t/*\n\t * Sub-menu item relationships\n\t */\n'
+shape=box color=black fillcolor=lightblue style=filled edge_color=blue
+begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+# Lock sub-menu headport to the West (unless `-c' was passed)
+[ "$SHOW_CMDLINE" -o ! "$SHOW_INCLUDES" ] && print_node edge "headport = w"
+print_node edge "style = bold" "color = $edge_color"
+for submenu_program in $submenu_program_list; do
+ for menu_program in $menu_program_list; do
+ case "$menu_program" in
+ [0-9][0-9][0-9].*/*) : fall-through ;;
+ *) continue # Not a menu item
+ esac
+
+ # Continue if program directories do not match
+ [ "${menu_program%%/*}" = "${submenu_program%%/*}" ] ||
+ continue
+
+ print_node2 "$menu_program" "$submenu_program"
+ break
+ done
+done
+end_nodelist
+
+#
+# [Optionally] Print include files
+#
+if [ "$SHOW_INCLUDES" ]; then
+ printf '\n\t/*\n\t * Include files\n\t */\n'
+ shape=oval color=black fillcolor=white style=filled
+ begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+ printf '\t\tconstraint = false;\n'
+ for include_file in $include_file_list; do
+ print_node "$include_file" \
+ "label = \"${include_file#*include/}\""
+ done
+ end_nodelist
+fi
+
+#
+# [Optionally] Print f_include() usage/relationships
+#
+if [ "$SHOW_INCLUDES" ]; then
+ printf '\n\t/*\n\t * Include usage\n\t */\n'
+ shape=oval color=black fillcolor=white style=filled edge_color=grey
+ begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+ print_node edge "style = dashed" "color = $edge_color"
+ file_list=$(
+ for file in \
+ $BSDCONFIG \
+ $menu_program_list \
+ $submenu_program_list \
+ $cmd_program_list \
+ $include_file_list \
+ ; do
+ [ -e "$file" ] && echo $file
+ done | sort -u
+ )
+ for file in $file_list; do
+ # Skip binary files and text files that don't use f_include()
+ grep -qlI f_include $file || continue
+
+ awk \
+ -v file="$file" \
+ -v item="${file%%/*}" \
+ -v bsdconfig="$BSDCONFIG" \
+ '
+ BEGIN { regex = "^f_include \\$BSDCFG_LIBE/" }
+ ( $0 ~ regex "include/" ) {
+ sub(regex, "")
+ if ( file == bsdconfig ) sub(".*/", "", file)
+ printf "\t\t\"%s\" -> \"%s\";\n", $0, file
+ }
+ ( $0 ~ regex "\\$APP_DIR/include/" ) {
+ sub(regex "\\$APP_DIR", item)
+ if ( file == bsdconfig ) sub(".*/", "", file)
+ printf "\t\t\"%s\" -> \"%s\";\n", $0, file
+ }
+ ' $file
+ done | sort | awk '
+ BEGIN { found = 0 }
+ {
+ # If already found or no-match... just spew
+ if ( found ) { print; next }
+ if ( $0 !~ /^[[:space:]]*"include\// ) { print; next }
+ printf "\t\tedge [ label = \"\\T\", fontsize = 9 ];\n"
+ print; found = 1
+ }'
+ end_nodelist
+fi
+
+#
+# Print command-line shortcuts
+#
+if [ "$SHOW_CMDLINE" ]; then
+ printf '\n\t/*\n\t * Command-line shortcuts\n\t */\n'
+ shape=parallelogram color=black fillcolor=lightseagreen style=filled
+ begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+ for file in */INDEX; do
+ awk -v item="${file%%/*}" '
+ /^menu_selection="/ {
+ sub(/^.*="/, "")
+ sub(/\|.*/, "")
+ printf "\t\t\"bsdconfig %s\"", $0
+ printf " [ label = \"%s\" ];\n", $0
+ }
+ ' $file
+ done
+ end_nodelist
+fi
+
+#
+# Print command-line shortcut relationships
+#
+if [ "$SHOW_CMDLINE" ]; then
+ printf '\n\t/*\n\t * Command-line shortcut relationships\n\t */\n'
+ shape=box color=black fillcolor=lightseagreen style=filled
+ begin_nodelist "$shape" "$color" "$fillcolor" "$style"
+ print_node edge "headport = w" "weight = 100.0"
+ print_node edge "style = bold" "color = $fillcolor"
+ for file in */INDEX; do
+ awk -v item="${file%%/*}" \
+ -v node_fillcolor="$node_fillcolor" \
+ -v edge_color="$edge_color" \
+ '
+ /^menu_selection="/ {
+ sub(/^.*="/, "")
+ sub(/"$/, "")
+
+ if ( ! $0 ) next
+
+ split($0, menusel, "|")
+ if ( menusel[2] !~ "^/" )
+ sub(/^/, item "/", menusel[2])
+
+ printf "\t\t\"bsdconfig %s\" -> \"%s\";\n",
+ menusel[1], menusel[2]
+ }
+ ' $file
+ done
+ end_nodelist
+fi
+
+#
+# Print clusters
+#
+bgcolor_bsdconfig="lightyellow"
+bgcolor_includes="gray98"
+bgcolor_menuitem="aliceblue"
+bgcolor_shortcuts="honeydew"
+printf '\n\t/*\n\t * Clusters\n\t */\n'
+printf '\tsubgraph "cluster_bsdconfig" {\n'
+printf '\t\tbgcolor = "%s";\n' "$bgcolor_bsdconfig"
+printf '\t\tlabel = "bsdconfig(8)";\n'
+printf '\t\ttooltip = "bsdconfig(8)";\n'
+print_node "bsdconfig"
+if [ "$SHOW_INCLUDES" ]; then
+ printf '\t\tsubgraph "cluster_bsdconfig_includes" {\n'
+ printf '\t\t\tbgcolor = "%s";\n' "$bgcolor_includes"
+ printf '\t\t\tlabel = "%s";\n' "$msg_includes"
+ for include_file in $include_file_list; do
+ case "$include_file" in
+ include/*) printf '\t\t\t"%s";\n' "$include_file";;
+ esac
+ done
+ printf '\t\t};\n'
+fi
+end_nodelist
+for INDEX in */INDEX; do
+ menu_title=
+ menu_help=
+ f_include_lang "$INDEX"
+
+ item="${INDEX%%/*}"
+ printf '\tsubgraph "cluster_%s" {\n' "$item"
+
+ case "$item" in
+ [0-9][0-9][0-9].*) bgcolor="$bgcolor_menuitem";;
+ *) bgcolor="$bgcolor_shortcuts"
+ esac
+ printf '\t\tbgcolor = "%s";\n' "$bgcolor"
+ if [ "$menu_title" ]; then
+ printf '\t\tlabel = "%s\\n\\"%s\\"";\n' "$item" "$menu_title"
+ else
+ printf '\t\tlabel = "%s";\n' "$item"
+ fi
+ printf '\t\ttooltip = "%s";\n' "${menu_help:-$item}"
+
+ program_list=$(
+ for program in \
+ $menu_program_list \
+ $submenu_program_list \
+ $cmd_program_list \
+ ; do
+ echo "$program"
+ done | sort -u
+ )
+ for program in $program_list; do
+ case "$program" in "$item"/*)
+ print_node "$program" "label = \"${program#*/}\""
+ esac
+ done
+
+ if [ "$SHOW_INCLUDES" ]; then
+ item_include_list=
+ [ -d "$item/include" ] &&
+ item_include_list=$( find "$item/include" -type f )
+ item_include_list=$(
+ for item_include in $item_include_list; do
+ for include_file in $include_file_list; do
+ [ "$item_include" = "$include_file" ] ||
+ continue
+ echo "$item_include"; break
+ done
+ done
+ )
+ if [ "$item_include_list" ]; then
+ printf '\t\tsubgraph "cluster_%s_includes" {\n' "$item"
+ printf '\t\t\tbgcolor = "%s";\n' "$bgcolor_includes"
+ printf '\t\t\tlabel = "%s";\n' "$msg_includes"
+ fi
+ for item_include in $item_include_list; do
+ printf '\t\t\t"%s";\n' "$item_include"
+ done
+ [ "$item_include_list" ] && printf '\t\t};\n'
+ fi
+
+ if [ "$SHOW_CMDLINE" ]; then
+ printf '\t\tsubgraph "cluster_%s_shortcuts" {\n' "$item"
+ printf '\t\t\tbgcolor = "%s";\n' "$bgcolor_shortcuts"
+ printf '\t\t\tlabel = "%s";\n' "$msg_shortcuts"
+ awk '/^menu_selection="/ {
+ sub(/^.*="/, "")
+ sub(/\|.*/, "")
+ printf "\t\t\t\"bsdconfig %s\";\n", $0
+ }' "$INDEX"
+ printf '\t\t};\n'
+ fi
+
+ end_nodelist
+done
+
+printf '\n};\n'
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/dot/include/Makefile b/usr.sbin/bsdconfig/dot/include/Makefile
new file mode 100644
index 0000000..9bbdea0
--- /dev/null
+++ b/usr.sbin/bsdconfig/dot/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/dot/include
+FILES= messages.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/dot/include/messages.subr b/usr.sbin/bsdconfig/dot/include/messages.subr
new file mode 100644
index 0000000..527f308
--- /dev/null
+++ b/usr.sbin/bsdconfig/dot/include/messages.subr
@@ -0,0 +1,30 @@
+# Copyright (c) 2012 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$
+
+msg_graph_label_with_command="bsdconfig(8)\\\ndot(1) output generated by \`\`%s''"
+msg_graph_label_with_command_and_date="bsdconfig(8)\\\ndot(1) output generated by \`\`%s'' on\\\n%s"
+msg_includes="Includes"
+msg_shortcuts="Shortcuts"
diff --git a/usr.sbin/bsdconfig/examples/Makefile b/usr.sbin/bsdconfig/examples/Makefile
new file mode 100644
index 0000000..f072350
--- /dev/null
+++ b/usr.sbin/bsdconfig/examples/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${SHAREDIR}/examples/bsdconfig
+FILES= bsdconfigrc
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/examples/bsdconfigrc b/usr.sbin/bsdconfig/examples/bsdconfigrc
new file mode 100644
index 0000000..a863a94
--- /dev/null
+++ b/usr.sbin/bsdconfig/examples/bsdconfigrc
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+# This file allows you to customize the behavior of bsdconfig.
+# Copy it to your $HOME/.bsdconfigrc and edit to suit.
+# defaults are shown.
+
+# debugging aid for development
+# f_dprintf() {
+# echo "$(date):$pgm: $1" >> $HOME/out
+# }
diff --git a/usr.sbin/bsdconfig/include/Makefile b/usr.sbin/bsdconfig/include/Makefile
new file mode 100644
index 0000000..898359a
--- /dev/null
+++ b/usr.sbin/bsdconfig/include/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/include
+FILES= common.subr dialog.subr messages.subr mustberoot.subr \
+ strings.subr sysrc.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/include/common.subr b/usr.sbin/bsdconfig/include/common.subr
new file mode 100644
index 0000000..c724c62
--- /dev/null
+++ b/usr.sbin/bsdconfig/include/common.subr
@@ -0,0 +1,299 @@
+if [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1
+#
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+#
+############################################################ GLOBALS
+
+#
+# Program name
+#
+pgm="${0##*/}"
+
+#
+# Program arguments
+#
+ARGC="$#"
+ARGV="$@"
+
+#
+# Global exit status variables
+#
+SUCCESS=0
+FAILURE=1
+
+############################################################ FUNCTIONS
+
+#
+# This is an empty function by default, to use it, copy
+# /usr/share/examples/bsdconfig/bsdconfigrc to $HOME/.bsdconfigrc
+#
+f_dprintf()
+{
+ : this page intentionally left blank
+}
+
+# f_err $fmt [ $opts ... ]
+#
+# Print a message to stderr (fd=2).
+#
+f_err()
+{
+ printf "$@" >&2
+}
+
+# f_quietly $command [ $arguments ... ]
+#
+# run a command quietly (quell any output to stdout or stderr)
+#
+f_quietly()
+{
+ "$@" > /dev/null 2>&1
+}
+
+# f_have $anything ...
+#
+# A wrapper to the `type' built-in. Returns true if argument is a valid shell
+# built-in, keyword, or externally-tracked binary, otherwise false.
+#
+f_have()
+{
+ f_quietly type "$@"
+}
+
+# f_die [ $status [ $fmt [ $opts ... ]]]
+#
+# Abruptly terminate due to an error optionally displaying a message in a
+# dialog box using printf(1) syntax.
+#
+f_die()
+{
+ local status=$FAILURE
+
+ # If there is at least one argument, take it as the status
+ if [ $# -gt 0 ]; then
+ status=$1
+ shift 1 # status
+ fi
+
+ # If there are still arguments left, pass them to f_show_msg
+ [ $# -gt 0 ] && f_show_msg "$@"
+
+ # Optionally call f_clean_up() function if it exists
+ f_have f_clean_up && f_clean_up
+
+ exit $status
+}
+
+# f_interrupt
+#
+# Interrupt handler.
+#
+f_interrupt()
+{
+ exec 2>&1 # fix sh(1) bug where stderr gets lost within async-trap
+ f_die
+}
+
+# f_show_msg $fmt [ $opts ... ]
+#
+# Display a message in a dialog box using printf(1) syntax.
+#
+f_show_msg()
+{
+ local msg
+ msg=$( printf "$@" )
+
+ #
+ # Use f_dialog_msgbox from dialog.subr if possible, otherwise fall
+ # back to dialog(1) (without options, making it obvious when using
+ # un-aided system dialog).
+ #
+ if f_have f_dialog_msgbox; then
+ f_dialog_msgbox "$msg"
+ else
+ dialog --msgbox "$msg" 0 0
+ fi
+}
+
+# f_include $file
+#
+# Include a shell subroutine file.
+#
+# If the subroutine file exists but returns error status during loading, exit
+# is called and execution is prematurely terminated with the same error status.
+#
+f_include()
+{
+ local file="$1"
+ . "$file" || exit $?
+}
+
+# f_include_lang $file
+#
+# Include a language file. Automatically takes $LANG and $LC_ALL into
+# considerationg when including $file (suffix ".$LC_ALL" or ".$LANG" will
+# automatically by added prior to loading the language file).
+#
+# No error is produced if (a) a language has been requested (by setting either
+# $LANG or $LC_ALL in the environment) and (b) the language file does not
+# exist -- in which case we will fall back to loading $file without-suffix.
+#
+# If the language file exists but returns error status during loading, exit
+# is called and execution is prematurely terminated with the same error status.
+#
+f_include_lang()
+{
+ local file="$1"
+ local lang="${LANG:-$LC_ALL}"
+
+ f_dprintf "lang=[$lang]"
+ if [ -f "$file.$lang" ]; then
+ . "$file.$lang" || exit $?
+ else
+ . "$file" || exit $?
+ fi
+}
+
+# f_usage $file [ $key1 $value1 ... ]
+#
+# Display USAGE file with optional pre-processor macro definitions. The first
+# argument is the template file containing the usage text to be displayed. If
+# $LANG or $LC_ALL (in order of preference, respectively) is set, ".encoding"
+# will automatically be appended as a suffix to the provided $file pathname.
+#
+# When processing $file, output begins at the first line containing that is
+# (a) not a comment, (b) not empty, and (c) is not pure-whitespace. All lines
+# appearing after this first-line are output, including (a) comments (b) empty
+# lines, and (c) lines that are purely whitespace-only.
+#
+# If additional arguments appear after $file, substitutions are made while
+# printing the contents of the USAGE file. The pre-processor macro syntax is in
+# the style of autoconf(1), for example:
+#
+# f_usage $file "FOO" "BAR"
+#
+# Will cause instances of "@FOO@" appearing in $file to be replaced with the
+# text "BAR" before bering printed to the screen.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_usage_awk='
+BEGIN { found = 0 }
+{
+ if ( !found && $0 ~ /^[[:space:]]*($|#)/ ) next
+ found = 1
+ print
+}
+'
+f_usage()
+{
+ local file="$1"
+ local lang="${LANG:-$LC_ALL}"
+
+ f_dprintf "lang=[$lang]"
+
+ shift 1 # file
+
+ local usage
+ if [ -f "$file.$lang" ]; then
+ usage=$( awk "$f_usage_awk" "$file.$lang" ) || exit $FAILURE
+ else
+ usage=$( awk "$f_usage_awk" "$file" ) || exit $FAILURE
+ fi
+
+ while [ $# -gt 0 ]; do
+ local key="$1"
+ export value="$2"
+ usage=$( echo "$usage" | awk \
+ "{ gsub(/@$key@/, ENVIRON[\"value\"]); print }" )
+ shift 2
+ done
+
+ f_err "%s\n" "$usage"
+
+ exit $FAILURE
+}
+
+# f_index_menu_selection $file $pgm
+#
+# Process $file looking for $menu_selection values that correspond to $pgm.
+# This function is for internationalization (i18n) mapping of the on-disk
+# scriptname ($pgm) into the localized language (given language-specific
+# $file). If $LANG or $LC_ALL (in orderder of preference, respectively) is set,
+# ".encoding" will automatically be appended as a suffix to the provided $file
+# pathname.
+#
+# If, within $file, multiple $menu_selection values map to $pgm, only the first
+# one will be returned. If no mapping can be made, the NULL string is returned.
+#
+# If $file does not exist, error status is returned along with the NULL string.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_index_menusel_awk='
+# Variables that should be defined on the invocation line:
+# -v pgm="program_name"
+#
+( $0 ~ "^menu_selection=.*\\|" pgm "\"" ) {
+ sub(/\|.*/, "")
+ sub(/^menu_selection="/, "")
+ print
+ exit
+}
+'
+f_index_menu_selection()
+{
+ local file="$1" pgm="$2"
+ local lang="${LANG:-$LC_ALL}"
+
+ f_dprintf "lang=[$lang]"
+
+ if [ -f "$file.$lang" ]; then
+ awk -v pgm="$pgm" "$f_index_menusel_awk" "$file.$lang" ||
+ exit $FAILURE
+ elif [ -f "$file" ]; then
+ awk -v pgm="$pgm" "$f_index_menusel_awk" "$file" ||
+ exit $FAILURE
+ else
+ return $FAILURE
+ fi
+}
+
+############################################################ MAIN
+
+#
+# Trap signals so we can recover gracefully
+#
+trap 'f_interrupt' SIGINT
+trap 'f_die' SIGTERM SIGPIPE SIGXCPU SIGXFSZ \
+ SIGFPE SIGTRAP SIGABRT SIGSEGV
+trap '' SIGALRM SIGPROF SIGUSR1 SIGUSR2 SIGHUP SIGVTALRM
+
+fi # ! $_COMMON_SUBR
diff --git a/usr.sbin/bsdconfig/include/dialog.subr b/usr.sbin/bsdconfig/include/dialog.subr
new file mode 100644
index 0000000..35c71cb
--- /dev/null
+++ b/usr.sbin/bsdconfig/include/dialog.subr
@@ -0,0 +1,1441 @@
+if [ ! "$_DIALOG_SUBR" ]; then _DIALOG_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/strings.subr
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Default directory to store dialog(1) temporary files
+#
+: ${DIALOG_TMPDIR:="/tmp"}
+
+############################################################ GLOBALS
+
+#
+# Default name of dialog(1) utility
+# NOTE: This is changed to "Xdialog" by the optional `-X' argument
+#
+DIALOG="dialog"
+
+#
+# Default dialog(1) title and backtitle text
+#
+DIALOG_TITLE="$pgm"
+DIALOG_BACKTITLE="bsdconfig"
+
+#
+# Settings used while interacting with dialog(1)
+#
+DIALOG_MENU_TAGS="123456789ABCDEFGHIJKLMNOPQRSTUVWYZabcdefghijklmnopqrstuvwxyz"
+
+#
+# Declare that we are fully-compliant with Xdialog(1) by unset'ing all
+# compatibility settings.
+#
+unset XDIALOG_HIGH_DIALOG_COMPAT
+unset XDIALOG_FORCE_AUTOSIZE
+unset XDIALOG_INFOBOX_TIMEOUT
+
+#
+# Default behavior is to call f_dialog_init() automatically if not already
+# called manually by the time the first f_dialog_*() function is used.
+#
+: ${DIALOG_SELF_INITIALIZE=1}
+
+############################################################ GENERIC FUNCTIONS
+
+# f_dialog_title [$new_title]
+#
+# Set the title of future dialog(1) ($DIALOG_TITLE) or backtitle of Xdialog(1)
+# ($DIALOG_BACKTITLE) invocations. If no arguments are given or the first
+# argument is NULL, the current title is returned.
+#
+# Each time this function is called, a backup of the current values is made
+# allowing a one-time (single-level) restoration of the previous title using the
+# f_dialog_title_restore() function (below).
+#
+f_dialog_title()
+{
+ local new_title="$1"
+
+ if [ "$new_title" ]; then
+ if [ "$USE_XDIALOG" ]; then
+ _DIALOG_BACKTITLE="$DIALOG_BACKTITLE"
+ DIALOG_BACKTITLE="$new_title"
+ else
+ _DIALOG_TITLE="$DIALOG_TITLE"
+ DIALOG_TITLE="$new_title"
+ fi
+ else
+ if [ "$USE_XDIALOG" ]; then
+ echo "$DIALOG_BACKTITLE"
+ else
+ echo "$DIALOG_TITLE"
+ fi
+ fi
+}
+
+# f_dialog_title_restore
+#
+# Restore the previous title set by the last call to f_dialog_title().
+# Restoration is non-recursive and only works to restore the most-recent title.
+#
+f_dialog_title_restore()
+{
+ if [ "$USE_XDIALOG" ]; then
+ DIALOG_BACKTITLE="$_DIALOG_BACKTITLE"
+ else
+ DIALOG_TITLE="$_DIALOG_TITLE"
+ fi
+}
+
+# f_dialog_backtitle [$new_backtitle]
+#
+# Set the backtitle of future dialog(1) ($DIALOG_BACKTITLE) or title of
+# Xdialog(1) ($DIALOG_TITLE) invocations. If no arguments are given or the
+# first argument is NULL, the current backtitle is returned.
+#
+f_dialog_backtitle()
+{
+ local new_backtitle="$1"
+
+ if [ "$new_backtitle" ]; then
+ if [ "$USE_XDIALOG" ]; then
+ _DIALOG_TITLE="$DIALOG_TITLE"
+ DIALOG_TITLE="$new_backtitle"
+ else
+ _DIALOG_BACKTITLE="$DIALOG_BACKTITLE"
+ DIALOG_BACKTITLE="$new_backtitle"
+ fi
+ else
+ if [ "$USE_XDIALOG" ]; then
+ echo "$DIALOG_TITLE"
+ else
+ echo "$DIALOG_BACKTITLE"
+ fi
+ fi
+}
+
+# f_dialog_backtitle_restore
+#
+# Restore the previous backtitle set by the last call to f_dialog_backtitle().
+# Restoration is non-recursive and only works to restore the most-recent
+# backtitle.
+#
+f_dialog_backtitle_restore()
+{
+ if [ "$USE_XDIALOG" ]; then
+ DIALOG_TITLE="$_DIALOG_TITLE"
+ else
+ DIALOG_BACKTITLE="$_DIALOG_BACKTITLE"
+ fi
+}
+
+############################################################ SIZE FUNCTIONS
+
+# f_dialog_infobox_size $title $backtitle $prompt [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--infobox' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, and [optionally] hline returning
+# the optimal width and height for the box (not exceeding the actual terminal
+# width or height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_infobox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
+ local min_width max_size
+
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ max_size=$( stty size ) # usually "24 80"
+ fi
+
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+ local height width=$min_width
+
+ #
+ # Bump width for long titles (but don't exceed terminal width).
+ #
+ n=$(( ${#title} + 4 ))
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ # Add 16.6% width for Xdialog(1)
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
+
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+
+ #
+ # For Xdialog(1), bump width for long backtitles (which appear within
+ # the window; don't exceed maximum width).
+ #
+ if [ "$USE_XDIALOG" ]; then
+ n=$(( ${#btitle} + 4 ))
+ n=$(( $n + $n / 6 ))
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ #
+ # Bump width for long prompts (if not already at maximum width).
+ #
+ if [ $width -lt $max_width ]; then
+ n=$( echo "$prompt" | f_longest_line_length )
+ n=$(( $n + 4 ))
+
+ # Add 16.6% width for Xdialog(1)
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ #
+ # Bump width for long hlines (if not already at maximum width).
+ # NOTE: Though Xdialog(1) supports `--hline', it's not currently used.
+ #
+ if [ ! "$USE_XDIALOG" ]; then
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#hline} + 10 ))
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+ fi
+
+ #
+ # Set height based on number of rows in prompt
+ #
+ height=$( echo "$prompt" | f_number_of_lines )
+ height=$(( $height + 2 ))
+
+ #
+ # For Xdialog(1) bump height if backtitle is enabled (displayed in the
+ # X11 window with a separator line between the backtitle and msg text)
+ #
+ if [ "$USE_XDIALOG" -a "$btitle" ]; then
+ n=$( echo "$btitle" | f_number_of_lines )
+ height=$(( $height + $n + 2 ))
+ fi
+
+ # Make sure height is less than maximum screen size
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_dialog_buttonbox_size $title $backtitle $prompt [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--msgbox' and `--yesno' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, and [optionally] hline returning
+# the optimal width and height for the box (not exceeding the actual terminal
+# width or height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_buttonbox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4"
+ local size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ # Add height to accomodate the buttons
+ height=$(( $height + 2 ))
+
+ # Adjust for clipping with Xdialog(1) on Linux/GTK2
+ [ "$USE_XDIALOG" ] && height=$(( $height + 3 ))
+
+ #
+ # Enforce maximum height regardless
+ #
+ local max_size
+ if [ "$USE_XDIALOG" ]; then
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ max_size=$( stty size ) # usually "24 80"
+ fi
+ local max_height="${max_size%%[$IFS]*}"
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_dialog_inputbox_size $title $backtitle $prompt $init [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--inputbox' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, initial text, and [optionally]
+# hline returning the optimal width and height for the box (not exceeding the
+# actual terminal width and height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_inputbox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" init="$4" hline="$5" n
+ local size="$( f_dialog_buttonbox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ local min_width max_size
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ max_size=$( stty size ) # usually "24 80"
+ fi
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+
+ #
+ # Add height to accomodate the input box
+ #
+ [ ! "$USE_XDIALOG" ] && height=$(( $height + 3 ))
+ [ $height -le $max_height ] || height=$max_height
+
+ #
+ # Bump width for initial text (if not already at maximum width).
+ # NOTE: Something neither dialog(1)/Xdialog(1) do, but worth it!
+ #
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#init} + 7 ))
+
+ # Add 16.6% width for Xdialog(1)
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_xdialog_2inputsbox_size $title $backtitle $prompt \
+# $label1 $init1 $label2 $init2
+#
+# Xdialog(1) does not perform auto-sizing of the width and height of
+# `--2inputsbox' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, label for the first field, initial
+# text for said field, label for the second field, and initial text for said
+# field returning the optimal width and height for the box (not exceeding the
+# actual terminal width and height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# Xdialog(1).
+#
+# Output is in the format of "height width".
+#
+f_xdialog_2inputsbox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3"
+ local label1="$4" init1="$5" label2="$6" init2="$7" n
+ local size="$( f_dialog_inputbox_size \
+ "$title" "$btitle" "$prompt" "$init1" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ local min_width=35
+ local max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+
+ # Add height for first label
+ height=$(( $height + 2 ))
+
+ #
+ # Bump width for first label text (if not already at maximum width).
+ #
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#label1} + 7 ))
+
+ # Add 16.6% width for Xdialog(1)
+ n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Add height for second label
+ height=$(( $height + 2 ))
+
+ #
+ # Bump width for second label text (if not already at maximum width).
+ #
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#label2} + 7 ))
+
+ # Add 16.6% width for Xdialog(1)
+ n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Add height for a second inputbox
+ height=$(( $height + 2 ))
+
+ #
+ # Bump width for second initial text (if not already at maximum width).
+ # NOTE: Something neither dialog(1)/Xdialog(1) do, but worth it!
+ #
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#init2} + 7 ))
+
+ # Add 16.6% width for Xdialog(1)
+ n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_dialog_menu_size $title $backtitle $prompt $hline \
+# $tag1 $item1 $tag2 $item2 ...
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--menu' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, hline and list of tag/item pairs,
+# returning the optimal width and height for the menu (not exceeding the actual
+# terminal width or height).
+#
+# Output is in the format of "height width rows".
+#
+f_dialog_menu_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
+ local min_width min_rows max_size
+
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ min_rows=1
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ min_rows=0
+ max_size=$( stty size ) # usually "24 80"
+ fi
+
+ local max_width="${max_size##*[$IFS]}"
+ local max_height="${max_size%%[$IFS]*}"
+ local box_size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local box_height="${box_size%%[$IFS]*}"
+ local box_width="${box_size##*[$IFS]}"
+ local max_rows=$(( $max_height - 8 ))
+ local height width=$box_width rows=$min_rows
+
+ shift 4 # title/btitle/prompt/hline
+
+ # If there's no prompt, bump the max-rows by 1
+ [ "$prompt" ] || max_rows=$(( $max_rows + 1 ))
+
+ #
+ # The sum total between the longest tag-length and longest item-length
+ # should be used for the menu width (not to exceed terminal width).
+ #
+ # Also, calculate the number of rows (not to exceed terminal height).
+ #
+ local longest_tag=0 longest_item=0
+ while [ $# -ge 2 ]; do
+ local tag="$1" item="$2"
+ shift 2 # tag/item
+
+ [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
+ [ ${#item} -gt $longest_item ] && longest_item=${#item}
+ [ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
+ done
+
+ # Update width
+ n=$(( $longest_tag + $longest_item + 10 ))
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+
+ # Fix rows and set height
+ [ $rows -gt 0 ] || rows=1
+ if [ "$USE_XDIALOG" ]; then
+ height=$(( $rows + $box_height + 7 ))
+ else
+ height=$(( $rows + $box_height + 4 ))
+ fi
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return all three
+ echo "$height $width $rows"
+}
+
+# f_dialog_menu_with_help_size $title $backtitle $prompt $hline \
+# $tag1 $item1 $help1 $tag2 $item2 $help2 ...
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--menu' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, hline and list of tag/item/help
+# triplets, returning the optimal width and height for the menu (not exceeding
+# the actual terminal width or height).
+#
+# Output is in the format of "height width rows".
+#
+f_dialog_menu_with_help_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
+ local min_width min_rows max_size
+
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ min_rows=1
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ min_rows=0
+ max_size=$( stty size ) # usually "24 80"
+ fi
+
+ local max_width="${max_size##*[$IFS]}"
+ local max_height="${max_size%%[$IFS]*}"
+ local box_size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local box_height="${box_size%%[$IFS]*}"
+ local box_width="${box_size##*[$IFS]}"
+ local max_rows=$(( $max_height - 8 ))
+ local height width=$box_width rows=$min_rows
+
+ shift 4 # title/btitle/prompt/hline
+
+ # If there's no prompt, bump the max-rows by 1
+ [ "$prompt" ] || max_rows=$(( $max_rows + 1 ))
+
+ #
+ # The sum total between the longest tag-length and longest item-length
+ # should be used for the menu width (not to exceed terminal width).
+ #
+ # Also, calculate the number of rows (not to exceed terminal height).
+ #
+ # Also, calculate the longest help while we're here. This will be used
+ # to influence the width of the menu if (and only-if) using Xdialog(1).
+ #
+ local longest_tag=0 longest_item=0 longest_help=0
+ while [ $# -ge 3 ]; do
+ local tag="$1" item="$2" help="$3"
+ shift 3 # tag/item/help
+
+ [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
+ [ ${#item} -gt $longest_item ] && longest_item=${#item}
+ [ ${#help} -gt $longest_help ] && longest_help=${#help}
+ [ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
+ done
+
+ # Update width
+ n=$(( $longest_tag + $longest_item + 10 ))
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+
+ # Update width for help text if using Xdialog(1)
+ if [ "$USE_XDIALOG" ]; then
+ n=$(( $longest_help + 10 ))
+ n=$(( $n + $n / 6 )) # +16.6%
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Fix rows and set height
+ [ $rows -gt 0 ] || rows=1
+ if [ "$USE_XDIALOG" ]; then
+ height=$(( $rows + $box_height + 8 ))
+ else
+ height=$(( $rows + $box_height + 4 ))
+ fi
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return all three
+ echo "$height $width $rows"
+}
+
+# f_dialog_radiolist_size $title $backtitle $prompt $hline \
+# $tag1 $item1 $status1 $tag2 $item2 $status2 ...
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--radiolist' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, hline and list of tag/item/status
+# triplets, returning the optimal width and height for the radiolist (not
+# exceeding the actual terminal width or height).
+#
+# Output is in the format of "height width rows".
+#
+f_dialog_radiolist_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
+ local min_width min_rows max_size
+
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ min_rows=1
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ min_rows=0
+ max_size=$( stty size ) # usually "24 80"
+ fi
+
+ local max_width="${max_size##*[$IFS]}"
+ local max_height="${max_size%%[$IFS]*}"
+ local box_size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local box_height="${box_size%%[$IFS]*}"
+ local box_width="${box_size##*[$IFS]}"
+ local max_rows=$(( $max_height - 8 ))
+ local height width=$box_width rows=$min_rows
+
+ shift 4 # title/btitle/prompt/hline
+
+ #
+ # The sum total between the longest tag-length, longest item-length,
+ # and radio-button width should be used for the menu width (not to
+ # exceed terminal width).
+ #
+ # Also, calculate the number of rows (not to exceed terminal height).
+ #
+ local longest_tag=0 longest_item=0
+ while [ $# -ge 2 ]; do
+ local tag="$1" item="$2" help="$3"
+ shift 3 # tag/item/status
+
+ [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
+ [ ${#item} -gt $longest_item ] && longest_item=${#item}
+ [ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
+ done
+
+ # Update width
+ n=$(( $longest_tag + $longest_item + 13 ))
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+
+ # Fix rows and set height
+ [ $rows -gt 0 ] || rows=1
+ if [ "$USE_XDIALOG" ]; then
+ height=$(( $rows + $box_height + 7 ))
+ else
+ height=$(( $rows + $box_height + 4 ))
+ fi
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return all three
+ echo "$height $width $rows"
+}
+
+# f_dialog_calendar_size $title $backtitle $prompt [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--calendar' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, and [optionally] hline returning
+# the optimal width and height for the box (not exceeding the actual terminal
+# width and height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_calendar_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n
+ local size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ local min_width min_height max_size
+ if [ "$USE_XDIALOG" ]; then
+ min_height=15
+ min_width=55
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_height=0
+ min_width=40
+ max_size=$( stty size ) # usually "24 80"
+ fi
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+
+ #
+ # Enforce the minimum width for displaying the calendar
+ #
+ [ $width -ge $min_width ] || width=$min_width
+
+ #
+ # When using dialog(1), the calendar box is unique from other dialog(1)
+ # boxes in-that the height passed should not accomodate the 15-lines
+ # required to display the calendar. This does not apply to Xdialog(1).
+ #
+ # When using Xdialog(1), the height must accomodate the 15-lines
+ # required to display the calendar.
+ #
+ # NOTE: Also under dialog(1), because we can't predict whether the user
+ # has disabled shadow's in their `$HOME/.dialogrc' file, we'll subtract
+ # 16 rather than 15. This does not apply to Xdialog(1).
+ #
+ max_height=$(( $max_height - 16 ))
+ height=$( echo "$prompt" | f_number_of_lines )
+ if [ "$USE_XDIALOG" ]; then
+ # Add height to accomodate for the embedded calendar widget
+ height=$(( $height + $min_height - 1 ))
+
+ # Also, bump height if backtitle is enabled
+ if [ "$btitle" ]; then
+ local n="$( echo "$btitle" | f_number_of_lines )"
+ height=$(( $height + $n + 2 ))
+ fi
+ else
+ [ "$prompt" ] && height=$(( $height + 1 ))
+ fi
+ [ $height -le $max_height ] || height=$max_height
+
+ #
+ # The calendar box refuses to display if too large.
+ #
+ max_width=$(( $max_width - 2 ))
+ [ $width -le $max_width ] || width=$max_width
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_dialog_timebox_size $title $backtitle $prompt [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--timebox' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, and [optionally] hline returning
+# the optimal width and height for the box (not exceeding the actual terminal
+# width and height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_timebox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n
+ local size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ local min_width min_height max_size
+ if [ "$USE_XDIALOG" ]; then
+ min_width=40
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_height=0
+ min_width=20
+ max_size=$( stty size ) # usually "24 80"
+ fi
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+
+ #
+ # Enforce the minimum width for displaying the timebox
+ #
+ [ $width -ge $min_width ] || width=$min_width
+
+ #
+ # When using dialog(1), the timebox box is unique from other dialog(1)
+ # boxes in-that the height passed should not accomodate the 6-lines
+ # required to display the timebox. This does not apply to Xdialog(1).
+ #
+ # When using Xdialog(1), the height seems to have no effect. All values
+ # provide the same results.
+ #
+ # NOTE: Also under dialog(1), because we can't predict whether the user
+ # has disabled shadow's in their `$HOME/.dialogrc' file, we'll subtract
+ # 7 rather than 6. This does not apply to Xdialog(1).
+ #
+ if [ "$USE_XDIALOG" ]; then
+ height=0 # Autosize; all values produce same results
+ else
+ max_height=$(( $max_height - 7 ))
+ height=$( echo "$prompt" | f_number_of_lines )
+ height=$(( $height + 1 ))
+ [ $height -le $max_height ] || height=$max_height
+ [ "$prompt" ] && height=$(( $height + 1 ))
+ fi
+
+ #
+ # The timebox box refuses to display if too large.
+ #
+ max_width=$(( $max_width - 2 ))
+ [ $width -le $max_width ] || width=$max_width
+
+ # Return both
+ echo "$height $width"
+}
+
+############################################################ CLEAR FUNCTIONS
+
+# f_dialog_clear
+#
+# Clears any/all previous dialog(1) displays.
+#
+f_dialog_clear()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ $DIALOG --clear
+}
+
+############################################################ INFO FUNCTIONS
+
+# f_dialog_info $info_text ...
+#
+# Throw up a dialog(1) infobox. The infobox remains until another dialog is
+# displayed or `dialog --clear' (or dialog_clear) is called.
+#
+f_dialog_info()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local info_text="$*"
+ local size="$( f_dialog_infobox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$info_text" )"
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ ${USE_XDIALOG:+--ignore-eof} \
+ ${USE_XDIALOG:+--no-buttons} \
+ --infobox \"\$info_text\" $size
+}
+
+# f_xdialog_info $info_text ...
+#
+# Throw up an Xdialog(1) infobox and do not dismiss it until stdin produces
+# EOF. This implies that you must execute this either as an rvalue to a pipe,
+# lvalue to indirection or in a sub-shell that provides data on stdin.
+#
+f_xdialog_info()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local info_text="$*"
+ local size="$( f_dialog_infobox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$info_text" )"
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --no-close --no-buttons \
+ --infobox \"\$info_text\" $size \
+ -1 # timeout of -1 means abort when EOF on stdin
+}
+
+############################################################ MSGBOX FUNCTIONS
+
+# f_dialog_msgbox $msg_text ...
+#
+# Throw up a dialog(1) msgbox. The msgbox remains until the user presses ENTER
+# or ESC, acknowledging the modal dialog.
+#
+# If the user presses ENTER, the exit status is zero (success), otherwise if
+# the user presses ESC the exit status is 255.
+#
+f_dialog_msgbox()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local msg_text="$*"
+ local size="$( f_dialog_buttonbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg_text" )"
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$msg_text\" $size
+}
+
+############################################################ YESNO FUNCTIONS
+
+# f_dialog_yesno $msg_text ...
+#
+# Display a dialog(1) Yes/No prompt to allow the user to make some decision.
+# The yesno prompt remains until the user presses ENTER or ESC, acknowledging
+# the modal dialog.
+#
+# If the user chooses YES the exit status is zero, or chooses NO the exit
+# status is one, or presses ESC the exit status is 255.
+#
+f_dialog_yesno()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local msg_text="$*"
+ local hline="$hline_arrows_tab_enter"
+ local size="$( f_dialog_buttonbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg_text" \
+ "$hline" )"
+
+ if [ "$USE_XDIALOG" ]; then
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_yes\" \
+ --cancel-label \"\$msg_no\" \
+ --yesno \"\$msg_text\" $size
+ else
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --yes-label \"\$msg_yes\" \
+ --no-label \"\$msg_no\" \
+ --yesno \"\$msg_text\" $size
+ fi
+}
+
+# f_dialog_noyes $msg_text ...
+#
+# Display a dialog(1) No/Yes prompt to allow the user to make some decision.
+# The noyes prompt remains until the user presses ENTER or ESC, acknowledging
+# the modal dialog.
+#
+# If the user chooses YES the exit status is zero, or chooses NO the exit
+# status is one, or presses ESC the exit status is 255.
+#
+# NOTE: This is just like the f_dialog_yesno function except "No" is default.
+#
+f_dialog_noyes()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local msg_text="$*"
+ local hline="$hline_arrows_tab_enter"
+ local size="$( f_dialog_buttonbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg_text" \
+ "$hline" )"
+
+ if [ "$USE_XDIALOG" ]; then
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --default-no \
+ --ok-label \"\$msg_yes\" \
+ --cancel-label \"\$msg_no\" \
+ --yesno \"\$msg_text\" $size
+ else
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --defaultno \
+ --yes-label \"\$msg_yes\" \
+ --no-label \"\$msg_no\" \
+ --yesno \"\$msg_text\" $size
+ fi
+}
+
+############################################################ INPUT FUNCTIONS
+
+# f_dialog_inputstr
+#
+# Obtain the inputstr entered by the user from the most recently displayed
+# dialog(1) inputbox and clean up any temporary files.
+#
+f_dialog_inputstr()
+{
+ local tmpfile="$DIALOG_TMPDIR/dialog.inputbox.$$"
+
+ [ -f "$tmpfile" ] || return $FAILURE
+
+ # Skip warnings and trim leading/trailing whitespace from user input
+ awk '
+ BEGIN { found = 0 }
+ {
+ if ( ! found )
+ {
+ if ( $0 ~ /^$/ ) next
+ if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next
+ found = 1
+ }
+ sub(/^[[:space:]]*/, "")
+ sub(/[[:space:]]*$/, "")
+ print
+ }
+ ' "$tmpfile" 2> /dev/null
+ f_quietly rm -f "$tmpfile"
+
+ return $SUCCESS
+}
+
+############################################################ MENU FUNCTIONS
+
+# f_dialog_menutag
+#
+# Obtain the menutag chosen by the user from the most recently displayed
+# dialog(1) menu and clean up any temporary files.
+#
+f_dialog_menutag()
+{
+ local tmpfile="$DIALOG_TMPDIR/dialog.menu.$$"
+
+ [ -f "$tmpfile" ] || return $FAILURE
+
+ awk '
+ BEGIN { found = 0 }
+ {
+ if ( found ) # ... just spew
+ {
+ print
+ next
+ }
+ if ( $0 ~ /^$/ ) next
+ if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next
+ found = 1
+ print
+ }
+ ' "$tmpfile" 2> /dev/null
+ f_quietly rm -f "$tmpfile"
+
+ return $SUCCESS
+}
+
+# f_dialog_menutag2item $tag_chosen $tag1 $item1 $tag2 $item2 ...
+#
+# To use the `--menu' option of dialog(1) you must pass an ordered list of
+# tag/item pairs on the command-line. When the user selects a menu option the
+# tag for that item is printed to stderr.
+#
+# This function allows you to dereference the tag chosen by the user back into
+# the item associated with said tag.
+#
+# Pass the tag chosen by the user as the first argument, followed by the
+# ordered list of tag/item pairs (HINT: use the same tag/item list as was
+# passed to dialog(1) for consistency).
+#
+# If the tag cannot be found, NULL is returned.
+#
+f_dialog_menutag2item()
+{
+ local tag="$1" tagn item
+ shift 1 # tag
+
+ while [ $# -gt 0 ]; do
+ tagn="$1"
+ item="$2"
+ shift 2 # tagn/item
+
+ if [ "$tag" = "$tagn" ]; then
+ echo "$item"
+ return $SUCCESS
+ fi
+ done
+ return $FAILURE
+}
+
+# f_dialog_menutag2item_with_help $tag_chosen $tag1 $item1 $help1 \
+# $tag2 $item2 $help2 ...
+#
+# To use the `--menu' option of dialog(1) with the `--item-help' option, you
+# must pass an ordered list of tag/item/help triplets on the command-line. When
+# the user selects a menu option the tag for that item is printed to stderr.
+#
+# This function allows you to dereference the tag chosen by the user back into
+# the item associated with said tag (help is discarded/ignored).
+#
+# Pass the tag chosen by the user as the first argument, followed by the
+# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
+# as was passed to dialog(1) for consistency).
+#
+# If the tag cannot be found, NULL is returned.
+#
+f_dialog_menutag2item_with_help()
+{
+ local tag="$1" tagn item
+ shift 1 # tag
+
+ while [ $# -gt 0 ]; do
+ tagn="$1"
+ item="$2"
+ shift 3 # tagn/item/help
+
+ if [ "$tag" = "$tagn" ]; then
+ echo "$item"
+ return $SUCCESS
+ fi
+ done
+ return $FAILURE
+}
+
+# f_dialog_menutag2index $tag_chosen $tag1 $item1 $tag2 $item2 ...
+#
+# To use the `--menu' option of dialog(1) you must pass an ordered list of
+# tag/item pairs on the command-line. When the user selects a menu option the
+# tag for that item is printed to stderr.
+#
+# This function allows you to dereference the tag chosen by the user back into
+# the index associated with said tag. The index is the one-based tag/item pair
+# array position within the ordered list of tag/item pairs passed to dialog(1).
+#
+# Pass the tag chosen by the user as the first argument, followed by the
+# ordered list of tag/item pairs (HINT: use the same tag/item list as was
+# passed to dialog(1) for consistency).
+#
+# If the tag cannot be found, NULL is returned.
+#
+f_dialog_menutag2index()
+{
+ local tag="$1" tagn n=1
+ shift 1 # tag
+
+ while [ $# -gt 0 ]; do
+ tagn="$1"
+ shift 2 # tagn/item
+
+ if [ "$tag" = "$tagn" ]; then
+ echo $n
+ return $SUCCESS
+ fi
+ n=$(( $n + 1 ))
+ done
+ return $FAILURE
+}
+
+# f_dialog_menutag2index_with_help $tag_chosen $tag1 $item1 $help1 \
+# $tag2 $item2 $help2 ...
+#
+# To use the `--menu' option of dialog(1) with the `--item-help' option, you
+# must pass an ordered list of tag/item/help triplets on the command-line. When
+# the user selects a menu option the tag for that item is printed to stderr.
+#
+# This function allows you to dereference the tag chosen by the user back into
+# the index associated with said tag. The index is the one-based tag/item/help
+# triplet array position within the ordered list of tag/item/help triplets
+# passed to dialog(1).
+#
+# Pass the tag chosen by the user as the first argument, followed by the
+# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
+# as was passed to dialog(1) for consistency).
+#
+# If the tag cannot be found, NULL is returned.
+#
+f_dialog_menutag2index_with_help()
+{
+ local tag="$1" tagn n=1
+ shift 1 # tag
+
+ while [ $# -gt 0 ]; do
+ tagn="$1"
+ shift 3 # tagn/item/help
+
+ if [ "$tag" = "$tagn" ]; then
+ echo $n
+ return $SUCCESS
+ fi
+ n=$(( $n + 1 ))
+ done
+ return $FAILURE
+}
+
+############################################################ INIT FUNCTIONS
+
+# f_dialog_init
+#
+# Initialize (or re-initialize) the dialog module after setting/changing any
+# of the following environment variables:
+#
+# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate
+# that Xdialog(1) should be used instead of dialog(1).
+#
+# SECURE Either NULL or Non-NULL. If given a value will indicate
+# that (while running as root) sudo(8) authentication is
+# required to proceed.
+#
+f_dialog_init()
+{
+ DIALOG_SELF_INITIALIZE=
+
+ #
+ # Process stored command-line arguments
+ #
+ SECURE=$( set -- "$ARGV"
+ while getopts S flag > /dev/null; do
+ case "$flag" in
+ S) echo 1;;
+ \?) continue;;
+ esac
+ done
+ )
+ USE_XDIALOG=$( set -- "$ARGV"
+ while getopts SX flag > /dev/null; do
+ case "$flag" in
+ S|X) echo 1;;
+ \?) continue;;
+ esac
+ done
+ )
+
+ #
+ # Process `-X' command-line option
+ #
+ [ "$USE_XDIALOG" ] && DIALOG=Xdialog
+
+ #
+ # Sanity check, or die gracefully
+ #
+ if ! f_have $DIALOG; then
+ unset USE_XDIALOG
+ failed_dialog="$DIALOG"
+ DIALOG=dialog
+ f_die 1 "$msg_no_such_file_or_directory" "$pgm" "$failed_dialog"
+ fi
+
+ #
+ # If we're already running as root but we got there by way of sudo(8)
+ # and we have X11, we should merge the xauth(1) credentials from our
+ # original user.
+ #
+ if [ "$USE_XDIALOG" ] &&
+ [ "$( id -u )" = "0" ] &&
+ [ "$SUDO_USER" -a "$DISPLAY" ]
+ then
+ if ! f_have xauth; then
+ # Die gracefully, as we [likely] can't use Xdialog(1)
+ unset USE_XDIALOG
+ DIALOG=dialog
+ f_die 1 "$msg_no_such_file_or_directory" "$pgm" "xauth"
+ fi
+ HOSTNAME=$(hostname)
+ displaynum="${DISPLAY#*:}"
+ eval xauth -if \~$SUDO_USER/.Xauthority extract - \
+ \"\$HOSTNAME/unix:\$displaynum\" \
+ \"\$HOSTNAME:\$displaynum\" | sudo sh -c 'xauth -ivf \
+ ~root/.Xauthority merge - > /dev/null 2>&1'
+ fi
+
+ #
+ # Probe Xdialog(1) for maximum height/width constraints, or die
+ # gracefully
+ #
+ if [ "$USE_XDIALOG" ]; then
+ if ! maxsize=$( LANG= LC_ALL= $DIALOG --print-maxsize 2>&1 )
+ then
+ # Xdialog(1) failed, fall back to dialog(1)
+ unset USE_XDIALOG
+ size=$( f_dialog_buttonbox_size "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$maxsize" "" )
+ eval dialog \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$maxsize\" $size
+ exit $FAILURE
+ fi
+
+ XDIALOG_MAXSIZE=$(
+ set -- ${maxsize##*:}
+
+ height=${1%,}
+ width=$2
+
+ echo $height $width
+ )
+ unset maxsize
+ fi
+
+ #
+ # If using Xdialog(1), swap DIALOG_TITLE with DIALOG_BACKTITLE.
+ # The reason for this is because many dialog(1) applications use
+ # --backtitle for the program name (which is better suited as
+ # --title with Xdialog(1)).
+ #
+ if [ "$USE_XDIALOG" ]; then
+ _DIALOG_TITLE="$DIALOG_TITLE"
+ DIALOG_TITLE="$DIALOG_BACKTITLE"
+ DIALOG_BACKTITLE="$_DIALOG_TITLE"
+ unset _DIALOG_TITLE
+ fi
+}
+
+############################################################ CLEAN-UP FUNCTIONS
+
+# f_clean_up
+#
+# Clean-up routines (run when script exits or is killed).
+#
+f_clean_up()
+{
+ f_quietly rm -f "$DIALOG_TMPDIR"/dialog.*.$$
+}
+
+############################################################ MAIN
+
+#
+# Trap signals so we can recover gracefully
+#
+trap 'f_clean_up' EXIT
+
+fi # ! $_DIALOG_SUBR
diff --git a/usr.sbin/bsdconfig/include/messages.subr b/usr.sbin/bsdconfig/include/messages.subr
new file mode 100644
index 0000000..282d936
--- /dev/null
+++ b/usr.sbin/bsdconfig/include/messages.subr
@@ -0,0 +1,56 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+field_username="Username:"
+field_password="Password:"
+hline_alnum_punc_tab_enter="Use alpha-numeric, punctuation, TAB or ENTER"
+hline_arrows_tab_enter="Press arrows, TAB or ENTER"
+msg_cancel="Cancel"
+msg_cannot_create_permission_denied="%s: cannot create %s: Permission denied"
+msg_directory_not_found="%s: Directory not found."
+msg_exit="Exit"
+msg_exit_bsdconfig="Exit bsdconfig"
+msg_help_text="This menu allows you to configure your system after the installation\nprocess is complete. At the minimum, you should probably set the root\npassword and the system time zone.\n\nFor extra goodies like bash, emacs, firefox, etc., you should look at the\n'Packages' item in this menu.\n\nFor setting the timezone after the system is installed, use the 'Time\nZone' item in this menu.\n\nFor more information on the overall general system configuration, see the\n/etc/rc.conf and /etc/defaults/rc.conf files. (Note: to inhibit displaying\nof this message, create an empty file: \$HOME/.bsdconfigrc or copy it from\n/usr/share/examples/bsdconfig/bsdconfigrc)"
+msg_main_menu="Main Menu"
+msg_menu_text="If you've already installed FreeBSD, you may use\nthis menu to customize it somewhat to suit your\nparticular configuration. Most importantly, you\ncan use the Packages utility to load extra '3rd\nparty' software not provided in the base\ndistributions."
+msg_must_be_root_to_execute="%s: must be root to execute"
+msg_nfailed_attempts="%u incorrect password attempts"
+msg_no="No"
+msg_no_such_file_or_directory="%s: %s: No such file or directory"
+msg_no_username="No username provided!"
+msg_not_found="not found"
+msg_ok="OK"
+msg_permission_denied="%s: %s: permission denied"
+msg_please_enter_password="Please enter your password for sudo(8):"
+msg_please_enter_username_password="Please enter a username and password for sudo(8):"
+msg_previous_syntax_errors="%s: Not overwriting \`%s' due to previous syntax errors"
+msg_secure_mode_requires_x11="Secure-mode requires X11 (use \`-X')!"
+msg_secure_mode_requires_root="Secure-mode requires root-access!"
+msg_sorry_try_again="Sorry, try again."
+msg_unknown_user="Unknown user: %s"
+msg_user_disallowed="User disallowed: %s"
+msg_yes="Yes"
diff --git a/usr.sbin/bsdconfig/include/mustberoot.subr b/usr.sbin/bsdconfig/include/mustberoot.subr
new file mode 100644
index 0000000..c646530
--- /dev/null
+++ b/usr.sbin/bsdconfig/include/mustberoot.subr
@@ -0,0 +1,360 @@
+if [ ! "$_MUSTBEROOT_SUBR" ]; then _MUSTBEROOT_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ CONFIGURATION
+# NOTE: These are not able to be overridden/inherited for security purposes.
+
+#
+# Number of tries a user gets to enter his/her password before we log the
+# sudo(8) failure and exit.
+#
+PASSWD_TRIES=3
+
+#
+# While in SECURE mode, should authentication as `root' be allowed? Set to
+# non-NULL to enable authentication as `root', otherwise disabled.
+#
+# WARNING:
+# Unless using a custom sudo(8) configuration, user `root' should not be
+# allowed because no password is required to become `root' when already `root'
+# and therefore, any value entered as password will work.
+#
+SECURE_ALLOW_ROOT=
+
+#
+# While in SECURE mode, should we divulge (through error message) when the
+# requested authentication user does not exist? Set to non-NULL to enable,
+# otherwise a non-existent user is treated like an invalid password.
+#
+SECURE_DIVULGE_UNKNOWN_USER=
+
+############################################################ FUNCTIONS
+
+# f_become_root_via_sudo
+#
+# If not running as root, prompt for sudo(8) credentials to become root.
+# Re-execution of the current program via sudo is automatically handled.
+#
+# The following environment variables effect functionality:
+#
+# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate
+# that Xdialog(1) should be used instead of dialog(1).
+#
+f_become_root_via_sudo()
+{
+ local msg hline size
+
+ [ "$( id -u )" = "0" ] && return $SUCCESS
+
+ f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm"
+
+ #
+ # Check sudo(8) access before prompting for password.
+ #
+ :| sudo -S -v 2> /dev/null
+ if [ $? -ne $SUCCESS ]; then
+ #
+ # sudo(8) access denied. Prompt for their password.
+ #
+ msg="$msg_please_enter_password"
+ hline="$hline_alnum_punc_tab_enter"
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+
+ #
+ # Continue prompting until they either Cancel, succeed
+ # or exceed the number of allowed failures.
+ #
+ local password nfailures=0 retval
+ while [ $nfailures -lt $PASSWD_TRIES ]; do
+ if [ "$USE_XDIALOG" ]; then
+ password=$( $DIALOG \
+ --title "$DIALOG_TITLE" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --password --inputbox "$msg" $size \
+ 2>&1 > /dev/null )
+ retval=$?
+
+ # Catch X11-related errors
+ [ $retval -eq 255 ] &&
+ f_die $retval "$password"
+ else
+ $DIALOG \
+ --title "$DIALOG_TITLE" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --insecure \
+ --passwordbox "$msg" $size \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+ retval=$?
+ password=$( f_dialog_inputstr )
+ fi
+
+ # Exit if the user cancelled.
+ [ $retval -eq $SUCCESS ] || exit $retval
+
+ #
+ # Validate sudo(8) credentials
+ #
+ sudo -S -v 2> /dev/null <<-EOF
+ $password
+ EOF
+ retval=$?
+ unset password # scrub memory
+ if [ $retval -eq $SUCCESS ]; then
+ # Access granted...
+ break
+ else
+ # Access denied...
+ nfailures=$(( $nfailures + 1 ))
+
+ # introduce a short delay
+ if [ $nfailures -lt $PASSWD_TRIES ]; then
+ f_dialog_info "$msg_sorry_try_again"
+ sleep 1
+ fi
+ fi
+ done
+
+ #
+ # If user exhausted number of allowed password tries, log
+ # the security event and exit immediately.
+ #
+ if [ $nfailures -ge $PASSWD_TRIES ]; then
+ msg=$( printf "$msg_nfailed_attempts" "$nfailures" )
+ logger -p auth.notice -t sudo " " \
+ "$USER : $msg" \
+ "; TTY=$(tty)" \
+ "; PWD=$PWD" \
+ "; USER=root" \
+ "; COMMAND=$0"
+ f_die 1 "sudo: $msg"
+ fi
+ fi
+
+ # Use xauth(1) to grant root the ability to use this X11/SSH session
+ if [ "$USE_XDIALOG" -a "$SSH_CONNECTION" -a "$DISPLAY" ]; then
+ f_have xauth || f_die 1 \
+ "$msg_no_such_file_or_directory" "$pgm" "xauth"
+ local HOSTNAME displaynum
+ HOSTNAME=$(hostname)
+ displaynum="${DISPLAY#*:}"
+ xauth -f ~/.Xauthority extract - $HOSTNAME/unix:$displaynum \
+ $HOSTNAME:$displaynum | sudo sh -c 'xauth -ivf \
+ ~root/.Xauthority merge - > /dev/null 2>&1'
+ fi
+
+ # Re-execute ourselves with sudo(8)
+ if [ $ARGC -gt 0 ]; then
+ exec sudo "$0" $ARGV
+ else
+ exec sudo "$0"
+ fi
+ exit $? # Never reached unless error
+}
+
+# f_authenticate_some_user
+#
+# Only used if running as root and requires X11 (see USE_XDIALOG below).
+# Prompts the user to enter a username and password to be authenticated via
+# sudo(8) to proceed.
+#
+# The following environment variables effect functionality:
+#
+# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate
+# that Xdialog(1) should be used instead of dialog(1).
+#
+f_authenticate_some_user()
+{
+ local msg hline size width height
+
+ f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm"
+
+ #
+ # Secure-mode has been requested.
+ #
+
+ [ "$USE_XDIALOG" ] || f_die 1 "$msg_secure_mode_requires_x11"
+ [ "$(id -u)" = "0" ] || f_die 1 "$msg_secure_mode_requires_root"
+
+ #
+ # Prompt for sudo(8) credentials.
+ #
+
+ msg="$msg_please_enter_username_password"
+ hline="$hline_alnum_punc_tab_enter"
+ size=$( f_xdialog_2inputsbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$field_username" "" \
+ "$field_password" "" )
+ width="${size##*[$IFS]}"
+ height="${size%%[$IFS]*}"
+ height=$(( $height + 2 )) # Add height for --password
+
+ #
+ # Continue prompting until they either Cancel, succeed or exceed the
+ # number of allowed failures.
+ #
+ local user_pass nfailures=0 retval
+ while [ $nfailures -lt $PASSWD_TRIES ]; do
+ user_pass=$( $DIALOG \
+ --title "$DIALOG_TITLE" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --password --2inputsbox "$msg" \
+ $height $width \
+ "$field_username" "" \
+ "$field_password" "" \
+ 2>&1 > /dev/null )
+ retval=$?
+
+ # Catch X11-related errors
+ [ $retval -eq 255 ] && f_die $retval "$user_pass"
+
+ # Exit if the user cancelled.
+ [ $retval -eq $SUCCESS ] || exit $retval
+
+ #
+ # Make sure the user exists and is non-root
+ #
+ local user password
+ user="${user_pass%%/*}"
+ password="${user_pass#*/}"
+ unset user_pass # scrub memory
+ if [ ! "$user" ]; then
+ nfailures=$(( $nfailures + 1 ))
+ f_dialog_msgbox "$msg_no_username"
+ continue
+ fi
+ if [ ! "$SECURE_ALLOW_ROOT" ]; then
+ case "$user" in
+ root|toor)
+ nfailures=$(( $nfailures + 1 ))
+ f_dialog_msgbox "$( printf \
+ "$msg_user_disallowed" "$user" )"
+ continue
+ esac
+ fi
+ if ! f_quietly id "$user"; then
+ nfailures=$(( $nfailures + 1 ))
+ if [ "$SECURE_DIVULGE_UNKNOWN_USER" ]; then
+ f_dialog_msgbox "$( printf \
+ "$msg_unknown_user" "$user" )"
+ elif [ $nfailures -lt $PASSWD_TRIES ]; then
+ f_dialog_info "$msg_sorry_try_again"
+ sleep 1
+ fi
+ continue
+ fi
+
+ #
+ # Validate sudo(8) credentials for given user
+ #
+ su -m "$user" <<-EOF
+ sh <<EOS
+ sudo -k
+ sudo -S -v 2> /dev/null <<EOP
+ $password
+ EOP
+ EOS
+ EOF
+ retval=$?
+ unset user
+ unset password # scrub memory
+
+ if [ $retval -eq $SUCCESS ]; then
+ # Access granted...
+ break
+ else
+ # Access denied...
+ nfailures=$(( $nfailures + 1 ))
+
+ # introduce a short delay
+ if [ $nfailures -lt $PASSWD_TRIES ]; then
+ f_dialog_info "$msg_sorry_try_again"
+ sleep 1
+ fi
+ fi
+ done
+
+ #
+ # If user exhausted number of allowed password tries, log
+ # the security event and exit immediately.
+ #
+ if [ $nfailures -ge $PASSWD_TRIES ]; then
+ msg=$( printf "$msg_nfailed_attempts" "$nfailures" )
+ logger -p auth.notice -t sudo " " \
+ "${SUDO_USER:-$USER} : $msg" \
+ "; TTY=$(tty)" \
+ "; PWD=$PWD" \
+ "; USER=root" \
+ "; COMMAND=$0"
+ f_die 1 "sudo: $message"
+ fi
+}
+
+# f_mustberoot_init
+#
+# If not already root, make the switch to root by re-executing ourselves via
+# sudo(8) using user-supplied credentials.
+#
+# The following environment variables effect functionality:
+#
+# SECURE Either NULL or Non-NULL. If given a value will indicate
+# that (while running as root) sudo(8) authentication is
+# required to proceed.
+#
+f_mustberoot_init()
+{
+ if [ "$(id -u)" != "0" -a ! "$SECURE" ]; then
+ f_become_root_via_sudo
+ elif [ "$SECURE" ]; then
+ f_authenticate_some_user
+ fi
+}
+
+fi # ! $_MUSTBEROOT_SUBR
diff --git a/usr.sbin/bsdconfig/include/strings.subr b/usr.sbin/bsdconfig/include/strings.subr
new file mode 100644
index 0000000..1a330ad
--- /dev/null
+++ b/usr.sbin/bsdconfig/include/strings.subr
@@ -0,0 +1,104 @@
+if [ ! "$_STRINGS_SUBR" ]; then _STRINGS_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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$
+
+# f_substr "$string" $start [ $length ]
+#
+# Simple wrapper to awk(1)'s `substr' function.
+#
+f_substr()
+{
+ local string="$1" start="${2:-0}" len="${3:-0}"
+ echo "$string" | awk "{ print substr(\$0, $start, $len) }"
+}
+
+# f_longest_line_length
+#
+# Simple wrapper to an awk(1) script to print the length of the longest line of
+# input (read from stdin). Supports the newline escape-sequence `\n' for
+# splitting a single line into multiple lines.
+#
+f_longest_line_length_awk='
+BEGIN { longest = 0 }
+{
+ if (split($0, lines, /\\n/) > 1)
+ {
+ for (n in lines)
+ {
+ len = length(lines[n])
+ longest = ( len > longest ? len : longest )
+ }
+ }
+ else
+ {
+ len = length($0)
+ longest = ( len > longest ? len : longest )
+ }
+}
+END { print longest }
+'
+f_longest_line_length()
+{
+ awk "$f_longest_line_length_awk"
+}
+
+# f_number_of_lines
+#
+# Simple wrapper to an awk(1) script to print the number of lines read from
+# stdin. Supports newline escape-sequence `\n' for splitting a single line into
+# multiple lines.
+#
+f_number_of_lines_awk='
+BEGIN { num_lines = 0 }
+{
+ num_lines += split($0, unused, /\\n/)
+}
+END { print num_lines }
+'
+f_number_of_lines()
+{
+ awk "$f_number_of_lines_awk"
+}
+
+# f_isinteger $arg
+#
+# Returns true if argument is a positive/negative whole integer.
+#
+f_isinteger()
+{
+ local arg="$1"
+
+ # Prevent division-by-zero
+ [ "$arg" = "0" ] && return $SUCCESS
+
+ # Attempt to perform arithmetic divison (an operation which will exit
+ # with error unless arg is a valid positive/negative whole integer).
+ #
+ ( : $((0/$arg)) ) > /dev/null 2>&1
+}
+
+fi # ! $_STRINGS_SUBR
diff --git a/usr.sbin/bsdconfig/include/sysrc.subr b/usr.sbin/bsdconfig/include/sysrc.subr
new file mode 100644
index 0000000..52e57bc
--- /dev/null
+++ b/usr.sbin/bsdconfig/include/sysrc.subr
@@ -0,0 +1,616 @@
+if [ ! "$_SYSRC_SUBR" ]; then _SYSRC_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Standard pathnames (inherit values from shell if available)
+#
+: ${RC_DEFAULTS:="/etc/defaults/rc.conf"}
+
+############################################################ GLOBALS
+
+#
+# Global exit status variables
+#
+SUCCESS=0
+FAILURE=1
+
+############################################################ FUNCTIONS
+
+# f_clean_env [ --except $varname ... ]
+#
+# Unset all environment variables in the current scope. An optional list of
+# arguments can be passed, indicating which variables to avoid unsetting; the
+# `--except' is required to enable the exclusion-list as the remainder of
+# positional arguments.
+#
+# Be careful not to call this in a shell that you still expect to perform
+# $PATH expansion in, because this will blow $PATH away. This is best used
+# within a sub-shell block "(...)" or "$(...)" or "`...`".
+#
+f_clean_env()
+{
+ local var arg except=
+
+ #
+ # Should we process an exclusion-list?
+ #
+ if [ "$1" = "--except" ]; then
+ except=1
+ shift 1
+ fi
+
+ #
+ # Loop over a list of variable names from set(1) built-in.
+ #
+ for var in $( set | awk -F= \
+ '/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' \
+ | grep -v '^except$'
+ ); do
+ #
+ # In POSIX bourne-shell, attempting to unset(1) OPTIND results
+ # in "unset: Illegal number:" and causes abrupt termination.
+ #
+ [ "$var" = OPTIND ] && continue
+
+ #
+ # Process the exclusion-list?
+ #
+ if [ "$except" ]; then
+ for arg in "$@" ""; do
+ [ "$var" = "$arg" ] && break
+ done
+ [ "$arg" ] && continue
+ fi
+
+ unset "$var"
+ done
+}
+
+# f_sysrc_get $varname
+#
+# Get a system configuration setting from the collection of system-
+# configuration files (in order: /etc/defaults/rc.conf /etc/rc.conf
+# and /etc/rc.conf).
+#
+# NOTE: Additional shell parameter-expansion formats are supported. For
+# example, passing an argument of "hostname%%.*" (properly quoted) will
+# return the hostname up to (but not including) the first `.' (see sh(1),
+# "Parameter Expansion" for more information on additional formats).
+#
+f_sysrc_get()
+{
+ # Sanity check
+ [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE
+
+ # Taint-check variable name
+ case "$1" in
+ [0-9]*)
+ # Don't expand possible positional parameters
+ return $FAILURE;;
+ *)
+ [ "$1" ] || return $FAILURE
+ esac
+
+ ( # Execute within sub-shell to protect parent environment
+
+ #
+ # Clear the environment of all variables, preventing the
+ # expansion of normals such as `PS1', `TERM', etc.
+ #
+ f_clean_env --except RC_CONFS RC_DEFAULTS SUCCESS
+
+ . "$RC_DEFAULTS" > /dev/null 2>&1
+
+ unset RC_DEFAULTS
+ # no longer needed
+
+ #
+ # If the query is for `rc_conf_files' then store the value that
+ # we inherited from sourcing RC_DEFAULTS (above) so that we may
+ # conditionally restore this value after source_rc_confs in the
+ # event that RC_CONFS does not customize the value.
+ #
+ if [ "$1" = "rc_conf_files" ]; then
+ _rc_conf_files="$rc_conf_files"
+ fi
+
+ #
+ # If RC_CONFS is defined, set $rc_conf_files to an explicit
+ # value, modifying the default behavior of source_rc_confs().
+ #
+ ( : ${RC_CONFS?} ) > /dev/null 2>&1
+ if [ $? -eq ${SUCCESS:-0} ]; then
+ rc_conf_files="$RC_CONFS"
+ _rc_confs_set=1
+ fi
+
+ unset SUCCESS
+ # no longer needed
+
+ source_rc_confs > /dev/null 2>&1
+
+ #
+ # If the query was for `rc_conf_files' AND after calling
+ # source_rc_confs the vaue has not changed, then we should
+ # restore the value to the one inherited from RC_DEFAULTS
+ # before performing the final query (preventing us from
+ # returning what was set via RC_CONFS when the intent was
+ # instead to query the value from the file(s) specified).
+ #
+ if [ "$1" = "rc_conf_files" -a \
+ "$_rc_confs_set" -a \
+ "$rc_conf_files" = "$RC_CONFS" \
+ ]; then
+ rc_conf_files="$_rc_conf_files"
+ unset _rc_conf_files
+ unset _rc_confs_set
+ fi
+
+ unset RC_CONFS
+ # no longer needed
+
+ #
+ # This must be the last functional line for both the sub-shell
+ # and the function to preserve the return status from formats
+ # such as "${varname?}" and "${varname:?}" (see "Parameter
+ # Expansion" in sh(1) for more information).
+ #
+ eval echo '"${'"$1"'}"' 2> /dev/null
+ )
+}
+
+# f_sysrc_get_default $varname
+#
+# Get a system configuration default setting from the default rc.conf(5) file
+# (or whatever RC_DEFAULTS points at).
+#
+f_sysrc_get_default()
+{
+ # Sanity check
+ [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE
+
+ # Taint-check variable name
+ case "$1" in
+ [0-9]*)
+ # Don't expand possible positional parameters
+ return $FAILURE;;
+ *)
+ [ "$1" ] || return $FAILURE
+ esac
+
+ ( # Execute within sub-shell to protect parent environment
+
+ #
+ # Clear the environment of all variables, preventing the
+ # expansion of normals such as `PS1', `TERM', etc.
+ #
+ f_clean_env --except RC_DEFAULTS
+
+ . "$RC_DEFAULTS" > /dev/null 2>&1
+
+ unset RC_DEFAULTS
+ # no longer needed
+
+ #
+ # This must be the last functional line for both the sub-shell
+ # and the function to preserve the return status from formats
+ # such as "${varname?}" and "${varname:?}" (see "Parameter
+ # Expansion" in sh(1) for more information).
+ #
+ eval echo '"${'"$1"'}"' 2> /dev/null
+ )
+}
+
+# f_sysrc_find $varname
+#
+# Find which file holds the effective last-assignment to a given variable
+# within the rc.conf(5) file(s).
+#
+# If the variable is found in any of the rc.conf(5) files, the function prints
+# the filename it was found in and then returns success. Otherwise output is
+# NULL and the function returns with error status.
+#
+f_sysrc_find()
+{
+ local varname="$1"
+ local regex="^[[:space:]]*$varname="
+ local rc_conf_files="$( f_sysrc_get rc_conf_files )"
+ local conf_files=
+ local file
+
+ # Check parameters
+ [ "$varname" ] || return $FAILURE
+
+ #
+ # If RC_CONFS is defined, set $rc_conf_files to an explicit
+ # value, modifying the default behavior of source_rc_confs().
+ #
+ [ "$RC_CONFS" ] && rc_conf_files="$RC_CONFS"
+
+ #
+ # Reverse the order of files in rc_conf_files (the boot process sources
+ # these in order, so we will search them in reverse-order to find the
+ # last-assignment -- the one that ultimately effects the environment).
+ #
+ for file in $rc_conf_files; do
+ conf_files="$file${conf_files:+ }$conf_files"
+ done
+
+ #
+ # Append the defaults file (since directives in the defaults file
+ # indeed affect the boot process, we'll want to know when a directive
+ # is found there).
+ #
+ conf_files="$conf_files${conf_files:+ }$RC_DEFAULTS"
+
+ #
+ # Find which file matches assignment to the given variable name.
+ #
+ for file in $conf_files; do
+ [ -f "$file" -a -r "$file" ] || continue
+ if grep -Eq "$regex" $file; then
+ echo $file
+ return $SUCCESS
+ fi
+ done
+
+ return $FAILURE # Not found
+}
+
+# f_sysrc_desc $varname
+#
+# Attempts to return the comments associated with varname from the rc.conf(5)
+# defaults file `/etc/defaults/rc.conf' (or whatever RC_DEFAULTS points to).
+#
+# Multi-line comments are joined together. Results are NULL if no description
+# could be found.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_sysrc_desc_awk='
+# Variables that should be defined on the invocation line:
+# -v varname="varname"
+#
+BEGIN {
+ regex = "^[[:space:]]*"varname"="
+ found = 0
+ buffer = ""
+}
+{
+ if ( ! found )
+ {
+ if ( ! match($0, regex) ) next
+
+ found = 1
+ sub(/^[^#]*(#[[:space:]]*)?/, "")
+ buffer = $0
+ next
+ }
+
+ if ( !/^[[:space:]]*#/ ||
+ /^[[:space:]]*[[:alpha:]_][[:alnum:]_]*=/ ||
+ /^[[:space:]]*#[[:alpha:]_][[:alnum:]_]*=/ ||
+ /^[[:space:]]*$/ ) exit
+
+ sub(/(.*#)*[[:space:]]*/, "")
+ buffer = buffer" "$0
+}
+END {
+ # Clean up the buffer
+ sub(/^[[:space:]]*/, "", buffer)
+ sub(/[[:space:]]*$/, "", buffer)
+
+ print buffer
+ exit ! found
+}
+'
+f_sysrc_desc()
+{
+ awk -v varname="$1" "$f_sysrc_desc_awk" < "$RC_DEFAULTS"
+}
+
+# f_sysrc_set $varname $new_value
+#
+# Change a setting in the system configuration files (edits the files in-place
+# to change the value in the last assignment to the variable). If the variable
+# does not appear in the source file, it is appended to the end of the primary
+# system configuration file `/etc/rc.conf'.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_sysrc_set_awk='
+# Variables that should be defined on the invocation line:
+# -v varname="varname"
+# -v new_value="new_value"
+#
+BEGIN {
+ regex = "^[[:space:]]*"varname"="
+ found = retval = 0
+}
+{
+ # If already found... just spew
+ if ( found ) { print; next }
+
+ # Does this line match an assignment to our variable?
+ if ( ! match($0, regex) ) { print; next }
+
+ # Save important match information
+ found = 1
+ matchlen = RSTART + RLENGTH - 1
+
+ # Store the value text for later munging
+ value = substr($0, matchlen + 1, length($0) - matchlen)
+
+ # Store the first character of the value
+ t1 = t2 = substr(value, 0, 1)
+
+ # Assignment w/ back-ticks, expression, or misc.
+ # We ignore these since we did not generate them
+ #
+ if ( t1 ~ /[`$\\]/ ) { retval = 1; print; next }
+
+ # Assignment w/ single-quoted value
+ else if ( t1 == "'\''" ) {
+ sub(/^'\''[^'\'']*/, "", value)
+ if ( length(value) == 0 ) t2 = ""
+ sub(/^'\''/, "", value)
+ }
+
+ # Assignment w/ double-quoted value
+ else if ( t1 == "\"" ) {
+ sub(/^"(.*\\\\+")*[^"]*/, "", value)
+ if ( length(value) == 0 ) t2 = ""
+ sub(/^"/, "", value)
+ }
+
+ # Assignment w/ non-quoted value
+ else if ( t1 ~ /[^[:space:];]/ ) {
+ t1 = t2 = "\""
+ sub(/^[^[:space:]]*/, "", value)
+ }
+
+ # Null-assignment
+ else if ( t1 ~ /[[:space:];]/ ) { t1 = t2 = "\"" }
+
+ printf "%s%c%s%c%s\n", substr($0, 0, matchlen), \
+ t1, new_value, t2, value
+}
+END { exit retval }
+'
+f_sysrc_set()
+{
+ local varname="$1" new_value="$2"
+
+ # Check arguments
+ [ "$varname" ] || return $FAILURE
+
+ #
+ # Find which rc.conf(5) file contains the last-assignment
+ #
+ local not_found=
+ local file="$( f_sysrc_find "$varname" )"
+ if [ "$file" = "$RC_DEFAULTS" -o ! "$file" ]; then
+ #
+ # We either got a null response (not found) or the variable
+ # was only found in the rc.conf(5) defaults. In either case,
+ # let's instead modify the first file from $rc_conf_files.
+ #
+
+ not_found=1
+
+ #
+ # If RC_CONFS is defined, use $RC_CONFS
+ # rather than $rc_conf_files.
+ #
+ if [ "$RC_CONFS" ]; then
+ file="${RC_CONFS%%[$IFS]*}"
+ else
+ file=$( f_sysrc_get rc_conf_files )
+ file="${file%%[$IFS]*}"
+ fi
+ fi
+
+ #
+ # If not found, append new value to last file and return.
+ #
+ if [ "$not_found" ]; then
+ echo "$varname=\"$new_value\"" >> "$file"
+ return $?
+ fi
+
+ #
+ # Perform sanity checks.
+ #
+ if [ ! -w "$file" ]; then
+ f_err "$msg_cannot_create_permission_denied\n" \
+ "$pgm" "$file"
+ return $FAILURE
+ fi
+
+ #
+ # Create a new temporary file to write to.
+ #
+ local tmpfile="$( mktemp -t "$pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ #
+ # Fixup permissions (else we're in for a surprise, as mktemp(1) creates
+ # the temporary file with 0600 permissions, and if we simply mv(1) the
+ # temporary file over the destination, the destination will inherit the
+ # permissions from the temporary file).
+ #
+ local mode
+ mode=$( stat -f '%#Lp' "$file" 2> /dev/null )
+ f_quietly chmod "${mode:-0644}" "$tmpfile"
+
+ #
+ # Fixup ownership. The destination file _is_ writable (we tested
+ # earlier above). However, this will fail if we don't have sufficient
+ # permissions (so we throw stderr into the bit-bucket).
+ #
+ local owner
+ owner=$( stat -f '%u:%g' "$file" 2> /dev/null )
+ f_quietly chown "${owner:-root:wheel}" "$tmpfile"
+
+ #
+ # Operate on the matching file, replacing only the last occurrence.
+ #
+ local new_contents retval
+ new_contents=$( tail -r $file 2> /dev/null )
+ new_contents=$( echo "$new_contents" | awk -v varname="$varname" \
+ -v new_value="$new_value" "$f_sysrc_set_awk" )
+ retval=$?
+
+ #
+ # Write the temporary file contents.
+ #
+ echo "$new_contents" | tail -r > "$tmpfile" || return $FAILURE
+ if [ $retval -ne $SUCCESS ]; then
+ echo "$varname=\"$new_value\"" >> "$tmpfile"
+ fi
+
+ #
+ # Taint-check our results.
+ #
+ if ! /bin/sh -n "$tmpfile"; then
+ f_err "$msg_previous_syntax_errors\n" "$pgm" "$file"
+ rm -f "$tmpfile"
+ return $FAILURE
+ fi
+
+ #
+ # Finally, move the temporary file into place.
+ #
+ mv "$tmpfile" "$file"
+}
+
+# f_sysrc_delete $varname
+#
+# Remove a setting from the system configuration files (edits files in-place).
+# Deletes all assignments to the given variable in all config files. If the
+# `-f file' option is passed, the removal is restricted to only those files
+# specified, otherwise the system collection of rc_conf_files is used.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_sysrc_delete_awk='
+# Variables that should be defined on the invocation line:
+# -v varname="varname"
+#
+BEGIN {
+ regex = "^[[:space:]]*"varname"="
+ found = 0
+}
+{
+ if ( $0 ~ regex )
+ found = 1
+ else
+ print
+}
+END { exit ! found }
+'
+f_sysrc_delete()
+{
+ local varname="$1"
+ local file
+
+ # Check arguments
+ [ "$varname" ] || return $FAILURE
+
+ #
+ # Operate on each of the specified files
+ #
+ for file in ${RC_CONFS:-$( f_sysrc_get rc_conf_files )}; do
+ [ -e "$file" ] || continue
+
+ #
+ # Create a new temporary file to write to.
+ #
+ local tmpfile="$( mktemp -t "$pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ #
+ # Fixup permissions and ownership (mktemp(1) defaults to 0600
+ # permissions) to instead match the destination file.
+ #
+ local mode owner
+ mode=$( stat -f '%#Lp' "$file" 2> /dev/null )
+ owner=$( stat -f '%u:%g' "$file" 2> /dev/null )
+ f_quietly chmod "${mode:-0644}" "$tmpfile"
+ f_quietly chown "${owner:-root:wheel}" "$tmpfile"
+
+ #
+ # Operate on the file, removing all occurrences, saving the
+ # output in our temporary file.
+ #
+ awk -v varname="$varname" "$f_sysrc_delete_awk" "$file" \
+ > "$tmpfile"
+ if [ $? -ne $SUCCESS ]; then
+ # The file didn't contain any assignments
+ rm -f "$tmpfile"
+ continue
+ fi
+
+ #
+ # Taint-check our results.
+ #
+ if ! /bin/sh -n "$tmpfile"; then
+ f_err "$msg_previous_syntax_errors\n" \
+ "$pgm" "$file"
+ rm -f "$tmpfile"
+ return $FAILURE
+ fi
+
+ #
+ # Perform sanity checks
+ #
+ if [ ! -w "$file" ]; then
+ f_err "$msg_permission_denied\n" "$pgm" "$file"
+ rm -f "$tmpfile"
+ return $FAILURE
+ fi
+
+ #
+ # Finally, move the temporary file into place.
+ #
+ mv "$tmpfile" "$file"
+ done
+}
+
+fi # ! $_SYSRC_SUBR
diff --git a/usr.sbin/bsdconfig/mouse/INDEX b/usr.sbin/bsdconfig/mouse/INDEX
new file mode 100644
index 0000000..cf7224c
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/INDEX
@@ -0,0 +1,58 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Mouse"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Configure the Mouse"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="mouse|mouse"
+menu_selection="mouse_enable|enable"
+menu_selection="mouse_type|type"
+menu_selection="mouse_port|port"
+menu_selection="mouse_flags|flags"
+menu_selection="mouse_disable|disable"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="mouse"
diff --git a/usr.sbin/bsdconfig/mouse/Makefile b/usr.sbin/bsdconfig/mouse/Makefile
new file mode 100644
index 0000000..3b68cad
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/110.mouse
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= disable enable flags mouse port type
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/mouse/USAGE b/usr.sbin/bsdconfig/mouse/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/mouse/disable b/usr.sbin/bsdconfig/mouse/disable
new file mode 100755
index 0000000..a3101a7
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/disable
@@ -0,0 +1,104 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="110.mouse"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# Location of moused(8) pidfile
+#
+MOUSED_PIDFILE=/var/run/moused.pid
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_mouse_disable"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Stop the mouse daemon
+#
+[ -r "$MOUSED_PIDFILE" ] &&
+ f_quietly kill "$( cat "$MOUSED_PIDFILE" )"
+f_sysrc_set moused_enable "NO" || f_die
+f_sysrc_set moused_type "NO" || f_die
+f_sysrc_delete moused_port || f_die
+f_sysrc_delete moused_flags || f_die
+
+#
+# Message box
+#
+f_dialog_title "$msg_message"
+hline="$hline_press_enter_or_space"
+prompt="$msg_mouse_daemon_is_disabled"
+size=$( f_dialog_buttonbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$prompt" )
+eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$prompt\" $size
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/mouse/enable b/usr.sbin/bsdconfig/mouse/enable
new file mode 100755
index 0000000..72565e2
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/enable
@@ -0,0 +1,118 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="110.mouse"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# Location of moused(8) pidfile
+#
+MOUSED_PIDFILE=/var/run/moused.pid
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_mouse_enable"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Get the type, port, and flags
+#
+type=$( f_sysrc_get moused_type )
+case "$type" in
+[Nn][Oo]|"") f_die 1 "$msg_please_select_protocol_and_port_first" ;;
+esac
+port=$( f_sysrc_get moused_port )
+[ "$port" ] || f_die 1 "$msg_please_select_protocol_and_port_first"
+flags=$( f_sysrc_get moused_flags )
+
+#
+# Start the mouse daemon
+#
+f_dialog_info "$msg_trying_to_start_the_mouse_daemon"
+[ -r "$MOUSED_PIDFILE" ] &&
+ f_quietly kill "$( cat "$MOUSED_PIDFILE" 2> /dev/null )"
+f_quietly vidcontrol -m on
+f_quietly moused -t "$type" -p "$port" $flags
+
+#
+# Confirm with the user that the mouse is working
+#
+f_dialog_title "$msg_user_confirmation_requested"
+f_dialog_yesno "$msg_now_move_the_mouse"
+retval=$?
+f_dialog_title_restore
+
+#
+# Stop the mouse daemon
+#
+f_quietly vidcontrol -m off
+if [ $retval -eq $SUCCESS ]; then
+ f_sysrc_set moused_enable "YES" || f_die
+ ln -fs /dev/sysmouse /dev/mouse || f_die # backwards compat
+else
+ [ -r "$MOUSED_PIDFILE" ] &&
+ f_quietly kill "$( cat "$MOUSED_PIDFILE" )"
+ f_sysrc_set moused_enable "NO" || f_die
+fi
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/mouse/flags b/usr.sbin/bsdconfig/mouse/flags
new file mode 100755
index 0000000..ab57f21
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/flags
@@ -0,0 +1,116 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="110.mouse"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# Location of moused(8) pidfile
+#
+MOUSED_PIDFILE=/var/run/moused.pid
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_mouse_flags"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Get the current flags
+#
+flags=$( f_sysrc_get moused_flags )
+
+#
+# Prompt the user with the current value
+#
+f_dialog_title "$msg_value_required"
+title="$DIALOG_TITLE"
+btitle="$DIALOG_BACKTITLE"
+f_dialog_title_restore
+hline=
+prompt="$msg_please_specify_the_mouse_daemon_flags"
+size=$( f_dialog_inputbox_size \
+ "$title" \
+ "$btitle" \
+ "$prompt" \
+ "$flags" \
+ "$hline" )
+eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$prompt\" $size \
+ \"\$flags\" \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+retval=$?
+flags=$( f_dialog_inputstr )
+
+[ $retval -eq $SUCCESS ] || f_die
+
+#
+# Save the new value
+#
+f_sysrc_set moused_flags "$flags" || f_die
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/mouse/include/Makefile b/usr.sbin/bsdconfig/mouse/include/Makefile
new file mode 100644
index 0000000..ed0b24d
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/110.mouse/include
+FILES= messages.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/mouse/include/messages.subr b/usr.sbin/bsdconfig/mouse/include/messages.subr
new file mode 100644
index 0000000..c6f4969
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/include/messages.subr
@@ -0,0 +1,90 @@
+# Copyright (c) 2012 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$
+
+hline_press_enter_or_space="Press enter or space"
+msg_auto="Auto"
+msg_auto_desc="Bus mouse, PS/2 style mouse or PnP serial mouse"
+msg_busmouse="BusMouse"
+msg_busmouse_desc="Logitech, ATI or MS bus mouse (/dev/mse0)"
+msg_cancel="Cancel"
+msg_com1="COM1"
+msg_com1_desc="Serial mouse on COM1 (/dev/cuau0)"
+msg_com2="COM2"
+msg_com2_desc="Serial mouse on COM2 (/dev/cuau1)"
+msg_com3="COM3"
+msg_com3_desc="Serial mouse on COM3 (/dev/cuau2)"
+msg_com4="COM4"
+msg_com4_desc="Serial mouse on COM4 (/dev/cuau3)"
+msg_disable="Disable"
+msg_disable_the_mouse_daemon="Disable the mouse daemon"
+msg_enable="Enable"
+msg_exit="Exit"
+msg_exit_this_menu="Exit this menu (returning to previous)"
+msg_flags="Flags"
+msg_glidepoint="GlidePoint"
+msg_glidepoint_desc="ALPS GlidePoint pad (serial)"
+msg_hitachi="Hitachi"
+msg_hitachi_desc="Hitachi tablet (serial)"
+msg_intellimouse="IntelliMouse"
+msg_intellimouse_desc="Microsoft IntelliMouse (serial)"
+msg_logitech="Logitech"
+msg_logitech_desc="Logitech protocol (old models) (serial)"
+msg_menu_text="You can cut and paste text in the text console by running the mouse\ndaemon. Specify a port and a protocol type of your mouse and enable\nthe mouse daemon. If you don't want this feature, select 6 to disable\nthe daemon.\nOnce you've enabled the mouse daemon, you can specify \"/dev/sysmouse\"\nas your mouse device and \"SysMouse\" or \"MouseSystems\" as mouse\nprotocol when running the X configuration utility (see Configuration\nmenu)."
+msg_message="Message"
+msg_microsoft="Microsoft"
+msg_microsoft_desc="Microsoft protocol (serial)"
+msg_mm_series="MM Series"
+msg_mm_series_desc="MM Series protocol (serial)"
+msg_mouseman="MouseMan"
+msg_mouseman_desc="Logitech MouseMan/TrackMan models (serial)"
+msg_mousesystems="MouseSystems"
+msg_mousesystems_desc="MouseSystems protocol (serial)"
+msg_mouse_daemon_is_disabled="The mouse daemon is disabled."
+msg_mouse_disable="Mouse Disable"
+msg_mouse_enable="Mouse Enable"
+msg_mouse_flags="Mouse Flags"
+msg_now_move_the_mouse="Now move the mouse and see if it works.\n(Note that buttons don't have any effect for now.)\n\n Is the mouse cursor moving?\n"
+msg_ok="OK"
+msg_please_configure_your_mouse="Please configure your mouse"
+msg_please_select_protocol_and_port_first="Please select a mouse protocol and a port first."
+msg_please_specify_the_mouse_daemon_flags="Please specify the mouse daemon flags. If you would like to\nemulate 3 buttons, use -3 here.\n "
+msg_port="Port"
+msg_port_menu_text="The built-in pointing device of laptop/notebook computers is usually\na PS/2 style device."
+msg_protocol_menu_text="If your mouse is attached to the PS/2 mouse port or the bus mouse port,\nyou should always choose \"Auto\", regardless of the model and the brand\nof the mouse. All other protocol types are for serial mice and should\nnot be used with the PS/2 port mouse or the bus mouse. If you have\na serial mouse and are not sure about its protocol, you should also try\n\"Auto\". It may not work for the serial mouse if the mouse does not\nsupport the PnP standard. But, it won't hurt. Many 2-button serial mice\nare compatible with \"Microsoft\" or \"MouseMan\". 3-button serial mice\nmay be compatible with \"MouseSystems\" or \"MouseMan\". If the serial\nmouse has a wheel, it may be compatible with \"IntelliMouse\"."
+msg_ps2="PS/2"
+msg_ps2_desc="PS/2 style mouse (/dev/psm0)"
+msg_select_a_protocol_type_for_your_mouse="Select a protocol type for your mouse"
+msg_select_mouse_port="Select mouse port"
+msg_select_mouse_protocol_type="Select mouse protocol type"
+msg_select_your_mouse_port_from_the_following_menu="Select your mouse port from the following menu"
+msg_set_additional_flags="Set additional flags"
+msg_test_and_run_the_mouse_daemon="Test and run the mouse daemon"
+msg_thinkingmouse="ThinkingMouse"
+msg_thinkingmouse_desc="Kensington ThinkingMouse (serial)"
+msg_trying_to_start_the_mouse_daemon="Trying to start the mouse daemon..."
+msg_type="Type"
+msg_user_confirmation_requested="User Confirmation Requested"
+msg_value_required="Value Required"
diff --git a/usr.sbin/bsdconfig/mouse/mouse b/usr.sbin/bsdconfig/mouse/mouse
new file mode 100755
index 0000000..f85c498
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/mouse
@@ -0,0 +1,134 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="110.mouse"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline=""
+ local prompt="$msg_menu_text"
+
+ menu_list="
+ 'X $msg_exit' '$msg_exit_this_menu'
+ '2 $msg_enable' '$msg_test_and_run_the_mouse_daemon'
+ '3 $msg_type' '$msg_select_mouse_protocol_type'
+ '4 $msg_port' '$msg_select_mouse_port'
+ '5 $msg_flags' '$msg_set_additional_flags'
+ '6 $msg_disable' '$msg_disable_the_mouse_daemon'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_please_configure_your_mouse"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+ "2 $msg_enable") # Test and run the mouse daemon
+ $BSDCFG_LIBE/$APP_DIR/enable ${USE_XDIALOG:+-X} ;;
+ "3 $msg_type") # Select mouse protocol type
+ $BSDCFG_LIBE/$APP_DIR/type ${USE_XDIALOG:+-X} ;;
+ "4 $msg_port") # Select mouse port
+ $BSDCFG_LIBE/$APP_DIR/port ${USE_XDIALOG:+-X} ;;
+ "5 $msg_flags") # Set additional flags
+ $BSDCFG_LIBE/$APP_DIR/flags ${USE_XDIALOG:+-X} ;;
+ "6 $msg_disable") # Disable the mouse daemon
+ $BSDCFG_LIBE/$APP_DIR/disable ${USE_XDIALOG:+-X} ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/mouse/port b/usr.sbin/bsdconfig/mouse/port
new file mode 100755
index 0000000..c7e1ae1
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/port
@@ -0,0 +1,142 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="110.mouse"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline=""
+ local prompt="$msg_port_menu_text"
+
+ menu_list="
+ '1 $msg_ps2' '$msg_ps2_desc'
+ '2 $msg_com1' '$msg_com1_desc'
+ '3 $msg_com2' '$msg_com2_desc'
+ '4 $msg_com3' '$msg_com3_desc'
+ '5 $msg_com4' '$msg_com4_desc'
+ '6 $msg_busmouse' '$msg_busmouse_desc'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_select_your_mouse_port_from_the_following_menu"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "1 $msg_ps2") # PS/2 style mouse (/dev/psm0)
+ f_sysrc_set moused_port "/dev/psm0" || f_die
+ break ;;
+ "2 $msg_com1") # Serial mouse on COM1 (/dev/cuau0)
+ f_sysrc_set moused_port "/dev/cuau0" || f_die
+ break ;;
+ "3 $msg_com2") # Serial mouse on COM2 (/dev/cuau1)
+ f_sysrc_set moused_port "/dev/cuau1" || f_die
+ break ;;
+ "4 $msg_com3") # Serial mouse on COM3 (/dev/cuau2)
+ f_sysrc_set moused_port "/dev/cuau2" || f_die
+ break ;;
+ "5 $msg_com4") # Serial mouse on COM4 (/dev/cuau3)
+ f_sysrc_set moused_port "/dev/cuau3" || f_die
+ break ;;
+ "6 $msg_busmouse") # Logitech, ATI or MS bus mouse (/dev/mse0)
+ f_sysrc_set moused_port "/dev/mse0" || f_die
+ break ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/mouse/type b/usr.sbin/bsdconfig/mouse/type
new file mode 100755
index 0000000..6513244
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/type
@@ -0,0 +1,158 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="110.mouse"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline=""
+ local prompt="$msg_protocol_menu_text"
+
+ menu_list="
+ '1 $msg_auto' '$msg_auto_desc'
+ '2 $msg_glidepoint' '$msg_glidepoint_desc'
+ '3 $msg_hitachi' '$msg_hitachi_desc'
+ '4 $msg_intellimouse' '$msg_intellimouse_desc'
+ '5 $msg_logitech' '$msg_logitech_desc'
+ '6 $msg_microsoft' '$msg_microsoft_desc'
+ '7 $msg_mm_series' '$msg_mm_series_desc'
+ '8 $msg_mouseman' '$msg_mouseman_desc'
+ '9 $msg_mousesystems' '$msg_mousesystems_desc'
+ 'A $msg_thinkingmouse' '$msg_thinkingmouse_desc'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_select_a_protocol_type_for_your_mouse"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "1 $msg_auto") # Bus mouse, PS/2 style mouse or PnP serial mouse
+ f_sysrc_set moused_type "auto" || f_die
+ break ;;
+ "2 $msg_glidepoint") # ALPS GlidePoint pad (serial)
+ f_sysrc_set moused_type "glidepoint" || f_die
+ break ;;
+ "3 $msg_hitachi") # Hitachi tablet (serial)
+ f_sysrc_set moused_type "mmhittab" || f_die
+ break ;;
+ "4 $msg_intellimouse") # Microsoft Intellimouse (serial)
+ f_sysrc_set moused_type "intellimouse" || f_die
+ break ;;
+ "5 $msg_logitech") # Logitech protocol (old models) (serial)
+ f_sysrc_set moused_type "logitech" || f_die
+ break ;;
+ "6 $msg_microsoft") # Microsoft protocol (serial)
+ f_sysrc_set moused_type "microsoft" || f_die
+ break ;;
+ "7 $msg_mm_series") # MM Series protocol (serial)
+ f_sysrc_set moused_type "mmseries" || f_die
+ break ;;
+ "8 $msg_mouseman") # Logitech MouseMan/TrackMan models (serial)
+ f_sysrc_set moused_type "mouseman" || f_die
+ break ;;
+ "9 $msg_mousesystems") # MouseSystems protocol (serial)
+ f_sysrc_set moused_type "mousesystems" || f_die
+ break ;;
+ "A $msg_thinkingmouse") # Kensignton ThinkingMouse (serial)
+ f_sysrc_set moused_type "thinkingmouse" || f_die
+ break ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/networking/INDEX b/usr.sbin/bsdconfig/networking/INDEX
new file mode 100644
index 0000000..1d23911
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/INDEX
@@ -0,0 +1,57 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Networking Management"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Setup Networking interfaces, services, etc."
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="networking|networking"
+menu_selection="defaultrouter|defaultrouter"
+menu_selection="hostname|hostname"
+menu_selection="nameservers|nameservers"
+menu_selection="netdev|devices"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="networking"
diff --git a/usr.sbin/bsdconfig/networking/Makefile b/usr.sbin/bsdconfig/networking/Makefile
new file mode 100644
index 0000000..fcd0509
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/120.networking
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= defaultrouter devices hostname nameservers networking
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/networking/USAGE b/usr.sbin/bsdconfig/networking/USAGE
new file mode 100644
index 0000000..a4dd74c
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2006-2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/networking/defaultrouter b/usr.sbin/bsdconfig/networking/defaultrouter
new file mode 100755
index 0000000..78d647d
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/defaultrouter
@@ -0,0 +1,73 @@
+#!/bin/sh
+#-
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/routing.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_default_router"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Change the default router/gateway
+#
+f_dialog_input_defaultrouter
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/networking/devices b/usr.sbin/bsdconfig/networking/devices
new file mode 100755
index 0000000..a12f782
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/devices
@@ -0,0 +1,158 @@
+#!/bin/sh
+#-
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/device.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/ipaddr.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/media.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/netmask.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line options
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_networking_devices"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ f_dialog_menu_netdev
+ retval=$?
+ interface=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || break
+
+ #
+ # dialog_menu_netdev adds an asterisk (*) to the right of the
+ # device name if the interface is active. Remove the asterisk
+ # from the device name if present.
+ #
+ case "$interface" in
+ *\*) interface="${interface%?}";;
+ esac
+
+ #
+ # Obtain initial interface settings to be configured. These will be
+ # passed to the f_dialog_menu_netdev_edit function-call below which
+ # will block until the user has either cancelled or finished editing
+ # the values.
+ #
+ # First, attempt to read stored configuration from rc.conf(5) and
+ # fallback to reading the active configuration if not configured in
+ # the rc.conf(5) file(s).
+ #
+ _ipaddr=
+ _netmask=
+ _ifconfig=$( f_sysrc_get ifconfig_$interface )
+ if [ "$_ifconfig" ]; then
+ # If DHCP get IP address/netmask later from ifconfig(8)
+ glob="[Dd][Hh][Cc][Pp]"
+ case "$_ifconfig" in
+ $glob) dhcp=1;;
+ [Ss][Yy][Nn][Cc]$glob) dhcp=1;;
+ [Nn][Oo][Ss][Yy][Nn][Cc]$glob) dhcp=1;;
+ *)
+ #
+ # Get IP address/netmask from rc.conf(5)
+ # configuration
+ #
+ dhcp=
+ eval "$( exec 2> /dev/null
+ set -- $_ifconfig
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ inet)
+ shift 1
+ echo "_ipaddr='$1'"
+ ;;
+ netmask)
+ shift 1
+ echo "_netmask='$1'"
+ ;;
+ esac
+ shift 1
+ done
+ )"
+ ;;
+ esac
+ fi
+
+ #
+ # Fill in IP address/netmask from active settings if no
+ # configuration could be extrapolated from rc.conf(5)
+ #
+ [ "$_ipaddr" ] || _ipaddr=$( f_ifconfig_inet $interface )
+ [ "$_netmask" ] || _netmask=$( f_ifconfig_netmask $interface )
+
+ # Get the extra options (this always comes from rc.conf(5))
+ _options=$( f_ifconfig_options $interface )
+
+ # Block on user-configuration of the probed settings
+ f_dialog_menu_netdev_edit \
+ $interface $_ipaddr $_netmask "$_options" $dhcp
+
+ # Return to root menu if above returns success
+ [ $? -eq $SUCCESS ] && break
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/networking/hostname b/usr.sbin/bsdconfig/networking/hostname
new file mode 100755
index 0000000..aec731d
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/hostname
@@ -0,0 +1,73 @@
+#!/bin/sh
+#-
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/hostname.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_hostname_domain"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Change the local hostname
+#
+f_dialog_input_hostname
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/networking/include/Makefile b/usr.sbin/bsdconfig/networking/include/Makefile
new file mode 100644
index 0000000..858ceba
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/120.networking/include
+FILES= common.subr device.subr hostname.subr ipaddr.subr media.subr \
+ messages.subr netmask.subr resolv.subr routing.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/networking/include/common.subr b/usr.sbin/bsdconfig/networking/include/common.subr
new file mode 100644
index 0000000..13e9795
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/common.subr
@@ -0,0 +1,65 @@
+if [ ! "$_NETWORKING_COMMON_SUBR" ]; then _NETWORKING_COMMON_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+
+############################################################ FUNCTIONS
+
+# f_mounted $local_directory
+#
+# Return success if a filesystem is mounted on a particular directory.
+#
+f_mounted()
+{
+ local dir="$1"
+ [ -d "$dir" ] || return $FAILURE
+ mount | grep -Eq " on $dir \([^)]+\)$"
+}
+
+# f_jailed
+#
+# Returns true if the current process is jail(8)ed.
+#
+f_jailed()
+{
+ ! f_quietly ps 1
+}
+
+# f_nfs_mounted
+#
+# Returns true if there are any NFS mounts currently active, otherwise false.
+#
+f_nfs_mounted()
+{
+ [ "$( df -t nfs )" ]
+}
+
+fi # ! $_NETWORKING_COMMON_SUBR
diff --git a/usr.sbin/bsdconfig/networking/include/device.subr b/usr.sbin/bsdconfig/networking/include/device.subr
new file mode 100644
index 0000000..5308854
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/device.subr
@@ -0,0 +1,489 @@
+if [ ! "$_NETWORKING_DEVICE_SUBR" ]; then _NETWORKING_DEVICE_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/common.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/ipaddr.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/media.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/netmask.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/resolv.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/routing.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ GLOBALS
+
+#
+# Settings used while interacting with various dialog(1) menus
+#
+: ${DIALOG_MENU_NETDEV_KICK_INTERFACES=1}
+: ${DIALOG_MENU_NETDEV_SLEEP_AFTER_KICK=3}
+
+############################################################ FUNCTIONS
+
+# f_device_desc $device_name
+#
+# Print a description for a device name (eg., `fxp0').
+#
+f_device_desc()
+{
+ local device="$1" d="[1234567890]" desc=""
+
+ # Check variables
+ [ "$device" ] || return $SUCCESS
+
+ #
+ # Return sysctl MIB dev.NAME.UNIT.%desc if it exists,
+ # otherwise fall through to below static list.
+ #
+ if f_have sysctl; then
+ local devname devunit
+ devname="${device%%$d*}"
+ devunit="${device#$devname}"
+ devunit="${devunit%%[a-zA-Z_]*}"
+ sysctl -n "dev.$devname.$devunit.%desc" 2> /dev/null &&
+ return $SUCCESS
+ fi
+
+ case "$device" in
+ # Network devices
+ ae$d) desc="Attansic/Atheros L2 Fast Ethernet";;
+ age$d) desc="Attansic/Atheros L1 Gigabit Ethernet";;
+ alc$d) desc="Atheros AR8131/AR8132 PCIe Ethernet";;
+ ale$d) desc="Atheros AR8121/AR8113/AR8114 PCIe Ethernet";;
+ an$d) desc="Aironet 4500/4800 802.11 wireless adapter";;
+ ath$d) desc="Atheros IEEE 802.11 wireless adapter";;
+ aue$d) desc="ADMtek USB Ethernet adapter";;
+ axe$d) desc="ASIX Electronics USB Ethernet adapter";;
+ bce$d) desc="Broadcom NetXtreme II Gigabit Ethernet card";;
+ bfe$d) desc="Broadcom BCM440x PCI Ethernet card";;
+ bge$d) desc="Broadcom BCM570x PCI Gigabit Ethernet card";;
+ bm$d) desc="Apple BMAC Built-in Ethernet";;
+ bwn$d) desc="Broadcom BCM43xx IEEE 802.11 wireless adapter";;
+ cas$d) desc="Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet";;
+ cc3i$d) desc="SDL HSSI sync serial PCI card";;
+ cue$d) desc="CATC USB Ethernet adapter";;
+ cxgb$d) desc="Chelsio T3 10Gb Ethernet card";;
+ dc$d) desc="DEC/Intel 21143 (and clones) PCI Fast Ethernet card";;
+ de$d) desc="DEC DE435 PCI NIC or other DC21040-AA based card";;
+ disc$d) desc="Software discard network interface";;
+ ed$d) desc="Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA";;
+ el$d) desc="3Com 3C501 Ethernet card";;
+ em$d) desc="Intel(R) PRO/1000 Ethernet card";;
+ en$d) desc="Efficient Networks ATM PCI card";;
+ ep$d) desc="3Com 3C509 Ethernet card/3C589 PCMCIA";;
+ et$d) desc="Agere ET1310 based PCI Express Gigabit Ethernet card";;
+ ex$d) desc="Intel EtherExpress Pro/10 Ethernet card";;
+ fe$d) desc="Fujitsu MB86960A/MB86965A Ethernet card";;
+ fpa$d) desc="DEC DEFPA PCI FDDI card";;
+ fwe$d) desc="FireWire Ethernet emulation";;
+ fwip$d) desc="IP over FireWire";;
+ fxp$d) desc="Intel EtherExpress Pro/100B PCI Fast Ethernet card";;
+ gem$d) desc="Apple GMAC or Sun ERI/GEM Ethernet adapter";;
+ hme$d) desc="Sun HME (Happy Meal Ethernet) Ethernet adapter";;
+ ie$d) desc="AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210";;
+ igb$d) desc="Intel(R) PRO/1000 PCI Express Gigabit Ethernet card";;
+ ipw$d) desc="Intel PRO/Wireless 2100 IEEE 802.11 adapter";;
+ iwi$d) desc="Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter";;
+ iwn$d) desc="Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter";;
+ ix$d) desc="Intel Etherexpress Ethernet card";;
+ ixgb$d) desc="Intel(R) PRO/10Gb Ethernet card";;
+ ixgbe$d) desc="Intel(R) PRO/10Gb Ethernet card";;
+ jme$d) desc="JMicron JMC250 Gigabit/JMC260 Fast Ethernet";;
+ kue$d) desc="Kawasaki LSI USB Ethernet adapter";;
+ le$d) desc="AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter";;
+ lge$d) desc="Level 1 LXT1001 Gigabit Ethernet card";;
+ lnc$d) desc="Lance/PCnet (Isolan/Novell NE2100/NE32-VL) Ethernet";;
+ lp$d) desc="Parallel Port IP (PLIP) peer connection";;
+ lo$d) desc="Loop-back (local) network interface";;
+ malo$d) desc="Marvell Libertas 88W8335 802.11 wireless adapter";;
+ msk$d) desc="Marvell/SysKonnect Yukon II Gigabit Ethernet";;
+ mxge$d) desc="Myricom Myri10GE 10Gb Ethernet card";;
+ nfe$d) desc="NVIDIA nForce MCP Ethernet";;
+ ng${d}_*|ng$d${d}_*|ng$d$d${d}_*|ng$d$d$d${d}_*|ng$d$d$d$d${d}_*)
+ desc="Vimage netgraph(4) bridged Ethernet device";;
+ nge$d) desc="NatSemi PCI Gigabit Ethernet card";;
+ nve$d) desc="NVIDIA nForce MCP Ethernet";;
+ nxge$d) desc="Neterion Xframe 10GbE Server/Storage adapter";;
+ pcn$d) desc="AMD Am79c79x PCI Ethernet card";;
+ plip$d) desc="Parallel Port IP (PLIP) peer connection";;
+ ral$d) desc="Ralink Technology IEEE 802.11 wireless adapter";;
+ ray$d) desc="Raytheon Raylink 802.11 wireless adapter";;
+ re$d) desc="RealTek 8139C+/8169/8169S/8110S PCI Ethernet adapter";;
+ rl$d) desc="RealTek 8129/8139 PCI Ethernet card";;
+ rue$d) desc="RealTek USB Ethernet card";;
+ rum$d) desc="Ralink Technology USB IEEE 802.11 wireless adapter";;
+ sf$d) desc="Adaptec AIC-6915 PCI Ethernet card";;
+ sge$d) desc="Silicon Integrated Systems SiS190/191 Ethernet";;
+ sis$d) desc="SiS 900/SiS 7016 PCI Ethernet card";;
+ sk$d) desc="SysKonnect PCI Gigabit Ethernet card";;
+ sn$d) desc="SMC/Megahertz Ethernet card";;
+ snc$d) desc="SONIC Ethernet card";;
+ sr$d) desc="SDL T1/E1 sync serial PCI card";;
+ ste$d) desc="Sundance ST201 PCI Ethernet card";;
+ stge$d) desc="Sundance/Tamarack TC9021 Gigabit Ethernet";;
+ ti$d) desc="Alteon Networks PCI Gigabit Ethernet card";;
+ tl$d) desc="Texas Instruments ThunderLAN PCI Ethernet card";;
+ tx$d) desc="SMC 9432TX Ethernet card";;
+ txp$d) desc="3Com 3cR990 Ethernet card";;
+ uath$d) desc="Atheros AR5005UG and AR5005UX USB wireless adapter";;
+ upgt$d) desc="Conexant/Intersil PrismGT USB wireless adapter";;
+ ural$d) desc="Ralink Technology RT2500USB 802.11 wireless adapter";;
+ urtw$d) desc="Realtek 8187L USB wireless adapter";;
+ vge$d) desc="VIA VT612x PCI Gigabit Ethernet card";;
+ vlan$d|vlan$d$d|vlan$d$d$d|vlan$d$d$d$d|vlan$d$d$d$d$d)
+ desc="IEEE 802.1Q VLAN network interface";;
+ vr$d) desc="VIA VT3043/VT86C100A Rhine PCI Ethernet card";;
+ vx$d) desc="3COM 3c590 / 3c595 Ethernet card";;
+ wb$d) desc="Winbond W89C840F PCI Ethernet card";;
+ wi$d) desc="Lucent WaveLAN/IEEE 802.11 wireless adapter";;
+ wpi$d) desc="Intel 3945ABG IEEE 802.11 wireless adapter";;
+ wx$d) desc="Intel Gigabit Ethernet (82452) card";;
+ xe$d) desc="Xircom/Intel EtherExpress Pro100/16 Ethernet card";;
+ xl$d) desc="3COM 3c90x / 3c90xB PCI Ethernet card";;
+ zyd$d) desc="ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter";;
+ # Unknown device
+ *) desc="<unknown network interface type>";;
+ esac
+ printf "%s\n" "$desc"
+}
+
+# f_dialog_menu_netdev
+#
+# Display a list of network devices with descriptions.
+#
+f_dialog_menu_netdev()
+{
+ #
+ # Display a message to let the user know we're working...
+ # (message will remain until we throw up the next dialog)
+ #
+ f_dialog_info "$msg_probing_network_interfaces"
+
+ #
+ # Get list of usable network interfaces
+ #
+ local d='[[:digit:]]+:'
+ local iflist="`echo "$(ifconfig -l):" | sed -E -e "
+ # Convert all spaces to colons
+ y/ /:/
+
+ # Prune unsavory interfaces
+ s/lo$d//g
+ s/ppp$d//g
+ s/sl$d//g
+ s/lp$d//g
+ s/fwe$d//g
+ s/faith$d//g
+ s/plip$d//g
+
+ # Convert all colons back into spaces
+ y/:/ /
+ "`"
+
+ #
+ # Optionally kick interfaces in the head to get them to accurately
+ # track the carrier status in realtime (required on FreeBSD).
+ #
+ if [ "$DIALOG_MENU_NETDEV_KICK_INTERFACES" ]; then
+ DIALOG_MENU_NETDEV_KICK_INTERFACES=
+
+ local ifn
+ for ifn in $iflist; do
+ f_quietly ifconfig $ifn up
+ done
+
+ if [ "$DIALOG_MENU_NETDEV_SLEEP_AFTER_KICK" ]; then
+ # interfaces need time to update carrier status
+ sleep $DIALOG_MENU_NETDEV_SLEEP_AFTER_KICK
+ fi
+ fi
+
+ #
+ # Mark any "active" interfaces with an asterisk (*)
+ # to the right of the device name.
+ #
+ interfaces=$(
+ for ifn in $iflist; do
+ active=$( ifconfig $ifn | awk \
+ '
+ ( $1 == "status:" ) \
+ {
+ if ( $2 == "active" ) { print 1; exit }
+ }
+ ' )
+ printf "'%s%s' '%s'\n" \
+ "$ifn" "${active:+*}" "$(f_device_desc "$ifn")"
+ done
+ )
+ if [ ! "$interfaces" ]; then
+ f_dialog_msgbox "$msg_no_network_interfaces"
+ return $FAILURE
+ fi
+
+ local hline="$hline_arrows_tab_enter"
+
+ #
+ # Ask user to select an interface
+ #
+ local prompt size
+ prompt="$msg_select_network_interface"
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $interfaces )
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $interfaces \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# f_dialog_menu_netdev_edit $interface $ipaddr $netmask $options $dhcp
+#
+# Allow a user to edit network interface settings. Current values are not
+# probed but rather taken from the positional arguments.
+#
+f_dialog_menu_netdev_edit()
+{
+ local interface="$1" ipaddr="$2" netmask="$3" options="$4" dhcp="$5"
+ local prompt menu_list size
+
+ #
+ # Create a duplicate set of variables for change-tracking...
+ #
+ local ipaddr_orig="$2" \
+ netmask_orig="$3" \
+ options_orig="$4" \
+ dhcp_orig="$5"
+
+ local hline="$hline_arrows_tab_enter"
+ prompt=$( printf "$msg_network_configuration" "$interface" )
+
+ #
+ # Loop forever until the user has finished configuring the different
+ # components of the network interface.
+ #
+ # To apply the settings, we need to know each of the following:
+ # - IP Address
+ # - Network subnet mask
+ # - Additional ifconfig(8) options
+ #
+ # It is only when we have all of the above values that we can make the
+ # changes effective because all three options must be specified at-once
+ # to ifconfig(8).
+ #
+ while :; do
+ local dhcp_status="$msg_disabled"
+ [ "$dhcp" ] && dhcp_status="$msg_enabled"
+
+ #
+ # Display configuration-edit menu
+ #
+ menu_list="
+ 'X $msg_save_exit' '$msg_return_to_previous_menu'
+ '2 $msg_dhcp' '$dhcp_status'
+ '3 $msg_ipaddr4' '$ipaddr'
+ '4 $msg_netmask' '$netmask'
+ '5 $msg_options' '$options'
+ "
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+
+ local retval=$?
+ local tag="$( f_dialog_menutag )"
+
+ # Return if "Cancel" was chosen (-1) or ESC was pressed (255)
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ #
+ # Call the below ``modifier functions'' whose job it is to take
+ # input from the user and assign the newly-acquired values back
+ # to the ipaddr, netmask, and options variables for us to re-
+ # read and display in the summary dialog.
+ #
+ case "$tag" in
+ X\ *) break;;
+ 2\ *) #
+ # Do not proceed if/when there are NFS-mounts currently
+ # active. If the network is changed while NFS-exported
+ # directories are mounted, the system may hang (if any
+ # NFS mounts are using that interface).
+ #
+ if f_nfs_mounted && ! f_jailed; then
+ local setting="$( printf "$msg_current_dhcp_status" \
+ "$interface" "$dhcp_status" )"
+ local message="$(
+ printf "$msg_nfs_mounts_may_cause_hang" \
+ "$setting"
+ )"
+ f_dialog_msgbox "$message"
+ continue
+ fi
+
+ #
+ # Toggle DHCP status
+ #
+ if [ "$dhcp_status" = "$msg_enabled" ]; then
+ dhcp=
+ else
+ trap - SIGINT
+ ( # Execute within sub-shell to allow/catch Ctrl-C
+ trap 'exit $FAILURE' SIGINT
+ msg=$( printf "$msg_scanning_for_dhcp" "$interface" )
+ if [ "$USE_XDIALOG" ]; then
+ (
+ f_quietly ifconfig $interface delete
+ f_quietly dhclient $interface
+ ) |
+ f_xdialog_info "$msg"
+ else
+ f_dialog_info "$msg"
+ f_quietly ifconfig $interface delete
+ f_quietly dhclient $interface
+ fi
+ )
+ retval=$?
+ trap 'interrupt' SIGINT
+ if [ $retval -eq $SUCCESS ]; then
+ dhcp=1
+ ipaddr=$( f_ifconfig_inet $interface )
+ netmask=$( f_ifconfig_netmask $interface )
+ options=
+
+ # Fixup search/domain in resolv.conf(5)
+ hostname=$( f_sysrc_get \
+ 'hostname:-$(hostname)' )
+ f_dialog_resolv_conf_update "$hostname"
+ fi
+ fi
+ ;;
+ 3\ *) f_dialog_input_ipaddr "$interface" "$ipaddr"
+ [ $? -eq $SUCCESS ] && dhcp=;;
+ 4\ *) f_dialog_input_netmask "$interface" "$netmask"
+ [ $? -eq $SUCCESS -a "$_netmask" ] && dhcp=;;
+ 5\ *) f_dialog_menu_media_options "$interface" "$options"
+ [ $? -eq $SUCCESS ] && dhcp=;;
+ esac
+ done
+
+ #
+ # Save only if the user changed at least one feature of the interface
+ #
+ if [ "$ipaddr" != "$ipaddr_orig" -o \
+ "$netmask" != "$netmask_orig" -o \
+ "$options" != "$options_orig" -o \
+ "$dhcp" != "$dhcp_orig" ]
+ then
+ f_dialog_info "$( printf "$msg_saving_network_interface" \
+ "$interface" )"
+
+ local value=
+ if [ "$dhcp" ]; then
+ f_sysrc_delete defaultrouter
+ value=DHCP
+ else
+ value="inet $ipaddr netmask $netmask"
+ value="$value${options:+ }$options"
+ fi
+
+ f_sysrc_set ifconfig_$interface "$value"
+ fi
+
+ #
+ # Re/Apply the settings if desired
+ #
+ if [ ! "$dhcp" ]; then
+ f_dialog_yesno "Would you like to bring the $interface" \
+ "interface up right now?"
+ if [ $? -eq $SUCCESS ]; then
+ f_dialog_info "$( printf "$msg_bring_interface_up" \
+ "$interface" )"
+
+ local dr="$( f_sysrc_get defaultrouter )" err
+ if [ "$dr" = "NO" -o ! "$dr" ]; then
+ dr=$( f_route_get_default )
+ [ "$dr" ] && f_sysrc_set defaultrouter "$dr"
+ fi
+ #
+ # Make a backup of resolv.conf(5) before using
+ # ifconfig(8) and then restore it afterward. This
+ # allows preservation of nameservers acquired via
+ # DHCP on FreeBSD-8.x (normally lost as ifconfig(8)
+ # usage causes dhclient(8) to exit which scrubs
+ # resolv.conf(5) by-default upon termination).
+ #
+ f_quietly cp -fp "$RESOLV_CONF" "$RESOLV_CONF.$$"
+ err=$( ifconfig $interface inet $ipaddr \
+ netmask $netmask $options 2>&1 )
+ if [ $? -eq $SUCCESS ]; then
+ if [ "$dr" -a "$dr" != "NO" ]; then
+ err=$( route add default "$dr" 2>&1 )
+ [ $? -eq $SUCCESS ] || \
+ dialog_msgbox "$err"
+ fi
+ else
+ dialog_msgbox "$err"
+ fi
+ if cmp -s "$RESOLV_CONF" "$RESOLV_CONF.$$"; then
+ f_quietly rm -f "$RESOLV_CONF.$$"
+ else
+ f_quietly mv -f "$RESOLV_CONF.$$" "$RESOLV_CONF"
+ fi
+ fi
+ fi
+
+ return $SUCCESS
+}
+
+fi # ! $_NETWORKING_DEVICE_SUBR
diff --git a/usr.sbin/bsdconfig/networking/include/hostname.subr b/usr.sbin/bsdconfig/networking/include/hostname.subr
new file mode 100644
index 0000000..0f671fe
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/hostname.subr
@@ -0,0 +1,211 @@
+if [ ! "$_NETWORKING_HOSTNAME_SUBR" ]; then _NETWORKING_HOSTNAME_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/sysrc.subr
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/common.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/resolv.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_dialog_validate_hostname $hostname
+#
+# Returns zero if the given argument (a fully-qualified hostname) is compliant
+# with standards set-forth in RFC's 952 and 1123 of the Network Working Group:
+#
+# RFC 952 - DoD Internet host table specification
+# http://tools.ietf.org/html/rfc952
+#
+# RFC 1123 - Requirements for Internet Hosts - Application and Support
+# http://tools.ietf.org/html/rfc1123
+#
+# See http://en.wikipedia.org/wiki/Hostname for a brief overview.
+#
+# The return status for invalid hostnames is one of:
+# 255 Entire hostname exceeds the maximum length of 255 characters.
+# 63 One or more individual labels within the hostname (separated by
+# dots) exceeds the maximum of 63 characters.
+# 1 One or more individual labels within the hostname contains one
+# or more invalid characters.
+# 2 One or more individual labels within the hostname starts or
+# ends with a hyphen (hyphens are allowed, but a label cannot
+# begin or end with a hyphen).
+# 3 One or more individual labels within the hostname are null.
+#
+# If the hostname is determined to be invalid, the appropriate error will be
+# displayed using the f_dialog_msgbox function.
+#
+f_dialog_validate_hostname()
+{
+ local fqhn="$1"
+
+ ( # Operate within a sub-shell to protect the parent environment
+
+ # Return error if the hostname exceeds 255 characters
+ [ ${#fqhn} -gt 255 ] && exit 255
+
+ IFS="." # Split on `dot'
+ for label in $fqhn; do
+
+ # Return error if the label exceeds 63 characters
+ [ ${#label} -gt 63 ] && exit 63
+
+ # Return error if the label is null
+ [ "$label" ] || exit 3
+
+ # Return error if label begins/ends with dash
+ case "$label" in
+ -*|*-) exit 2
+ esac
+
+ # Return error if the label contains any invalid chars
+ echo "$label" | grep -q '^[[:alnum:]-]*$' || exit 1
+
+ done
+ )
+
+ #
+ # Produce an appropriate error message if necessary.
+ #
+ local retval=$?
+ case $retval in
+ 1) f_dialog_msgbox "$( printf \
+ "$msg_hostname_label_contains_invalid_chars" "$fqhn" )";;
+ 2) f_dialog_msgbox "$( printf \
+ "$msg_hostname_label_starts_or_ends_with_hyphen" "$fqhn" )";;
+ 3) f_dialog_msgbox "$( printf \
+ "$msg_hostname_label_is_null" "$fqhn" )";;
+ 63) f_dialog_msgbox "$( printf \
+ "$msg_hostname_label_exceeds_max_length" "$fqhn" )";;
+ 255) f_dialog_msgbox "$( printf \
+ "$msg_hostname_exceeds_max_length" "$fqhn" )";;
+ esac
+
+ return $retval
+}
+
+# f_dialog_input_hostname
+#
+# Edits the current hostname.
+#
+f_dialog_input_hostname()
+{
+ local hostname="$( f_sysrc_get 'hostname:-$(hostname)' )"
+ local hostname_orig="$hostname" # for change-tracking
+
+ local msg
+ if [ "$USE_XDIALOG" ]; then
+ msg="$xmsg_please_enter_fqhn"
+ else
+ msg="$msg_please_enter_fqhn"
+ fi
+
+ local hline="$hline_alnum_punc_tab_enter"
+
+ #
+ # Loop until the user provides taint-free input.
+ #
+ local size height width
+ while :; do
+
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hostname" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$hostname\" \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+
+ local retval=$?
+ hostname=$( f_dialog_inputstr )
+
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Taint-check the user's input
+ f_dialog_validate_hostname "$hostname" && break
+
+ done
+
+ #
+ # Save hostname only if the user changed the hostname.
+ #
+ if [ "$hostname" != "$hostname_orig" ]; then
+ f_dialog_info "$msg_saving_hostname"
+ f_sysrc_set hostname "$hostname"
+ fi
+
+ #
+ # Update resolv.conf(5) search/domain directives
+ #
+ f_dialog_resolv_conf_update "$hostname"
+
+ #
+ # Only ask to apply setting if the current hostname is different than
+ # the stored configuration (in rc.conf(5)).
+ #
+ if [ "$( hostname )" != "$( f_sysrc_get hostname )" ]; then
+ [ ! "$USE_XDIALOG" ] && dialog_clear
+
+ #
+ # If connected via ssh(1) and performing X11-Forwarding, don't
+ # allow the hostname to be changed to prevent the fatal error
+ # "X11 connection rejected because of wrong authentication."
+ #
+ if [ "$USE_XDIALOG" -a "$SSH_CONNECTION" ]; then
+ f_dialog_msgbox "$(
+ printf "$msg_activate_hostname_x11warning" \
+ "$( hostname )" "$hostname"
+ )"
+ else
+ f_dialog_yesno "$(
+ printf "$msg_activate_hostname" \
+ "$( hostname )" "$hostname" \
+ )" \
+ && hostname "$hostname"
+ fi
+ fi
+
+ return $SUCCESS
+}
+
+fi # ! $_NETWORKING_HOSTNAME_SUBR
diff --git a/usr.sbin/bsdconfig/networking/include/ipaddr.subr b/usr.sbin/bsdconfig/networking/include/ipaddr.subr
new file mode 100644
index 0000000..7333302
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/ipaddr.subr
@@ -0,0 +1,236 @@
+if [ ! "$_NETWORKING_IPADDR_SUBR" ]; then _NETWORKING_IPADDR_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/sysrc.subr
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/common.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_ifconfig_inet $interface
+#
+# Returns the IPv4 address associated with $interface.
+#
+f_ifconfig_inet()
+{
+ local interface="$1"
+ ifconfig "$interface" 2> /dev/null | awk \
+ '
+ BEGIN { found = 0 }
+ ( $1 == "inet" ) \
+ {
+ print $2
+ found = 1
+ exit
+ }
+ END { exit ! found }
+ '
+}
+
+# f_dialog_validate_ipaddr $ipaddr
+#
+# Returns zero if the given argument (an IP address) is of the proper format.
+#
+# The return status for invalid IP address is one of:
+# 1 One or more individual octets within the IP address (separated
+# by dots) contains one or more invalid characters.
+# 2 One or more individual octets within the IP address are null
+# and/or missing.
+# 3 One or more individual octets within the IP address exceeds the
+# maximum of 255 (or 2^8, being an octet comprised of 8 bits).
+# 4 The IP address has either too few or too many octets.
+#
+# If the IP address is determined to be invalid, the appropriate error will be
+# displayed using the above dialog_msgbox function.
+#
+f_dialog_validate_ipaddr()
+{
+ local ip="$1"
+
+ ( # Operate within a sub-shell to protect the parent environment
+
+ # Track number of octets for error checking
+ noctets=0
+
+ IFS="." # Split on `dot'
+ for octet in $ip; do
+
+ # Return error if the octet is null
+ [ "$octet" ] || exit 2
+
+ # Return error if not a whole integer
+ f_isinteger "$octet" || exit 1
+
+ # Return error if not a positive integer
+ [ $octet -ge 0 ] || exit 1
+
+ # Return error if the octet exceeds 255
+ [ $octet -gt 255 ] && exit 3
+
+ noctets=$(( $noctets + 1 ))
+
+ done
+
+ [ $noctets -eq 4 ] || exit 4
+ )
+
+ #
+ # Produce an appropriate error message if necessary.
+ #
+ local retval=$?
+ case $retval in
+ 1) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_addr_octet_contains_invalid_chars" "$ip" )";;
+ 2) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_addr_octet_is_null" "$ip" )";;
+ 3) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_addr_octet_exceeds_max_value" "$ip" )";;
+ 4) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_addr_octet_missing_or_extra" "$ip" )";;
+ esac
+
+ return $retval
+}
+
+# f_dialog_input_ipaddr $interface $ipaddr
+#
+# Allows the user to edit a given IP address. If the user does not cancel or
+# press ESC, the $ipaddr environment variable will hold the newly-configured
+# value upon return.
+#
+# Optionally, the user can enter the format "IP_ADDRESS/NBITS" to set the
+# netmask at the same time as the IP address. If such a format is entered by
+# the user, the $netmask environment variable will hold the newly-configured
+# netmask upon return.
+#
+f_dialog_input_ipaddr()
+{
+ local interface="$1" _ipaddr="$2" _input
+
+ #
+ # Return with-error when there are NFS-mounts currently active. If the
+ # IP address is changed while NFS-exported directories are mounted, the
+ # system may hang (if any NFS mounts are using that interface).
+ #
+ if f_nfs_mounted && ! f_jailed; then
+ local setting="$( printf "$msg_current_ipaddr" \
+ "$interface" "$_ipaddr" )"
+ local message="$( printf "$msg_nfs_mounts_may_cause_hang" \
+ "$setting" )"
+ f_dialog_msgbox "$message"
+ return $FAILURE
+ fi
+
+ local msg="$( printf "$msg_please_enter_new_ip_addr" "$interface" )"
+ local hline="$hline_num_punc_tab_enter"
+ local size="$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_ipaddr" \
+ "$hline" )"
+
+ #
+ # Loop until the user provides taint-free input.
+ #
+ while :; do
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_ipaddr\" \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+
+ local retval=$?
+ _input=$( f_dialog_inputstr )
+
+ #
+ # Return error status if:
+ # - User has not made any changes to the given value
+ # - User has either pressed ESC or chosen Cancel/No
+ #
+ [ "$_ipaddr" = "$_input" ] && return $FAILURE
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Return success if NULL value was entered
+ [ "$_input" ] || return $SUCCESS
+
+ # Take only the first "word" of the user's input
+ _ipaddr="$_input"
+ _ipaddr="${_ipaddr%%[$IFS]*}"
+
+ # Taint-check the user's input
+ f_dialog_validate_ipaddr "${_ipaddr%%/*}" && break
+ done
+
+ #
+ # Support the syntax: IP_ADDRESS/NBITS
+ #
+ local _netmask=""
+ case "$_ipaddr" in
+ */*)
+ local nbits="${_ipaddr#*/}" n=0
+ _ipaddr="${_ipaddr%%/*}"
+
+ #
+ # Taint-check $nbits to be (a) a positive whole-integer,
+ # and (b) to be less than or equal to 32. Otherwise, set
+ # $n so that the below loop never executes.
+ #
+ ( f_isinteger "$nbits" && [ $nbits -ge 0 -a $nbits -le 32 ] ) \
+ || n=4
+
+ while [ $n -lt 4 ]; do
+ _netmask="$_netmask${_netmask:+.}$((
+ (65280 >> ($nbits - 8 * $n) & 255)
+ * ((8*$n) < $nbits & $nbits <= (8*($n+1)))
+ + 255 * ($nbits > (8*($n+1)))
+ ))"
+ n=$(( $n + 1 ))
+ done
+ ;;
+ esac
+
+ ipaddr="$_ipaddr"
+ [ "$_netmask" ] && netmask="$_netmask"
+
+ return $SUCCESS
+}
+
+fi # ! $_NETWORKING_IPADDR_SUBR
diff --git a/usr.sbin/bsdconfig/networking/include/media.subr b/usr.sbin/bsdconfig/networking/include/media.subr
new file mode 100644
index 0000000..0f0f9fe
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/media.subr
@@ -0,0 +1,235 @@
+if [ ! "$_NETWORKING_MEDIA_SUBR" ]; then _NETWORKING_MEDIA_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/common.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_ifconfig_options $interface
+#
+# Returns any/all extra ifconfig(8) parameters associated with $interface.
+#
+f_ifconfig_options()
+{
+ local interface="$1"
+ [ "$interface" ] || return $SUCCESS
+
+ #
+ # Loop over the options, removing what we don't want
+ #
+ (
+ set -- $( f_sysrc_get ifconfig_$interface )
+
+ #
+ # Return if the the interface is configured for DHCP
+ #
+ glob="[Dd][Hh][Cc][Pp]"
+ case "$*" in
+ $glob|[Ss][Yy][Nn][Cc]$glob|[Nn][Oo][Ss][Yy][Nn][Cc]$glob)
+ exit $SUCCESS
+ esac
+
+ output=
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ inet|netmask) shift 1;;
+ *) output="$output${output:+ }$1"
+ esac
+ shift 1
+ done
+ echo "$output"
+ )
+}
+
+# f_ifconfig_media $interface
+#
+# Returns list of supported media for $interface.
+#
+f_ifconfig_media()
+{
+ local interface="$1"
+ ifconfig -m "$interface" 2> /dev/null | awk \
+ '
+ BEGIN { media_found = 0 }
+ {
+ if ( media_found == 1 ) { print; next }
+ }
+ ( $1 $2 == "supported" "media:" ) \
+ {
+ media_found = 1
+ next
+ }
+ END { exit ! media_found }
+ '
+}
+
+# f_dialog_input_options $interface
+#
+# Input custom interface options.
+#
+f_dialog_input_options()
+{
+ local interface="$1"
+
+ #
+ # Return with-error when there are NFS-mounts currently active. If the
+ # options are changed while NFS-exported directories are mounted,
+ # the system may hang (if any NFS mounts are using that interface).
+ #
+ if f_nfs_mounted && ! f_jailed; then
+ local setting="$( printf "$msg_current_options" \
+ "$interface" "$options" )"
+ local message="$( printf "$msg_nfs_mounts_may_cause_hang" \
+ "$setting" )"
+ f_dialog_msgbox "$message"
+ return $FAILURE
+ fi
+
+ local msg="$( printf "$msg_please_enter_mediaopts" "$interface" )"
+ local hline="$hline_alnum_punc_tab_enter"
+
+ $DIALOG \
+ --title "$DIALOG_TITLE" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --inputbox "$msg" 9 70 \
+ "$options" \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+
+ local retval=$?
+ local _options="$( f_dialog_inputstr )"
+
+ [ $retval -eq $SUCCESS ] && options="$_options"
+
+ return $retval
+}
+
+# f_dialog_menu_media_options $interface
+#
+# Display a menu of additional media options for the given network interface.
+#
+f_dialog_menu_media_options()
+{
+ local interface="$1" _options="$2"
+ #
+ # Not all network interfaces support additional media options, but
+ # when available we should prompt the user to select from a list
+ # of available options (or none, as is the first/default option).
+ #
+
+ #
+ # Return with-error when there are NFS-mounts currently active. If the
+ # media options are changed while NFS-exported directories are mounted,
+ # the system may hang (if any NFS mounts are using that interface).
+ #
+ if f_nfs_mounted && ! f_jailed; then
+ local setting="$( printf "$msg_current_options" \
+ "$interface" "$_options" )"
+ local message="$( printf "$msg_nfs_mounts_may_cause_hang" \
+ "$setting" )"
+ f_dialog_msgbox "$message"
+ return $FAILURE
+ fi
+
+ #
+ # Build list of additional media options
+ #
+ local opt_none="$msg_no_options"
+ local opt_cust="$msg_custom"
+ local supported_media="$(
+ f_ifconfig_media $interface | \
+ ( index=1
+
+ echo "'$( f_substr "$DIALOG_MENU_TAGS" $index 1 )'"
+ echo "'$opt_none'"
+ index=$(( $index + 1 ))
+
+ echo "'$( f_substr "$DIALOG_MENU_TAGS" $index 1 )'"
+ echo "'$opt_cust'"
+ index=$(( $index + 1 ))
+
+ while read media_options; do
+ [ $index -lt ${#DIALOG_MENU_TAGS} ] || break
+ echo "'$( f_substr "$DIALOG_MENU_TAGS" $index 1 )'"
+ echo "'$media_options'"
+ index=$(( $index + 1 ))
+ done
+ )
+ )"
+
+ local msg
+ if [ "$USE_XDIALOG" ]; then
+ msg=$( printf "$xmsg_supported_media_options" \
+ "$interface" "$interface" )
+ else
+ msg=$( printf "$msg_supported_media_options" \
+ "$interface" "$interface" )
+ fi
+
+ local hline="$hline_arrows_tab_enter"
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$msg\" 21 60 12 \
+ $supported_media \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+
+ local retval=$?
+ if [ $retval -eq $SUCCESS ]; then
+ local tag="$( f_dialog_menutag )"
+ options=$( eval f_dialog_menutag2item \"\$tag\" \
+ $supported_media )
+ [ "$options" = "$opt_none" ] && options=
+
+ if [ "$options" = "$opt_cust" ]; then
+ options="$_options"
+ f_dialog_input_options "$interface"
+ retval=$?
+ fi
+ fi
+
+ return $retval
+}
+
+fi # ! $_NETWORKING_MEDIA_SUBR
diff --git a/usr.sbin/bsdconfig/networking/include/messages.subr b/usr.sbin/bsdconfig/networking/include/messages.subr
new file mode 100644
index 0000000..dac8e20
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/messages.subr
@@ -0,0 +1,100 @@
+# Copyright (c) 2012 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$
+
+hline_alnum_punc_tab_enter="Use alpha-numeric, punctuation, TAB or ENTER"
+hline_arrows_tab_enter="Press arrows, TAB or ENTER"
+hline_num_punc_tab_enter="Use numbers, punctuation, TAB or ENTER"
+msg_activate_default_router="Would you like to activate the new defaultrouter right now?\nIf you choose NO or press ESC, changes will be applied\nduring the next boot.\n\n Current Default Router: %s\n New Default Router: %s\n"
+msg_activate_hostname="Would you like to activate the new hostname right now?\nIf you choose NO or press ESC, changes will be applied\nduring the next boot.\n\n Current Hostname: %s\n New Hostname: %s\n\nNOTE: Your shell prompt may still reflect the original\nhostname until your next login."
+msg_activate_hostname_x11warning="WARNING! Activating the new hostname during an X11-Forwarded\n ssh(1) session will cause an X11 authentication error.\n\n Current Hostname: %s\n New Hostname: %s\n\nNOTE: Settings will become active upon reboot or if you\n relaunch this utility either locally or on the console."
+msg_add="Add"
+msg_add_nameserver="Add a new nameserver"
+msg_bring_interface_up="Would you like to bring the %s interface up right now?"
+msg_cancel="Cancel"
+msg_current_default_router="Current Default Route/Gateway: %s"
+msg_current_dhcp_status="Current DHCP status for %s: %s"
+msg_current_ipaddr="Current IP Address for %s: %s"
+msg_current_options="Current Options for %s: %s"
+msg_current_subnet="Current Subnet Mask for %s: %s"
+msg_custom="Custom (Manual)"
+msg_default_router="Default Router/Gateway"
+msg_dhcp="DHCP"
+msg_disabled="Disabled"
+msg_dns_configuration="DNS Nameserver Configuration:\nChoose Exit when finished else Cancel."
+msg_dns_nameservers="DNS nameservers"
+msg_enabled="Enabled"
+msg_exit="Exit"
+msg_hostname_domain="Hostname/Domain"
+msg_hostname_exceeds_max_length="ERROR! The hostname entered exceeds the maximum length of\n255 characters.\n\nInvalid Hostname: %s"
+msg_hostname_label_contains_invalid_chars="ERROR! One or more individual labels within the hostname\n(separated by dots) contains one or more invalid characters.\nLabels are case-insensitive and must contain only 0-9, a-z,\n or dash (though must not begin with or end with a dash).\n\nInvalid Hostname: %s"
+msg_hostname_label_exceeds_max_length="ERROR! One or more individual labels within the hostname\n(separated by dots) exceeds the maximum of 63 characters.\n\nInvalid Hostname: %s"
+msg_hostname_label_is_null="ERROR! One or more individual labels within the hostname\n(separated by dots) are null.\n\nInvalid Hostname: %s"
+msg_hostname_label_starts_or_ends_with_hyphen="ERROR! One or more individual labels within the hostname\n(separated by dots) starts or ends with a hyphen (hyphens\nare allowed, but a label cannot begin or end with a hyphen).\n\nInvalid Hostname: %s"
+msg_internal_error_nsindex_value="FATAL! dialog_input_nameserver_edit_awk: variable\nnsindex must be a whole positive integer greater-\nthan or equal-to zero.\n\nInvalid nsindex: %s"
+msg_ipaddr4="ipaddr"
+msg_ipv4_addr_octet_contains_invalid_chars="ERROR! One or more individual octets within the IP address\n(separated by dots) contains one or more invalid characters.\nOctets must contain only the characters 0-9.\n\nInvalid IP Address: %s"
+msg_ipv4_addr_octet_exceeds_max_value="ERROR! One or more individual octets within the IP address\n(separated by dots) exceeds the maximum of 255.\n\nInvalid IP Address: %s"
+msg_ipv4_addr_octet_is_null="ERROR! One or more individual octets within the IP address\n(separated by dots) are null and/or missing.\n\nInvalid IP Address: %s"
+msg_ipv4_addr_octet_missing_or_extra="ERROR! The IP address entered has either too few or too many\noctets.\n\nInvalid IP Address: %s"
+msg_ipv4_mask_field_contains_invalid_chars="ERROR! One or more individual fields within the subnet mask\n(separated by dots) contains one or more invalid characters.\n\nInvalid Subnet Mask: %s"
+msg_ipv4_mask_field_exceeds_max_value="ERROR! One or more individual fields within the subnet mask\n(separated by dots) exceeds the maximum of 255.\n\nInvalid Subnet Mask: %s"
+msg_ipv4_mask_field_invalid_value="ERROR! One or more individual fields within the subnet mask\n(separated by dots) contains one or more invalid integers.\nFields must be one of 0/128/192/224/240/248/252/254/255.\n\nInvalid Subnet Mask: %s"
+msg_ipv4_mask_field_is_null="ERROR! One or more individual fields within the subnet mask\n(separated by dots) are null and/or missing.\n\nInvalid Subnet Mask: %s"
+msg_ipv4_mask_field_missing_or_extra="ERROR! The subnet mask entered has either too few or too many\nfields.\n\nInvalid Subnet Mask: %s"
+msg_netmask="netmask"
+msg_network_configuration="%s Network Configuration:\nChoose Save/Exit when finished or Cancel."
+msg_network_interfaces="Network Interfaces"
+msg_network_management="Network Management"
+msg_networking_devices="Networking Devices"
+msg_nfs_mounts_may_cause_hang="WARNING! Changing this setting while NFS directories are\nmounted may cause the system to hang. Please exit this\nutility and dismount any/all remaining NFS-mounts before\nattempting to change this setting.\n\n%s"
+msg_no_network_interfaces="No network interfaces detected."
+msg_no_options="No options (Default)"
+msg_ok="OK"
+msg_options="options"
+msg_please_enter_default_router="Please enter the IP address of your default\nrouter/gateway. The address entered will be\napplied as the default gateway for all interfaces\nusing route(4)."
+msg_please_enter_fqhn="Please enter your fully qualified hostname (e.g. full.example.com). The\ndomain portion of the hostname will be configured in resolv.conf(5)."
+msg_please_enter_mediaopts="Please enter additional network media options to be passed to ifconfig(8) for the %s interface:"
+msg_please_enter_nameserver="Please enter the new IP address of the DNS nameserver:"
+msg_please_enter_nameserver_existing="Please enter the new IP address of the DNS nameserver\n(set to the NULL string [Ctrl-U] to remove entry):"
+msg_please_enter_new_ip_addr="Please enter the new IP address of the %s interface:"
+msg_please_enter_subnet_mask="Please enter the new network subnet mask for the %s interface:"
+msg_probing_network_interfaces="Probing network interface devices..."
+msg_removing_nameserver="Removing DNS nameserver from resolv.conf(5)..."
+msg_resolv_conf_changed_while_editing="ERROR! resolv.conf(5) has changed while editing this\nvalue. Please try again after waiting a few seconds."
+msg_resolv_conf_entry_no_longer_exists="ERROR! The entry you are trying to edit no longer\nexists in resolv.conf(5). Please try again after\nwaiting a few seconds."
+msg_return_to_previous_menu="Return to previous menu"
+msg_save_exit="Save/Exit"
+msg_saving_default_router="Saving new default router/gateway settings..."
+msg_saving_hostname="Saving new hostname/domain settings..."
+msg_saving_nameserver="Saving new DNS nameserver to resolv.conf(5)..."
+msg_saving_nameserver_existing="Editing DNS nameserver in resolv.conf(5)..."
+msg_saving_network_interface="Saving %s network interface settings..."
+msg_scanning_for_dhcp="Scanning for DHCP servers on %s interface..."
+msg_select_network_interface="Select a network interface to configure.\n\n* Interface is marked as \"active\""
+msg_supported_media_options="Below is a list of supported media options for the %s interface. Please select the options that you would like to set for the %s network interface"
+xmsg_please_enter_fqhn="Please enter your fully qualified hostname (e.g. foo.bar.com).\n The domain portion of the hostname will be configured in resolv.conf(5)."
+xmsg_please_enter_nameserver_existing="Please enter the new IP address of the DNS nameserver\n(set to the NULL string to remove entry):"
+xmsg_supported_media_options="Below is a list of supported media options for the %s interface. Please\nselect the options that you would like to set for the %s network interface"
diff --git a/usr.sbin/bsdconfig/networking/include/netmask.subr b/usr.sbin/bsdconfig/networking/include/netmask.subr
new file mode 100644
index 0000000..169acca
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/netmask.subr
@@ -0,0 +1,215 @@
+if [ ! "$_NETWORKING_NETMASK_SUBR" ]; then _NETWORKING_NETMASK_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/common.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_ifconfig_netmask $interface
+#
+# Returns the IPv4 subnet mask associated with $interface.
+#
+f_ifconfig_netmask()
+{
+ local interface="$1" octets
+ octets=$( ifconfig "$interface" 2> /dev/null | awk \
+ '
+ BEGIN { found = 0 }
+ ( $1 == "inet" ) \
+ {
+ printf "%s %s %s %s\n",
+ substr($4,3,2),
+ substr($4,5,2),
+ substr($4,7,2),
+ substr($4,9,2)
+ found = 1
+ exit
+ }
+ END { exit ! found }
+ ' ) || return $FAILURE
+
+ local octet netmask=
+ for octet in $octets; do
+ netmask="$netmask${netmask:+.}$( printf "%u" "0x$octet" )"
+ done
+ echo $netmask
+}
+
+# f_dialog_validate_netmask $netmask
+#
+# Returns zero if the given argument (a subnet mask) is of the proper format.
+#
+# The return status for invalid IP address is one of:
+# 1 One or more individual fields within the subnet mask (separated
+# by dots) contains one or more invalid characters.
+# 2 One or more individual fields within the subnet mask are null
+# and/or missing.
+# 3 One or more individual fields within the subnet mask exceeds
+# the maximum of 255 (a full 8-bit register).
+# 4 The subnet mask has either too few or too many fields.
+# 5 One or more individual fields within the subnet mask is an
+# invalid integer (only 0,128,192,224,240,248,252,254,255 are
+# valid integers).
+#
+# If the subnet mask is determined to be invalid, the appropriate error will be
+# displayed using the f_dialog_msgbox function.
+#
+f_dialog_validate_netmask()
+{
+ local mask="$1"
+
+ ( # Operate within a sub-shell to protect the parent environment
+
+ # Track number of fields for error checking
+ nfields=0
+
+ IFS="." # Split on `dot'
+ for field in $mask; do
+
+ # Return error if the field is null
+ [ "$field" ] || exit 2
+
+ # Return error if not a whole positive integer
+ f_isinteger "$field" || exit 1
+
+ # Return error if the field exceeds 255
+ [ $field -gt 255 ] && exit 3
+
+ # Return error if the field is an invalid integer
+ case "$field" in
+ 0|128|192|224|240|248|252|254|255) :;;
+ *) exit 5;;
+ esac
+
+ nfields=$(( $nfields + 1 ))
+
+ done
+
+ [ $nfields -eq 4 ] || exit 4
+ )
+
+ #
+ # Produce an appropriate error message if necessary.
+ #
+ local retval=$?
+ case $retval in
+ 1) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_mask_field_contains_invalid_chars" "$mask" )";;
+ 2) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_mask_field_is_null" "$mask" )";;
+ 3) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_mask_field_exceeds_max_value" "$mask" )";;
+ 4) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_mask_field_missing_or_extra" "$mask" )";;
+ 5) f_dialog_msgbox "$( printf \
+ "$msg_ipv4_mask_field_invalid_value" "$mask" )";;
+ esac
+
+ return $retval
+}
+
+# f_dialog_input_netmask $interface $netmask
+#
+# Edits the IP netmask of the given interface.
+#
+f_dialog_input_netmask()
+{
+ local interface="$1" _netmask="$2" _input
+
+ #
+ # Return with-error when there are NFS-mounts currently active. If the
+ # subnet mask is changed while NFS-exported directories are mounted,
+ # the system may hang (if any NFS mounts are using that interface).
+ #
+ if f_nfs_mounted && ! f_jailed; then
+ local setting="$( printf "$msg_current_subnet" \
+ "$interface" "$_netmask" )"
+ local message="$( printf "$msg_nfs_mounts_may_cause_hang" \
+ "$setting" )"
+ f_dialog_msgbox "$message"
+ return $FAILURE
+ fi
+
+ local msg="$( printf "$msg_please_enter_subnet_mask" "$interface" )"
+ local hline="$hline_num_punc_tab_enter"
+ local size="$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_netmask" \
+ "$hline" )"
+
+ #
+ # Loop until the user provides taint-free input.
+ #
+ while :; do
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_netmask\" \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+
+ local retval=$?
+ _input=$( f_dialog_inputstr )
+
+ #
+ # Return error status if:
+ # - User has not made any changes to the given value
+ # - User has either pressed ESC or chosen Cancel/No
+ #
+ [ "$_netmask" = "$_input" ] && return $FAILURE
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Return success if NULL value was entered
+ [ "$_input" ] || return $SUCCESS
+
+ # Take only the first "word" of the user's input
+ _netmask="$_input"
+ _netmask="${_netmask%%[$IFS]*}"
+
+ # Taint-check the user's input
+ f_dialog_validate_netmask "$_netmask" && break
+ done
+
+ netmask="$_netmask"
+}
+
+fi # ! $_NETWORKING_NETMASK_SUBR
diff --git a/usr.sbin/bsdconfig/networking/include/resolv.subr b/usr.sbin/bsdconfig/networking/include/resolv.subr
new file mode 100644
index 0000000..8eab18e
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/resolv.subr
@@ -0,0 +1,509 @@
+if [ ! "$_NETWORKING_RESOLV_SUBR" ]; then _NETWORKING_RESOLV_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/common.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/ipaddr.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Path to resolv.conf(5).
+#
+: ${RESOLV_CONF:="/etc/resolv.conf"}
+
+#
+# When updating resolv.conf(5), should we populate the `search' directive with
+# all possible sub-domains? In example, if the domain is "sub.domain.com", when
+# the below option is set to 1, include both "sub.domain.com" and "domain.com"
+# in the `search' directive, otherwise use only "sub.domain.com".
+#
+# When enabled (set to 1), specify the minimum number of dots required for each
+# `search' domain by setting the second option below, `RESOLVER_SEARCH_NDOTS'.
+#
+: ${RESOLVER_SEARCH_DOMAINS_ALL:=1}
+: ${RESOLVER_SEARCH_NDOTS:=1}
+
+############################################################ FUNCTIONS
+
+# f_resolv_conf_domain
+#
+# Returns the domain configured in resolv.conf(5).
+#
+f_resolv_conf_domain()
+{
+ tail -r "$RESOLV_CONF" 2> /dev/null | awk \
+ '
+ BEGIN { found = 0 }
+ ( tolower($1) == "domain" ) \
+ {
+ print $2
+ found = 1
+ exit
+ }
+ END { exit ! found }
+ '
+}
+
+# f_resolv_conf_search
+#
+# Returns the search configured in resolv.conf(5).
+#
+f_resolv_conf_search()
+{
+ tail -r "$RESOLV_CONF" 2> /dev/null | awk \
+ '
+ BEGIN { found = 0 }
+ {
+ tl0 = tolower($0)
+ if ( match(tl0, /^[[:space:]]*search[[:space:]]+/) ) {
+ search = substr($0, RLENGTH + 1)
+ sub(/[[:space:]]*#.*$/, "", search)
+ gsub(/[[:space:]]+/, " ", search)
+ print search
+ found = 1
+ exit
+ }
+ }
+ END { exit ! found }
+ '
+}
+
+# f_resolv_conf_nameservers
+#
+# Returns nameserver(s) configured in resolv.conf(5).
+#
+f_resolv_conf_nameservers()
+{
+ awk \
+ '
+ BEGIN { found = 0 }
+ ( $1 == "nameserver" ) \
+ {
+ print $2
+ found = 1
+ }
+ END { exit ! found }
+ ' \
+ "$RESOLV_CONF" 2> /dev/null
+}
+
+# f_dialog_resolv_conf_update $hostname
+#
+# Updates the search/domain directives in resolv.conf(5) given a valid fully-
+# qualified hostname.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_dialog_resolv_conf_update_awk='
+# Variables that should be defined on the invocation line:
+# -v domain="domain"
+# -v search_all="0|1"
+# -v search_ndots="1+"
+#
+BEGIN {
+ domain_found = search_found = 0
+
+ if ( search_all ) {
+ search = ""
+ subdomain = domain
+ if ( search_ndots < 1 )
+ search_ndots = 1
+
+ ndots = split(subdomain, labels, ".") - 1
+ while ( ndots-- >= search_ndots ) {
+ if ( length(search) ) search = search " "
+ search = search subdomain
+ sub(/[^.]*\./, "", subdomain)
+ }
+ }
+ else search = domain
+}
+{
+ if ( domain_found && search_found ) { print; next }
+
+ tl0 = tolower($0)
+ if ( ! domain_found && \
+ match(tl0, /^[[:space:]]*domain[[:space:]]+/) ) \
+ {
+ if ( length(domain) ) {
+ printf "%s%s\n", substr($0, 0, RLENGTH), domain
+ domain_found = 1
+ }
+ }
+ else if ( ! search_found && \
+ match(tl0, /^[[:space:]]*search[[:space:]]+/) ) \
+ {
+ if ( length(search) ) {
+ printf "%s%s\n", substr($0, 0, RLENGTH), search
+ search_found = 1
+ }
+ }
+ else print
+}
+END {
+ if ( ! search_found && length(search) )
+ printf "search\t%s\n", search
+ if ( ! domain_found && length(domain) )
+ printf "domain\t%s\n", domain
+}
+'
+f_dialog_resolv_conf_update()
+{
+ local hostname="$1"
+
+ #
+ # Extrapolate the desired domain search parameter for resolv.conf(5)
+ #
+ local search ndots domain="${hostname#*.}"
+ if [ "$RESOLVER_SEARCH_DOMAINS_ALL" = "1" ]; then
+ search=""
+ ndots=$( IFS=.; set -- $domain; echo $(( $# - 1 )) )
+ while [ $ndots -ge ${RESOLVER_SEARCH_NDOTS:-1} ]; do
+ search="$search${search:+ }$domain"
+ domain="${domain#*.}"
+ ndots=$(( $ndots - 1 ))
+ done
+ domain="${hostname#*.}"
+ else
+ search="$domain"
+ fi
+
+ #
+ # Save domain/search information only if different from resolv.conf(5)
+ #
+ if [ "$domain" != "$( f_resolv_conf_domain )" -o \
+ "$search" != "$( f_resolv_conf_search )" ]
+ then
+ f_dialog_info "Saving new domain/search settings" \
+ "to resolv.conf(5)..."
+
+ #
+ # Create a new temporary file to write our resolv.conf(5)
+ # update with our new `domain' and `search' directives.
+ #
+ local tmpfile="$( mktemp -t "$pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ #
+ # Fixup permissions and ownership (mktemp(1) creates the
+ # temporary file with 0600 permissions -- change the
+ # permissions and ownership to match resolv.conf(5) before
+ # we write it out and mv(1) it into place).
+ #
+ local mode="$( stat -f '%#Lp' "$RESOLV_CONF" 2> /dev/null )"
+ local owner="$( stat -f '%u:%g' "$RESOLV_CONF" 2> /dev/null )"
+ f_quietly chmod "${mode:-0644}" "$tmpfile"
+ f_quietly chown "${owner:-root:wheel}" "$tmpfile"
+
+ #
+ # Operate on resolv.conf(5), replacing only the last
+ # occurrences of `domain' and `search' directives (or add
+ # them to the top if not found), in strict-adherence to the
+ # following entry in resolver(5):
+ #
+ # The domain and search keywords are mutually exclusive.
+ # If more than one instance of these keywords is present,
+ # the last instance will override.
+ #
+ # NOTE: If RESOLVER_SEARCH_DOMAINS_ALL is set to `1' in the
+ # environment, all sub-domains will be added to the `search'
+ # directive, not just the FQDN.
+ #
+ local domain="${hostname#*.}" new_contents
+ [ "$domain" = "$hostname" ] && domain=
+ new_contents=$( tail -r "$RESOLV_CONF" 2> /dev/null )
+ new_contents=$( echo "$new_contents" | awk \
+ -v domain="$domain" \
+ -v search_all="${RESOLVER_SEARCH_DOMAINS_ALL:-1}" \
+ -v search_ndots="${RESOLVER_SEARCH_NDOTS:-1}" \
+ "$f_dialog_resolv_conf_update_awk" )
+
+ #
+ # Write the temporary file contents and move the temporary
+ # file into place.
+ #
+ echo "$new_contents" | tail -r > "$tmpfile" || return $FAILURE
+ f_quietly mv "$tmpfile" "$RESOLV_CONF"
+
+ fi
+}
+
+# f_dialog_input_nameserver [ $n $nameserver ]
+#
+# Allows the user to edit a given nameserver. The first argument is the
+# resolv.conf(5) nameserver ``instance'' integer. For example, this will be one
+# if editing the first nameserver instance, two if editing the second, three if
+# the third, ad nauseum. If this argument is zero, null, or missing, the value
+# entered by the user (if non-null) will be added to resolv.conf(5) as a new
+# `nameserver' entry. The second argument is the IPv4 address of the nameserver
+# to be edited -- this will be displayed as the initial value during the edit.
+#
+# Taint-checking is performed when editing an existing entry (when the second
+# argument is one or higher) in that the first argument must match the current
+# value of the Nth `nameserver' instance in resolv.conf(5) else an error is
+# generated discarding any/all changes.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_dialog_input_nameserver_edit_awk='
+# Variables that should be defined on the invocation line:
+# -v nsindex="1+"
+# -v old_value="..."
+# -v new_value="..."
+#
+BEGIN {
+ if ( nsindex < 1 ) exit 1
+ found = n = 0
+}
+{
+ if ( found ) { print; next }
+
+ if ( match(tolower($0), /^[[:space:]]*nameserver[[:space:]]+/)) {
+ if ( ++n == nsindex ) {
+ if ( $2 != old_value ) exit 2
+ if ( new_value != "" ) printf "%s%s\n", \
+ substr($0, 0, RLENGTH), new_value
+ found = 1
+ }
+ else print
+ }
+ else print
+}
+END { if ( ! found ) exit 3 }
+'
+f_dialog_input_nameserver()
+{
+ local index="${1:-0}" old_ns="$2" new_ns
+ local ns="$old_ns"
+
+ #
+ # Perform sanity checks
+ #
+ f_isinteger "$index" || return $FAILURE
+ [ $index -ge 0 ] || return $FAILURE
+
+ local msg
+ if [ $index -gt 0 ]; then
+ if [ "$USE_XDIALOG" ]; then
+ msg="$xmsg_please_enter_nameserver_existing"
+ else
+ msg="$msg_please_enter_nameserver_existing"
+ fi
+ else
+ msg="$msg_please_enter_nameserver"
+ fi
+
+ local hline="$hline_num_punc_tab_enter"
+ local size="$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$ns" \
+ "$hline" )"
+
+ #
+ # Loop until the user provides taint-free input.
+ #
+ while :; do
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$ns\" \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+
+ local retval=$?
+ new_ns=$( f_dialog_inputstr )
+
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Take only the first "word" of the user's input
+ new_ns="${new_ns%%[$IFS]*}"
+
+ # Taint-check the user's input
+ [ "$new_ns" ] || break
+ f_dialog_validate_ipaddr "$new_ns" && break
+
+ # Update prompt to allow user to re-edit previous entry
+ ns="$new_ns"
+
+ done
+
+ #
+ # Save only if the user changed the nameserver.
+ #
+ if [ $index -eq "0" -a "$new_ns" ]; then
+ f_dialog_info "$msg_saving_nameserver"
+ printf "nameserver\t%s\n" "$new_ns" >> "$RESOLV_CONF"
+ return $SUCCESS
+ elif [ $index -gt 0 -a "$old_ns" != "$new_ns" ]; then
+ if [ "$new_ns" ]; then
+ msg="$msg_saving_nameserver_existing"
+ else
+ msg="$msg_removing_nameserver"
+ fi
+ f_dialog_info "$msg"
+
+ #
+ # Create a new temporary file to write our new resolv.conf(5)
+ #
+ local tmpfile="$( mktemp -t "$pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ #
+ # Quietly fixup permissions and ownership
+ #
+ local mode owner
+ mode=$( stat -f '%#Lp' "$RESOLV_CONF" 2> /dev/null )
+ owner=$( stat -f '%u:%g' "$RESOLV_CONF" 2> /dev/null )
+ f_quietly chmod "${mode:-0644}" "$tmpfile"
+ f_quietly chown "${owner:-root:wheel}" "$tmpfile"
+
+ #
+ # Operate on resolv.conf(5)
+ #
+ local new_contents
+ new_contents=$( awk -v nsindex="$index" \
+ -v old_value="$old_ns" \
+ -v new_value="$new_ns" \
+ "$f_dialog_input_nameserver_edit_awk" \
+ "$RESOLV_CONF" )
+
+ #
+ # Produce an appropriate error message if necessary.
+ #
+ local retval=$?
+ case $retval in
+ 1) f_die 1 "$msg_internal_error_nsindex_value" "$nsindex";;
+ 2) f_dialog_msgbox "$msg_resolv_conf_changed_while_editing"
+ return $retval;;
+ 3) f_dialog_msgbox "$msg_resolv_conf_entry_no_longer_exists"
+ return $retval;;
+ esac
+
+ #
+ # Write the temporary file contents and move the temporary
+ # file into place.
+ #
+ echo "$new_contents" > "$tmpfile" || return $FAILURE
+ f_quietly mv "$tmpfile" "$RESOLV_CONF"
+ fi
+}
+
+# f_dialog_menu_nameservers
+#
+# Edit the nameservers in resolv.conf(5).
+#
+f_dialog_menu_nameservers()
+{
+ local opt_exit="$msg_return_to_previous_menu"
+ local opt_add="$msg_add_nameserver"
+ local hline="$hline_arrows_tab_enter"
+ local prompt size
+
+ #
+ # Loop forever until the user has finished configuring nameservers
+ #
+ prompt="$msg_dns_configuration"
+ while :; do
+ #
+ # Re/Build list of nameservers
+ #
+ local nameservers="$( f_resolv_conf_nameservers )"
+ local menu_list="$(
+ index=1
+
+ echo "'X $msg_exit' '$opt_exit'"
+ index=$(( $index + 1 ))
+
+ echo "'A $msg_add' '$opt_add'"
+ index=$(( $index + 1 ))
+
+ for ns in $nameservers; do
+ [ $index -lt ${#DIALOG_MENU_TAGS} ] || break
+ tag=$( f_substr "$DIALOG_MENU_TAGS" $index 1 )
+ echo "'$tag nameserver' '$ns'"
+ index=$(( $index + 1 ))
+ done
+ )"
+
+ #
+ # Display configuration-edit menu
+ #
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+
+ local retval=$?
+ local tag="$( f_dialog_menutag )" ns=""
+
+ # Return if "Cancel" was chosen (-1) or ESC was pressed (255)
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ case "$tag" in
+ "X $msg_exit") break;;
+ "A $msg_add")
+ f_dialog_input_nameserver
+ ;;
+ *)
+ n=$( eval f_dialog_menutag2index \"\$tag\" $menu_list )
+ ns=$( eval f_dialog_menutag2item \"\$tag\" $menu_list )
+ f_dialog_input_nameserver $(( $n - 2 )) "$ns"
+ ;;
+ esac
+ done
+}
+
+fi # ! $_NETWORKING_RESOLV_SUBR
diff --git a/usr.sbin/bsdconfig/networking/include/routing.subr b/usr.sbin/bsdconfig/networking/include/routing.subr
new file mode 100644
index 0000000..f4c7017
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/routing.subr
@@ -0,0 +1,168 @@
+if [ ! "$_NETWORKING_ROUTING_SUBR" ]; then _NETWORKING_ROUTING_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/sysrc.subr
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/common.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/ipaddr.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_route_get_default
+#
+# Returns the IP address of the currently active default router.
+#
+f_route_get_default()
+{
+ route -n get default 2> /dev/null | awk \
+ '
+ BEGIN { found = 0 }
+ ( $1 == "gateway:" ) \
+ {
+ print $2
+ found = 1
+ exit
+ }
+ END { exit ! found }
+ '
+}
+
+# f_dialog_input_defaultrouter
+#
+# Edits the default router.
+#
+f_dialog_input_defaultrouter()
+{
+ #
+ # Get the defaultrouter. When this is not configured, the default is
+ # "NO", however we don't ever want to present this default to the user
+ # in the following dialog. If the current value is "NO", then try to
+ # obtain the value from the running system using route(8).
+ #
+ # NOTE: Our `f_route_get_default' function will return NULL if the
+ # system does not have an active default router set (which is what we
+ # want).
+ #
+ local defaultrouter="$( f_sysrc_get 'defaultrouter:-NO' )"
+ local defaultrouter_orig="$defaultrouter" # for change-tracking
+ case "$defaultrouter" in
+ [Nn][Oo])
+ defaultrouter=$( f_route_get_default )
+ ;;
+ esac
+
+ #
+ # Return with-error when there are NFS-mounts currently active. If the
+ # default router/gateway is changed while NFS-exported directories are
+ # mounted, the system will hang.
+ #
+ if f_nfs_mounted && ! f_jailed; then
+ local setting="$( printf "$msg_current_default_router" \
+ "$defaultrouter" )"
+ local message="$( printf "$msg_nfs_mounts_may_cause_hang" \
+ "$setting" )"
+ f_dialog_msgbox "$message"
+ return $FAILURE
+ fi
+
+ local msg="$msg_please_enter_default_router"
+ local hline="$hline_num_punc_tab_enter"
+ local size="$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$defaultrouter" \
+ "$hline" )"
+
+ #
+ # Loop until the user provides taint-free input.
+ #
+ while :; do
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$defaultrouter\" \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+
+ local retval=$?
+ defaultrouter=$( f_dialog_inputstr )
+
+ [ "$defaultrouter" ] || return $SUCCESS
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Taint-check the user's input
+ f_dialog_validate_ipaddr "$defaultrouter" && break
+ done
+
+ #
+ # Save only if the user changed the default router/gateway.
+ #
+ if [ "$defaultrouter" != "$defaultrouter_orig" ]; then
+ f_dialog_info "$msg_saving_default_router"
+
+ # Save the default router/gateway
+ f_sysrc_set defaultrouter "$defaultrouter"
+ fi
+
+ #
+ # Only ask to apply setting if the current defaultrouter is different
+ # than the stored configuration (in rc.conf(5)).
+ #
+ if [ "$( f_route_get_default )" != "$defaultrouter" ]; then
+ f_dialog_clear
+ f_dialog_yesno "$(
+ printf "$msg_activate_default_router" \
+ "$( f_route_get_default )" "$defaultrouter"
+ )"
+
+ if [ $? -eq $SUCCESS ]; then
+ local err
+
+ # Apply the default router/gateway
+ f_quietly route delete default
+ err=$( route add default "$defaultrouter" 2>&1 )
+ if [ $? -ne $SUCCESS ]; then
+ f_dialog_msgbox "$err"
+ return $FAILURE
+ fi
+ fi
+ fi
+}
+
+fi # ! $_NETWORKING_ROUTING_SUBR
diff --git a/usr.sbin/bsdconfig/networking/nameservers b/usr.sbin/bsdconfig/networking/nameservers
new file mode 100755
index 0000000..ae8e812
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/nameservers
@@ -0,0 +1,73 @@
+#!/bin/sh
+#-
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="120.networking"
+f_include $BSDCFG_LIBE/$APP_DIR/include/resolv.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_dns_nameservers"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Change the DNS nameservers
+#
+f_dialog_menu_nameservers
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/networking/networking b/usr.sbin/bsdconfig/networking/networking
new file mode 100755
index 0000000..8b9cc8f
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/networking
@@ -0,0 +1,146 @@
+#!/bin/sh
+#-
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="120.networking"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_arrows_tab_enter"
+
+ menu_list="
+ 'X' '$msg_exit'
+ '1' '$msg_hostname_domain'
+ '2' '$msg_network_interfaces'
+ '3' '$msg_default_router'
+ '4' '$msg_dns_nameservers'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\" $size $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_network_management"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ X) # Exit
+ break
+ ;;
+
+ 1) # Hostname/Domain
+ $BSDCFG_LIBE/$APP_DIR/hostname ${USE_XDIALOG:+-X}
+ ;;
+
+ 2) # Network Interfaces
+ $BSDCFG_LIBE/$APP_DIR/devices ${USE_XDIALOG:+-X}
+
+ # Make subsequent uses of this menu faster by not performing
+ # "ifconfig up" (limiting the pain one must endure). See also
+ # `$BSDCFG_LIBE/$APP_DIR/include/device.subr'.
+ #
+ export DIALOG_MENU_NETDEV_KICK_INTERFACES=
+ ;;
+
+ 3) # Default Router/Gateway
+ $BSDCFG_LIBE/$APP_DIR/defaultrouter ${USE_XDIALOG:+-X}
+ ;;
+
+ 4) # DNS nameservers
+ $BSDCFG_LIBE/$APP_DIR/nameservers ${USE_XDIALOG:+-X}
+ ;;
+
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/password/INDEX b/usr.sbin/bsdconfig/password/INDEX
new file mode 100644
index 0000000..224897b
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/INDEX
@@ -0,0 +1,53 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Root Password"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Set the system manager's password"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="password|password"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="password"
diff --git a/usr.sbin/bsdconfig/password/Makefile b/usr.sbin/bsdconfig/password/Makefile
new file mode 100644
index 0000000..4990907
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/040.password
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= password
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/password/USAGE b/usr.sbin/bsdconfig/password/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/password/include/Makefile b/usr.sbin/bsdconfig/password/include/Makefile
new file mode 100644
index 0000000..1c1d0e1
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/040.password/include
+FILES= messages.subr password.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/password/include/messages.subr b/usr.sbin/bsdconfig/password/include/messages.subr
new file mode 100644
index 0000000..ac01ccc
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/include/messages.subr
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 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$
+
+hline_alnum_punc_tab_enter="Use alpha-numeric, punctuation, TAB or ENTER"
+msg_cancel="Cancel"
+msg_ok="OK"
+msg_password="Password"
+msg_password_changed="Password successfully changed."
+msg_password_is_empty="Password is empty."
+msg_passwords_do_not_match="Passwords do not match."
+msg_reenter_password="Re-enter Password"
+msg_root_password="Root Password"
diff --git a/usr.sbin/bsdconfig/password/include/password.subr b/usr.sbin/bsdconfig/password/include/password.subr
new file mode 100644
index 0000000..846b76b
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/include/password.subr
@@ -0,0 +1,122 @@
+if [ ! "$_PASSWORD_PASSWORD_SUBR" ]; then _PASSWORD_PASSWORD_SUBR=1
+#
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+APP_DIR="040.password"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_dialog_input_password
+#
+# Prompt the user to enter a password (twice). If the user does not cancel or
+# press ESC, the $pw_password environment variable will hold the password.
+#
+f_dialog_input_password()
+{
+ local hline="$hline_alnum_punc_tab_enter"
+ local msg size rmsg rsize
+
+ msg=$( printf "$msg_password" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "" \
+ "$hline" )
+
+ rmsg=$( printf "$msg_reenter_password" )
+ rsize=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$rmsg" \
+ "" \
+ "$hline" )
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local retval _password1 _password2
+ while :; do
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$msg\" $size \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password1=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$rmsg\" $rsize \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password2=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for NULL entry
+ if ! [ "$_password1" -o "$_password2" ]; then
+ f_show_msg "$msg_password_is_empty"
+ continue
+ fi
+
+ # Check for password mismatch
+ if [ "$_password1" != "$_password2" ]; then
+ f_show_msg "$msg_passwords_do_not_match"
+ continue
+ fi
+
+ pw_password="$_password1"
+ break
+ done
+
+ return $SUCCESS
+}
+
+fi # ! $_PASSWORD_PASSWORD_SUBR
diff --git a/usr.sbin/bsdconfig/password/password b/usr.sbin/bsdconfig/password/password
new file mode 100755
index 0000000..2cbd54c
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/password
@@ -0,0 +1,82 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="040.password"
+f_include $BSDCFG_LIBE/$APP_DIR/include/password.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# Default login of system manager
+#
+USER_ROOT=root
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_root_password"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+if f_dialog_input_password; then
+ err=$( echo "$pw_password" | pw usermod $USER_ROOT -h 0 2>&1 ) ||
+ f_die $? "%s" "$err"
+ f_show_msg "$msg_password_changed"
+fi
+
+return $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/security/INDEX b/usr.sbin/bsdconfig/security/INDEX
new file mode 100644
index 0000000..1a271ec
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/INDEX
@@ -0,0 +1,54 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Security"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Set Security Parameters"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="security|security"
+menu_selection="kern_securelevel|kern_securelevel"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="security"
diff --git a/usr.sbin/bsdconfig/security/Makefile b/usr.sbin/bsdconfig/security/Makefile
new file mode 100644
index 0000000..c230973
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/130.security
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= kern_securelevel security
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/security/USAGE b/usr.sbin/bsdconfig/security/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/security/include/Makefile b/usr.sbin/bsdconfig/security/include/Makefile
new file mode 100644
index 0000000..7cdfcc6
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/130.security/include
+FILES= messages.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/security/include/messages.subr b/usr.sbin/bsdconfig/security/include/messages.subr
new file mode 100644
index 0000000..162cebd
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/include/messages.subr
@@ -0,0 +1,48 @@
+# Copyright (c) 2012 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$
+
+hline_arrows_tab_enter="Press arrows, TAB or ENTER"
+hline_select_securelevel_to_operate_at="Select a securelevel to operate at"
+msg_cancel="Cancel"
+msg_disable_securelevels="Disable securelevels"
+msg_disabled="Disabled"
+msg_exit="Exit"
+msg_exit_this_menu="Exit this menu (returning to previous)"
+msg_highly_secure="Highly Secure"
+msg_highly_secure_mode="Highly secure mode"
+msg_menu_text="This menu allows you to configure aspects of the operating system security\npolicy. Please read the system documentation carefully before modifying\nthese settings, as they may cause service disruption if used improperly.\n\nMost settings will take affect only following a system reboot."
+msg_network_secure="Network Secure"
+msg_network_secure_mode="Network secure mode"
+msg_nfs_port="NFS port"
+msg_nfs_port_desc="Require that the NFS clients use reserved ports"
+msg_ok="OK"
+msg_secure="Secure"
+msg_secure_mode="Secure mode"
+msg_securelevel="Securelevel"
+msg_securelevel_desc="Configure securelevels for the system"
+msg_securelevels_menu_text="This menu allows you to select the securelevel your system runs with.\nWhen operating at a securelevel, certain root privileges are disabled,\nwhich may increase resistance to exploits and protect system integrity.\nIn secure mode system flags may not be overridden by the root user,\naccess to direct kernel memory is limited, and kernel modules may not\nbe changed. In highly secure mode, mounted file systems may not be\nmodified on-disk, tampering with the system clock is prohibited. In\nnetwork secure mode configuration changes to firewalling are prohibited.\n "
+msg_securelevels_menu_title="Securelevel Configuration Menu"
+msg_system_security_options_menu="System Security Options Menu"
diff --git a/usr.sbin/bsdconfig/security/kern_securelevel b/usr.sbin/bsdconfig/security/kern_securelevel
new file mode 100755
index 0000000..f457e94
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/kern_securelevel
@@ -0,0 +1,135 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="130.security"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_select_securelevel_to_operate_at"
+ local prompt="$msg_securelevels_menu_text"
+
+ menu_list="
+ 'X $msg_exit' '$msg_exit_this_menu'
+ '$msg_disabled' '$msg_disable_securelevels'
+ '$msg_secure' '$msg_secure_mode'
+ '$msg_highly_secure' '$msg_highly_secure_mode'
+ '$msg_network_secure' '$msg_network_secure_mode'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_securelevels_menu_title"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+dialog_menu_main
+retval=$?
+mtag=$( f_dialog_menutag )
+
+[ $retval -eq 0 ] || f_die
+
+case "$mtag" in
+"$msg_disabled")
+ f_sysrc_set kern_securelevel_enable "NO"
+ ;;
+"$msg_secure")
+ f_sysrc_set kern_securelevel_enable "YES"
+ f_sysrc_set kern_securelevel "1"
+ ;;
+"$msg_highly_secure")
+ f_sysrc_set kern_securelevel_enable "YES"
+ f_sysrc_set kern_securelevel "2"
+ ;;
+"$msg_network_secure")
+ f_sysrc_set kern_securelevel_enable "YES"
+ f_sysrc_set kern_securelevel "3"
+ ;;
+esac
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/security/security b/usr.sbin/bsdconfig/security/security
new file mode 100755
index 0000000..25754a5
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/security
@@ -0,0 +1,149 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="130.security"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_arrows_tab_enter"
+ local prompt="$msg_menu_text"
+
+ menu_list="
+ 'X <<< $msg_exit' '$msg_exit_this_menu'
+ " # END-QUOTE
+
+ case "$( f_sysrc_get kern_securelevel_enable )" in
+ [Yy][Ee][Ss])
+ local kern_securelevel="$( f_sysrc_get kern_securelevel )"
+ if [ ${#kern_securelevel} -eq 1 ] &&
+ f_isinteger "$kern_securelevel"
+ then menu_list="$menu_list
+ '2 [$kern_securelevel] $msg_securelevel'"
+ else menu_list="$menu_list
+ '2 [X] $msg_securelevel'"
+ fi
+ menu_list="$menu_list '$msg_securelevel_desc'"
+ ;;
+ *) menu_list="$menu_list
+ '2 [ ] $msg_securelevel' '$msg_securelevel_desc'"
+ esac
+
+ case "$( f_sysrc_get nfs_reserved_port_only )" in
+ [Yy][Ee][Ss]) menu_list="$menu_list
+ '3 [X] $msg_nfs_port' '$msg_nfs_port_desc'";;
+ *) menu_list="$menu_list
+ '3 [ ] $msg_nfs_port' '$msg_nfs_port_desc'";;
+ esac
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_system_security_options_menu"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X <<< $msg_exit") break ;;
+ "2 ["?"] $msg_securelevel") # Configure securelevels for the system
+ $BSDCFG_LIBE/$APP_DIR/kern_securelevel ${USE_XDIALOG:+-X} ;;
+ "3 [X] $msg_nfs_port") # Require that NFS clients use reserved ports
+ f_sysrc_set nfs_reserved_port_only "NO";;
+ "3 [ ] $msg_nfs_port") # Same; Toggle value
+ f_sysrc_set nfs_reserved_port_only "YES";;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/startup/INDEX b/usr.sbin/bsdconfig/startup/INDEX
new file mode 100644
index 0000000..1b6f5cd
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/INDEX
@@ -0,0 +1,58 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Startup"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Set Startup Parameters"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="startup|startup"
+menu_selection="startup_misc|misc"
+menu_selection="startup_rcadd|rcadd"
+menu_selection="startup_rcconf|rcconf"
+menu_selection="startup_rcdelete|rcdelete"
+menu_selection="startup_rcvar|rcvar"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="startup"
diff --git a/usr.sbin/bsdconfig/startup/Makefile b/usr.sbin/bsdconfig/startup/Makefile
new file mode 100644
index 0000000..dc198da
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/140.startup
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= misc rcadd rcconf rcdelete rcedit rcvar startup
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/startup/USAGE b/usr.sbin/bsdconfig/startup/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/startup/include/Makefile b/usr.sbin/bsdconfig/startup/include/Makefile
new file mode 100644
index 0000000..c155eb0
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/140.startup/include
+FILES= messages.subr rcconf.subr rcedit.subr rcvar.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/startup/include/messages.subr b/usr.sbin/bsdconfig/startup/include/messages.subr
new file mode 100644
index 0000000..b3cb57f
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/include/messages.subr
@@ -0,0 +1,112 @@
+# Copyright (c) 2012 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$
+
+hline_alnum_punc_tab_enter="Use alpha-numeric, punctuation, TAB or ENTER"
+hline_arrows_tab_enter="Press arrows, TAB or ENTER"
+msg_accounting="Accounting"
+msg_accounting_desc="This host wishes to run process accounting."
+msg_add_custom="Add Custom"
+msg_add_from_list="Add From List"
+msg_add_new="Add New"
+msg_add_new_desc="Add new directive"
+msg_add_new_help="Add new rc.conf(5) configuration directive"
+msg_add_startup_directive="Add Startup Directive"
+msg_all="All"
+msg_all_desc="Select all directives"
+msg_all_help="Select all displayed rc.conf(5) configuration directives"
+msg_apm="APM"
+msg_apm_desc="Auto-power management services (typically laptops)"
+msg_are_you_sure_you_want_to_delete="Are you sure you want to delete the \`%s' directive\nfrom the rc.conf(5) collection of system configuration files?"
+msg_are_you_sure_you_want_delete_the_following="Are you sure you want to delete the following directives\nfrom the rc.conf(5) collection of system configuration files?"
+msg_cancel="Cancel"
+msg_choose_view_details="Choose View Details"
+msg_creating_menu_list="Creating menu list...\nThis may take a while."
+msg_creating_rcconf_map="Creating rc.conf(5) map...\nThis may take a while."
+msg_creating_rcvar_map="Creating rcvar map...\nThis may take a while."
+msg_default_value="Default: %s"
+msg_delete="Delete"
+msg_delete_desc="Delete directive(s)"
+msg_delete_help="Select one or more directives from a list to delete"
+msg_delete_selected="Delete Selected"
+msg_delete_selected_desc="Delete selected directive(s)"
+msg_delete_selected_help="Delete each of the selected rc.conf(5) configuration directives"
+msg_delete_startup_directives="Delete Startup Directive(s)"
+msg_deleting_selected_directives="Deleting selected directive(s)..."
+msg_desc="Description"
+msg_desc_desc="Toggle display of system description"
+msg_details="Details"
+msg_exit="Exit"
+msg_exit_cancel="Exit/Cancel"
+msg_exit_cancel_desc="Return to previous menu"
+msg_exit_cancel_help="Return to the previous menu (selected items are untouched)"
+msg_exit_desc="Return to previous menu"
+msg_exit_help="Exit this menu (returning to previous)"
+msg_exit_this_menu="Exit this menu (returning to previous)"
+msg_info="Info"
+msg_lpd="lpd"
+msg_lpd_desc="This host has a printer and wants to run lpd."
+msg_miscellaneous_startup_services="Miscellaneous Startup Services"
+msg_miscellaneous_menu_text="This menu allows you to configure various aspects of your system's\nstartup configuration. Use [SPACE] or [ENTER] to select items, and\n[TAB] to move to the buttons. Select Exit to leave this menu."
+msg_named="named"
+msg_named_desc="Run a local name server on this host"
+msg_named_flags="named flags"
+msg_named_flags_desc="Set default flags to named (if enabled)"
+msg_nis_client="NIS client"
+msg_nis_client_desc="This host wishes to be an NIS client."
+msg_nis_domainname="NIS domainname"
+msg_nis_domainname_desc="Set NIS domainname (if enabled)"
+msg_nis_server="NIS Server"
+msg_nis_server_desc="This host wishes to be an NIS server."
+msg_none="None"
+msg_none_desc="Un-Select all directives"
+msg_none_help="Un-Select all rc.conf(5) configuration directives"
+msg_ok="OK"
+msg_please_enter_a_new_value="Please enter a new value for \`%s' (Default: %s):"
+msg_please_enter_rcvar_name="Please enter rc.conf(5) variable name:"
+msg_please_select_an_rcconf_directive="Please select an rc.conf(5) directive:"
+msg_rcvar_contains_invalid_chars="ERROR! rc.conf(5) variable name contains invalid characters.\n Name may only consist of letters [a-zA-Z], numbers [0-9],\n or underscore [_] and must not start with a number."
+msg_rcvar_must_start_with="ERROR! rc.conf(5) variable name must start with\n a letter [a-zA-Z] or underscore [_]."
+msg_reset="Reset"
+msg_reset_desc="Reset to default view settings"
+msg_sco="SCO"
+msg_sco_desc="This host wants to be able to run IBCS2 binaries."
+msg_show_configured="Show Configured"
+msg_show_configured_desc="Calculate rc.conf(5) locations (slow)"
+msg_show_default_value="Show Default/Value"
+msg_show_default_value_desc="Show default/configured values"
+msg_show_value="Show Value"
+msg_show_value_desc="Show configured startup value"
+msg_startup="Startup"
+msg_startup_dirs="Startup dirs"
+msg_startup_dirs_desc="Set the list of dirs to look for startup scripts"
+msg_svr4="SVR4"
+msg_svr4_desc="This host wants to be able to run SVR4 binaries."
+msg_toggle_startup_services="Toggle Startup Services"
+msg_value_required="Value Required"
+msg_view_details="View Details"
+msg_view_details_desc="Choose view details"
+msg_view_details_help="Choose which details are shown in the current view"
+msg_view_edit_startup_configuration="View/Edit Startup Configuration"
diff --git a/usr.sbin/bsdconfig/startup/include/rcconf.subr b/usr.sbin/bsdconfig/startup/include/rcconf.subr
new file mode 100644
index 0000000..88bed49
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/include/rcconf.subr
@@ -0,0 +1,466 @@
+if [ ! "$_STARTUP_RCCONF_SUBR" ]; then _STARTUP_RCCONF_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="140.startup"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ GLOBALS
+
+#
+# Initialize in-memory cache variables
+#
+STARTUP_RCCONF_MAP=
+_STARTUP_RCCONF_MAP=
+
+#
+# Define what a variable looks like
+#
+STARTUP_RCCONF_REGEX="^[[:alpha:]_][[:alnum:]_]*="
+
+#
+# Default path to on-disk cache file(s)
+#
+STARTUP_RCCONF_MAP_CACHEFILE="/var/run/bsdconfig/startup_rcconf_map.cache"
+
+############################################################ FUNCTIONS
+
+# f_startup_rcconf_list
+#
+# Produce a list of non-default configuration variables configured in the
+# rc.conf(5) collection of files.
+#
+f_startup_rcconf_list()
+{
+ ( # Operate within a sub-shell to protect the parent environment
+ . "$RC_DEFAULTS" > /dev/null
+ f_clean_env --except PATH STARTUP_RCCONF_REGEX rc_conf_files
+ source_rc_confs > /dev/null
+ export _rc_conf_files_file="$( f_sysrc_find rc_conf_files )"
+ export RC_DEFAULTS
+ set | awk -F= "
+ function test_print(var)
+ {
+ if ( var == \"OPTIND\" ) return
+ if ( var == \"PATH\" ) return
+ if ( var == \"RC_DEFAULTS\" ) return
+ if ( var == \"STARTUP_RCCONF_REGEX\" ) return
+ if ( var == \"_rc_conf_files_file\" ) return
+ if ( var == \"rc_conf_files\" )
+ {
+ if ( ENVIRON[\"_rc_conf_files_file\"] == \
+ ENVIRON[\"RC_DEFAULTS\"] ) return
+ }
+ print var
+ }
+ /$STARTUP_RCCONF_REGEX/ { test_print(\$1) }"
+ )
+}
+
+# f_startup_rcconf_map
+#
+# Produce a map (beit from in-memory cache or on-disk cache) of rc.conf(5)
+# variables and their descriptions. The map returned has the following format:
+#
+# var description
+#
+# With each as follows:
+#
+# var the rc.conf(5) variable
+# description description of the variable
+#
+f_startup_rcconf_map()
+{
+ # If the in-memory cached value is available, return it immediately
+ if [ "$_STARTUP_RCCONF_MAP" ]; then
+ echo "$STARTUP_RCCONF_MAP"
+ return $SUCCESS
+ fi
+
+ #
+ # create the in-memory cache (potentially from validated on-disk cache)
+ #
+
+ #
+ # Calculate digest used to determine if the on-disk global persistant
+ # cache file (containg this digest on the first line) is valid and can
+ # be used to quickly populate the cache value for immediate return.
+ #
+ local rc_defaults_digest
+ rc_defaults_digest=$( md5 < "$RC_DEFAULTS" )
+
+ #
+ # Check to see if the global persistant cache file exists
+ #
+ if [ -f "$STARTUP_RCCONF_MAP_CACHEFILE" ]; then
+ #
+ # Attempt to populate the in-memory cache with the (soon to be)
+ # be validated on-disk cache. If validation fails, fall-back to
+ # the current value and provide error exit status.
+ #
+ STARTUP_RCCONF_MAP=$(
+ ( # Get digest as the first word on the first line
+ read digest rest_ignored
+
+ #
+ # If the stored digest matches the calculated-
+ # one populate the in-memory cache from the on-
+ # disk cache and provide success exit status.
+ #
+ if [ "$digest" = "$rc_defaults_digest" ]; then
+ cat
+ exit $SUCCESS
+ else
+ # Otherwise, return the current value
+ echo "$STARTUP_RCCONF_MAP"
+ exit $FAILURE
+ fi
+ ) < "$STARTUP_RCCONF_MAP_CACHEFILE"
+ )
+ export STARTUP_RCCONF_MAP
+ if [ $? -eq $SUCCESS ]; then
+ export _STARTUP_RCCONF_MAP=1
+ echo "$STARTUP_RCCONF_MAP"
+ return $SUCCESS
+ fi
+ # Otherwise, fall-thru to create in-memory cache from scratch
+ fi
+
+ #
+ # If we reach this point, we need to generate the data from scratch
+ # (and after we do, we'll attempt to create the global persistant
+ # cache file to speed up future executions).
+ #
+
+ STARTUP_RCCONF_MAP=$(
+ f_clean_env --except \
+ PATH \
+ RC_DEFAULTS \
+ STARTUP_RCCONF_REGEX \
+ f_sysrc_desc_awk
+ . "$RC_DEFAULTS"
+
+ # Unset variables we don't want reported
+ unset source_rc_confs_defined
+
+ for var in $( set | awk -F= "
+ function test_print(var)
+ {
+ if ( var == \"OPTIND\" ) return
+ if ( var == \"PATH\" ) return
+ if ( var == \"RC_DEFAULTS\" ) return
+ if ( var == \"STARTUP_RCCONF_REGEX\" ) return
+ if ( var == \"f_sysrc_desc_awk\" ) return
+ print var
+ }
+ /$STARTUP_RCCONF_REGEX/ { test_print(\$1) }
+ " ); do
+ echo $var "$( f_sysrc_desc $var )"
+ done
+ )
+ export STARTUP_RCCONF_MAP
+ export _STARTUP_RCCONF_MAP=1
+ echo "$STARTUP_RCCONF_MAP"
+
+ #
+ # Attempt to create the persistant global cache
+ #
+
+ # Create a new temporary file to write to
+ local tmpfile="$( mktemp -t "$pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ # Write the temporary file contents
+ echo "$rc_defaults_digest" > "$tmpfile"
+ echo "$STARTUP_RCCONF_MAP" >> "$tmpfile"
+
+ # Finally, move the temporary file into place
+ case "$STARTUP_RCCONF_MAP_CACHEFILE" in
+ */*) f_quietly mkdir -p "${STARTUP_RCCONF_MAP_CACHEFILE%/*}"
+ esac
+ mv "$tmpfile" "$STARTUP_RCCONF_MAP_CACHEFILE"
+}
+
+# f_startup_rcconf_map_expand
+#
+# Expands the map ($RCCONF_MAP) into the shell environment namespace by
+# creating _${var}_desc variables containing the description of each variable
+# encountered.
+#
+# NOTE: Variables are exported for later-required awk(1) ENVIRON visibility.
+#
+f_startup_rcconf_map_expand()
+{
+ eval "$( echo "$RCCONF_MAP" | awk '
+ BEGIN {
+ rword = "^[[:space:]]*[^[:space:]]*[[:space:]]*"
+ }
+ {
+ var = $1
+ desc = $0
+ sub(rword, "", desc)
+ gsub(/'\''/, "'\''\\'\'\''", desc)
+ printf "_%s_desc='\''%s'\''\n", var, desc
+ printf "export _%s_desc\n", var
+ }' )"
+}
+
+# f_dialog_input_view_details
+#
+# Display a menu for selecting which details are to be displayed. The following
+# variables are tracked/modified by the menu/user's selection:
+#
+# SHOW_DESC Show or hide descriptions
+#
+# Mutually exclusive options:
+#
+# SHOW_VALUE Show the value (default; override only)
+# SHOW_VALUE_DEFAULT Show both value and default
+# SHOW_CONFIGURED Show rc.conf(5) file variable is configured in
+#
+# Each variable is treated as a boolean (NULL for false, non-NULL for true).
+#
+# Variables are exported for later-required awk(1) ENVIRON visibility.
+#
+f_dialog_input_view_details()
+{
+ local menu_list size
+ local hline="$hline_arrows_tab_enter"
+ local prompt=""
+
+ local md=" " m1=" " m2=" " m3=" "
+ [ "$SHOW_DESC" ] && md="X"
+ [ "$SHOW_VALUE" ] && m1="*"
+ [ "$SHOW_DEFAULT_VALUE" ] && m2="*"
+ [ "$SHOW_CONFIGURED" ] && m3="*"
+
+ menu_list="
+ 'X $msg_exit' '$msg_exit_this_menu'
+ 'R $msg_reset' '$msg_reset_desc'
+ 'D [$md] $msg_desc' '$msg_desc_desc'
+ '1 ($m1) $msg_show_value' '$msg_show_value_desc'
+ '2 ($m2) $msg_show_default_value' '$msg_show_default_value_desc'
+ '3 ($m3) $msg_show_configured' '$msg_show_configured_desc'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ f_dialog_title "$msg_choose_view_details"
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+
+ local retval=$?
+ local mtag="$( f_dialog_menutag )"
+
+ f_dialog_title_restore
+
+ [ $retval -eq 0 ] || return $SUCCESS
+ [ "$mtag" = "X $msg_exit" ] && return $SUCCESS
+
+ case "$mtag" in
+ "R $msg_reset")
+ SHOW_VALUE=1
+ SHOW_DESC=1
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=
+ ;;
+ "D [X] $msg_desc") SHOW_DESC= ;;
+ "D [ ] $msg_desc") SHOW_DESC=1 ;;
+ "1 ("?") $msg_show_value")
+ SHOW_VALUE=1
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=
+ ;;
+ "2 ("?") $msg_show_default_value")
+ SHOW_VALUE=
+ SHOW_DEFAULT_VALUE=1
+ SHOW_CONFIGURED=
+ ;;
+ "3 ("?") $msg_show_configured")
+ SHOW_VALUE=
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=1
+ ;;
+ esac
+}
+
+# f_dialog_input_rclist
+#
+# Presents a menu of rc.conf(5) defaults (with, or without descriptions). This
+# function should be treated like a call to dialog(1) (the exit status should
+# be captured and f_dialog_menutag() should be used to clean-up and get the
+# user's response).
+#
+f_dialog_input_rclist()
+{
+ local size
+ local hline="$hline_arrows_tab_enter"
+ local prompt="$msg_please_select_an_rcconf_directive"
+ local menu_list
+
+ menu_list="
+ 'X $msg_exit' '' ${SHOW_DESC:+'$msg_exit_help'}
+ " # END-QUOTE
+
+ if [ ! "$_RCCONF_MAP" ]; then
+ # Generate RCCONF_MAP of `var desc ...' per-line
+ f_dialog_info "$msg_creating_rcconf_map"
+ RCCONF_MAP=$( f_startup_rcconf_map )
+ export RCCONF_MAP
+ # Generate _${var}_desc variables from $RCCONF_MAP
+ f_startup_rcconf_map_expand
+ export _RCCONF_MAP=1
+ fi
+
+ menu_list="$menu_list $(
+ export SHOW_DESC
+ echo "$RCCONF_MAP" | awk '
+ BEGIN {
+ prefix = ""
+ rword = "^[[:space:]]*[^[:space:]]*[[:space:]]*"
+ }
+ {
+ cur_prefix = tolower(substr($1, 1, 1))
+ printf "'\''"
+ if ( prefix != cur_prefix )
+ prefix = cur_prefix
+ else
+ printf " "
+ rcvar = $1
+ printf "%s'\'' '\'\''", rcvar
+ if ( ENVIRON["SHOW_DESC"] ) {
+ desc = $0
+ sub(rword, "", desc)
+ gsub(/'\''/, "'\''\\'\'\''", desc)
+ printf " '\''%s'\''", desc
+ }
+ printf "\n"
+ }'
+ )"
+
+ set -f # noglob
+
+ size=$( eval f_dialog_menu_${SHOW_DESC:+with_help_}size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ ${SHOW_DESC:+--item-help} \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# f_dialog_input_rcvar [$init]
+#
+# Allows the user to enter the name for a new rc.conf(5) variable. If the user
+# does not cancel or press ESC, the $rcvar variable will hold the newly-
+# configured value upon return.
+#
+f_dialog_input_rcvar()
+{
+ local msg="$msg_please_enter_rcvar_name"
+ local hline="$hline_alnum_tab_enter"
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local size _input="$1"
+ while :; do
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for invalid entry (1of2)
+ if ! echo "$_input" | grep -q "^[[:alpha:]_]"; then
+ f_show_msg "$msg_rcvar_must_start_with"
+ continue
+ fi
+
+ # Check for invalid entry (2of2)
+ if ! echo "$_input" | grep -q "^[[:alpha:]_][[:alnum:]_]*$"
+ then
+ f_show_msg "$msg_rcvar_contains_invalid_chars"
+ continue
+ fi
+
+ rcvar="$_input"
+ break
+ done
+
+ f_dprintf "f_dialog_input_rcvar: rcvar->[$rcvar]"
+
+ return $SUCCESS
+}
+
+fi # ! $_STARTUP_RCCONF_SUBR
diff --git a/usr.sbin/bsdconfig/startup/include/rcedit.subr b/usr.sbin/bsdconfig/startup/include/rcedit.subr
new file mode 100644
index 0000000..325f1fe
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/include/rcedit.subr
@@ -0,0 +1,106 @@
+if [ ! "$_STARTUP_RCEDIT_SUBR" ]; then _STARTUP_RCEDIT_SUBR=1
+#
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="140.startup"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_dialog_rcedit $var [[--] $init ...]
+#
+# Allow the user to enter a new value for a given rc.conf(5) variable. If the
+# user does not cancel or press ESC, the variable will be saved without
+# confirmation.
+#
+# If the second argument is non-NULL, it will be processed as the initial text
+# to be displayed, overriding the default behavior to display the currently
+# configured value as the initial text.
+#
+# If instead the second argument is "--", then the third argument (NULL or
+# otherwise) will be treated as the initial text.
+#
+f_dialog_rcedit()
+{
+ local msg size retval var="$1" _input
+ local hline="$hline_alnum_punc_tab_enter"
+
+ msg=$( printf "$msg_please_enter_a_new_value" \
+ "$var" "$( f_sysrc_get_default "$var" )" )
+
+ shift 1 # var
+ if [ "$1" ]; then
+ [ "$1" = "--" ] && shift 1 # --
+ _input="$1"
+ else
+ _input=$( f_sysrc_get "$var" )
+ fi
+
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ local opterm="--"
+ [ "$USE_XDIALOG" ] && opterm=
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ $opterm \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Return if the value has not changed from current
+ local cur_val="$( f_sysrc_get "$var" )"
+ [ "$_input" = "$cur_val" ] && return $SUCCESS
+
+ f_dprintf "$var: [$cur_val]->[$_input]"
+
+ err=$( f_sysrc_set "$var" "$_input" 2>&1 ) ||
+ f_show_msg "$err"
+}
+
+fi # ! $_STARTUP_RCEDIT_SUBR
diff --git a/usr.sbin/bsdconfig/startup/include/rcvar.subr b/usr.sbin/bsdconfig/startup/include/rcvar.subr
new file mode 100644
index 0000000..c7ad74d
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/include/rcvar.subr
@@ -0,0 +1,206 @@
+if [ ! "$_STARTUP_RCVAR_SUBR" ]; then _STARTUP_RCVAR_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+############################################################ CONFIGURATION
+
+#
+# Default path to the `/etc/rc.d' directory where service(8) scripts are stored
+#
+: ${ETC_RC_D:=/etc/rc.d}
+
+#
+# Default path to `/etc/rc.subr' (for find_local_scripts_new())
+#
+: ${ETC_RC_SUBR:=/etc/rc.subr}
+
+############################################################ GLOBALS
+
+#
+# Initialize in-memory cache variables
+#
+STARTUP_RCVAR_MAP=
+_STARTUP_RCVAR_MAP=
+
+#
+# Define what an rcvar looks like
+#
+STARTUP_RCVAR_REGEX='[[:alpha:]_][[:alnum:]_]*="([Yy][Ee][Ss]|[Nn][Oo])"'
+
+#
+# Default path to on-disk cache file(s)
+#
+STARTUP_RCVAR_MAP_CACHEFILE="/var/run/bsdconfig/startup_rcvar_map.cache"
+
+############################################################ FUNCTIONS
+
+# f_startup_rcvar_map
+#
+# Produce a map (beit from in-memory cache or on-disk cache) of rc.d scripts
+# and their associated rcvar's. The map returned has the following format:
+#
+# rcvar default script description
+#
+# With each as follows:
+#
+# rcvar the variable used to enable this rc.d script
+# default default value for this variable
+# script the rc.d script in-question
+# description description of the variable from rc.conf(5) defaults
+#
+f_startup_rcvar_map()
+{
+ # If the in-memory cached value is available, return it immediately
+ if [ "$_STARTUP_RCVAR_MAP" ]; then
+ echo "$STARTUP_RCVAR_MAP"
+ return $SUCCESS
+ fi
+
+ #
+ # create the in-memory cache (potentially from validated on-disk cache)
+ #
+
+ # Get a list of /etc/rc.d scripts ...
+ local file rc_script_list=
+ for file in "$ETC_RC_D"/*; do
+ [ -f "$file" ] || continue
+ [ -x "$file" ] || continue
+ rc_script_list="$rc_script_list${rc_script_list:+ }$file"
+ done
+ # ... and /usr/local/etc/rc.d scripts
+ rc_script_list="$rc_script_list${rc_script_list:+ }$(
+ local_startup=$( f_sysrc_get local_startup )
+ f_include "$ETC_RC_SUBR"
+ find_local_scripts_new
+ echo $local_rc
+ )"
+
+ #
+ # Calculate a digest given the checksums of all dependencies (scripts and
+ # the defaults file). This digest will be used to determine if an on-disk
+ # global persistant cache file (containg this digest on the first line)
+ # is valid and can be used to quickly populate the cache value for
+ # immediate return.
+ #
+ local rc_script_list_digest
+ rc_script_list_digest=$( cd "$ETC_RC_D" &&
+ cksum "$RC_DEFAULTS" $rc_script_list | md5 )
+
+ #
+ # Check to see if the global persistant cache file exists
+ #
+ if [ -f "$STARTUP_RCVAR_MAP_CACHEFILE" ]; then
+ #
+ # Attempt to populate the in-memory cache with the (soon to be)
+ # be validated on-disk cache. If validation fails, fall-back to
+ # the current value and provide error exit status.
+ #
+ STARTUP_RCVAR_MAP=$(
+ ( # Get digest as the first word on the first line
+ read digest rest_ignored
+
+ #
+ # If the stored digest matches the calculated-one
+ # populate the in-memory cache from the on-disk
+ # cache and provide success exit status.
+ #
+ if [ "$digest" = "$rc_script_list_digest" ]; then
+ cat
+ exit $SUCCESS
+ else
+ # Otherwise, return the current value
+ echo "$STARTUP_RCVAR_MAP"
+ exit $FAILURE
+ fi
+ ) < "$STARTUP_RCVAR_MAP_CACHEFILE"
+ )
+ export STARTUP_RCVAR_MAP
+ if [ $? -eq $SUCCESS ]; then
+ export _STARTUP_RCVAR_MAP=1
+ echo "$STARTUP_RCVAR_MAP"
+ return $SUCCESS
+ fi
+ # Otherwise, fall-through to create in-memory cache from scratch
+ fi
+
+ #
+ # If we reach this point, we need to generate the data from scratch
+ # (and after we do, we'll attempt to create the global persistant
+ # cache file to speed up future executions).
+ #
+
+ STARTUP_RCVAR_MAP=$(
+ for script in $rc_script_list; do
+ rcvar_list=$( $script rcvar | awk -F= \
+ -v script="$script" '
+ /^'"$STARTUP_RCVAR_REGEX"'/ {
+ if ( $2 ~ /^"[Yy][Ee][Ss]"$/ )
+ print $1 ",YES"
+ else
+ print $1 ",NO"
+ }' )
+ for entry in $rcvar_list; do
+ rcvar="${entry%%,*}"
+ rcvar_default=$( f_sysrc_get_default "$rcvar" )
+ [ "$rcvar_default" ] ||
+ rcvar_default="${entry#*,}"
+ rcvar_desc=$( f_sysrc_desc "$rcvar" )
+ echo $rcvar ${rcvar_default:-NO} \
+ $script "$rcvar_desc"
+ done
+ done | sort -u
+ )
+ export STARTUP_RCVAR_MAP
+ export _STARTUP_RCVAR_MAP=1
+ echo "$STARTUP_RCVAR_MAP"
+
+ #
+ # Attempt to create the persistant global cache
+ #
+
+ # Create a new temporary file to write to
+ local tmpfile="$( mktemp -t "$pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ # Write the temporary file contents
+ echo "$rc_script_list_digest" > "$tmpfile"
+ echo "$STARTUP_RCVAR_MAP" >> "$tmpfile"
+
+ # Finally, move the temporary file into place
+ case "$STARTUP_RCVAR_MAP_CACHEFILE" in
+ */*) f_quietly mkdir -p "${STARTUP_RCVAR_MAP_CACHEFILE%/*}"
+ esac
+ mv "$tmpfile" "$STARTUP_RCVAR_MAP_CACHEFILE"
+}
+
+fi # ! $_STARTUP_RCVAR_SUBR
diff --git a/usr.sbin/bsdconfig/startup/misc b/usr.sbin/bsdconfig/startup/misc
new file mode 100755
index 0000000..1dd2694
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/misc
@@ -0,0 +1,406 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="140.startup"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ GLOBALS
+
+#
+# Operating environment
+#
+UNAME_P=$( uname -p ) # Processor Architecture (i.e. i386)
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list var_list size
+ local hline="$hline_arrows_tab_enter"
+ local prompt="$msg_miscellaneous_menu_text"
+
+ menu_list="
+ 'X <<< $msg_exit' '$msg_exit_this_menu'
+ " # END-QUOTE
+
+ var_list="
+ accounting_enable
+ local_startup
+ lpd_enable
+ named_enable
+ named_flags
+ nis_client_enable
+ nis_server_enable
+ nisdomainname
+ startup_dirs
+ " # END-QUOTE
+
+ if [ "$UNAME_P" = "i386" ]; then
+ var_list="$var_list
+ apm_enable
+ ibcs2_enable
+ svr4_enable
+ " # END-QUOTE
+ fi
+
+ menu_list="$menu_list $(
+ . "$RC_DEFAULTS"
+ source_rc_confs
+ export $var_list
+ export msg_apm msg_apm_desc
+ export msg_startup_dirs msg_startup_dirs_desc
+ export msg_named msg_named_desc
+ export msg_named_flags msg_named_flags_desc
+ export msg_nis_client msg_nis_client_desc
+ export msg_nis_domainname msg_nis_domainname_desc
+ export msg_nis_server msg_nis_server_desc
+ export msg_accounting msg_accounting_desc
+ export msg_lpd msg_lpd_desc
+ export msg_sco msg_sco_desc
+ export msg_svr4 msg_svr4_desc
+ :| awk \
+ -v uname_p="$UNAME_P" \
+ -v menu_tags="$DIALOG_MENU_TAGS" \
+ -v menu_fmt="'%c [%c] %s' '%s'\n" \
+ -v sep_fmt="' ' ' -- '\n" \
+ 'END {
+ i = 1
+ if ( uname_p == "i386" )
+ {
+ #
+ # APM: Auto-power management services
+ # (typically laptops)
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( ENVIRON["apm_enable"] ~ \
+ /^[Yy][Ee][Ss]$/ ? "X" : " " ),
+ ENVIRON["msg_apm"],
+ ENVIRON["msg_apm_desc"]
+ }
+
+ # Separator
+ printf sep_fmt
+
+ #
+ # Startup dirs: Set the list of dirs to look for
+ # startup scripts
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( length(ENVIRON["local_startup"]) > 0 \
+ ? "X" : " " ),
+ ENVIRON["msg_startup_dirs"],
+ ENVIRON["msg_startup_dirs_desc"]
+
+ #
+ # named: Run a local name server on this host
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( ENVIRON["named_enable"] ~ \
+ /^[Yy][Ee][Ss]$/ ? "X" : " " ),
+ ENVIRON["msg_named"],
+ ENVIRON["msg_named_desc"]
+
+ #
+ # named flags: Set default flags to named (if enabled)
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( length(ENVIRON["named_flags"]) > 0 \
+ ? "X" : " " ),
+ ENVIRON["msg_named_flags"],
+ ENVIRON["msg_named_flags_desc"]
+
+ #
+ # NIS client: This host wishes to be an NIS client.
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( ENVIRON["nis_client_enable"] ~ \
+ /^[Yy][Ee][Ss]$/ ? "X" : " " ),
+ ENVIRON["msg_nis_client"],
+ ENVIRON["msg_nis_client_desc"]
+
+ #
+ # NIS domainname: Set NIS domainname (if enabled)
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( length(ENVIRON["nisdomainname"]) > 0 \
+ ? "X" : " " ),
+ ENVIRON["msg_nis_domainname"],
+ ENVIRON["msg_nis_domainname_desc"]
+
+ #
+ # NIS server: This host wishes to be an NIS server.
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( ENVIRON["nis_server_enable"] ~ \
+ /^[Yy][Ee][Ss]$/ ? "X" : " " ),
+ ENVIRON["msg_nis_server"],
+ ENVIRON["msg_nis_server_desc"]
+
+ # Separator
+ printf sep_fmt
+
+ #
+ # Accounting: This host wishes to run process
+ # accounting.
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( ENVIRON["accounting_enable"] ~ \
+ /^[Yy][Ee][Ss]$/ ? "X" : " " ),
+ ENVIRON["msg_accounting"],
+ ENVIRON["msg_accounting_desc"]
+
+ #
+ # lpd: This host has a printer and wants to run lpd.
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( ENVIRON["lpd_enable"] ~ \
+ /^[Yy][Ee][Ss]$/ ? "X" : " " ),
+ ENVIRON["msg_lpd"],
+ ENVIRON["msg_lpd_desc"]
+
+ if ( uname_p == "i386" )
+ {
+ #
+ # SCO: This host wants to be able to run IBCS2
+ # binaries.
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( ENVIRON["ibcs2_enable"] ~ \
+ /^[Yy][Ee][Ss]$/ ? "X" : " " ),
+ ENVIRON["msg_sco"],
+ ENVIRON["msg_sco_desc"]
+
+ #
+ # SVR4: This host wants to be able to run SVR4
+ # binaries.
+ #
+ printf menu_fmt, substr(menu_tags, i++, 1),
+ ( ENVIRON["svr4_enable"] ~ \
+ /^[Yy][Ee][Ss]$/ ? "X" : " " ),
+ ENVIRON["msg_svr4"],
+ ENVIRON["msg_svr4_desc"]
+ }
+ }'
+ )"
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# dialog_input_value [ $prompt [ $init ] ]
+#
+# Prompt the user to input a value. If the user does not cancel or press ESC,
+# the return value is zero ($SUCCESS) and $value holds the user's input.
+#
+dialog_input_value()
+{
+ local hline="$hline_alnum_tab_enter"
+ local size prompt="$1" _input="$2"
+
+ f_dialog_title "$msg_value_required"
+
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$prompt" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$prompt\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ f_dialog_title_restore
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ value="$_input"
+ return $SUCCESS
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_miscellaneous_startup_services"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X <<< $msg_exit") break ;;
+ ?" ["?"] $msg_apm")
+ case "$mtag" in
+ ?" [X] "*) err=$( f_sysrc_set apm_enable NO 2>&1 ) ;;
+ ?" [ ] "*) err=$( f_sysrc_set apm_enable YES 2>&1 ) ;;
+ esac
+ [ $? -eq $SUCCESS ] || f_show_msg "%s\n" "$err" ;;
+ ?" ["?"] $msg_startup_dirs")
+ dialog_input_value \
+ "$msg_startup_dirs_desc" \
+ "$( f_sysrc_get local_startup )"
+ if [ $? -eq $SUCCESS ]; then
+ err=$( f_sysrc_set local_startup "$value" ) ||
+ f_show_msg "%s\n" "$err"
+ fi
+ ;;
+ ?" ["?"] $msg_named")
+ case "$mtag" in
+ ?" [X] "*) err=$( f_sysrc_set named_enable NO 2>&1 ) ;;
+ ?" [ ] "*) err=$( f_sysrc_set named_enable YES 2>&1 ) ;;
+ esac
+ [ $? -eq $SUCCESS ] || f_show_msg "%s\n" "$err" ;;
+ ?" ["?"] $msg_named_flags")
+ dialog_input_value \
+ "$msg_named_flags_desc" \
+ "$( f_sysrc_get named_flags )"
+ if [ $? -eq $SUCCESS ]; then
+ err=$( f_sysrc_set named_flags "$value" ) ||
+ f_show_msg "%s\n" "$err"
+ fi
+ ;;
+ ?" ["?"] $msg_nis_client")
+ case "$mtag" in
+ ?" [X] "*) err=$( f_sysrc_set nis_client_enable NO 2>&1 ) ;;
+ ?" [ ] "*)
+ err=$( f_sysrc_set nis_client_enable YES 2>&1 ) \
+ && err=$( f_sysrc_set rpcbind_enable YES 2>&1 ) ;;
+ esac
+ [ $? -eq $SUCCESS ] || f_show_msg "%s\n" "$err" ;;
+ ?" ["?"] $msg_nis_domainname")
+ dialog_input_value \
+ "$msg_nis_domainname_desc" \
+ "$( f_sysrc_get nisdomainname )"
+ if [ $? -eq $SUCCESS ]; then
+ err=$( f_sysrc_set nisdomainname "$value" ) ||
+ f_show_msg "%s\n" "$err"
+ fi
+ ;;
+ ?" ["?"] $msg_nis_server")
+ case "$mtag" in
+ ?" [X] "*) err=$( f_sysrc_set nis_server_enable NO 2>&1 ) ;;
+ ?" [ ] "*)
+ err=$( f_sysrc_set nis_server_enable YES 2>&1 ) \
+ && err=$( f_sysrc_set rpcbind_enable YES 2>&1 ) ;;
+ esac
+ [ $? -eq $SUCCESS ] || f_show_msg "%s\n" "$err" ;;
+ ?" ["?"] $msg_accounting")
+ case "$mtag" in
+ ?" [X] "*) err=$( f_sysrc_set accounting_enable NO 2>&1 ) ;;
+ ?" [ ] "*) err=$( f_sysrc_set accounting_enable YES 2>&1 ) ;;
+ esac
+ [ $? -eq $SUCCESS ] || f_show_msg "%s\n" "$err" ;;
+ ?" ["?"] $msg_lpd")
+ case "$mtag" in
+ ?" [X] "*) err=$( f_sysrc_set lpd_enable NO 2>&1 ) ;;
+ ?" [ ] "*) err=$( f_sysrc_set lpd_enable YES 2>&1 ) ;;
+ esac
+ [ $? -eq $SUCCESS ] || f_show_msg "%s\n" "$err" ;;
+ ?" ["?"] $msg_sco")
+ case "$mtag" in
+ ?" [X] "*) err=$( f_sysrc_set ibcs2_enable NO 2>&1 ) ;;
+ ?" [ ] "*) err=$( f_sysrc_set ibcs2_enable YES 2>&1 ) ;;
+ esac
+ [ $? -eq $SUCCESS ] || f_show_msg "%s\n" "$err" ;;
+ ?" ["?"] $msg_svr4")
+ case "$mtag" in
+ ?" [X] "*) err=$( f_sysrc_set svr4_enable NO 2>&1 ) ;;
+ ?" [ ] "*) err=$( f_sysrc_set svr4_enable YES 2>&1 ) ;;
+ esac
+ [ $? -eq $SUCCESS ] || f_show_msg "%s\n" "$err" ;;
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/startup/rcadd b/usr.sbin/bsdconfig/startup/rcadd
new file mode 100755
index 0000000..1fba829
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/rcadd
@@ -0,0 +1,153 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="140.startup"
+f_include $BSDCFG_LIBE/$APP_DIR/include/rcconf.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ GLOBALS
+
+#
+# Options
+#
+# Inherit SHOW_DESC value if set, otherwise default to 1
+( : ${SHOW_DESC?} ) > /dev/null 2>&1 || SHOW_DESC=1
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_arrows_tab_enter"
+ local prompt=""
+
+ menu_list="
+ '1' '$msg_add_from_list'
+ '2' '$msg_add_custom'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_add_startup_directive"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ 1) # Add From List
+ # Loop for easy return
+ while :; do
+ f_dialog_input_rclist
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || break
+
+ case "$mtag" in
+ "X $msg_exit" ) break ;;
+ *) # Anything else is a directive
+ rcvar="${mtag# }"
+ $BSDCFG_LIBE/$APP_DIR/rcedit \
+ ${USE_XDIALOG:+-X} \
+ "$rcvar" || continue
+ esac
+ break
+ done
+ [ $retval -eq 0 ] || continue
+ ;;
+ 2) # Add Custom
+ f_dialog_input_rcvar || continue
+ $BSDCFG_LIBE/$APP_DIR/rcedit ${USE_XDIALOG:+-X} "$rcvar" ||
+ continue
+ ;;
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/startup/rcconf b/usr.sbin/bsdconfig/startup/rcconf
new file mode 100755
index 0000000..a18cad1
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/rcconf
@@ -0,0 +1,246 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="140.startup"
+f_include $BSDCFG_LIBE/$APP_DIR/include/rcconf.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ GLOBALS
+
+#
+# Global map/menu-list for the main menu
+#
+RCCONF_MAP=
+_RCCONF_MAP=
+RCCONF_MENU_LIST=
+
+#
+# Options
+#
+# Inherit SHOW_DESC value if set, otherwise default to 1
+( : ${SHOW_DESC?} ) > /dev/null 2>&1 || SHOW_DESC=1
+# Selectively inherit SHOW_* value (in order of preference)
+if [ "$SHOW_DEFAULT_VALUE" ]; then
+ SHOW_DEFAULT_VALUE=1
+ SHOW_CONFIGURED=
+ SHOW_VALUE=
+elif [ "$SHOW_CONFIGURED" ]; then
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=1
+ SHOW_VALUE=
+else
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=
+ SHOW_VALUE=1
+fi
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local size
+ local hline="$hline_arrows_tab_enter"
+ local prompt=""
+
+ RCCONF_MENU_LIST="
+ 'X $msg_exit' '$msg_exit_desc'
+ ${SHOW_DESC:+'$msg_exit_help'}
+ '> $msg_add_new' '$msg_add_new_desc'
+ ${SHOW_DESC:+'$msg_add_new_help'}
+ '> $msg_delete' '$msg_delete_desc'
+ ${SHOW_DESC:+'$msg_delete_help'}
+ ${USE_XDIALOG:+
+ '> $msg_view_details' '$msg_view_details_desc'
+ ${SHOW_DESC:+'$msg_view_details_help'}
+ }
+ " # END-QUOTE
+
+ if [ ! "$_RCCONF_MAP" ]; then
+ # Genreate RCCONF_MAP of `var desc ...' per-line
+ f_dialog_info "$msg_creating_rcconf_map"
+ RCCONF_MAP=$( f_startup_rcconf_map )
+ export RCCONF_MAP
+ # Generate _${var}_desc variables from $RCCONF_MAP
+ f_startup_rcconf_map_expand
+ export _RCCONF_MAP=1
+ fi
+
+ # Show infobox for modes that take a while to calculate/display
+ [ "$SHOW_DEFAULT_VALUE" -o "$SHOW_CONFIGURED" ] &&
+ f_dialog_info "$msg_creating_menu_list"
+
+ RCCONF_MENU_LIST="$RCCONF_MENU_LIST $(
+ . "$RC_DEFAULTS" > /dev/null
+ source_rc_confs > /dev/null
+ var_list=$( f_startup_rcconf_list )
+ for var in $var_list; do
+ eval export $var
+ [ "$SHOW_DEFAULT_VALUE" ] && export \
+ _${var}_default="$( f_sysrc_get_default $var )"
+ [ "$SHOW_CONFIGURED" ] && export \
+ _${var}_file="$( f_sysrc_find $var )"
+ done
+ export SHOW_VALUE SHOW_DESC SHOW_DEFAULT_VALUE SHOW_CONFIGURED
+ export msg_default_value
+ echo "$var_list" | awk '
+ BEGIN {
+ prefix = ""
+ }
+ {
+ cur_prefix = tolower(substr($1, 1, 1))
+ printf "'\''"
+ if ( prefix != cur_prefix )
+ prefix = cur_prefix
+ else
+ printf " "
+ var = $1
+ printf "%s'\'' '\''", var
+ if ( ENVIRON["SHOW_DEFAULT_VALUE"] ) {
+ default = ENVIRON["_" var "_default"]
+ gsub(/'\''/, "'\''\\'\'\''", default)
+ value = ENVIRON[var]
+ gsub(/'\''/, "'\''\\'\'\''", value)
+ printf ENVIRON["msg_default_value"] "; %s",
+ default, value
+ } else if ( ENVIRON["SHOW_CONFIGURED"] ) {
+ printf "%s", ENVIRON["_" var "_file"]
+ } else { # SHOW_VALUE (default behavior)
+ value = ENVIRON[var]
+ gsub(/'\''/, "'\''\\'\'\''", value)
+ printf "%s", value
+ }
+ printf "'\''"
+ if ( ENVIRON["SHOW_DESC"] ) {
+ desc = ENVIRON["_" var "_desc"]
+ gsub(/'\''/, "'\''\\'\'\''", desc)
+ printf " '\''%s'\''", desc
+ }
+ printf "\n"
+ }'
+ )"
+
+ set -f # noglob
+
+ size=$( eval f_dialog_menu_${SHOW_DESC:+with_help_}size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $RCCONF_MENU_LIST )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --help-button \
+ --help-label \"\$msg_details\" \
+ ${SHOW_DESC:+--item-help} \
+ --menu \"\$prompt\" $size \
+ $RCCONF_MENU_LIST \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_view_edit_startup_configuration"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ if [ "$USE_XDIALOG" ]; then
+ case "$mtag" in
+ "> $msg_view_details")
+ f_dialog_input_view_details
+ continue
+ esac
+ elif [ $retval -eq 2 ]; then
+ # The ``Help'' button (labeled "Details") was pressed
+ f_dialog_input_view_details
+ continue
+ fi
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+ "> $msg_add_new")
+ $BSDCFG_LIBE/$APP_DIR/rcadd ${USE_XDIALOG:+-X}
+ ;;
+ "> $msg_delete")
+ # rcdelete has a similar interface that can inherit the below:
+ export SHOW_VALUE SHOW_DESC SHOW_DEFAULT_VALUE SHOW_CONFIGURED
+ $BSDCFG_LIBE/$APP_DIR/rcdelete ${USE_XDIALOG:+-X}
+ ;;
+ *) # Anything else is a variable to edit
+ $BSDCFG_LIBE/$APP_DIR/rcedit ${USE_XDIALOG:+-X} "${mtag# }"
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/startup/rcdelete b/usr.sbin/bsdconfig/startup/rcdelete
new file mode 100755
index 0000000..acec48e
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/rcdelete
@@ -0,0 +1,355 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="140.startup"
+f_include $BSDCFG_LIBE/$APP_DIR/include/rcconf.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ GLOBALS
+
+#
+# Global map/menu-list for the main menu
+#
+RCCONF_MAP=
+_RCCONF_MAP=
+RCCONF_MENU_LIST=
+
+#
+# Options
+#
+# Inherit SHOW_DESC value if set, otherwise default to 1
+( : ${SHOW_DESC?} ) > /dev/null 2>&1 || SHOW_DESC=1
+# Selectively inherit SHOW_* value (in order of preference)
+if [ "$SHOW_DEFAULT_VALUE" ]; then
+ SHOW_DEFAULT_VALUE=1
+ SHOW_CONFIGURED=
+ SHOW_VALUE=
+elif [ "$SHOW_CONFIGURED" ]; then
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=1
+ SHOW_VALUE=
+else
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=
+ SHOW_VALUE=1
+fi
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local size
+ local hline="$hline_arrows_tab_enter"
+ local prompt=""
+
+ RCCONF_MENU_LIST="
+ 'X $msg_exit_cancel' '$msg_exit_cancel_desc'
+ ${SHOW_DESC:+'$msg_exit_cancel_help'}
+ '> $msg_delete_selected' '$msg_delete_selected_desc'
+ ${SHOW_DESC:+'$msg_delete_selected_help'}
+ '> $msg_all' '$msg_all_desc'
+ ${SHOW_DESC:+'$msg_all_help'}
+ '> $msg_none' '$msg_none_desc'
+ ${SHOW_DESC:+'$msg_none_help'}
+ ${USE_XDIALOG:+
+ '> $msg_view_details' '$msg_view_details_desc'
+ ${SHOW_DESC:+'$msg_view_details_help'}
+ }
+ " # END-QUOTE
+
+ if [ ! "$_RCCONF_MAP" ]; then
+ # Genreate RCCONF_MAP of `var desc ...' per-line
+ f_dialog_info "$msg_creating_rcconf_map"
+ RCCONF_MAP=$( f_startup_rcconf_map )
+ export RCCONF_MAP
+ # Generate _${var}_desc variables from $RCCONF_MAP
+ f_startup_rcconf_map_expand
+ export _RCCONF_MAP=1
+ fi
+
+ # Show infobox for modes that take a while to calculate/display
+ [ "$SHOW_DEFAULT_VALUE" -o "$SHOW_CONFIGURED" ] &&
+ f_dialog_info "$msg_creating_menu_list"
+
+ RCCONF_MENU_LIST="$RCCONF_MENU_LIST $(
+ . "$RC_DEFAULTS" > /dev/null
+ source_rc_confs > /dev/null
+ var_list=$( f_startup_rcconf_list )
+ for var in $var_list; do
+ eval export $var
+ [ "$SHOW_DEFAULT_VALUE" ] && export \
+ _${var}_default="$( f_sysrc_get_default $var )"
+ [ "$SHOW_CONFIGURED" ] && export \
+ _${var}_file="$( f_sysrc_find $var )"
+ done
+ export SHOW_VALUE SHOW_DESC SHOW_DEFAULT_VALUE SHOW_CONFIGURED
+ export msg_default_value
+ echo "$var_list" | awk '
+ BEGIN {
+ prefix = ""
+ }
+ {
+ cur_prefix = tolower(substr($1, 1, 1))
+ printf "'\''"
+ if ( prefix != cur_prefix )
+ prefix = cur_prefix
+ else
+ printf " "
+ var = $1
+ printf "%s'\'' '\''[", var
+ if ( ENVIRON["_" var "_delete"] )
+ printf "X"
+ else
+ printf " "
+ printf "] "
+ if ( ENVIRON["SHOW_DEFAULT_VALUE"] ) {
+ default = ENVIRON["_" var "_default"]
+ gsub(/'\''/, "'\''\\'\'\''", default)
+ value = ENVIRON[var]
+ gsub(/'\''/, "'\''\\'\'\''", value)
+ printf ENVIRON["msg_default_value"] "; %s",
+ default, value
+ } else if ( ENVIRON["SHOW_CONFIGURED"] ) {
+ printf "%s", ENVIRON["_" var "_file"]
+ } else { # SHOW_VALUE (default behavior)
+ value = ENVIRON[var]
+ gsub(/'\''/, "'\''\\'\'\''", value)
+ printf "%s", value
+ }
+ printf "'\''"
+ if ( ENVIRON["SHOW_DESC"] ) {
+ desc = ENVIRON["_" var "_desc"]
+ gsub(/'\''/, "'\''\\'\'\''", desc)
+ printf " '\''%s'\''", desc
+ }
+ printf "\n"
+ }'
+ )"
+
+ set -f # noglob
+
+ size=$( eval f_dialog_menu_${SHOW_DESC:+with_help_}size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $RCCONF_MENU_LIST )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --help-button \
+ --help-label \"\$msg_details\" \
+ ${SHOW_DESC:+--item-help} \
+ --menu \"\$prompt\" $size \
+ $RCCONF_MENU_LIST \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# dialog_menu_delete $var1 [$var2 ...]
+#
+# Get the user's blessing to delete one or more variables.
+# if (and only-if) the user confirms (does not press ESC or Cancel/NO).
+#
+dialog_menu_delete()
+{
+ local size
+ local hline="$hline_arrows_tab_enter"
+ local prompt="$msg_are_you_sure_you_want_delete_the_following"
+ local var_list menu_list
+
+ [ $# -ge 1 ] || return $FAILURE
+
+ if [ $# -eq 1 ]; then
+ msg=$( printf "$msg_are_you_sure_you_want_to_delete" \
+ "$delete_vars" )
+ f_dialog_noyes "$msg"
+ return $?
+ fi
+
+ var_list=$( for var in $*; do echo "$var"; done | sort -u )
+ menu_list=$(
+ . "$RC_DEFAULTS"
+ source_rc_confs
+ echo "$var_list" | awk '
+ BEGIN {
+ prefix = ""
+ }
+ {
+ cur_prefix = tolower(substr($1, 1, 1))
+ printf "'\''"
+ if ( prefix != cur_prefix )
+ prefix = cur_prefix
+ else
+ printf " "
+ var = $1
+ printf "%s'\'' '\'\''\n", var
+ }'
+ )
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ local defaultno="defaultno"
+ [ "$USE_XDIALOG" ] && defaultno="default-no"
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --$defaultno \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_delete_startup_directives"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ if [ "$USE_XDIALOG" ]; then
+ case "$mtag" in
+ "> $msg_view_details")
+ f_dialog_input_view_details
+ continue
+ esac
+ elif [ $retval -eq 2 ]; then
+ # The ``Help'' button (labeled "Details") was pressed
+ f_dialog_input_view_details
+ continue
+ fi
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit_cancel") break ;;
+ "> $msg_delete_selected")
+ delete_vars=
+ for var in $( f_startup_rcconf_list ); do
+ [ "$( eval echo \$_${var}_delete )" ] || continue
+ delete_vars="$delete_vars${delete_vars:+ }$var"
+ done
+ unset var # no longer needed
+ if dialog_menu_delete $delete_vars; then
+ f_dialog_title "$msg_info"
+ f_dialog_info "$msg_deleting_selected_directives"
+ f_dialog_title_restore
+ for var in $delete_vars; do
+ err=$( f_sysrc_delete $var 2>&1 )
+ if [ $? -ne $SUCCESS ]; then
+ f_show_msg "%s\n" "$err"
+ break
+ fi
+ done
+ unset var # no longer needed
+ fi
+ ;;
+ "> $msg_all")
+ for var in $( f_startup_rcconf_list ); do
+ setvar _${var}_delete 1
+ export _${var}_delete
+ done
+ unset var # no longer needed
+ ;;
+ "> $msg_none")
+ var_list=$( set | awk -F= "
+ /$STARTUP_RCCONF_REGEX/ {
+ if (\$1 ~ /^_[[:alpha:]_][[:alnum:]_]*_delete/)
+ print \$1
+ }"
+ )
+ [ "$var_list" ] && unset $var_list
+ unset var_list # no longer needed
+ ;;
+ *) # Anything else is a variable to edit
+ var="${mtag# }"
+
+ # Toggle the state-variable and loop back to menu
+ if ( eval : \${_${var}_delete?} ) > /dev/null 2>&1; then
+ unset _${var}_delete
+ else
+ setvar _${var}_delete 1
+ export _${var}_delete
+ fi
+ unset var # no longer needed
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/startup/rcedit b/usr.sbin/bsdconfig/startup/rcedit
new file mode 100755
index 0000000..19d1941
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/rcedit
@@ -0,0 +1,69 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="140.startup"
+f_include $BSDCFG_LIBE/$APP_DIR/include/rcedit.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+f_dialog_rcedit "$@"
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/startup/rcvar b/usr.sbin/bsdconfig/startup/rcvar
new file mode 100755
index 0000000..e66f3bb
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/rcvar
@@ -0,0 +1,200 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/sysrc.subr
+
+APP_DIR="140.startup"
+f_include $BSDCFG_LIBE/$APP_DIR/include/rcvar.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ GLOBALS
+
+#
+# Global map/menu-list for the main menu
+#
+RCVAR_MAP=
+_RCVAR_MAP=
+RCVAR_MENU_LIST=
+
+#
+# Options
+#
+# Inherit SHOW_DESC value if set, otherwise default to 1
+( ${SHOW_DESC?} ) > /dev/null 2>&1 || SHOW_DESC=1
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local size
+ local hline="$hline_arrows_tab_enter"
+ local prompt=""
+
+ RCVAR_MENU_LIST="
+ 'X $msg_exit' '$msg_exit_this_menu'
+ ${SHOW_DESC:+'$msg_exit_this_menu'}
+ " # END-QUOTE
+
+ if [ ! "$_RCVAR_MAP" ]; then
+ # Genreate RCVAR_MAP of `rcvar dflt script desc ...' per-line
+ f_dialog_info "$msg_creating_rcvar_map"
+ RCVAR_MAP=$( f_startup_rcvar_map )
+ export RCVAR_MAP
+ export _RCVAR_MAP=1
+ fi
+
+ RCVAR_MENU_LIST="$RCVAR_MENU_LIST $(
+ . "$RC_DEFAULTS" > /dev/null
+ source_rc_confs > /dev/null
+ for rcvar in $( echo "$RCVAR_MAP" | awk '{print $1}' ); do
+ eval export $rcvar
+ done
+ export SHOW_DESC msg_default_value
+ echo "$RCVAR_MAP" | awk '
+ BEGIN {
+ prefix = ""
+ rword = "^[[:space:]]*[^[:space:]]*[[:space:]]*"
+ }
+ {
+ cur_prefix = tolower(substr($1, 1, 1))
+ printf "'\''"
+ if ( prefix != cur_prefix )
+ prefix = cur_prefix
+ else
+ printf " "
+ rcvar = $1
+ default = $2
+ script = $3
+ printf "%s'\'' '\''", rcvar
+ if ( ENVIRON[rcvar] ~ /[Yy][Ee][Ss]/ )
+ printf "[X] "
+ else
+ printf "[ ] "
+ printf "%s; " ENVIRON["msg_default_value"],
+ script, default
+ printf "'\''"
+ if ( ENVIRON["SHOW_DESC"] ) {
+ desc = $0
+ sub(rword, "", desc)
+ sub(rword, "", desc)
+ sub(rword, "", desc)
+ gsub(/'\''/, "'\''\\'\'\''", desc)
+ printf " '\''%s'\''", desc
+ }
+ printf "\n"
+ }'
+ )"
+
+ set -f # noglob
+
+ size=$( eval f_dialog_menu_${SHOW_DESC:+with_help_}size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $RCVAR_MENU_LIST )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ ${SHOW_DESC:+--item-help} \
+ --menu \"\$prompt\" $size \
+ $RCVAR_MENU_LIST \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_toggle_startup_services"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+ *) # Anything else is an rcvar to toggle
+
+ rcvar="${mtag# }"
+ value=$( eval f_dialog_menutag2item${SHOW_DESC:+_with_help} \
+ \"\$mtag\" $RCVAR_MENU_LIST )
+
+ # Determine the new [toggled] value to use
+ case "$value" in
+ "[X]"*) value="NO";;
+ *) value="YES";;
+ esac
+
+ err=$( f_sysrc_set "$rcvar" "$value" 2>&1 ) ||
+ f_show_msg "$err"
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/startup/startup b/usr.sbin/bsdconfig/startup/startup
new file mode 100755
index 0000000..70e82e0
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/startup
@@ -0,0 +1,128 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="140.startup"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_arrows_tab_enter"
+ local prompt=""
+
+ menu_list="
+ 'X' '$msg_exit'
+ '1' '$msg_toggle_startup_services'
+ '2' '$msg_view_edit_startup_configuration'
+ '3' '$msg_miscellaneous_startup_services'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_startup"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ X) # Exit
+ break ;;
+ 1) # Toggle Startup Services
+ $BSDCFG_LIBE/$APP_DIR/rcvar ${USE_XDIALOG:+-X} ;;
+ 2) # View/Edit Startup Configuration
+ $BSDCFG_LIBE/$APP_DIR/rcconf ${USE_XDIALOG:+-X} ;;
+ 3) # Miscellaneous Startup Services
+ $BSDCFG_LIBE/$APP_DIR/misc ${USE_XDIALOG:+-X} ;;
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/timezone/INDEX b/usr.sbin/bsdconfig/timezone/INDEX
new file mode 100644
index 0000000..af17594
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/INDEX
@@ -0,0 +1,53 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Timezone"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Set up Time Zone"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="timezone|timezone"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="timezone"
diff --git a/usr.sbin/bsdconfig/timezone/Makefile b/usr.sbin/bsdconfig/timezone/Makefile
new file mode 100644
index 0000000..f77a37b
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/090.timezone
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= timezone
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/timezone/USAGE b/usr.sbin/bsdconfig/timezone/USAGE
new file mode 100644
index 0000000..a88369c
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/USAGE
@@ -0,0 +1,42 @@
+# Copyright (c) 2011-2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [-ehnrSsvX] [-C chroot_dir] [zinfo_file | zinfo_name]
+OPTIONS:
+ -h Print usage statement and exit.
+ -e Only return success on exit if user selects a timezone AND
+ the selected timezone was successfully installed. By default
+ (without this flag), success is always returned unless an
+ error has occurred.
+ -n Do not create or copy files.
+ -r Reinstall the zoneinfo file installed last time. The name is
+ obtained from /var/db/zoneinfo.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -s Skip the initial question about adjusting the clock if
+ not set to UTC.
+ -v Verbose. Enable extra output when installing the zone file.
+ -X Enable the use of Xdialog(1) instead of dialog(1).
diff --git a/usr.sbin/bsdconfig/timezone/include/Makefile b/usr.sbin/bsdconfig/timezone/include/Makefile
new file mode 100644
index 0000000..a4c5ba1
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/include/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/090.timezone/include
+FILES= continents.subr countries.subr iso3166.subr menus.subr \
+ messages.subr zones.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/timezone/include/continents.subr b/usr.sbin/bsdconfig/timezone/include/continents.subr
new file mode 100644
index 0000000..126020c
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/include/continents.subr
@@ -0,0 +1,138 @@
+if [ ! "$_TIMEZONE_CONTINENTS_SUBR" ]; then _TIMEZONE_CONTINENTS_SUBR=1
+#
+# Copyright (c) 2011-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+
+APP_DIR="090.timezone"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# List of worldly continents/oceans (export'ed for awk(1) ENVIRON visibility)
+#
+export CONTINENTS="
+ africa
+ america
+ antarctica
+ arctic
+ asia
+ atlantic
+ australia
+ europe
+ indian
+ pacific
+ utc
+"
+
+#
+# Directory name of each continent/ocean (in _PATH_ZONEINFO)
+#
+export continent_africa_name="Africa"
+export continent_america_name="America"
+export continent_antarctica_name="Antarctica"
+export continent_arctic_name="Arctic"
+export continent_asia_name="Asia"
+export continent_atlantic_name="Atlantic"
+export continent_australia_name="Australia"
+export continent_europe_name="Europe"
+export continent_indian_name="Indian"
+export continent_pacific_name="Pacific"
+export continent_utc_name="UTC"
+
+#
+# Export i18n menu texts of continents/oceans for awk(1) ENVIRON visibility
+# NOTE: These are defined in messages.subr included above.
+#
+export continent_africa_title
+export continent_america_title
+export continent_antarctica_title
+export continent_arctic_title
+export continent_asia_title
+export continent_atlantic_title
+export continent_australia_title
+export continent_europe_title
+export continent_indian_title
+export continent_pacific_title
+export continent_utc_title
+
+############################################################ FUNCTIONS
+
+# f_continent $cont $property
+#
+# Returns a single property of a given continent. Available properties are:
+#
+# name Directory name of continent/ocean as it appears in
+# _PATH_ZONEINFO.
+# title Menu text of this continent/ocean to be displayed in the
+# continent-selection menu.
+# nitems Number of submenu items associated with this
+# continent/ocean.
+# tlc_N 2-character country code of the Nth submenu item associated
+# with this continent displayed in the country-selection menu
+# (which appears after continent selection).
+# menu_list Menu-list of regions for this continent.
+#
+f_continent()
+{
+ local cont="$1" property="$2"
+ eval echo \"\${continent_${cont}_$property}\"
+}
+
+# f_find_continent $title
+#
+# Returns continent identifier given continent title.
+#
+f_find_continent()
+{
+ local cont
+ for cont in $CONTINENTS; do
+ if [ "$1" = "$( f_continent $cont title )" ]; then
+ echo "$cont"
+ return $SUCCESS
+ fi
+ done
+ return $FAILURE
+}
+
+# f_OCEANP $cont
+#
+# Returns "1" if the first argument is an ocean, otherwise NULL.
+#
+f_OCEANP()
+{
+ case "$1" in
+ arctic|atlantic|indian|pacific)
+ echo 1
+ esac
+}
+
+fi # ! $_TIMEZONE_CONTINENTS_SUBR
diff --git a/usr.sbin/bsdconfig/timezone/include/countries.subr b/usr.sbin/bsdconfig/timezone/include/countries.subr
new file mode 100644
index 0000000..9c6a164
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/include/countries.subr
@@ -0,0 +1,78 @@
+if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1
+#
+# Copyright (c) 2011-2012 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 (INLUDING, 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$
+
+# f_country $code $property
+#
+# Returns a single property of a given country. Available properties are:
+#
+# name Name of the country as read from _PATH_ISO3166.
+# nzones Number of zones within the country (-1 if country has
+# only a single zone).
+# filename The filename portion of the TZ field (after the `/') as
+# read from _PATH_ZONETAB.
+# cont The principal continent in which the country lies (appears
+# before the `/' in the TZ field of _PATH_ZONETAB).
+# filename_N Like filename, but for the Nth zone when the country has
+# multiple zones (nzones > 0).
+# cont_N Like cont, but for the Nth zone when the country has
+# multiple zones (nzones > 0).
+# descr_N Like name, but for the Nth zone when the country has
+# multiple zones (nzones > 0)
+#
+f_country()
+{
+ local code="$1" property="$2"
+ eval echo \"\${country_${code}_$property}\"
+}
+
+# f_sort_countries
+#
+# Sorts alphabetically the 2-character country codes listed in $COUNTRIES based
+# on the name of each country.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_sort_countries_awk='
+{
+ split($0, array, /[[:space:]]+/)
+ for (item in array)
+ {
+ tlc = array[item]
+ print ENVIRON["country_" tlc "_name"] " " tlc
+ }
+}
+'
+f_sort_countries()
+{
+ COUNTRIES=$( echo "$COUNTRIES" | awk "$f_sort_countries_awk" |
+ sort | awk '{print $NF}' )
+ export COUNTRIES
+}
+
+fi # ! $_TIMEZONE_COUNTRIES_SUBR
diff --git a/usr.sbin/bsdconfig/timezone/include/iso3166.subr b/usr.sbin/bsdconfig/timezone/include/iso3166.subr
new file mode 100644
index 0000000..d69f3da
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/include/iso3166.subr
@@ -0,0 +1,197 @@
+if [ ! "$_TIMEZONE_ISO3166_SUBR" ]; then _TIMEZONE_ISO3166_SUBR=1
+#
+# Copyright (c) 2011-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+
+APP_DIR="090.timezone"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Standard pathnames
+#
+_PATH_ISO3166="/usr/share/misc/iso3166"
+
+#
+# Export required i18n messages for awk(1) ENVIRON visibility
+#
+export msg_country_code_multiply_defined
+export msg_invalid_code
+export msg_invalid_format
+
+############################################################ FUNCTIONS
+
+# f_read_iso3166_table
+#
+# Read the ISO 3166 country code database in _PATH_ISO3166:
+# /usr/share/misc/iso3166 on FreeBSD
+# /usr/share/zoneinfo/iso3166.tab on Linux, Mac OS X, and Cygwin
+#
+# The format of this file on FreeBSD is:
+# two three number name
+#
+# The format of this file on Linux, Mac OS X, and Cygwin is:
+# two name
+#
+# With each of the following elements (described below) being separated by a
+# single tab character:
+#
+# two ISO 3166 2-character country code
+# three ISO 3166 3-character country code (if provided)
+# number ISO 3166 numeric country code (if provided)
+# name Human-readable country name (may contain spaces)
+#
+# Variables created by this function:
+#
+# COUNTRIES
+# A space-separated list of 2-character country codes.
+# country_CODE_name
+# The country `name' (as described above).
+#
+# where CODE is the 2-character country code.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_read_iso3166_table_awk='
+# Variables that should be defined on the invocation line:
+# -v progname="progname"
+#
+BEGIN {
+ lineno = 0
+ failed = 0
+}
+function die(fmt, argc, argv)
+{
+ printf "f_die 1 \"%%s: %s\" \"%s\"", fmt, progname
+ for (n = 1; n <= argc; n++)
+ printf " \"%s\"", argv[n]
+ print ""
+ failed++
+ exit 1
+}
+function add_country(tlc, name)
+{
+ if (country_name[tlc])
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ argv[3] = tlc
+ argv[4] = name
+ die(ENVIRON["msg_country_code_multiply_defined"], 4, argv)
+ }
+
+ country_name[tlc] = name
+}
+function print_country_name(tlc)
+{
+ name = country_name[tlc]
+ gsub(/"/, "\\\"", name)
+ printf "country_%s_name=\"%s\"\n", tlc, name
+ printf "export country_%s_name\n", tlc
+}
+/^#/ {
+ lineno++
+ next
+}
+!/^#/ {
+ lineno++
+
+ # Split the current record (on TAB) into an array
+ split($0, line, /\t/)
+
+ # Get the ISO3166-1 (Alpha 1) 2-letter country code
+ tlc = line[1]
+
+ #
+ # Validate the two-character country code
+ #
+ if (length(tlc) != 2)
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ die(ENVIRON["msg_invalid_format"], 2, argv)
+ }
+ if (!match(tlc, /^[A-Z][A-Z]$/))
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ argv[3] = tlc
+ die(ENVIRON["msg_invalid_code"], 3, argv)
+ }
+
+ #
+ # Calculate the substr start-position of the name
+ #
+ name_start = 0
+ n = 4
+ if (FILENAME ~ /\.tab$/)
+ n = 2
+ while (--n)
+ {
+ #
+ # Validate field-length of 2nd/3rd columns while we are here
+ #
+ if (n > 1 && length(line[n]) != 3)
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ die(ENVIRON["msg_invalid_format"], 2, argv)
+ }
+
+ name_start += length(line[n]) + 1
+ }
+
+ # Get the name field
+ name = substr($0, name_start + 1)
+
+ add_country(tlc, name)
+}
+END {
+ list = ""
+ for (tlc in country_name)
+ {
+ list = list (length(list) > 0 ? " " : "") tlc
+ print_country_name(tlc)
+ }
+ printf "COUNTRIES=\"%s\"\n", list
+ print "export COUNTRIES"
+}
+'
+f_read_iso3166_table()
+{
+ eval $( awk -v progname="$pgm" \
+ "$f_read_iso3166_table_awk" \
+ "$_PATH_ISO3166" )
+}
+
+fi # ! $_TIMEZONE_ISO3166_SUBR
diff --git a/usr.sbin/bsdconfig/timezone/include/menus.subr b/usr.sbin/bsdconfig/timezone/include/menus.subr
new file mode 100644
index 0000000..46bdc04
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/include/menus.subr
@@ -0,0 +1,220 @@
+if [ ! "$_TIMEZONE_MENUS_SUBR" ]; then _TIMEZONE_MENUS_SUBR=1
+#
+# Copyright (c) 2011-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+############################################################ GLOBALS
+
+#
+# Export special included variables required by awk(1) for `ENVIRON' visibility
+#
+export DIALOG_MENU_TAGS
+
+############################################################ FUNCTIONS
+
+# f_make_menus
+#
+# Creates the tag/item ordered-pair list environment variables for the
+# continent and country menus.
+#
+# Required variables [from continents.subr]:
+#
+# CONTINENTS
+# Space-separated list of continents.
+# continent_*_title
+# Desired menu text for the continent represented by *.
+#
+# Required variables [created by f_read_iso3166_table from iso3166.subr]:
+#
+# COUNTRIES
+# Space-separated list of 2-character country codes.
+# country_*_name :: when country_*_nzones < 0
+# Desired menu text for the country-zone represented by *, the 2-
+# character country code.
+#
+# Required variables [created by f_read_zones from zones.subr]:
+#
+# country_*_nzones
+# Number of zones for the country represented by *, the 2-
+# character country code. Should be -1 if the country has only
+# one single zone, otherwise 1 or greater to indicate how many
+# zones the country has.
+# country_*_cont :: when country_*_nzones < 0
+# Principal continent (or ocean) in which the country-zone
+# represented by *, the 2-character country code, resides.
+# country_*_cont_N :: when country_*_nzones > 0
+# Principal continent (or ocean) in which zone-N of the country
+# represented by * resides, the 2-character country code.
+# country_*_descr_N :: when country_*_nzones > 0
+# Desired submenu text for zone-N of the country represented by
+# *, the 2-character country code.
+#
+# Variables created by this function:
+#
+# continent_menu_list
+# Menu-list of continents.
+# continent_*_nitems
+# Number of items associated with the continent represented by *,
+# the continent identifier.
+# continent_*_tlc_N
+# 2-character country code of the Nth item in the continent menu
+# for the continent represented by *, the continent identifier.
+# continent_*_menu_list
+# Menu-list of countries/zones for each continent represented by
+# *, the continent identifier.
+# country_*_menu_list
+# For countries that have multiple zones, this is the submenu-
+# list of zones for said country represented by *, the 2-
+# character country code.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_make_menus_awk='
+function add_zone_n_to_country_menu(tlc, n)
+{
+ zone_title = ENVIRON["country_" tlc "_descr_" n]
+ gsub(/'\''/, "'\''\\'\'''\''", zone_title)
+ country_menu_list[tlc] = country_menu_list[tlc] \
+ ( length(country_menu_list[tlc]) > 0 ? "\n" : "" ) \
+ n " '\''" zone_title "'\''"
+}
+BEGIN {
+ #
+ # First, count up all the countries in each continent/ocean.
+ # Be careful to count those countries which have multiple zones
+ # only once for each. NB: some countries are in multiple
+ # continents/oceans.
+ #
+ i = split(ENVIRON["COUNTRIES"], countries, /[[:space:]]+/)
+ for (cp = 1; cp <= i; cp++)
+ {
+ tlc = countries[cp]
+ title = ENVIRON["country_" tlc "_name"]
+ gsub(/'\''/, "'\''\\'\'''\''", title)
+ nzones = ENVIRON["country_" tlc "_nzones"]
+ if (!nzones)
+ {
+ # Country has no zones
+ continue
+ }
+ else if (nzones < 0)
+ {
+ # Country has only one zone
+ cont = ENVIRON["country_" tlc "_cont"]
+ nitems = ++continent_nitems[cont]
+ continent_tlc[cont,nitems] = tlc
+ continent_title[cont,nitems] = title
+ }
+ else
+ {
+ # Country has one or more zones
+ for (n = 1; n <= nzones; n++)
+ {
+ add_zone_n_to_country_menu(tlc, n)
+ cont = ENVIRON["country_" tlc "_cont_" n]
+ for (x = 1; x < n; x++)
+ {
+ contx = ENVIRON["country_"tlc"_cont_"x]
+ if (cont == contx) break
+ }
+ if (x == n)
+ {
+ nitems = ++continent_nitems[cont]
+ continent_tlc[cont,nitems] = tlc
+ continent_title[cont,nitems] = title
+ }
+ }
+ }
+ }
+}
+END {
+ tags = ENVIRON["DIALOG_MENU_TAGS"]
+ cont_menu_list = ""
+ tagn = 0
+
+ #
+ # Assemble the menu items in the menu list for each continent/ocean.
+ #
+ i = split(ENVIRON["CONTINENTS"], array, /[[:space:]]+/)
+ for (item = 1; item <= i; item++)
+ {
+ cont = array[item]
+ if (!cont) continue
+
+ if (++tagn >= length(tags)) break
+ tag = substr(tags, tagn, 1)
+ cont_menu_list = cont_menu_list \
+ ( length(cont_menu_list) > 0 ? "\n" : "" ) \
+ "'\''" tag "'\'' '\''" \
+ ENVIRON["continent_" cont "_title"] "'\''"
+
+ nitems = continent_nitems[cont]
+ printf "continent_%s_nitems=%d\n", cont, nitems
+
+ menu_list = ""
+ for (n = 1; n <= nitems; n++)
+ {
+ printf "continent_%s_tlc_%d=%s\n",
+ cont, n, continent_tlc[cont,n]
+
+ title = continent_title[cont,n]
+ menu_list = menu_list \
+ ( length(menu_list) > 0 ? "\n" : "" ) \
+ n " '\''" title "'\''"
+ }
+
+ gsub(/"/, "\\\"", menu_list)
+ printf "continent_%s_menu_list=\"%s\"\n", cont, menu_list
+ }
+
+ gsub(/"/, "\\\"", continent_menu_list)
+ printf "continent_menu_list=\"%s\"\n", cont_menu_list
+ print "export continent_menu_list"
+
+ #
+ # Dump the submenus of countries with multiple zones
+ #
+ for (tlc in country_menu_list)
+ {
+ menu_list = country_menu_list[tlc]
+ gsub(/"/, "\\\"", menu_list)
+ printf "country_%s_menu_list=\"%s\"\n", tlc, menu_list
+ }
+}
+'
+f_make_menus()
+{
+ eval $( :| awk "$f_make_menus_awk" )
+}
+
+fi # ! $_TIMEZONE_MENUS_SUBR
diff --git a/usr.sbin/bsdconfig/timezone/include/messages.subr b/usr.sbin/bsdconfig/timezone/include/messages.subr
new file mode 100644
index 0000000..6a7f045
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/include/messages.subr
@@ -0,0 +1,78 @@
+# Copyright (c) 2012 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$
+
+continent_africa_title="Africa"
+continent_america_title="America -- North and South"
+continent_antarctica_title="Antarctica"
+continent_arctic_title="Arctic Ocean"
+continent_asia_title="Asia"
+continent_atlantic_title="Atlantic Ocean"
+continent_australia_title="Australia"
+continent_europe_title="Europe"
+continent_indian_title="Indian Ocean"
+continent_pacific_title="Pacific Ocean"
+continent_utc_title="UTC"
+msg_cancel="Cancel"
+msg_cannot_open_for_reading="Cannot open %s for reading. Does it exist?"
+msg_confirmation="Confirmation"
+msg_conflicting_zone_definition="%s:%d: conflicting zone definition"
+msg_copied_timezone_file="Copied timezone file from %s to %s"
+msg_copying_file="Copying %s to %s"
+msg_country_code_invalid="%s:%d: country code \`%s' invalid"
+msg_country_code_multiply_defined="%s:%d: country code \`%s' multiply defined: %s"
+msg_country_code_unknown="%s:%d: country code \`%s' unknown"
+msg_country_time_zones="%s Time Zones"
+msg_country_title="Countries in %s"
+msg_created_symlink="Created symbolic link from %s to %s"
+msg_creating_symlink="Creating symbolic link %s to %s"
+msg_default_zone_provided="Default timezone provided"
+msg_done="Done"
+msg_error="Error"
+msg_error_reading="Error reading %s."
+msg_info="Info"
+msg_invalid_code="%s:%d: invalid code \`%s'"
+msg_invalid_country_code="%s:%d: invalid country code \`%s'"
+msg_invalid_format="%s:%d: invalid format"
+msg_invalid_region="%s:%d: invalid region \`%s'"
+msg_invalid_zone_name="%s:%d: invalid zone name \`%s'"
+msg_is_machine_clock_utc="Is the machine's CMOS clock set to UTC? If it is set to local time,\nor you don't know, please choose NO here!"
+msg_island_and_group_title="Islands and groups in the %s"
+msg_look_reasonable="Does the abbreviation \`%s' look reasonable?"
+msg_no="No"
+msg_ok="OK"
+msg_removed_file="Removed %s"
+msg_removing_file="Removing %s"
+msg_select_country="Select a country"
+msg_select_island_or_group="Select an island or group"
+msg_select_local_or_utc="Select local or UTC (Greenwhich Mean Time) clock"
+msg_select_region="Select a region"
+msg_select_zone="Select a zone which observes the same time as your locality."
+msg_time_zone="Time Zone"
+msg_unable_to_determine_name_from_db="Unable to determine earlier installed zoneinfo name. Check %s"
+msg_use_default_zone="Use the default \`%s' zone?"
+msg_yes="Yes"
+msg_zone_multiply_defined="%s:%d: zone multiply defined"
+msg_zone_must_have_description="%s:%d: zone must have description"
diff --git a/usr.sbin/bsdconfig/timezone/include/zones.subr b/usr.sbin/bsdconfig/timezone/include/zones.subr
new file mode 100644
index 0000000..704d02f
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/include/zones.subr
@@ -0,0 +1,670 @@
+if [ ! "$_TIMEZONE_ZONES_SUBR" ]; then _TIMEZONE_ZONES_SUBR=1
+#
+# Copyright (c) 2011-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+APP_DIR="090.timezone"
+f_include $BSDCFG_LIBE/$APP_DIR/include/continents.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Standard pathnames
+#
+_PATH_ZONETAB="/usr/share/zoneinfo/zone.tab"
+_PATH_ZONEINFO="/usr/share/zoneinfo"
+_PATH_LOCALTIME="/etc/localtime"
+_PATH_DB="/var/db/zoneinfo"
+
+#
+# Export required i18n messages for awk(1) ENVIRON visibility
+#
+export msg_conflicting_zone_definition
+export msg_country_code_invalid
+export msg_country_code_unknown
+export msg_invalid_country_code
+export msg_invalid_format
+export msg_invalid_region
+export msg_invalid_zone_name
+export msg_zone_multiply_defined
+export msg_zone_must_have_description
+
+############################################################ FUNCTIONS
+
+# f_read_zones
+#
+# Read the zone descriptions database in _PATH_ZONETAB:
+# /usr/share/zoneinfo/zone.tab on all OSes
+#
+# The format of this file (on all OSes) is:
+# code coordinates TZ comments
+#
+# With each of the following elements (described below) being separated by a
+# single tab character:
+#
+# code
+# The ISO 3166 2-character country code.
+# coordinates
+# Latitude and logitude of the zone's principal location in ISO
+# 6709 sign-degrees-minutes-seconds format, either +-DDMM+-DDDMM
+# or +-DDMMSS+-DDDMMSS, first latitude (+ is north), then long-
+# itude (+ is east).
+# TZ
+# Zone name used in value of TZ environment variable.
+# comments
+# Comments; present if and only if the country has multiple rows.
+#
+# Required variables [from continents.subr]:
+#
+# CONTINENTS
+# Space-separated list of continents.
+# continent_*_name
+# Directory element in _PATH_ZONEINFO for the continent
+# represented by *.
+#
+# Required variables [created by f_read_iso3166_table from iso3166.subr]:
+#
+# country_CODE_name
+# Country name of the country represented by CODE, the 2-
+# character country code.
+#
+# Variables created by this function:
+#
+# country_CODE_nzones
+# Either set to `-1' to indicate that the 2-character country
+# code has only a single zone associated with it (and therefore
+# you should query the `country_CODE_*' environment variables),
+# or set to `0' or higher to indicate how many zones are assoc-
+# iated with the given country code. When multiple zones are
+# configured for a single code, you should instead query the
+# `country_CODE_*_N' environment variables (e.g., `echo
+# $country_AQ_descr_1' prints the description of the first
+# timezone in Antarctica).
+# country_CODE_filename
+# The ``filename'' portion of the TZ value that appears after the
+# `/' (e.g., `Hong_Kong' from `Asia/Hong_Kong' or `Isle_of_Man'
+# from `Europe/Isle_of_Man').
+# country_CODE_cont
+# The ``continent'' portion of the TZ value that appears before
+# the `/' (e.g., `Asia' from `Asia/Hong_Kong' or `Europe' from
+# `Europe/Isle_of_Man').
+# country_CODE_descr
+# The comments associated with the ISO 3166 code entry (if any).
+#
+# NOTE: CODE is the 2-character country code.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_read_zones_awk='
+# Variables that should be defined on the invocation line:
+# -v progname="progname"
+#
+BEGIN {
+ lineno = 0
+ failed = 0
+
+ #
+ # Initialize continents array/map (name => id)
+ #
+ split(ENVIRON["CONTINENTS"], array, /[[:space:]]+/)
+ for (item in array)
+ {
+ cont = array[item]
+ if (!cont) continue
+ name = ENVIRON["continent_" cont "_name"]
+ continents[name] = cont
+ }
+}
+function die(fmt, argc, argv)
+{
+ printf "f_die 1 \"%%s: %s\" \"%s\"", fmt, progname
+ for (n = 1; n <= argc; n++)
+ printf " \"%s\"", argv[n]
+ print ""
+ failed++
+ exit 1
+}
+function find_continent(name)
+{
+ return continents[name]
+}
+function add_zone_to_country(lineno, tlc, descr, file, cont)
+{
+ #
+ # Validate the two-character country code
+ #
+ if (!match(tlc, /^[A-Z][A-Z]$/))
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ argv[3] = tlc
+ die(ENVRION["msg_country_code_invalid"], 3, argv)
+ }
+ if (!ENVIRON["country_" tlc "_name"])
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ argv[3] = tlc
+ die(ENVIRON["msg_country_code_unknown"], 3, argv)
+ }
+
+ #
+ # Add Zone to an array that we will parse at the end
+ #
+ if (length(descr) > 0)
+ {
+ if (country_nzones[tlc] < 0)
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ die(ENVIRON["msg_conflicting_zone_definition"], 2, argv)
+ }
+
+ n = ++country_nzones[tlc]
+ country_cont[tlc,n] = cont
+ country_filename[tlc,n] = file
+ country_descr[tlc,n] = descr
+ }
+ else
+ {
+ if (country_nzones[tlc] > 0)
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ die(ENVIRON["msg_zone_must_have_description"], 2, argv)
+ }
+ if (country_nzones[tlc] < 0)
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ die(ENVIRON["msg_zone_multiply_defined"], 2, argv)
+ }
+
+ country_nzones[tlc] = -1
+ country_cont[tlc] = cont
+ country_filename[tlc] = file
+ }
+}
+function print_country_code(tlc)
+{
+ nz = country_nzones[tlc]
+
+ printf "country_%s_nzones=%d\n", tlc, nz
+ printf "export country_%s_nzones\n", tlc
+
+ if (nz < 0)
+ {
+ printf "country_%s_cont=\"%s\"\n", tlc, country_cont[tlc]
+ printf "export country_%s_cont\n", tlc
+ printf "country_%s_filename=\"%s\"\n",
+ tlc, country_filename[tlc]
+ }
+ else
+ {
+ n = 0
+ while ( ++n <= nz )
+ {
+ printf "country_%s_cont_%d=\"%s\"\n",
+ tlc, n, country_cont[tlc,n]
+ printf "export country_%s_cont_%d\n", tlc, n
+ printf "country_%s_filename_%d=\"%s\"\n",
+ tlc, n, country_filename[tlc,n]
+ printf "country_%s_descr_%d=\"%s\"\n",
+ tlc, n, country_descr[tlc,n]
+ }
+ }
+}
+/^#/ {
+ lineno++
+ next
+}
+!/^#/ {
+ lineno++
+
+ #
+ # Split the current record (on TAB) into an array
+ #
+ if (split($0, line, /\t/) < 2)
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ die(ENVIRON["msg_invalid_format"], 2, argv)
+ }
+
+ # Get the ISO3166-1 (Alpha 1) 2-letter country code
+ tlc = line[1]
+
+ #
+ # Validate the two-character country code
+ #
+ if (length(tlc) != 2)
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ argv[3] = tlc
+ die(ENVIRON["msg_invalid_country_code"], 3, argv)
+ }
+
+ # Get the TZ field
+ tz = line[3]
+
+ #
+ # Validate the TZ field
+ #
+ if (!match(tz, "/"))
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ argv[3] = tz
+ die(ENVIRON["msg_invalid_zone_name"], 3, argv)
+ }
+
+ #
+ # Get the continent portion of the TZ field
+ #
+ contbuf = tz
+ sub("/.*$", "", contbuf)
+
+ #
+ # Validate the continent
+ #
+ cont = find_continent(contbuf)
+ if (!cont)
+ {
+ argv[1] = FILENAME
+ argv[2] = lineno
+ argv[3] = contbuf
+ die(ENVIRON["msg_invalid_region"], 3, argv)
+ }
+
+ #
+ # Get the filename portion of the TZ field
+ #
+ filename = tz
+ sub("^[^/]*/", "", filename)
+
+ #
+ # Calculate the substr start-position of the comment
+ #
+ descr_start = 0
+ n = 4
+ while (--n)
+ descr_start += length(line[n]) + 1
+
+ # Get the comment field
+ descr = substr($0, descr_start + 1)
+
+ add_zone_to_country(lineno, tlc, descr, filename, cont)
+}
+END {
+ if (failed) exit failed
+ for (tlc in country_nzones)
+ print_country_code(tlc)
+}
+'
+f_read_zones()
+{
+ eval $( awk -v progname="$pgm" \
+ "$f_read_zones_awk" \
+ "$_PATH_ZONETAB" )
+}
+
+# f_install_zoneinfo_file $filename
+#
+# Installs a zone file to _PATH_LOCALTIME.
+#
+f_install_zoneinfo_file()
+{
+ local zoneinfo_file="$1"
+ local copymode title msg err size
+
+ if [ -L "$_PATH_LOCALTIME" ]; then
+ copymode=
+ elif [ ! -e "$_PATH_LOCALTIME" ]; then
+ # Nothing there yet...
+ copymode=1
+ else
+ copymode=1
+ fi
+
+ if [ "$VERBOSE" ]; then
+ if [ ! "$zoneinfo_file" ]; then
+ msg=$( printf "$msg_removing_file" "$_PATH_LOCALTIME" )
+ elif [ "$copymode" ]; then
+ msg=$( printf "$msg_copying_file" \
+ "$zoneinfo_file" "$_PATH_LOCALTIME" )
+ else
+ msg=$( printf "$msg_creating_symlink" \
+ "$_PATH_LOCALTIME" "$zoneinfo_file" )
+ fi
+ if [ "$USEDIALOG" ]; then
+ f_dialog_title "$msg_info"
+ title="$DIALOG_TITLE"
+ btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ size=$( f_dialog_buttonbox_size "$title" \
+ "$btitle" "$msg" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$msg\" $size
+ else
+ printf "%s\n" "$msg"
+ fi
+ fi
+
+ if [ "$REALLYDOIT" ]; then
+ f_dialog_title "$msg_error"
+ title="$DIALOG_TITLE"
+ btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+
+ if [ ! "$zoneinfo_file" ]; then
+
+ err=$( rm -f "$_PATH_LOCALTIME" 2>&1 )
+ if [ "$err" ]; then
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$err" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$err\" $size
+ else
+ f_err "%s\n" "$err"
+ fi
+ return $FAILURE
+ fi
+
+ err=$( rm -f "$_PATH_DB" 2>&1 )
+ if [ "$err" ]; then
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$err" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$err\" $size
+ else
+ f_err "%s\n" "$err"
+ fi
+ return $FAILURE
+ fi
+
+ if [ "$VERBOSE" ]; then
+ title="$msg_done"
+ msg=$( printf "$msg_removed_file" \
+ "$_PATH_LOCALTIME" )
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$msg" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$msg\" $size
+ else
+ printf "%s\n" "$msg"
+ fi
+ fi
+
+ return $SUCCESS
+
+ fi # ! zoneinfo_file
+
+ if [ "$copymode" ]; then
+
+ err=$( rm -f "$_PATH_LOCALTIME" 2>&1 )
+ if [ "$err" ]; then
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$err" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$err\" $size
+ else
+ f_err "%s\n" "$err"
+ fi
+ return $FAILURE
+ fi
+
+ err=$( umask 222 && : 2>&1 > "$_PATH_LOCALTIME" )
+ if [ "$err" ]; then
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$err" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$err\" $size
+ else
+ f_err "%s\n" "$err"
+ fi
+ return $FAILURE
+ fi
+
+ err=$( cat "$zoneinfo_file" 2>&1 > "$_PATH_LOCALTIME" )
+ if [ "$err" ]; then
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$err" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$err\" $size
+ else
+ f_err "%s\n" "$err"
+ fi
+ return $FAILURE
+ fi
+
+ else # ! copymode
+
+ err=$( ( :< "$zoneinfo_file" ) 2>&1 )
+ if [ "$err" ]; then
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$err" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$err\" $size
+ else
+ f_err "%s\n" "$err"
+ fi
+ return $FAILURE
+ fi
+
+ err=$( rm -f "$_PATH_LOCALTIME" 2>&1 )
+ if [ "$err" ]; then
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$err" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$err\" $size
+ else
+ f_err "%s\n" "$err"
+ fi
+ return $FAILURE
+ fi
+
+ err=$( ln -s "$zoneinfo_file" "$_PATH_LOCALTIME" 2>&1 )
+ if [ "$err" ]; then
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" \
+ "$btitle" \
+ "$err" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$err\" $size
+ else
+ f_err "%s\n" "$err"
+ fi
+ return $FAILURE
+ fi
+
+ fi # copymode
+
+ if [ "$VERBOSE" ]; then
+ title="$msg_done"
+ if [ "$copymode" ]; then
+ msg=$( printf "$msg_copied_timezone_file" \
+ "$zoneinfo_file" \
+ "$_PATH_LOCALTIME" )
+ else
+ msg=$( printf "$msg_created_symlink" \
+ "$_PATH_LOCALTIME" \
+ "$zoneinfo_file" )
+ fi
+ if [ "$USEDIALOG" ]; then
+ size=$( f_dialog_buttonbox_size \
+ "$title" "$btitle" "$msg" )
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$msg\" $size
+ else
+ printf "%s\n" "$msg"
+ fi
+ fi
+
+ fi # REALLYDOIT
+
+ return $SUCCESS
+}
+
+# f_install_zoneinfo $zoneinfo
+#
+# Install a zoneinfo file relative to _PATH_ZONEINFO. The given $zoneinfo
+# will be written to _PATH_DB (usable later with the `-r' flag).
+#
+f_install_zoneinfo()
+{
+ local zoneinfo="$1"
+ local rv
+
+ f_install_zoneinfo_file "$_PATH_ZONEINFO/$zoneinfo"
+ rv=$?
+
+ # Save knowledge for later
+ if [ "$REALLYDOIT" -a $rv -eq $SUCCESS ]; then
+ if : 2> /dev/null > "$_PATH_DB"; then
+ cat <<-EOF > "$_PATH_DB"
+ $zoneinfo
+ EOF
+ fi
+ fi
+
+ return $rv
+}
+
+# f_confirm_zone $filename
+#
+# Prompt the user to confirm the new timezone data. The first (and only)
+# argument should be the pathname to the zoneinfo file, either absolute or
+# relative to `/usr/share/zoneinfo' (e.g., "America/Los_Angeles").
+#
+# The return status is 0 if "Yes" is chosen, 1 if "No", and 255 if Esc is
+# pressed (see dialog(1) for additional details).
+#
+f_confirm_zone()
+{
+ local filename="$1"
+ f_dialog_title "$msg_confirmation"
+ local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ local tm_zone="$( TZ="$filename" date +%Z )"
+ local prompt="$( printf "$msg_look_reasonable" "$tm_zone" )"
+ local height=5 width=72
+
+ if [ "$USE_XDIALOG" ]; then
+ height=$(( $height + 4 ))
+ $DIALOG \
+ --title "$title" \
+ --backtitle "$btitle" \
+ --ok-label "$msg_yes" \
+ --cancel-label "$msg_no" \
+ --yesno "$prompt" $height $width
+ else
+ $DIALOG \
+ --title "$title" \
+ --backtitle "$btitle" \
+ --yes-label "$msg_yes" \
+ --no-label "$msg_no" \
+ --yesno "$prompt" $height $width
+ fi
+}
+
+# f_set_zone_utc
+#
+# Resets to the UTC timezone.
+#
+f_set_zone_utc()
+{
+ f_confirm_zone "" || return $FAILURE
+ f_install_zoneinfo_file ""
+}
+
+fi # ! $_TIMEZONE_ZONES_SUBR
diff --git a/usr.sbin/bsdconfig/timezone/timezone b/usr.sbin/bsdconfig/timezone/timezone
new file mode 100755
index 0000000..2b41d90
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/timezone
@@ -0,0 +1,448 @@
+#!/bin/sh
+#-
+# Copyright (c) 2011-2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+
+APP_DIR="090.timezone"
+f_include $BSDCFG_LIBE/$APP_DIR/include/continents.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/countries.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/iso3166.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/menus.subr
+f_include $BSDCFG_LIBE/$APP_DIR/include/zones.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# Standard pathnames
+#
+_PATH_DB="/var/db/zoneinfo"
+_PATH_WALL_CMOS_CLOCK="/etc/wall_cmos_clock"
+
+############################################################ GLOBALS
+
+#
+# Options
+#
+REALLYDOIT=1
+REINSTALL=
+USEDIALOG=1
+SKIPUTC=
+VERBOSE=
+TZ_OR_FAIL=
+CHROOTENV=
+
+#
+# Dummy vars (populated dynamically)
+#
+COUNTRIES= # list of 2-character country codes created by f_read_iso3166_table
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local title="$DIALOG_TITLE"
+ local btitle="$DIALOG_BACKTITLE"
+ local prompt="$msg_select_region"
+ local size
+
+ size=$( eval f_dialog_menu_size \
+ \"\$title\" \
+ \"\$btitle\" \
+ \"\$prompt\" \
+ \"\" \
+ $continent_menu_list )
+
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $continent_menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts C:ehnrsSvX flag; do
+ case "$flag" in
+ C) CHROOTENV="$OPTARG";;
+ e) TZ_OR_FAIL=1;;
+ n) REALLYDOIT=;;
+ r) REINSTALL=1
+ USEDIALOG=;;
+ s) SKIPUTC=1;;
+ v) VERBOSE=1;;
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_time_zone"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Process `-C chroot_directory' command-line argument
+#
+if [ "$CHROOTENV" ]; then
+ _PATH_ZONETAB="$CHROOTENV$_PATH_ZONETAB"
+ _PATH_ISO3166="$CHROOTENV$_PATH_ISO3166"
+ _PATH_ZONEINFO="$CHROOTENV$_PATH_ZONEINFO"
+ _PATH_LOCALTIME="$CHROOTENV$_PATH_LOCALTIME"
+ _PATH_DB="$CHROOTENV$_PATH_DB"
+ _PATH_WALL_CMOS_CLOCK="$CHROOTENV$_PATH_WALL_CMOS_CLOCK"
+fi
+
+#
+# Process `-r' command-line option
+#
+if [ "$REINSTALL" ]; then
+ [ -f "$_PATH_DB" -a -r "$_PATH_DB" ] ||
+ f_die 1 "$msg_cannot_open_for_reading" "$_PATH_DB"
+ zoneinfo=$( cat "$_PATH_DB" ) ||
+ f_die 1 "$msg_error_reading" "$_PATH_DB"
+ [ "$zoneinfo" ] ||
+ f_die 1 "$msg_unable_to_determine_name_from_db" "$_PATH_DB"
+ f_install_zoneinfo "$zoneinfo"
+ exit $?
+fi
+
+#
+# If the arguments on the command-line do not specify a file,
+# then interpret it as a zoneinfo name
+#
+if [ $# -ge 1 ]; then
+ zoneinfo="$1"
+
+ if [ ! -f "$zoneinfo" ]; then
+ USEDIALOG=
+ f_install_zoneinfo "$zoneinfo"
+ exit $?
+ fi
+
+ # FALLTHROUGH
+fi
+
+#
+# Process the UTC option
+#
+if [ "$_PATH_WALL_CMOS_CLOCK" -a ! "$SKIPUTC" ]; then
+ f_dialog_title "$msg_select_local_or_utc"
+ title="$DIALOG_TITLE"
+ btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ msg="$msg_is_machine_clock_utc"
+
+ if [ "$USE_XDIALOG" ]; then
+ defaultno="default-no"
+ height=10 width=77
+ else
+ defaultno="defaultno"
+ height=7 width=73
+ fi
+
+ if [ "$USE_XDIALOG" ]; then
+ $DIALOG \
+ --title "$title" \
+ --backtitle "$btitle" \
+ --$defaultno \
+ --ok-label "$msg_yes" \
+ --cancel-label "$msg_no" \
+ --yesno "$msg" $height $width
+ result=$?
+ else
+ $DIALOG \
+ --title "$title" \
+ --backtitle "$btitle" \
+ --$defaultno \
+ --yes-label "$msg_yes" \
+ --no-label "$msg_no" \
+ --yesno "$msg" $height $width
+ result=$?
+ fi
+
+ if [ $result -eq 0 ]; then
+ # User chose YES
+ [ "$REALLYDOIT" ] &&
+ f_quietly rm -f "$_PATH_WALL_CMOS_CLOCK"
+ else
+ # User chose NO, pressed ESC (or Ctrl-C), or closed box
+ [ "$REALLYDOIT" ] &&
+ ( umask 222 && :> "$_PATH_WALL_CMOS_CLOCK" )
+ fi
+fi
+
+#
+# Process optional default zone argument
+#
+if [ $# -ge 1 ]; then
+ default="$1"
+
+ f_dialog_title "$msg_default_zone_provided"
+ title="$DIALOG_TITLE"
+ btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ msg=$( printf "\n$msg_use_default_zone" "$default" )
+ size=$( f_dialog_buttonbox_size "$title" "$btitle" "$msg" )
+
+ if [ "$USE_XDIALOG" ]; then
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_yes\" \
+ --cancel-label \"\$msg_no\" \
+ --yesno \"\$msg\" $size
+ result=$?
+ else
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --yes-label \"\$msg_yes\" \
+ --no-label \"\$msg_no\" \
+ --yesno \"\$msg\" $size
+ result=$?
+ fi
+
+ if [ $result -eq 0 ]; then
+ # User chose YES
+ f_install_zoneinfo_file "$default"
+ result=$?
+ [ ! "$USE_XDIALOG" ] && f_dialog_clear
+ exit $result
+ fi
+
+ [ ! "$USE_XDIALOG" ] && f_dialog_clear
+fi
+
+#
+# Override the user-supplied umask
+#
+umask 022
+
+#
+# Read databases and perform initialization
+#
+f_read_iso3166_table # creates $COUNTRIES and $country_*_name
+f_read_zones # creates $country_*_{descr,cont,filename}
+f_sort_countries # sorts the countries listed for each continent
+f_make_menus # creates $continent_menu_list and $continent_*_menu_list
+
+#
+# Launch application main menu
+#
+NEED_CONTINENT=1
+NEED_COUNTRY=1
+while :; do
+ if [ "$NEED_CONTINENT" ]; then
+ dialog_menu_main # prompt the user to select a continent/ocean
+ retval=$?
+ mtag=$( f_dialog_menutag )
+
+ if [ $retval -ne 0 ]; then
+ [ "$TZ_OR_FAIL" ] && f_die
+ exit $SUCCESS
+ fi
+
+ NEED_CONTINENT=
+
+ continent=$( eval f_dialog_menutag2item \"\$mtag\" \
+ $continent_menu_list )
+ cont=$( f_find_continent "$continent" )
+ cont_title=$( f_continent $cont title )
+ nitems=$( f_continent $cont nitems )
+ isocean=$( f_OCEANP $cont )
+ fi
+
+ if [ "$NEED_COUNTRY" ]; then
+ if [ "$cont_title" = "$continent_utc_title" ]; then
+ if f_set_zone_utc; then
+ break
+ else
+ NEED_CONTINENT=1
+ continue
+ fi
+ fi
+
+ #
+ # Short cut -- if there's only one country, don't post a menu.
+ #
+ if [ $nitems -eq 1 ]; then
+ tag=1
+ else
+ #
+ # It's amazing how much good grammar really matters...
+ #
+ if [ ! "$isocean" ]; then
+ title=$( printf "$msg_country_title" \
+ "$cont_title" )
+ f_dialog_title "$title"
+ title="$DIALOG_TITLE"
+ btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ prompt="$msg_select_country"
+ else
+ title=$( printf "$msg_island_and_group_title" \
+ "$cont_title" )
+ f_dialog_title "$title"
+ title="$DIALOG_TITLE"
+ btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ prompt="$msg_select_island_or_group"
+ fi
+
+ #
+ # Calculate size of menu
+ #
+ menu_list=$( f_continent $cont menu_list )
+ size=$( eval f_dialog_menu_size \
+ \"\$title\" \
+ \"\$btitle\" \
+ \"\$prompt\" \
+ \"\" \
+ $menu_list )
+
+ #
+ # Launch the country selection menu
+ #
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+ retval=$?
+ tag=$( f_dialog_menutag )
+
+ if [ $retval -ne 0 ]; then
+ NEED_CONTINENT=1
+ continue # back to main menu
+ fi
+ fi
+
+ # Get the country code from the user's selection
+ tlc=$( f_continent $cont tlc_$tag )
+
+ NEED_COUNTRY=
+ fi
+
+ #
+ # If the selection has only one zone (nzones == -1),
+ # just set it.
+ #
+ nzones=$( f_country $tlc nzones )
+ if [ $nzones -lt 0 ]; then
+ real_cont=$( f_country $tlc cont )
+ real_continent=$( f_continent $real_cont name )
+ name=$( f_country $tlc name )
+ filename=$( f_country $tlc filename )
+
+ if ! f_confirm_zone "$real_continent/$filename"; then
+ [ $nitems -eq 1 ] && NEED_CONTINENT=1
+ NEED_COUNTRY=1
+ continue
+ fi
+ else
+ title=$( printf "$msg_country_time_zones" \
+ "$( f_country $tlc name )" )
+ f_dialog_title "$title"
+ title="$DIALOG_TITLE"
+ btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ prompt="$msg_select_zone"
+ menu_list=$( f_country $tlc menu_list )
+ size=$( eval f_dialog_menu_size \"\$title\" \"\$btitle\" \
+ \"\$prompt\" \"\" $menu_list )
+
+ #
+ # Launch the zone selection menu
+ # NOTE: This is as deep as we go
+ #
+ eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+ retval=$?
+ n=$( f_dialog_menutag )
+
+ if [ $retval -ne 0 ]; then
+ [ $nitems -eq 1 ] && NEED_CONTINENT=1
+ NEED_COUNTRY=1
+ continue
+ fi
+
+ real_cont=$( f_country $tlc cont_$n )
+ real_continent=$( f_continent $real_cont name )
+ name=$( f_country $tlc name )
+ filename=$( f_country $tlc filename_$n )
+
+ f_confirm_zone "$real_continent/$filename" || continue
+ fi
+
+ [ $retval -eq 0 ] || continue # back to main menu
+
+ if ! f_install_zoneinfo "$real_continent/$filename"; then
+ [ $nzones -lt 0 ] && NEED_COUNTRY=1
+ else
+ break
+ fi
+done
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/ttys/INDEX b/usr.sbin/bsdconfig/ttys/INDEX
new file mode 100644
index 0000000..4ecc68e
--- /dev/null
+++ b/usr.sbin/bsdconfig/ttys/INDEX
@@ -0,0 +1,53 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Ttys"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Configure Ttys"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="ttys|ttys"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="ttys"
diff --git a/usr.sbin/bsdconfig/ttys/Makefile b/usr.sbin/bsdconfig/ttys/Makefile
new file mode 100644
index 0000000..b77bc24
--- /dev/null
+++ b/usr.sbin/bsdconfig/ttys/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/150.ttys
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= ttys
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/ttys/USAGE b/usr.sbin/bsdconfig/ttys/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/ttys/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/ttys/include/Makefile b/usr.sbin/bsdconfig/ttys/include/Makefile
new file mode 100644
index 0000000..9333abe
--- /dev/null
+++ b/usr.sbin/bsdconfig/ttys/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/150.ttys/include
+FILES= messages.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/ttys/include/messages.subr b/usr.sbin/bsdconfig/ttys/include/messages.subr
new file mode 100644
index 0000000..296f756
--- /dev/null
+++ b/usr.sbin/bsdconfig/ttys/include/messages.subr
@@ -0,0 +1,31 @@
+# Copyright (c) 2012 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$
+
+msg_configure_ttys="Configure TTYs"
+msg_help_text="Configuration of system TTYs requires editing the /etc/ttys file.\nTypical configuration activities might include enabling getty(8)\non the first serial port to allow login via serial console after\nreboot, or to enable xdm. The default ttys file enables normal\nvirtual consoles, and most sites will not need to perform manual\nconfiguration.\n\nTo load /etc/ttys in the editor, select [Yes], otherwise, [No]."
+msg_no_such_file_or_directory="%s: %s: No such file or directory"
+msg_permission_denied="%s: %s: permission denied"
+msg_user_confirmation_requested="User Confirmation Requested"
diff --git a/usr.sbin/bsdconfig/ttys/ttys b/usr.sbin/bsdconfig/ttys/ttys
new file mode 100755
index 0000000..83715ca
--- /dev/null
+++ b/usr.sbin/bsdconfig/ttys/ttys
@@ -0,0 +1,128 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 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 (INLUDING, 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="150.ttys"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+#
+# Default text-editor to use
+#
+: ${EDITOR:=ee}
+
+
+#
+# If X11 is requested, which terminal and what options should we use?
+#
+X11TERM=xterm
+X11TERM_OPTS=
+
+#
+# Location of ttys(5)
+#
+ETC_TTYS=/etc/ttys
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_configure_ttys"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+f_dialog_title "$msg_user_confirmation_requested"
+f_dialog_yesno "$msg_help_text" || exit $SUCCESS
+f_dialog_title_restore
+
+#
+# Make sure $EDITOR exists and is executable
+#
+case "$EDITOR" in
+*/*)
+ [ -e "$EDITOR" ] ||
+ f_die 1 "$msg_no_such_file_or_directory" "$pgm" "$EDITOR"
+ [ -x "$EDITOR" ] ||
+ f_die 1 "$msg_permission_denied" "$pgm" "$EDITOR"
+ ;;
+*)
+ f_have "$EDITOR" ||
+ f_die 1 "$msg_no_such_file_or_directory" "$pgm" "$EDITOR"
+esac
+
+#
+# If Xdialog(1) is requested, we'll need to wrap bsdinstall(8) into xterm(1)
+#
+if [ "$USE_XDIALOG" ]; then
+ #
+ # Make sure $X11TERM exists and is executable
+ #
+ case "$X11TERM" in
+ */*)
+ [ -e "$X11TERM" ] || f_die 1 \
+ "$msg_no_such_file_or_directory" "$pgm" "$X11TERM"
+ [ -x "$X11TERM" ] || f_die 1 \
+ "$msg_permission_denied" "$pgm" "$X11TERM"
+ ;;
+ *)
+ f_have "$X11TERM" || f_die 1 \
+ "$msg_no_such_file_or_directory" "$pgm" "$X11TERM"
+ esac
+
+ exec $X11TERM $X11TERM_OPTS -e $EDITOR $ETC_TTYS
+else
+ exec $EDITOR $ETC_TTYS
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/INDEX b/usr.sbin/bsdconfig/usermgmt/INDEX
new file mode 100644
index 0000000..81e43aa
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/INDEX
@@ -0,0 +1,60 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Login/Group Management"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Manage system user and/or group information"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="usermgmt|usermgmt"
+menu_selection="useradd|useradd"
+menu_selection="useredit|useredit"
+menu_selection="userdel|userdel"
+menu_selection="groupmgmt|usermgmt"
+menu_selection="groupadd|groupadd"
+menu_selection="groupedit|groupedit"
+menu_selection="groupdel|groupdel"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="usermgmt"
diff --git a/usr.sbin/bsdconfig/usermgmt/Makefile b/usr.sbin/bsdconfig/usermgmt/Makefile
new file mode 100644
index 0000000..7c1b3e5
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/070.usermgmt
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= groupadd groupdel groupedit groupinput \
+ useradd userdel useredit userinput usermgmt
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/usermgmt/USAGE b/usr.sbin/bsdconfig/usermgmt/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/usermgmt/groupadd b/usr.sbin/bsdconfig/usermgmt/groupadd
new file mode 100755
index 0000000..c4f4fde
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/groupadd
@@ -0,0 +1,64 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+APP_DIR="070.usermgmt"
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Chain-load to groupinput to centralize code and minimize duplication
+#
+f_dialog_init
+$BSDCFG_LIBE/$APP_DIR/groupinput ${USE_XDIALOG:+-X} mode="Add"
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/groupdel b/usr.sbin/bsdconfig/usermgmt/groupdel
new file mode 100755
index 0000000..aa5a71d
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/groupdel
@@ -0,0 +1,93 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/group_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_delete $msg_group"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Loop until the user Exits, Cancels or presses ESC
+#
+while :; do
+ f_dialog_menu_group_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+
+ *) # anything else is a group name
+ $BSDCFG_LIBE/$APP_DIR/groupinput \
+ ${USE_XDIALOG:+-X} mode="Delete" group="$mtag"
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/groupedit b/usr.sbin/bsdconfig/usermgmt/groupedit
new file mode 100755
index 0000000..beb11af
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/groupedit
@@ -0,0 +1,93 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/group_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_edit_view $msg_group"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Loop until the user Exits, Cancels or presses ESC
+#
+while :; do
+ f_dialog_menu_group_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+
+ *) # anything else is a group name
+ $BSDCFG_LIBE/$APP_DIR/groupinput \
+ ${USE_XDIALOG:+-X} mode="Edit/View" group="$mtag"
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/groupinput b/usr.sbin/bsdconfig/usermgmt/groupinput
new file mode 100755
index 0000000..96186be
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/groupinput
@@ -0,0 +1,295 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/group_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+# set some reasonable defaults if /etc/adduser.conf does not exist.
+[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf
+: ${passwdtype:="yes"}
+
+############################################################ FUNCTIONS
+
+# save_changes
+#
+# Save any/all settings (actions performed depend on $mode value).
+#
+save_changes()
+{
+ local err retval=$SUCCESS
+
+ case "$mode" in
+ Delete)
+ err=$( pw groupdel "$group_name" 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_group_deleted"
+ ;;
+ Add)
+ local cmd="pw groupadd -n '$group_name'"
+ [ "$group_gid" ] && cmd="$cmd -g '$group_gid'"
+ [ "$group_members" != "$cur_group_members" ] &&
+ cmd="$cmd -M '$group_members'"
+ if [ "$pw_group_password_disable" ]; then
+ cmd="$cmd -h -"
+ elif [ "$group_password" ]; then
+ cmd="echo \"\$group_password\" | $cmd -h 0"
+ fi
+ f_dprintf "cmd=$cmd"
+ err=$( eval $cmd 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_group_added"
+ ;;
+ Edit/View)
+ local cmd="pw groupmod -n '$group_name'"
+ [ "$group_gid" ] && cmd="$cmd -g '$group_gid'"
+ [ "$group_members" != "$cur_group_members" ] &&
+ cmd="$cmd -M '$group_members'"
+ if [ "$pw_group_password_disable" ]; then
+ cmd="$cmd -h -"
+ elif [ "$group_password" ]; then
+ cmd="echo \"\$group_password\" | $cmd -h 0"
+ fi
+ f_dprintf "cmd=$cmd"
+ err=$( eval $cmd 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_group_updated"
+ ;;
+ esac
+
+ save_flag=
+ return $SUCCESS
+}
+
+# dialog_title_update $mode
+#
+# Set the title based on the given $mode.
+#
+dialog_title_update()
+{
+ local mode="$1"
+ case "$mode" in
+ Add) f_dialog_title "$msg_add $msg_group" ;;
+ Edit/View) f_dialog_title "$msg_edit_view $msg_group: $group" ;;
+ Delete) f_dialog_title "$msg_delete $msg_group: $group" ;;
+ esac
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while [ $# -gt 0 ]; do
+ key="${1%%=*}"
+ value="${1#*=}"
+ f_dprintf "key=[$key] value=[$value]"
+ case "$key" in
+ mode) mode="$value";;
+ group) group="$value";;
+ esac
+ shift
+done
+f_dprintf "mode=[$mode] group=[$group]"
+
+#
+# Initialize
+#
+f_dialog_init
+dialog_title_update "$mode"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+menu_text=
+save_flag=
+hline="$hline_arrows_tab_enter"
+
+if [ "$mode" = "Add" ]; then
+ #
+ # Ask a series of questions to pre-fill the editor screen.
+ #
+ # The defaults used in each dialog should allow the user to simply
+ # hit ENTER to proceed, because cancelling a single dialog will
+ # cause them to be returned to the main groupmenu.
+ #
+
+ f_dialog_input_group_name || exit 0
+ [ "$passwdtype" = "yes" ] &&
+ { f_dialog_input_group_password || exit 0; }
+ f_dialog_input_group_gid || exit 0
+ f_dialog_input_group_members || exit 0
+fi
+
+if [ "$mode" = "Edit/View" -o "$mode" = "Delete" ]; then
+ f_input_group "$group" || f_die 1 "$msg_group_not_found"
+fi
+
+cur_group_name="$group_name"
+cur_group_password="$group_password"
+cur_group_gid="$group_gid"
+cur_group_members="$group_members"
+
+[ "$mode" = "Delete" ] && save_flag=1
+
+#
+# Loop until the user decides to Exit, Cancel, or presses ESC
+#
+while :; do
+ dialog_title_update "$mode"
+
+ menu_text=
+ menu_exit="$msg_exit"
+ if [ "$save_flag" ]; then
+ if [ "$mode" = "Delete" ]; then
+ menu_exit="$msg_delete/$msg_exit"
+ menu_text="$msg_delete_exit_or_cancel"
+ else
+ menu_exit="$msg_save/$msg_exit"
+ menu_text="$msg_save_exit_or_cancel"
+ fi
+ fi
+
+ case "$mode" in
+ Delete)
+ menu_items="
+ 'X' '$menu_exit'
+ '1' '$msg_group: $group_name'
+ '-' '$msg_password: -----'
+ '-' '$msg_group_id: $group_gid'
+ '-' '$msg_group_members: $group_members'
+ " # END-QUOTE
+ ;;
+ *)
+ menu_items="
+ 'X' '$menu_exit'
+ '1' '$msg_group: $group_name'
+ '2' '$msg_password: -----'
+ '3' '$msg_group_id: $group_gid'
+ '4' '$msg_group_members: $group_members'
+ " # END-QUOTE
+ esac
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$menu_text\" \
+ \"\$hline\" \
+ $menu_items )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$menu_text\" $size \
+ $menu_items \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ # Exit if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || f_die
+
+ case "$mtag" in
+ X) # Exit
+ if [ "$save_flag" ]; then
+ save_changes || continue
+ fi
+ break
+ ;;
+ 1) # Group Name
+ case "$mode" in
+ Add) f_dialog_input_group_name "$group_name" ;;
+ Edit/View|Delete)
+ f_dialog_menu_group_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ # Loop if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ [ "$mtag" = "X $msg_exit" ] && continue
+
+ group="$mtag"
+ f_input_group "$group" || f_die 1 "$msg_group_not_found"
+ cur_group_name="$group_name"
+ cur_group_password="$group_password"
+ cur_group_gid="$group_gid"
+ cur_group_members="$group_members"
+ [ "$mode" != "Delete" ] && save_flag=
+ esac
+ ;;
+ 2) # Password
+ f_dialog_input_group_password
+ ;;
+ 3) # GID
+ f_dialog_input_group_gid "$group_gid"
+ ;;
+ 4) # Users in Group
+ f_dialog_input_group_members "$group_members"
+ ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/include/Makefile b/usr.sbin/bsdconfig/usermgmt/include/Makefile
new file mode 100644
index 0000000..15f88aa
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/070.usermgmt/include
+FILES= group_input.subr messages.subr user_input.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/usermgmt/include/group_input.subr b/usr.sbin/bsdconfig/usermgmt/include/group_input.subr
new file mode 100644
index 0000000..b4121b1
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/group_input.subr
@@ -0,0 +1,437 @@
+if [ ! "$_USERMGMT_GROUP_INPUT_SUBR" ]; then _USERMGMT_GROUP_INPUT_SUBR=1
+#
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_input_group $group
+#
+# Given $group name or id, create the environment variables group_name,
+# group_gid, and group_members (and group_password is reset to NULL).
+#
+f_input_group()
+{
+ eval $( pw groupshow "$1" | awk -F: '
+ {
+ printf "group_name='\'%s\''\n", $1
+ printf "group_password=\n"
+ printf "group_gid='\'%s\''\n", $3
+ printf "group_members='\'%s\''\n", $4
+ exit
+ }' )
+}
+
+# f_dialog_menu_group_list
+#
+# Allows the user to select a group from a list.
+#
+f_dialog_menu_group_list()
+{
+ local menu_list size
+ local hline="$hline_alnum_punc_tab_enter"
+
+ menu_list="
+ 'X $msg_exit' ''
+ " # END-QUOTE
+
+ # Add groups from group(5)
+ menu_list="$menu_list $( pw groupshow -a | awk -F: '
+ !/^[[:space:]]*(#|$)/ {
+ printf "'\'%s\'\ \'%s\''\n", $1, $1
+ }'
+ )"
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\" $size $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# f_dialog_input_group_name [$group_name]
+#
+# Allows the user to enter a new groupname for a given group. If the user does
+# not cancel or press ESC, the $group_name variable will hold the
+# newly-configured value upon return.
+#
+# If $cur_group_name is defined, the user can enter that and by-pass error-
+# checking (allowing the user to "revert" to an old value without, for example,
+# being told that the groupname already exists).
+#
+f_dialog_input_group_name()
+{
+ local msg="$( printf "$msg_group" )"
+ local hline="$hline_alnum_tab_enter"
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local size retval _name="$1" _input="$1"
+ while :; do
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for no-change
+ [ "$_input" = "$_name" ] && return $SUCCESS
+
+ # Check for reversion
+ if [ "$_input" = "$cur_group_name" ]; then
+ group_name="$cur_group_name"
+ return $SUCCESS
+ fi
+
+ # Check for NULL entry
+ if [ ! "$_input" ]; then
+ f_show_msg "$msg_group_is_empty"
+ continue
+ fi
+
+ # Check for invalid entry
+ if ! echo "$_input" | grep -q "^[[:alpha:]]"; then
+ f_show_msg "$msg_group_must_start_with_letter"
+ continue
+ fi
+
+ # Check for duplicate entry
+ if f_quietly pw groupshow -n "$_input"; then
+ f_show_msg "$msg_group_already_used" "$_input"
+ continue
+ fi
+
+ group_name="$_input"
+ break
+ done
+ save_flag=1
+
+ f_dprintf "group_name: [$cur_group_name]->[$group_name]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_group_password
+#
+# Prompt the user to enter a password (twice).
+#
+f_dialog_input_group_password()
+{
+ local hline="$hline_alnum_punc_tab_enter"
+ local msg size rmsg rsize
+
+ msg=$( printf "$msg_group_password" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "" \
+ "$hline" )
+
+ rmsg=$( printf "$msg_reenter_group_password" )
+ rsize=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$rmsg" \
+ "" \
+ "$hline" )
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local retval _password1 _password2
+ while :; do
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$msg\" $size \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password1=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$rmsg\" $rsize \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password2=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for password mismatch
+ if [ "$_password1" != "$_password2" ]; then
+ f_show_msg "$msg_group_passwords_do_not_match"
+ continue
+ fi
+
+ # Check for NULL entry
+ if [ ! "$_password1" ]; then
+ f_dialog_yesno \
+ "$msg_disable_password_auth_for_group" ||
+ continue
+ pw_group_password_disable=1
+ else
+ pw_group_password_disable=
+ fi
+
+ group_password="$_password1"
+ break
+ done
+ save_flag=1
+
+ f_dprintf "group_password: [$cur_group_password]->[$group_password]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_group_gid [$group_gid]
+#
+# Allow the user to enter a new GID for a given group. If the user does not
+# cancel or press ESC, the $group_gid variable will hold the newly-configured
+# value upon return.
+#
+f_dialog_input_group_gid()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_num_tab_enter"
+
+ msg=$( printf "$msg_group_id_leave_empty_for_default" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ group_gid="$_input"
+ save_flag=1
+
+ f_dprintf "group_gid: [$cur_group_gid]->[$group_gid]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_group_members [$group_members]
+#
+# Allow the user to modify a list of members for a given group. If the user does
+# not cancel or press ESC, the $group_members variable will hold the newly-
+# configured value upon return.
+#
+f_dialog_input_group_members()
+{
+ local menu_choice msg size retval _input="$1"
+ local hline="$hline_num_arrows_tab_enter"
+ local user
+ local menu_list
+ local all_users_valid
+ local _group_members
+ local checklist_users
+
+ menu_list="
+ 'X' '$msg_continue'
+ '1' '$msg_select_group_members_from_list'
+ '2' '$msg_enter_group_members_manually'
+ " # END-QUOTE
+
+ while :; do
+ msg="$msg_group_members:"
+ menu_size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$msg\" \
+ \"\$hline\" \
+ $menu_list )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$msg\" $menu_size \
+ $menu_list \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+ retval=$?
+ menu_choice=$( f_dialog_menutag )
+ f_dprintf "retval=$retval menu_choice=[$menu_choice]"
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ case "$menu_choice" in
+ X) # Exit
+ break ;;
+ 1) # Select Group Members from a list
+ user_list=$( pw usershow -a | awk -F: '
+ !/^[[:space:]]*(#|$)/ { printf "%s\n", $1 }' )
+ checklist_users=
+ for user in $user_list; do
+ checklist_users="$checklist_users $user \"\""
+ if echo "$_input" | grep -q "\<$user\>"; then
+ checklist_users="$checklist_users on"
+ else
+ checklist_users="$checklist_users off"
+ fi
+ done
+
+ size=$( eval f_dialog_radiolist_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $checklist_users )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --separate-output \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --checklist \"\$msg\" $size \
+ $checklist_users \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ _group_members=$( f_dialog_inputstr | tr '\n' ' ' |
+ sed -e 's/[[:space:]]\{1,\}/,/g;s/^,//;s/,$//' )
+
+ # Return to previous menu if user has either
+ # pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input="$_group_members"
+ ;;
+ 2) # Enter Group Members manually
+ hline="$hline_num_tab_enter"
+ msg=$(
+ printf "$msg_group_members ($msg_separated_by_commas)"
+ )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _group_members=$( f_dialog_inputstr )
+
+ # Return to previous menu if user has either
+ # pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input="$_group_members"
+ ;;
+ esac
+ done
+
+ group_members="$_input"
+ save_flag=1
+ f_dprintf "group_members: [$cur_group_members]->[$group_members]"
+
+ return $SUCCESS
+}
+
+fi # ! $_USERMGMT_GROUP_INPUT_SUBR
diff --git a/usr.sbin/bsdconfig/usermgmt/include/messages.subr b/usr.sbin/bsdconfig/usermgmt/include/messages.subr
new file mode 100644
index 0000000..e2e7bf3
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/messages.subr
@@ -0,0 +1,111 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+hline_alnum_punc_tab_enter="Use alpha-numeric, punctuation, TAB or ENTER"
+hline_alnum_tab_enter="Use alpha-numeric, TAB or ENTER"
+hline_arrows_space_tab_enter="Use arrows, SPACE, TAB or ENTER"
+hline_arrows_tab_enter="Press arrows, TAB or ENTER"
+hline_num_arrows_tab_enter="Use numbers, arrows, TAB or ENTER"
+hline_num_tab_enter="Use numbers, TAB or ENTER"
+msg_account_expires_in_how_many_days="Account expires in how many days?"
+msg_account_expires_on="Account Expires on"
+msg_account_does_not_expire="Account does not expire"
+msg_add="Add"
+msg_add_group="Add Group"
+msg_add_login="Add Login"
+msg_cancel="Cancel"
+msg_continue="Continue"
+msg_create_dotfiles="Create Dotfiles"
+msg_create_home_directory="Create Home Directory"
+msg_delete="Delete"
+msg_delete_exit_or_cancel="Choose Delete/Exit when finished or Cancel."
+msg_delete_group="Delete Group"
+msg_delete_home_directory="Delete Home Directory"
+msg_delete_login="Delete Login"
+msg_delete_primary_group="Delete Primary Group"
+msg_deleting_home_directory="Deleting home directory..."
+msg_disable_password_auth_for_account="Disable password authentication for this account?"
+msg_disable_password_auth_for_group="Disable password authentication for this group?"
+msg_edit_date_time_with_a_calendar="Edit date/time with a calendar"
+msg_edit_group="Edit/View Group"
+msg_edit_login="Edit/View Login"
+msg_edit_view="Edit/View"
+msg_enter_group_members_manually="Enter Group Members manually"
+msg_enter_number_of_days_into_the_future="Enter number of days into the future"
+msg_enter_value_manually="Edit value manually"
+msg_error="ERROR!"
+msg_exit="Exit"
+msg_full_name="Full Name"
+msg_group="Group"
+msg_group_added="Group Added"
+msg_group_already_used="%s: Group is already used."
+msg_group_deleted="Group Deleted"
+msg_group_is_empty="Group is empty."
+msg_group_id="Group ID"
+msg_group_id_leave_empty_for_default="Group ID (Leave empty for default)"
+msg_group_members="Group Members"
+msg_group_must_start_with_letter="Group must start with a letter."
+msg_group_not_found="%s: Group not found."
+msg_group_password="Group Password"
+msg_group_passwords_do_not_match="Group Passwords do not match."
+msg_group_updated="Group Updated"
+msg_home_directory="Home Directory"
+msg_invalid_number_of_days="Invalid number of days."
+msg_invalid_number_of_seconds="Invalid number of seconds."
+msg_login="Login"
+msg_login_added="Login Added"
+msg_login_already_used="%s: Login is already used."
+msg_login_class="Login Class"
+msg_login_deleted="Login Deleted"
+msg_login_is_empty="Login is empty."
+msg_login_management="Login/Group Management"
+msg_login_must_start_with_letter="Login must start with a letter."
+msg_login_not_found="Login not found."
+msg_login_updated="Login Updated"
+msg_member_of_groups="Member of Groups"
+msg_n_a="N/A"
+msg_number_of_seconds_since_epoch="Number of seconds since the Epoch\n(1 = %s)\nNULL or zero to disable:"
+msg_no="No"
+msg_ok="OK"
+msg_password="Password"
+msg_password_expires_in_how_many_days="Password expires in how many days?"
+msg_password_expires_on="Password Expires on"
+msg_passwords_do_not_match="Passwords do not match."
+msg_password_does_not_expire="Password does not expire"
+msg_reenter_group_password="Re-enter Group Password"
+msg_reenter_password="Re-enter Password"
+msg_save="Save"
+msg_save_exit_or_cancel="Choose Save/Exit when finished or Cancel."
+msg_separated_by_commas="Separated by commas"
+msg_select_group_members_from_list="Select Group Members from a list"
+msg_select_login_shell="Select Login Shell"
+msg_shell="Shell"
+msg_user="User"
+msg_user_id="UID"
+msg_user_id_leave_empty_for_default="UID (Leave empty for default)"
+msg_warning="WARNING!"
+msg_yes="Yes"
diff --git a/usr.sbin/bsdconfig/usermgmt/include/user_input.subr b/usr.sbin/bsdconfig/usermgmt/include/user_input.subr
new file mode 100644
index 0000000..a522f9d
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/user_input.subr
@@ -0,0 +1,1180 @@
+if [ ! "$_USERMGMT_USER_INPUT_SUBR" ]; then _USERMGMT_USER_INPUT_SUBR=1
+#
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Default location of shells(5)
+#
+: ${ETC_SHELLS:=/etc/shells}
+
+############################################################ FUNCTIONS
+
+# f_get_member_groups $user
+#
+# Get a list of additional groups $user is a member of in group(5).
+#
+f_get_member_groups()
+{
+ echo $( pw groupshow -a | awk -F: "/[:,]$1(,|\$)/{print \$1}" )
+}
+
+# f_input_user $user
+#
+# Given $user name or id, create the environment variables pw_name, pw_uid,
+# pw_gid, pw_class, pw_password_expire, pw_account_expire, pw_gecos,
+# pw_home_dir, pw_shell, and pw_member_groups (and pw_password is reset to
+# NULL).
+#
+f_input_user()
+{
+ local user="$1"
+ eval $( pw usershow "$user" | awk -F: '
+ {
+ printf "pw_name='\'%s\''\n", $1
+ printf "pw_password=\n"
+ printf "pw_uid='\'%s\''\n", $3
+ printf "pw_gid='\'%s\''\n", $4
+ printf "pw_class='\'%s\''\n", $5
+ printf "pw_password_expire='\'%s\''\n", $6
+ printf "pw_account_expire='\'%s\''\n", $7
+ printf "pw_gecos='\'%s\''\n", $8
+ printf "pw_home_dir='\'%s\''\n", $9
+ printf "pw_shell='\'%s\''\n", $10
+ }' )
+ pw_member_groups=$( f_get_member_groups "$user" )
+}
+
+# f_dialog_menu_user_list
+#
+# Allows the user to select a login from a list.
+#
+f_dialog_menu_user_list()
+{
+ local menu_list size
+ local hline="$hline_alnum_punc_tab_enter"
+
+ menu_list="
+ 'X $msg_exit' ''
+ " # END-QUOTE
+
+ # Add users from passwd(5)
+ menu_list="$menu_list $( pw usershow -a | awk -F: '
+ !/^[[:space:]]*(#|$)/ {
+ printf "'\'%s\'\ \'%s\''\n", $1, $8
+ }'
+ )"
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\" $size $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# f_dialog_input_member_groups [$member_groups]
+#
+# Allows the user to edit group memberships for a given user. If the user does
+# not cancel or press ESC, the $pw_member_groups variable will hold the newly-
+# configured value upon return.
+#
+f_dialog_input_member_groups()
+{
+ local msg="$( printf "$msg_member_of_groups" )"
+ local hline="$hline_alnum_tab_enter"
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local size retval all_groups checklist_groups="" _member_groups="$1"
+ all_groups=$( pw groupshow -a | awk -F: '
+ !/^[[:space:]]*(#|$)/ {
+ printf "%s\n", $1
+ }'
+ )
+ for grp in $all_groups; do
+ checklist_groups="$checklist_groups $grp $grp"
+ if echo "$_member_groups" | grep -q "\<$grp\>"; then
+ checklist_groups="$checklist_groups on"
+ else
+ checklist_groups="$checklist_groups off"
+ fi
+ done
+
+ while :; do
+ size=$( eval f_dialog_radiolist_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $checklist_groups )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --separate-output \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --checklist \"\$msg\" $size \
+ $checklist_groups \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _member_groups=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ #
+ # Validate each of the groups the user has entered
+ #
+ local group all_groups_valid=1
+ for group in $_member_groups; do
+ if ! f_quietly pw groupshow -n "$group"; then
+ f_show_msg "$msg_group_not_found" "$group"
+ all_groups_valid=
+ break
+ fi
+ done
+ [ "$all_groups_valid" ] || continue
+
+ pw_member_groups="$_member_groups"
+ break
+ done
+ save_flag=1
+
+ local debug="pw_member_groups:"
+ f_dprintf "$debug [$cur_pw_member_groups]->[$pw_member_groups]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_name [$name]
+#
+# Allows the user to enter a new username for a given user. If the user does
+# not cancel or press ESC, the $pw_name variable will hold the newly-configured
+# value upon return.
+#
+# If $cur_pw_name is defined, the user can enter that and by-pass error-
+# checking (allowing the user to "revert" to an old value without, for example,
+# being told that the username already exists).
+#
+f_dialog_input_name()
+{
+ local msg="$( printf "$msg_login" )"
+ local hline="$hline_alnum_tab_enter"
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local size retval _name="$1" _input="$1"
+ while :; do
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for no-change
+ [ "$_input" = "$_name" ] && return $SUCCESS
+
+ # Check for reversion
+ if [ "$_input" = "$cur_pw_name" ]; then
+ pw_name="$cur_pw_name"
+ return $SUCCESS
+ fi
+
+ # Check for NULL entry
+ if [ ! "$_input" ]; then
+ f_show_msg "$msg_login_is_empty"
+ continue
+ fi
+
+ # Check for invalid entry
+ if ! echo "$_input" | grep -q "^[[:alpha:]]"; then
+ f_show_msg "$msg_login_must_start_with_letter"
+ continue
+ fi
+
+ # Check for duplicate entry
+ if f_quietly pw usershow -n "$_input"; then
+ f_show_msg "$msg_login_already_used" "$_input"
+ continue
+ fi
+
+ pw_name="$_input"
+ break
+ done
+ save_flag=1
+
+ f_dprintf "pw_name: [$cur_pw_name]->[$pw_name]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_password
+#
+# Prompt the user to enter a password (twice).
+#
+f_dialog_input_password()
+{
+ local hline="$hline_alnum_punc_tab_enter"
+ local msg size rmsg rsize
+
+ msg=$( printf "$msg_password" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "" \
+ "$hline" )
+
+ rmsg=$( printf "$msg_reenter_password" )
+ rsize=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$rmsg" \
+ "" \
+ "$hline" )
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local retval _password1 _password2
+ while :; do
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$msg\" $size \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password1=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$rmsg\" $rsize \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password2=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for password mismatch
+ if [ "$_password1" != "$_password2" ]; then
+ f_show_msg "$msg_passwords_do_not_match"
+ continue
+ fi
+
+ # Check for NULL entry
+ if [ ! "$_password1" ]; then
+ f_dialog_yesno \
+ "$msg_disable_password_auth_for_account" ||
+ continue
+ pw_password_disable=1
+ else
+ pw_password_disable=
+ fi
+
+ pw_password="$_password1"
+ break
+ done
+ save_flag=1
+
+ f_dprintf "pw_password: [$cur_pw_password]->[$pw_password]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_gecos [$gecos]
+#
+# Allow the user to enter new GECOS information for a given user. This
+# information is commonly used to store the ``Full Name'' of the user. If the
+# user does not cancel or press ESC, the $pw_gecos variable will hold the
+# newly-configured value upon return.
+#
+f_dialog_input_gecos()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_alnum_punc_tab_enter"
+
+ msg=$( printf "$msg_full_name" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_gecos="$_input"
+ save_flag=1
+
+ f_dprintf "pw_gecos: [$cur_pw_gecos]->[$pw_gecos]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_uid [$uid]
+#
+# Allow the user to enter a new UID for a given user. If the user does not
+# cancel or press ESC, the $pw_uid variable will hold the newly-configured
+# value upon return.
+#
+f_dialog_input_uid()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_num_tab_enter"
+
+ msg=$( printf "$msg_user_id_leave_empty_for_default" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_uid="$_input"
+ save_flag=1
+
+ f_dprintf "pw_uid: [$cur_pw_uid]->[$pw_uid]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_gid [$gid]
+#
+# Allow the user to enter a new primary GID for a given user. If the user does
+# not cancel or press ESC, the $pw_gid variable will hold the newly-configured
+# value upon return.
+#
+f_dialog_input_gid()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_num_tab_enter"
+
+ msg=$( printf "$msg_group_id_leave_empty_for_default" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_gid="$_input"
+ save_flag=1
+
+ f_dprintf "pw_gid: [$cur_pw_gid]->[$pw_gid]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_class [$class]
+#
+# Allow the user to enter a new login class for a given user. If the user does
+# not cancel or press ESC, the $pw_class variable will hold the newly-
+# configured value upon return.
+#
+f_dialog_input_class()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_alnum_tab_enter"
+
+ msg=$( printf "$msg_login_class" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_class="$_input"
+ save_flag=1
+
+ f_dprintf "pw_class: [$cur_pw_class]->[$pw_class]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_change [$seconds]
+#
+# Allow the user to enter a date/time (in number-of-seconds since the `epoch')
+# for when a given user's password must be changed. If the user does not cancel
+# or press ESC, the $pw_password_expire variable will hold the newly-
+# configured value upon return.
+#
+f_dialog_input_change()
+{
+ local calendar_size timebox_size
+ local msg menu_size size retval _input="$1"
+ local hline="$hline_num_arrows_tab_enter"
+
+ local menu_list="
+ '1' '$msg_password_does_not_expire'
+ '2' '$msg_edit_date_time_with_a_calendar'
+ '3' '$msg_enter_number_of_days_into_the_future'
+ '4' '$msg_enter_value_manually'
+ " # END-QUOTE
+
+ #
+ # Loop until the user provides taint-free/cancellation-free input
+ #
+ while :; do
+ msg="$msg_password_expires_on"
+ menu_size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$msg\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$msg\" $menu_size \
+ $menu_list \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+ retval=$?
+ date_type=$( f_dialog_menutag )
+ f_dprintf "retval=$retval date_type=[$date_type]"
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ case "$date_type" in
+ 1) # Password does not expire
+ _input=""
+ break ;;
+
+ 2) # Edit date/time with a calendar
+ local _input_date _input_time ret_date ret_time
+
+ local secs="$_input"
+ { f_isinteger "$secs" && [ $secs -gt 0 ]; } || secs=
+ _input_date=$( date -j -f "%s" -- "$secs" \
+ "+%d %m %Y" 2> /dev/null )
+ calendar_size=$( f_dialog_calendar_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --calendar \"\$msg\" $calendar_size \
+ $_input_date \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_date=$( f_dialog_inputstr )
+ f_dprintf "retval=$retval ret_date=[$ret_date]"
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input_time=
+ [ "$secs" ] && _input_time=$( date -j \
+ -f %s -- "$_input" "+%H %M %S" 2> /dev/null )
+ timebox_size=$( f_dialog_timebox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --timebox \"\$msg\" $timebox_size \
+ $_input_time \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_time=$( f_dialog_inputstr )
+ f_dprintf "retval=$retval ret_time=[$ret_time]"
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input=$( date \
+ -j -f "%d/%m/%Y %T" \
+ -- "$ret_date $ret_time" \
+ +%s 2> /dev/null )
+ f_dprintf "_input=[$_input]"
+ break ;;
+
+ 3) # Enter number of days into the future
+ local ret_days seconds="$( date +%s )"
+
+ f_isinteger "$_input" || _input=0
+ [ $_input -gt 0 -a $_input -gt $seconds ] &&
+ ret_days=$(( ( $_input - $seconds ) / 86400 ))
+ f_isinteger "$ret_days" &&
+ ret_days=$(( $ret_days + 1 ))
+
+ msg="$msg_password_expires_in_how_many_days"
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$ret_days" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$ret_days\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_days=$( f_dialog_inputstr )
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ # Taint-check the user's input
+ if ! f_isinteger "$ret_days"; then
+ f_show_msg "$msg_invalid_number_of_days"
+ continue
+ fi
+
+ f_dprintf "ret_days=[$ret_days]"
+ case "$ret_days" in
+ [-+]*) _input=$( date -v${ret_days}d +%s );;
+ 0) _input=$( date +%s );;
+ *) _input=$( date -v+${ret_days}d +%s );;
+ esac
+ f_dprintf "_input=[$_input]"
+ break ;;
+
+ 4) # Enter value manually
+ local ret_secs
+
+ msg=$( printf "$msg_number_of_seconds_since_epoch" \
+ "$( date -r 1 "+%c %Z" )" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ ret_secs=$( f_dialog_inputstr )
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input="$ret_secs"
+
+ # Taint-check the user's input
+ if ! f_isinteger "${_input:-0}"; then
+ f_show_msg "$msg_invalid_number_of_seconds"
+ continue
+ fi
+
+ f_dprintf "_input=[$_input]"
+ break ;;
+
+ esac
+
+ done # Loop forever
+
+ pw_password_expire="$_input"
+ save_flag=1
+
+ local debug=pw_password_expire
+ f_dprintf "$debug: [$cur_pw_password_expire]->[$pw_password_expire]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_expire [$seconds]
+#
+# Allow the user to enter a date/time (in number-of-seconds since the `epoch')
+# for when a given user's account should become expired. If the user does not
+# cancel or press ESC, the $pw_account_expire variable will hold the newly-
+# configured value upon return.
+#
+f_dialog_input_expire()
+{
+ local calendar_size timebox_size
+ local msg menu_size size retval _input="$1"
+ local hline="$hline_num_arrows_tab_enter"
+
+ local menu_list="
+ '1' '$msg_account_does_not_expire'
+ '2' '$msg_edit_date_time_with_a_calendar'
+ '3' '$msg_enter_number_of_days_into_the_future'
+ '4' '$msg_enter_value_manually'
+ " # END-QUOTE
+
+ #
+ # Loop until the user provides taint-free/cancellation-free input
+ #
+ while :; do
+ msg="$msg_account_expires_on"
+ menu_size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$msg\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$msg\" $menu_size \
+ $menu_list \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+ retval=$?
+ date_type=$( f_dialog_menutag )
+ f_dprintf "retval=$retval date_type=[$date_type]"
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ case "$date_type" in
+ 1) # Account does not expire
+ _input=""
+ break ;;
+
+ 2) # Edit date/time with a calendar
+ local _input_date _input_time ret_date ret_time
+
+ local secs="$_input"
+ { f_isinteger "$secs" && [ $secs -gt 0 ]; } || secs=
+ _input_date=$( date -j -f "%s" -- "$secs" \
+ "+%d %m %Y" 2> /dev/null )
+ calendar_size=$( f_dialog_calendar_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --calendar \"\$msg\" $calendar_size \
+ $_input_date \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_date=$( f_dialog_inputstr )
+ f_dprintf "retval=$retval ret_date=[$ret_date]"
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input_time=
+ [ "$secs" ] && _input_time=$( date -j \
+ -f %s -- "$_input" "+%H %M %S" 2> /dev/null )
+ timebox_size=$( f_dialog_timebox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --timebox \"\$msg\" $timebox_size \
+ $_input_time \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_time=$( f_dialog_inputstr )
+ f_dprintf "retval=$retval ret_time=[$ret_time]"
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input=$( date \
+ -j -f "%d/%m/%Y %T" \
+ -- "$ret_date $ret_time" \
+ +%s 2> /dev/null )
+ f_dprintf "_input=[$_input]"
+ break ;;
+
+ 3) # Enter number of days into the future
+ local ret_days seconds="$( date +%s )"
+
+ f_isinteger "$_input" || _input=0
+ [ $_input -gt 0 -a $_input -gt $seconds ] &&
+ ret_days=$(( ( $_input - $seconds ) / 86400 ))
+ f_isinteger "$ret_days" &&
+ ret_days=$(( $ret_days + 1 ))
+
+ msg="$msg_account_expires_in_how_many_days"
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$ret_days" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$ret_days\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_days=$( f_dialog_inputstr )
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ # Taint-check the user's input
+ if ! f_isinteger "$ret_days"; then
+ f_show_msg "$msg_invalid_number_of_days"
+ continue
+ fi
+
+ f_dprintf "ret_days=[$ret_days]"
+ case "$ret_days" in
+ [-+]*) _input=$( date -v${ret_days}d +%s );;
+ 0) _input=$( date +%s );;
+ *) _input=$( date -v+${ret_days}d +%s );;
+ esac
+ f_dprintf "_input=[$_input]"
+ break ;;
+
+ 4) # Enter value manually
+ local ret_secs
+
+ msg=$( printf "$msg_number_of_seconds_since_epoch" \
+ "$( date -r 1 "+%c %Z" )" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ ret_secs=$( f_dialog_inputstr )
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input="$ret_secs"
+
+ # Taint-check the user's input
+ if ! f_isinteger "${_input:-0}"; then
+ f_show_msg "$msg_invalid_number_of_seconds"
+ continue
+ fi
+
+ f_dprintf "_input=[$_input]"
+ break ;;
+
+ esac
+
+ done # Loop forever
+
+ pw_account_expire="$_input"
+ save_flag=1
+
+ local debug=pw_account_expire
+ f_dprintf "$debug: [$cur_pw_account_expire]->[$pw_account_expire]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_home_dir [$home_dir]
+#
+# Allow the user to enter a new home directory for a given user. If the user
+# does not cancel or press ESC, the $pw_home_dir variable will hold the newly-
+# configured value upon return.
+#
+f_dialog_input_home_dir()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_alnum_punc_tab_enter"
+
+ msg=$( printf "$msg_home_directory" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_home_dir="$_input"
+ save_flag=1
+
+ f_dprintf "pw_home_dir: [$cur_pw_home_dir]->[$pw_home_dir]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_home_create
+#
+# Prompt the user to confirm creation of a given user's home directory. If the
+# user does not cancel (by choosing "No") or press ESC, the $pw_home_create
+# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
+# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
+#
+f_dialog_input_home_create()
+{
+ local retval
+
+ f_dialog_yesno "$msg_create_home_directory"
+ retval=$?
+
+ if [ $retval -eq $SUCCESS ]; then
+ pw_home_create="$msg_yes"
+ else
+ pw_home_create="$msg_no"
+ fi
+ save_flag=1
+
+ f_dprintf "pw_home_create: [$cur_pw_home_create]->[$pw_home_create]"
+
+ [ $retval -ne 255 ] # return failure if user pressed ESC
+}
+
+# f_dialog_input_group_delete
+#
+# Prompt the user to confirm deletion of a given user's primary group. If the
+# user does not cancel (by choosing "No") or press ESC, the $pw_group_delete
+# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
+# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
+#
+f_dialog_input_group_delete()
+{
+ local retval
+
+ if f_isinteger "$pw_gid"; then
+ if [ $pw_gid -lt 1000 ]; then
+ f_dialog_noyes "$msg_delete_primary_group"
+ else
+ f_dialog_yesno "$msg_delete_primary_group"
+ fi
+ elif [ "$pw_gid" ]; then
+ local gid=0
+ gid=$( pw groupshow "$pw_gid" | awk -F: '{print $3}' )
+ if f_isinteger "$gid" && [ $gid -lt 1000 ]; then
+ f_dialog_noyes "$msg_delete_primary_group"
+ else
+ f_dialog_yesno "$msg_delete_primary_group"
+ fi
+ else
+ f_dialog_yesno "$msg_delete_primary_group"
+ fi
+ retval=$?
+
+ if [ $retval -eq $SUCCESS ]; then
+ pw_group_delete="$msg_yes"
+ else
+ pw_group_delete="$msg_no"
+ fi
+ save_flag=1
+
+ f_dprintf "pw_group_delete: [$cur_pw_group_delete]->[$pw_group_delete]"
+
+ [ $retval -ne 255 ] # return failure if user pressed ESC
+}
+
+# f_dialog_input_home_delete
+#
+# Prompt the user to confirm deletion of a given user's home directory. If the
+# user does not cancel (by choosing "No") or press ESC, the $pw_home_delete
+# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
+# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
+#
+f_dialog_input_home_delete()
+{
+ local retval
+
+ f_dialog_yesno "$msg_delete_home_directory"
+ retval=$?
+
+ if [ $retval -eq $SUCCESS ]; then
+ pw_home_delete="$msg_yes"
+ else
+ pw_home_delete="$msg_no"
+ fi
+ save_flag=1
+
+ f_dprintf "pw_home_delete: [$cur_pw_home_delete]->[$pw_home_delete]"
+
+ [ $retval -ne 255 ] # return failure if user pressed ESC
+}
+
+# f_dialog_input_dotfiles_create
+#
+# Prompt the user to confirm population of a given user's home directory with
+# sample dotfiles. If the user does not cancel (by choosing "No") or press ESC,
+# the $pw_dotfiles_create variable will hold $msg_yes upon return, otherwise
+# $msg_no. Use these return variables ($msg_yes and $msg_no) for comparison to
+# be i18n-compatible.
+#
+f_dialog_input_dotfiles_create()
+{
+ local retval
+
+ f_dialog_yesno "$msg_create_dotfiles"
+ retval=$?
+
+ if [ $retval -eq $SUCCESS ]; then
+ pw_dotfiles_create="$msg_yes"
+ else
+ pw_dotfiles_create="$msg_no"
+ fi
+ save_flag=1
+
+ local debug="pw_dotfiles_create:"
+ f_dprintf "$debug: [$cur_pw_dotfiles_create]->[$pw_dotfiles_create]"
+
+ [ $retval -ne 255 ] # return failure if user pressed ESC
+}
+
+# f_dialog_input_shell [$shell]
+#
+# Allow the user to select a new login shell for a given user. If the user does
+# not cancel or press ESC, the $pw_home_dir variable will hold the newly-
+# configured value upon return.
+#
+#
+f_dialog_input_shell()
+{
+ local size retval shells shell_list _input="$1"
+ local hline="$hline_arrows_space_tab_enter"
+ local prompt="$msg_select_login_shell"
+
+ shells=$( awk '!/^[[:space:]]*(#|$)/{print}' "$ETC_SHELLS" )
+ shell_list=$(
+ for shell in $shells; do
+ if [ "$shell" = "$_input" ]; then
+ echo "'$shell' '' 'on'"
+ else
+ echo "'$shell' '' 'off'"
+ fi
+ done
+ )
+
+ size=$( eval f_dialog_radiolist_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $shell_list )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --radiolist \"\$prompt\" $size \
+ $shell_list \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_shell="$_input"
+ save_flag=1
+
+ f_dprintf "pw_shell: [$cur_pw_shell]->[$pw_shell]"
+
+ return $SUCCESS
+}
+
+fi # ! $_USERMGMT_USER_INPUT_SUBR
diff --git a/usr.sbin/bsdconfig/usermgmt/useradd b/usr.sbin/bsdconfig/usermgmt/useradd
new file mode 100755
index 0000000..8dc1934
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/useradd
@@ -0,0 +1,64 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+APP_DIR="070.usermgmt"
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Chain-load to userinput to centralize code and minimize duplication
+#
+f_dialog_init
+$BSDCFG_LIBE/$APP_DIR/userinput ${USE_XDIALOG:+-X} mode="Add"
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/userdel b/usr.sbin/bsdconfig/usermgmt/userdel
new file mode 100755
index 0000000..49a54c4
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/userdel
@@ -0,0 +1,93 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/user_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_delete $msg_login"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Loop until the user Exits, Cancels or presses ESC
+#
+while :; do
+ f_dialog_menu_user_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+
+ *) # anything else is a userid
+ $BSDCFG_LIBE/$APP_DIR/userinput \
+ ${USE_XDIALOG:+-X} mode="Delete" user="$mtag"
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/useredit b/usr.sbin/bsdconfig/usermgmt/useredit
new file mode 100755
index 0000000..3109d36
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/useredit
@@ -0,0 +1,93 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/user_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_edit_view $msg_login"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Loop until the user Exits, Cancels or presses ESC
+#
+while :; do
+ f_dialog_menu_user_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+
+ *) # anything else is a userid
+ $BSDCFG_LIBE/$APP_DIR/userinput \
+ ${USE_XDIALOG:+-X} mode="Edit/View" user="$mtag"
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/userinput b/usr.sbin/bsdconfig/usermgmt/userinput
new file mode 100755
index 0000000..43a750e
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/userinput
@@ -0,0 +1,515 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/user_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ CONFIGURATION
+
+# set some reasonable defaults if /etc/adduser.conf does not exist.
+[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf
+: ${passwdtype:="yes"}
+: ${homeprefix:="/home"}
+: ${defaultshell:="/bin/sh"}
+: ${udotdir:="/usr/share/skel"}
+
+############################################################ FUNCTIONS
+
+# copy_dotfiles
+#
+# Copy `skel' dot-files to a new home directory.
+#
+copy_dotfiles()
+{
+ ( # Operate within sub-shell to protect CWD/glob of parent
+ cd "$udotdir" || exit $?
+ set +f # glob
+ for file in dot.*; do
+ cp -n "$file" "$pw_home_dir/${file#dot}" || exit $?
+ done
+ )
+}
+
+# save_changes
+#
+# Save any/all settings (actions performed depend on $mode value).
+#
+save_changes()
+{
+ local err retval=$SUCCESS
+
+ case "$mode" in
+ Delete)
+ err=$( pw userdel -u "$pw_uid" 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_login_deleted"
+
+ if [ "$pw_group_delete" = "$msg_yes" ] &&
+ f_quietly pw groupshow -g "$pw_gid"
+ then
+ err=$( pw groupdel -g "$pw_gid" 2>&1 ) ||
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ fi
+
+ if [ "$pw_home_delete" = "$msg_yes" ]; then
+ f_dialog_info "$msg_deleting_home_directory"
+ err=$( rm -Rf "$pw_home_dir" 2>&1 ) ||
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ fi
+ ;;
+ Add)
+ local cmd="pw useradd -n '$pw_name'"
+ [ "$pw_member_groups" ] && cmd="$cmd -G '$pw_member_groups'"
+ [ "$pw_class" ] && cmd="$cmd -L '$pw_class'"
+ [ "$pw_gecos" ] && cmd="$cmd -c '$pw_gecos'"
+ [ "$pw_home_dir" ] && cmd="$cmd -d '$pw_home_dir'"
+ [ "$pw_account_expire" ] && cmd="$cmd -e '$pw_account_expire'"
+ [ "$pw_gid" ] && cmd="$cmd -g '$pw_gid'"
+ [ "$pw_password_expire" ] && cmd="$cmd -p '$pw_password_expire'"
+ [ "$pw_shell" ] && cmd="$cmd -s '$pw_shell'"
+ [ "$pw_uid" ] && cmd="$cmd -u '$pw_uid'"
+ if [ "$pw_password_disable" ]; then
+ cmd="$cmd -h -"
+ elif [ "$pw_password" ]; then
+ cmd="echo \"\$pw_password\" | $cmd -h 0"
+ fi
+ f_dprintf "cmd=$cmd"
+ err=$( eval $cmd 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_login_added"
+
+ if [ "$pw_home_create" = "$msg_yes" ]; then
+ err=$( mkdir -p "$pw_home_dir" 2>&1 )
+ if [ $? -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ elif [ -e "$pw_home_dir" ]; then
+ err=$( chown -R "$pw_uid:$pw_gid" \
+ "$pw_home_dir" 2>&1 )
+ [ $? -eq $SUCCESS ] || f_show_msg \
+ "%s %s\n" "$msg_warning" "$err"
+ fi
+ fi
+
+ if [ "$pw_dotfiles_create" = "$msg_yes" ]; then
+ err=$( copy_dotfiles 2>&1 ) ||
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ fi
+
+ user="$pw_name"
+ f_quietly pw usershow -n "$pw_name" &&
+ mode="Edit/View" # Change mode
+ ;;
+ Edit/View)
+ local cmd="pw usermod -n '$pw_name'"
+ [ "$pw_member_groups" ] && cmd="$cmd -G '$pw_member_groups'"
+ [ "$pw_class" ] && cmd="$cmd -L '$pw_class'"
+ [ "$pw_gecos" ] && cmd="$cmd -c '$pw_gecos'"
+ [ "$pw_home_dir" ] && cmd="$cmd -d '$pw_home_dir'"
+ [ "$pw_account_expire" ] && cmd="$cmd -e '$pw_account_expire'"
+ [ "$pw_gid" ] && cmd="$cmd -g '$pw_gid'"
+ [ "$pw_password_expire" ] && cmd="$cmd -p '$pw_password_expire'"
+ [ "$pw_shell" ] && cmd="$cmd -s '$pw_shell'"
+ [ "$pw_uid" ] && cmd="$cmd -u '$pw_uid'"
+ if [ "$pw_password_disable" ]; then
+ cmd="$cmd -h -"
+ elif [ "$pw_password" ]; then
+ cmd="echo \"\$pw_password\" | $cmd -h 0"
+ fi
+ f_dprintf "cmd=$cmd"
+ err=$( eval $cmd 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_login_updated"
+
+ if [ "$pw_home_create" = "$msg_yes" ]; then
+ err=$( mkdir -p "$pw_home_dir" )
+ if [ $? -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ elif [ -e "$pw_home_dir" ]; then
+ err=$( chown -R "$pw_uid:$pw_gid" \
+ "$pw_home_dir" 2>&1 )
+ [ $? -eq $SUCCESS ] || f_show_msg \
+ "%s %s\n" "$msg_warning" "$err"
+ fi
+ fi
+
+ if [ "$pw_dotfiles_create" = "$msg_yes" ]; then
+ err=$( copy_dotfiles 2>&1 ) ||
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ fi
+ ;;
+ esac
+
+ save_flag=
+ return $SUCCESS
+}
+
+# dialog_title_update $mode
+#
+# Set the title based on the given $mode.
+#
+dialog_title_update()
+{
+ local mode="$1"
+ case "$mode" in
+ Add) f_dialog_title "$msg_add $msg_user" ;;
+ Edit/View) f_dialog_title "$msg_edit_view $msg_user: $user" ;;
+ Delete) f_dialog_title "$msg_delete $msg_user: $user" ;;
+ esac
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while [ $# -gt 0 ]; do
+ key="${1%%=*}"
+ value="${1#*=}"
+ f_dprintf "key=[$key] value=[$value]"
+ case "$key" in
+ mode) mode="$value";;
+ user) user="$value";;
+ esac
+ shift
+done
+f_dprintf "mode=[$mode] user=[$user]"
+
+#
+# Initialize
+#
+f_dialog_init
+dialog_title_update "$mode"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+menu_text=
+save_flag=
+hline="$hline_arrows_tab_enter"
+
+if [ "$mode" = "Add" ]; then
+ #
+ # Ask a series of questions to pre-fill the editor screen.
+ #
+ # The defaults used in each dialog should allow the user to simply
+ # hit ENTER to proceed, because cancelling a single dialog will
+ # cause them to be returned to the main usermenu.
+ #
+
+ f_dialog_input_name || exit 0
+ f_dialog_input_gecos "$pw_name" || exit 0
+ [ "$passwdtype" = "yes" ] &&
+ { f_dialog_input_password || exit 0; }
+ f_dialog_input_uid || exit 0
+ f_dialog_input_gid || exit 0
+ f_dialog_input_member_groups || exit 0
+ f_dialog_input_class || exit 0
+ f_dialog_input_change || exit 0
+ f_dialog_input_expire || exit 0
+ f_dialog_input_home_dir "$homeprefix/$pw_name" || exit 0
+ pw_dotfiles_create="$msg_no"
+ if [ ! -d "$homeprefix/$pw_name" ]; then
+ f_dialog_input_home_create || exit 0
+ [ "$pw_home_create" = "$msg_yes" ] &&
+ { f_dialog_input_dotfiles_create || exit 0; }
+ fi
+ f_dialog_input_shell "$defaultshell" || exit 0
+fi
+
+if [ "$mode" = "Edit/View" -o "$mode" = "Delete" ]; then
+ f_input_user "$user" || f_die 1 "$msg_login_not_found"
+fi
+
+if [ "$mode" = "Edit/View" ]; then
+ [ -d "$pw_home_dir" ] || pw_home_create="$msg_no"
+ pw_dotfiles_create="$msg_no"
+fi
+
+if [ "$mode" = "Delete" ]; then
+ f_dialog_input_group_delete || exit 0
+ pw_home_delete="$msg_no"
+ [ -d "$pw_home_dir" ] &&
+ { f_dialog_input_home_delete || exit 0; }
+fi
+
+cur_pw_name="$pw_name"
+cur_pw_password="$pw_password"
+cur_pw_uid="$pw_uid"
+cur_pw_gid="$pw_gid"
+cur_pw_member_groups="$pw_member_groups"
+cur_pw_class="$pw_class"
+cur_pw_password_expire="$pw_password_expire"
+cur_pw_account_expire="$pw_account_expire"
+cur_pw_gecos="$pw_gecos"
+cur_pw_home_dir="$pw_home_dir"
+cur_pw_shell="$pw_shell"
+cur_pw_group_delete="$pw_group_delete"
+cur_pw_home_create="$pw_home_create"
+cur_pw_home_delete="$pw_home_delete"
+cur_pw_dotfiles_create="$pw_dotfiles_create"
+
+[ "$mode" = "Delete" ] && save_flag=1
+
+#
+# Loop until the user decides to Exit, Cancel, or presses ESC
+#
+while :; do
+ dialog_title_update "$mode"
+
+ menu_text=
+ menu_exit="$msg_exit"
+ if [ "$save_flag" ]; then
+ if [ "$mode" = "Delete" ]; then
+ menu_exit="$msg_delete/$msg_exit"
+ menu_text="$msg_delete_exit_or_cancel"
+ else
+ menu_exit="$msg_save/$msg_exit"
+ menu_text="$msg_save_exit_or_cancel"
+ fi
+ fi
+
+ pw_password_expires_on="$pw_password_expire"
+ f_isinteger "$pw_password_expire" && [ $pw_password_expire -ne 0 ] &&
+ pw_password_expires_on=$(
+ date -r "$pw_password_expire" "+%F %T %Z"
+ )
+ pw_account_expires_on="$pw_account_expire"
+ f_isinteger "$pw_account_expire" && [ "$pw_account_expire" -ne 0 ] &&
+ pw_account_expires_on=$(
+ date -r "$pw_account_expire" "+%F %T %Z"
+ )
+
+ case "$mode" in
+ Delete)
+ menu_items="
+ 'X' '$menu_exit'
+ '1' '$msg_login: $pw_name'
+ '-' '$msg_full_name: $pw_gecos'
+ '-' '$msg_password: -----'
+ '-' '$msg_user_id: $pw_uid'
+ '-' '$msg_group_id: $pw_gid'
+ '-' '$msg_member_of_groups: $pw_member_groups'
+ '-' '$msg_login_class: $pw_class'
+ '-' '$msg_password_expires_on: $pw_password_expires_on'
+ '-' '$msg_account_expires_on: $pw_account_expires_on'
+ '-' '$msg_home_directory: $pw_home_dir'
+ '-' '$msg_shell: $pw_shell'
+ " # END-QUOTE
+ ;;
+ *)
+ menu_items="
+ 'X' '$menu_exit'
+ '1' '$msg_login: $pw_name'
+ '2' '$msg_full_name: $pw_gecos'
+ '3' '$msg_password: -----'
+ '4' '$msg_user_id: $pw_uid'
+ '5' '$msg_group_id: $pw_gid'
+ '6' '$msg_member_of_groups: $pw_member_groups'
+ '7' '$msg_login_class: $pw_class'
+ '8' '$msg_password_expires_on: $pw_password_expires_on'
+ '9' '$msg_account_expires_on: $pw_account_expires_on'
+ 'A' '$msg_home_directory: $pw_home_dir'
+ 'B' '$msg_shell: $pw_shell'
+ " # END-QUOTE
+ esac
+
+ case "$mode" in
+ Add|Edit/View)
+ if [ -d "$pw_home_dir" ]; then menu_items="$menu_items
+ '-' '$msg_create_home_directory: $msg_n_a'
+ 'D' '$msg_create_dotfiles: $pw_dotfiles_create'
+ "; else menu_items="$menu_items
+ 'C' '$msg_create_home_directory: $pw_home_create'
+ 'D' '$msg_create_dotfiles: $pw_dotfiles_create'
+ "; fi
+ ;;
+ Delete)
+ if [ -d "$pw_home_dir" ]; then menu_items="$menu_items
+ 'C' '$msg_delete_primary_group: $pw_group_delete'
+ 'D' '$msg_delete_home_directory: $pw_home_delete'
+ "; else menu_items="$menu_items
+ 'C' '$msg_delete_primary_group: $pw_group_delete'
+ '-' '$msg_delete_home_directory: $msg_n_a'
+ "; fi
+ ;;
+ esac
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$menu_text\" \
+ \"\$hline\" \
+ $menu_items )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$menu_text\" $size \
+ $menu_items \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ # Exit if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || f_die
+
+ case "$mtag" in
+ X) # Exit
+ if [ "$save_flag" ]; then
+ save_changes || continue
+ fi
+ break
+ ;;
+ 1) # Login
+ case "$mode" in
+ Add) f_dialog_input_name "$pw_name" ;;
+ Edit/View|Delete)
+ f_dialog_menu_user_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ # Loop if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ [ "$mtag" = "X $msg_exit" ] && continue
+
+ user="$mtag"
+ f_input_user "$user" || f_die 1 "$msg_login_not_found"
+ cur_pw_name="$pw_name"
+ cur_pw_password="$pw_password"
+ cur_pw_uid="$pw_uid"
+ cur_pw_gid="$pw_gid"
+ cur_pw_member_groups="$pw_member_groups"
+ cur_pw_class="$pw_class"
+ cur_pw_password_expire="$pw_password_expire"
+ cur_pw_account_expire="$pw_account_expire"
+ cur_pw_gecos="$pw_gecos"
+ cur_pw_home_dir="$pw_home_dir"
+ cur_pw_shell="$pw_shell"
+ cur_pw_group_delete="$pw_group_delete"
+ cur_pw_home_create="$pw_home_create"
+ cur_pw_home_delete="$pw_home_delete"
+ cur_pw_dotfiles_create="$pw_dotfiles_create"
+ [ "$mode" != "Delete" ] && save_flag=
+ esac
+ ;;
+ 2) # Full Name
+ f_dialog_input_gecos "$pw_gecos"
+ ;;
+ 3) # Password
+ f_dialog_input_password
+ ;;
+ 4) # UID
+ f_dialog_input_uid "$pw_uid"
+ ;;
+ 5) # Default Group
+ f_dialog_input_gid "$pw_gid"
+ ;;
+ 6) # Member of Groups
+ f_dialog_input_member_groups "$pw_member_groups"
+ ;;
+ 7) # Login Class
+ f_dialog_input_class "$pw_class"
+ ;;
+ 8) # Password Expire on
+ f_dialog_input_change "$pw_password_expire"
+ ;;
+ 9) # Account Expire on
+ f_dialog_input_expire "$pw_account_expire"
+ ;;
+ A) # Home Directory
+ f_dialog_input_home_dir "$pw_home_dir"
+ ;;
+ B) # Shell
+ f_dialog_input_shell "$pw_shell"
+ ;;
+ esac
+
+ case "$mode" in
+ Delete)
+ case "$mtag" in
+ C) # Delete Primary Group
+ f_dialog_input_group_delete ;;
+ D) # Delete Home Directory
+ f_dialog_input_home_delete ;;
+ esac
+ ;;
+ Add|Edit/View)
+ case "$mtag" in
+ C) # Create Home Directory
+ f_dialog_input_home_create
+ [ "$pw_home_create" = "$msg_no" ] &&
+ pw_dotfiles_create="$msg_no"
+ ;;
+ D) # Create Dotfiles
+ f_dialog_input_dotfiles_create
+ [ "$pw_dotfiles_create" = "$msg_yes" ] &&
+ pw_home_create="$msg_yes"
+ ;;
+ esac
+ ;;
+ esac
+
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/usermgmt b/usr.sbin/bsdconfig/usermgmt/usermgmt
new file mode 100755
index 0000000..460f46b
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/usermgmt
@@ -0,0 +1,150 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_arrows_tab_enter"
+
+ menu_list="
+ 'X' '$msg_exit'
+ '1' '$msg_add_login'
+ '2' '$msg_edit_login'
+ '3' '$msg_delete_login'
+ '-' '-'
+ '4' '$msg_add_group'
+ '5' '$msg_edit_group'
+ '6' '$msg_delete_group'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\" $size $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_login_management"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ X) # Exit
+ exit 0
+ ;;
+
+ 1) # Add User
+ $BSDCFG_LIBE/$APP_DIR/useradd ${USE_XDIALOG:+-X}
+ ;;
+
+ 2) # Edit/View User
+ $BSDCFG_LIBE/$APP_DIR/useredit ${USE_XDIALOG:+-X}
+ ;;
+
+ 3) # Delete User
+ $BSDCFG_LIBE/$APP_DIR/userdel ${USE_XDIALOG:+-X}
+ ;;
+
+ 4) # Add Group
+ $BSDCFG_LIBE/$APP_DIR/groupadd ${USE_XDIALOG:+-X}
+ ;;
+
+ 5) # Edit/View Group
+ $BSDCFG_LIBE/$APP_DIR/groupedit ${USE_XDIALOG:+-X}
+ ;;
+
+ 6) # Delete Group
+ $BSDCFG_LIBE/$APP_DIR/groupdel ${USE_XDIALOG:+-X}
+ ;;
+
+ esac
+done
+
+################################################################################
+# END
+################################################################################
OpenPOWER on IntegriCloud