
Also hard-code the VPN types strongswan and fortisslvpn. https://bugzilla.redhat.com/show_bug.cgi?id=1337300
1524 lines
63 KiB
Bash
1524 lines
63 KiB
Bash
# nmcli(1) completion -*- shell-script -*-
|
|
# Originally based on
|
|
# https://github.com/GArik/bash-completion/blob/master/completions/nmcli
|
|
|
|
_nmcli_list()
|
|
{
|
|
COMPREPLY=( $( compgen -W '$1' -- $cur ) )
|
|
}
|
|
|
|
_nmcli_list_nl()
|
|
{
|
|
local IFS=$'\n'
|
|
COMPREPLY=( $( compgen -W '$1' -- $cur ) )
|
|
|
|
# Now escape special characters (spaces, single and double quotes),
|
|
# so that the argument is really regarded a single argument by bash.
|
|
# See http://stackoverflow.com/questions/1146098/properly-handling-spaces-and-quotes-in-bash-completion
|
|
local escaped_single_quote="'\''"
|
|
local i=0
|
|
local entry
|
|
for entry in ${COMPREPLY[*]}
|
|
do
|
|
if [[ "${cur:0:1}" == "'" ]]; then
|
|
# started with single quote, escaping only other single quotes
|
|
# [']bla'bla"bla\bla bla --> [']bla'\''bla"bla\bla bla
|
|
COMPREPLY[$i]="${entry//\'/${escaped_single_quote}}"
|
|
elif [[ "${cur:0:1}" == '"' ]]; then
|
|
# started with double quote, escaping all double quotes and all backslashes
|
|
# ["]bla'bla"bla\bla bla --> ["]bla'bla\"bla\\bla bla
|
|
entry="${entry//\\/\\\\}"
|
|
entry="${entry//\"/\\\"}"
|
|
COMPREPLY[$i]="$entry"
|
|
else
|
|
# no quotes in front, escaping _everything_
|
|
# [ ]bla'bla"bla\bla bla --> [ ]bla\'bla\"bla\\bla\ bla
|
|
entry="${entry//\\/\\\\}"
|
|
entry="${entry//\'/\'}"
|
|
entry="${entry//\"/\\\"}"
|
|
entry="${entry// /\\ }"
|
|
COMPREPLY[$i]="$entry"
|
|
fi
|
|
(( i++ ))
|
|
done
|
|
|
|
# Work-around bash_completion issue where bash interprets a colon
|
|
# as a separator.
|
|
# Colon is escaped here. Change "\\:" back to ":".
|
|
# See also:
|
|
# http://stackoverflow.com/questions/28479216/how-to-give-correct-suggestions-to-tab-complete-when-my-words-contains-colons
|
|
# http://stackoverflow.com/questions/2805412/bash-completion-for-maven-escapes-colon/12495727
|
|
i=0
|
|
for entry in ${COMPREPLY[*]}
|
|
do
|
|
entry="${entry//\\\\:/:}"
|
|
COMPREPLY[$i]=${entry}
|
|
(( i++ ))
|
|
done
|
|
}
|
|
|
|
_nmcli_con_show()
|
|
{
|
|
nmcli -t -f "$1" connection show $2 2> /dev/null
|
|
}
|
|
|
|
_nmcli_wifi_list()
|
|
{
|
|
nmcli -t -f "$1" device wifi list 2>/dev/null
|
|
}
|
|
|
|
_nmcli_dev_status()
|
|
{
|
|
nmcli -t -f "$1" device status 2>/dev/null
|
|
}
|
|
|
|
_nmcli_array_has_value() {
|
|
# expects the name of an array as first parameter and
|
|
# returns true if if one of the remaining arguments is
|
|
# contained in the array ${$1[@]}
|
|
eval "local ARRAY=(\"\${$1[@]}\")"
|
|
local arg a
|
|
shift
|
|
for arg; do
|
|
for a in "${ARRAY[@]}"; do
|
|
if [[ "$a" = "$arg" ]]; then
|
|
return 0
|
|
fi
|
|
done
|
|
done
|
|
return 1
|
|
}
|
|
|
|
_nmcli_array_delete_at()
|
|
{
|
|
eval "local ARRAY=(\"\${$1[@]}\")"
|
|
local i
|
|
local tmp=()
|
|
local lower=$2
|
|
local upper=${3:-$lower}
|
|
|
|
# for some reason the following fails. So this clumsy workaround...
|
|
# A=(a "")
|
|
# echo " >> ${#A[@]}"
|
|
# >> 2
|
|
# A=("${A[@]:1}")
|
|
# echo " >> ${#A[@]}"
|
|
# >> 0
|
|
# ... seriously???
|
|
|
|
for i in "${!ARRAY[@]}"; do
|
|
if [[ "$i" -lt "$2" || "$i" -gt "${3-$2}" ]]; then
|
|
tmp=("${tmp[@]}" "${ARRAY[$i]}")
|
|
fi
|
|
done
|
|
eval "$1=(\"\${tmp[@]}\")"
|
|
}
|
|
|
|
_nmcli_compl_match_option()
|
|
{
|
|
local S="$1"
|
|
local V
|
|
shift
|
|
if [[ "${S:0:2}" == "--" ]]; then
|
|
S="${S:2}"
|
|
elif [[ "${S:0:1}" == "-" ]]; then
|
|
S="${S:1}"
|
|
fi
|
|
for V; do
|
|
case "$V" in
|
|
"$S"*)
|
|
printf "%s" "$V"
|
|
return 0
|
|
;;
|
|
esac
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# OPTIONS appear first at the command line (before the OBJECT).
|
|
# This iterates over the argument list and tries to complete
|
|
# the options. If there are options that are to be completed,
|
|
# zero is returned and completion will be performed.
|
|
# Otherwise it will remove all the option parameters from the ${words[@]}
|
|
# array and return with zero (so that completion of OBJECT can continue).
|
|
_nmcli_compl_OPTIONS()
|
|
{
|
|
local i W
|
|
|
|
for (( ; ; )); do
|
|
if [[ "${#words[@]}" -le 1 ]]; then
|
|
return 1
|
|
fi
|
|
W="$(_nmcli_compl_match_option "${words[0]}" "${LONG_OPTIONS[@]}")"
|
|
if [[ $? != 0 ]]; then
|
|
return 2
|
|
fi
|
|
|
|
# remove the options already seen.
|
|
for i in ${!LONG_OPTIONS[@]}; do
|
|
if [[ "${LONG_OPTIONS[$i]}" == "$W" ]]; then
|
|
_nmcli_array_delete_at LONG_OPTIONS $i
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ "$HELP_ONLY_AS_FIRST" == '1' ]]; then
|
|
for i in ${!LONG_OPTIONS[@]}; do
|
|
if [[ "${LONG_OPTIONS[$i]}" == "help" ]]; then
|
|
_nmcli_array_delete_at LONG_OPTIONS $i
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
case "$W" in
|
|
terse)
|
|
_nmcli_array_delete_at words 0
|
|
;;
|
|
pretty)
|
|
_nmcli_array_delete_at words 0
|
|
;;
|
|
ask)
|
|
_nmcli_array_delete_at words 0
|
|
;;
|
|
show-secrets)
|
|
_nmcli_array_delete_at words 0
|
|
;;
|
|
order)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
local ord="${words[1]}"
|
|
local ord_sta=""
|
|
local i
|
|
local c=()
|
|
|
|
# FIXME: currently the completion considers colon as separator
|
|
# for words. Hence the following doesn't work as $ord will
|
|
# not contain any colons at this point.
|
|
# See https://bugzilla.gnome.org/show_bug.cgi?id=745157
|
|
|
|
if [[ $ord = *":"* ]]; then
|
|
ord_sta="${ord%:*}:"
|
|
ord="${ord##*:}"
|
|
fi
|
|
if [[ $ord = [-+]* ]]; then
|
|
ord_sta="$ord_sta${ord:0:1}"
|
|
fi
|
|
for i in active name type path; do
|
|
c=("${c[@]}" "$ord_sta$i")
|
|
done
|
|
_nmcli_list "${c[*]}"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
active)
|
|
_nmcli_array_delete_at words 0
|
|
;;
|
|
version)
|
|
_nmcli_array_delete_at words 0
|
|
;;
|
|
help)
|
|
_nmcli_array_delete_at words 0
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
HELP_ONLY_AS_FIRST=0
|
|
return 0
|
|
fi
|
|
HELP_ONLY_AS_FIRST=0
|
|
;;
|
|
temporary)
|
|
_nmcli_array_delete_at words 0
|
|
;;
|
|
mode)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "tabular multiline"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
colors)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "yes no auto"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
fields)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "all common
|
|
NAME UUID TYPE TIMESTAMP TIMESTAMP-REAL AUTOCONNECT READONLY DBUS-PATH ACTIVE DEVICE STATE ACTIVE-PATH
|
|
connection 802-3-ethernet 802-1x 802-11-wireless 802-11-wireless-security ipv4 ipv6 serial ppp pppoe gsm cdma bluetooth 802-11-olpc-mesh vpn wimax infiniband bond vlan adsl bridge bridge-port team team-port dcb tun ip-tunnel macvlan vxlan
|
|
GENERAL IP4 DHCP4 IP6 DHCP6 VPN
|
|
profile active"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
escape)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "no yes"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
wait)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list ""
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
*)
|
|
# something unexpected. We are finished with parsing the OPTIONS.
|
|
return 2
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# after the OPTIONS, the OBJECT, the COMMAND and possible the COMMAND_CONNECTION, the syntax for nmcli
|
|
# expects several options with parameters. This function can parse them and remove them from the words array.
|
|
_nmcli_compl_ARGS()
|
|
{
|
|
local aliases=${@}
|
|
local OPTIONS_ALL N_REMOVE_WORDS REMOVE_OPTIONS OPTIONS_HAS_MANDATORY i
|
|
OPTIONS_ALL=("${OPTIONS[@]}")
|
|
OPTIONS_UNKNOWN_OPTION=
|
|
|
|
OPTIONS_HAS_MANDATORY=0
|
|
if [[ "${#OPTIONS_MANDATORY[@]}" -ge 1 ]]; then
|
|
OPTIONS_HAS_MANDATORY=1
|
|
fi
|
|
|
|
for (( ; ; )); do
|
|
if [[ "${#words[@]}" -le 1 ]]; then
|
|
# we have no more words left...
|
|
if [[ ${#OPTIONS[@]} -eq 0 ]]; then
|
|
return 1;
|
|
fi
|
|
if [[ "$COMMAND_ARGS_WAIT_OPTIONS" -ne 1 ]]; then
|
|
_nmcli_list "$(echo "${OPTIONS[@]}")"
|
|
return 0
|
|
fi
|
|
COMMAND_ARGS_WAIT_OPTIONS=0
|
|
return 1
|
|
fi
|
|
if ! _nmcli_array_has_value OPTIONS_ALL "${words[0]}"; then
|
|
# This is an entirely unknown option.
|
|
OPTIONS_UNKNOWN_OPTION="?${words[0]}"
|
|
return 1
|
|
fi
|
|
if [[ "$OPTIONS_HAS_MANDATORY" -eq 1 && "${#OPTIONS_MANDATORY[@]}" -eq 0 ]]; then
|
|
# we had some mandatory options, but they are all satisfied... stop here...
|
|
# This means, that we can continue with more additional options from the NEXT_GROUP.
|
|
return 1
|
|
fi
|
|
|
|
N_REMOVE_WORDS=2
|
|
REMOVE_OPTIONS=("${words[0]}")
|
|
|
|
# change option name to alias
|
|
WORD0="${words[0]}"
|
|
for alias in "${aliases[@]}" ; do
|
|
if [[ "${WORD0}" == ${alias%%:*} ]]; then
|
|
WORD0=${alias#*:}
|
|
break
|
|
fi
|
|
done
|
|
|
|
case "${WORD0}" in
|
|
level)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "OFF ERR WARN INFO DEBUG TRACE"
|
|
return 0
|
|
fi
|
|
;;
|
|
domains)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
local OPTIONS_DOM=(ALL DEFAULT PLATFORM RFKILL ETHER WIFI BT MB DHCP4 DHCP6 PPP WIFI_SCAN IP4 IP6 AUTOIP4 DNS VPN SHARING SUPPLICANT AGENTS SETTINGS SUSPEND CORE DEVICE OLPC WIMAX INFINIBAND FIREWALL ADSL BOND VLAN BRIDGE DBUS_PROPS TEAM CONCHECK DCB DISPATCH)
|
|
if [[ "${words[1]}" != "" ]]; then
|
|
|
|
# split the comma separaeted domain string into its parts LOGD
|
|
local oIFS="$IFS"
|
|
IFS=","
|
|
local LOGD=($(printf '%s' "${words[1]}" | sed 's/\(^\|,\)/,#/g'))
|
|
IFS="$oIFS"
|
|
unset oIFS
|
|
|
|
local LOGDLAST LOGDLAST_IS_OPTION LOGDI i
|
|
# first we iterate over all present domains and remove them from OPTIONS_DOM
|
|
for LOGDI in ${LOGD[@]}; do
|
|
LOGDI="${LOGDI:1}"
|
|
LOGDLAST="$LOGDI"
|
|
LOGDLAST_IS_OPTION=0
|
|
for i in ${!OPTIONS_DOM[*]}; do
|
|
if [[ "${OPTIONS_DOM[$i]}" = "$LOGDI" ]]; then
|
|
LOGDLAST_IS_OPTION=1
|
|
unset OPTIONS_DOM[$i]
|
|
fi
|
|
done
|
|
done
|
|
|
|
local OPTIONS_DOM2=()
|
|
if [[ "$LOGDLAST" = "" ]]; then
|
|
# we have a word that ends with ','. Just append all remaining options.
|
|
for i in ${!OPTIONS_DOM[*]}; do
|
|
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${words[1]}${OPTIONS_DOM[$i]}"
|
|
done
|
|
else
|
|
# if the last option is not "" we keep only those option with the same prefix
|
|
# as the last domain (LOGDLAST)
|
|
for i in ${!OPTIONS_DOM[*]}; do
|
|
if [[ "${OPTIONS_DOM[$i]:0:${#LOGDLAST}}" == "$LOGDLAST" ]]; then
|
|
# modify the option with the present prefix
|
|
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${words[1]}${OPTIONS_DOM[$i]:${#LOGDLAST}}"
|
|
fi
|
|
done
|
|
|
|
if [[ $LOGDLAST_IS_OPTION -eq 1 ]]; then
|
|
# if the last logd itself was a valid iption, ${words[1]} is itself a valid match
|
|
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${words[1]}"
|
|
|
|
# also, add all remaining options by comma separated to the word.
|
|
for i in ${!OPTIONS_DOM[*]}; do
|
|
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${words[1]},${OPTIONS_DOM[$i]}"
|
|
done
|
|
fi
|
|
if [[ ${#OPTIONS_DOM2[@]} -eq 1 ]]; then
|
|
for i in ${!OPTIONS_DOM[*]}; do
|
|
if [[ "$LOGDLAST" != "${OPTIONS_DOM[$i]:0:${#LOGDLAST}}" ]]; then
|
|
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${OPTIONS_DOM2[0]},${OPTIONS_DOM[$i]}"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
fi
|
|
OPTIONS_DOM=(${OPTIONS_DOM2[@]})
|
|
fi
|
|
|
|
_nmcli_list "$(echo "${OPTIONS_DOM[@]}")"
|
|
return 0
|
|
fi
|
|
;;
|
|
type)
|
|
if [[ "$OPTIONS_TYPE" != "" ]]; then
|
|
return 1
|
|
fi
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
if [[ "${words[1]:0:1}" = "8" ]]; then
|
|
# usually we don't want to show the 802-x types (because the shorter aliases are more
|
|
# user friendly. Only complete them, if the current word already starts with an "8".
|
|
_nmcli_list "802-3-ethernet 802-11-wireless 802-11-olpc-mesh"
|
|
else
|
|
_nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe adsl tun ip-tunnel macvlan vxlan"
|
|
fi
|
|
return 0
|
|
fi
|
|
OPTIONS_TYPE="${words[1]}"
|
|
|
|
if [[ "x$OPTIONS_MANDATORY_IFNAME" != x ]]; then
|
|
# the ifname is not a mandatory option for a few connection types...
|
|
# Check, if we have such a 'type' and remove the 'ifname' from the list
|
|
# of mandatory options.
|
|
case "$OPTIONS_TYPE" in
|
|
vl|vla|vlan| \
|
|
bond| \
|
|
team| \
|
|
bridge)
|
|
for i in ${!OPTIONS_MANDATORY[*]}; do
|
|
if [[ "${OPTIONS_MANDATORY[$i]}" = "ifname" ]]; then
|
|
unset OPTIONS_MANDATORY[$i]
|
|
fi
|
|
done
|
|
;;
|
|
*)
|
|
;;
|
|
|
|
esac
|
|
OPTIONS_MANDATORY_IFNAME=
|
|
fi
|
|
;;
|
|
master)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
if [[ "${words[1]}" = "" ]]; then
|
|
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
|
|
else
|
|
_nmcli_list_nl "$(printf "%s\n%s\n%s" "$(_nmcli_dev_status DEVICE)" "$(_nmcli_con_show UUID)")"
|
|
fi
|
|
return 0
|
|
fi
|
|
;;
|
|
dev)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
if [[ "${words[1]}" = "" ]]; then
|
|
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
|
|
else
|
|
_nmcli_list_nl "$(printf "%s\n%s\n%s" "$(_nmcli_dev_status DEVICE)" "$(_nmcli_wifi_list BSSID)" "$(_nmcli_con_show UUID)")"
|
|
fi
|
|
return 0
|
|
fi
|
|
;;
|
|
primary| \
|
|
ifname)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
|
|
return 0
|
|
fi
|
|
;;
|
|
mode)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
case "$OPTIONS_TYPE" in
|
|
"wifi")
|
|
_nmcli_list "infrastructure ap adhoc"
|
|
;;
|
|
"tun")
|
|
_nmcli_list "tun tap"
|
|
;;
|
|
"ip-tunnel")
|
|
_nmcli_list "ipip gre sit isatap vti ip6ip6 ipip6 ip6gre vti6"
|
|
;;
|
|
"macvlan")
|
|
_nmcli_list "vepa bridge private passthru source"
|
|
;;
|
|
"bond"| \
|
|
*)
|
|
_nmcli_list "balance-rr active-backup balance-xor broadcast 802.3ad balance-tlb balance-alb"
|
|
esac
|
|
return 0
|
|
fi
|
|
;;
|
|
transport-mode)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "datagram connected"
|
|
return 0
|
|
fi
|
|
;;
|
|
vpn-type)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "vpnc openvpn pptp openconnect openswan libreswan strongswan ssh l2tp iodine fortisslvpn"
|
|
return 0
|
|
fi
|
|
;;
|
|
slave-type)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "bond team bridge"
|
|
return 0
|
|
fi
|
|
;;
|
|
lacp-rate)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "slow fast"
|
|
return 0
|
|
fi
|
|
;;
|
|
bt-type)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "panu dun-gsm dun-cdma"
|
|
return 0
|
|
fi
|
|
;;
|
|
wep-key-type)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "key phrase"
|
|
return 0
|
|
fi
|
|
;;
|
|
managed| \
|
|
autoconnect| \
|
|
stp| \
|
|
hairpin| \
|
|
save| \
|
|
hidden| \
|
|
private| \
|
|
pi| \
|
|
vnet-hdr| \
|
|
multi-queue|\
|
|
tap)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "yes no"
|
|
return 0
|
|
fi
|
|
;;
|
|
config)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
compopt -o default
|
|
COMPREPLY=()
|
|
return 0
|
|
fi
|
|
;;
|
|
ip4| \
|
|
ip6| \
|
|
gw4| \
|
|
gw6| \
|
|
priority| \
|
|
forward-delay| \
|
|
hello-time| \
|
|
max-age| \
|
|
ageing-time| \
|
|
nsp| \
|
|
path-cost| \
|
|
name| \
|
|
mtu| \
|
|
cloned-mac| \
|
|
addr| \
|
|
parent| \
|
|
miimon| \
|
|
arp-interval| \
|
|
arp-ip-target| \
|
|
downdelay| \
|
|
updelay| \
|
|
p-key| \
|
|
mac| \
|
|
id| \
|
|
flags| \
|
|
ingress| \
|
|
dhcp-anycast| \
|
|
channel| \
|
|
egress| \
|
|
apn| \
|
|
con-name| \
|
|
user| \
|
|
username| \
|
|
service| \
|
|
password)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
return 0
|
|
fi
|
|
;;
|
|
passwd-file| \
|
|
file)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
compopt -o default
|
|
COMPREPLY=()
|
|
return 0
|
|
fi
|
|
;;
|
|
ssid)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list_nl "$(_nmcli_wifi_list SSID)"
|
|
return 0
|
|
fi
|
|
;;
|
|
ap| \
|
|
bssid)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list_nl "$(_nmcli_wifi_list BSSID)"
|
|
return 0
|
|
fi
|
|
;;
|
|
encapsulation)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "vcmux llc"
|
|
return 0
|
|
fi
|
|
;;
|
|
protocol)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "pppoa pppoe ipoatm"
|
|
return 0
|
|
fi
|
|
;;
|
|
band)
|
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
|
_nmcli_list "a bg"
|
|
return 0
|
|
fi
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
|
|
if [[ "${#OPTIONS_NEXT_GROUP[@]}" -gt 0 ]]; then
|
|
if _nmcli_array_has_value OPTIONS_NEXT_GROUP "${words[0]}"; then
|
|
# the current value is from the next group...
|
|
# We back off, because the current group is complete.
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
_nmcli_array_delete_at words 0 $((N_REMOVE_WORDS-1))
|
|
# remove the options already seen.
|
|
for i in ${!OPTIONS[*]}; do
|
|
if [[ "${OPTIONS[$i]}" = "${REMOVE_OPTIONS[0]}" || "${OPTIONS[$i]}" = "${REMOVE_OPTIONS[1]}" ]]; then
|
|
if ! _nmcli_array_has_value OPTIONS_REPEATABLE "${OPTIONS[$i]}" ; then
|
|
unset OPTIONS[$i]
|
|
fi
|
|
fi
|
|
done
|
|
for i in ${!OPTIONS_MANDATORY[*]}; do
|
|
if [[ "${OPTIONS_MANDATORY[$i]}" = "${REMOVE_OPTIONS[0]}" || "${OPTIONS_MANDATORY[$i]}" = "${REMOVE_OPTIONS[1]}" ]]; then
|
|
unset OPTIONS_MANDATORY[$i]
|
|
fi
|
|
done
|
|
done
|
|
}
|
|
|
|
# some commands expect a connection as parameter. This connection can either be given
|
|
# as id|uuid|path|apath. Parse that connection parameter.
|
|
# Actually, it can also ask for a device name, like `nmcli device set [ifname] <ifname>`
|
|
_nmcli_compl_ARGS_CONNECTION()
|
|
{
|
|
if ! _nmcli_array_has_value OPTIONS "${words[0]}"; then
|
|
COMMAND_CONNECTION_TYPE=
|
|
COMMAND_CONNECTION_ID="${words[0]}"
|
|
_nmcli_array_delete_at words 0
|
|
return 1
|
|
fi
|
|
COMMAND_CONNECTION_TYPE="${words[0]}"
|
|
COMMAND_CONNECTION_ID="${words[1]}"
|
|
local CON_TYPE=
|
|
if [[ "x$COMMAND_CONNECTION_ACTIVE" != x ]]; then
|
|
CON_TYPE=--active
|
|
fi
|
|
case "${words[0]}" in
|
|
id)
|
|
if [[ ${#words[@]} -le 2 ]]; then
|
|
_nmcli_list_nl "$(_nmcli_con_show NAME $CON_TYPE)"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
uuid)
|
|
if [[ ${#words[@]} -le 2 ]]; then
|
|
_nmcli_list_nl "$(_nmcli_con_show UUID $CON_TYPE)"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
path)
|
|
if [[ ${#words[@]} -le 2 ]]; then
|
|
_nmcli_list_nl "$(_nmcli_con_show DBUS-PATH $CON_TYPE)"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
apath)
|
|
if [[ ${#words[@]} -le 2 ]]; then
|
|
_nmcli_list_nl "$(_nmcli_con_show ACTIVE-PATH --active)"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
ifname)
|
|
if [[ ${#words[@]} -le 2 ]]; then
|
|
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
;;
|
|
*)
|
|
COMMAND_CONNECTION_TYPE=
|
|
COMMAND_CONNECTION_ID="${words[0]}"
|
|
_nmcli_array_delete_at words 0
|
|
;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
_nmcli_compl_COMMAND() {
|
|
local command="$1"
|
|
shift
|
|
local V=("$@")
|
|
local H=
|
|
if [[ "${command[0]:0:1}" != '-' ]]; then
|
|
H=help
|
|
elif [[ "${command[0]:1:1}" == '-' || "${command[0]}" == "-" ]]; then
|
|
H=--help
|
|
else
|
|
H=-help
|
|
fi
|
|
if [[ "x$COMPL_COMMAND_NO_HELP" == x ]]; then
|
|
V=("${V[@]}" "$H")
|
|
fi
|
|
_nmcli_list "${V[*]}"
|
|
}
|
|
|
|
_nmcli_compl_COMMAND_nl() {
|
|
local command="$1"
|
|
local a="$2"
|
|
shift
|
|
shift
|
|
local V=("$@")
|
|
local H=
|
|
if [[ "${command[0]:0:1}" != '-' ]]; then
|
|
V=("${V[@]/#/--}")
|
|
H=help
|
|
elif [[ "${command[0]:1:1}" == '-' || "${command[0]}" == "-" ]]; then
|
|
V=("${V[@]/#/--}")
|
|
H=--help
|
|
else
|
|
V=("${V[@]/#/-}")
|
|
H=-help
|
|
fi
|
|
if [[ "x$COMPL_COMMAND_NO_HELP" == x ]]; then
|
|
V=("${V[@]}" "$H")
|
|
fi
|
|
local IFS=$'\n'
|
|
V="${V[*]}"
|
|
_nmcli_list_nl "$(printf "%s%s\n%s" "" "$V" "$a")"
|
|
}
|
|
|
|
_nmcli_compl_PROPERTIES()
|
|
{
|
|
while [[ "${#words[@]}" -gt 0 ]]; do
|
|
if [[ ${#words[@]} -le 1 ]]; then
|
|
local PREFIX=""
|
|
|
|
if [[ "${words[0]:0:1}" == [+-] ]]; then
|
|
PREFIX="${words[0]:0:1}"
|
|
fi
|
|
_nmcli_list_nl "$(echo -e 'print\nquit\nyes' |nmcli c edit "$@" 2>/dev/null |awk -F: '/\..*:/ {print "'$PREFIX'"$1}')"
|
|
return 0
|
|
elif [[ ${#words[@]} -le 2 ]]; then
|
|
return 0
|
|
fi
|
|
_nmcli_array_delete_at words 0 1
|
|
done
|
|
_nmcli_list_nl "$(echo -e 'print\nquit\nyes' |nmcli c edit "$@" 2>/dev/null |awk -F: '/\..*:/ {print $1}')"
|
|
}
|
|
|
|
_nmcli()
|
|
{
|
|
local cur prev words cword i
|
|
_init_completion || return
|
|
|
|
# we don't care about any arguments after the current cursor position
|
|
# because we only parse from left to right. So, if there are some arguments
|
|
# right of the cursor, just ignore them. Also don't care about ${words[0]}.
|
|
_nmcli_array_delete_at words $((cword+1)) ${#words[@]}
|
|
_nmcli_array_delete_at words 0
|
|
|
|
# _init_completion returns the words with all the quotes and escaping
|
|
# characters. We don't care about them, drop them at first.
|
|
for i in ${!words[@]}; do
|
|
words[i]="$(printf '%s' "${words[i]}" | xargs printf '%s\n' 2>/dev/null || true)"
|
|
done
|
|
|
|
# In case the cursor is not at the end of the line,
|
|
# $cur consists of spaces that we want do remove.
|
|
# For example: `nmcli connection modify id <TAB> lo`
|
|
if [[ "$cur" =~ ^[[:space:]]+ ]]; then
|
|
cur=''
|
|
fi
|
|
|
|
local OPTIONS_UNKNOWN_OPTION OPTIONS_TYPE OPTIONS_TYPED OPTIONS OPTIONS_MANDATORY COMMAND_ARGS_WAIT_OPTIONS OPTIONS_IP OPTIONS_MANDATORY OPTIONS_NEXT_GROUP OPTIONS_SEP OPTIONS_REPEATABLE
|
|
local COMMAND_CONNECTION_TYPE COMMAND_CONNECTION_ID OPTIONS_MANDATORY_IFNAME HELP_ONLY_AS_FIRST
|
|
local COMMAND_CONNECTION_ACTIVE=""
|
|
|
|
HELP_ONLY_AS_FIRST=
|
|
local LONG_OPTIONS=(terse pretty mode fields colors escape ask show-secrets wait version help)
|
|
_nmcli_compl_OPTIONS
|
|
i=$?
|
|
|
|
if [[ "$HELP_ONLY_AS_FIRST" == '0' ]]; then
|
|
# got a --help. No more completion.
|
|
return 0
|
|
fi
|
|
|
|
case $i in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
# we show for completion either the (remaining) OPTIONS
|
|
# (if the current word starts with a dash) or the OBJECT list
|
|
# otherwise.
|
|
if [[ "${words[0]:0:1}" != '-' ]]; then
|
|
OPTIONS=(help general networking radio connection device agent monitor)
|
|
elif [[ "${words[0]:1:1}" == '-' || "${words[0]}" == "-" ]]; then
|
|
OPTIONS=("${LONG_OPTIONS[@]/#/--}")
|
|
else
|
|
OPTIONS=("${LONG_OPTIONS[@]/#/-}")
|
|
fi
|
|
_nmcli_list "${OPTIONS[*]}"
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
local command="${words[1]}"
|
|
case "${words[0]}" in
|
|
h|he|hel|help)
|
|
;;
|
|
g|ge|gen|gene|gener|genera|general)
|
|
if [[ ${#words[@]} -eq 2 ]]; then
|
|
_nmcli_compl_COMMAND "$command" status permissions logging hostname
|
|
elif [[ ${#words[@]} -gt 2 ]]; then
|
|
case "$command" in
|
|
ho|hos|host|hostn|hostna|hostnam|hostname)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" \
|
|
"$(printf '%s\n%s\n%s\n' \
|
|
"$(nmcli general hostname 2>/dev/null)" \
|
|
"$(cat /etc/hostname 2>/dev/null)" \
|
|
"$(hostnamectl status 2>/dev/null | sed -n '1s/^.\+hostname: \(.\+\)$/\1/p')" \
|
|
"$HOSTNAME")"
|
|
fi
|
|
;;
|
|
l|lo|log|logg|loggi|loggin|logging)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}" level domains
|
|
else
|
|
_nmcli_array_delete_at words 0 1
|
|
OPTIONS=(level domains)
|
|
_nmcli_compl_ARGS
|
|
fi
|
|
;;
|
|
s|st|sta|stat|statu|status| \
|
|
p|pe|per|perm|permi|permis|permiss|permissi|permissio|permission|permissions)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}"
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
;;
|
|
n|ne|net|netw|netwo|networ|network|networki|networkin|networking)
|
|
if [[ ${#words[@]} -eq 2 ]]; then
|
|
_nmcli_compl_COMMAND "$command" on off connectivity
|
|
elif [[ ${#words[@]} -eq 3 ]]; then
|
|
case "$command" in
|
|
c|co|con|conn|conne|connec|connect|connecti|connectiv|connectivi|connectivit|connectivity)
|
|
_nmcli_compl_COMMAND "${words[2]}" "check"
|
|
;;
|
|
esac
|
|
fi
|
|
;;
|
|
r|ra|rad|radi|radio)
|
|
if [[ ${#words[@]} -eq 2 ]]; then
|
|
_nmcli_compl_COMMAND "$command" all wifi wwan
|
|
elif [[ ${#words[@]} -eq 3 ]]; then
|
|
case "$command" in
|
|
a|al|all | w|wi|wif|wifi | ww|wwa|wwan)
|
|
_nmcli_compl_COMMAND "${words[2]}" "on off"
|
|
;;
|
|
esac
|
|
fi
|
|
;;
|
|
c|co|con|conn|conne|connec|connect|connecti|connectio|connection)
|
|
if [[ ${#words[@]} -eq 2 ]]; then
|
|
_nmcli_compl_COMMAND "$command" show up down add modify clone edit delete monitor reload load import export
|
|
elif [[ ${#words[@]} -gt 2 ]]; then
|
|
case "$command" in
|
|
s|sh|sho|show)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME)")" active order
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help active order)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
i=$?
|
|
|
|
if ! _nmcli_array_has_value LONG_OPTIONS active; then
|
|
COMMAND_CONNECTION_ACTIVE=1
|
|
fi
|
|
|
|
case $i in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
if [[ "x$COMMAND_CONNECTION_ACTIVE" = x ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
|
|
|
|
else
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME --active)")" "${LONG_OPTIONS[@]}"
|
|
fi
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
OPTIONS=(id uuid path apath)
|
|
while [[ ${#words[@]} -gt 0 ]]; do
|
|
_nmcli_compl_ARGS_CONNECTION && return 0
|
|
done
|
|
if [[ "x$COMMAND_CONNECTION_ACTIVE" = x ]]; then
|
|
_nmcli_list_nl "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME)")"
|
|
else
|
|
_nmcli_list_nl "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME --active)")"
|
|
fi
|
|
fi
|
|
;;
|
|
u|up)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "ifname\nid\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "ifname\nid\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
local COMMAND_CONNECTION_TYPE=''
|
|
OPTIONS=(ifname id uuid path)
|
|
_nmcli_compl_ARGS_CONNECTION && return 0
|
|
|
|
if [[ "$COMMAND_CONNECTION_TYPE" = "ifname" ]]; then
|
|
OPTIONS=(ap nsp passwd-file)
|
|
else
|
|
OPTIONS=(ifname ap nsp passwd-file)
|
|
fi
|
|
_nmcli_compl_ARGS
|
|
fi
|
|
;;
|
|
d|do|dow|down)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME --active)")"
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME --active)")" "${LONG_OPTIONS[@]}"
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
OPTIONS=(id uuid path apath)
|
|
COMMAND_CONNECTION_ACTIVE=1
|
|
_nmcli_compl_ARGS_CONNECTION && return 0
|
|
fi
|
|
;;
|
|
a|ad|add)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect master slave-type
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect master slave-type
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
OPTIONS_TYPE=
|
|
OPTIONS=(type ifname con-name autoconnect save master slave-type)
|
|
OPTIONS_MANDATORY=(type ifname)
|
|
COMMAND_ARGS_WAIT_OPTIONS=1
|
|
OPTIONS_MANDATORY_IFNAME=1
|
|
_nmcli_compl_ARGS && return 0
|
|
|
|
OPTIONS_MANDATORY_IFNAME=
|
|
if _nmcli_array_has_value OPTIONS "${OPTIONS_MANDATORY[@]}"; then
|
|
# we still have some missing mandatory options...
|
|
if [[ "$OPTIONS_UNKNOWN_OPTION" != '' ]]; then
|
|
if ! _nmcli_array_has_value OPTIONS "${OPTIONS_UNKNOWN_OPTION:1}"; then
|
|
# if we encountered an unknown option while having mandatory
|
|
# options, just return.
|
|
return 0
|
|
fi
|
|
fi
|
|
_nmcli_list "$(echo "${OPTIONS[@]}")"
|
|
return 0
|
|
fi
|
|
|
|
OPTIONS_IP=(ip4 ip6 gw4 gw6)
|
|
OPTIONS_SEP=(--)
|
|
OPTIONS_MANDATORY=()
|
|
case "$OPTIONS_TYPE" in
|
|
802-3|802-3-|802-3-e|802-3-et|802-3-eth|802-3-ethe|802-3-ether|802-3-ethern|802-3-etherne|802-3-ethernet| \
|
|
e|et|eth|ethe|ether|ethern|etherne|ethernet)
|
|
OPTIONS_TYPE=ethernet
|
|
OPTIONS_TYPED=(mac cloned-mac mtu)
|
|
;;
|
|
802-11-w|802-11-wi|802-11-wir|802-11-wire|802-11-wirel|802-11-wirele|802-11-wireles|802-11-wireless| \
|
|
wif|wifi)
|
|
OPTIONS_TYPE=wifi
|
|
OPTIONS_TYPED=(ssid mac cloned-mac mtu mode)
|
|
OPTIONS_MANDATORY=(ssid)
|
|
;;
|
|
wim|wima|wimax)
|
|
OPTIONS_TYPE=wimax
|
|
OPTIONS_TYPED=(mac nsp)
|
|
;;
|
|
g|gs|gsm)
|
|
OPTIONS_TYPE=gsm
|
|
OPTIONS_TYPED=(apn user password)
|
|
OPTIONS_MANDATORY=(apn)
|
|
;;
|
|
c|cd|cdm|cdma)
|
|
OPTIONS_TYPE=cdma
|
|
OPTIONS_TYPED=(user password)
|
|
;;
|
|
i|in|inf|infi|infin|infini|infinib|infiniba|infiniban|infiniband)
|
|
OPTIONS_TYPE=infiniband
|
|
OPTIONS_TYPED=(mac mtu transport-mode parent p-key)
|
|
;;
|
|
bl|blu|blue|bluet|blueto|bluetoo|bluetoot|bluetooth)
|
|
OPTIONS_TYPE=bluetooth
|
|
OPTIONS_TYPED=(addr bt-type)
|
|
;;
|
|
vl|vla|vlan)
|
|
OPTIONS_TYPE=vlan
|
|
OPTIONS_TYPED=(dev id flags ingress egress mtu)
|
|
OPTIONS_MANDATORY=(dev)
|
|
;;
|
|
bond)
|
|
OPTIONS_TYPE=bond
|
|
OPTIONS_TYPED=(mode miimon downdelay updelay arp-interval arp-ip-target primary lacp-rate)
|
|
;;
|
|
team)
|
|
OPTIONS_TYPE=team
|
|
OPTIONS_TYPED=(config)
|
|
;;
|
|
bridge)
|
|
OPTIONS_TYPE=bridge
|
|
OPTIONS_TYPED=(stp priority forward-delay hello-time max-age ageing-time mac)
|
|
;;
|
|
vp|vpn)
|
|
OPTIONS_TYPE=vpn
|
|
OPTIONS_TYPED=(vpn-type user)
|
|
OPTIONS_MANDATORY=(vpn-type)
|
|
;;
|
|
802-11-o|802-11-ol|802-11-olp|802-11-olpc|802-11-olpc-|802-11-olpc-m|802-11-olpc-me|802-11-olpc-mes|802-11-olpc-mesh| \
|
|
o|ol|olp|olpc|olpc-|olpc-m|olpc-me|olpc-mes|olpc-mesh)
|
|
OPTIONS_TYPE=olpc-mesh
|
|
OPTIONS_TYPED=(ssid channel dhcp-anycast)
|
|
OPTIONS_MANDATORY=(ssid)
|
|
;;
|
|
p|pp|ppp|pppo|pppoe)
|
|
OPTIONS_TYPE=pppoe
|
|
OPTIONS_TYPED=(username password service mtu mac)
|
|
OPTIONS_MANDATORY=(username)
|
|
;;
|
|
a|ad|ads|adsl)
|
|
OPTIONS_TYPE=adsl
|
|
OPTIONS_TYPED=(username password protocol encapsulation)
|
|
OPTIONS_MANDATORY=(username protocol)
|
|
;;
|
|
tu|tun)
|
|
OPTIONS_TYPE=tun
|
|
OPTIONS_TYPED=(mode owner group pi vnet-hdr multi-queue)
|
|
OPTIONS_MANDATORY=(mode)
|
|
;;
|
|
ip|ip-|ip-t|ip-tu|ip-tun|ip-tunn|ip-tunne|ip-tunnel)
|
|
OPTIONS_TYPE=ip-tunnel
|
|
OPTIONS_TYPED=(mode remote local dev)
|
|
OPTIONS_MANDATORY=(mode remote)
|
|
;;
|
|
m|ma|mac|macv|macvl|macvla|macvlan)
|
|
OPTIONS_TYPE=macvlan
|
|
OPTIONS_TYPED=(dev mode tap)
|
|
OPTIONS_MANDATORY=(dev mode)
|
|
;;
|
|
vx|vxl|vxla|vxlan)
|
|
OPTIONS_TYPE=vxlan
|
|
OPTIONS_TYPED=(id remote local dev source-port-min source-port-max destination-port)
|
|
OPTIONS_MANDATORY=(id remote)
|
|
;;
|
|
*)
|
|
# for an unknown connection type, we stop completion here
|
|
return 0
|
|
;;
|
|
esac
|
|
if [[ "$COMMAND_ARGS_WAIT_OPTIONS" -ne 1 ]]; then
|
|
# means, we are at the end of options. Nothing more to parse, just show
|
|
# what are the options now.
|
|
if [[ "${#OPTIONS_MANDATORY[@]}" -gt 0 ]]; then
|
|
_nmcli_list "$(echo "${OPTIONS[@]}") $(echo "${OPTIONS_TYPED[@]}")"
|
|
else
|
|
_nmcli_list "$(echo "${OPTIONS[@]}") $(echo "${OPTIONS_TYPED[@]}") $(echo "${OPTIONS_IP[@]}") $(echo "${OPTIONS_SEP[@]}")"
|
|
fi
|
|
return 0
|
|
fi
|
|
if [[ "${#OPTIONS[@]}" -gt 0 ]]; then
|
|
# we still have some options from before, but no mandatory ones. Mix them with OPTIONS_TYPED
|
|
# and continue parsing the options...
|
|
OPTIONS=("${OPTIONS[@]}" "${OPTIONS_TYPED[@]}")
|
|
OPTIONS_NEXT_GROUP=("${OPTIONS_TYPED[@]}")
|
|
_nmcli_compl_ARGS && return 0
|
|
|
|
if [[ "$COMMAND_ARGS_WAIT_OPTIONS" -ne 1 ]]; then
|
|
# means, we are at the end of options. Nothing more to parse, just show
|
|
# what are the options now.
|
|
if [[ "${#OPTIONS_MANDATORY[@]}" -gt 0 ]]; then
|
|
_nmcli_list "$(echo "${OPTIONS[@]}")"
|
|
else
|
|
_nmcli_list "$(echo "${OPTIONS[@]}") $(echo "${OPTIONS_IP[@]}") $(echo "${OPTIONS_SEP[@]}")"
|
|
fi
|
|
return 0
|
|
fi
|
|
|
|
if [[ "$OPTIONS_UNKNOWN_OPTION" != "" ]]; then
|
|
# there was an unknown option specified. Maybe we have to stop with the completion.
|
|
if [[ "${#OPTIONS_MANDATORY[@]}" -gt 0 ]]; then
|
|
# we have an unknown option, but still mandatory ones that must be fullfiled first.
|
|
return 0
|
|
fi
|
|
if ! (_nmcli_array_has_value OPTIONS_IP "${OPTIONS_UNKNOWN_OPTION:1}" ||
|
|
_nmcli_array_has_value OPTIONS_SEP "${OPTIONS_UNKNOWN_OPTION:1}"); then
|
|
# the unknown option is neither an IP option nor a separator.
|
|
return 0
|
|
fi
|
|
# The unknown option is an IP option or a separator, which is fine... continue...
|
|
fi
|
|
|
|
fi
|
|
OPTIONS=("${OPTIONS_TYPED[@]}")
|
|
OPTIONS_NEXT_GROUP=()
|
|
|
|
if [[ "${#OPTIONS_MANDATORY[@]}" -ge 1 ]]; then
|
|
# we have some mandatory options... don't check for IP options yet...
|
|
_nmcli_compl_ARGS && return 0
|
|
|
|
if _nmcli_array_has_value OPTIONS "${OPTIONS_MANDATORY[@]}"; then
|
|
_nmcli_list "$(echo "${OPTIONS[@]}")"
|
|
return 0
|
|
fi
|
|
|
|
if [[ "$OPTIONS_UNKNOWN_OPTION" != "" ]]; then
|
|
if ! (_nmcli_array_has_value OPTIONS_IP "${OPTIONS_UNKNOWN_OPTION:1}" ||
|
|
_nmcli_array_has_value OPTIONS_SEP "${OPTIONS_UNKNOWN_OPTION:1}"); then
|
|
# the unknown option is neither an IP option nor a separator.
|
|
return 0
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
|
|
# no mandatory options... do final completion including IP options
|
|
OPTIONS=("${OPTIONS[@]}" "${OPTIONS_IP[@]}" "${OPTIONS_SEP[@]}")
|
|
OPTIONS_NEXT_GROUP=("${OPTIONS_IP[@]}" "${OPTIONS_SEP[@]}")
|
|
_nmcli_compl_ARGS && return 0
|
|
|
|
if [[ "$OPTIONS_UNKNOWN_OPTION" != "" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
if [[ "$COMMAND_ARGS_WAIT_OPTIONS" -ne 1 ]]; then
|
|
# means, we are at the end of options. Nothing more to parse, just show
|
|
# what are the options now.
|
|
_nmcli_list "$(echo "${OPTIONS[@]}")"
|
|
return 0
|
|
fi
|
|
|
|
|
|
# process the last group of options, as the OPTIONS_TYPED are already handled...
|
|
OPTIONS=("${OPTIONS_IP[@]}" "${OPTIONS_SEP[@]}")
|
|
OPTIONS_NEXT_GROUP=("${OPTIONS_SEP[@]}")
|
|
COMMAND_ARGS_WAIT_OPTIONS=0
|
|
_nmcli_compl_ARGS && return 0
|
|
|
|
_nmcli_array_delete_at words 0
|
|
_nmcli_compl_PROPERTIES type "$OPTIONS_TYPE"
|
|
|
|
return 0
|
|
|
|
fi
|
|
;;
|
|
e|ed|edi|edit)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\ntype\ncon-name\n%s" "$(_nmcli_con_show NAME)")"
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\ntype\ncon-name\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
if [[ "${words[0]}" = 'type' || "${words[0]}" = 'con-name' ]]; then
|
|
OPTIONS=(type con-name)
|
|
_nmcli_compl_ARGS
|
|
else
|
|
OPTIONS=(id uuid path apath)
|
|
_nmcli_compl_ARGS_CONNECTION
|
|
fi
|
|
fi
|
|
;;
|
|
m|mo|mod|modi|modif|modify)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" temporary
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help temporary)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
OPTIONS=(id uuid path)
|
|
_nmcli_compl_ARGS_CONNECTION && return 0
|
|
|
|
_nmcli_compl_PROPERTIES ${COMMAND_CONNECTION_TYPE} "$COMMAND_CONNECTION_ID"
|
|
|
|
return 0
|
|
fi
|
|
;;
|
|
c|cl|clo|clon|clone)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" temporary
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help temporary)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
OPTIONS=(id uuid path)
|
|
_nmcli_compl_ARGS_CONNECTION && return 0
|
|
|
|
return 0
|
|
fi
|
|
;;
|
|
|
|
de|del|dele|delet|delete| \
|
|
mon|moni|monit|monito|monitor)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help)
|
|
_nmcli_compl_OPTIONS
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if ! _nmcli_array_has_value LONG_OPTIONS "help"; then
|
|
return 0
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
OPTIONS=(id uuid path apath)
|
|
while [[ ${#words[@]} -gt 0 ]]; do
|
|
_nmcli_compl_ARGS_CONNECTION && return 0
|
|
done
|
|
_nmcli_list_nl "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
|
|
fi
|
|
;;
|
|
l|lo|loa|load)
|
|
if [[ ${#words[@]} -gt 2 ]]; then
|
|
# we should also complete for help/--help, but who to mix that
|
|
# with file name completion?
|
|
compopt -o default
|
|
COMPREPLY=()
|
|
fi
|
|
;;
|
|
i|im|imp|impo|impor|import)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}" type file --temporary
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help temporary)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}" type file
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
OPTIONS=(type file)
|
|
OPTIONS_MANDATORY=(type file)
|
|
_nmcli_compl_ARGS type:vpn-type
|
|
return 0
|
|
fi
|
|
;;
|
|
e|ex|exp|expo|expor|export)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
|
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
|
_nmcli_array_delete_at words 0 1
|
|
|
|
LONG_OPTIONS=(help)
|
|
HELP_ONLY_AS_FIRST=1
|
|
_nmcli_compl_OPTIONS
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
OPTIONS=(id uuid path)
|
|
_nmcli_compl_ARGS_CONNECTION && return 0
|
|
return 0
|
|
fi
|
|
;;
|
|
|
|
esac
|
|
fi
|
|
;;
|
|
d|de|dev|devi|devic|device)
|
|
if [[ ${#words[@]} -eq 2 ]]; then
|
|
_nmcli_compl_COMMAND "$command" status show connect reapply disconnect delete monitor wifi set lldp
|
|
elif [[ ${#words[@]} -gt 2 ]]; then
|
|
case "$command" in
|
|
s|st|sta|stat|statu|status)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}"
|
|
fi
|
|
;;
|
|
sh|sho|show| \
|
|
r|re|rea|reap|reapp|reappl|reapply| \
|
|
c|co|con|conn|conne|connec|connect)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)"
|
|
fi
|
|
;;
|
|
d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect| \
|
|
de|del|dele|delet|delete| \
|
|
m|mo|mon|moni|monit|monito|monitor)
|
|
if [[ ${#words[@]} -ge 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)"
|
|
fi
|
|
;;
|
|
se|set)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "ifname\n%s" "$(_nmcli_dev_status DEVICE)")"
|
|
else
|
|
_nmcli_array_delete_at words 0 1
|
|
OPTIONS=(ifname)
|
|
_nmcli_compl_ARGS_CONNECTION && return 0
|
|
OPTIONS=(autoconnect managed)
|
|
_nmcli_compl_ARGS
|
|
fi
|
|
;;
|
|
w|wi|wif|wifi)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}" list connect hotspot rescan
|
|
else
|
|
case "${words[2]}" in
|
|
l|li|lis|list)
|
|
_nmcli_array_delete_at words 0 2
|
|
OPTIONS=(ifname bssid)
|
|
_nmcli_compl_ARGS
|
|
;;
|
|
c|co|con|conn|conne|connec|connect)
|
|
if [[ ${#words[@]} -eq 4 ]]; then
|
|
if [[ "${words[3]}" = "" ]]; then
|
|
_nmcli_list_nl "$(_nmcli_wifi_list SSID)"
|
|
else
|
|
_nmcli_list_nl "$(printf "%s\n%s" "$(_nmcli_wifi_list SSID)" "$(_nmcli_wifi_list BSSID)")"
|
|
fi
|
|
else
|
|
_nmcli_array_delete_at words 0 3
|
|
local OPTIONS=(password wep-key-type ifname bssid name private hidden)
|
|
_nmcli_compl_ARGS
|
|
fi
|
|
;;
|
|
h|ho|hot|hots|hotsp|hotspo|hotspot)
|
|
_nmcli_array_delete_at words 0 2
|
|
OPTIONS=(ifname con-name ssid band channel password)
|
|
_nmcli_compl_ARGS
|
|
;;
|
|
r|re|res|resc|resca|rescan)
|
|
_nmcli_array_delete_at words 0 2
|
|
OPTIONS_REPEATABLE=(ssid)
|
|
OPTIONS=(ifname ssid)
|
|
_nmcli_compl_ARGS
|
|
;;
|
|
esac
|
|
fi
|
|
;;
|
|
l|ll|lld|lldp)
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
_nmcli_compl_COMMAND "${words[2]}" list
|
|
else
|
|
case "${words[2]}" in
|
|
l|li|lis|list)
|
|
_nmcli_array_delete_at words 0 2
|
|
OPTIONS=(ifname)
|
|
_nmcli_compl_ARGS
|
|
;;
|
|
esac
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
;;
|
|
a|ag|age|agen|agent)
|
|
if [[ ${#words[@]} -eq 2 ]]; then
|
|
_nmcli_compl_COMMAND "$command" secret polkit all
|
|
fi
|
|
;;
|
|
m|mo|mon|moni|monit|monito|monitor)
|
|
;;
|
|
esac
|
|
|
|
return 0
|
|
} &&
|
|
complete -F _nmcli nmcli
|
|
|
|
# ex: ts=4 sw=4 et filetype=sh
|