1252995Sdteske#!/bin/sh 2252995Sdteske#- 3252995Sdteske# Copyright (c) 2012 Ron McDowell 4263791Sdteske# Copyright (c) 2012-2014 Devin Teske 5252995Sdteske# All rights reserved. 6252995Sdteske# 7252995Sdteske# Redistribution and use in source and binary forms, with or without 8252995Sdteske# modification, are permitted provided that the following conditions 9252995Sdteske# are met: 10252995Sdteske# 1. Redistributions of source code must retain the above copyright 11252995Sdteske# notice, this list of conditions and the following disclaimer. 12252995Sdteske# 2. Redistributions in binary form must reproduce the above copyright 13252995Sdteske# notice, this list of conditions and the following disclaimer in the 14252995Sdteske# documentation and/or other materials provided with the distribution. 15252995Sdteske# 16252995Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17252995Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18252995Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19252995Sdteske# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20252995Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21252995Sdteske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22252995Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23252995Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24252995Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25252995Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26252995Sdteske# SUCH DAMAGE. 27252995Sdteske# 28252995Sdteske# $FreeBSD$ 29252995Sdteske# 30252995Sdteske############################################################ INCLUDES 31252995Sdteske 32252995Sdteske# When common.subr is included, it automatically scans "$@" for `-d' and/or 33252995Sdteske# `-D file' arguments to conditionally enable debugging. Similarly, when 34252995Sdteske# dialog.subr is included, it automatically scans "$@" for `-X' and/or `-S'. 35252995Sdteske# To prevent this scanning from becoming confused by extra options, define 36252995Sdteske# any/all extra arguments to use in the optstring to getopts when scanning 37252995Sdteske# for dedicated options such as those described. 38252995Sdteske# 39252995Sdteske# NOTE: This needs to be declared before including `common.subr'. 40252995Sdteske# NOTE: You really only need to list flags that require an argument as unknown 41252995Sdteske# flags are silently accepted unless they take an argument (in which case 42252995Sdteske# the following argument will terminate option processing unless it looks 43252995Sdteske# like a flag). 44252995Sdteske# 45252995SdteskeGETOPTS_EXTRA="f:" 46252995Sdteske 47252995SdteskeBSDCFG_SHARE="/usr/share/bsdconfig" 48252995Sdteske. $BSDCFG_SHARE/common.subr || exit 1 49252995Sdteskef_dprintf "%s: loading includes..." "$0" 50252995Sdteskef_include $BSDCFG_SHARE/dialog.subr 51252995Sdteskef_include $BSDCFG_SHARE/mustberoot.subr 52252995Sdteskef_include $BSDCFG_SHARE/strings.subr 53252995Sdteske 54252995SdteskeBSDCFG_LIBE="/usr/libexec/bsdconfig" 55252995Sdteskef_include_lang $BSDCFG_LIBE/include/messages.subr 56252995Sdteske 57252995SdteskeBSDCONFIG_HELPFILE=$BSDCFG_LIBE/include/bsdconfig.hlp 58252995SdteskeUSAGE_HELPFILE=$BSDCFG_LIBE/include/usage.hlp 59252995Sdteske 60252995Sdteske############################################################ CONFIGURATION 61252995Sdteske 62252995Sdteske# 63252995Sdteske# Alternate `local' libexec directory for add-on modules (e.g., from ports) 64252995Sdteske# 65252995SdteskeBSDCFG_LOCAL_LIBE="/usr/local/libexec/bsdconfig" 66252995Sdteske 67252995Sdteske############################################################ FUNCTIONS 68252995Sdteske 69252995Sdteske# usage 70252995Sdteske# 71252995Sdteske# display usage and exit 72252995Sdteske# 73252995Sdteskeusage() 74252995Sdteske{ 75252995Sdteske local index="INDEX" 76252995Sdteske local cmd_list # Calculated below 77252995Sdteske 78252995Sdteske cd $BSDCFG_LIBE 79252995Sdteske # No need to preserve CWD (headed toward exit) 80252995Sdteske 81252995Sdteske # Test for language-specific indices 82252995Sdteske f_quietly ls */"$index.${LANG:-$LC_ALL}" && 83252995Sdteske index="$index.${LANG:-$LC_ALL}" 84252995Sdteske 85252995Sdteske cmd_list=$( 86252995Sdteske awk '/^menu_selection="/ { 87252995Sdteske sub(/\|.*/, "") 88252995Sdteske sub(/^menu_selection="/, "") 89252995Sdteske print 90252995Sdteske }' */$index | sort 91252995Sdteske ) 92252995Sdteske 93252995Sdteske local alt_cmd_list # Calculated below (if $BSDCFG_LOCAL_LIBE exists) 94252995Sdteske if f_quietly cd $BSDCFG_LOCAL_LIBE; then 95252995Sdteske # No need to preserve CWD (headed toward exit) 96252995Sdteske 97252995Sdteske # Test for language-specific indices 98252995Sdteske f_quietly ls */"$index.${LANG:-$LC_ALL}" && 99252995Sdteske index="$index.${LANG:-$LC_ALL}" 100252995Sdteske 101252995Sdteske alt_cmd_list=$( 102252995Sdteske awk '/^menu_selection="/ { 103252995Sdteske sub(/\|.*/, "") 104252995Sdteske sub(/^menu_selection="/, "") 105252995Sdteske print 106252995Sdteske }' */$index 2> /dev/null | sort 107252995Sdteske ) 108252995Sdteske 109252995Sdteske # Conflate lists, removing duplicates 110252995Sdteske cmd_list=$( printf "%s\n%s\n" \ 111252995Sdteske "$cmd_list" "$alt_cmd_list" | sort -u ) 112252995Sdteske fi 113252995Sdteske 114252995Sdteske # 115252995Sdteske # Determine the longest command-length (in characters) 116252995Sdteske # 117252995Sdteske local longest_cmd 118252995Sdteske longest_cmd=$( echo "$cmd_list" | f_longest_line_length ) 119252995Sdteske f_dprintf "longest_cmd=[%s]" "$longest_cmd" 120252995Sdteske 121252995Sdteske # 122252995Sdteske # Determine the maximum width of terminal/console 123252995Sdteske # 124252995Sdteske local max_size="$( stty size 2> /dev/null )" 125252995Sdteske : ${max_size:="24 80"} 126252995Sdteske local max_width="${max_size#*[$IFS]}" 127252995Sdteske f_dprintf "max_width=[%s]" "$max_width" 128252995Sdteske 129252995Sdteske # 130252995Sdteske # Using the longest command-length as the width of a single column, 131252995Sdteske # determine if we can use more than one column to display commands. 132252995Sdteske # 133252995Sdteske local x=$longest_cmd ncols=1 134252995Sdteske x=$(( $x + 8 )) # Accomodate leading tab character 135252995Sdteske x=$(( $x + 3 + $longest_cmd )) # Preload end of next column 136252995Sdteske while [ $x -lt $max_width ]; do 137252995Sdteske ncols=$(( $ncols + 1 )) 138252995Sdteske x=$(( $x + 3 + $longest_cmd )) 139252995Sdteske done 140252995Sdteske f_dprintf "ncols=[%u] x=[%u]" $ncols $x 141252995Sdteske 142252995Sdteske # 143252995Sdteske # Re-format the command-list into multiple columns 144252995Sdteske # 145252995Sdteske cmd_list=$( eval "$( echo "$cmd_list" | 146252995Sdteske awk -v ncols=$ncols -v size=$longest_cmd ' 147252995Sdteske BEGIN { 148252995Sdteske n = 0 149252995Sdteske row_item[1] = "" 150252995Sdteske } 151252995Sdteske function print_row() 152252995Sdteske { 153252995Sdteske fmt = "printf \"\\t%-" size "s" 154252995Sdteske for (i = 1; i < cur_col; i++) 155252995Sdteske fmt = fmt " %-" size "s" 156252995Sdteske fmt = fmt "\\n\"" 157252995Sdteske printf "%s", fmt 158252995Sdteske for (i = 1; i <= cur_col; i++) 159252995Sdteske printf " \"%s\"", row_item[i] 160252995Sdteske print "" 161252995Sdteske } 162252995Sdteske { 163252995Sdteske n++ 164252995Sdteske cur_col = (( n - 1 ) % ncols ) + 1 165252995Sdteske printf "f_dprintf \"row_item[%u]=[%%s]\" \"%s\"\n", 166252995Sdteske cur_col, $0 167252995Sdteske row_item[cur_col] = $0 168252995Sdteske if ( cur_col == ncols ) print_row() 169252995Sdteske } 170252995Sdteske END { 171252995Sdteske if ( cur_col < ncols ) print_row() 172252995Sdteske }' )" 173252995Sdteske ) 174252995Sdteske 175252995Sdteske f_usage $BSDCFG_LIBE/USAGE \ 176252995Sdteske "PROGRAM_NAME" "$pgm" \ 177252995Sdteske "COMMAND_LIST" "$cmd_list" 178252995Sdteske 179252995Sdteske # Never reached 180252995Sdteske} 181252995Sdteske 182252995Sdteske# dialog_menu_main 183252995Sdteske# 184252995Sdteske# Display the dialog(1)-based application main menu. 185252995Sdteske# 186252995Sdteskedialog_menu_main() 187252995Sdteske{ 188252995Sdteske local title="$DIALOG_TITLE" 189252995Sdteske local btitle="$DIALOG_BACKTITLE" 190252995Sdteske local prompt="$msg_menu_text" 191252995Sdteske local menu_list=" 192252995Sdteske 'X' '$msg_exit' '$msg_exit_bsdconfig' 193252995Sdteske '1' '$msg_usage' '$msg_quick_start_how_to_use_this_menu_system' 194252995Sdteske " # END-QUOTE 195252995Sdteske local defaultitem= # Calculated below 196252995Sdteske local hline= 197252995Sdteske 198252995Sdteske # 199252995Sdteske # Pick up the base modules (directories named `[0-9][0-9][0-9].*') 200252995Sdteske # 201252995Sdteske local menuitem menu_title menu_help menu_selection index=2 202252995Sdteske for menuitem in $( cd $BSDCFG_LIBE && ls -d [0-9][0-9][0-9].* ); do 203252995Sdteske [ -f "$BSDCFG_LIBE/$menuitem/INDEX" ] || continue 204252995Sdteske [ $index -lt ${#DIALOG_MENU_TAGS} ] || break 205252995Sdteske 206252995Sdteske menu_program= menu_title= menu_help= 207252995Sdteske f_include_lang $BSDCFG_LIBE/$menuitem/INDEX 208252995Sdteske [ "$menu_program" ] || continue 209252995Sdteske 210252995Sdteske case "$menu_program" in 211252995Sdteske /*) : already fully qualified ;; 212252995Sdteske *) menu_program="$menuitem/$menu_program" 213252995Sdteske esac 214252995Sdteske 215252995Sdteske tag=$( f_substr "$DIALOG_MENU_TAGS" $index 1 ) 216252995Sdteske setvar "menu_program$tag" "$menu_program" 217252995Sdteske 218252995Sdteske f_shell_escape "$menu_title" menu_title 219252995Sdteske f_shell_escape "$menu_help" menu_help 220252995Sdteske menu_list="$menu_list '$tag' '$menu_title' '$menu_help'" 221252995Sdteske 222252995Sdteske index=$(( $index + 1 )) 223252995Sdteske done 224252995Sdteske 225252995Sdteske # 226252995Sdteske # Process the `local' libexec sources. 227252995Sdteske # 228252995Sdteske # Whereas modules in $BSDCFG_LIBE must be named [0-9][0-9][0-9].* 229252995Sdteske # modules in $BSDCFG_LOCAL_LIBE should NOT be named this way (making it 230252995Sdteske # more practical for port-maintainers). 231252995Sdteske # 232252995Sdteske # This also has the fortunate side-effect of making the de-duplication 233252995Sdteske # effort rather simple (because so-called `base' modules must be named 234252995Sdteske # differently than add-on modules). 235252995Sdteske # 236252995Sdteske local separator_added= 237252995Sdteske for menuitem in $( cd "$BSDCFG_LOCAL_LIBE" 2> /dev/null && ls -d * ) 238252995Sdteske do 239252995Sdteske # Skip the module if it looks like a `base' module 240252995Sdteske case "$menuitem" in [0-9][0-9][0-9].*) continue;; esac 241252995Sdteske 242252995Sdteske [ -f "$BSDCFG_LOCAL_LIBE/$menuitem/INDEX" ] || continue 243252995Sdteske [ $index -lt ${#DIALOG_MENU_TAGS} ] || break 244252995Sdteske 245252995Sdteske menu_program= menu_title= menu_help= 246252995Sdteske f_include_lang $BSDCFG_LOCAL_LIBE/$menuitem/INDEX || continue 247252995Sdteske [ "$menu_program" ] || continue 248252995Sdteske 249252995Sdteske if [ ! "$separator_added" ]; then 250252995Sdteske menu_list="$menu_list '-' '-' ''" 251252995Sdteske separator_added=1 252252995Sdteske fi 253252995Sdteske 254252995Sdteske case "$menu_program" in 255252995Sdteske /*) : already fully qualified ;; 256252995Sdteske *) menu_program="$BSDCFG_LOCAL_LIBE/$menuitem/$menu_program" 257252995Sdteske esac 258252995Sdteske 259252995Sdteske tag=$( f_substr "$DIALOG_MENU_TAGS" $index 1 ) 260252995Sdteske setvar "menu_program$tag" "$menu_program" 261252995Sdteske 262252995Sdteske f_shell_escape "$menu_title" menu_title 263252995Sdteske f_shell_escape "$menu_help" menu_help 264252995Sdteske menu_list="$menu_list '$tag' '$menu_title' '$menu_help'" 265252995Sdteske 266252995Sdteske index=$(( $index + 1 )) 267252995Sdteske done 268252995Sdteske 269252995Sdteske local height width rows 270252995Sdteske eval f_dialog_menu_with_help_size height width rows \ 271252995Sdteske \"\$title\" \ 272252995Sdteske \"\$btitle\" \ 273252995Sdteske \"\$prompt\" \ 274252995Sdteske \"\$hline\" \ 275252995Sdteske $menu_list 276252995Sdteske 277252995Sdteske # Obtain default-item from previously stored selection 278252995Sdteske f_dialog_default_fetch defaultitem 279252995Sdteske 280252995Sdteske local menu_choice 281252995Sdteske menu_choice=$( eval $DIALOG \ 282252995Sdteske --clear \ 283252995Sdteske --title \"\$title\" \ 284252995Sdteske --backtitle \"\$btitle\" \ 285252995Sdteske --hline \"\$hline\" \ 286252995Sdteske --item-help \ 287252995Sdteske --ok-label \"\$msg_ok\" \ 288252995Sdteske --cancel-label \"\$msg_exit_bsdconfig\" \ 289252995Sdteske --help-button \ 290252995Sdteske --help-label \"\$msg_help\" \ 291252995Sdteske ${USE_XDIALOG:+--help \"\"} \ 292252995Sdteske --default-item \"\$defaultitem\" \ 293252995Sdteske --menu \"\$prompt\" \ 294252995Sdteske $height $width $rows \ 295252995Sdteske $menu_list \ 296252995Sdteske 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD 297252995Sdteske ) 298252995Sdteske local retval=$? 299252995Sdteske f_dialog_data_sanitize menu_choice 300252995Sdteske f_dialog_menutag_store "$menu_choice" 301252995Sdteske 302252995Sdteske # Only update default-item on success 303263791Sdteske [ $retval -eq $DIALOG_OK ] && f_dialog_default_store "$menu_choice" 304252995Sdteske 305252995Sdteske return $retval 306252995Sdteske} 307252995Sdteske 308252995Sdteske############################################################ MAIN 309252995Sdteske 310252995Sdteske# 311252995Sdteske# If $0 is not "bsdconfig", interpret it either as a keyword to a menuitem or 312252995Sdteske# as a valid resword (see script.subr for additional details about reswords). 313252995Sdteske# 314252995Sdteskeif [ "$pgm" != "bsdconfig" ]; then 315252995Sdteske if indexfile=$( f_index_file "$pgm" ) && 316252995Sdteske cmd=$( f_index_menusel_command "$indexfile" "$pgm" ) 317252995Sdteske then 318263791Sdteske f_dprintf "pgm=[%s] cmd=[%s] *=[%s]" "$pgm" "$cmd" "$*" 319252995Sdteske exec "$cmd" "$@" || exit 1 320252995Sdteske else 321252995Sdteske f_include $BSDCFG_SHARE/script.subr 322252995Sdteske for resword in $RESWORDS; do 323252995Sdteske [ "$pgm" = "$resword" ] || continue 324252995Sdteske # Found a match 325252995Sdteske f_dprintf "pgm=[%s] A valid resWord!" "$pgm" 326263791Sdteske f_dispatch $resword $resword "$@" 327252995Sdteske exit $? 328252995Sdteske done 329252995Sdteske fi 330252995Sdteskefi 331252995Sdteske 332252995Sdteske# 333252995Sdteske# Process command-line arguments 334252995Sdteske# 335252995Sdteskescripts_loaded=0 336252995Sdteskewhile getopts f:h$GETOPTS_STDARGS flag; do 337252995Sdteske case "$flag" in 338252995Sdteske f) [ $scripts_loaded -eq 0 ] && f_include $BSDCFG_SHARE/script.subr 339252995Sdteske f_script_load "$OPTARG" 340252995Sdteske scripts_loaded=$(( $scripts_loaded + 1 )) ;; 341252995Sdteske h|\?) usage ;; 342252995Sdteske esac 343252995Sdteskedone 344263791Sdteskeshift $(( $OPTIND - 1 )) 345252995Sdteske 346252995Sdteske# If we've loaded any scripts, do not continue any further 347252995Sdteske[ $scripts_loaded -gt 0 ] && exit 348252995Sdteske 349252995Sdteske# 350252995Sdteske# Initialize 351252995Sdteske# 352252995Sdteskef_dialog_title "$msg_main_menu" 353252995Sdteske 354252995Sdteske[ "$SECURE" ] && f_mustberoot_init 355252995Sdteske 356252995Sdteske# Incorporate rc-file if it exists 357252995Sdteske[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc" 358252995Sdteske 359252995Sdteske# 360252995Sdteske# If a non-option argument was passed, process it as a menuitem selection... 361252995Sdteske# 362252995Sdteskeif [ "$1" ]; then 363252995Sdteske # 364252995Sdteske # ...unless it's a long-option for usage. 365252995Sdteske # 366252995Sdteske case "$1" in -help|--help|-\?) 367252995Sdteske usage 368252995Sdteske # Not reached 369252995Sdteske esac 370252995Sdteske 371252995Sdteske # 372252995Sdteske # Find the INDEX (possibly i18n) claiming this keyword and get the 373252995Sdteske # command to execute from the menu_selection line. 374252995Sdteske # 375252995Sdteske if ! { indexfile=$( f_index_file "$1" ) && 376252995Sdteske cmd=$( f_index_menusel_command "$indexfile" "$1" ) 377252995Sdteske }; then 378252995Sdteske # no matches, display usage (which shows valid keywords) 379252995Sdteske f_err "%s: %s: $msg_not_found\n" "$pgm" "$1" 380252995Sdteske usage 381252995Sdteske # Not reached 382252995Sdteske fi 383252995Sdteske 384263791Sdteske f_dprintf "cmd=[%s] *=[%s]" "$cmd" "$*" 385252995Sdteske shift 386252995Sdteske exec $cmd ${USE_XDIALOG:+-X} "$@" || exit 1 387252995Sdteske # Not reached 388252995Sdteskefi 389252995Sdteske 390252995Sdteske# 391252995Sdteske# Launch application main menu 392252995Sdteske# 393252995Sdteskewhile :; do 394252995Sdteske dialog_menu_main 395252995Sdteske retval=$? 396252995Sdteske f_dialog_menutag_fetch mtag 397252995Sdteske f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" 398252995Sdteske 399263791Sdteske if [ $retval -eq $DIALOG_HELP ]; then 400252995Sdteske f_show_help "$BSDCONFIG_HELPFILE" 401252995Sdteske continue 402263791Sdteske elif [ $retval -ne $DIALOG_OK ]; then 403252995Sdteske f_die 404252995Sdteske fi 405252995Sdteske 406252995Sdteske case "$mtag" in 407252995Sdteske X) break ;; 408252995Sdteske 1) # Usage 409252995Sdteske f_show_help "$USAGE_HELPFILE" 410252995Sdteske continue 411252995Sdteske esac 412252995Sdteske 413252995Sdteske # Anything else is a dynamically loaded menuitem 414252995Sdteske 415252995Sdteske f_getvar menu_program$mtag menu_program 416252995Sdteske case "$menu_program" in 417252995Sdteske /*) cmd="$menu_program" ;; 418252995Sdteske *) cmd="$BSDCFG_LIBE/$menu_program" 419252995Sdteske esac 420252995Sdteske f_dprintf "cmd=[%s]" "$cmd" 421252995Sdteske $cmd ${USE_XDIALOG:+-X} 422252995Sdteskedone 423252995Sdteske 424252995Sdteskeexit $SUCCESS 425252995Sdteske 426252995Sdteske################################################################################ 427252995Sdteske# END 428252995Sdteske################################################################################ 429