| make_small() { | |
| local w=$1 | |
| echo $w | tr A-Z a-z | |
| } | |
| show_instances() | |
| { | |
| local cur="$1" | |
| local bufs=$(trace-cmd list -B) | |
| if [ "$bufs" == "No buffer instances defined" ]; then | |
| return 0 | |
| fi | |
| COMPREPLY=( $(compgen -W "${bufs}" -- "${cur}") ) | |
| return 0 | |
| } | |
| show_virt() | |
| { | |
| local cur="$1" | |
| if ! which virsh &>/dev/null; then | |
| return 1 | |
| fi | |
| local virt=`virsh list | awk '/^ *[0-9]/ { print $2 }'` | |
| COMPREPLY=( $(compgen -W "${virt}" -- "${cur}") ) | |
| return 0 | |
| } | |
| show_options() | |
| { | |
| local cur="$1" | |
| local options=$(trace-cmd list -o | sed -e 's/^\(no\)*\(.*\)/\2 no\2/') | |
| COMPREPLY=( $(compgen -W "${options}" -- "${cur}") ) | |
| return 0 | |
| } | |
| __show_files() | |
| { | |
| COMPREPLY=( $(compgen -f -- "$cur") ) | |
| if [ ${#COMPREPLY[@]} -gt 1 ]; then | |
| return 0; | |
| fi | |
| # directories get '/' instead of space | |
| DIRS=( $(compgen -d -- "$cur")) | |
| if [ ${#DIRS[@]} -eq 1 ]; then | |
| compopt -o nospace | |
| COMPREPLY="$DIRS/" | |
| return 0; | |
| fi | |
| return 0 | |
| } | |
| cmd_options() | |
| { | |
| local type="$1" | |
| local cur="$2" | |
| local extra="$3" | |
| local cmds=$(trace-cmd $type -h 2>/dev/null|grep "^ *-" | \ | |
| sed -e 's/ *\(-[^ ]*\).*/\1/') | |
| COMPREPLY=( $(compgen -W "${cmds} ${extra}" -- "${cur}") ) | |
| } | |
| cmd_options_files() | |
| { | |
| cmd_options "$1" "$2" "$3" | |
| if [ ${#COMPREPLY[@]} -eq 0 ]; then | |
| __show_files "${cur}" | |
| fi | |
| } | |
| plugin_options() | |
| { | |
| local cur="$1" | |
| local opts=$(trace-cmd list -O | sed -ne 's/option://p') | |
| COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) | |
| } | |
| compression_param() | |
| { | |
| local opts=$(trace-cmd list -c | grep -v 'Supported' | cut -d "," -f1) | |
| opts+=" any none " | |
| COMPREPLY=( $(compgen -W "${opts}") ) | |
| } | |
| list_events() { | |
| local cur=$1 | |
| local list=$(trace-cmd list -e "$cur") | |
| local prefix=${cur%%:*} | |
| if [ -z "$cur" -o "$cur" != "$prefix" ]; then | |
| echo "${list}" | |
| else | |
| local events=$(for e in $list; do echo ${e/*:/}; done | sort -u) | |
| local systems=$(for s in $list; do echo ${s/:*/:}; done | sort -u) | |
| echo "${events} ${systems}" | |
| fi | |
| } | |
| __trace_cmd_list_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| case "$prev" in | |
| list) | |
| local cmds=$(trace-cmd list -h |egrep "^ {10}-" | \ | |
| sed -e 's/^ *\(-[^ ]*\).*/\1/') | |
| COMPREPLY=( $(compgen -W "${cmds}" -- "${cur}") ) | |
| ;; | |
| -e) | |
| local list=`list_events "$cur"` | |
| COMPREPLY=( $(compgen -W "all $list" -- "${cur}") ) | |
| ;; | |
| *) | |
| size=${#words[@]} | |
| if [ $size -gt 3 ]; then | |
| if [ "$cur" == "-" ]; then | |
| let size=$size-3 | |
| else | |
| let size=$size-2 | |
| fi | |
| local w="${words[$size]}" | |
| if [ "$w" == "-e" ]; then | |
| local cmds=$(trace-cmd list -h |egrep "^ {12}-" | \ | |
| sed -e 's/.*\(-.\).*/\1/') | |
| COMPREPLY=( $(compgen -W "${cmds}" -- "${cur}") ) | |
| fi | |
| fi | |
| ;; | |
| esac | |
| } | |
| __trace_cmd_show_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| case "$prev" in | |
| -B) | |
| show_instances "$cur" | |
| ;; | |
| --hist|--trigger) | |
| local list=`list_events $cur` | |
| COMPREPLY=( $(compgen -W "all ${list}" -- "${cur}") ) | |
| ;; | |
| *) | |
| cmd_options show "$cur" | |
| ;; | |
| esac | |
| } | |
| __trace_cmd_extract_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| case "$prev" in | |
| extract) | |
| cmd_options "$prev" "$cur" | |
| ;; | |
| -B) | |
| show_instances "$cur" | |
| ;; | |
| *) | |
| __show_files | |
| ;; | |
| esac | |
| } | |
| __trace_cmd_record_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| case "$prev" in | |
| -e) | |
| local list=`list_events $cur` | |
| COMPREPLY=( $(compgen -W "all ${list}" -- "${cur}") ) | |
| # This is still to handle the "*:*" special case | |
| if [[ -n "$prefix" ]]; then | |
| local reply_n=${#COMPREPLY[*]} | |
| for (( i = 0; i < $reply_n; i++)); do | |
| COMPREPLY[$i]=${COMPREPLY[i]##${prefix}:} | |
| done | |
| fi | |
| ;; | |
| -p) | |
| local plugins=$(trace-cmd list -p) | |
| COMPREPLY=( $(compgen -W "${plugins}" -- "${cur}" ) ) | |
| ;; | |
| -l|-n|-g) | |
| # This is extremely slow still (may take >1sec). | |
| local funcs=$(trace-cmd list -f | sed 's/ .*//') | |
| COMPREPLY=( $(compgen -W "${funcs}" -- "${cur}") ) | |
| ;; | |
| -B) | |
| show_instances "$cur" | |
| ;; | |
| -O) | |
| show_options "$cur" | |
| ;; | |
| -A) | |
| if ! show_virt "$cur"; then | |
| cmd_options_files record "$cur" | |
| fi | |
| ;; | |
| --compression) | |
| compression_param | |
| ;; | |
| *) | |
| # stream start and profile do not show all options | |
| cmd_options_files record "$cur" | |
| ;; | |
| esac | |
| } | |
| __trace_cmd_report_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| case "$prev" in | |
| -O) | |
| plugin_options "$cur" | |
| ;; | |
| *) | |
| cmd_options_files report "$cur" | |
| ;; | |
| esac | |
| } | |
| dynevent_options() | |
| { | |
| local cur="$1" | |
| local opts=("kprobe" "kretprobe" "uprobe" "uretprobe" "eprobe" "synth" "all") | |
| COMPREPLY=( $(compgen -W "${opts[*]}" -- "${cur}") ) | |
| } | |
| __trace_cmd_reset_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| case "$prev" in | |
| -B) | |
| show_instances "$cur" | |
| ;; | |
| -k) | |
| dynevent_options "$cur" | |
| ;; | |
| *) | |
| cmd_options reset "$cur" | |
| ;; | |
| esac | |
| } | |
| __trace_cmd_dump_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| case "$prev" in | |
| -i) | |
| __show_files | |
| ;; | |
| *) | |
| cmd_options dump "$cur" | |
| ;; | |
| esac | |
| } | |
| __trace_cmd_convert_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| case "$prev" in | |
| -i) | |
| __show_files | |
| ;; | |
| -o) | |
| __show_files | |
| ;; | |
| --compression) | |
| compression_param | |
| ;; | |
| *) | |
| cmd_options convert "$cur" | |
| ;; | |
| esac | |
| } | |
| ##### SQLHIST COMMANDS ##### | |
| prev_keyword() { | |
| local i=$1 | |
| shift | |
| local words=("$@") | |
| while [ $i -gt 0 ]; do | |
| let i=$i-1 | |
| local w=`make_small ${words[$i]}` | |
| case $w in | |
| select) | |
| echo "select" | |
| return | |
| ;; | |
| from) | |
| echo "from" | |
| return | |
| ;; | |
| as) | |
| echo "as" | |
| return | |
| ;; | |
| on) | |
| echo "on" | |
| return | |
| ;; | |
| join) | |
| echo "join" | |
| return | |
| ;; | |
| where) | |
| echo "where" | |
| return | |
| ;; | |
| *) | |
| if [ "$w" != "${w%%,}" ]; then | |
| echo "," | |
| return | |
| fi | |
| if [ "$w" != "${w%%=}" ]; then | |
| echo "=" | |
| return | |
| fi | |
| ;; | |
| esac | |
| done | |
| echo "" | |
| } | |
| prev_command() { | |
| local i=$1 | |
| shift | |
| local words=("$@") | |
| while [ $i -gt 0 ]; do | |
| let i=$i-1 | |
| local w=`make_small ${words[$i]}` | |
| case $w in | |
| select) | |
| echo "select" | |
| return | |
| ;; | |
| from) | |
| echo "from" | |
| return | |
| ;; | |
| on) | |
| echo "on" | |
| return | |
| ;; | |
| join) | |
| echo "join" | |
| return | |
| ;; | |
| where) | |
| echo "where" | |
| return | |
| ;; | |
| esac | |
| done | |
| echo "" | |
| } | |
| add_vars() { | |
| local words=("$@") | |
| local i=$COMP_CWORD | |
| let found_from=0 | |
| while [ $i -gt 0 ]; do | |
| let i=$i-1 | |
| local w=`make_small ${words[$i]}` | |
| case $w in | |
| "from") | |
| let found_from=1 | |
| ;; | |
| *) | |
| if [ $found_from ]; then | |
| start=`echo $w | sed -e 's/\.[^\.]*$//'` | |
| if [ "$start" != "$w" -a "$start" == "${start%%\.*}" ]; then | |
| echo -n "$start " | |
| fi | |
| fi | |
| ;; | |
| esac | |
| done | |
| } | |
| add_options() { | |
| local cur="$1" | |
| local list="$2" | |
| COMPREPLY=( $(compgen -W "${list}" -- "${cur}") ) | |
| } | |
| print_fields() { | |
| local event=$1 | |
| local var=$2 | |
| local extra=$3 | |
| local list=`trace-cmd list -e "^${event/\./:}\$" -F | cut -d';' -f1 | sed -ne 's/\t.*:.* \(.*\)/\1/p' |sed -e 's/\[.*\]//'` | |
| for field in $list $extra; do | |
| echo "$event.$field" | |
| if [ ! -z "$var" ]; then | |
| echo "$var.$field" | |
| fi | |
| done | |
| } | |
| select_options() { | |
| local cur=$1 | |
| local extra=$2 | |
| local list=`list_events "${cur/\./:}" | sed -e 's/:/./g'` | |
| local select_list=" TIMESTAMP_DELTA TIMESTAMP_DELTA_USECS $extra" | |
| local select_fields=" TIMESTAMP TIMESTAMP_USECS STACKTRACE" | |
| add_options "$cur" "$list $select_list" | |
| local cnt=${#COMPREPLY[@]} | |
| if [ $cnt -eq 1 ]; then | |
| local comp=${COMPREPLY[0]} | |
| local w=$(compgen -W "$select_list" -- "$comp" ) | |
| if [ -z "$w" ]; then | |
| COMPREPLY=("$comp.") | |
| compopt -o nospace | |
| fi | |
| elif [ $cnt -eq 0 ]; then | |
| local w=`echo $cur | sed -e 's/\.[^\.]*$//'` | |
| list=`print_fields $w "" "$select_fields"` | |
| COMPREPLY=( $(compgen -W "${list}" -- "${cur}") ) | |
| fi | |
| } | |
| check_as() { | |
| local words=("$@") | |
| last_key=`prev_keyword $COMP_CWORD ${words[@]}` | |
| if [ "$last_key" != "as" ]; then | |
| echo -n "AS" | |
| fi | |
| } | |
| on_list() { | |
| local type=$1 | |
| shift | |
| local words=("$@") | |
| local i=$COMP_CWORD | |
| local var="" | |
| while [ $i -gt 0 ]; do | |
| let i=$i-1 | |
| local w=`make_small ${words[$i]}` | |
| case $w in | |
| "from"|"join") | |
| if [ $w == $type ]; then | |
| print_fields ${words[$i+1]} "$var" | |
| return | |
| fi | |
| var="" | |
| ;; | |
| as) | |
| var=${words[$i+1]} | |
| ;; | |
| esac | |
| done | |
| } | |
| update_completion() { | |
| local cur=$1 | |
| shift | |
| local words=("$@") | |
| if [ ${#COMPREPLY[@]} -gt 0 ]; then | |
| return | |
| fi | |
| for w in ${words[@]}; do | |
| if [ "$w" != "${w##$cur}" ]; then | |
| COMPREPLY=("$w") | |
| return | |
| fi | |
| done | |
| } | |
| __trace_cmd_sqlhist_complete() | |
| { | |
| local prev=$1 | |
| local cur=$2 | |
| shift 2 | |
| local words=("$@") | |
| if [ "$cur" != "${cur%%,}" ]; then | |
| COMPREPLY=("$cur") | |
| return | |
| fi | |
| local p=`make_small $prev` | |
| if [ "$p" != "${p%%,}" ]; then | |
| p=`prev_command $COMP_CWORD ${words[@]}` | |
| fi | |
| case "$p" in | |
| "sqlhist") | |
| cmd_options sqlhist "$cur" "SELECT" | |
| update_completion "$cur" select | |
| ;; | |
| "select") | |
| select_options "$cur" | |
| ;; | |
| "on") | |
| list=`on_list "from" ${words[@]}` | |
| add_options "$cur" "$list" | |
| ;; | |
| "as") | |
| local last_cmd=`prev_command $COMP_CWORD ${words[@]}` | |
| case $last_cmd in | |
| "from"|"join") | |
| list=`add_vars ${words[@]}` | |
| if [ ! -z "$list" ]; then | |
| add_options "$cur" "$list" | |
| fi | |
| ;; | |
| esac | |
| ;; | |
| "from"|"join") | |
| local list=$(trace-cmd list -e "${cur/\./:}" | tr : .) | |
| local prefix=${cur/\./} | |
| if [ -z "$cur" -o "$cur" != "$prefix" ]; then | |
| COMPREPLY=( $(compgen -W "${list}" -- "${cur}") ) | |
| else | |
| local events=$(for e in $list; do echo ${e/*\./}; done | sort -u) | |
| local systems=$(for s in $list; do echo ${s/\.*/.}; done | sort -u) | |
| COMPREPLY=( $(compgen -W "all ${events} ${systems}" -- "${cur}") ) | |
| fi | |
| ;; | |
| *) | |
| local last_cmd=`prev_command $COMP_CWORD ${words[@]}` | |
| local list=`check_as ${words[@]}` | |
| local alist="" | |
| if [ ! -z "$list" ]; then | |
| alist="as" | |
| fi | |
| case $last_cmd in | |
| "select") | |
| if [ "$cur" != "${cur%%,}" ]; then | |
| select_options "$cur" "$list" | |
| else | |
| add_options "$cur" "FROM , $list" | |
| update_completion "$cur" from $alist | |
| fi | |
| ;; | |
| "from") | |
| add_options "$cur" "JOIN $list" | |
| update_completion "$cur" join $alist | |
| ;; | |
| "join") | |
| add_options "$cur" "ON $list" | |
| update_completion "$cur" on $alist | |
| ;; | |
| "on") | |
| if [ "$cur" != "${cur%%=}" ]; then | |
| COMPREPLY=("") | |
| else | |
| last_key=`prev_keyword $COMP_CWORD ${words[@]}` | |
| if [ "$last_key" == "=" ]; then | |
| if [ $prev == "=" ]; then | |
| list=`on_list "join" ${words[@]}` | |
| add_options "$cur" "$list" | |
| else | |
| add_options "$cur" "WHERE" | |
| update_completion "$cur" where | |
| fi | |
| else | |
| add_options "$cur" "=" | |
| fi | |
| fi | |
| ;; | |
| "where") | |
| ;; | |
| *) | |
| cmd_options sqlhist "$cur" "SELECT" | |
| update_completion "$cur" select | |
| ;; | |
| esac | |
| ;; | |
| esac | |
| } | |
| ##### SQLHIST COMMANDS END ##### | |
| __show_command_options() | |
| { | |
| local command="$1" | |
| local prev="$2" | |
| local cur="$3" | |
| local cmds=( $(trace-cmd --help 2>/dev/null | \ | |
| grep " - " | sed 's/^ *//; s/ -.*//') ) | |
| for cmd in ${cmds[@]}; do | |
| if [ $cmd == "$command" ]; then | |
| local opts=$(trace-cmd $cmd -h 2>/dev/null|grep "^ *-" | \ | |
| sed -e 's/ *\(-[^ ]*\).*/\1/') | |
| if [ "$prev" == "-B" ]; then | |
| for opt in ${opts[@]}; do | |
| if [ "$opt" == "-B" ]; then | |
| show_instances "$cur" | |
| return 0 | |
| fi | |
| done | |
| fi | |
| COMPREPLY=( $(compgen -W "${opts}" -- "$cur")) | |
| break | |
| fi | |
| done | |
| if [ ${#COMPREPLY[@]} -eq 0 ]; then | |
| __show_files "${cur}" | |
| fi | |
| } | |
| _trace_cmd_complete() | |
| { | |
| local cur="" | |
| local prev="" | |
| local words=() | |
| # Not to use COMP_WORDS to avoid buggy behavior of Bash when | |
| # handling with words including ":", like: | |
| # | |
| # prev="${COMP_WORDS[COMP_CWORD-1]}" | |
| # cur="${COMP_WORDS[COMP_CWORD]}" | |
| # | |
| # Instead, we use _get_comp_words_by_ref() magic. | |
| _get_comp_words_by_ref -n : cur prev words | |
| if [ "$prev" == "trace-cmd" ]; then | |
| local cmds=$(trace-cmd --help 2>/dev/null | \ | |
| grep " - " | sed 's/^ *//; s/ -.*//') | |
| COMPREPLY=( $(compgen -W "${cmds}" -- "${cur}") ) | |
| return; | |
| fi | |
| local w="${words[1]}" | |
| case "$w" in | |
| list) | |
| __trace_cmd_list_complete "${prev}" "${cur}" ${words[@]} | |
| return 0 | |
| ;; | |
| show) | |
| __trace_cmd_show_complete "${prev}" "${cur}" ${words[@]} | |
| return 0 | |
| ;; | |
| extract) | |
| __trace_cmd_extract_complete "${prev}" "${cur}" ${words[@]} | |
| return 0 | |
| ;; | |
| record|stream|start|set|profile) | |
| __trace_cmd_record_complete "${prev}" "${cur}" ${words[@]} | |
| return 0 | |
| ;; | |
| report) | |
| __trace_cmd_report_complete "${prev}" "${cur}" ${words[@]} | |
| return 0 | |
| ;; | |
| reset) | |
| __trace_cmd_reset_complete "${prev}" "${cur}" "${words[@]}" | |
| return 0 | |
| ;; | |
| dump) | |
| __trace_cmd_dump_complete "${prev}" "${cur}" ${words[@]} | |
| return 0 | |
| ;; | |
| convert) | |
| __trace_cmd_convert_complete "${prev}" "${cur}" ${words[@]} | |
| return 0 | |
| ;; | |
| sqlhist) | |
| __trace_cmd_sqlhist_complete "${prev}" "${cur}" ${words[@]} | |
| return 0 | |
| ;; | |
| *) | |
| __show_command_options "$w" "${prev}" "${cur}" | |
| ;; | |
| esac | |
| } | |
| complete -F _trace_cmd_complete trace-cmd |