| #!/bin/bash |
| |
| # ----------------------------------------------------------------- |
| # ipset set listing wrapper script |
| # |
| # https://github.com/AllKind/ipset_list |
| # https://sourceforge.net/projects/ipset-list/ |
| # ----------------------------------------------------------------- |
| |
| # Copyright (C) 2013-2014 AllKind (AllKind@fastest.cc) |
| # |
| # 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 <http://www.gnu.org/licenses/>. |
| |
| # ----------------------------------------------------------------- |
| # |
| # This is the bash programmable completion for ipset_list |
| # (put it into ~/.bash_completion or /etc/bash_completion.d/) |
| # |
| # ----------------------------------------------------------------- |
| |
| # Name may be modified |
| ipset_list=ipset_list |
| |
| # ----------------------------------------------------------------- |
| |
| # ----------------------------------------------------------------- |
| # DO NOT MODIFY ANYTHING BEYOND THIS LINE! |
| # ----------------------------------------------------------------- |
| |
| shopt -s extglob |
| |
| # ----------------------------------------------------------------- |
| # Functions |
| # ----------------------------------------------------------------- |
| |
| _ipset_list_show_sets() { |
| COMPREPLY=( $( compgen -W '${sets[@]}' -- "$cur" ) ) |
| # dedupe sets listing |
| for ((i=set_index; i < ${#words[@]}-1; i++)); do |
| _ipset_list_remove_reply_entry "${words[i]}" |
| done |
| } |
| |
| _ipset_list_remove_reply_entry() { |
| local -i x |
| while (($#)); do |
| for x in ${!COMPREPLY[@]}; do |
| if [[ ${COMPREPLY[x]} = $1 ]]; then |
| if [[ $_DEBUG_NF_COMPLETION ]]; then |
| printf "removing dupe entry COMPREPLY[$x]: %s\n" \ |
| "${COMPREPLY[x]}" |
| fi |
| unset COMPREPLY[x] |
| break |
| fi |
| done |
| shift |
| done |
| } |
| |
| # ----------------------------------------------------------------- |
| # Main |
| # ----------------------------------------------------------------- |
| |
| _ipset_list_complete() { |
| local -i i=x=got_bashcompl=0 |
| local -i show_all=isolate=show_members=resolve=headers_only=names_only=0 |
| local -i header_operation=set_index=0 |
| local cur prev cword words str_tmp |
| local sets=( $("${ipset_list:-ipset_list}" -n) ) |
| local opts=(-- -? -a -c -d -h -i -m -n -r -s -t -v) |
| local Copts=(-Ca -Cs -Co) |
| local Fopts=(-Fh -Fi -Fg -Fr -Oi) |
| local Hopts=(-Hi -Hr -Hs -Ht -Hv) |
| local Topts=(-Tm -To -Ts) |
| local Xopts=(-Xh -Xg -Xr -Xs -Xo) |
| local arr_types=() |
| |
| : ${PATH:=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin} |
| |
| COMPREPLY=() |
| |
| # expecting _get_comp_words_by_ref() to exist from bash_completion |
| if declare -f _get_comp_words_by_ref &>/dev/null; then got_bashcompl=1 |
| _get_comp_words_by_ref -n : cur prev cword words || return |
| else got_bashcompl=0 # not so neat, but a workaround |
| COMP_WORDBREAKS="${COMP_WORDBREAKS//:/}" |
| cur="${COMP_WORDS[COMP_CWORD]}" |
| prev="${COMP_WORDS[COMP_CWORD-1]}" |
| cword=$COMP_CWORD |
| for i in ${!COMP_WORDS[@]}; do words[i]="${COMP_WORDS[i]}"; done |
| fi |
| |
| #_DEBUG_NF_COMPLETION=Y |
| if [[ $_DEBUG_NF_COMPLETION ]]; then |
| printf "\nCOMP_WORDBREAKS: <%s>\n" "$COMP_WORDBREAKS" |
| printf "COMP_LINE: <%s>\n" "$COMP_LINE" |
| printf "COMP_TYPE: <%s>\n" "$COMP_TYPE" |
| printf "COMP_POINT: <%s>\n" "$COMP_POINT" |
| printf "COMP_KEY: <%s>\n" "$COMP_KEY" |
| printf "COMP_CWORD: <%s>\n" "$COMP_CWORD" |
| printf "\ncur: <%s> prev: <%s>\n" "$cur" "$prev" |
| printf "words:\n" |
| printf "<%s>\n" "${words[@]}" |
| fi |
| |
| # collect info of cmdline |
| for ((i=1; i < ${#words[@]}-1; i++)); do |
| case "${words[i]}" in |
| -a) ((set_index)) && break || show_all=1 ;; |
| -i) ((set_index)) && break || isolate=1 Copts=(-Co) ;; |
| -m) ((set_index)) && break || show_members=1 ;; |
| -n) ((set_index)) && break || names_only=1 ;; |
| -r) ((set_index)) && break || resolve=1 ;; |
| -t) ((set_index)) && break || headers_only=1 Xopts=(-Xh -Xs) Fopts=(${Fopts[*]/-Oi/}) ;; |
| --) ((set_index)) && break || set_index=$((i+1)) ;; |
| -\?|-h|-v) |
| ((set_index)) || return 0 |
| ;; |
| @(-Fh|-Fi|-Hi|-Xh)) ((set_index)) && break || header_operation=1 ;; |
| *) |
| ((set_index)) && break |
| # options expecting an opt arg |
| str_tmp="@(-@(d|Fg|Fh|Fi|Fr|Hi|Ht|Hr|Hs|Hv|Mc|Oi|To|Xg|Xh|Xr|Xs))" |
| if [[ ${words[i-1]} = $str_tmp ]]; then |
| continue |
| fi |
| # if not an option, register set index |
| str_tmp="@(-@(-|?|a|c|d|h|i|m|n|r|s|t|v|Ca|Cs|Co|Fg|Fh|Fi|Fr|Hi|Ht|Hr|Hs|Hv|Mc|Oi|To|Tm|Ts|Xg|Xh|Xo|Xr))" |
| if [[ ${words[i]} != $str_tmp ]]; then |
| for x in ${!sets[@]}; do |
| if [[ ${sets[x]} = ${words[i]} ]]; then |
| set_index=$i |
| break |
| fi |
| done |
| fi |
| esac |
| done |
| |
| # invalid combinations of options |
| if ((names_only)); then |
| if ((headers_only)); then |
| return 0 |
| fi |
| fi |
| if ((headers_only||names_only)); then |
| if ((show_all || show_members || isolate || resolve)); then |
| return 0 |
| fi |
| elif ((isolate)); then |
| if ((show_all || header_operation)); then |
| return 0 |
| fi |
| fi |
| |
| # start setting compreply |
| # all depends on $set_index |
| if ((set_index)); then |
| if ((isolate && cword > set_index)); then |
| return 0 # allow only one set with isolate |
| fi |
| # dont' allow an option after the set name(s) |
| # allows to list sets which start with an hyphen |
| # and also handles those who have the name of ipset_list options |
| _ipset_list_show_sets |
| else |
| if [[ $prev = @(-@(\?|d|h|v|Fg|Fi|Fr|Hi|Ht|Oi|To|Xg|Xr)) ]]; then |
| return 0 |
| elif [[ $prev = -Xs ]]; then |
| # list sets if user does not want to enter a glob |
| _ipset_list_show_sets |
| elif [[ $prev = -Ht ]]; then i=0 |
| # show supported set types |
| while read -r; do |
| [[ $REPLY = "Supported set types:"* ]] && ((!i)) && \ |
| i=1 && continue |
| ((i)) || continue |
| if [[ $REPLY = *:* ]]; then |
| set -- $REPLY |
| arr_types[${#arr_types[@]}]="$1" |
| fi |
| done < <(ipset help) |
| for i in ${!arr_types[@]}; do # remove dupe entries |
| for ((x=i+1; x < ${#arr_types[@]}; x++)); do |
| if [[ ${arr_types[i]} = ${arr_types[x]} ]]; then |
| unset arr_types[x] |
| fi |
| done |
| done |
| COMPREPLY=( $( compgen -W '${arr_types[@]}' -- "$cur" ) ) |
| elif [[ $prev = @(-Fh|-Xh) ]]; then |
| # retrieve list of headers |
| if ((${#sets[*]} > 0)); then |
| while read -r; do |
| [[ $REPLY = Name ]] && continue |
| COMPREPLY[${#COMPREPLY[@]}]="$REPLY" |
| done < <("$ipset_list" -t "${sets[0]}"|command awk -F: '{print $1}') |
| compopt -o nospace |
| local IFS=$'\n' |
| if [[ $prev = -Xh ]]; then |
| COMPREPLY=( $( compgen -P '"' -S ':*"' \ |
| -W '${COMPREPLY[@]}' -- "$cur" ) ) |
| elif [[ $prev = -Fh ]]; then |
| COMPREPLY=( $( compgen -P '"' -S ':"' \ |
| -W '${COMPREPLY[@]}' -- "$cur" ) ) |
| fi |
| fi |
| elif [[ $prev = @(-@(Hr|Hs|Hv|Mc)) ]]; then |
| # options making use of arithmetic comparison |
| compopt -o nospace |
| COMPREPLY=( $( compgen -P '\' -W '\! \< \> \<= \>=' -- "$cur" ) ) |
| elif [[ $cur = -* ]]; then |
| # any option is requested |
| case "$prev" in |
| @(-@(\?|d|h|v|Fg|Fh|Fi|Fr|Hi|Ht|Hr|Hs|Hv|Mc|Oi|To|Xg|Xh|Xr))) |
| # options that exclude any other option, |
| # or need a value we can't predict |
| return 0 |
| ;; |
| esac |
| # these options don't allow any other |
| if ((${#words[@]} > 2)); then |
| opts=("${opts[@]/@(-v|-h|-\?)/}") |
| fi |
| # some options allow only a subset of other options |
| if ((isolate)); then |
| COMPREPLY=( $(compgen -W '-- -Co -d -r -s -Fg -Fr -Oi -To -Xg -Xo -Xr' -- $cur ) ) |
| elif ((names_only)); then |
| COMPREPLY=( $(compgen -W \ |
| '-- -c ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} -Xs' \ |
| -- $cur ) ) |
| elif ((headers_only)); then |
| COMPREPLY=( $(compgen -W \ |
| '-- -c ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \ |
| -- $cur ) ) |
| elif ((show_members)); then |
| COMPREPLY=( $(compgen -W \ |
| '-- -c -d -r -s ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} -Xg -Xr -Xo' \ |
| -- $cur ) ) |
| elif ((show_all)); then |
| COMPREPLY=( $(compgen -W \ |
| '-- -c -d -r -s ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \ |
| -- $cur ) ) |
| elif ((resolve)); then |
| COMPREPLY=( $(compgen -W \ |
| '-- -a -c -d -s -m ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \ |
| -- $cur ) ) |
| elif ((header_operation)); then |
| COMPREPLY=( $(compgen -W \ |
| '-- -a -c -d -s -m -t ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \ |
| -- $cur ) ) |
| else |
| COMPREPLY=( $(compgen -W \ |
| '${opts[@]} ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \ |
| -- $cur ) ) |
| fi |
| # post process the reply |
| if ((${#COMPREPLY[@]})); then |
| x=$((set_index ? set_index : ${#words[*]}-1)) |
| # mutual exclusive options |
| for ((i=1; i < x; i++)); do |
| case "${words[i]}" in |
| -Fg) _ipset_list_remove_reply_entry "-Fr" ;; |
| -Fr) _ipset_list_remove_reply_entry "-Fg" ;; |
| -Xg) _ipset_list_remove_reply_entry "-Xr" ;; |
| -Xr) _ipset_list_remove_reply_entry "-Xg" ;; |
| esac |
| # options allowed multiple times |
| if [[ ${words[i]} = @(""|-|-@(Fh|Fi|Hi|Mc|Oi|Xh|Xs)) ]]; then |
| continue |
| else # remove dupe |
| _ipset_list_remove_reply_entry "${words[i]}" |
| fi |
| done |
| fi |
| elif [[ $cur = * ]]; then |
| # non option request |
| # default to sets listing |
| _ipset_list_show_sets |
| fi |
| fi |
| |
| ((got_bashcompl)) && __ltrim_colon_completions "$cur" |
| |
| if [[ $_DEBUG_NF_COMPLETION ]]; then |
| printf "COMPREPLY:\n" |
| printf "<%s>\n" "${COMPREPLY[@]}" |
| fi |
| } |
| complete -F _ipset_list_complete "${ipset_list:-ipset_list}" |
| |