#!/usr/bin/env bash # Copyright (C) 2023 Rudra Saraswat # # This file is part of blend. # # blend is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # blend 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 blend. If not, see . if [ ! -f '/run/.containerenv' ]; then echo 'not running in container' exit 1 fi shopt -s extglob while true; do case $1 in --uid) if [ -n "$2" ]; then _cuid="$2" shift shift fi ;; --group) if [ -n "$2" ]; then _cgid="$2" shift shift fi ;; --username) if [ -n "$2" ]; then _uname="$2" shift shift fi ;; --home) if [ -n "$2" ]; then _uhome="$2" shift shift fi ;; -*) exit 1 ;; *) break ;; esac done cat << 'EOF' ▄▄▄▄ ██▓ ▓█████ ███▄ █ ▓█████▄ ▓█████▄ ▓██▒ ▓█ ▀ ██ ▀█ █ ▒██▀ ██▌ ▒██▒ ▄██▒██░ ▒███ ▓██ ▀█ ██▒░██ █▌ ▒██░█▀ ▒██░ ▒▓█ ▄ ▓██▒ ▐▌██▒░▓█▄ ▌ ░▓█ ▀█▓░██████▒░▒████▒▒██░ ▓██░░▒████▓ ░▒▓███▀▒░ ▒░▓ ░░░ ▒░ ░░ ▒░ ▒ ▒ ▒▒▓ ▒ ▒░▒ ░ ░ ░ ▒ ░ ░ ░ ░░ ░░ ░ ▒░ ░ ▒ ▒ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ =================== Credits =================== * NVIDIA driver support - Luca Di Maio (from Distrobox) EOF echo echo 'Starting blend... (this may take a few minutes)' echo bmount() { ! [[ -d "$1" ]] && ! [[ -f "$1" ]] && return 0 # check if source dir exists ! [[ -e "$2" ]] && findmnt "$2" &>/dev/null && umount "$2" # unmount target dir if a mount [[ -d "$1" ]] && mkdir -p "$2" # create target dir if source is a dir [[ -f "$1" ]] && mkdir -p "$(dirname "$2")"; touch "$2" # create target file if source is a file mountflags="rslave" ! [[ -z "$3" ]] && mountflags="$3" mount --rbind -o "$mountflags" "$1" "$2" &>/dev/null } if [[ ! -f '/.init_blend.lock' ]]; then ### echo 'nameserver 1.1.1.1' > /etc/resolv.conf if command -v apt-get &>/dev/null; then apt-get update &>/dev/null DEBIAN_FRONTEND=noninteractive apt-get -y install bash bc curl less wget apt-utils apt-transport-https dialog \ diffutils findutils gnupg2 sudo time util-linux libnss-myhostname \ lsof ncurses-base passwd inotify-tools pinentry-curses libegl1-mesa \ libgl1-mesa-glx libvulkan1 mesa-vulkan-drivers &>/dev/null elif command -v pacman &>/dev/null; then pacman --noconfirm -Syyu &>/dev/null pacman --noconfirm -Sy bash bc curl wget diffutils findutils gnupg sudo time util-linux vte-common lsof ncurses pinentry \ mesa opengl-driver vulkan-intel vulkan-radeon base-devel git inotify-tools &>/dev/null elif command -v dnf &>/dev/null; then dnf config-manager --set-enabled crb &>/dev/null dnf install -y epel-release &>/dev/null dnf install -y --allowerasing bash bc curl wget diffutils findutils dnf-plugins-core gnupg2 less lsof passwd pinentry \ procps-ng vte-profile ncurses util-linux sudo time shadow-utils vulkan mesa-vulkan-drivers \ mesa-dri-drivers inotify-tools &>/dev/null fi mkdir -p /usr/local/bin wget -O /usr/local/bin/host-spawn "https://github.com/1player/host-spawn/releases/latest/download/host-spawn-$(uname -m)" &>/dev/null chmod 755 /usr/local/bin/host-spawn fi ### for i in /var/log/journal /var/lib/systemd/coredump /var/lib/flatpak; do bmount "/run/host/${i}" "$i" ro done for i in /etc/host.conf /run/media /media /mnt /var/mnt \ /run/libvirt /etc/machine-id /run/netconfig/ /run/udev \ /run/systemd/journal /run/systemd/seats /run/systemd/sessions \ /run/systemd/users /run/systemd/resolve/ /srv /var/lib/libvirt; do bmount "/run/host/${i}" "$i" rw done init_ro_mounts=" /run/systemd/journal /var/log/journal /run/systemd/resolve /run/systemd/seats /run/systemd/sessions /run/systemd/users /var/lib/systemd/coredump /etc/localtime" ### Section START https://github.com/89luca89/distrobox/blob/main/distrobox-init#L772 host_sockets="$(find /run/host/run -name 'user' \ -prune -o -path /run/host/run/media \ -prune -o -name 'nscd' \ -prune -o -name 'bees' \ -prune -o -name 'system_bus_socket' \ -prune -o -type s -print \ 2> /dev/null || :)" ### Section END for i in ${host_sockets}; do container_socket="$(echo -n "$i" | sed 's/\/run\/host//g')" if [ ! -S "${container_socket}" ] && [ ! -L "${container_socket}" ]; then rm -f "${container_socket}" mkdir -p "$(dirname "${container_socket}")" ln -s "$i" "${container_socket}" fi done bmount "/run/host/usr/share/themes" "/usr/local/share/themes" ro bmount "/run/host/usr/share/icons" "/usr/local/share/icons" ro bmount "/run/host/usr/share/fonts" "/usr/local/share/fonts" ro bmount "/usr/bin/host-blend" "/usr/bin/blend" ro # sudo touch /.init_blend.lock if [[ ! -f '/.init_blend.lock' ]]; then ####################################################################### # NVIDIA driver integration. This is straight from https://github.com/89luca89/distrobox/blob/main/distrobox-init#L816, # entirely thanks to an effort by Luca Di Maio, save for a few tweaks for init-blend. Thanks, in case you're reading this! NVIDIA_FILES="$(find /run/host/usr/ \ -path "/run/host/usr/share/doc*" -prune -o \ -path "/run/host/usr/src*" -prune -o \ -path "/run/host/usr/lib*/modules*" -prune -o \ -path "/run/host/usr/share/man*" -prune -o \ -path "/run/host/usr/lib*" -prune -o \ -type f -iname "*nvidia*" -print 2 /usr/lib/rpm/macros.d/macros.blend elif [ -d "/etc/dpkg/" ]; then mkdir -p /etc/dpkg/dpkg.cfg.d /etc/apt/apt.conf.d echo -n > /etc/dpkg/dpkg.cfg.d/00_blend for net_mount in ${HOST_MOUNTS_RO} ${HOST_MOUNTS} '/etc/hosts' '/etc/resolv.conf' '/etc/localtime'; do printf "path-exclude %s/*\n" "${net_mount}" >> /etc/dpkg/dpkg.cfg.d/00_blend done echo -n > /etc/apt/apt.conf.d/00_blend for init_mount in ${init_ro_mounts}; do printf 'DPkg::Pre-Invoke {"if findmnt %s >/dev/null; then umount -l %s; fi";};\n' \ "${init_mount}" "${init_mount}" >> /etc/apt/apt.conf.d/00_blend printf 'DPkg::Post-Invoke {"if [ -e /run/host/%s ] || [ -e /run/host/$(readlink -fm /run/host/%s) ]; then mount --rbind $(readlink -fm /run/host/%s) %s 2>/dev/null || mount --rbind /run/host/$(readlink -fm /run/host/%s) %s; fi";};\n' \ "${init_mount}" "${init_mount}" "${init_mount}" "${init_mount}" "${init_mount}" "${init_mount}" >> /etc/apt/apt.conf.d/00_blend done ### Section END elif [ -d "/usr/share/libalpm/scripts" ]; then echo "#!/bin/sh" > /usr/share/libalpm/scripts/00_blend_pre_hook.sh echo "#!/bin/sh" > /usr/share/libalpm/scripts/01_blend_post_hook.sh echo "#!/bin/sh" > /usr/share/libalpm/scripts/02_blend_post_hook.sh for net_mount in ${HOST_MOUNTS_RO}; do echo "findmnt ${net_mount} &>/dev/null && umount ${net_mount} || :" >> /usr/share/libalpm/scripts/00_blend_pre_hook.sh echo "test -e /run/host/${net_mount} && mount --rbind -o ro /run/host/${net_mount} ${net_mount} || :" >> /usr/share/libalpm/scripts/02_blend_post_hook.sh done echo -e '#!/bin/sh\necho -e "#!/bin/sh\nexit 0" > /usr/share/libalpm/scripts/systemd-hook' >/usr/share/libalpm/scripts/01_blend_post_hook.sh chmod 755 /usr/share/libalpm/scripts/*blend*.sh for p in 00_blend_pre_hook 01_blend_post_hook 02_blend_post_hook; do when=PostTransaction [[ -z "${p##*pre*}" ]] && when=PreTransaction cat << EOF > "/usr/share/libalpm/hooks/${p}.hook" [Trigger] Operation = Install Operation = Upgrade Type = Package Target = * [Action] Description = blend ${p} When = ${when} Exec = /usr/share/libalpm/scripts/${p}.sh EOF done fi mkdir -p /etc/sudoers.d if ! grep -q 'Defaults !fqdn' /etc/sudoers.d/sudoers &>/dev/null; then printf "Defaults !fqdn\n" >> /etc/sudoers.d/sudoers fi if ! grep -q "\"${_uname}\" ALL = (root) NOPASSWD:ALL" /etc/sudoers.d/sudoers &>/dev/null; then printf "\"%s\" ALL = (root) NOPASSWD:ALL\n" "$_uname" >> /etc/sudoers.d/sudoers fi if ! grep -q "^${_uname}:" /etc/group; then if ! groupadd --force --gid "$_cgid" "$_uname"; then printf "%s:x:%s:" "$_uname" "$_cgid" >> /etc/group fi fi useradd --uid "$_cuid" --gid "$_cgid" --shell "/bin/bash" --no-create-home --home "$_uhome" "$_uname" &>/dev/null chown root /etc/sudo.conf chown root /usr/bin/sudo chmod 4755 /usr/bin/sudo fi if ! command -v inotify-tools &>/dev/null; then if command -v apt-get &>/dev/null; then apt-get update &>/dev/null DEBIAN_FRONTEND=noninteractive apt-get -y install inotify-tools &>/dev/null elif command -v pacman &>/dev/null; then pacman --noconfirm -Syyu &>/dev/null pacman --noconfirm -Sy inotify-tools &>/dev/null elif command -v dnf &>/dev/null; then dnf install -y --allowerasing inotify-tools &>/dev/null fi fi source /run/.containerenv CONTAINER_NAME="$name" if [[ ! -f '/.init_blend.lock' ]] && command -v pacman &>/dev/null; then cd /; git clone https://aur.archlinux.org/yay.git &>/dev/null; cd yay chown -R "$_uname" . &>/log sudo -u "$_uname" makepkg --noconfirm -si &>/dev/null cd /; rm -rf yay touch /.init_blend.lock fi for full_file in /usr/bin/*; do if [[ -x "$full_file" ]]; then file="$(basename "${full_file}")" if [[ ! -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" ]]; then mkdir -p "${HOME}/.local/bin/blend_bin" echo "#!/bin/bash" > "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" echo '[ -f /run/.containerenv ] && { if [[ -e "/usr/bin/'"${file}"'" ]]; then /usr/bin/'"${file}"' "$@"; exit $?; else echo "This command can be accessed from the host, or from the container '"'${CONTAINER_NAME}'"'."; exit 127; fi } || :' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" echo 'BLEND_ALLOW_ROOT= BLEND_NO_CHECK= blend enter -cn '"${CONTAINER_NAME}"' -- '"${file}"' "$@"' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" chmod 755 "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" fi fi done mkdir -p /usr/share/applications touch "/usr/share/applications/empty_file.desktop" for full_file in /usr/share/applications/*.desktop; do file="$(basename "${full_file}")" mkdir -p "${HOME}/.local/share/applications" echo -n > "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" while read -r line; do if [[ $line == Name* ]]; then echo "${line} (container ${CONTAINER_NAME})" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" elif [[ $line == Exec* ]]; then echo "Exec=blend enter -cn ${CONTAINER_NAME} -- ${line:5}" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" elif [[ $line == Icon* ]]; then if [[ -e "${line:5}" ]]; then mkdir -p "${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}"; cp "${line:5}" "${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}" echo "Icon=${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}/$(basename "${line:5}")" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" else ICON_PATH="$(find /usr/share/icons/hicolor -type f -iname "*${line:5}*" -print -quit 2>/dev/null)" mkdir -p "$(dirname "${ICON_PATH}" | sed 's/\/usr\/share/'"\/home\/${_uname}"'\/.local\/share/g')" FINAL_ICON_PATH="$(dirname "${ICON_PATH}" | sed 's/\/usr\/share/'"\/home\/${_uname}"'\/.local\/share/g')/$(echo "${file%.*}").$(basename "${ICON_PATH}" | sed 's/^.*\.//')" cp "${ICON_PATH}" "${FINAL_ICON_PATH}" &>/dev/null echo "Icon=${FINAL_ICON_PATH}" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" fi else echo "$line" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" fi done < "/usr/share/applications/${file}" sed -i 's/DBusActivatable=true/DBusActivatable=false/g' "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" sed -i '/^TryExec/d' "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" chmod 755 "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" done echo "Completed container setup." mkdir -p /usr/share/applications /usr/bin inotifywait -m /usr/share/applications /usr/bin -e create,delete,move 2>/dev/null | while read dir action file; do ( if [[ "$dir" == "/usr/bin/" ]]; then if [[ "$action" == *"CREATE"* ]]; then if [[ ! -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" ]] && [[ -x "/usr/bin/${file}" ]]; then mkdir -p "${HOME}/.local/bin/blend_bin" echo "#!/bin/bash" > "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" echo '[ -f /run/.containerenv ] && { if [[ -e "/usr/bin/'"${file}"'" ]]; then /usr/bin/'"${file}"' "$@"; exit $?; else echo "This command can be accessed from the host, or from the container '"'${CONTAINER_NAME}'"'."; exit 127; fi } || :' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" echo 'BLEND_ALLOW_ROOT= BLEND_NO_CHECK= blend enter -cn '"${CONTAINER_NAME}"' -- '"${file}"' "$@"' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" chmod 755 "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" fi elif [[ "$action" == *"DELETE"* ]]; then rm -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" elif [[ "$action" == *"MOVED_FROM"* ]]; then rm -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" elif [[ "$action" == *"MOVED_TO"* ]]; then if [[ ! -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" ]] && [[ -x "/usr/bin/${file}" ]]; then mkdir -p "${HOME}/.local/bin/blend_bin" echo "#!/bin/bash" > "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" echo '[ -f /run/.containerenv ] && { if [[ -e "/usr/bin/'"${file}"'" ]]; then /usr/bin/'"${file}"' "$@"; exit $?; else echo "This command can be accessed from the host, or from the container '"'${CONTAINER_NAME}'"'."; exit 127; fi } || :' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" echo 'BLEND_ALLOW_ROOT= BLEND_NO_CHECK= blend enter -cn '"${CONTAINER_NAME}"' -- '"${file}"' "$@"' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" chmod 755 "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" fi fi fi ) & ( if [[ "$dir" == "/usr/share/applications/" ]]; then if [[ "$action" == *"CREATE"* ]] || [[ "$action" == *"MOVED_TO"* ]]; then if [[ "$file" == *'.desktop' ]]; then mkdir -p "${HOME}/.local/share/applications" echo -n > "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" while read -r line; do if [[ $line == Name* ]]; then echo "${line} (${CONTAINER_NAME})" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" elif [[ $line == Exec* ]]; then echo "Exec=blend enter -cn ${CONTAINER_NAME} -- ${line:5}" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" elif [[ $line == Icon* ]]; then if [[ -e "${line:5}" ]]; then mkdir -p "${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}"; cp "${line:5}" "${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}" echo "Icon=${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}/$(basename "${line:5}")" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" else ICON_PATH="$(find /usr/share/icons/hicolor -type f -iname "*${line:5}*" -print -quit 2>/dev/null)" mkdir -p "$(dirname "${ICON_PATH}" | sed 's/\/usr\/share/'"\/home\/${_uname}"'\/.local\/share/g')" FINAL_ICON_PATH="$(dirname "${ICON_PATH}" | sed 's/\/usr\/share/'"\/home\/${_uname}"'\/.local\/share/g')/$(echo "${file%.*}").$(basename "${ICON_PATH}" | sed 's/^.*\.//')" cp "${ICON_PATH}" "${FINAL_ICON_PATH}" &>/dev/null echo "Icon=${FINAL_ICON_PATH}" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" fi else echo "$line" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" fi done < "/usr/share/applications/${file}" sed -i 's/DBusActivatable=true/DBusActivatable=false/g' "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" sed -i '/^TryExec/d' "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" chmod 755 "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" fi elif [[ "$action" == *"DELETE"* ]]; then rm -f "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" elif [[ "$action" == *"MOVED_FROM"* ]]; then rm -f "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}" fi fi ) & done & while true; do for i in /etc/hosts /etc/localtime /etc/resolv.conf; do cp "/run/host/${i}" / &>/dev/null || : done sleep 5 done