Make Conty even more portable

Conty now uses statically linked bash and busybox, so it no longer depends on system-wide bash, tar and gzip.

And other improvements in this commit:

* NVIDIA_HANDLER improved and enabled by default.
* Reworked the self-update feature, it uses fuse-overlayfs now instead of extracting the whole image.
* Added the CUSTOM_MNT, which allows to use Conty with already mounted custom moint points and directory structures.
* create-conty.sh now automatically sets the correct sizes in conty-start.sh
* Added more locales
This commit is contained in:
Kron4ek 2023-05-28 16:52:18 +05:00
parent 3beb06e146
commit 27677599f8
7 changed files with 439 additions and 283 deletions

View file

@ -15,18 +15,62 @@ if (( EUID == 0 )) && [ -z "$ALLOW_ROOT" ]; then
fi
# Conty version
script_version="1.23.1"
script_version="1.24"
# Important variables to manually adjust after modification!
# Needed to avoid problems with mounting due to an incorrect offset.
script_size=34762
utils_size=2564623
#
# If you build Conty without some of the components, you can set their
# size to 0
init_size=40000
bash_size=1339208
script_size=35842
busybox_size=1161112
utils_size=4049807
# Full path to the script
if [ -n "${BASH_SOURCE[0]}" ]; then
script_literal="${BASH_SOURCE[0]}"
else
script_literal="${0}"
fi
script_name="$(basename "${script_literal}")"
script="$(readlink -f "${script_literal}")"
# MD5 of the last 1 MB of the file
script_md5="$(tail -c 1000000 "${script}" | md5sum | head -c 7)"
script_id="$$"
# Working directory where the utils will be extracted
# And where the image will be mounted
# The default path is /tmp/scriptname_username_scriptmd5
# And if /tmp is mounted with noexec, the default path
# is ~/.local/share/Conty/scriptname_username_scriptmd5
conty_dir_name="$(basename "${script}")"_"${USER}"_"${script_md5}"
if [ -z "${BASE_DIR}" ]; then
export working_dir=/tmp/"${conty_dir_name}"
else
export working_dir="${BASE_DIR}"/"${conty_dir_name}"
fi
if [ "${USE_SYS_UTILS}" != 1 ] && [ "${busybox_size}" -gt 0 ]; then
busybox_bin_dir="${working_dir}"/busybox_bins
busybox_path="${busybox_bin_dir}"/busybox
if [ ! -f "${busybox_bin_dir}"/echo ]; then
mkdir -p "${busybox_bin_dir}"
tail -c +$((init_size+bash_size+script_size+1)) "${script}" | head -c "${busybox_size}" > "${busybox_path}"
chmod +x "${busybox_path}" 2>/dev/null
"${busybox_path}" --install -s "${busybox_bin_dir}" &>/dev/null
fi
if "${busybox_bin_dir}"/echo &>/dev/null; then
export PATH="${busybox_bin_dir}:${PATH}"
fi
fi
# Help output
msg_help="
Usage: ${script_name} [COMMAND] [ARGUMENTS]
@ -63,10 +107,6 @@ Arguments:
Additional disk space (about 6x the size of the current file)
is needed during the update process.
-U Same as -u with the addition of updating the init script and
the integrated utils. This option may break Conty in some cases,
use with caution!
-v Display version of this script
-V Display version of the image
@ -135,6 +175,12 @@ Environment variables:
XEPHYR_SIZE Sets the size of the Xephyr window. The default is
800x600.
CUSTOM_MNT Sets a custom mount point for the Conty. This allows
Conty to be used with already mounted filesystems.
Conty will not mount its image on this mount point,
but it will use files that are already present
there.
Additional notes:
System directories/files will not be available inside the container if
you set the SANDBOX variable but don't bind (mount) any items or set
@ -150,8 +196,8 @@ example, from a file manager) will automatically launch the Conty's
graphical interface.
Besides updating all packages, you can also install and remove packages
using the same -u (or -U) argument. To install packages add them as
additional arguments, to remove add a minus sign (-) before their names.
using the same -u argument. To install packages add them as additional
arguments, to remove add a minus sign (-) before their names.
To install: ${script_name} -u pkgname1 pkgname2 pkgname3 ...
To remove: ${script_name} -u -pkgname1 -pkgname2 -pkgname3 ...
In this case Conty will update all packages and additionally install
@ -161,31 +207,17 @@ If you are using an Nvidia GPU, please read the following:
https://github.com/Kron4ek/Conty#known-issues
"
# MD5 of the last 1 MB of the file
script_md5="$(tail -c 1000000 "${script}" | md5sum | head -c 7)"
script_id="${RANDOM}"
# Working directory where the utils will be extracted
# And where the image will be mounted
# The default path is /tmp/scriptname_username_scriptmd5
# And if /tmp is mounted with noexec, the default path
# is ~/.local/share/Conty/scriptname_username_scriptmd5
conty_dir_name="$(basename "${script}")"_"${USER}"_"${script_md5}"
if [ -z "${BASE_DIR}" ]; then
export working_dir=/tmp/"${conty_dir_name}"
if [ -n "${CUSTOM_MNT}" ] && [ -d "${CUSTOM_MNT}" ]; then
mount_point="${CUSTOM_MNT}"
else
export working_dir="${BASE_DIR}"/"${conty_dir_name}"
fi
mount_point="${working_dir}"/mnt
fi
export overlayfs_dir="${HOME}"/.local/share/Conty/overlayfs_"${script_md5}"
export nvidia_drivers_dir="${HOME}"/.local/share/Conty/nvidia_"${script_md5}"
# Offset where the image is stored
offset=$((script_size+utils_size))
offset=$((init_size+bash_size+script_size+busybox_size+utils_size))
# Detect if the image is compressed with DwarFS or SquashFS
if [ "$(tail -c +$((offset+1)) "${script}" | head -c 6)" = "DWARFS" ]; then
@ -201,6 +233,9 @@ dwarfs_comp_arguments=(-l7 -C zstd:level=19 --metadata-compression null \
-S 22 -B 2 --order nilsimsa:255:60000:60000 \
--bloom-filter-size 11 -W 15 -w 3 --no-create-timestamp)
# Enable NVIDIA_HANDLER by default
NVIDIA_HANDLER="${NVIDIA_HANDLER:-1}"
unset script_is_symlink
if [ -L "${script_literal}" ]; then
script_is_symlink=1
@ -323,27 +358,45 @@ mount_overlayfs () {
}
nvidia_driver_handler () {
if lsmod | grep nvidia 1>/dev/null || nvidia-smi 1>/dev/null; then
if [ "$(ls /tmp/hostlibs/x86_64-linux-gnu/libGLX_nvidia.so.* 2>/dev/null)" ]; then
if [ -f /sys/module/nvidia/version ]; then
nvidia_driver_version="$(cat /sys/module/nvidia/version)"
fi
if [ -z "${nvidia_driver_version}" ] && \
[ "$(ls /tmp/hostlibs/x86_64-linux-gnu/libGLX_nvidia.so.* 2>/dev/null)" ]; then
nvidia_driver_version="$(basename /tmp/hostlibs/x86_64-linux-gnu/libGLX_nvidia.so.*.* | tail -c +18)"
elif [ "$(ls /tmp/hostlibs/libGLX_nvidia.so.* 2>/dev/null)" ]; then
fi
if ([ "${nvidia_driver_version}" = "*.*" ] || [ -z "${nvidia_driver_version}" ]) && \
[ "$(ls /tmp/hostlibs/x86_64-linux-gnu/nvidia/current/libGLX_nvidia.so.* 2>/dev/null)" ]; then
nvidia_driver_version="$(basename /tmp/hostlibs/x86_64-linux-gnu/nvidia/current/libGLX_nvidia.so.*.* | tail -c +18)"
fi
if ([ "${nvidia_driver_version}" = "*.*" ] || [ -z "${nvidia_driver_version}" ]) && \
[ "$(ls /tmp/hostlibs/libGLX_nvidia.so.* 2>/dev/null)" ]; then
nvidia_driver_version="$(basename /tmp/hostlibs/libGLX_nvidia.so.*.* | tail -c +18)"
elif nvidia-smi 1>/dev/null; then
fi
if ([ "${nvidia_driver_version}" = "*.*" ] || [ -z "${nvidia_driver_version}" ]) && nvidia-smi &>/dev/null; then
nvidia_driver_version="$(nvidia-smi --query-gpu=driver_version --format=csv,noheader)"
elif modinfo nvidia &>/dev/null; then
fi
if ([ "${nvidia_driver_version}" = "*.*" ] || [ -z "${nvidia_driver_version}" ]) && modinfo nvidia &>/dev/null; then
nvidia_driver_version="$(modinfo -F version nvidia 2>/dev/null)"
fi
else
echo "Seems like your system has no Nvidia driver loaded"
if [ "$(ls /usr/lib/libGLX_nvidia.so.* 2>/dev/null)" ]; then
container_nvidia_version="$(basename /usr/lib/libGLX_nvidia.so.*.* | tail -c +18)"
fi
if [ -z "${nvidia_driver_version}" ] || [ "${nvidia_driver_version}" = "" ]; then
echo "Unable to determine Nvidia driver version"
rm -f "${nvidia_drivers_dir}"/current-nvidia-version
exit 1
fi
if [ -z "${nvidia_driver_version}" ]; then
echo "Unable to determine the Nvidia driver version"
exit 1
fi
if [ "$(cat "${nvidia_drivers_dir}"/current-nvidia-version 2>/dev/null)" = "${nvidia_driver_version}" ]; then
if [ "$(cat "${nvidia_drivers_dir}"/current-nvidia-version 2>/dev/null)" = "${nvidia_driver_version}" ] || \
[ "${nvidia_driver_version}" = "${container_nvidia_version}" ]; then
exit
fi
@ -361,7 +414,7 @@ nvidia_driver_handler () {
curl -#Lo nvidia.run "${driver_url}"
# If the previous download failed, get the URL from FlatHub repo
if [ ! -s nvidia.run ]; then
if [ ! -s nvidia.run ] || [ "$(stat -c%s nvidia.run)" -lt 30000000 ]; then
rm -f nvidia.run
driver_url="https:$(curl -#Lo - "https://raw.githubusercontent.com/flathub/org.freedesktop.Platform.GL.nvidia/master/data/nvidia-${nvidia_driver_version}-i386.data" | cut -d ':' -f 6)"
curl -#Lo nvidia.run "${driver_url}"
@ -391,6 +444,27 @@ nvidia_driver_handler () {
cd "${OLD_PWD}"
}
update_conty () {
reflector --protocol https --score 5 --sort rate --save /etc/pacman.d/mirrorlist
fakeroot -- pacman -Syy 2>/dev/null
date -u +"%d-%m-%Y %H:%M (DMY UTC)" > /version
fakeroot -- pacman --noconfirm -S archlinux-keyring 2>/dev/null
fakeroot -- pacman --noconfirm -S chaotic-keyring 2>/dev/null
rm -rf /etc/pacman.d/gnupg/*
fakeroot -- pacman-key --init
echo "keyserver hkps://keyserver.ubuntu.com" >> /etc/pacman.d/gnupg/gpg.conf
fakeroot -- pacman-key --populate archlinux
fakeroot -- pacman-key --populate chaotic
fakeroot -- pacman --noconfirm --overwrite "*" -Su 2>/dev/null
fakeroot -- pacman --noconfirm -Runs ${pkgsremove} 2>/dev/null
fakeroot -- pacman --noconfirm -S ${pkgsinstall} 2>/dev/null
ldconfig -C /etc/ld.so.cache
rm -f /var/cache/pacman/pkg/*
pacman -Q > /pkglist.x86_64.txt
update-ca-trust
locale-gen
}
# Check if FUSE is installed
if ! command -v fusermount3 1>/dev/null && ! command -v fusermount 1>/dev/null; then
echo "Please install fuse2 or fuse3 and run the script again."
@ -434,13 +508,16 @@ fi
# Extract utils.tar.gz
mkdir -p "${working_dir}"
if [ "${USE_SYS_UTILS}" != 1 ]; then
if ([ "${USE_SYS_UTILS}" != 1 ] && [ "${utils_size}" -gt 0 ]) || [ "$1" = "-u" ]; then
# Check if filesystem of the working_dir is mounted without noexec
if ! exec_test; then
if [ -z "${BASE_DIR}" ]; then
export working_dir="${HOME}"/.local/share/Conty/"${conty_dir_name}"
if [ -z "${CUSTOM_MNT}" ]; then
mount_point="${working_dir}"/mnt
fi
fi
if ! exec_test; then
echo "Seems like /tmp is mounted with noexec or you don't have write access!"
@ -458,16 +535,18 @@ if [ "${USE_SYS_UTILS}" != 1 ]; then
if [ "${dwarfs_image}" = 1 ]; then
mount_tool="${working_dir}"/utils/dwarfs"${fuse_version}"
extraction_tool="${working_dir}"/utils/dwarfsextract
compression_tool="${working_dir}"/utils/mkdwarfs
else
mount_tool="${working_dir}"/utils/squashfuse"${fuse_version}"
extraction_tool="${working_dir}"/utils/unsquashfs
compression_tool="${working_dir}"/utils/mksquashfs
fi
bwrap="${working_dir}"/utils/bwrap
fuse_overlayfs="${working_dir}"/utils/fuse-overlayfs
if [ ! -f "${mount_tool}" ] || [ ! -f "${bwrap}" ]; then
tail -c +$((script_size+1)) "${script}" | head -c "${utils_size}" | tar -C "${working_dir}" -zxf -
tail -c +$((init_size+bash_size+script_size+busybox_size+1)) "${script}" | head -c "${utils_size}" | tar -C "${working_dir}" -zxf -
if [ ! -f "${mount_tool}" ] || [ ! -f "${bwrap}" ]; then
clear
@ -481,6 +560,7 @@ if [ "${USE_SYS_UTILS}" != 1 ]; then
chmod +x "${bwrap}" 2>/dev/null
chmod +x "${extraction_tool}" 2>/dev/null
chmod +x "${fuse_overlayfs}" 2>/dev/null
chmod +x "${compression_tool}" 2>/dev/null
fi
else
if ! command -v bwrap 1>/dev/null; then
@ -546,212 +626,6 @@ if [ "$1" = "-H" ] && [ -z "${script_is_symlink}" ]; then
exit
fi
if { [ "$1" = "-u" ] || [ "$1" = "-U" ]; } && [ -z "${script_is_symlink}" ]; then
OLD_PWD="${PWD}"
# Check if the current directory is writable
# And if it's not, use ~/.local/share/Conty as a working directory
if ! touch test_rw 2>/dev/null; then
update_temp_dir="${HOME}"/.local/share/Conty/conty_update_temp
else
update_temp_dir="${OLD_PWD}"/conty_update_temp
fi
rm -f test_rw
# Remove conty_update_temp directory if it already exists
chmod -R 700 "${update_temp_dir}" 2>/dev/null
rm -rf "${update_temp_dir}"
mkdir -p "${update_temp_dir}"
cd "${update_temp_dir}" || exit 1
if command -v awk 1>/dev/null; then
current_file_size="$(stat -c "%s" "${script}")"
available_disk_space="$(df -P -B1 "${update_temp_dir}" | awk 'END {print $4}')"
required_disk_space="$((current_file_size*7))"
if [ "${available_disk_space}" -lt "${required_disk_space}" ]; then
echo "Not enough free disk space"
echo "You need at least $((required_disk_space/1024/1024)) MB of free space"
exit 1
fi
fi
tail -c +$((script_size+1)) "${script}" | head -c "${utils_size}" | tar -C "${update_temp_dir}" -zxf -
if [ "${dwarfs_image}" = 1 ]; then
chmod +x utils/dwarfsextract 2>/dev/null
chmod +x utils/mkdwarfs 2>/dev/null
if [ ! -x "utils/dwarfsextract" ] || [ ! -x "utils/mkdwarfs" ]; then
missing_utils="dwarfsextract and/or mkdwarfs"
fi
else
chmod +x utils/unsquashfs 2>/dev/null
chmod +x utils/mksquashfs 2>/dev/null
if [ ! -x "utils/unsquashfs" ] || [ ! -x "utils/mksquashfs" ]; then
missing_utils="unsquashfs and/or mksquashfs"
fi
fi
if [ -n "${missing_utils}" ]; then
echo "The integrated utils don't contain ${missing_utils}."
echo "Or your file system is mounted with noexec."
exit 1
fi
tools_wrapper () {
"${update_temp_dir}"/utils/ld-linux-x86-64.so.2 --library-path "${update_temp_dir}"/utils "$@"
}
# Since Conty is used here to update itself, it's necessary to disable
# some environment variables for this to work properly
unset DISABLE_NET
unset HOME_DIR
unset SANDBOX_LEVEL
# Enable SANDBOX
export SANDBOX=1
export QUIET_MODE=1
# Extract the image
clear
echo "Extracting the image"
if [ "${dwarfs_image}" = 1 ]; then
mkdir sqfs
tools_wrapper "${update_temp_dir}"/utils/dwarfsextract \
-i "${script}" -o sqfs -O "${offset}" --cache-size "${dwarfs_cache_size}" \
--num-workers "${dwarfs_num_workers}"
else
tools_wrapper "${update_temp_dir}"/utils/unsquashfs \
-o "${offset}" -user-xattrs -d sqfs "${script}"
fi
# Download or extract the utils.tar.gz and the init script depending
# on what command line argument is used (-u or -U)
clear
if [ "$1" = "-U" ] && command -v curl 1>/dev/null; then
if [ "${dwarfs_image}" = 1 ]; then
utils="utils_dwarfs.tar.gz"
else
utils="utils.tar.gz"
fi
echo "Downloading the init script and the utils"
curl -#LO "https://github.com/Kron4ek/Conty/raw/master/conty-start.sh"
curl -#Lo utils.tar.gz "https://github.com/Kron4ek/Conty/raw/master/${utils}"
fi
if [ ! -s conty-start.sh ] || [ ! -s utils.tar.gz ]; then
echo "Extracting the init script and the integrated utils"
tail -c +$((script_size+1)) "${script}" | head -c "${utils_size}" > utils.tar.gz
head -c "${script_size}" "${script}" > conty-start.sh
fi
# Check if there are additional arguments passed
shift
if [ -n "$1" ]; then
packagelist=("$@")
# Check which packages to install and which ones to remove
for i in "${packagelist[@]}"; do
if [ "$(echo "${i}" | head -c 1)" = "-" ]; then
pkgsremove+=" ${i:1}"
else
pkgsinstall+=" ${i}"
fi
done
export pkgsremove
export pkgsinstall
fi
# Generate a script to perform inside Conty
# It updates Arch mirrorlist
# Updates keyrings
# Updates all installed packages
# Installs additional packages (if requested)
# Removes packages (if requested)
# Clears package cache
# Updates SSL CA certificates
# Generates locales
cat <<EOF > container-update.sh
reflector --protocol https --score 5 --sort rate --save /etc/pacman.d/mirrorlist
fakeroot -- pacman -Syy 2>/dev/null
date -u +"%d-%m-%Y %H:%M (DMY UTC)" > /version
fakeroot -- pacman --noconfirm -S archlinux-keyring 2>/dev/null
fakeroot -- pacman --noconfirm -S chaotic-keyring 2>/dev/null
rm -rf /etc/pacman.d/gnupg
fakeroot -- pacman-key --init
echo "keyserver hkps://keyserver.ubuntu.com" >> /etc/pacman.d/gnupg/gpg.conf
fakeroot -- pacman-key --populate archlinux
fakeroot -- pacman-key --populate chaotic
fakeroot -- pacman --noconfirm --overwrite "*" -Su 2>/dev/null
fakeroot -- pacman --noconfirm -Runs ${pkgsremove} 2>/dev/null
fakeroot -- pacman --noconfirm -S ${pkgsinstall} 2>/dev/null
ldconfig -C /etc/ld.so.cache
rm -f /var/cache/pacman/pkg/*
pacman -Qn > /pkglist.x86_64.txt
pacman -Qm >> /pkglist.x86_64.txt
update-ca-trust
locale-gen
EOF
rm -f sqfs/etc/resolv.conf
cp /etc/resolv.conf sqfs/etc/resolv.conf
mkdir -p sqfs/run/shm
# Execute the previously generated script
clear
echo "Updating and installing packages"
bash "${script}" --bind sqfs / --ro-bind /sys /sys --dev-bind /dev /dev \
--proc /proc --bind "${update_temp_dir}" "${update_temp_dir}" \
bash container-update.sh
# Create an image
clear
echo "Creating an image"
if [ "${dwarfs_image}" = 1 ]; then
tools_wrapper "${update_temp_dir}"/utils/mkdwarfs \
-i sqfs -o image "${dwarfs_comp_arguments[@]}"
else
tools_wrapper "${update_temp_dir}"/utils/mksquashfs \
sqfs image "${squashfs_comp_arguments[@]}"
fi
# Combine into a single executable
clear
echo "Combining everything into a single executable"
cat conty-start.sh utils.tar.gz image > conty_updated.sh
chmod +x conty_updated.sh
mv -f "${script}" "${script}".old."${script_md5}" 2>/dev/null
mv -f conty_updated.sh "${script}" 2>/dev/null || move_failed=1
if [ "${move_failed}" = 1 ]; then
mv -f conty_updated.sh "${OLD_PWD}" 2>/dev/null || \
mv -f conty_updated.sh "${HOME}" 2>/dev/null
fi
chmod -R 700 sqfs 2>/dev/null
rm -rf "${update_temp_dir}"
clear
echo "Conty has been updated!"
if [ "${move_failed}" = 1 ]; then
echo
echo "Replacing ${script} with the new one failed!"
echo
echo "You can find conty_updated.sh in the current working"
echo "directory or in your HOME."
fi
exit
fi
run_bwrap () {
unset sandbox_params
unset unshare_net
@ -759,6 +633,7 @@ run_bwrap () {
unset non_standard_home
unset xsockets
unset mount_opt
unset pacman_dirs
if [ -n "${WAYLAND_DISPLAY}" ]; then
wayland_socket="${WAYLAND_DISPLAY}"
@ -887,10 +762,20 @@ run_bwrap () {
if ([ "${NVIDIA_HANDLER}" = 1 ] || [ "${USE_OVERLAYFS}" = 1 ]) && \
[ "$(ls "${overlayfs_dir}"/merged 2>/dev/null)" ]; then
newroot_path="${overlayfs_dir}"/merged
pacman_dirs=(--bind-try "${overlayfs_dir}"/merged/var/lib/pacman /var/lib/pacman \
--bind-try "${overlayfs_dir}"/merged/var/cache/pacman /var/cache/pacman)
else
newroot_path="${mount_point}"
fi
conty_variables="BASE_DIR DISABLE_NET DISABLE_X11 HOME_DIR QUIET_MODE \
SANDBOX SANDBOX_LEVEL USE_OVERLAYFS NVIDIA_HANDLER \
USE_SYS_UTILS XEPHYR_SIZE CUSTOM_MNT"
for v in ${conty_variables}; do
unset_vars+=(--unsetenv "${v}")
done
show_msg
launch_wrapper "${bwrap}" \
@ -916,9 +801,11 @@ run_bwrap () {
"${non_standard_home[@]}" \
"${sandbox_params[@]}" \
"${custom_home[@]}" \
"${pacman_dirs[@]}" \
"${mount_opt[@]}" \
"${xsockets[@]}" \
"${unshare_net[@]}" \
"${unset_vars[@]}" \
--setenv PATH "${CUSTOM_PATH}" \
"$@"
}
@ -932,10 +819,12 @@ trap_exit () {
umount --lazy "${overlayfs_dir}"/merged 2>/dev/null
fi
if [ -z "${CUSTOM_MNT}" ]; then
fusermount"${fuse_version}" -uz "${mount_point}" 2>/dev/null || \
umount --lazy "${mount_point}" 2>/dev/null
fi
if [ ! "$(ls "${mount_point}" 2>/dev/null)" ]; then
if [ ! "$(ls "${mount_point}" 2>/dev/null)" ] || [ -n "${CUSTOM_MNT}" ]; then
rm -rf "${working_dir}"
fi
fi
@ -1048,6 +937,118 @@ if [ "$(ls "${mount_point}" 2>/dev/null)" ] || \
exit
fi
if [ "$1" = "-u" ] && [ -z "${script_is_symlink}" ] && [ -z "${CUSTOM_MNT}" ]; then
export overlayfs_dir="${HOME}"/.local/share/Conty/update_overlayfs
rm -rf "${overlayfs_dir}"
if mount_overlayfs; then
USE_OVERLAYFS=1
QUIET_MODE=1
unset DISABLE_NET
unset HOME_DIR
unset SANDBOX_LEVEL
unset SANDBOX
unset DISABLE_X11
if ! touch test_rw 2>/dev/null; then
cd "${HOME}" || exit 1
fi
rm -f test_rw
OLD_PWD="${PWD}"
mkdir conty_update_temp
cd conty_update_temp || exit 1
if command -v awk 1>/dev/null; then
current_file_size="$(stat -c "%s" "${script}")"
available_disk_space="$(df -P -B1 "${PWD}" | awk 'END {print $4}')"
required_disk_space="$((current_file_size*7))"
if [ "${available_disk_space}" -lt "${required_disk_space}" ]; then
echo "Not enough free disk space"
echo "You need at least $((required_disk_space/1024/1024)) MB of free space"
exit 1
fi
fi
# Check if there are additional arguments passed
shift
if [ -n "$1" ]; then
packagelist=("$@")
# Check which packages to install and which ones to remove
for i in "${packagelist[@]}"; do
if [ "$(echo "${i}" | head -c 1)" = "-" ]; then
pkgsremove+=" ${i:1}"
else
pkgsinstall+=" ${i}"
fi
done
export pkgsremove
export pkgsinstall
fi
clear
echo "Updating and installing packages..."
cp -r "${mount_point}"/etc/pacman.d/gnupg "${overlayfs_dir}"/gnupg
export -f update_conty
run_bwrap --bind "${overlayfs_dir}"/gnupg /etc/pacman.d/gnupg \
--bind "${overlayfs_dir}"/merged/var/lib/pacman /var/lib/pacman \
--bind-try "${overlayfs_dir}"/merged/var/cache/pacman /var/cache/pacman \
bash -c update_conty
if [ "${dwarfs_image}" = 1 ]; then
compression_command=("${compression_tool}" -i "${overlayfs_dir}"/merged -o image "${dwarfs_comp_arguments[@]}")
else
compression_command=("${compression_tool}" "${overlayfs_dir}"/merged image "${squashfs_comp_arguments[@]}")
fi
clear
echo "Creating an image..."
launch_wrapper "${compression_command[@]}"
if [ "${init_size}" -gt 0 ]; then
tail -c +$((init_size+bash_size+1)) "${script}" | head -c "${script_size}" > conty-start.sh
else
head -c "${script_size}" "${script}" > conty-start.sh
fi
tail -c +$((init_size+bash_size+script_size+busybox_size+1)) "${script}" | head -c "${utils_size}" > utils.tar.gz
# Combine into a single executable
clear
echo "Combining everything into a single executable..."
cat "${working_dir}"/utils/init "${working_dir}"/utils/bash \
conty-start.sh "${working_dir}"/utils/busybox utils.tar.gz \
image > conty_updated.sh
chmod +x conty_updated.sh
mv -f "${script}" "${script}".old."${script_md5}" 2>/dev/null
mv -f conty_updated.sh "${script}" 2>/dev/null || move_failed=1
fusermount"${fuse_version}" -uz "${overlayfs_dir}"/merged 2>/dev/null || \
umount --lazy "${overlayfs_dir}"/merged 2>/dev/null
rm -rf "${overlayfs_dir}" "${OLD_PWD}"/conty_update_temp
clear
echo "Conty has been updated!"
if [ "${move_failed}" = 1 ]; then
echo
echo "Replacing ${script} with the new one failed!"
echo
echo "You can find conty_updated.sh in the current working"
echo "directory or in your HOME."
fi
else
echo "Failed to mount overlayfs"
echo "Cannot update Conty"
fi
exit
fi
if [ "${USE_OVERLAYFS}" = 1 ]; then
if mount_overlayfs; then
show_msg "Using overlayfs"
@ -1058,6 +1059,7 @@ if [ "$(ls "${mount_point}" 2>/dev/null)" ] || \
fi
if [ "${NVIDIA_HANDLER}" = 1 ]; then
if [ -f /sys/module/nvidia/version ] || lsmod | grep nvidia 1>/dev/null; then
if mount_overlayfs; then
show_msg "Nvidia driver handler is enabled"
@ -1068,15 +1070,22 @@ if [ "$(ls "${mount_point}" 2>/dev/null)" ] || \
mkdir -p "${nvidia_drivers_dir}"
export -f nvidia_driver_handler
DISABLE_NET=0 run_bwrap --tmpfs /tmp --tmpfs /var --tmpfs /run \
DISABLE_NET=0 QUIET_MODE=1 run_bwrap --tmpfs /tmp --tmpfs /var --tmpfs /run \
--bind-try /usr/lib /tmp/hostlibs \
--bind-try /usr/lib64 /tmp/hostlibs \
--bind-try "${nvidia_drivers_dir}" "${nvidia_drivers_dir}" \
--bind "${nvidia_drivers_dir}" "${nvidia_drivers_dir}" \
bash -c nvidia_driver_handler
else
echo "Nvidia driver handler disabled due to overlayfs errors"
unset NVIDIA_HANDLER
fi
else
unset NVIDIA_HANDLER
fi
if [ ! -f "${nvidia_drivers_dir}"/current-nvidia-version ]; then
unset NVIDIA_HANDLER
fi
fi
# If SANDBOX_LEVEL is 3, run Xephyr and openbox before running applications

View file

@ -69,6 +69,7 @@ ar_EG.UTF-8 UTF-8
en_US.UTF-8 UTF-8
en_GB.UTF-8 UTF-8
en_CA.UTF-8 UTF-8
en_SG.UTF-8 UTF-8
es_MX.UTF-8 UTF-8
zh_CN.UTF-8 UTF-8
fr_FR.UTF-8 UTF-8
@ -78,6 +79,7 @@ es_ES.UTF-8 UTF-8
de_DE.UTF-8 UTF-8
pt_BR.UTF-8 UTF-8
it_IT.UTF-8 UTF-8
id_ID.UTF-8 UTF-8
ja_JP.UTF-8 UTF-8
bg_BG.UTF-8 UTF-8
pl_PL.UTF-8 UTF-8
@ -87,6 +89,7 @@ tr_TR.UTF-8 UTF-8
hu_HU.UTF-8 UTF-8
cs_CZ.UTF-8 UTF-8
bn_IN UTF-8
hi_IN UTF-8
EOF
}

View file

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Dependencies: squashfs-tools or dwarfs
# Dependencies: sed, squashfs-tools or dwarfs
script_dir="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
@ -31,7 +31,6 @@ dwarfs_compressor_arguments=(-l7 -C zstd:level=19 --metadata-compression null \
use_existing_image="false"
image_path="${script_dir}"/image
bootstrap="${script_dir}"/root.x86_64
launch_wrapper () {
@ -47,6 +46,11 @@ launch_wrapper () {
fi
}
if ! command -v sed 1>/dev/null; then
echo "sed is required"
exit 1
fi
cd "${script_dir}" || exit 1
if [ "${dwarfs}" = "true" ]; then
@ -57,7 +61,7 @@ else
compressor_command=(mksquashfs "${bootstrap}" "${image_path}" "${squashfs_compressor_arguments[@]}")
fi
if [ ! -f "${utils}" ] || [ "$(wc -c < "${utils}")" -lt 1000 ]; then
if [ ! -f "${utils}" ] || [ "$(wc -c < "${utils}")" -lt 100000 ]; then
rm -f "${utils}"
curl -#LO "https://github.com/Kron4ek/Conty/raw/master/${utils}"
fi
@ -75,10 +79,6 @@ if [ $? != 0 ]; then
exit 1
fi
if [ "${USE_SYS_UTILS}" != 0 ]; then
rm -rf utils
fi
# Check if selected compression algorithm is supported by mksquashfs
if [ "${USE_SYS_UTILS}" != 0 ] && [ "${dwarfs}" != "true" ] && command -v grep 1>/dev/null; then
# mksquashfs writes its output to stderr instead of stdout
@ -112,8 +112,41 @@ if [ ! -f "${image_path}" ] || [ "${use_existing_image}" != "true" ]; then
launch_wrapper "${compressor_command[@]}"
fi
if command -v sed 1>/dev/null; then
utils_size="$(stat -c%s "${utils}")"
init_size=0
bash_size=0
busybox_size=0
if [ -s utils/init ]; then
init_size="$(stat -c%s utils/init)"
fi
if [ -s utils/bash ]; then
bash_size="$(stat -c%s utils/bash)"
fi
if [ -s utils/busybox ]; then
busybox_size="$(stat -c%s utils/busybox)"
fi
if [ "${init_size}" = 0 ] || [ "${bash_size}" = 0 ]; then
init_size=0
bash_size=0
rm -f utils/init utils/bash
fi
sed -i "s/init_size=.*/init_size=${init_size}/" conty-start.sh
sed -i "s/bash_size=.*/bash_size=${bash_size}/" conty-start.sh
sed -i "s/busybox_size=.*/busybox_size=${busybox_size}/" conty-start.sh
sed -i "s/utils_size=.*/utils_size=${utils_size}/" conty-start.sh
sed -i "s/script_size=.*/script_size=$(stat -c%s conty-start.sh)/" conty-start.sh
sed -i "s/script_size=.*/script_size=$(stat -c%s conty-start.sh)/" conty-start.sh
fi
# Combine the files into a single executable using cat
cat conty-start.sh "${utils}" "${image_path}" > conty.sh
cat utils/init utils/bash conty-start.sh utils/busybox "${utils}" "${image_path}" > conty.sh
chmod +x conty.sh
clear

View file

@ -1,7 +1,8 @@
#!/usr/bin/env bash
# General build dependencies: gawk grep lz4 zstd curl gcc make autoconf
# libtool pkgconf libcap fuse2 (or fuse3) lzo xz zlib findutils
# libtool pkgconf libcap fuse2 (or fuse3) lzo xz zlib findutils musl
# kernel-headers-musl sed
#
# Dwarfs build dependencies: fuse2 (or fuse3) openssl jemalloc
# xxhash boost lz4 xz zstd libarchive libunwind google-glod gtest fmt
@ -20,6 +21,8 @@ lz4_version="1.9.4"
zstd_version="1.5.5"
squashfs_tools_version="4.6.1"
fuse_overlayfs_version="1.12"
busybox_version="1.36.1"
bash_version="5.2.15"
export CC=gcc
export CXX=g++
@ -35,11 +38,16 @@ curl -#Lo lz4.tar.gz https://github.com/lz4/lz4/archive/refs/tags/v${lz4_version
curl -#Lo zstd.tar.gz https://github.com/facebook/zstd/archive/refs/tags/v${zstd_version}.tar.gz
curl -#Lo bwrap.tar.gz https://github.com/containers/bubblewrap/archive/refs/tags/v${bwrap_version}.tar.gz
curl -#Lo fuse-overlayfs.tar.gz https://github.com/containers/fuse-overlayfs/archive/refs/tags/v${fuse_overlayfs_version}.tar.gz
curl -#Lo busybox.tar.bz2 https://busybox.net/downloads/busybox-${busybox_version}.tar.bz2
curl -#Lo bash.tar.gz https://ftp.gnu.org/gnu/bash/bash-${bash_version}.tar.gz
cp "${script_dir}"/init.c init.c
tar xf lz4.tar.gz
tar xf zstd.tar.gz
tar xf bwrap.tar.gz
tar xf fuse-overlayfs.tar.gz
tar xf busybox.tar.bz2
tar xf bash.tar.gz
if [ "${build_dwarfs}" != "true" ]; then
curl -#Lo squashfuse.tar.gz https://github.com/vasi/squashfuse/archive/refs/tags/${squashfuse_version}.tar.gz
@ -65,6 +73,19 @@ make -j"$(nproc)" DESTDIR="${script_dir}"/build-utils/bin install
cd ../zstd-"${zstd_version}" || exit 1
ZSTD_LEGACY_SUPPORT=0 HAVE_ZLIB=0 HAVE_LZMA=0 HAVE_LZ4=0 BACKTRACE=0 make -j"$(nproc)" DESTDIR="${script_dir}"/build-utils/bin install
cd ../busybox-${busybox_version} || exit 1
make defconfig
sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/g' .config
make CC=musl-gcc -j"$(nproc)"
cd ../bash-${bash_version}
curl -#Lo bash.patch "https://raw.githubusercontent.com/robxu9/bash-static/master/custom/bash-musl-strtoimax-debian-1023053.patch"
patch -Np1 < ./bash.patch
CFLAGS="${CFLAGS} -static" CC=musl-gcc ./configure --without-bash-malloc
autoconf -f
CFLAGS="${CFLAGS} -static" CC=musl-gcc ./configure --without-bash-malloc
CFLAGS="${CFLAGS} -static" CC=musl-gcc make -j"$(nproc)"
if [ "${build_dwarfs}" != "true" ]; then
cd ../squashfuse-"${squashfuse_version}" || exit 1
./autogen.sh
@ -89,6 +110,9 @@ mv bin/usr/local/lib/liblz4.so."${lz4_version}" utils/liblz4.so.1
mv bin/usr/local/lib/libzstd.so."${zstd_version}" utils/libzstd.so.1
mv bin/usr/local/lib/libfuseprivate.so.0.0.0 utils/libfuseprivate.so.0
mv bin/usr/local/lib/libsquashfuse.so.0.0.0 utils/libsquashfuse.so.0
mv "${script_dir}"/build-utils/busybox-${busybox_version}/busybox utils
mv "${script_dir}"/build-utils/bash-${bash_version}/bash utils
mv "${script_dir}"/build-utils/init utils
if ! ldd utils/squashfuse | grep -q libfuse.so.2; then
mv utils/squashfuse utils/squashfuse3
@ -99,6 +123,8 @@ if [ "${build_dwarfs}" = "true" ]; then
if command -v clang++ 1>/dev/null; then
export CC=clang
export CXX=clang++
export CFLAGS="${CFLAGS} -O3"
export CXXFLAGS="${CFLAGS}"
fi
git clone https://github.com/mhx/dwarfs.git --recursive
@ -148,9 +174,33 @@ fi
find utils -type f -exec strip --strip-unneeded {} \; 2>/dev/null
init_program_size=40000
conty_script_size="$(($(stat -c%s "${script_dir}"/conty-start.sh)+1000))"
bash_size="$(stat -c%s utils/bash)"
sed -i "s/#define SCRIPT_SIZE 0/#define SCRIPT_SIZE ${conty_script_size}/g" init.c
sed -i "s/#define BASH_SIZE 0/#define BASH_SIZE ${bash_size}/g" init.c
sed -i "s/#define PROGRAM_SIZE 0/#define PROGRAM_SIZE ${init_program_size}/g" init.c
musl-gcc -o init -static init.c
strip --strip-unneeded init
padding_size="$((init_program_size-$(stat -c%s init)))"
if [ "${padding_size}" -gt 0 ]; then
dd if=/dev/zero of=padding bs=1 count="${padding_size}" &>/dev/null
cat init padding > init_new
rm -f init padding
mv init_new init
fi
mv init utils
cat <<EOF > utils/info
bubblewrap ${bwrap_version}
fuse-overlayfs ${fuse_overlayfs_version}
busybox ${busybox_version}
bash ${bash_version}
lz4 ${lz4_version}
zstd ${zstd_version}
EOF

61
init.c Normal file
View file

@ -0,0 +1,61 @@
// This is a bash-static initializer for Conty
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
// Replace all 0 below before compilation
// The size of our statically compiled bash binary
#define BASH_SIZE 0
// The size of conty-start.sh script
// It can be bigger than the actual size of the script
#define SCRIPT_SIZE 0
// The size of this program itself after compilation
// It can be bigger than the actual size of the program
#define PROGRAM_SIZE 0
// Bubblewrap can handle up to 9000 arguments
// And we reserve 1000 for internal use in Conty
#define MAX_ARGS_NUMBER 8000
int main(int argc, char* argv[])
{
if (argc > MAX_ARGS_NUMBER) {
printf("Too many arguments");
return 1;
}
char program_path[8192] = { 0 };
int binary_code[BASH_SIZE + 1];
char bash_script[SCRIPT_SIZE + 1];
readlink("/proc/self/exe", program_path, sizeof program_path);
FILE *current_program = fopen(program_path, "rb");
int bash_binary = memfd_create("bash-static", 0);
fseek(current_program, PROGRAM_SIZE, 0);
fread(binary_code, BASH_SIZE, 1, current_program);
write(bash_binary, binary_code, BASH_SIZE);
fseek(current_program, PROGRAM_SIZE + BASH_SIZE, 0);
fread(bash_script, SCRIPT_SIZE, 1, current_program);
fclose(current_program);
char * bash_args[MAX_ARGS_NUMBER + 5] = {program_path, "-c", "--", bash_script, argv[0]};
int k = 5;
for (int i = 1; i < argc; i++, k++) {
bash_args[k] = argv[i];
}
bash_args[k] = NULL;
fexecve(bash_binary, bash_args, environ);
printf("Failed to execute builtin bash-static");
return 0;
}

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:20b855587b07fa71c8be8e73220495fcee7c9ec290914e982b76fd184fa67094
size 2564623
oid sha256:eefb9b12b71605d0cc2925c497f2447b2eaf383540522d4967ccd8e2053b29c5
size 4049807

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ef56bd72810c1c05a6f4cd77e816b2741ab014b421c00eb0337602c5a11d0959
size 9431944
oid sha256:bb6d97c95baab37870c80f73e190de4dbb4a29327054c8d24e3ecf7122b10ed2
size 10917484