Update lxc-mount-manager.sh

This commit is contained in:
MacRimi
2025-09-02 18:22:34 +02:00
parent cd231b90d8
commit f6b192cc1e

View File

@@ -1,18 +1,17 @@
#!/bin/bash
# ==========================================================
# ProxMenux - LXC Mount Manager (Standalone - CLEAN v1)
# ProxMenux - LXC Mount Manager
# ==========================================================
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
# License : MIT
# Version : 3.0-clean
# Version : 3.1-enhanced
# Last Updated: $(date +%d/%m/%Y)
# ==========================================================
BASE_DIR="/usr/local/share/proxmenux"
source "$BASE_DIR/utils.sh"
SHARE_COMMON_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main/scripts/global/share-common.func"
if ! source <(curl -s "$SHARE_COMMON_URL" 2>/dev/null); then
SHARE_COMMON_LOADED=false
@@ -25,7 +24,6 @@ initialize_cache
# ==========================================================
get_container_uid_shift() {
local ctid="$1"
local conf="/etc/pve/lxc/${ctid}.conf"
@@ -36,12 +34,10 @@ get_container_uid_shift() {
return 0
fi
local unpriv
unpriv=$(grep "^unprivileged:" "$conf" | awk '{print $2}')
if [[ "$unpriv" == "1" ]]; then
uid_shift=$(grep "^lxc.idmap" "$conf" | grep 'u 0' | awk '{print $5}' | head -1)
echo "${uid_shift:-100000}"
return 0
@@ -51,7 +47,6 @@ get_container_uid_shift() {
return 0
}
setup_container_access() {
local ctid="$1" group_name="$2" host_gid="$3" host_dir="$4"
local uid_shift mapped_gid
@@ -63,51 +58,181 @@ setup_container_access() {
uid_shift=$(get_container_uid_shift "$ctid")
# ===================================================================
# CONTAINER TYPE DETECTION AND STRATEGY
# ===================================================================
if [[ "$uid_shift" -eq 0 ]]; then
msg_ok "$(translate "PRIVILEGED container detected - using direct UID/GID mapping")"
mapped_gid="$host_gid"
msg_ok "$(translate "Privileged container - using same GID as host:") $host_gid"
container_type="privileged"
else
msg_ok "$(translate "UNPRIVILEGED container detected - using mapped UID/GID")"
mapped_gid=$((uid_shift + host_gid))
msg_ok "$(translate "Unprivileged container - using mapped GID:") $mapped_gid (host GID: $host_gid, shift: $uid_shift)"
container_type="unprivileged"
msg_ok "UID shift: $uid_shift, Host GID: $host_gid → Container GID: $mapped_gid"
fi
pct exec "$ctid" -- sh -c "
if ! getent group $group_name >/dev/null 2>&1; then
groupadd -g $mapped_gid $group_name 2>/dev/null || true
# ===================================================================
# STEP 1: ACL TOOLS (only for unprivileged containers)
# ===================================================================
if [[ "$container_type" == "unprivileged" ]]; then
if ! command -v setfacl >/dev/null 2>&1; then
msg_info "$(translate "Installing ACL tools (REQUIRED for unprivileged containers)...")"
apt-get update >/dev/null 2>&1
apt-get install -y acl >/dev/null 2>&1
if command -v setfacl >/dev/null 2>&1; then
msg_ok "$(translate "ACL tools installed successfully")"
else
msg_error "$(translate "Failed to install ACL tools - permissions may not work correctly")"
fi
else
ct_gid=\$(getent group $group_name | cut -d: -f3)
if [ \"\$ct_gid\" != \"$mapped_gid\" ]; then
msg_ok "$(translate "ACL tools already available")"
fi
else
msg_ok "$(translate "Privileged container - ACL tools not required (using POSIX permissions)")"
fi
# ===================================================================
# STEP 2: CONTAINER GROUP CONFIGURATION
# ===================================================================
msg_info "$(translate "Configuring container group with") $container_type $(translate "strategy...")"
pct exec "$ctid" -- sh -c "
# Remove existing group if GID is wrong
if getent group $group_name >/dev/null 2>&1; then
current_gid=\$(getent group $group_name | cut -d: -f3)
if [ \"\$current_gid\" != \"$mapped_gid\" ]; then
groupdel $group_name 2>/dev/null || true
groupadd -g $mapped_gid $group_name 2>/dev/null || true
fi
fi
getent passwd | while IFS=: read -r username _ uid gid _ home _; do
if [ \"\$uid\" -eq 0 ] || [ \"\$uid\" -ge 1000 ] || [ \"\$username\" = \"nobody\" ] || [ \"\$username\" = \"www-data\" ]; then
usermod -aG $group_name \"\$username\" 2>/dev/null || true
fi
done
# Create group with correct GID
groupadd -g $mapped_gid $group_name 2>/dev/null || true
" 2>/dev/null
msg_ok "$(translate "Container group configured:") $group_name (GID: $mapped_gid)"
if command -v setfacl >/dev/null 2>&1; then
pct exec "$ctid" -- getent passwd | awk -F: '{print $1, $3}' | while read user uid; do
[[ "$uid" -eq 0 ]] && continue
host_uid=$((uid_shift + uid))
setfacl -m u:$host_uid:rwx "$host_dir" 2>/dev/null || true
done
msg_ok "$(translate "ACL permissions applied for container users")"
# ===================================================================
# STEP 3: USER PROCESSING (different strategies)
# ===================================================================
local container_users
container_users=$(pct exec "$ctid" -- getent passwd | awk -F: '{print $1 ":" $3}' 2>/dev/null)
local users_added=0
local acls_applied=0
if [[ "$container_type" == "privileged" ]]; then
msg_ok "$(translate "Privileged container:") $users_added $(translate "users added to group (no ACLs needed)")"
else
msg_info "$(translate "Using UNPRIVILEGED strategy: mapped UIDs + ACL permissions")"
while IFS=: read -r username ct_uid; do
if [[ -n "$username" && "$ct_uid" =~ ^[0-9]+$ ]]; then
local host_uid=$((uid_shift + ct_uid))
if pct exec "$ctid" -- usermod -aG "$group_name" "$username" 2>/dev/null; then
users_added=$((users_added + 1))
if command -v setfacl >/dev/null 2>&1; then
setfacl -m u:$host_uid:rwx "$host_dir" 2>/dev/null
setfacl -m d:u:$host_uid:rwx "$host_dir" 2>/dev/null
acls_applied=$((acls_applied + 1))
fi
case "$username" in
root|www-data|ncp|nobody|ubuntu|debian)
msg_ok "$(translate "Configured user:") $username (CT_UID:$ct_uid → HOST_UID:$host_uid)"
;;
esac
fi
fi
done <<< "$container_users"
msg_ok "$(translate "Unprivileged container:") $users_added $(translate "users added,") $acls_applied $(translate "ACL entries applied")"
fi
# ===================================================================
# STEP 4: DIRECTORY PERMISSIONS
# ===================================================================
msg_info "$(translate "Setting optimal directory permissions...")"
chmod 2775 "$host_dir" 2>/dev/null || true
chgrp "$group_name" "$host_dir" 2>/dev/null || true
msg_ok "$(translate "Host directory permissions:") 2775 root:$group_name"
msg_ok "$(translate "Group mapping ensured:") host=$host_gid → ct=$mapped_gid"
msg_ok "$(translate "Multi-approach access configuration completed")"
# ===================================================================
# STEP 5: VERIFICATION
# ===================================================================
msg_info "$(translate "Verifying configuration...")"
if [[ "$container_type" == "unprivileged" ]] && command -v getfacl >/dev/null 2>&1; then
local acl_count=$(getfacl "$host_dir" 2>/dev/null | grep "^user:" | grep -v "^user::" | wc -l)
msg_ok "$(translate "ACL entries configured:") $acl_count"
# Show sample ACL entries
if [[ $acl_count -gt 0 ]]; then
echo -e "${TAB}${BGN}$(translate "ACL entries:")${CL}"
getfacl "$host_dir" 2>/dev/null | grep "^user:" | grep -v "^user::" | head -3 | while read acl_line; do
echo -e "${TAB} ${BL}$acl_line${CL}"
done
fi
fi
local test_users=("www-data" "root" "ncp" "nobody")
local successful_tests=0
for test_user in "${test_users[@]}"; do
if pct exec "$ctid" -- id "$test_user" >/dev/null 2>&1; then
if pct exec "$ctid" -- su -s /bin/bash "$test_user" -c "ls '$4' >/dev/null 2>&1" 2>/dev/null; then
successful_tests=$((successful_tests + 1))
fi
fi
done
if [[ $successful_tests -gt 0 ]]; then
msg_ok "$(translate "Access verification:") $successful_tests $(translate "users can access mount point")"
fi
if [[ "$container_type" == "privileged" ]]; then
msg_ok "$(translate "PRIVILEGED container configuration completed - using direct POSIX permissions")"
else
msg_ok "$(translate "UNPRIVILEGED container configuration completed - using ACL permissions")"
fi
return 0
}
@@ -133,6 +258,10 @@ get_next_mp_index() {
}
add_bind_mount() {
local ctid="$1" host_path="$2" ct_path="$3"
local mpidx result
@@ -147,7 +276,6 @@ add_bind_mount() {
return 1
fi
if pct config "$ctid" | grep -q "$host_path"; then
echo -e
msg_warn "$(translate "Directory already mounted in container configuration.")"
@@ -177,61 +305,6 @@ add_bind_mount() {
select_container_mount_point() {
local ctid="$1"
local host_dir="$2"
local choice mount_point existing_dirs options
while true; do
choice=$(whiptail --title "$(translate "Configure Mount Point inside LXC")" \
--menu "$(translate "Where to mount inside container?")" 18 70 5 \
"1" "$(translate "Create new directory in /mnt")" \
"2" "$(translate "Use existing directory in /mnt")" \
"3" "$(translate "Enter path manually")" \
"4" "$(translate "Cancel")" 3>&1 1>&2 2>&3) || return 1
case "$choice" in
1)
mount_point=$(whiptail --inputbox "$(translate "Enter folder name for /mnt:")" 10 60 "shared" 3>&1 1>&2 2>&3) || continue
[[ -z "$mount_point" ]] && continue
mount_point="/mnt/$mount_point"
pct exec "$ctid" -- mkdir -p "$mount_point" 2>/dev/null
;;
2)
existing_dirs=$(pct exec "$ctid" -- ls -1 /mnt 2>/dev/null | awk '{print "/mnt/"$1" "$1}')
if [[ -z "$existing_dirs" ]]; then
whiptail --msgbox "$(translate "No existing directories found in /mnt")" 8 60
continue
fi
mount_point=$(whiptail --title "$(translate "Select Existing Folder")" \
--menu "$(translate "Choose a folder from /mnt:")" 20 70 10 \
$existing_dirs 3>&1 1>&2 2>&3) || continue
;;
3)
mount_point=$(whiptail --inputbox "$(translate "Enter full path:")" 10 70 "/mnt/shared" 3>&1 1>&2 2>&3) || continue
[[ -z "$mount_point" ]] && continue
pct exec "$ctid" -- mkdir -p "$mount_point" 2>/dev/null
;;
4)
return 1
;;
esac
if pct exec "$ctid" -- test -d "$mount_point" 2>/dev/null; then
echo "$mount_point"
return 0
else
whiptail --msgbox "$(translate "Could not create or access directory:") $mount_point" 8 70
continue
fi
done
}
mount_host_directory_to_lxc() {
# Step 1: Select container
@@ -256,9 +329,7 @@ mount_host_directory_to_lxc() {
return 1
fi
fi
msg_ok "$(translate 'Select LXC container')"
msg_ok "$(translate 'Container selected and running')"
# Step 2: Select host directory
local host_dir
@@ -266,7 +337,7 @@ mount_host_directory_to_lxc() {
if [[ -z "$host_dir" ]]; then
return 1
fi
msg_ok "$(translate 'Select Host directory')"
msg_ok "$(translate 'Host directory selected')"
# Step 3: Setup group
local group_name="sharedfiles"
@@ -280,7 +351,7 @@ mount_host_directory_to_lxc() {
chown -R root:"$group_name" "$host_dir" 2>/dev/null || true
chmod -R 2775 "$host_dir" 2>/dev/null || true
msg_ok "$(translate 'Select container mount point')"
msg_ok "$(translate 'Host group configured')"
# Step 4: Select container mount point
local ct_mount_point
@@ -316,19 +387,9 @@ $(translate "Proceed?")"
return 1
fi
# Step 7: Setup access ======================================================
# Step 7: Setup access (handles both privileged and unprivileged)
setup_container_access "$container_id" "$group_name" "$group_gid" "$host_dir"
# ===========================================================================
# Step 8: Final setup
pct exec "$container_id" -- chgrp "$group_name" "$ct_mount_point" 2>/dev/null || true
pct exec "$container_id" -- chmod 2775 "$ct_mount_point" 2>/dev/null || true
@@ -341,6 +402,11 @@ $(translate "Proceed?")"
echo -e "${TAB}${BGN}$(translate 'Mount Point:')${CL} ${BL}$ct_mount_point${CL}"
echo -e "${TAB}${BGN}$(translate 'Group:')${CL} ${BL}$group_name (GID: $group_gid)${CL}"
if [[ "$uid_shift" -eq 0 ]]; then
echo -e "${TAB}${BGN}$(translate 'Permission Strategy:')${CL} ${BL}POSIX (direct mapping)${CL}"
else
echo -e "${TAB}${BGN}$(translate 'Permission Strategy:')${CL} ${BL}ACL (mapped UIDs)${CL}"
fi
echo -e ""
if whiptail --yesno "$(translate "Restart container to activate mount?")" 8 60; then
@@ -370,9 +436,7 @@ $(translate "Proceed?")"
read -r
}
# ==========================================================
# Main menu
main_menu() {
while true; do
choice=$(dialog --title "$(translate 'LXC Mount Manager')" \
@@ -401,6 +465,4 @@ main_menu() {
done
}
main_menu