From 2da4cc46343ae05c0af9088b6e85b8b449a2bf80 Mon Sep 17 00:00:00 2001 From: Toni Schmidbauer Date: Fri, 8 Mar 2019 07:42:29 +0100 Subject: [PATCH] Add a run command This makes 'toolbox enter' similar to 'toolbox run $SHELL'. The 'run' command is meant to spawn arbitrary binaries present inside the toolbox container. Therefore it doesn't make sense for it to fall back to /bin/bash, like it does for 'enter' if $SHELL is absent. It's expected that users might use 'run' to create ad-hoc *.desktop files. That's why it neither offers to create nor falls back to an existing container like 'enter' does, because such interactions can't happen when used in a *.desktop file. It's also a more advanced command that new users are less likely to be interested in. Hence, this shouldn't affect usability. Some changes by Debarshi Ray. https://github.com/debarshiray/toolbox/pull/76 --- completion/bash/toolbox | 5 +-- doc/meson.build | 1 + doc/toolbox-run.1.md | 60 ++++++++++++++++++++++++++++++++ toolbox | 77 ++++++++++++++++++++++++++++++++++++----- 4 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 doc/toolbox-run.1.md diff --git a/completion/bash/toolbox b/completion/bash/toolbox index c2936f7..9fb47ff 100644 --- a/completion/bash/toolbox +++ b/completion/bash/toolbox @@ -13,7 +13,7 @@ __toolbox() { local MIN_VERSION=29 local RAWHIDE_VERSION=31 - local verbose_commands="create enter list" + local verbose_commands="create enter list run" local commands="$verbose_commands rm rmi" declare -A options @@ -21,7 +21,8 @@ __toolbox() { [enter]="--container --release" \ [list]="--containers --images" \ [rm]="--all --force" \ - [rmi]="--all --force") + [rmi]="--all --force" \ + [run]="--container --release") _init_completion -s || return diff --git a/doc/meson.build b/doc/meson.build index 92e6596..e5f0a96 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -11,6 +11,7 @@ manuals = [ 'toolbox-list.1', 'toolbox-rm.1', 'toolbox-rmi.1', + 'toolbox-run.1', ] foreach manual: manuals diff --git a/doc/toolbox-run.1.md b/doc/toolbox-run.1.md new file mode 100644 index 0000000..8eda3d9 --- /dev/null +++ b/doc/toolbox-run.1.md @@ -0,0 +1,60 @@ +% toolbox-run(1) + +## NAME +toolbox\-run - Run a command in an existing toolbox container + +## SYNOPSIS +**toolbox run** [*--container NAME* | *-c NAME*] + [*--release RELEASE* | *-r RELEASE*] [*COMMAND*] + +## DESCRIPTION + +Runs a command inside an existing toolbox container. The container should have +been created using the `toolbox create` command. + +A toolbox container is an OCI container. Therefore, `toolbox run` is analogous +to a `podman start` followed by a `podman exec`. + +On Fedora the toolbox containers are tagged with the version of the OS that +corresponds to the content inside them. Their names are prefixed with the name +of the base image and suffixed with the current user name. + +## OPTIONS ## + +The following options are understood: + +**--container** NAME, **-c** NAME + +Run command inside a toolbox container with the given NAME. This is +useful when there are multiple toolbox containers created from the +same base image, or entirely customized containers created from +custom-built base images. + +**--release** RELEASE, **-r** RELEASE + +Run command inside a toolbox container for a different operating +system RELEASE than the host. + +## EXAMPLES + +### Run ls inside a toolbox container using the default image matching the host OS + +``` +$ toolbox run ls -la +``` + +### Run emacs inside a toolbox container using the default image for Fedora 30 + +``` +$ toolbox run --release f30 emacs +``` + +### Run uptime inside a custom toolbox container using a custom image + +``` +$ toolbox run --container foo uptime +``` + +## SEE ALSO + +`buildah(1)`, `podman(1)`, `podman-exec(1)`, `podman-start(1)` diff --git a/toolbox b/toolbox index 8700df0..4f3463f 100755 --- a/toolbox +++ b/toolbox @@ -988,10 +988,20 @@ create() enter() +{ + run true false "$SHELL" -l +} + + +run() ( + fallback_to_bash="$1" + pedantic="$2" + program="$3" + shift 3 + create_toolbox_container=false prompt_for_create=true - shell_to_exec=/bin/bash echo "$base_toolbox_command: checking if container $toolbox_container exists" >&3 @@ -1008,6 +1018,11 @@ enter() # shellcheck disable=SC2030 toolbox_container="$toolbox_container_old" else + if $pedantic; then + enter_print_container_not_found "$toolbox_container" + exit 1 + fi + if ! containers=$(list_container_names); then enter_print_container_not_found "$toolbox_container" exit 1 @@ -1088,25 +1103,34 @@ enter() set_environment=$(create_environment_options) - echo "$base_toolbox_command: looking for $SHELL in container $toolbox_container" >&3 + echo "$base_toolbox_command: looking for $program in container $toolbox_container" >&3 - if $prefix_sudo podman exec "$toolbox_container" test -f "$SHELL" 2>&3; then - shell_to_exec="$SHELL" - else - echo "$base_toolbox_command: $SHELL not found in $toolbox_container; using $shell_to_exec instead" >&3 + # shellcheck disable=SC2016 + if ! $prefix_sudo podman exec "$toolbox_container" sh -c 'command -v "$1"' sh "$program" >/dev/null 2>&3; then + if $fallback_to_bash; then + echo "$base_toolbox_command: $program not found in $toolbox_container; using /bin/bash instead" >&3 + program=/bin/bash + else + echo "$base_toolbox_command: command '$program' not found in container $toolbox_container" >&2 + exit 127 + fi fi - echo "$base_toolbox_command: trying to exec $shell_to_exec in container $toolbox_container" >&3 + echo "$base_toolbox_command: running in container $toolbox_container:" >&3 + echo "$base_toolbox_command: $program" >&3 + for i in "$@"; do + echo "$base_toolbox_command: $i" >&3 + done # shellcheck disable=SC2016 # for the command passed to capsh # shellcheck disable=SC2086 $prefix_sudo podman exec \ - $set_environment \ --interactive \ --tty \ + $set_environment \ "$toolbox_container" \ - capsh --caps="" -- -c 'cd "$1"; shift; exec "$@"' /bin/sh "$PWD" "$shell_to_exec" -l 2>&3 + capsh --caps="" -- -c 'cd "$1"; shift; exec "$@"' /bin/sh "$PWD" "$program" "$@" 2>&3 ) @@ -1524,6 +1548,10 @@ usage() echo " or: toolbox [-y | --assumeyes]" echo " rmi [-a | --all]" echo " [-f | --force] [ ...]" + echo " or: toolbox [-v | --verbose]" + echo " [-y | --assumeyes]" + echo " run [-c | --container ]" + echo " [-r | --release ] " echo " or: toolbox --help" } @@ -1798,6 +1826,37 @@ case $op in fi exit ;; + run ) + if is_integer "$podman_pid"; then + # shellcheck disable=SC2119 + forward_to_host + else + while has_prefix "$1" -; do + case $1 in + -c | --container ) + shift + exit_if_missing_argument --container "$1" + toolbox_container=$1 + ;; + -r | --release ) + shift + exit_if_missing_argument --release "$1" + arg=$(echo "$1" | sed "s/^F\|^f//" 2>&3) + exit_if_non_positive_argument --release "$arg" + release=$arg + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + if ! update_container_and_image_names; then + exit 1 + fi + run false true "$@" + fi + exit + ;; * ) echo "$base_toolbox_command: unrecognized command '$op'" >&2 echo "Try '$base_toolbox_command --help' for more information." >&2