#compdef sysdig # This completion code is based on the cmdline interface as it exists in sysdig # 0.1.90 # this must match fields_info.cpp local DESCRIPTION_TEXT_START=20 # handles completion of filter fields function _filter () { # I run 'sysdig -l' to get a list of available filter types to generate the # user choice local in_field=0 fields typeset -a fields _call_program chisel_info sysdig -l 2>/dev/null | while IFS='' read -r line; do if [[ $line =~ "^([a-zA-Z0-9_]+\.[a-zA-Z0-9_\.]+) +(.*?)$" ]]; then # starting a new field in_field=1 fields[$#fields+1]="$match[1]:$match[2]" elif (($in_field)) && [[ $line =~ "^ {$DESCRIPTION_TEXT_START}(.*)" ]]; then # field continuation fields[$#fields]+=$match[1] else in_field=0 fi done # Here I use _describe -S '' to omit the closing quote when completing. # Otherwise if you have # # $ sysdig -p '%fd.si # # and you press TAB, you'll get # # $ sysdig -p '%fd.sip' # # Note the trailing ', which I don't want if [[ -z $1 ]]; then # full filter expansion local ops ops=("=" "!=" "<" "<=" ">" ">=" "contains" "and" "or" "not" "(" ")") # Remove the FILTER-ONLY string, since we don't need to indicate that to # the user here fields=(${fields/"(FILTER ONLY) "/}) # _describe -t fields 'Fields' fields _describe -t operators 'Operators' ops elif [[ $1 == "format" ]]; then # expanding format specifiers local allfields_withpercent; # add a leading '%', and remove all FILTER-ONLY fields allfields_withpercent=("%"${^fields:#*FILTER ONLY*}) # skip all leading characters that can't be in a field name. This lets # me specify multiple fields in the string or do things like # "%fd.cip,%fd.cport" compset -P "*[^a-zA-Z0-9_%\.]" _describe -t format_fields 'Format fields' allfields_withpercent -S '' fi } # handles completion for chisel names function _chisels () { # I run 'sysdig -cl' to get a list of available chisels, and build an # _alternative command to generate the user choice local incategory=0 alts_types alts_chisels typeset -a alts_types alts_chisels function closetype() { if [[ -n "$alts_types[$#alts_types]" ]] && (($#alts_chisels)); then # append the trailing " local descriptions_for_type typeset -a descriptions_for_type descriptions_for_type=(${^alts_chisels}\") alts_types[$#alts_types]+=$descriptions_for_type[*]'))' fi alts_chisels=() incategory=0 } _call_program chisels sysdig -cl 2>/dev/null | while IFS='' read -r line; do if [[ $line =~ "^-+$" ]]; then # skip lines such as # ----------------- continue; elif [[ -z "$line" ]]; then # empty lines reset the category closetype elif [[ $line =~ "^Category: (.*)" ]]; then # got a new category closetype incategory=1 local category=$match[1] local index=$(($#alts_types+1)) alts_types[$index]="category_$index:$category:((" elif (($incategory)) && [[ $line =~ "^([a-zA-Z0-9_-]+) *(.+?)" ]]; then # got a chisel local name=$match[1]; local descr=$match[2]; local index=$(($#alts_chisels+1)) alts_chisels[$index]+="${name}\\:\"$descr" # leave out closing " to # allow line # continuations elif (($incategory)) && [[ $line =~ "^ {$DESCRIPTION_TEXT_START}(.*)" ]]; then # field continuation alts_chisels[$#alts_chisels]+=$match[1] fi done closetype _alternative $alts_types[*] } # returns (in $$1) a description of a given argument of a given chisel function _get_chisel_arg () { # I run 'sysdig -i ' to get a description of this chisel. I parse # the argument list at the end of this description. This list looks like # this # # Args: # [int] arg1 - blah blah blah blah blah # [int] arg2 - something blah blah blah blah blah blah blah b # lah blah blah blah blah # # The odd line wrapping is a result of a sysdig bug (patch in review), so # here I assume that this has been fixed local outputvar=$1 chisel=$2 nth_want=$3 local in_arglist=0 in_argwant=0 nth_have=0 _call_program chisel_info sysdig -i $chisel 2>/dev/null | while IFS='' read -r line; do if (($in_arglist)); then # I'm in the argument list if (($in_argwant)); then if [[ $line =~ "^ {$DESCRIPTION_TEXT_START}(.*?)$" ]]; then # I'm in a continuation line for my argument I strip the # leading whitespace and append eval "$outputvar+=\$match[1]" else # Done reading my argument return fi elif [[ $line =~ "^\[" ]] && ((++nth_have == $nth_want)); then # I'm in the argument I want! ((++in_argwant)) eval "$outputvar=\$line"; fi elif [[ $line =~ "^Args:" ]]; then in_arglist=1 continue fi done } # If the cursor is in a chisel argument, returns (in $$1) the description of this # argument. Otherwise returns '' function _in_chiselarg () { local outputvar=$1 local index=$words[(i)-c] local chisel_index=$words[(i)--chisel] if [[ $index -le $CURRENT ]]; then # the -c index is valid ; elif [[ $chisel_index -le $CURRENT ]]; then # the --chisel index is valid index=$chisel_index; else # neither index is valid, so return false return fi # There is a chisel argument somewhere on the commandline. I look to see if # I'm currently typing into it, and return the description if so local chisel=$words[$index+1] local nth=$(($CURRENT-$index-1)) _get_chisel_arg $outputvar $chisel $nth } function _chiselarg () { # the index of the -c/--chisel argument local description=$1 _alternative "chiselarg:$description:" } local context state state_descr line typeset -A opt_args _arguments \ '(-A --print-ascii)'{-A,--print-ascii}'[Only print the text portion of data buffers]' \ '(-b --print-base64)'{-b,--print-base64}'[Print data buffers in base64]' \ '(-cl --list-chisels)'{-cl,--list-chisels}'[lists the available chisels]' \ '(-d --displayflt)'{-d,--displayflt}'[Make the given filter a display one]' \ '(-D --debug)'{-D,--debug}'[Capture events about sysdig itself]' \ '(-E --exclude-users)'{-E,--exclude-users}'[Don'\''t create the user/group tables when starting]' \ '(-F --fatfile)'{-F,--fatfile}'[Enable fatfile mode]' \ '(-h --help)'{-h,--help}'[Print this help]' \ '(-j --json)'{-j,--json}'[Emit output as JSON]' \ '(-L --list-events)'{-L,--list-events}'[List the events that the engine supports]' \ '(-l -lv --list)'{-l,--list}'[List the fields that can be used for filtering]' \ '(-l -lv --list)-lv[Verbosely list the fields that can be used for filtering]' \ '(-P --progress)'{-P,--progress}'[Print progress on stderr while processing trace files]' \ '(-q --quiet)'{-q,--quiet}'[Do not print events on the screen]' \ '(-S --summary)'{-S,--summary}'[Print the event summary when the capture ends]' \ '(-v --verbose)'{-v,--verbose}'[Verbose output]' \ '(-x --print-hex)'{-x,--print-hex}'[Print data buffers in hex]' \ '(-X --print-hex-ascii)'{-X,--print-hex-ascii}'[Print data buffers in hex and ASCII]' \ '(-z --compress)'{-z,--compress}'[Enables compression for stored tracefiles]' \ '(-n --numevents)'{-n,--numevents=-}'[Stop capturing after events]:Max events:' \ '(-p --print)'{-p,--print=-}'[Specify the event format]:Event output format:->format' \ '(-r --read)'{-r,--read=-}'[Read events from ]:Input file:_files -g "*.scap"' \ '(-w --write)'{-w,--write=-}'[Write events to ]:Output file:_files -g "*.scap"' \ '(-s --snaplen)'{-s,--snaplen=-}'[Capture the first bytes of each I/O buffer]:Buffer length (bytes):' \ '(-t --timetype)'{-t,--timetype=-}'[Change the way event time is displayed]:Time-reporting type:(( \ h\:"human-readable string" \ a\:"absolute timestamp from epoch" \ r\:"relative time from capture start" \ d\:"delta between enter/exit"))' \ '(-c --chisel)'{-c,--chisel}'[Run a given chisel]:Chisel:->chisel' \ '(-i --chisel-info)'{-i,--chisel-info}'[Get a detailed chisel description]:Chisel:->chisel' \ '*:Filter or chisel argument:->filter_or_chiselarg' && return 0 # Sysdig 0.1.85 had these options too, but they were problematic, so I'm # removing them until they can be fixed # '(-C --file-size)'{-C,--file-size=-}'[Chunk captures to files of given size]:Maximum chunk file size:' # '(-G --seconds)'{-G,--seconds=-}'[Rotate the capture file every seconds]:Rotation period (seconds):' # '(-W --limit)'{-W,--limit}'[Limit split captures (-C or -G) to a given number of files]:Maximum number of files' case $state in (chisel) _chisels ;; (format) _filter format ;; (filter_or_chiselarg) local chiselarg _in_chiselarg chiselarg if [[ -n "$chiselarg" ]]; then _chiselarg $chiselarg else _filter fi ;; esac # Local Variables: # mode:sh # End: