From: Michael Tremer Date: Tue, 30 Dec 2014 01:30:40 +0000 (+0000) Subject: Add bash-completion for the network command X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bae373600e3519cee78b44b931289532d4dcffa0;p=people%2Fstevee%2Fnetwork.git Add bash-completion for the network command --- diff --git a/Makefile.am b/Makefile.am index 96d59e42..8a5e4adf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,6 +28,7 @@ AUTOMAKE_OPTIONS = color-tests # keep itermediate files .SECONDARY: +bashcompletiondir= $(datadir)/bash-completion/completions libexecdir = $(prefix)/lib pkgconfigdatadir = $(datadir)/pkgconfig pppdir = $(sysconfdir)/ppp @@ -261,6 +262,11 @@ dist_sysctl_DATA = \ # ------------------------------------------------------------------------------ +dist_bashcompletion_SCRIPTS = \ + src/bash-completion/network + +# ------------------------------------------------------------------------------ + dist_tmpfiles_DATA = \ src/tmpfiles/network diff --git a/src/bash-completion/network b/src/bash-completion/network new file mode 100644 index 00000000..ad6bd958 --- /dev/null +++ b/src/bash-completion/network @@ -0,0 +1,282 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2014 Michael Tremer # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# 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. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### +# network(8) completion + +function _network_find_on_cmdline () { + local word subcommand c=0 + while [ ${c} -lt ${cword} ]; do + word="${words[c]}" + for subcommand in ${1}; do + if [ "${subcommand}" = "${word}" ]; then + echo "${subcommand}" + return + fi + done + ((c++)) + done +} + +function _network_complete_hooks() { + local type="${1}" + + COMPREPLY=( $(compgen -W "$(network raw list-hooks "${type}")" -- "${cur}") ) +} + +function _network_complete_ports() { + COMPREPLY=( $(compgen -W "$(network raw list-ports)" -- "${cur}") ) +} + +function _network_complete_zones() { + COMPREPLY=( $(compgen -W "$(network raw list-zones)" -- "${cur}") ) +} + +function _network_device() { + local words=( $@ ) + + local commands="list $(network raw list-devices)" + local cmd="$(_network_find_on_cmdline "${commands}")" + if [[ -z "${cmd}" ]]; then + COMPREPLY=( $(compgen -W "${commands}" -- "${cur}") ) + return 0 + fi + + local args="${words[@]:1}" + case "${cmd}" in + list) + return 0 + ;; + *) + _network_device_subcommand ${args} + ;; + esac +} + +function _network_device_subcommand() { + local words=( $@ ) + + local commands="discover monitor status unlock ussd" + local cmd="$(_network_find_on_cmdline "${commands}")" + + if [[ -z "${cmd}" ]]; then + COMPREPLY=( $(compgen -W "discover monitor status unlock ussd" \ + -- "${cur}") ) + return 0 + fi + + case "${cmd}" in + ussd) + # TODO + ;; + esac +} + +function _network_port() { + local words=( $@ ) + + local commands="new destroy $(network raw list-ports)" + local cmd="$(_network_find_on_cmdline "${commands}")" + if [[ -z "${cmd}" ]]; then + COMPREPLY=( $(compgen -W "${commands}" -- "${cur}") ) + return 0 + fi + + local args="${words[@]:1}" + case "${cmd}" in + new) + _network_complete_hooks "port" + ;; + destroy) + _network_complete_ports + ;; + *) + local args="${words[@]:1}" + _network_port_subcommand ${args} + ;; + esac +} + +function _network_port_subcommand() { + local words=( $@ ) + + local commands="create down edit remove status up" + local cmd="$(_network_find_on_cmdline "${commands}")" + if [[ -z "${cmd}" ]]; then + COMPREPLY=( $(compgen -W "${commands}" -- "${cur}") ) + return 0 + fi +} + +function _network_settings() { + local words=( $@ ) + + local key keys + for key in $(network raw list-settings); do + keys="${keys} ${key}=" + done + COMPREPLY=( $(compgen -W "${keys}" -- "${cur}") ) +} + +function _network_zone() { + local words=( $@ ) + + local commands="new destroy $(network raw list-zones)" + local cmd="$(_network_find_on_cmdline "${commands}")" + if [[ -z "${cmd}" ]]; then + COMPREPLY=( $(compgen -W "${commands}" -- "${cur}") ) + return 0 + fi + + local args="${words[@]:1}" + case "${cmd}" in + new) + # TODO + return 0 + ;; + destroy) + _network_complete_zones + ;; + *) + local zone="${cmd}" + local args="${words[@]:1}" + _network_zone_subcommand "${zone}" ${args} + ;; + esac +} + +function _network_zone_subcommand() { + local zone="${1}" + shift + + local words=( $@ ) + + local commands="config disable down edit enable port status up" + local cmd="$(_network_find_on_cmdline "${commands}")" + if [[ -z "${cmd}" ]]; then + COMPREPLY=( $(compgen -W "${commands}" -- "${cur}") ) + return 0 + fi + + local args="${words[@]:1}" + case "${cmd}" in + config) + # TODO + ;; + port) + _network_zone_subcommand_port "${zone}" ${args} + ;; + esac +} + +function _network_zone_subcommand_port() { + local zone="${1}" + shift + + local words=( $@ ) + + local commands="attach detach $(network raw list-ports-of-zone "${zone}")" + local cmd="$(_network_find_on_cmdline "${commands}")" + if [[ -z "${cmd}" ]]; then + COMPREPLY=( $(compgen -W "${commands}" -- "${cur}") ) + return 0 + fi + + case "${cmd}" in + attach) + COMPREPLY=( $(compgen -W "$(network raw list-free-ports "${zone}")" \ + -- "${cur}") ) + ;; + detach) + COMPREPLY=( $(compgen -W "$(network raw list-ports-of-zone "${zone}")" \ + -- "${cur}") ) + ;; + *) + local port="${cmd}" + local args="${words[@]:1}" + _network_zone_subcommand_port_subcommand "${zone}" "${port}" ${args} + ;; + esac +} + +function _network_zone_subcommand_port_subcommand() { + local zone="${1}" + local port="${2}" + shift 2 + + local words=( $@ ) + + local commands="edit" + local cmd="$(_network_find_on_cmdline "${commands}")" + if [[ -z "${cmd}" ]]; then + COMPREPLY=( $(compgen -W "${commands}" -- "${cur}") ) + return 0 + fi + + case "${cmd}" in + edit) + # TODO auto-complete the zone-port hook + ;; + esac +} + +function _network() { + local cur prev words cword + _init_completion || return + + local cmd i + for (( i=1; i < ${#words[@]} - 1; i++ )); do + [[ "${words[i]}" = -* ]] && continue + cmd="${words[i]}" && break + done + + if [[ -z "${cmd}" ]]; then + case "${cur}" in + -*) + COMPREPLY=( $(compgen -W "--debug" -- "${cur}") ) + ;; + *) + COMPREPLY=( $(compgen -W "device hostname port settings status zone" \ + -- "${cur}") ) + ;; + esac + + return 0 + fi + + local args="${words[@]:i+1}" + case "${cmd}" in + device) + _network_device ${args} + ;; + port) + _network_port ${args} + ;; + settings) + _network_settings ${args} + ;; + start|stop|status) + # start, stop and status optionally take a zone + _network_complete_zones + ;; + zone) + _network_zone ${args} + ;; + esac +} && complete -F _network network diff --git a/src/functions/functions.hook b/src/functions/functions.hook index 90532973..f8e2b6b5 100644 --- a/src/functions/functions.hook +++ b/src/functions/functions.hook @@ -30,6 +30,22 @@ function hook_dir() { } NETWORK_HOOKS_DIR_ZONES="$(hook_dir zone)" +function hook_list() { + local type="${1}" + assert isoneof type port zone + + local dir="$(hook_dir "${type}")" + assert isset dir + + local hook + for hook in ${dir}/*; do + hook_exists "${hook}" || continue + print "${hook}" + done + + return ${EXIT_OK} +} + function hook_exists() { local type=${1} local hook=${2} diff --git a/src/functions/functions.ports b/src/functions/functions.ports index a6370913..059b8f24 100644 --- a/src/functions/functions.ports +++ b/src/functions/functions.ports @@ -23,6 +23,47 @@ function port_dir() { echo "${NETWORK_CONFIG_DIR}/ports" } +function port_list() { + local port + for port in $(port_dir)/*; do + port="$(basename "${port}")" + if port_exists "${port}"; then + print "${port}" + fi + done +} + +function port_list_in_use() { + local ports_in_use + + # Collect all ports that are attached to a zone + local zone + for zone in $(zones_get_all); do + list_append ports_in_use $(zone_get_ports "${zone}") + done + + # Collect all ports that are enslaved by an other port + local port + for port in $(port_list); do + list_append ports_in_use $(port_get_slaves "${port}") + done + + list_sort ${ports_in_use} +} + +function port_list_free() { + local ports_in_use="$(port_list_in_use)" + + local port + for port in $(port_list); do + if ! list_match "${port}" ${ports_in_use}; then + print "${port}" + fi + done + + return ${EXIT_OK} +} + function port_get_hook() { local port=${1} assert isset port @@ -65,13 +106,7 @@ function port_settings_write() { } function ports_get_all() { - local port - - for port in $(port_dir)/*; do - [ -f "${port}" ] || continue - - basename ${port} - done + port_list } function port_file() { diff --git a/src/functions/functions.settings b/src/functions/functions.settings index 2f2821ff..9e78858f 100644 --- a/src/functions/functions.settings +++ b/src/functions/functions.settings @@ -263,6 +263,10 @@ function network_settings_print() { settings_print ${NETWORK_SETTINGS_FILE_PARAMS} } +function network_settings_list() { + print "${NETWORK_SETTINGS_FILE_PARAMS}" +} + function firewall_settings_read() { settings_read "${FIREWALL_SETTINGS_FILE}" "${FIREWALL_SETTINGS_PARAMS}" } diff --git a/src/network b/src/network index 80ddae0d..ebd1b5c2 100644 --- a/src/network +++ b/src/network @@ -1244,6 +1244,42 @@ function cli_dns_server() { exit ${EXIT_OK} } +function cli_raw() { + local cmd="${1}" + assert isset cmd + shift + + case "${cmd}" in + list-devices) + device_list + ;; + list-free-ports) + port_list_free + ;; + list-hooks) + hook_list $@ + ;; + list-ports) + port_list + ;; + list-ports-of-zone) + zone_get_ports $@ + ;; + list-settings) + network_settings_list + ;; + list-zones) + zones_get_all + ;; + *) + error "No such command: ${cmd}" + exit ${EXIT_ERROR} + ;; + esac + + exit ${EXIT_OK} +} + # Process the given action case "${action}" in init) @@ -1268,6 +1304,10 @@ case "${action}" in cli_help $@ ;; + raw) + cli_raw $@ + ;; + *) error "Invalid command given: ${action}" cli_usage "network help"