Skip to content

Instantly share code, notes, and snippets.

@Bluscream
Created May 31, 2026 04:40
Show Gist options
  • Select an option

  • Save Bluscream/df09e8253f74ba8bf04c4feb38ff6c2a to your computer and use it in GitHub Desktop.

Select an option

Save Bluscream/df09e8253f74ba8bf04c4feb38ff6c2a to your computer and use it in GitHub Desktop.
#!/bin/bash
ACTION=$1
SMB_URL=$2
if [[ -z "$SMB_URL" ]]; then
kdialog --error "No SMB/NFS URL provided."
exit 1
fi
# Determine protocol and extract details
if [[ "$SMB_URL" =~ ^nfs:// ]]; then
PROTOCOL="nfs"
URL_NO_PREFIX=${SMB_URL#nfs://}
SERVER=$(echo "$URL_NO_PREFIX" | cut -d'/' -f1)
SHARE=$(echo "$URL_NO_PREFIX" | cut -d'/' -f2-)
SHARE=${SHARE%/} # Strip trailing slash
UNC="${SERVER}:/${SHARE}"
FS_TYPE="nfs"
OPTIONS="rw,soft"
elif [[ "$SMB_URL" =~ ^smb:// ]]; then
PROTOCOL="smb"
URL_NO_PREFIX=${SMB_URL#smb://}
SERVER=$(echo "$URL_NO_PREFIX" | cut -d'/' -f1)
SHARE=$(echo "$URL_NO_PREFIX" | cut -d'/' -f2)
UNC="//${SERVER}/${SHARE}"
FS_TYPE="cifs"
OPTIONS="uid=$(id -u),gid=$(id -g)"
else
kdialog --error "Unsupported protocol. Only smb:// and nfs:// paths are supported."
exit 1
fi
if [[ -z "$SERVER" || -z "$SHARE" ]]; then
kdialog --error "Invalid URL: $SMB_URL. Must specify a server and share path."
exit 1
fi
# Gather all names and IPs associated with the target server
SERVER_NAMES=()
SERVER_NAMES+=("$SERVER")
while read -r ip host extra; do
if [[ -n "$ip" ]]; then SERVER_NAMES+=("$ip"); fi
if [[ -n "$host" ]]; then SERVER_NAMES+=("$host"); fi
done < <(getent hosts "$SERVER" 2>/dev/null)
# Remove duplicates from SERVER_NAMES
SERVER_NAMES=($(echo "${SERVER_NAMES[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
# Helper function to match a UNC path regardless of hostname/IP differences
match_unc() {
local candidate=$1
[[ -z "$candidate" ]] && return 1
# Clean up standard formatting
local clean=${candidate#//}
local srv=$(echo "$clean" | cut -d'/' -f1 | cut -d':' -f1)
local shr=$(echo "$clean" | cut -d'/' -f2- | cut -d':' -f2-)
shr=${shr%/} # strip trailing slash
# Verify share matches
if [[ "${shr,,}" != "${SHARE,,}" ]]; then
return 1
fi
# Check if the server matches any alias/IP we found
for name in "${SERVER_NAMES[@]}"; do
if [[ "${srv,,}" == "${name,,}" ]]; then
return 0
fi
done
return 1
}
get_systemd_unit_for_unc() {
for f in /etc/systemd/system/*.mount; do
if [[ -f "$f" ]]; then
WHAT_LINE=$(grep "^What=" "$f" | cut -d'=' -f2- | xargs)
if match_unc "$WHAT_LINE"; then
echo "$f"
return 0
fi
fi
done
return 1
}
find_fstab_line() {
while read -r line; do
[[ "$line" =~ ^[[:space:]]*# ]] && continue
[[ -z "$line" ]] && continue
local first_col=$(echo "$line" | awk '{print $1}')
if match_unc "$first_col"; then
echo "$line"
return 0
fi
done < /etc/fstab
return 1
}
find_active_mount() {
findmnt -t cifs,nfs -n -o TARGET,SOURCE | while read -r mnt_target mnt_source; do
if match_unc "$mnt_source"; then
echo "$mnt_target"
return 0
fi
done
return 1
}
# Run matches
ACTIVE_MOUNT=$(find_active_mount)
FSTAB_LINE=$(find_fstab_line)
SYSTEMD_UNIT=$(get_systemd_unit_for_unc)
if [[ "$ACTION" == "mount" || "$ACTION" == "mount_temp" ]]; then
# Check if already mounted
if [[ -n "$FSTAB_LINE" ]]; then
kdialog --msgbox "This share is already configured in /etc/fstab."
exit 0
fi
if [[ -n "$SYSTEMD_UNIT" ]]; then
kdialog --msgbox "This share already has an active systemd mount unit."
exit 0
fi
if [[ -n "$ACTIVE_MOUNT" ]]; then
kdialog --msgbox "This share is already currently mounted at $ACTIVE_MOUNT."
exit 0
fi
if [[ "$ACTION" == "mount" ]]; then
MOUNT_METHOD=$(kdialog --radiolist "Select persistent mount method for $UNC:" \
"fstab" "/etc/fstab (Traditional)" on \
"systemd" "systemd .mount unit (Modern)" off)
if [[ -z "$MOUNT_METHOD" ]]; then exit 0; fi
TITLE="Select Local Mount Point for Persistent Mount of $UNC"
else
MOUNT_METHOD="temp"
TITLE="Select Local Mount Point for Temporary Mount of $UNC"
fi
DEFAULT_NAME="${SERVER}_${SHARE//\//_}"
CUSTOM_NAME=$(kdialog --inputbox "Enter a name for the mount folder:" "$DEFAULT_NAME" --title "Mount Folder Name")
if [[ $? -ne 0 || -z "$CUSTOM_NAME" ]]; then exit 0; fi
DEFAULT_DIR="/mnt/${PROTOCOL}/$CUSTOM_NAME"
DEFAULT_DIR=$(realpath -m "$DEFAULT_DIR")
# Prompt user for default path or custom selection
kdialog --yesno "Mount network share at this location?<br><br><b>$DEFAULT_DIR</b>" --title "Mount Location"
if [[ $? -eq 0 ]]; then
MOUNT_POINT="$DEFAULT_DIR"
else
# Select custom location
PARENT_DIR="/mnt/${PROTOCOL}"
MOUNT_POINT=$(kdialog --getexistingdirectory "$PARENT_DIR" --title "$TITLE")
if [[ -z "$MOUNT_POINT" ]]; then exit 0; fi
MOUNT_POINT=$(realpath -m "$MOUNT_POINT")
fi
CRED_FILE="/root/.smbcredentials_${SERVER}_${SHARE//\//_}"
# Define standard mounting generator helper
generate_mount_script() {
local method=$1
local opt=$2
local cred_script=$3
if [[ "$method" == "fstab" ]]; then
cat <<EOF
mkdir -p "$MOUNT_POINT"
$cred_script
echo "${UNC} ${MOUNT_POINT} ${FS_TYPE} ${opt} 0 0" >> /etc/fstab
if ! mount "${MOUNT_POINT}" 2>&1; then
# Rollback
sed -i '\|^[[:space:]]*${UNC}[[:space:]]|d' /etc/fstab
if [[ "$PROTOCOL" == "smb" ]]; then rm -f "$CRED_FILE"; fi
exit 1
fi
EOF
elif [[ "$method" == "systemd" ]]; then
cat <<EOF
mkdir -p "$MOUNT_POINT"
$cred_script
UNIT_NAME=\$(systemd-escape --path --suffix=mount "$MOUNT_POINT")
UNIT_FILE="/etc/systemd/system/\${UNIT_NAME}"
cat <<UNIT_EOF > "\$UNIT_FILE"
[Unit]
Description=Mount for $UNC
Requires=network-online.target
After=network-online.target
[Mount]
What=$UNC
Where=$MOUNT_POINT
Type=${FS_TYPE}
Options=$opt
[Install]
WantedBy=multi-user.target
UNIT_EOF
systemctl daemon-reload
systemctl enable "\$UNIT_NAME"
if ! systemctl start "\$UNIT_NAME" 2>&1; then
echo "--- systemd mount failed ---"
journalctl -u "\$UNIT_NAME" -n 15 --no-pager
# Rollback
systemctl disable "\$UNIT_NAME" || true
rm -f "\$UNIT_FILE"
systemctl daemon-reload
if [[ "$PROTOCOL" == "smb" ]]; then rm -f "$CRED_FILE"; fi
exit 1
fi
EOF
elif [[ "$method" == "temp" ]]; then
cat <<EOF
mkdir -p "$MOUNT_POINT"
$cred_script
if ! mount -t ${FS_TYPE} "$UNC" "$MOUNT_POINT" -o "$opt" 2>&1; then
if [[ "$PROTOCOL" == "smb" ]]; then rm -f "$CRED_FILE"; fi
exit 1
fi
EOF
fi
}
# First attempt: Try as guest/anonymous for SMB, or standard options for NFS
if [[ "$PROTOCOL" == "smb" ]]; then
CURRENT_OPTIONS="${OPTIONS},guest"
SCRIPT=$(generate_mount_script "$MOUNT_METHOD" "$CURRENT_OPTIONS" "")
else
SCRIPT=$(generate_mount_script "$MOUNT_METHOD" "$OPTIONS" "")
fi
# Execute first attempt
ERR_MSG=$(pkexec bash -c "$SCRIPT")
EXIT_CODE=$?
# Check if failed and is credential error (only relevant for SMB/CIFS)
if [[ $EXIT_CODE -ne 0 && "$PROTOCOL" == "smb" ]]; then
# Look for typical credential rejection indicators in output
if [[ "$ERR_MSG" =~ [Pp]ermission|[Aa]ccess|[Ll]ogon|[Kk]ey|[Cc]redential|13 ]]; then
# Prompt user for credentials
USERNAME=$(kdialog --inputbox "Guest mount failed. This share requires credentials.\n\nEnter username for $UNC:" "")
if [[ $? -eq 0 && -n "$USERNAME" ]]; then
PASSWORD=$(kdialog --password "Enter password for $USERNAME:")
if [[ $? -eq 0 ]]; then
# Reconfigure payload with credential settings
CURRENT_OPTIONS="${OPTIONS},credentials=${CRED_FILE}"
CRED_SCRIPT="echo 'username=${USERNAME}' > \"$CRED_FILE\"; echo 'password=${PASSWORD}' >> \"$CRED_FILE\"; chmod 600 \"$CRED_FILE\";"
SCRIPT=$(generate_mount_script "$MOUNT_METHOD" "$CURRENT_OPTIONS" "$CRED_SCRIPT")
# Re-attempt mounting with credentials
ERR_MSG=$(pkexec bash -c "$SCRIPT")
EXIT_CODE=$?
else
exit 0 # User canceled password
fi
else
exit 0 # User canceled username
fi
fi
fi
# Display final status popup
if [[ $EXIT_CODE -eq 0 ]]; then
if [[ "$MOUNT_METHOD" == "temp" ]]; then
kdialog --passivepopup "Successfully temporarily mounted $UNC to $MOUNT_POINT" 3
else
kdialog --passivepopup "Successfully permanently mounted $UNC to $MOUNT_POINT using $MOUNT_METHOD" 3
fi
else
if [[ -n "$ERR_MSG" ]]; then
kdialog --error "Failed to mount $UNC.\n\nError Details:\n$ERR_MSG"
else
kdialog --error "Failed to mount $UNC. Please verify your network settings and make sure mount tools are installed."
fi
fi
elif [[ "$ACTION" == "unmount" ]]; then
if [[ -z "$ACTIVE_MOUNT" && -z "$FSTAB_LINE" && -z "$SYSTEMD_UNIT" ]]; then
kdialog --error "Share is not currently mounted, nor is it configured in fstab/systemd."
exit 1
fi
# Determine exact UNCs and credentials used in fstab/systemd to clean them up properly
FSTAB_UNC=$(echo "$FSTAB_LINE" | awk '{print $1}')
if [[ -n "$SYSTEMD_UNIT" ]]; then
SYSTEMD_UNC=$(grep "^What=" "$SYSTEMD_UNIT" | cut -d'=' -f2- | xargs)
SYS_CLEAN=${SYSTEMD_UNC#//}
SYS_SERVER=$(echo "$SYS_CLEAN" | cut -d'/' -f1 | cut -d':' -f1)
SYS_SHARE=$(echo "$SYS_CLEAN" | cut -d'/' -f2- | cut -d':' -f2-)
SYS_SHARE=${SYS_SHARE%/}
CRED_FILE="/root/.smbcredentials_${SYS_SERVER}_${SYS_SHARE//\//_}"
UNIT_NAME=$(basename "$SYSTEMD_UNIT")
SCRIPT=$(cat <<EOF
systemctl stop "$UNIT_NAME" || true
systemctl disable "$UNIT_NAME" || true
rm -f "$SYSTEMD_UNIT"
systemctl daemon-reload
if [[ -n "$FSTAB_UNC" ]]; then sed -i '\|^[[:space:]]*'"$FSTAB_UNC"'[[:space:]]|d' /etc/fstab; fi
rm -f "$CRED_FILE"
if [[ -n "$ACTIVE_MOUNT" ]]; then rmdir "$ACTIVE_MOUNT" 2>/dev/null || true; fi
EOF
)
else
# Fstab or temporary mount
CLEAN_UNC="${FSTAB_UNC:-$UNC}"
CLEAN_SRC=${CLEAN_UNC#//}
CLEAN_SERVER=$(echo "$CLEAN_SRC" | cut -d'/' -f1 | cut -d':' -f1)
CLEAN_SHARE=$(echo "$CLEAN_SRC" | cut -d'/' -f2- | cut -d':' -f2-)
CLEAN_SHARE=${CLEAN_SHARE%/}
CRED_FILE="/root/.smbcredentials_${CLEAN_SERVER}_${CLEAN_SHARE//\//_}"
SCRIPT=$(cat <<EOF
if [[ -n "$ACTIVE_MOUNT" ]]; then umount "$ACTIVE_MOUNT" || true; fi
if [[ -n "$FSTAB_UNC" ]]; then sed -i '\|^[[:space:]]*'"$FSTAB_UNC"'[[:space:]]|d' /etc/fstab; fi
rm -f "$CRED_FILE"
rm -f "/root/.smbcredentials_${SERVER}_${SHARE//\//_}" # Fallback cleanup
if [[ -n "$ACTIVE_MOUNT" ]]; then rmdir "$ACTIVE_MOUNT" 2>/dev/null || true; fi
EOF
)
fi
pkexec bash -c "$SCRIPT"
if [[ $? -eq 0 ]]; then
kdialog --passivepopup "Successfully unmounted and cleaned up network share." 3
else
kdialog --error "Failed to unmount share."
fi
fi
[Desktop Entry]
Type=Service
ServiceTypes=KonqPopupMenu/Plugin
MimeType=inode/directory;
X-KDE-Protocols=smb,nfs
Actions=PermanentMount;TemporaryMount;PermanentUnmount;
[Desktop Action PermanentMount]
Name=Permanently Mount Network Share
Icon=drive-harddisk-network
Exec=sh -c '"$HOME/.local/bin/dolphin-smb-mount.sh" mount "$0"' %u
[Desktop Action TemporaryMount]
Name=Temporarily Mount Network Share
Icon=network-server
Exec=sh -c '"$HOME/.local/bin/dolphin-smb-mount.sh" mount_temp "$0"' %u
[Desktop Action PermanentUnmount]
Name=Unmount Network Share
Icon=media-eject
Exec=sh -c '"$HOME/.local/bin/dolphin-smb-mount.sh" unmount "$0"' %u
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment