liaf/liaf
#!/usr/bin/env sh
ARCH=$(uname -m)
ALPINE_VER="3.24.2"
ALPINE_BRANCH=${ALPINE_VER%.*}
CONFIG_FOLDER="$HOME/.config/liaf"
CONFIG_FILE="liaf.conf"
CONFIG_FILE_PATH="$CONFIG_FOLDER/$CONFIG_FILE"
DIST_FOLDER="$HOME/.local/share/liaf"
TYPE="sandbox"
USER_ID=$(id -u)
HOME_IN_CHROOT="/home/user"
if [ -f "$CONFIG_FILE_PATH" ]; then
. $CONFIG_FILE_PATH
else
echo "Making config folder..."
mkdir -p $CONFIG_FOLDER
echo 'ARCH=$(uname -m)
ALPINE_VER="3.24.2"
ALPINE_BRANCH="${ALPINE_VER%.*}"
DIST_FOLDER="$HOME/.local/share/liaf"
TYPE="sandbox"
' > $CONFIG_FILE_PATH
. $CONFIG_FILE_PATH
fi
print_err() {
printf '\033[31mError: %s\033[0m\n' "$*" >&2
}
require_bwrap() {
if ! command -v bwrap >/dev/null 2>&1; then
print_err "For building sandbox is required Bubblewrap."
exit 1
fi
}
make_sandbox(){
require_bwrap
echo "Using $CONFIG_FILE_PATH ..."
echo "Building sandbox in $CURR_PROJECT_FOLDER..."
if [ -d "$CURR_PROJECT_FOLDER" ]; then
print_err "Unable to create the directory; it already exists."
exit 1
fi
if [ ! -d "$CURR_PROJECT_FOLDER/ctr" ]; then
mkdir -p "$CURR_PROJECT_FOLDER/ctr"
fi
if [ ! -d "$CURR_PROJECT_FOLDER/ctr" ]; then
print_err "Problem on creating folder!"
exit 1
fi
cd $CURR_PROJECT_FOLDER/ctr
wget https://dl-cdn.alpinelinux.org/alpine/v$ALPINE_BRANCH/releases/$ARCH/alpine-minirootfs-$ALPINE_VER-$ARCH.tar.gz -O alpine.tar.gz
tar xzf alpine.tar.gz
rm alpine.tar.gz
mkdir -p "run/user/$USER_ID"
cd ..
echo "#!/bin/sh
xhost +
CUSTOM_OPTS=\"\"
bwrap \
--die-with-parent \
--unshare-pid \
--unshare-user \
--uid "$USER_ID" \
--bind ./ctr / \
\$CUSTOM_OPTS \
--bind "/run/user/$USER_ID" "/run/user/$USER_ID" \
--setenv HOME $HOME_IN_CHROOT \
--setenv XDG_RUNTIME_DIR "/run/user/$USER_ID" \
--setenv PULSE_SERVER "unix:/run/user/$USER_ID/pulse/native" \
--dev-bind /dev/snd /dev/snd \
--dev /dev \
--proc /proc \
--tmpfs /tmp \
--ro-bind /etc/resolv.conf /etc/resolv.conf \
"\$1"
" > run.sh
echo "#!/bin/sh
/sbin/apk update
/sbin/apk add pulseaudio-utils pipewire-pulse alsa-utils fontconfig font-noto font-dejavu
/bin/touch "/run/user/$USER_ID/pipewire-0"
"> ./ctr/usr/local/bin/setup_multimedia.sh
chmod +x ./ctr/usr/local/bin/setup_multimedia.sh
cat > shell.sh <<'EOF'
#!/bin/sh
exec ./run.sh "/bin/ash -l"
EOF
chmod +x *.sh
mkdir -p ctr/home/user
}
make_chroot(){
echo "Using $CONFIG_FILE_PATH ..."
echo "Building chroot in $CURR_PROJECT_FOLDER..."
if [ -d "$CURR_PROJECT_FOLDER" ]; then
print_err "Unable to create the directory; it already exists."
exit 1
fi
if [ ! -d "$CURR_PROJECT_FOLDER/ctr" ]; then
mkdir -p "$CURR_PROJECT_FOLDER/ctr"
fi
if [ ! -d "$CURR_PROJECT_FOLDER/ctr" ]; then
print_err "Problem on creating folder!"
exit 1
fi
cd $CURR_PROJECT_FOLDER/ctr
wget https://dl-cdn.alpinelinux.org/alpine/v$ALPINE_BRANCH/releases/$ARCH/alpine-minirootfs-$ALPINE_VER-$ARCH.tar.gz -O alpine.tar.gz
tar xzf alpine.tar.gz
rm alpine.tar.gz
cd ..
echo "#!/bin/sh" > run.sh
echo "cp /etc/resolv.conf ./ctr/etc/resolv.conf
mount --bind /dev ./ctr/dev
mount -t proc /proc ./ctr/proc
mount -t sysfs /sys ./ctr/sys
chroot ./ctr /bin/ash -l
./umount.sh
" >> run.sh
chmod +x run.sh
echo "#!/bin/sh" > umount.sh
echo "umount ctr/dev
umount ctr/proc
umount ctr/sys" >> umount.sh
chmod +x umount.sh
cat > shell.sh <<'EOF'
#!/bin/sh
exec ./run.sh "/bin/ash -l"
EOF
chmod +x shell.sh
}
print_help(){
echo ""
echo "Build a sandbox:"
echo "Usage: liaf -a <ARCH> -v <ALPINE VERSION> -t <sandbox/chroot> -o <PROJECT NAME>"
echo ""
echo "Run a shell in the sandbox:"
echo "liaf -r <sandbox name> "
echo ""
echo "Run a prcess in the sandbox:"
echo "liaf -r <sandbox name> -e <path/to/exe>"
echo ""
echo "Show all sandboxes:"
echo "liaf -l"
echo ""
echo "Delete a sandbox:"
echo "liaf -d <sandbox name>"
}
# list_environments(){
# ls -w 1 $DIST_FOLDER || print_error "Impossible list environments" && exit 1
# exit 0
# }
list_environments() {
if [ ! -d "$DIST_FOLDER" ]; then
print_err "No environments found."
return 1
fi
ls -1 "$DIST_FOLDER"
}
delete_folder() {
if [ "$#" -ne 1 ]; then
echo "Usage: delete_folder FOLDER_NAME"
return 1
fi
folder="$DIST_FOLDER/$1"
if [ ! -d "$folder" ]; then
print_err "Folder $folder does not exist!"
exit 1
fi
printf "Delete '%s' and all its contents? [y/N] " "$folder"
read answer
case "$answer" in
y|Y|yes|Yes|YES)
rm -rf "$folder" && echo "Folder deleted."
;;
*)
echo "Operation cancelled."
;;
esac
exit 0
}
while getopts "a:v:o:t:r:e:h:d:l" opt; do
case "$opt" in
a) ARCH=$OPTARG ;;
v) ALPINE_VER=$OPTARG ;;
t) TYPE=$OPTARG ;;
o) PROJECT_NAME=$OPTARG ;;
r) RUN=$OPTARG ;;
e) EXE=$OPTARG ;;
d) delete_folder "$OPTARG" ;;
l) list_environments; exit $? ;;
h) print_help ; exit 0 ;;
*) print_help ; exit 1 ;;
esac
done
if [ "$#" -eq 0 ]; then
print_help
exit 1
fi
if [ -z "$RUN" ] && [ -z "$PROJECT_NAME" ]; then
print_help
exit 1
fi
if [ -n "$RUN" ]; then
if [ -n "$RUN" ] && [ -z "$EXE" ] && [ -f "$DIST_FOLDER/$RUN/shell.sh" ]; then
echo "Runnning $RUN ..."
cd "$DIST_FOLDER/$RUN"
./shell.sh
exit 0
elif [ -n "$RUN" ] && [ -n "$EXE" ] && [ -f "$DIST_FOLDER/$RUN/run.sh" ]; then
echo "Runnningi $EXE in $RUN ..."
cd "$DIST_FOLDER/$RUN"
./run.sh "$EXE"
exit 0
else
print_err "sandbox is not present!"
exit 1
fi
fi
ALPINE_BRANCH=${ALPINE_VER%.*}
#For debug
echo "Arch: $ARCH, Alpine version: $ALPINE_BRANCH, Project type: $TYPE , Output folder: $DIST_FOLDER/$PROJECT_NAME"
if [ -z "$PROJECT_NAME" ]; then
echo "Please select a Project name with -o <your_project_name>" >&2
exit 1
else
CURR_PROJECT_FOLDER=$DIST_FOLDER/$PROJECT_NAME
echo "Current project folder is $CURR_PROJECT_FOLDER"
fi
case "$TYPE" in
sandbox)
make_sandbox
;;
chroot)
make_chroot
;;
*)
echo "Select a type. Please."
exit 1
;;
esac