Just realized that I missed the confirmation email from Peter,

So, here is his signed-off-by,

Signed-off-by: Peter Amidon <pe...@picnicpark.org>

On Mon, Feb 23, 2015 at 8:45 AM, Alex Wang <al...@nicira.com> wrote:

> Waiting for a sign-off from Peter,
>
> But I'd like to send it out as RFC first~
>
> Thanks,
> Alex Wang,
>
> On Mon, Feb 23, 2015 at 8:48 AM, Alex Wang <al...@nicira.com> wrote:
>
>> From: Peter Amidon <pe...@picnicpark.org>
>>
>> This patch adds bash command-line completion script for ovs-vsctl.
>> Therein, codes are added to ovs-vsctl to allow it to print the
>> options and command arguments.  The ovs-vsctl-bashcomp.bash will
>> parse the vsctl command and complete on the user input.
>>
>> The completion script can do the following::
>>
>> - display available completion and complete on user input for
>>   global/local options, command, and argument.
>>
>> - query database and expand keywords like 'table/record/column/key'
>>   to available completions.
>>
>> - deal with argument relations like 'one and more', 'zero or one'.
>>
>> - complete multiple ovs-vsctl commands cascaded via '--'.
>>
>> To use the script, either copy it inside /etc/bash_completion.d/
>> or manually run it via . ovs-vsctl-bashcomp.bash.
>>
>> Signed-off-by: Alex Wang <al...@nicira.com>
>> ---
>>  AUTHORS                           |    1 +
>>  utilities/automake.mk             |    1 +
>>  utilities/ovs-vsctl-bashcomp.bash |  778
>> +++++++++++++++++++++++++++++++++++++
>>  utilities/ovs-vsctl.c             |  287 +++++++++++---
>>  4 files changed, 1018 insertions(+), 49 deletions(-)
>>  create mode 100755 utilities/ovs-vsctl-bashcomp.bash
>>
>> diff --git a/AUTHORS b/AUTHORS
>> index c85ecd4..75fe3a5 100644
>> --- a/AUTHORS
>> +++ b/AUTHORS
>> @@ -300,6 +300,7 @@ Pankaj Thakkar          thak...@nicira.com
>>  Pasi Kärkkäinen         pa...@iki.fi
>>  Paulo Cravero           pcrav...@as2594.net
>>  Pawan Shukla            shuk...@vmware.com
>> +Peter Amidon            pe...@picnicpark.org
>>  Peter Balland           pe...@nicira.com
>>  Peter Phaal             peter.ph...@inmon.com
>>  Prabina Pattnaik        prabina.pattn...@nechclst.in
>> diff --git a/utilities/automake.mk b/utilities/automake.mk
>> index 09d6702..5aae782 100644
>> --- a/utilities/automake.mk
>> +++ b/utilities/automake.mk
>> @@ -30,6 +30,7 @@ docs += utilities/ovs-command-bashcomp.INSTALL.md
>>  EXTRA_DIST += \
>>         utilities/ovs-check-dead-ifs.in \
>>         utilities/ovs-appctl-bashcomp.bash \
>> +       utilities/ovs-vsctl-bashcomp.bash \
>>         utilities/ovs-command-bashcomp.INSTALL.md \
>>         utilities/ovs-ctl.in \
>>         utilities/ovs-dev.py \
>> diff --git a/utilities/ovs-vsctl-bashcomp.bash
>> b/utilities/ovs-vsctl-bashcomp.bash
>> new file mode 100755
>> index 0000000..ba4429f
>> --- /dev/null
>> +++ b/utilities/ovs-vsctl-bashcomp.bash
>> @@ -0,0 +1,778 @@
>> +SAVE_IFS=$IFS
>> +IFS="
>> +"
>> +_OVSDB_SERVER_LOCATION=""
>> +
>> +# Run ovs-vsctl and make sure that ovs-vsctl is always called with
>> +# the correct --db argument.
>> +_ovs_vsctl () {
>> +    local _db
>> +
>> +    if [ -n "$_OVSDB_SERVER_LOCATION" ]; then
>> +        _db="--db=$_OVSDB_SERVER_LOCATION"
>> +    fi
>> +    ovs-vsctl ${_db} "$@"
>> +}
>> +
>> +# ovs-vsctl --commands outputs in this format:
>> +#
>> +# main = <localopts>,<name>,<options>
>> +# localopts = ([<localopt>] )*
>> +# localopt = --[^]]*
>> +# name = [^,]*
>> +# arguments = ((!argument|?argument|*argument|+argument) )*
>> +# argument = ([^ ]*|argument\|argument)
>> +#
>> +# The [] characters in local options are just delimiters.  The
>> +# argument prefixes mean:
>> +#   !argument :: The argument is required
>> +#   ?argument :: The argument is optional
>> +#   *argument :: The argument may appear any number (0 or more) times
>> +#   +argument :: The argument may appear one or more times
>> +# A bar (|) character in an argument means thing before bar OR thing
>> +# after bar; for example, del-port can take a port or an interface.
>> +
>> +_OVS_VSCTL_COMMANDS="$(_ovs_vsctl --commands)"
>> +
>> +# This doesn't complete on short arguments, so it filters them out.
>> +_OVS_VSCTL_OPTIONS="$(_ovs_vsctl --options | awk '/^--/ { print $0 }' \
>> +                      | sed -e 's/\(.*\)=ARG/\1=/')"
>> +IFS=$SAVE_IFS
>> +
>> +declare -A _OVS_VSCTL_PARSED_ARGS
>> +declare -A _OVS_VSCTL_NEW_RECORDS
>> +
>> +# This is a convenience function to make sure that user input is
>> +# looked at as a fixed string when being compared to something.  $1 is
>> +# the input; this behaves like 'grep "^$1"' but deals with regex
>> +# metacharacters in $1.
>> +_ovs_vsctl_check_startswith_string () {
>> +    awk 'index($0, thearg)==1' thearg="$1"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on global options.
>> +_ovs_vsctl_bashcomp_globalopt () {
>> +    local options result
>> +
>> +    options=""
>> +    result=$(printf "%s\n" "${_OVS_VSCTL_OPTIONS}" \
>> +             | _ovs_vsctl_check_startswith_string "${1%=*}")
>> +    if [[ $result =~ "=" ]]; then
>> +        options="NOSPACE"
>> +    fi
>> +    printf -- "${options}\nEO\n${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on local options.
>> +_ovs_vsctl_bashcomp_localopt () {
>> +    local options result possible_opts
>> +
>> +    possible_opts=$(printf "%s\n" "${_OVS_VSCTL_COMMANDS}" | cut -f1
>> -d',')
>> +    # This finds all options that could go together with the
>> +    # already-seen ones
>> +    for prefix_arg in $1; do
>> +        possible_opts=$(printf "%s\n" "$possible_opts" \
>> +                        | grep -- "\[${prefix_arg%%=*}=\?\]")
>> +    done
>> +    result=$(printf "%s\n" "${possible_opts}" \
>> +             | tr ' ' '\n' | tr -s '\n' | sort | uniq)
>> +    # This removes the already-seen options from the list so that
>> +    # users aren't completed for the same option twice.
>> +    for prefix_arg in $1; do
>> +        result=$(printf "%s\n" "${result}" \
>> +                 | grep -v -- "\[${prefix_arg%%=*}=\?\]")
>> +    done
>> +    result=$(printf "%s\n" "${result}" | sed -ne 's/\[\(.*\)\]/\1/p' \
>> +             | _ovs_vsctl_check_startswith_string "$2")
>> +    if [[ $result =~ "=" ]]; then
>> +        options="NOSPACE"
>> +    fi
>> +    printf -- "${options}\nEO\n${result}"
>> +}
>> +
>> +# $1 = given local options.
>> +# $2 = word to complete on.
>> +# Complete on command that could contain the given local options.
>> +_ovs_vsctl_bashcomp_command () {
>> +    local result possible_cmds
>> +
>> +    possible_cmds=$(printf "%s\n" "${_OVS_VSCTL_COMMANDS}")
>> +    for prefix_arg in $1; do
>> +        possible_cmds=$(printf "%s\n" "$possible_cmds" \
>> +                        | grep -- "\[$prefix_arg=\?\]")
>> +    done
>> +    result=$(printf "%s\n" "${possible_cmds}" \
>> +             | cut -f2 -d',' \
>> +             | _ovs_vsctl_check_startswith_string "$2")
>> +    printf -- "${result}"
>> +}
>> +
>> +# $1 = completion result to check.
>> +# Return 0 if the completion result is non-empty, otherwise return 1.
>> +_ovs_vsctl_detect_nonzero_completions () {
>> +    local tmp newarg
>> +
>> +    newarg=${1#*EO}
>> +    readarray tmp <<< "$newarg"
>> +    if [ "${#tmp[@]}" -eq 1 ] && [ "${#newarg}" -eq 0 ]; then
>> +        return 1
>> +    fi
>> +    return 0
>> +}
>> +
>> +# $1 = argument format to expand.
>> +# Expand '+ARGUMENT' in argument format to '!ARGUMENT *ARGUMENT'.
>> +_ovs_vsctl_expand_command () {
>> +    result=$(printf "%s\n" "${_OVS_VSCTL_COMMANDS}" \
>> +             | grep -- ",$1," | cut -f3 -d',' | tr ' ' '\n' \
>> +             | awk '/\+.*/ { name=substr($0,2);
>> +                             print "!"name; print "*"name; next; }
>> +                    1')
>> +    printf -- "${result}\n!--"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on table.
>> +_ovs_vsctl_complete_table () {
>> +    local result
>> +
>> +    result=$(ovsdb-client --no-heading list-tables
>> $_OVSDB_SERVER_LOCATION Open_vSwitch \
>> +        | _ovs_vsctl_check_startswith_string "$1")
>> +    printf -- "EO\n%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on record.  Provide both the name and uuid.
>> +_ovs_vsctl_complete_record () {
>> +    local table uuids names new_record
>> +
>> +    table="${_OVS_VSCTL_PARSED_ARGS[TABLE]}"
>> +    new_record="${_OVS_VSCTL_NEW_RECORDS[${table^^}]}"
>> +    # Tables should always have an _uuid column
>> +    uuids=$(_ovs_vsctl --no-heading -f table -d bare --columns=_uuid \
>> +                      list $table | _ovs_vsctl_check_startswith_string
>> "$1")
>> +    # Names don't always exist, silently ignore if the name column is
>> +    # unavailable.
>> +    names=$(_ovs_vsctl --no-heading -f table -d bare \
>> +                      --columns=name list $table \
>> +                      2>/dev/null \
>> +            | _ovs_vsctl_check_startswith_string "$1")
>> +    printf -- "EO\n%s\n%s\n%s\n" "${uuids}" "${names}" "${new_record}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on bridge.
>> +_ovs_vsctl_complete_bridge () {
>> +    local result
>> +
>> +    result=$(_ovs_vsctl list-br | _ovs_vsctl_check_startswith_string
>> "$1")
>> +    printf -- "EO\n%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on port.  If a bridge has already been specified,
>> +# just complete for that bridge.
>> +_ovs_vsctl_complete_port () {
>> +    local ports result
>> +
>> +    if [ -n "${_OVS_VSCTL_PARSED_ARGS[BRIDGE]}" ]; then
>> +        ports=$(_ovs_vsctl list-ports
>> "${_OVS_VSCTL_PARSED_ARGS[BRIDGE]}")
>> +    else
>> +        local all_ports
>> +        all_ports=$(_ovs_vsctl --format=table \
>> +                              --no-headings \
>> +                              --columns=name \
>> +                              list Port)
>> +        ports=$(printf "$all_ports" | tr -d '" ' | sort -u)
>> +    fi
>> +    result=$(_ovs_vsctl_check_startswith_string "$1" <<< "$ports")
>> +    printf -- "EO\n%s\n" "${result}"
>> +}
>> +
>> +# $1:  Atom to complete (as usual)
>> +# $2:  Table to complete the key in
>> +# $3:  Column to find keys in
>> +# $4:  Prefix for each completion
>> +# Complete on key based on given table and column info.
>> +_ovs_vsctl_complete_key_given_table_column () {
>> +    local keys
>> +
>> +    keys=$(_ovs_vsctl --no-heading --columns="$3" list \
>> +                     "$2" \
>> +           | tr -d '{\"}' | tr -s ', ' '\n' | cut -d'=' -f1 \
>> +           | xargs printf "$4%s\n" | _ovs_vsctl_check_startswith_string
>> "$1")
>> +    result="${keys}"
>> +    printf -- "%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on key.
>> +__complete_key () {
>> +    # KEY is used in both br-set-external-id/br-get-external id (in
>> +    # which case it is implicitly a key in the external-id column) and
>> +    # in remove, where it is a table key.  This checks to see if table
>> +    # is set (the remove scenario), and then decides what to do.
>> +    local result
>> +
>> +    if [ -n "${_OVS_VSCTL_PARSED_ARGS[TABLE]}" ]; then
>> +        local column=$(tr -d '\n' <<<
>> ${_OVS_VSCTL_PARSED_ARGS["COLUMN"]})
>> +        result=$(_ovs_vsctl_complete_key_given_table_column \
>> +                     "$1" \
>> +                     ${_OVS_VSCTL_PARSED_ARGS["TABLE"]} \
>> +                     $column \
>> +                     "")
>> +    else
>> +        result=$(_ovs_vsctl br-get-external-id \
>> +                           ${_OVS_VSCTL_PARSED_ARGS["BRIDGE"]} \
>> +                 | cut -d'=' -f1 | _ovs_vsctl_check_startswith_string
>> "$1")
>> +    fi
>> +    printf -- "%s" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on key.
>> +_ovs_vsctl_complete_key () {
>> +    # KEY is used in both br-set-external-id/br-get-external id (in
>> +    # which case it is implicitly a key in the external-id column) and
>> +    # in remove, where it is a table key.  This checks to see if table
>> +    # is set (the remove scenario), and then decides what to do.
>> +    local result
>> +
>> +    result="$(__complete_key $1)"
>> +    # If result is empty, just use user input as result.
>> +    if [ -z "$result" ]; then
>> +        result=$1
>> +    fi
>> +    printf -- "EO\n%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on value.
>> +_ovs_vsctl_complete_value () {
>> +    local result
>> +
>> +    # Just use user input as result.
>> +    if [ -z "$result" ]; then
>> +        result=$1
>> +    fi
>> +    printf -- "EO\n%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on key=value.
>> +_ovs_vsctl_complete_key_value () {
>> +    local orig_completions new_completions
>> +
>> +    orig_completions=$(__complete_key "$1")
>> +    for completion in ${orig_completions#*EO}; do
>> +        new_completions="${new_completions} ${completion}="
>> +    done
>> +    # If 'new_completions' is empty, just use user input as result.
>> +    if [ -z "$new_completions" ]; then
>> +        new_completions=$1
>> +    fi
>> +    printf -- "NOSPACE\nEO\n%s" "${new_completions}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on column.
>> +_ovs_vsctl_complete_column () {
>> +    local columns result
>> +
>> +    columns=$(ovsdb-client --no-headings list-columns
>> $_OVSDB_SERVER_LOCATION \
>> +        Open_vSwitch ${_OVS_VSCTL_PARSED_ARGS["TABLE"]})
>> +    result=$(printf "%s\n" "${columns}" \
>> +             | tr -d ':' | cut -d' ' -f1 \
>> +             | _ovs_vsctl_check_startswith_string "$1" | sort | uniq)
>> +    printf -- "EO\n%s\n" "${result}"
>> +}
>> +
>> +# Extract all system interfaces.
>> +_ovs_vsctl_get_sys_intf () {
>> +    local result
>> +
>> +    case "$(uname -o)" in
>> +        *Linux*)
>> +            result=$(ip -o link 2>/dev/null | cut -d':' -f2 \
>> +                     | sed -e 's/^ \(.*\)/\1/')
>> +            ;;
>> +        *)
>> +            result=$(ifconfig -a -s 2>/dev/null | cut -f1 -d' ' | tail
>> -n +2)
>> +            ;;
>> +    esac
>> +    printf "%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on system interface.
>> +_ovs_vsctl_complete_sysiface () {
>> +    local result
>> +
>> +    result=$(_ovs_vsctl_get_sys_intf |
>> _ovs_vsctl_check_startswith_string "$1")
>> +    printf -- "EO\n%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on interface.  If a bridge has already been specified,
>> +# just complete for that bridge.
>> +_ovs_vsctl_complete_iface () {
>> +    local result
>> +
>> +    if [ -n "${_OVS_VSCTL_PARSED_ARGS[BRIDGE]}" ]; then
>> +        result=$(_ovs_vsctl list-ifaces
>> "${_OVS_VSCTL_PARSED_ARGS[BRIDGE]}")
>> +    else
>> +        for bridge in $(_ovs_vsctl list-br); do
>> +            local ifaces
>> +
>> +            ifaces=$(_ovs_vsctl list-ifaces "${bridge}")
>> +            result="${result} ${ifaces}"
>> +        done
>> +    fi
>> +    printf "EO\n%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on COLUMN?:KEY=VALUE.
>> +_ovs_vsctl_complete_column_optkey_value () {
>> +    local result column key value completion
>> +
>> +    column=$(printf "%s\n" "$1" | cut -d '=' -f1 | cut -d':' -f1)
>> +    key=$(printf "%s\n" "$1" | cut -d '=' -f1 | cut -s -d':' -f2)
>> +    # The tr -d '\n' <<< makes sure that there are no leading or
>> +    # trailing accidental newlines.
>> +    table=$(tr -d '\n' <<< ${_OVS_VSCTL_PARSED_ARGS["TABLE"]})
>> +    # This might also be called after add-port or add-bond; in those
>> +    # cases, the table should implicitly be assumed to be "Port".
>> +    # This is done by checking if a NEW- parameter has been
>> +    # encountered and, if it has, using that type without the NEW- as
>> +    # the table.
>> +    if [ -z "$table" ]; then
>> +        if [ -n ${_OVS_VSCTL_PARSED_ARGS["NEW-PORT"]} ] \
>> +           || [ -n ${_OVS_VSCTL_PARSED_ARGS["NEW-BOND-PORT"]} ]; then
>> +            table="Port"
>> +        fi
>> +    fi
>> +    if [ -z "$key" ]; then
>> +        local columns=$(ovsdb-client --no-headings list-columns \
>> +            $_OVSDB_SERVER_LOCATION Open_vSwitch $table)
>> +
>> +        result=$(printf "%s\n" "${columns}" \
>> +                 | awk '/key.*value/ { print $1":"; next }
>> +                                     { print $1; next }' \
>> +                 | _ovs_vsctl_check_startswith_string "$1" | sort | uniq)
>> +    fi
>> +    if [[ $1 =~ ":" ]]; then
>> +        result=$(_ovs_vsctl_complete_key_given_table_column \
>> +                     "$key" "$table" "$column" "$column:")
>> +    fi
>> +    # If result is empty, just use user input as result.
>> +    if [ -z "$result" ]; then
>> +        result=$1
>> +    fi
>> +    printf -- "NOSPACE\nEO\n%s\n" "${result}"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on filename.
>> +_ovs_vsctl_complete_filename () {
>> +    local result
>> +
>> +    result=$(compgen -o filenames -A file "$1")
>> +    printf -- "EO\n%s\n" "${result}"
>> +}
>> +
>> +_ovs_vsctl_complete_bridge_fail_mode () {
>> +    printf -- "EO\nstandalone\nsecure"
>> +}
>> +
>> +# $1 = word to complete on.
>> +# Complete on target.
>> +_ovs_vsctl_complete_target () {
>> +    local result
>> +
>> +    if [[ "$1" =~ ^p?u ]]; then
>> +        local protocol pathname expansion_base result
>> +
>> +        protocol=$(cut -d':' -f1 <<< "$1")
>> +        pathname=$(cut -s -d':' -f2 <<< "$1")
>> +        expansion_base=$(compgen -W "unix punix" "$protocol")
>> +        expansion_base="$expansion_base:"
>> +        result=$(compgen -o filenames -A file \
>> +                         -P $expansion_base "${pathname}")
>> +        printf -- "NOSPACE\nEO\n%s\n" "${result}"
>> +    else
>> +        printf -- "NOSPACE\nEO\nssl:\ntcp:\nunix:\npssl:\nptcp:\npunix:"
>> +    fi
>> +}
>> +
>> +# Extract PS1 prompt.
>> +_ovs_vsctl_get_PS1 () {
>> +
>> +    # Original inspiration from
>> +    #
>> http://stackoverflow.com/questions/10060500/bash-how-to-evaluate-ps1-ps2,
>> +    # but changed quite a lot to make it more robust.
>> +
>> +    # Make sure the PS1 used doesn't include any of the special
>> +    # strings used to identify the prompt
>> +    myPS1="$(sed 's/Begin prompt/\\Begin prompt/; s/End prompt/\\End
>> prompt/' <<< "$PS1")"
>> +    # Export the current environment in case the prompt uses any
>> +    vars="$(env | cut -d'=' -f1)"
>> +    for var in $vars; do export $var; done
>> +    funcs="$(declare -F | cut -d' ' -f3)"
>> +    for func in $funcs; do export -f $func; done
>> +    # Get the prompt
>> +    v="$(bash --norc --noprofile -i 2>&1 <<< $'PS1=\"'"$myPS1"$'\" \n#
>> Begin prompt\n# End prompt')"
>> +    v="${v##*# Begin prompt}"
>> +    printf -- "$(tail -n +2 <<< "${v%# End prompt*}" | sed 's/\\Begin
>> prompt/Begin prompt/; s/\\End prompt/End prompt/')"
>> +
>> +}
>> +
>> +# Request a new value from user.  Nothing to complete on.
>> +_ovs_vsctl_complete_new () {
>> +    local two_word_type message result
>> +
>> +    if [ ! "$1" = "--" ]; then
>> +        two_word_type="${2/-/ }"
>> +        message="\nEnter a
>> ${two_word_type,,}:\n$(_ovs_vsctl_get_PS1)$COMP_LINE"
>> +        if [ -n "$1" ]; then
>> +            result="$1"
>> +        fi
>> +        printf -- "NOCOMP\nBM%sEM\nEO\n%s\n" "${message}" "${result}"
>> +    fi
>> +}
>> +
>> +_ovs_vsctl_complete_dashdash () {
>> +    printf -- "EO\n%s\n" "--"
>> +}
>> +
>> +
>> +# These functions are given two arguments:
>> +#
>> +# $1 is the word being completed
>> +#
>> +# $2 is the type of completion --- only currently useful for the
>> +# NEW-* functions.
>> +#
>> +# Note that the NEW-* functions actually are ``completed''; currently
>> +# the completions are just used to save the fact that they have
>> +# appeared for later use (i.e. implicit table calculation).
>> +#
>> +# The output is of the form <options>EO<completions>, where EO stands
>> +# for end options.  Currently available options are:
>> +#  - NOSPACE: Do not add a space at the end of each completion
>> +#  - NOCOMP: Do not complete, but store the output of the completion
>> +#    func in _OVS_VSCTL_PARSED_ARGS for later usage.
>> +#  - BM<message>EM: Print the <message>
>> +declare -A _OVS_VSCTL_ARG_COMPLETION_FUNCS=(
>> +    ["TABLE"]=_ovs_vsctl_complete_table
>> +    ["RECORD"]=_ovs_vsctl_complete_record
>> +    ["BRIDGE"]=_ovs_vsctl_complete_bridge
>> +    ["PARENT"]=_ovs_vsctl_complete_bridge
>> +    ["PORT"]=_ovs_vsctl_complete_port
>> +    ["KEY"]=_ovs_vsctl_complete_key
>> +    ["VALUE"]=_ovs_vsctl_complete_value
>> +    ["ARG"]=_ovs_vsctl_complete_value
>> +    ["IFACE"]=_ovs_vsctl_complete_iface
>> +    ["SYSIFACE"]=_ovs_vsctl_complete_sysiface
>> +    ["COLUMN"]=_ovs_vsctl_complete_column
>> +    ["COLUMN?:KEY"]=_ovs_vsctl_complete_column_optkey_value
>> +    ["COLUMN?:KEY=VALUE"]=_ovs_vsctl_complete_column_optkey_value
>> +    ["KEY=VALUE"]=_ovs_vsctl_complete_key_value
>> +    ["?KEY=VALUE"]=_ovs_vsctl_complete_key_value
>> +    ["PRIVATE-KEY"]=_ovs_vsctl_complete_filename
>> +    ["CERTIFICATE"]=_ovs_vsctl_complete_filename
>> +    ["CA-CERT"]=_ovs_vsctl_complete_filename
>> +    ["MODE"]=_ovs_vsctl_complete_bridge_fail_mode
>> +    ["TARGET"]=_ovs_vsctl_complete_target
>> +    ["NEW-BRIDGE"]=_ovs_vsctl_complete_new
>> +    ["NEW-PORT"]=_ovs_vsctl_complete_new
>> +    ["NEW-BOND-PORT"]=_ovs_vsctl_complete_new
>> +    ["NEW-VLAN"]=_ovs_vsctl_complete_new
>> +    ["--"]=_ovs_vsctl_complete_dashdash
>> +)
>> +
>> +# $1: Argument type, may include vertical bars to mean OR
>> +# $2: Beginning of completion
>> +#
>> +# Note that this checks for existance in
>> +# _OVS_VSCTL_ARG_COMPLETION_FUNCS; if the argument type ($1) is not
>> +# there it will fail gracefully.
>> +_ovs_vsctl_possible_completions_of_argument () {
>> +    local possible_types completions tmp
>> +
>> +    completions="EO"
>> +
>> +    possible_types=$(printf "%s\n" "$1" | tr '|' '\n')
>> +    for type in $possible_types; do
>> +        if [ ${_OVS_VSCTL_ARG_COMPLETION_FUNCS["${type^^}"]} ]; then
>> +            tmp=$(${_OVS_VSCTL_ARG_COMPLETION_FUNCS["${type^^}"]} \
>> +                      "$2" "${type^^}")
>> +            tmp_noEO="${tmp#*EO}"
>> +            tmp_EO="${tmp%%EO*}"
>> +            completions=$(printf "%s%s\n%s" "${tmp_EO}" \
>> +                                 "${completions}" "${tmp_noEO}")
>> +        fi
>> +    done
>> +    printf "%s\n" "${completions}"
>> +}
>> +
>> +# $1 = List of argument types
>> +# $2 = current pointer into said list
>> +# $3 = word to complete on
>> +# Outputs list of possible completions
>> +# The return value is the index in the cmd_args($1) list that should
>> +# next be matched, if only one of them did, or 254 if there are no
>> +# matches, so it doesn't know what comes next.
>> +_ovs_vsctl_complete_argument() {
>> +    local cmd_args arg expansion index
>> +
>> +    new=$(printf "%s\n" "$1" | grep -- '.\+')
>> +    readarray -t cmd_args <<< "$new";
>> +    arg=${cmd_args[$2]}
>> +    case ${arg:0:1} in
>> +        !)
>> +            expansion=$(_ovs_vsctl_possible_completions_of_argument \
>> +                            "${arg:1}" $3)
>> +            index=$(($2+1))
>> +            ;;
>> +        \?|\*)
>> +            local tmp1 tmp2 arg2_index tmp2_noEO tmp2_EO
>> +            tmp1=$(_ovs_vsctl_possible_completions_of_argument
>> "${arg:1}" $3)
>> +            tmp2=$(_ovs_vsctl_complete_argument "$1" "$(($2+1))" "$3")
>> +            arg2_index=$?
>> +            if _ovs_vsctl_detect_nonzero_completions "$tmp1" \
>> +               && _ovs_vsctl_detect_nonzero_completions "$tmp2"; then
>> +                if [ "${arg:0:1}" = "*" ]; then
>> +                    index=$2;
>> +                else
>> +                    index=$(($2+1));
>> +                fi
>> +            fi
>> +            if _ovs_vsctl_detect_nonzero_completions "$tmp1" \
>> +               && (! _ovs_vsctl_detect_nonzero_completions "$tmp2"); then
>> +                if [ "${arg:0:1}" = "*" ]; then
>> +                    index=$2;
>> +                else
>> +                    index=$(($2+1));
>> +                fi
>> +            fi
>> +            if (! _ovs_vsctl_detect_nonzero_completions "$tmp1") \
>> +               && _ovs_vsctl_detect_nonzero_completions "$tmp2"; then
>> +                index=$arg2_index
>> +            fi
>> +            if (! _ovs_vsctl_detect_nonzero_completions "$tmp1") \
>> +               && (! _ovs_vsctl_detect_nonzero_completions "$tmp2"); then
>> +                index=254
>> +            fi
>> +            # Don't allow secondary completions to inhibit primary
>> +            # completions:
>> +            if [[ $tmp2 =~ ^([^E]|E[^O])*NOCOMP ]]; then
>> +                tmp2=""
>> +            fi
>> +            tmp2_noEO="${tmp2#*EO}"
>> +            tmp2_EO="${tmp2%%EO*}"
>> +            expansion=$(printf "%s%s\n%s" "${tmp2_EO}" \
>> +                               "${tmp1}" "${tmp2_noEO}")
>> +            ;;
>> +    esac
>> +    printf "%s\n" "$expansion"
>> +    return $index
>> +}
>> +
>> +_ovs_vsctl_detect_nospace () {
>> +    if [[ $1 =~ ^([^E]|E[^O])*NOSPACE ]]; then
>> +        _OVS_VSCTL_COMP_NOSPACE=true
>> +    fi
>> +}
>> +
>> +_ovs_vsctl_process_messages () {
>> +    local message
>> +
>> +    message="${1#*BM}"
>> +    message="${message%%EM*}"
>> +    if [ "$test" = "true" ]; then
>> +        printf -- "--- BEGIN MESSAGE"
>> +    fi
>> +    printf "${message}"
>> +    if [ "$test" = "true" ]; then
>> +        printf -- "--- END MESSAGE"
>> +    fi
>> +}
>> +
>> +# The general strategy here is that the same functions that decide
>> +# completions can also capture the necessary context for later
>> +# completions.  This means that there is no distinction between the
>> +# processing for words that are not the current word and words that
>> +# are the current word.
>> +#
>> +# Parsing up until the command word happens starts with everything
>> +# valid; as the syntax order of ovs-vsctl is fairly strict, when types
>> +# of words that preclude other words from happending can turn them
>> +# off; this is controlled by valid_globals, valid_opts, and
>> +# valid_commands.  given_opts is used to narrow down which commands
>> +# are valid based on the previously given options.
>> +#
>> +# After the command has been detected, the parsing becomes more
>> +# complicated.  The cmd_pos variable is set to 0 when the command is
>> +# detected; it is used as a pointer into an array of the argument
>> +# types for that given command.  The argument types are stored in both
>> +# cmd_args and raw_cmd as the main loop uses properties of arrays to
>> +# detect certain conditions, but arrays cannot be passed to functions.
>> +# To be able to deal with optional or repeatable arguments, the exit
>> +# status of the function _ovs_vsctl_complete_argument represents where
>> +# it has determined that the next argument will be.
>> +_ovs_vsctl_bashcomp () {
>> +    local cur valid_globals cmd_args raw_cmd cmd_pos valid_globals
>> valid_opts
>> +    local test="false"
>> +
>> +    # Prepare the COMP_* variables based on input.
>> +    if [ "$1" = "test" ]; then
>> +        test="true"
>> +        export COMP_LINE="ovs-vsctl $2"
>> +        tmp="ovs-vsctl"$'\n'"$(tr ' ' '\n' <<< "${COMP_LINE}x")"
>> +        tmp="${tmp%x}"
>> +        readarray -t COMP_WORDS \
>> +                  <<< "$tmp"
>> +        export COMP_WORDS
>> +        export COMP_CWORD="$((${#COMP_WORDS[@]}-1))"
>> +        export PS1="> "
>> +        # This is used to make the PS1-extraction code not emit extra
>> +        # escape sequences; it seems like bash assumes that unknown
>> +        # terminal names are dumb which means this should work even in
>> +        # the unlikely occurence of the terminal "dumb" not existing.
>> +        export TERM="dumb"
>> +    fi
>> +
>> +    # Extract the conf.db path.
>> +    db=$(sed -n 's/.*--db=\([^ ]*\).*/\1/p' <<< "$COMP_LINE")
>> +    if [ -n "$db" ]; then
>> +        _OVSDB_SERVER_LOCATION="$db"
>> +    fi
>> +
>> +    # If having trouble accessing the database, return.
>> +    if ! _ovs_vsctl get-manager 2>/dev/null; then
>> +        return 1;
>> +    fi
>> +
>> +    _OVS_VSCTL_PARSED_ARGS=()
>> +    _OVS_VSCTL_NEW_RECORDS=()
>> +    cmd_pos=-1
>> +    cur=${COMP_WORDS[COMP_CWORD]}
>> +    valid_globals=true
>> +    valid_opts=true
>> +    valid_commands=true
>> +    given_opts=""
>> +    index=1
>> +    export COMP_WORDBREAKS=" "
>> +    for word in "${COMP_WORDS[@]:1:${COMP_CWORD}} "; do
>> +        _OVS_VSCTL_COMP_NOSPACE=false
>> +        local completion
>> +        completion=""
>> +        if [ $cmd_pos -gt -1 ]; then
>> +            local tmp tmp_noop arg possible_newindex
>> +            tmp=$(_ovs_vsctl_complete_argument "$raw_cmd" "$cmd_pos"
>> "$word")
>> +            possible_newindex=$?
>> +            # Check for nospace.
>> +            _ovs_vsctl_detect_nospace $tmp
>> +            # Remove all options.
>> +            tmp_noop="${tmp#*EO}"
>> +
>> +            # Allow commands to specify that they should not be
>> +            # completed
>> +            if ! [[ $tmp =~ ^([^E]|E[^O])*NOCOMP ]]; then
>> +                # Directly assignment, since 'completion' is guaranteed
>> to
>> +                # to be empty.
>> +                completion="$tmp_noop"
>> +                # If intermediate completion is empty, it means that the
>> current
>> +                # argument is invalid.  And we should not continue.
>> +                if [ $index -lt $COMP_CWORD ] \
>> +                    && (! _ovs_vsctl_detect_nonzero_completions
>> "$completion"); then
>> +                    _ovs_vsctl_process_messages "BM\nCannot complete
>> \'${COMP_WORDS[$index]}\' at index
>> ${index}:\n$(_ovs_vsctl_get_PS1)${COMP_LINE}EM\nEO\n"
>> +                    return 1
>> +                fi
>> +            else
>> +                # Only allow messages when there is no completion
>> +                # printout and when on the current word.
>> +                if [ $index -eq $COMP_CWORD ]; then
>> +                    _ovs_vsctl_process_messages "${tmp}"
>> +                fi
>> +                # Append the new record to _OVS_VSCTL_NEW_RECORDS.
>> +
>> _OVS_VSCTL_NEW_RECORDS["${cmd_args[$cmd_pos]##*-}"]="${_OVS_VSCTL_NEW_RECORDS["${cmd_args[$cmd_pos]##*-}"]}
>> $tmp_noop"
>> +            fi
>> +            if [[ $cmd_pos -lt ${#cmd_args} ]]; then
>> +                _OVS_VSCTL_PARSED_ARGS["${cmd_args[$cmd_pos]:1}"]=$word
>> +            fi
>> +            if [ $possible_newindex -lt 254 ]; then
>> +                cmd_pos=$possible_newindex
>> +            fi
>> +        fi
>> +
>> +        if [ $valid_globals == true ]; then
>> +            tmp=$(_ovs_vsctl_bashcomp_globalopt $word)
>> +            _ovs_vsctl_detect_nospace $tmp
>> +            completion="${completion} ${tmp#*EO}"
>> +        fi
>> +        if [ $valid_opts == true ]; then
>> +            tmp=$(_ovs_vsctl_bashcomp_localopt "$given_opts" $word)
>> +            _ovs_vsctl_detect_nospace $tmp
>> +            completion="${completion} ${tmp#*EO}"
>> +            if [ $index -lt $COMP_CWORD ] \
>> +               && _ovs_vsctl_detect_nonzero_completions "$tmp"; then
>> +                valid_globals=false
>> +                given_opts="${given_opts} ${word}"
>> +            fi
>> +        fi
>> +        if [ $valid_commands = true ]; then
>> +            tmp=$(_ovs_vsctl_bashcomp_command "$given_opts" $word)
>> +            _ovs_vsctl_detect_nospace $tmp
>> +            completion="${completion} ${tmp#*EO}"
>> +            if [ $index -lt $COMP_CWORD ] \
>> +               && _ovs_vsctl_detect_nonzero_completions "$tmp"; then
>> +                valid_globals=false
>> +                valid_opts=false
>> +                valid_commands=false
>> +                cmd_pos=0
>> +                raw_cmd=$(_ovs_vsctl_expand_command "$word")
>> +                readarray -t cmd_args <<< "$raw_cmd"
>> +            fi
>> +        fi
>> +        if [ "$word" = "--" ] && [ $index -lt $COMP_CWORD ]; then
>> +            # Empty the parsed args array.
>> +            _OVS_VSCTL_PARSED_AGS=()
>> +            cmd_pos=-1
>> +            # No longer allow global options after '--'.
>> +            valid_globals=false
>> +            valid_opts=true
>> +            valid_commands=true
>> +            given_opts=""
>> +        fi
>> +        completion="$(sort -u <<< "$(tr ' ' '\n' <<< ${completion})")"
>> +        if [ $index -eq $COMP_CWORD ]; then
>> +            if [ "$test" = "true" ]; then
>> +                if [ "${_OVS_VSCTL_COMP_NOSPACE}" = "true" ]; then
>> +                    printf "%s" "$completion" | sed -e '/^$/d'
>> +                else
>> +                    printf "%s" "$completion" | sed -e '/^$/d; s/$/ /g'
>> +                fi
>> +                printf "\n"
>> +            else
>> +                if [ "${_OVS_VSCTL_COMP_NOSPACE}" = "true" ]; then
>> +                    compopt -o nospace
>> +                    COMPREPLY=( $(compgen -W "${completion}" -- $word) )
>> +                else
>> +                    compopt +o nospace
>> +                    COMPREPLY=( $(compgen -W "${completion}" -- $word) )
>> +                fi
>> +            fi
>> +        fi
>> +        index=$(($index+1))
>> +    done
>> +}
>> +
>> +if [ "$1" = "test" ]; then
>> +    _ovs_vsctl_bashcomp "$@"
>> +else
>> +    complete -F _ovs_vsctl_bashcomp ovs-vsctl
>> +fi
>> diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
>> index 8b64245..c39c2ba 100644
>> --- a/utilities/ovs-vsctl.c
>> +++ b/utilities/ovs-vsctl.c
>> @@ -34,6 +34,7 @@
>>  #include "fatal-signal.h"
>>  #include "hash.h"
>>  #include "json.h"
>> +#include "list.h"
>>  #include "ovsdb-data.h"
>>  #include "ovsdb-idl.h"
>>  #include "poll-loop.h"
>> @@ -63,6 +64,11 @@ struct vsctl_command_syntax {
>>      int min_args;               /* Min number of arguments following
>> name. */
>>      int max_args;               /* Max number of arguments following
>> name. */
>>
>> +    /* Names that roughly describe the arguments that the command
>> +     * uses.  These should be similar to the names displayed in the
>> +     * man page or in the help output. */
>> +    const char *arguments;
>> +
>>      /* If nonnull, calls ovsdb_idl_add_column() or ovsdb_idl_add_table()
>> for
>>       * each column or table in ctx->idl that it uses. */
>>      void (*prerequisites)(struct vsctl_context *ctx);
>> @@ -85,6 +91,7 @@ struct vsctl_command_syntax {
>>      /* A comma-separated list of supported options, e.g. "--a,--b", or
>> the
>>       * empty string if the command does not support any options. */
>>      const char *options;
>> +
>>      enum { RO, RW } mode;       /* Does this command modify the
>> database? */
>>  };
>>
>> @@ -141,6 +148,8 @@ OVS_NO_RETURN static void vsctl_exit(int status);
>>  OVS_NO_RETURN static void vsctl_fatal(const char *, ...)
>> OVS_PRINTF_FORMAT(1, 2);
>>  static char *default_db(void);
>>  OVS_NO_RETURN static void usage(void);
>> +OVS_NO_RETURN static void print_vsctl_commands(void);
>> +OVS_NO_RETURN static void print_vsctl_options(const struct option
>> *options);
>>  static void parse_options(int argc, char *argv[], struct shash
>> *local_options);
>>  static bool might_write_to_db(char **argv);
>>
>> @@ -292,6 +301,8 @@ parse_options(int argc, char *argv[], struct shash
>> *local_options)
>>          OPT_PEER_CA_CERT,
>>          OPT_LOCAL,
>>          OPT_RETRY,
>> +        OPT_COMMANDS,
>> +        OPT_OPTIONS,
>>          VLOG_OPTION_ENUMS,
>>          TABLE_OPTION_ENUMS
>>      };
>> @@ -304,6 +315,8 @@ parse_options(int argc, char *argv[], struct shash
>> *local_options)
>>          {"timeout", required_argument, NULL, 't'},
>>          {"retry", no_argument, NULL, OPT_RETRY},
>>          {"help", no_argument, NULL, 'h'},
>> +        {"commands", no_argument, NULL, OPT_COMMANDS},
>> +        {"options", no_argument, NULL, OPT_OPTIONS},
>>          {"version", no_argument, NULL, 'V'},
>>          VLOG_LONG_OPTIONS,
>>          TABLE_LONG_OPTIONS,
>> @@ -418,6 +431,12 @@ parse_options(int argc, char *argv[], struct shash
>> *local_options)
>>          case 'h':
>>              usage();
>>
>> +        case OPT_COMMANDS:
>> +            print_vsctl_commands();
>> +
>> +        case OPT_OPTIONS:
>> +            print_vsctl_options(global_long_options);
>> +
>>          case 'V':
>>              ovs_print_version(0, 0);
>>              printf("DB Schema %s\n", ovsrec_get_db_version());
>> @@ -729,6 +748,153 @@ Other options:\n\
>>      exit(EXIT_SUCCESS);
>>  }
>>
>> +/* Converts the command arguments into format that can be parsed by
>> + * bash completion script.
>> + *
>> + * Therein, arguments will be attached with following prefixes:
>> + *
>> + *    !argument :: The argument is required
>> + *    ?argument :: The argument is optional
>> + *    *argument :: The argument may appear any number (0 or more) times
>> + *    +argument :: The argument may appear one or more times
>> + *
>> + */
>> +static void
>> +print_command_arguments(const struct vsctl_command_syntax *command)
>> +{
>> +    /*
>> +     * The argument string is parsed in reverse.  We use a stack
>> 'oew_stack'
>> +     * to keep track of nested optionals.  Whenever a ']' is
>> encountered, we
>> +     * push an element to 'oew_stack'.  The 'optional_ends_word' is set
>> if
>> +     * the ']' is not nested.  Subsequently, we pop an entry everytime
>> '[' is
>> +     * met.
>> +     *
>> +     * We use 'whole_word_is_optional' value to decide whether or not a
>> ! or
>> +     * + should be added on encountering a space: if the optional
>> surronds
>> +     * the whole word then it shouldn't be, but if it is only a part of
>> the
>> +     * word (i.e. [key=]value), it should be.
>> +     */
>> +    struct oew_stack_element {
>> +        bool optional_ends_word;
>> +        struct ovs_list node;
>> +    };
>> +
>> +    const char *arguments = command->arguments;
>> +    struct ovs_list oew_stack;
>> +    int length = strlen(arguments);
>> +    char *simple_args = xzalloc(2 * length * sizeof(char));
>> +    /* One char has already been written: \0 */
>> +    int chars_written = 1;
>> +    int in_repeated = 0;
>> +    bool whole_word_is_optional = false;
>> +    int i;
>> +
>> +    list_init(&oew_stack);
>> +
>> +    for (i = 1; i <= length; i++) {
>> +        int simple_index = 2 * length - chars_written - 1;
>> +        char current = arguments[length-i];
>> +        struct oew_stack_element *elem;
>> +        int oew;
>> +
>> +        switch(current) {
>> +        case ']':
>> +            elem = xmalloc(sizeof *elem);
>> +            if (i == 1
>> +                || arguments[length-i+1] == ' '
>> +                || arguments[length-i+1] == '.') {
>> +                elem->optional_ends_word = true;
>> +            } else {
>> +                elem->optional_ends_word = false;
>> +            }
>> +            list_push_back(&oew_stack, &elem->node);
>> +            break;
>> +        case '[':
>> +            elem = CONTAINER_OF(list_pop_back(&oew_stack),
>> +                                struct oew_stack_element,
>> +                                node);
>> +            oew = elem->optional_ends_word;
>> +            free(elem);
>> +            /* Checks if the whole word is optional, and sets the
>> +             * 'whole_word_is_optional' accordingly. */
>> +            if ((i == length || arguments[length-i-1] == ' ')
>> +                && oew) {
>> +                simple_args[simple_index] = in_repeated ? '*' : '?';
>> +                whole_word_is_optional = oew;
>> +            } else {
>> +                simple_args[simple_index] = '?';
>> +                whole_word_is_optional = 0;
>> +            }
>> +            chars_written++;
>> +            break;
>> +        case ' ':
>> +            if (!whole_word_is_optional) {
>> +                simple_args[simple_index] = in_repeated ? '+' : '!';
>> +                chars_written++;
>> +            }
>> +            simple_args[2 * length - ++chars_written] = ' ';
>> +            in_repeated = 0;
>> +            whole_word_is_optional = false;
>> +            break;
>> +        case '.':
>> +            in_repeated = 1;
>> +            break;
>> +        default:
>> +            simple_args[simple_index] = current;
>> +            chars_written++;
>> +        }
>> +    }
>> +    if (arguments[0] != '[' && chars_written > 1) {
>> +        simple_args[2 * length - ++chars_written] = in_repeated ? '+' :
>> '!';
>> +    }
>> +    printf("%s", simple_args + 2 * length - chars_written);
>> +}
>> +
>> +
>> +static void
>> +print_vsctl_commands(void)
>> +{
>> +    const struct vsctl_command_syntax *p;
>> +
>> +    for (p = get_all_commands(); p->name; p++) {
>> +        char *options = xstrdup(p->options);
>> +        char *options_begin = options;
>> +        char *item;
>> +
>> +        for (item = strsep(&options, ",");
>> +             item != NULL;
>> +             item = strsep(&options, ",")) {
>> +            if (strlen(item) > 0) {
>> +                printf("[%s] ", item);
>> +            }
>> +        }
>> +        printf(",%s,", p->name);
>> +        print_command_arguments(p);
>> +        printf("\n");
>> +
>> +        free(options_begin);
>> +    }
>> +
>> +    exit(EXIT_SUCCESS);
>> +}
>> +
>> +
>> +static void
>> +print_vsctl_options(const struct option *options)
>> +{
>> +    for (; options->name; options++) {
>> +        const struct option *o = options;
>> +
>> +        printf("--%s%s\n", o->name, o->has_arg ? "=ARG" : "");
>> +        if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) {
>> +            printf("-%c%s\n", o->val, o->has_arg ? " ARG" : "");
>> +        }
>> +    }
>> +
>> +    exit(EXIT_SUCCESS);
>> +}
>> +
>> +
>>  static char *
>>  default_db(void)
>>  {
>> @@ -3545,6 +3711,7 @@ cmd_remove(struct vsctl_context *ctx)
>>          rm_type.n_max = UINT_MAX;
>>          error = ovsdb_datum_from_string(&rm, &rm_type,
>>                                          ctx->argv[i], ctx->symtab);
>> +
>>          if (error) {
>>              if (ovsdb_type_is_map(&rm_type)) {
>>                  rm_type.value.type = OVSDB_TYPE_VOID;
>> @@ -4263,75 +4430,97 @@ try_again:
>>
>>  static const struct vsctl_command_syntax all_commands[] = {
>>      /* Open vSwitch commands. */
>> -    {"init", 0, 0, NULL, cmd_init, NULL, "", RW},
>> -    {"show", 0, 0, pre_cmd_show, cmd_show, NULL, "", RO},
>> +    {"init", 0, 0, "", NULL, cmd_init, NULL, "", RW},
>> +    {"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "", RO},
>>
>>      /* Bridge commands. */
>> -    {"add-br", 1, 3, pre_get_info, cmd_add_br, NULL, "--may-exist", RW},
>> -    {"del-br", 1, 1, pre_get_info, cmd_del_br, NULL, "--if-exists", RW},
>> -    {"list-br", 0, 0, pre_get_info, cmd_list_br, NULL, "--real,--fake",
>> RO},
>> -    {"br-exists", 1, 1, pre_get_info, cmd_br_exists, NULL, "", RO},
>> -    {"br-to-vlan", 1, 1, pre_get_info, cmd_br_to_vlan, NULL, "", RO},
>> -    {"br-to-parent", 1, 1, pre_get_info, cmd_br_to_parent, NULL, "", RO},
>> -    {"br-set-external-id", 2, 3, pre_cmd_br_set_external_id,
>> -     cmd_br_set_external_id, NULL, "", RW},
>> -    {"br-get-external-id", 1, 2, pre_cmd_br_get_external_id,
>> +    {"add-br", 1, 3, "NEW-BRIDGE [PARENT] [NEW-VLAN]", pre_get_info,
>> +     cmd_add_br, NULL, "--may-exist", RW},
>> +    {"del-br", 1, 1, "BRIDGE", pre_get_info, cmd_del_br,
>> +     NULL, "--if-exists", RW},
>> +    {"list-br", 0, 0, "", pre_get_info, cmd_list_br, NULL,
>> "--real,--fake",
>> +     RO},
>> +    {"br-exists", 1, 1, "BRIDGE", pre_get_info, cmd_br_exists, NULL, "",
>> RO},
>> +    {"br-to-vlan", 1, 1, "BRIDGE", pre_get_info, cmd_br_to_vlan, NULL,
>> "",
>> +     RO},
>> +    {"br-to-parent", 1, 1, "BRIDGE", pre_get_info, cmd_br_to_parent,
>> NULL,
>> +     "", RO},
>> +    {"br-set-external-id", 2, 3, "BRIDGE KEY [VALUE]",
>> +     pre_cmd_br_set_external_id, cmd_br_set_external_id, NULL, "", RW},
>> +    {"br-get-external-id", 1, 2, "BRIDGE [KEY]",
>> pre_cmd_br_get_external_id,
>>       cmd_br_get_external_id, NULL, "", RO},
>>
>>      /* Port commands. */
>> -    {"list-ports", 1, 1, pre_get_info, cmd_list_ports, NULL, "", RO},
>> -    {"add-port", 2, INT_MAX, pre_get_info, cmd_add_port, NULL,
>> "--may-exist",
>> -     RW},
>> -    {"add-bond", 4, INT_MAX, pre_get_info, cmd_add_bond, NULL,
>> -     "--may-exist,--fake-iface", RW},
>> -    {"del-port", 1, 2, pre_get_info, cmd_del_port, NULL,
>> +    {"list-ports", 1, 1, "BRIDGE", pre_get_info, cmd_list_ports, NULL,
>> "",
>> +     RO},
>> +    {"add-port", 2, INT_MAX, "BRIDGE NEW-PORT [COLUMN[:KEY]=VALUE]...",
>> +     pre_get_info, cmd_add_port, NULL, "--may-exist", RW},
>> +    {"add-bond", 4, INT_MAX,
>> +     "BRIDGE NEW-BOND-PORT SYSIFACE... [COLUMN[:KEY]=VALUE]...",
>> pre_get_info,
>> +     cmd_add_bond, NULL, "--may-exist,--fake-iface", RW},
>> +    {"del-port", 1, 2, "[BRIDGE] PORT|IFACE", pre_get_info,
>> cmd_del_port, NULL,
>>       "--if-exists,--with-iface", RW},
>> -    {"port-to-br", 1, 1, pre_get_info, cmd_port_to_br, NULL, "", RO},
>> +    {"port-to-br", 1, 1, "PORT", pre_get_info, cmd_port_to_br, NULL, "",
>> RO},
>>
>>      /* Interface commands. */
>> -    {"list-ifaces", 1, 1, pre_get_info, cmd_list_ifaces, NULL, "", RO},
>> -    {"iface-to-br", 1, 1, pre_get_info, cmd_iface_to_br, NULL, "", RO},
>> +    {"list-ifaces", 1, 1, "BRIDGE", pre_get_info, cmd_list_ifaces, NULL,
>> "",
>> +     RO},
>> +    {"iface-to-br", 1, 1, "IFACE", pre_get_info, cmd_iface_to_br, NULL,
>> "",
>> +     RO},
>>
>>      /* Controller commands. */
>> -    {"get-controller", 1, 1, pre_controller, cmd_get_controller, NULL,
>> "", RO},
>> -    {"del-controller", 1, 1, pre_controller, cmd_del_controller, NULL,
>> "", RW},
>> -    {"set-controller", 1, INT_MAX, pre_controller, cmd_set_controller,
>> NULL,
>> +    {"get-controller", 1, 1, "BRIDGE", pre_controller,
>> cmd_get_controller,
>> +     NULL, "", RO},
>> +    {"del-controller", 1, 1, "BRIDGE", pre_controller,
>> cmd_del_controller,
>> +     NULL, "", RW},
>> +    {"set-controller", 1, INT_MAX, "BRIDGE TARGET...", pre_controller,
>> +     cmd_set_controller, NULL, "", RW},
>> +    {"get-fail-mode", 1, 1, "BRIDGE", pre_get_info, cmd_get_fail_mode,
>> NULL,
>> +     "", RO},
>> +    {"del-fail-mode", 1, 1, "BRIDGE", pre_get_info, cmd_del_fail_mode,
>> NULL,
>>       "", RW},
>> -    {"get-fail-mode", 1, 1, pre_get_info, cmd_get_fail_mode, NULL, "",
>> RO},
>> -    {"del-fail-mode", 1, 1, pre_get_info, cmd_del_fail_mode, NULL, "",
>> RW},
>> -    {"set-fail-mode", 2, 2, pre_get_info, cmd_set_fail_mode, NULL, "",
>> RW},
>> +    {"set-fail-mode", 2, 2, "BRIDGE MODE", pre_get_info,
>> cmd_set_fail_mode,
>> +     NULL, "", RW},
>>
>>      /* Manager commands. */
>> -    {"get-manager", 0, 0, pre_manager, cmd_get_manager, NULL, "", RO},
>> -    {"del-manager", 0, 0, pre_manager, cmd_del_manager, NULL, "", RW},
>> -    {"set-manager", 1, INT_MAX, pre_manager, cmd_set_manager, NULL, "",
>> RW},
>> +    {"get-manager", 0, 0, "", pre_manager, cmd_get_manager, NULL, "",
>> RO},
>> +    {"del-manager", 0, 0, "", pre_manager, cmd_del_manager, NULL, "",
>> RW},
>> +    {"set-manager", 1, INT_MAX, "TARGET...", pre_manager,
>> cmd_set_manager,
>> +     NULL, "", RW},
>>
>>      /* SSL commands. */
>> -    {"get-ssl", 0, 0, pre_cmd_get_ssl, cmd_get_ssl, NULL, "", RO},
>> -    {"del-ssl", 0, 0, pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW},
>> -    {"set-ssl", 3, 3, pre_cmd_set_ssl, cmd_set_ssl, NULL, "--bootstrap",
>> RW},
>> +    {"get-ssl", 0, 0, "", pre_cmd_get_ssl, cmd_get_ssl, NULL, "", RO},
>> +    {"del-ssl", 0, 0, "", pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW},
>> +    {"set-ssl", 3, 3, "PRIVATE-KEY CERTIFICATE CA-CERT", pre_cmd_set_ssl,
>> +     cmd_set_ssl, NULL, "--bootstrap", RW},
>>
>>      /* Switch commands. */
>> -    {"emer-reset", 0, 0, pre_cmd_emer_reset, cmd_emer_reset, NULL, "",
>> RW},
>> +    {"emer-reset", 0, 0, "", pre_cmd_emer_reset, cmd_emer_reset, NULL,
>> "", RW},
>>
>>      /* Database commands. */
>> -    {"comment", 0, INT_MAX, NULL, NULL, NULL, "", RO},
>> -    {"get", 2, INT_MAX, pre_cmd_get, cmd_get, NULL, "--if-exists,--id=",
>> RO},
>> -    {"list", 1, INT_MAX, pre_cmd_list, cmd_list, NULL,
>> +    {"comment", 0, INT_MAX, "[ARG]...", NULL, NULL, NULL, "", RO},
>> +    {"get", 2, INT_MAX, "TABLE RECORD [COLUMN[:KEY]]...",pre_cmd_get,
>> cmd_get,
>> +     NULL, "--if-exists,--id=", RO},
>> +    {"list", 1, INT_MAX, "TABLE [RECORD]...", pre_cmd_list, cmd_list,
>> NULL,
>>       "--if-exists,--columns=", RO},
>> -    {"find", 1, INT_MAX, pre_cmd_find, cmd_find, NULL, "--columns=", RO},
>> -    {"set", 3, INT_MAX, pre_cmd_set, cmd_set, NULL, "--if-exists", RW},
>> -    {"add", 4, INT_MAX, pre_cmd_add, cmd_add, NULL, "--if-exists", RW},
>> -    {"remove", 4, INT_MAX, pre_cmd_remove, cmd_remove, NULL,
>> "--if-exists",
>> -     RW},
>> -    {"clear", 3, INT_MAX, pre_cmd_clear, cmd_clear, NULL, "--if-exists",
>> RW},
>> -    {"create", 2, INT_MAX, pre_create, cmd_create, post_create, "--id=",
>> RW},
>> -    {"destroy", 1, INT_MAX, pre_cmd_destroy, cmd_destroy, NULL,
>> -     "--if-exists,--all", RW},
>> -    {"wait-until", 2, INT_MAX, pre_cmd_wait_until, cmd_wait_until, NULL,
>> "",
>> -     RO},
>> -
>> -    {NULL, 0, 0, NULL, NULL, NULL, NULL, RO},
>> +    {"find", 1, INT_MAX, "TABLE [COLUMN[:KEY]=VALUE]...", pre_cmd_find,
>> +     cmd_find, NULL, "--columns=", RO},
>> +    {"set", 3, INT_MAX, "TABLE RECORD COLUMN[:KEY]=VALUE...",
>> pre_cmd_set,
>> +     cmd_set, NULL, "--if-exists", RW},
>> +    {"add", 4, INT_MAX, "TABLE RECORD COLUMN [KEY=]VALUE...",
>> pre_cmd_add,
>> +     cmd_add, NULL, "--if-exists", RW},
>> +    {"remove", 4, INT_MAX, "TABLE RECORD COLUMN KEY|VALUE|KEY=VALUE...",
>> +     pre_cmd_remove, cmd_remove, NULL, "--if-exists", RW},
>> +    {"clear", 3, INT_MAX, "TABLE RECORD COLUMN...", pre_cmd_clear,
>> cmd_clear,
>> +     NULL, "--if-exists", RW},
>> +    {"create", 2, INT_MAX, "TABLE COLUMN[:KEY]=VALUE...", pre_create,
>> +     cmd_create, post_create, "--id=", RW},
>> +    {"destroy", 1, INT_MAX, "TABLE [RECORD]...", pre_cmd_destroy,
>> cmd_destroy,
>> +     NULL, "--if-exists,--all", RW},
>> +    {"wait-until", 2, INT_MAX, "TABLE RECORD [COLUMN[:KEY]=VALUE]...",
>> +     pre_cmd_wait_until, cmd_wait_until, NULL, "", RO},
>> +
>> +    {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO},
>>  };
>>
>>  static const struct vsctl_command_syntax *get_all_commands(void)
>> --
>> 1.7.9.5
>>
>>
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to