# vyatta configuration mode command interpreter functions # **** License **** # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # A copy of the GNU General Public License is available as # `/usr/share/common-licenses/GPL' in the Debian GNU/Linux distribution # or on the World Wide Web at `http://www.gnu.org/copyleft/gpl.html'. # You can also obtain it by writing to the Free Software Foundation, # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, # MA 02110-1301, USA. # # Author: Vyatta # Description: Command interpreter functions for config mode # # **** End License **** ### Top level commands and help ### _vyatta_cfg_cmds=( "confirm" \ "comment" \ "commit" \ "commit-confirm" \ "compare" \ "copy" \ "delete" \ "discard" \ "edit" \ "exit" \ "load" \ "merge" \ "rename" \ "rollback" \ "rollback-soft" \ "run" \ "save" \ "set" \ "show" ) _vyatta_cfg_helps=( \ "Confirm prior commit-confirm" \ "Add comment to this configuration element" \ "Commit the current set of changes" \ "Commit the current set of changes with 'confirm' required" \ "Compare configuration revisions" \ "Copy a configuration element" \ "Delete a configuration element" \ "Discard uncommitted changes" \ "Edit a sub-element" \ "Exit from this configuration level" \ "Load configuration from a file and replace running configuration" \ "Load configuration from a file and merge running configuration" \ "Rename a configuration element" \ "Rollback to a prior config revision (requires reboot)" \ "Rollback to a prior config revision (without reboot)" \ "Run an operational-mode command" \ "Save configuration to a file" \ "Set the value of a parameter or create a new element" \ "Show the configuration (default values may be suppressed)" \ ) ### End Top level commands and help ### vyatta_cfg_expand_top_level () { local cmd=$1 local -a filtered_cmds=() get_prefix_filtered_list ${cmd} _vyatta_cfg_cmds filtered_cmds local found is_elem_of "${cmd}" _vyatta_cfg_cmds found=$? local fcmd if [[ "${#filtered_cmds[@]}" == "1" || "$found" == "0" ]]; then if [[ "${#filtered_cmds[@]}" == "1" ]]; then fcmd=${filtered_cmds[0]} else fcmd=$cmd fi else fcmd=$cmd fi echo $fcmd } ### Top level command wrappers ### vyatta_config_show () { local -a opts=() local -a args=() for arg in "$@"; do if [ "$arg" == "-all" ]; then opts+=('--show-show-defaults') else args+=("$arg") fi done cli-shell-api "${opts[@]}" -- showCfg "${args[@]}" \ | eval "${VYATTA_PAGER:-cat}" } vyatta_config_commit () { if ! vyatta_cli_shell_api sessionChanged; then echo "No configuration changes to commit" return 1; fi local comment="commit" local next=0 local -a args=() for arg in "$@"; do if [ "$next" == "1" ]; then comment=$arg next=0; elif [ "$arg" == "comment" ]; then next=1 elif [ "$arg" == "confirm" ]; then echo Use commit-confirm command return 1; else args[${#args[@]}]="$arg" fi done export COMMIT_COMMENT="$comment" export COMMIT_VIA=cli /opt/vyatta/sbin/my_commit "${args[@]}" 2>&1 unset COMMIT_VIA unset COMMIT_COMMENT } vyatta_config_commit-confirm () { if ! vyatta_cli_shell_api sessionChanged; then echo "No configuration changes to commit" return 1; fi local -a args=() local first=1 local minutes=10 for arg in "$@"; do if [ "$first" = "1" ]; then if [[ $arg = *[[:digit:]]* ]]; then minutes=$arg else args[${#args[@]}]="$arg" fi first=0 else args[${#args[@]}]="$arg" fi done cmd="${vyos_bin_dir}/config-mgmt commit_confirm -t=$minutes" eval "sudo sg vyattacfg \"$cmd\" " if [ $? = 0 ]; then export IN_COMMIT_CONFIRM=t vyatta_config_commit "$@" unset IN_COMMIT_CONFIRM fi } vyatta_config_confirm () { ${vyos_bin_dir}/config-mgmt confirm } vyatta_config_compare () { local -a comp=( "saved" ) local -a filtered=() get_prefix_filtered_list $1 comp filtered if [[ "${filtered[0]}" == "saved" ]]; then ${vyos_bin_dir}/config-mgmt compare --saved else ${vyos_bin_dir}/config-mgmt wrap_compare --options "$@" | eval "${VYATTA_PAGER:-cat}" fi } vyatta_config_save () { if vyatta_cli_shell_api sessionChanged; then echo -e "Warning: you have uncommitted changes that will not be saved.\n" fi # return to top level. reset_edit_level # transform individual args into quoted strings local arg='' local save_cmd="${vyos_libexec_dir}/vyos-save-config.py" for arg in "$@"; do save_cmd+=" '$arg'" done eval "sudo sg vyattacfg \"umask 0002 ; $save_cmd\"" vyatta_cli_shell_api unmarkSessionUnsaved } reboot () { echo "Exit from configure mode before rebooting." } poweroff () { echo "Exit from configure mode before shutting down." } vyatta_config_rollback () { if [ $# != 1 ]; then echo "Error: must include a revision # to rollback to" return 1; fi sudo ${vyos_bin_dir}/config-mgmt rollback --rev "$@" } vyatta_config_rollback-soft () { if [ $# != 1 ]; then echo "Error: must include a revision # to rollback to" return 1; fi ${vyos_bin_dir}/config-mgmt rollback_soft --rev "$@" } shutdown () { echo "Exit from configure mode before shutting down system." } reset_edit_level () { vyatta_cli_shell_api getEditResetEnv return $? } vyatta_config_load () { # don't load if there are uncommitted changes. if vyatta_cli_shell_api sessionChanged; then echo "Cannot load: configuration modified." echo "Commit or discard the changes before loading a config file." return 1 fi # return to top level. reset_edit_level ${vyos_libexec_dir}/vyos-load-config.py "$@" } vyatta_config_merge () { # don't load if there are uncommitted changes. if vyatta_cli_shell_api sessionChanged; then echo "Cannot merge: configuration modified." echo "Commit or discard the changes before merging a config file." return 1 fi # return to top level. reset_edit_level ${vyos_libexec_dir}/vyos-merge-config.py "$@" } top () { if vyatta_cli_shell_api editLevelAtRoot; then echo "Already at the top level" return 0 fi # go to the top level. reset_edit_level } vyatta_config_edit () { vyatta_cli_shell_api getEditEnv "$@" return $? } up () { vyatta_cli_shell_api getEditUpEnv "$@" return $? } really_exit() { if vyatta_cli_shell_api sessionUnsaved; then echo "Warning: configuration changes have not been saved." fi vyatta_cli_shell_api teardownSession unset _OFR_CONFIGURE builtin exit 0 } vyatta_config_exit () { local discard local -a comp=( "discard" ) local -a filtered=() get_prefix_filtered_list $1 comp filtered if [ $# == 0 ]; then discard=0 elif [ $# == 1 ] && [ "${filtered[0]}" == "discard" ]; then discard=1 else echo "Invalid argument \"$*\" for 'exit'" return 1 fi if vyatta_cli_shell_api editLevelAtRoot; then # we are at the root level. check if we can really exit. if vyatta_cli_shell_api sessionChanged; then if (( ! discard )); then echo "Cannot exit: configuration modified." echo "Use 'exit discard' to discard the changes and exit." return 1 fi fi really_exit fi # "exit" to the root level. reset_edit_level } # run op mode commands vyatta_config_run () { if [ $# == 0 ]; then echo -e "\n Incomplete command: run\n" return 1 fi if [[ "set" =~ "$1" ]]; then _vyatta_op_run "$@" elif [[ "$1" =~ "/" ]]; then local args=("$@") ${args[0]} "${args[@]:1}" else /opt/vyatta/bin/vyatta-op-cmd-wrapper "$@" fi } ### End Top level command wrappers ### ### Top level wrappers ### vyatta_cfg_cmd_run () { local cmd=$1 local output='' if [[ "$cmd" == "edit" ]]; then vyatta_config_edit "${@:2}" elif [[ "$cmd" == "show" ]]; then vyatta_config_show "${@:2}" else cmd="/opt/vyatta/sbin/my_$cmd" output=$($cmd "${@:2}") fi vyatta_cfg_print_output "$output" } vyatta_cfg_print_output () { local output=$1 if [[ ! -z "${output}" ]];then output=$(echo "$output" | sed -e 's/^/ /') echo -ne "\n${output}\n\n" | eval "${VYATTA_PAGER:-cat}" fi } vyatta_cfg_validate_cmd () { local cmd=$1 local -a expanded_api_args=( "$@" ) local editlvl=$(cli-shell-api getEditLevelStr) local path='' local opath='' for arg in "${expanded_api_args[@]:1}"; do if [[ "$path" == '' ]]; then path="$arg" else path="$path $arg" fi if ! cli-shell-api validateTmplPath -- ${editlvl} ${path}; then _cli_shell_api_comp_values=() vyatta_cli_shell_api getCompletionEnv $cmd ${path} if [[ "${#_cli_shell_api_comp_values[@]}" != "1" && "${#_cli_shell_api_comp_values[@]}" != "0" ]]; then local -a _get_help_text_items=( "${_cli_shell_api_hitems[@]}" ) local -a _get_help_text_helps=( "${_cli_shell_api_hstrs[@]}" ) local vyatta_help_text='' if [[ $opath == '' ]]; then echo -ne "\n Configuration path: [$arg] is ambiguous\n" >&2 else echo -ne "\n Configuration path: $opath [$arg] is ambiguous\n" >&2 fi get_help_text echo -e "$vyatta_help_text\n" | sed 's/^P/ P/' echo -e " ${cmd^} failed\n" break else if [[ $opath == '' ]]; then echo -ne "\n Configuration path: [$arg] is not valid\n ${cmd^} failed\n\n" >&2 else echo -ne "\n Configuration path: $opath [$arg] is not valid\n ${cmd^} failed\n\n" >&2 fi break fi else opath=$path fi done } vyatta_config_copy () { local cmd=$1 if [[ "${#@}" == "1" ]]; then vyatta_cfg_cmd_run $cmd return fi local -a args=( "$@" ) local -a param1=( "$cmd" ${args[@]:1:2} ) local -a param2=( "$cmd" ${args[@]:4:5} ) local editlvl=$(cli-shell-api getEditLevelStr) expanded_api_args=( ) vyatta_config_expand_compwords "${param1[@]}" param1=( "${expanded_api_args[@]}" ) expanded_api_args=( ) vyatta_config_expand_compwords "${param2[@]}" param2=( "${expanded_api_args[@]}" ) if [[ "${args[3]}" != "to" ]]; then echo -ne "\n Invalid command: $cmd ${param1[@]:1} ${args[3]} ${param2[@]:1}\n\n" >&2 elif cli-shell-api validateTmplPath -- ${editlvl[*]} "${param1[@]:1}" && cli-shell-api validateTmplPath -- ${editlvl[*]} "${param2[@]:1}" ; then cmd="/opt/vyatta/sbin/my_$cmd" output=$(eval "$cmd ${param1[@]:1} to ${param2[@]:1} | sed -e 's/^/ /'") if [[ ! -z "${output}" ]];then echo -ne "\n${output}\n\n" fi else if ! cli-shell-api validateTmplPath -- ${editlvl[*]} "${param1[@]:1}"; then _cli_shell_api_comp_values=() vyatta_cli_shell_api getCompletionEnv $cmd ${param1[1]} if [[ "${#_cli_shell_api_comp_values[@]}" != "1" && "${#_cli_shell_api_comp_values[@]}" != "0" ]]; then echo -ne "\n Ambiguous command: $cmd [${param1[1]}]\n" >&2 echo -ne "\n Possible completions: ${_cli_shell_api_comp_values[@]}\n\n" >&2 else echo -ne "\n Invalid command: $cmd [${param1[1]}]\n\n" >&2 fi elif ! cli-shell-api validateTmplPath -- ${editlvl[*]} "${param1[@]:2}"; then _cli_shell_api_comp_values=() vyatta_cli_shell_api getCompletionEnv $cmd "${param2[1]}" if [[ "${#_cli_shell_api_comp_values[@]}" != "1" && "${#_cli_shell_api_comp_values[@]}" != "0" ]]; then echo -ne "\n Ambiguous command: $cmd ${param2[@]:1} to [${param2[1]}]\n" >&2 echo -ne "\n Possible completions: ${_cli_shell_api_comp_values[@]}\n\n" >&2 else echo -ne "\n Invalid command: $cmd ${param1[@]:1} to [${param2[1]}]\n\n" >&2 fi else echo -ne "\n Invalid command: $cmd ${param1[@]:1} to ${param2[@]:1}\n\n" >&2 fi fi } vyatta_config_comment () { local cmd=$1 if [[ "${#@}" == "1" ]]; then vyatta_cfg_cmd_run $cmd return fi # change the ifs so we can extract the entire comment local -a args=( "$@" ) # extract the comment local comment="'${args[$[${#args[@]}-1]]}'" args=( "${args[@]:0:$[${#args[@]}-1]}" ) local -a expanded_api_args=() # expand the comment command local editlvl=$(cli-shell-api getEditLevelStr) vyatta_config_expand_compwords "${args[@]}" if [[ "$#" != "${#expanded_api_args[@]}" ]]; then expanded_api_args+=( $comment ) fi # use the standard run function with the comment expansion output=$(eval "/opt/vyatta/sbin/my_${expanded_api_args[0]} ${expanded_api_args[@]:1}") vyatta_cfg_print_output "$output" } vyatta_cfg_cmd () { # commands that need expanded paths get called through here local cmd=$1 if [[ "$#" == "1" ]]; then vyatta_cfg_cmd_run $cmd return fi local -a args=( "$@" ) local -a expanded_api_args=() local editlvl=$(cli-shell-api getEditLevelStr) vyatta_config_expand_compwords "${args[@]}" if [[ "${expanded_api_args[@]:$[${#expanded_api_args[@]}-1]}" == "-all" ]] && [[ "${expanded_api_args[0]}" == "show" ]]; then if [[ $[${#expanded_api_args[@]}-2] -eq 0 ]]; then vyatta_cfg_cmd_run "${expanded_api_args[@]}" elif cli-shell-api validateTmplPath -- ${editlvl[*]} \ "${expanded_api_args[@]:1:$[${#expanded_api_args[@]}-2]}"; then vyatta_cfg_cmd_run "${expanded_api_args[@]}" else vyatta_cfg_validate_cmd "${expanded_api_args[@]}" fi elif cli-shell-api validateTmplPath -- ${editlvl[*]} "${expanded_api_args[@]:1}"; then vyatta_cfg_cmd_run "${expanded_api_args[@]}" else # find broken portion of command vyatta_cfg_validate_cmd "${expanded_api_args[@]}" fi } ### Top level wrappers ### ### Main run command ### vyatta_cfg_run () { # if run with bash builtin "set -/+*" run set and return # this happens when a different completion script runs eval "set ..." # (VyOS T1604) if [[ "$1" == "set" && "$2" =~ ^(-|\+).* ]]; then set "${@:2}" return fi # validate top level command and execute proper function local cmd=$1 local -a args=( "$@" ) local -a filtered_cmds get_prefix_filtered_list $cmd _vyatta_cfg_cmds filtered_cmds local found is_elem_of "${cmd}" _vyatta_cfg_cmds found=$? stty echo 2> /dev/null # turn echo on, this is a workaround for bug 7570 # not a fix we need to look at why the readline library # is getting confused on paged help text. if [[ "${#filtered_cmds[@]}" == "0" ]]; then echo -ne "\n Invalid command: [$cmd]\n\n" >&2 return 1 elif [[ "${#filtered_cmds[@]}" != "1" && "$found" == "1" ]]; then echo -ne "\n Ambiguous command: [$cmd]\n" >&2 local -a fitems=() local -a fstrs=() local -a _get_help_text_items=( "${_vyatta_cfg_cmds[@]}" ) local -a _get_help_text_helps=( "${_vyatta_cfg_helps[@]}" ) get_prefix_filtered_list2 "$cmd" \ _get_help_text_items fitems _get_help_text_helps fstrs _get_help_text_items=( "${fitems[@]}" ) _get_help_text_helps=( "${fstrs[@]}" ) get_help_text echo -e "$vyatta_help_text\n" | sed 's/^P/ P/' return 1 fi local fcmd; if is_elem_of "${cmd}" _vyatta_cfg_cmds; then fcmd=$cmd else fcmd=${filtered_cmds[0]} fi case $fcmd in compare) vyatta_config_compare "${@:2}" ;; comment) vyatta_config_comment "${args[@]}" ;; # comment is a special case copy|rename) vyatta_config_copy $fcmd ${@:2} ;; # copy is a special case exit) vyatta_config_exit "${@:2}" ;; run) vyatta_config_run "${@:2}" ;; load) vyatta_config_load "${@:2}" ;; commit) vyatta_config_commit "${@:2}";; confirm) vyatta_config_confirm "${@:2}";; rollback) vyatta_config_rollback "${@:2}";; rollback-soft) vyatta_config_rollback-soft "${@:2}";; commit-confirm) vyatta_config_commit-confirm "${@:2}";; compare) vyatta_config_compare "${@:2}";; save) vyatta_config_save "${@:2}" ;; merge) vyatta_config_merge "${@:2}" ;; *) vyatta_cfg_cmd $fcmd "${@:2}" ;; # commands requiring path expansion must go through here esac } ### Initalize top level command alias and completion functions _vyatta_cfg_init () { # empty and default line compeletion complete -E -F vyatta_config_complete complete -D -F vyatta_config_default_complete # create the top level aliases for the unambiguous portions of the commands # this is the only place we need an entire enumerated list of the subcommands for cmd in "${_vyatta_cfg_cmds[@]}"; do for pos in $(seq 1 ${#cmd}); do case ${cmd:0:$pos} in for|do|done|if|fi|case|while|tr ) continue ;; *) ;; esac local -a filtered_cmds=() get_prefix_filtered_list ${cmd:0:$pos} _vyatta_cfg_cmds filtered_cmds local found is_elem_of "${cmd:0:$pos}" _vyatta_cfg_cmds found=$? if [[ "${#filtered_cmds[@]}" == "1" || "${cmd:0:$pos}" == "$cmd" || "$found" == "0" ]]; then local fcmd if [[ "${#filtered_cmds[@]}" == "1" ]]; then fcmd=${filtered_cmds[0]} elif is_elem_of "${cmd:0:$pos}" _vyatta_cfg_cmds; then fcmd=${cmd:0:$pos} else fcmd=$cmd fi case $fcmd in save|load|merge) complete -F vyatta_loadsave_complete ${cmd:0:$pos} ;; discard|confirm) complete -F vyatta_single_word_complete ${cmd:0:$pos} ;; run) complete -F vyatta_run_complete ${cmd:0:$pos} ;; compare) complete -F vyatta_compare_complete ${cmd:0:$pos} ;; rollback) complete -F vyatta_rollback_complete ${cmd:0:$pos} ;; rollback-soft) complete -F vyatta_rollback-soft_complete ${cmd:0:$pos} ;; commit|commit-confirm) complete -F vyatta_commit_complete ${cmd:0:$pos} ;; *) complete -F vyatta_config_complete ${cmd:0:$pos} ;; esac else complete -F vyatta_config_complete ${cmd:0:$pos} fi eval alias ${cmd:0:$pos}=\'vyatta_cfg_run ${cmd:0:$pos}\' done done shopt -s histverify }