toolbox/toolbox
Debarshi Ray d63b0a9c0f Expose a few more host locations inside the container under /run/host
This is meant to alleviate some of the pain of not being able to modify
the list of bind mounts once a toolbox container has been created. For
some cases, especially where read-only access is enough, one can get
by with setting up symbolic links inside the toolbox container.

Based on an idea from Colin Walters.

https://github.com/debarshiray/toolbox/pull/264
2019-09-18 17:11:39 +02:00

2141 lines
66 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
#
# Copyright © 2018 2019 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.
#
exec 3>/dev/null
arguments=""
assume_yes=false
base_toolbox_command=$(basename "$0" 2>&3)
base_toolbox_image=""
# 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 \
VTE_VERSION \
WAYLAND_DISPLAY \
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=""
prefix_sudo=""
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
LBC='\033[1;34m' # Light Blue 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 $?
)
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 /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 container $container" >&3
if ! $prefix_sudo podman 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 /etc/profile.d/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
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=$($prefix_sudo podman 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_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
. /etc/os-release
echo "$ID"
)
get_host_version_id()
(
# shellcheck disable=SC1091
. /etc/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 ! $prefix_sudo podman 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"
$prefix_sudo podman 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=$($prefix_sudo podman 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=$($prefix_sudo podman 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
)
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 $prefix_sudo podman 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 $prefix_sudo podman 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 $prefix_sudo podman 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
$prefix_sudo podman 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
)
create()
(
enter_command_skip="$1"
dbus_system_bus_address="unix:path=/var/run/dbus/system_bus_socket"
dns_none=""
home_link=""
flatpak_system_directory_bind=""
kcm_socket=""
kcm_socket_bind=""
libvirt_system_directory_bind=""
monitor_host=""
no_hosts=""
run_media_path_bind=""
toolbox_profile_bind=""
ulimit_host=""
# 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)
if [ -d /var/lib/flatpak ] 2>&3; then
flatpak_system_directory_bind="--volume /var/lib/flatpak:/var/lib/flatpak:ro"
fi
# 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
if [ -d /run/libvirt ] 2>&3; then
libvirt_system_directory_bind="--volume /run/libvirt:/run/libvirt"
fi
echo "$base_toolbox_command: checking if 'podman create' supports --dns=none and --no-hosts" >&3
if $prefix_sudo podman create --help 2>&3 | grep "hosts" >/dev/null 2>&3; then
echo "$base_toolbox_command: 'podman create' supports --dns=none and --no-hosts" >&3
dns_none="--dns none"
no_hosts="--no-hosts"
monitor_host="--monitor-host"
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=$($prefix_sudo podman 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 $prefix_sudo podman 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 ! group_for_sudo=$(get_group_for_sudo); then
echo "$base_toolbox_command: failed to create container $toolbox_container: group for sudo not found" >&2
return 1
fi
toolbox_path_bind="--volume $TOOLBOX_PATH:/usr/bin/toolbox:ro"
toolbox_path_set="--env TOOLBOX_PATH=$TOOLBOX_PATH"
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"
fi
if [ -d /run/media ] 2>&3; then
run_media_path_bind="--volume /run/media:/run/media:rslave"
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
$prefix_sudo podman create \
$dns_none \
$toolbox_path_set \
--group-add "$group_for_sudo" \
--hostname toolbox \
--ipc host \
--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 \
$flatpak_system_directory_bind \
$kcm_socket_bind \
$libvirt_system_directory_bind \
$run_media_path_bind \
$toolbox_path_bind \
$toolbox_profile_bind \
--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 /media:/media:rslave \
--volume /mnt:/mnt:rslave \
--volume /run:/run/host/run:rslave \
--volume /tmp:/run/host/tmp:rslave \
--volume /usr:/run/host/usr:rslave \
--volume /var:/run/host/var:rslave \
"$base_toolbox_image_full" \
toolbox --verbose init-container \
--home "$HOME" \
$home_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()
{
run true true false "$SHELL" -l
}
init_container()
{
init_container_home="$1"
init_container_home_link="$2"
init_container_monitor_host="$3"
init_container_shell="$4"
init_container_uid="$5"
init_container_user="$6"
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 \
&& unlink 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 && unlink 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 \
&& unlink 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
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 \
&& unlink 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 ! 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/debarshiray/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: 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 ! $prefix_sudo podman container exists "$toolbox_container" 2>&3; then
echo "$base_toolbox_command: container $toolbox_container not found" >&3
if $prefix_sudo podman 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 $prefix_sudo podman 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 ! $prefix_sudo podman start "$toolbox_container" >/dev/null 2>&3; then
echo "$base_toolbox_command: failed to start container $toolbox_container" >&2
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 ! $prefix_sudo podman start "$toolbox_container" >/dev/null 2>&3; then
echo "$base_toolbox_command: failed to start container $toolbox_container" >&2
exit 1
fi
if ! copy_etc_profile_d_toolbox_to_container "$toolbox_container"; then
exit 1
fi
fi
if ! $prefix_sudo podman 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 ! $prefix_sudo podman 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
$prefix_sudo podman 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\\"
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=$($prefix_sudo podman 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=$($prefix_sudo podman 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
# shellcheck disable=SC2059
printf "${LBC}Images created by toolbox${NC}\n"
echo "$output"
fi
return 0
)
containers_get_details()
(
containers="$1"
if ! echo "$containers" | while read -r container; do
[ "$container" = "" ] 2>&3 && continue
if ! $prefix_sudo podman 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
# shellcheck disable=SC2059
printf "${LBC}Containers created by toolbox${NC}\n"
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=$($prefix_sudo podman 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
echo "$base_toolbox_command: checking if 'podman system migrate' exists" >&3
if ! $prefix_sudo podman system --help 2>&3 | grep "Migrate containers" >/dev/null 2>&3; then
echo "$base_toolbox_command: migration not needed: 'podman system migrate' doesn't exist" >&3
return 0
fi
if ! version=$($prefix_sudo podman version --format "{{.Version}}" 2>&3); then
echo "$base_toolbox_command: unable to migrate containers: Podman version couldn't be read" >&2
return 1
fi
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: $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: $version is old" >&3
return 0
fi
fi
if ! $prefix_sudo podman 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=$($prefix_sudo podman 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=$($prefix_sudo podman 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 ! $prefix_sudo podman 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=$($prefix_sudo podman 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 ! $prefix_sudo podman 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=$($prefix_sudo podman 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=$($prefix_sudo podman 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 ! $prefix_sudo podman 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=$($prefix_sudo podman 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 ! $prefix_sudo podman 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"
)
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 "$@")
host_id=$(get_host_id)
if [ "$host_id" = "fedora" ] 2>&3; then
release_default=$(get_host_version_id)
else
release_default="29"
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
;;
--sudo )
prefix_sudo="sudo"
;;
-v | --verbose )
exec 3>&2
verbose=true
;;
* )
exit_if_unrecognized_option "$1"
esac
shift
done
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
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
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_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
;;
--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_monitor_host" \
"$init_container_shell" \
"$init_container_uid" \
"$init_container_user"
exit "$?"
;;
* )
echo "$base_toolbox_command: unrecognized command '$op'" >&2
echo "Try '$base_toolbox_command --help' for more information." >&2
exit 1
;;
esac
fi
if ! migrate; then
exit 1
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_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"
fi
if $ls_containers && [ "$containers" != "" ] 2>&3; then
echo "$containers"
fi
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
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