diff options
Diffstat (limited to 'contrib/bash_completion.d')
-rw-r--r-- | contrib/bash_completion.d/Makefile.am | 5 | ||||
-rw-r--r-- | contrib/bash_completion.d/zfs | 391 |
2 files changed, 396 insertions, 0 deletions
diff --git a/contrib/bash_completion.d/Makefile.am b/contrib/bash_completion.d/Makefile.am new file mode 100644 index 000000000..4f13af6b3 --- /dev/null +++ b/contrib/bash_completion.d/Makefile.am @@ -0,0 +1,5 @@ +bashcompletiondir = $(sysconfdir)/bash_completion.d + +noinst_DATA = zfs + +EXTRA_DIST = $(noinst_DATA) diff --git a/contrib/bash_completion.d/zfs b/contrib/bash_completion.d/zfs new file mode 100644 index 000000000..914db43cb --- /dev/null +++ b/contrib/bash_completion.d/zfs @@ -0,0 +1,391 @@ +# Copyright (c) 2013, Aneurin Price <[email protected]> + +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: + +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +if [[ -w /dev/zfs ]]; then + __ZFS_CMD="zfs" + __ZPOOL_CMD="zpool" +else + __ZFS_CMD="sudo zfs" + __ZPOOL_CMD="sudo zpool" +fi + +__zfs_get_commands() +{ + $__ZFS_CMD 2>&1 | awk '/^\t[a-z]/ {print $1}' | cut -f1 -d '|' | uniq +} + +__zfs_get_properties() +{ + $__ZFS_CMD get 2>&1 | awk '$2 == "YES" || $2 == "NO" {print $1}'; echo all name space +} + +__zfs_get_editable_properties() +{ + $__ZFS_CMD get 2>&1 | awk '$2 == "YES" {print $1"="}' +} + +__zfs_get_inheritable_properties() +{ + $__ZFS_CMD get 2>&1 | awk '$3 == "YES" {print $1}' +} + +__zfs_list_datasets() +{ + $__ZFS_CMD list -H -o name -t filesystem,volume +} + +__zfs_list_filesystems() +{ + $__ZFS_CMD list -H -o name -t filesystem +} + +__zfs_match_snapshot() +{ + local base_dataset=${cur%@*} + if [[ $base_dataset != $cur ]] + then + $__ZFS_CMD list -H -o name -t snapshot -d 1 $base_dataset + else + $__ZFS_CMD list -H -o name -t filesystem,volume | awk '{print $1"@"}' + fi +} + +__zfs_match_explicit_snapshot() +{ + local base_dataset=${cur%@*} + if [[ $base_dataset != $cur ]] + then + $__ZFS_CMD list -H -o name -t snapshot -d 1 $base_dataset + fi +} + +__zfs_match_multiple_snapshots() +{ + local existing_opts=$(expr "$cur" : '\(.*\)[%,]') + if [[ $existing_opts ]] + then + local base_dataset=${cur%@*} + if [[ $base_dataset != $cur ]] + then + local cur=${cur##*,} + if [[ $cur =~ ^%|%.*% ]] + then + # correct range syntax is start%end + return 1 + fi + local range_start=$(expr "$cur" : '\(.*%\)') + $__ZFS_CMD list -H -o name -t snapshot -d 1 $base_dataset | sed 's$.*@$'$range_start'$g' + fi + else + __zfs_match_explicit_snapshot; __zfs_list_datasets + fi +} + +__zfs_list_volumes() +{ + $__ZFS_CMD list -H -o name -t volume +} + +__zfs_argument_chosen() +{ + local word property + for word in $(seq $((COMP_CWORD-1)) -1 2) + do + local prev="${COMP_WORDS[$word]}" + if [[ ${COMP_WORDS[$word-1]} != -[tos] ]] + then + if [[ "$prev" == [^,]*,* ]] || [[ "$prev" == *[@:]* ]] + then + return 0 + fi + for property in $@ + do + if [[ $prev == "$property" ]] + then + return 0 + fi + done + fi + done + return 1 +} + +__zfs_complete_ordered_arguments() +{ + local list1=$1 + local list2=$2 + local cur=$3 + local extra=$4 + if __zfs_argument_chosen $list1 + then + COMPREPLY=($(compgen -W "$list2 $extra" -- "$cur")) + else + COMPREPLY=($(compgen -W "$list1 $extra" -- "$cur")) + fi +} + +__zfs_complete_multiple_options() +{ + local options=$1 + local cur=$2 + + COMPREPLY=($(compgen -W "$options" -- "${cur##*,}")) + local existing_opts=$(expr "$cur" : '\(.*,\)') + if [[ $existing_opts ]] + then + COMPREPLY=( "${COMPREPLY[@]/#/${existing_opts}}" ) + fi +} + +__zfs_complete_switch() +{ + local options=$1 + if [[ ${cur:0:1} == - ]] + then + COMPREPLY=($(compgen -W "-{$options}" -- "$cur")) + return 0 + else + return 1 + fi +} + +__zfs_complete() +{ + local cur prev cmd cmds + COMPREPLY=() + # Don't split on colon + _get_comp_words_by_ref -n : -c cur -p prev -w COMP_WORDS -i COMP_CWORD + cmd="${COMP_WORDS[1]}" + + if [[ ${prev##*/} == zfs ]] + then + cmds=$(__zfs_get_commands) + COMPREPLY=($(compgen -W "$cmds -?" -- "$cur")) + return 0 + fi + + case "${cmd}" in + clone) + case "${prev}" in + -o) + COMPREPLY=($(compgen -W "$(__zfs_get_editable_properties)" -- "$cur")) + ;; + *) + if ! __zfs_complete_switch "o,p" + then + if __zfs_argument_chosen + then + COMPREPLY=($(compgen -W "$(__zfs_list_datasets)" -- "$cur")) + else + COMPREPLY=($(compgen -W "$(__zfs_match_snapshot)" -- "$cur")) + fi + fi + ;; + esac + ;; + get) + case "${prev}" in + -d) + COMPREPLY=($(compgen -W "" -- "$cur")) + ;; + -t) + __zfs_complete_multiple_options "filesystem volume snapshot all" "$cur" + ;; + -s) + __zfs_complete_multiple_options "local default inherited temporary none" "$cur" + ;; + -o) + __zfs_complete_multiple_options "name property value source received all" "$cur" + ;; + *) + if ! __zfs_complete_switch "H,r,p,d,o,t,s" + then + if __zfs_argument_chosen $(__zfs_get_properties) + then + COMPREPLY=($(compgen -W "$(__zfs_match_explicit_snapshot) $(__zfs_list_datasets)" -- "$cur")) + else + __zfs_complete_multiple_options "$(__zfs_get_properties)" "$cur" + fi + fi + ;; + esac + ;; + inherit) + if ! __zfs_complete_switch "r" + then + __zfs_complete_ordered_arguments "$(__zfs_get_inheritable_properties)" "$(__zfs_match_explicit_snapshot) $(__zfs_list_datasets)" $cur + fi + ;; + list) + case "${prev}" in + -d) + COMPREPLY=($(compgen -W "" -- "$cur")) + ;; + -t) + __zfs_complete_multiple_options "filesystem volume snapshot all" "$cur" + ;; + -o) + __zfs_complete_multiple_options "$(__zfs_get_properties)" "$cur" + ;; + -s|-S) + COMPREPLY=($(compgen -W "$(__zfs_get_properties)" -- "$cur")) + ;; + *) + if ! __zfs_complete_switch "H,r,d,o,t,s,S" + then + COMPREPLY=($(compgen -W "$(__zfs_match_explicit_snapshot) $(__zfs_list_datasets)" -- "$cur")) + fi + ;; + esac + ;; + promote) + COMPREPLY=($(compgen -W "$(__zfs_list_filesystems)" -- "$cur")) + ;; + rollback) + if ! __zfs_complete_switch "r,R,f" + then + COMPREPLY=($(compgen -W "$(__zfs_match_snapshot)" -- "$cur")) + fi + ;; + send) + if ! __zfs_complete_switch "d,n,P,p,R,v,i,I" + then + COMPREPLY=($(compgen -W "$(__zfs_match_snapshot)" -- "$cur")) + fi + ;; + snapshot) + case "${prev}" in + -o) + COMPREPLY=($(compgen -W "$(__zfs_get_editable_properties)" -- "$cur")) + ;; + *) + if ! __zfs_complete_switch "o,r" + then + COMPREPLY=($(compgen -W "$(__zfs_list_datasets | awk '{print $1"@"}')" -- "$cur")) + fi + ;; + esac + ;; + set) + __zfs_complete_ordered_arguments "$(__zfs_get_editable_properties)" "$(__zfs_match_explicit_snapshot) $(__zfs_list_datasets)" $cur + ;; + upgrade) + case "${prev}" in + -a|-V|-v) + COMPREPLY=($(compgen -W "" -- "$cur")) + ;; + *) + if ! __zfs_complete_switch "a,V,v,r" + then + COMPREPLY=($(compgen -W "$(__zfs_list_filesystems)" -- "$cur")) + fi + ;; + esac + ;; + destroy) + if ! __zfs_complete_switch "d,f,n,p,R,r,v" + then + __zfs_complete_multiple_options "$(__zfs_match_multiple_snapshots)" $cur + fi + ;; + *) + COMPREPLY=($(compgen -W "$(__zfs_match_explicit_snapshot) $(__zfs_list_datasets)" -- "$cur")) + ;; + esac + __ltrim_colon_completions "$cur" + return 0 +} + +__zpool_get_commands() +{ + $__ZPOOL_CMD 2>&1 | awk '/^\t[a-z]/ {print $1}' | uniq +} + +__zpool_get_properties() +{ + $__ZPOOL_CMD get 2>&1 | awk '$2 == "YES" || $2 == "NO" {print $1}'; echo all +} + +__zpool_get_editable_properties() +{ + $__ZPOOL_CMD get 2>&1 | awk '$2 == "YES" {print $1"="}' +} + +__zpool_list_pools() +{ + $__ZPOOL_CMD list -H -o name +} + +__zpool_complete() +{ + local cur prev cmd cmds + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + cmd="${COMP_WORDS[1]}" + + if [[ ${prev##*/} == zpool ]] + then + cmds=$(__zpool_get_commands) + COMPREPLY=($(compgen -W "$cmds" -- "$cur")) + return 0 + fi + + case "${cmd}" in + get) + __zfs_complete_ordered_arguments "$(__zpool_get_properties)" "$(__zpool_list_pools)" $cur + return 0 + ;; + import) + if [[ $prev == -d ]] + then + _filedir -d + else + COMPREPLY=($(compgen -W "$(__zpool_list_pools) -d" -- "$cur")) + fi + return 0 + ;; + set) + __zfs_complete_ordered_arguments "$(__zpool_get_editable_properties)" "$(__zpool_list_pools)" $cur + return 0 + ;; + add|attach|clear|create|detach|offline|online|remove|replace) + local pools="$(__zpool_list_pools)" + if __zfs_argument_chosen $pools + then + _filedir + else + COMPREPLY=($(compgen -W "$pools" -- "$cur")) + fi + return 0 + ;; + *) + COMPREPLY=($(compgen -W "$(__zpool_list_pools)" -- "$cur")) + return 0 + ;; + esac + +} + +complete -F __zfs_complete zfs +complete -F __zpool_complete zpool |