Files
ProxMenux/scripts/share/nfs_lxc_server.sh
T
MacRimi 085cbf7e68 scope the change journal to host changes, in three sections
The change journal exists so a sysadmin sees what ProxMenux changed on the host — its own configuration, packages and services — not how it uses the host or configures a guest. Several scripts recorded operations that are neither: disk passthrough to a VM, container conversions, VM import/export, mounting a share into an LXC. Those are restored to their original, uninstrumented form. Scripts that operate on the host while also installing a package now record only the package: format-disk keeps its exFAT-tools install, the UUP ISO builder its build dependencies, and the share/host scripts their packages, services and /etc/fstab writes, while the mount and unmount operations they used to log are dropped.

The page now reads in three sections: what ProxMenux optimized after install (each function under its menu name), what its other host scripts changed (by script), and what it installed (packages and utilities, each referencing the script that installed it). A file reads as created or modified with its diff, a service shows its state transition, and the undo line appears only when a revert is possible.
2026-09-10 15:20:39 +02:00

600 lines
24 KiB
Bash

#!/bin/bash
# ==========================================================
# ProxMenux - NFS Server Manager for LXC
# ==========================================================
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
# License : GPL-3.0
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
# Version : 1.0
# ==========================================================
# Description:
# Manages NFS exports from inside a Proxmox LXC container.
# Requires a privileged container (the kernel NFS server module
# needs capabilities that unprivileged CTs do not expose).
#
# Features:
# - Install and configure nfs-kernel-server inside the CT.
# - Create NFS exports for folders under /mnt.
# - Set up a universal "sharedfiles" group (GID 101000) on the
# CT as a convention for cross-CT file sharing.
# - List configured exports and check service status.
# - Remove exports cleanly.
# ==========================================================
# Configuration
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
# Load shared functions
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
select_privileged_lxc
setup_universal_sharedfiles_group() {
local ctid="$1"
msg_info "$(translate "Setting sharedfiles group with UID remapping...")"
if ! pct exec "$ctid" -- getent group sharedfiles >/dev/null 2>&1; then
pct exec "$ctid" -- groupadd -g 101000 sharedfiles
msg_ok "$(translate "Created sharedfiles group (GID: 101000)")"
else
local current_gid=$(pct exec "$ctid" -- getent group sharedfiles | cut -d: -f3)
if [[ "$current_gid" != "101000" ]]; then
pct exec "$ctid" -- groupmod -g 101000 sharedfiles
msg_ok "$(translate "Updated sharedfiles group to GID: 101000")"
else
msg_ok "$(translate "Sharedfiles group already exists (GID: 101000)")"
fi
fi
local lxc_users=$(pct exec "$ctid" -- awk -F: '$3 >= 1000 && $3 < 65534 {print $1 ":" $3}' /etc/passwd)
if [[ -n "$lxc_users" ]]; then
msg_info "$(translate "Adding existing users to sharedfiles group...")"
while IFS=: read -r username uid; do
if [[ -n "$username" ]]; then
pct exec "$ctid" -- usermod -a -G sharedfiles "$username" 2>/dev/null || true
msg_ok "$(translate "Added user") $username (UID: $uid) $(translate "to sharedfiles group")"
fi
done <<< "$lxc_users"
fi
# `+ 100000` UID-shift only makes sense in unprivileged containers
# (UID 0 in CT == UID 100000 on host). `select_privileged_lxc` already
# gated the flow to privileged CTs above, so the shift is meaningless
# here and creates phantom `remap_NNNN` accounts that don't map to
# any real UID. Skip the loop in privileged context. Audit Tier 6 —
# UID-shift remapping en CTs privilegiados donde no aplica.
local _is_unpriv=0
if pct config "$ctid" 2>/dev/null | grep -qE '^unprivileged:\s*1'; then
_is_unpriv=1
fi
local remapped_count=0
if (( _is_unpriv == 1 )); then
msg_info "$(translate "Creating UID remapping for unprivileged container compatibility...")"
if [[ -n "$lxc_users" ]]; then
while IFS=: read -r username uid; do
if [[ -n "$uid" ]]; then
local remapped_uid=$((uid + 100000))
local remapped_username="remap_${uid}"
if ! pct exec "$ctid" -- id "$remapped_username" >/dev/null 2>&1; then
pct exec "$ctid" -- useradd -u "$remapped_uid" -g sharedfiles -s /bin/false -M "$remapped_username" 2>/dev/null || true
msg_ok "$(translate "Created remapped user") $remapped_username (UID: $remapped_uid)"
((remapped_count++))
else
pct exec "$ctid" -- usermod -g sharedfiles "$remapped_username" 2>/dev/null || true
fi
fi
done <<< "$lxc_users"
fi
local common_uids=(33 1000 1001 1002)
for base_uid in "${common_uids[@]}"; do
local remapped_uid=$((base_uid + 100000))
local remapped_username="remap_${base_uid}"
if ! pct exec "$ctid" -- id "$remapped_username" >/dev/null 2>&1; then
pct exec "$ctid" -- useradd -u "$remapped_uid" -g sharedfiles -s /bin/false -M "$remapped_username" 2>/dev/null || true
msg_ok "$(translate "Created common remapped user") $remapped_username (UID: $remapped_uid)"
((remapped_count++))
fi
done
msg_ok "$(translate "Universal sharedfiles group configured with") $remapped_count $(translate "remapped users")"
else
msg_ok "$(translate "Privileged container — UID-shift remapping skipped (not applicable)")"
fi
}
select_mount_point() {
while true; do
METHOD=$(whiptail --backtitle "ProxMenux" --title "$(translate "Select Folder")" \
--menu "$(translate "How do you want to select the folder to export?")" 15 60 5 \
"auto" "$(translate "Select from folders inside /mnt")" \
"manual" "$(translate "Enter path manually")" \
3>&1 1>&2 2>&3)
if [[ $? -ne 0 ]]; then
return 1
fi
case "$METHOD" in
auto)
DIRS=$(pct exec "$CTID" -- find /mnt -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
if [[ -z "$DIRS" ]]; then
whiptail --title "$(translate "No Folders")" --msgbox "$(translate "No folders found inside /mnt in the CT.")" 8 60
continue
fi
OPTIONS=()
while IFS= read -r dir; do
name=$(basename "$dir")
OPTIONS+=("$dir" "$name")
done <<< "$DIRS"
MOUNT_POINT=$(whiptail --backtitle "ProxMenux" --title "$(translate "Select Folder")" \
--menu "$(translate "Choose a folder to export:")" 20 60 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
if [[ $? -ne 0 ]]; then
return 1
fi
[[ -n "$MOUNT_POINT" ]] && return 0
;;
manual)
CT_NAME=$(pct config "$CTID" | awk -F: '/hostname/ {print $2}' | xargs)
DEFAULT_MOUNT_POINT="/mnt/${CT_NAME}_nfs"
MOUNT_POINT=$(whiptail --title "$(translate "Mount Point")" \
--inputbox "$(translate "Enter the mount point for the NFS export (e.g., /mnt/mynfs):")" \
10 70 "$DEFAULT_MOUNT_POINT" 3>&1 1>&2 2>&3)
if [[ $? -ne 0 ]]; then
return 1
fi
if [[ -z "$MOUNT_POINT" ]]; then
whiptail --title "$(translate "Error")" \
--msgbox "$(translate "No mount point was specified.")" 8 50
continue
fi
pct exec "$CTID" -- mkdir -p "$MOUNT_POINT" 2>/dev/null
return 0
;;
esac
done
}
get_network_config() {
NETWORK=$(whiptail --backtitle "ProxMenux" --title "$(translate "Network Configuration")" --menu "\n$(translate "Select network access level:")" 15 70 4 \
"1" "$(translate "Local network only (192.168.0.0/16)")" \
"2" "$(translate "Specific subnet (enter manually)")" \
"3" "$(translate "Specific host (enter IP)")" 3>&1 1>&2 2>&3)
case "$NETWORK" in
1)
NETWORK_RANGE="192.168.0.0/16"
;;
2)
clear
NETWORK_RANGE=$(whiptail --inputbox "$(translate "Enter subnet (e.g., 192.168.0.0/24):")" 10 60 "192.168.0.0/24" --title "$(translate "Subnet")" 3>&1 1>&2 2>&3)
[[ -z "$NETWORK_RANGE" ]] && return 1
;;
3)
dialog
NETWORK_RANGE=$(whiptail --inputbox "$(translate "Enter host IP (e.g., 192.168.0.100):")" 10 60 --title "$(translate "Host IP")" 3>&1 1>&2 2>&3)
[[ -z "$NETWORK_RANGE" ]] && return 1
;;
*)
return 1
;;
esac
return 0
}
select_export_options() {
EXPORT_OPTIONS=$(whiptail --title "$(translate "Export Options")" --menu \
"\n$(translate "Select export permissions:")" 15 70 3 \
"1" "$(translate "Read-Write (universal)")" \
"2" "$(translate "Read-Only")" \
"3" "$(translate "Custom options")" 3>&1 1>&2 2>&3)
case "$EXPORT_OPTIONS" in
1)
OPTIONS="rw,sync,no_subtree_check,no_root_squash"
;;
2)
OPTIONS="ro,sync,no_subtree_check,no_root_squash"
;;
3)
OPTIONS=$(whiptail --inputbox "$(translate "Enter custom NFS options:")" \
10 70 "rw,sync,no_subtree_check,no_root_squash" \
--title "$(translate "Custom Options")" 3>&1 1>&2 2>&3)
[[ -z "$OPTIONS" ]] && OPTIONS="rw,sync,no_subtree_check,no_root_squash"
;;
*)
OPTIONS="rw,sync,no_subtree_check,no_root_squash"
;;
esac
}
create_nfs_export() {
show_proxmenux_logo
msg_title "$(translate "Create LXC server NFS")"
sleep 2
select_mount_point || return
get_network_config || return
select_export_options || return
msg_ok "$(translate "Directory successfully.")"
if ! pct exec "$CTID" -- dpkg -s nfs-kernel-server &>/dev/null; then
msg_info "$(translate "Installing NFS server packages inside the CT...")"
pct exec "$CTID" -- bash -c "apt-get update && apt-get install -y nfs-kernel-server nfs-common rpcbind"
pct exec "$CTID" -- systemctl enable --now rpcbind nfs-kernel-server
msg_ok "$(translate "NFS server installed successfully.")"
else
msg_ok "$(translate "NFS server is already installed.")"
fi
setup_universal_sharedfiles_group "$CTID"
msg_info "$(translate "Setting directory ownership and permissions...")"
# Hand off ownership/perm setup to the shared helper. It detects the
# underlying filesystem (ext4/xfs/zfs/exfat/ntfs-fuse/…), picks the
# right strategy (chown+chmod, ACLs, or just inform the user when
# the FS can't carry POSIX permissions), and verifies the result
# with `runuser`. Empty username — NFS doesn't authenticate per-user
# the way Samba does; the `sharedfiles` group is all we need.
pmx_setup_share_permissions "$CTID" "$MOUNT_POINT" ""
EXPORT_LINE="$MOUNT_POINT $NETWORK_RANGE($OPTIONS)"
if pct exec "$CTID" -- grep -q "^$MOUNT_POINT " /etc/exports; then
if dialog --yesno "$(translate "Do you want to update the existing export?")" \
10 60 --title "$(translate "Update Export")"; then
pct exec "$CTID" -- sed -i "\|^$MOUNT_POINT |d" /etc/exports
pct exec "$CTID" -- bash -c "echo '$EXPORT_LINE' >> /etc/exports"
show_proxmenux_logo
msg_title "$(translate "Create LXC server NFS")"
msg_ok "$(translate "Directory successfully.")"
msg_ok "$(translate "Export updated successfully.")"
msg_ok "$(translate "NFS server is already installed.")"
msg_ok "$(translate "Directory configured with sharedfiles group ownership")"
fi
else
pct exec "$CTID" -- bash -c "echo '$EXPORT_LINE' >> /etc/exports"
msg_ok "$(translate "Export added successfully.")"
fi
pct exec "$CTID" -- systemctl restart rpcbind nfs-kernel-server
pct exec "$CTID" -- exportfs -ra
CT_IP=$(pct exec "$CTID" -- hostname -I | awk '{print $1}')
echo -e ""
msg_ok "$(translate "NFS export created successfully!")"
echo -e ""
echo -e "${TAB}${BOLD}$(translate "Connection details:")${CL}"
echo -e "${TAB}${BGN}$(translate "Server IP:")${CL} ${BL}$CT_IP${CL}"
echo -e "${TAB}${BGN}$(translate "Export path:")${CL} ${BL}$MOUNT_POINT${CL}"
echo -e "${TAB}${BGN}$(translate "Mount options:")${CL} ${BL}$OPTIONS${CL}"
echo -e "${TAB}${BGN}$(translate "Network access:")${CL} ${BL}$NETWORK_RANGE${CL}"
echo -e "${TAB}${BGN}$(translate "NFS Version:")${CL} ${BL}Auto-negotiation (NFSv3/NFSv4)${CL}"
echo -e ""
echo -e "${TAB}${BOLD}$(translate "Mount Examples:")${CL}"
echo -e "${TAB}${BGN}$(translate "Auto-negotiate:")${CL} ${BL}mount -t nfs $CT_IP:$MOUNT_POINT /mnt/nfs${CL}"
echo -e "${TAB}${BGN}$(translate "Force NFSv4:")${CL} ${BL}mount -t nfs4 $CT_IP:$MOUNT_POINT /mnt/nfs${CL}"
echo -e "${TAB}${BGN}$(translate "Force NFSv3:")${CL} ${BL}mount -t nfs -o vers=3 $CT_IP:$MOUNT_POINT /mnt/nfs${CL}"
echo ""
msg_success "$(translate "Press Enter to return to menu...")"
read -r
}
view_exports() {
show_proxmenux_logo
msg_title "$(translate "View Current Exports")"
echo -e "$(translate "Current NFS exports in CT") $CTID:"
echo "=================================="
if pct exec "$CTID" -- test -f /etc/exports; then
EXPORTS=$(pct exec "$CTID" -- cat /etc/exports | grep -v '^#' | grep -v '^$')
if [[ -n "$EXPORTS" ]]; then
echo "$EXPORTS"
echo ""
echo "$(translate "Active exports:")"
pct exec "$CTID" -- showmount -e localhost 2>/dev/null || echo "$(translate "No active exports or showmount not available")"
echo ""
echo "$(translate "Universal Group Configuration:")"
echo "=================================="
if pct exec "$CTID" -- getent group sharedfiles >/dev/null 2>&1; then
local group_members=$(pct exec "$CTID" -- getent group sharedfiles | cut -d: -f4)
local sharedfiles_gid=$(pct exec "$CTID" -- getent group sharedfiles | cut -d: -f3)
echo "$(translate "Shared group: sharedfiles (GID:") $sharedfiles_gid)"
local member_count=$(echo "$group_members" | tr ',' '\n' | wc -l)
echo "$(translate "Total members:") $member_count $(translate "users")"
local remapped_users=$(pct exec "$CTID" -- getent passwd | grep "^remap_" | wc -l)
if [[ "$remapped_users" -gt 0 ]]; then
echo "$(translate "Remapped users:") $remapped_users $(translate "users (for unprivileged compatibility)")"
fi
echo "$(translate "Universal compatibility: ENABLED")"
echo "$(translate "NFS Version: Auto-negotiation (NFSv3/NFSv4)")"
else
echo "$(translate "Universal group: NOT CONFIGURED")"
fi
CT_IP=$(pct exec "$CTID" -- hostname -I | awk '{print $1}')
echo ""
echo "=================================="
echo -e "${TAB}${BOLD}$(translate "Connection Details:")${CL}"
echo -e "${TAB}${BGN}$(translate "Server IP:")${CL} ${BL}$CT_IP${CL}"
while IFS= read -r export_line; do
if [[ -n "$export_line" ]]; then
EXPORT_PATH=$(echo "$export_line" | awk '{print $1}')
echo -e "${TAB}${BGN}$(translate "Export path:")${CL} ${BL}$EXPORT_PATH${CL}"
echo ""
fi
done <<< "$EXPORTS"
else
echo "$(translate "No exports configured.")"
fi
else
echo "$(translate "/etc/exports file does not exist.")"
fi
echo ""
msg_success "$(translate "Press Enter to return to menu...")"
read -r
}
delete_export() {
if ! pct exec "$CTID" -- test -f /etc/exports; then
dialog --title "$(translate "Error")" --msgbox "\n$(translate "No exports file found.")" 8 50
return
fi
EXPORTS=$(pct exec "$CTID" -- awk '!/^#|^$/ {print NR, $0}' /etc/exports)
if [[ -z "$EXPORTS" ]]; then
dialog --title "$(translate "No Exports")" --msgbox "$(translate "No exports found in /etc/exports.")" 8 60
return
fi
OPTIONS=()
while read -r line; do
[[ -z "$line" ]] && continue
NUM=$(echo "$line" | awk '{print $1}')
EXPORT_LINE=$(echo "$line" | cut -d' ' -f2-)
EXPORT_PATH=$(echo "$EXPORT_LINE" | awk '{print $1}')
EXPORT_CLIENT=$(echo "$EXPORT_LINE" | awk '{print $2}' | cut -d'(' -f1)
[[ -z "$EXPORT_PATH" || -z "$EXPORT_CLIENT" ]] && continue
OPTIONS+=("$NUM" "$EXPORT_PATH $EXPORT_CLIENT")
done <<< "$EXPORTS"
SELECTED_NUM=$(dialog --title "$(translate "Delete Export")" --menu "$(translate "Select an export to delete:")" 20 70 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
[ -z "$SELECTED_NUM" ] && return
EXPORT_LINE=$(echo "$EXPORTS" | awk -v num="$SELECTED_NUM" '$1 == num {$1=""; print substr($0,2)}')
if whiptail --yesno "$(translate "Are you sure you want to delete this export?")\n\n$EXPORT_LINE" 10 70 --title "$(translate "Confirm Deletion")"; then
show_proxmenux_logo
msg_title "$(translate "Delete Export")"
pct exec "$CTID" -- sed -i "${SELECTED_NUM}d" /etc/exports
pct exec "$CTID" -- exportfs -ra
pct exec "$CTID" -- systemctl restart nfs-kernel-server
msg_ok "$(translate "Export deleted and NFS service restarted.")"
fi
msg_success "$(translate "Press Enter to return to menu...")"
read -r
}
check_nfs_status() {
show_proxmenux_logo
msg_title "$(translate "Check NFS Status")"
echo -e "$(translate "NFS Service Status in CT") $CTID:"
echo "=================================="
if pct exec "$CTID" -- dpkg -s nfs-kernel-server &>/dev/null; then
echo "$(translate "NFS Server: INSTALLED")"
if pct exec "$CTID" -- systemctl is-active --quiet nfs-kernel-server; then
echo "$(translate "NFS Service: RUNNING")"
else
echo "$(translate "NFS Service: STOPPED")"
fi
if pct exec "$CTID" -- systemctl is-active --quiet rpcbind; then
echo "$(translate "RPC Bind Service: RUNNING")"
else
echo "$(translate "RPC Bind Service: STOPPED")"
fi
echo ""
echo "$(translate "NFS Version Configuration:")"
echo "$(translate "Version: Auto-negotiation (NFSv3/NFSv4)")"
echo "$(translate "Client determines best version to use")"
echo ""
echo "$(translate "Universal Group Configuration:")"
if pct exec "$CTID" -- getent group sharedfiles >/dev/null 2>&1; then
echo "$(translate "Shared group: CONFIGURED")"
local group_members=$(pct exec "$CTID" -- getent group sharedfiles | cut -d: -f4)
local sharedfiles_gid=$(pct exec "$CTID" -- getent group sharedfiles | cut -d: -f3)
echo "$(translate "Group GID:") $sharedfiles_gid"
local member_count=$(echo "$group_members" | tr ',' '\n' | wc -l)
echo "$(translate "Total members:") $member_count $(translate "users")"
local remapped_users=$(pct exec "$CTID" -- getent passwd | grep "^remap_" | wc -l)
echo "$(translate "Remapped users:") $remapped_users $(translate "users")"
echo "$(translate "Universal compatibility: ENABLED")"
else
echo "$(translate "Universal group: NOT CONFIGURED")"
fi
echo ""
echo "$(translate "Listening ports:")"
pct exec "$CTID" -- ss -tlnp | grep -E ':(111|2049|20048)' || echo "$(translate "No NFS ports found")"
else
echo "$(translate "NFS Server: NOT INSTALLED")"
fi
echo ""
msg_success "$(translate "Press Enter to return to menu...")"
read -r
}
uninstall_nfs() {
if ! pct exec "$CTID" -- dpkg -s nfs-kernel-server &>/dev/null; then
dialog --title "$(translate "NFS Not Installed")" --msgbox "\n$(translate "NFS server is not installed in this CT.")" 8 60
return
fi
if ! whiptail --title "$(translate "Uninstall NFS Server")" \
--yesno "$(translate "WARNING: This will completely remove NFS server from the CT.")\n\n$(translate "This action will:")\n$(translate "• Stop all NFS services")\n$(translate "• Remove all exports")\n$(translate "• Uninstall NFS packages")\n$(translate "• Remove universal sharedfiles group")\n$(translate "• Clean up remapped users")\n\n$(translate "Are you sure you want to continue?")" \
18 70; then
return
fi
show_proxmenux_logo
msg_title "$(translate "Uninstall NFS Server")"
msg_info "$(translate "Stopping NFS services...")"
pct exec "$CTID" -- systemctl stop nfs-kernel-server 2>/dev/null || true
pct exec "$CTID" -- systemctl stop rpcbind 2>/dev/null || true
pct exec "$CTID" -- systemctl disable nfs-kernel-server 2>/dev/null || true
pct exec "$CTID" -- systemctl disable rpcbind 2>/dev/null || true
msg_ok "$(translate "NFS services stopped and disabled.")"
if pct exec "$CTID" -- test -f /etc/exports; then
pct exec "$CTID" -- truncate -s 0 /etc/exports
msg_ok "$(translate "Exports cleared.")"
fi
msg_info "$(translate "Removing remapped users...")"
local remapped_users=$(pct exec "$CTID" -- getent passwd | grep "^remap_" | cut -d: -f1)
if [[ -n "$remapped_users" ]]; then
while IFS= read -r username; do
if [[ -n "$username" ]]; then
pct exec "$CTID" -- userdel "$username" 2>/dev/null || true
msg_ok "$(translate "Removed remapped user:") $username"
fi
done <<< "$remapped_users"
fi
if pct exec "$CTID" -- getent group sharedfiles >/dev/null 2>&1; then
local regular_members=$(pct exec "$CTID" -- getent group sharedfiles | cut -d: -f4 | tr ',' '\n' | grep -v "^remap_" | wc -l)
if [[ "$regular_members" -eq 0 ]]; then
pct exec "$CTID" -- groupdel sharedfiles 2>/dev/null || true
msg_ok "$(translate "Removed sharedfiles group.")"
else
msg_warn "$(translate "Kept sharedfiles group (has regular users assigned).")"
fi
fi
pct exec "$CTID" -- apt-get remove --purge -y nfs-kernel-server nfs-common 2>/dev/null || true
pct exec "$CTID" -- apt-get autoremove -y 2>/dev/null || true
msg_ok "$(translate "NFS packages removed.")"
msg_info "$(translate "Cleaning up remaining processes...")"
pct exec "$CTID" -- pkill -f nfs 2>/dev/null || true
pct exec "$CTID" -- pkill -f rpc 2>/dev/null || true
sleep 2
msg_ok "$(translate "Universal NFS server has been completely uninstalled!")"
echo -e ""
echo -e "${TAB}${BOLD}$(translate "Uninstallation Summary:")${CL}"
echo -e "${TAB}${BGN}$(translate "Services:")${CL} ${BL}$(translate "Stopped and disabled")${CL}"
echo -e "${TAB}${BGN}$(translate "Packages:")${CL} ${BL}$(translate "Removed")${CL}"
echo -e "${TAB}${BGN}$(translate "Exports:")${CL} ${BL}$(translate "Cleared")${CL}"
echo -e "${TAB}${BGN}$(translate "Universal Group:")${CL} ${BL}$(translate "Cleaned up")${CL}"
echo -e "${TAB}${BGN}$(translate "Remapped Users:")${CL} ${BL}$(translate "Removed")${CL}"
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r
}
# === Main Menu ===
while true; do
CHOICE=$(dialog --title "$(translate "NFS LXC Manager - CT") $CTID" --menu "$(translate "Choose an option:")" 20 70 12 \
"1" "$(translate "Create Universal NFS Export")" \
"2" "$(translate "View Current Exports")" \
"3" "$(translate "Delete Export")" \
"4" "$(translate "Check NFS Status")" \
"5" "$(translate "Uninstall NFS Server")" \
"6" "$(translate "Exit")" 3>&1 1>&2 2>&3)
case $CHOICE in
1) create_nfs_export ;;
2) view_exports ;;
3) delete_export ;;
4) check_nfs_status ;;
5) uninstall_nfs ;;
6) exit 0 ;;
*) exit 0 ;;
esac
done