#!/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_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)" # Defaults no_color=0 # 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_manager="autodetect" # 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 # 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 [ "$(id -ru)" -ne 0 ]; then # If the DBX_SUDO_PROGRAM/distrobox_sudo_program variable was set by the # user, use its value instead of "sudo". But only if not running the script # as root (UID 0). distrobox_sudo_program=${DBX_SUDO_PROGRAM:-${distrobox_sudo_program:-"sudo"}} fi [ -n "${DBX_CONTAINER_MANAGER}" ] && container_manager="${DBX_CONTAINER_MANAGER}" # 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-list Options: --help/-h: show this message --no-color: disable color formatting --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 --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 ;; --no-color) shift no_color=1 ;; -r | --root) shift rootful=1 ;; -v | --verbose) verbose=1 shift ;; -V | --version) printf "distrobox: %s\n" "${version}" exit 0 ;; --) # End of all options. shift break ;; -*) # Invalid options. printf >&2 "ERROR: Invalid flag '%s'\n\n" "$1" show_help exit 1 ;; *) # Default case: If no more options then break out of the loop. break ;; esac done set -o errexit set -o nounset # set verbosity if [ "${verbose}" -ne 0 ]; then set -o xtrace fi # We depend on a container manager let's be sure we have it # First we use podman, else docker, else lilipod case "${container_manager}" in autodetect) if command -v podman > /dev/null; then container_manager="podman" elif command -v podman-launcher > /dev/null; then container_manager="podman-launcher" elif command -v docker > /dev/null; then container_manager="docker" elif command -v lilipod > /dev/null; then container_manager="lilipod" fi ;; podman) container_manager="podman" ;; podman-launcher) container_manager="podman-launcher" ;; lilipod) container_manager="lilipod" ;; docker) container_manager="docker" ;; *) printf >&2 "Invalid input %s.\n" "${container_manager}" printf >&2 "The available choices are: 'autodetect', 'podman', 'docker', 'lilipod'\n" ;; esac # Be sure we have a container manager to work with. if ! command -v "${container_manager}" > /dev/null; then # Error: we need at least one between docker, podman or lilipod. printf >&2 "Missing dependency: we need a container manager.\n" printf >&2 "Please install one of podman, docker or lilipod.\n" 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 fi # add verbose if -v is specified if [ "${verbose}" -ne 0 ]; then container_manager="${container_manager} --log-level debug" fi # prepend sudo (or the specified sudo program) if we want our container manager to be rootful if [ "${rootful}" -ne 0 ]; then container_manager="${distrobox_sudo_program-} ${container_manager}" fi # List containers using custom format that included MOUNTS # we do this as we can detect the custom mounts done by distrobox to distringuish # between a normal container and a distrobox one. container_list=$(${container_manager} ps -a --no-trunc --format \ "{{.ID}}|{{.Image}}|{{.Names}}|{{.Status}}|{{.Labels}}{{.Mounts}}") printf "%-12s | %-20s | %-18s | %-30s\n" \ "ID" "NAME" "STATUS" "IMAGE" IFS=' ' # if we're in not a tty, don't use colors GREEN="" YELLOW="" CLEAR="" if [ -t 0 ] && [ -t 1 ] && [ "${no_color}" -ne 1 ]; then # we're in a tty, use colors GREEN='\033[32m' YELLOW='\033[33m' CLEAR='\033[0m' fi # Header of the output for container in ${container_list}; do # Check if the current container has a custom mount point for distrobox. if [ -z "${container##*distrobox*}" ]; then # Extract the information for the single container to pretty print it container_id="$(printf "%s" "${container}" | cut -d'|' -f1 | cut -c1-12)" container_image="$(printf "%s" "${container}" | cut -d'|' -f2)" container_name="$(printf "%s" "${container}" | cut -d'|' -f3)" container_status="$(printf "%s" "${container}" | cut -d'|' -f4)" IFS=' ' # If the container is Up and Running, print it in green and go next. if [ -z "${container_status##*Up*}" ] || [ -z "${container_status##*running*}" ]; then # echo -e is not defined in posix, and printing with %s will not work # for colors, so we're disabling this lint for color prints. # shellcheck disable=SC2059 printf "${GREEN}" else # shellcheck disable=SC2059 printf "${YELLOW}" fi # print it in yellow if not Running printf "%-12s | %-20s | %-18s | %-30s" \ "${container_id}" "${container_name}" "${container_status}" "${container_image}" # shellcheck disable=SC2059 printf "${CLEAR}\n" fi done