Files
2026-04-15 00:42:18 -04:00

97 lines
2.8 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<EOF
Usage: lab-mount <container|user> <host-path> [container-path]
Bind-mounts a host directory into an LXC container, persisting across reboots.
If container-path is omitted, it mirrors host-path inside the container.
Examples:
lab-mount alice /mnt/nas/shared # -> /mnt/nas/shared inside lxc-alice
lab-mount alice /mnt/nas/shared /data/shared # -> /data/shared inside lxc-alice
lab-mount lxc-alice /mnt/nas/shared # container name directly also works
To mount for ALL containers:
lab-mount --all /mnt/nas/shared /data/shared
EOF
exit 1
}
mount_into() {
local CONTAINER="$1"
local HOST_PATH="$2"
local CONT_PATH="$3"
local ROOTFS="/var/lib/lxc/${CONTAINER}/rootfs"
local CONFIG="/var/lib/lxc/${CONTAINER}/config"
if [[ ! -d "$ROOTFS" ]]; then
echo "ERROR: container '$CONTAINER' not found" >&2
return 1
fi
if [[ ! -e "$HOST_PATH" ]]; then
echo "ERROR: host path '$HOST_PATH' does not exist" >&2
return 1
fi
# create mountpoint inside rootfs
mkdir -p "${ROOTFS}${CONT_PATH}"
# check if this bind mount is already in config
local ENTRY="lxc.mount.entry = ${HOST_PATH} ${CONT_PATH#/} none bind,create=dir 0 0"
if grep -qF "$ENTRY" "$CONFIG" 2>/dev/null; then
echo "Already configured: ${CONTAINER} ${HOST_PATH} -> ${CONT_PATH}"
return 0
fi
# add persistent bind mount to container config
echo "$ENTRY" >> "$CONFIG"
echo "Added to config: ${CONTAINER} ${HOST_PATH} -> ${CONT_PATH}"
# if the container is running, also mount it live
local STATE
STATE=$(lxc-info -n "$CONTAINER" -sH 2>/dev/null || true)
if [[ "$STATE" == "RUNNING" ]]; then
# lxc-attach to mount from inside
lxc-attach --clear-env -n "$CONTAINER" -- /bin/bash -c "
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
mkdir -p '${CONT_PATH}'
"
# note: live bind mounts into running unprivileged containers via config
# may require a container restart to take effect
echo "NOTE: restart the container for the mount to take effect:"
echo " lxc-stop -n ${CONTAINER} && lxc-start -n ${CONTAINER}"
fi
}
resolve_container() {
local NAME="$1"
# if it already starts with lxc-, use as-is
if [[ "$NAME" == lxc-* ]]; then
echo "$NAME"
elif [[ -f "/home/${NAME}/.lxc-container" ]]; then
cat "/home/${NAME}/.lxc-container"
else
echo "lxc-${NAME}"
fi
}
# --- parse args ---
[[ $# -lt 2 ]] && usage
if [[ "$1" == "--all" ]]; then
HOST_PATH="$2"
CONT_PATH="${3:-$HOST_PATH}"
for dir in /var/lib/lxc/lxc-*/; do
CONTAINER=$(basename "$dir")
mount_into "$CONTAINER" "$HOST_PATH" "$CONT_PATH"
done
else
CONTAINER=$(resolve_container "$1")
HOST_PATH="$2"
CONT_PATH="${3:-$HOST_PATH}"
mount_into "$CONTAINER" "$HOST_PATH" "$CONT_PATH"
fi