- automontaje (servicio de runit, root): monta memorias USB y tarjetas SD en /mnt/ETIQUETA o /mnt/sdXY y las desmonta al sacarlas, con notificación. FAT/exFAT/NTFS (ntfs3 del kernel) a nombre del usuario; los discos internos (ID_BUS distinto de usb) no se tocan. - bateria: al 3 % sin cargador avisa y, si en 10 s sigue descargando, suspende con sudo -n zzz (sudoers.d/zzz: solo zzz sin argumentos, sin contraseña, para wheel). - .xinitrc: xss-lock bloquea con slock tras 30 min de inactividad y la pantalla se apaga un minuto después. - install.sh: xss-lock, tlp y tlp-rdw; servicios tlp y automontaje; los sudoers se validan con visudo y se instalan con modo 440. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UdJsHrbkmzhoCb6TthP2m
98 lines
2.8 KiB
Bash
Executable file
98 lines
2.8 KiB
Bash
Executable file
#!/bin/sh
|
|
# Monta solas las memorias USB y tarjetas SD en /mnt/ETIQUETA (o /mnt/sdXY
|
|
# si no tienen etiqueta) y las desmonta al sacarlas, avisando con una
|
|
# notificación al usuario de la sesión gráfica. Lo lanza runit como root
|
|
# (servicio automontaje). Los discos internos no se tocan.
|
|
|
|
# Usuario dueño de la sesión de dwm, o el primero normal (UID 1000).
|
|
usuario() {
|
|
pid=$(pgrep -xo dwm) && stat -c %u "/proc/$pid" || echo 1000
|
|
}
|
|
|
|
# avisar TÍTULO TEXTO: notificación en la sesión gráfica, si la hay
|
|
avisar() {
|
|
pid=$(pgrep -xo dwm) || return 0
|
|
nombre=$(getent passwd "$(stat -c %u "/proc/$pid")" | cut -d: -f1)
|
|
entorno=$(tr '\0' '\n' <"/proc/$pid/environ" |
|
|
grep -E '^(DISPLAY|DBUS_SESSION_BUS_ADDRESS|XDG_RUNTIME_DIR)=')
|
|
# shellcheck disable=SC2086
|
|
env $entorno chpst -u "$nombre" notify-send -i drive-removable-media \
|
|
"$1" "$2" >/dev/null 2>&1 &
|
|
}
|
|
|
|
montar() {
|
|
dev=$1 tipo=$2 etiqueta=$3
|
|
findmnt -rn -S "$dev" >/dev/null && return
|
|
|
|
dir=/mnt/$(printf %s "$etiqueta" | tr -c 'A-Za-z0-9._-' _)
|
|
if [ "$dir" = /mnt/ ] || mountpoint -q "$dir" ||
|
|
{ [ -d "$dir" ] && [ -n "$(ls -A "$dir")" ]; }; then
|
|
dir=/mnt/${dev#/dev/}
|
|
fi
|
|
|
|
# Los sistemas de archivos de Windows no guardan dueños: se montan a
|
|
# nombre del usuario para que pueda escribir sin sudo.
|
|
uid=$(usuario)
|
|
gid=$(getent passwd "$uid" | cut -d: -f4)
|
|
opts=nosuid,nodev,noatime
|
|
case $tipo in
|
|
vfat) opts=$opts,uid=$uid,gid=$gid,umask=022,utf8,flush ;;
|
|
exfat) opts=$opts,uid=$uid,gid=$gid,umask=022 ;;
|
|
ntfs) tipo=ntfs3 opts=$opts,uid=$uid,gid=$gid,umask=022 ;;
|
|
esac
|
|
|
|
mkdir -p "$dir"
|
|
if mount -t "$tipo" -o "$opts" "$dev" "$dir"; then
|
|
avisar "Memoria montada" "$dir"
|
|
else
|
|
rmdir "$dir" 2>/dev/null
|
|
avisar "No se pudo montar" "$dev ($tipo)"
|
|
fi
|
|
}
|
|
|
|
desmontar() {
|
|
dir=$(findmnt -rn -o TARGET -S "$1") || return 0
|
|
case $dir in /mnt/*) ;; *) return ;; esac
|
|
umount -l "$dir" && rmdir "$dir" 2>/dev/null
|
|
avisar "Memoria desconectada" "$dir"
|
|
}
|
|
|
|
limpiar() {
|
|
accion='' dev='' bus='' uso='' tipo='' etiqueta=''
|
|
}
|
|
|
|
# Lee eventos de udev (bloques KEY=VALOR separados por una línea vacía).
|
|
procesar() {
|
|
limpiar
|
|
while IFS= read -r linea; do
|
|
case $linea in
|
|
ACTION=*) accion=${linea#*=} ;;
|
|
DEVNAME=*) dev=${linea#*=} ;;
|
|
ID_BUS=*) bus=${linea#*=} ;;
|
|
ID_FS_USAGE=*) uso=${linea#*=} ;;
|
|
ID_FS_TYPE=*) tipo=${linea#*=} ;;
|
|
ID_FS_LABEL=*) etiqueta=${linea#*=} ;;
|
|
'')
|
|
case $bus:$dev in usb:* | *:/dev/mmcblk*) ;; *) dev='' ;; esac
|
|
if [ -n "$dev" ]; then
|
|
case $accion in
|
|
add | change) [ "$uso" = filesystem ] &&
|
|
montar "$dev" "$tipo" "$etiqueta" ;;
|
|
remove) desmontar "$dev" ;;
|
|
esac
|
|
fi
|
|
limpiar
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
{
|
|
# Primero lo que ya está conectado, luego los eventos nuevos
|
|
for d in /sys/class/block/*; do
|
|
echo ACTION=add
|
|
udevadm info --query=property --path="$d"
|
|
echo
|
|
done
|
|
exec udevadm monitor --udev --property --subsystem-match=block
|
|
} | procesar
|