#!/bin/sh # SPDX-License-Identifier: GPL-3.0-only # # This file is part of the distrobox project: # https://github.com/89luca89/distrobox # # Copyright (C) 2021 distrobox contributors # # distrobox is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 3 # as published by the Free Software Foundation. # # distrobox is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with distrobox; if not, see . # POSIX # Optional env variables: # DBX_CONTAINER_MANAGER # DBX_CONTAINER_NAME # DBX_VERBOSE # DBX_SUDO_PROGRAM # Despite of running this script via SUDO/DOAS being not supported (the # script itself will call the appropriate tool when necessary), we still want # to allow people to run it as root, logged in in a shell, and create rootful # containers. # # SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS. if { [ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ] } && [ "$(id -ru)" -eq 0 ]; then printf >&2 "Running %s via SUDO/DOAS is not supported. Instead, please try running:\n" "$(basename "${0}")" printf >&2 " %s --root %s\n" "$(basename "${0}")" "$*" exit 1 fi # Ensure we have our env variables correctly set [ -z "${USER}" ] && USER="$(id -run)" [ -z "${HOME}" ] && HOME="$(getent passwd "${USER}" | cut -d':' -f6)" [ -z "${SHELL}" ] && SHELL="$(getent passwd "${USER}" | cut -d':' -f7)" trap cleanup TERM INT HUP name=$(mktemp -u distrobox-XXXXXXXXXX) container_command="" create_flags="" distrobox_path="$(dirname "${0}")" extra_flags="" # If the user runs this script as root in a login shell, set rootful=1. # There's no need for them to pass the --root flag option in such cases. [ "$(id -ru)" -eq 0 ] && rootful=1 || rootful=0 verbose=0 version="1.8.2.2" container_additional_packages="" container_init_hook=" " container_manager_additional_flags="" container_pre_init_hook=" " # Source configuration files, this is done in an hierarchy so local files have # priority over system defaults # leave priority to environment variables. # # On NixOS, for the distrobox derivation to pick up a static config file shipped # by the package maintainer the path must be relative to the script itself. self_dir="$(dirname "$(realpath "$0")")" nix_config_file="${self_dir}/../share/distrobox/distrobox.conf" config_files=" ${nix_config_file} /usr/share/distrobox/distrobox.conf /usr/share/defaults/distrobox/distrobox.conf /usr/etc/distrobox/distrobox.conf /usr/local/share/distrobox/distrobox.conf /etc/distrobox/distrobox.conf ${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf ${HOME}/.distroboxrc " for config_file in ${config_files}; do # Shellcheck will give error for sourcing a variable file as it cannot follow # it. We don't care so let's disable this linting for now. # shellcheck disable=SC1090 [ -e "${config_file}" ] && . "$(realpath "${config_file}")" done [ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}" # Fixup variable=[true|false], in case we find it in the config file(s) [ "${verbose}" = "true" ] && verbose=1 [ "${verbose}" = "false" ] && verbose=0 # show_help will print usage to stdout. # Arguments: # None # Expected global variables: # version: distrobox version # Expected env variables: # None # Outputs: # print usage with examples. show_help() { cat << EOF distrobox version: ${version} Usage: distrobox-ephemeral [--root/-r] Options: --root/-r: launch podman/docker/lilipod with root privileges. Note that if you need root this is the preferred way over "sudo distrobox" (note: if using a program other than 'sudo' for root privileges is necessary, specify it through the DBX_SUDO_PROGRAM env variable, or 'distrobox_sudo_program' config variable) --verbose/-v: show more verbosity --help/-h: show this message --/-e: end arguments execute the rest as command to execute at login default: default ${USER}'s shell --version/-V: show version See also: distrobox-ephemeral also inherits all the flags from distrobox-create: EOF } # Parse arguments while :; do case $1 in -h | --help) # Call a "show_help" function to display a synopsis, then exit. show_help "${distrobox_path}"/distrobox-create --help | tail -n +2 exit 0 ;; -r | --root) shift rootful=1 ;; -v | --verbose) verbose=1 shift ;; -V | --version) printf "distrobox: %s\n" "${version}" exit 0 ;; -e | --exec | --) shift container_command="-- $*" break ;; -n | --name) # Ignore --name on ephemeral if [ -n "$2" ]; then name="${2}" shift shift fi ;; -a | --additional-flags) if [ -n "$2" ]; then container_manager_additional_flags="${container_manager_additional_flags} ${2}" shift shift fi ;; -ap | --additional-packages) if [ -n "$2" ]; then container_additional_packages="${container_additional_packages} ${2}" shift shift fi ;; --init-hooks) if [ -n "$2" ]; then container_init_hook="$2" shift shift fi ;; --pre-init-hooks) if [ -n "$2" ]; then container_pre_init_hook="${2}" shift shift fi ;; *) # Default case: If no more options then break out of the loop. # If we have a flagless option and container_name is not specified # then let's accept argument as container_name if [ -n "$1" ]; then create_flags="${create_flags} $1" shift else break fi ;; esac done set -o nounset # set verbosity if [ "${verbose}" -ne 0 ]; then set -o xtrace extra_flags="${extra_flags} --verbose" fi # prepend sudo (or the specified sudo program) if we want our container manager to be rootful if [ "${rootful}" -ne 0 ]; then extra_flags="${extra_flags} --root" fi # generate_ephemeral_create_command will produce a distrobox-create command to execute. # Arguments: # None # Expected global variables: # distrobox_path = string distrobox path # name = string container name # extra_flags = string extra flags to inject # create_flags = string create extra flags to inject # Expected env variables: # None # Outputs: # prints the distrobox-create command handling special flags generate_ephemeral_create_command() { result_command="${distrobox_path}/distrobox-create" if [ -n "${container_manager_additional_flags}" ]; then result_command="${result_command} \ --additional-flags \"${container_manager_additional_flags}\"" fi if [ -n "${container_additional_packages}" ]; then result_command="${result_command} \ --additional-packages \"${container_additional_packages}\"" fi if [ -n "${container_init_hook}" ]; then result_command="${result_command} \ --init-hooks \"${container_init_hook}\"" fi if [ -n "${container_pre_init_hook}" ]; then result_command="${result_command} \ --pre-init-hooks \"${container_pre_init_hook}\"" fi result_command="${result_command} \ ${extra_flags} ${create_flags} --yes --name ${name}" # Return generated command. printf "%s" "${result_command}" } # cleanup will ensure we remove the ephemeral container # Arguments: # None # Expected global variables: # name: string the name of the container # extra_flags: string extra flags to append to the distrobox command # distrobox_path: string path to the distrobox script # Expected env variables: # None # Outputs: # None cleanup() { trap - TERM INT HUP # shellcheck disable=SC2086 "${distrobox_path}"/distrobox-rm ${extra_flags} --force "${name}" --yes } cmd="$(generate_ephemeral_create_command)" # shellcheck disable=SC2086 eval ${cmd} # shellcheck disable=SC2086 "${distrobox_path}"/distrobox-enter ${extra_flags} "${name}" ${container_command} exit_code="$?" cleanup exit "${exit_code}"