├── .gitignore ├── RunDir ├── rootfs ├── usr │ ├── bin │ │ ├── cip │ │ ├── nocap │ │ ├── pac │ │ ├── tcpfw │ │ ├── getdimg │ │ ├── httpfw │ │ ├── packey │ │ ├── dbus-flmgr │ │ ├── hostexec │ │ ├── panelipmon │ │ ├── rim-build │ │ ├── rim-dinteg │ │ ├── rim-psmon │ │ ├── rim-shrink │ │ ├── rim-update │ │ ├── webm2gif │ │ ├── xclipfrom │ │ ├── xclipsync │ │ ├── rim-desktop │ │ └── rim-bootstrap │ └── share │ │ └── libalpm │ │ ├── scripts │ │ ├── update-rootfs │ │ ├── fix-ldconfig │ │ ├── fix-pamac │ │ ├── fix-gamemode │ │ └── fix-pacutils │ │ └── hooks │ │ ├── fix-pacutils.hook │ │ ├── update-rootfs.hook │ │ ├── fix-ldconfig.hook │ │ ├── fix-gamemode.hook │ │ ├── fix-pacstrap.hook │ │ ├── fix-resolvconf.hook │ │ ├── fix-pamac.hook │ │ ├── rebuild-runimage.hook │ │ ├── desktop-integration-remove.hook │ │ └── desktop-integration.hook └── var │ └── RunDir │ ├── utils │ ├── cip │ ├── pac │ ├── packey │ ├── webm2gif │ ├── dbus-flmgr │ ├── panelipmon │ ├── nocap │ ├── xclipsync │ ├── httpfw │ ├── xclipfrom │ ├── tcpfw │ ├── rim-update │ ├── rim-psmon │ ├── hostexec │ ├── rim-bootstrap │ ├── rim-desktop │ ├── rim-dinteg │ ├── rim-shrink │ ├── rim-build │ └── getdimg │ └── config │ └── dwarfs.prof ├── rim-bootstrap ├── screenshots └── rim-shell.png ├── PKGBUILD ├── LICENSE ├── examples ├── runimage-ubuntu.sh ├── runimage-debian.sh ├── runimage-void.sh ├── runimage-fedora.sh ├── steam.sh └── runimage-alpine-busybox.sh ├── utils.install ├── .github └── workflows │ └── ci.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.tar* 2 | -------------------------------------------------------------------------------- /RunDir: -------------------------------------------------------------------------------- 1 | rootfs/var/RunDir -------------------------------------------------------------------------------- /rootfs/usr/bin/cip: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/cip -------------------------------------------------------------------------------- /rootfs/usr/bin/nocap: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/nocap -------------------------------------------------------------------------------- /rootfs/usr/bin/pac: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/pac -------------------------------------------------------------------------------- /rootfs/usr/bin/tcpfw: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/tcpfw -------------------------------------------------------------------------------- /rim-bootstrap: -------------------------------------------------------------------------------- 1 | rootfs/var/RunDir/utils/rim-bootstrap -------------------------------------------------------------------------------- /rootfs/usr/bin/getdimg: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/getdimg -------------------------------------------------------------------------------- /rootfs/usr/bin/httpfw: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/httpfw -------------------------------------------------------------------------------- /rootfs/usr/bin/packey: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/packey -------------------------------------------------------------------------------- /rootfs/usr/bin/dbus-flmgr: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/dbus-flmgr -------------------------------------------------------------------------------- /rootfs/usr/bin/hostexec: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/hostexec -------------------------------------------------------------------------------- /rootfs/usr/bin/panelipmon: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/panelipmon -------------------------------------------------------------------------------- /rootfs/usr/bin/rim-build: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/rim-build -------------------------------------------------------------------------------- /rootfs/usr/bin/rim-dinteg: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/rim-dinteg -------------------------------------------------------------------------------- /rootfs/usr/bin/rim-psmon: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/rim-psmon -------------------------------------------------------------------------------- /rootfs/usr/bin/rim-shrink: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/rim-shrink -------------------------------------------------------------------------------- /rootfs/usr/bin/rim-update: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/rim-update -------------------------------------------------------------------------------- /rootfs/usr/bin/webm2gif: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/webm2gif -------------------------------------------------------------------------------- /rootfs/usr/bin/xclipfrom: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/xclipfrom -------------------------------------------------------------------------------- /rootfs/usr/bin/xclipsync: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/xclipsync -------------------------------------------------------------------------------- /rootfs/usr/bin/rim-desktop: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/rim-desktop -------------------------------------------------------------------------------- /rootfs/usr/bin/rim-bootstrap: -------------------------------------------------------------------------------- 1 | ../../var/RunDir/utils/rim-bootstrap -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/cip: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | curl -s ifconfig.io 2>/dev/null 3 | -------------------------------------------------------------------------------- /screenshots/rim-shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VHSgunzo/runimage/HEAD/screenshots/rim-shell.png -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/pac: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | if [ "$EUID" != 0 ] 3 | then sudo /usr/bin/pacman "$@" 4 | else /usr/bin/pacman "$@" 5 | fi 6 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/packey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | if [ "$EUID" != 0 ] 3 | then sudo /usr/bin/pacman-key "$@" 4 | else /usr/bin/pacman-key "$@" 5 | fi 6 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/scripts/update-rootfs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | unset LD_PRELOAD 3 | cp -rTf /var/rootfs /var/RunDir/rootfs 2>/dev/null 4 | rm -rf /var/rootfs/{,.[!.],..?}* 5 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/webm2gif: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ffmpeg -y -i "$1" -vf palettegen _tmp_palette.png 4 | ffmpeg -y -i "$1" -i _tmp_palette.png -filter_complex paletteuse -r 10 "${1%.webm}.gif" 5 | rm _tmp_palette.png 6 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/fix-pacutils.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Package 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = pacutils 6 | 7 | [Action] 8 | Description = Updating pacutils... 9 | When = PostTransaction 10 | Exec = /usr/share/libalpm/scripts/fix-pacutils 11 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/update-rootfs.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = var/rootfs/* 6 | 7 | [Action] 8 | Description = Updating rootfs... 9 | When = PostTransaction 10 | Exec = /usr/share/libalpm/scripts/update-rootfs 11 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/fix-ldconfig.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = usr/bin/ldconfig 6 | 7 | [Action] 8 | Description = Updating ldconfig... 9 | When = PostTransaction 10 | Exec = /usr/share/libalpm/scripts/fix-ldconfig 11 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/fix-gamemode.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = usr/bin/gamemoderun 6 | 7 | [Action] 8 | Description = Updating gamemode... 9 | When = PostTransaction 10 | Exec = /usr/share/libalpm/scripts/fix-gamemode 11 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/fix-pacstrap.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = usr/bin/pacstrap 6 | 7 | [Action] 8 | Description = Updating pacstrap... 9 | When = PostTransaction 10 | Exec = /usr/bin/sh -c 'sed -i "s|\$setup \"\$newroot\"|# &|" /usr/bin/pacstrap' 11 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/fix-resolvconf.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = usr/bin/resolvconf 6 | 7 | [Action] 8 | Description = Updating resolvconf... 9 | When = PostTransaction 10 | Exec = /usr/bin/sh -c 'sed -i "s|warn \"could not detect a useable init system\"|# &|g" /usr/bin/resolvconf' 11 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/fix-pamac.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = usr/bin/pamac 6 | Target = usr/bin/pamac-installer 7 | Target = usr/bin/pamac-manager 8 | Target = usr/bin/pamac-tray 9 | 10 | [Action] 11 | Description = Updating pamac... 12 | When = PostTransaction 13 | Exec = /usr/share/libalpm/scripts/fix-pamac 14 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/dbus-flmgr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | dbus-filemgr() { 4 | dbus-send --session --dest=org.freedesktop.FileManager1 \ 5 | --type=method_call /org/freedesktop/FileManager1 \ 6 | org.freedesktop.FileManager1.ShowItems array:string:"file://$@" string:"" 7 | } 8 | 9 | if [ -n "$1" ] 10 | then 11 | dbus-filemgr "$@" 12 | else 13 | dbus-filemgr "$HOME" 14 | fi 15 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/panelipmon: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | unset TOR_IP TORIP 3 | TOR_IP="$(proxychains -q curl 2ip.ru 2>/dev/null)" 4 | NET_DEV="$(ip route show default|awk '{print$5}'|head -1)" 5 | PUB_IP="$(curl ifconfig.io 2>/dev/null)" 6 | [ -n "$TOR_IP" ] && \ 7 | TORIP=" | TOR IP : $TOR_IP" 8 | echo -e "PUB IP : ${PUB_IP}${TORIP}\n\ 9 | NET $NET_DEV : $(ip route|grep -w "$NET_DEV"|grep -om1 'src .*'|awk '{print$2}')" 10 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/nocap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Use this to disable capabilities for run steam or another bubblewrap, if you don't disable capabilities by RIM_NO_CAP=1 3 | # $ nocap steam 4 | # See https://github.com/containers/bubblewrap/issues/380 5 | # And https://github.com/containers/bubblewrap/issues/397 6 | # Or Gamecope bug https://github.com/Plagman/gamescope/issues/309 7 | setpriv --ambient-caps '-all' "$@" 8 | # capsh --caps="" -- -c "$@" 9 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/scripts/fix-ldconfig: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | if [[ "$(head -c +4 '/usr/bin/ldconfig' 2>/dev/null)" =~ 'ELF' ]] 4 | then 5 | mv /usr/bin/ldconfig /usr/bin/_ldconfig 6 | echo '#!/usr/bin/env sh 7 | if [ -x /run/host/usr/sbin/_ldconfig ] 8 | then exec /run/host/usr/sbin/_ldconfig "$@" 2>/dev/null 9 | else exec _ldconfig "$@" 2>/dev/null 10 | fi' > /usr/bin/ldconfig 11 | chmod +x /usr/bin/ldconfig 12 | fi 13 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/rebuild-runimage.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = var/RunDir/Run* 6 | Target = var/RunDir/utils/* 7 | Target = var/RunDir/sharun/* 8 | Target = var/RunDir/static/* 9 | Target = var/RunDir/config/* 10 | 11 | [Action] 12 | Description = Updating RunDir... 13 | When = PostTransaction 14 | Exec = /usr/bin/sh -c 'if [[ -n "$RUNIMAGE" && -d "$RUNPIDDIR" ]];then /usr/bin/touch "$RUNPIDDIR/rebuild";fi' 15 | -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: VHSgunzo 2 | 3 | pkgname='runimage-utils' 4 | pkgver='0.43.1' 5 | pkgrel='1' 6 | pkgdesc='Utilities and scripts for RunImage container' 7 | url="https://github.com/VHSgunzo/runimage" 8 | arch=('any') 9 | license=('MIT') 10 | source=('runimage-utils.tar') 11 | sha256sums=('SKIP') 12 | depends=('pacutils') 13 | install='utils.install' 14 | 15 | package() { 16 | find "${srcdir}" -type f -name '.keep' -exec rm -f {} \; 17 | cp -arTf --no-preserve=ownership "$srcdir/rootfs" "$pkgdir" 18 | } 19 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/scripts/fix-pamac: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | for bin in pamac pamac-installer pamac-tray pamac-manager 4 | do 5 | if [[ "$(head -c +4 "/usr/bin/$bin" 2>/dev/null)" =~ 'ELF' ]] 6 | then 7 | mv -f "/usr/bin/$bin" "/usr/bin/_$bin" 8 | cat << EOF > "/usr/bin/$bin" 9 | #!/usr/bin/sh 10 | if [ "\$EUID" != 0 ] 11 | then sudo /usr/bin/_$bin "\$@" 12 | else /usr/bin/_$bin "\$@" 13 | fi 14 | EOF 15 | chmod +x "/usr/bin/$bin" 16 | fi 17 | done 18 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/xclipsync: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -z "$DISPLAY" || -z "$SYS_DISPLAY" ]] 4 | then 5 | echo 'clipsync: $DISPLAY and $SYS_DISPLAY must be set.' 6 | exit 99 7 | fi 8 | 9 | xclip -display "$SYS_DISPLAY" -selection CLIPBOARD -o|\ 10 | xclip -display "$DISPLAY" -selection CLIPBOARD -i 11 | while true 12 | do 13 | DISPLAY=$SYS_DISPLAY xclipfrom "$DISPLAY" $DESKTOP_KEY 2>/dev/null || exit 1 14 | DISPLAY=$DISPLAY xclipfrom "$SYS_DISPLAY" $DESKTOP_KEY 2>/dev/null || exit 1 15 | done 16 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/httpfw: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | is_exe_exist() { command -v "$@" &>/dev/null ; } 4 | 5 | if [ "$1" ] 6 | then local_port="$1" 7 | else 8 | echo "Specify the port for sharing!" 9 | exit 1 10 | fi 11 | if is_exe_exist cloudflared 12 | then cloudflared tunnel --url http://127.0.0.1:$local_port --no-autoupdate |& \ 13 | grep --line-buffered -A1 'has been created'|grep --line-buffered -o 'https.*\.com' 14 | else 15 | echo "Cloudflared client not found!" 16 | exit 1 17 | fi 18 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/scripts/fix-gamemode: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | echo '#!/usr/bin/bash 4 | [[ "$DBUS_SESSION_BUS_ADDRESS" =~ "unix:path=$RUNPIDDIR/rdbus" ]] && \ 5 | GAMEMODEDBUS="dbus-launch"||\ 6 | unset GAMEMODEDBUS 7 | GAMEMODEAUTO_NAME="libgamemodeauto.so.0" 8 | if ! pidof gamemoded &>/dev/null 9 | then 10 | nohup /usr/bin/gamemoded &>/dev/null & 11 | sleep 0.1 12 | fi 13 | exec $GAMEMODEDBUS env LD_PRELOAD="${GAMEMODEAUTO_NAME}${LD_PRELOAD:+:$LD_PRELOAD}" $GAMEMODERUNEXEC "$@" 14 | ' > /usr/bin/gamemoderun 15 | chmod +x /usr/bin/gamemoderun 16 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/xclipfrom: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env wish 2 | 3 | wm withdraw . 4 | 5 | set otherDisplay [lindex $argv 0] 6 | puts "proxying CLIPBOARD from $otherDisplay" 7 | 8 | proc handleSelection {offset maxChars} { 9 | global otherDisplay 10 | puts "CLIPBOARD data requested" 11 | variable result 12 | catch {exec -keepnewline xclip -display $otherDisplay -selection CLIPBOARD -o} result 13 | return $result 14 | } 15 | 16 | proc lostSelection {} { 17 | puts "lost selection\n" 18 | exit 0 19 | } 20 | 21 | selection handle -selection CLIPBOARD . handleSelection 22 | selection own -selection CLIPBOARD -command lostSelection . 23 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/scripts/fix-pacutils: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | for bin in pactrans pacrepairfile pacrepairdb 4 | do 5 | if [[ "$(head -c +4 "/usr/bin/$bin" 2>/dev/null)" =~ 'ELF' ]] 6 | then 7 | mv -f "/usr/bin/$bin" "/usr/bin/_$bin" 8 | cat << EOF > "/usr/bin/$bin" 9 | #!/usr/bin/sh 10 | if [ "\$EUID" != 0 ] 11 | then sudo /usr/bin/_$bin "\$@" 12 | else /usr/bin/_$bin "\$@" 13 | fi 14 | EOF 15 | 16 | chmod +x "/usr/bin/$bin" 17 | fi 18 | done 19 | 20 | for mode in install remove 21 | do 22 | rm -f "/usr/bin/pac$mode" 23 | 24 | cat << EOF > "/usr/bin/pac$mode" 25 | #!/usr/bin/sh 26 | /usr/bin/pactrans --$mode "\$@" 27 | EOF 28 | 29 | chmod +x "/usr/bin/pac$mode" 30 | done 31 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/tcpfw: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | serveo=serveo.net # 138.68.79.95 4 | 5 | is_exe_exist() { command -v "$@" &>/dev/null ; } 6 | 7 | if [ "$1" ] 8 | then local_port="$1" 9 | else 10 | echo "Specify the port for sharing!" 11 | exit 1 12 | fi 13 | 14 | [ "$2" ] && rem_port="$2"||\ 15 | rem_port=0 # random port 16 | 17 | if is_exe_exist autossh 18 | then SSH_ARGS=(autossh -M 0) 19 | elif is_exe_exist ssh 20 | then SSH_ARGS=(ssh) # To reconnect automatically, you need to install autossh 21 | else 22 | echo "SSH client not found!" 23 | exit 1 24 | fi 25 | 26 | "${SSH_ARGS[@]}" -o ServerAliveInterval=10 -o ServerAliveCountMax=3 \ 27 | -o TCPKeepAlive=yes -o ForwardAgent=no -o ForwardX11=no \ 28 | -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ 29 | -o LogLevel=ERROR -o IdentitiesOnly=yes \ 30 | -R $rem_port:127.0.0.1:$local_port $serveo|\ 31 | stdbuf -o0 awk '{print $NF}' 32 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/desktop-integration-remove.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Remove 4 | Target = usr/share/mime/application/* 5 | Target = usr/share/mime/audio/* 6 | Target = usr/share/mime/chemical/* 7 | Target = usr/share/mime/font/* 8 | Target = usr/share/mime/image/* 9 | Target = usr/share/mime/inode/* 10 | Target = usr/share/mime/message/* 11 | Target = usr/share/mime/model/* 12 | Target = usr/share/mime/multipart/* 13 | Target = usr/share/mime/packages/* 14 | Target = usr/share/mime/text/* 15 | Target = usr/share/mime/video/* 16 | Target = usr/share/mime/x-content/* 17 | Target = usr/share/mime/x-epoc/* 18 | Target = usr/share/icons/*.svg 19 | Target = usr/share/icons/*.png 20 | Target = usr/share/icons/hicolor/* 21 | Target = usr/share/applications/* 22 | Target = usr/share/desktop-directories/* 23 | Target = etc/xdg/menus/applications-merged/* 24 | 25 | [Action] 26 | Description = Remove desktop integration... 27 | When = PreTransaction 28 | Exec = /var/RunDir/utils/rim-dinteg --remove hook 29 | NeedsTargets 30 | -------------------------------------------------------------------------------- /rootfs/usr/share/libalpm/hooks/desktop-integration.hook: -------------------------------------------------------------------------------- 1 | [Trigger] 2 | Type = Path 3 | Operation = Install 4 | Operation = Upgrade 5 | Target = usr/share/mime/application/* 6 | Target = usr/share/mime/audio/* 7 | Target = usr/share/mime/chemical/* 8 | Target = usr/share/mime/font/* 9 | Target = usr/share/mime/image/* 10 | Target = usr/share/mime/inode/* 11 | Target = usr/share/mime/message/* 12 | Target = usr/share/mime/model/* 13 | Target = usr/share/mime/multipart/* 14 | Target = usr/share/mime/packages/* 15 | Target = usr/share/mime/text/* 16 | Target = usr/share/mime/video/* 17 | Target = usr/share/mime/x-content/* 18 | Target = usr/share/mime/x-epoc/* 19 | Target = usr/share/icons/*.svg 20 | Target = usr/share/icons/*.png 21 | Target = usr/share/icons/hicolor/* 22 | Target = usr/share/applications/* 23 | Target = usr/share/desktop-directories/* 24 | Target = etc/xdg/menus/applications-merged/* 25 | 26 | [Action] 27 | Description = Add desktop integration... 28 | When = PostTransaction 29 | Exec = /var/RunDir/utils/rim-dinteg --add hook 30 | NeedsTargets 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 VHSgunzo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/runimage-ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ARCH=$(uname -m) 5 | 6 | export RIM_NO_NVIDIA_CHECK=1 7 | 8 | if [ ! -x runimage ] 9 | then 10 | curl -L https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-$ARCH -o runimage 11 | chmod +x runimage 12 | fi 13 | 14 | rm -rf rootfs 15 | ./runimage getdimg -x rootfs ubuntu:latest 16 | 17 | echo -e 'nameserver 1.1.1.1\nnameserver 8.8.8.8' > rootfs/etc/resolv.conf 18 | 19 | RIM_ROOT=1 ./runimage sh -c 'apt update && apt install -y bash coreutils curl findutils gawk grep iproute2 \ 20 | kmod procps sed tar util-linux gnu-which gocryptfs libnotify-bin lsof slirp4netns socat x11-xserver-utils \ 21 | gzip xz-utils zstd lz4 jq binutils patchelf nftables iptables iputils-ping fakeroot fakechroot file dbus'||true 22 | 23 | curl -L https://raw.githubusercontent.com/VHSgunzo/runimage-fake-sudo-pkexec/refs/heads/main/usr/bin/sudo \ 24 | -o rootfs/usr/bin/sudo && chmod +x rootfs/usr/bin/sudo 25 | 26 | curl -sL https://github.com/VHSgunzo/runimage-fake-nvidia-driver/raw/refs/heads/main/fake-nvidia-driver.tar|\ 27 | tar -xvf- -C rootfs 28 | 29 | ./runimage rim-shrink --back --docs --locales --pkgcache --pycache 30 | 31 | ./runimage rim-build runimage-ubuntu -c 22 -b 24 32 | 33 | chmod u+rw -R rootfs 34 | rm -rf rootfs 35 | -------------------------------------------------------------------------------- /examples/runimage-debian.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ARCH=$(uname -m) 5 | 6 | export RIM_NO_NVIDIA_CHECK=1 7 | 8 | if [ ! -x runimage ] 9 | then 10 | curl -L https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-$ARCH -o runimage 11 | chmod +x runimage 12 | fi 13 | 14 | rm -rf rootfs 15 | ./runimage getdimg -x rootfs debian:latest 16 | 17 | echo -e 'nameserver 1.1.1.1\nnameserver 8.8.8.8' > rootfs/etc/resolv.conf 18 | 19 | RIM_ROOT=1 ./runimage sh -c 'apt update && apt install -y bash coreutils curl findutils gawk grep iproute2 \ 20 | kmod procps sed tar util-linux gnu-which gocryptfs libnotify-bin lsof slirp4netns socat x11-xserver-utils \ 21 | gzip xz-utils zstd lz4 jq binutils patchelf nftables iptables openresolv iputils-ping fakeroot fakechroot file dbus'||true 22 | 23 | curl -L https://raw.githubusercontent.com/VHSgunzo/runimage-fake-sudo-pkexec/refs/heads/main/usr/bin/sudo \ 24 | -o rootfs/usr/bin/sudo && chmod +x rootfs/usr/bin/sudo 25 | 26 | curl -sL https://github.com/VHSgunzo/runimage-fake-nvidia-driver/raw/refs/heads/main/fake-nvidia-driver.tar|\ 27 | tar -xvf- -C rootfs 28 | 29 | ./runimage rim-shrink --back --docs --locales --pkgcache --pycache 30 | 31 | ./runimage rim-build runimage-debian -c 22 -b 24 32 | 33 | chmod u+rw -R rootfs 34 | rm -rf rootfs 35 | -------------------------------------------------------------------------------- /examples/runimage-void.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ARCH=$(uname -m) 5 | 6 | export RIM_NO_NVIDIA_CHECK=1 7 | 8 | if [ ! -x runimage ] 9 | then 10 | curl -L https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-$ARCH -o runimage 11 | chmod +x runimage 12 | fi 13 | 14 | rm -rf rootfs 15 | ./runimage getdimg -x rootfs ghcr.io/void-linux/void-glibc:latest 16 | 17 | echo -e 'nameserver 1.1.1.1\nnameserver 8.8.8.8' > rootfs/etc/resolv.conf 18 | 19 | RIM_ROOT=1 ./runimage sh -c 'xbps-install -Syu xbps ; \ 20 | xbps-install -Sy bash coreutils curl findutils gawk grep iproute2 kmod \ 21 | procps-ng sed tar util-linux which gocryptfs libnotify lsof slirp4netns socat xhost gzip xz \ 22 | zstd lz4 jq binutils patchelf nftables iptables-nft openresolv iputils fakeroot file dbus ; ldconfig'||true 23 | 24 | curl -L https://raw.githubusercontent.com/VHSgunzo/runimage-fake-sudo-pkexec/refs/heads/main/usr/bin/sudo \ 25 | -o rootfs/usr/bin/sudo && chmod +x rootfs/usr/bin/sudo 26 | 27 | curl -sL https://github.com/VHSgunzo/runimage-fake-nvidia-driver/raw/refs/heads/main/fake-nvidia-driver.tar|\ 28 | tar -xvf- -C rootfs 29 | 30 | ./runimage rim-shrink --back --docs --locales --pkgcache --pycache 31 | 32 | ./runimage rim-build runimage-void -c 22 -b 24 33 | 34 | chmod u+rw -R rootfs 35 | rm -rf rootfs 36 | -------------------------------------------------------------------------------- /examples/runimage-fedora.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ARCH=$(uname -m) 5 | 6 | export RIM_NO_NVIDIA_CHECK=1 7 | 8 | if [ ! -x runimage ] 9 | then 10 | curl -L https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-$ARCH -o runimage 11 | chmod +x runimage 12 | fi 13 | 14 | rm -rf rootfs 15 | ./runimage getdimg -x rootfs fedora:latest 16 | 17 | echo -e 'nameserver 1.1.1.1\nnameserver 8.8.8.8' > rootfs/etc/resolv.conf 18 | 19 | RIM_ROOT=1 ./runimage sh -c 'yum copr enable nucleo/gocryptfs -y && yum update -y ; \ 20 | yum install -y bash coreutils curl findutils gawk grep iproute kmod procps-ng sed \ 21 | tar util-linux which gocryptfs libnotify lsof slirp4netns socat xhost gzip xz zstd \ 22 | lz4 jq binutils patchelf nftables iptables-nft openresolv iputils fakeroot fakechroot file dbus-tools'||true 23 | 24 | curl -L https://raw.githubusercontent.com/VHSgunzo/runimage-fake-sudo-pkexec/refs/heads/main/usr/bin/sudo \ 25 | -o rootfs/usr/bin/sudo && chmod +x rootfs/usr/bin/sudo 26 | 27 | curl -sL https://github.com/VHSgunzo/runimage-fake-nvidia-driver/raw/refs/heads/main/fake-nvidia-driver.tar|\ 28 | tar -xvf- -C rootfs 29 | 30 | ./runimage rim-shrink --back --docs --locales --pkgcache --pycache 31 | rm -rf rootfs/var/cache/libdnf*/* 32 | 33 | ./runimage rim-build runimage-fedora -c 22 -b 24 34 | 35 | chmod u+rw -R rootfs 36 | rm -rf rootfs 37 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/config/dwarfs.prof: -------------------------------------------------------------------------------- 1 | sharun/bin/bash 2 | rootfs/usr/lib/lib.path 3 | rootfs/usr/lib/ld-linux-x86-64.so.2 4 | rootfs/usr/bin/bash 5 | rootfs/usr/lib/libreadline.so.8.3 6 | rootfs/usr/lib/libc.so.6 7 | rootfs/usr/lib/libncursesw.so.6.5 8 | Run.sh 9 | rootfs/usr/bin/sed 10 | rootfs/usr/lib/libacl.so.1.1.2302 11 | rootfs/usr/bin/realpath 12 | rootfs/usr/bin/basename 13 | rootfs/usr/bin/tty 14 | rootfs/usr/bin/grep 15 | rootfs/usr/lib/libpcre2-8.so.0.15.0 16 | rootfs/usr/bin/cat 17 | sharun/bin/.version 18 | rootfs/.version 19 | rootfs/.type 20 | rootfs/.build 21 | sharun/bin/uruntime 22 | rootfs/usr/bin/mkdir 23 | rootfs/usr/bin/chmod 24 | rootfs/usr/bin/id 25 | rootfs/usr/lib/libnss_systemd.so.2 26 | rootfs/usr/lib/libm.so.6 27 | rootfs/usr/lib/libcap.so.2.77 28 | rootfs/usr/lib/libgcc_s.so.1 29 | rootfs/usr/bin/xhost 30 | rootfs/usr/lib/libXmuu.so.1.0.0 31 | rootfs/usr/lib/libX11.so.6.4.0 32 | rootfs/usr/lib/libxcb.so.1.1.0 33 | rootfs/usr/lib/libXau.so.6.0.0 34 | rootfs/usr/lib/libXdmcp.so.6.0.0 35 | rootfs/usr/bin/ls 36 | rootfs/usr/bin/head 37 | rootfs/usr/bin/date 38 | rootfs/usr/bin/sleep 39 | rootfs/usr/bin/tr 40 | sharun/bin/bwrap 41 | sharun/bin/cpids 42 | rootfs/usr/bin/gawk 43 | rootfs/usr/lib/libmpfr.so.6.2.2 44 | rootfs/usr/lib/libgmp.so.10.5.0 45 | sharun/bin/tini 46 | sharun/bin/ssrv 47 | rootfs/usr/bin/ps 48 | rootfs/usr/lib/libproc2.so.1.0.0 49 | rootfs/usr/lib/libsystemd.so.0.41.0 50 | rootfs/usr/bin/true 51 | rootfs/etc/ld.so.cache 52 | rootfs/usr/bin/rm 53 | rootfs/usr/bin/rmdir 54 | -------------------------------------------------------------------------------- /utils.install: -------------------------------------------------------------------------------- 1 | ## arg 1: the new package version 2 | #pre_install() { 3 | # do something here 4 | #} 5 | 6 | ## arg 1: the new package version 7 | post_install() { 8 | if [ -f '/usr/bin/pacstrap' ] && \ 9 | ! grep -q '# $setup' '/usr/bin/pacstrap' 10 | then sed -i 's|$setup "$newroot"|# &|' '/usr/bin/pacstrap' 11 | fi 12 | if [ -f '/usr/bin/resolvconf' ] && \ 13 | ! grep -q '# warn "could' '/usr/bin/resolvconf' 14 | then sed -i 's|warn "could not detect a useable init system"|# &|g' '/usr/bin/resolvconf' 15 | fi 16 | if [ -f '/usr/bin/pamac' ] 17 | then /usr/share/libalpm/scripts/fix-pamac 18 | fi 19 | if [ -f '/usr/bin/pactrans' ] 20 | then /usr/share/libalpm/scripts/fix-pacutils 21 | fi 22 | if [ -f '/usr/bin/ldconfig' ] 23 | then /usr/share/libalpm/scripts/fix-ldconfig 24 | fi 25 | if [ -f '/usr/bin/gamemoderun' ] && \ 26 | ! grep -q '/rdbus' '/usr/bin/gamemoderun' 27 | then /usr/share/libalpm/scripts/fix-gamemode 28 | fi 29 | } 30 | 31 | ## arg 1: the new package version 32 | ## arg 2: the old package version 33 | #pre_upgrade() { 34 | # do something here 35 | #} 36 | 37 | ## arg 1: the new package version 38 | ## arg 2: the old package version 39 | post_upgrade() { 40 | post_install 41 | } 42 | 43 | ## arg 1: the old package version 44 | #pre_remove() { 45 | # do something here 46 | #} 47 | 48 | ## arg 1: the old package version 49 | #post_remove() { 50 | # do something here 51 | #} 52 | -------------------------------------------------------------------------------- /examples/steam.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # An example of steam packaging in a RunImage container 5 | 6 | if [ ! -x 'runimage' ] 7 | then 8 | echo '== download base RunImage' 9 | curl -o runimage -L "https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-$(uname -m)" 10 | chmod +x runimage 11 | fi 12 | 13 | run_install() { 14 | set -e 15 | 16 | INSTALL_PKGS=( 17 | steam egl-wayland vulkan-radeon lib32-vulkan-radeon vulkan-tools vulkan-intel 18 | lib32-vulkan-intel vulkan-nouveau lib32-vulkan-nouveau vulkan-swrast lib32-vulkan-swrast 19 | lib32-libpipewire libpipewire pipewire lib32-libpipewire libpulse lib32-libpulse 20 | vulkan-mesa-layers lib32-vulkan-mesa-layers freetype2 lib32-freetype2 21 | ) 22 | 23 | echo '== checking for updates' 24 | rim-update 25 | 26 | echo '== install packages' 27 | pac --needed --noconfirm -S "${INSTALL_PKGS[@]}" 28 | 29 | echo '== install glibc with patches for Easy Anti-Cheat (optionally)' 30 | yes|pac -S glibc-eac lib32-glibc-eac 31 | 32 | echo '== shrink (optionally)' 33 | rim-shrink --all 34 | 35 | echo '== create RunImage config for app (optionally)' 36 | echo \ 37 | 'RIM_CMPRS_LVL="${RIM_CMPRS_LVL:=22}" 38 | RIM_CMPRS_BSIZE="${RIM_CMPRS_BSIZE:=24}" 39 | 40 | RIM_SHARE_ICONS="${RIM_SHARE_ICONS:=1}" 41 | RIM_SHARE_FONTS="${RIM_SHARE_FONTS:=1}" 42 | RIM_SHARE_THEMES="${RIM_SHARE_THEMES:=1}" 43 | 44 | RIM_UPDATE_SHRINK="${RIM_UPDATE_SHRINK:=1}"' \ 45 | > "$RUNDIR/config/steam.rcfg" 46 | 47 | echo '== Build new DwarFS runimage with zstd 22 lvl and 24 block size' 48 | rim-build -d -c 22 -b 24 steam.RunImage 49 | } 50 | export -f run_install 51 | 52 | ########################## 53 | 54 | # enable OverlayFS mode, disable Nvidia driver check and run install steps 55 | RIM_OVERFS_MODE=1 RIM_NO_NVIDIA_CHECK=1 \ 56 | ./runimage bash -c run_install 57 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ⚙️ Continuous bootstrap 📦 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "0 0 * * 0" #At 00:00 UTC on Sunday every Week 7 | 8 | jobs: 9 | bootstrap_and_release: 10 | name: runimage-bootstrap 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | with: 18 | path: main 19 | filter: "blob:none" 20 | 21 | - name: Install deps 22 | run: | 23 | sudo sh -c 'apt update && apt install qemu-user-static zsync -y' 24 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns <<<0 25 | docker pull tonistiigi/binfmt:latest 26 | docker run --privileged --rm tonistiigi/binfmt --uninstall qemu-* 27 | docker run --privileged --rm tonistiigi/binfmt --install all 28 | 29 | - name: Bootstrap RunImage 30 | run: | 31 | set -x ; set -e 32 | mkdir -p release && cd release||exit 1 33 | 34 | # x86_64 35 | ../main/rim-bootstrap 36 | zsyncmake runimage-x86_64 37 | 38 | # aarch64 39 | TARGETARCH=arm64 ../main/rim-bootstrap 40 | zsyncmake runimage-aarch64 41 | 42 | rm -f runimage 43 | 44 | echo "\ 45 | ----------------------------------------------------------------------------------------------------------------------------- 46 | * [runimage-x86_64](https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-x86_64) | [pkg_list-x86_64.txt](https://github.com/VHSgunzo/runimage/releases/download/continuous/pkg_list-x86_64.txt) 47 | ----------------------------------------------------------------------------------------------------------------------------- 48 | * [runimage-aarch64](https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-aarch64) | [pkg_list-aarch64.txt](https://github.com/VHSgunzo/runimage/releases/download/continuous/pkg_list-aarch64.txt) 49 | ----------------------------------------------------------------------------------------------------------------------------- 50 | " > ../RELEASE_NOTE.md 51 | 52 | - name: Release 53 | uses: softprops/action-gh-release@v2 54 | with: 55 | tag_name: "continuous" 56 | prerelease: false 57 | draft: false 58 | body_path: "RELEASE_NOTE.md" 59 | files: release/* 60 | -------------------------------------------------------------------------------- /examples/runimage-alpine-busybox.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ARCH=$(uname -m) 5 | 6 | export RIM_NO_NVIDIA_CHECK=1 7 | 8 | # musl has a little DNS crap 9 | export RIM_UNSHARE_RESOLVCONF=1 10 | 11 | if [ ! -x runimage ] 12 | then 13 | curl -L https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-$ARCH -o runimage 14 | chmod +x runimage 15 | fi 16 | 17 | rm -rf rootfs 18 | ./runimage getdimg -x rootfs alpine:latest 19 | chmod u+rw -R rootfs 20 | 21 | echo -e 'options timeout:2 attempts:3/nnameserver 1.1.1.1\nnameserver 8.8.8.8' > rootfs/etc/resolv.conf 22 | 23 | RIM_ROOT=1 ./runimage apk add bash coreutils curl findutils gawk grep iproute2 kmod procps-ng sed \ 24 | tar util-linux which gocryptfs libnotify lsof slirp4netns socat xhost gzip xz zstd lz4 jq binutils \ 25 | patchelf nftables iptables openresolv iputils file fakeroot dbus||true 26 | 27 | curl -L https://raw.githubusercontent.com/VHSgunzo/runimage-fake-sudo-pkexec/refs/heads/main/usr/bin/sudo \ 28 | -o rootfs/usr/bin/sudo && chmod +x rootfs/usr/bin/sudo 29 | 30 | ./runimage rim-shrink --back --docs --locales --pkgcache --pycache 31 | 32 | ./runimage rim-build runimage-alpine -c 22 -b 24 33 | 34 | chmod u+rw -R rootfs 35 | rm -rf rootfs 36 | 37 | ######################### 38 | 39 | rm -rf RunDir 40 | mkdir -p RunDir/config 41 | 42 | ./runimage-alpine bash -c '/var/RunDir/sharun/lib4bin -k -p -s -g -d RunDir/sharun $(cat /var/RunDir/sharun/bin.list) ; \ 43 | cp /var/RunDir/sharun/bin.list RunDir/sharun/ ; \ 44 | cp /var/RunDir/sharun/bin/.version RunDir/sharun/bin/ ; \ 45 | (cd RunDir && ln -sf sharun/bin static)' 46 | 47 | mkdir -p RunDir/rootfs/etc 48 | mkdir -p RunDir/rootfs/usr/lib 49 | ./runimage-alpine bash -c 'cp -fr /etc/ssl RunDir/rootfs/etc/' 50 | echo -e 'options timeout:2 attempts:3/nnameserver 1.1.1.1\nnameserver 8.8.8.8' > RunDir/rootfs/etc/resolv.conf 51 | 52 | ./runimage-alpine bash -c 'cp -f /var/RunDir/sharun/lib4bin RunDir/sharun/ ; \ 53 | cp -f /var/RunDir/sharun/bin/{bwrap,chisel,ssrv,tini,unionfs,uruntime,cpids} RunDir/sharun/bin/ ; \ 54 | (cd RunDir/sharun/bin && for bin in {dwarfs,dwarfsck,dwarfsextract,mkdwarfs,mksquashfs,squashfuse,unsquashfs}; \ 55 | do ln -sf uruntime "$bin"; done) ; \ 56 | cp -fr /var/RunDir/{utils,Run,Run.sh} RunDir/' 57 | 58 | ./runimage-alpine getdimg -x RunDir/rootfs busybox:musl 59 | 60 | RIM_ROOTFS=RunDir/rootfs ./RunDir/Run rim-shrink --back --docs --locales --pkgcache --pycache 61 | 62 | mkdir -p RunDir/config 63 | echo 'RIM_UNSHARE_RESOLVCONF="${RIM_UNSHARE_RESOLVCONF:=1}"' > RunDir/config/Run.rcfg 64 | 65 | ./RunDir/Run rim-build runimage-busybox -c 22 -b 24 66 | 67 | chmod u+rw -R RunDir 68 | rm -rf RunDir 69 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/rim-update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RED='\033[1;91m' 4 | GREEN='\033[1;92m' 5 | RESETCOLOR='\033[1;00m' 6 | 7 | [ -f "$RIMENVFL" ] && \ 8 | source "$RIMENVFL" 9 | 10 | [[ ! "$RUNTTY" =~ tty|pts ]] && \ 11 | NOT_TERM=1||NOT_TERM=0 12 | 13 | is_exe_exist() { command -v "$@" &>/dev/null ; } 14 | 15 | nocolor() { sed -r 's|\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]||g' ; } 16 | 17 | info_msg() { 18 | if [ "$RIM_QUIET_MODE" != 1 ] 19 | then echo -e "${GREEN}[ INFO ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 20 | if [[ "$NOT_TERM" == 1 && "$RIM_NOTIFY" == 1 ]] 21 | then notify-send -a 'RunImage Info' "$(echo -e "$@"|nocolor)" 2>/dev/null & 22 | fi 23 | fi 24 | } 25 | 26 | error_msg() { 27 | echo -e "${RED}[ ERROR ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 28 | if [ "$NOT_TERM" == 1 ] 29 | then notify-send -a 'RunImage Error' "$(echo -e "$@"|nocolor)" 2>/dev/null & 30 | fi 31 | } 32 | 33 | print_help() { 34 | echo -e "[ Usage ]: rim-update [OPTIONS] 35 | 36 | [ Options ]: 37 | --shrink Run rim-shrink --all after update (env: RIM_UPDATE_SHRINK=1) 38 | --cleanup Run rim-shrink --pkgcache after update (env: RIM_UPDATE_CLEANUP=1) 39 | -h, --help Show this message" 40 | exit 1 41 | } 42 | 43 | case "$1" in 44 | -h|--help) print_help ;; 45 | --shrink ) RIM_UPDATE_SHRINK=1 ;; 46 | --cleanup) RIM_UPDATE_CLEANUP=1 ;; 47 | esac 48 | 49 | export RIM_UPDATE_CLEANUP RIM_UPDATE_SHRINK 50 | if is_exe_exist pacman 51 | then 52 | PACKEYRINGS=(archlinux-keyring) 53 | 54 | grep "^\[chaotic-aur\]" "/etc/pacman.conf" &>/dev/null && \ 55 | PACKEYRINGS+=(chaotic-keyring) 56 | 57 | grep "^\[blackarch\]" "/etc/pacman.conf" &>/dev/null && \ 58 | PACKEYRINGS+=(blackarch-keyring) 59 | 60 | pac -Sy "${PACKEYRINGS[@]}" --needed --noconfirm && \ 61 | pactrans --sysupgrade --yolo||\ 62 | exit 1 63 | elif is_exe_exist apt 64 | then 65 | apt update && \ 66 | apt upgrade -y||\ 67 | exit 1 68 | elif is_exe_exist apk 69 | then 70 | apk -U upgrade||\ 71 | exit 1 72 | elif is_exe_exist xbps-install 73 | then 74 | xbps-install -Syu||\ 75 | exit 1 76 | else 77 | error_msg "The package manager cannot be detected!" 78 | exit 1 79 | fi 80 | 81 | unset PKGCACHE_ITEMS 82 | ([ -n "$(ls -A "/var/cache/pacman/pkg/" 2>/dev/null)" ]||\ 83 | [ -n "$(ls -A "/var/cache/apt/archives"/*.deb 2>/dev/null)" ]||\ 84 | [ -n "$(ls -A "/var/cache/apk/" 2>/dev/null)" ]||\ 85 | [ -n "$(ls -A "/var/cache/xbps/" 2>/dev/null)" ]) && \ 86 | PKGCACHE_ITEMS=1 87 | 88 | if [ "$RIM_UPDATE_SHRINK" == 1 ] 89 | then "$RUNUTILS/rim-shrink" --all 90 | elif [ "$RIM_UPDATE_CLEANUP" == 1 ] 91 | then 92 | info_msg "Cleanup rootfs..." 93 | RIM_QUIET_MODE=1 "$RUNUTILS/rim-shrink" --pkgcache 94 | fi 95 | 96 | if [ "$PKGCACHE_ITEMS" == 1 ] 97 | then touch "$RUNPIDDIR/is_pkgs" 98 | fi 99 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/rim-psmon: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export RED='\033[1;91m' 4 | export BLUE='\033[1;94m' 5 | export GREEN='\033[1;92m' 6 | export YELLOW='\033[1;33m' 7 | export RESETCOLOR='\033[1;00m' 8 | 9 | [[ ! "$RUNTTY" =~ tty|pts ]] && \ 10 | NOT_TERM=1||NOT_TERM=0 11 | 12 | red_msg() { echo -e "${RED}${@}${RESETCOLOR}" ; } 13 | blue_msg() { echo -e "${BLUE}${@}${RESETCOLOR}" ; } 14 | green_msg() { echo -e "${GREEN}${@}${RESETCOLOR}" ; } 15 | yellow_msg() { echo -e "${YELLOW}${@}${RESETCOLOR}" ; } 16 | 17 | rpids_ps() { 18 | set -o pipefail 19 | for rpid in "$@" 20 | do 21 | if [[ -n "$rpid" && -d "/proc/$rpid" ]] 22 | then 23 | red_msg "\n===========================================================" 24 | green_msg "Monitoring of processes from RUNPID: ${BLUE}$rpid" 25 | red_msg "-----------------------------------------------------------" 26 | echo "$(ps -fp $("$RUNSTATIC/cpids" "$rpid" 2>/dev/null) 2>/dev/null)" 27 | red_msg "===========================================================" 28 | else norpids="$(( norpids + 1 ))" 29 | fi 30 | done 31 | if [ "$norpids" == "${#@}" ] 32 | then kill -2 $(pgrep -fa watch|grep "rpids_check.*$RPIDSMONPID"|awk '{print$1}') 2>/dev/null 33 | fi 34 | } 35 | 36 | rpids_check() { 37 | IFS=$'\n' 38 | if [ -n "$A_RPIDS" ] 39 | then 40 | [[ "$A_RPIDS" =~ ^declare ]] && \ 41 | eval "$A_RPIDS" && unset A_RPIDS 42 | rpids_ps "${RPIDS[@]}" 43 | else 44 | RPIDS=($(ls -d "$RUNTMPDIR"/* 2>/dev/null|grep -v "$RUNPID"|awk -F/ '{print$NF}')) 45 | if [ -n "$RPIDS" ] 46 | then rpids_ps "${RPIDS[@]}" 47 | else 48 | green_msg "Waiting for RunImage containers..." 49 | return 1 50 | fi 51 | fi 52 | } 53 | 54 | rpids_check_loop() { watch -ctn 0.5 -x bash -c rpids_check $RPIDSMONPID ; } 55 | 56 | error_msg() { 57 | echo -e "${RED}[ ERROR ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 58 | if [ "$NOT_TERM" == 1 ] 59 | then notify-send -a 'RunImage Error' "$(echo -e "$@"|nocolor)" 2>/dev/null & 60 | fi 61 | } 62 | 63 | print_help() { 64 | echo -e "[ Usage ]: rim-psmon [OPTIONS] RUNPIDs 65 | 66 | [ Options ]: 67 | -p, --ps Print the list of RunImage processes 68 | -h, --help Show this message" 69 | exit 1 70 | } 71 | 72 | unset RPIDS_PS A_RPIDS RPIDS 73 | case "$1" in 74 | -h|--help) print_help ;; 75 | -p|--ps ) shift ; RPIDS_PS=1 ;; 76 | -*) error_msg "Unknown parameter: ${BLUE}$1\n"; print_help ;; 77 | esac 78 | 79 | if [ -n "$1" ] 80 | then 81 | RPIDS=("$@") 82 | export A_RPIDS="$(declare -p RPIDS 2>/dev/null)" 83 | fi 84 | 85 | export RPIDSMONPID=$BASHPID 86 | export -f rpids_check rpids_ps blue_msg \ 87 | red_msg green_msg yellow_msg 88 | 89 | if [ "$RPIDS_PS" == 1 ] 90 | then rpids_check $RPIDSMONPID 91 | else rpids_check_loop 92 | fi 93 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/hostexec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RED='\033[1;91m' 4 | BLUE='\033[1;94m' 5 | GREEN='\033[1;92m' 6 | YELLOW='\033[1;33m' 7 | RESETCOLOR='\033[1;00m' 8 | PATH="$PATH:$RUNSTATIC" 9 | SELFNAME="$(basename "$0")" 10 | 11 | [ -f "$RIMENVFL" ] && \ 12 | source "$RIMENVFL" 13 | 14 | [[ ! "$RUNTTY" =~ tty|pts ]] && \ 15 | NOT_TERM=1||NOT_TERM=0 16 | 17 | error_msg() { 18 | echo -e "${RED}[ ERROR ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 19 | if [ "$NOT_TERM" == 1 ] 20 | then notify-send -a 'RunImage Error' "$@" 2>/dev/null & 21 | fi 22 | } 23 | 24 | set_terminal() { 25 | if hostexec which konsole &>/dev/null 26 | then args+=("konsole" "-e") 27 | elif hostexec which gnome-terminal &>/dev/null 28 | then args+=("gnome-terminal" "--wait" "--") 29 | elif hostexec which xfce4-terminal &>/dev/null 30 | then args+=("xfce4-terminal" "--disable-server" "-x") 31 | elif hostexec which qterminal &>/dev/null 32 | then args+=("qterminal" "-e") 33 | elif hostexec which kitty &>/dev/null 34 | then args+=("kitty" "-e") 35 | elif hostexec which deepin-terminal &>/dev/null 36 | then args+=("deepin-terminal" "-e") 37 | elif hostexec which lxterminal &>/dev/null 38 | then args+=("lxterminal" "-e") 39 | elif hostexec which roxterm &>/dev/null 40 | then args+=("roxterm" "-e") 41 | elif hostexec which alacritty &>/dev/null 42 | then args+=("alacritty" "-e") 43 | elif hostexec which tilix &>/dev/null 44 | then args+=("tilix" "-e") 45 | elif hostexec which st &>/dev/null 46 | then args+=("st" "-e") 47 | elif hostexec which cool-retro-term &>/dev/null 48 | then args+=("cool-retro-term" "-e") 49 | elif hostexec which xterm &>/dev/null 50 | then args+=("xterm" "-bg" "black" "-fg" "white" "-e") 51 | elif hostexec which sakura &>/dev/null # next terminals don't recognize spaces 52 | then args+=("sakura" "-e") 53 | elif hostexec which terminology &>/dev/null 54 | then args+=("terminology" "-e") 55 | elif hostexec which terminator &>/dev/null 56 | then args+=("terminator" "-e") # need 57 | elif hostexec which tilda &>/dev/null 58 | then args+=("tilda" "-c") 59 | else 60 | error_msg "The terminal application cannot be detected!" 61 | return 1 62 | fi 63 | } 64 | 65 | set_supassapp() { 66 | if hostexec which pkexec &>/dev/null 67 | then args+=("pkexec") 68 | elif hostexec which kdesu &>/dev/null 69 | then args+=("kdesu" "--noignorebutton" "-t") 70 | elif hostexec which gksudo &>/dev/null 71 | then args+=("gksudo") 72 | elif hostexec which gksu &>/dev/null 73 | then args+=("gksu") 74 | elif hostexec which sudo &>/dev/null 75 | then 76 | set_terminal && \ 77 | args+=("sudo") || \ 78 | return 1 79 | else 80 | error_msg "The app for requesting the superuser pass not found!" 81 | return 1 82 | fi 83 | } 84 | 85 | print_help() { 86 | echo -e "[ Usage ]: hostexec [OPTIONS] {executable} {executable args} 87 | 88 | [ Options ]: 89 | -su, --superuser {args} Execute command as superuser 90 | -t, --terminal {args} Execute command in host terminal 91 | -h, --help Show this message" 92 | exit 1 93 | } 94 | 95 | if [ -e "$RIM_HEXEC_SOCK" ] 96 | then 97 | if [ "$SELFNAME" != 'hostexec' ] 98 | then args=("$SELFNAME") 99 | else 100 | unset args 101 | while [[ $# -gt 0 ]] 102 | do 103 | case "$1" in 104 | -h |--help) print_help ; exit 0 ;; 105 | -t |--terminal) shift ; set_terminal || exit 1 ;; 106 | -su|--superuser) shift ; set_supassapp || exit 1 ;; 107 | *) break ;; 108 | esac 109 | done 110 | fi 111 | [ "$RIM_EXEC_SAME_PWD" == 1 ] && \ 112 | export SSRV_CWD="$PWD" 113 | SSRV_SOCK="unix:$RIM_HEXEC_SOCK" \ 114 | exec /var/RunDir/static/ssrv "${args[@]}" "$@" 115 | else 116 | error_msg "HOSTEXEC socket not found!" 117 | exit 1 118 | fi 119 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/rim-bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | shopt -s extglob 4 | SYS_ARCH="$(uname -m)" 5 | 6 | # disable Nvidia driver check and RunImage messages 7 | export RIM_NO_NVIDIA_CHECK=1 RIM_QUIET_MODE=1 8 | 9 | if [[ ! -x 'runimage' && ! -x 'RunDir/Run' ]] 10 | then 11 | echo '== get base runimage' 12 | curl -o runimage -L "https://github.com/VHSgunzo/runimage/releases/download/continuous/runimage-$SYS_ARCH" 13 | chmod +x runimage 14 | fi 15 | 16 | cleanup() { 17 | echo '== cleanup' 18 | [ -d rootfs ] && \ 19 | chmod u+rw -R rootfs 20 | [ -d RunDir ] && \ 21 | chmod u+rw -R RunDir 22 | rm -rf rootfs RunDir uruntime 23 | } 24 | 25 | trap 'cleanup' EXIT INT TERM 26 | 27 | if [ ! -x 'RunDir/Run' ] 28 | then 29 | echo '== extract base RunImage' 30 | ./runimage --runtime-extract 31 | fi 32 | 33 | # (use TARGETARCH env var for get custom ARCH image) 34 | echo '== get and extract docker image to rootfs dir' 35 | rm -rf rootfs 36 | sysdrm=( 37 | systemd dbus-broker dbus-broker-units 38 | dbus-units device-mapper cryptsetup kbd popt 39 | ) 40 | if [[ ! -n "$TARGETARCH" && "$SYS_ARCH" == 'x86_64' ]] 41 | then 42 | dimg_repo='archlinux:base' 43 | sysdrm+=(systemd-sysvcompat) 44 | else 45 | dimg_repo='lopsided/archlinux:latest' 46 | fi 47 | ./RunDir/Run getdimg --extract rootfs "${dimg_repo}" 48 | 49 | echo '== prepare rootfs' 50 | export RIM_ROOT=1 51 | echo -e 'nameserver 1.1.1.1\nnameserver 8.8.8.8' > rootfs/etc/resolv.conf 52 | rm -f rootfs/usr/share/libalpm/hooks/{package-cleanup,man-page-remove}.hook 53 | ./RunDir/Run rim-shrink 54 | ./RunDir/Run pacman --noconfirm -Rdd "${sysdrm[@]}" 55 | ROOTFS_ARCH="$(./RunDir/Run uname -m 2>/dev/null)" 56 | 57 | echo '== update rootfs' 58 | ## https://runimage-repo.static.hf.space 59 | ## https://github.com/runimage/repo/releases/download 60 | ./RunDir/Run pacman -Sy archlinux-keyring --needed --noconfirm 61 | ./RunDir/Run pacman --noconfirm -U "https://github.com/runimage/repo/releases/download/$ROOTFS_ARCH/runimage-mirrorlist.pkg.tar.zst" 62 | yes|./RunDir/Run pacman -Syu --overwrite '*' 63 | 64 | echo '== add BlackArch repo' 65 | if [ ! -x '/tmp/strap.sh' ] 66 | then 67 | curl -L https://blackarch.org/strap.sh -o /tmp/strap.sh 68 | sed -i '/blackarch-officials/d' /tmp/strap.sh 69 | chmod +x /tmp/strap.sh 70 | fi 71 | ./RunDir/Run /tmp/strap.sh 72 | ./RunDir/Run pacman --noconfirm -S blackarch-keyring --overwrite '*' 73 | 74 | if [ "$ROOTFS_ARCH" == 'x86_64' ] 75 | then 76 | echo '== add Chaotic-AUR repo' 77 | ./RunDir/Run pacman-key --recv-key 3056513887B78AEB --keyserver keyserver.ubuntu.com 78 | ./RunDir/Run pacman-key --lsign-key 3056513887B78AEB 79 | ./RunDir/Run pacman --noconfirm -U https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-keyring.pkg.tar.zst 80 | ./RunDir/Run pacman --noconfirm -U https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-mirrorlist.pkg.tar.zst 81 | fi 82 | 83 | echo '== install base RunImage packages' 84 | BASE_PKGS=( 85 | # bash coreutils curl findutils gawk grep iproute2 86 | # kmod procps-ng sed tar util-linux which gocryptfs 87 | # libnotify lsof slirp4netns socat xorg-xhost gzip 88 | # xz zstd lz4 jq binutils patchelf file 89 | runimage-utils runimage-static runimage-rootfs 90 | fake-sudo-pkexec fake-systemd Run-wrapper 91 | fakeroot fakechroot iptables-nft nftables 92 | openresolv iputils 93 | ) 94 | if [ "$SYS_ARCH" != "$ROOTFS_ARCH" ] 95 | then cp -Trf 'RunDir/sharun' "RunDir/sharun-$SYS_ARCH" 96 | fi 97 | yes|./RunDir/Run pacman --overwrite '*' -S "${BASE_PKGS[@]}" 98 | if [ -d "RunDir/sharun-$SYS_ARCH" ] 99 | then 100 | cp -Tr RunDir/sharun "RunDir/sharun-$ROOTFS_ARCH" 101 | rm -rf RunDir/sharun 102 | mv "RunDir/sharun-$SYS_ARCH" RunDir/sharun 103 | fi 104 | 105 | if [ "$ROOTFS_ARCH" == 'x86_64' ] 106 | then 107 | echo '== install lib32 packages' 108 | ./RunDir/Run pacman --noconfirm -Sy lib32-glibc lib32-fakeroot lib32-fakechroot 109 | 110 | echo '== install fake Nvidia driver' 111 | ./RunDir/Run pacman --noconfirm -Sy fake-nvidia-driver 112 | fi 113 | 114 | echo '== update locales' 115 | # cat < rootfs/etc/locale.gen 116 | # ar_EG.UTF-8 UTF-8 117 | # en_US.UTF-8 UTF-8 118 | # en_GB.UTF-8 UTF-8 119 | # en_CA.UTF-8 UTF-8 120 | # en_SG.UTF-8 UTF-8 121 | # es_MX.UTF-8 UTF-8 122 | # zh_CN.UTF-8 UTF-8 123 | # fr_FR.UTF-8 UTF-8 124 | # ru_RU.UTF-8 UTF-8 125 | # ru_UA.UTF-8 UTF-8 126 | # es_ES.UTF-8 UTF-8 127 | # de_DE.UTF-8 UTF-8 128 | # pt_BR.UTF-8 UTF-8 129 | # it_IT.UTF-8 UTF-8 130 | # id_ID.UTF-8 UTF-8 131 | # ja_JP.UTF-8 UTF-8 132 | # bg_BG.UTF-8 UTF-8 133 | # pl_PL.UTF-8 UTF-8 134 | # da_DK.UTF-8 UTF-8 135 | # ko_KR.UTF-8 UTF-8 136 | # tr_TR.UTF-8 UTF-8 137 | # hu_HU.UTF-8 UTF-8 138 | # cs_CZ.UTF-8 UTF-8 139 | # bn_IN UTF-8 140 | # hi_IN UTF-8 141 | # EOF 142 | ./RunDir/Run pacman --noconfirm -Sy glibc 143 | 144 | # optional 145 | echo '== remove python and perl' 146 | ./RunDir/Run pacman --noconfirm -Rsndd python perl 147 | 148 | if [ -n "$1" ] 149 | then 150 | echo '== install additional packages' 151 | ./RunDir/Run pacman --noconfirm -Sy "$@" 152 | fi 153 | 154 | echo '== shrink backup files, docs, man, locales, package cache, python cache, strip debug symbols' 155 | ./RunDir/Run rim-shrink --back --docs --locales --pkgcache --pycache --strip 156 | 157 | echo "== create pkg_list.txt" 158 | ./RunDir/Run rim-pkgls > "pkg_list-${ROOTFS_ARCH}.txt" 159 | 160 | echo '== build new runimage' 161 | if [ -d "RunDir/sharun-$ROOTFS_ARCH" ] 162 | then 163 | [ ! -x 'uruntime' ] && \ 164 | cp -f RunDir/static/uruntime . 165 | rm -rf RunDir/sharun RunDir/rootfs 166 | mv "RunDir/sharun-$ROOTFS_ARCH" RunDir/sharun 167 | mv rootfs RunDir/rootfs 168 | date '+%y.%m.%d.%H%M%S' > RunDir/rootfs/.build 169 | ./uruntime --runtime-mkdwarfs -f --set-owner 0 --set-group 0 --no-history --log-level error \ 170 | --no-create-timestamp --header RunDir/static/uruntime --chmod u+rw \ 171 | -i RunDir -o "runimage-$ROOTFS_ARCH" -B16 --compression zstd:level=22 -S26 172 | chmod +x "runimage-$ROOTFS_ARCH" 173 | else ./RunDir/Run rim-build -d -b 26 -z -c 22 "runimage-$ROOTFS_ARCH" 174 | fi 175 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/rim-desktop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RED='\033[1;91m' 4 | BLUE='\033[1;94m' 5 | GREEN='\033[1;92m' 6 | YELLOW='\033[1;33m' 7 | RESETCOLOR='\033[1;00m' 8 | 9 | [ -f "$RIMENVFL" ] && \ 10 | source "$RIMENVFL" 11 | 12 | [[ ! "$RUNTTY" =~ tty|pts ]] && \ 13 | NOT_TERM=1||NOT_TERM=0 14 | 15 | export GDK_BACKEND=x11 16 | export XDG_SESSION_TYPE=x11 17 | export DESKTOP_KEY="$BASHPID" 18 | export SYS_DISPLAY="$DISPLAY" 19 | RIM_DESKTOP_DISPLAY="${RIM_DESKTOP_DISPLAY:=1337}" 20 | 21 | nocolor() { sed -r 's|\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]||g' ; } 22 | 23 | error_msg() { 24 | echo -e "${RED}[ ERROR ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 25 | if [ "$NOT_TERM" == 1 ] 26 | then notify-send -a 'RunImage Error' "$(echo -e "$@"|nocolor)" 2>/dev/null & 27 | fi 28 | } 29 | 30 | info_msg() { 31 | if [ "$RIM_QUIET_MODE" != 1 ] 32 | then echo -e "${GREEN}[ INFO ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 33 | if [[ "$NOT_TERM" == 1 && "$RIM_NOTIFY" == 1 ]] 34 | then notify-send -a 'RunImage Info' "$(echo -e "$@"|nocolor)" 2>/dev/null & 35 | fi 36 | fi 37 | } 38 | 39 | warn_msg() { 40 | if [[ "$RIM_QUIET_MODE" != 1 && "$RIM_NO_WARN" != 1 ]] 41 | then echo -e "${YELLOW}[ WARNING ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 42 | if [[ "$NOT_TERM" == 1 && "$RIM_NOTIFY" == 1 ]] 43 | then notify-send -a 'RunImage Warning' "$(echo -e "$@"|nocolor)" 2>/dev/null & 44 | fi 45 | fi 46 | } 47 | 48 | is_exe_exist() { command -v "$@" &>/dev/null ; } 49 | 50 | is_not_ro() { 51 | if [ ! -w "$RUNROOTFS" ] 52 | then 53 | error_msg "Unable to install dependencies. Read-only!" 54 | exit 1 55 | fi 56 | } 57 | 58 | is_pid() { [[ -n "$1" && -d "/proc/$1" ]]; } 59 | 60 | empty_msg() { 61 | error_msg "${YELLOW}Option ${BLUE}$1 ${YELLOW}requires a non-empty argument!\n" 62 | print_help 63 | } 64 | 65 | print_help() { 66 | echo -e "[ Usage ]: rim-desktop [OPTIONS] 67 | 68 | [ Options ]: 69 | -d, --display Sets \$DISPLAY (env: RIM_DESKTOP_DISPLAY=1337) 70 | -f, --fullscreen Starts Xephyr in fullscreen mode (env: RIM_XEPHYR_FULLSCREEN=1) 71 | -h, --help Show this message 72 | -s, --size Sets Xephyr resolution (env: RIM_XEPHYR_SIZE=1600x900) 73 | -u, --unclip Disables clipboard synchronization (env: RIM_DESKTOP_UNCLIP=1)" 74 | exit 1 75 | } 76 | 77 | while [[ $# -gt 0 ]] 78 | do 79 | case "$1" in 80 | -h|--help ) print_help ;; 81 | -f|--fullscreen) RIM_XEPHYR_FULLSCREEN=1 ;; 82 | -u|--unclip ) RIM_DESKTOP_UNCLIP=1 ;; 83 | -d|--display ) 84 | if [[ -n "$2" && "$2" != -* ]] 85 | then RIM_DESKTOP_DISPLAY="$2"; shift 86 | else empty_msg "$1" 87 | fi ;; 88 | -s|--size ) 89 | if [[ -n "$2" && "$2" != -* ]] 90 | then RIM_XEPHYR_SIZE="$2"; shift 91 | else empty_msg "$1" 92 | fi ;; 93 | -*) error_msg "Unknown parameter: ${BLUE}$1\n"; print_help ;; 94 | esac 95 | shift 96 | done 97 | 98 | if [[ "$RUNTTY" =~ "tty" && ! -d '/run/udev' ]] 99 | then 100 | error_msg "/run/udev not found in RunImage container!" 101 | [ "$FORCE_KILL_PPID" != 1 ]||sleep 3 102 | exit 1 103 | elif [[ "$RIM_UNSHARE_DBUS" != 1 || "$RIM_UNSHARE_PIDS" != 1 ]]||\ 104 | [[ "$RUNTTY" =~ "tty" && "$FORCE_KILL_PPID" != 1 ]] 105 | then 106 | error_msg "Launch the RunImage desktop from the outside!" 107 | echo -e "$GREEN$ $RUNSRCNAME rim-desktop" 108 | exit 1 109 | fi 110 | 111 | [[ "$INSIDE_RUNIMAGE" == 1 && ! -d "$RUNROOTFS" ]] && \ 112 | RUNROOTFS='/' 113 | 114 | if is_exe_exist pacman 115 | then 116 | if [ "$(pacman -Qq xorg-server tk tcl xclip xfce4-session pavucontrol qt5ct 2>/dev/null|wc -l)" != "7" ] && is_not_ro 117 | then 118 | info_msg "Installing the necessary dependencies..." 119 | pac -Syu --noconfirm && \ 120 | pac --needed --noconfirm -S extra/xorg tk tcl xclip xfce4 xfce4-goodies pavucontrol qt5ct && \ 121 | pac --noconfirm -Rdd xfce4-screensaver xfce4-power-manager||\ 122 | exit 1 123 | fi 124 | elif is_exe_exist apk 125 | then 126 | if [ "$(apk list xorg-server xorg-server-xephyr tk tcl xclip xfce4-session pavucontrol 2>/dev/null|\ 127 | grep installed|\ 128 | grep -E '^xorg-server-[0-9]|^xorg-server-xephyr-[0-9]|^tk-[0-9]|^tcl-[0-9]|^xclip-[0-9]|^xfce4-session-[0-9]|^pavucontrol-[0-9]'|wc -l)" != "7" ] && \ 129 | is_not_ro 130 | then 131 | info_msg "Installing the necessary dependencies..." 132 | apk add xorg-server xorg-server-xephyr tk tcl xclip xfce4 xfce4-terminal pavucontrol||\ 133 | exit 1 134 | fi 135 | elif is_exe_exist apt 136 | then 137 | if [ "$(dpkg --get-selections|awk '{print$1}'|\ 138 | grep -Ew '^xserver-xorg$|^xserver-xephyr$|^tk$|^tcl$|^xclip$|^xfce4-session$|^pavucontrol$|^qt5ct$'|\ 139 | wc -l)" != "8" ] && is_not_ro 140 | then 141 | info_msg "Installing the necessary dependencies..." 142 | sudo apt update && \ 143 | sudo apt upgrade -y && \ 144 | sudo apt install task-xfce-desktop xorg tk tcl xclip xfce4 \ 145 | xfce4-goodies pavucontrol xserver-xephyr qt5ct -y||\ 146 | exit 1 147 | fi 148 | elif is_exe_exist xbps-install 149 | then 150 | if [ "$(xbps-query --list-pkgs|awk '{print$2}'|\ 151 | grep -E '^xorg-server-[0-9]|^xorg-server-xephyr-[0-9]|^tk-[0-9]|^tcl-[0-9]|^xclip-[0-9]|^xfce4-session-[0-9]|^pavucontrol-[0-9]|^qt5ct-[0-9]'|\ 152 | wc -l)" != "7" ] && is_not_ro 153 | then 154 | info_msg "Installing the necessary dependencies..." 155 | xbps-install -Syu && \ 156 | xbps-install -Sy xorg-server xorg-fonts xorg-server-xephyr tk tcl xclip xfce4 xfce4-terminal pavucontrol pipewire qt5ct||\ 157 | exit 1 158 | fi 159 | else 160 | error_msg "The package manager cannot be detected!" 161 | exit 1 162 | fi 163 | 164 | [ ! -e '/usr/bin/pm-is-supported' ] && \ 165 | ln -sf /bin/false /usr/bin/pm-is-supported 166 | 167 | # PID randomizer (UNSHARE_PIDS ICEauthority bug) 168 | [ "$RIM_UNSHARE_PIDS" == 1 ] && \ 169 | for _ in $(seq 0 $(echo $RANDOM|head -c 2)) ; do /usr/bin/true ; done 170 | 171 | while true 172 | do 173 | [ ! -f "/tmp/.X$RIM_DESKTOP_DISPLAY-lock" ] && \ 174 | break 175 | RIM_DESKTOP_DISPLAY="$(( $RIM_DESKTOP_DISPLAY + 1 ))" 176 | done 177 | 178 | unset RUN_X 179 | if [[ "$RUNTTY" =~ "tty" ]] 180 | then 181 | export DISPLAY=:$RIM_DESKTOP_DISPLAY 182 | info_msg "Xorg DISPLAY=$DISPLAY" 183 | unset XEPHYR RIM_XEPHYR_FULLSCREEN \ 184 | RIM_XEPHYR_SIZE XEPHYR_DISPLAY 185 | if [ -x "/usr/lib/Xorg.wrap" ] 186 | then XORG="/usr/lib/Xorg.wrap" 187 | elif [ -x "/usr/bin/Xorg" ] 188 | then XORG="/usr/bin/Xorg" 189 | elif [ -x "/usr/bin/X" ] 190 | then XORG="/usr/bin/X" 191 | else XORG="/bin/Xorg" 192 | fi 193 | $XORG -nolisten tcp vt$XDG_VTNR $DISPLAY & 194 | export XORG_PID="$!" 195 | sleep 0.01 196 | is_pid "$XORG_PID" && RUN_X=1 || \ 197 | error_msg "Failed to start Xorg!" 198 | else 199 | [ -n "$DISPLAY" ] && \ 200 | XEPHYR=1||unset XEPHYR 201 | fi 202 | 203 | if [[ "$XEPHYR" == 1 || "$RIM_XEPHYR_FULLSCREEN" == 1 || -n "$RIM_XEPHYR_SIZE" ]] 204 | then 205 | XEPHYR_DISPLAY=:$RIM_DESKTOP_DISPLAY 206 | info_msg "Xephyr DISPLAY=$XEPHYR_DISPLAY" 207 | if [ "$RIM_XEPHYR_FULLSCREEN" == 1 ] 208 | then 209 | info_msg "Xephyr in full-screen mode" 210 | elif [ ! -n "$RIM_XEPHYR_SIZE" ] 211 | then 212 | RIM_XEPHYR_SIZE="1600x900" 213 | info_msg "Xephyr screen resolution: 1600x900" 214 | elif [ -n "$RIM_XEPHYR_SIZE" ] 215 | then 216 | RIM_XEPHYR_SIZE="$RIM_XEPHYR_SIZE" 217 | info_msg "Xephyr screen resolution: $RIM_XEPHYR_SIZE" 218 | fi 219 | Xephyr $([ "$RIM_XEPHYR_FULLSCREEN" == 1 ] && echo "-fullscreen"||echo "-screen $RIM_XEPHYR_SIZE") \ 220 | +extension GLX +iglx -resizeable -br -title "RunImage Desktop [$XEPHYR_DISPLAY]" \ 221 | -once -ac -name 'RunImage' $XEPHYR_DISPLAY &>/dev/null & 222 | export XEPHYR_PID="$!" 223 | sleep 0.01 224 | if is_pid "$XEPHYR_PID" 225 | then 226 | export DISPLAY=$XEPHYR_DISPLAY 227 | RUN_X=1 228 | else 229 | error_msg "Failed to start Xephyr!" 230 | fi 231 | fi 232 | 233 | EXEC_STATUS=1 234 | if [ "$RUN_X" == 1 ] 235 | then 236 | run_xfce4() { 237 | unset -f run_xfce4 238 | unset WAYLAND_DISPLAY XDG_MENU_PREFIX XDG_SESSION_DESKTOP \ 239 | DESKTOP_SESSION XDG_CURRENT_DESKTOP 240 | (try_count=0 241 | while is_pid "$XORG_PID" || is_pid "$XEPHYR_PID" 242 | do 243 | if [ "$try_count" -le 5 ] 244 | then 245 | (( try_count++ )) 246 | sleep 0.1 247 | xfwm4 --replace --vblank=xpresent --sm-client-disable --compositor=on 248 | else 249 | error_msg "Failed to start xfwm4!" 250 | break 251 | fi 252 | done) & 253 | XFWM_PID="$!" 254 | unset -f is_pid 255 | sleep 0.1 256 | if [[ -n "$SYS_DISPLAY" && "$RIM_DESKTOP_UNCLIP" != 1 ]] 257 | then 258 | xclipsync & 259 | XCLIPSYNC_PID="$!" 260 | else 261 | warn_msg "Clipboard synchronization is disabled!" 262 | fi 263 | sleep 0.1 264 | bash /etc/xdg/xfce4/xinitrc 265 | EXEC_STATUS="$?" 266 | kill $XCLIPSYNC_PID $XFWM_PID $XEPHYR_PID $XORG_PID 2>/dev/null 267 | kill $(pgrep -fa xclipfrom|grep "$DESKTOP_KEY"|awk '{print$1}') 2>/dev/null 268 | rm -rf "/tmp/.X$RIM_DESKTOP_DISPLAY-lock" 2>/dev/null 269 | [ "$XORG_PID" ] && reset 270 | return $EXEC_STATUS 271 | } 272 | info_msg "Launching RunImage Desktop..." 273 | export -f run_xfce4 is_pid 274 | dbus-run-session bash -c run_xfce4 275 | EXEC_STATUS="$?" 276 | fi 277 | exit $EXEC_STATUS 278 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/rim-dinteg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RED='\033[1;91m' 4 | BLUE='\033[1;94m' 5 | GREEN='\033[1;92m' 6 | YELLOW='\033[1;33m' 7 | RESETCOLOR='\033[1;00m' 8 | 9 | [ -f "$RIMENVFL" ] && \ 10 | source "$RIMENVFL" 11 | 12 | [[ ! "$RUNTTY" =~ tty|pts ]] && \ 13 | NOT_TERM=1||NOT_TERM=0 14 | 15 | [[ "$RIM_PORTABLE_HOME" == 1 && -d "$SYS_HOME" ]] && \ 16 | HOME="$SYS_HOME" 17 | 18 | RIM_DINTEG_DIR="${RIM_DINTEG_DIR:=$HOME/.local/share}" 19 | DINTEG_APPS_DIR="$RIM_DINTEG_DIR/applications" 20 | ICONS_DIRS=('/usr/share/icons' '/usr/share/pixmaps') 21 | APPS_DIR='/usr/share/applications' 22 | 23 | IGNORE_FILES=( 24 | 'mimeinfo.cache' 25 | 'icon-theme.cache' 26 | ) 27 | INTEG_DIRS=( 28 | "$APPS_DIR" 29 | '/usr/share/desktop-directories' 30 | '/etc/xdg/menus/applications-merged' 31 | ) 32 | for ICONS_DIR in "${ICONS_DIRS[@]}" 33 | do INTEG_DIRS+=("$ICONS_DIR"/*.svg "$ICONS_DIR"/*.png "$ICONS_DIR/hicolor") 34 | done 35 | MIME_DIRS=( 36 | '/usr/share/mime/packages' 37 | '/usr/share/mime/inode' 38 | '/usr/share/mime/text' 39 | '/usr/share/mime/application' 40 | '/usr/share/mime/model' 41 | '/usr/share/mime/video' 42 | '/usr/share/mime/font' 43 | '/usr/share/mime/image' 44 | '/usr/share/mime/audio' 45 | '/usr/share/mime/multipart' 46 | '/usr/share/mime/x-content' 47 | '/usr/share/mime/message' 48 | '/usr/share/mime/chemical' 49 | '/usr/share/mime/x-epoc' 50 | ) 51 | 52 | if [ -d "$RUNDINTEGDIR" ] 53 | then 54 | ACTINTEGFL="$RUNDINTEGDIR/act" 55 | ADDINTEGFL="$RUNDINTEGDIR/add" 56 | RMINTEGFL="$RUNDINTEGDIR/rm" 57 | LSINTEGFL="$RUNDINTEGDIR/ls" 58 | fi 59 | 60 | nocolor() { sed -r 's|\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]||g' ; } 61 | 62 | info_msg() { 63 | if [ "$RIM_QUIET_MODE" != 1 ] 64 | then echo -e "${GREEN}[ INFO ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 65 | if [[ "$NOT_TERM" == 1 && "$RIM_NOTIFY" == 1 ]] 66 | then notify-send -a 'RunImage Info' "$(echo -e "$@"|nocolor)" 2>/dev/null & 67 | fi 68 | fi 69 | } 70 | 71 | error_msg() { 72 | echo -e "${RED}[ ERROR ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 73 | if [ "$NOT_TERM" == 1 ] 74 | then notify-send -a 'RunImage Error' "$(echo -e "$@"|nocolor)" 2>/dev/null & 75 | fi 76 | } 77 | 78 | empty_msg() { 79 | error_msg "${YELLOW}Option ${BLUE}$1 ${YELLOW}requires a non-empty argument!\n" 80 | print_help 81 | } 82 | 83 | lsapps() { 84 | local apps="$(grep -m1 '^Name=' -nr "$APPS_DIR" 2>/dev/null|\ 85 | sed 's|.*:Name=||g;s|.*|"&"|g'|sort -u)" 86 | [ -n "$apps" ] && cat -n<<<"$apps" 87 | } 88 | 89 | lsintegapps() { 90 | if [ -d "$RUNDINTEGDIR" ] 91 | then fifo_ls 92 | else 93 | local apps="$(grep -m1 '^Name=.*' -nr "$DINTEG_APPS_DIR"/*-rim.desktop 2>/dev/null|\ 94 | sed 's|.*:Name=||g;s| \[RunImage\]$||g;s|.*|"&"|g'|sort -u)" 95 | [ -n "$apps" ] && cat -n<<<"$apps" 96 | fi 97 | } 98 | 99 | find_fl() { find "$@" -type f 2>/dev/null|sort ; } 100 | 101 | upd_ddb() { update-desktop-database -q "$DINTEG_APPS_DIR" &>/dev/null ; } 102 | 103 | upd_mdb() { update-mime-database "$RIM_DINTEG_DIR/mime" &>/dev/null ; } 104 | 105 | fifo_add() { 106 | echo a > "$ACTINTEGFL" 107 | echo "$1" > "$ADDINTEGFL" 108 | } 109 | 110 | fifo_ls() { 111 | echo l > "$ACTINTEGFL" 112 | cat "$LSINTEGFL" 113 | } 114 | 115 | fifo_rm() { 116 | echo r > "$ACTINTEGFL" 117 | echo "$1" > "$RMINTEGFL" 118 | } 119 | 120 | dinteg() { 121 | while read -r file 122 | do 123 | [[ ! "${IGNORE_FILES[@]}" =~ "$(basename "$file")" ]]||\ 124 | continue 125 | [ "${file:0:1}" == '/' ]||\ 126 | file="/${file}" 127 | if [[ -f "$file" || "$file" == "$RUNPIDDIR/dinteg/"* ]] 128 | then 129 | unset postfix postfix_dir exec_args 130 | if [ -d "$RUNDINTEGDIR" ] 131 | then dinteg_dir="$RUNDINTEGDIR" 132 | else 133 | if [ "$file" == *'/menus/'* ] 134 | then 135 | [[ "$RIM_DINTEG_DIR" =~ ^"$HOME" ]] && \ 136 | dinteg_dir="$HOME/.config"||\ 137 | dinteg_dir='/etc/xdg' 138 | else dinteg_dir="$RIM_DINTEG_DIR" 139 | fi 140 | fi 141 | if [[ "$file" == "$RUNPIDDIR/dinteg/"* ]] 142 | then 143 | cp_mv=mv 144 | postfix="$(sed "s|$RUNPIDDIR/dinteg/||g"<<<"$file")" 145 | else 146 | cp_mv=cp 147 | postfix="$(cut -d'/' -f4-<<<"$file"|sed 's|.desktop$|-rim.desktop|i;s|.png$|-rim.png|i;s|.svg$|-rim.svg|i;s|.xml$|-rim.xml|i')" 148 | fi 149 | postfix_dir="$(dirname "$postfix")" 150 | dinteg_file="${dinteg_dir}/${postfix}" 151 | dinteg_file_dir="${dinteg_dir}/${postfix_dir}" 152 | case "$act" in 153 | a) 154 | mkdir $verb -p "$dinteg_file_dir" 155 | "$cp_mv" $verb -f "$file" "$dinteg_file" 156 | if [[ "$dinteg_file" == *'.desktop' && "$file" != "$RUNPIDDIR/dinteg/"* ]] 157 | then 158 | exec_args="env " 159 | [ -n "$RIM_OVERFS_ID" ] && \ 160 | exec_args+="RIM_OVERFS_ID='$RIM_OVERFS_ID' " 161 | exec_args+="RIM_AUTORUN=0 " 162 | exec_args+="'$RUNSRC' " 163 | 164 | if grep -oq '^Icon=/' "$dinteg_file" 165 | then 166 | sed -i "s|^Icon.*|Icon=${dinteg_dir}/$(grep -m1 '^Icon=' "$dinteg_file"|\ 167 | cut -d'/' -f4-)|g;s|.png$|-rim.png|i;s|.svg$|-rim.svg|i" "$dinteg_file" 168 | else sed -i "s|^Icon.*|&-rim|g" "$dinteg_file" 169 | fi 170 | sed -i "s|^Comment.*=.*|& [RunImage]|g;s|^Exec=|Exec=$exec_args|g;/^TryExec/d;/^DBusActivatable/d" "$dinteg_file" 171 | chmod $verb +x "$dinteg_file" 172 | fi 173 | if [ -d "$RUNDINTEGDIR" ] 174 | then fifo_add "$dinteg_file" 175 | fi 176 | ;; 177 | r) 178 | if [ -d "$RUNDINTEGDIR" ] 179 | then fifo_rm "$dinteg_file" 180 | else 181 | [ -f "$dinteg_file" ] && \ 182 | rm $verb -f "$dinteg_file" 183 | fi 184 | ;; 185 | *) return 1 ;; 186 | esac 187 | fi 188 | done 189 | } 190 | 191 | print_help() { 192 | echo -e "[ Usage ]: rim-dinteg [OPTIONS] app app... 193 | 194 | [ Options ]: 195 | -a, --add [num|name|all|mime] Add applications to apps menu 196 | -h, --help Show this message 197 | -l, --list [a|added] List applications 198 | -m, --mime With MIME types (env: RIM_DINTEG_MIME=1) 199 | -d, --dinteg-dir /path Desktop integration directory (env: RIM_DINTEG_DIR=/path) 200 | -v, --verbose Verbose output 201 | -r, --remove [num|name|all|mime] Remove applications from apps menu" 202 | exit 1 203 | } 204 | 205 | unset act ret verb 206 | while [[ $# -gt 0 ]] 207 | do 208 | case "$1" in 209 | -m|--mime ) shift ; RIM_DINTEG_MIME=1 ;; 210 | -d|--dinteg-dir) 211 | if [[ -n "$2" && "$2" != -* ]] 212 | then 213 | RIM_DINTEG_DIR="$2" 214 | DINTEG_APPS_DIR="$RIM_DINTEG_DIR/applications"; shift 2 215 | else empty_msg "$1" 216 | fi ;; 217 | -v|--verbose) shift ; verb='-v' ;; 218 | -a|--add ) shift ; act=a ;; 219 | -r|--remove ) shift ; act=r ;; 220 | -h|--help ) print_help ;; 221 | -l|--list ) shift 222 | ret=1 223 | case "$1" in 224 | a|added) lsintegapps ;; 225 | *) lsapps ;; 226 | esac 227 | if [ "$?" == 0 ] 228 | then ret=0 229 | else error_msg "No apps found!" 230 | fi 231 | exit $ret 232 | ;; 233 | -*) error_msg "Unknown parameter: ${BLUE}$1\n"; print_help ;; 234 | *) break ;; 235 | esac 236 | done 237 | 238 | if [[ -n "$1" && -n "$act" ]] 239 | then 240 | case "$1" in 241 | hook) shift 242 | unset verb 243 | if [ "$RIM_DINTEG" == 1 ] 244 | then dinteg 245 | else echo "Desktop integration is disabled!" 246 | fi 247 | ;; 248 | all) shift 249 | [ "$RIM_DINTEG_MIME" == 1 ] && \ 250 | INTEG_DIRS+=("${MIME_DIRS[@]}") 251 | find_fl "${INTEG_DIRS[@]}"|dinteg 252 | upd_ddb 253 | if [ "$RIM_DINTEG_MIME" == 1 ] 254 | then upd_mdb 255 | fi 256 | ;; 257 | mime) shift 258 | find_fl "${MIME_DIRS[@]}"|dinteg 259 | upd_mdb 260 | ;; 261 | *) IFS=$'\n' 262 | app_list="$(case "$act" in 263 | a) lsapps ;; 264 | r) lsintegapps ;; 265 | esac)" 266 | for app in "$@" 267 | do 268 | (if [[ "$app" =~ ^[0-9]+$ ]] 269 | then app_name="$(gawk '($1 == "'$app'")'<<<"$app_list"|gawk '{$1=""}1'|sed 's|"||g'|sed 's|^ ||g')" 270 | else app_name="$app" 271 | fi 272 | integ_files=("$(grep -wim1 "^Name=$app_name$" -lr "$APPS_DIR" 2>/dev/null|head -1)") 273 | if [ -n "$integ_files" ] 274 | then 275 | case "$act" in 276 | a) act_info='Add' ;; 277 | r) act_info='Remove' ;; 278 | esac 279 | info_msg "$act_info app: $app_name" 280 | icon_name="$(grep -m1 "^Icon=" "$integ_files" 2>/dev/null|sed 's|^Icon=||')" 281 | if [ -n "$icon_name" ] 282 | then 283 | if [ -f "$icon_name" ] 284 | then integ_files+=("$icon_name") 285 | else integ_files+=($(find_fl "${ICONS_DIRS[@]}" -name "${icon_name}.*" 2>/dev/null)) 286 | fi 287 | fi 288 | for file in "${integ_files[@]}";do echo "$file";done|dinteg 289 | else 290 | error_msg "The app was not found: $([ "$app_name" ] && echo "$app_name"||echo "$app")" 291 | exit 1 292 | fi) 293 | done 294 | ;; 295 | esac 296 | else 297 | error_msg "Specify the action and the name or number of the app!" 298 | print_help 299 | fi 300 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/rim-shrink: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | shopt -s extglob 3 | 4 | RED='\033[1;91m' 5 | BLUE='\033[1;94m' 6 | GREEN='\033[1;92m' 7 | YELLOW='\033[1;33m' 8 | RESETCOLOR='\033[1;00m' 9 | 10 | [ -f "$RIMENVFL" ] && \ 11 | source "$RIMENVFL" 12 | 13 | [[ ! "$RUNTTY" =~ tty|pts ]] && \ 14 | NOT_TERM=1||NOT_TERM=0 15 | 16 | count=0 17 | BATCH_SIZE=100 18 | wait_batch() { 19 | (( count++ )) 20 | (( count % BATCH_SIZE == 0 )) && wait && count=0 21 | } 22 | 23 | find_type() { 24 | local NAMES 25 | local names=() 26 | [ "$1" == '*' ] && unset type||\ 27 | local type=(-type "$1") 28 | IFS='|' read -r -a NAMES <<<"$2" 29 | for name in "${NAMES[@]}" 30 | do 31 | if [ -n "$name" ] 32 | then 33 | [[ "${#names[@]}" -gt 1 ]] && \ 34 | names+=(-o) 35 | names+=(-iname "$name") 36 | fi 37 | done 38 | shift 2 39 | find "$@" "${type[@]}" -perm -u+w "${names[@]}" 2>/dev/null 40 | } 41 | 42 | nocolor() { sed -r 's|\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]||g' ; } 43 | 44 | info_msg() { 45 | if [ "$RIM_QUIET_MODE" != 1 ] 46 | then echo -e "${GREEN}[ INFO ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 47 | if [[ "$NOT_TERM" == 1 && "$RIM_NOTIFY" == 1 ]] 48 | then notify-send -a 'RunImage Info' "$(echo -e "$@"|nocolor)" 2>/dev/null & 49 | fi 50 | fi 51 | } 52 | 53 | warn_msg() { 54 | if [[ "$RIM_QUIET_MODE" != 1 && "$RIM_NO_WARN" != 1 ]] 55 | then echo -e "${YELLOW}[ WARNING ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 56 | if [[ "$NOT_TERM" == 1 && "$RIM_NOTIFY" == 1 ]] 57 | then notify-send -a 'RunImage Warning' "$(echo -e "$@"|nocolor)" 2>/dev/null & 58 | fi 59 | fi 60 | } 61 | 62 | error_msg() { 63 | echo -e "${RED}[ ERROR ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 64 | if [ "$NOT_TERM" == 1 ] 65 | then notify-send -a 'RunImage Error' "$(echo -e "$@"|nocolor)" 2>/dev/null & 66 | fi 67 | } 68 | 69 | print_help() { 70 | echo -e "[ Usage ]: rim-shrink [OPTIONS] /path/RunDir 71 | 72 | [ Options ]: 73 | -a, --all Shrink all (env: RIM_SHRINK_ALL=1) 74 | -b, --back Shrink backup files '*.old' '*.back' (env: RIM_SHRINK_BACK=1) 75 | -c, --staticlibs Shrink static libs '*.a' (env: RIM_SHRINK_STATICLIBS=1) 76 | -d, --docs Shrink /usr/share/{man,doc,help,info,gtk-doc} and '*.md' 'README*' (env: RIM_SHRINK_DOCS=1) 77 | -s, --strip Strip all debugging symbols & sections (env: RIM_SHRINK_STRIP=1) 78 | -l, --locales Shrink all locales except uk ru en en_US (env: RIM_SHRINK_LOCALES=1) 79 | -o, --objects Shrink object files '*.o' (env: RIM_SHRINK_OBJECTS=1) 80 | -p, --pkgcache Shrink packages cache (env: RIM_SHRINK_PKGCACHE=1) 81 | -r, --src Shrink source code files for build (env: RIM_SHRINK_SRC=1) 82 | -y, --pycache Shrink '__pycache__' directories (env: RIM_SHRINK_PYCACHE=1) 83 | -h, --help Show this message 84 | -v, --verbose Verbose output" 85 | exit 1 86 | } 87 | 88 | unset verb 89 | while [[ $# -gt 0 ]] 90 | do 91 | case "$1" in 92 | -a|--all ) RIM_SHRINK_ALL=1 ;; 93 | -c|--staticlibs) RIM_SHRINK_STATICLIBS=1 ;; 94 | -d|--docs ) RIM_SHRINK_DOCS=1 ;; 95 | -s|--strip ) RIM_SHRINK_STRIP=1 ;; 96 | -l|--locales ) RIM_SHRINK_LOCALES=1 ;; 97 | -o|--objects ) RIM_SHRINK_OBJECTS=1 ;; 98 | -p|--pkgcache ) RIM_SHRINK_PKGCACHE=1 ;; 99 | -r|--src ) RIM_SHRINK_SRC=1 ;; 100 | -b|--back ) RIM_SHRINK_BACK=1 ;; 101 | -y|--pycache ) RIM_SHRINK_PYCACHE=1 ;; 102 | -h|--help ) print_help ;; 103 | -v|--verbose ) verb='-v' ;; 104 | -*) error_msg "Unknown parameter: ${BLUE}$1\n"; print_help ;; 105 | *) RUNDIR="$1" ; RUNROOTFS="$1/rootfs" ;; 106 | esac 107 | shift 108 | done 109 | 110 | [ "$RIM_SHRINK_ALL" == 1 ] && \ 111 | RIM_SHRINK_SRC=1 RIM_SHRINK_DOCS=1 \ 112 | RIM_SHRINK_STRIP=1 RIM_SHRINK_LOCALES=1 \ 113 | RIM_SHRINK_STATICLIBS=1 RIM_SHRINK_OBJECTS=1 \ 114 | RIM_SHRINK_PKGCACHE=1 RIM_SHRINK_BACK=1 \ 115 | RIM_SHRINK_PYCACHE=1 116 | 117 | [[ ! -n "$RUNDIR" && -d "$OVERFS_MNT" ]] && \ 118 | RUNDIR="$OVERFS_MNT" 119 | 120 | RUNDIR="${RUNDIR:=RunDir}" 121 | RUNROOTFS="${RUNROOTFS:=$RUNDIR/rootfs}" 122 | 123 | [[ "$INSIDE_RUNIMAGE" == 1 && ! -d "$RUNROOTFS" ]] && \ 124 | RUNROOTFS='/' 125 | 126 | if [[ -d "$RUNDIR" && -d "$RUNROOTFS" ]] 127 | then 128 | if [ -w "$RUNROOTFS" ] 129 | then 130 | [ -n "$verb" ] && \ 131 | info_msg "Shrinking rootfs: '$RUNROOTFS'..."|| 132 | info_msg "Shrinking rootfs..." 133 | 134 | IFS=$'\n' 135 | unset FSCAN 136 | SHRINK_ITEMS=( 137 | "$RUNROOTFS"/usr/share/libalpm/hooks/*systemd* 138 | "$RUNROOTFS"/usr/share/libalpm/scripts/*systemd* 139 | "$RUNROOTFS"/usr/share/libalpm/hooks/dbus-reload.hook 140 | "$RUNROOTFS"/etc/X11/xinit/xinitrc.d/50-systemd-user.sh 141 | "$RUNROOTFS"/usr/share/libalpm/hooks/60-depmod.hook 142 | "$RUNROOTFS"/usr/share/libalpm/hooks/60-mkinitcpio-remove.hook 143 | "$RUNROOTFS"/usr/share/libalpm/hooks/70-dkms-install.hook 144 | "$RUNROOTFS"/usr/share/libalpm/hooks/70-dkms-upgrade.hook 145 | "$RUNROOTFS"/usr/share/libalpm/hooks/71-dkms-remove.hook 146 | "$RUNROOTFS"/usr/share/libalpm/hooks/90-mkinitcpio-install.hook 147 | "$RUNROOTFS"/usr/share/libalpm/hooks/grub.hook 148 | "$RUNROOTFS"/usr/share/libalpm/scripts/depmod 149 | "$RUNROOTFS"/usr/share/libalpm/scripts/dkms 150 | "$RUNROOTFS"/usr/share/libalpm/scripts/mkinitcpio 151 | "$RUNROOTFS"/usr/share/libalpm/hooks/90-update-appstream-cache.hook 152 | "$RUNROOTFS"/var/tmp/* 153 | "$RUNROOTFS"/var/cache/ldconfig/aux-cache~ 154 | "$RUNROOTFS"/etc/ld.so.cache~ 155 | "$RUNROOTFS"/{dev,sys,proc,tmp,run}/* 156 | $(find_type f '*.log' "$RUNROOTFS"/var/log/) 157 | ) 158 | 159 | [ "$RIM_SHRINK_PKGCACHE" == 1 ] && FSCAN+='*.pacnew|*.pacsave|' && \ 160 | SHRINK_ITEMS+=( 161 | "$RUNROOTFS"/var/lib/pacman/sync/* 162 | "$RUNROOTFS"/var/cache/pacman/pkg/* 163 | "$RUNROOTFS"/etc/pacman.d/gnupg/pubring.gpg~ 164 | "$RUNROOTFS"/etc/pacman.d/gnupg/S.* 165 | "$RUNROOTFS"/var/lib/pacman/db.lck 166 | "$RUNROOTFS"/var/cache/apt/archives/*.deb 167 | "$RUNROOTFS"/var/cache/apt/*.bin 168 | "$RUNROOTFS"/var/lib/apt/lists/deb.* 169 | "$RUNROOTFS"/var/log/apt/* 170 | "$RUNROOTFS"/var/cache/apk/* 171 | "$RUNROOTFS"/var/cache/xbps/* 172 | ) 173 | 174 | [ "$RIM_SHRINK_LOCALES" == 1 ] && SHRINK_ITEMS+=( 175 | "$RUNROOTFS"/usr/share/locale/!(locale.alias|uk|ru|en|en_US) 176 | ) 177 | 178 | [ "$RIM_SHRINK_PYCACHE" == 1 ] && SHRINK_ITEMS+=( 179 | $(find_type d '__pycache__' "$RUNROOTFS"/) 180 | ) 181 | 182 | [ "$RIM_SHRINK_SRC" == 1 ] && \ 183 | FSCAN+='*.h|*.pc|*.c|*.cc|*.cpp|*.hpp|CMakeLists*|Makefile*|*.cmake|*.in|*.inc|' && \ 184 | SHRINK_ITEMS+=( 185 | "$RUNROOTFS"/usr/include/* 186 | "$RUNROOTFS"/usr/src/* 187 | "$RUNROOTFS"/usr/*/*pkgconfig/* 188 | ) 189 | 190 | [ "$RIM_SHRINK_DOCS" == 1 ] && FSCAN+='*.md|README*|' && \ 191 | SHRINK_ITEMS+=( 192 | "$RUNROOTFS"/usr/share/man/* 193 | "$RUNROOTFS"/usr/share/doc/* 194 | "$RUNROOTFS"/usr/share/info/* 195 | "$RUNROOTFS"/usr/share/help/* 196 | "$RUNROOTFS"/usr/share/gtk-doc/* 197 | ) 198 | 199 | [ "$RIM_SHRINK_BACK" == 1 ] && FSCAN+='*.old|*.back|' 200 | 201 | [ "$RIM_SHRINK_OBJECTS" == 1 ] && FSCAN+='*.o|' 202 | 203 | [ "$RIM_SHRINK_STATICLIBS" == 1 ] && FSCAN+='*.a|' 204 | 205 | LIBDIRS=( 206 | "$RUNROOTFS"/lib "$RUNROOTFS"/lib64 "$RUNROOTFS"/lib32 \ 207 | "$RUNROOTFS"/usr/lib "$RUNROOTFS"/usr/lib32 \ 208 | "$RUNROOTFS"/usr/lib64 "$RUNROOTFS"/usr/libexec \ 209 | "$RUNROOTFS"/usr/local/lib "$RUNROOTFS"/usr/local/lib32 \ 210 | "$RUNROOTFS"/usr/local/lib64 "$RUNROOTFS"/usr/local/libexec 211 | ) 212 | 213 | nv_version="$(cat /sys/module/nvidia/version 2>/dev/null)" 214 | nv_version_inside="$(basename "$RUNROOTFS"/usr/lib/libGLX_nvidia.so.*.*|tail -c +18)" 215 | [[ -n "$nv_version" && "$nv_version_inside" == '000.00.00' ]] && SHRINK_ITEMS+=( 216 | $(find_type '*' "*so.$nv_version" "${LIBDIRS[@]}") 217 | ) 218 | 219 | [ -n "$FSCAN" ] && SHRINK_ITEMS+=($(find_type f "$FSCAN" "$RUNROOTFS"/)) 220 | 221 | for item in "${SHRINK_ITEMS[@]}" 222 | do rm $verb -rf "$item" & wait_batch 223 | done 224 | 225 | if [ "$RIM_SHRINK_STRIP" == 1 ] 226 | then 227 | if command -v strip &>/dev/null 228 | then 229 | for file in $(find_type f '*' "$RUNROOTFS"/bin "$RUNROOTFS"/sbin \ 230 | "$RUNROOTFS"/usr/bin "$RUNROOTFS"/usr/sbin "$RUNROOTFS"/opt \ 231 | "$RUNROOTFS"/usr/local/bin "$RUNROOTFS"/usr/local/sbin \ 232 | "${LIBDIRS[@]}"|\ 233 | grep -Ev 'strip|bash|libtinfo\.so.*|librt\.so.*|libzstd\.so.*|libz\.so.*|libsframe\.so.*|libbfd-.*\.so|libpthread\.so.*|libc\.so.*|ld-musl.*\.so.*|ld-linux.*\.so.*|\.o$|\.a$|libncursesw\.so.*|libreadline\.so.*') 234 | do 235 | (if [[ "$(head -c +4 "$file")" =~ 'ELF' ]] 236 | then strip $verb --strip-debug "$file" 237 | fi) 2>/dev/null & wait_batch 238 | done 239 | else 240 | warn_msg "strip not found! skipping..." 241 | fi 242 | fi 243 | 244 | if [ -f "$RUNROOTFS"/etc/ld.so.version ] 245 | then 246 | info_msg "Found ld.so.version!" 247 | rm $verb -f "$RUNROOTFS"/etc/ld.so.version 248 | [ "$RUNROOTFS" != "$RUNDIR/rootfs" ] && \ 249 | export RIM_ROOTFS="$RUNROOTFS" 250 | RIM_TMP_HOME=0 RIM_XORG_CONF=0 RIM_SHARE_BOOT=0 \ 251 | RIM_RUN_IN_ONE=0 RIM_HOST_TOOLS=0 RIM_SANDBOX_NET=0 \ 252 | RIM_TMP_HOME_DL=0 RIM_UNSHARE_NSS=1 RIM_SHARE_FONTS=0 \ 253 | RIM_UNSHARE_HOME=1 RIM_SHARE_THEMES=0 RIM_SANDBOX_HOME=0 \ 254 | RIM_PORTABLE_HOME=0 RIM_UNSHARE_USERS=1 RIM_UNSHARE_HOSTS=1 \ 255 | RIM_WAIT_RPIDS_EXIT=0 RIM_SANDBOX_HOME_DL=0 RIM_NO_NVIDIA_CHECK=1 \ 256 | RIM_UNSHARE_MODULES=1 RIM_ENABLE_HOSTEXEC=0 RIM_UNSHARE_HOSTNAME=1 \ 257 | RIM_UNSHARE_LOCALTIME=1 RIM_UNSHARE_RESOLVCONF=1 RIM_OVERFS_MODE=0 \ 258 | RIM_NO_CRYPTFS_MOUNT=1 NO_NVIDIA_CHECK=1 QUIET_MODE=1 SANDBOX_NET=0 \ 259 | RIM_CONFIG=0 RIM_QUIET_MODE=1 RIM_AUTORUN=0 RIMSHRINKLDSO=1 \ 260 | "$RUNDIR/Run" ldconfig 261 | rm $verb -f "$RUNROOTFS"/etc/ld.so.cache~ \ 262 | "$RUNROOTFS"/var/cache/ldconfig/aux-cache~ 263 | fi 264 | 265 | wait 266 | else 267 | error_msg "Unable to shrink rootfs. Read-only!" 268 | exit 1 269 | fi 270 | else 271 | error_msg "RunDir: '$RUNDIR' or rootfs: '$RUNROOTFS' not found!" 272 | exit 1 273 | fi 274 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/rim-build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RED='\033[1;91m' 4 | BLUE='\033[1;94m' 5 | GREEN='\033[1;92m' 6 | YELLOW='\033[1;33m' 7 | RESETCOLOR='\033[1;00m' 8 | 9 | [ -f "$RIMENVFL" ] && \ 10 | source "$RIMENVFL" 11 | 12 | [[ ! "$RUNTTY" =~ tty|pts ]] && \ 13 | NOT_TERM=1||NOT_TERM=0 14 | 15 | BUILDKEY="$BASHPID" 16 | EXEPT_RUNSRCNAMES=("AppRun" "Run" "rim-build" "rim-desktop" "rim-update") 17 | 18 | nocolor() { sed -r 's|\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]||g' ; } 19 | 20 | error_msg() { 21 | echo -e "${RED}[ ERROR ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 22 | if [ "$NOT_TERM" == 1 ] 23 | then notify-send -a 'RunImage Error' "$(echo -e "$@"|nocolor)" 2>/dev/null & 24 | fi 25 | } 26 | 27 | info_msg() { 28 | if [ "$RIM_QUIET_MODE" != 1 ] 29 | then echo -e "${GREEN}[ INFO ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 30 | if [[ "$NOT_TERM" == 1 && "$RIM_NOTIFY" == 1 ]] 31 | then notify-send -a 'RunImage Info' "$(echo -e "$@"|nocolor)" 2>/dev/null & 32 | fi 33 | fi 34 | } 35 | 36 | warn_msg() { 37 | if [[ "$RIM_QUIET_MODE" != 1 && "$RIM_NO_WARN" != 1 ]] 38 | then echo -e "${YELLOW}[ WARNING ][$(date +"%Y.%m.%d %T")]: $@ $RESETCOLOR" 1>&2 39 | if [[ "$NOT_TERM" == 1 && "$RIM_NOTIFY" == 1 ]] 40 | then notify-send -a 'RunImage Warning' "$(echo -e "$@"|nocolor)" 2>/dev/null & 41 | fi 42 | fi 43 | } 44 | 45 | empty_msg() { 46 | error_msg "${YELLOW}Option ${BLUE}$1 ${YELLOW}requires a non-empty argument!\n" 47 | print_help 48 | } 49 | 50 | print_help() { 51 | echo -e "[ Usage ]: rim-build [OPTIONS] /path/runimage 52 | 53 | [ Options ]: 54 | -b, --bsize '1M|20' Set block size (env: RIM_CMPRS_BSIZE=1M) 55 | -c, --clvl '1-22' Set compression level (env: RIM_CMPRS_LVL=1) 56 | -d, --dwfs Use DwarFS file system (env: RIM_CMPRS_FS=dwfs) 57 | -f, --dwfs-hfile '/path' DwarFS hotness list file (env: RIM_BUILD_DWFS_HFILE=/path) (0 to disable) 58 | -l, --lz4 Use lz4 compression (for DwarFS clvl 1-12) (env: RIM_CMPRS_ALGO=lz4) 59 | -h, --help Show this message 60 | -k, --keep Creates a backup of the old RunImage (env: RIM_KEEP_OLD_BUILD=1) 61 | -s, --sqfs Use SquashFS file system (env: RIM_CMPRS_FS=sqfs) 62 | -x, --xz Use xz (lzma for DwarFS clvl 1-9) compression (env: RIM_CMPRS_ALGO=xz) 63 | -z, --zstd Use zstd compression (clvl 1-22) (env: RIM_CMPRS_ALGO=zstd)" 64 | exit 1 65 | } 66 | 67 | if [ -d "$OVERFS_MNT" ] 68 | then 69 | RUNDIR="$OVERFS_MNT" 70 | RUNSTATIC="$RUNDIR/static" 71 | fi 72 | 73 | RUNRUNTIME="$RUNSTATIC/uruntime" 74 | if [ ! -x "$RUNRUNTIME" ] 75 | then 76 | error_msg "RunImage runtime not found!" 77 | exit 1 78 | fi 79 | 80 | RIM_CMPRS_FS="${RIM_CMPRS_FS:=dwfs}" 81 | RIM_CMPRS_ALGO="${RIM_CMPRS_ALGO:=zstd}" 82 | RIM_CMPRS_LVL="${RIM_CMPRS_LVL:=1}" 83 | 84 | unset RUNBASENAME clvl 85 | while [[ $# -gt 0 ]] 86 | do 87 | case "$1" in 88 | -h|--help ) print_help ;; 89 | -z|--zstd ) RIM_CMPRS_ALGO='zstd' ;; 90 | -x|--xz ) RIM_CMPRS_ALGO='xz' ;; 91 | -l|--lz4 ) RIM_CMPRS_ALGO='lz4' ;; 92 | -s|--sqfs ) RIM_CMPRS_FS='sqfs' ;; 93 | -d|--dwfs ) RIM_CMPRS_FS='dwfs' ;; 94 | -k|--keep ) RIM_KEEP_OLD_BUILD='1' ;; 95 | -c|--clvl ) 96 | if [[ -n "$2" && "$2" != -* ]] 97 | then clvl=1; RIM_CMPRS_LVL="$2"; shift 98 | else empty_msg "$1" 99 | fi ;; 100 | -b|--bsize) 101 | if [[ -n "$2" && "$2" != -* ]] 102 | then RIM_CMPRS_BSIZE="$2"; shift 103 | else empty_msg "$1" 104 | fi ;; 105 | -f| --dwfs-hfile ) 106 | if [[ -n "$2" && "$2" != -* ]] 107 | then RIM_BUILD_DWFS_HFILE="$2"; shift 108 | else empty_msg "$1" 109 | fi ;; 110 | -*) error_msg "Unknown parameter: ${BLUE}$1\n"; print_help ;; 111 | *) 112 | if [ -d "$(dirname "$1" 2>/dev/null)" ] 113 | then 114 | if [ -d "$1" ] 115 | then 116 | if [[ "${EXEPT_RUNSRCNAMES[@]}" =~ "$RUNSRCNAME" ]] 117 | then RUNBASENAME="$1/runimage" 118 | else RUNBASENAME="$1/$RUNSRCNAME" 119 | fi 120 | else RUNBASENAME="$1" 121 | fi 122 | else 123 | error_msg "The build directory does not exist!" 124 | exit 1 125 | fi ;; 126 | esac 127 | shift 128 | done 129 | 130 | info_msg "RunImage build" 131 | 132 | if [ ! -n "$RUNBASENAME" ] 133 | then 134 | if [[ "${EXEPT_RUNSRCNAMES[@]}" =~ "$RUNSRCNAME" ]] 135 | then RUNBASENAME="runimage" 136 | else RUNBASENAME="$RUNSRCNAME" 137 | fi 138 | fi 139 | 140 | if [[ "${RUNSRC,,}" =~ .*\.(runimage|rim)$ && \ 141 | ! "${RUNBASENAME,,}" =~ .*\.(runimage|rim)$ ]] 142 | then RUNBASENAME="${RUNBASENAME}.${RUNSRC##*.}" 143 | fi 144 | 145 | NEWRUNIMAGE="$(realpath "$RUNBASENAME" 2>/dev/null||echo "$(dirname "$RUNBASENAME")/$(basename "$RUNBASENAME")").new$BUILDKEY" 146 | OLDRUNIMAGE="${NEWRUNIMAGE%.new$BUILDKEY}" 147 | [[ -f "$NEWRUNIMAGE" || -d "$NEWRUNIMAGE" || -L "$NEWRUNIMAGE" ]] && \ 148 | rm -rf "$NEWRUNIMAGE" 149 | 150 | CMPRS_CMD=() 151 | CMPRS_EXCLUDE=() 152 | case "$RIM_CMPRS_FS" in 153 | sqfs) 154 | info_msg "Compression file system: SquashFS" 155 | RUNOFFSET="$("$RUNRUNTIME" --runtime-offset 2>/dev/null||"$RUNRUNTIME" --appimage-offset 2>/dev/null)" 156 | CMPRS_CMD+=("$RUNSTATIC/mksquashfs" "$RUNDIR" "$NEWRUNIMAGE") 157 | [ -f "$RUNDIR/cryptfs/gocryptfs.conf" ] && \ 158 | CMPRS_EXCLUDE+=(-wildcards -e 'rootfs/*' 'rootfs/.*') 159 | CMPRS_CMD+=( 160 | -root-owned -offset "$RUNOFFSET" -no-recovery -no-xattrs 161 | -noappend -mkfs-time 0 -action "chmod(u+rw)@! perm(u+rw)" 162 | -action "prune @ type(c) || type(s) || type(b) || type(p)" -b 163 | ) 164 | ;; 165 | dwfs) 166 | info_msg "Compression file system: DwarFS" 167 | trap "rm -f '$NEWRUNIMAGE'" INT TERM EXIT 168 | CMPRS_CMD+=("$RUNSTATIC/mkdwarfs") 169 | if [ "$RIM_BUILD_DWFS_HFILE" != 0 ] 170 | then 171 | DWFS_BHOTFILE="$RUNDIR/config/dwarfs.prof" 172 | DWFS_CHOTFILE="$RUNIMAGEDIR/config/dwarfs.prof" 173 | DWFS_HOTFILE="$RUNIMAGEDIR/dwarfs.prof" 174 | if [ ! -f "$RIM_BUILD_DWFS_HFILE" ] 175 | then 176 | if [ -f "$DWFS_HOTFILE" ] 177 | then RIM_BUILD_DWFS_HFILE="$DWFS_HOTFILE" 178 | elif [ -f "$DWFS_CHOTFILE" ] 179 | then RIM_BUILD_DWFS_HFILE="$DWFS_CHOTFILE" 180 | elif [ -f "$DWFS_BHOTFILE" ] 181 | then RIM_BUILD_DWFS_HFILE="$DWFS_BHOTFILE" 182 | fi 183 | fi 184 | if [ -f "$RIM_BUILD_DWFS_HFILE" ] 185 | then 186 | CMPRS_CMD+=( 187 | --hotness-list="$RIM_BUILD_DWFS_HFILE" 188 | --order hotness::explicit:file="$RIM_BUILD_DWFS_HFILE" 189 | ) 190 | info_msg "Found DwarFS hotness list file: $RIM_BUILD_DWFS_HFILE" 191 | fi 192 | fi 193 | [ -f "$RUNDIR/cryptfs/gocryptfs.conf" ] && \ 194 | CMPRS_EXCLUDE+=("--filter=- rootfs/*/**" "--filter=- rootfs/.*" "--filter=- rootfs/*") 195 | CMPRS_CMD+=( 196 | -f --set-owner 0 --set-group 0 --no-history --log-level error 197 | --no-create-timestamp --header "$RUNRUNTIME" --chmod u+rw --memory-limit=auto 198 | -i "$RUNDIR" -o "$NEWRUNIMAGE" --categorize=hotness -B16 --compression 199 | ) 200 | ;; 201 | *) error_msg "Invalid compression file system: $RIM_CMPRS_FS"; print_help ;; 202 | esac 203 | 204 | case "$RIM_CMPRS_ALGO" in 205 | zstd) 206 | info_msg "Compression algorithm: zstd" 207 | if [ "$RIM_CMPRS_FS" == 'sqfs' ] 208 | then 209 | RIM_CMPRS_BSIZE="${RIM_CMPRS_BSIZE:=128K}" 210 | CMPRS_CMD+=("$RIM_CMPRS_BSIZE" -comp zstd -Xcompression-level "$RIM_CMPRS_LVL") 211 | else 212 | RIM_CMPRS_BSIZE="${RIM_CMPRS_BSIZE:=18}" 213 | CMPRS_CMD+=(zstd:level="$RIM_CMPRS_LVL" -S"$RIM_CMPRS_BSIZE") 214 | fi 215 | info_msg "Compression level: $RIM_CMPRS_LVL" 216 | ;; 217 | lz4) 218 | info_msg "Compression algorithm: lz4" 219 | if [ "$RIM_CMPRS_FS" == 'sqfs' ] 220 | then 221 | RIM_CMPRS_BSIZE="${RIM_CMPRS_BSIZE:=256K}" 222 | CMPRS_CMD+=("$RIM_CMPRS_BSIZE" -comp lz4 -Xhc) 223 | else 224 | RIM_CMPRS_BSIZE="${RIM_CMPRS_BSIZE:=20}" 225 | CMPRS_CMD+=(lz4hc:level="$RIM_CMPRS_LVL" -S"$RIM_CMPRS_BSIZE") 226 | info_msg "Compression level: $RIM_CMPRS_LVL" 227 | fi 228 | ;; 229 | xz) 230 | if [ "$RIM_CMPRS_FS" == 'sqfs' ] 231 | then 232 | info_msg "Compression algorithm: xz" 233 | RIM_CMPRS_BSIZE="${RIM_CMPRS_BSIZE:=1M}" 234 | CMPRS_CMD+=("$RIM_CMPRS_BSIZE" -comp xz -Xdict-size 100%) 235 | else 236 | info_msg "Compression algorithm: lzma" 237 | RIM_CMPRS_BSIZE="${RIM_CMPRS_BSIZE:=22}" 238 | CMPRS_CMD+=(lzma:extreme:level="$RIM_CMPRS_LVL" -S"$RIM_CMPRS_BSIZE") 239 | info_msg "Compression level: $RIM_CMPRS_LVL" 240 | fi 241 | ;; 242 | *) error_msg "Invalid compression algorithm: $RIM_CMPRS_ALGO"; print_help ;; 243 | esac 244 | info_msg "Compression block size: $RIM_CMPRS_BSIZE" 245 | 246 | [ -n "$CMPRS_EXCLUDE" ] && CMPRS_CMD+=("${CMPRS_EXCLUDE[@]}") 247 | 248 | [[ "$INSIDE_RUNIMAGE" == 1 && ! -d "$RUNROOTFS" ]] && \ 249 | RUNROOTFS='/' 250 | 251 | unset IS_PACLOCKFL 252 | PACLOCKFL="$RUNROOTFS/var/lib/pacman/db.lck" 253 | if [ -w "$RUNROOTFS" ] 254 | then 255 | info_msg "Updating build timestamp..." 256 | date '+%y.%m.%d.%H%M%S' > "$RUNROOTFS/.build" 257 | info_msg "Cleanup rootfs..." 258 | if [ -f "$PACLOCKFL" ] 259 | then 260 | IS_PACLOCKFL=1 261 | rm -f "$PACLOCKFL" 262 | fi 263 | RUNUTILS="${RUNUTILS:=$RUNDIR/utils}" 264 | RIM_QUIET_MODE=1 "$RUNSTATIC/bash" \ 265 | "$RUNUTILS/rim-shrink" --pkgcache 266 | else 267 | warn_msg "Unable to update build timestamp. Read-only!" 268 | warn_msg "Unable to cleanup rootfs. Read-only!" 269 | fi 270 | 271 | info_msg "Creating new RunImage..." 272 | info_msg "Path: '$OLDRUNIMAGE'" 273 | "${CMPRS_CMD[@]}" 274 | cmprs_stat=$? 275 | 276 | [ "$IS_PACLOCKFL" == 1 ] && \ 277 | touch "$PACLOCKFL" 278 | 279 | if [[ "$cmprs_stat" != 1 && -f "$NEWRUNIMAGE" ]] 280 | then 281 | if [ "$RIM_CMPRS_FS" == 'sqfs' ] 282 | then 283 | info_msg "Embedding RunImage runtime..." 284 | if ! dd if="$RUNRUNTIME" bs="$RUNOFFSET" count=1 of="$NEWRUNIMAGE" conv=notrunc &>/dev/null 285 | then 286 | error_msg "Failed to embed RunImage runtime!" 287 | rm -f "$NEWRUNIMAGE" 288 | exit 1 289 | fi 290 | fi 291 | info_msg "Marking RunImage as executable..." 292 | if ! chmod +x "$NEWRUNIMAGE" 293 | then 294 | error_msg "Failed to mark RunImage as executable!" 295 | exit 1 296 | fi 297 | if [ -f "$OLDRUNIMAGE" ] 298 | then 299 | if [ "$RIM_KEEP_OLD_BUILD" == 1 ] 300 | then 301 | info_msg "Saving old RunImage: '${OLDRUNIMAGE}.old'" 302 | mv -f "${OLDRUNIMAGE}" "${OLDRUNIMAGE}.old" 303 | else 304 | info_msg "Removing old RunImage..." 305 | rm -f "$OLDRUNIMAGE" 306 | [ -f "${OLDRUNIMAGE}.old" ] && \ 307 | rm -f "${OLDRUNIMAGE}.old" 308 | fi 309 | fi 310 | if ! mv -f "$NEWRUNIMAGE" "$OLDRUNIMAGE" 311 | then 312 | trap - EXIT 313 | error_msg "Failed to rename new RunImage: [$NEWRUNIMAGE] -> [$OLDRUNIMAGE]" 314 | exit 1 315 | fi 316 | RUNIMAGESIZE=($(du -sm "$OLDRUNIMAGE")) 317 | info_msg "The build is complete!" 318 | info_msg "Final size: $RUNIMAGESIZE MB" 319 | else 320 | error_msg "The build failed!" 321 | exit 1 322 | fi 323 | -------------------------------------------------------------------------------- /rootfs/var/RunDir/utils/getdimg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | # Based on https://github.com/moby/moby/blob/master/contrib/download-frozen-image-v2.sh 5 | # Modified to support multiple registries (Docker Hub, GHCR, etc.) 6 | 7 | # Check if essential commands are in our PATH 8 | for cmd in curl jq gawk grep tar sha256sum; do 9 | if ! command -v $cmd &> /dev/null; then 10 | echo >&2 "error: '$cmd' not found!" 11 | exit 1 12 | fi 13 | done 14 | 15 | usage() { 16 | echo "[ Usage ]: $0 [OPTIONS] dir image[:tag][@digest] ..." 17 | echo "$0 /tmp/my-images hello-world:latest alpine:3.18 ghcr.io/void-linux/void-musl:latest" 18 | echo "$0 /tmp/specific-digest hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7" 19 | echo 20 | echo "[ Options ]:" 21 | echo " -a, --arch Override the machine architecture (env: TARGETARCH=amd64)" 22 | echo " --variant Override the machine architecture variant (env: TARGETVARIANT=v8)" 23 | echo " -x, --extract Extract image layers (env: EXTRACT_LAYERS=1)" 24 | echo " -h, --help Show this message" 25 | [ -z "$1" ] || exit "$1" 26 | } 27 | 28 | # --- Colors for output --- 29 | # Reset 30 | Color_Off='\033[0m' # Text Reset 31 | # Regular Colors 32 | Red='\033[0;31m' # Red 33 | Green='\033[0;32m' # Green 34 | Yellow='\033[0;33m' # Yellow 35 | Blue='\033[0;34m' # Blue 36 | Purple='\033[0;35m' # Purple 37 | Cyan='\033[0;36m' # Cyan 38 | # --- End Colors --- 39 | 40 | workDir="" 41 | extractDir="" 42 | 43 | while [[ "$#" -gt 0 ]]; do 44 | case $1 in 45 | -h|--help) usage 0 >&2 ;; 46 | -x|--extract) EXTRACT_LAYERS=1; shift ;; 47 | --variant) 48 | if [[ -n "$2" && "$2" != -* ]] 49 | then TARGETVARIANT="$2"; shift 2 50 | else 51 | echo -e >&2 -e "${Yellow}Option ${Blue}$1 ${Yellow}requires a non-empty argument!${Color_Off}\n" 52 | usage 1 >&2 53 | fi 54 | ;; 55 | -a|--arch) 56 | if [[ -n "$2" && "$2" != -* ]] 57 | then TARGETARCH="$2"; shift 2 58 | else 59 | echo -e >&2 -e "${Yellow}Option ${Blue}$1 ${Yellow}requires a non-empty argument!${Color_Off}\n" 60 | usage 1 >&2 61 | fi 62 | ;; 63 | -*) echo -e >&2 -e "${Red}Unknown parameter: $1${Color_Off}\n"; usage 1 >&2 ;; 64 | *) break ;; 65 | esac 66 | done 67 | 68 | if [ "$EXTRACT_LAYERS" != 1 ] 69 | then workDir="$1" # dir for building tar in 70 | else extractDir="$1"; workDir="$extractDir/tmpdir-$$" 71 | fi 72 | shift || usage 1 >&2 73 | 74 | if ! [ $# -gt 0 ] || [ -z "$workDir" ]; then 75 | usage 2 >&2 76 | fi 77 | mkdir -p "$workDir" 78 | 79 | # Script-level data structures and flags (no 'local' here) 80 | declare -A repositories_data # Associative array for repositories file content 81 | manifestJsonEntries=() # Array for manifest.json entries 82 | doNotGenerateManifestJson="" # Flag 83 | # These will be set by functions but need script scope 84 | auth_base_url="" 85 | auth_service_name="" 86 | bearer_token="" 87 | 88 | # Bash v4+ needed for associative arrays, using temp files for wider compatibility 89 | # Using script-level variable (no 'local' here) 90 | newlineIFS=$'\n' 91 | major=$(echo "${BASH_VERSION%%[^0.9]}" | cut -d. -f1) 92 | if [ "$major" -ge 4 ]; then 93 | newlineIFS=$'\r\n' 94 | fi 95 | 96 | # --- Helper Functions --- 97 | 98 | # Tries to parse realm and service from WWW-Authenticate header 99 | # Sets global variables: auth_base_url, auth_service_name 100 | parse_auth_header() { 101 | local header_line="$1" 102 | # Reset globals 103 | auth_base_url="" 104 | auth_service_name="" 105 | 106 | # Example Header: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/alpine:pull" 107 | if [[ "$header_line" =~ realm=\"([^\"]+)\" ]]; then 108 | auth_base_url="${BASH_REMATCH[1]}" 109 | fi 110 | if [[ "$header_line" =~ service=\"([^\"]+)\" ]]; then 111 | auth_service_name="${BASH_REMATCH[1]}" 112 | fi 113 | 114 | # Fallback for Docker Hub if service is missing 115 | if [[ -n "$auth_base_url" && -z "$auth_service_name" ]] && [[ "$auth_base_url" == *"auth.docker.io"* ]]; then 116 | auth_service_name="registry.docker.io" 117 | fi 118 | } 119 | 120 | # Get Authentication Token 121 | # Usage: get_token registry_host image_path 122 | # Sets global variable: bearer_token 123 | get_token() { 124 | local registry_host="$1" 125 | local image_path="$2" 126 | bearer_token="" # Reset global token 127 | 128 | # 1. Make a preliminary request to V2 endpoint to get WWW-Authenticate header 129 | local auth_header 130 | auth_header=$(curl -s -D - "${registry_host}/v2/" -o /dev/null | grep -i -E '^WWW-Authenticate:') || true 131 | 132 | if [[ -z "$auth_header" ]]; then 133 | # Try the manifest endpoint directly if /v2/ didn't give auth header (e.g., for GCR) 134 | auth_header=$(curl -s -D - "${registry_host}/v2/${image_path}/manifests/latest" -o /dev/null | grep -i -E '^WWW-Authenticate:') || true 135 | fi 136 | 137 | if [[ -n "$auth_header" ]]; then 138 | parse_auth_header "$auth_header" # This function sets globals auth_base_url, auth_service_name 139 | 140 | if [[ -n "$auth_base_url" ]] && [[ -n "$auth_service_name" ]]; then 141 | local scope="repository:${image_path}:pull" 142 | echo " Authenticating with ${auth_service_name} at ${auth_base_url} for scope ${scope}..." >&2 143 | # Set the global bearer_token 144 | bearer_token=$(curl -fsSL "${auth_base_url}?service=${auth_service_name}&scope=${scope}" | jq --raw-output '.token // .access_token // ""') 145 | if [[ -z "$bearer_token" ]]; then 146 | echo -e >&2 " ${Yellow}Warning: Failed to get token. Proceeding anonymously (might fail for private images).${Color_Off}" 147 | else 148 | echo -e >&2 " ${Green}Authentication token obtained.${Color_Off}" 149 | fi 150 | else 151 | echo -e >&2 " ${Yellow}Warning: Could not parse authentication realm/service from WWW-Authenticate header. Proceeding anonymously.${Color_Off}" 152 | echo -e >&2 " Header was: ${auth_header}" 153 | fi 154 | else 155 | echo -e >&2 " ${Yellow}Warning: No WWW-Authenticate header found. Proceeding anonymously (might fail).${Color_Off}" 156 | # Special handling for known public registries if needed (e.g. Docker Hub allows anonymous pulls for public images) 157 | if [[ "$registry_host" == "https://registry-1.docker.io" ]]; then 158 | echo -e >&2 " (Registry is Docker Hub, anonymous pull might work for public images)" 159 | fi 160 | fi 161 | } 162 | 163 | # Fetch Blob (Layer or Config) 164 | # Usage: fetch_blob token registry_base image_path digest target_file [curl_args...] 165 | fetch_blob() { 166 | local token="$1" 167 | local registry_base="$2" 168 | local image_path="$3" 169 | local digest="$4" 170 | local targetFile="$5" 171 | shift 5 172 | local curlArgs=("$@") 173 | 174 | local authHeader="" 175 | if [[ -n "$token" ]]; then 176 | authHeader="Authorization: Bearer $token" 177 | fi 178 | 179 | local blobUrl="${registry_base}/v2/${image_path}/blobs/${digest}" 180 | echo " Fetching blob: ${digest:0:16}..." >&2 181 | 182 | local curlHeadersResponse 183 | # Use -f to fail on server errors, -L to follow redirects 184 | curlHeadersResponse=$( 185 | curl -fSL "${curlArgs[@]}" \ 186 | ${authHeader:+-H "$authHeader"} \ 187 | "$blobUrl" \ 188 | -o "$targetFile" \ 189 | -D - # Capture headers to check for redirects if needed (though -L handles them) 190 | ) 191 | 192 | # Check if the file was downloaded successfully (curl -f checks HTTP status) 193 | if [ $? -ne 0 ]; then 194 | echo -e >&2 "${Red}Error: Failed to download blob ${digest} from ${blobUrl}${Color_Off}" 195 | # Optionally print headers for debugging 196 | # echo "$curlHeadersResponse" >&2 197 | rm -f "$targetFile" # Clean up partial download 198 | return 1 199 | fi 200 | 201 | # Check if file has content (curl might succeed with 0 bytes on certain errors without -f) 202 | if [ ! -s "$targetFile" ]; then 203 | echo -e >&2 "${Red}Error: Downloaded blob ${digest} is empty.${Color_Off}" 204 | rm -f "$targetFile" 205 | return 1 206 | fi 207 | 208 | echo " Blob ${digest:0:16} downloaded successfully." >&2 209 | return 0 210 | } 211 | 212 | # Extract Layer if requested 213 | try_extract_layer() { 214 | if [ "$EXTRACT_LAYERS" == 1 ]; then 215 | local layerTarPath="$1" 216 | local layerIdDir="$(dirname "$layerTarPath")" 217 | local layerId="$(basename "$layerIdDir")" 218 | echo " Extracting layer: ${layerId:0:12}..." >&2 219 | # Ensure target directory exists 220 | mkdir -p "$extractDir" 221 | # Use tar options for potentially better overlay handling if available, but stick to basics for compatibility 222 | if ! tar --exclude='dev/*' --exclude='proc/*' --exclude='sys/*' \ 223 | --exclude='run/*' --exclude='tmp/*' \ 224 | --no-same-owner -xf "$layerTarPath" -C "$extractDir"; then 225 | echo -e >&2 "${Red}Error extracting layer ${layerId:0:12}. Check permissions or tar integrity.${Color_Off}" 226 | # Decide whether to stop or continue 227 | # exit 1 # Uncomment to stop on extraction error 228 | fi 229 | # Remove the layer directory from the temporary workDir after extraction 230 | rm -rf "$layerIdDir" 231 | echo " Layer ${layerId:0:12} extracted." >&2 232 | fi 233 | } 234 | 235 | # Handle 'application/vnd.docker.distribution.manifest.v2+json' or OCI v1 manifest 236 | # Usage: handle_single_manifest_v2 manifest_json registry_base image_path image_tag bearer_token image_identifier 237 | handle_single_manifest_v2() { 238 | local manifestJson="$1" 239 | local registry_base="$2" 240 | local image_path="$3" 241 | local image_tag="$4" 242 | local token="$5" 243 | local imageIdentifier="$6" 244 | 245 | local configDigest 246 | configDigest="$(echo "$manifestJson" | jq --raw-output '.config.digest')" 247 | if [[ -z "$configDigest" || "$configDigest" == "null" ]]; then 248 | echo -e >&2 "${Red}Error: Could not find config digest in manifest for ${imageIdentifier}${Color_Off}" 249 | return 1 250 | fi 251 | local imageId="${configDigest#*:}" 252 | 253 | local configFile="$imageId.json" 254 | if ! fetch_blob "$token" "$registry_base" "$image_path" "$configDigest" "$workDir/$configFile" -s; then 255 | echo -e >&2 "${Red}Error fetching config blob ${configDigest} for ${imageIdentifier}${Color_Off}" 256 | return 1 257 | fi 258 | 259 | local layersFs 260 | layersFs="$(echo "$manifestJson" | jq --raw-output --compact-output '.layers[]')" 261 | local IFS="$newlineIFS" 262 | local layers 263 | mapfile -t layers <<< "$layersFs" 264 | unset IFS 265 | 266 | echo " Downloading ${#layers[@]} layers for '${imageIdentifier}'..." >&2 267 | local layerId="" 268 | local layerFiles=() 269 | 270 | local i # Loop variable, effectively local to the loop 271 | for i in "${!layers[@]}"; do 272 | local layerMeta="${layers[$i]}" 273 | 274 | local layerMediaType 275 | layerMediaType="$(echo "$layerMeta" | jq --raw-output '.mediaType')" 276 | local layerDigest 277 | layerDigest="$(echo "$layerMeta" | jq --raw-output '.digest')" 278 | local layerSize 279 | layerSize="$(echo "$layerMeta" | jq --raw-output '.size')" # For info 280 | 281 | if [[ -z "$layerDigest" || "$layerDigest" == "null" ]]; then 282 | echo -e >&2 "${Red}Error: Found layer with missing digest in manifest for ${imageIdentifier}${Color_Off}" 283 | continue # Skip this layer or return 1? Skipping for now. 284 | fi 285 | 286 | # Create a fake layer ID based on this layer's digest and the previous layer's fake ID 287 | # This matches the structure `docker save` creates 288 | local parentId="$layerId" 289 | layerId="$(echo -n "$parentId"$'\n'"$layerDigest" | sha256sum | cut -d' ' -f1)" # Updates local layerId 290 | 291 | mkdir -p "$workDir/$layerId" 292 | 293 | local layerTar="$layerId/layer.tar" 294 | local layerTarPath="$workDir/$layerTar" 295 | 296 | # Check if layer already exists (useful for resuming or deduplication) 297 | if [ -f "$layerTarPath" ]; then 298 | # Optional: Add size/checksum verification here if needed 299 | echo " Skipping existing layer: ${layerId:0:12} (${layerDigest:0:16})" >&2 300 | else 301 | case "$layerMediaType" in 302 | application/vnd.oci.image.layer.v1.tar+gzip | application/vnd.docker.image.rootfs.diff.tar.gzip | \ 303 | application/vnd.oci.image.layer.v1.tar+zstd | application/vnd.docker.image.rootfs.diff.tar.zst ) # Add zstd support if needed 304 | # Note: Handling zstd would require 'unzstd' command and potentially different tar options 305 | if [[ "$layerMediaType" == *zstd || "$layerMediaType" == *zst ]]; then 306 | echo -e >&2 "${Yellow}Warning: Zstandard layer found (${layerDigest:0:16}). Extraction might require 'zstd' package.${Color_Off}" 307 | fi 308 | 309 | # Fetch the blob 310 | if ! fetch_blob "$token" "$registry_base" "$image_path" "$layerDigest" "$layerTarPath" --progress-bar; then 311 | echo -e >&2 "${Red}Error fetching layer blob ${layerDigest} for ${imageIdentifier}. Skipping layer.${Color_Off}" 312 | rm -rf "$workDir/$layerId" # Clean up failed layer dir 313 | continue # Skip to next layer 314 | fi 315 | ;; 316 | # Handle non-compressed variants if they exist 317 | application/vnd.oci.image.layer.v1.tar | application/vnd.docker.image.rootfs.diff.tar ) 318 | if ! fetch_blob "$token" "$registry_base" "$image_path" "$layerDigest" "$layerTarPath" --progress-bar; then 319 | echo -e >&2 "${Red}Error fetching layer blob ${layerDigest} for ${imageIdentifier}. Skipping layer.${Color_Off}" 320 | rm -rf "$workDir/$layerId" # Clean up failed layer dir 321 | continue # Skip to next layer 322 | fi 323 | ;; 324 | *) 325 | echo -e >&2 "${Red}Error: Unsupported layer mediaType for ${layerDigest}: '$layerMediaType'${Color_Off}" 326 | # Decide whether to skip or fail 327 | # return 1 # Fail hard 328 | rm -rf "$workDir/$layerId" # Clean up 329 | continue # Skip layer 330 | ;; 331 | esac 332 | fi 333 | 334 | # Add layer tar path to list for manifest.json generation (only if not extracting) 335 | if [ "$EXTRACT_LAYERS" != 1 ]; then 336 | layerFiles+=("$layerTar") # Modifies local layerFiles 337 | fi 338 | 339 | # Generate metadata files if not extracting 340 | if [ "$EXTRACT_LAYERS" != 1 ]; then 341 | echo '1.0' > "$workDir/$layerId/VERSION" 342 | # Create minimal json file for the layer ID 343 | if [ ! -s "$workDir/$layerId/json" ]; then 344 | local parentJson="" 345 | [[ -n "$parentId" ]] && parentJson="$(printf ', "parent": "%s"' "$parentId")" 346 | # Create a basic JSON structure. More fields could be added if needed, 347 | # but Docker load seems tolerant of minimal info here. 348 | # Using epoch timestamp for simplicity, actual timestamp isn't critical here. 349 | printf '{ "id": "%s", "created": "1970-01-01T00:00:00Z"%s }' "$layerId" "$parentJson" > "$workDir/$layerId/json" 350 | fi 351 | fi 352 | 353 | # Extract the layer if requested 354 | try_extract_layer "$layerTarPath" 355 | 356 | done # End layer loop 357 | 358 | 359 | if [ "$EXTRACT_LAYERS" != 1 ]; then 360 | # Use the ID of the *last* layer created as the image ID for the repositories file 361 | local finalImageId="$layerId" 362 | 363 | # Munge the top layer manifest (config) to create the final layer's json for older Docker versions 364 | # It expects the main config under the final layer ID directory. 365 | # We copy the downloaded config and add id/parent references. 366 | if [[ -n "$finalImageId" ]] && [[ -f "$workDir/$configFile" ]]; then 367 | # parentId holds the ID of the second-to-last layer processed (parent of the final layer) 368 | # We need to pass either the JSON string value of parentId or the JSON literal null. 369 | local parentIdJsonValue="null" # Default to JSON null literal 370 | if [[ -n "$parentId" ]]; then 371 | # Safely create a valid JSON string from the parentId variable 372 | # Using jq -n ensures correct quoting/escaping if parentId contains special chars 373 | parentIdJsonValue=$(jq -n --arg p "$parentId" '$p') 374 | fi 375 | 376 | # Use --argjson with the correctly formatted JSON value (string or null) 377 | jq --arg id "$finalImageId" --argjson parentIdValue "$parentIdJsonValue" \ 378 | '. | . + {id: $id} + (if $parentIdValue != null then {parent: $parentIdValue} else {} end)' \ 379 | "$workDir/$configFile" > "$workDir/$finalImageId/json" 380 | 381 | elif [[ -z "$finalImageId" ]] && [[ -n "$imageId" ]]; then 382 | # This case might occur if there were 0 layers? Unlikely but handle fallback. 383 | echo >&2 "${Yellow}Warning: No layers processed for ${imageIdentifier}, cannot generate final layer JSON structure correctly. Using base config ID.${Color_Off}" 384 | finalImageId=$imageId # Fallback to original image ID from config digest 385 | # If we fallback, maybe copy the config without parent info? 386 | if [[ -f "$workDir/$configFile" ]]; then 387 | jq --arg id "$finalImageId" '. | . + {id: $id}' "$workDir/$configFile" > "$workDir/$finalImageId/json" 388 | fi 389 | elif [[ -z "$finalImageId" ]]; then 390 | echo >&2 "${Red}Error: Cannot determine final image ID for ${imageIdentifier}.${Color_Off}" 391 | # Decide how critical this is - maybe return 1? 392 | return 1 # Or continue if possible 393 | fi 394 | 395 | # --- The rest of the 'if [ "$EXTRACT_LAYERS" != 1 ]; then' block follows --- 396 | # Add entry for manifest.json 397 | local repoTagName="${image_path#library\/}:${image_tag}" 398 | # If registry was not docker hub, include it 399 | if [[ "$registry_base" != "https://registry-1.docker.io" ]]; then 400 | local registryHostName="${registry_base#https://}" 401 | repoTagName="${registryHostName}/${image_path}:${image_tag}" 402 | fi 403 | 404 | local layersJsonArray="[]" 405 | if [ ${#layerFiles[@]} -gt 0 ]; then 406 | layersJsonArray=$(printf '%s\n' "${layerFiles[@]}" | jq -R . | jq -s .) 407 | fi 408 | 409 | local manifestJsonEntry 410 | manifestJsonEntry="$(jq -n --arg cfg "$configFile" --argjson layers "$layersJsonArray" --argjson tags "[\"$repoTagName\"]" \ 411 | '{ Config: $cfg, RepoTags: $tags, Layers: $layers }')" 412 | 413 | # Modify global manifestJsonEntries array 414 | manifestJsonEntries+=("$manifestJsonEntry") 415 | 416 | # Add to global repositories_data structure 417 | local repoKey="${repoTagName%:*}" 418 | local tagKey="$image_tag" 419 | # Make sure finalImageId is actually set before using it 420 | if [[ -n "$finalImageId" ]]; then 421 | repositories_data["$repoKey:$tagKey"]="$finalImageId" # Modify global repo data 422 | else 423 | echo >&2 "${Yellow}Warning: finalImageId was not set when trying to update repositories data for ${repoKey}:${tagKey}.${Color_Off}" 424 | fi 425 | fi 426 | return 0 # Success 427 | } 428 | 429 | # Get Target Architecture 430 | get_target_arch() { 431 | if [ -n "${TARGETARCH:-}" ]; then 432 | echo "${TARGETARCH}" 433 | return 0 434 | fi 435 | 436 | # Try uname 437 | if type uname > /dev/null; then 438 | local uArch 439 | uArch="$(uname -m)" 440 | case "${uArch}" in 441 | x86_64 | amd64) echo "amd64" ;; 442 | aarch64 | arm64) echo "arm64" ;; 443 | armv[78]l*) echo "arm" ;; # Basic ARM detection 444 | arm) echo "arm" ;; # Generic ARM 445 | i[3-6]86) echo "386" ;; 446 | *) 447 | echo -e >&2 "${Yellow}Warning: Unsupported architecture '${uArch}'. Falling back to amd64. Set TARGETARCH manually.${Color_Off}" 448 | echo "amd64" 449 | ;; 450 | esac 451 | return 0 452 | fi 453 | 454 | echo -e >&2 "${Yellow}Warning: Cannot determine CPU arch using 'uname'. Falling back to amd64. Set TARGETARCH manually.${Color_Off}" 455 | echo "amd64" 456 | } 457 | 458 | # Get Target Variant (less common, usually empty) 459 | get_target_variant() { 460 | echo "${TARGETVARIANT:-}" # Often v6, v7, v8 for ARM 461 | } 462 | 463 | # --- Main Processing Loop --- 464 | 465 | # Script-level counter (no 'local' here) 466 | processed_images=0 467 | # imageSpec is loop variable, effectively local to loop iteration 468 | for imageSpec in "$@"; do 469 | echo -e "${Cyan}Processing image: ${imageSpec}${Color_Off}" 470 | 471 | # --- Parse Image Specification --- 472 | # Format: [registry/][user/]repository[:tag][@digest] 473 | # These variables are scoped to the loop iteration (no 'local' needed/allowed here) 474 | registryHost="registry-1.docker.io" # Default registry 475 | imagePath="" 476 | tag="latest" # Default tag 477 | digest="" 478 | 479 | # Extract digest if present 480 | if [[ "$imageSpec" == *@* ]]; then 481 | digest="${imageSpec##*@}" 482 | imageSpec="${imageSpec%%@*}" # Remove digest part for now 483 | fi 484 | 485 | # Extract tag if present 486 | if [[ "$imageSpec" == *:* ]]; then 487 | tag="${imageSpec##*:}" 488 | imageSpec="${imageSpec%%:*}" # Remove tag part 489 | fi 490 | 491 | # Check for registry hostname (contains '.' or ':') 492 | if [[ "${imageSpec%%/*}" == *.* ]] || [[ "${imageSpec%%/*}" == *:* ]]; then 493 | registryHost="${imageSpec%%/*}" 494 | imagePath="${imageSpec#*/}" 495 | else 496 | # No registry specified, assume Docker Hub 497 | imagePath="$imageSpec" 498 | # Add 'library/' prefix for official Docker Hub images unless already namespaced 499 | if [[ "$imagePath" != */* ]]; then 500 | imagePath="library/$imagePath" 501 | fi 502 | fi 503 | 504 | # Final check for empty image path (e.g., user provided only "ghcr.io/") 505 | if [[ -z "$imagePath" ]]; then 506 | echo -e >&2 "${Red}Error: Invalid image specification '${imageSpec}'. Image path cannot be empty.${Color_Off}" 507 | continue # Skip to next image 508 | fi 509 | 510 | # Variables scoped to the loop iteration (no 'local' needed/allowed here) 511 | registryBase="https://${registryHost}" # Construct registry base URL 512 | fetchRef="${digest:-$tag}" # Use digest if specified, otherwise tag 513 | imageIdentifier="${registryHost}/${imagePath}:${tag}${digest:+@$digest}" # For display 514 | 515 | echo " Registry: ${registryBase}" >&2 516 | echo " Image Path: ${imagePath}" >&2 517 | echo " Tag: ${tag}" >&2 518 | [[ -n "$digest" ]] && echo " Digest: ${digest}" >&2 519 | echo " Reference to fetch: ${fetchRef}" >&2 520 | 521 | 522 | # --- Get Authentication Token --- 523 | # Global var bearer_token is set by this function 524 | get_token "$registryBase" "$imagePath" # Updates global bearer_token 525 | 526 | # Variable scoped to the loop iteration (no 'local' needed/allowed here) 527 | authCurlHeader=() # Array for curl header option 528 | if [[ -n "$bearer_token" ]]; then 529 | authCurlHeader=(-H "Authorization: Bearer $bearer_token") 530 | fi 531 | 532 | # --- Fetch Manifest --- 533 | echo " Fetching manifest for ${fetchRef}..." >&2 534 | # Variable scoped to the loop iteration (no 'local' needed/allowed here) 535 | manifestJson="" 536 | manifestJson=$( 537 | curl -fsSL \ 538 | "${authCurlHeader[@]}" \ 539 | -H 'Accept: application/vnd.oci.image.index.v1+json' \ 540 | -H 'Accept: application/vnd.docker.distribution.manifest.list.v2+json' \ 541 | -H 'Accept: application/vnd.oci.image.manifest.v1+json' \ 542 | -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' \ 543 | "${registryBase}/v2/${imagePath}/manifests/${fetchRef}" 544 | ) 545 | 546 | if [ $? -ne 0 ] || [[ "${manifestJson:0:1}" != '{' ]]; then 547 | echo -e >&2 "${Red}Error: Failed to fetch manifest for ${imageIdentifier} (${fetchRef})." 548 | echo -e >&2 " Response was: ${manifestJson:-}" 549 | # Attempt to get a more specific error using -i 550 | echo -e >&2 " Trying fetch with headers..." 551 | curl -fSL -i \ 552 | "${authCurlHeader[@]}" \ 553 | -H 'Accept: application/vnd.oci.image.index.v1+json' \ 554 | -H 'Accept: application/vnd.docker.distribution.manifest.list.v2+json' \ 555 | -H 'Accept: application/vnd.oci.image.manifest.v1+json' \ 556 | -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' \ 557 | "${registryBase}/v2/${imagePath}/manifests/${fetchRef}" >&2 || true 558 | continue # Skip to next image 559 | fi 560 | 561 | # --- Process Manifest --- 562 | # Variable scoped to the loop iteration (no 'local' needed/allowed here) 563 | schemaVersion="" 564 | schemaVersion="$(echo "$manifestJson" | jq --raw-output '.schemaVersion // 1')" # Default to 1 if missing 565 | 566 | case "$schemaVersion" in 567 | 2) 568 | # Variable scoped to the case block (no 'local' needed/allowed here) 569 | mediaType="" 570 | mediaType="$(echo "$manifestJson" | jq --raw-output '.mediaType // ""')" 571 | 572 | case "$mediaType" in 573 | # Single Architecture Manifests 574 | application/vnd.oci.image.manifest.v1+json | \ 575 | application/vnd.docker.distribution.manifest.v2+json) 576 | echo " Processing V2 manifest (${mediaType})..." >&2 577 | # Pass the global bearer_token to the function 578 | if ! handle_single_manifest_v2 "$manifestJson" "$registryBase" "$imagePath" "$tag" "$bearer_token" "$imageIdentifier"; then 579 | echo -e >&2 "${Red}Failed to process manifest for ${imageIdentifier}${Color_Off}" 580 | # Decide whether to continue or exit 581 | else 582 | processed_images=$((processed_images + 1)) # Update global counter 583 | fi 584 | ;; 585 | 586 | # Multi-Architecture Manifest (Manifest List / OCI Index) 587 | application/vnd.oci.image.index.v1+json | \ 588 | application/vnd.docker.distribution.manifest.list.v2+json) 589 | echo " Processing manifest list (${mediaType})..." >&2 590 | # Variables scoped to this case block (no 'local' needed/allowed here) 591 | manifestsFs="" 592 | manifestsFs="$(echo "$manifestJson" | jq --raw-output --compact-output '.manifests[]')" 593 | IFS="$newlineIFS" # Temporarily shadow global IFS in this scope 594 | manifests=() 595 | mapfile -t manifests <<< "$manifestsFs" 596 | unset IFS 597 | 598 | found_manifest="" 599 | targetArch=$(get_target_arch) 600 | targetVariant=$(get_target_variant) 601 | echo " Searching for architecture: ${targetArch}${targetVariant:+/${targetVariant}}" >&2 602 | 603 | # 'i' is loop variable 604 | for i in "${!manifests[@]}"; do 605 | # Variables scoped to this inner loop (no 'local' needed/allowed here) 606 | manifestEntryJson="${manifests[$i]}" 607 | entryDigest="" entryArch="" entryVariant="" entryOS="" 608 | entryDigest="$(echo "$manifestEntryJson" | jq --raw-output '.digest // ""')" 609 | entryArch="$(echo "$manifestEntryJson" | jq --raw-output '.platform.architecture // ""')" 610 | entryVariant="$(echo "$manifestEntryJson" | jq --raw-output '.platform.variant // ""')" 611 | entryOS="$(echo "$manifestEntryJson" | jq --raw-output '.platform.os // "linux"')" # Assume linux if unspecified 612 | 613 | # Match criteria: OS (usually linux), Architecture, and Variant (if specified) 614 | if [[ "$entryOS" == "linux" ]] && \ 615 | [[ "$entryArch" == "$targetArch" ]] && \ 616 | ( [[ -z "$targetVariant" ]] || [[ "$entryVariant" == "$targetVariant" ]] || [[ "$entryVariant" == "null" ]] ); then 617 | 618 | echo " Found matching manifest: Digest=${entryDigest:0:16}, Arch=${entryArch}, Variant=${entryVariant:-}" >&2 619 | # Fetch the architecture-specific manifest 620 | # Variable scoped here (no 'local' needed/allowed here) 621 | subManifestJson="" 622 | subManifestJson=$( 623 | curl -fsSL \ 624 | "${authCurlHeader[@]}" \ 625 | -H 'Accept: application/vnd.oci.image.manifest.v1+json' \ 626 | -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' \ 627 | "${registryBase}/v2/${imagePath}/manifests/${entryDigest}" 628 | ) 629 | if [ $? -ne 0 ] || [[ "${subManifestJson:0:1}" != '{' ]]; then 630 | echo -e >&2 "${Red}Error: Failed to fetch specific manifest ${entryDigest} for ${imageIdentifier}${Color_Off}" 631 | # Optionally try next match? For now, fail this image. 632 | found_manifest="error" 633 | break 634 | fi 635 | 636 | # Process the fetched single-arch manifest 637 | # Pass the global bearer_token 638 | if ! handle_single_manifest_v2 "$subManifestJson" "$registryBase" "$imagePath" "$tag" "$bearer_token" "${imageIdentifier} (arch ${entryArch})"; then 639 | echo -e >&2 "${Red}Failed to process arch-specific manifest for ${imageIdentifier}${Color_Off}" 640 | found_manifest="error" 641 | else 642 | found_manifest="found" 643 | processed_images=$((processed_images + 1)) # Update global counter 644 | fi 645 | break # Found a match, stop searching 646 | fi 647 | done # End manifest list loop 648 | 649 | if [[ -z "$found_manifest" ]]; then 650 | echo -e >&2 "${Red}Error: Manifest for ${targetArch}${targetVariant:+/${targetVariant}} not found in list for ${imageIdentifier}${Color_Off}" 651 | echo -e >&2 "Available Architectures:" 652 | echo "$manifestJson" | jq -c '.manifests[] | { arch: .platform.architecture, variant: .platform.variant, os: .platform.os, digest: .digest }' >&2 653 | elif [[ "$found_manifest" == "error" ]]; then 654 | echo -e >&2 "${Red}Error occurred while processing the selected architecture manifest for ${imageIdentifier}${Color_Off}" 655 | fi 656 | ;; 657 | *) 658 | echo -e >&2 "${Red}Error: Unknown V2 manifest mediaType for ${imageIdentifier}: '$mediaType'${Color_Off}" 659 | ;; 660 | esac 661 | ;; 662 | 1) 663 | echo -e >&2 "${Yellow}Warning: Schema V1 manifest found for ${imageIdentifier}. Support is limited and may be less reliable.${Color_Off}" 664 | if [[ -z "$doNotGenerateManifestJson" && "$EXTRACT_LAYERS" != 1 ]]; then 665 | echo -e >&2 "${Yellow} Schema V1 does not support generating manifest.json. Docker history might be incomplete.${Color_Off}" 666 | doNotGenerateManifestJson=1 # Set global flag 667 | fi 668 | 669 | # V1 handling adapted from original script - might need adjustments 670 | # Variables scoped to this case block (no 'local' needed/allowed here) 671 | layersFs="" history="" imageId="" 672 | layersFs="$(echo "$manifestJson" | jq --raw-output '.fsLayers | .[] | .blobSum')" 673 | history="$(echo "$manifestJson" | jq --compact-output '.history // .fsLayers | [.[] | .v1Compatibility // {id: .blobSum}]')" # Try to get history, fallback to blobsums as IDs 674 | imageId="$(echo "$history" | jq --raw-output '.[0] | fromjson? | .id // .[0] // ""' )" # Get ID from first history entry 675 | 676 | if [[ -z "$imageId" ]]; then 677 | echo -e >&2 "${Red}Error: Could not determine base image ID for V1 manifest ${imageIdentifier}${Color_Off}" 678 | continue 679 | fi 680 | 681 | # Variable scoped here (no 'local' needed/allowed here) 682 | IFS="$newlineIFS" # Shadow global IFS 683 | layers=() 684 | mapfile -t layers <<< "$layersFs" 685 | unset IFS 686 | 687 | echo " Downloading V1 layers for '$imageIdentifier' (${#layers[@]} layers)..." >&2 688 | # Variable scoped here (no 'local' needed/allowed here) 689 | layerId="" # Track parent for V1 structure if possible 690 | 691 | # 'i' is loop variable 692 | for i in "${!layers[@]}"; do 693 | # Variables scoped to this loop (no 'local' needed/allowed here) 694 | imageLayer="${layers[$i]}" # This is the layer digest (blobSum) 695 | layerJson="{}" # Default minimal JSON 696 | currentLayerId=$imageId # Use base ID for first, generate for subsequent? V1 structure is tricky. 697 | # Let's try generating IDs similar to V2 for consistency in tar structure. 698 | 699 | # Try to get layer-specific ID from history if possible 700 | histEntryJson=$(echo "$history" | jq --raw-output ".[$i] | fromjson?") 701 | if [[ -n "$histEntryJson" ]]; then 702 | layerJson=$histEntryJson 703 | currentLayerId=$(echo "$layerJson" | jq -r '.id // ""') 704 | fi 705 | # If no ID from history, generate one based on blob + parent (less standard for V1) 706 | if [[ -z "$currentLayerId" ]]; then 707 | parentId="$layerId" # Use previous loop's layerId 708 | currentLayerId="$(echo -n "$parentId"$'\n'"$imageLayer" | sha256sum | cut -d' ' -f1)" 709 | fi 710 | layerId=$currentLayerId # Update for next parent tracking 711 | 712 | mkdir -p "$workDir/$layerId" 713 | layerTar="$layerId/layer.tar" 714 | layerTarPath="$workDir/$layerTar" 715 | 716 | if [ -f "$layerTarPath" ]; then 717 | echo " Skipping existing V1 layer: ${layerId:0:12} (${imageLayer:0:16})" >&2 718 | else 719 | # Pass the global bearer_token 720 | if ! fetch_blob "$bearer_token" "$registryBase" "$imagePath" "$imageLayer" "$layerTarPath" --progress-bar; then 721 | echo -e >&2 "${Red}Error fetching V1 layer blob ${imageLayer}. Skipping layer.${Color_Off}" 722 | rm -rf "$workDir/$layerId" 723 | continue 724 | fi 725 | fi 726 | 727 | if [ "$EXTRACT_LAYERS" != 1 ]; then 728 | echo '1.0' > "$workDir/$layerId/VERSION" 729 | echo "$layerJson" > "$workDir/$layerId/json" # Save the v1Compatibility JSON if found 730 | fi 731 | 732 | try_extract_layer "$layerTarPath" 733 | done # End V1 layer loop 734 | 735 | if [ "$EXTRACT_LAYERS" != 1 ]; then 736 | # Add to repositories data structure for V1 737 | # Variables scoped here (no 'local' needed/allowed here) 738 | repoTagName="${imagePath#library\/}:${tag}" # Use image path (strip library/ if present) and tag 739 | # If registry was not docker hub, include it 740 | if [[ "$registryBase" != "https://registry-1.docker.io" ]]; then 741 | registryHostName="${registryBase#https://}" 742 | repoTagName="${registryHostName}/${imagePath}:${tag}" 743 | fi 744 | repoKey="${repoTagName%:*}" # Key is image name without tag 745 | tagKey="$tag" 746 | repositories_data["$repoKey:$tagKey"]="$layerId" # Use the *last* layer ID generated - update global 747 | fi 748 | processed_images=$((processed_images + 1)) # Update global counter 749 | ;; 750 | *) 751 | echo -e >&2 "${Red}Error: Unknown manifest schemaVersion for ${imageIdentifier}: '$schemaVersion'${Color_Off}" 752 | ;; 753 | esac # End schemaVersion case 754 | 755 | echo -e "${Green}Finished processing: ${imageIdentifier}${Color_Off}\n" 756 | 757 | done # End imageSpec loop 758 | 759 | # --- Finalization --- 760 | 761 | if [ "$processed_images" -eq 0 ]; then 762 | echo -e >&2 "${Red}No images were successfully processed.${Color_Off}" 763 | rm -rf "$workDir" # Clean up temp dir if nothing worked 764 | exit 1 765 | fi 766 | 767 | if [ "$EXTRACT_LAYERS" != 1 ]; then 768 | # --- Create repositories File --- 769 | echo "Generating repositories metadata..." >&2 770 | # Variable scoped here (no 'local' needed/allowed here) 771 | repositoriesJson=$(jq -n '{}') # Start with empty JSON object 772 | # Group tags by repository key 773 | # Associative array scoped here (no 'local' needed/allowed here) 774 | declare -A grouped_repos 775 | # Loop variables scoped to loop (no 'local' needed/allowed here) 776 | repo_tag_key="" 777 | repo_key="" 778 | tag_key="" 779 | image_id="" 780 | for repo_tag_key in "${!repositories_data[@]}"; do 781 | repo_key="${repo_tag_key%:*}" 782 | tag_key="${repo_tag_key#*:}" 783 | image_id="${repositories_data[$repo_tag_key]}" 784 | grouped_repos["$repo_key"]="${grouped_repos[$repo_key]:+$grouped_repos[$repo_key],}\"$tag_key\": \"$image_id\"" 785 | done 786 | 787 | # Build the final JSON string 788 | # Array scoped here (no 'local' needed/allowed here) 789 | repo_entries=() 790 | # Loop variable scoped to loop (no 'local' needed/allowed here) 791 | for repo_key in "${!grouped_repos[@]}"; do 792 | repo_entries+=("\"$repo_key\": { ${grouped_repos[$repo_key]} }") 793 | done 794 | repositoriesJson="{$(IFS=,; echo "${repo_entries[*]}")}" 795 | 796 | # Validate and write JSON 797 | if echo "$repositoriesJson" | jq '.' > "$workDir/repositories"; then 798 | echo " repositories file created." >&2 799 | else 800 | echo -e >&2 "${Red}Error: Failed to generate valid JSON for repositories file.${Color_Off}" 801 | echo "$repositoriesJson" > "$workDir/repositories.invalid" # Save for debugging 802 | fi 803 | 804 | # --- Create manifest.json File --- 805 | if [ -z "$doNotGenerateManifestJson" ] && [ ${#manifestJsonEntries[@]} -gt 0 ]; then 806 | echo "Generating manifest.json..." >&2 807 | # Combine individual manifest entries into a JSON array 808 | # Variable scoped here (no 'local' needed/allowed here) 809 | manifestJsonArrayString="[$(IFS=,; echo "${manifestJsonEntries[*]}")]" 810 | if echo "$manifestJsonArrayString" | jq '.' > "$workDir/manifest.json"; then 811 | echo " manifest.json created." >&2 812 | else 813 | echo -e >&2 "${Red}Error: Failed to generate valid JSON for manifest.json.${Color_Off}" 814 | echo "$manifestJsonArrayString" > "$workDir/manifest.json.invalid" # Save for debugging 815 | fi 816 | else 817 | rm -f "$workDir/manifest.json" # Ensure no outdated manifest exists if skipped 818 | if [ -n "$doNotGenerateManifestJson" ]; then 819 | echo -e >&2 "${Yellow}Skipped manifest.json generation due to V1 schema image(s).${Color_Off}" 820 | fi 821 | fi 822 | 823 | echo -e "${Green}Download of image(s) into ${Cyan}'${workDir}' complete.${Color_Off}" 824 | echo "Use 'docker load' to import the image(s):" 825 | echo -e " ${Cyan}tar -cC '$workDir' . | docker load${Color_Off}" 826 | else 827 | # --- Extraction Mode --- 828 | echo -e "${Green}Image(s) layer(s) extraction complete.${Color_Off}" 829 | # Move contents from temp working dir to final extraction dir if needed 830 | # (Currently extraction happens directly into extractDir, tmpdir just holds tars briefly) 831 | if [ -d "$workDir" ]; then 832 | # If anything is left in workDir (e.g., config files), move it? 833 | # Or just clean it up. Let's clean it up. 834 | rm -rf "$workDir" 835 | fi 836 | # Ensure correct permissions if needed 837 | chmod -R u+rw "$extractDir" 838 | echo -e "Layer(s) extracted to: ${Green}${extractDir}${Color_Off}" 839 | fi 840 | 841 | exit 0 842 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RunImage 2 | 3 | ## **Portable single-file Linux container in unprivileged user namespaces** 4 | 5 | ![image](screenshots/rim-shell.png) 6 | 7 | RunImage is designed to be completely static and portable to run on almost any Linux distribution. It is based on a specially configured [Arch Linux rootfs](https://github.com/VHSgunzo/runimage-rootfs). The technology of single-file containerization is based on [unprivileged user namespaces](https://lwn.net/Articles/531114) and works with a [uruntime](https://github.com/VHSgunzo/uruntime), [DwarFS](https://github.com/mhx/dwarfs) (or [SquashFS](https://docs.kernel.org/filesystems/squashfs.html)) image, statically compiled [binaries](https://github.com/VHSgunzo/runimage-static) and [sharun](https://github.com/VHSgunzo/sharun) for the operation of the container [Run.sh script](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/Run.sh), and containerization itself is carried out by [statically compiled](https://github.com/VHSgunzo/bubblewrap-static/releases) [Bubblewrap](https://github.com/containers/bubblewrap) with [tini](https://github.com/VHSgunzo/tini) as init and [ssrv](https://github.com/VHSgunzo/ssrv) as shell server/client. 8 | 9 | In addition, RunImage has the ability to isolate itself from the main system, use separate portable or sandbox home directories and configuration files for each executable file, and has the ability to run separate X11 servers, including running multiple Xorg servers on TTY (XFCE is used as DE) 10 | 11 | You can use it to develop or run any applications and games, including applications and games for Windows, launch games from retro platforms using popular emulators, work with the office, with remote desktops, multimedia, browsers, messengers, and even run virtual machines with QEMU/KVM and Virt-Manager, USB and block device forwarding in VM also works. 12 | 13 | Also inside the container, you can use various means of proxification, such as proxychains, tor and others and run VNC and SSH servers. 14 | In network sandbox mode you can use VPN (tested [openvpn](https://community.openvpn.net/openvpn), [wireguard](https://www.wireguard.com/), [sshuttle](https://github.com/sshuttle/sshuttle), [tun2proxy](https://github.com/blechschmidt/tun2proxy)) and other network tools without root rights. 15 | 16 | The full list of installed packages can be found in the [**releases**](https://github.com/VHSgunzo/runimage/releases/continuous) file `pkg_list{-release-type}.txt` 17 | 18 | ## Features: 19 | 20 | * Supports the `x86_64` and `aarch64` architectures. 21 | * A portable single executable file with an idea - downloaded and launched. Nothing needs to be installed in the system. 22 | * Works on most Linux distributions, including even very old ones or without glibc or systemd and in live boot mode. 23 | * OverlayFS mode (It looks like the usual means of containerization like docker) (See [Usage](https://github.com/VHSgunzo/runimage#usage)) 24 | * Read-Write mount in OverlayFS mode. 25 | * The ability to en/decrypt container rootfs 26 | * Running and working without root rights, including package management. 27 | * The ability to work in a packed and unpacked form. 28 | * The ability to run both 32-bit and 64-bit executable files. 29 | * Based on Arch Linux, contains the latest software and [AUR](https://aur.archlinux.org) support. 30 | * Access to [BlackArch](https://github.com/BlackArch/blackarch) repo. 31 | * Access to [Chaotic-AUR](https://aur.chaotic.cx) repo. 32 | * Own Pacman [repository](https://runimage-repo.hf.space) with [mirror](https://github.com/runimage/repo). 33 | * Updating without extraction runimage and automatic rebuild if the update was successful. 34 | * The ability to launching AppImage applications with FUSE mount (not needed to extract). 35 | * The ability to exec commands at the host level (see RIM_ENABLE_HOSTEXEC and [hostexec](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/hostexec)) 36 | * The ability to use both separate home directories for each executable file, and completely seamless use of the system home directory. 37 | * The ability to use separate container configuration files for each launched executable file 38 | * There is no performance drawdown. All applications and executable files run at the same speed as in the system 39 | * The ability to Filesystem, X11, DBUS, UDEV, Network, SystemD, USERs and PIDs sandboxing. 40 | * Port forwarding in sandbox network mode (TCP, UDP, SOCKS5 proxy and reverse mode supports). 41 | * Temporary home directory in RAM (can be used as a real private mode for browsers and applications) 42 | * Sandbox and portable home directory. 43 | * The ability to launching a full DE in windowed/full screen mode and on TTY 44 | * Works with any versions of nvidia proprietary drivers 45 | * Works in Wayland session. 46 | * Monitoring of running processes 47 | * Background processes control 48 | * The ability to execute commands in a single container or in specified container. 49 | * The ability to start and control SystemD services with [fake-systemd](https://github.com/VHSgunzo/runimage-fake-systemd) package. 50 | * The ability to use custom rootfs (alpine-based, debian-based, voidlinux-based supports) 51 | * Usability and comprehensibility. 52 | 53 | ## Requirements: 54 | 55 | * Supported architectures (should work on any Linux kernel architecture. However, it is currently only built for `x86_64` and `aarch64`) 56 | * Minimum recommended Linux kernel version 4.18+ (tested on Centos 7 with 3.10 and on Ubuntu 12.04 with 3.11 using SUID Bubblewrap and it's works, but 5.0+ with [unprivileged user namespaces](https://lwn.net/Articles/531114) support is recommended) 57 | * FUSE (but not necessarily, because it is possible to work in unpacked form without FUSE mounting). Also you can create /dev/fuse manually (as root) if the kernel module exists (see this [code](https://github.com/libfuse/libfuse/blob/f0e08cc700d629da2d46def8b620b0ed858cc0d9/util/install_helper.sh#L35)): 58 | ``` 59 | mknod /dev/fuse -m 0666 c 10 229 60 | ``` 61 | 62 | ## To get started: 63 | 64 | 1. Download continuous release from the [**releases**](https://github.com/VHSgunzo/runimage/releases/continuous) page. ([HF mirror](https://huggingface.co/runimage/releases/tree/main/stable)) 65 | 2. Make it executable before run. 66 | ``` 67 | chmod +x runimage 68 | ``` 69 | 70 | ## Usage: 71 | 72 | ``` 73 | ┌──[user@host]─[~] 74 | └──╼ $ runimage {args} {executable} {executable args} 75 | 76 | rim-help Show this usage info 77 | rim-version Show RunImage, rootfs, static, runtime version 78 | rim-pkgls Show packages installed in RunImage 79 | rim-binls Show executables in RunImage 80 | rim-shell {args} Run RunImage shell or execute a command in RunImage shell 81 | rim-desktop {args} Launch RunImage desktop 82 | rim-ofsls Show the list of RunImage OverlayFS 83 | rim-ofsrm {id id ...|all} Remove OverlayFS 84 | rim-build {args} Build new RunImage container 85 | rim-update {args} Update packages and rebuild RunImage 86 | rim-kill {RUNPIDs|all} Kill running RunImage containers 87 | rim-psmon {args} {RUNPIDs} Monitoring of processes running in RunImage containers 88 | rim-exec {RUNPID} {args} Exec command in running container 89 | rim-portfw {RUNPID} {args} Forward additional ports 90 | rim-dinteg {args} Desktop integration 91 | rim-shrink {args} Shrink RunImage rootfs 92 | rim-bootstrap {pkg pkg} Bootstrap new RunImage 93 | rim-encfs {build args} Encrypt RunImage rootfs 94 | rim-decfs {build args} Decrypt RunImage rootfs 95 | rim-enc-passwd {build args} Change decrypt password for encrypted RunImage rootfs 96 | 97 | Only for not extracted (RunImage runtime options): 98 | --runtime-extract {pattern} Extract content from embedded filesystem image 99 | --runtime-extract-and-run {args} Run RunImage after extraction without using FUSE 100 | --runtime-help Show RunImage runtime help 101 | --runtime-offset Print byte offset to start of embedded 102 | --runtime-portable-home Create a portable home folder to use as $HOME 103 | --runtime-portable-config Create a portable config folder to use as $XDG_CONFIG_HOME 104 | --runtime-version Print version of RunImage runtime 105 | --runtime-mount Mount embedded filesystem image and print 106 | mount point and wait for kill with Ctrl-C 107 | --runtime-squashfuse {args} Launch squashfuse 108 | --runtime-unsquashfs {args} Launch unsquashfs 109 | --runtime-mksquashfs {args} Launch mksquashfs 110 | --runtime-dwarfs {args} Launch dwarfs 111 | --runtime-dwarfsck {args} Launch dwarfsck 112 | --runtime-mkdwarfs {args} Launch mkdwarfs 113 | --runtime-dwarfsextract {args} Launch dwarfsextract 114 | 115 | Configuration environment variables: 116 | RIM_ROOTFS=/path/rootfs Specifies custom rootfs (0 to disable) 117 | RIM_NO_NET=1 Disables network access 118 | RIM_TMP_HOME=1 Creates tmpfs /home/$USER and /root in RAM and uses it as $HOME 119 | RIM_TMP_HOME_DL=1 As above, but with binding $HOME/Downloads dir 120 | RIM_SANDBOX_HOME=1 Creates sandbox home dir 121 | RIM_SANDBOX_HOME_DL=1 As above, but with binding $HOME/Downloads dir 122 | RIM_SANDBOX_HOME_DIR=/path/dir Specifies sandbox home dir 123 | RIM_UNSHARE_HOME=1 Unshares host home dir 124 | RIM_UNSHARE_HOME_DL=1 As above, but with binding $HOME/Downloads dir 125 | RIM_PORTABLE_HOME=1 Creates a portable home dir and uses it as $HOME 126 | RIM_PORTABLE_HOME_DIR=/path/dir Specifies a portable home dir and uses it as $HOME 127 | RIM_PORTABLE_CONFIG=1 Creates a portable config dir and uses it as $XDG_CONFIG_HOME 128 | RIM_NO_CLEANUP=1 Disables unmounting and cleanup mountpoints 129 | RIM_UNSHARE_PIDS=1 Unshares all host processes 130 | RIM_UNSHARE_USERS=1 Don't bind-mount /etc/{passwd,group} 131 | RIM_UNSHARE_HOSTNAME=1 Unshares UTS namespace and hostname 132 | RIM_UNSHARE_HOSTS=1 Unshares host /etc/hosts 133 | RIM_UNSHARE_RESOLVCONF=1 Unshares host /etc/resolv.conf 134 | RIM_COPY_RESOLVCONF=1 Copies host /etc/resolv.conf 135 | RIM_UNSHARE_RUN=1 Unshares host /run 136 | RIM_SHARE_SYSTEMD=1 Shares host SystemD 137 | RIM_UNSHARE_DBUS=1 Unshares host DBUS 138 | RIM_UNSHARE_UDEV=1 Unshares host UDEV (/run/udev) 139 | RIM_UNSHARE_XDGRUN=1 Unshares host $XDG_RUNTIME_DIR 140 | RIM_UNSHARE_XDGSOUND=1 Unshares host $XDG_RUNTIME_DIR sound sockets 141 | RIM_UNSHARE_MODULES=1 Unshares host kernel modules (/usr/lib/modules) 142 | RIM_UNSHARE_LOCALTIME=1 Unshares host localtime (/etc/localtime) 143 | RIM_UNSHARE_NSS=1 Unshares host NSS (/etc/nsswitch.conf) 144 | RIM_UNSHARE_TMP=1 Unshares host /tmp 145 | RIM_UNSHARE_TMPX11UNIX=1 Unshares host /tmp/.X11-unix 146 | RIM_UNSHARE_MACHINEID=1 Unshares host /etc/machine-id 147 | RIM_SPOOF_MACHINEID=1 Spoof /etc/machine-id with a random id 148 | RIM_MACHINEID_FILE=/path/machine-id Binds machine-id to /etc/machine-id in RunImage (0 to disable) 149 | RIM_UNSHARE_DEF_MOUNTS=1 Unshares default mount points (/mnt /media /run/media) 150 | RIM_SHARE_BOOT=1 Shares host /boot 151 | RIM_SHARE_ICONS=1 Shares host /usr/share/icons 152 | RIM_SHARE_FONTS=1 Shares host /usr/share/fonts 153 | RIM_SHARE_THEMES=1 Shares host /usr/share/themes 154 | RIM_SHARE_PKGCACHE=1 Shares host packages cache 155 | RIM_BIND=/path:/path,/path1:/path1 Binds specified paths to the container 156 | RIM_BIND_RO=/path:/path,/path1:/path1 Binds specified paths to the container in read-only 157 | RIM_BIND_PWD=1 Binds $PWD to the container 158 | RIM_BIND_RO_PWD=1 Binds $PWD to the container in read-only 159 | RIM_NO_NVIDIA_CHECK=1 Disables checking the nvidia driver version 160 | RIM_SYS_NVLIBS=1 Try to use system Nvidia libraries 161 | RIM_NO_32BIT_NVLIBS_CHECK=1 Disable 32-bit Nvidia libraries check 162 | RIM_NVIDIA_DRIVERS_DIR=/path/dir Specifies custom Nvidia driver images dir 163 | RIM_CACHEDIR=/path/dir Specifies custom RunImage cache dir 164 | RIM_OVERFSDIR=/path/dir Specifies custom RunImage OverlayFS dir 165 | RIM_OVERFS_MODE=1 Enables OverlayFS mode 166 | RIM_NO_BWRAP_OVERLAY=1 Disables Bubblewrap overlay for OverlayFS mode 167 | RIM_NO_CRYPTFS_MOUNT=1 Disables mount encrypted RunImage rootfs 168 | RIM_KEEP_OVERFS=1 Enables OverlayFS mode with saving after closing RunImage 169 | RIM_OVERFS_ID=ID Specifies the OverlayFS ID 170 | RIM_SHELL=shell Selects $SHELL in RunImage 171 | RIM_NO_CAP=1 Disables Bubblewrap capabilities (Default: ALL, drop CAP_SYS_NICE) 172 | you can also use nocap in RunImage 173 | RIM_IN_SAME_PTY=1 Start shell session in same PTY 174 | RIM_TTY_ALLOC_PTY=1 Allocate PTY for shell session on TTY 175 | RIM_AUTORUN='{executable} {args}' Autorun mode for executable from PATH (0 to disable) 176 | RIM_RUN_IN_ONE=1 Execute commands in one container 177 | RIM_ALLOW_ROOT=1 Allows to run RunImage under root user 178 | RIM_QUIET_MODE=1 Disables all non-error RunImage messages 179 | RIM_NO_WARN=1 Disables all warning RunImage messages 180 | RIM_NOTIFY=1 Enables non-error RunImage notification 181 | RUNIMAGE_EXTRACT_AND_RUN=1 Run RunImage after extraction without using FUSE 182 | TMPDIR=/path/TMPDIR Used for extract and run options 183 | RIM_CONFIG=/path/config.rcfg RunImage сonfiguration file (0 to disable) 184 | RIM_ENABLE_HOSTEXEC=1 Enables the ability to execute commands at the host level 185 | RIM_HOST_TOOLS=cmd,cmd Enables specified commands from the host (0 to disable) 186 | RIM_HOST_XDG_OPEN=1 Enables xdg-open from the host 187 | RIM_WAIT_RPIDS_EXIT=1 Wait for all processes to exit 188 | RIM_EXEC_SAME_PWD=1 Use same $PWD for rim-exec and hostexec 189 | RIM_SANDBOX_NET=1 Creates a network sandbox 190 | RIM_SNET_SHARE_HOST=1 Creates a network sandbox with access to host loopback 191 | RIM_SNET_CIDR=11.22.33.0/24 Specifies TAP iface subnet in network sandbox (Def: 10.0.2.0/24) 192 | RIM_SNET_TAPNAME=tap0 Specifies TAP iface name in network sandbox (Def: eth0) 193 | RIM_SNET_MAC=B6:40:E0:8B:A6:D7 Specifies TAP iface MAC in network sandbox (Def: random) 194 | RIM_SNET_MTU=65520 Specifies TAP iface MTU in network sandbox (Def: 1500) 195 | RIM_SNET_TAPIP=11.22.33.44 For set TAP iface IP in network sandbox mode (Def: 10.0.2.100) 196 | RIM_SNET_PORTFW='2222:22 R:53:53/UDP' Enables port forwarding in network sandbox mode (1 to enable) 197 | RIM_SNET_DROP_CIDRS=1 Drop access to host CIDR's in network sandbox mode 198 | RIM_HOSTS_FILE=/path/hosts Binds specified file to /etc/hosts (0 to disable) 199 | RIM_RESOLVCONF_FILE=/path/resolv.conf Binds specified file to /etc/resolv.conf (0 to disable) 200 | RIM_BWRAP_ARGS+=() Array with Bubblewrap arguments (for config file) 201 | RIM_EXEC_ARGS+=() Array with Bubblewrap exec arguments (for config file) 202 | RIM_CRYPTFS_PASSFILE=/path/passfile Specifies passfile for decrypt encrypted RunImage rootfs 203 | RIM_XORG_CONF=/path/xorg.conf Binds xorg.conf to /etc/X11/xorg.conf in RunImage (0 to disable) 204 | (Default: /etc/X11/xorg.conf bind from the system) 205 | RIM_SYS_BWRAP=1 Using system bwrap 206 | RIM_SYS_SQFUSE=1 Using system squashfuse 207 | RIM_SYS_UNSQFS=1 Using system unsquashfs 208 | RIM_SYS_MKSQFS=1 Using system mksquashfs 209 | RIM_SYS_UNIONFS=1 Using system unionfs 210 | RIM_SYS_SLIRP=1 Using system slirp4netns 211 | RIM_SYS_GOCRYPTFS=1 Using system gocryptfs 212 | RIM_SYS_TOOLS=1 Use all binaries from the system 213 | If they are not found in the system - auto return to the built-in 214 | rim-build: 215 | RIM_KEEP_OLD_BUILD=1 Creates a backup of the old RunImage when building a new one 216 | RIM_CMPRS_FS={sqfs|dwfs} Specifies the compression filesystem for RunImage build 217 | RIM_CMPRS_BSIZE={1M|20} Specifies the compression filesystem block size for RunImage build 218 | RIM_CMPRS_ALGO={zstd|xz|lz4} Specifies the compression algo for RunImage build 219 | RIM_CMPRS_LVL={1-22|1-9|1-12} Specifies the compression ratio for RunImage build 220 | RIM_BUILD_DWFS_HFILE=/path DwarFS hotness list file (Default: $RUNIMAGEDIR/dwarfs.prof) (0 to disable) 221 | rim-update: 222 | RIM_UPDATE_SHRINK=1 Run rim-shrink --all after update 223 | RIM_UPDATE_CLEANUP=1 Run rim-shrink --pkgcache after update 224 | rim-dinteg: 225 | RIM_DINTEG=1 Enables desktop integration pacman hook 226 | RIM_DINTEG_MIME=1 Desktop integration with MIME types 227 | RIM_DINTEG_DIR=/path Desktop integration directory (Default: $HOME/.local/share) 228 | rim-desktop: 229 | RIM_XEPHYR_SIZE=HEIGHTxWIDTH Sets RunImage desktop resolution (Default: 1600x900) 230 | RIM_DESKTOP_DISPLAY=9999 Sets RunImage desktop $DISPLAY (Default: 1337) 231 | RIM_XEPHYR_FULLSCREEN=1 Starts RunImage desktop in full screen mode 232 | RIM_DESKTOP_UNCLIP=1 Disables clipboard synchronization for RunImage desktop 233 | rim-shrink: 234 | RIM_SHRINK_ALL=1 Shrink all 235 | RIM_SHRINK_BACK=1 Shrink backup files '*.old' '*.back' 236 | RIM_SHRINK_STATICLIBS=1 Shrink static libs '*.a' 237 | RIM_SHRINK_DOCS=1 Shrink /usr/share/{man,doc,help,info,gtk-doc} and '*.md' 'README*' 238 | RIM_SHRINK_STRIP=1 Strip all debugging symbols & sections 239 | RIM_SHRINK_LOCALES=1 Shrink all locales except uk ru en en_US 240 | RIM_SHRINK_OBJECTS=1 Shrink object files '*.o' 241 | RIM_SHRINK_PKGCACHE=1 Shrink packages cache 242 | RIM_SHRINK_SRC=1 Shrink source code files for build 243 | RIM_SHRINK_PYCACHE=1 Shrink '__pycache__' directories 244 | ``` 245 | ## Other environment variables at runtime: 246 | ||| 247 | |---|---| 248 | |INSIDE_RUNIMAGE=1 | If inside RunImage | 249 | |RUNIMAGE=/path/runimage | RunImage path (for packed) | 250 | |RUNOFFSET=1234 | Image offset (for packed) | 251 | |ARG0=runimage | Null argument | 252 | |RUNPID=1234 | PID of Run.sh script | 253 | |RUNPPID=1233 | Parent PID of Run.sh script | 254 | |RUNDIR=/path/RunDir | Run binary directory | 255 | |RUNROOTFS=/path/rootfs | RootFS directory | 256 | |RUNSTATIC=/path/static | Static binaries directory | 257 | |RUNIMAGEDIR=/path/dir | RunImage or RunDir directory | 258 | |RUNCONFIGDIR=/path/config | RunImage external configs directory | 259 | |SANDBOXHOMEDIR=/path/sandbox-home | Sandbox homes directory | 260 | |PORTABLEHOMEDIR=/path/portable-home | Portable homes directory | 261 | |RUNCACHEDIR=/path/cache | Cache directory | 262 | |NVIDIA_DRIVERS_DIR=/path/nvidia-drivers| Nvidia driver images directory | 263 | |RUNSRCNAME=runimage | RunImage or link or executable name | 264 | |RUNIMAGE_VERSION=1.2.3 | RunImage version | 265 | |RUNROOTFS_VERSION=1.2.3 | RootFS version | 266 | |RUNSTATIC_VERSION=1.2.3 | Static version | 267 | |RUNRUNTIME_VERSION=1.2.3 | RunImage runtime version | 268 | |RUNOVERFSDIR=/path/overlayfs | Directory for all OverlayFS | 269 | |OVERFS_DIR=/path/overlayfs/id | OverlayFS ID directory | 270 | |OVERFS_MNT=/path/overlayfs/id/mnt | OverlayFS ID mount directory | 271 | |RUNRUNTIME=/path/uruntime | RunImage runtime | 272 | |RUNROOTFSTYPE=base | Rootfs type | 273 | |FUSE_PIDS=1235 | PIDs of all RunImage FUSE tools | 274 | |RUNUSER=user | The name of the user who runs RunImage | 275 | |REUIDDIR=/tmp/.r$EUID | RunImage EUID working directory | 276 | |RUNTMPDIR=$REUIDDIR/run | RunImage RUNPIDs working directory | 277 | |RUNPIDDIR=$RUNTMPDIR/$RUNPID | RunImage RUNPID working directory | 278 | |BWINFFL=$RUNPIDDIR/bwinf | Bubblewrap info file | 279 | |RIMENVFL=$RUNPIDDIR/rimenv | RIM environment variables file | 280 | |RUNDIRFL=$RUNPIDDIR/rundir | RunImage RunDir path file | 281 | 282 | ## Utils scripts: 283 | ||| 284 | |---|---| 285 | |[cip](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/cip) | Сheck public ip | 286 | |[dbus-flmgr](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/dbus-flmgr) | Launch the system file manager via dbus | 287 | |[getdimg](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/getdimg) | For download docker container images | 288 | |[hostexec](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/hostexec) | For execute commands at the host level (see ENABLE_HOSTEXEC) | 289 | |[httpfw](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/httpfw) | For expose a local HTTP web service to the internet | 290 | |[nocap](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/nocap) | Disables container capabilities | 291 | |[pac](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/pac) | sudo pacman (fake sudo) | 292 | |[packey](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/packey) | sudo pacman-key (fake sudo) | 293 | |[panelipmon](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/panelipmon) | Shows information about an active network connection | 294 | |[rim-bootstrap](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/rim-bootstrap) | For bootstrap new runimage | 295 | |[rim-build](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/rim-build) | For the runimage build | 296 | |[rim-desktop](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/rim-desktop) | For the desktop mode | 297 | |[rim-dinteg](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/rim-dinteg) | For desktop integration | 298 | |[rim-psmon](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/rim-psmon) | For monitoring of processes running in runimage containers | 299 | |[rim-shrink](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/rim-shrink) | For shrinking unnecessary files | 300 | |[rim-update](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/rim-update) | For runimage update | 301 | |[tcpfw](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/tcpfw) | For expose a local TCP port to the internet | 302 | |[webm2gif](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/webm2gif) | Convert webm to gif | 303 | |[xclipfrom](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/xclipfrom) | For clipboard synchronization in desktop mode | 304 | |[xclipsync](https://github.com/VHSgunzo/runimage/blob/main/rootfs/var/RunDir/utils/xclipsync) | For clipboard synchronization in desktop mode | 305 | 306 | ## Additional information: 307 | You can create a symlink/hardlink to runimage or rename runimage and give it the name 308 | of some executable from the PATH, this will allow you to run 309 | runimage in autorun mode for this executable. 310 | 311 | The same principle applies to the RIM_AUTORUN env var: 312 | ┌─[user@host]─[~] 313 | └──╼ $ RIM_AUTORUN="ls -la" runimage {autorun executable args} 314 | 315 | Here runimage will become something like an alias for 'ls' in runimage 316 | with the '-la' argument. You can also use RIM_AUTORUN as an array 317 | for complex commands in the config. 318 | RIM_AUTORUN=("ls" "-la" "/path/to something") 319 | This will also work in extracted form. 320 | 321 | When using the RIM_PORTABLE_HOME and RIM_PORTABLE_CONFIG variables, runimage will create or 322 | search for these directories next to itself. The same behavior will occur when 323 | adding a runimage or Run binary or renamed or symlink/hardlink to them in the PATH 324 | it can be used both extracted and compressed and for all executable files being run: 325 | "$PORTABLEHOMEDIR/Run" 326 | "$RUNIMAGEDIR/Run.config" 327 | if a symlink/hardlink to runimage is used: 328 | "$PORTABLEHOMEDIR/{symlink/hardlink_name}" 329 | "$RUNIMAGEDIR/{symlink/hardlink_name}.config" 330 | or with runimage/Run name: 331 | "$PORTABLEHOMEDIR/{runimage/Run_name}" 332 | "$RUNIMAGEDIR/{runimage/Run_name}.config" 333 | It can also be with the name of the executable file from RIM_AUTORUN env var, 334 | or with the same name as the executable being run. 335 | RIM_SANDBOX_HOME* similar to RIM_PORTABLE_HOME, but the system HOME becomes isolated. 336 | RIM_SANDBOX_HOME_DIR and RIM_PORTABLE_HOME_DIR point to a specific directory or create it in the absence of. 337 | 338 | RunImage uses fakechroot and fakeroot, which allows you to use root commands, including in 339 | unpacked form, to update the rootfs or install/remove packages. 340 | sudo and pkexec have also been replaced with fake ones. 341 | 342 | ### RunImage configuration file: 343 | Special BASH-syntax file with the .rcfg extension, which describes additional 344 | instructions and env vars for run runimage. 345 | Configuration file can be located next to runimage: 346 | "$RUNIMAGEDIR/{runimage/Run_name}.rcfg" 347 | it can be used both extracted and compressed and for all executable files being run: 348 | "$RUNIMAGEDIR/Run.rcfg" 349 | if a symlink/hardlink to runimage is used: 350 | "$RUNIMAGEDIR/{symlink/hardlink_name}.rcfg" 351 | or in $RUNCONFIGDIR directory: 352 | "$RUNCONFIGDIR/Run.rcfg" 353 | "$RUNCONFIGDIR/{runimage/Run_name}.rcfg" 354 | "$RUNCONFIGDIR/{symlink/hardlink_name}.rcfg" 355 | It can also be with the name of the executable file from RIM_AUTORUN env var, 356 | or with the same name as the executable being run. 357 | In $RUNDIR/config there are default configs in RunImage, they are run in priority, 358 | then external configs are run if they are found. 359 | 360 | ### RunImage desktop: 361 | Ability to run RunImage in desktop mode. Default DE: XFCE 362 | For RunImage desktop to work, PIDs and DBUS unsharing is required. This will happen 363 | automatically when running outside the container. 364 | If the launch is carried out from an already running desktop, then Xephyr will start 365 | in windowed/full screen mode (see RIM_XEPHYR_* env vars) 366 | Use CTRL+SHIFT to grab the keyboard and mouse. 367 | It is also possible to run on TTY with Xorg (see RIM_XORG_CONF env vars) 368 | To do this, just log in to TTY and run RunImage desktop. 369 | Important! The launch on the TTY should be carried out only under the user under whom the 370 | login to the TTY was carried out. 371 | 372 | [ Usage ]: rim-desktop [OPTIONS] 373 | [ Options ]: 374 | -d, --display Sets $DISPLAY (env: RIM_DESKTOP_DISPLAY=1337) 375 | -f, --fullscreen Starts Xephyr in fullscreen mode (env: RIM_XEPHYR_FULLSCREEN=1) 376 | -h, --help Show this message 377 | -s, --size Sets Xephyr resolution (env: RIM_XEPHYR_SIZE=1600x900) 378 | -u, --unclip Disables clipboard synchronization (env: RIM_DESKTOP_UNCLIP=1) 379 | 380 | ### RunImage OverlayFS: 381 | Allows you to create additional separate layers to modify the container filesystem without 382 | changing the original container filesystem. Works by unionfs-fuse and Bubblewrap overlay 383 | in packed and unpacked. Also, in packed form, it allows you to mount the container in Read-Write mode. 384 | 385 | It also allows you to attach to the same OverlayFS when you specify it's ID. 386 | If OverlayFS with such ID does not exist, it will be created: 387 | ┌─[user@host]─[~] 388 | └──╼ $ RIM_OVERFS_ID=1337 runimage {args} 389 | 390 | To save OverlayFS after closing the container, use RIM_KEEP_OVERFS: 391 | ┌─[user@host]─[~] 392 | └──╼ $ RIM_KEEP_OVERFS=1 runimage {args} 393 | 394 | To run a one-time OverlayFS, use RIM_OVERFS_MODE: 395 | ┌─[user@host]─[~] 396 | └──╼ $ RIM_OVERFS_MODE=1 runimage {args} 397 | 398 | You can also disable the Bubblewrap overlay using RIM_NO_BWRAP_OVERLAY=1, but in this case 399 | the Read-Write speed will decrease. 400 | 401 | For show the list of RunImage OverlayFS use rim-ofsls: 402 | ┌─[user@host]─[~] 403 | └──╼ $ runimage rim-ofsls 404 | 405 | For remove OverlayFS use rim-ofsrm: 406 | ┌─[user@host]─[~] 407 | └──╼ $ runimage rim-ofsrm [ID ID...|all] 408 | 409 | ### RunImage build: 410 | Allows you to create your own runimage containers. 411 | By default, runimage is created in the current directory with a standard name, 412 | with DwarFS filesystem, zstd 1 lvl compression and 128 KB block size. 413 | If a new RunImage is successfully build, the old one is deleted. 414 | To optimize the launch of an image with the DwarFS filesystem, you can run the 415 | runimage with open file profiling enabled (env var DWARFS_ANALYSIS_FILE=dwarfs.prof) 416 | Then you can rebuild the image. The file will be automatically found in the directories: 417 | $RUNIMAGEDIR/dwarfs.prof 418 | $RUNIMAGEDIR/config/dwarfs.prof 419 | $RUNDIR/config/dwarfs.prof 420 | Or you can specify it in the RIM_BUILD_DWFS_HFILE=/dwarfs.prof var (see rim-build usage) 421 | 422 | This works both externally by passing build args: 423 | ┌─[user@host]─[~] 424 | └──╼ $ runimage rim-build {build args} 425 | 426 | And it also works inside the running: 427 | ┌─[user@runimage]─[~] 428 | └──╼ $ rim-build {build args} 429 | 430 | [ Usage ]: rim-build [OPTIONS] /path/runimage 431 | [ Options ]: 432 | -b, --bsize '1M|20' Set block size (env: RIM_CMPRS_BSIZE=1M) 433 | -c, --clvl '1-22' Set compression level (env: RIM_CMPRS_LVL=1) 434 | -d, --dwfs Use DwarFS file system (env: RIM_CMPRS_FS=dwfs) 435 | -f, --dwfs-hfile '/path' DwarFS hotness list file (env: RIM_BUILD_DWFS_HFILE=/path) (0 to disable) 436 | -l, --lz4 Use lz4 compression (for DwarFS clvl 1-12) (env: RIM_CMPRS_ALGO=lz4) 437 | -h, --help Show this message 438 | -k, --keep Creates a backup of the old RunImage (env: RIM_KEEP_OLD_BUILD=1) 439 | -s, --sqfs Use SquashFS file system (env: RIM_CMPRS_FS=sqfs) 440 | -x, --xz Use xz (lzma for DwarFS clvl 1-9) compression (env: RIM_CMPRS_ALGO=xz) 441 | -z, --zstd Use zstd compression (clvl 1-22) (env: RIM_CMPRS_ALGO=zstd) 442 | 443 | ### RunImage update: 444 | Allows you to update packages and rebuild RunImage. When running outside the container, 445 | rim-update can also take rim-build arguments to build a new RunImage in case of 446 | successful package updates. 447 | ┌─[user@host]─[~] 448 | └──╼ $ runimage rim-update [OPTIONS] {build args} 449 | 450 | And it also works inside runimage: 451 | ┌─[user@runimage]─[~] 452 | └──╼ $ rim-update [OPTIONS] {build args} 453 | 454 | By default, update and rebuild is performed in "$RUNIMAGEDIR" 455 | 456 | [ Usage ]: rim-update [OPTIONS] 457 | [ Options ]: 458 | --shrink Run rim-shrink --all after update (env: RIM_UPDATE_SHRINK=1) 459 | --cleanup Run rim-shrink --pkgcache after update (env: RIM_UPDATE_CLEANUP=1) 460 | -h, --help Show this message 461 | 462 | ### RunImage network sandbox: 463 | Allows you to create a private network namespace with slirp4netns and inside the container 464 | manage routing, create/delete network interfaces, connect to a vpn (checked openvpn 465 | and wireguard), configure your resolv.conf and hosts, etc. (see RIM_SANDBOX_NET and RIM_SNET_*) 466 | By default, network sandbox created in 10.0.2.0/24 subnet, with eth0 TAP name, 10.0.2.100 TAP ip, 467 | 1500 TAP MTU, and random MAC. 468 | And you can also enable port forwarding in network sandbox mode with modifyed chisel. 469 | Supported TCP, UDP port forwarding, socks5 proxy and reverse mode. 470 | 471 | For example, this will forward 22 TCP port from container to 2222 TCP port in host, 472 | reverse forward 53 UDP port from host to 53 UDP port in container 473 | and start socks5 proxy to container on 1080 port in host: 474 | ┌─[user@host]─[~] 475 | └──╼ $ RIM_SNET_PORTFW='2222:22 R:53:53/UDP 1080:socks' runimage {args} 476 | 477 | You can also run additional port forwarding on a running container with enabled port forwardin option: 478 | ┌─[user@host]─[~] 479 | └──╼ $ runimage rim-portfw $RUNPID 8080:80 123:123/UDP 480 | 481 | Also network access in container may be disabled with RIM_NO_NET=1 482 | 483 | ### RunImage hostexec: 484 | Allows you to run commands at the host level with ssrv shell server/client. 485 | ┌─[user@host]─[~] 486 | └──╼ $ RIM_ENABLE_HOSTEXEC=1 runimage {args} 487 | 488 | [ Usage ]: hostexec [OPTIONS] {executable} {executable args} 489 | [ Options ]: 490 | -su, --superuser {args} Execute command as superuser 491 | -t, --terminal {args} Execute command in host terminal 492 | -h, --help Show this message 493 | 494 | ### RunImage desktop integration: 495 | Allows you to integrate applications from a container into the system application menu. 496 | You can also enable pacman hook with RIM_DINTEG=1 env var to automatically add and remove 497 | applications to the system menu when working with the package manager inside the container. 498 | 499 | [ Usage ]: rim-dinteg [OPTIONS] app app... 500 | [ Options ]: 501 | -a, --add [num|name|all|mime] Add applications to apps menu 502 | -h, --help Show this message 503 | -l, --list [a|added] List applications 504 | -m, --mime With MIME types (env: RIM_DINTEG_MIME=1) 505 | -d, --dinteg-dir /path Desktop integration directory (env: RIM_DINTEG_DIR=/path) 506 | -v, --verbose Verbose output 507 | -r, --remove [num|name|all|mime] Remove applications from apps menu 508 | 509 | ### RunImage processes monitoring: 510 | Allows you to monitor the processes running in the container. 511 | 512 | [ Usage ]: rim-psmon [OPTIONS] RUNPIDs 513 | [ Options ]: 514 | -p, --ps Print the list of RunImage processes 515 | -h, --help Show this message 516 | 517 | ### RunImage shrink: 518 | Allows you to reduce the size of the container by deleting some files. 519 | 520 | [ Usage ]: rim-shrink [OPTIONS] /path/RunDir 521 | [ Options ]: 522 | -a, --all Shrink all (env: RIM_SHRINK_ALL=1) 523 | -b, --back Shrink backup files '*.old' '*.back' (env: RIM_SHRINK_BACK=1) 524 | -c, --staticlibs Shrink static libs '*.a' (env: RIM_SHRINK_STATICLIBS=1) 525 | -d, --docs Shrink /usr/share/{man,doc,help,info,gtk-doc} and '*.md' 'README*' (env: RIM_SHRINK_DOCS=1) 526 | -s, --strip Strip all debugging symbols & sections (env: RIM_SHRINK_STRIP=1) 527 | -l, --locales Shrink all locales except uk ru en en_US (env: RIM_SHRINK_LOCALES=1) 528 | -o, --objects Shrink object files '*.o' (env: RIM_SHRINK_OBJECTS=1) 529 | -p, --pkgcache Shrink packages cache (env: RIM_SHRINK_PKGCACHE=1) 530 | -r, --src Shrink source code files for build (env: RIM_SHRINK_SRC=1) 531 | -y, --pycache Shrink '__pycache__' directories (env: RIM_SHRINK_PYCACHE=1) 532 | -h, --help Show this message 533 | -v, --verbose Verbose output 534 | 535 | ### RunImage bootstrap: 536 | Allows you to create a new RunImage from a base Docker image archlinux:base for x86_64 537 | and lopsided/archlinux:latest for aarch64. 538 | You can also specify additional packages that you want to add to the container. 539 | 540 | ┌─[user@host]─[~] 541 | └──╼ $ runimage rim-bootstrap {pkg pkg} 542 | 543 | ┌─[user@host]─[~] - for aarch64 (required qemu-user-static in x86_64 system) 544 | └──╼ $ TARGETARCH=arm64 runimage rim-bootstrap {pkg pkg} 545 | 546 | ### RunImage encryption: 547 | Allows you to en/decrypt rootfs with gocryptfs. 548 | 549 | Encrypt RunImage rootfs: 550 | ┌─[user@host]─[~] 551 | └──╼ $ runimage rim-encfs {build args} 552 | 553 | Decrypt RunImage rootfs: 554 | ┌─[user@host]─[~] 555 | └──╼ $ runimage rim-decfs {build args} 556 | 557 | You can also specify the build args, and after successful en/decryption, the runimage 558 | will be rebuild with the specified parameters. 559 | You can also specify passfile with RIM_CRYPTFS_PASSFILE=/path/passfile env var 560 | for automatic decryption, or by default, the passfile will be searched in: 561 | "$RUNDIR/passfile" 562 | "$RUNIMAGEDIR/passfile" 563 | 564 | ### RunImage custom rootfs: 565 | Allows you to use custom rootfs with RIM_ROOTFS=/path/rootfs env var. 566 | 567 | You can also use getdimg to download a Docker image: 568 | [ Usage ]: /home/user/.local/bin/getdimg [OPTIONS] dir image[:tag][@digest] ... 569 | /home/user/.local/bin/getdimg /tmp/my-images hello-world:latest alpine:3.18 ghcr.io/void-linux/void-musl:latest 570 | /home/user/.local/bin/getdimg /tmp/specific-digest hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7 571 | 572 | [ Options ]: 573 | -a, --arch Override the machine architecture (env: TARGETARCH=amd64) 574 | --variant Override the machine architecture variant (env: TARGETVARIANT=v8) 575 | -x, --extract Extract image layers (env: EXTRACT_LAYERS=1) 576 | -h, --help Show this message 577 | 578 | For example, you can use alpine (and others) rootfs with RunImage: 579 | ┌─[user@host]─[~] 580 | └──╼ $ ./runimage getdimg --extract rootfs alpine:latest 581 | 582 | Do not forget to configure the DNS server (if it is not already configured): 583 | ┌─[user@host]─[~] 584 | └──╼ $ echo -e 'nameserver 1.1.1.1\nnameserver 8.8.8.8' > rootfs/etc/resolv.conf 585 | 586 | And then just run runimage. By default, custom rootfs will be searched in "$RUNIMAGEDIR/rootfs": 587 | ┌─[user@host]─[~] 588 | └──╼ $ ./runimage {args} 589 | 590 | If you are going to build RunImage with custom rootfs, then do not forget to install 591 | the necessary dependencies for operation of Run.sh and others runimage scripts: 592 | ┌─[user@host]─[~] 593 | └──╼ $ RIM_ROOT=1 ./runimage apk add bash coreutils curl findutils gawk grep iproute2 kmod procps-ng \ 594 | sed tar util-linux which gocryptfs libnotify lsof slirp4netns socat xhost gzip xz zstd lz4 jq binutils \ 595 | patchelf nftables iptables openresolv iputils file 596 | 597 | And then you can run the build: 598 | ┌─[user@host]─[~] 599 | └──╼ $ ./runimage rim-build runimage-alpine -c 22 -b 24 600 | 601 | ### For Nvidia users with a proprietary driver: 602 | If the nvidia driver version does not match in runimage and in the host, runimage 603 | will make an image with the nvidia driver of the required version from local Nvidia libs, 604 | or from official Nvidia driver installer, or will download a ready-made image 605 | from the repository and further used as an additional module to runimage. 606 | You can download a ready-made driver image from the releases or build driver image manually: 607 | https://github.com/VHSgunzo/runimage-nvidia-drivers 608 | In runimage, a fake version of the nvidia driver is installed by default to reduce the size: 609 | https://github.com/VHSgunzo/runimage-fake-nvidia-driver 610 | But you can also install the usual nvidia driver of your version in runimage. 611 | Checking the nvidia driver version can be disabled using RIM_NO_NVIDIA_CHECK=1 env var. 612 | You can also force an attempt to use the local version of the driver using RIM_SYS_NVLIBS=1 env var. 613 | When searching for libs, a search for 32-bit versions will also be performed, 614 | this can be disabled using RIM_NO_32BIT_NVLIBS_CHECK=1 env var. 615 | If the libs are not found, will be made an attempt to download the driver. 616 | The nvidia driver image can be located next to runimage: 617 | "$RUNIMAGEDIR/{nvidia_version}.nv.drv" 618 | or in $RUNIMAGEDIR/nvidia-drivers (Default): 619 | "$RUNIMAGEDIR/nvidia-drivers/{nvidia_version}.nv.drv" 620 | or the driver can be extracted as the directory 621 | "$RUNIMAGEDIR/nvidia-drivers/{nvidia_version}" 622 | also, the driver can be in RunImage in a packed or unpacked form: 623 | "$RUNDIR/nvidia-drivers/{nvidia_version}.nv.drv" - image 624 | "$RUNDIR/nvidia-drivers/{nvidia_version}" - directory 625 | 626 | ## Rebuild your own RunImage: 627 | 628 | * [Download](https://github.com/VHSgunzo/runimage/releases/continuous) base version of the runimage 629 | * Make it executable: 630 | ``` 631 | chmod +x runimage 632 | ``` 633 | * Run it in OverlayFS mode (If you are using a proprietary nvidia driver, then I recommend disabling the driver check function by `RIM_NO_NVIDIA_CHECK=1` for proper rebuild in manual mode. You do not need to do this in automatic mode): 634 | ``` 635 | RIM_OVERFS_MODE=1 ./runimage 636 | echo OVERFS_MNT=$OVERFS_MNT 637 | ``` 638 | * Install or remove the necessary packages, change `$OVERFS_MNT/rootfs`, etc. You can change `$OVERFS_MNT/rootfs` in the standard ways for you. But do not close the container until the moment of build. 639 | * You can also specify your own type of rootfs in `$OVERFS_MNT/rootfs/.type` file, but it's not necessary. 640 | * After all the manipulations with rootfs, create a new runimage using this command in the container: 641 | ``` 642 | rim-build 643 | ``` 644 | * Or from another terminal tab with RIM_OVERFS_ID: 645 | ``` 646 | RIM_OVERFS_ID=$ID ./runimage rim-build 647 | ``` 648 | * After the build is completed, you can close the container: 649 | ``` 650 | exit 651 | # or CTRL-D 652 | ``` 653 | 654 |
655 | Troubleshooting and problem solving 656 | 657 | 658 | * To start SystemD services with systemctl in RunImage SystemD replaced with [fake-systemd](https://github.com/VHSgunzo/runimage-fake-systemd) package based on [docker-systemctl-replacement](https://github.com/gdraheim/docker-systemctl-replacement) with some modification. It's depend on python3 659 | * To start the SSH server you need to install patched [runimage-openssh](https://github.com/VHSgunzo/runimage-openssh) package from runimage [pacman repo](https://github.com/runimage/repo) 660 | ``` 661 | pac -Sy runimage-openssh 662 | ssh-keygen -A 663 | # Don't forget to add your ssh keys for authorization to /etc/ssh/authorized_keys in the container 664 | # or to $HOME/.ssh/authorized_keys 665 | # password authorization disabled and don't work 666 | systemctl start sshd # systemctl depend on python3 667 | # OR 668 | /usr/bin/sshd -D & 669 | ``` 670 | 671 | * If SELinux is enabled in the system, then there may be problems with the launch and operation of Wine ([solution](https://www.tecmint.com/disable-selinux-in-centos-rhel-fedora)) 672 | * When using `RIM_TMP_HOME`* you may run out of RAM, be careful with this. 673 | * It is also advisable to use TMPDIR when using `--runtime-extract-and-run` or `RUNTIME_EXTRACT_AND_RUN=1`, because by default, unpacking before starting will be carried out in /tmp, which may also lead to the end of RAM 674 | * Xephyr does not support GL acceleration and Vulkan has performance issues (But this is not related to RunImage) 675 | * Possible tearing on nvidia in RunImage desktop mode ([solution](https://wiki.archlinux.org/title/NVIDIA/Troubleshooting#Avoid_screen_tearing)) 676 | * If you have problems with sound when running RunImage desktop on TTY, just restart pulseaudio. 677 | 678 | killall pulseaudio ; pulseaudio -D 679 | 680 |
681 | 682 |
683 | Projects based on RunImage 684 | 685 | 686 | * [Lux Wine](https://github.com/VHSgunzo/lux-wine) 687 | * [PortArch](https://github.com/VHSgunzo/portarch) 688 | * [NitroWine](https://github.com/RusNor/NitroWine) 689 | * [StartWine-Launcher](https://github.com/RusNor/StartWine-Launcher) 690 | * [Steam-appimage](https://github.com/ivan-hc/Steam-appimage) 691 | 692 |
693 | 694 |
695 | Main used projects 696 | 697 | 698 | * [archlinux](https://archlinux.org) 699 | * [blackarch](https://github.com/BlackArch/blackarch) 700 | * [chaotic-aur](https://aur.chaotic.cx) 701 | * [uruntime](https://github.com/VHSgunzo/uruntime) and [runimage-uruntime](https://github.com/VHSgunzo/runimage-uruntime) 702 | * [runimage-rootfs](https://github.com/VHSgunzo/runimage-rootfs) 703 | * [runimage-static](https://github.com/VHSgunzo/runimage-static) 704 | * [sharun](https://github.com/VHSgunzo/sharun) 705 | * [Run-wrapper](https://github.com/VHSgunzo/Run-wrapper) 706 | * [bubblewrap-static](https://github.com/VHSgunzo/bubblewrap-static) and [runimage-bubblewrap](https://github.com/VHSgunzo/runimage-bubblewrap) 707 | * [tini](https://github.com/VHSgunzo/tini) and [runimage-tini](https://github.com/VHSgunzo/runimage-tini) 708 | * [ssrv](https://github.com/VHSgunzo/ssrv) and [runimage-ssrv](https://github.com/VHSgunzo/runimage-ssrv) 709 | * [runimage-repo](https://github.com/runimage/repo) 710 | * [runimage-mirrorlist](https://github.com/VHSgunzo/runimage-mirrorlist) 711 | * [runimage-openssh](https://github.com/VHSgunzo/runimage-openssh) 712 | * [runimage-fake-nvidia-driver](https://github.com/VHSgunzo/runimage-fake-nvidia-driver) 713 | * [runimage-nvidia-drivers](https://github.com/VHSgunzo/runimage-nvidia-drivers) 714 | * [runimage-fake-sudo-pkexec](https://github.com/VHSgunzo/runimage-fake-sudo-pkexec) 715 | * [runimage-fake-systemd](https://github.com/VHSgunzo/runimage-fake-systemd) 716 | * [squashfs-tools-static](https://github.com/VHSgunzo/squashfs-tools-static) 717 | * [squashfuse-static](https://github.com/VHSgunzo/squashfuse-static) 718 | * [unionfs-fuse-static](https://github.com/VHSgunzo/unionfs-fuse-static) and [runimage-unionfs-fuse](https://github.com/VHSgunzo/runimage-unionfs-fuse) 719 | * [slirp4netns](https://github.com/rootless-containers/slirp4netns/releases) 720 | * [fakeroot](https://github.com/mackyle/fakeroot) 721 | * [fakechroot](https://github.com/dex4er/fakechroot) 722 | * [pacutils](https://github.com/andrewgregory/pacutils) 723 | * [chisel](https://github.com/VHSgunzo/chisel) and [runimage-chisel](https://github.com/VHSgunzo/runimage-chisel) 724 | * [runimage-cpids](https://github.com/VHSgunzo/runimage-cpids) 725 | 726 |
727 | 728 |
729 | RunImage tested and works on 730 | 731 | 732 | * [Adelie Linux](https://www.adelielinux.org/) 733 | * [AlmaLinux](https://almalinux.org/) 734 | * [Alpine](https://www.alpinelinux.org/) 735 | * [Alt Workstation](https://www.basealt.ru/alt-workstation/description) 736 | * [Antergos](https://en.wikipedia.org/wiki/Antergos) 737 | * [antiX](https://antixlinux.com/) 738 | * [Arch Linux](https://archlinux.org/) 739 | * [ArcoLinux](https://arcolinux.com/) 740 | * [Artix Linux](https://artixlinux.org/) 741 | * [Astra Linux](https://astralinux.ru/) 742 | * [Batocera](https://batocera.org/) 743 | * [Bodhi Linux](https://www.bodhilinux.com/) 744 | * [BlendOS](https://blendos.co/) 745 | * [CachyOS](https://cachyos.org/) 746 | * [Calculate](https://www.calculate-linux.org/) 747 | * [CentOS](https://www.centos.org/) 748 | * [ChromeOS Flex](https://chromeenterprise.google/intl/en_us/os/chromeosflex/) 749 | * [Clear Linux](https://clearlinux.org/) 750 | * [Debian](https://www.debian.org/) 751 | * [Deepin](https://www.deepin.org/) 752 | * [EasyOS](https://easyos.org) 753 | * [ElementaryOS](https://elementary.io/) 754 | * [EndeavourOS](https://endeavouros.com/) 755 | * [EuroLinux](https://en.euro-linux.com/) 756 | * [Fedora Silverblue](https://silverblue.fedoraproject.org/) 757 | * [Fedora Workstation](https://getfedora.org/en/workstation/) 758 | * [Garuda Linux](https://garudalinux.org/) 759 | * [Gentoo](https://www.gentoo.org/) 760 | * [GoboLinux](https://gobolinux.org/) 761 | * [Green Linux](https://greenlinux.ru/) 762 | * [Grml Linux](https://grml.org/) 763 | * [Kali Linux](https://www.kali.org/) 764 | * [KDE neon](https://neon.kde.org/) 765 | * [Kodachi](https://www.digi77.com/linux-kodachi/) 766 | * [Kubuntu](https://kubuntu.org/) 767 | * [Linux Lite](https://www.linuxliteos.com/) 768 | * [Linux Mint](https://linuxmint.com/) 769 | * [Lubuntu](https://lubuntu.me/) 770 | * [Mageia](https://www.mageia.org/) 771 | * [Manjaro](https://manjaro.org/) 772 | * [MX Linux](https://mxlinux.org/) 773 | * [Nitrux nxOS](https://nxos.org/) 774 | * [NixOS](https://nixos.org/) 775 | * [Nobara](https://nobaraproject.org/) 776 | * [openSUSE](https://www.opensuse.org/) 777 | * [Oracle Linux](https://www.oracle.com/linux/) 778 | * [Parrot](https://www.parrotsec.org/) 779 | * [PCLinuxOS](https://www.pclinuxos.com/) 780 | * [PeppermintOS (Devuan)](https://peppermintos.com/) 781 | * [Pop!_OS](https://pop.system76.com/) 782 | * [Porteus](http://www.porteus.org/) 783 | * [Puppy Linux](https://puppylinux.com/) 784 | * [Qubes](https://www.qubes-os.org/) 785 | * [Red OS](https://redos.red-soft.ru/) 786 | * [Rocky Linux](https://rockylinux.org/ru/) 787 | * [ROSA](https://www.rosalinux.ru/) 788 | * [Simply/ALT Linux](https://www.basealt.ru/simplylinux) 789 | * [Slackware](http://www.slackware.com/) 790 | * [Slax Linux](https://www.slax.org/) 791 | * [Solus](https://getsol.us/home/) 792 | * [SparkyLinux](https://sparkylinux.org/) 793 | * [SpiralLinux](https://spirallinux.github.io/) 794 | * [SteamOS (HoloISO)](https://github.com/theVakhovskeIsTaken/holoiso) 795 | * [Tails](https://tails.boum.org/) 796 | * [Ubuntu](https://ubuntu.com/) 797 | * [Ubuntu MATE](https://ubuntu-mate.org/) 798 | * [UBLinux](https://ublinux.ru/) 799 | * [VanillaOS](https://vanillaos.org/) 800 | * [Venom Linux](https://venomlinux.org/) 801 | * [Void Linux](https://voidlinux.org/) 802 | * [Whonix](https://www.whonix.org/) 803 | * [Windowsfx (Linuxfx)](https://www.windowsfx.org/) 804 | * [Windows Subsystem for Linux (WSL 2 on Win 11)](https://learn.microsoft.com/en-us/windows/wsl/install) 805 | * [Xubuntu](https://xubuntu.org/) 806 | * [Zorin OS](https://zorin.com/os/) 807 | 808 |
809 | --------------------------------------------------------------------------------