2025-08-22 18:05:14 +02:00
#!/bin/bash
# ==========================================================
2026-04-01 23:09:51 +02:00
# ProxMenux - NFS Host Manager for Proxmox Host
2025-08-22 18:05:14 +02:00
# ==========================================================
2026-04-01 23:09:51 +02:00
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
2026-05-09 18:59:59 +02:00
# License : GPL-3.0
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
# Version : 1.0
2025-08-22 18:05:14 +02:00
# ==========================================================
# Description:
2026-05-26 12:41:50 +02:00
# Mounts an external NFS export on the Proxmox host.
# User picks one or both methods:
# 1. As Proxmox storage (pvesm add nfs) → /mnt/pve/<id>
# 2. As host fstab mount → user-chosen path
#
# Method 2 is for users who want the host to mount the share
# for LXC bind-mounts WITHOUT exposing it as a Proxmox storage
# in the Datacenter UI. The mount path is opened up so
# unprivileged LXCs can read/write through a bind-mount —
# all permission tweaks happen on the host side, NEVER inside
# the container.
2026-05-09 18:59:59 +02:00
#
# Features:
# - Auto-discover NFS servers on the local subnet (nmap).
# - Reachability validation chain (ping + nc + showmount).
# - Content-type checklist (import/backup/iso/vztmpl/images/
# rootdir/snippets).
# - View, remove and connectivity-test for existing storages.
2025-08-22 18:05:14 +02:00
# ==========================================================
2025-11-03 01:36:57 +00:00
LOCAL_SCRIPTS = "/usr/local/share/proxmenux/scripts"
2025-08-22 18:05:14 +02:00
BASE_DIR = "/usr/local/share/proxmenux"
UTILS_FILE = " $BASE_DIR /utils.sh "
VENV_PATH = "/opt/googletrans-env"
if [ [ -f " $UTILS_FILE " ] ] ; then
source " $UTILS_FILE "
fi
load_language
initialize_cache
2026-04-01 23:09:51 +02:00
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
2025-08-30 18:56:49 +02:00
fi
2025-08-22 18:05:14 +02:00
2026-04-01 23:09:51 +02:00
# ==========================================================
# STORAGE CONFIG READER
# ==========================================================
get_storage_config( ) {
local storage_id = " $1 "
awk -v id = " $storage_id " '
/^[ a-z] +: / { found = ( $0 ~ ": " id" $" ) ; next }
found && /^[ ^ \t ] / { exit }
found { print }
' /etc/pve/storage.cfg
}
2025-09-03 23:13:21 +02:00
2026-04-01 23:09:51 +02:00
# ==========================================================
# SERVER DISCOVERY
# ==========================================================
2025-08-22 18:05:14 +02:00
discover_nfs_servers( ) {
show_proxmenux_logo
2026-04-01 23:09:51 +02:00
msg_title " $( translate "Add NFS Share as Proxmox Storage" ) "
2025-08-22 18:05:14 +02:00
msg_info " $( translate "Scanning network for NFS servers..." ) "
HOST_IP = $( hostname -I | awk '{print $1}' )
NETWORK = $( echo " $HOST_IP " | cut -d. -f1-3) .0/24
if ! which nmap >/dev/null 2>& 1; then
apt-get install -y nmap & >/dev/null
fi
SERVERS = $( nmap -p 2049 --open " $NETWORK " 2>/dev/null | grep -B 4 "2049/tcp open" | grep "Nmap scan report" | awk '{print $5}' | sort -u || true )
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
if [ [ -z " $SERVERS " ] ] ; then
cleanup
2026-04-01 23:09:51 +02:00
dialog --clear --title " $( translate "No Servers Found" ) " \
--msgbox " $( translate "No NFS servers found on the network." ) \n\n $( translate "You can add servers manually." ) " 10 60
2025-08-22 18:05:14 +02:00
return 1
fi
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
OPTIONS = ( )
while IFS = read -r server; do
if [ [ -n " $server " ] ] ; then
EXPORTS_COUNT = $( showmount -e " $server " 2>/dev/null | tail -n +2 | wc -l || echo "0" )
2026-04-01 23:09:51 +02:00
OPTIONS += ( " $server " " NFS Server ( $EXPORTS_COUNT exports) " )
2025-08-22 18:05:14 +02:00
fi
done <<< " $SERVERS "
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
if [ [ ${# OPTIONS [@] } -eq 0 ] ] ; then
cleanup
2025-09-06 23:18:11 +02:00
dialog --clear --title " $( translate "No Valid Servers" ) " --msgbox " $( translate "No accessible NFS servers found." ) " 8 50
2025-08-22 18:05:14 +02:00
return 1
fi
2026-04-01 23:09:51 +02:00
2025-09-06 23:18:11 +02:00
cleanup
2026-04-01 23:09:51 +02:00
NFS_SERVER = $( whiptail --backtitle "ProxMenux" --title " $( translate "Select NFS Server" ) " \
--menu " $( translate "Choose an NFS server:" ) " 20 80 10 " ${ OPTIONS [@] } " 3>& 1 1>& 2 2>& 3)
2025-08-22 18:05:14 +02:00
[ [ -n " $NFS_SERVER " ] ] && return 0 || return 1
}
select_nfs_server( ) {
2026-04-01 23:09:51 +02:00
METHOD = $( dialog --backtitle "ProxMenux" --title " $( translate "NFS Server Selection" ) " \
--menu " $( translate "How do you want to select the NFS server?" ) " 15 70 3 \
"auto" " $( translate "Auto-discover servers on network" ) " \
"manual" " $( translate "Enter server IP/hostname manually" ) " \
3>& 1 1>& 2 2>& 3)
2025-08-22 18:05:14 +02:00
case " $METHOD " in
auto)
discover_nfs_servers || return 1
; ;
manual)
clear
2026-04-01 23:09:51 +02:00
NFS_SERVER = $( whiptail --inputbox " $( translate "Enter NFS server IP or hostname:" ) " \
10 60 --title " $( translate "NFS Server" ) " 3>& 1 1>& 2 2>& 3)
2025-08-22 18:05:14 +02:00
[ [ -z " $NFS_SERVER " ] ] && return 1
; ;
*)
return 1
; ;
esac
return 0
}
select_nfs_export( ) {
if ! which showmount >/dev/null 2>& 1; then
whiptail --title " $( translate "NFS Client Error" ) " \
2026-04-01 23:09:51 +02:00
--msgbox " $( translate "showmount command is not working properly." ) \n\n $( translate "Please check the installation." ) " \
10 60
2025-08-22 18:05:14 +02:00
return 1
fi
if ! ping -c 1 -W 3 " $NFS_SERVER " >/dev/null 2>& 1; then
whiptail --title " $( translate "Connection Error" ) " \
2026-04-01 23:09:51 +02:00
--msgbox " $( translate "Cannot reach server" ) $NFS_SERVER \n\n $( translate "Please check:" ) \n• $( translate "Server IP/hostname is correct" ) \n• $( translate "Network connectivity" ) \n• $( translate "Server is online" ) " \
12 70
2025-08-22 18:05:14 +02:00
return 1
fi
if ! nc -z -w 3 " $NFS_SERVER " 2049 2>/dev/null; then
whiptail --title " $( translate "NFS Port Error" ) " \
2026-04-01 23:09:51 +02:00
--msgbox " $( translate "NFS port (2049) is not accessible on" ) $NFS_SERVER \n\n $( translate "Please check:" ) \n• $( translate "NFS server is running" ) \n• $( translate "Firewall settings" ) \n• $( translate "NFS service is enabled" ) " \
12 70
2025-08-22 18:05:14 +02:00
return 1
fi
EXPORTS_OUTPUT = $( showmount -e " $NFS_SERVER " 2>& 1)
EXPORTS_RESULT = $?
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
if [ [ $EXPORTS_RESULT -ne 0 ] ] ; then
ERROR_MSG = $( echo " $EXPORTS_OUTPUT " | grep -i "error\|failed\|denied" | head -1)
2026-04-01 23:09:51 +02:00
whiptail --title " $( translate "NFS Error" ) " \
--msgbox " $( translate "Failed to connect to" ) $NFS_SERVER \n\n $( translate "Error:" ) : $ERROR_MSG " \
12 80
2025-08-22 18:05:14 +02:00
return 1
fi
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
EXPORTS = $( echo " $EXPORTS_OUTPUT " | tail -n +2 | awk '{print $1}' | grep -v " ^ $" )
if [ [ -z " $EXPORTS " ] ] ; then
whiptail --title " $( translate "No Exports Found" ) " \
2026-04-01 23:09:51 +02:00
--msgbox " $( translate "No exports found on server" ) $NFS_SERVER \n\n $( translate "You can enter the export path manually." ) " \
12 70
NFS_EXPORT = $( whiptail --inputbox " $( translate "Enter NFS export path (e.g., /mnt/shared):" ) " \
10 60 --title " $( translate "Export Path" ) " 3>& 1 1>& 2 2>& 3)
2025-08-22 18:05:14 +02:00
[ [ -z " $NFS_EXPORT " ] ] && return 1
return 0
fi
OPTIONS = ( )
while IFS = read -r export_line; do
if [ [ -n " $export_line " ] ] ; then
EXPORT_PATH = $( echo " $export_line " | awk '{print $1}' )
2026-04-01 23:09:51 +02:00
CLIENTS = $( echo " $EXPORTS_OUTPUT " | grep " ^ $EXPORT_PATH " | awk '{for(i=2;i<=NF;i++) printf "%s ",$i; print ""}' | sed 's/[[:space:]]*$//' )
2025-08-22 18:05:14 +02:00
if [ [ -n " $CLIENTS " ] ] ; then
OPTIONS += ( " $EXPORT_PATH " " $CLIENTS " )
else
OPTIONS += ( " $EXPORT_PATH " " $( translate "NFS export" ) " )
fi
fi
done <<< " $EXPORTS "
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
if [ [ ${# OPTIONS [@] } -eq 0 ] ] ; then
2026-04-01 23:09:51 +02:00
NFS_EXPORT = $( whiptail --inputbox " $( translate "Enter NFS export path (e.g., /mnt/shared):" ) " \
10 60 --title " $( translate "Export Path" ) " 3>& 1 1>& 2 2>& 3)
2025-08-22 18:05:14 +02:00
[ [ -n " $NFS_EXPORT " ] ] && return 0 || return 1
fi
2026-04-01 23:09:51 +02:00
NFS_EXPORT = $( whiptail --title " $( translate "Select NFS Export" ) " \
--menu " $( translate "Choose an export to mount:" ) " 20 70 10 " ${ OPTIONS [@] } " 3>& 1 1>& 2 2>& 3)
[ [ -n " $NFS_EXPORT " ] ] && return 0 || return 1
2025-08-22 18:05:14 +02:00
}
validate_host_export_exists( ) {
local server = " $1 "
local export = " $2 "
2026-05-26 17:21:24 +02:00
VALIDATION_OUTPUT = $( showmount -e " $server " 2>/dev/null | grep " ^ ${ export } [[:space:]] " )
2025-08-22 18:05:14 +02:00
if [ [ -n " $VALIDATION_OUTPUT " ] ] ; then
return 0
else
show_proxmenux_logo
echo -e
msg_error " $( translate "Export not found on server:" ) $export "
return 1
fi
}
2026-04-01 23:09:51 +02:00
# ==========================================================
# STORAGE CONFIGURATION
# ==========================================================
configure_nfs_storage( ) {
STORAGE_ID = $( whiptail --inputbox " $( translate "Enter storage ID for Proxmox:" ) " \
10 60 " nfs- $( echo " $NFS_SERVER " | tr '.' '-' ) " \
--title " $( translate "Storage ID" ) " 3>& 1 1>& 2 2>& 3)
[ [ $? -ne 0 ] ] && return 1
[ [ -z " $STORAGE_ID " ] ] && STORAGE_ID = " nfs- $( echo " $NFS_SERVER " | tr '.' '-' ) "
if [ [ ! " $STORAGE_ID " = ~ ^[ a-zA-Z0-9] [ a-zA-Z0-9_-] *$ ] ] ; then
whiptail --msgbox " $( translate "Invalid storage ID. Use only letters, numbers, hyphens and underscores." ) " 8 70
return 1
fi
local raw_content
raw_content = $( dialog --backtitle "ProxMenux" \
--title " $( translate "Content Types" ) " \
--checklist " \n $( translate "Select content types for this storage:" ) \n $( translate "(Import is selected by default — required for disk image imports)" ) " 18 65 7 \
"import" " $( translate "Import — disk image imports" ) " on \
"backup" " $( translate "Backup — VM and CT backups" ) " off \
"iso" " $( translate "ISO image — installation images" ) " off \
"vztmpl" " $( translate "Container template— LXC templates" ) " off \
"images" " $( translate "Disk image — VM disk images" ) " off \
"rootdir" " $( translate "Container — LXC root directories" ) " off \
"snippets" " $( translate "Snippets — hook scripts / config" ) " off \
3>& 1 1>& 2 2>& 3)
[ [ $? -ne 0 ] ] && return 1
# Convert dialog checklist output (quoted space-separated) to comma-separated
MOUNT_CONTENT = $( echo " $raw_content " | tr -d '"' | tr -s ' ' ',' | sed 's/^,//;s/,$//' )
[ [ -z " $MOUNT_CONTENT " ] ] && MOUNT_CONTENT = "import"
return 0
}
2025-08-22 18:05:14 +02:00
add_proxmox_nfs_storage( ) {
local storage_id = " $1 "
local server = " $2 "
local export = " $3 "
2026-04-01 23:09:51 +02:00
local content = " ${ 4 :- import } "
2025-08-22 18:05:14 +02:00
msg_info " $( translate "Starting Proxmox storage integration..." ) "
2026-04-01 23:09:51 +02:00
2025-09-03 23:13:21 +02:00
if ! command -v pvesm >/dev/null 2>& 1; then
2025-08-22 18:05:14 +02:00
msg_error " $( translate "pvesm command not found. This should not happen on Proxmox." ) "
return 1
fi
if pvesm status " $storage_id " >/dev/null 2>& 1; then
msg_warn " $( translate "Storage ID already exists:" ) $storage_id "
2026-04-01 23:09:51 +02:00
if ! whiptail --yesno " $( translate "Storage ID already exists. Do you want to remove and recreate it?" ) " \
8 60 --title " $( translate "Storage Exists" ) " ; then
return 0
2025-08-22 18:05:14 +02:00
fi
pvesm remove " $storage_id " 2>/dev/null || true
fi
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
msg_ok " $( translate "Storage ID is available" ) "
2026-04-12 20:32:34 +02:00
msg_info " $( translate "NFS storage adding in progress..." ) "
2025-09-03 23:13:21 +02:00
if pvesm_output = $( pvesm add nfs " $storage_id " \
2025-08-22 18:05:14 +02:00
--server " $server " \
--export " $export " \
2025-09-03 23:13:21 +02:00
--content " $content " 2>& 1) ; then
2026-04-01 23:09:51 +02:00
2025-09-03 23:13:21 +02:00
msg_ok " $( translate "NFS storage added successfully!" ) "
2026-04-01 23:09:51 +02:00
2025-09-03 23:13:21 +02:00
local nfs_version = "Auto-negotiated"
2026-04-01 23:09:51 +02:00
if get_storage_config " $storage_id " | grep -q "options.*vers=" ; then
nfs_version = " v $( get_storage_config " $storage_id " | grep "options" | grep -o "vers=[0-9.]*" | cut -d= -f2) "
2025-09-03 23:13:21 +02:00
fi
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
echo -e ""
2026-04-01 23:09:51 +02:00
echo -e " ${ TAB } ${ BOLD } $( translate "Storage Added:" ) ${ CL } "
2025-08-22 18:05:14 +02:00
echo -e " ${ TAB } ${ BGN } $( translate "Storage ID:" ) ${ CL } ${ BL } $storage_id ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Server:" ) ${ CL } ${ BL } $server ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Export:" ) ${ CL } ${ BL } $export ${ CL } "
2025-09-03 23:13:21 +02:00
echo -e " ${ TAB } ${ BGN } $( translate "Content Types:" ) ${ CL } ${ BL } $content ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "NFS Version:" ) ${ CL } ${ BL } $nfs_version ${ CL } "
2026-04-01 23:09:51 +02:00
echo -e " ${ TAB } ${ BGN } $( translate "Mount Path:" ) ${ CL } ${ BL } /mnt/pve/ $storage_id ${ CL } "
2025-08-22 18:05:14 +02:00
echo -e ""
msg_ok " $( translate "Storage is now available in Proxmox web interface under Datacenter > Storage" ) "
return 0
else
msg_error " $( translate "Failed to add NFS storage to Proxmox." ) "
2026-04-01 23:09:51 +02:00
echo -e " ${ TAB } $( translate "Error details:" ) : $pvesm_output "
echo -e ""
2025-08-22 18:05:14 +02:00
msg_info2 " $( translate "You can add it manually through:" ) "
echo -e " ${ TAB } • $( translate "Proxmox web interface: Datacenter > Storage > Add > NFS" ) "
2026-04-01 23:09:51 +02:00
echo -e " ${ TAB } • pvesm add nfs $storage_id --server $server --export $export --content $content "
2025-08-22 18:05:14 +02:00
return 1
fi
}
2026-05-26 12:41:50 +02:00
# ==========================================================
# FSTAB MOUNT (host-only, NOT as Proxmox storage)
# ==========================================================
# Pick a mount path on the host. Default is /mnt/<export-basename>.
# Validates the path is absolute and not already in use.
select_host_mount_path( ) {
local default_name
default_name = $( basename " $NFS_EXPORT " )
[ [ -z " $default_name " || " $default_name " = = "/" ] ] && default_name = "nfs_share"
while true; do
HOST_MOUNT_PATH = $( whiptail --inputbox \
" $( translate "Enter the host mount path:" ) \n\n $( translate "Default location is /mnt/<name>. The share will be mounted here on the host. Use this path in /etc/fstab. For LXC access, bind-mount this path with the LXC Mount Manager." ) " \
14 70 " /mnt/ $default_name " \
--title " $( translate "Host Mount Path" ) " 3>& 1 1>& 2 2>& 3)
[ [ $? -ne 0 ] ] && return 1
[ [ -z " $HOST_MOUNT_PATH " ] ] && HOST_MOUNT_PATH = " /mnt/ $default_name "
if [ [ ! " $HOST_MOUNT_PATH " = ~ ^/.+ ] ] ; then
whiptail --msgbox " $( translate "Mount path must be an absolute path starting with /" ) " 8 60
continue
fi
if mount | grep -q " on $HOST_MOUNT_PATH " ; then
whiptail --msgbox " $( translate "Something is already mounted at:" ) $HOST_MOUNT_PATH \n\n $( translate "Choose a different path or unmount it first." ) " 10 70
continue
fi
if grep -qE " [[:space:]] ${ HOST_MOUNT_PATH } [[:space:]] " /etc/fstab 2>/dev/null; then
if ! whiptail --yesno " $( translate "An fstab entry already exists for:" ) $HOST_MOUNT_PATH \n\n $( translate "Replace it?" ) " 10 70 \
--title " $( translate "fstab entry exists" ) " ; then
continue
fi
FSTAB_REPLACE = 1
else
FSTAB_REPLACE = 0
fi
break
done
return 0
}
# Pick NFS mount options for the fstab entry.
select_nfs_mount_options( ) {
local choice
choice = $( dialog --backtitle "ProxMenux" \
--title " $( translate "Mount Options" ) " \
--menu " $( translate "Select mount options:" ) " 15 70 4 \
"1" " $( translate "Read/Write (default)" ) " \
"2" " $( translate "Read-only" ) " \
"3" " $( translate "Custom" ) " \
3>& 1 1>& 2 2>& 3)
[ [ $? -ne 0 ] ] && return 1
case " $choice " in
1) NFS_MOUNT_OPTS = "rw,hard,nofail,_netdev,rsize=131072,wsize=131072,timeo=600,retrans=2" ; ;
2) NFS_MOUNT_OPTS = "ro,hard,nofail,_netdev,rsize=131072,wsize=131072,timeo=600,retrans=2" ; ;
3)
NFS_MOUNT_OPTS = $( whiptail --inputbox \
" $( translate "Enter custom NFS mount options:" ) " \
10 70 "rw,hard,nofail,_netdev,rsize=131072,wsize=131072,timeo=600,retrans=2" \
--title " $( translate "Custom Options" ) " 3>& 1 1>& 2 2>& 3)
[ [ $? -ne 0 ] ] && return 1
[ [ -z " $NFS_MOUNT_OPTS " ] ] && NFS_MOUNT_OPTS = "rw,hard,nofail,_netdev"
; ;
esac
return 0
}
# Mount the NFS export on the host and persist to /etc/fstab.
# Permission tweaks happen on the host side ONLY — never inside any LXC.
mount_nfs_via_fstab( ) {
local server = " $1 "
local export_path = " $2 "
local mount_path = " $3 "
local mount_opts = " $4 "
local replace = " $5 "
msg_info " $( translate "Preparing host mount..." ) "
if [ [ ! -d " $mount_path " ] ] ; then
if ! mkdir -p " $mount_path " 2>/dev/null; then
msg_error " $( translate "Failed to create mount point:" ) $mount_path "
return 1
fi
fi
msg_ok " $( translate "Mount point ready:" ) $mount_path "
msg_info " $( translate "Mounting NFS share..." ) "
if ! mount -t nfs -o " $mount_opts " " ${ server } : ${ export_path } " " $mount_path " >/dev/null 2>& 1; then
msg_error " $( translate "Failed to mount NFS share on host." ) "
return 1
fi
msg_ok " $( translate "NFS share mounted at:" ) $mount_path "
# Verify host can write (informational — NFS server controls write access).
if touch " $mount_path /.proxmenux_write_test " 2>/dev/null; then
rm -f " $mount_path /.proxmenux_write_test " 2>/dev/null
msg_ok " $( translate "Host write access confirmed." ) "
else
msg_warn " $( translate "No host write access — server-side ACL or root_squash. Continuing anyway." ) "
fi
# Best-effort: open perms so an unprivileged LXC bind-mounting this path
# can read/write. NFS controls perms server-side; these calls succeed only
# if the server export allows them. Failures are silent.
chmod 1777 " $mount_path " 2>/dev/null || true
setfacl -m o::rwx " $mount_path " 2>/dev/null || true
# Persist in /etc/fstab.
if [ [ " $replace " = = "1" ] ] ; then
sed -i " \|[[:space:]] ${ mount_path } [[:space:]]|d " /etc/fstab
fi
echo " ${ server } : ${ export_path } $mount_path nfs $mount_opts 0 0 " >> /etc/fstab
msg_ok " $( translate "Added to /etc/fstab." ) "
systemctl daemon-reload 2>/dev/null || true
echo -e ""
echo -e " ${ TAB } ${ BOLD } $( translate "Host fstab Mount:" ) ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Server:" ) ${ CL } ${ BL } $server ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Export:" ) ${ CL } ${ BL } $export_path ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Mount path:" ) ${ CL } ${ BL } $mount_path ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Options:" ) ${ CL } ${ BL } $mount_opts ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Persistent:" ) ${ CL } ${ BL } $( translate "yes (survives reboot)" ) ${ CL } "
echo -e ""
msg_info2 " $( translate "To use this share from an LXC, bind-mount it via:" ) "
echo -e " ${ TAB } pct set <ctid> -mpN $mount_path ,mp=<container-path>,shared=1,backup=0 "
echo -e " ${ TAB } $( translate "or use the ProxMenux LXC Mount Manager." ) "
return 0
}
# ==========================================================
# MOUNT METHOD SELECTION
# ==========================================================
# Show a checklist with the two mount methods (pvesm / fstab).
# User must mark at least one and press OK; if none is marked,
# loop and show the dialog again. Cancel exits the flow.
# Sets MODE_PVESM and MODE_FSTAB to 0 or 1 on success.
select_mount_methods( ) {
MODE_PVESM = 0
MODE_FSTAB = 0
while true; do
local result
result = $( dialog --backtitle "ProxMenux" \
--title " $( translate "Mount Method" ) " \
--checklist " \n $( translate "Choose how to mount the NFS share on this host. Mark one or both options:" ) \n\n $( translate "• Proxmox storage (pvesm): visible in Datacenter > Storage, mount at /mnt/pve/<id>" ) \n $( translate "• Host fstab: mounted at a path you choose, NOT visible as Proxmox storage" ) \n $( translate "• Both: mounts twice (pvesm + an independent fstab entry)" ) " 20 78 2 \
"pvesm" " $( translate "As Proxmox storage" ) " off \
"fstab" " $( translate "As host fstab mount only" ) " off \
3>& 1 1>& 2 2>& 3)
local rc = $?
[ [ $rc -ne 0 ] ] && return 1 # Cancel → abort the whole flow
# Parse selection
if echo " $result " | grep -qw "pvesm" ; then MODE_PVESM = 1; fi
if echo " $result " | grep -qw "fstab" ; then MODE_FSTAB = 1; fi
if [ [ " $MODE_PVESM " = = "1" || " $MODE_FSTAB " = = "1" ] ] ; then
return 0
fi
whiptail --msgbox " $( translate "Please mark at least one option, or press Cancel to exit." ) " 8 70
done
}
2026-04-01 23:09:51 +02:00
# ==========================================================
# MAIN OPERATIONS
# ==========================================================
2025-08-22 18:05:14 +02:00
2026-05-26 12:41:50 +02:00
mount_nfs_share( ) {
2025-08-22 18:05:14 +02:00
if ! which showmount >/dev/null 2>& 1; then
2026-04-01 23:09:51 +02:00
msg_info " $( translate "Installing NFS client tools..." ) "
apt-get update & >/dev/null
apt-get install -y nfs-common & >/dev/null
msg_ok " $( translate "NFS client tools installed" ) "
2025-08-22 18:05:14 +02:00
fi
2026-04-01 23:09:51 +02:00
# Step 1: Select server
2025-08-22 18:05:14 +02:00
select_nfs_server || return
2026-04-01 23:09:51 +02:00
# Step 2: Select export
2025-08-22 18:05:14 +02:00
select_nfs_export || return
2026-04-01 23:09:51 +02:00
# Step 3: Validate export
2025-08-22 18:05:14 +02:00
if ! validate_host_export_exists " $NFS_SERVER " " $NFS_EXPORT " ; then
echo -e ""
msg_error " $( translate "Cannot proceed with invalid export path." ) "
2026-04-01 23:09:51 +02:00
msg_success " $( translate "Press Enter to continue..." ) "
2025-08-22 18:05:14 +02:00
read -r
return
fi
2026-05-26 12:41:50 +02:00
# Step 4: Pick mount method(s) — pvesm, fstab, or both
select_mount_methods || return
2025-08-22 18:05:14 +02:00
2026-05-26 12:41:50 +02:00
# Step 5a: If pvesm selected, gather storage params
if [ [ " $MODE_PVESM " = = "1" ] ] ; then
configure_nfs_storage || return
fi
# Step 5b: If fstab selected, gather host mount params
if [ [ " $MODE_FSTAB " = = "1" ] ] ; then
select_host_mount_path || return
select_nfs_mount_options || return
fi
2025-08-22 18:05:14 +02:00
2026-05-26 12:41:50 +02:00
# Step 6: Apply
2026-04-01 23:09:51 +02:00
show_proxmenux_logo
2026-05-26 12:41:50 +02:00
msg_title " $( translate "Mount NFS Share on Host" ) "
2026-04-01 23:09:51 +02:00
msg_ok " $( translate "NFS server:" ) $NFS_SERVER "
msg_ok " $( translate "NFS export:" ) $NFS_EXPORT "
2026-05-26 12:41:50 +02:00
if [ [ " $MODE_PVESM " = = "1" ] ] ; then
msg_ok " $( translate "Method:" ) pvesm ( $( translate "Storage ID:" ) $STORAGE_ID , $( translate "content:" ) $MOUNT_CONTENT ) "
fi
if [ [ " $MODE_FSTAB " = = "1" ] ] ; then
msg_ok " $( translate "Method:" ) fstab ( $( translate "Mount path:" ) $HOST_MOUNT_PATH ) "
fi
2026-04-01 23:09:51 +02:00
echo -e ""
2025-08-22 18:05:14 +02:00
2026-05-26 12:41:50 +02:00
local overall_rc = 0
if [ [ " $MODE_PVESM " = = "1" ] ] ; then
if ! add_proxmox_nfs_storage " $STORAGE_ID " " $NFS_SERVER " " $NFS_EXPORT " " $MOUNT_CONTENT " ; then
overall_rc = 1
fi
echo -e ""
fi
if [ [ " $MODE_FSTAB " = = "1" ] ] ; then
if ! mount_nfs_via_fstab " $NFS_SERVER " " $NFS_EXPORT " " $HOST_MOUNT_PATH " " $NFS_MOUNT_OPTS " " $FSTAB_REPLACE " ; then
overall_rc = 1
fi
fi
2025-08-22 18:05:14 +02:00
echo -e ""
2026-05-26 12:41:50 +02:00
if [ [ " $overall_rc " = = "0" ] ] ; then
msg_success " $( translate "Press Enter to continue..." ) "
else
msg_warn " $( translate "Some operations failed — review messages above. Press Enter to continue..." ) "
fi
2025-08-22 18:05:14 +02:00
read -r
}
2026-05-26 17:21:24 +02:00
# ==========================================================
# FSTAB ENTRY DISCOVERY (host mounts NOT registered with pvesm)
# ==========================================================
# Print every NFS entry in /etc/fstab as: server|export|mount_path|opts
# Skips comments and blank lines. Includes both currently-mounted and
# inactive entries (the live state is reported by the caller).
list_nfs_fstab_entries( ) {
awk '
/^[ [ :space:] ] *#/ { next }
/^[ [ :space:] ] *$/ { next }
$3 = = "nfs" || $3 = = "nfs4" {
# $1 = server:/export, $2 = mount path, $4 = opts
split( $1 , srv_exp, ":" )
print srv_exp[ 1] "|" srv_exp[ 2] "|" $2 "|" $4
}
' /etc/fstab 2>/dev/null
}
# Echo "active" if the given path is currently mounted, "inactive" otherwise.
check_mount_state( ) {
local path = " $1 "
if mount | grep -q " on ${ path } type " ; then
echo "active"
else
echo "inactive"
fi
}
2026-04-01 23:09:51 +02:00
view_nfs_storages( ) {
2025-08-22 18:05:14 +02:00
show_proxmenux_logo
2026-05-26 17:21:24 +02:00
msg_title " $( translate "NFS Mounts on Host" ) "
2025-08-22 18:05:14 +02:00
2026-04-01 23:09:51 +02:00
echo "=================================================="
2025-09-03 23:13:21 +02:00
echo ""
2025-08-22 18:05:14 +02:00
2026-05-26 17:21:24 +02:00
# ---- Proxmox storages (pvesm) ----
local NFS_STORAGES = ""
if command -v pvesm >/dev/null 2>& 1; then
NFS_STORAGES = $( pvesm status 2>/dev/null | awk '$2 == "nfs" {print $1, $3}' )
2025-08-22 18:05:14 +02:00
fi
2026-04-01 23:09:51 +02:00
if [ [ -z " $NFS_STORAGES " ] ] ; then
2026-05-26 17:21:24 +02:00
msg_warn " $( translate "No NFS Proxmox storages configured." ) "
2026-04-01 23:09:51 +02:00
else
2026-05-26 17:21:24 +02:00
echo -e " ${ BOLD } $( translate "NFS Proxmox storages (pvesm):" ) ${ CL } "
2026-04-01 23:09:51 +02:00
echo ""
while IFS = " " read -r storage_id storage_status; do
[ [ -z " $storage_id " ] ] && continue
2026-05-26 17:21:24 +02:00
local storage_info server export_path content
2026-04-01 23:09:51 +02:00
storage_info = $( get_storage_config " $storage_id " )
server = $( echo " $storage_info " | awk '$1 == "server" {print $2}' )
export_path = $( echo " $storage_info " | awk '$1 == "export" {print $2}' )
content = $( echo " $storage_info " | awk '$1 == "content" {print $2}' )
2026-05-26 17:21:24 +02:00
echo -e " ${ TAB } ${ BOLD } $storage_id ${ CL } ${ TAB } [pvesm] "
2026-04-01 23:09:51 +02:00
echo -e " ${ TAB } ${ BGN } $( translate "Server:" ) ${ CL } ${ BL } $server ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Export:" ) ${ CL } ${ BL } $export_path ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Content:" ) ${ CL } ${ BL } $content ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Mount Path:" ) ${ CL } ${ BL } /mnt/pve/ $storage_id ${ CL } "
if [ [ " $storage_status " = = "active" ] ] ; then
echo -e " ${ TAB } ${ BGN } $( translate "Status:" ) ${ CL } ${ GN } $( translate "Active" ) ${ CL } "
2025-08-22 18:05:14 +02:00
else
2026-04-01 23:09:51 +02:00
echo -e " ${ TAB } ${ BGN } $( translate "Status:" ) ${ CL } ${ RD } $storage_status ${ CL } "
2025-08-22 18:05:14 +02:00
fi
2026-04-01 23:09:51 +02:00
echo ""
done <<< " $NFS_STORAGES "
2025-08-22 18:05:14 +02:00
fi
2026-04-01 23:09:51 +02:00
2026-05-26 17:21:24 +02:00
# ---- Host fstab mounts (NOT pvesm) ----
local FSTAB_ENTRIES
FSTAB_ENTRIES = $( list_nfs_fstab_entries)
if [ [ -z " $FSTAB_ENTRIES " ] ] ; then
echo -e " ${ BOLD } $( translate "Host fstab NFS mounts:" ) ${ CL } $( translate "(none)" ) "
else
echo -e " ${ BOLD } $( translate "Host fstab NFS mounts (not registered with pvesm):" ) ${ CL } "
echo ""
while IFS = "|" read -r server export_path mount_path opts; do
[ [ -z " $mount_path " ] ] && continue
local mstate
mstate = $( check_mount_state " $mount_path " )
echo -e " ${ TAB } ${ BOLD } $( basename " $mount_path " ) ${ CL } ${ TAB } [fstab] "
echo -e " ${ TAB } ${ BGN } $( translate "Server:" ) ${ CL } ${ BL } $server ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Export:" ) ${ CL } ${ BL } $export_path ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Mount Path:" ) ${ CL } ${ BL } $mount_path ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Options:" ) ${ CL } ${ BL } $opts ${ CL } "
if [ [ " $mstate " = = "active" ] ] ; then
echo -e " ${ TAB } ${ BGN } $( translate "Status:" ) ${ CL } ${ GN } $( translate "Active" ) ${ CL } "
else
echo -e " ${ TAB } ${ BGN } $( translate "Status:" ) ${ CL } ${ RD } $( translate "Inactive (entry in fstab, not currently mounted)" ) ${ CL } "
fi
echo ""
done <<< " $FSTAB_ENTRIES "
fi
2026-04-01 23:09:51 +02:00
echo ""
msg_success " $( translate "Press Enter to continue..." ) "
2025-08-22 18:05:14 +02:00
read -r
}
2026-04-01 23:09:51 +02:00
remove_nfs_storage( ) {
2026-05-26 17:21:24 +02:00
# Collect every removable NFS entry: pvesm storages and fstab-only mounts.
local OPTIONS = ( )
local has_pvesm = 0
local has_fstab = 0
# pvesm-registered NFS storages
if command -v pvesm >/dev/null 2>& 1; then
local NFS_STORAGES
NFS_STORAGES = $( pvesm status 2>/dev/null | awk '$2 == "nfs" {print $1}' )
if [ [ -n " $NFS_STORAGES " ] ] ; then
has_pvesm = 1
while IFS = read -r storage_id; do
[ [ -z " $storage_id " ] ] && continue
local storage_info server export_path
storage_info = $( get_storage_config " $storage_id " )
server = $( echo " $storage_info " | awk '$1 == "server" {print $2}' )
export_path = $( echo " $storage_info " | awk '$1 == "export" {print $2}' )
# Encode key with a prefix so we know how to handle the selection.
OPTIONS += ( " pvesm: $storage_id " " [pvesm] $storage_id ( $server : $export_path ) " )
done <<< " $NFS_STORAGES "
fi
2025-08-22 18:05:14 +02:00
fi
2026-05-26 17:21:24 +02:00
# fstab-only NFS mounts
local FSTAB_ENTRIES
FSTAB_ENTRIES = $( list_nfs_fstab_entries)
if [ [ -n " $FSTAB_ENTRIES " ] ] ; then
has_fstab = 1
while IFS = "|" read -r server export_path mount_path opts; do
[ [ -z " $mount_path " ] ] && continue
OPTIONS += ( " fstab: $mount_path " " [fstab] $mount_path ( $server : $export_path ) " )
done <<< " $FSTAB_ENTRIES "
fi
if [ [ " $has_pvesm " = = "0" && " $has_fstab " = = "0" ] ] ; then
dialog --backtitle "ProxMenux" --title " $( translate "Nothing to remove" ) " \
--msgbox " \n $( translate "No NFS Proxmox storage and no NFS fstab mount found on this host." ) " 9 70
2025-08-22 18:05:14 +02:00
return
fi
2026-05-26 17:21:24 +02:00
local SELECTED
SELECTED = $( dialog --backtitle "ProxMenux" --title " $( translate "Remove NFS Mount" ) " \
--menu " $( translate "Select the entry to remove. [pvesm] entries are removed from Proxmox storage; [fstab] entries are unmounted and removed from /etc/fstab." ) " \
20 90 12 \
2026-04-01 23:09:51 +02:00
" ${ OPTIONS [@] } " 3>& 1 1>& 2 2>& 3)
[ [ -z " $SELECTED " ] ] && return
2026-05-26 17:21:24 +02:00
local kind = " ${ SELECTED %% : * } "
local target = " ${ SELECTED #* : } "
2026-04-01 23:09:51 +02:00
2026-05-26 17:21:24 +02:00
case " $kind " in
pvesm)
local storage_info server export_path content
storage_info = $( get_storage_config " $target " )
server = $( echo " $storage_info " | awk '$1 == "server" {print $2}' )
export_path = $( echo " $storage_info " | awk '$1 == "export" {print $2}' )
content = $( echo " $storage_info " | awk '$1 == "content" {print $2}' )
2026-04-01 23:09:51 +02:00
2026-05-26 17:21:24 +02:00
if whiptail --yesno " $( translate "Remove Proxmox NFS storage:" ) \n\n $target \n\n $( translate "Server:" ) : $server \n $( translate "Export:" ) : $export_path \n $( translate "Content:" ) : $content \n\n $( translate "WARNING: This removes the storage from Proxmox. The NFS server is not affected." ) " \
16 80 --title " $( translate "Confirm Remove" ) " ; then
2026-04-01 23:09:51 +02:00
2026-05-26 17:21:24 +02:00
show_proxmenux_logo
msg_title " $( translate "Remove NFS Storage" ) "
2026-04-01 23:09:51 +02:00
2026-05-26 17:21:24 +02:00
if pvesm remove " $target " 2>/dev/null; then
msg_ok " $( translate "Storage" ) $target $( translate "removed successfully from Proxmox." ) "
else
msg_error " $( translate "Failed to remove storage." ) "
fi
echo -e ""
msg_success " $( translate "Press Enter to continue..." ) "
read -r
fi
; ;
fstab)
local mount_path = " $target "
local fstab_line
fstab_line = $( awk -v mp = " $mount_path " '$2 == mp && ($3 == "nfs" || $3 == "nfs4") {print; exit}' /etc/fstab)
if whiptail --yesno " $( translate "Remove NFS fstab mount:" ) \n\n $mount_path \n\n $( translate "fstab line:" ) \n $fstab_line \n\n $( translate "Steps that will run:" ) \n 1. $( translate "umount the path if currently mounted" ) \n 2. $( translate "delete the matching line from /etc/fstab" ) \n 3. $( translate "remove the (now-empty) directory if possible" ) \n\n $( translate "WARNING: The NFS server is not affected. The mount directory contents are NOT deleted (data stays on the server)." ) " \
20 90 --title " $( translate "Confirm Remove" ) " ; then
show_proxmenux_logo
msg_title " $( translate "Remove NFS fstab Mount" ) "
# Try umount only if currently mounted; never force.
if mount | grep -q " on ${ mount_path } type " ; then
if umount " $mount_path " 2>/dev/null; then
msg_ok " $( translate "Unmounted:" ) $mount_path "
else
msg_warn " $( translate "Could not unmount" ) $mount_path . $( translate "The fstab entry will still be removed; reboot or manual umount needed." ) "
fi
else
msg_info2 " $( translate "Not currently mounted — skipping umount." ) "
fi
# Delete the matching line(s) from /etc/fstab using awk (exact $2 + $3 match).
cp /etc/fstab /etc/fstab.proxmenux.bak 2>/dev/null
if awk -v mp = " $mount_path " '
$2 = = mp && ( $3 = = "nfs" || $3 = = "nfs4" ) { next }
{ print }
' /etc/fstab > /etc/fstab.tmp && mv /etc/fstab.tmp /etc/fstab; then
msg_ok " $( translate "Removed entry from /etc/fstab" ) ( $( translate "backup at /etc/fstab.proxmenux.bak" ) ) "
else
msg_error " $( translate "Failed to edit /etc/fstab — remove the line manually." ) "
fi
systemctl daemon-reload 2>/dev/null || true
# Try to remove the directory if empty; keep it otherwise.
if [ [ -d " $mount_path " ] ] && rmdir " $mount_path " 2>/dev/null; then
msg_ok " $( translate "Removed empty mount directory:" ) $mount_path "
fi
echo -e ""
msg_success " $( translate "Press Enter to continue..." ) "
read -r
fi
; ;
esac
2025-08-22 18:05:14 +02:00
}
2026-04-01 23:09:51 +02:00
test_nfs_connectivity( ) {
2025-08-22 18:05:14 +02:00
show_proxmenux_logo
2026-04-01 23:09:51 +02:00
msg_title " $( translate "Test NFS Connectivity" ) "
echo "=================================================="
echo ""
2025-08-22 18:05:14 +02:00
if which showmount >/dev/null 2>& 1; then
2026-04-01 23:09:51 +02:00
msg_ok " $( translate "NFS Client Tools: AVAILABLE" ) "
2025-08-22 18:05:14 +02:00
if systemctl is-active --quiet rpcbind 2>/dev/null; then
2026-04-01 23:09:51 +02:00
msg_ok " $( translate "RPC Bind Service: RUNNING" ) "
2025-08-22 18:05:14 +02:00
else
2026-04-01 23:09:51 +02:00
msg_warn " $( translate "RPC Bind Service: STOPPED - starting..." ) "
2025-08-22 18:05:14 +02:00
systemctl start rpcbind 2>/dev/null || true
fi
2026-04-01 23:09:51 +02:00
else
msg_warn " $( translate "NFS Client Tools: NOT AVAILABLE" ) "
fi
echo ""
if command -v pvesm >/dev/null 2>& 1; then
echo -e " ${ BOLD } $( translate "Proxmox NFS Storage Status:" ) ${ CL } "
NFS_STORAGES = $( pvesm status 2>/dev/null | awk '$2 == "nfs" {print $1, $3}' )
if [ [ -n " $NFS_STORAGES " ] ] ; then
while IFS = " " read -r storage_id storage_status; do
[ [ -z " $storage_id " ] ] && continue
local server
server = $( get_storage_config " $storage_id " | awk '$1 == "server" {print $2}' )
2026-05-26 17:21:24 +02:00
echo -n " [pvesm] $storage_id ( $server ): "
2026-04-01 23:09:51 +02:00
if ping -c 1 -W 2 " $server " >/dev/null 2>& 1; then
echo -ne " ${ GN } $( translate "Reachable" ) ${ CL } "
if nc -z -w 2 " $server " 2049 2>/dev/null; then
echo -e " | NFS port 2049: ${ GN } $( translate "Open" ) ${ CL } "
else
echo -e " | NFS port 2049: ${ RD } $( translate "Closed" ) ${ CL } "
fi
if showmount -e " $server " >/dev/null 2>& 1; then
echo -e " $( translate "Export list:" ) ${ GN } $( translate "Available" ) ${ CL } "
2025-08-22 18:05:14 +02:00
else
2026-04-01 23:09:51 +02:00
echo -e " $( translate "Export list:" ) ${ RD } $( translate "Failed" ) ${ CL } "
2025-08-22 18:05:14 +02:00
fi
2026-04-01 23:09:51 +02:00
else
echo -e " ${ RD } $( translate "Unreachable" ) ${ CL } "
2025-08-22 18:05:14 +02:00
fi
2026-04-01 23:09:51 +02:00
if [ [ " $storage_status " = = "active" ] ] ; then
echo -e " $( translate "Proxmox status:" ) ${ GN } $storage_status ${ CL } "
else
echo -e " $( translate "Proxmox status:" ) ${ RD } $storage_status ${ CL } "
fi
echo ""
done <<< " $NFS_STORAGES "
2025-08-22 18:05:14 +02:00
else
2026-05-26 17:21:24 +02:00
echo " $( translate "No NFS Proxmox storage configured." ) "
2025-08-22 18:05:14 +02:00
fi
else
2026-04-01 23:09:51 +02:00
msg_warn " $( translate "pvesm not available." ) "
2025-08-22 18:05:14 +02:00
fi
2025-08-30 18:56:49 +02:00
2026-05-26 17:21:24 +02:00
# ---- fstab-only NFS mounts ----
local FSTAB_ENTRIES
FSTAB_ENTRIES = $( list_nfs_fstab_entries)
echo ""
echo -e " ${ BOLD } $( translate "Host fstab NFS Mounts:" ) ${ CL } "
if [ [ -z " $FSTAB_ENTRIES " ] ] ; then
echo " $( translate "(none)" ) "
else
while IFS = "|" read -r server export_path mount_path opts; do
[ [ -z " $mount_path " ] ] && continue
echo -n " [fstab] $mount_path ( $server : $export_path ): "
if ping -c 1 -W 2 " $server " >/dev/null 2>& 1; then
echo -ne " ${ GN } $( translate "Reachable" ) ${ CL } "
if nc -z -w 2 " $server " 2049 2>/dev/null; then
echo -e " | NFS port 2049: ${ GN } $( translate "Open" ) ${ CL } "
else
echo -e " | NFS port 2049: ${ RD } $( translate "Closed" ) ${ CL } "
fi
else
echo -e " ${ RD } $( translate "Unreachable" ) ${ CL } "
fi
local mstate
mstate = $( check_mount_state " $mount_path " )
if [ [ " $mstate " = = "active" ] ] ; then
echo -e " $( translate "Mount status:" ) ${ GN } $( translate "Active" ) ${ CL } "
else
echo -e " $( translate "Mount status:" ) ${ RD } $( translate "Not currently mounted" ) ${ CL } "
fi
echo ""
done <<< " $FSTAB_ENTRIES "
fi
2025-08-30 18:56:49 +02:00
echo ""
2026-04-01 23:09:51 +02:00
msg_success " $( translate "Press Enter to continue..." ) "
2025-08-22 18:05:14 +02:00
read -r
}
2026-04-01 23:09:51 +02:00
# ==========================================================
# MAIN MENU
# ==========================================================
2025-08-22 18:05:14 +02:00
while true; do
2026-04-01 23:09:51 +02:00
CHOICE = $( dialog --backtitle "ProxMenux" \
--title " $( translate "NFS Host Manager - Proxmox Host" ) " \
--menu " $( translate "Choose an option:" ) " 18 70 6 \
2026-05-26 12:41:50 +02:00
"1" " $( translate "Mount NFS Share on Host" ) " \
2026-05-26 17:21:24 +02:00
"2" " $( translate "View NFS Mounts (pvesm + fstab)" ) " \
"3" " $( translate "Remove NFS Mount (pvesm or fstab)" ) " \
2026-04-01 23:09:51 +02:00
"4" " $( translate "Test NFS Connectivity" ) " \
"5" " $( translate "Exit" ) " \
3>& 1 1>& 2 2>& 3)
2025-08-22 18:05:14 +02:00
RETVAL = $?
if [ [ $RETVAL -ne 0 ] ] ; then
exit 0
fi
2026-04-01 23:09:51 +02:00
2025-08-22 18:05:14 +02:00
case $CHOICE in
2026-05-26 12:41:50 +02:00
1) mount_nfs_share ; ;
2026-04-01 23:09:51 +02:00
2) view_nfs_storages ; ;
3) remove_nfs_storage ; ;
4) test_nfs_connectivity ; ;
5) exit 0 ; ;
2025-08-22 18:05:14 +02:00
*) exit 0 ; ;
esac
2025-09-03 23:13:21 +02:00
done