2021-11-18 16:53:42 +01:00
#!/bin/sh
2021-12-31 01:02:46 +01:00
# SPDX-License-Identifier: GPL-3.0-only
#
2022-02-11 18:31:13 +01:00
# This file is part of the distrobox project:
# https://github.com/89luca89/distrobox
2021-12-31 01:02:46 +01:00
#
# 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 <http://www.gnu.org/licenses/>.
2021-11-18 16:53:42 +01:00
# POSIX
2021-11-22 13:21:33 +01:00
# Expected env variables:
# HOME
# USER
2021-12-29 22:33:36 +00:00
# Optional env variables:
2022-05-26 00:15:03 +08:00
# DBX_CONTAINER_ALWAYS_PULL
2022-03-20 15:08:30 +01:00
# DBX_CONTAINER_CUSTOM_HOME
2022-10-19 19:16:26 +02:00
# DBX_CONTAINER_HOME_PREFIX
2021-12-31 17:08:29 +01:00
# DBX_CONTAINER_IMAGE
2022-03-20 15:08:30 +01:00
# DBX_CONTAINER_MANAGER
2021-12-31 17:08:29 +01:00
# DBX_CONTAINER_NAME
2024-02-18 18:08:36 +01:00
# DBX_CONTAINER_HOSTNAME
2022-12-19 15:16:24 +01:00
# DBX_CONTAINER_GENERATE_ENTRY
2021-12-31 17:08:29 +01:00
# DBX_NON_INTERACTIVE
2024-05-01 04:58:31 -05:00
# DBX_VERBOSE
2022-07-10 17:24:50 -03:00
# DBX_SUDO_PROGRAM
2025-10-23 21:28:11 +11:00
# DBX_USERNS_NOLIMIT
2021-11-18 16:53:42 +01:00
2023-02-10 13:07:28 -03:00
# 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.
2024-05-02 09:07:01 +02:00
if {
[ -n " ${ SUDO_USER } " ] || [ -n " ${ DOAS_USER } " ]
} && [ " $( id -ru) " -eq 0 ] ; then
2023-02-10 13:07:28 -03:00
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 } " ) " " $* "
2022-02-21 10:44:12 +01:00
exit 1
fi
2024-05-09 16:11:51 +02:00
# 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) "
2021-11-22 03:13:52 +01:00
# Defaults
2023-06-14 08:45:31 +02:00
container_additional_packages = ""
2023-08-03 15:01:32 +02:00
container_additional_volumes = ""
2022-05-26 00:15:03 +08:00
container_always_pull = 0
2021-12-22 12:50:40 +01:00
container_clone = ""
2023-06-14 08:45:31 +02:00
container_generate_entry = 1
2022-10-19 19:16:26 +02:00
container_home_prefix = ""
2022-03-20 15:08:30 +01:00
container_image = ""
2024-06-20 11:54:32 +02:00
container_image_default = "registry.fedoraproject.org/fedora-toolbox:latest"
2022-01-27 22:51:33 +01:00
container_init_hook = ""
2022-03-20 15:08:30 +01:00
container_manager = "autodetect"
2022-01-22 12:38:53 +01:00
container_manager_additional_flags = ""
2025-01-19 16:06:13 +01:00
container_platform = ""
2022-03-20 15:08:30 +01:00
container_name = ""
2023-06-14 08:45:31 +02:00
container_name_default = "my-distrobox"
2024-02-18 18:08:36 +01:00
container_hostname = ""
2022-05-15 11:14:24 -07:00
container_pre_init_hook = ""
2021-12-31 00:05:09 +01:00
container_user_custom_home = ""
2021-11-22 03:13:52 +01:00
container_user_gid = " $( id -rg) "
2021-12-10 23:46:29 +01:00
container_user_home = " ${ HOME :- "/" } "
2021-11-18 16:53:42 +01:00
container_user_name = " ${ USER } "
container_user_uid = " $( id -ru) "
2022-01-28 21:46:38 +01:00
dryrun = 0
2023-06-14 08:45:31 +02:00
init = 0
non_interactive = 0
2023-04-06 16:52:32 -04:00
nvidia = 0
2023-08-07 01:37:40 +02:00
nopasswd = 0
2023-04-06 16:52:32 -04:00
unshare_ipc = 0
2024-02-16 00:02:33 +01:00
unshare_groups = 0
2023-04-06 16:52:32 -04:00
unshare_netns = 0
2023-08-26 14:20:56 +02:00
unshare_process = 0
unshare_devsys = 0
2024-02-01 22:55:03 +01:00
2022-09-16 10:39:10 +01:00
# Use cd + dirname + pwd so that we do not have relative paths in mount points
# We're not using "realpath" here so that symlinks are not resolved this way
# "realpath" would break situations like Nix or similar symlink based package
# management.
distrobox_entrypoint_path = " $( cd " $( dirname " ${ 0 } " ) " && pwd ) /distrobox-init"
distrobox_export_path = " $( cd " $( dirname " ${ 0 } " ) " && pwd ) /distrobox-export"
2023-04-06 22:20:00 +02:00
distrobox_genentry_path = " $( cd " $( dirname " ${ 0 } " ) " && pwd ) /distrobox-generate-entry"
2023-06-14 08:45:31 +02:00
distrobox_hostexec_path = " $( cd " $( dirname " ${ 0 } " ) " && pwd ) /distrobox-host-exec"
2023-04-06 22:20:00 +02:00
# In case some of the scripts are not in the same path as create, let's search
2022-09-16 10:39:10 +01:00
# in PATH for them.
[ ! -e " ${ distrobox_entrypoint_path } " ] && distrobox_entrypoint_path = " $( command -v distrobox-init) "
[ ! -e " ${ distrobox_export_path } " ] && distrobox_export_path = " $( command -v distrobox-export) "
2023-04-06 22:20:00 +02:00
[ ! -e " ${ distrobox_genentry_path } " ] && distrobox_genentry_path = " $( command -v distrobox-generate-entry) "
2023-06-14 08:45:31 +02:00
[ ! -e " ${ distrobox_hostexec_path } " ] && distrobox_hostexec_path = " $( command -v distrobox-host-exec) "
2023-02-10 13:07:28 -03:00
# 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.
[ " ${ container_user_uid } " -eq 0 ] && rootful = 1 || rootful = 0
2025-10-23 21:28:11 +11:00
userns_nolimit = 0
2021-11-18 16:53:42 +01:00
verbose = 0
2026-04-27 14:25:31 +02:00
version = "1.8.2.5"
2021-11-18 16:53:42 +01:00
2024-02-01 22:22:45 +01:00
app_cache_dir = ${ XDG_CACHE_HOME :- " ${ HOME } /.cache" } /distrobox
2022-03-20 15:08:30 +01:00
# Source configuration files, this is done in an hierarchy so local files have
# priority over system defaults
# leave priority to environment variables.
2024-02-01 22:55:03 +01:00
#
# 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 " ) " ) "
2024-02-02 15:30:10 +01:00
nix_config_file = " ${ self_dir } /../share/distrobox/distrobox.conf"
2024-02-01 22:55:03 +01:00
2022-03-20 15:08:30 +01:00
config_files = "
2024-02-01 23:07:18 +01:00
${ nix_config_file }
2022-03-20 15:08:30 +01:00
/usr/share/distrobox/distrobox.conf
2023-06-30 19:00:24 +02:00
/usr/share/defaults/distrobox/distrobox.conf
2022-07-30 10:18:22 +02:00
/usr/etc/distrobox/distrobox.conf
2023-06-30 19:00:24 +02:00
/usr/local/share/distrobox/distrobox.conf
2022-03-20 15:08:30 +01:00
/etc/distrobox/distrobox.conf
2022-08-17 16:28:36 +02:00
${ XDG_CONFIG_HOME :- " ${ HOME } /.config" } /distrobox/distrobox.conf
2022-03-20 15:08:30 +01:00
${ HOME } /.distroboxrc
"
for config_file in ${ config_files } ; do
2022-07-16 18:35:04 +02:00
# 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.
2022-03-20 15:08:30 +01:00
# shellcheck disable=SC1090
2024-02-03 17:14:31 +01:00
[ -e " ${ config_file } " ] && . " $( realpath " ${ config_file } " ) "
2022-03-20 15:08:30 +01:00
done
2023-02-10 13:07:28 -03:00
# If we're running this script as root -- as in logged in in the shell as root
# user, and not via SUDO/DOAS --, we don't need to set distrobox_sudo_program
# as it's meaningless for this use case.
if [ " ${ container_user_uid } " -ne 0 ] ; then
# If the DBX_SUDO_PROGRAM/distrobox_sudo_program variable was set by the
2023-03-19 15:53:56 +08:00
# user, use its value instead of "sudo". But only if not running the script
2023-02-10 13:07:28 -03:00
# as root (UID 0).
distrobox_sudo_program = ${ DBX_SUDO_PROGRAM :- ${ distrobox_sudo_program :- "sudo" }}
fi
2022-06-11 17:38:59 +02:00
2022-05-26 00:15:03 +08:00
[ -n " ${ DBX_CONTAINER_ALWAYS_PULL } " ] && container_always_pull = " ${ DBX_CONTAINER_ALWAYS_PULL } "
2022-03-20 15:08:30 +01:00
[ -n " ${ DBX_CONTAINER_CUSTOM_HOME } " ] && container_user_custom_home = " ${ DBX_CONTAINER_CUSTOM_HOME } "
2022-10-19 19:16:26 +02:00
[ -n " ${ DBX_CONTAINER_HOME_PREFIX } " ] && container_home_prefix = " ${ DBX_CONTAINER_HOME_PREFIX } "
2022-03-20 15:08:30 +01:00
[ -n " ${ DBX_CONTAINER_IMAGE } " ] && container_image = " ${ DBX_CONTAINER_IMAGE } "
[ -n " ${ DBX_CONTAINER_MANAGER } " ] && container_manager = " ${ DBX_CONTAINER_MANAGER } "
[ -n " ${ DBX_CONTAINER_NAME } " ] && container_name = " ${ DBX_CONTAINER_NAME } "
2024-02-18 18:08:36 +01:00
[ -n " ${ DBX_CONTAINER_HOSTNAME } " ] && container_hostname = " ${ DBX_CONTAINER_HOSTNAME } "
2023-09-18 20:02:50 +02:00
[ -n " ${ DBX_CONTAINER_GENERATE_ENTRY } " ] && container_generate_entry = " ${ DBX_CONTAINER_GENERATE_ENTRY } "
2024-05-01 04:58:31 -05:00
[ -n " ${ DBX_NON_INTERACTIVE } " ] && non_interactive = " ${ DBX_NON_INTERACTIVE } "
2024-02-19 18:20:15 +01:00
[ -n " ${ DBX_VERBOSE } " ] && verbose = " ${ DBX_VERBOSE } "
2025-10-23 21:28:11 +11:00
[ -n " ${ DBX_USERNS_NOLIMIT } " ] && userns_nolimit = " ${ DBX_USERNS_NOLIMIT } "
2024-02-19 18:20:15 +01:00
# Fixup variable=[true|false], in case we find it in the config file(s)
[ " ${ non_interactive } " = "true" ] && non_interactive = 1
[ " ${ non_interactive } " = "false" ] && non_interactive = 0
[ " ${ verbose } " = "true" ] && verbose = 1
[ " ${ verbose } " = "false" ] && verbose = 0
2025-10-23 21:28:11 +11:00
[ " ${ userns_nolimit } " = "true" ] && userns_nolimit = 1
[ " ${ userns_nolimit } " = "false" ] && userns_nolimit = 0
2022-03-20 15:08:30 +01:00
2024-05-01 18:09:55 +02:00
# show_help will print usage to stdout.
2021-11-18 16:53:42 +01:00
# Arguments:
# None
2024-05-01 18:09:55 +02:00
# Expected global variables:
# version: string distrobox version
# container_image_default: string default container image to use
# container_name_default: string default container name to use
# Expected env variables:
# None
2021-11-18 16:53:42 +01:00
# Outputs:
# print usage with examples.
2024-05-02 09:07:01 +02:00
show_help()
{
2022-03-30 11:05:21 +02:00
cat << EOF
2021-12-10 09:08:06 +01:00
distrobox version: ${version}
2021-12-08 17:15:30 +01:00
2021-12-10 09:08:06 +01:00
Usage:
2021-12-13 17:19:13 +01:00
2022-01-27 22:51:33 +01:00
distrobox create --image alpine:latest --name test --init-hooks "touch /var/tmp/test1 && touch /var/tmp/test2"
2024-02-01 16:34:23 -05:00
distrobox create --image fedora:39 --name test --additional-flags "--env MY_VAR-value"
2024-02-03 16:57:03 +01:00
distrobox create --image fedora:39 --name test --volume /opt/my-dir:/usr/local/my-dir:rw --additional-flags "--pids-limit 100"
2022-05-15 11:14:24 -07:00
distrobox create -i docker.io/almalinux/8-init --init --name test --pre-init-hooks "dnf config-manager --enable powertools && dnf -y install epel-release"
2024-02-01 16:34:23 -05:00
distrobox create --clone fedora-39 --name fedora-39-copy
2022-05-25 18:24:38 +02:00
distrobox create --image alpine my-alpine-container
2024-06-20 11:54:32 +02:00
distrobox create --image registry.fedoraproject.org/fedora-toolbox:latest --name fedora-toolbox-latest
2022-05-25 18:24:38 +02:00
distrobox create --pull --image centos:stream9 --home ~/distrobox/centos9
2023-03-09 20:23:29 +01:00
distrobox create --image alpine:latest --name test2 --additional-packages "git tmux vim"
2023-03-26 16:00:21 +02:00
distrobox create --image ubuntu:22.04 --name ubuntu-nvidia --nvidia
2022-01-22 12:38:53 +01:00
2022-01-01 11:13:29 +01:00
DBX_NON_INTERACTIVE=1 DBX_CONTAINER_NAME=test-alpine DBX_CONTAINER_IMAGE=alpine distrobox-create
2021-12-29 22:33:36 +00:00
2021-12-10 09:08:06 +01:00
Options:
2021-12-13 17:19:13 +01:00
2022-12-19 12:59:30 +01:00
--image/-i: image to use for the container default: ${container_image_default}
2024-02-18 18:08:36 +01:00
--name/-n: name for the distrobox default: ${container_name_default}
2024-05-01 12:38:40 +02:00
--hostname: hostname for the distrobox default: $(uname -n)
2022-05-26 00:15:03 +08:00
--pull/-p: pull the image even if it exists locally (implies --yes)
2022-05-01 08:03:03 +02:00
--yes/-Y: non-interactive, pull images without asking
2025-09-28 10:45:40 +02:00
--root/-r: launch podman/docker/lilipod with root privileges. This is the only supported way to run with root
2025-09-28 11:25:15 +02:00
privileges. Do not use "sudo distrobox". If you need to specify a different program (e.g. 'doas') for root privileges,
2025-09-28 10:45:40 +02:00
use the DBX_SUDO_PROGRAM environment variable or the 'distrobox_sudo_program' config variable.
2021-12-22 12:50:40 +01:00
--clone/-c: name of the distrobox container to use as base for a new container
this will be useful to either rename an existing distrobox or have multiple copies
of the same environment.
2022-09-12 08:49:30 +02:00
--home/-H: select a custom HOME directory for the container. Useful to avoid host's home littering with temp files.
--volume: additional volumes to add to the container
2022-01-22 12:38:53 +01:00
--additional-flags/-a: additional flags to pass to the container manager command
2023-03-09 20:19:05 +01:00
--additional-packages/-ap: additional packages to install during initial container setup
2024-06-29 13:42:43 +02:00
--init-hooks: additional commands to execute at the end of container initialization
--pre-init-hooks: additional commands to execute at the start of container initialization
2022-09-12 08:49:30 +02:00
--init/-I: use init system (like systemd) inside the container.
2023-08-26 14:20:56 +02:00
this will make host's processes not visible from within the container. (assumes --unshare-process)
2024-02-02 02:48:05 +05:30
may require additional packages depending on the container image: https://github.com/89luca89/distrobox/blob/main/docs/useful_tips.md#using-init-system-inside-a-distrobox
2023-03-26 16:00:21 +02:00
--nvidia: try to integrate host's nVidia drivers in the guest
2025-01-19 16:06:13 +01:00
--platform: specify which platform to use, eg: linux/arm64
2023-08-26 14:20:56 +02:00
--unshare-devsys: do not share host devices and sysfs dirs from host
2024-02-16 00:02:33 +01:00
--unshare-groups: do not forward user's additional groups into the container
2023-09-17 12:53:49 +02:00
--unshare-ipc: do not share ipc namespace with host
2023-08-26 14:20:56 +02:00
--unshare-netns: do not share the net namespace with host
2023-09-17 12:53:49 +02:00
--unshare-process: do not share process namespace with host
2023-08-26 14:20:56 +02:00
--unshare-all: activate all the unshare flags below
2022-11-01 17:53:10 +01:00
--compatibility/-C: show list of compatible images
2021-12-11 00:59:38 +01:00
--help/-h: show this message
2022-09-11 11:37:03 +02:00
--no-entry: do not generate a container entry in the application list
2022-01-28 21:46:38 +01:00
--dry-run/-d: only print the container manager command generated
2021-12-11 00:59:38 +01:00
--verbose/-v: show more verbosity
--version/-V: show version
2022-02-21 10:44:12 +01:00
2023-08-07 01:37:40 +02:00
--absolutely-disable-root-password-i-am-really-positively-sure: ⚠️ ⚠️ when setting up a rootful distrobox, this will skip user password setup, leaving it blank. ⚠️ ⚠️
2022-02-21 10:44:12 +01:00
Compatibility:
for a list of compatible images and container managers, please consult the man page:
man distrobox-compatibility
2022-11-01 17:53:10 +01:00
or run
distrobox create --compatibility
2022-02-21 10:44:12 +01:00
or consult the documentation page on: https://github.com/89luca89/distrobox/blob/main/docs/compatibility.md
2021-12-10 09:08:06 +01:00
EOF
2021-11-18 16:53:42 +01:00
}
2024-05-01 18:09:55 +02:00
# show_compatibility will print the list of compatible images to stdout, caching locally in a file.
2022-11-01 17:53:10 +01:00
# Arguments:
# None
2024-03-25 19:51:37 +01:00
# Expected global variables:
2024-05-01 18:09:55 +02:00
# app_cache_dir: cache dir to write to
# version: distrobox version
# Expected env variables:
# None
2022-11-01 17:53:10 +01:00
# Outputs:
# print usage with examples.
2024-05-02 09:07:01 +02:00
show_compatibility()
{
2024-02-01 22:22:45 +01:00
if [ ! -e " ${ app_cache_dir } /distrobox-compatibility- ${ version } " ] ||
[ ! -s " ${ app_cache_dir } /distrobox-compatibility- ${ version } " ] ; then
mkdir -p " ${ app_cache_dir } "
2022-11-01 17:53:10 +01:00
# If we don't have a cache file, we need connectivity. Ensure we have
# one and return error if not.
if ! curl -s "https://github.com" > /dev/null; then
printf >& 2 "ERROR: no cache file and no connectivity found, cannot retrieve compatibility list.\n"
exit 1
fi
# We want to download the correspondent version of the compatibility table and extract a list from it.
# Always use the docs as source of truth for this.
curl -s \
"https://raw.githubusercontent.com/89luca89/distrobox/ ${ version } /docs/compatibility.md" |
2023-06-17 09:43:15 +02:00
sed -n -e '/| Alma/,/| Void/ p' |
2022-11-01 17:53:10 +01:00
cut -d '|' -f 4 |
sed 's|<br>|\n|g' |
tr -d ' ' |
2024-02-01 22:22:45 +01:00
sort -u > " ${ app_cache_dir } /distrobox-compatibility- ${ version } "
2022-11-01 17:53:10 +01:00
fi
2024-02-01 22:22:45 +01:00
cat " ${ app_cache_dir } /distrobox-compatibility- ${ version } "
2022-11-01 17:53:10 +01:00
}
2021-11-18 16:53:42 +01:00
# Parse arguments
while :; do
case $1 in
2022-03-30 11:05:21 +02:00
-h | --help)
# Call a "show_help" function to display a synopsis, then exit.
show_help
exit 0
;;
-v | --verbose)
verbose = 1
2021-11-18 16:53:42 +01:00
shift
2022-03-30 11:05:21 +02:00
;;
-V | --version)
printf "distrobox: %s\n" " ${ version } "
exit 0
;;
2022-09-11 11:37:03 +02:00
--no-entry)
shift
2022-12-19 15:16:24 +01:00
container_generate_entry = 0
2022-09-11 11:37:03 +02:00
;;
2022-03-30 11:05:21 +02:00
-d | --dry-run)
2021-12-22 12:50:40 +01:00
shift
2022-03-30 11:05:21 +02:00
dryrun = 1
;;
2022-05-01 08:03:03 +02:00
-r | --root)
shift
rootful = 1
;;
2023-08-07 01:37:40 +02:00
--absolutely-disable-root-password-i-am-really-positively-sure)
shift
nopasswd = 1
;;
2022-03-30 11:05:21 +02:00
-I | --init)
2021-12-22 12:50:40 +01:00
shift
2022-03-30 11:05:21 +02:00
init = 1
2024-02-16 00:02:33 +01:00
unshare_groups = 1
2023-08-26 14:20:56 +02:00
unshare_process = 1
;;
--unshare-ipc)
shift
unshare_ipc = 1
2022-03-30 11:05:21 +02:00
;;
2024-02-16 00:02:33 +01:00
--unshare-groups)
shift
unshare_groups = 1
;;
2023-04-06 16:52:32 -04:00
--unshare-netns)
shift
unshare_netns = 1
;;
2023-08-26 14:20:56 +02:00
--unshare-process)
shift
unshare_process = 1
;;
2023-08-30 10:58:09 +00:00
--unshare-devsys)
2023-08-26 14:20:56 +02:00
shift
unshare_devsys = 1
;;
--unshare-all)
2023-04-06 16:52:32 -04:00
shift
2024-02-16 00:02:33 +01:00
unshare_devsys = 1
unshare_groups = 1
2023-04-06 16:52:32 -04:00
unshare_ipc = 1
2023-08-26 14:20:56 +02:00
unshare_netns = 1
unshare_process = 1
2023-04-06 16:52:32 -04:00
;;
2022-11-01 17:53:10 +01:00
-C | --compatibility)
show_compatibility
exit 0
;;
2022-03-30 11:05:21 +02: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
;;
2024-02-18 18:08:36 +01:00
--hostname)
if [ -n " $2 " ] ; then
container_hostname = " $2 "
shift
shift
fi
;;
2022-03-30 11:05:21 +02:00
-c | --clone)
if [ -n " $2 " ] ; then
container_clone = " $2 "
shift
shift
fi
;;
-H | --home)
if [ -n " $2 " ] ; then
2024-10-12 13:02:43 +02:00
# Remove trailing slashes
container_user_custom_home = " $( echo " $2 " | sed 's:/*$::' ) "
2022-03-30 11:05:21 +02:00
shift
shift
fi
;;
2022-05-26 00:15:03 +08:00
-p | --pull)
container_always_pull = 1
shift
;;
2023-03-26 16:00:21 +02:00
--nvidia)
shift
nvidia = 1
;;
2022-03-30 11:05:21 +02:00
-Y | --yes)
non_interactive = 1
2022-01-22 12:38:53 +01:00
shift
2022-03-30 11:05:21 +02:00
;;
--volume)
if [ -n " $2 " ] ; then
2023-08-03 15:01:32 +02:00
container_additional_volumes = " ${ container_additional_volumes } ${ 2 } "
2022-03-30 11:05:21 +02:00
shift
shift
fi
;;
2025-01-19 16:06:13 +01:00
--platform)
if [ -n " $2 " ] ; then
container_platform = "--platform= ${ 2 } "
shift
shift
fi
;;
2022-03-30 11:05:21 +02:00
-a | --additional-flags)
if [ -n " $2 " ] ; then
container_manager_additional_flags = " ${ container_manager_additional_flags } ${ 2 } "
shift
shift
fi
;;
2023-03-09 20:19:05 +01:00
-ap | --additional-packages)
if [ -n " $2 " ] ; then
container_additional_packages = " ${ container_additional_packages } ${ 2 } "
shift
shift
fi
;;
2022-03-30 11:05:21 +02:00
--init-hooks)
if [ -n " $2 " ] ; then
container_init_hook = " $2 "
shift
shift
fi
;;
2022-05-15 11:14:24 -07:00
--pre-init-hooks)
if [ -n " $2 " ] ; then
2022-12-05 09:37:52 -08:00
container_pre_init_hook = " ${ 2 } "
2022-05-15 11:14:24 -07:00
shift
shift
fi
;;
2022-03-30 11:05:21 +02:00
--) # End of all options.
2022-01-22 12:38:53 +01:00
shift
2022-01-07 09:58:23 +01:00
break
2022-03-30 11:05:21 +02:00
;;
2022-05-04 08:38:11 -07:00
-*) # Invalid options.
printf >& 2 "ERROR: Invalid flag '%s'\n\n" " $1 "
show_help
exit 1
;;
2022-03-30 11:05:21 +02:00
*) # 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
container_name = " $1 "
shift
else
break
fi
;;
2021-11-18 16:53:42 +01:00
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
2021-12-28 22:24:16 +01:00
# If no clone option and no container image, let's choose a default image to use.
# Fedora toolbox is a sensitive default
2021-12-22 12:50:40 +01:00
if [ -z " ${ container_clone } " ] && [ -z " ${ container_image } " ] ; then
2021-12-28 22:24:16 +01:00
container_image = " ${ container_image_default } "
2021-12-22 12:50:40 +01:00
fi
2022-05-25 19:38:16 +02:00
# If no name is specified and we're using the default container_image, then let's
# set a default name for the container, that is distinguishable from the default
# toolbx one. This will avoid problems when using both toolbx and distrobox on
# the same system.
if [ -z " ${ container_name } " ] && [ " ${ container_image } " = " ${ container_image_default } " ] ; then
2022-12-19 12:59:30 +01:00
container_name = " ${ container_name_default } "
2022-05-25 19:38:16 +02:00
fi
2021-12-29 22:33:36 +00:00
# If no container_name is declared, we build our container name starting from the
# container image specified.
#
# Examples:
# alpine -> alpine
# ubuntu:20.04 -> ubuntu-20.04
2024-02-01 16:34:23 -05:00
# registry.fedoraproject.org/fedora-toolbox:39 -> fedora-toolbox-39
2021-12-29 22:33:36 +00:00
# ghcr.io/void-linux/void-linux:latest-full-x86_64 -> void-linux-latest-full-x86_64
if [ -z " ${ container_name } " ] ; then
2022-03-15 11:51:02 +01:00
container_name = " $( basename " ${ container_image } " | sed -E 's/[:.]/-/g' ) "
2021-12-29 22:33:36 +00:00
fi
2024-02-18 18:08:36 +01:00
# set the container hostname to default value
if [ -z " ${ container_hostname } " ] ; then
2024-05-01 12:38:40 +02:00
container_hostname = " $( uname -n) "
if [ " ${ unshare_netns } " -eq 1 ] ; then
container_hostname = " ${ container_name } . ${ container_hostname } "
fi
2024-02-18 18:08:36 +01:00
fi
# check if container hostname is less than 64 chars to prevent issues
if [ " $( printf "%s" " ${ container_hostname } " | wc -m) " -gt 64 ] ; then
printf >& 2 "ERROR: Invalid hostname '%s', longer than 64 characters\n" " ${ container_hostname } "
printf >& 2 "ERROR: Use use --hostname argument to set it manually\n"
2023-08-26 08:41:45 +00:00
exit 1
fi
2021-12-15 02:01:53 +01:00
# We depend on a container manager let's be sure we have it
2023-09-15 10:58:15 +02:00
# First we use podman, else docker, else lilipod
2022-03-20 15:08:30 +01:00
case " ${ container_manager } " in
2022-03-30 11:05:21 +02:00
autodetect)
if command -v podman > /dev/null; then
container_manager = "podman"
2023-09-15 10:58:15 +02:00
elif command -v podman-launcher > /dev/null; then
container_manager = "podman-launcher"
2022-03-30 11:05:21 +02:00
elif command -v docker > /dev/null; then
container_manager = "docker"
2023-09-15 10:58:15 +02:00
elif command -v lilipod > /dev/null; then
container_manager = "lilipod"
2022-03-30 11:05:21 +02:00
fi
;;
podman)
2022-03-20 15:08:30 +01:00
container_manager = "podman"
2022-03-30 11:05:21 +02:00
;;
2023-09-15 10:58:15 +02:00
podman-launcher)
container_manager = "podman-launcher"
;;
lilipod)
container_manager = "lilipod"
;;
2022-03-30 11:05:21 +02:00
docker)
2022-03-20 15:08:30 +01:00
container_manager = "docker"
2022-03-30 11:05:21 +02:00
;;
*)
printf >& 2 "Invalid input %s.\n" " ${ container_manager } "
2023-09-15 10:58:15 +02:00
printf >& 2 "The available choices are: 'autodetect', 'podman', 'docker', 'lilipod'\n"
2022-03-30 11:05:21 +02:00
;;
2022-03-20 15:08:30 +01:00
esac
2021-12-19 13:10:45 +01:00
# Be sure we have a container manager to work with.
2022-05-30 22:20:33 +02:00
if ! command -v " ${ container_manager } " > /dev/null && [ " ${ dryrun } " -eq 0 ] ; then
2023-09-15 10:58:15 +02:00
# Error: we need at least one between docker, podman or lilipod.
2022-05-30 22:20:33 +02:00
printf >& 2 "Missing dependency: we need a container manager.\n"
2023-09-15 10:58:15 +02:00
printf >& 2 "Please install one of podman, docker or lilipod.\n"
2022-05-30 22:20:33 +02:00
printf >& 2 "You can follow the documentation on:\n"
printf >& 2 "\tman distrobox-compatibility\n"
printf >& 2 "or:\n"
printf >& 2 "\thttps://github.com/89luca89/distrobox/blob/main/docs/compatibility.md\n"
exit 127
2021-12-13 17:34:38 +01:00
fi
2021-12-19 13:22:36 +01:00
# add verbose if -v is specified
if [ " ${ verbose } " -ne 0 ] ; then
container_manager = " ${ container_manager } --log-level debug"
fi
2021-12-13 17:34:38 +01:00
2023-09-15 10:58:15 +02:00
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
2022-05-01 08:03:03 +02:00
if [ " ${ rootful } " -ne 0 ] ; then
2023-03-09 19:35:02 +01:00
container_manager = " ${ distrobox_sudo_program - } ${ container_manager } "
2022-05-01 08:03:03 +02:00
fi
2023-08-07 01:37:40 +02:00
# if nopasswd, then let the init know via a mountpoint
if [ " ${ nopasswd } " -ne 0 ] ; then
container_manager_additional_flags = " ${ container_manager_additional_flags }
--volume /dev/null:/run/.nopasswd:ro"
fi
2026-03-19 10:53:26 +00:00
# Signal rootless mode explicitly so distrobox-init does not rely solely on
# the /etc/shadow heuristic, which gives false positives on Docker Desktop
# (macOS) where the container always has root access to the VM filesystem.
if [ " ${ rootful } " -eq 0 ] ; then
container_manager_additional_flags = " ${ container_manager_additional_flags }
--volume /dev/null:/run/.distrobox.rootless:ro"
fi
2023-08-03 15:01:32 +02:00
# inject additional volumes if specified
if [ -n " ${ container_additional_volumes } " ] ; then
for volume in ${ container_additional_volumes } ; do
container_manager_additional_flags = " ${ container_manager_additional_flags }
--volume ${ volume } "
done
fi
2024-03-25 19:51:37 +01:00
# Check that we have a complete distrobox installation or
# entrypoint and export will not work.
if [ -z " ${ distrobox_entrypoint_path } " ] || [ -z " ${ distrobox_export_path } " ] ; then
printf >& 2 "Error: no distrobox-init found in %s\n" " ${ PATH } "
exit 127
fi
2024-05-01 18:09:55 +02:00
# get_clone_image will return the image name of a cloned existing container taken
# as input.
2021-12-25 21:20:09 +01:00
# Arguments:
# None
2024-03-25 19:51:37 +01:00
# Expected global variables:
2024-05-01 18:09:55 +02:00
# container_manager: string container manager to use
# container_clone: string container name to clone
# Expected env variables:
# None
2021-12-25 21:20:09 +01:00
# Outputs:
# prints the image name of the newly cloned container
2024-05-02 09:07:01 +02:00
get_clone_image()
{
2021-12-22 12:50:40 +01:00
# We need to clone a container.
# to do this we will commit the container and create a new tag. Then use it
# as image for the new container.
#
# to perform this we first ensure the source container exists and that the
# source container is stopped, else the clone will not work,
container_source_status = " $( ${ container_manager } inspect --type container \
2024-12-14 17:34:34 +01:00
--format '{{.State.Status}}' " ${ container_clone } " ) "
2021-12-22 12:50:40 +01:00
# If the container is not already running, we need to start if first
if [ " ${ container_source_status } " = "running" ] ; then
2022-01-11 12:54:50 +01:00
printf >& 2 "Container %s is running.\nPlease stop it first.\n" " ${ container_clone } "
2021-12-22 12:50:40 +01:00
printf >& 2 "Cannot clone a running container.\n"
return 1
fi
# Now we can extract the container ID and commit it to use as source image
# for the new container.
container_source_id = " $( ${ container_manager } inspect --type container \
2024-12-14 17:34:34 +01:00
--format '{{.ID}}' " ${ container_clone } " ) "
2022-06-11 19:19:03 +02:00
container_commit_tag = " $( echo " ${ container_clone } : $( date +%F) " | tr '[:upper:]' '[:lower:]' ) "
2021-12-22 12:50:40 +01:00
# Commit current container state to a new image tag
printf >& 2 "Duplicating %s...\n" " ${ container_clone } "
if ! ${ container_manager } container commit \
2022-03-30 11:05:21 +02:00
" ${ container_source_id } " " ${ container_commit_tag } " > /dev/null; then
2021-12-22 12:50:40 +01:00
printf >& 2 "Cannot clone container: %s\n" " ${ container_clone } "
return 1
fi
# Return the image tag to use for the new container creation.
printf "%s" " ${ container_commit_tag } "
return 0
}
2024-05-01 18:09:55 +02:00
# generate_create_command will produce a Podman or Docker command to execute.
2021-11-18 16:53:42 +01:00
# Arguments:
# None
2024-03-25 19:51:37 +01:00
# Expected global variables:
2024-05-01 18:09:55 +02:00
# container_manager: string container manager to use
# container_name: string container name
# container_image: string container image
# container_manager_additional_flags: string container manager additional flags to use
# container_hostname: string container hostname
# container_additional_packages: string additional packages
# container_pre_init_hook: string pre init hooks
# container_init_hook: string init hooks
# container_user_home: string user's home path
# container_user_name: string user's username
# container_user_uid: string user's UID
# container_user_gid: string user's GID
# container_home_prefix: string container's custom home prefix
# container_user_custom_home: string container's custom home path
# init: bool initful
# nvidia: bool nvidia integration
# rootful: bool rootful
# unshare_devsys: bool unshare devsys
# unshare_groups: bool unshare groups
# unshare_ipc: bool unshare ipc
# unshare_netns: bool unshare netns
# unshare_process: bool unshare proc
# Expected env variables:
# None
2021-11-18 16:53:42 +01:00
# Outputs:
2023-09-15 10:58:15 +02:00
# prints the podman, docker or lilipod command to create the distrobox container
2024-05-02 09:07:01 +02:00
generate_create_command()
{
2026-03-19 10:53:26 +00:00
# On macOS, Docker Desktop mounts all paths as private in its Linux VM,
# so rslave/rshared bind propagation is not supported.
if [ " $( uname -s) " = "Darwin" ] ; then
rslave = ""
2026-05-04 05:10:30 -04:00
rorslave = ":ro"
2026-03-19 10:53:26 +00:00
else
rslave = ":rslave"
2026-05-04 05:10:30 -04:00
rorslave = ":ro,rslave"
2026-03-19 10:53:26 +00:00
fi
2021-11-18 16:53:42 +01:00
# Set the container hostname the same as the container name.
2021-12-19 13:22:36 +01:00
result_command = " ${ container_manager } create"
2025-01-19 16:06:13 +01:00
result_command = " ${ result_command } ${ container_platform } "
2021-12-16 12:21:03 +01:00
# use the host's namespace for ipc, network, pid, ulimit
2021-12-10 14:20:55 +01:00
result_command = " ${ result_command }
2024-02-18 18:08:36 +01:00
--hostname \" ${ container_hostname } \"
2022-02-22 11:18:41 +01:00
--name \" ${ container_name } \"
2021-12-11 18:50:40 +01:00
--privileged
--security-opt label=disable
2023-08-29 14:51:14 +00:00
--security-opt apparmor=unconfined
2024-02-03 16:57:03 +01:00
--pids-limit=-1
2021-12-15 02:01:53 +01:00
--user root:root"
2021-12-02 19:54:01 +01:00
2023-04-06 23:01:29 +02:00
if [ " ${ unshare_ipc } " -eq 0 ] ; then
2023-04-06 16:52:32 -04:00
result_command = " ${ result_command }
--ipc host"
fi
2023-04-06 23:01:29 +02:00
if [ " ${ unshare_netns } " -eq 0 ] ; then
2023-04-06 16:52:32 -04:00
result_command = " ${ result_command }
--network host"
fi
2023-08-26 14:20:56 +02:00
if [ " ${ unshare_process } " -eq 0 ] ; then
2022-01-28 23:30:25 +01:00
result_command = " ${ result_command }
--pid host"
fi
2021-12-13 20:20:08 +01:00
# 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-13 16:46:56 +01:00
#
2021-12-13 20:20:08 +01:00
# Mount user home, dev and host's root inside container.
# This grants access to external devices like usb webcams, disks and so on.
2021-12-13 16:46:56 +01:00
#
2021-12-13 20:20:08 +01:00
# Mount also the distrobox-init utility as the container entrypoint.
2022-05-30 22:20:33 +02:00
# Also mount in the container the distrobox-export and distrobox-host-exec
# utilities.
2021-12-13 13:55:21 +01:00
result_command = " ${ result_command }
2022-07-15 20:01:11 +02:00
--label \"manager=distrobox\"
2024-02-16 00:02:33 +01:00
--label \"distrobox.unshare_groups= ${ unshare_groups } \"
2023-06-30 19:00:46 +02:00
--env \"SHELL= $( basename " ${ SHELL :- "/bin/bash" } " ) \"
2022-02-22 11:18:41 +01:00
--env \"HOME= ${ container_user_home } \"
2023-08-16 10:58:51 +01:00
--env \"container= ${ container_manager } \"
2024-02-15 17:56:42 +01:00
--env \"TERMINFO_DIRS=/usr/share/terminfo:/run/host/usr/share/terminfo\"
2024-05-01 12:38:40 +02:00
--env \"CONTAINER_ID= ${ container_name } \"
2026-03-19 10:53:26 +00:00
--volume /tmp:/tmp ${ rslave }
2022-09-16 10:39:10 +01:00
--volume \" ${ distrobox_entrypoint_path } \":/usr/bin/entrypoint:ro
--volume \" ${ distrobox_export_path } \":/usr/bin/distrobox-export:ro
--volume \" ${ distrobox_hostexec_path } \":/usr/bin/distrobox-host-exec:ro
2026-03-19 10:53:26 +00:00
--volume \" ${ container_user_home } \":\" ${ container_user_home } \" ${ rslave } "
2021-12-10 09:28:16 +01:00
2024-05-01 12:33:09 +02:00
# Due to breaking change in https://github.com/opencontainers/runc/commit/d4b670fca6d0ac606777376440ffe49686ce15f4
# now we cannot mount /:/run/host as before, as it will try to mount RO partitions as RW thus breaking things.
# This will ensure we will mount directories one-by-one thus avoiding this problem.
#
# This happens ONLY with podman+runc, docker and lilipod are unaffected, so let's do this only if we have podman AND runc.
2025-11-26 15:21:42 +01:00
if echo " ${ container_manager } " | grep -q "podman" && ${ container_manager } info 2> /dev/null | grep -q runc > /dev/null 2>& 1; then
2024-05-01 12:33:09 +02:00
for rootdir in /*; do
# Skip symlinks
if [ -L " ${ rootdir } " ] ; then
continue
fi
# Find if the directory belongs to a RO mount, if do, mount it as RO+Rslave
if findmnt --notruncate --noheadings --list --output OPTIONS --target " ${ rootdir } " |
tr ',' '\n' | grep -q "^ro $" ; then
result_command = " ${ result_command }
2026-05-04 05:10:30 -04:00
--volume ${ rootdir } :/run/host ${ rootdir }${ rorslave } "
2024-05-01 12:33:09 +02:00
continue
fi
# Else we mount it RW+Rslave
result_command = " ${ result_command }
2026-03-19 10:53:26 +00:00
--volume ${ rootdir } :/run/host ${ rootdir }${ rslave } "
2024-05-01 12:33:09 +02:00
done
else
# We're either on podman+crun, docker or lilipod, let's keep old behaviour
result_command = " ${ result_command }
2026-03-19 10:53:26 +00:00
--volume /:/run/host/ ${ rslave } "
2024-05-01 12:33:09 +02:00
fi
2023-08-26 14:20:56 +02:00
if [ " ${ unshare_devsys } " -eq 0 ] ; then
result_command = " ${ result_command }
2026-03-19 10:53:26 +00:00
--volume /dev:/dev ${ rslave }
--volume /sys:/sys ${ rslave } "
2023-08-26 14:20:56 +02:00
fi
2023-08-16 10:01:32 +00:00
# In case of initful containers, we implement a series of mountpoint in order
# for systemd to work properly inside a container.
# The following are a flag-based implementation of what podman's --systemd flag
# does under the hood, as explained in their docs here:
# https://docs.podman.io/en/latest/markdown/options/systemd.html
#
# set the default stop signal to SIGRTMIN+3.
# mount tmpfs file systems on the following directories
# /run
# /run/lock
# /tmp
# /var/lib/journal
# /sys/fs/cgroup/systemd <- this one is done by cgroupns=host
2023-08-16 10:58:51 +01:00
if [ " ${ init } " -eq 1 ] && echo " ${ container_manager } " | grep -q "docker" ; then
2023-08-29 14:51:14 +00:00
# In case of docker we're actually rootful, so we need to use hosts cgroups
result_command = " ${ result_command }
--cgroupns host"
fi
if [ " ${ init } " -eq 1 ] && echo " ${ container_manager } " | grep -vq "podman" ; then
2023-09-15 10:58:15 +02:00
# In case of all other non-podman container managers, we can do this
2023-08-16 10:58:51 +01:00
result_command = " ${ result_command }
--stop-signal SIGRTMIN+3
--mount type=tmpfs,destination=/run
--mount type=tmpfs,destination=/run/lock
--mount type=tmpfs,destination=/var/lib/journal"
fi
2023-08-14 09:41:24 +00:00
# This fix is needed so that the container can have a separate devpts instance
# inside
# This will mount an empty /dev/pts, and the init will take care of mounting
# a new devpts with the proper flags set
# Mounting an empty volume there, is needed in order to ensure that no package
# manager tries to fiddle with /dev/pts/X that would not be writable by them
2023-08-16 10:01:32 +00:00
#
# This implementation is done this way in order to be compatible with both
# docker and podman
2023-08-26 13:11:40 +00:00
if [ " ${ unshare_devsys } " -eq 0 ] ; then
result_command = " ${ result_command }
--volume /dev/pts
--volume /dev/null:/dev/ptmx"
fi
2023-08-14 09:41:24 +00:00
2022-03-11 16:23:27 +01:00
# This fix is needed as on Selinux systems, the host's selinux sysfs directory
# will be mounted inside the rootless container.
#
# This works around this and allows the rootless container to work when selinux
# policies are installed inside it.
#
# Ref. Podman issue 4452:
# https://github.com/containers/podman/issues/4452
2022-03-12 11:36:35 +01:00
if [ -e "/sys/fs/selinux" ] ; then
result_command = " ${ result_command }
--volume /sys/fs/selinux"
fi
2022-03-11 16:23:27 +01:00
2022-04-25 21:32:38 +02:00
# This fix is needed as systemd (or journald) will try to set ACLs on this
# path. For now overlayfs and fuse.overlayfs are not compatible with ACLs
#
# This works around this using an unnamed volume so that this path will be
# mounted with a normal non-overlay FS, allowing ACLs and preventing errors.
#
2022-05-30 22:20:33 +02:00
# This work around works in conjunction with distrobox-init's package manager
# setups.
2022-04-25 21:32:38 +02:00
# So that we can use pre/post hooks for package managers to present to the
# systemd install script a blank path to work with, and mount the host's
# journal path afterwards.
result_command = " ${ result_command }
--volume /var/log/journal"
2022-01-27 18:44:49 +01:00
# In some systems, for example using sysvinit, /dev/shm is a symlink
# to /run/shm, instead of the other way around.
# Resolve this detecting if /dev/shm is a symlink and mount original
# source also in the container.
2023-08-26 14:20:56 +02:00
if [ -L "/dev/shm" ] && [ " ${ unshare_ipc } " -eq 0 ] ; then
2022-01-27 18:44:49 +01:00
result_command = " ${ result_command }
--volume $( realpath /dev/shm) : $( realpath /dev/shm) "
fi
2022-01-30 21:28:10 +01:00
2023-09-15 10:58:15 +02:00
# Ensure that both all container managers (not only podman) support forwarding of RedHat subscription-manager
2023-08-29 19:05:34 +00:00
# This is needed in order to have a working subscription forwarded into the container,
# this will ensure that rhel-9-for-x86_64-appstream-rpms and rhel-9-for-x86_64-baseos-rpms repos
# will be available in the container, so that distrobox-init will be able to
# install properly all the dependencies like mesa drivers.
#
# /run/secrets is a standard location for RHEL containers, that is being pointed by
# /etc/rhsm-host by default.
2024-02-01 23:33:34 +01:00
RHEL_SUBSCRIPTION_FILES = "
/etc/pki/entitlement/:/run/secrets/etc-pki-entitlement:ro
/etc/rhsm/:/run/secrets/rhsm:ro
/etc/yum.repos.d/redhat.repo:/run/secrets/redhat.repo:ro
"
for rhel_file in ${ RHEL_SUBSCRIPTION_FILES } ; do
if [ -e " $( echo " ${ rhel_file } " | cut -d':' -f1) " ] ; then
result_command = " ${ result_command }
--volume ${ rhel_file } "
fi
done
2023-08-29 19:05:34 +00:00
2024-02-16 18:06:24 +01:00
# If we have a home prefix to use, ano no custom home set, then we set
# the custom home to be PREFIX/CONTAINER_NAME
2022-10-19 19:16:26 +02:00
if [ -n " ${ container_home_prefix } " ] && [ -z " ${ container_user_custom_home } " ] ; then
2024-02-16 18:06:24 +01:00
container_user_custom_home = " ${ container_home_prefix } / ${ container_name } "
2022-10-19 19:16:26 +02:00
fi
2021-12-30 23:53:58 +01:00
# If we have a custom home to use,
# 1- override the HOME env variable
2022-10-19 19:16:26 +02:00
# 2- export the DISTROBOX_HOST_HOME env variable pointing to original HOME
2022-01-01 22:51:26 +01:00
# 3- mount the custom home inside the container.
2021-12-30 23:53:58 +01:00
if [ -n " ${ container_user_custom_home } " ] ; then
2022-10-19 19:16:26 +02:00
if [ ! -d " ${ container_user_custom_home } " ] ; then
if ! mkdir -p " ${ container_user_custom_home } " ; then
printf >& 2 "Do you have permission to write to %s?\n" " ${ container_user_custom_home } "
exit 1
fi
fi
2021-12-30 23:53:58 +01:00
result_command = " ${ result_command }
2022-09-07 12:26:58 +02:00
--env \"HOME= ${ container_user_custom_home } \"
--env \"DISTROBOX_HOST_HOME= ${ container_user_home } \"
2026-03-19 10:53:26 +00:00
--volume \" ${ container_user_custom_home } : ${ container_user_custom_home }${ rslave } \""
2021-12-30 23:53:58 +01:00
fi
2021-12-22 23:16:55 +01:00
# Mount also the /var/home dir on ostree based systems
2021-12-24 10:36:57 +01:00
# do this only if $HOME was not already set to /var/home/username
if [ " ${ container_user_home } " != "/var/home/ ${ container_user_name } " ] &&
[ -d "/var/home/ ${ container_user_name } " ] ; then
2021-12-22 23:16:55 +01:00
result_command = " ${ result_command }
2026-03-19 10:53:26 +00:00
--volume \"/var/home/ ${ container_user_name } \":\"/var/home/ ${ container_user_name } \" ${ rslave } "
2021-12-22 23:16:55 +01:00
fi
2021-12-13 20:20:08 +01:00
# Mount also the XDG_RUNTIME_DIR to ensure functionality of the apps.
2023-08-05 16:41:45 +02:00
# This is skipped in case of initful containers, so that a dedicated
# systemd user session can be used.
if [ -d "/run/user/ ${ container_user_uid } " ] && [ " ${ init } " -eq 0 ] ; then
2021-12-13 16:46:56 +01:00
result_command = " ${ result_command }
2026-03-19 10:53:26 +00:00
--volume /run/user/ ${ container_user_uid } :/run/user/ ${ container_user_uid }${ rslave } "
2021-11-18 16:53:42 +01:00
fi
2021-12-02 19:54:01 +01:00
2021-12-13 20:20:08 +01:00
# These are dynamic configs needed by the container to function properly
2021-12-13 16:46:56 +01:00
# and integrate with the host
#
# We're doing this now instead of inside the init because some distros will
# have symlinks places for these files that use absolute paths instead of
2022-05-04 16:38:51 +00:00
# relative paths.
# This is the bare minimum to ensure connectivity inside the container.
2022-05-11 14:55:38 +02:00
# These files, will then be kept updated by the main loop every 15 seconds.
2023-06-10 08:54:40 +00:00
if [ " ${ unshare_netns } " -eq 0 ] ; then
NET_FILES = "
/etc/hosts
/etc/resolv.conf
"
2024-05-01 12:38:40 +02:00
# If container_hostname is custom, we skip mounting /etc/hostname, else
# we want to keep it in sync
if [ " ${ container_hostname } " = " $( uname -n) " ] ; then
NET_FILES = " ${ NET_FILES } /etc/hostname"
fi
2023-06-10 08:54:40 +00:00
for net_file in ${ NET_FILES } ; do
if [ -e " ${ net_file } " ] ; then
2023-06-20 18:48:03 +02:00
result_command = " ${ result_command }
--volume ${ net_file } : ${ net_file } :ro"
2023-06-10 08:54:40 +00:00
fi
done
fi
2021-12-13 16:46:56 +01:00
2021-12-16 12:21:03 +01:00
# These flags are not supported by docker, so we use them only if our
# container manager is podman.
2023-02-10 12:01:35 +01:00
if echo " ${ container_manager } " | grep -q "podman" ; then
2025-05-27 10:43:47 +02:00
# If possible, always prefer crun, as it allows keeping original groups.
# useful for rootless containers.
if command -v crun > /dev/null 2>& 1; then
result_command = " ${ result_command }
--runtime=crun"
fi
2021-12-15 02:01:53 +01:00
result_command = " ${ result_command }
2024-02-16 00:02:33 +01:00
--annotation run.oci.keep_original_groups=1
2024-02-15 16:16:44 +01:00
--ulimit host"
2023-08-14 02:14:37 +02:00
2022-03-25 21:19:02 +01:00
if [ " ${ init } " -eq 1 ] ; then
result_command = " ${ result_command }
--systemd=always"
fi
2023-08-14 02:14:37 +02:00
2022-05-30 22:20:33 +02:00
# Use keep-id only if going rootless.
if [ " ${ rootful } " -eq 0 ] ; then
result_command = " ${ result_command }
--userns keep-id"
2025-10-23 21:28:11 +11:00
# Test if podman supports keep-id:size=
2025-11-22 01:45:57 -07:00
if podman run --rm --userns= keep-id:size= 65536 " ${ container_image } " /bin/true > /dev/null 2>& 1 || [ " $? " -eq 127 ] ; then
2025-10-23 21:28:11 +11:00
has_keepid_size = 1
else
has_keepid_size = 0
fi
# Add :size=65536 if wanted
if [ " ${ has_keepid_size } " -eq 1 ] && [ " ${ userns_nolimit } " -eq 0 ] ; then
result_command = " ${ result_command } :size=65536"
fi
2022-05-30 22:20:33 +02:00
fi
2021-12-15 02:01:53 +01:00
fi
2022-01-22 12:38:53 +01:00
# Add additional flags
2023-08-03 15:01:32 +02:00
result_command = " ${ result_command }
${ container_manager_additional_flags } "
2022-01-22 12:38:53 +01:00
2021-12-13 20:20:08 +01:00
# Now execute the entrypoint, refer to `distrobox-init -h` for instructions
2022-07-12 23:16:09 +02:00
#
# Be aware that entrypoint corresponds to distrobox-init, the copying of it
# inside the container is moved to distrobox-enter, in the start phase.
# This is done to make init, export and host-exec location independent from
# the host, and easier to upgrade.
2022-12-05 10:44:54 -06:00
#
# We set the entrypoint _before_ running the container image so that
# we can override any user provided entrypoint if need be
2023-06-20 18:48:03 +02:00
result_command = " ${ result_command }
--entrypoint /usr/bin/entrypoint
${ container_image }
--verbose
--name \" ${ container_user_name } \"
2022-02-11 18:31:13 +01:00
--user ${ container_user_uid }
--group ${ container_user_gid }
2022-02-22 11:18:41 +01:00
--home \" ${ container_user_custom_home :- " ${ container_user_home } " } \"
--init \" ${ init } \"
2023-03-26 16:00:21 +02:00
--nvidia \" ${ nvidia } \"
2022-12-05 09:37:52 -08:00
--pre-init-hooks \" ${ container_pre_init_hook } \"
2023-03-09 20:19:05 +01:00
--additional-packages \" ${ container_additional_packages } \"
2022-02-11 18:31:13 +01:00
-- ' ${ container_init_hook } '
2023-06-20 18:48:03 +02:00
"
2021-12-30 23:53:58 +01:00
# use container_user_custom_home if defined, else fallback to normal home.
2021-12-10 09:08:06 +01:00
2021-12-13 20:20:08 +01:00
# Return generated command.
2021-12-10 09:08:06 +01:00
printf "%s" " ${ result_command } "
2021-11-18 16:53:42 +01:00
}
2022-01-28 21:46:38 +01:00
# dry run mode, just generate the command and print it. No creation.
if [ " ${ dryrun } " -ne 0 ] ; then
if [ -n " ${ container_clone } " ] ; then
container_image = " ${ container_clone } "
fi
2024-03-25 19:51:37 +01:00
cmd = " $( generate_create_command) "
2023-06-20 18:48:03 +02:00
cmd = " $( echo " ${ cmd } " | sed 's/\t//g' ) "
2022-01-28 21:46:38 +01:00
printf "%s\n" " ${ cmd } "
exit 0
fi
2021-12-13 18:07:20 +01:00
# Check if the container already exists.
# If it does, notify the user and exit.
2022-03-30 11:05:21 +02:00
if ${ container_manager } inspect --type container " ${ container_name } " > /dev/null 2>& 1; then
2021-12-13 18:07:20 +01:00
printf "Distrobox named '%s' already exists.\n" " ${ container_name } "
2022-05-02 16:41:16 +02:00
printf "To enter, run:\n\n"
2023-02-10 13:07:28 -03:00
# If it's a rootful container AND user is not logged as root.
if [ " ${ rootful } " -eq 1 ] && [ " ${ container_user_uid } " -ne 0 ] ; then
printf "distrobox enter --root %s\n\n" " ${ container_name } "
# If user is logged as root OR it's a rootless container.
elif [ " ${ container_user_uid } " -eq 0 ] || [ " ${ rootful } " -eq 0 ] ; then
printf "distrobox enter %s\n\n" " ${ container_name } "
2022-05-02 16:41:16 +02:00
fi
2021-12-13 18:07:20 +01:00
exit 0
fi
2021-12-22 12:50:40 +01:00
# if we are using the clone flag, let's set the image variable
# to the output of container duplication
if [ -n " ${ container_clone } " ] ; then
2024-12-14 17:34:34 +01:00
if ! echo " ${ container_manager } " | grep -Eq "podman|docker" ; then
printf >& 2 "ERROR: clone is only supported with docker and podman\n"
exit 127
fi
2024-03-25 19:51:37 +01:00
container_image = " $( get_clone_image) "
2021-12-22 12:50:40 +01:00
fi
2024-03-25 19:51:37 +01:00
2022-05-25 18:24:38 +02:00
# First, check if the image exists in the host or auto-pull is enabled
2021-12-13 18:07:20 +01:00
# If not prompt to download it.
2022-05-25 18:24:38 +02:00
if [ " ${ container_always_pull } " -eq 1 ] ||
! ${ container_manager } inspect --type image " ${ container_image } " > /dev/null 2>& 1; then
# If we do auto-pull, don't ask questions
2022-05-26 00:15:03 +08:00
if [ " ${ non_interactive } " -eq 1 ] || [ " ${ container_always_pull } " -eq 1 ] ; then
response = "yes"
else
2021-12-29 22:33:36 +00:00
# Prompt to download it.
2022-01-21 16:48:37 +01:00
printf >& 2 "Image %s not found.\n" " ${ container_image } "
2022-01-22 19:51:52 +01:00
printf >& 2 "Do you want to pull the image now? [Y/n]: "
2021-12-29 22:33:36 +00:00
read -r response
2022-01-22 19:51:52 +01:00
response = " ${ response :- "Y" } "
2021-12-29 22:33:36 +00:00
fi
2021-12-13 18:07:20 +01:00
2021-12-09 18:43:18 +01:00
# Accept only y,Y,Yes,yes,n,N,No,no.
case " ${ response } " in
2022-03-30 11:05:21 +02:00
y | Y | Yes | yes | YES)
# Pull the image
2025-01-19 16:39:30 +01:00
# shellcheck disable=SC2086
2025-01-19 16:06:13 +01:00
${ container_manager } pull ${ container_platform } " ${ container_image } "
2022-03-30 11:05:21 +02:00
;;
n | N | No | no | NO)
printf >& 2 "next time, run this command first:\n"
printf >& 2 "\t%s pull %s\n" " ${ container_manager } " " ${ container_image } "
exit 0
;;
*) # Default case: If no more options then break out of the loop.
printf >& 2 "Invalid input.\n"
printf >& 2 "The available choices are: y,Y,Yes,yes,YES or n,N,No,no,NO.\nExiting.\n"
exit 1
;;
2021-12-09 18:19:13 +01:00
esac
2021-11-18 16:53:42 +01:00
fi
2021-12-13 18:07:20 +01:00
# Generate the create command and run it
2022-06-22 11:13:08 +02:00
printf >& 2 "Creating '%s' using image %s\t" " ${ container_name } " " ${ container_image } "
2024-03-25 19:51:37 +01:00
cmd = " $( generate_create_command) "
2021-12-12 13:33:43 +01:00
# Eval the generated command. If successful display an helpful message.
2021-12-10 09:28:16 +01:00
# shellcheck disable=SC2086
2022-06-11 17:26:34 +02:00
if eval ${ cmd } > /dev/null; then
printf >& 2 "\033[32m [ OK ]\n\033[0mDistrobox '%s' successfully created.\n" " ${ container_name } "
2022-06-22 11:13:08 +02:00
printf >& 2 "To enter, run:\n\n"
2023-02-10 13:07:28 -03:00
# If it's a rootful container AND user is not logged as root.
if [ " ${ rootful } " -eq 1 ] && [ " ${ container_user_uid } " -ne 0 ] ; then
2022-06-11 17:26:34 +02:00
printf "distrobox enter --root %s\n\n" " ${ container_name } "
2023-02-10 13:07:28 -03:00
# If user is logged as root OR it's a rootless container.
elif [ " ${ container_user_uid } " -eq 0 ] || [ " ${ rootful } " -eq 0 ] ; then
2022-06-11 17:26:34 +02:00
printf "distrobox enter %s\n\n" " ${ container_name } "
2022-05-02 16:41:16 +02:00
fi
2022-08-28 19:15:18 +02:00
# We've created the box, let's also create the entry
2022-08-30 00:42:35 +02:00
if [ " ${ rootful } " -eq 0 ] ; then
2022-12-19 15:16:24 +01:00
if [ " ${ container_generate_entry } " -ne 0 ] ; then
2023-04-06 22:20:00 +02:00
" ${ distrobox_genentry_path } " " ${ container_name } "
2022-09-11 11:37:03 +02:00
fi
2022-08-30 00:42:35 +02:00
fi
2024-10-12 05:08:15 -05:00
else
error = " $? "
printf >& 2 "\033[31m [ ERR ]\033[0m failed to create container.\n"
2024-10-12 13:02:43 +02:00
exit " ${ error } "
2021-12-12 13:33:43 +01:00
fi