a0602e4485
The POSIX shell Toolbox has been replaced by the Go implementation quite a long time ago. People on several ocassions created PRs that still update it, or end up using it by mistake when building from source. It was not clear that the POSIX shell implementation has been deprecated and is no longer maintained. https://github.com/containers/toolbox/pull/698
2638 lines
82 KiB
Bash
Executable file
2638 lines
82 KiB
Bash
Executable file
#!/bin/sh
|
||
#
|
||
# Copyright © 2018 – 2021 Red Hat, Inc.
|
||
#
|
||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
# you may not use this file except in compliance with the License.
|
||
# You may obtain a copy of the License at
|
||
#
|
||
# http://www.apache.org/licenses/LICENSE-2.0
|
||
#
|
||
# Unless required by applicable law or agreed to in writing, software
|
||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
# See the License for the specific language governing permissions and
|
||
# limitations under the License.
|
||
#
|
||
|
||
# THIS IMPLEMENTATION OF TOOLBOX IS NO LONGER MAINTAINED.
|
||
# Please, use the Go implementation instead.
|
||
|
||
exec 3>/dev/null
|
||
|
||
arguments=""
|
||
assume_yes=false
|
||
base_toolbox_command=$(basename "$0" 2>&3)
|
||
base_toolbox_image=""
|
||
cgroups_version=""
|
||
|
||
# Based on the nameRegex value in:
|
||
# https://github.com/containers/libpod/blob/master/libpod/options.go
|
||
container_name_regexp="[a-zA-Z0-9][a-zA-Z0-9_.-]*"
|
||
|
||
environment=$(set)
|
||
environment_variables="COLORTERM \
|
||
COLUMNS \
|
||
DBUS_SESSION_BUS_ADDRESS \
|
||
DBUS_SYSTEM_BUS_ADDRESS \
|
||
DESKTOP_SESSION \
|
||
DISPLAY \
|
||
LANG \
|
||
LINES \
|
||
SHELL \
|
||
SSH_AUTH_SOCK \
|
||
TERM \
|
||
TOOLBOX_PATH \
|
||
USER \
|
||
VTE_VERSION \
|
||
WAYLAND_DISPLAY \
|
||
XAUTHORITY \
|
||
XDG_CURRENT_DESKTOP \
|
||
XDG_DATA_DIRS \
|
||
XDG_MENU_PREFIX \
|
||
XDG_RUNTIME_DIR \
|
||
XDG_SEAT \
|
||
XDG_SESSION_DESKTOP \
|
||
XDG_SESSION_ID \
|
||
XDG_SESSION_TYPE \
|
||
XDG_VTNR"
|
||
fgc=""
|
||
|
||
podman_command="podman"
|
||
registry="registry.fedoraproject.org"
|
||
registry_candidate="candidate-registry.fedoraproject.org"
|
||
release=""
|
||
release_default=""
|
||
spinner_animation="[>----] [=>---] [==>--] [===>-] [====>] [----<] [---<=] [--<==] [-<===] [<====]"
|
||
spinner_template="toolbox-spinner-XXXXXXXXXX"
|
||
tab="$(printf '\t')"
|
||
toolbox_command_path=""
|
||
toolbox_container=""
|
||
toolbox_container_default=""
|
||
toolbox_container_old_v1=""
|
||
toolbox_container_old_v2=""
|
||
toolbox_container_prefix_default=""
|
||
toolbox_image=""
|
||
toolbox_runtime_directory="$XDG_RUNTIME_DIR"/toolbox
|
||
user_id_real=$(id -ru 2>&3)
|
||
verbose=false
|
||
|
||
|
||
LGC='\033[1;32m' # Light Green Color
|
||
NC='\033[0m' # No Color
|
||
|
||
|
||
has_prefix()
|
||
(
|
||
str="$1"
|
||
prefix="$2"
|
||
|
||
ret_val=1
|
||
|
||
case "$str" in
|
||
"$prefix"* )
|
||
ret_val=0
|
||
;;
|
||
* )
|
||
ret_val=1
|
||
;;
|
||
esac
|
||
|
||
return "$ret_val"
|
||
)
|
||
|
||
|
||
has_substring()
|
||
(
|
||
haystack="$1"
|
||
needle="$2"
|
||
|
||
ret_val=1
|
||
|
||
case "$haystack" in
|
||
*"$needle"* )
|
||
ret_val=0
|
||
;;
|
||
* )
|
||
ret_val=1
|
||
;;
|
||
esac
|
||
|
||
return "$ret_val"
|
||
)
|
||
|
||
|
||
is_integer()
|
||
{
|
||
[ "$1" != "" ] && [ "$1" -eq "$1" ] 2>&3
|
||
return "$?"
|
||
}
|
||
|
||
|
||
save_positional_parameters()
|
||
{
|
||
for i; do
|
||
printf "%s\\n" "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" 2>&3
|
||
done
|
||
echo " "
|
||
}
|
||
|
||
|
||
spinner_start()
|
||
(
|
||
directory="$1"
|
||
message="$2"
|
||
|
||
if $verbose; then
|
||
rm --force --recursive "$directory" 2>&3
|
||
return 0
|
||
fi
|
||
|
||
if ! touch "$directory/spinner-start" 2>&3; then
|
||
echo "$base_toolbox_command: unable to start spinner: spinner start file couldn't be created" >&2
|
||
return 1
|
||
fi
|
||
|
||
printf "%s" "$message"
|
||
tput civis 2>&3
|
||
|
||
exec 4>"$directory/spinner-start"
|
||
if ! flock 4 2>&3; then
|
||
echo "$base_toolbox_command: unable to start spinner: spinner lock couldn't be acquired" >&2
|
||
return 1
|
||
fi
|
||
|
||
(
|
||
while [ -f "$directory/spinner-start" ]; do
|
||
echo "$spinner_animation" | sed "s/ /\n/g" 2>&3 | while read -r frame; do
|
||
if ! [ -f "$directory/spinner-start" ] 2>&3; then
|
||
break
|
||
fi
|
||
|
||
printf "%s" "$frame"
|
||
|
||
frame_len=${#frame}
|
||
i=0
|
||
while [ "$i" -lt "$frame_len" ]; do
|
||
printf "\b"
|
||
i=$((i + 1))
|
||
done
|
||
|
||
sleep 1
|
||
done
|
||
done
|
||
|
||
printf "\033[2K" # delete entire line regardless of cursor position
|
||
printf "\r"
|
||
tput cnorm 2>&3
|
||
) &
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
spinner_stop()
|
||
(
|
||
$verbose && return
|
||
directory="$1"
|
||
|
||
exec 4>"$directory/spinner-start"
|
||
|
||
if ! rm "$directory/spinner-start" 2>&3; then
|
||
echo "$base_toolbox_command: unable to stop spinner: spinner start file couldn't be removed" >&2
|
||
return
|
||
fi
|
||
|
||
if ! flock 4 2>&3; then
|
||
echo "$base_toolbox_command: unable to stop spinner: spinner lock couldn't be acquired" >&2
|
||
return
|
||
fi
|
||
|
||
rm --force --recursive "$directory" 2>&3
|
||
)
|
||
|
||
|
||
ask_for_confirmation()
|
||
(
|
||
default_response="$1"
|
||
prompt="$2"
|
||
ret_val=0
|
||
|
||
while :; do
|
||
printf "%s " "$prompt"
|
||
read -r user_response
|
||
|
||
if [ "$user_response" = "" ] 2>&3; then
|
||
user_response="$default_response"
|
||
else
|
||
user_response=$(echo "$user_response" | tr "[:upper:]" "[:lower:]" 2>&3)
|
||
fi
|
||
|
||
if [ "$user_response" = "no" ] 2>&3 || [ "$user_response" = "n" ] 2>&3; then
|
||
ret_val=1
|
||
break
|
||
elif [ "$user_response" = "yes" ] 2>&3 || [ "$user_response" = "y" ] 2>&3; then
|
||
ret_val=0
|
||
break
|
||
fi
|
||
done
|
||
|
||
return "$ret_val"
|
||
)
|
||
|
||
|
||
container_name_is_valid()
|
||
(
|
||
name="$1"
|
||
|
||
echo "$name" | grep "^$container_name_regexp$" >/dev/null 2>&3
|
||
return "$?"
|
||
)
|
||
|
||
|
||
container_start()
|
||
(
|
||
container="$1"
|
||
|
||
error_message=$( ($podman_command start "$container" >/dev/null) 2>&1)
|
||
ret_val="$?"
|
||
[ "$error_message" != "" ] 2>&3 && echo "$error_message" >&3
|
||
|
||
if [ "$ret_val" -ne 0 ] 2>&3; then
|
||
if echo "$error_message" | grep "use system migrate to mitigate" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: checking if 'podman system migrate' supports --new-runtime" >&3
|
||
|
||
if ! ($podman_command system migrate --help 2>&3 | grep "new-runtime" >/dev/null 2>&3); then
|
||
echo "$base_toolbox_command: container $container doesn't support cgroups v$cgroups_version" >&2
|
||
echo "Update Podman to version 1.6.2 or newer." >&2
|
||
return 1
|
||
else
|
||
echo "$base_toolbox_command: 'podman system migrate' supports --new-runtime" >&3
|
||
|
||
oci_runtime_required="runc"
|
||
[ "$cgroups_version" -eq 2 ] 2>&3 && oci_runtime_required="crun"
|
||
|
||
echo "$base_toolbox_command: migrating containers to OCI runtime $oci_runtime_required" >&3
|
||
|
||
if ! $podman_command system migrate --new-runtime "$oci_runtime_required" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to migrate containers to OCI runtime $oci_runtime_required" >&2
|
||
echo "Factory reset with: toolbox reset" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! $podman_command start "$container" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: container $container doesn't support cgroups v$cgroups_version" >&2
|
||
echo "Factory reset with: toolbox reset" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
else
|
||
echo "$base_toolbox_command: failed to start container $container" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
copy_etc_profile_d_toolbox_to_container()
|
||
(
|
||
container="$1"
|
||
|
||
profile_d_lock="$toolbox_runtime_directory"/profile.d-toolbox.lock
|
||
|
||
# shellcheck disable=SC2174
|
||
if ! mkdir --mode 700 --parents "$toolbox_runtime_directory" 2>&3; then
|
||
echo "$base_toolbox_command: unable to copy $toolbox_runtime_directory/toolbox.sh: runtime directory not created" >&2
|
||
return 1
|
||
fi
|
||
|
||
exec 5>"$profile_d_lock"
|
||
if ! flock 5 2>&3; then
|
||
echo "$base_toolbox_command: unable to copy $toolbox_runtime_directory/toolbox.sh: copy lock not acquired" >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! [ -f "$toolbox_runtime_directory"/toolbox.sh ] 2>&3; then
|
||
echo "$base_toolbox_command: $toolbox_runtime_directory/toolbox.sh not found" >&2
|
||
return 0
|
||
fi
|
||
|
||
echo "$base_toolbox_command: copying $toolbox_runtime_directory/toolbox.sh to container $container" >&3
|
||
|
||
if ! $podman_command exec \
|
||
--user root:root \
|
||
"$container" \
|
||
sh -c "cp $toolbox_runtime_directory/toolbox.sh /etc/profile.d" sh 2>&3; then
|
||
echo "$base_toolbox_command: unable to copy $toolbox_runtime_directory/toolbox.sh to container $container" >&2
|
||
return 1
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
copy_etc_profile_d_toolbox_to_runtime_directory()
|
||
(
|
||
profile_d_lock="$toolbox_runtime_directory"/profile.d-toolbox.lock
|
||
|
||
if ! [ -f /etc/profile.d/toolbox.sh ] 2>&3; then
|
||
echo "$base_toolbox_command: /etc/profile.d/toolbox.sh not found" >&2
|
||
return 0
|
||
fi
|
||
|
||
# shellcheck disable=SC2174
|
||
if ! mkdir --mode 700 --parents "$toolbox_runtime_directory" 2>&3; then
|
||
echo "$base_toolbox_command: unable to copy /etc/profile.d/toolbox.sh: runtime directory not created" >&2
|
||
return 1
|
||
fi
|
||
|
||
exec 5>"$profile_d_lock"
|
||
if ! flock 5 2>&3; then
|
||
echo "$base_toolbox_command: unable to copy /etc/profile.d/toolbox.sh: copy lock not acquired" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: copying /etc/profile.d/toolbox.sh to $toolbox_runtime_directory" >&3
|
||
|
||
if ! cp /etc/profile.d/toolbox.sh "$toolbox_runtime_directory" 2>&3; then
|
||
echo "$base_toolbox_command: unable to copy /etc/profile.d/toolbox.sh to $toolbox_runtime_directory" >&2
|
||
return 1
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
create_enter_command()
|
||
(
|
||
container="$1"
|
||
|
||
if [ "$container" = "$toolbox_container_default" ] 2>&3; then
|
||
echo "$base_toolbox_command enter"
|
||
elif [ "$container" = "$toolbox_container_prefix_default-$release" ] 2>&3; then
|
||
echo "$base_toolbox_command enter --release $release"
|
||
else
|
||
echo "$base_toolbox_command enter --container $container"
|
||
fi
|
||
)
|
||
|
||
|
||
create_environment_options()
|
||
(
|
||
columns=""
|
||
lines=""
|
||
|
||
if terminal_size=$(stty size 2>&3); then
|
||
columns=$(echo "$terminal_size" | cut --delimiter " " --fields 2 2>&3)
|
||
if ! is_integer "$columns"; then
|
||
echo "$base_toolbox_command: failed to parse the number of columns from the terminal size" >&3
|
||
columns=""
|
||
fi
|
||
|
||
lines=$(echo "$terminal_size" | cut --delimiter " " --fields 1 2>&3)
|
||
if ! is_integer "$lines"; then
|
||
echo "$base_toolbox_command: failed to parse the number of lines from the terminal size" >&3
|
||
lines=""
|
||
fi
|
||
else
|
||
echo "$base_toolbox_command: failed to read terminal size" >&3
|
||
fi
|
||
|
||
echo "$environment_variables" \
|
||
| sed "s/ \+/\n/g" 2>&3 \
|
||
| {
|
||
environment_options=""
|
||
echo "$base_toolbox_command: creating list of environment variables to forward" >&3
|
||
value=""
|
||
while read -r variable; do
|
||
if echo "$environment" | grep "^$variable" >/dev/null 2>&3; then
|
||
eval value="$""$variable"
|
||
echo "$base_toolbox_command: $variable=$value" >&3
|
||
environment_options="$environment_options --env=$variable=$value"
|
||
else
|
||
echo "$base_toolbox_command: $variable is unset" >&3
|
||
fi
|
||
done
|
||
|
||
if ! (echo "$environment_options" | grep COLUMNS >/dev/null 2>&3) && [ "$columns" != "" ] 2>&3; then
|
||
environment_options="$environment_options --env=COLUMNS=$columns"
|
||
fi
|
||
|
||
if ! (echo "$environment_options" | grep LINES >/dev/null 2>&3) && [ "$lines" != "" ] 2>&3; then
|
||
environment_options="$environment_options --env=LINES=$lines"
|
||
fi
|
||
|
||
environment_options=${environment_options#" "}
|
||
echo "$base_toolbox_command: created options for environment variables to forward" >&3
|
||
echo "$environment_options" >&3
|
||
echo "$environment_options"
|
||
}
|
||
)
|
||
|
||
|
||
create_toolbox_container_name()
|
||
(
|
||
image="$1"
|
||
|
||
basename=$(image_reference_get_basename "$image")
|
||
if [ "$basename" = "" ] 2>&3; then
|
||
return 100
|
||
fi
|
||
|
||
tag=$(image_reference_get_tag "$image")
|
||
if [ "$tag" = "" ] 2>&3; then
|
||
return 101
|
||
fi
|
||
|
||
echo "$basename-$tag"
|
||
return 0
|
||
)
|
||
|
||
|
||
create_toolbox_image_name()
|
||
(
|
||
# Based on the ResolveName function implemented in:
|
||
# https://github.com/containers/buildah/blob/master/util/util.go
|
||
|
||
if image_reference_can_be_id "$base_toolbox_image"; then
|
||
if base_toolbox_image_id=$($podman_command inspect \
|
||
--format "{{.Id}}" \
|
||
--type image \
|
||
"$base_toolbox_image" 2>&3); then
|
||
if has_prefix "$base_toolbox_image_id" "$base_toolbox_image"; then
|
||
echo "$base_toolbox_image-$USER:latest"
|
||
return 0
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
basename=$(image_reference_get_basename "$base_toolbox_image")
|
||
if [ "$basename" = "" ] 2>&3; then
|
||
return 100
|
||
fi
|
||
|
||
tag=$(image_reference_get_tag "$base_toolbox_image")
|
||
if [ "$tag" = "" ] 2>&3; then
|
||
echo "$basename-$USER:latest"
|
||
else
|
||
echo "$basename-$USER:$tag"
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
enter_print_container_not_found()
|
||
(
|
||
container="$1"
|
||
|
||
echo "$base_toolbox_command: container $container not found" >&2
|
||
echo "Use the 'create' command to create a toolbox." >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
)
|
||
|
||
|
||
get_cgroups_version()
|
||
(
|
||
version=1
|
||
|
||
if ! mounts=$(mount 2>&3); then
|
||
echo "$base_toolbox_command: failed to detect cgroups version: couldn't list mount points" >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! (echo "$mounts" | grep "^cgroup " >/dev/null 2>&3) && (echo "$mounts" | grep "^cgroup2 " >/dev/null 2>&3); then
|
||
version=2
|
||
fi
|
||
|
||
echo "$version"
|
||
return 0
|
||
)
|
||
|
||
|
||
get_group_for_sudo()
|
||
(
|
||
group=""
|
||
if getent group sudo >/dev/null 2>&3; then
|
||
group="sudo"
|
||
elif getent group wheel >/dev/null 2>&3; then
|
||
group="wheel"
|
||
else
|
||
return 1
|
||
fi
|
||
|
||
echo "$group"
|
||
return 0
|
||
)
|
||
|
||
|
||
get_host_id()
|
||
(
|
||
# shellcheck disable=SC1091
|
||
. /usr/lib/os-release
|
||
echo "$ID"
|
||
)
|
||
|
||
|
||
get_host_variant_id()
|
||
(
|
||
# shellcheck disable=SC1091
|
||
. /usr/lib/os-release
|
||
echo "$VARIANT_ID"
|
||
)
|
||
|
||
|
||
get_host_version_id()
|
||
(
|
||
# shellcheck disable=SC1091
|
||
. /usr/lib/os-release
|
||
echo "$VERSION_ID"
|
||
)
|
||
|
||
|
||
image_reference_can_be_id()
|
||
(
|
||
image="$1"
|
||
|
||
echo "$image" | grep "^[a-f0-9]\{6,64\}$" >/dev/null 2>&3
|
||
return "$?"
|
||
)
|
||
|
||
|
||
image_reference_get_basename()
|
||
(
|
||
image="$1"
|
||
|
||
domain=$(image_reference_get_domain "$image")
|
||
remainder=${image#$domain}
|
||
path=${remainder%:*}
|
||
basename=${path##*/}
|
||
echo "$basename"
|
||
)
|
||
|
||
|
||
image_reference_get_domain()
|
||
(
|
||
image="$1"
|
||
|
||
image_reference_has_domain "$image" && domain=${image%%/*}
|
||
echo "$domain"
|
||
)
|
||
|
||
|
||
image_reference_get_tag()
|
||
(
|
||
image="$1"
|
||
|
||
domain=$(image_reference_get_domain "$image")
|
||
remainder=${image#$domain}
|
||
|
||
tag=""
|
||
if (echo "$remainder" | grep ":" >/dev/null 2>&3); then
|
||
tag=${remainder#*:}
|
||
fi
|
||
|
||
echo "$tag"
|
||
)
|
||
|
||
|
||
image_reference_has_domain()
|
||
(
|
||
# Based on the splitDockerDomain function implemented in:
|
||
# https://github.com/docker/distribution/blob/master/reference/normalize.go
|
||
|
||
image="$1"
|
||
|
||
if ! (echo "$image" | grep "/" >/dev/null 2>&3); then
|
||
return 1
|
||
fi
|
||
|
||
prefix=${image%%/*}
|
||
if ! (echo "$prefix" | grep "[.:]" >/dev/null 2>&3) && [ "$prefix" != "localhost" ] 2>&3; then
|
||
return 1
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
images_get_details()
|
||
(
|
||
images="$1"
|
||
|
||
if ! echo "$images" | while read -r image; do
|
||
[ "$image" = "" ] 2>&3 && continue
|
||
|
||
if ! $podman_command images \
|
||
--format "{{.ID}} {{.Repository}}:{{.Tag}} {{.Created}}" \
|
||
--noheading \
|
||
"$image" 2>&3; then
|
||
echo "$base_toolbox_command: failed to get details for image $image" >&2
|
||
return 1
|
||
fi
|
||
echo
|
||
done; then
|
||
return 1
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
is_etc_profile_d_toolbox_a_bind_mount()
|
||
{
|
||
container="$1"
|
||
|
||
$podman_command inspect --format "[{{range .Mounts}}{{.Dst}} {{end}}]" --type container "$container" 2>&3 \
|
||
| grep /etc/profile.d/toolbox.sh >/dev/null 2>/dev/null 2>&3
|
||
|
||
return "$?"
|
||
}
|
||
|
||
|
||
list_container_names()
|
||
(
|
||
if ! containers_old=$($podman_command ps \
|
||
--all \
|
||
--filter "label=com.redhat.component=fedora-toolbox" \
|
||
--format "{{.Names}}" 2>&3); then
|
||
echo "$base_toolbox_command: failed to list containers with com.redhat.component=fedora-toolbox" >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! containers=$($podman_command ps \
|
||
--all \
|
||
--filter "label=com.github.debarshiray.toolbox=true" \
|
||
--format "{{.Names}}" 2>&3); then
|
||
echo "$base_toolbox_command: failed to list containers with com.github.debarshiray.toolbox=true" >&2
|
||
return 1
|
||
fi
|
||
|
||
printf "%s\n%s\n" "$containers_old" "$containers" | sort 2>&3 | uniq 2>&3
|
||
return 0
|
||
)
|
||
|
||
|
||
mount_bind()
|
||
(
|
||
source="$1"
|
||
target="$2"
|
||
mount_flags="$3"
|
||
|
||
mount_o=""
|
||
|
||
! [ -d "$source" ] 2>&3 && ! [ -f "$source" ] 2>&3 && return 0
|
||
|
||
if [ -d "$source" ] 2>&3; then
|
||
echo "$base_toolbox_command: creating $target" >&3
|
||
|
||
if ! mkdir --parents "$target" 2>&3; then
|
||
echo "$base_toolbox_command: failed to create $target" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
echo "$base_toolbox_command: binding $target to $source" >&3
|
||
|
||
[ "$mount_flags" = "" ] 2>&3 || mount_o="-o $mount_flags"
|
||
|
||
# shellcheck disable=SC2086
|
||
if ! mount --rbind $mount_o "$source" "$target" 2>&3; then
|
||
echo "$base_toolbox_command: failed to bind $target to $source" >&2
|
||
return 1
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
pull_base_toolbox_image()
|
||
(
|
||
domain=""
|
||
has_domain=false
|
||
prompt_for_download=true
|
||
pull_image=false
|
||
|
||
if image_reference_can_be_id "$base_toolbox_image"; then
|
||
echo "$base_toolbox_command: looking for image $base_toolbox_image" >&3
|
||
|
||
if $podman_command image exists "$base_toolbox_image" >/dev/null 2>&3; then
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
image_reference_has_domain "$base_toolbox_image" && has_domain=true
|
||
|
||
if ! $has_domain; then
|
||
echo "$base_toolbox_command: looking for image localhost/$base_toolbox_image" >&3
|
||
|
||
if $podman_command image exists "localhost/$base_toolbox_image" >/dev/null 2>&3; then
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
if $has_domain; then
|
||
base_toolbox_image_full="$base_toolbox_image"
|
||
else
|
||
base_toolbox_image_full="$registry/$fgc/$base_toolbox_image"
|
||
fi
|
||
|
||
echo "$base_toolbox_command: looking for image $base_toolbox_image_full" >&3
|
||
|
||
if $podman_command image exists "$base_toolbox_image_full" >/dev/null 2>&3; then
|
||
return 0
|
||
fi
|
||
|
||
domain=$(image_reference_get_domain "$base_toolbox_image_full")
|
||
if $assume_yes || [ "$domain" = "localhost" ] 2>&3; then
|
||
prompt_for_download=false
|
||
pull_image=true
|
||
fi
|
||
|
||
if $prompt_for_download; then
|
||
echo "Image required to create toolbox container."
|
||
|
||
prompt=$(printf "Download %s (500MB)? [y/N]:" "$base_toolbox_image_full")
|
||
if ask_for_confirmation "n" "$prompt"; then
|
||
pull_image=true
|
||
else
|
||
pull_image=false
|
||
fi
|
||
fi
|
||
|
||
if ! $pull_image; then
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: pulling image $base_toolbox_image_full" >&3
|
||
|
||
if spinner_directory=$(mktemp --directory --tmpdir $spinner_template 2>&3); then
|
||
spinner_message="Pulling $base_toolbox_image_full: "
|
||
if ! spinner_start "$spinner_directory" "$spinner_message"; then
|
||
spinner_directory=""
|
||
fi
|
||
else
|
||
echo "$base_toolbox_command: unable to start spinner: spinner directory not created" >&2
|
||
spinner_directory=""
|
||
fi
|
||
|
||
$podman_command pull $base_toolbox_image_full >/dev/null 2>&3
|
||
ret_val=$?
|
||
|
||
if [ "$spinner_directory" != "" ]; then
|
||
spinner_stop "$spinner_directory"
|
||
fi
|
||
|
||
if [ "$ret_val" -ne 0 ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to pull base image $base_toolbox_image" >&2
|
||
fi
|
||
|
||
return $ret_val
|
||
)
|
||
|
||
|
||
unshare_userns_rm()
|
||
(
|
||
path="$1"
|
||
|
||
if ! unshare_directory=$(mktemp --directory --tmpdir "toolbox-unshare-userns-rm-XXXXXXXXXX" 2>&3); then
|
||
echo "$base_toolbox_command: failed to enter user namespace: directory couldn't be created" >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! touch "$unshare_directory/map" 2>&3; then
|
||
echo "$base_toolbox_command: failed to enter user namespace: file couldn't be created" >&2
|
||
return 1
|
||
fi
|
||
|
||
exec 4>"$unshare_directory/map"
|
||
if ! flock 4 2>&3; then
|
||
echo "$base_toolbox_command: failed to enter user namespace: lock couldn't be acquired" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: parsing /etc/subgid" >&3
|
||
|
||
if ! subgid_entry=$(grep "^$USER:" /etc/subgid 2>&3); then
|
||
echo "$base_toolbox_command: failed to enter user namespace: no entry in /etc/subgid" >&2
|
||
return 1
|
||
fi
|
||
|
||
userns_gid_start=$(echo "$subgid_entry" | cut --delimiter ":" --fields 2 2>&3)
|
||
if ! is_integer "$userns_gid_start"; then
|
||
echo "$base_toolbox_command: failed to enter user namespace: cannot parse the first sub-GID" >&2
|
||
return 1
|
||
fi
|
||
|
||
userns_gid_len=$(echo "$subgid_entry" | cut --delimiter ":" --fields 3 2>&3)
|
||
if ! is_integer "$userns_gid_len"; then
|
||
echo "$base_toolbox_command: failed to enter user namespace: cannot parse the sub-GID count" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: parsing /etc/subuid" >&3
|
||
|
||
if ! subuid_entry=$(grep "^$USER:" /etc/subuid 2>&3); then
|
||
echo "$base_toolbox_command: failed to enter user namespace: no entry in /etc/subuid" >&2
|
||
return 1
|
||
fi
|
||
|
||
userns_uid_start=$(echo "$subuid_entry" | cut --delimiter ":" --fields 2 2>&3)
|
||
if ! is_integer "$userns_uid_start"; then
|
||
echo "$base_toolbox_command: failed to enter user namespace: cannot parse the first sub-UID" >&2
|
||
return 1
|
||
fi
|
||
|
||
userns_uid_len=$(echo "$subuid_entry" | cut --delimiter ":" --fields 3 2>&3)
|
||
if ! is_integer "$userns_uid_len"; then
|
||
echo "$base_toolbox_command: failed to enter user namespace: cannot parse the sub-UID count" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: unsharing user namespace" >&3
|
||
|
||
unshare --user sh -c "flock $unshare_directory/map rm --force --recursive $path" 2>&3 &
|
||
unshare_pid="$!"
|
||
|
||
echo "$base_toolbox_command: setting GID and UID map of user namespace" >&3
|
||
|
||
if ! newgidmap "$unshare_pid" 0 "$user_id_real" 1 1 "$userns_gid_start" "$userns_gid_len" 2>&3; then
|
||
echo "$base_toolbox_command: failed to set GID mapping of user namespace" >&2
|
||
kill -9 "$unshare_pid" 2>&3
|
||
return 1
|
||
fi
|
||
|
||
if ! newuidmap "$unshare_pid" 0 "$user_id_real" 1 1 "$userns_uid_start" "$userns_uid_len" 2>&3; then
|
||
echo "$base_toolbox_command: failed to set UID mapping of user namespace" >&2
|
||
kill -9 "$unshare_pid" 2>&3
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: GID map of user namespace:" >&3
|
||
cat /proc/"$unshare_pid"/gid_map 1>&3 2>&3
|
||
|
||
echo "$base_toolbox_command: UID map of user namespace:" >&3
|
||
cat /proc/"$unshare_pid"/uid_map 1>&3 2>&3
|
||
|
||
if ! flock --unlock 4 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove $path: lock couldn't be unlocked" >&2
|
||
kill -9 "$unshare_pid" 2>&3
|
||
return 1
|
||
fi
|
||
|
||
if ! wait "$unshare_pid" 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove $path" >&2
|
||
return 1
|
||
fi
|
||
|
||
rm --force --recursive "$unshare_directory" 2>&3
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
create()
|
||
(
|
||
enter_command_skip="$1"
|
||
|
||
dbus_system_bus_address="unix:path=/var/run/dbus/system_bus_socket"
|
||
home_link=""
|
||
kcm_socket=""
|
||
kcm_socket_bind=""
|
||
media_link=""
|
||
media_path_bind=""
|
||
mnt_link=""
|
||
mnt_path_bind=""
|
||
run_media_path_bind=""
|
||
toolbox_profile_bind=""
|
||
ulimit_host=""
|
||
usr_mount_destination_flags="ro"
|
||
|
||
# shellcheck disable=SC2153
|
||
if [ "$DBUS_SYSTEM_BUS_ADDRESS" != "" ]; then
|
||
dbus_system_bus_address=$DBUS_SYSTEM_BUS_ADDRESS
|
||
fi
|
||
dbus_system_bus_path=$(echo "$dbus_system_bus_address" | cut --delimiter = --fields 2 2>&3)
|
||
dbus_system_bus_path=$(readlink --canonicalize "$dbus_system_bus_path" 2>&3)
|
||
|
||
# Note that 'systemctl show ...' doesn't terminate with a non-zero exit
|
||
# code when used with an unknown unit. eg.:
|
||
# $ systemctl show --value --property Listen foo
|
||
# $ echo $?
|
||
# 0
|
||
if ! kcm_socket_listen=$(systemctl show --value --property Listen sssd-kcm.socket 2>&3); then
|
||
echo "$base_toolbox_command: failed to use 'systemctl show'" >&3
|
||
kcm_socket_listen=""
|
||
elif [ "$kcm_socket_listen" = "" ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to read property Listen from sssd-kcm.socket" >&3
|
||
else
|
||
echo "$base_toolbox_command: checking value $kcm_socket_listen of property Listen in sssd-kcm.socket" >&3
|
||
|
||
if ! (echo "$kcm_socket_listen" | grep " (Stream)$" >/dev/null 2>&3); then
|
||
echo "$base_toolbox_command: unknown socket in sssd-kcm.socket" >&2
|
||
echo "$base_toolbox_command: expected SOCK_STREAM" >&2
|
||
kcm_socket_listen=""
|
||
elif ! (echo "$kcm_socket_listen" | grep "^/" >/dev/null 2>&3); then
|
||
echo "$base_toolbox_command: unknown socket in sssd-kcm.socket" >&2
|
||
echo "$base_toolbox_command: expected file system socket in the AF_UNIX family" >&2
|
||
kcm_socket_listen=""
|
||
fi
|
||
fi
|
||
|
||
echo "$base_toolbox_command: parsing value $kcm_socket_listen of property Listen in sssd-kcm.socket" >&3
|
||
|
||
if [ "$kcm_socket_listen" != "" ] 2>&3; then
|
||
kcm_socket=${kcm_socket_listen%" (Stream)"}
|
||
kcm_socket_bind="--volume $kcm_socket:$kcm_socket"
|
||
fi
|
||
|
||
echo "$base_toolbox_command: checking if 'podman create' supports --ulimit host" >&3
|
||
|
||
if man podman-create 2>&3 | grep "You can pass host" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: 'podman create' supports --ulimit host" >&3
|
||
|
||
ulimit_host="--ulimit host"
|
||
fi
|
||
|
||
if ! pull_base_toolbox_image; then
|
||
return 1
|
||
fi
|
||
|
||
if image_reference_has_domain "$base_toolbox_image"; then
|
||
base_toolbox_image_full="$base_toolbox_image"
|
||
else
|
||
if ! base_toolbox_image_full=$($podman_command inspect \
|
||
--format "{{index .RepoTags 0}}" \
|
||
--type image \
|
||
"$base_toolbox_image" 2>&3); then
|
||
echo "$base_toolbox_command: failed to get RepoTag for base image $base_toolbox_image" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: base image $base_toolbox_image resolved to $base_toolbox_image_full" >&3
|
||
fi
|
||
|
||
echo "$base_toolbox_command: checking if container $toolbox_container already exists" >&3
|
||
|
||
enter_command=$(create_enter_command "$toolbox_container")
|
||
if $podman_command container exists "$toolbox_container" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: container $toolbox_container already exists" >&2
|
||
echo "Enter with: $enter_command" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
return 1
|
||
fi
|
||
|
||
if [ -f /etc/profile.d/toolbox.sh ] 2>&3; then
|
||
toolbox_profile_bind="--volume /etc/profile.d/toolbox.sh:/etc/profile.d/toolbox.sh:ro"
|
||
elif [ -f /usr/share/profile.d/toolbox.sh ] 2>&3; then
|
||
toolbox_profile_bind="--volume /usr/share/profile.d/toolbox.sh:/etc/profile.d/toolbox.sh:ro"
|
||
else
|
||
echo "$base_toolbox_command: failed to bind mount toolbox.sh" >&3
|
||
fi
|
||
|
||
if [ -d /media ] 2>&3; then
|
||
echo "$base_toolbox_command: checking if /media is a symbolic link to /run/media" >&3
|
||
|
||
if [ "$(readlink /media)" = run/media ] 2>&3; then
|
||
echo "$base_toolbox_command: /media is a symbolic link to /run/media" >&3
|
||
media_link="--media-link"
|
||
else
|
||
media_path_bind="--volume /media:/media:rslave"
|
||
fi
|
||
fi
|
||
|
||
echo "$base_toolbox_command: checking if /mnt is a symbolic link to /var/mnt" >&3
|
||
|
||
if [ "$(readlink /mnt)" = var/mnt ] 2>&3; then
|
||
echo "$base_toolbox_command: /mnt is a symbolic link to /var/mnt" >&3
|
||
mnt_link="--mnt-link"
|
||
else
|
||
mnt_path_bind="--volume /mnt:/mnt:rslave"
|
||
fi
|
||
|
||
if [ -d /run/media ] 2>&3; then
|
||
run_media_path_bind="--volume /run/media:/run/media:rslave"
|
||
fi
|
||
|
||
echo "$base_toolbox_command: checking if /usr is mounted read-only or read-write" >&3
|
||
|
||
if ! usr_mount_point=$(df --output=target /usr | tail --lines 1 2>&3); then
|
||
echo "$base_toolbox_command: failed to get the mount-point of /usr" >&2
|
||
else
|
||
echo "$base_toolbox_command: mount-point of /usr is $usr_mount_point" >&3
|
||
|
||
if ! usr_mount_source_flags=$(findmnt --noheadings --output OPTIONS "$usr_mount_point" 2>&3); then
|
||
echo "$base_toolbox_command: failed to get the mount options of $usr_mount_point" >&2
|
||
else
|
||
echo "$base_toolbox_command: mount flags of /usr on the host are $usr_mount_source_flags" >&3
|
||
|
||
if echo "$usr_mount_source_flags" | grep --invert-match "ro" >/dev/null 2>&3; then
|
||
usr_mount_destination_flags="rw"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
if ! home_canonical=$(readlink --canonicalize "$HOME" 2>&3); then
|
||
echo "$base_toolbox_command: failed to canonicalize $HOME" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: $HOME canonicalized to $home_canonical" >&3
|
||
|
||
echo "$base_toolbox_command: checking if /home is a symbolic link to /var/home" >&3
|
||
|
||
if [ "$(readlink /home)" = var/home ] 2>&3; then
|
||
echo "$base_toolbox_command: /home is a symbolic link to /var/home" >&3
|
||
home_link="--home-link"
|
||
fi
|
||
|
||
echo "$base_toolbox_command: calling org.freedesktop.Flatpak.SessionHelper.RequestSession" >&3
|
||
|
||
if ! gdbus call \
|
||
--session \
|
||
--dest org.freedesktop.Flatpak \
|
||
--object-path /org/freedesktop/Flatpak/SessionHelper \
|
||
--method org.freedesktop.Flatpak.SessionHelper.RequestSession >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to call org.freedesktop.Flatpak.SessionHelper.RequestSession" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: creating container $toolbox_container" >&3
|
||
|
||
if spinner_directory=$(mktemp --directory --tmpdir $spinner_template 2>&3); then
|
||
spinner_message="Creating container $toolbox_container: "
|
||
if ! spinner_start "$spinner_directory" "$spinner_message"; then
|
||
spinner_directory=""
|
||
fi
|
||
else
|
||
echo "$base_toolbox_command: unable to start spinner: spinner directory not created" >&2
|
||
spinner_directory=""
|
||
fi
|
||
|
||
# shellcheck disable=SC2086
|
||
$podman_command create \
|
||
--dns none \
|
||
--env TOOLBOX_PATH="$TOOLBOX_PATH" \
|
||
--hostname toolbox \
|
||
--ipc host \
|
||
--label "com.github.containers.toolbox=true" \
|
||
--label "com.github.debarshiray.toolbox=true" \
|
||
--name $toolbox_container \
|
||
--network host \
|
||
--no-hosts \
|
||
--pid host \
|
||
--privileged \
|
||
--security-opt label=disable \
|
||
$ulimit_host \
|
||
--userns=keep-id \
|
||
--user root:root \
|
||
$kcm_socket_bind \
|
||
$media_path_bind \
|
||
$mnt_path_bind \
|
||
$run_media_path_bind \
|
||
$toolbox_profile_bind \
|
||
--volume "$TOOLBOX_PATH":/usr/bin/toolbox:ro \
|
||
--volume "$XDG_RUNTIME_DIR":"$XDG_RUNTIME_DIR" \
|
||
--volume "$XDG_RUNTIME_DIR"/.flatpak-helper/monitor:/run/host/monitor \
|
||
--volume "$dbus_system_bus_path":"$dbus_system_bus_path" \
|
||
--volume "$home_canonical":"$home_canonical":rslave \
|
||
--volume /etc:/run/host/etc \
|
||
--volume /dev:/dev:rslave \
|
||
--volume /run:/run/host/run:rslave \
|
||
--volume /tmp:/run/host/tmp:rslave \
|
||
--volume /usr:/run/host/usr:"$usr_mount_destination_flags",rslave \
|
||
--volume /var:/run/host/var:rslave \
|
||
"$base_toolbox_image_full" \
|
||
toolbox --verbose init-container \
|
||
--home "$HOME" \
|
||
$home_link \
|
||
$media_link \
|
||
$mnt_link \
|
||
--monitor-host \
|
||
--shell "$SHELL" \
|
||
--uid "$user_id_real" \
|
||
--user "$USER" >/dev/null 2>&3
|
||
ret_val=$?
|
||
|
||
if [ "$spinner_directory" != "" ]; then
|
||
spinner_stop "$spinner_directory"
|
||
fi
|
||
|
||
if [ $ret_val -ne 0 ]; then
|
||
echo "$base_toolbox_command: failed to create container $toolbox_container" >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! $enter_command_skip; then
|
||
echo "Created container: $toolbox_container"
|
||
echo "Enter with: $enter_command"
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
enter()
|
||
(
|
||
emit_escape_sequence=false
|
||
host_id=$(get_host_id)
|
||
host_variant_id=$(get_host_variant_id)
|
||
|
||
if [ "$host_id" = "fedora" ] 2>&3 \
|
||
&& { [ "$host_variant_id" = "silverblue" ] 2>&3 || [ "$host_variant_id" = "workstation" ] 2>&3; }; then
|
||
emit_escape_sequence=true
|
||
fi
|
||
|
||
run "$emit_escape_sequence" true false "$SHELL" -l
|
||
)
|
||
|
||
|
||
init_container()
|
||
{
|
||
init_container_home="$1"
|
||
init_container_home_link="$2"
|
||
init_container_media_link="$3"
|
||
init_container_mnt_link="$4"
|
||
init_container_monitor_host="$5"
|
||
init_container_shell="$6"
|
||
init_container_uid="$7"
|
||
init_container_user="$8"
|
||
|
||
if [ "$XDG_RUNTIME_DIR" = "" ] 2>&3; then
|
||
echo "$base_toolbox_command: XDG_RUNTIME_DIR is unset" >&3
|
||
|
||
XDG_RUNTIME_DIR=/run/user/"$init_container_uid"
|
||
echo "$base_toolbox_command: XDG_RUNTIME_DIR set to $XDG_RUNTIME_DIR" >&3
|
||
|
||
toolbox_runtime_directory="$XDG_RUNTIME_DIR"/toolbox
|
||
fi
|
||
|
||
init_container_initialized_stamp="$toolbox_runtime_directory"/container-initialized-"$$"
|
||
|
||
echo "$base_toolbox_command: creating /run/.toolboxenv" >&3
|
||
|
||
if ! touch /run/.toolboxenv 2>&3; then
|
||
echo "$base_toolbox_command: failed to create /run/.toolboxenv" >&2
|
||
return 1
|
||
fi
|
||
|
||
if $init_container_monitor_host; then
|
||
working_directory="$PWD"
|
||
|
||
if [ -d /run/host/etc ] 2>&3; then
|
||
if ! readlink /etc/host.conf >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: redirecting /etc/host.conf to /run/host/etc/host.conf" >&3
|
||
|
||
if ! (cd /etc 2>&3 \
|
||
&& rm --force host.conf 2>&3 \
|
||
&& ln --symbolic /run/host/etc/host.conf host.conf 2>&3); then
|
||
echo "$base_toolbox_command: failed to redirect /etc/host.conf to /run/host/etc/host.conf" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if ! readlink /etc/hosts >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: redirecting /etc/hosts to /run/host/etc/hosts" >&3
|
||
|
||
if ! (cd /etc 2>&3 \
|
||
&& rm --force hosts 2>&3 \
|
||
&& ln --symbolic /run/host/etc/hosts hosts 2>&3); then
|
||
echo "$base_toolbox_command: failed to redirect /etc/hosts to /run/host/etc/hosts" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if ! readlink /etc/resolv.conf >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: redirecting /etc/resolv.conf to /run/host/etc/resolv.conf" >&3
|
||
|
||
if ! (cd /etc 2>&3 \
|
||
&& rm --force resolv.conf 2>&3 \
|
||
&& ln --symbolic /run/host/etc/resolv.conf resolv.conf 2>&3); then
|
||
echo "$base_toolbox_command: failed to redirect /etc/resolv.conf to /run/host/etc/resolv.conf" \
|
||
>&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
|
||
if ! mount_bind /run/host/etc/machine-id /etc/machine-id ro; then
|
||
return 1
|
||
fi
|
||
|
||
if ! mount_bind /run/host/run/libvirt /run/libvirt; then
|
||
return 1
|
||
fi
|
||
|
||
if ! mount_bind /run/host/run/systemd/journal /run/systemd/journal; then
|
||
return 1
|
||
fi
|
||
|
||
if [ -d /sys/fs/selinux ] 2>&3; then
|
||
if ! mount_bind /usr/share/empty /sys/fs/selinux; then
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if ! mount_bind /run/host/var/lib/flatpak /var/lib/flatpak ro; then
|
||
return 1
|
||
fi
|
||
|
||
if ! mount_bind /run/host/var/log/journal /var/log/journal ro; then
|
||
return 1
|
||
fi
|
||
|
||
if ! mount_bind /run/host/var/mnt /var/mnt rslave; then
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if [ -d /run/host/monitor ] 2>&3; then
|
||
if ! localtime_target=$(readlink /etc/localtime >/dev/null 2>&3) \
|
||
|| [ "$localtime_target" != "/run/host/monitor/localtime" ] 2>&3; then
|
||
echo "$base_toolbox_command: redirecting /etc/localtime to /run/host/monitor/localtime" >&3
|
||
|
||
if ! (cd /etc 2>&3 \
|
||
&& rm --force localtime 2>&3 \
|
||
&& ln --symbolic /run/host/monitor/localtime localtime 2>&3); then
|
||
echo "$base_toolbox_command: failed to redirect /etc/localtime to /run/host/monitor/localtime" \
|
||
>&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if ! readlink /etc/timezone >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: redirecting /etc/timezone to /run/host/monitor/timezone" >&3
|
||
|
||
if ! (cd /etc 2>&3 \
|
||
&& rm --force timezone 2>&3 \
|
||
&& ln --symbolic /run/host/monitor/timezone timezone 2>&3); then
|
||
echo "$base_toolbox_command: failed to redirect /etc/timezone to /run/host/monitor/timezone" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
if ! cd "$working_directory" 2>&3; then
|
||
echo "$base_toolbox_command: failed to restore working directory" >&2
|
||
fi
|
||
fi
|
||
|
||
if $init_container_media_link && ! readlink /media >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: making /media a symbolic link to /run/media" >&3
|
||
|
||
# shellcheck disable=SC2174
|
||
if ! (rmdir /media 2>&3 \
|
||
&& mkdir --mode 0755 --parents /run/media 2>&3 \
|
||
&& ln --symbolic run/media /media 2>&3); then
|
||
echo "$base_toolbox_command: failed to make /media a symbolic link" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if $init_container_mnt_link && ! readlink /mnt >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: making /mnt a symbolic link to /var/mnt" >&3
|
||
|
||
# shellcheck disable=SC2174
|
||
if ! (rmdir /mnt 2>&3 \
|
||
&& mkdir --mode 0755 --parents /var/mnt 2>&3 \
|
||
&& ln --symbolic var/mnt /mnt 2>&3); then
|
||
echo "$base_toolbox_command: failed to make /mnt a symbolic link" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if ! id -u "$init_container_user" >/dev/null 2>&3; then
|
||
if $init_container_home_link ; then
|
||
echo "$base_toolbox_command: making /home a symlink" >&3
|
||
|
||
# shellcheck disable=SC2174
|
||
if ! (rmdir /home 2>&3 \
|
||
&& mkdir --mode 0755 --parents /var/home 2>&3 \
|
||
&& ln --symbolic var/home /home 2>&3); then
|
||
echo "$base_toolbox_command: failed to make /home a symlink" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if ! groups=$(get_group_for_sudo); then
|
||
echo "$base_toolbox_command: failed to add user $init_container_user: group for sudo not found" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: adding user $init_container_user with UID $init_container_uid" >&3
|
||
|
||
if ! useradd \
|
||
--home-dir "$init_container_home" \
|
||
--no-create-home \
|
||
--shell "$init_container_shell" \
|
||
--uid "$init_container_uid" \
|
||
--groups "$groups" \
|
||
"$init_container_user" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to add user $init_container_user with UID $init_container_uid" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: removing password for user $init_container_user" >&3
|
||
|
||
if ! passwd --delete "$init_container_user" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove password for user $init_container_user" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: removing password for user root" >&3
|
||
|
||
if ! passwd --delete root >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove password for user root" >&2
|
||
return 1
|
||
fi
|
||
|
||
fi
|
||
|
||
if [ -d /etc/krb5.conf.d ] 2>&3 && ! [ -f /etc/krb5.conf.d/kcm_default_ccache ] 2>&3; then
|
||
echo "$base_toolbox_command: setting KCM as the default Kerberos credential cache" >&3
|
||
|
||
cat <<EOF >/etc/krb5.conf.d/kcm_default_ccache 2>&3
|
||
# Written by Toolbox
|
||
# https://github.com/containers/toolbox
|
||
#
|
||
# # To disable the KCM credential cache, comment out the following lines.
|
||
|
||
[libdefaults]
|
||
default_ccache_name = KCM:
|
||
EOF
|
||
ret_val=$?
|
||
|
||
if [ "$ret_val" -ne 0 ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to set KCM as the default Kerberos credential cache" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
echo "$base_toolbox_command: finished initializing container" >&3
|
||
|
||
if ! touch "$init_container_initialized_stamp" 2>&3; then
|
||
echo "$base_toolbox_command: failed to create initialization stamp" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: going to sleep" >&3
|
||
|
||
exec sleep +Inf
|
||
}
|
||
|
||
|
||
run()
|
||
(
|
||
emit_escape_sequence="$1"
|
||
fallback_to_bash="$2"
|
||
pedantic="$3"
|
||
program="$4"
|
||
shift 4
|
||
|
||
create_toolbox_container=false
|
||
prompt_for_create=true
|
||
|
||
echo "$base_toolbox_command: checking if container $toolbox_container exists" >&3
|
||
|
||
if ! $podman_command container exists "$toolbox_container" 2>&3; then
|
||
echo "$base_toolbox_command: container $toolbox_container not found" >&3
|
||
|
||
if $podman_command container exists "$toolbox_container_old_v1" 2>&3; then
|
||
echo "$base_toolbox_command: container $toolbox_container_old_v1 found" >&3
|
||
|
||
# shellcheck disable=SC2030
|
||
toolbox_container="$toolbox_container_old_v1"
|
||
elif $podman_command container exists "$toolbox_container_old_v2" 2>&3; then
|
||
echo "$base_toolbox_command: container $toolbox_container_old_v2 found" >&3
|
||
|
||
# shellcheck disable=SC2030
|
||
toolbox_container="$toolbox_container_old_v2"
|
||
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
|
||
fi
|
||
|
||
containers_count=$(echo "$containers" | grep --count . 2>&3)
|
||
if ! is_integer "$containers_count"; then
|
||
enter_print_container_not_found "$toolbox_container"
|
||
exit 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: found $containers_count containers" >&3
|
||
|
||
if [ "$containers_count" -eq 0 ] 2>&3; then
|
||
if $assume_yes; then
|
||
create_toolbox_container=true
|
||
prompt_for_create=false
|
||
fi
|
||
|
||
if $prompt_for_create; then
|
||
prompt="No toolbox containers found. Create now? [y/N]"
|
||
if ask_for_confirmation "n" "$prompt"; then
|
||
create_toolbox_container=true
|
||
else
|
||
create_toolbox_container=false
|
||
fi
|
||
fi
|
||
|
||
if ! $create_toolbox_container; then
|
||
echo "A container can be created later with the 'create' command." >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
fi
|
||
|
||
if ! update_container_and_image_names; then
|
||
exit 1
|
||
fi
|
||
|
||
if ! create true; then
|
||
exit 1
|
||
fi
|
||
elif [ "$containers_count" -eq 1 ] 2>&3 \
|
||
&& [ "$toolbox_container" = "$toolbox_container_default" ] 2>&3; then
|
||
echo "$base_toolbox_command: container $toolbox_container not found" >&2
|
||
|
||
toolbox_container=$(echo "$containers" | grep . 2>&3 | head --lines 1 2>&3)
|
||
echo "Entering container $toolbox_container instead." >&2
|
||
echo "Use the 'create' command to create a different toolbox." >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
else
|
||
echo "$base_toolbox_command: container $toolbox_container not found" >&2
|
||
echo "Use the '--container' option to select a toolbox." >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
echo "$base_toolbox_command: calling org.freedesktop.Flatpak.SessionHelper.RequestSession" >&3
|
||
|
||
if ! gdbus call \
|
||
--session \
|
||
--dest org.freedesktop.Flatpak \
|
||
--object-path /org/freedesktop/Flatpak/SessionHelper \
|
||
--method org.freedesktop.Flatpak.SessionHelper.RequestSession >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to call org.freedesktop.Flatpak.SessionHelper.RequestSession" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: starting container $toolbox_container" >&3
|
||
|
||
if is_etc_profile_d_toolbox_a_bind_mount "$toolbox_container"; then
|
||
echo "$base_toolbox_command: /etc/profile.d/toolbox.sh already mounted in container $toolbox_container" >&3
|
||
|
||
if ! container_start "$toolbox_container"; then
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "$base_toolbox_command: /etc/profile.d/toolbox.sh not mounted in container $toolbox_container" >&3
|
||
|
||
if ! copy_etc_profile_d_toolbox_to_runtime_directory; then
|
||
exit 1
|
||
fi
|
||
|
||
if ! container_start "$toolbox_container"; then
|
||
exit 1
|
||
fi
|
||
|
||
if ! copy_etc_profile_d_toolbox_to_container "$toolbox_container"; then
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
echo "$base_toolbox_command: inspecting entry point of container $toolbox_container" >&3
|
||
|
||
if ! entry_point=$($podman_command inspect --format "{{index .Config.Cmd 0}}" --type container "$toolbox_container" 2>&3); then
|
||
echo "$base_toolbox_command: failed to inspect entry point of container $toolbox_container" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: entry point of container $toolbox_container is $entry_point" >&3
|
||
|
||
if [ "$entry_point" = "toolbox" ] 2>&3; then
|
||
echo "$base_toolbox_command: waiting for container $toolbox_container to finish initializing" >&3
|
||
|
||
if ! entry_point_pid=$($podman_command inspect --format "{{.State.Pid}}" --type container "$toolbox_container" 2>&3); then
|
||
echo "$base_toolbox_command: failed to inspect entry point PID of container $toolbox_container" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if ! is_integer "$entry_point_pid"; then
|
||
echo "$base_toolbox_command: failed to parse entry point PID of container $toolbox_container" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [ "$entry_point_pid" -le 0 ] 2>&3; then
|
||
echo "$base_toolbox_command: invalid entry point PID of container $toolbox_container" >&2
|
||
exit 1
|
||
fi
|
||
|
||
container_initialized_stamp="$toolbox_runtime_directory/container-initialized-$entry_point_pid"
|
||
container_initialized_timeout=25 #s
|
||
|
||
i=0
|
||
while ! [ -f "$container_initialized_stamp" ] 2>&3; do
|
||
sleep 1 2>&3
|
||
|
||
i=$((i + 1))
|
||
if [ "$i" -eq "$container_initialized_timeout" ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to initialize container $toolbox_container" >&2
|
||
exit 1
|
||
fi
|
||
done
|
||
else
|
||
echo "$base_toolbox_command: container $toolbox_container uses deprecated features" >&2
|
||
echo "Consider recreating it with Toolbox version 0.0.17 or newer." >&2
|
||
fi
|
||
|
||
if ! $podman_command exec --user root:root "$toolbox_container" touch /run/.toolboxenv 2>&3; then
|
||
echo "$base_toolbox_command: failed to create /run/.toolboxenv in container $toolbox_container" >&2
|
||
exit 1
|
||
fi
|
||
|
||
set_environment=$(create_environment_options)
|
||
|
||
echo "$base_toolbox_command: looking for $program in container $toolbox_container" >&3
|
||
|
||
# shellcheck disable=SC2016
|
||
if ! $podman_command exec \
|
||
--user "$USER" \
|
||
"$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: running in container $toolbox_container:" >&3
|
||
echo "$base_toolbox_command: $program" >&3
|
||
for i in "$@"; do
|
||
echo "$base_toolbox_command: $i" >&3
|
||
done
|
||
|
||
$emit_escape_sequence && printf "\033]777;container;push;%s;toolbox\033\\" "$toolbox_container"
|
||
|
||
# shellcheck disable=SC2016
|
||
# for the command passed to capsh
|
||
# shellcheck disable=SC2086
|
||
$podman_command exec \
|
||
--interactive \
|
||
--tty \
|
||
--user "$USER" \
|
||
--workdir "$PWD" \
|
||
$set_environment \
|
||
"$toolbox_container" \
|
||
capsh --caps="" -- -c 'exec "$@"' /bin/sh "$program" "$@" 2>&3
|
||
ret_val="$?"
|
||
|
||
$emit_escape_sequence && printf "\033]777;container;pop;;\033\\"
|
||
|
||
if [ "$ret_val" -eq 127 ] 2>&3; then
|
||
# shellcheck disable=SC2016
|
||
if ! $podman_command exec \
|
||
--user "$USER" \
|
||
"$toolbox_container" \
|
||
sh -c 'test -d "$1"' sh "$PWD" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: directory '$PWD' not found in container $toolbox_container" >&2
|
||
fi
|
||
fi
|
||
|
||
exit "$ret_val"
|
||
)
|
||
|
||
|
||
help()
|
||
(
|
||
to_help_command="$1"
|
||
|
||
if [ "$to_help_command" = "" ] 2>&3 || [ "$to_help_command" = "$base_toolbox_command" ] 2>&3; then
|
||
exec man toolbox 2>&1
|
||
fi
|
||
|
||
exec man toolbox-"$to_help_command" 2>&1
|
||
)
|
||
|
||
|
||
list_images()
|
||
(
|
||
output=""
|
||
|
||
if ! images_old=$($podman_command images \
|
||
--filter "label=com.redhat.component=fedora-toolbox" \
|
||
--format "{{.Repository}}:{{.Tag}}" 2>&3); then
|
||
echo "$base_toolbox_command: failed to list images with com.redhat.component=fedora-toolbox" >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! images=$($podman_command images \
|
||
--filter "label=com.github.debarshiray.toolbox=true" \
|
||
--format "{{.Repository}}:{{.Tag}}" 2>&3); then
|
||
echo "$base_toolbox_command: failed to list images with com.github.debarshiray.toolbox=true" >&2
|
||
return 1
|
||
fi
|
||
|
||
images=$(printf "%s\n%s\n" "$images_old" "$images" | sort 2>&3 | uniq 2>&3)
|
||
if ! details=$(images_get_details "$images"); then
|
||
return 1
|
||
fi
|
||
|
||
if [ "$details" != "" ] 2>&3; then
|
||
table_data=$(printf "%s\t%s\t%s\n" "IMAGE ID" "IMAGE NAME" "CREATED"; echo "$details")
|
||
if ! output=$(echo "$table_data" | sed "s/ \{2,\}/\t/g" 2>&3 | column -s "$tab" -t 2>&3); then
|
||
echo "$base_toolbox_command: failed to parse list of images" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if [ "$output" != "" ]; then
|
||
echo "$output"
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
containers_get_details()
|
||
(
|
||
containers="$1"
|
||
|
||
if ! echo "$containers" | while read -r container; do
|
||
[ "$container" = "" ] 2>&3 && continue
|
||
|
||
if ! $podman_command ps --all \
|
||
--filter "name=$container" \
|
||
--format "{{.ID}} {{.Names}} {{.Created}} {{.Status}} {{.Image}}" 2>&3; then
|
||
echo "$base_toolbox_command: failed to get details for container $container" >&2
|
||
return 1
|
||
fi
|
||
done; then
|
||
return 1
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
list_containers()
|
||
(
|
||
output=""
|
||
|
||
if ! containers=$(list_container_names); then
|
||
return 1
|
||
fi
|
||
|
||
if ! details=$(containers_get_details "$containers"); then
|
||
return 1
|
||
fi
|
||
|
||
if [ "$details" != "" ] 2>&3; then
|
||
table_data=$(printf "%s\t%s\t%s\t%s\t%s\n" "CONTAINER ID" "CONTAINER NAME" "CREATED" "STATUS" "IMAGE NAME"
|
||
echo "$details")
|
||
if ! output=$(echo "$table_data" | sed "s/ \{2,\}/\t/g" 2>&3 | column -s "$tab" -t 2>&3); then
|
||
echo "$base_toolbox_command: failed to parse list of containers" >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if [ "$output" != "" ]; then
|
||
echo "$output" | head --lines 1 2>&3
|
||
|
||
echo "$output" | tail --lines +2 2>&3 \
|
||
| (
|
||
while read -r container; do
|
||
id=$(echo "$container" | cut --delimiter " " --fields 1 2>&3)
|
||
is_running=$($podman_command inspect "$id" --format "{{.State.Running}}" 2>&3)
|
||
if $is_running; then
|
||
# shellcheck disable=SC2059
|
||
printf "${LGC}$container${NC}\n"
|
||
else
|
||
echo "$container"
|
||
fi
|
||
done
|
||
)
|
||
fi
|
||
|
||
return 0
|
||
)
|
||
|
||
|
||
migrate()
|
||
(
|
||
configuration_directory="$HOME/.config/toolbox"
|
||
migrate_stamp="$configuration_directory/podman-system-migrate"
|
||
|
||
migrate_lock="$toolbox_runtime_directory"/migrate.lock
|
||
|
||
if ! version=$($podman_command version --format "{{.Version}}" 2>&3); then
|
||
echo "$base_toolbox_command: unable to migrate containers: Podman version couldn't be read" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: current Podman version is $version" >&3
|
||
|
||
if ! mkdir --parents "$configuration_directory" 2>&3; then
|
||
echo "$base_toolbox_command: unable to migrate containers: configuration directory not created" >&2
|
||
return 1
|
||
fi
|
||
|
||
# shellcheck disable=SC2174
|
||
if ! mkdir --mode 700 --parents "$toolbox_runtime_directory" 2>&3; then
|
||
echo "$base_toolbox_command: unable to migrate containers: runtime directory not created" >&2
|
||
return 1
|
||
fi
|
||
|
||
exec 5>"$migrate_lock"
|
||
if ! flock 5 2>&3; then
|
||
echo "$base_toolbox_command: unable to migrate containers: migration lock not acquired" >&3
|
||
return 1
|
||
fi
|
||
|
||
if [ -f "$migrate_stamp" ] 2>&3; then
|
||
if grep "$version" "$migrate_stamp" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: migration not needed: Podman version $version is unchanged" >&3
|
||
return 0
|
||
fi
|
||
|
||
if ! version_old=$(printf "%s\n" "$version" \
|
||
| cat "$migrate_stamp" - 2>&3 \
|
||
| sort --version-sort 2>&3 \
|
||
| head --lines 1 2>&3); then
|
||
echo "$base_toolbox_command: unable to migrate containers: Podman versions couldn't be sorted" >&2
|
||
return 1
|
||
fi
|
||
|
||
if [ "$version" = "$version_old" ] 2>&3; then
|
||
echo "$base_toolbox_command: migration not needed: Podman version $version is old" >&3
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
if ! $podman_command system migrate >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: unable to migrate containers" >&2
|
||
return 1
|
||
fi
|
||
|
||
echo "$version" >"$migrate_stamp"
|
||
return 0
|
||
)
|
||
|
||
|
||
remove_containers()
|
||
(
|
||
ids=$1
|
||
all=$2
|
||
force=$3
|
||
|
||
ret_val=0
|
||
|
||
$force && force_option="--force"
|
||
|
||
if $all; then
|
||
if ! ids_old=$($podman_command ps \
|
||
--all \
|
||
--filter "label=com.redhat.component=fedora-toolbox" \
|
||
--format "{{.ID}}" 2>&3); then
|
||
echo "$base_toolbox_command: failed to list containers with com.redhat.component=fedora-toolbox" >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! ids=$($podman_command ps \
|
||
--all \
|
||
--filter "label=com.github.debarshiray.toolbox=true" \
|
||
--format "{{.ID}}" 2>&3); then
|
||
echo "$base_toolbox_command: failed to list containers with com.github.debarshiray.toolbox=true" >&2
|
||
return 1
|
||
fi
|
||
|
||
ids=$(printf "%s\n%s\n" "$ids_old" "$ids" | sort 2>&3 | uniq 2>&3)
|
||
if [ "$ids" != "" ]; then
|
||
ret_val=$(echo "$ids" \
|
||
| (
|
||
while read -r id; do
|
||
if ! $podman_command rm $force_option "$id" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove container $id" >&2
|
||
ret_val=1
|
||
fi
|
||
done
|
||
|
||
echo "$ret_val"
|
||
)
|
||
)
|
||
fi
|
||
else
|
||
ret_val=$(echo "$ids" \
|
||
| sed "s/ \+/\n/g" 2>&3 \
|
||
| (
|
||
while read -r id; do
|
||
if ! labels=$($podman_command inspect \
|
||
--format "{{.Config.Labels}}" \
|
||
--type container \
|
||
"$id" 2>&3); then
|
||
echo "$base_toolbox_command: failed to inspect $id" >&2
|
||
ret_val=1
|
||
continue
|
||
fi
|
||
|
||
if ! has_substring "$labels" "com.github.debarshiray.toolbox" \
|
||
&& ! has_substring "$labels" "com.redhat.component:fedora-toolbox"; then
|
||
echo "$base_toolbox_command: $id is not a toolbox container" >&2
|
||
ret_val=1
|
||
continue
|
||
fi
|
||
|
||
if ! $podman_command rm $force_option "$id" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove container $id" >&2
|
||
ret_val=1
|
||
fi
|
||
done
|
||
|
||
echo "$ret_val"
|
||
)
|
||
)
|
||
fi
|
||
|
||
return "$ret_val"
|
||
)
|
||
|
||
|
||
remove_images()
|
||
(
|
||
ids=$1
|
||
all=$2
|
||
force=$3
|
||
|
||
ret_val=0
|
||
|
||
$force && force_option="--force"
|
||
|
||
if $all; then
|
||
if ! ids_old=$($podman_command images \
|
||
--filter "label=com.redhat.component=fedora-toolbox" \
|
||
--format "{{.ID}}" 2>&3); then
|
||
echo "$0: failed to list images with com.redhat.component=fedora-toolbox" >&2
|
||
return 1
|
||
fi
|
||
|
||
if ! ids=$($podman_command images \
|
||
--all \
|
||
--filter "label=com.github.debarshiray.toolbox=true" \
|
||
--format "{{.ID}}" 2>&3); then
|
||
echo "$0: failed to list images with com.github.debarshiray.toolbox=true" >&2
|
||
return 1
|
||
fi
|
||
|
||
ids=$(printf "%s\n%s\n" "$ids_old" "$ids" | sort 2>&3 | uniq 2>&3)
|
||
if [ "$ids" != "" ]; then
|
||
ret_val=$(echo "$ids" \
|
||
| (
|
||
while read -r id; do
|
||
if ! $podman_command rmi $force_option "$id" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove image $id" >&2
|
||
ret_val=1
|
||
fi
|
||
done
|
||
|
||
echo "$ret_val"
|
||
)
|
||
)
|
||
fi
|
||
else
|
||
ret_val=$(echo "$ids" \
|
||
| sed "s/ \+/\n/g" 2>&3 \
|
||
| (
|
||
while read -r id; do
|
||
if ! labels=$($podman_command inspect \
|
||
--format "{{.Labels}}" \
|
||
--type image \
|
||
"$id" 2>&3); then
|
||
echo "$base_toolbox_command: failed to inspect $id" >&2
|
||
ret_val=1
|
||
continue
|
||
fi
|
||
|
||
if ! has_substring "$labels" "com.github.debarshiray.toolbox" \
|
||
&& ! has_substring "$labels" "com.redhat.component:fedora-toolbox"; then
|
||
echo "$base_toolbox_command: $id is not a toolbox image" >&2
|
||
ret_val=1
|
||
continue
|
||
fi
|
||
|
||
if ! $podman_command rmi $force_option "$id" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove image $id" >&2
|
||
ret_val=1
|
||
fi
|
||
done
|
||
|
||
echo "$ret_val"
|
||
)
|
||
)
|
||
fi
|
||
|
||
return "$ret_val"
|
||
)
|
||
|
||
|
||
reset()
|
||
(
|
||
do_reset=false
|
||
prompt_for_reset=true
|
||
ret_val=0
|
||
|
||
if [ "$user_id_real" -eq 0 ] 2>&3; then
|
||
if [ -d /run/containers ] 2>&3; then
|
||
echo "$base_toolbox_command: The 'reset' command cannot be used after other commands" >&2
|
||
echo "Reboot the system before using it again." >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
return 1
|
||
fi
|
||
else
|
||
if [ -d "$XDG_RUNTIME_DIR"/overlay-containers ] 2>&3 \
|
||
|| [ -d "$XDG_RUNTIME_DIR"/overlay-layers ] 2>&3 \
|
||
|| [ -d "$XDG_RUNTIME_DIR"/overlay-locks ] 2>&3; then
|
||
echo "$base_toolbox_command: The 'reset' command cannot be used after other commands" >&2
|
||
echo "Reboot the system before using it again." >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
if $assume_yes; then
|
||
do_reset=true
|
||
prompt_for_reset=false
|
||
fi
|
||
|
||
if $prompt_for_reset; then
|
||
echo "All existing podman (and toolbox) containers and images will be removed."
|
||
|
||
prompt=$(printf "Continue? [y/N]:")
|
||
if ask_for_confirmation "n" "$prompt"; then
|
||
do_reset=true
|
||
else
|
||
do_reset=false
|
||
fi
|
||
fi
|
||
|
||
if ! $do_reset; then
|
||
return 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: resetting local state" >&3
|
||
|
||
if [ "$user_id_real" -eq 0 ] 2>&3; then
|
||
if ! rm --force --recursive /var/lib/containers/cache >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove /var/lib/containers/cache" >&2
|
||
ret_val=1
|
||
fi
|
||
|
||
if ! rm --force --recursive /var/lib/containers/sigstore/* >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove the contents of /var/lib/containers/sigstore" >&2
|
||
ret_val=1
|
||
fi
|
||
|
||
if ! rm --force --recursive /var/lib/containers/storage >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove /var/lib/containers/storage" >&2
|
||
ret_val=1
|
||
fi
|
||
else
|
||
if ! unshare_userns_rm "$HOME/.local/share/containers"; then
|
||
ret_val=1
|
||
fi
|
||
|
||
if ! rm --force --recursive "$HOME/.config/containers" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove $HOME/.config/containers" >&2
|
||
ret_val=1
|
||
fi
|
||
fi
|
||
|
||
if ! rm --force --recursive "$HOME/.config/toolbox" >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: failed to remove $HOME/.config/toolbox" >&2
|
||
ret_val=1
|
||
fi
|
||
|
||
return "$ret_val"
|
||
)
|
||
|
||
|
||
exit_if_extra_operand()
|
||
{
|
||
if [ "$1" != "" ]; then
|
||
echo "$base_toolbox_command: extra operand '$1'" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
|
||
exit_if_missing_argument()
|
||
{
|
||
if [ "$2" = "" ]; then
|
||
echo "$base_toolbox_command: missing argument for '$1'" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
|
||
exit_if_non_positive_argument()
|
||
{
|
||
if ! is_integer "$2"; then
|
||
echo "$base_toolbox_command: invalid argument for '$1'" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
fi
|
||
if [ "$2" -le 0 ] 2>&3; then
|
||
echo "$base_toolbox_command: invalid argument for '$1'" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
|
||
exit_if_unrecognized_option()
|
||
{
|
||
echo "$base_toolbox_command: unrecognized option '$1'" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
}
|
||
|
||
|
||
# shellcheck disable=SC2120
|
||
forward_to_host()
|
||
(
|
||
if ! command -v flatpak-spawn >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: flatpak-spawn not found" >&2
|
||
return 1
|
||
fi
|
||
|
||
eval "set -- $arguments"
|
||
|
||
set_environment=$(create_environment_options)
|
||
|
||
echo "$base_toolbox_command: forwarding to host:" >&3
|
||
echo "$base_toolbox_command: $TOOLBOX_PATH" >&3
|
||
for i in "$@"; do
|
||
echo "$base_toolbox_command: $i" >&3
|
||
done
|
||
|
||
# shellcheck disable=SC2086
|
||
flatpak-spawn $set_environment --host "$TOOLBOX_PATH" "$@" 2>&3
|
||
ret_val="$?"
|
||
|
||
return "$ret_val"
|
||
)
|
||
|
||
|
||
update_container_and_image_names()
|
||
{
|
||
[ "$release" = "" ] 2>&3 && release="$release_default"
|
||
|
||
if [ "$base_toolbox_image" = "" ] 2>&3; then
|
||
base_toolbox_image="fedora-toolbox:$release"
|
||
else
|
||
release=$(image_reference_get_tag "$base_toolbox_image")
|
||
[ "$release" = "" ] 2>&3 && release="$release_default"
|
||
fi
|
||
|
||
fgc="f$release"
|
||
echo "$base_toolbox_command: Fedora generational core is $fgc" >&3
|
||
|
||
echo "$base_toolbox_command: base image is $base_toolbox_image" >&3
|
||
|
||
toolbox_image=$(create_toolbox_image_name)
|
||
if ! (
|
||
ret_val=$?
|
||
if [ "$ret_val" -ne 0 ] 2>&3; then
|
||
if [ "$ret_val" -eq 100 ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to get the basename of base image $base_toolbox_image" >&2
|
||
else
|
||
echo "$base_toolbox_command: failed to create an ID for the customized user-specific image" >&2
|
||
fi
|
||
|
||
exit 1
|
||
fi
|
||
|
||
exit 0
|
||
); then
|
||
return 1
|
||
fi
|
||
|
||
# shellcheck disable=SC2031
|
||
if [ "$toolbox_container" = "" ]; then
|
||
toolbox_container=$(create_toolbox_container_name "$base_toolbox_image")
|
||
if ! (
|
||
ret_val=$?
|
||
if [ "$ret_val" -ne 0 ] 2>&3; then
|
||
if [ "$ret_val" -eq 100 ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to get the basename of image $base_toolbox_image" >&2
|
||
elif [ "$ret_val" -eq 101 ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to get the tag of image $base_toolbox_image" >&2
|
||
else
|
||
echo "$base_toolbox_command: failed to create a name for the toolbox container" >&2
|
||
fi
|
||
|
||
exit 1
|
||
fi
|
||
|
||
exit 0
|
||
); then
|
||
return 1
|
||
fi
|
||
|
||
if ! container_name_is_valid "$toolbox_container"; then
|
||
echo "$base_toolbox_command: generated container name $toolbox_container is invalid" >&2
|
||
echo "Container names must match '$container_name_regexp'." >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
return 1
|
||
fi
|
||
|
||
toolbox_container_old_v1=$(create_toolbox_container_name "$toolbox_image")
|
||
if ! (
|
||
ret_val=$?
|
||
if [ "$ret_val" -ne 0 ] 2>&3; then
|
||
if [ "$ret_val" -eq 100 ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to get the basename of image $toolbox_image" >&2
|
||
elif [ "$ret_val" -eq 101 ] 2>&3; then
|
||
echo "$base_toolbox_command: failed to get the tag of image $toolbox_image" >&2
|
||
else
|
||
echo "$base_toolbox_command: failed to create a name for the toolbox container" >&2
|
||
fi
|
||
|
||
exit 1
|
||
fi
|
||
|
||
exit 0
|
||
); then
|
||
return 1
|
||
fi
|
||
|
||
toolbox_container_old_v2="$toolbox_image"
|
||
fi
|
||
|
||
echo "$base_toolbox_command: container is $toolbox_container" >&3
|
||
return 0
|
||
}
|
||
|
||
|
||
arguments=$(save_positional_parameters "$@")
|
||
|
||
echo "THIS IMPLEMENTATION OF TOOLBOX IS NO LONGER MAINTAINED."
|
||
echo "Please, use the Go implementation instead."
|
||
echo
|
||
|
||
host_id=$(get_host_id)
|
||
if [ "$host_id" = "fedora" ] 2>&3; then
|
||
release_default=$(get_host_version_id)
|
||
else
|
||
release_default="30"
|
||
fi
|
||
toolbox_container_prefix_default="fedora-toolbox"
|
||
toolbox_container_default="$toolbox_container_prefix_default-$release_default"
|
||
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
--assumeyes | -y )
|
||
assume_yes=true
|
||
;;
|
||
-h | --help )
|
||
if [ -f /run/.containerenv ] 2>&3; then
|
||
if ! [ -f /run/.toolboxenv ] 2>&3; then
|
||
echo "$base_toolbox_command: this is not a toolbox container" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# shellcheck disable=SC2119
|
||
forward_to_host
|
||
exit
|
||
fi
|
||
|
||
help "$2"
|
||
exit
|
||
;;
|
||
-v | --verbose )
|
||
exec 3>&2
|
||
verbose=true
|
||
;;
|
||
-vv | --very-verbose )
|
||
exec 3>&2
|
||
podman_command="podman --log-level debug"
|
||
verbose=true
|
||
;;
|
||
* )
|
||
exit_if_unrecognized_option "$1"
|
||
esac
|
||
shift
|
||
done
|
||
|
||
echo "$base_toolbox_command: running as real user ID $user_id_real" >&3
|
||
|
||
if ! toolbox_command_path=$(realpath "$0" 2>&3); then
|
||
echo "$base_toolbox_command: failed to resolve absolute path to $0" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: resolved absolute path for $0 to $toolbox_command_path" >&3
|
||
|
||
if [ -f /run/.containerenv ] 2>&3; then
|
||
if [ "$TOOLBOX_PATH" = "" ] 2>&3; then
|
||
echo "$base_toolbox_command: TOOLBOX_PATH not set" >&2
|
||
exit 1
|
||
fi
|
||
else
|
||
if [ "$user_id_real" -ne 0 ] 2>&3; then
|
||
echo "$base_toolbox_command: checking if /etc/subgid and /etc/subuid have entries for user $USER" >&3
|
||
|
||
if ! grep "^$USER:" /etc/subgid >/dev/null 2>&3 || ! grep "^$USER:" /etc/subuid >/dev/null 2>&3; then
|
||
echo "$base_toolbox_command: /etc/subgid and /etc/subuid don't have entries for user $USER" >&2
|
||
echo "See the podman(1), subgid(5), subuid(5) and usermod(8) manuals for more" >&2
|
||
echo "information." >&2
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
if [ "$TOOLBOX_PATH" = "" ] 2>&3; then
|
||
TOOLBOX_PATH="$toolbox_command_path"
|
||
fi
|
||
fi
|
||
|
||
echo "$base_toolbox_command: TOOLBOX_PATH is $TOOLBOX_PATH" >&3
|
||
|
||
if [ "$1" = "" ]; then
|
||
echo "$base_toolbox_command: missing command" >&2
|
||
echo >&2
|
||
echo "These are some common commands:" >&2
|
||
echo "create Create a new toolbox container" >&2
|
||
echo "enter Enter an existing toolbox container" >&2
|
||
echo "list List all existing toolbox containers and images" >&2
|
||
echo >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
fi
|
||
|
||
op=$1
|
||
shift
|
||
|
||
if [ -f /run/.containerenv ] 2>&3; then
|
||
case $op in
|
||
create | enter | list | rm | rmi | run | help )
|
||
if ! [ -f /run/.toolboxenv ] 2>&3; then
|
||
echo "$base_toolbox_command: this is not a toolbox container" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# shellcheck disable=SC2119
|
||
forward_to_host
|
||
exit "$?"
|
||
;;
|
||
init-container )
|
||
init_container_home_link=false
|
||
init_container_media_link=false
|
||
init_container_mnt_link=false
|
||
init_container_monitor_host=false
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
-h | --help )
|
||
# shellcheck disable=SC2119
|
||
forward_to_host
|
||
exit
|
||
;;
|
||
--home )
|
||
shift
|
||
exit_if_missing_argument --home "$1"
|
||
init_container_home="$1"
|
||
;;
|
||
--home-link )
|
||
init_container_home_link=true
|
||
;;
|
||
--media-link )
|
||
init_container_media_link=true
|
||
;;
|
||
--mnt-link )
|
||
init_container_mnt_link=true
|
||
;;
|
||
--monitor-host )
|
||
init_container_monitor_host=true
|
||
;;
|
||
--shell )
|
||
shift
|
||
exit_if_missing_argument --shell "$1"
|
||
init_container_shell="$1"
|
||
;;
|
||
--uid )
|
||
shift
|
||
exit_if_missing_argument --uid "$1"
|
||
init_container_uid="$1"
|
||
;;
|
||
--user )
|
||
shift
|
||
exit_if_missing_argument --user "$1"
|
||
init_container_user="$1"
|
||
;;
|
||
* )
|
||
exit_if_unrecognized_option "$1"
|
||
esac
|
||
shift
|
||
done
|
||
init_container \
|
||
"$init_container_home" \
|
||
"$init_container_home_link" \
|
||
"$init_container_media_link" \
|
||
"$init_container_mnt_link" \
|
||
"$init_container_monitor_host" \
|
||
"$init_container_shell" \
|
||
"$init_container_uid" \
|
||
"$init_container_user"
|
||
exit "$?"
|
||
;;
|
||
reset )
|
||
echo "$base_toolbox_command: The 'reset' command cannot be used inside containers" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
;;
|
||
* )
|
||
echo "$base_toolbox_command: unrecognized command '$op'" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
if ! cgroups_version=$(get_cgroups_version); then
|
||
exit 1
|
||
fi
|
||
|
||
echo "$base_toolbox_command: running on a cgroups v$cgroups_version host" >&3
|
||
|
||
if [ "$op" != "reset" ] 2>&3; then
|
||
if ! migrate; then
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
case $op in
|
||
create )
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
--candidate-registry )
|
||
registry=$registry_candidate
|
||
;;
|
||
-c | --container )
|
||
shift
|
||
exit_if_missing_argument --container "$1"
|
||
arg=$1
|
||
if ! container_name_is_valid "$arg"; then
|
||
echo "$base_toolbox_command: invalid argument for '--container'" >&2
|
||
echo "Container names must match '$container_name_regexp'." >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
fi
|
||
toolbox_container="$arg"
|
||
;;
|
||
-h | --help )
|
||
help "$op"
|
||
exit
|
||
;;
|
||
-i | --image )
|
||
shift
|
||
exit_if_missing_argument --image "$1"
|
||
base_toolbox_image=$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
|
||
exit_if_extra_operand "$1"
|
||
if ! update_container_and_image_names; then
|
||
exit 1
|
||
fi
|
||
if ! create false; then
|
||
exit 1
|
||
fi
|
||
exit
|
||
;;
|
||
enter )
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
-c | --container )
|
||
shift
|
||
exit_if_missing_argument --container "$1"
|
||
toolbox_container=$1
|
||
;;
|
||
-h | --help )
|
||
help "$op"
|
||
exit
|
||
;;
|
||
-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
|
||
exit_if_extra_operand "$1"
|
||
if ! update_container_and_image_names; then
|
||
exit 1
|
||
fi
|
||
enter
|
||
exit
|
||
;;
|
||
help )
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
-h | --help )
|
||
help "$op"
|
||
exit
|
||
;;
|
||
* )
|
||
exit_if_unrecognized_option "$1"
|
||
esac
|
||
shift
|
||
done
|
||
help "$1"
|
||
exit
|
||
;;
|
||
init-container )
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
-h | --help )
|
||
help "$op"
|
||
exit
|
||
esac
|
||
shift
|
||
done
|
||
echo "$base_toolbox_command: The 'init-container' command can only be used inside containers" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
;;
|
||
list )
|
||
ls_add_empty_line=false
|
||
ls_images=false
|
||
ls_containers=false
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
-c | --containers )
|
||
ls_containers=true
|
||
;;
|
||
-h | --help )
|
||
help "$op"
|
||
exit
|
||
;;
|
||
-i | --images )
|
||
ls_images=true
|
||
;;
|
||
* )
|
||
exit_if_unrecognized_option "$1"
|
||
esac
|
||
shift
|
||
done
|
||
exit_if_extra_operand "$1"
|
||
|
||
if ! $ls_containers && ! $ls_images; then
|
||
ls_containers=true
|
||
ls_images=true
|
||
fi
|
||
|
||
if $ls_images; then
|
||
if ! images=$(list_images); then
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
if $ls_containers; then
|
||
if ! containers=$(list_containers); then
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
if $ls_images && [ "$images" != "" ] 2>&3; then
|
||
echo "$images"
|
||
ls_add_empty_line=true
|
||
fi
|
||
|
||
if $ls_containers && [ "$containers" != "" ] 2>&3; then
|
||
$ls_add_empty_line && echo ""
|
||
echo "$containers"
|
||
fi
|
||
|
||
exit
|
||
;;
|
||
reset )
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
-h | --help )
|
||
help "$op"
|
||
exit
|
||
;;
|
||
* )
|
||
exit_if_unrecognized_option "$1"
|
||
esac
|
||
shift
|
||
done
|
||
exit_if_extra_operand "$1"
|
||
|
||
reset
|
||
exit "$?"
|
||
;;
|
||
rm | rmi )
|
||
rm_all=false
|
||
rm_force=false
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
-a | --all )
|
||
rm_all=true
|
||
;;
|
||
-f | --force )
|
||
rm_force=true
|
||
;;
|
||
-h | --help )
|
||
help "$op"
|
||
exit
|
||
;;
|
||
* )
|
||
exit_if_unrecognized_option "$1"
|
||
esac
|
||
shift
|
||
done
|
||
|
||
rm_ids=""
|
||
if $rm_all; then
|
||
exit_if_extra_operand "$1"
|
||
else
|
||
exit_if_missing_argument "$op" "$1"
|
||
while [ "$1" != "" ]; do
|
||
rm_ids="$rm_ids $1"
|
||
shift
|
||
done
|
||
fi
|
||
|
||
rm_ids=$(echo "$rm_ids" | sed "s/^ \+//" 2>&3)
|
||
|
||
if [ "$op" = "rm" ]; then
|
||
remove_containers "$rm_ids" "$rm_all" "$rm_force"
|
||
else
|
||
remove_images "$rm_ids" "$rm_all" "$rm_force"
|
||
fi
|
||
exit
|
||
;;
|
||
run )
|
||
while has_prefix "$1" -; do
|
||
case $1 in
|
||
-c | --container )
|
||
shift
|
||
exit_if_missing_argument --container "$1"
|
||
toolbox_container=$1
|
||
;;
|
||
-h | --help )
|
||
help "$op"
|
||
exit
|
||
;;
|
||
-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
|
||
exit_if_missing_argument "$op" "$1"
|
||
if ! update_container_and_image_names; then
|
||
exit 1
|
||
fi
|
||
run false false true "$@"
|
||
exit
|
||
;;
|
||
* )
|
||
echo "$base_toolbox_command: unrecognized command '$op'" >&2
|
||
echo "Try '$base_toolbox_command --help' for more information." >&2
|
||
exit 1
|
||
esac
|