diff --git a/Makefile b/Makefile index f51abfd66..c1bbafaaa 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ localtest localunittest localintegration \ test unittest integration +PREFIX := $(DESTDIR)/usr/local +BINDIR := $(PREFIX)/sbin RUNC_IMAGE := runc_dev RUNC_TEST_IMAGE := runc_test PROJECT := github.com/opencontainers/runc @@ -16,7 +18,7 @@ export GOPATH := $(CURDIR)/Godeps/_workspace MAN_DIR := $(CURDIR)/man/man8 MAN_PAGES = $(shell ls $(MAN_DIR)/*.8) MAN_PAGES_BASE = $(notdir $(MAN_PAGES)) -MAN_INSTALL_PATH := /usr/local/share/man/man8/ +MAN_INSTALL_PATH := ${PREFIX}/share/man/man8/ all: $(RUNC_LINK) go build -i -ldflags "-X main.gitCommit=${COMMIT}" -tags "$(BUILDTAGS)" -o runc . @@ -62,14 +64,20 @@ localintegration: all bats -t tests/integration${TESTFLAGS} install: - install -D -m0755 runc /usr/local/sbin/runc + install -D -m0755 runc $(BINDIR)/runc + +install-bash: + install -D -m0644 contrib/completions/bash/runc $(PREFIX)/share/bash-completion/completions/runc install-man: install -d -m 755 $(MAN_INSTALL_PATH) install -m 644 $(MAN_PAGES) $(MAN_INSTALL_PATH) uninstall: - rm -f /usr/local/sbin/runc + rm -f $(BINDIR)/runc + +uninstall-bash: + rm -f $(PREFIX)/share/bash-completion/completions/runc uninstall-man: rm -f $(addprefix $(MAN_INSTALL_PATH),$(MAN_PAGES_BASE)) diff --git a/contrib/completions/bash/runc b/contrib/completions/bash/runc new file mode 100644 index 000000000..4fe6fb7f2 --- /dev/null +++ b/contrib/completions/bash/runc @@ -0,0 +1,700 @@ +#!/bin/bash +# +# bash completion file for runc command +# +# This script provides completion of: +# - commands and their options +# - filepaths +# +# To enable the completions either: +# - place this file in /usr/share/bash-completion/completions +# or +# - copy this file to e.g. ~/.runc-completion.sh and add the line +# below to your .bashrc after bash completion features are loaded +# . ~/.runc-completion.sh +# +# Configuration: +# + + +# Note for developers: +# Please arrange options sorted alphabetically by long name with the short +# options immediately following their corresponding long form. +# This order should be applied to lists, alternatives and code blocks. + +__runc_previous_extglob_setting=$(shopt -p extglob) +shopt -s extglob + +__runc_list_all() { + COMPREPLY=( $( compgen -W "$(runc list -q)" -- $cur) ) +} + +__runc_pos_first_nonflag() { + local argument_flags=$1 + + local counter=$((${subcommand_pos:-${command_pos}} + 1)) + while [ $counter -le $cword ]; do + if [ -n "$argument_flags" ] && eval "case '${words[$counter]}' in $argument_flags) true ;; *) false ;; esac"; then + (( counter++ )) + else + case "${words[$counter]}" in + -*) + ;; + *) + break + ;; + esac + fi + (( counter++ )) + done + + echo $counter +} + +# Transforms a multiline list of strings into a single line string +# with the words separated by "|". +# This is used to prepare arguments to __runc_pos_first_nonflag(). +__runc_to_alternatives() { + local parts=( $1 ) + local IFS='|' + echo "${parts[*]}" +} + +# Transforms a multiline list of options into an extglob pattern +# suitable for use in case statements. +__runc_to_extglob() { + local extglob=$( __runc_to_alternatives "$1" ) + echo "@($extglob)" +} + +# Subcommand processing. +# Locates the first occurrence of any of the subcommands contained in the +# first argument. In case of a match, calls the corresponding completion +# function and returns 0. +# If no match is found, 1 is returned. The calling function can then +# continue processing its completion. +# +# TODO if the preceding command has options that accept arguments and an +# argument is equal ot one of the subcommands, this is falsely detected as +# a match. +__runc_subcommands() { + local subcommands="$1" + + local counter=$(($command_pos + 1)) + while [ $counter -lt $cword ]; do + case "${words[$counter]}" in + $(__runc_to_extglob "$subcommands") ) + subcommand_pos=$counter + local subcommand=${words[$counter]} + local completions_func=_runc_${command}_${subcommand} + declare -F $completions_func >/dev/null && $completions_func + return 0 + ;; + esac + (( counter++ )) + done + return 1 +} + +# List all Signals +__runc_list_signals() { + COMPREPLY=( $( compgen -W "$(for i in $(kill -l | xargs); do echo $i; done | grep SIG)")) +} + +# suppress trailing whitespace +__runc_nospace() { + # compopt is not available in ancient bash versions + type compopt &>/dev/null && compopt -o nospace +} + +# The list of capabilities is defined in types.go, ALL was added manually. +__runc_complete_capabilities() { + COMPREPLY=( $( compgen -W " + ALL + AUDIT_CONTROL + AUDIT_WRITE + AUDIT_READ + BLOCK_SUSPEND + CHOWN + DAC_OVERRIDE + DAC_READ_SEARCH + FOWNER + FSETID + IPC_LOCK + IPC_OWNER + KILL + LEASE + LINUX_IMMUTABLE + MAC_ADMIN + MAC_OVERRIDE + MKNOD + NET_ADMIN + NET_BIND_SERVICE + NET_BROADCAST + NET_RAW + SETFCAP + SETGID + SETPCAP + SETUID + SYS_ADMIN + SYS_BOOT + SYS_CHROOT + SYSLOG + SYS_MODULE + SYS_NICE + SYS_PACCT + SYS_PTRACE + SYS_RAWIO + SYS_RESOURCE + SYS_TIME + SYS_TTY_CONFIG + WAKE_ALARM + " -- "$cur" ) ) +} + + +_runc_exec() { + local boolean_options=" + --help + --no-new-privs + --tty, -t + --detach, -d + " + + local options_with_args=" + --console + --cwd + --env, -e + --user, -u + --process, -p + --pid-file + --process-label + --apparmor + --cap, -c + " + + local all_options="$options_with_args $boolean_options" + + case "$prev" in + --cap|-c) + __runc_complete_capabilities + return + ;; + + --console|--cwd|--process|--apparmor) + case "$cur" in + *:*) + # TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine) + ;; + '') + COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) + __runc_nospace + ;; + /*) + _filedir + __runc_nospace + ;; + esac + return + ;; + --env|-e) + COMPREPLY=( $( compgen -e -- "$cur" ) ) + __runc_nospace + return + ;; + $(__runc_to_extglob "$options_with_args") ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +# global options that may appear after the runc command +_runc_runc() { + local boolean_options=" + $global_boolean_options + --help + --version -v + --debug + " + local options_with_args=" + --log + --log-format + --root + --criu + " + + case "$prev" in + --log|--root|--criu) + case "$cur" in + *:*) + # TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine) + ;; + '') + COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) + __runc_nospace + ;; + *) + _filedir + __runc_nospace + ;; + esac + return + ;; + + --log-format) + COMPREPLY=( $( compgen -W 'text json' -- "$cur" ) ) + return + ;; + + $(__runc_to_extglob "$options_with_args") ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + local counter=$( __runc_pos_first_nonflag $(__runc_to_extglob "$options_with_args") ) + if [ $cword -eq $counter ]; then + COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) ) + fi + ;; + esac +} + +_runc_pause() { + local boolean_options=" + --help + -h + " + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc_delete() { + local boolean_options=" + --help + -h + " + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc_kill() { + local boolean_options=" + --help + -h + " + + case "$prev" in + "kill") + __runc_list_all + return + ;; + *) + __runc_list_signals + return + ;; + esac + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc_events() { + local boolean_options=" + --help + --stats + " + + local options_with_args=" + --interval + " + + case "$prev" in + $(__runc_to_extglob "$options_with_args")) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc_list() { + local boolean_options=" + --help + --quiet + -q + " + + local options_with_args=" + --format + -f + " + + case "$prev" in + --format|-f) + COMPREPLY=( $( compgen -W 'text json' -- "$cur" ) ) + return + ;; + + $(__runc_to_extglob "$options_with_args")) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + local counter=$( __runc_pos_first_nonflag $(__runc_to_extglob "$options_with_args") ) + ;; + esac +} + +_runc_spec() { + local boolean_options=" + --help + " + + local options_with_args=" + --bundle + -b + " + + case "$prev" in + --bundle|-b) + case "$cur" in + '') + COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) + __runc_nospace + ;; + /*) + _filedir + __runc_nospace + ;; + esac + return + ;; + + $(__runc_to_extglob "$options_with_args")) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + local counter=$( __runc_pos_first_nonflag $(__runc_to_extglob "$options_with_args") ) + ;; + esac +} + +_runc_start() { + local boolean_options=" + --help + --detatch + -d + --no-subreaper + --no-pivot + " + + local options_with_args=" + --bundle + -b + --console + --pid-file + " + + case "$prev" in + --bundle|-b|--console|--pid-file) + case "$cur" in + '') + COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) + __runc_nospace + ;; + /*) + _filedir + __runc_nospace + ;; + esac + return + ;; + + $(__runc_to_extglob "$options_with_args")) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc_checkpoint() { + local boolean_options=" + --help + -h + --leave-running + --tcp-established + --ext-unix-sk + --shell-job + --file-locks + " + + local options_with_args=" + --image-path + --work-path + --page-server + --manage-cgroups-mode + " + + case "$prev" in + --page-server) + ;; + + --manage-cgroups-mode) + COMPREPLY=( $( compgen -W "soft full strict" -- "$cur" ) ) + return + ;; + + --image-path|--work-path) + case "$cur" in + *:*) + # TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine) + ;; + '') + COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) + __runc_nospace + ;; + *) + _filedir + __runc_nospace + ;; + esac + return + ;; + + $(__runc_to_extglob "$options_with_args")) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc_help() { + local counter=$(__runc_pos_first_nonflag) + if [ $cword -eq $counter ]; then + COMPREPLY=( $( compgen -W "${commands[*]}" -- "$cur" ) ) + fi +} + +_runc_restore() { + local boolean_options=" + --help + --tcp-established + --ext-unix-sk + --shell-job + --file-locks + --detach + -d + --no-subreaper + --no-pivot + " + + local options_with_args=" + -b + --bundle + --image-path + --work-path + --manage-cgroups-mode + --pid-file + " + + local all_options="$options_with_args $boolean_options" + + case "$prev" in + --manage-cgroups-mode) + COMPREPLY=( $( compgen -W "soft full strict" -- "$cur" ) ) + return + ;; + + --pid-file|--image-path|--work-path|--bundle|-b) + case "$cur" in + *:*) + # TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine) + ;; + '') + COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) + __runc_nospace + ;; + /*) + _filedir + __runc_nospace + ;; + esac + return + ;; + + $(__runc_to_extglob "$options_with_args") ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc_resume() { + local boolean_options=" + --help + -h + " + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc_state() { + local boolean_options=" + --help + -h + " + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + *) + __runc_list_all + ;; + esac +} + +_runc() { + local previous_extglob_setting=$(shopt -p extglob) + shopt -s extglob + + local commands=( + checkpoint + delete + events + exec + init + kill + list + pause + restore + resume + spec + start + state + help + h + ) + + # These options are valid as global options for all client commands + # and valid as command options for `runc daemon` + local global_boolean_options=" + --help -h + --version -v + " + + COMPREPLY=() + local cur prev words cword + _get_comp_words_by_ref -n : cur prev words cword + + local command='runc' command_pos=0 subcommand_pos + local counter=1 + while [ $counter -lt $cword ]; do + case "${words[$counter]}" in + -*) + ;; + =) + (( counter++ )) + ;; + *) + command="${words[$counter]}" + command_pos=$counter + break + ;; + esac + (( counter++ )) + done + + local completions_func=_runc_${command} + declare -F $completions_func >/dev/null && $completions_func + + eval "$previous_extglob_setting" + return 0 +} + +eval "$__runc_previous_extglob_setting" +unset __runc_previous_extglob_setting + +complete -F _runc runc