Index: head/usr.sbin/bsdconfig/bsdconfig =================================================================== --- head/usr.sbin/bsdconfig/bsdconfig (revision 295107) +++ head/usr.sbin/bsdconfig/bsdconfig (revision 295108) @@ -1,428 +1,428 @@ #!/bin/sh #- # Copyright (c) 2012 Ron McDowell # Copyright (c) 2012-2014 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 # When common.subr is included, it automatically scans "$@" for `-d' and/or # `-D file' arguments to conditionally enable debugging. Similarly, when # dialog.subr is included, it automatically scans "$@" for `-X' and/or `-S'. # To prevent this scanning from becoming confused by extra options, define # any/all extra arguments to use in the optstring to getopts when scanning # for dedicated options such as those described. # # NOTE: This needs to be declared before including `common.subr'. # NOTE: You really only need to list flags that require an argument as unknown # flags are silently accepted unless they take an argument (in which case # the following argument will terminate option processing unless it looks # like a flag). # GETOPTS_EXTRA="f:" BSDCFG_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 f_dprintf "%s: loading includes..." "$0" f_include $BSDCFG_SHARE/dialog.subr f_include $BSDCFG_SHARE/mustberoot.subr f_include $BSDCFG_SHARE/strings.subr BSDCFG_LIBE="/usr/libexec/bsdconfig" f_include_lang $BSDCFG_LIBE/include/messages.subr BSDCONFIG_HELPFILE=$BSDCFG_LIBE/include/bsdconfig.hlp USAGE_HELPFILE=$BSDCFG_LIBE/include/usage.hlp ############################################################ CONFIGURATION # # Alternate `local' libexec directory for add-on modules (e.g., from ports) # BSDCFG_LOCAL_LIBE="/usr/local/libexec/bsdconfig" ############################################################ FUNCTIONS # usage # # display usage and exit # usage() { local index="INDEX" local cmd_list # Calculated below cd $BSDCFG_LIBE # No need to preserve CWD (headed toward exit) # 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 ) local alt_cmd_list # Calculated below (if $BSDCFG_LOCAL_LIBE exists) if f_quietly cd $BSDCFG_LOCAL_LIBE; then # No need to preserve CWD (headed toward exit) # Test for language-specific indices f_quietly ls */"$index.${LANG:-$LC_ALL}" && index="$index.${LANG:-$LC_ALL}" alt_cmd_list=$( awk '/^menu_selection="/ { sub(/\|.*/, "") sub(/^menu_selection="/, "") print }' */$index 2> /dev/null | sort ) # Conflate lists, removing duplicates cmd_list=$( printf "%s\n%s\n" \ "$cmd_list" "$alt_cmd_list" | sort -u ) fi # # Determine the longest command-length (in characters) # local longest_cmd longest_cmd=$( echo "$cmd_list" | f_longest_line_length ) f_dprintf "longest_cmd=[%s]" "$longest_cmd" # # Determine the maximum width of terminal/console # local max_size="$( stty size 2> /dev/null )" : ${max_size:="24 80"} local max_width="${max_size#*[$IFS]}" f_dprintf "max_width=[%s]" "$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 )) # Accommodate 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=[%u] x=[%u]" $ncols $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]\" \"%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" # Never reached } # 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=" 'X' '$msg_exit' '$msg_exit_bsdconfig' '1' '$msg_usage' '$msg_quick_start_how_to_use_this_menu_system' " # END-QUOTE local defaultitem= # Calculated below local hline= # # Pick up the base modules (directories named `[0-9][0-9][0-9].*') # local menuitem menu_title menu_help menu_selection index=2 for menuitem in $( cd $BSDCFG_LIBE && ls -d [0-9][0-9][0-9].* ); do [ -f "$BSDCFG_LIBE/$menuitem/INDEX" ] || continue [ $index -lt ${#DIALOG_MENU_TAGS} ] || break menu_program= menu_title= menu_help= f_include_lang $BSDCFG_LIBE/$menuitem/INDEX [ "$menu_program" ] || continue case "$menu_program" in /*) : already fully qualified ;; *) menu_program="$menuitem/$menu_program" esac - tag=$( f_substr "$DIALOG_MENU_TAGS" $index 1 ) + f_substr -v tag "$DIALOG_MENU_TAGS" $index 1 setvar "menu_program$tag" "$menu_program" f_shell_escape "$menu_title" menu_title f_shell_escape "$menu_help" menu_help menu_list="$menu_list '$tag' '$menu_title' '$menu_help'" index=$(( $index + 1 )) done # # Process the `local' libexec sources. # # Whereas modules in $BSDCFG_LIBE must be named [0-9][0-9][0-9].* # modules in $BSDCFG_LOCAL_LIBE should NOT be named this way (making it # more practical for port-maintainers). # # This also has the fortunate side-effect of making the de-duplication # effort rather simple (because so-called `base' modules must be named # differently than add-on modules). # local separator_added= for menuitem in $( cd "$BSDCFG_LOCAL_LIBE" 2> /dev/null && ls -d * ) do # Skip the module if it looks like a `base' module case "$menuitem" in [0-9][0-9][0-9].*) continue;; esac [ -f "$BSDCFG_LOCAL_LIBE/$menuitem/INDEX" ] || continue [ $index -lt ${#DIALOG_MENU_TAGS} ] || break menu_program= menu_title= menu_help= f_include_lang $BSDCFG_LOCAL_LIBE/$menuitem/INDEX || continue [ "$menu_program" ] || continue if [ ! "$separator_added" ]; then menu_list="$menu_list '-' '-' ''" separator_added=1 fi case "$menu_program" in /*) : already fully qualified ;; *) menu_program="$BSDCFG_LOCAL_LIBE/$menuitem/$menu_program" esac - tag=$( f_substr "$DIALOG_MENU_TAGS" $index 1 ) + f_substr -v tag "$DIALOG_MENU_TAGS" $index 1 setvar "menu_program$tag" "$menu_program" f_shell_escape "$menu_title" menu_title f_shell_escape "$menu_help" menu_help menu_list="$menu_list '$tag' '$menu_title' '$menu_help'" index=$(( $index + 1 )) done local height width rows eval f_dialog_menu_with_help_size height width rows \ \"\$title\" \ \"\$btitle\" \ \"\$prompt\" \ \"\$hline\" \ $menu_list # Obtain default-item from previously stored selection f_dialog_default_fetch defaultitem local menu_choice menu_choice=$( eval $DIALOG \ --clear \ --title \"\$title\" \ --backtitle \"\$btitle\" \ --hline \"\$hline\" \ --item-help \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_exit_bsdconfig\" \ --help-button \ --help-label \"\$msg_help\" \ ${USE_XDIALOG:+--help \"\"} \ --default-item \"\$defaultitem\" \ --menu \"\$prompt\" \ $height $width $rows \ $menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_data_sanitize menu_choice f_dialog_menutag_store "$menu_choice" # Only update default-item on success [ $retval -eq $DIALOG_OK ] && f_dialog_default_store "$menu_choice" return $retval } ############################################################ MAIN # # If $0 is not "bsdconfig", interpret it either as a keyword to a menuitem or # as a valid resword (see script.subr for additional details about reswords). # if [ "$pgm" != "bsdconfig" ]; then if indexfile=$( f_index_file "$pgm" ) && cmd=$( f_index_menusel_command "$indexfile" "$pgm" ) then f_dprintf "pgm=[%s] cmd=[%s] *=[%s]" "$pgm" "$cmd" "$*" exec "$cmd" "$@" || exit 1 else f_include $BSDCFG_SHARE/script.subr for resword in $RESWORDS; do [ "$pgm" = "$resword" ] || continue # Found a match f_dprintf "pgm=[%s] A valid resWord!" "$pgm" f_dispatch $resword $resword "$@" exit $? done fi fi # # Process command-line arguments # scripts_loaded=0 while getopts f:h$GETOPTS_STDARGS flag; do case "$flag" in f) [ $scripts_loaded -eq 0 ] && f_include $BSDCFG_SHARE/script.subr f_script_load "$OPTARG" scripts_loaded=$(( $scripts_loaded + 1 )) ;; h|\?) usage ;; esac done shift $(( $OPTIND - 1 )) # If we've loaded any scripts, do not continue any further [ $scripts_loaded -gt 0 ] && exit # # Initialize # f_dialog_title "$msg_main_menu" [ "$SECURE" ] && f_mustberoot_init # Incorporate rc-file if it exists [ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc" # # 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 # Not reached esac # # Find the INDEX (possibly i18n) claiming this keyword and get the # command to execute from the menu_selection line. # if ! { indexfile=$( f_index_file "$1" ) && cmd=$( f_index_menusel_command "$indexfile" "$1" ) }; then # no matches, display usage (which shows valid keywords) f_err "%s: %s: $msg_not_found\n" "$pgm" "$1" usage # Not reached fi f_dprintf "cmd=[%s] *=[%s]" "$cmd" "$*" shift exec $cmd ${USE_XDIALOG:+-X} "$@" || exit 1 # Not reached fi # # Launch application main menu # while :; do dialog_menu_main retval=$? f_dialog_menutag_fetch mtag f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" if [ $retval -eq $DIALOG_HELP ]; then f_show_help "$BSDCONFIG_HELPFILE" continue elif [ $retval -ne $DIALOG_OK ]; then f_die fi case "$mtag" in X) break ;; 1) # Usage f_show_help "$USAGE_HELPFILE" continue esac # Anything else is a dynamically loaded menuitem f_getvar menu_program$mtag menu_program case "$menu_program" in /*) cmd="$menu_program" ;; *) cmd="$BSDCFG_LIBE/$menu_program" esac f_dprintf "cmd=[%s]" "$cmd" $cmd ${USE_XDIALOG:+-X} done exit $SUCCESS ################################################################################ # END ################################################################################ Index: head/usr.sbin/bsdconfig/networking/share/media.subr =================================================================== --- head/usr.sbin/bsdconfig/networking/share/media.subr (revision 295107) +++ head/usr.sbin/bsdconfig/networking/share/media.subr (revision 295108) @@ -1,247 +1,247 @@ if [ ! "$_NETWORKING_MEDIA_SUBR" ]; then _NETWORKING_MEDIA_SUBR=1 # # Copyright (c) 2006-2013 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_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 f_dprintf "%s: loading includes..." networking/media.subr f_include $BSDCFG_SHARE/dialog.subr f_include $BSDCFG_SHARE/networking/common.subr f_include $BSDCFG_SHARE/strings.subr f_include $BSDCFG_SHARE/sysrc.subr BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="120.networking" 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 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. If the user does not press ESC or choose # Cancel/No, $options will hold the user's input. Default input is taken from # the same variable ($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 f_sprintf setting "$msg_current_options" \ "$interface" "$options" f_noyes "$msg_nfs_mounts_may_cause_hang" "$setting" || return $DIALOG_CANCEL fi local msg f_sprintf msg "$msg_please_enter_mediaopts" "$interface" local hline="$hline_alnum_punc_tab_enter" local _options _options=$( $DIALOG \ --title "$DIALOG_TITLE" \ --backtitle "$DIALOG_BACKTITLE" \ --hline "$hline" \ --ok-label "$msg_ok" \ --cancel-label "$msg_cancel" \ --inputbox "$msg" 9 70 \ "$options" \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_line_sanitize _options [ $retval -eq $DIALOG_OK ] && 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 f_sprintf setting "$msg_current_options" \ "$interface" "$_options" f_noyes "$msg_nfs_mounts_may_cause_hang" "$setting" || return $DIALOG_CANCEL 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'" + f_substr -v tagn "$DIALOG_MENU_TAGS" $index 1 + echo "'$tagn' '$opt_none'" index=$(( $index + 1 )) - echo "'$( f_substr "$DIALOG_MENU_TAGS" $index 1 )'" - echo "'$opt_cust'" + f_substr -v tagn "$DIALOG_MENU_TAGS" $index 1 + echo "'$tagn' '$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'" + f_substr -v tagn "$DIALOG_MENU_TAGS" $index 1 + echo "'$tagn' '$media_options'" index=$(( $index + 1 )) done ) )" local msg if [ "$USE_XDIALOG" ]; then f_sprintf msg "$xmsg_supported_media_options" \ "$interface" "$interface" else f_sprintf msg "$msg_supported_media_options" \ "$interface" "$interface" fi local hline="$hline_arrows_tab_enter" local tag tag=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --menu \"\$msg\" 21 60 12 \ $supported_media \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_data_sanitize tag if [ $retval -eq $DIALOG_OK ]; then options=$( eval f_dialog_menutag2item \"\$tag\" \ $supported_media ) case "$options" in "$opt_none") options= ;; "$opt_cust") options="$_options" f_dialog_input_options "$interface" retval=$? ;; esac fi return $retval } ############################################################ MAIN f_dprintf "%s: Successfully loaded." networking/media.subr fi # ! $_NETWORKING_MEDIA_SUBR Index: head/usr.sbin/bsdconfig/networking/share/resolv.subr =================================================================== --- head/usr.sbin/bsdconfig/networking/share/resolv.subr (revision 295107) +++ head/usr.sbin/bsdconfig/networking/share/resolv.subr (revision 295108) @@ -1,502 +1,502 @@ if [ ! "$_NETWORKING_RESOLV_SUBR" ]; then _NETWORKING_RESOLV_SUBR=1 # # Copyright (c) 2006-2013 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_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 f_dprintf "%s: loading includes..." networking/resolv.subr f_include $BSDCFG_SHARE/dialog.subr f_include $BSDCFG_SHARE/media/tcpip.subr f_include $BSDCFG_SHARE/networking/common.subr f_include $BSDCFG_SHARE/networking/ipaddr.subr f_include $BSDCFG_SHARE/strings.subr BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="120.networking" f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr ############################################################ CONFIGURATION # # 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_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 funcname=f_dialog_resolv_conf_update local hostname="$1" # # Extrapolate the desired domain search parameter for resolv.conf(5) # local search nfields ndots domain="${hostname#*.}" if [ "$RESOLVER_SEARCH_DOMAINS_ALL" = "1" ]; then search= IFS=. f_count_ifs nfields "$domain" ndots=$(( $nfields - 1 )) while [ $ndots -ge ${RESOLVER_SEARCH_NDOTS:-1} ]; do search="$search $domain" domain="${domain#*.}" ndots=$(( $ndots - 1 )) done search="${search# }" 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 f_eval_catch -dk tmpfile $funcname mktemp \ 'mktemp -t "%s"' "$tmpfile" || return $DIALOG_CANCEL # # 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 owner f_eval_catch -dk mode $funcname stat \ 'stat -f "%%#Lp" "%s"' "$RESOLV_CONF" || mode=0644 f_eval_catch -dk owner $funcname stat \ 'stat -f "%%u:%%g" "%s"' "$RESOLV_CONF" || owner="root:wheel" f_eval_catch -d $funcname chmod \ 'chmod "%s" "%s"' "$mode" "$tmpfile" f_eval_catch -d $funcname chown \ 'chown "%s" "%s"' "$owner" "$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 $DIALOG_CANCEL f_eval_catch -d $funcname mv \ 'mv "%s" "%s"' "$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 funcname=f_dialog_input_nameserver local index="${1:-0}" old_ns="$2" new_ns local ns="$old_ns" # # Perform sanity checks # f_isinteger "$index" || return $DIALOG_CANCEL [ $index -ge 0 ] || return $DIALOG_CANCEL 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 # # Loop until the user provides taint-free input. # while :; do f_dialog_input new_ns "$msg" "$ns" \ "$hline_num_punc_tab_enter" || return $? # 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 $DIALOG_OK 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 f_eval_catch -dk tmpfile $funcname mktemp \ 'mktemp -t "%s"' "$pgm" || return $DIALOG_CANCEL # # Quietly fixup permissions and ownership # local mode owner f_eval_catch -dk mode $funcname stat \ 'stat -f "%%#Lp" "%s"' "$RESOLV_CONF" || mode=0644 f_eval_catch -dk owner $funcname stat \ 'stat -f "%%u:%%g" "%s"' "$RESOLV_CONF" || owner="root:wheel" f_eval_catch -d $funcname chmod \ 'chmod "%s" "%s"' "$mode" "$tmpfile" f_eval_catch -d $funcname chown \ 'chown "%s" "%s"' "$owner" "$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_show_msg "$msg_resolv_conf_changed_while_editing" return $retval ;; 3) f_show_msg "$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 $DIALOG_CANCEL f_eval_catch -d $funcname mv \ 'mv "%s" "%s"' "$tmpfile" "$RESOLV_CONF" fi } # f_dialog_menu_nameservers # # Edit the nameservers in resolv.conf(5). # f_dialog_menu_nameservers() { local prompt="$msg_dns_configuration" local menu_list # Calculated below local hline="$hline_arrows_tab_enter" local defaultitem= local height width rows local opt_exit="$msg_return_to_previous_menu" local opt_add="$msg_add_nameserver" # # Loop forever until the user has finished configuring nameservers # while :; do # # Re/Build list of nameservers # local nameservers f_resolv_conf_nameservers nameservers 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 ) + f_substr -v tag "$DIALOG_MENU_TAGS" $index 1 echo "'$tag nameserver' '$ns'" index=$(( $index + 1 )) done ) # # Display configuration-edit menu # eval f_dialog_menu_size height width rows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ \"\$prompt\" \ \"\$hline\" \ $menu_list local tag tag=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --default-item \"\$defaultitem\" \ --menu \"\$prompt\" \ $height $width $rows \ $menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_data_sanitize tag # Return if "Cancel" was chosen (-1) or ESC was pressed (255) if [ $retval -ne $DIALOG_OK ]; then return $retval else # Only update default-item on success defaultitem="$tag" fi case "$tag" in "X $msg_exit") break ;; "A $msg_add") f_dialog_input_nameserver ;; *) local n ns 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 } ############################################################ MAIN f_dprintf "%s: Successfully loaded." networking/resolv.subr fi # ! $_NETWORKING_RESOLV_SUBR