[Bash-completion-devel] squashing bug #311844 (completion for /sbin/tc)
Raphaël Droz
raphael.droz+floss at gmail.com
Sun Nov 20 17:55:47 UTC 2011
I'm back with this one:
http://alioth.debian.org/tracker/index.php?func=detail&aid=311844&group_id=100114&atid=413095
http://www.mail-archive.com/bash-completion-devel@lists.alioth.debian.org/msg01042.html
I reworked the whole so that it's far more readable/reviewable, even
with its 900 LOC.
I've kept some _tc_error which indicate unimplemented completion
paths but, if removed, anyone using tc should appreciate this completion
in its current shape.
The the most missing part is about the "action" object where almost all
has still to be done.
but other than that it is fairly usable, advises welcomed
[ files attached, tc-* helpers living into helpers/ ]
Git:
http://gitorious.org/drzraf/bash-completion/blobs/master/completions/tc
http://gitorious.org/drzraf/bash-completion/trees/master/helpers
Raph
-------------- next part --------------
# tc(8) langu^Wcommand completion -*- shell-script -*-
# Rapha?l Droz <raphael.droz+floss at gmail.com>
_tc() {
. ${BASH_SOURCE[0]%/*}/../helpers/tc-helpers
. ${BASH_SOURCE[0]%/*}/../helpers/tc-qdisc
. ${BASH_SOURCE[0]%/*}/../helpers/tc-class
. ${BASH_SOURCE[0]%/*}/../helpers/tc-filter
. ${BASH_SOURCE[0]%/*}/../helpers/tc-action
local cur prev words cword
_init_completion || return
local object cmd objpos QDISC_KIND CLASS_QDISC_KIND i
QDISC_KIND="{p,b}fifo{,_fast} htb tbf prio cbq red sfq stab hfsc netem drr gred"
CLASS_QDISC_KIND='cbq dsmark drr hfsc htb'
# TODO: find a stable way to identify both categories, like
# CLASS_QDISC_KIND="$(_tc_getsched sch)"
# if i=1 after esac; then we'll have to deal with more complex things
let i=0
COMPREPLY=()
case $prev in
qdisc)
COMPREPLY+=( link )
;;&
qdisc|class|filter)
COMPREPLY+=( add del replace change show list ls help )
COMPREPLY=( $(compgen -W '${COMPREPLY[@]}' -- $cur ) )
;;
action|actions)
_tc-action
;;
monitor)
;;
-batch|-b)
_filedir
;;
rate|bandwidth|ceil|weight|peakrate)
if [[ -n $cur ]]; then
[[ ${cur:${#cur}-1:1} =~ k|K|m|M|g|G|b|B ]] &&
COMPREPLY=( $(compgen -W "${cur}{bit,ps}" -- $cur ) ) ||
COMPREPLY=( $(compgen -W "${cur}{b,k,m,g}{bit,bps}" -- $cur ) )
fi
;;
# TODO : max,min,limit also ?
burst|avpkt|mpu|cell|quantum|mtu|limit|max|min)
if [[ -n $cur ]]; then
[[ ${cur:${#cur}-1:1} =~ k|K|m|M|g|G|b ]] &&
COMPREPLY=( $(compgen -W "${cur}{bit,}" -- $cur ) ) ||
COMPREPLY=( $(compgen -W "${cur}{k,m,g,}{bit,}" -- $cur ) )
[[ ${cur:${#cur}-1:1} = a ]] && COMPREPLY=( )
fi
;;
linklayer)
# TODO
COMPREPLY=( atm )
;;
delay)
# TODO
COMPREPLY=( $(compgen -W "${cur}..." -- $cur ) )
;;
# TODO1: unsure this always applies
flowid|classid)
COMPREPLY=( $(compgen -W "$(_tc-handle-list class)" -- $cur ) )
;;
# TODO2: unsure this always apply
parent)
COMPREPLY=( $(compgen -W "$(_tc-handle-list parent)" -- $cur ) )
;;
# appends 'dev' if ${prev} is one of the following
# as compgen -W '...' -S ' dev' doesn't appear to work
# 'show' case is handled separatly later
add|del|replace|change|link|ls|list|show)
COMPREPLY=( $(compgen -W 'dev' -- $cur ) )
;;
# 'dev' keyword is always followed by an interface name
dev)
_available_interfaces
;;
*)
i=1
;;
esac
[[ $i -eq 0 ]] && return 0
# may be useful soon
object=$(_tc_get_arg_matching 'qdisc|class|filter|actions?|monitor' 1 5)
objpos=$?
cmd=${COMP_WORDS[$objpos+1]}
# to avoid (possible|futur|imaginary) confusion in the tc ocean
# in case we find some other dashed switches,
# so limit the impact of these tests to the case
# where the OBJECT is not yet defined
# (at the beginning of the command line)
# TODO: look for mutually exclusive option (are they all ?)
if [[ "$cur" == -* ]] && [[ -z $object ]]; then
COMPREPLY=( $( compgen -W '-s -stats -statistics -d -details -r -raw
-p -pretty -i -iec -batch -force' -- $cur ) )
return 0
# no case matched until now, we are at the very beginning of the cmdline
# maybe a duplicate of [ -z "$object" ] below
elif [[ $cword -eq 1 ]]; then
COMPREPLY=( $( compgen -W 'qdisc class filter action monitor' -- $cur ) )
return 0
fi
# here comes the hard stuff, no more $prev to dig around
# no more stones petit Poucet
# but hopefully, we just grabbed :
# - the OBJECT
# - its position
# and, as we go, ...
# the following command
[[ -z $object ]] && {
# TODO : OBJECT completion according to given switches
# because no OBJECT means a switch
COMPREPLY=( $( compgen -W 'qdisc class filter action monitor' -- $cur ) )
return 0
}
[[ -z $cmd ]] && COMPREPLY=( _tc_error5 ) && return
# grabs some common option which need an argument
# (they have a priority over the other cases)
# see TODO2
# _tc_in_cmd parent && ! _tc_has_args 'parent' 1 &&
# COMPREPLY=( $(compgen -W "$(_tc-handle-list qdisc)" -- $cur ) ) &&
# return 0
# see TODO1
# _tc_in_cmd classid && ! _tc_has_args 'classid' 1 &&
# COMPREPLY=( $(compgen -W "$(_tc-handle-list class)" -- $cur ) ) &&
# return 0
_tc_in_cmd handle && ! _tc_has_args 'handle' 1 && return 0
# we factor that stuff here rather than below
# it about handling all the keywords after the qdisc|class object
# but before a QDISC has been specified
if [[ $object =~ qdisc|class && $cmd != show ]]; then
# argument and kernel variable argument (see _tc-makecomp())
local arg qdisc excl
local strleft=()
[[ $object = qdisc ]] && {
arg='handle root ingress parent estimator stab help'
qdisc=$QDISC_KIND
excl='root ingress parent'
}
[[ $object = class ]] && {
arg='classid parent root help'
qdisc=$CLASS_QDISC_KIND
excl='root parent'
}
# if there is already a DQISC in the cmd, let's
# forget about $arg option and continue,
# they should have been
# specified before.
if ! _tc_in_cmd "$qdisc"; then
_tc-makecomp "$arg" "$qdisc" "$excl"
return 0
fi
fi
# others cases not treated above
case $object in
# TODO: the 'show' command is mostly common
# for 'qdisc' and 'filter' objects
qdisc)
_tc-qdisc "$cmd"
;;
class)
_tc-class "$cmd"
;;
filter)
_tc-filter "$cmd"
;;
action|actions)
_tc-action "$cmd"
;;
esac
return 0
} &&
complete -F _tc +o nospace tc
-------------- next part --------------
# tc(8) helpers -*- shell-script -*-
# Rapha?l Droz <raphael.droz+floss at gmail.com>
_tc_has_args() {
[[ $# -ne 2 ]] && return 1
local i j opt argnb
opt=$1 && shift
let argnb=$1
let i=1
# first search for this option
while (( $i <= $COMP_CWORD )); do
# found, let's have a look to its arguments now
if [[ ${COMP_WORDS[$i]} = $opt ]]; then
let j=$i+1
while (( $j <= $((i+$argnb)) )); do
# this one is null, returns 1
[[ -z ${COMP_WORDS[$j]} ]] && return 1
((j++))
done
# last but not least :
# either the next argument should exists
# either $COMP_CWORDS should be $j+1 to
# be sure a space has been appended
# It won't work with -o nospace
# or it will if -o nospace does increment
# $COMP_CWORD as does the default behavior (untested)
# echo -e "\n$opt, j=$j\nCOMP_WORDS[$((j-1))]=${COMP_WORDS[$j-1]}" > /dev/stderr
# echo -e "\nCOMP_WORDS[$j]=${COMP_WORDS[$j]}\nCOMP_CWORD=$COMP_CWORD passed" > /dev/stderr
[[ -n ${COMP_WORDS[$j]} ]] && return 0
# notice here that j had been given a final
# while-increment so it should be equal
# to the new CWORD
[[ $j -eq $COMP_CWORD ]] && return 0
return 1
fi
((i++))
done
return 1
}
# echoes the command line word from COMP_WORDS which matches
# the regexp in $1, optionally between "start" and "end" position
# returns the position or 255 if not found (no one should enter
# a 255 words long tc command line)
_tc_get_arg_matching() {
[[ -z $1 ]] && return 255
local let i=1 let limit=$COMP_CWORD let start=1
local aarg a
aarg=$1 && shift
[[ -n $1 ]] && { let start=$1; shift; }
[[ -n $1 ]] && { let limit=$1; shift; }
(( $limit > $COMP_CWORD )) && limit=$COMP_CWORD
(( $start < 1 )) && start=1
(( $start > $limit )) && {
a=$limit
limit=$start
start=$a
}
let i=$start
while (( $i < $limit )); do
if [[ ${COMP_WORDS[$i]} =~ $aarg ]]; then
echo ${COMP_WORDS[$i]}
return $i
fi
((i++))
done
return 255
}
# Returns 0 if the at least one of the words
# passed in the first argument is found in the cmdline.
# If a second argument "i" is given, the search starts
# from ${COMP_WORDS[$i]} instead of 1
_tc_in_cmd() {
[[ -z $1 ]] && return 1
local let i=0 j=0
local aarg=($(compgen -W "$1")) && shift
[[ -n $1 ]] && i=$1 && shift
while [ $((i++)) -lt $((COMP_CWORD-1)) ]; do
while (( $j < ${#aarg[@]} )); do
[[ ${COMP_WORDS[$i]} = ${aarg[$j]} ]] && {
#echo "${aarg[$j]} match ${COMP_WORDS[$i]} ($i)" > /dev/stderr
return 0
}
((j++))
done
j=0
done
return 1
}
_tc_dumpcmd() {
local let i=0
while [[ -n ${COMP_WORDS[$i]} ]]; do
echo ${COMP_WORDS[$((i++))]}
done
return
}
_tc_get-device() {
local let i=0
_tc_dumpcmd | \
while read f; do
[[ $i -eq 1 ]] && echo $f && break
[[ $f = dev ]] && i=1
done
[[ $i -eq 1 ]]
}
_tc_get-command() {
local let i=0
_tc_dumpcmd|while read f; do
[[ $i -eq 1 && $f =~ add|change|del(ete)?|replace|show|get|list|ls|flush ]] && \
echo $f && break
[[ $f =~ qdisc|class|filter|actions? ]] && i=1
done
(( $i == 1 ))
}
# list available kernel schedulers|actions|filters
_tc_getsched() {
echo $(ls /lib/modules/$(uname -r)/kernel/net/sched/$1_*.ko 2>/dev/null| \
sed "s/^.*$1_\([a-z0-9-]*\)\.ko/\1/")
}
# generate COMPREPLY being given
# some options candidate for completion
# some other options candidate for completion
# which won't be checked for duplication
# some options mutually exclusive
_tc-makecomp() {
# argument and kernel variable argument
local arg varg excl strleft=()
arg="$1" && shift
varg="$1" && shift
excl="$1" && shift
#echo -e "\n1=$arg\n2=$varg\n3=$excl" > /dev/stderr
for i in $arg; do
# if $i already in cmdline : skip it from compgen
# if :
# $i is part of the exclusive arguments
# and
# one of the exclusive arguments is already in the cmdline
# --> skip it from compgen
_tc_in_cmd "$i" || {
[[ $i =~ ${excl// /|} ]] && _tc_in_cmd "$excl"
} && continue
strleft+=($i)
done
COMPREPLY=( $(compgen -W "${strleft[*]} $varg" -- $cur ) )
}
# create a list of a given OBJECT for a given INTERFACE
# if no INTERFACE is given, it's guess with _tc_get-device
# if "all" is given as the INTERFACE, all interface are used
_tc-handle-list() {
local obj=$1 && shift
# default (no 2nd parameter, default to the current used interface)
local aif="dev $(_tc_get-device)"
# sadly, _known_interface should be usable outside the COMPREPLY :|
if [[ -n $1 ]]; then
aif="dev $1"
[ $aid = all ] && unset aif
fi
local tc
which tc &> /dev/null || tc=/sbin/tc # not root ?
if [[ $obj =~ qdisc|class|filter ]]; then
[[ $obj = qdisc ]] && $tc $obj show $aif|sed 's/^.* .* \([0-9a-f]\{1,4\}:\).*/\1/' 2>/dev/null
[[ $obj = class ]] && $tc $obj show $aif|sed 's/^.* .* \([0-9a-f]\{1,4\}:.\).*/\1/' 2>/dev/null
fi
return 0
}
-------------- next part --------------
# tc(8) qdisc helpers -*- shell-script -*-
# Rapha?l Droz <raphael.droz+floss at gmail.com>
_tc-qdisc() {
local cmd="$1" && shift
# show [ dev IF ] [ ingress ]
case $cmd in
show)
## TODO
## would have been really nice
## but the real principles of spaces law
#_available_interfaces
#a=${COMPREPLY[*]}
#COMPREPLY=()
#b=${a// /\\ ,}
# COMPREPLY=( $(compgen -S test -W "{dev\ {$b\ },}{ingress,}" -- $cur ) )
## bug even without "space bug" above
# COMPREPLY=( $(compgen -S test -W "{dev_{$b},}{ingress,}" -- $cur ) )
# old solution
if _tc_in_cmd dev; then
! _tc_has_args dev 1 && _available_interfaces || \
COMPREPLY=(ingress)
elif ! _tc_in_cmd ingress; then
COMPREPLY=(dev ingress)
fi
;;
# here we expect that the QDISC is already specified in
# the command line
*)
_tc-qdisc-qdisc && return 0
case $prev in
# may want to move this one in _tc()
# tc qdisc (add|change|replace|link) dev DEV stab <TAB>
stab)
COMPREPLY=(mtu tsize mpu overhead linklayer)
;;
*)
# very specific cases
# tc qdisc (add|change|replace|link) dev DEV netmem distribution <TAB>
if _tc_in_cmd netmem && [[ $prev = distribution ]]; then
COMPREPLY=(uniform normal pareto paretonormal)
else
COMPREPLY=( _tc_error1 )
return 0;
fi
;;
esac
;;
esac
COMPREPLY=( $(compgen -W '${COMPREPLY[@]}' -- $cur ) )
return 0
}
# command line like:
# tc qdisc (add|change|replace|link) dev DEV QDISC <TAB>
_tc-qdisc-qdisc() {
# accepted values from $(ls -1 iproute2-2.6.38/src/tc/q_*.c) are:
# atm cbq drr dsmark fifo gred hfsc htb ingress multiq netem prio red rr sfq tbf
case $prev in
atm|drr|dsmark|multiq|rr)
return 0
;;
# TODO {p,b}fifo_fast ?
bfifo|pfifo)
COMPREPLY=(limit)
;;
cbq)
# TODO : cell mpu ewma
COMPREPLY=(bandwidth avpkt)
;;
gred)
# not pretty
COMPREPLY=(setup DP limit min max avpkt burst probability bandwidth prio)
;;
hfsc)
COMPREPLY=(default)
;;
htb)
COMPREPLY=(default r2q debug)
;;
netem)
COMPREPLY=(limit delay distribution drop corrupt duplicate reorder gap)
;;
prio)
COMPREPLY=(bands priomap mutiqueue)
;;
red)
COMPREPLY=(limit min max avpkt burst probability bandwidth)
;;
sfq)
COMPREPLY=(limit perturb quantum)
;;
tbf)
COMPREPLY=(limit burst rate mtu peakrate latency overhead linklayer)
;;
# when the previous parameter is not a valid QDISC,
# we fallback on _tc-qdisc()
*)
return 1
;;
esac
COMPREPLY=( $(compgen -W '${COMPREPLY[@]}' -- $cur ) )
return 0
}
-------------- next part --------------
# tc(8) class helpers -*- shell-script -*-
# Rapha?l Droz <raphael.droz+floss at gmail.com>
_tc-class() {
local cmd="$1" && shift
# TODO: redundant with _tc()
local CLASS_QDISC_KIND='cbq dsmark drr hfsc htb'
# show [ dev IF ] [ ingress ]
case $cmd in
show)
COMPREPLY=( $(compgen -W 'dev root parent' -- $cur ) )
return 0
;;
esac
! _tc_in_cmd "$CLASS_QDISC_KIND" && {
COMPREPLY=( _tc_error2 )
return 0
}
local totest ret
# maybe we have something the filter can handle, give $cur to it
# even if not the previous word
totest=$(_tc_get_arg_matching "${CLASS_QDISC_KIND// /|}")
ret=$?
# otherwise let's test and throw an error
[ $ret -eq 255 ] && totest=$prev
case $totest in
cbq)
_tc-class-cbq
return 0
;;
dnmask)
COMPREPLY=(mask value)
;;
drr)
COMPREPLY=(quantum)
;;
hfsc)
_tc-class-cbq
return 0
;;
htb)
_tc-class-htb
return 0
;;
*)
COMPREPLY=( tc_error6 )
return 0
;;
esac
COMPREPLY=( $(compgen -W '${COMPREPLY[@]}' -- $cur ) )
return 0
}
_tc-class-cbq() {
case $prev in
cbq)
# TODO: not really correct
COMPREPLY=( $(compgen -W 'bandwidth rate maxburst' -- $cur ) )
;;
esac
return 0
}
_tc-class-hfsc() {
case $prev in
rt|ls|sc|ul)
# TODO
#COMPREPLY=( $( compgen -W '{1..9}' -- "$cur" ) )
;;
*)
COMPREPLY=( $(compgen -W 'rt ls sc ul' -- $cur ) )
;;
esac
return 0
}
_tc-class-htb() {
case $prev in
htb)
COMPREPLY=(rate burst mpu overhead prio
slot pslot ceil cburst mtu quantum)
;;
burst|mpu|overhead|prio|slot|pslot|ceil|cburst|mtu|quantum)
return 0
;;
*)
COMPREPLY=(burst mpu overhead prio slot pslot
ceil cburst mtu quantum)
;;
esac
COMPREPLY=( $(compgen -W '${COMPREPLY[@]}' -- $cur ) )
return 0
}
-------------- next part --------------
# tc(8) filter helpers -*- shell-script -*-
# Rapha?l Droz <raphael.droz+floss at gmail.com>
# filtering is a bit more complex than qdisc and class
_tc-filter() {
local cmd="$1" && shift
if [[ $cmd = show ]]; then
# old solution, see qdisc show in _tc-qdisc()
#TODO : use _tc_makecomp
#TODO : replace available_interface with those
# which contain a filter
if _tc_in_cmd dev; then
! _tc_has_args 'dev' 1 && _available_interfaces || \
COMPREPLY=( $(compgen -W 'root parent' -- $cur ) )
else
COMPREPLY=( $(compgen -W 'dev' -- $cur ) )
fi
return 0
fi
# WARN: this list depends on what has been compiled
# TODO: handle kernel builtin modules ?
local cls=$(_tc_getsched cls)
[[ -z ${cls[@]} ]] && \
cls="api basic cgroup flow fw route rsvp rsvp6 tcindex u32"
local filtertype filterpos
local PROTO='ip{v4,v6,} irda {r,}arp wan_ppp ppp{ses,disc}'
# TODO : parent is also accepted, before or after protocol
# need to look of the mutual exclusions
# TODO : prio is also accepted (at least after protocol)
if ! _tc_in_cmd protocol; then
COMPREPLY=(protocol)
_tc_in_cmd pref && COMPREPLY+=(pref)
COMPREPLY=( $(compgen -W '${COMPREPLY[@]}' -- $cur ) )
return 0
fi
if ! _tc_has_args protocol 1; then
COMPREPLY=( $(compgen -W "$PROTO" -- $cur ) )
return 0
fi
if ! _tc_in_cmd "$cls"; then
_tc_in_cmd estimator && ! _tc_has_args estimator 2 && return 0
_tc-makecomp 'estimator root classid handle help pref parent' "$cls" 'root parent classid'
return 0
fi
filtertype=$(_tc_get_arg_matching ${cls// /|})
filterpos=$?
_tc-filter-filter $filtertype $filterpos && return 0
# TODO shouldn't happens
COMPREPLY=( _tc_error_filter_$filtertype )
return 0
}
_tc-filter-filter() {
local filtertype=$1 && shift
local let filterpos=$1 && shift
case $filtertype in
basic)
# giving up here : complexity 1, developper 0
(( $COMP_CWORD > $((filterpos+1)) )) && return 0
COMPREPLY=( $(compgen -W 'match police action classid' -- $cur ) )
;;
flow)
_tc-filter-flow
;;
u32)
_tc-filter-u32
;;
fw)
_tc-filter-fw
;;
route)
_tc-filter-route
;;
rsvp|rsvp6)
_tc-filter-rsvp
;;
tcindex)
_tc-filter-tcindex
;;
*)
return 1
;;
esac
return 0
}
_tc-filter-u32-match() {
echo TODO
}
_tc-filter-u32() {
local sample='ip ip6 udp tcp icmp u{32,16,8} mark'
local u32opts ipopts tcpopts
case $prev in
u32)
#TODO: the following is only valid if the word before
# $prev is *NOT* 'match'
COMPREPLY=( $(compgen -W 'match link classid police offset \
ht hashkey sample divisor flowid divisor help' -- $cur ) )
;;
match)
COMPREPLY=( $(compgen -W "$sample" -- $cur ) )
;;
#look TODO1
#@(flowid|classid))
# COMPREPLY=( $(compgen -W "$(_tc-handle-list class)" -- $cur ) )
# ;;
police)
COMPREPLY=( $(compgen -W 'rate' -- $cur ) )
;;
rate)
COMPREPLY=( )
;;
burst)
COMPREPLY=( )
;;
link)
COMPREPLY=( )
;;
offset)
COMPREPLY=( )
;;
ht)
COMPREPLY=( )
;;
hashkey)
COMPREPLY=( )
;;
sample)
COMPREPLY=( $(compgen -W "$sample" -- $cur ) )
;;
*)
_tc-filter-u32-deep
;;
esac
return 0
}
_tc-filter-u32-deep() {
_tc_get_arg_matching u32 &> /dev/null
local filterpos=$?
local u32opts=(match link classid police offset ht
hashkey sample divisor flowid divisor)
# TODO: make the lists (ip,tcp) more complete
if [ "${COMP_WORDS[$filterpos+1]}" = match ]; then
if [ "${COMP_WORDS[$filterpos+2]}" = ip ]; then
# TODO: no put bulk $ipopts but check for duplicates
ipopts="tos port src dst {s,d}port protocol"
if [[ ! $prev =~ ${ipopts// /|} ]]; then
COMPREPLY=( $(compgen -W "$iptops ${u32opts[@]}" -- $cur ) )
return 0
else
case $prev in
dst)
_known_hosts
return 0
;;
esac
fi
elif [ "${COMP_WORDS[$filterpos+2]}" = tcp ]; then
# TODO: no put bulk $ipopts but check for duplicates
tcpopts="dst"
if [[ ! $prev =~ ${tcpopts// /|} ]]; then
COMPREPLY=( $(compgen -W "$tcptops ${u32opts[@]}" -- $cur ) )
return 0
else
case $prev in
dst)
_known_hosts
return 0
;;
esac
fi
else
return 0
fi
fi
# match $sample :: port tos ...
# police & rate & burst :: mtu peakrate avrate overhead linklayer action {pipe,ok,reclassify,drop,continue}
return 0;
}
_tc-filter-flow() {
local key='src dst proto proto-src proto-dst iif priority \
mark nfct nfct-src nfct-dst nfct-proto-src \
nfct-proto-dst rt-classid sk-uid sk-gi'
case $prev in
flow)
COMPREPLY=( $(compgen -W 'map hash' -- $cur ) )
;;
map)
COMPREPLY=( $(compgen -W 'key' -- $cur ) )
;;
hash)
COMPREPLY=( $(compgen -W 'keys' -- $cur ) )
;;
key)
COMPREPLY=( $(compgen -W "$key" -- $cur ) )
;;
esac
# last arg in "$key" :: and or xor rshift addend
# and
# divisor baseclass match police action
return 0
}
_tc-filter-fw() {
case $prev in
fw)
COMPREPLY=( $(compgen -W 'classid police help' -- $cur ) )
;;
classid)
COMPREPLY=( )
;;
police)
COMPREPLY=( )
;;
esac
return 0
}
_tc-filter-route() {
case $prev in
route)
COMPREPLY=( $(compgen -W 'from{,if} to flowid police' -- $cur ) )
;;
fromif)
COMPREPLY=( )
;;
from|to)
COMPREPLY=( )
;;
flowid)
COMPREPLY=( )
;;
police)
COMPREPLY=( )
;;
esac
return 0
}
_tc-filter-rsvp() {
case $prev in
rsvp|rsvp6)
COMPREPLY=( $(compgen -W 'ipproto' -- $cur ) )
;;
ipproto)
COMPREPLY=( )
;;
session)
_know_hosts
;;
esac
return 0
## "$PROTO" :: session | flowlabel | spi/ah | spi/esp | u{8,16,32}
## _known_host :: port (COMPREPLY=( ))
# TODO : sender, classid, police tunnel{id,}
}
_tc-filter-tcindex() {
case $prev in
tcindex)
COMPREPLY=( $(compgen -W 'hash mask shift pass_on fall_through \
classid police' -- $cur ) )
;;
hash|mask|shift)
COMPREPLY=( )
;;
classid)
COMPREPLY=( )
;;
police)
COMPREPLY=( )
;;
esac
return 0
}
-------------- next part --------------
# tc(8) action helpers -*- shell-script -*-
# Rapha?l Droz <raphael.droz+floss at gmail.com>
# short dream about completing tc "action" object
_tc-action() {
local cmd="$1" && shift
local ACTSPECOP
if [[ -z $cmd ]]; then
COMPREPLY=( $(compgen -W "add change replace get delete
ls list flush action help" -- $cur ) )
else
case $cmd in
add|change|replace)
ACTSPECOP=ACR
;;
get|delete)
ACTSPECOP=GD
;;
ls|list|flush)
ACTSPECOP=FL
;;
action)
ACTSPECOP=x
;;
esac
#_tc_getsched act
COMPREPLY=( )
fi
return 0
}
More information about the Bash-completion-devel
mailing list