mirror of
https://github.com/89luca89/distrobox.git
synced 2026-08-19 01:14:49 -05:00
244 lines
6.3 KiB
Bash
Executable File
244 lines
6.3 KiB
Bash
Executable File
#!/bin/sh
|
|
# POSIX
|
|
# Expected env variables:
|
|
# HOME
|
|
# USER
|
|
# SHELL
|
|
|
|
trap '[ "$?" -ne 0 ] && printf "An error occurred\n"' EXIT
|
|
|
|
# Defaults
|
|
verbose=0
|
|
version="distrobox_version_placeholder"
|
|
|
|
# Print usage to stdout.
|
|
# Arguments:
|
|
# None
|
|
# Outputs:
|
|
# print usage with examples.
|
|
show_help() {
|
|
cat <<EOF
|
|
distrobox version: ${version}
|
|
|
|
Usage:
|
|
|
|
distrobox-init --name ${USER} --user $(id -ru) --group $(id -rg) --home ${HOME}
|
|
|
|
Options:
|
|
--name/-n: user name
|
|
--user/-u: uid of the user
|
|
--group/-g: gid of the user
|
|
--home/-d: path/to/home of the user
|
|
--help/-h: show this message
|
|
--verbose/-v: show more verbosity
|
|
--version/-V: show version
|
|
"
|
|
EOF
|
|
}
|
|
|
|
# Parse arguments
|
|
while :; do
|
|
case $1 in
|
|
-h | --help)
|
|
# Call a "show_help" function to display a synopsis, then exit.
|
|
show_help
|
|
exit 0
|
|
;;
|
|
-v | --verbose)
|
|
shift
|
|
verbose=1
|
|
;;
|
|
-V | --version)
|
|
printf "distrobox: %s\n" "${version}"
|
|
exit 0
|
|
;;
|
|
-n | --name)
|
|
if [ -n "$2" ]; then
|
|
container_user_name="$2"
|
|
s${container_user_name}hift
|
|
shift
|
|
fi
|
|
;;
|
|
-d | --home)
|
|
if [ -n "$2" ]; then
|
|
container_user_home="$2"
|
|
shift
|
|
shift
|
|
fi
|
|
;;
|
|
-u | --user)
|
|
if [ -n "$2" ]; then
|
|
container_user_uid="$2"
|
|
shift
|
|
shift
|
|
fi
|
|
;;
|
|
-g | --group)
|
|
if [ -n "$2" ]; then
|
|
container_user_gid="$2"
|
|
shift
|
|
shift
|
|
fi
|
|
;;
|
|
*) # Default case: If no more options then break out of the loop.
|
|
break ;;
|
|
esac
|
|
done
|
|
|
|
# Ensure the foundamental variables are set and not empty, we will not proceed if
|
|
# they are not all set.
|
|
[ -z "${container_user_name}" ] && printf >&2 "Invalid arguments, missing username\n" && exit 2
|
|
[ -z "${container_user_uid}" ] && printf >&2 "Invalid arguments, missing user uid\n" && exit 2
|
|
[ -z "${container_user_gid}" ] && printf >&2 "Invalid arguments, missing user gud\n" && exit 2
|
|
[ -z "${container_user_home}" ] && printf >&2 "Invalid argument, missing user home\n" && exit 2
|
|
|
|
# Also check we're running inside a container and not on the host
|
|
if [ ! -f /run/.containerenv ]; then
|
|
printf >&2 "You must run %s inside a container...\n" " $(basename "$0")"
|
|
exit 126
|
|
fi
|
|
|
|
set -o errexit
|
|
set -o nounset
|
|
# set verbosity
|
|
if [ "${verbose}" -ne 0 ]; then
|
|
set -o xtrace
|
|
fi
|
|
|
|
# Bind mount or error.
|
|
# Arguments:
|
|
# source_dir
|
|
# target_dir
|
|
# mount_flags -> optional
|
|
# Outputs:
|
|
# No output if all ok
|
|
# Error if not
|
|
mount_bind() (
|
|
source_dir="$1"
|
|
target_dir="$2"
|
|
mount_flags="$3"
|
|
mount_o=""
|
|
|
|
# if source dir doesn't exist, just exit normally
|
|
! [ -d "${source_dir}" ] && ! [ -f "${source_dir}" ] && return 0
|
|
|
|
# if the source_dir exists, then create the target_dir
|
|
if [ -d "${source_dir}" ]; then
|
|
# exit if not successful
|
|
if ! mkdir -p "${target_dir}"; then
|
|
printf >&2 "Cannot create mount target directory: %s\n" "${target_dir}"
|
|
return 1
|
|
fi
|
|
elif [ -f "${source_dir}" ]; then
|
|
# exit if not successful
|
|
if ! touch "${target_dir}"; then
|
|
printf >&2 "Cannot create mount target file: %s\n" "${target_dir}"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Add mountflags if needed
|
|
[ "${mount_flags}" = "" ] || mount_o="-o ${mount_flags}"
|
|
# bind mount source_dir to target_dir, return error if not successful
|
|
# shellcheck disable=SC2086
|
|
if ! mount --rbind ${mount_o} "${source_dir}" "${target_dir}"; then
|
|
printf >&2 "Failed to bind mount %s to %s\n" "${source_dir}" "${target_dir}"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
)
|
|
|
|
# Return sudoers groups.
|
|
# Arguments:
|
|
# None
|
|
# Outputs:
|
|
# return all sudoers groups, error if not present.
|
|
list_sudo_groups() (
|
|
group=""
|
|
if grep -q "sudo:" /etc/group; then
|
|
group="sudo"
|
|
elif grep -q "wheel:" /etc/group; then
|
|
group="wheel"
|
|
else
|
|
# No group for root, create one
|
|
groupadd wheel
|
|
group="wheel"
|
|
fi
|
|
|
|
printf "%s" "${group}"
|
|
return 0
|
|
)
|
|
|
|
# Extract shell name from the $SHELL environment variable
|
|
# If not present as package in the container, we want to install it.
|
|
shell_pkg="$(basename "${SHELL}")"
|
|
# Check if dependencies are met for the script to run.
|
|
if ! command -v mount || ! command -v passwd ||
|
|
! command -v sudo || ! command -v useradd ||
|
|
! command -v usermod || ! command -v "${shell_pkg}"; then
|
|
|
|
# check which pkg manager we have at disposal
|
|
# and make sure we have all the dependencies we need to function.
|
|
if command -v apk; then
|
|
apk add --no-cache sudo shadow procps util-linux "${shell_pkg}"
|
|
elif command -v apt-get; then
|
|
apt-get update && apt-get install -y --no-install-recommends sudo apt-utils passwd procps util-linux "${shell_pkg}"
|
|
elif command -v dnf; then
|
|
dnf install -y --setopt=install_weak_deps=False sudo shadow-utils passwd procps-ng util-linux "${shell_pkg}"
|
|
elif command -v pacman; then
|
|
pacman -Sy --noconfirm sudo procps-ng shadow util-linux "${shell_pkg}"
|
|
elif command -v yum; then
|
|
yum install -y --setopt=install_weak_deps=False sudo shadow-utils passwd procps util-linux "${shell_pkg}"
|
|
elif command -v zypper; then
|
|
zypper install -y --no-recommends sudo shadow procps util-linux "${shell_pkg}"
|
|
else
|
|
printf >&2 "FAILED TO INSTALL BASE DEPENDENCIES\n"
|
|
# Exit as command not found
|
|
exit 127
|
|
fi
|
|
|
|
fi
|
|
|
|
# We'll also bind mount in READ-ONLY useful directories from the host
|
|
HOST_MOUNTS_RO="/etc/machine-id /var/lib/flatpak /var/lib/systemd/coredump /var/log/journal"
|
|
for host_mount_ro in ${HOST_MOUNTS_RO}; do
|
|
mount_bind /run/host"${host_mount_ro}" "${host_mount_ro}" ro
|
|
done
|
|
|
|
# We'll also bind mount READ-WRITE useful mountpoints to pass external drives and libvirt from
|
|
# the host to the container
|
|
HOST_MOUNTS="/media /mnt /run/systemd/journal /run/libvirt /var/mnt /var/lib/libvirt"
|
|
for host_mount in ${HOST_MOUNTS}; do
|
|
mount_bind /run/host"${host_mount}" "${host_mount}" rw
|
|
done
|
|
|
|
# Do not check fqdn when doing sudo, it will not work anyways
|
|
printf "Defaults !fqdn\n" >>/etc/sudoers
|
|
# Ensure passwordless sudo is set up for user
|
|
printf "%s ALL = (root) NOPASSWD:ALL\n" "${container_user_name}" >>/etc/sudoers
|
|
|
|
# Let's add our user to the container
|
|
# if the user already exists, just add it to the sudoers groups
|
|
if ! grep -q "${container_user_name}" /etc/group; then
|
|
groupadd --force --gid "${container_user_uid}" "${container_user_name}"
|
|
fi
|
|
if ! useradd \
|
|
--home-dir "${container_user_home}" \
|
|
--no-create-home \
|
|
--shell /bin/bash \
|
|
--uid "${container_user_uid}" \
|
|
--gid "${container_user_gid}" \
|
|
--groups "$(list_sudo_groups)" \
|
|
"${container_user_name}"; then
|
|
|
|
usermod -aG "$(list_sudo_groups)" "${container_user_name}"
|
|
fi
|
|
# Delete password for root and user
|
|
passwd --delete "${container_user_name}"
|
|
passwd --delete root
|
|
|
|
printf "container_setup_done\n"
|
|
# Keepalive loop
|
|
sleep infinity
|