mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-04-23 12:10:38 +00:00
248 lines
8.8 KiB
Bash
248 lines
8.8 KiB
Bash
#!/bin/bash
|
|
# ==========================================================
|
|
# ProxMenux - Local Shared Directory Manager
|
|
# ==========================================================
|
|
# Author : MacRimi
|
|
# Copyright : (c) 2024 MacRimi
|
|
# License : MIT
|
|
# Version : 1.0
|
|
# Last Updated: 08/04/2026
|
|
# ==========================================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
LOCAL_SCRIPTS_LOCAL="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
LOCAL_SCRIPTS_DEFAULT="/usr/local/share/proxmenux/scripts"
|
|
LOCAL_SCRIPTS="$LOCAL_SCRIPTS_DEFAULT"
|
|
BASE_DIR="/usr/local/share/proxmenux"
|
|
UTILS_FILE="$LOCAL_SCRIPTS/utils.sh"
|
|
|
|
if [[ -f "$LOCAL_SCRIPTS_LOCAL/utils.sh" ]]; then
|
|
LOCAL_SCRIPTS="$LOCAL_SCRIPTS_LOCAL"
|
|
UTILS_FILE="$LOCAL_SCRIPTS/utils.sh"
|
|
elif [[ ! -f "$UTILS_FILE" ]]; then
|
|
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
fi
|
|
|
|
if [[ -f "$UTILS_FILE" ]]; then
|
|
source "$UTILS_FILE"
|
|
fi
|
|
|
|
SHARE_COMMON_FILE="$LOCAL_SCRIPTS/global/share-common.func"
|
|
if ! source "$SHARE_COMMON_FILE" 2>/dev/null; then
|
|
msg_error "$(translate "Could not load shared functions. Script cannot continue.")"
|
|
exit 1
|
|
fi
|
|
|
|
load_language
|
|
initialize_cache
|
|
|
|
if ! command -v pveversion >/dev/null 2>&1; then
|
|
dialog --backtitle "ProxMenux" --title "$(translate "Error")" \
|
|
--msgbox "$(translate "This script must be run on a Proxmox host.")" 8 60
|
|
exit 1
|
|
fi
|
|
|
|
# ==========================================================
|
|
|
|
|
|
|
|
|
|
lsm_apply_multi_unpriv_permissions() {
|
|
local dir="$1"
|
|
|
|
[[ -z "$dir" || ! -d "$dir" ]] && return 1
|
|
|
|
# root:root ownership — no new group needed.
|
|
chown root:root "$dir" 2>/dev/null || true
|
|
|
|
# 1777 = sticky bit (prevents cross-container file deletion) + world-rwx.
|
|
# Unprivileged LXC UIDs (100000+) appear as 'others' on the host,
|
|
# so 'o+rwx' is what grants them read+write access.
|
|
chmod 1777 "$dir" 2>/dev/null || true
|
|
|
|
# Ensure existing content is readable/writable regardless of UID mapping.
|
|
chmod -R a+rwX "$dir" 2>/dev/null || true
|
|
find "$dir" -type d -exec chmod 1777 {} + 2>/dev/null || true
|
|
|
|
if command -v setfacl >/dev/null 2>&1; then
|
|
# Remove restrictive ACLs and enforce permissive inheritance for new files.
|
|
setfacl -b -R "$dir" 2>/dev/null || true
|
|
setfacl -R -m u::rwx,g::rwx,o::rwx,m::rwx "$dir" 2>/dev/null || true
|
|
setfacl -R -m d:u::rwx,d:g::rwx,d:o::rwx,d:m::rwx "$dir" 2>/dev/null || true
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Returns a free name like /mnt/shared, /mnt/shared2, /mnt/shared3 …
|
|
lsm_next_free_name() {
|
|
local base="${1:-shared}"
|
|
local candidate="/mnt/$base"
|
|
[[ ! -d "$candidate" ]] && echo "$candidate" && return
|
|
local n=2
|
|
while [[ -d "/mnt/${base}${n}" ]]; do
|
|
((n++))
|
|
done
|
|
echo "/mnt/${base}${n}"
|
|
}
|
|
|
|
lsm_list_mnt_folders() {
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Folders in /mnt")"
|
|
|
|
echo "=================================================="
|
|
|
|
if [[ ! -d /mnt ]] || [[ -z "$(ls -A /mnt 2>/dev/null)" ]]; then
|
|
echo ""
|
|
echo -e "${TAB}$(translate "No folders found in /mnt.")"
|
|
else
|
|
local found=false
|
|
while IFS= read -r dir; do
|
|
[[ ! -d "$dir" ]] && continue
|
|
found=true
|
|
local perms owner
|
|
perms=$(stat -c "%a" "$dir" 2>/dev/null)
|
|
owner=$(stat -c "%U:%G" "$dir" 2>/dev/null)
|
|
echo ""
|
|
echo -e "${TAB}${BGN}$(translate "Directory:")${CL} ${BL}$dir${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Permissions:")${CL} ${BL}${perms} $(stat -c "(%A)" "$dir" 2>/dev/null)${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Owner:")${CL} ${BL}${owner}${CL}"
|
|
done < <(find /mnt -mindepth 1 -maxdepth 1 -type d | sort)
|
|
|
|
if [[ "$found" = false ]]; then
|
|
echo ""
|
|
echo -e "${TAB}$(translate "No folders found in /mnt.")"
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
echo "=================================================="
|
|
echo ""
|
|
|
|
# Summary of /mnt available space
|
|
if mountpoint -q /mnt 2>/dev/null || [[ -d /mnt ]]; then
|
|
local mnt_avail mnt_total
|
|
mnt_avail=$(df -h /mnt 2>/dev/null | awk 'NR==2{print $4}')
|
|
mnt_total=$(df -h /mnt 2>/dev/null | awk 'NR==2{print $2}')
|
|
if [[ -n "$mnt_avail" ]]; then
|
|
echo -e "${TAB}${BGN}$(translate "Available space in /mnt:")${CL} ${BL}${mnt_avail} $(translate "of") ${mnt_total}${CL}"
|
|
echo ""
|
|
fi
|
|
fi
|
|
|
|
msg_success "$(translate "Press Enter to return to menu...")"
|
|
read -r
|
|
}
|
|
|
|
# Result is stored in LSM_SELECTED_MOUNT_POINT (not echoed) to avoid subshell issues
|
|
LSM_SELECTED_MOUNT_POINT=""
|
|
|
|
lsm_select_host_mount_point_dialog() {
|
|
local title="${1:-$(translate "Select Shared Directory Location")}"
|
|
local base_name="${2:-shared}"
|
|
local choice folder_name result mount_point
|
|
LSM_SELECTED_MOUNT_POINT=""
|
|
|
|
# Auto-suggest a free name in /mnt
|
|
local suggested
|
|
suggested=$(lsm_next_free_name "$base_name")
|
|
|
|
while true; do
|
|
choice=$(dialog --backtitle "ProxMenux" \
|
|
--title "$title" \
|
|
--menu "\n$(translate "Where do you want the host folder?")" 16 72 4 \
|
|
"1" "$(translate "Create new folder in /mnt")" \
|
|
"2" "$(translate "Enter custom path")" \
|
|
"3" "$(translate "View existing folders in /mnt")" \
|
|
"4" "$(translate "Cancel")" \
|
|
3>&1 1>&2 2>&3) || return 1
|
|
|
|
case "$choice" in
|
|
1)
|
|
folder_name=$(dialog --backtitle "ProxMenux" \
|
|
--title "$(translate "Folder Name")" \
|
|
--inputbox "\n$(translate "Enter folder name for /mnt:")" 10 70 "$(basename "$suggested")" \
|
|
3>&1 1>&2 2>&3) || continue
|
|
[[ -z "$folder_name" ]] && continue
|
|
mount_point="/mnt/$folder_name"
|
|
# Only warn if the user manually typed an existing name
|
|
if [[ -d "$mount_point" ]]; then
|
|
if ! dialog --backtitle "ProxMenux" --title "$(translate "Directory Exists")" \
|
|
--yesno "\n$(translate "Directory already exists. Continue with permission setup?")" 8 70; then
|
|
continue
|
|
fi
|
|
fi
|
|
;;
|
|
2)
|
|
result=$(dialog --backtitle "ProxMenux" \
|
|
--title "$(translate "Custom Path")" \
|
|
--inputbox "\n$(translate "Enter full path:")" 10 80 "" \
|
|
3>&1 1>&2 2>&3) || continue
|
|
[[ -z "$result" ]] && continue
|
|
mount_point="$result"
|
|
if [[ -d "$mount_point" ]]; then
|
|
if ! dialog --backtitle "ProxMenux" --title "$(translate "Directory Exists")" \
|
|
--yesno "\n$(translate "Directory already exists. Continue with permission setup?")" 8 70; then
|
|
continue
|
|
fi
|
|
fi
|
|
;;
|
|
3)
|
|
lsm_list_mnt_folders
|
|
# Refresh suggestion after viewing
|
|
suggested=$(lsm_next_free_name "$base_name")
|
|
continue
|
|
;;
|
|
4) return 1 ;;
|
|
*) continue ;;
|
|
esac
|
|
|
|
if [[ ! "$mount_point" =~ ^/ ]]; then
|
|
dialog --backtitle "ProxMenux" --title "$(translate "Invalid Path")" \
|
|
--msgbox "\n$(translate "Path must be absolute (start with /).")" 8 60
|
|
continue
|
|
fi
|
|
|
|
LSM_SELECTED_MOUNT_POINT="$mount_point"
|
|
return 0
|
|
done
|
|
}
|
|
|
|
create_shared_directory() {
|
|
lsm_select_host_mount_point_dialog "$(translate "Select Shared Directory Location")" "shared"
|
|
[[ -z "$LSM_SELECTED_MOUNT_POINT" ]] && return
|
|
SHARED_DIR="$LSM_SELECTED_MOUNT_POINT"
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Create Shared Directory")"
|
|
|
|
if ! mkdir -p "$SHARED_DIR" 2>/dev/null; then
|
|
msg_error "$(translate "Failed to create directory:") $SHARED_DIR"
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
return 1
|
|
fi
|
|
msg_ok "$(translate "Directory created:") $SHARED_DIR"
|
|
|
|
lsm_apply_multi_unpriv_permissions "$SHARED_DIR"
|
|
|
|
pmx_share_map_set "$SHARED_DIR" "open"
|
|
|
|
echo -e ""
|
|
echo -e "${TAB}${BOLD}$(translate "Shared Directory Ready:")${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Directory:")${CL} ${BL}$SHARED_DIR${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Permissions:")${CL} ${BL}1777 (rwxrwxrwt)${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Owner:")${CL} ${BL}root:root${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Access profile:")${CL} ${BL}$(translate "Compatible with privileged and unprivileged LXC containers")${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "ACL Status:")${CL} ${BL}$(translate "Open rwx + default inheritance for new files")${CL}"
|
|
echo -e ""
|
|
msg_success "$(translate "Press Enter to return to menu...")"
|
|
read -r
|
|
}
|
|
|
|
|
|
|
|
|
|
create_shared_directory
|