Krolyxon
Commit 1f888d7

Branches

Refs →

aurora.localbinmounter

81 lines ยท 3.4 KB ยท Bourne Again Shell (bash)

1#!/bin/sh
2# Menu to mount drives, LUKS partitions and Android phones, the standard way:
3# udisks mounts drives to /run/media/$USER/<label> (fstab entries to their fstab
4# target) and unlocks LUKS with a passphrase asked in aurora's runner; phones go
5# through gvfs (/run/user/$UID/gvfs/mtp:host=...). Root is asked via polkit. See unmounter.
6
7menu() { aurora-run -d -p "$1"; }
8notify() { notify-send -a mounter "$@"; }
9# Lock a LUKS device we unlocked if we bail out before mounting it.
10cancel() { [ -n "$unlocked" ] && udisksctl lock -b "$unlocked" >/dev/null 2>&1; exit 1; }
11die() { notify -u critical "๐Ÿ’พ Mount failed" "$1"; cancel; }
12
13# "๐Ÿ’พ /dev/sdb1 32G LABEL (vfat)" per unmounted filesystem; LUKS only while locked
14# (an open one is listed as its mapper). jq instead of parsing lsblk: labels are arbitrary.
15drives() {
16 lsblk -Jpo NAME,TYPE,FSTYPE,SIZE,LABEL,MOUNTPOINT | jq -r '
17 .. | objects | select(has("name"))
18 | select((.type | test("^(part|disk|rom|crypt)$")) and .fstype != null and .mountpoint == null)
19 | select(.fstype | test("^(swap|LVM2_member|linux_raid_member)$") | not)
20 | select(.fstype != "crypto_LUKS" or ((.children // []) | length) == 0)
21 | (if .fstype == "crypto_LUKS" then "๐Ÿ”’" else "๐Ÿ’พ" end) as $icon
22 | "\($icon) \(.name) \(.size) \(if .label then .label + " " else "" end)(\(.fstype | sub("crypto_"; "")))"'
23}
24
25# "๐Ÿ“ฑ mtp://Google_Pixel_7_XXXX/ Pixel 7" per unmounted phone, from gvfs's volume list.
26phones() {
27 mounted="$(gio mount -l 2>/dev/null)"
28 gio mount -li 2>/dev/null | awk '
29 /^ *Volume\([0-9]+\): / { sub(/^ *Volume\([0-9]+\): /, ""); name = $0 }
30 /^ *activation_root=mtp:\/\// { sub(/^ *activation_root=/, ""); print $0 "\t" name }' |
31 while IFS=" " read -r uri name; do
32 printf '%s\n' "$mounted" | grep -qF -- "-> $uri" && continue
33 printf '๐Ÿ“ฑ %s %s\n' "$uri" "$name"
34 done
35}
36
37mountphone() {
38 uri="$1"
39 err="$(gio mount "$uri" 2>&1)" ||
40 die "$err
41Unlock the phone and set USB to File transfer."
42 notify "๐Ÿ“ฑ Phone mounted" "${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/gvfs/mtp:host=$(echo "$uri" | sed 's|^mtp://||; s|/$||')"
43}
44
45mountdrive() {
46 dev="$1"
47
48 if [ "$(lsblk -dno FSTYPE "$dev")" = "crypto_LUKS" ]; then
49 pass="$(aurora-run -d --password --lines=0 --prompt="๐Ÿ”’" --placeholder="Passphrase for $dev" </dev/null)" || exit 1
50 out="$(printf '%s' "$pass" | udisksctl unlock -b "$dev" --key-file /dev/stdin 2>&1)" ||
51 die "Could not unlock $dev: $out"
52 unset pass
53 unlocked="$dev"
54 # "Unlocked /dev/sda2 as /dev/dm-3."
55 dev="$(echo "$out" | sed -n 's/.* as \(.*\)\.$/\1/p')"
56 udevadm settle 2>/dev/null
57 [ -n "$(lsblk -dno FSTYPE "$dev")" ] || die "$unlocked unlocked, but has no filesystem on it."
58 fi
59
60 # "Mounted /dev/sdb1 at /run/media/k/LABEL" (older udisks add a trailing dot)
61 out="$(udisksctl mount -b "$dev" 2>&1)" || die "$out"
62 mp="$(echo "$out" | sed -n 's/^Mounted .* at \(.*\)$/\1/p' | sed 's/\.$//')"
63
64 # Linux filesystems keep their owner: offer to take the root dir of the drive.
65 if [ -n "$mp" ] && [ ! -w "$mp" ]; then
66 owner="$(stat -c %U "$mp")"
67 [ "$(printf 'Yes\nNo' | menu "$mp is owned by $owner. Make it yours?")" = "Yes" ] &&
68 pkexec chown "$(id -u):$(id -g)" "$mp"
69 fi
70 notify "๐Ÿ’พ Mounted" "$dev โ†’ ${mp:-$out}"
71}
72
73list="$(drives; phones)"
74[ -z "$list" ] && { notify "๐Ÿ’พ Mounter" "Nothing to mount."; exit 0; }
75
76chosen="$(echo "$list" | menu "Mount")" || exit 1
77target="$(echo "$chosen" | awk '{print $2}')"
78case "$chosen" in
79 "๐Ÿ“ฑ"*) mountphone "$target" ;;
80 *) mountdrive "$target" ;;
81esac