Files
distrobox/distrobox-create
T

216 lines
6.3 KiB
Bash
Raw Normal View History

2021-11-18 16:53:42 +01:00
#!/bin/sh
# POSIX
2021-11-22 13:21:33 +01:00
# Expected env variables:
# HOME
# USER
2021-11-18 16:53:42 +01:00
trap '[ "$?" -ne 0 ] && printf "An error occurred\n"' EXIT
2021-11-22 03:13:52 +01:00
# We depend on podman let's be sure we have it
if ! command -v podman >/dev/null; then
printf >&2 "Missing dependency: podman\n"
2021-11-22 03:13:52 +01:00
exit 127
fi
# Defaults
container_image="registry.fedoraproject.org/fedora-toolbox:35"
container_name="fedora-toolbox-35"
container_user_gid="$(id -rg)"
container_user_home="${HOME:-"/"}"
2021-11-18 16:53:42 +01:00
container_user_name="${USER}"
container_user_uid="$(id -ru)"
2021-12-01 19:29:17 +01:00
distrobox_entrypoint_path="$(command -v distrobox-init)"
distrobox_export_path="$(command -v distrobox-export)"
2021-11-18 16:53:42 +01:00
verbose=0
2021-12-08 16:31:36 +01:00
version="distrobox_version_placeholder"
2021-11-18 16:53:42 +01:00
# Print usage to stdout.
# Arguments:
# None
# Outputs:
# print usage with examples.
show_help() {
cat <<EOF
distrobox version: ${version}
2021-12-08 17:15:30 +01:00
2021-12-10 09:28:16 +01:00
distrobox-create takes care of creating the container with input name and image.
Created container will be tightly integrated with the host, allowing to share
2021-12-10 19:44:30 +01:00
the HOME directory of the user, external storage, external usb devices and
2021-12-10 09:28:16 +01:00
graphical apps (X11/Wayland) and audio.
Usage:
2021-12-01 19:29:17 +01:00
distrobox-create --image registry.fedoraproject.org/fedora-toolbox:35 --name fedora-toolbox-35
2021-11-18 16:53:42 +01:00
Options:
--image/-i: image to use for the container default: registry.fedoraproject.org/fedora-toolbox:35
--name/-n: name for the distrobox default: fedora-toolbox-35
--help/-h: show this message
--verbose/-v: show more verbosity
--version/-V: show version
EOF
2021-11-18 16:53:42 +01:00
}
# Parse arguments
while :; do
case $1 in
-h | --help)
# Call a "show_help" function to display a synopsis, then exit.
show_help
2021-12-09 18:28:39 +01:00
exit 0
2021-11-18 16:53:42 +01:00
;;
2021-12-02 19:54:01 +01:00
-v | --verbose)
2021-11-18 16:53:42 +01:00
verbose=1
shift
;;
2021-12-08 16:31:36 +01:00
-V | --version)
printf "distrobox: %s\n" "${version}"
2021-12-09 18:28:39 +01:00
exit 0
2021-12-08 16:31:36 +01:00
;;
2021-11-18 16:53:42 +01:00
-i | --image)
if [ -n "$2" ]; then
container_image="$2"
shift
shift
fi
;;
-n | --name)
if [ -n "$2" ]; then
container_name="$2"
shift
shift
fi
;;
--) # End of all options.
shift
break
;;
*) # Default case: If no more options then break out of the loop.
break ;;
esac
done
set -o errexit
set -o nounset
# set verbosity
2021-11-21 15:05:32 +01:00
if [ "${verbose}" -ne 0 ]; then
2021-11-18 16:53:42 +01:00
set -o xtrace
fi
# Generate Podman command to execute.
# Arguments:
# None
# Outputs:
2021-12-01 19:29:17 +01:00
# prints the podman command to create the distrobox container
2021-11-18 16:53:42 +01:00
generate_command() {
# Set the container hostname the same as the container name.
# use the host's namespace for ipc, network, pid, ulimit
result_command="podman create"
2021-12-10 09:28:16 +01:00
# add podman verbose if -v is specified
2021-12-02 19:54:01 +01:00
if [ "${verbose}" -ne 0 ]; then
result_command="${result_command} --log-level debug"
2021-12-02 19:54:01 +01:00
fi
2021-12-10 14:20:55 +01:00
result_command="${result_command}
--env=\"XDG_RUNTIME_DIR=/run/user/${container_user_uid}\"
2021-11-18 16:53:42 +01:00
--hostname ${container_name}
--ipc host"
# mount useful stuff inside the container.
# we also mount host's root filesystem to /run/host, to be
# able to syphon dynamic configurations from the host
#
2021-12-01 19:29:17 +01:00
# also mount the distrobox-init utility as the container entrypoint
result_command="${result_command} --name ${container_name}
--env=\"SHELL=${SHELL}\"
2021-11-18 16:53:42 +01:00
--network host
--pid host
--privileged
--security-opt label=disable
--ulimit host
--user root:root
--userns keep-id
2021-12-01 19:29:17 +01:00
--volume ${distrobox_entrypoint_path}:/usr/bin/entrypoint:ro"
2021-12-02 19:54:01 +01:00
2021-12-01 19:29:17 +01:00
# let's check if we can include distrobox-export or not
if [ -n "${distrobox_export_path}" ]; then
result_command="${result_command} --volume ${distrobox_export_path}:/usr/bin/distrobox-export:ro"
2021-11-22 03:13:52 +01:00
fi
2021-12-02 19:54:01 +01:00
2021-12-11 00:46:57 +01:00
result_command="${result_command} --volume ${container_user_home}:${container_user_home}:rslave"
result_command="${result_command} --volume /dev:/dev:rslave"
2021-12-02 19:54:01 +01:00
# useful mounts from host to the container using /run/host as a base
host_directories="/ /etc /media /mnt /run /tmp /usr /var"
2021-12-09 02:07:39 +01:00
for host_directory in ${host_directories}; do
# Check if the directory exists first
if [ -d "${host_directory}" ]; then
result_command="${result_command} --volume ${host_directory}:/run/host${host_directory}:rslave"
2021-12-02 19:54:01 +01:00
fi
done
2021-12-10 09:28:16 +01:00
# those are dynamic configs needed by the container to function properly
# and integrate with the host
2021-12-10 09:28:16 +01:00
host_links="/etc/host.conf /etc/hosts /etc/resolv.conf /etc/localtime"
for host_link in ${host_links}; do
# Check if the file exists first
if [ -f "${host_link}" ]; then
# Use realpath to not have multi symlink mess
result_command="${result_command} --volume $(realpath "${host_link}"):${host_link}:ro"
fi
done
2021-12-02 19:54:01 +01:00
2021-11-18 16:53:42 +01:00
# mount also the XDG_RUNTIME_DIR to ensure functionality of the apps
2021-12-11 00:46:57 +01:00
if [ -d "/run/user/${container_user_uid}" ]; then
result_command="${result_command} --volume /run/user/${container_user_uid}:/run/user/${container_user_uid}"
2021-11-18 16:53:42 +01:00
fi
2021-12-11 00:09:10 +01:00
result_command="${result_command} --mount type=devpts,destination=/dev/pts"
2021-12-02 19:54:01 +01:00
2021-11-18 16:53:42 +01:00
# find all the user's socket and mount them inside the container
# this will allow for continuity of functionality between host and container
# for example using `podman --remote` to control the host's podman from inside
# the container
2021-12-09 19:20:46 +01:00
host_sockets="$(find /run -iname "*socket" ! -path "/run/user/*" 2>/dev/null || :)"
for socket in ${host_sockets}; do
result_command="${result_command} --volume ${socket}:${socket}"
2021-11-18 16:53:42 +01:00
done
2021-12-02 19:54:01 +01:00
2021-12-01 19:29:17 +01:00
# now execute the entrypoint, refer to `distrobox-init -h` for instructions
result_command="${result_command} ${container_image}
2021-12-11 00:46:57 +01:00
/usr/bin/entrypoint -v --name ${container_user_name}
--user ${container_user_uid}
--group ${container_user_gid}
--home ${container_user_home}"
printf "%s" "${result_command}"
2021-11-18 16:53:42 +01:00
}
2021-12-02 19:54:01 +01:00
# check that we have a complete distrobox installation or
# entrypoint and export will not work.
[ -z "${distrobox_entrypoint_path}" ] && printf >&2 "Error: no distrobox-init found in %s\n" "${PATH}" && exit 127
2021-12-02 19:54:01 +01:00
2021-11-18 16:53:42 +01:00
# First, check if the image exists in the host
if [ -z "$(podman images -q "${container_image}")" ]; then
printf >&2 "Image not found.\n"
2021-12-09 18:28:39 +01:00
printf >&2 "Do you want to pull the image now?[y/n] "
read -r response
# Accept only y,Y,Yes,yes,n,N,No,no.
case "${response}" in
2021-12-09 18:28:39 +01:00
y | Y | yes | Yes)
# Pull the image
podman pull "${container_image}"
;;
2021-12-09 18:28:39 +01:00
n | N | no | No)
printf >&2 "next time, run this command first:\n"
printf >&2 " podman pull %s\n" "${container_image}"
2021-12-09 18:28:39 +01:00
exit 0
;;
*) # Default case: If no more options then break out of the loop.
printf >&2 "The available choices are: y,Y,Yes,yes,n,N,No,no. Exiting.\n"
2021-12-09 18:28:39 +01:00
exit 1
;;
esac
2021-11-18 16:53:42 +01:00
fi
# Generate the command and execute
2021-12-10 09:28:16 +01:00
cmd="$(generate_command)"
# shellcheck disable=SC2086
eval ${cmd}