[-]
[+]
|
Added |
ipset.changes
|
|
[-]
[+]
|
Changed |
ipset.spec
^
|
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/ChangeLog
^
|
@@ -1,3 +1,11 @@
+6.17
+ - Fix revision printing in XML mode (reported by Mart Frauenlob)
+ - Correct "Suspicious condition (assignment + comparison)" (Thomas Jarosch)
+ - Fix error path when protocol number is used with port range
+ - Interactive mode error after syntax error (reported by Mart Frauenlob)
+ - The ipset_bash_completion tool is added
+ - The ipset_list tool is added
+
6.16
- Remove all modules before testing resize
- build: support for Linux 3.7 UAPI (Jan Engelhardt)
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/Makefile.am
^
|
@@ -58,6 +58,14 @@
./update ip_set_hash.h
./update ip_set_list.h
+update_utils:
+ wget -O /tmp/ipset-bash-completion.tar.gz http://sourceforge.net/projects/ipset-bashcompl/files/latest/download
+ cd utils/ipset_bash_completion; tar xz --strip-components=1 -f /tmp/ipset-bash-completion.tar.gz
+ rm -f /tmp/ipset-bash-completion.tar.gz
+ wget -O /tmp/ipset-list.tar.gz http://sourceforge.net/projects/ipset-list/files/latest/download
+ cd utils/ipset_list; tar xz --strip-components=1 -f /tmp/ipset-list.tar.gz
+ rm -f /tmp/ipset-list.tar.gz
+
tests:
cd tests; ./runtest.sh
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/Makefile.in
^
|
@@ -859,6 +859,14 @@
./update ip_set_hash.h
./update ip_set_list.h
+update_utils:
+ wget -O /tmp/ipset-bash-completion.tar.gz http://sourceforge.net/projects/ipset-bashcompl/files/latest/download
+ cd utils/ipset_bash_completion; tar xz --strip-components=1 -f /tmp/ipset-bash-completion.tar.gz
+ rm -f /tmp/ipset-bash-completion.tar.gz
+ wget -O /tmp/ipset-list.tar.gz http://sourceforge.net/projects/ipset-list/files/latest/download
+ cd utils/ipset_list; tar xz --strip-components=1 -f /tmp/ipset-list.tar.gz
+ rm -f /tmp/ipset-list.tar.gz
+
tests:
cd tests; ./runtest.sh
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/configure
^
|
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.65 for ipset 6.16.1.
+# Generated by GNU Autoconf 2.65 for ipset 6.17.
#
# Report bugs to <kadlec@blackhole.kfki.hu>.
#
@@ -705,8 +705,8 @@
# Identity of this package.
PACKAGE_NAME='ipset'
PACKAGE_TARNAME='ipset'
-PACKAGE_VERSION='6.16.1'
-PACKAGE_STRING='ipset 6.16.1'
+PACKAGE_VERSION='6.17'
+PACKAGE_STRING='ipset 6.17'
PACKAGE_BUGREPORT='kadlec@blackhole.kfki.hu'
PACKAGE_URL=''
@@ -1474,7 +1474,7 @@
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures ipset 6.16.1 to adapt to many kinds of systems.
+\`configure' configures ipset 6.17 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1544,7 +1544,7 @@
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of ipset 6.16.1:";;
+ short | recursive ) echo "Configuration of ipset 6.17:";;
esac
cat <<\_ACEOF
@@ -1666,7 +1666,7 @@
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-ipset configure 6.16.1
+ipset configure 6.17
generated by GNU Autoconf 2.65
Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2037,7 +2037,7 @@
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by ipset $as_me 6.16.1, which was
+It was created by ipset $as_me 6.17, which was
generated by GNU Autoconf 2.65. Invocation command line was
$ $0 $@
@@ -2919,7 +2919,7 @@
# Define the identity of the package.
PACKAGE='ipset'
- VERSION='6.16.1'
+ VERSION='6.17'
cat >>confdefs.h <<_ACEOF
@@ -15565,7 +15565,7 @@
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by ipset $as_me 6.16.1, which was
+This file was extended by ipset $as_me 6.17, which was
generated by GNU Autoconf 2.65. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -15631,7 +15631,7 @@
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-ipset config.status 6.16.1
+ipset config.status 6.17
configured by $0, generated by GNU Autoconf 2.65,
with options \\"\$ac_cs_config\\"
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/configure.ac
^
|
@@ -1,5 +1,5 @@
dnl Boilerplate
-AC_INIT([ipset], [6.16.1], [kadlec@blackhole.kfki.hu])
+AC_INIT([ipset], [6.17], [kadlec@blackhole.kfki.hu])
AC_CONFIG_AUX_DIR([build-aux])
AC_CANONICAL_HOST
AC_CONFIG_MACRO_DIR([m4])
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/kernel/ChangeLog
^
|
@@ -1,3 +1,8 @@
+6.17
+ - Make sure ip_set_max isn't set to IPSET_INVALID_ID
+ - netfilter: ipset: timeout values corrupted on set resize (Josh Hunt)
+ - "Directory not empty" error message (reported by John Brendler)
+
6.16.1
- Add ipset package version to external module description
- Backport RCU handling up to 2.6.32.x
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/kernel/include/linux/netfilter/ipset/ip_set_ahash.h
^
|
@@ -857,6 +857,8 @@
retry:
ret = 0;
htable_bits++;
+ pr_debug("attempt to resize set %s from %u to %u, t %p\n",
+ set->name, orig->htable_bits, htable_bits, orig);
if (!htable_bits) {
/* In case we have plenty of memory :-) */
pr_warning("Cannot increase the hashsize of set %s further\n",
@@ -876,7 +878,7 @@
data = ahash_tdata(n, j);
m = hbucket(t, HKEY(data, h->initval, htable_bits));
ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), 0,
- type_pf_data_timeout(data));
+ ip_set_timeout_get(type_pf_data_timeout(data)));
if (ret < 0) {
read_unlock_bh(&set->lock);
ahash_destroy(t);
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/kernel/net/netfilter/ipset/ip_set_core.c
^
|
@@ -811,7 +811,7 @@
struct ip_set **list, **tmp;
ip_set_id_t i = ip_set_max + IP_SET_INC;
- if (i < ip_set_max)
+ if (i < ip_set_max || i == IPSET_INVALID_ID)
/* Wraparound */
goto cleanup;
@@ -1507,7 +1507,8 @@
if (ret == -EAGAIN)
ret = 1;
- return ret < 0 ? ret : ret > 0 ? 0 : -IPSET_ERR_EXIST;
+ return (ret < 0 && ret != -ENOTEMPTY) ? ret :
+ ret > 0 ? 0 : -IPSET_ERR_EXIST;
}
/* Get headed data of a set */
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/lib/parse.c
^
|
@@ -442,11 +442,10 @@
protoent = getprotobyname(strcasecmp(str, "icmpv6") == 0
? "ipv6-icmp" : str);
if (protoent == NULL) {
- uint8_t protonum;
- int err;
+ uint8_t protonum = 0;
- if (!((err = string_to_u8(session, str, &protonum) == 0) &&
- (protoent = getprotobynumber(protonum)) != NULL))
+ if (string_to_u8(session, str, &protonum) ||
+ (protoent = getprotobynumber(protonum)) == NULL)
return syntax_err("cannot parse '%s' "
"as a protocol", str);
}
@@ -615,7 +614,9 @@
default:
if (!STREQ(a, "0")) {
syntax_err("Protocol %s can be used "
- "with pseudo port value 0 only.");
+ "with pseudo port value 0 only.",
+ tmp);
+ err = -1;
goto error;
}
ipset_data_flags_set(data, IPSET_FLAG(opt));
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/lib/session.c
^
|
@@ -851,7 +851,7 @@
safe_snprintf(session,
"<ipset name=\"%s\">\n"
" <type>%s</type>\n"
- " <revision%u</revision\n"
+ " <revision>%u</revision\n"
" <header>\n",
ipset_data_setname(data),
type->name, type->revision);
|
[-]
[+]
|
Changed |
ipset-6.17.tar.xz/src/ipset.c
^
|
@@ -563,6 +563,8 @@
case IPSET_CMD_NONE:
if (interactive) {
printf("No command specified\n");
+ if (session)
+ ipset_envopt_parse(session, 0, "reset");
return 0;
}
if (argc > 1 && STREQ(argv[1], "-")) {
@@ -574,12 +576,15 @@
c = cmdline;
while (isspace(c[0]))
c++;
- if (c[0] == '\0' || c[0] == '#')
+ if (c[0] == '\0' || c[0] == '#') {
+ printf("%s> ", program_name);
continue;
+ }
/* Build fake argv, argc */
build_argv(c);
- /* Execute line: ignore errors */
- parse_commandline(newargc, newargv);
+ /* Execute line: ignore soft errors */
+ if (parse_commandline(newargc, newargv) < 0)
+ handle_error();
printf("%s> ", program_name);
}
return exit_error(NO_PROBLEM, NULL);
|
[-]
[+]
|
Added |
ipset-6.17.tar.xz/utils
^
|
+(directory)
|
[-]
[+]
|
Added |
ipset-6.17.tar.xz/utils/ipset_bash_completion
^
|
+(directory)
|
[-]
[+]
|
Added |
ipset-6.17.tar.xz/utils/ipset_bash_completion/README.md
^
|
@@ -0,0 +1,4 @@
+ipset-bash-completion
+=====================
+
+Programmable completion code (bash) for ipset (netfilter.org)
|
[-]
[+]
|
Added |
ipset-6.17.tar.xz/utils/ipset_bash_completion/ipset_bash_completion
^
|
@@ -0,0 +1,414 @@
+#!/bin/bash
+
+# -----------------------------------------------------------------
+# Programmable completion code for ipset (netfilter.org)
+#
+# https://github.com/AllKind/ipset-bash-completion
+# https://sourceforge.net/projects/ipset-bashcompl
+# -----------------------------------------------------------------
+
+# Copyright (C) 2013 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/>.
+
+# -----------------------------------------------------------------
+# Tested with ipset versions:
+# 6.16.1
+# -----------------------------------------------------------------
+#
+# Put it into ~/.bash_completion or /etc/bash_completion.d/
+#
+# -----------------------------------------------------------------
+#
+# Version 1.9
+#
+# -----------------------------------------------------------------
+
+
+_ipset_bash_default_compl() { # taken from examples - modified by me
+# call with the word to be completed as $1
+local t
+if [[ $1 == \$\(* ]]; then # command substitution
+ t=${1#??}
+ COMPREPLY=( $(compgen -c -P '$(' $t) )
+elif [[ $1 == \$\{* ]]; then # variables with a leading `${'
+ t=${1#??}
+ COMPREPLY=( $(compgen -v -P '${' -S '}' $t) )
+elif [[ $1 == \$* ]]; then # variables with a leading `$'
+ t=${1#?}
+ COMPREPLY=( $(compgen -v -P '$' $t ) )
+elif [[ "$1" == *@* ]]; then # hostname
+ t=${1#*@}
+ COMPREPLY=( $( compgen -A hostname $t ) )
+elif [[ $1 == *[*?[]* ]]; then # sh-style glob pattern
+ COMPREPLY=( $( compgen -G "$1" ) )
+# ksh-style extended glob pattern - must be complete
+elif shopt -q extglob && [[ $1 == *[?*+\!@]\(*\)* ]]; then
+ COMPREPLY=( $( compgen -G "$1" ) )
+fi
+}
+
+_ipset_complete() {
+shopt -s extglob
+local cur prev str_action ips_version
+local -i i=x=y=got_action=in_list=0
+local -i ignore_errors=use_file=names_only=headers_only=save_format=res_sort=0
+local arr_sets=() arr_types=() arr_members=()
+
+# ipset version check 6.x upwards (to v?) is supported
+ips_version="$(ipset --version)"
+ips_version="${ips_version#ipset v}"
+ips_version="${ips_version%%.*}"
+[[ $ips_version = +([[:digit:]]) ]] || return 1
+((ips_version < 6)) && return 1
+
+COMPREPLY=()
+COMP_WORDBREAKS=$' \t\n"\'><=;|&('
+
+# expecting _get_comp_words_by_ref() to exist from bash_completion
+_get_comp_words_by_ref cur || return
+_get_comp_words_by_ref prev || return
+
+#DEBUG=Y
+if [[ $DEBUG ]]; 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 "COMP_WORDS:\n"
+ printf "<%s>\n" "${COMP_WORDS[@]}"
+ printf "cur: <%s> prev: <%s>\n" "$cur" "$prev"
+fi
+
+for i in ${!COMP_WORDS[@]}; do # check if we already have an action registered
+ if [[ ${COMP_WORDS[i]} = @(create|add|del|test|destroy|list|save|restore|flush|rename|swap|help|version) ]]; then
+ if [[ ${COMP_WORDS[i]} != save ]]; then
+ got_action=1 str_action=${COMP_WORDS[i]}
+ break
+ else
+ if [[ ${COMP_WORDS[i-1]} != -o ]]; then
+ got_action=1 str_action=${COMP_WORDS[i]}
+ break
+ fi
+ fi
+ fi
+done
+
+# collect information about used options
+for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do
+ case "${COMP_WORDS[i]}" in
+ -\!) ignore_errors=1 ;;
+ -f) use_file=1 ;;
+ -n) names_only=1 ;;
+ -t) headers_only=1 ;;
+ -o) save_format=1
+ if [[ $prev = -o ]]; then
+ save_format=2 # expecting opt-arg
+ elif [[ ${COMP_WORDS[i+1]} = save ]]; then
+ save_format=3 # no -n/-t with -o save
+ fi
+ ;;
+ -r|-s) res_sort=1 ;;
+ esac
+done
+
+# invalid combination of options
+if ((names_only && headers_only)); then
+ COMPREPLY=()
+ return 0
+elif ((names_only || headers_only)); then
+ if ((res_sort || ignore_errors)) || ((save_format == 3)); then
+ COMPREPLY=()
+ return 0
+ fi
+elif ((ignore_errors)); then
+ if ((res_sort || save_format)); then
+ COMPREPLY=()
+ return 0
+ fi
+fi
+
+# for help or create, find supported set types and save them into an array
+if [[ $str_action = @(help|create) ]]; then i=0
+ 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
+fi
+
+case "$cur" in
+ -*) # any option is requested
+ if ((save_format == 2)); then
+ COMPREPLY=()
+ return 0
+ fi
+ case "$prev" in
+ create|add|del|test|rename|swap) # -option not expected
+ COMPREPLY=()
+ return 0
+ ;;
+ \<|\>|-f) compopt -o nospace # expecting filenames as completion
+ COMPREPLY=( $( compgen -f -- $cur ) )
+ return 0
+ ;;
+ -) COMPREPLY=() # interactive mode
+ return 0
+ ;;
+ esac
+ if ((got_action)); then
+ case "$str_action" in
+ create|add|del)
+ COMPREPLY=( -\! -q )
+ for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do
+ if [[ $str_action = ${COMP_WORDS[i]} && ${COMP_WORDS[i+2]} = -* ]]; then
+ COMPREPLY=() # option not expected, want command value
+ break
+ fi
+ done
+ ;;
+ destroy|flush) COMPREPLY=( -q ) ;;
+ list)
+ if ((names_only || headers_only)); then
+ COMPREPLY=( -f -o -q )
+ elif ((res_sort)); then
+ COMPREPLY=( -f -o -q -r -s )
+ elif ((save_format == 1)); then
+ COMPREPLY=( -f -q -r -s -t )
+ elif ((save_format == 3)); then
+ COMPREPLY=( -f -q -r -s )
+ else
+ COMPREPLY=( -f -n -o -q -r -s -t )
+ fi
+ ;;
+ restore) COMPREPLY=( -\! -f -q ) ;;
+ save) COMPREPLY=( -f -q ) ;;
+ rename|swap|test) COMPREPLY=( -q )
+ for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do
+ if [[ $str_action = ${COMP_WORDS[i]} && ${COMP_WORDS[i+2]} = -* ]]; then
+ COMPREPLY=() # option not expected, want command value
+ break
+ fi
+ done
+ ;;
+ help|version) COMPREPLY=()
+ return 0
+ ;;
+ esac
+ else COMPREPLY=( - -\! -f -n -o -q -r -s -t )
+ if ((names_only || headers_only)) && ((save_format == 1)); then
+ COMPREPLY=( -f -q )
+ elif ((names_only || headers_only)); then
+ COMPREPLY=( -f -o -q )
+ elif ((res_sort)); then
+ COMPREPLY=( -f -o -q -r -s )
+ elif ((save_format == 1)); then
+ COMPREPLY=( -f -q -r -s -t )
+ elif ((save_format == 3)); then
+ COMPREPLY=( -f -q -r -s )
+ elif ((ignore_errors)); then
+ COMPREPLY=( -f -q )
+ elif ((use_file)); then
+ COMPREPLY=( -\! -n -o -q -r -s -t )
+ fi
+ fi
+ ;;
+ \<|\>) # redirection operator
+ compopt -o nospace
+ COMPREPLY=( $( compgen -f ) ) # no $cur, so completion starts without space after redirection
+ return 0
+ ;;
+ \$\{*) # variables with a leading `${'
+ COMPREPLY=( $(compgen -v -P '${' -S '}' ${cur#??}) )
+ return 0
+ ;;
+ \$*) # variables with a leading `$'
+ COMPREPLY=( $(compgen -v -P '$' ${cur#?} ) )
+ return 0
+ ;;
+ *) # not an option
+ if ((got_action)); then
+ arr_sets=( $(ipset list -n ) )
+ else
+ COMPREPLY=( $( compgen -W 'create add del test destroy list save restore flush rename swap help version' -- $cur ) )
+ fi
+ case "$prev" in # depend on previous option
+ restore) COMPREPLY=( \< )
+ for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do
+ if [[ ${COMP_WORDS[i]} = -f ]]; then
+ COMPREPLY=() # don't show redirector if we have option -f
+ break
+ fi
+ done
+ return 0
+ ;;
+ create|version) COMPREPLY=()
+ return 0
+ ;;
+ add|del|destroy|rename|swap|test)
+ COMPREPLY=( $( compgen -W '${arr_sets[@]}' -- $cur ) )
+ return 0
+ ;;
+ save)
+ if [[ $str_action = save ]]; then
+ COMPREPLY=( $( compgen -W '${arr_sets[@]}' -- $cur ) )
+ else
+ if ((save_format == 3)); then
+ COMPREPLY=( $( compgen -W 'list' -- $cur ) )
+ fi
+ fi
+ ;;
+ list) COMPREPLY=( $( compgen -W '${arr_sets[@]}' -- $cur ) )
+ return 0
+ ;;
+ help) COMPREPLY=( $( compgen -W '${arr_types[@]}' -- $cur ) )
+ return 0
+ ;;
+ -o)
+ if ((names_only || headers_only)); then
+ COMPREPLY=( $( compgen -W 'plain xml' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W 'plain save xml' -- $cur ) )
+ fi
+ return 0
+ ;;
+ -f) compopt -o nospace
+ COMPREPLY=( $( compgen -f -- $cur ) )
+ return 0
+ ;;
+ \<|\>) compopt -o nospace
+ COMPREPLY=( $( compgen -f -- $cur ) )
+ return 0
+ ;;
+ -) COMPREPLY=() # interactive mode
+ return 0
+ ;;
+ *)
+ if ((got_action)); then
+ COMPREPLY=( $( compgen -W '${arr_sets[@]}' -- $cur ) )
+ for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do
+ case "${COMP_WORDS[i]}" in
+ add)
+ for ((x=${COMP_WORDS[i+1]}; x <= ${#COMP_WORDS[@]}; x++)); do
+ if [[ ${COMP_WORDS[x]} = $prev ]]; then
+ COMPREPLY=() # only list sets after the action command
+ break 2
+ fi
+ done
+ break
+ ;;
+ create) COMPREPLY=()
+ if [[ ${COMP_WORDS[i+1]} = $prev ]]; then
+ COMPREPLY=( $( compgen -W '${arr_types[@]}' -- $cur ) )
+ fi
+ break
+ ;;
+ del) # complete members
+ if [[ ${COMP_WORDS[i+1]} = $prev ]]; then
+ while read -r; do
+ [[ $REPLY = Members:* ]] && in_list=1 && continue
+ ((in_list)) || continue
+ arr_members[${#arr_members[@]}]="$REPLY"
+ done < <(ipset list "$prev" 2>/dev/null)
+ COMPREPLY=( $( compgen -W '${arr_members[@]}' -- $cur ) )
+ else
+ COMPREPLY=()
+ fi
+ break
+ ;;
+ help)
+ if [[ ${COMP_WORDS[i+1]} ]]; then
+ COMPREPLY=() # don't go further than showing the set types
+ return 0
+ fi
+ break
+ ;;
+ restore) COMPREPLY=() # not a redirecton
+ break
+ ;;
+ swap)
+ for x in ${!arr_sets[@]}; do
+ if [[ ${arr_sets[x]} = ${COMP_WORDS[i+2]} ]]; then
+ COMPREPLY=() # only list two sets
+ break 2
+ fi
+ done
+ break
+ ;;
+ *)
+ for ((y=1; y <= ${#COMP_WORDS[@]}; y++)); do
+ [[ ${COMP_WORDS[y]} ]] || continue
+ for x in ${!arr_sets[@]}; do
+ if [[ ${arr_sets[x]} = ${COMP_WORDS[y]} ]]; then
+ COMPREPLY=() # list only one set
+ break 2
+ fi
+ done
+ done
+ ;;
+ esac
+ done
+ else # we don't have the action yet, check options to display appropiate actions
+ if ((save_format || names_only || headers_only)); then
+ COMPREPLY=( $( compgen -W 'list' -- $cur ) )
+ return 0
+ elif ((res_sort)); then
+ COMPREPLY=( $( compgen -W 'list save' -- $cur ) )
+ return 0
+ elif ((ignore_errors && use_file)); then
+ COMPREPLY=( $( compgen -W 'restore' -- $cur ) )
+ return 0
+ elif ((ignore_errors)); then
+ COMPREPLY=( $( compgen -W 'create add del restore' -- $cur ) )
+ return 0
+ elif ((use_file)); then
+ COMPREPLY=( $( compgen -W 'list save restore' -- $cur ) )
+ return 0
+ fi
+ fi
+ ;;
+ esac
+ ;;
+esac
+if ((${#COMPREPLY[@]})); then # post process the reply
+ for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do # remove dupe options
+ [[ ${COMP_WORDS[i]} = @(""|-) ]] && continue
+ for x in ${!COMPREPLY[@]}; do
+ if [[ ${COMP_WORDS[i]} = ${COMPREPLY[x]} ]]; then
+ unset COMPREPLY[$x]
+ break
+ fi
+ done
+ done
+else
+ _ipset_bash_default_compl "$cur"
+fi
+if [[ $DEBUG ]]; then
+ printf "COMPREPLY:\n"
+ printf "<%s>\n" "${COMPREPLY[@]}"
+fi
+}
+complete -F _ipset_complete ipset
|
[-]
[+]
|
Added |
ipset-6.17.tar.xz/utils/ipset_list
^
|
+(directory)
|
[-]
[+]
|
Added |
ipset-6.17.tar.xz/utils/ipset_list/README.md
^
|
@@ -0,0 +1,66 @@
+ipset_list
+==========
+
+ipset set listing wrapper script
+
+
+Features:
+==========
+(in addition to the native ipset options)
+
+- Calculate sum of set members (and match on that count).
+- List only members of a specified set.
+- Choose a delimiter character for separating members.
+- Show only sets containing a specific (glob matching) header.
+- Arithmetic comparison on headers with an integer value.
+- Match members using a globbing or regex pattern.
+- Suppress listing of (glob matching) sets.
+- Suppress listing of (glob matching) headers.
+- Suppress listing of members matching a glob or regex pattern.
+- Calculate the total size in memory of all matching sets.
+- Calculate the amount of matching, excluded and traversed sets.
+- Colorize the output.
+- Operate on a single, selected, or all sets.
+
+
+Examples:
+==========
+
+- `ipset_list` - no args, just list set names
+- `ipset_list -c` - show all set names and their member sum
+- `ipset_list -t` - show all sets, but headers only
+- `ipset_list -c -t setA` - show headers and member sum of setA
+- `ipset_list -i setA` - show only members entries of setA
+- `ipset_list -c -m setA setB` - show members and sum of setA & setB
+- `ipset_list -a -c -d :` - show all sets members, sum and use `:' as entry delimiter
+- `ipset_list -a -c setA` - show all info of setA and its members sum
+- `ipset_list -c -m -d $'\n' setA` - show members and sum of setA, delim with newline
+- `ipset_list -m -r -s setA` - show members of setA resolved and sorted
+- `ipset_list -Fi References:0` - show all sets with 0 references
+- `ipset_list -Hr 0` - shortcut for -Fi References:0
+- `ipset_list -Ht "!(hash:ip)"` - show sets which are not of type hash:ip
+- `ipset_list -Ht "!(bitmap:*)"` - show sets wich are not of any bitmap type
+- `ipset_list -Cs -Ht "hash:*"` - find sets of any hash type, count their amount.
+- `ipset_list -Ts` - show all set names and total count of sets.
+- `ipset_list -Tm` - calculate total size in memory of all sets.
+- `ipset_list -Xs setA -Xs setB` - show all set names, but exclude setA and setB.
+- `ipset_list -Xs "set[AB]"` - show all set names, but exclude setA and setB.
+- `ipset_list -Mc 0` - show sets with zero members
+- `ipset_list -Mc '>=100'` - show sets with a member count greater or equal to 100
+- `ipset_list -Hr \>=1 -Hv 0 -Hs \>10000` - find sets with at least one reference, revision of 0 and size in memory greater than 10000
+- `ipset_list -i -Fr "^210\..*" setA` - show only members of setA matching the regex "^210\\..*"
+- `ipset_list -a -c -Fh "Type:hash:ip" -Fr "^210\..*"` - show all information of sets with type hash:ip, matching the regex "^210\\..*", show match and members sum
+- `ipset_list -Fh Type:hash:ip -Fh "Header:family inet *"` - show all set names, which are of type hash:ip and header of ipv4.
+- `ipset_list -t -Xh "Revision:*" -Xh "References:*"` - show all sets headers, but exclude Revision and References entries.
+- `ipset_list -c -m -Xg "210.*" setA` - show members of setA, but suppress listing of entries matching the glob pattern "210.*", show count of excluded and total members.
+- `ipset_list -m -Fg "!(210.*)" setA` - show members of setA excluding the elements matching the negated glob.
+- `ipset_list -a -Xh "@(@(H|R|M)e*):*"` - show all info of all sets, but suppress Header, References, Revision and Member header entries (headers existing as per ipset 6.x -> tested version).
+- `ipset_list -t -Tm -Xh "@(Type|Re*|Header):*"` - show all sets headers, but suppress all but name and memsize entry, calculate the total memory size of all sets.
+- `ipset_list -t -Tm -Xh "!(Size*|Type):*" -Ts -Co` List all sets headers, but suppress all but name, type and memsize entry,
+ count amount of sets, calculate total memory usage, colorize the output.
+- `ipset_list -t -Ht "!(@(bit|port)map):*" -Xh "!(Type):*"` - show all sets that are neither of type bitmap or portmap, suppress all but the type header.
+- `ipset_list -c -t -Cs -Ts -Xh "@(Size*|Re*|Header):*" -Ht "!(bitmap:*)"` - find all sets not of any bitmap type, count their members sum, display only the 'Type' header, count amount of matching and traversed sets.
+- `ipset_list -Co -c -Ts -Tm` - show all set names, count their members, count total amount of sets, show total memory usage of all sets, colorize the output
+- `ipset_list -m -r -To 0` - show members of all sets, try to resolve hosts, set the timeout to 0 (effectivly disabling it).
+
+
|
[-]
[+]
|
Added |
ipset-6.17.tar.xz/utils/ipset_list/ipset_list
^
|
@@ -0,0 +1,827 @@
+#!/bin/bash
+
+# -----------------------------------------------------------------
+# ipset set listing wrapper script
+#
+# https://github.com/AllKind/ipset_list
+# https://sourceforge.net/projects/ipset-list/
+# -----------------------------------------------------------------
+
+# Copyright (C) 2013 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/>.
+
+# -----------------------------------------------------------------
+# Tested with ipset versions:
+# 6.16.1
+# -----------------------------------------------------------------
+
+# -----------------------------------------------------------------
+# Features (in addition to the native ipset options):
+# - Calculate sum of set members (and match on that count).
+# - List only members of a specified set.
+# - Choose a delimiter character for separating members.
+# - Show only sets containing a specific (glob matching) header.
+# - Arithmetic comparison on headers with an integer value.
+# - Match members using a globbing or regex pattern.
+# - Suppress listing of (glob matching) sets.
+# - Suppress listing of (glob matching) headers.
+# - Suppress listing of members matching a glob or regex pattern.
+# - Calculate the total size in memory of all matching sets.
+# - Calculate the amount of matching, excluded and traversed sets.
+# - Colorize the output.
+# - Operate on a single, selected, or all sets.
+# -----------------------------------------------------------------
+
+# -----------------------------------------------------------------
+# Examples:
+# $0 - no args, just list set names
+# $0 -c - show all set names and their member sum
+# $0 -t - show all sets, but headers only
+# $0 -c -t setA - show headers and member sum of setA
+# $0 -i setA - show only members entries of setA
+# $0 -c -m setA setB - show members and sum of setA & setB
+# $0 -a -c -d : - show all sets members, sum and use `:' as entry delimiter
+# $0 -a -c setA - show all info of setA and its members sum
+# $0 -c -m -d $'\n' setA - show members and sum of setA, delim with newline
+# $0 -m -r -s setA - show members of setA resolved and sorted
+# $0 -Ts - show all set names and total count of sets.
+# $0 -Tm - calculate total size in memory of all sets.
+# $0 -Mc 0 - show sets with zero members
+# $0 -Mc '>=100' - show sets with a member count greater or equal to 100
+# $0 -Fi References:0 - show all sets with 0 references
+# $0 -Hr 0 - shortcut for `-Fi References:0'
+# $0 -Xs setA -Xs setB - show all set names, but exclude setA and setB.
+# $0 -Xs "set[AB]" - show all set names, but exclude setA and setB.
+# $0 -Cs -Ht "hash:*" - find sets of any hash type, count their amount.
+# $0 -Ht "!(hash:ip)" - show sets which are not of type hash:ip
+# $0 -Ht "!(bitmap:*)" - show sets wich are not of any bitmap type
+# $0 -i -Fr "^210\..*" setA - show only members of setA matching the regex "^210\..*"
+# $0 -a -c -Fh "Type:hash:ip" -Fr "^210\..*"
+#+ - show all information of sets with type hash:ip,
+#+ matching the regex "^210\..*", show match and members sum.
+#
+# $0 -m -Fg "!(210.*)" setA
+#+ show members of setA excluding the elements matching the negated glob.
+#
+# $0 -Hr \>=1 -Hv 0 -Hs \>10000 - find sets with at least one reference,
+#+ revision of 0 and size in memory greater than 10000
+#
+# $0 -Fh Type:hash:ip -Fh "Header:family inet *"
+#+ - show all set names, which are of type hash:ip and header of ipv4.
+#
+# $0 -t -Xh "Revision:*" -Xh "References:*"
+#+ - show all sets headers, but exclude Revision and References entries.
+#
+# $0 -t -Ht "!(@(bit|port)map):*" -Xh "!(Type):*" - show all sets that are
+#+ neither of type bitmap or portmap, suppress all but the type header.
+#
+# $0 -c -m -Xg "210.*" setA - show members of setA, but suppress listing of entries
+#+ matching the glob pattern "210.*", show count of excluded and total members.
+#
+# $0 -t -Tm -Xh "@(Type|Re*|Header):*"
+#+ show all sets headers, but suppress all but name and memsize entry,
+#+ calculate the total memory size of all sets.
+#
+# $0 -t -Tm -Xh "!(Size*|Type):*" -Ts -Co
+# + List all sets headers, but suppress all but name, type and memsize entry,
+# + count amount of sets, calculate total memory usage, colorize the output.
+#
+# $0 -c -t -Cs -Ts -Xh "@(Size*|Re*|Header):*" -Ht "!(bitmap:*)"
+#+ find all sets not of any bitmap type, count their members sum,
+#+ display only the 'Type' header,
+#+ count amount of matching and traversed sets.
+#
+# $0 -a -Xh "@(@(H|R|M)e*):*" - show all info of all sets,
+#+ but suppress Header, References, Revision and Member header entries.
+#+ (headers existing as per ipset 6.x -> tested version).
+#
+# $0 -Co -c -Ts -Tm - show all set names, count their members,
+# + count total amount of sets, show total memory usage of all sets,
+# + colorize the output
+#
+# $0 -m -r -To 0 - show members of all sets, try to resolve hosts,
+# set the timeout to 0 (effectivly disabling it).
+# -----------------------------------------------------------------
+
+# -----------------------------------------------------------------
+# Modify here
+# -----------------------------------------------------------------
+
+# path to ipset. defaults to `/sbin/ipset' if unset.
+ipset="/sbin/ipset"
+
+# default delimiter character for set members (elements).
+# defaults to whitespace if unset.
+# use delim=$'\n' to use the ipset default newline as delimiter.
+delim=" "
+
+# default read timeout (for reading sets - esp. with the -r switch).
+# the command line option -To overrides this.
+TMOUT=30
+
+# colorize the output (bool 0/1).
+colorize=0
+
+# path to cl (to colorize the output).
+# https://github.com/AllKind/cl
+# defaults to `/usr/local/bin/cl' if unset.
+cl="/usr/local/bin/cl"
+
+# define colors
+# run `cl --list' to retrieve the valid color names
+#
+# default foreground color
+# defaults to: white
+col_fg="white"
+
+# default background color
+# defaults to: black
+col_bg="black"
+
+# color for headers
+# defaults to: cyan
+col_headers="cyan"
+
+# color for members
+# defaults to: yellow
+col_members="yellow"
+
+# color for matches
+# defaults to: red
+col_match="red"
+
+# color for displaying of memsize
+# defaults to: green
+col_memsize="green"
+
+# color for counting of matched sets
+# defaults to: magenta
+col_set_count="magenta"
+
+# color for counting of traversed sets
+# defaults to: blue
+col_set_total="blue"
+
+# general higlightning color
+# defaults to: white
+col_highlight="white"
+
+# -----------------------------------------------------------------
+# DO NOT MODIFY ANYTHING BEYOND THIS LINE!
+# -----------------------------------------------------------------
+
+
+# bash check
+if [ -z "$BASH" ]; then
+ printf "\`BASH' variable is not available. Not running bash?\n" >&2
+ exit 1
+fi
+
+# shell settings
+shopt -s extglob
+set -f
+set +o posix
+set +u
+
+# variables
+export LC_ALL=C
+readonly version=2.6
+readonly me="${0//*\//}"
+readonly oIFS="$IFS"
+declare ips_version="" str_search="" str_match_on_msum="" str_xclude="" opt str_hval str_op
+declare -i show_all=show_count=show_members=headers_only=names_only=isolate=calc_mem=count_sets=sets_total=0
+declare -i match_on_header=glob_search=regex_search=member_count=match_count=do_count=0
+declare -i exclude_header=glob_xclude_element=glob_xclude_element=exclude_set=0
+declare -i in_header=found_set=found_hxclude=found_sxclude=xclude_count=mem_total=mem_tmp=set_count=sets_sum=i=x=idx=0
+declare -a arr_sets arr_par arr_hcache arr_mcache arr_hsearch arr_hsearch_int arr_hxclude arr_sxclude
+
+# functions
+ex_miss_optarg() {
+printf "%s of option \`%s' is missing\n" "$2" "$1" >&2
+exit 2
+}
+
+ex_invalid_usage() {
+printf "%s\n" "$*" >&2
+exit 2
+}
+
+is_int() {
+[[ $1 = +([[:digit:]]) ]]
+}
+
+is_compare_str() {
+[[ $1 = ?(\!|<|>|<=|>=)+([[:digit:]]) ]]
+}
+# -----------------------------------------------------------------
+
+# validate value of colorize
+if [[ ${colorize:=0} != [01] ]]; then
+ ex_invalid_usage "value of variable \`colorize' \`$colorize' is not 0 or 1."
+fi
+
+# parse cmd-line options
+while (($#)); do
+ case "$1" in
+ -\?|-h) printf "\n\tipset set listing wrapper script\n\n"
+ printf '%s [option [opt-arg]] [set-name] [...]\n\n' "$me"
+ printf '%s %s\n' "$me" "{-?|-h} | -n"
+ printf '%s %s\n\t%s\n' "$me" "[-i|-r|-s|-Co] [-d char] [-To value]"\
+ "[{-Fg|-Fr}|{-Xg|-Xr} pattern] set-name"
+ printf '%s %s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n' "$me"\
+ "[-t|-c|-Co|-Cs|-Tm|-Ts] [-Fh header-glob:value-glob] [...]"\
+ "[-Fi header-glob:[!|<|>|<=|>=]value] [...]"\
+ "[-Fg|-Fr pattern] [-Ht type-glob]"\
+ "[-Hr|-Hs|-Hv [!|<|>|<=|>=]value]"\
+ "[-Mc [!|<|>|<=|>=]value] [-To value]"\
+ "[-Xh header-glob:value-glob] [...]"\
+ "[-Xs setname-glob] [...] [set-name] [...]"
+ printf '%s %s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n' "$me"\
+ "[-a|-c|-m|-r|-s|-Co|-Cs|-Tm|-Ts] [-d char]"\
+ "[-Fh header-glob:value-glob] [...]"\
+ "[-Fi header-glob:[!|<|>|<=|>=]value] [...]"\
+ "[-Fg|-Fr pattern] [-Ht type-glob]"\
+ "[-Hr|-Hs|-Hv [!|<|>|<=|>=]value]"\
+ "[-Mc [!|<|>|<=|>=]value] [-To value]"\
+ "[-Xh header-glob:value-glob] [...]"\
+ "[-Xg|-Xr pattern] [-Xs setname-glob] [...] [set-name] [...]"
+ printf 'options:\n'
+ printf '%-13s%s\n' '-a' 'show all information but with default delim (whitespace).'\
+ '-c' 'calculate members and match (-Fg|-Fr) sum.'\
+ '-d delim' 'delimiter character for separating member entries.'\
+ '-h|-?' 'show this help text.'\
+ '-i' 'show only the members of a single set.'\
+ '-m' 'show set members.'\
+ '-n' "show set names only (raw \`ipset list -n' output)."\
+ '-r' 'try to resolve ip addresses in the output (slow!).'\
+ '-s' 'print elements sorted (if supported by the set type).'\
+ '-t' 'show set headers only.'\
+ '-v' 'version information.'\
+ '-Co' "colorize output (requires \`cl')."\
+ '-Cs' 'count amount of matching sets.'\
+ '-Fg pattern' 'match on members using a [ext]glob pattern.'\
+ '-Fr pattern' 'match on members using a regex (=~ operator) pattern.'
+ printf '%s\n\t%s\n' '-Fh header-glob:value-glob [...]'\
+ 'show sets containing one or more [ext]glob matching headers.'
+ printf '%s\n\t%s\n' '-Fi header-glob:[!|<|>|<=|>=]value [...]'\
+ 'show sets matching one or more integer valued header entries.'
+ printf '%-24s%s\n' '-Ht set-type-glob' 'match on set type.'\
+ '-Hr [!|<|>|<=|>=]value' 'match on number of references (value=int).'\
+ '-Hs [!|<|>|<=|>=]value' 'match on size in memory (value=int).'\
+ '-Hv [!|<|>|<=|>=]value' 'match on revision number (value=int).'\
+ '-Mc [!|<|>|<=|>=]value' 'match on member count (value=int).'
+ printf '%-13s%s\n' '-Tm' 'calculate total memory usage of all matching sets.'\
+ '-To' 'set timeout value (int) for read (listing sets).'\
+ '-Ts' 'count amount of traversed sets.'
+ printf '%s\n\t%s\n' '-Xh header-glob:value-glob [...]'\
+ 'exclude one or more [ext]glob matching header entries.'
+ printf '%-13s%s\n' '-Xg pattern' 'exclude members matching a [ext]glob pattern.'\
+ '-Xr pattern' 'exclude members matching a regex pattern.'\
+ '-Xs pattern' 'exclude sets matching a [ext]glob pattern.'
+ exit 0
+ ;;
+ -a) show_all=1 # like `ipset list', but with $delim as delim
+ shift
+ ;;
+ -c) show_count=1 # show sum of member entries
+ shift
+ ;;
+ -i) isolate=1 # show only members of a single set
+ shift
+ ;;
+ -m) show_members=1 # show set members
+ shift
+ ;;
+ -n) names_only=1 # only list set names
+ shift
+ ;;
+ -t) headers_only=1 # show only set headers
+ shift
+ ;;
+ -s|-r) arr_par[i++]="$1" # ipset sort & resolve options are passed on
+ shift
+ ;;
+ -d) # delimiter char for separating member entries
+ [[ $2 ]] || ex_miss_optarg $1 "delim character"
+ if ((${#2} > 1)); then
+ ex_invalid_usage "only one character is allowed as delim"
+ fi
+ delim="$2"
+ shift 2
+ ;;
+ -o) if [[ $2 != plain ]]; then
+ ex_invalid_usage "only plain output is supported"
+ else
+ shift 2
+ fi
+ ;;
+ -Cs) count_sets=1 # calculate total count of matching sets
+ shift
+ ;;
+ -Co) colorize=1 # colorize the output (requires cl)
+ shift
+ ;;
+ -Fg) glob_search=1 # find entry with globbing pattern
+ [[ $2 ]] || ex_miss_optarg $1 "glob pattern"
+ str_search="$2"
+ shift 2
+ ;;
+ -Fr) regex_search=1 # find entry with regex pattern
+ [[ $2 ]] || ex_miss_optarg $1 "regex pattern"
+ str_search="$2"
+ shift 2
+ ;;
+ -Fh) let match_on_header+=1 # show only sets, which contain a matching header entry
+ [[ $2 ]] || ex_miss_optarg $1 "header pattern"
+ if [[ $2 = *:* ]]; then
+ arr_hsearch[x++]="$2"
+ shift 2
+ else
+ ex_invalid_usage "invalid format of header descriptor. expecting: \`*:*'"
+ fi
+ ;;
+ -Fi) let match_on_header+=1 # show only sets, containing a matching (int compare) header entry
+ [[ $2 ]] || ex_miss_optarg $1 "header pattern"
+ if is_compare_str "$2"; then
+ arr_hsearch_int[idx++]="$2"
+ shift 2
+ else
+ ex_invalid_usage "invalid format of header descriptor. expecting: \`name:[!|<|>|<=|>=]value'"
+ fi
+ ;;
+ -Hr) let match_on_header+=1 # shortcut for -Fi References:...
+ [[ $2 ]] || ex_miss_optarg $1 "header pattern"
+ if is_compare_str "$2"; then
+ arr_hsearch_int[idx++]="References:$2"
+ shift 2
+ else
+ ex_invalid_usage "invalid format of references header descriptor. expecting: \`[!|<|>|<=|>=]value'"
+ fi
+ ;;
+ -Hs) let match_on_header+=1 # shortcut for -Fi "Size in Memory:..."
+ [[ $2 ]] || ex_miss_optarg $1 "header pattern"
+ if is_compare_str "$2"; then
+ arr_hsearch_int[idx++]="Size in memory:$2"
+ shift 2
+ else
+ ex_invalid_usage "invalid format of memsize header descriptor. expecting: \`[!|<|>|<=|>=]value'"
+ fi
+ ;;
+ -Ht) let match_on_header+=1 # shortcut for -Fh Type:x:y
+ [[ $2 ]] || ex_miss_optarg $1 "header pattern"
+ if [[ $2 = *:* ]]; then
+ arr_hsearch[x++]="Type:$2"
+ shift 2
+ else
+ ex_invalid_usage "invalid format of set type descriptor. expecting: \`*:*'."
+ fi
+ ;;
+ -Hv) let match_on_header+=1 # shortcut for -Fi Revision:...
+ [[ $2 ]] || ex_miss_optarg $1 "header pattern"
+ if is_compare_str "$2"; then
+ arr_hsearch_int[idx++]="Revision:$2"
+ shift 2
+ else
+ ex_invalid_usage "invalid format of revision header descriptor. expecting: \`[!|<|>|<=|>=]value'"
+ fi
+ ;;
+ -Mc) do_count=1 # match on the count of members
+ [[ $2 ]] || ex_miss_optarg $1 "value pattern"
+ if is_compare_str "$2"; then
+ str_match_on_msum="$2"
+ shift 2
+ else
+ ex_invalid_usage "invalid format of match on member count value. expecting: \`[!|<|>|<=|>=]value'"
+ fi
+ ;;
+ -To) # set the timeout for read (limited to integer)
+ [[ $2 ]] || ex_miss_optarg $1 "value"
+ TMOUT=$2
+ shift 2
+ ;;
+ -Tm) calc_mem=1 # caculate total memory usage of all matching sets
+ shift
+ ;;
+ -Ts) sets_total=1 # caculate sum of all traversed sets
+ shift
+ ;;
+ -Xh) exclude_header=1 # don't show certain headers
+ [[ $2 ]] || ex_miss_optarg $1 "header pattern"
+ if [[ $2 = *:* ]]; then
+ arr_hxclude[${#arr_hxclude[@]}]="$2"
+ shift 2
+ else
+ ex_invalid_usage "invalid format of header descriptor. expecting: \`*:*'"
+ fi
+ ;;
+ -Xg) glob_xclude_element=1 # suppress printing of matching members using a globbing pattern
+ [[ $2 ]] || ex_miss_optarg $1 "glob pattern"
+ str_xclude="$2"
+ shift 2
+ ;;
+ -Xr) regex_xclude_element=1 # suppress printing of matching members using a regex pattern
+ [[ $2 ]] || ex_miss_optarg $1 "regex pattern"
+ str_xclude="$2"
+ shift 2
+ ;;
+ -Xs) exclude_set=1 # don't show certain sets
+ [[ $2 ]] || ex_miss_optarg $1 "set name ([ext]glob pattern)"
+ arr_sxclude[${#arr_sxclude[@]}]="$2"
+ shift 2
+ ;;
+ -\!|-f) ex_invalid_usage "unsupported option: \`$1'"
+ ;;
+ -v) printf "%s version %s\n" "$me" "$version"
+ exit 0
+ ;;
+ *) break
+ esac
+done
+declare -i i=x=idx=0
+
+# check for ipset program and version
+[[ -x ${ipset:=/sbin/ipset} ]] || {
+ printf "ipset binary \`%s' does not exist, or is not executable. check \`ipset' variable\n" "$ipset" >&2
+ exit 1
+}
+ips_version="$("$ipset" --version)"
+ips_version="${ips_version#ipset v}"
+ips_version="${ips_version%%.*}"
+if ! is_int "$ips_version"; then
+ printf "failed retrieving ipset version. expected digits, got: \`%s'\n" "$ips_version" >&2
+ exit 1
+fi
+if ((ips_version < 6)); then
+ printf "found version \`%s' - ipset versions from 6.x and upwards are supported\n" "$ips_version" >&2
+ exit 1
+fi
+
+# validate TMOUT variable
+if [[ $TMOUT ]] && ! is_int "$TMOUT"; then
+ ex_invalid_usage "timeout value \`$TMOUT' is not an integer"
+fi
+
+# option logic
+if ((names_only)); then
+ if ((headers_only||show_count||show_members||show_all||isolate||\
+ match_on_header||do_count||glob_search||regex_search||calc_mem||\
+ glob_xclude_element||regex_xclude_element||count_sets||sets_total||exclude_set))
+ then
+ ex_invalid_usage "option -n does not allow another option"
+ fi
+ # raw ipset output
+ "$ipset" list -n
+ exit $?
+fi
+if ((headers_only)); then
+ if ((show_members || show_all || isolate)); then
+ ex_invalid_usage "options -t and -a|-i|-m are mutually exclusive"
+ fi
+fi
+if ((isolate)); then
+ if ((show_count||show_all||calc_mem||count_sets||sets_total||exclude_set)); then
+ ex_invalid_usage "options -i and -a|-c|-Cs|-Tm|-Ts|-Xs are mutually exclusive"
+ fi
+ if ((match_on_header)); then
+ ex_invalid_usage "option -i does not allow matching on header entries"
+ fi
+fi
+if ((glob_search || regex_search)); then
+ if ((glob_search && regex_search)); then
+ ex_invalid_usage "options -Fg and -Fr are mutually exclusive"
+ fi
+ if ((glob_xclude_element || regex_xclude_element)); then
+ ex_invalid_usage "options -Fg|-Fr and -Xg|-Xr are mutually exclusive"
+ fi
+fi
+if ((exclude_header)); then
+ if ! ((headers_only || show_all)); then
+ ex_invalid_usage "option -Xh requires -a or -t"
+ fi
+fi
+if ((glob_xclude_element || regex_xclude_element)); then
+ if ! ((show_members || show_all || isolate)); then
+ ex_invalid_usage "options -Fg|-Fr require any of -a|-i|-m"
+ fi
+fi
+if ((colorize)); then
+ if ! [[ -x ${cl:=/usr/local/bin/cl} ]]; then
+ printf "cl program \`%s' does not exist, or is not executable. check \`cl' variable\n" "$cl" >&2
+ exit 1
+ fi
+ # set color defaults if unset
+ : ${col_fg:=white}
+ : ${col_bg:=black}
+ : ${col_headers:=cyan}
+ : ${col_members:=yellow}
+ : ${col_match:=red}
+ : ${col_memsize:=green}
+ : ${col_set_count:=magenta}
+ : ${col_set_total:=blue}
+ : ${col_highlight:=white}
+
+ # check if color defines are valid
+ for opt in col_fg col_bg col_headers col_members col_match col_memsize \
+ col_set_count col_set_total col_highlight
+ do
+ ($cl ${!opt}) || ex_invalid_usage "variable \`$opt' has an invalid color value: \`${!opt}'"
+ done
+ [[ -t 1 ]] || colorize=0 # output is not a terminal
+fi
+
+# sets to work on (no arg means all sets)
+while IFS=$'\n' read -r; do
+ arr_sets[idx++]="$REPLY"
+done < <("$ipset" list -n)
+if ! ((${#arr_sets[@]})); then
+ printf "Cannot find any sets\n" >&2
+ exit 1
+fi
+if [[ $1 ]]; then # there are remaining arg(s)
+ for opt in "$@"; do found_set=0 # check if the sets exist
+ for idx in ${!arr_sets[@]}; do
+ if [[ $opt = ${arr_sets[idx]} ]]; then found_set=1
+ break
+ fi
+ done
+ if ! ((found_set)); then
+ ex_invalid_usage "\`$opt' is not a valid option nor an existing set name"
+ fi
+ done
+ if ((isolate)); then
+ if (($# != 1)); then
+ ex_invalid_usage "option -i is only valid for a single set"
+ fi
+ fi
+ arr_sets=("$@") # reassign remaining args
+else
+ if ((isolate)); then
+ ex_invalid_usage "option -i is only valid for a single set"
+ fi
+fi
+
+# read sets
+for idx in "${!arr_sets[@]}"; do found_set=0 arr_hcache=() arr_mcache=()
+ while read -r || {
+ (($? > 128)) && \
+ printf "timeout reached or signal received, while reading set \`%s'.\n" \
+ "${arr_sets[idx]}" >&2 && continue 2;
+ }; do
+ case "$REPLY" in
+ "") : ;;
+ Name:*) # header opened (set found)
+ if ((in_header)); then
+ printf "unexpected entry: \`%s' - header not closed?\n" "$REPLY" >&2
+ exit 1
+ fi
+ let sets_sum+=1
+ if ((exclude_set)); then # don't show certain sets
+ for x in ${!arr_sxclude[@]}; do
+ if [[ ${arr_sets[idx]} = ${arr_sxclude[x]} ]]; then let found_sxclude+=1
+ continue 3 # don't unset, as user could list sets multiple times
+ fi
+ done
+ fi
+ in_header=1 found_set=1 found_header=0 member_count=0 match_count=0 xclude_count=0 mem_tmp=0 i=0 x=0
+ if ! ((isolate)); then # if showing members only, continue without saving any header data
+ if ! ((headers_only||show_members||show_all||show_count||match_on_header||do_count||calc_mem||glob_search||regex_search))
+ then
+ in_header=0
+ if ((colorize)); then
+ arr_hcache[x++]="$($cl bold $col_headers)${REPLY}$($cl normal $col_fg $col_bg)"
+ else
+ arr_hcache[x++]="$REPLY"
+ fi
+ break # nothing to show but the names
+ else
+ if ((colorize)); then
+ arr_hcache[x++]=$'\n'"$($cl bold $col_headers)${REPLY}$($cl normal $col_fg $col_bg)"
+ else
+ arr_hcache[x++]=$'\n'"$REPLY"
+ fi
+ fi
+ fi
+ ;;
+ Members:*) # closes header (if not `ipset -t')
+ if ! ((in_header)); then
+ printf "unexpected entry: \`%s' - header not opened?\n" "$REPLY" >&2
+ exit 1
+ fi
+ in_header=0 found_hxclude=0
+ if ((match_on_header)); then
+ if ((found_header != match_on_header)); then found_set=0
+ break # set does not contain wanted header
+ fi
+ fi
+ if ((exclude_header)); then # don't show certain headers
+ for idx in ${!arr_hxclude[@]}; do
+ if [[ ${REPLY%%:*} = ${arr_hxclude[idx]%%:*} && ${REPLY#*: } = ${arr_hxclude[idx]#*:} ]]
+ then found_hxclude=1
+ break
+ fi
+ done
+ fi
+ if ((show_all && ! found_hxclude)); then
+ if ((colorize)); then
+ arr_hcache[x++]="$($cl bold $col_headers)${REPLY}$($cl normal $col_fg $col_bg)"
+ else
+ arr_hcache[x++]="$REPLY"
+ fi
+ fi
+ ;;
+ *) # either in-header, or member entry
+ if ! ((found_set)); then
+ printf "no set opened by \`Name:'. unexpected entry \`%s'.\n" "$REPLY" >&2
+ exit 1
+ fi
+ if ((in_header)); then # we should be in the header
+ if ((match_on_header && found_header < match_on_header)); then # match on an header entry
+ for idx in ${!arr_hsearch[@]}; do # string compare
+ if [[ ${REPLY%%:*} = ${arr_hsearch[idx]%%:*} && ${REPLY#*: } = ${arr_hsearch[idx]#*:} ]]
+ then let found_header+=1
+ fi
+ done
+ for idx in ${!arr_hsearch_int[@]}; do # int compare
+ if [[ ${REPLY%%:*} = ${arr_hsearch_int[idx]%%:*} ]]; then # header name matches
+ if ! is_int "${REPLY#*: }"; then
+ printf "header value \`%s' is not an integer.\n" "${REPLY#*: }" >&2
+ exit 1
+ fi
+ str_hval="${arr_hsearch_int[idx]#*:}"
+ str_op="${str_hval//[[:digit:]]}" # compare operator defaults to `=='
+ [[ ${str_op:===} = \! ]] && str_op='!='
+ if ((${REPLY#*: } $str_op ${str_hval//[[:punct:]]})); then
+ let found_header+=1
+ fi
+ fi
+ done
+ fi
+ if ((calc_mem)); then
+ if [[ ${REPLY%%:*} = "Size in memory" ]]; then
+ if ! is_int "${REPLY#*: }"; then
+ printf "header value \`%s' is not an integer.\n" "${REPLY#*: }" >&2
+ exit 1
+ fi
+ # save to temp, in case we throw away the set, if it doesn't match other criteria
+ mem_tmp=${REPLY#*: }
+ fi
+ fi
+ if ((headers_only || show_all)); then found_hxclude=0
+ if ((exclude_header)); then # don't show certain headers
+ for idx in ${!arr_hxclude[@]}; do
+ if [[ ${REPLY%%:*} = ${arr_hxclude[idx]%%:*} && ${REPLY#*: } = ${arr_hxclude[idx]#*:} ]]
+ then found_hxclude=1
+ break
+ fi
+ done
+ fi
+ if ! ((found_hxclude)); then
+ arr_hcache[x++]="$REPLY"
+ fi
+ fi
+ else # this should be a member entry
+ if ((show_members || show_all || isolate || glob_search || regex_search)); then
+ if ((glob_search)); then # show sets with matching members
+ if [[ $REPLY = $str_search ]]; then let match_count+=1
+ if ((show_members || show_all || isolate)); then
+ arr_mcache[i++]="$REPLY"
+ fi
+ fi
+ elif ((regex_search)); then # show sets with matching members
+ if [[ $REPLY =~ $str_search ]]; then let match_count+=1
+ if ((show_members || show_all || isolate)); then
+ arr_mcache[i++]="$REPLY"
+ fi
+ fi
+ else
+ if ((glob_xclude_element)); then # exclude matching members
+ if ! [[ $REPLY = $str_xclude ]]; then
+ arr_mcache[i++]="$REPLY"
+ else let xclude_count+=1
+ fi
+ elif ((regex_xclude_element)); then # exclude matching members
+ if ! [[ $REPLY =~ $str_xclude ]]; then
+ arr_mcache[i++]="$REPLY"
+ else let xclude_count+=1
+ fi
+ else
+ arr_mcache[i++]="$REPLY"
+ fi
+ fi
+ else # nothing to show or search for, do we need to count members?
+ if ! ((show_count || do_count)); then
+ break # nothing more to do for this set
+ fi
+ fi
+ let member_count+=1
+ fi
+ esac
+ done < <("$ipset" list "${arr_sets[idx]}" "${arr_par[@]}")
+ if ((found_set)); then # print gathered information
+ if ((glob_search || regex_search)) && ((match_count == 0)); then
+ continue # glob or regex search didn't match
+ fi
+ if [[ $str_match_on_msum ]]; then # match on member sum
+ str_op="${str_match_on_msum//[[:digit:]]}"
+ [[ ${str_op:===} = \! ]] && str_op='!='
+ if ! (($member_count $str_op ${str_match_on_msum//[[:punct:]]})); then
+ continue # does not match
+ fi
+ fi
+ let set_count+=1 # count amount of matching sets
+ if ((calc_mem)); then
+ let mem_total+=$mem_tmp
+ fi
+ if ((${#arr_hcache[@]})); then
+ if ((colorize)); then
+ printf "$($cl $col_headers)%b$($cl normal $col_fg $col_bg)\n" "${arr_hcache[@]}"
+ else
+ printf "%s\n" "${arr_hcache[@]}"
+ fi
+ fi
+ if ((${#arr_mcache[@]})); then
+ IFS="${delim:= }"
+ if ((colorize)); then
+ printf "$($cl $col_members)%s$($cl normal $col_fg $col_bg)" "${arr_mcache[*]}"
+ else
+ printf "%s" "${arr_mcache[*]}"
+ fi
+ IFS="$oIFS"
+ printf "\n"
+ fi
+ if ((show_count)); then
+ if ((glob_search || regex_search)); then
+ if ((colorize)); then
+ printf "$($cl $col_match)Match count$($cl normal $col_fg $col_bg):\
+ $($cl bold $col_match)%d$($cl normal $col_fg $col_bg)\n" $match_count
+ else
+ printf "Match count: %d\n" $match_count
+ fi
+ fi
+ if ((glob_xclude_element || regex_xclude_element)); then
+ if ((colorize)); then
+ printf "$($cl $col_match)Exclude count$($cl normal $col_fg $col_bg):\
+ $($cl bold $col_match)%d$($cl normal $col_fg $col_bg)\n" $xclude_count
+ else
+ printf "Exclude count: %d\n" $xclude_count
+ fi
+ fi
+ if ((colorize)); then
+ printf "$($cl bold $col_highlight)Member count$($cl normal $col_fg $col_bg):\
+ $($cl bold $col_members)%d$($cl normal $col_fg $col_bg)\n" $member_count
+ else
+ printf "Member count: %d\n" $member_count
+ fi
+ fi
+ fi
+done
+if ((count_sets || calc_mem || sets_total || exclude_set)); then
+ printf "\n"
+ if ((count_sets)); then
+ if ((colorize)); then
+ printf "$($cl bold $col_highlight)Count$($cl normal $col_fg $col_bg) of all\
+ $($cl bold $col_set_count)matched sets$($cl normal $col_fg $col_bg):\
+ $($cl bold $col_set_count)%d$($cl normal $col_fg $col_bg)\n" $set_count
+ else
+ printf "Count of all matched sets: %d\n" $set_count
+ fi
+ if ((exclude_set)); then
+ if ((colorize)); then
+ printf "$($cl bold $col_highlight)Count$($cl normal $col_fg $col_bg) of all\
+ $($cl bold $col_match)excluded sets$($cl normal $col_fg $col_bg):\
+ $($cl bold $col_match)%d$($cl normal $col_fg $col_bg)\n" $found_sxclude
+ else
+ printf "Count of all excluded sets: %d\n" $found_sxclude
+ fi
+ fi
+ fi
+ if ((sets_total)); then
+ if ((colorize)); then
+ printf "$($cl bold $col_highlight)Count$($cl normal $col_fg $col_bg) of all\
+ $($cl bold $col_set_total)traversed sets$($cl normal $col_fg $col_bg):\
+ $($cl bold $col_set_total)%d$($cl normal $col_fg $col_bg)\n" $sets_sum
+ else
+ printf "Count of all traversed sets: %d\n" $sets_sum
+ fi
+ fi
+ if ((calc_mem)); then
+ if ((colorize)); then
+ printf "$($cl bold $col_memsize)Total memory size$($cl normal $col_fg $col_bg)\
+ of all matched sets: $($cl bold $col_memsize)%d$($cl normal $col_fg $col_bg)\n" $mem_total
+ else
+ printf "Total memory size of all matched sets: %d\n" $mem_total
+ fi
+ fi
+fi
|
[-]
[+]
|
Added |
ipset-6.17.tar.xz/utils/ipset_list/ipset_list_bash_completion
^
|
@@ -0,0 +1,203 @@
+#!/bin/bash
+
+# -----------------------------------------------------------------
+# ipset set listing wrapper script
+#
+# https://github.com/AllKind/ipset_list
+# https://sourceforge.net/projects/ipset-list/
+# -----------------------------------------------------------------
+
+# Copyright (C) 2013 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
+
+_remove_reply_entry() {
+local -i x
+while (($#)); do
+ for x in ${!COMPREPLY[@]}; do
+ if [[ ${COMPREPLY[x]} = $1 ]]; then
+ unset COMPREPLY[x]
+ break
+ fi
+ done
+ shift
+done
+}
+
+_ipset_list_complete() {
+local -i i=x=show_all=isolate=show_members=resolve=headers_only=0
+local cur prev
+local sets=()
+sets=( $("$ipset_list" -n ) )
+local opts=(-? -a -c -d -h -i -m -n -r -s -t -v)
+local Copts=(-Cs -Co)
+local Fopts=(-Fh -Fi -Fg -Fr)
+local Hopts=(-Hr -Hs -Ht -Hv)
+local Topts=(-Tm -To -Ts)
+local Xopts=(-Xh -Xg -Xr -Xs)
+
+: ${PATH:=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin}
+
+COMPREPLY=()
+_get_comp_words_by_ref cur || return
+_get_comp_words_by_ref prev || return
+
+#DEBUG=Y
+if [[ $DEBUG ]]; then
+ printf "\ncur: <%s> prev: <%s>\n" "$cur" "$prev"
+ printf "COMP_WORDS:\n"
+ printf "<%s>\n" "${COMP_WORDS[@]}"
+fi
+
+# dont' allow an option after the set name(s)
+if [[ $cur = -* ]]; then
+ for i in ${!sets[@]}; do
+ [[ ${sets[i]} = $prev ]] && return 0
+ done
+fi
+# some options allow only a subset of other options
+for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do
+ case "${COMP_WORDS[i]}" in
+ -a) show_all=1 ;;
+ -i) isolate=1 ;;
+ -m) show_members=1 ;;
+ -r) resolve=1 ;;
+ -t) headers_only=1 ;;
+ -\?|-h|-n|-v)
+ return 0
+ ;;
+ esac
+done
+# invalid combinations of options
+if ((headers_only)); then
+ if ((show_all || show_members || isolate || resolve)); then
+ return 0
+ fi
+elif ((isolate && show_all)); then
+ return 0
+fi
+
+case "$cur" in
+ -C) COMPREPLY=( ${Copts[@]} $cur )
+ for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do # no set counting on -i
+ if [[ ${COMP_WORDS[i]} = -i ]]; then
+ COMPREPLY=( -Co )
+ break
+ fi
+ done
+ ;;
+ -F) COMPREPLY=( ${Fopts[@]} ) ;;
+ -H) COMPREPLY=( ${Hopts[@]} ) ;;
+ -M) COMPREPLY=( -Mc ) ;;
+ -T) COMPREPLY=( ${Topts[@]} ) ;;
+ -X) COMPREPLY=( ${Xopts[@]} ) ;;
+ -*) # any option is requested
+ case "$prev" in # options that exclude any other option, or need a value we can't predict
+ @(-@(\?|d|h|n|v|Fg|Fh|Fi|Fr|Ht|Hr|Hs|Hv|Mc|To|Xg|Xh|Xr)))
+ return 0
+ ;;
+ esac
+ if ((${#COMP_WORDS[@]} > 2)); then # these options don't allow any other
+ opts=("${opts[@]/@(-n|-h|-\?)/}")
+ fi
+ # some options allow only a subset of other options
+ if ((isolate)); then
+ COMPREPLY=( -Co -d -r -s $cur )
+ elif ((headers_only)); then
+ COMPREPLY=( -c ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]} )
+ elif ((show_members)); then
+ COMPREPLY=( -c -d -r -s ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} )
+ elif ((show_all)); then
+ COMPREPLY=( -c -d -r -s ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]} )
+ elif ((resolve)); then
+ COMPREPLY=( -a -c -d -s -m ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]} )
+ else
+ COMPREPLY=( ${opts[@]} ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]} )
+ fi
+ ;;
+ *) # not an option was requested
+ COMPREPLY=( $( compgen -W '${sets[@]}' -- $cur ) )
+ case "$prev" in
+ -Xh) # retrieve list of headers
+ COMPREPLY=()
+ 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'
+ COMPREPLY=( $( compgen -P '"' -S ':*"' -W '${COMPREPLY[@]}' -- $cur ) )
+ ;;
+ @(-@(Hr|Hs|Hv|Mc))) # options making use of arithmetic comparison
+ compopt -o nospace
+ COMPREPLY=( '\!' '\<' '\>' '\<=' '\>=' )
+ ;;
+ @(-@(\?|d|h|n|v|Fg|Fh|Fi|Fr|Ht|To|Xg|Xr))) COMPREPLY=() ;;
+ esac
+ if ((isolate)); then # allow only one set with isolate
+ for i in ${!sets[@]}; do
+ if [[ ${sets[i]} = $prev ]]; then
+ COMPREPLY=()
+ break
+ fi
+ done
+ fi
+esac
+if ((${#COMPREPLY[@]})); then # post process the reply
+ for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do # mutual exclusive options
+ case "${COMP_WORDS[i]}" in
+ -Fg) _remove_reply_entry "-Fr" "-Xg" "-Xr" ;;
+ -Fr) _remove_reply_entry "-Fg" "-Xg" "-Xr" ;;
+ -Xg) _remove_reply_entry "-Fg" "-Fr" "-Xr" ;;
+ -Xr) _remove_reply_entry "-Fg" "-Fr" "-Xg" ;;
+ esac
+ done
+ for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do # remove options that can only be used once
+ if [[ ${COMP_WORDS[i]} = @(""|-|-@(Fh|Fi|Xh|Xs)) ]]; then
+ continue
+ else
+ for x in ${!COMPREPLY[@]}; do
+ if [[ ${COMP_WORDS[i]} = ${COMPREPLY[x]} ]]; then
+ unset COMPREPLY[$x]
+ break
+ fi
+ done
+ fi
+ done
+fi
+if [[ $DEBUG ]]; then
+ printf "COMPREPLY:\n"
+ printf "<%s>\n" "${COMPREPLY[@]}"
+fi
+}
+complete -F _ipset_list_complete "$ipset_list"
+
|