Files
distrobox/distrobox-init
T
2021-12-01 19:29:17 +01:00

249 lines
6.5 KiB
Bash
Executable File

#!/bin/sh
# POSIX
# Expected env variables:
# HOME
# USER
trap '[ "$?" -ne 0 ] && echo An error occurred' EXIT
# Defaults
verbose=0
# Print usage to stdout.
# Arguments:
# None
# Outputs:
# print usage with examples.
show_help() {
echo "USAGE:
distrobox-init --name $USER --user $(id -ru) --group $(id -rg) --home $HOME
Arguments:
--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
-v: show more verbosity
"
}
# Parse arguments
while :; do
case $1 in
-h | --help)
# Call a "show_help" function to display a synopsis, then exit.
show_help
exit
;;
-v)
shift
verbose=1
;;
-n | --name)
if [ -n "$2" ]; then
container_user_name="$2"
shift
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}" ] && echo "Invalid arguments, missing username" && exit 1
[ -z "${container_user_uid}" ] && echo "Invalid arguments, missing user uid" && exit 1
[ -z "${container_user_gid}" ] && echo "Invalid arguments, missing user gud" && exit 1
[ -z "${container_user_home}" ] && echo "Invalid argument, missing user home" && exit 1
# Also check we're running inside a container and not on the host
if [ ! -f /run/.containerenv ]; then
echo "You must run $(basename "$0") inside a container..."
exit 1
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
echo "Cannot create mount target directory: ${target_dir}"
return 1
fi
elif [ -f "${source_dir}" ]; then
# exit if not successful
if ! touch "${target_dir}"; then
echo "Cannot create mount target file: ${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
if ! mount --rbind ${mount_o} "${source_dir}" "${target_dir}"; then
echo "Failed to bind mount ${source_dir} to ${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
echo "${group}"
return 0
)
# We will use host's dynamic config for some functionalities, ensure they are
# symlinks to host's file inside the container.
#
# We do this before checking dependencies, as network access will be needed to
# install them if not found.
HOST_LINKS="/etc/host.conf /etc/hosts /etc/resolv.conf /etc/localtime /etc/timezone"
for link in $HOST_LINKS; do
rm -f "${link}"
ln -s /run/host"${link}" "${link}"
done
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
echo "FAILED TO INSTALL BASE DEPENDENCIES"
# Exit as command not found
exit 127
fi
fi
# We'll also bind mount in READ-ONLY useful folders from the host
HOST_MOUNTS_RO="/etc/machine-id /var/lib/flatpak /var/lib/systemd/coredump /var/log/journal"
for mount_ro in $HOST_MOUNTS_RO; do
mount_bind /run/host"${mount_ro}" "${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 mount in $HOST_MOUNTS; do
mount_bind /run/host"${mount}" "${mount}" rw
done
# If not present, mount host's theme folder in ~/.themes
if mkdir -p "${container_user_home}/.themes/"; then
if ! ln -s /run/host/usr/share/themes/* "${container_user_home}/.themes/"; then
echo "Error: cannot link container's themes to host home."
fi
fi
# If not present, mount host's icons folder in ~/.themes
if mkdir -p "${container_user_home}/.icons/"; then
if ! ln -s /run/host/usr/share/icons/* "${container_user_home}/.icons/"; then
echo "Error: cannot link container's icons to host home."
fi
fi
# Ensure passwordless sudo is set up for user
echo "Defaults !fqdn" >>/etc/sudoers
echo "${container_user_name} ALL = (root) NOPASSWD:ALL" >>/etc/sudoers
# Let's add our user to the container
# if the user already exists, just add it to the sudoers groups
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
echo "container_setup_done"
# Keepalive loop
sleep infinity