Automontaje de USB, suspender con batería agotada, bloqueo por inactividad y TLP
- 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
This commit is contained in:
parent
2c2adaaa79
commit
2850a4fc73
7 changed files with 148 additions and 10 deletions
19
README.md
19
README.md
|
|
@ -43,9 +43,11 @@ Hace seis pasos, que también se pueden lanzar por separado
|
|||
subclaves de autenticación. `.bashrc` ya apunta `SSH_AUTH_SOCK` al agente.
|
||||
Si `~/.gnupg` no existe todavía, no hace nada.
|
||||
6. `sistema`: copia `sistema/` en `/`, activa los servicios de runit (dbus,
|
||||
elogind, polkitd, NetworkManager, bluetoothd, acpid, chronyd), quita
|
||||
dhcpcd y wpa_supplicant (NetworkManager ya gestiona la red) y añade el
|
||||
usuario a los grupos audio, video, input, network y bluetooth.
|
||||
elogind, polkitd, NetworkManager, bluetoothd, acpid, chronyd, tlp,
|
||||
automontaje), quita dhcpcd y wpa_supplicant (NetworkManager ya gestiona la
|
||||
red) y añade el usuario a los grupos audio, video, input, network y
|
||||
bluetooth. Los archivos de `sudoers.d` se validan con `visudo` y se
|
||||
instalan con modo 440.
|
||||
|
||||
Después hay que cerrar sesión y volver a entrar (por los grupos) y lanzar
|
||||
`startx`.
|
||||
|
|
@ -109,7 +111,16 @@ y muestran una notificación.
|
|||
- Al entrar en tty1 se lanza `startx` solo (`.bash_profile`); en las demás
|
||||
tty no.
|
||||
- `.xinitrc` arranca también `gammastep` (luz cálida de 20:00 a 8:00, con
|
||||
transición de una hora) y `bateria` (avisa al 15 % y, en rojo, al 5 %).
|
||||
transición de una hora) y `bateria` (avisa al 15 % y, en rojo, al 5 %; al
|
||||
3 % suspende con `sudo -n zzz`, permitido sin contraseña en
|
||||
`sistema/etc/sudoers.d/zzz`).
|
||||
- Tras 30 minutos sin tocar nada se bloquea con slock (`xss-lock`) y un
|
||||
minuto después se apaga la pantalla.
|
||||
- Memorias USB y tarjetas SD: el servicio `automontaje` (runit, como root)
|
||||
las monta en `/mnt/ETIQUETA`, o en `/mnt/sdXY` si no tienen etiqueta, y
|
||||
las desmonta al sacarlas, con una notificación. FAT, exFAT y NTFS quedan a
|
||||
nombre del usuario; los discos internos no se tocan. Antes de sacar una
|
||||
memoria en la que se ha escrito, `sync` (o `sudo umount /mnt/...`).
|
||||
- Carpetas del usuario en inglés y sin tildes (`user-dirs.dirs`):
|
||||
Documents, Downloads e Images.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
#!/bin/sh
|
||||
# Avisa con una notificación cuando la batería baja del 15 % y del 5 %
|
||||
# mientras se descarga (una vez por umbral; al enchufar el cargador se
|
||||
# reinicia). Se lanza desde .xinitrc y se queda comprobando cada minuto.
|
||||
# mientras se descarga, y al 3 % suspende (con slock, como al cerrar la
|
||||
# tapa) en vez de dejar que se apague de golpe. Cada umbral actúa una vez;
|
||||
# al enchufar el cargador se reinicia. Se lanza desde .xinitrc y comprueba
|
||||
# cada minuto. Suspender usa "sudo -n zzz" (regla en sistema/etc/sudoers.d).
|
||||
|
||||
BAJA=15
|
||||
CRITICA=5
|
||||
SUSPENDER=3
|
||||
|
||||
bat=
|
||||
for b in /sys/class/power_supply/BAT*; do
|
||||
|
|
@ -18,6 +21,12 @@ while :; do
|
|||
estado=$(cat "$bat/status")
|
||||
if [ "$estado" != Discharging ]; then
|
||||
avisado=100
|
||||
elif [ "$nivel" -le "$SUSPENDER" ] && [ "$avisado" -gt "$SUSPENDER" ]; then
|
||||
notify-send -u critical -h string:x-dunst-stack-tag:bateria \
|
||||
-i battery-empty "Batería agotada" "Queda un $nivel %: suspendiendo en 10 s"
|
||||
avisado=$SUSPENDER
|
||||
sleep 10
|
||||
[ "$(cat "$bat/status")" = Discharging ] && sudo -n zzz
|
||||
elif [ "$nivel" -le "$CRITICA" ] && [ "$avisado" -gt "$CRITICA" ]; then
|
||||
notify-send -u critical -h string:x-dunst-stack-tag:bateria \
|
||||
-i battery-empty "Batería crítica" "Queda un $nivel %: enchufa el cargador ya"
|
||||
|
|
|
|||
|
|
@ -34,4 +34,10 @@ clipmenud &
|
|||
gammastep &
|
||||
bateria &
|
||||
|
||||
# Bloquear con slock tras 30 minutos sin tocar nada, y apagar la pantalla un
|
||||
# minuto después. Al suspender ya bloquea el hook de zzz (--ignore-sleep).
|
||||
xset s 1800 1800
|
||||
xset dpms 0 0 1860
|
||||
xss-lock --ignore-sleep -- slock &
|
||||
|
||||
exec dwm
|
||||
|
|
|
|||
16
install.sh
16
install.sh
|
|
@ -17,9 +17,9 @@ PAQUETES="
|
|||
libXrender-devel xorgproto imlib2-devel zlib-devel libxcrypt-devel
|
||||
|
||||
xorg xinit setxkbmap xrandr dbus elogind polkit
|
||||
picom dunst libnotify feh maim xclip gammastep
|
||||
picom dunst libnotify feh maim xclip gammastep xss-lock
|
||||
pipewire wireplumber libspa-bluetooth alsa-pipewire rtkit pavucontrol
|
||||
NetworkManager bluez blueman acpid chrony
|
||||
NetworkManager bluez blueman acpid chrony tlp tlp-rdw
|
||||
font-firacode nerd-fonts-symbols-ttf papirus-icon-theme papirus-folders
|
||||
sassc gtk-engine-murrine gnome-themes-extra qt5ct qt6ct
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ SUCKLESS="dwm st dmenu slstatus slock scroll clipmenu"
|
|||
# Tema GTK Everforest, en una versión fija para que siempre salga igual
|
||||
GTK_TEMA_REPO=https://github.com/Fausto-Korpsvart/Everforest-GTK-Theme
|
||||
GTK_TEMA_COMMIT=9b8be4d6648ae9eaae3dd550105081f8c9054825
|
||||
SERVICIOS="dbus elogind polkitd NetworkManager bluetoothd acpid chronyd"
|
||||
SERVICIOS="dbus elogind polkitd NetworkManager bluetoothd acpid chronyd tlp automontaje"
|
||||
# NetworkManager gestiona la red él solo; estos servicios se pelean con él.
|
||||
SERVICIOS_FUERA="dhcpcd wpa_supplicant"
|
||||
GRUPOS="audio video input network bluetooth"
|
||||
|
|
@ -159,7 +159,15 @@ sistema() {
|
|||
cd "$DIR/sistema"
|
||||
find . -type f | while read -r f; do
|
||||
f=${f#.}
|
||||
sudo install -D -m "$(stat -c %a ".$f")" ".$f" "$f"
|
||||
case $f in
|
||||
/etc/sudoers.d/*)
|
||||
# git no guarda el modo 440 que exige sudo; y un sudoers
|
||||
# roto deja sin sudo, así que se valida antes de copiarlo.
|
||||
visudo -cf ".$f" >/dev/null || die "sudoers inválido: $f"
|
||||
sudo install -D -m 440 ".$f" "$f"
|
||||
;;
|
||||
*) sudo install -D -m "$(stat -c %a ".$f")" ".$f" "$f" ;;
|
||||
esac
|
||||
echo " $f"
|
||||
done
|
||||
cd "$DIR"
|
||||
|
|
|
|||
3
sistema/etc/sudoers.d/zzz
Normal file
3
sistema/etc/sudoers.d/zzz
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# El script bateria suspende con "sudo -n zzz" cuando la batería llega al
|
||||
# límite. Solo zzz sin argumentos, sin contraseña, para los de wheel.
|
||||
%wheel ALL=(root) NOPASSWD: /usr/bin/zzz ""
|
||||
3
sistema/etc/sv/automontaje/run
Executable file
3
sistema/etc/sv/automontaje/run
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
exec 2>&1
|
||||
exec /usr/local/bin/automontaje
|
||||
98
sistema/usr/local/bin/automontaje
Executable file
98
sistema/usr/local/bin/automontaje
Executable file
|
|
@ -0,0 +1,98 @@
|
|||
#!/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
|
||||
Loading…
Add table
Add a link
Reference in a new issue