2025-08-26 13:26:22 +02:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
# ==========================================================
|
|
|
|
# ProxMenux - Global Share Functions (reusable)
|
|
|
|
# File: scripts/global/share_common.func
|
|
|
|
# ==========================================================
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
if [[ -n "${__PROXMENUX_SHARE_COMMON__}" ]]; then
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
__PROXMENUX_SHARE_COMMON__=1
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
: "${PROXMENUX_DEFAULT_SHARE_GROUP:=sharedfiles}"
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
: "${PROXMENUX_SHARE_MAP_DB:=/usr/local/share/proxmenux/share-map.db}"
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
mkdir -p "$(dirname "$PROXMENUX_SHARE_MAP_DB")" 2>/dev/null || true
|
|
|
|
touch "$PROXMENUX_SHARE_MAP_DB" 2>/dev/null || true
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
pmx_share_map_get() {
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
local key="$1"
|
|
|
|
awk -F'=' -v k="$key" '$1==k {print $2}' "$PROXMENUX_SHARE_MAP_DB" 2>/dev/null | tail -n1
|
|
|
|
}
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
pmx_share_map_set() {
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
local key="$1" val="$2"
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
sed -i "\|^${key}=|d" "$PROXMENUX_SHARE_MAP_DB" 2>/dev/null || true
|
|
|
|
echo "${key}=${val}" >> "$PROXMENUX_SHARE_MAP_DB"
|
|
|
|
}
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
pmx_choose_or_create_group() {
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
local default_group="${1:-$PROXMENUX_DEFAULT_SHARE_GROUP}"
|
|
|
|
local choice group_name
|
2025-08-30 11:36:52 +02:00
|
|
|
choice=$(whiptail --title "$(translate "Shared Group")" --menu "$(translate "Choose a group policy for this shared directory:")" 18 78 6 \
|
|
|
|
"1" "$(translate "Use sharefiles group default (recommended)")" \
|
|
|
|
"2" "$(translate "Create a new group for isolation")" \
|
|
|
|
"3" "$(translate "Select an existing group")" \
|
|
|
|
3>&1 1>&2 2>&3) || { echo ""; return 1; }
|
2025-08-26 13:26:22 +02:00
|
|
|
|
|
|
|
case "$choice" in
|
2025-08-30 11:36:52 +02:00
|
|
|
1)
|
|
|
|
|
2025-08-26 13:56:00 +02:00
|
|
|
pmx_ensure_host_group "$default_group" >/dev/null || return 1
|
2025-08-26 13:26:22 +02:00
|
|
|
echo "$default_group"
|
|
|
|
;;
|
2025-08-30 11:36:52 +02:00
|
|
|
2)
|
2025-08-26 13:26:22 +02:00
|
|
|
group_name=$(whiptail --inputbox "$(translate "Enter new group name:")" 10 70 "sharedfiles-project" --title "$(translate "New Group")" 3>&1 1>&2 2>&3) || { echo ""; return 1; }
|
|
|
|
[[ -z "$group_name" ]] && { msg_error "$(translate "Group name cannot be empty.")"; echo ""; return 1; }
|
2025-08-26 13:56:00 +02:00
|
|
|
pmx_ensure_host_group "$group_name" >/dev/null || return 1
|
2025-08-26 13:26:22 +02:00
|
|
|
echo "$group_name"
|
|
|
|
;;
|
2025-08-30 11:36:52 +02:00
|
|
|
3)
|
|
|
|
|
|
|
|
groups=$(getent group | awk -F: '$3 >= 1000 && $1 != "nogroup" && $1 !~ /^pve/ {print $1 ":" $3}')
|
|
|
|
if [[ -z "$groups" ]]; then
|
|
|
|
whiptail --title "$(translate "Groups")" --msgbox "$(translate "No user groups found.")" 8 60
|
|
|
|
echo ""; return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
menu_args=()
|
|
|
|
while IFS=: read -r gname gid; do
|
|
|
|
menu_args+=("$gname" "GID=$gid")
|
|
|
|
done <<< "$groups"
|
|
|
|
|
|
|
|
group_name=$(whiptail --title "$(translate "Existing Groups")" --menu "$(translate "Select an existing group:")" 20 70 12 \
|
|
|
|
"${menu_args[@]}" \
|
|
|
|
3>&1 1>&2 2>&3) || { echo ""; return 1; }
|
|
|
|
|
2025-08-26 13:56:00 +02:00
|
|
|
pmx_ensure_host_group "$group_name" >/dev/null || return 1
|
2025-08-26 13:26:22 +02:00
|
|
|
echo "$group_name"
|
|
|
|
;;
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
*) echo ""; return 1;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
pmx_ensure_host_group() {
|
2025-08-27 18:15:26 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
local group_name="$1"
|
2025-08-27 18:15:26 +02:00
|
|
|
local suggested_gid="$2"
|
|
|
|
|
2025-08-26 13:56:00 +02:00
|
|
|
if ! getent group "$group_name" >/dev/null 2>&1; then
|
2025-08-27 18:15:26 +02:00
|
|
|
if [[ -n "$suggested_gid" ]]; then
|
|
|
|
|
|
|
|
if getent group "$suggested_gid" >/dev/null 2>&1; then
|
|
|
|
msg_error "$(translate "GID already in use:") $suggested_gid"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
groupadd -g "$suggested_gid" "$group_name" >/dev/null 2>&1
|
|
|
|
else
|
|
|
|
groupadd "$group_name" >/dev/null 2>&1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [[ $? -eq 0 ]]; then
|
2025-08-26 13:26:22 +02:00
|
|
|
msg_ok "$(translate "Group created:") $group_name"
|
|
|
|
else
|
|
|
|
msg_error "$(translate "Failed to create group:") $group_name"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
fi
|
2025-08-27 18:15:26 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
local gid
|
|
|
|
gid="$(getent group "$group_name" | cut -d: -f3)"
|
|
|
|
if [[ -z "$gid" ]]; then
|
|
|
|
msg_error "$(translate "Failed to resolve group GID for") $group_name"
|
|
|
|
return 1
|
|
|
|
fi
|
2025-08-27 18:15:26 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
echo "$gid"
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
pmx_prepare_host_shared_dir() {
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
local dir="$1" group_name="$2"
|
|
|
|
[[ -z "$dir" || -z "$group_name" ]] && { msg_error "$(translate "Internal error: missing arguments in pmx_prepare_host_shared_dir")"; return 1; }
|
|
|
|
|
|
|
|
if [[ ! -d "$dir" ]]; then
|
|
|
|
if mkdir -p "$dir" 2>/dev/null; then
|
|
|
|
msg_ok "$(translate "Created directory on host:") $dir"
|
|
|
|
else
|
|
|
|
msg_error "$(translate "Failed to create directory on host:") $dir"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
chown -R root:"$group_name" "$dir" 2>/dev/null || true
|
|
|
|
chmod -R 2775 "$dir" 2>/dev/null || true
|
|
|
|
|
|
|
|
if command -v setfacl >/dev/null 2>&1; then
|
|
|
|
setfacl -R -m d:g:"$group_name":rwx -m d:o::rx -m g:"$group_name":rwx "$dir" 2>/dev/null || true
|
|
|
|
msg_ok "$(translate "Default ACLs applied for group inheritance.")"
|
|
|
|
else
|
|
|
|
msg_warn "$(translate "setfacl not found; default ACLs were not applied.")"
|
|
|
|
fi
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
pmx_select_host_mount_point() {
|
2025-08-30 11:36:52 +02:00
|
|
|
|
2025-08-26 13:26:22 +02:00
|
|
|
local title="${1:-$(translate "Select Mount Point")}"
|
|
|
|
local default_path="${2:-/mnt/shared}"
|
|
|
|
local choice folder_name result
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
choice=$(whiptail --title "$title" --menu "$(translate "Where do you want the host folder?")" 16 76 4 \
|
|
|
|
"mnt" "$(translate "Create folder in /mnt")" \
|
|
|
|
"srv" "$(translate "Create folder in /srv")" \
|
|
|
|
"media" "$(translate "Create folder in /media")" \
|
|
|
|
"custom" "$(translate "Enter custom path")" 3>&1 1>&2 2>&3) || { echo ""; return 1; }
|
|
|
|
|
|
|
|
case "$choice" in
|
|
|
|
mnt)
|
|
|
|
folder_name=$(whiptail --inputbox "$(translate "Enter folder name for /mnt:")" 10 70 "shared" --title "$(translate "Folder Name")" 3>&1 1>&2 2>&3) || { echo ""; return 1; }
|
|
|
|
[[ -z "$folder_name" ]] && continue
|
|
|
|
echo "/mnt/$folder_name"; return 0;;
|
|
|
|
srv)
|
|
|
|
folder_name=$(whiptail --inputbox "$(translate "Enter folder name for /srv:")" 10 70 "shared" --title "$(translate "Folder Name")" 3>&1 1>&2 2>&3) || { echo ""; return 1; }
|
|
|
|
[[ -z "$folder_name" ]] && continue
|
|
|
|
echo "/srv/$folder_name"; return 0;;
|
|
|
|
media)
|
|
|
|
folder_name=$(whiptail --inputbox "$(translate "Enter folder name for /media:")" 10 70 "shared" --title "$(translate "Folder Name")" 3>&1 1>&2 2>&3) || { echo ""; return 1; }
|
|
|
|
[[ -z "$folder_name" ]] && continue
|
|
|
|
echo "/media/$folder_name"; return 0;;
|
|
|
|
custom)
|
|
|
|
result=$(whiptail --inputbox "$(translate "Enter full path:")" 10 80 "$default_path" --title "$(translate "Custom Path")" 3>&1 1>&2 2>&3) || { echo ""; return 1; }
|
|
|
|
[[ -z "$result" ]] && continue
|
|
|
|
echo "$result"; return 0;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
select_host_directory() {
|
|
|
|
local method choice result
|
|
|
|
|
|
|
|
method=$(whiptail --title "$(translate "Select Host Directory")" --menu "$(translate "How do you want to select the host folder to mount?")" 15 70 4 \
|
|
|
|
"mnt" "$(translate "Select from /mnt directories")" \
|
|
|
|
"srv" "$(translate "Select from /srv directories")" \
|
|
|
|
"media" "$(translate "Select from /media directories")" \
|
|
|
|
"manual" "$(translate "Enter path manually")" 3>&1 1>&2 2>&3) || return 1
|
|
|
|
|
|
|
|
case "$method" in
|
|
|
|
mnt|srv|media)
|
|
|
|
local base_path="/$method"
|
|
|
|
local host_dirs=("$base_path"/*)
|
|
|
|
local options=()
|
|
|
|
|
|
|
|
for dir in "${host_dirs[@]}"; do
|
|
|
|
if [[ -d "$dir" ]]; then
|
|
|
|
options+=("$dir" "$(basename "$dir")")
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
if [[ ${#options[@]} -eq 0 ]]; then
|
|
|
|
msg_error "$(translate "No directories found in") $base_path"
|
|
|
|
return 1
|
2025-08-26 13:26:22 +02:00
|
|
|
fi
|
2025-08-30 11:36:52 +02:00
|
|
|
|
|
|
|
result=$(whiptail --title "$(translate "Select Host Folder")" \
|
|
|
|
--menu "$(translate "Select the folder to mount:")" 20 80 10 "${options[@]}" 3>&1 1>&2 2>&3)
|
|
|
|
;;
|
|
|
|
manual)
|
|
|
|
result=$(whiptail --title "$(translate "Enter Path")" \
|
|
|
|
--inputbox "$(translate "Enter the full path to the host folder:")" 10 70 "/mnt/" 3>&1 1>&2 2>&3)
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
if [[ -z "$result" ]]; then
|
|
|
|
return 1
|
2025-08-26 13:26:22 +02:00
|
|
|
fi
|
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
if [[ ! -d "$result" ]]; then
|
|
|
|
msg_error "$(translate "The selected path is not a valid directory:") $result"
|
|
|
|
return 1
|
|
|
|
fi
|
2025-08-26 13:26:22 +02:00
|
|
|
|
2025-08-30 11:36:52 +02:00
|
|
|
echo "$result"
|
2025-08-30 11:43:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
select_lxc_container() {
|
|
|
|
local ct_list ctid ct_status
|
|
|
|
|
|
|
|
ct_list=$(pct list | awk 'NR>1 {print $1, $2, $3}')
|
|
|
|
if [[ -z "$ct_list" ]]; then
|
|
|
|
dialog --title "$(translate "Error")" \
|
|
|
|
--msgbox "$(translate "No LXC containers available")" 8 50
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
local options=()
|
|
|
|
while read -r id name status; do
|
|
|
|
if [[ -n "$id" ]]; then
|
|
|
|
options+=("$id" "$name ($status)")
|
|
|
|
fi
|
|
|
|
done <<< "$ct_list"
|
|
|
|
|
|
|
|
ctid=$(dialog --title "$(translate "Select LXC Container")" \
|
|
|
|
--menu "$(translate "Select container:")" 20 70 12 \
|
|
|
|
"${options[@]}" 3>&1 1>&2 2>&3)
|
|
|
|
|
|
|
|
if [[ -z "$ctid" ]]; then
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "$ctid"
|
|
|
|
return 0
|
2025-08-30 11:36:52 +02:00
|
|
|
}
|