Created
May 31, 2026 04:40
-
-
Save Bluscream/df09e8253f74ba8bf04c4feb38ff6c2a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [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