En el mundo de la informática, pocas cosas más molestas hay que un disco duro pase a mejor vida, lo que además siempre será en el peor momento. El siguiente script revisa todos los discos duros instalados (externos o internos) y envía una notificación por Telegram si detecta que a uno o más de los discos le queda poco tiempo de vida. Al recibir un mensaje así, sabemos que debemos sustituir esa unidad por otra nueva, idealmente sería clonada en su reemplazo.
#!/bin/bash
BOT_TOKEN="EL TOKEN DE TU BOT"
CHAT_ID="EL ID DE TU CUENTA EN TELEGRAM"
LOG_FILE=/var/log/check_disks.log # El log se limpiará mediante logrotate.
HOSTNAME=$(hostname)
# Se añaden las rutas por si cron o anacron las necesitan
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
enviar_alerta() {
local mensaje="$HOSTNAME tiene la siguiente alerta de disco: $1"
# Enviar notificación a Telegram
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d "chat_id=$CHAT_ID" \
--data-urlencode "text=$mensaje" > /dev/null
}
# sd[a-z]: Linux no mantiene fijo el fichero del disco sino que se lo asigna en función del orden de "llegada" (orden en que "despiertan" los discos)
for disco in /dev/sd[a-z]; do
# Si no es un fichero de disco salta al siguiente dispositivo
if ! test -b "$disco" ; then
continue
fi
# El flag -n standby evita despertar al disco si está dormido, así se evita desgaste innecesario.
LSTR=$(smartctl -H -n standby "$disco" 2>&1)
# Los dormidos que sigan con Morfeo. El lector de tarjetas vacío (usb bridge) se ignora:
if echo "$LSTR" | grep -iqE "Device is in Standby|unknown usb bridge"; then
continue
fi
# Si la salud general no es PASSED, alerta al canto
if ! echo "$LSTR" | grep -qE "PASSED|OK"; then
# Extrae modelo y nº de serie del disco
IDENTIDAD=$(lsblk -d -n -o MODEL,SERIAL "$disco" | xargs)
# fallback para embellecer el mensaje en el improbable caso de que lsblk salga con un chorro de babas
if test -z "$IDENTIDAD" ; then
IDENTIDAD="desconocido"
fi
MENSAJE="El disco [$IDENTIDAD] (actualmente $disco) reporta problemas. Output: $LSTR"
enviar_alerta "$MENSAJE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $MENSAJE" >> $LOG_FILE
fi
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Chequeo finalizado." >> $LOG_FILE
El añadido de rutas (PATH) es para evitar posibles problemas derivados del hecho de que el cron se ejecuta en entornos muy restringidos, es decir, cuando el usuario abre una terminal tiene un PATH completo, pero un cron que arranca de forma automática en segundo plano lo hace con un PATH mínimo, que podría ser meramente «/usr/bin:/bin». En este sentido, debe tenerse en cuenta que el script debe programarse en el crontab de root o no podrá accederse a la información del disco duro:
vic@blackBox:/etc$ smartctl -H /dev/sda
smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.8.0-124-generic] (local build)
Copyright (C) 2002-23, Bruce Allen, Christian Franke, www.smartmontools.org
Smartctl open device: /dev/sda failed: Permission denied
El script funciona tanto para discos duros sólidos como mecánicos. Requiere tener instalados smartmontools (que proporciona smartctl) y util-linux (que proporciona lsblk). Además, tiene una feature que si para ti es un bug puedes borrarla fácilmente: Cuando un disco duro está «dormido» (en standby), lo cual es habitual en discos duros externos dedicados a las copias de seguridad, no es interrogado acerca de su estado para evitar que arranque y se desgaste innecesariamente. Como la necesidad o no de algo es relativa, depende de las circunstancias, se pueden despertar para interrogarlos eliminando el «Device is in Standby» de la orden grep del condicional. La otra cadena que busca ese grep es para evitar que el lector de tarjetas SD dé un falso positivo.
Lo mejor es programar el script para que se ejecute periódicamente mediante crontab, siendo la periodicidad semanal la ideal para todos los equipos que no sean servidores, debiendo aumentarse para estos últimos. Por cierto, si no se trata de un servidor y el equipo no está siempre encendido, como es el caso de la mayor parte de equipos domésticos, se puede programar mediante Anacron, también disponible en el ecosistema Linux / UNIX, para asegurar su ejecución semanal.
En el caso de tener el script ejecutándose en diferentes máquinas, ya sean servidores, ordenadores de la familia, de un centro educativo o de una empresa, la variable HOSTNAME nos identificará cuál de ellas tiene el disco duro desgastado.
¿Por qué Telegram?
La notificación se hace mediante Telegram simplemente por ser muy fácil su realización, pero también se podría usar una cuenta de correo (por ejemplo Gmail) en la que identificarse y enviar el correo mediante curl. La creación de un bot es muy fácil en Telegram: sólo debemos empezar con «/start» la charla con BotFather y nos guiará en el proceso:
Al final del proceso nos indicará el token para poder acceder a la API de nuestro bot. En la constante CHAT_ID debemos poner el identificador de nuestro usuario de Telegram, pues en realidad esta aplicación de mensajería trabaja con chats, no con usuarios. Una vez más, enviar un «/start» al bot «User Info · Get ID · idbot» nos devuelve el ID, entre otros datos.
Finalmente, aclarar que si el fichero de log se crea en /var/log/ es para delegar a logrotate, la herramienta nativa de Linux encargada de trocear, comprimir y eliminar logs antiguos, la gestión del fichero y así poder disfrutar de la filosofía Linux de «configurar y olvidar». Sólo queda configurarlo en «/etc/logrotate.d/». A modo de ejemplo, esta es mi configuración:
vic@blackBox:/etc$ cat /etc/logrotate.d/check-disks /var/log/check_disks.log { weekly rotate 4 missingok notifempty create 0640 root root }
El código también está disponible en GitHub.
