Add Drive Health (gustav0ar/drive-health) (#58)
* add Drive Health * declare optional package manager commands * use live Drive Health screenshot * hide redundant dependency subtitle * fix drive error counter alerts * stabilize transient SMART availability * address collector packaging review * refactor: use generic collector service name * test: harden collector packaging checks
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if (( EUID != 0 )); then
|
||||
echo "Run this installer with sudo." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
project_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
service_name="noctalia-drive-health"
|
||||
target_user="${SUDO_USER:-${1:-}}"
|
||||
|
||||
if [[ -z "$target_user" || "$target_user" == root ]] || ! id "$target_user" >/dev/null 2>&1; then
|
||||
echo "Unable to determine the desktop user. Run with sudo, or pass the username explicitly." >&2
|
||||
exit 1
|
||||
fi
|
||||
target_gid="$(id -g "$target_user")"
|
||||
|
||||
for dependency in sh smartctl lsblk systemctl install sed mktemp id; do
|
||||
if ! command -v "$dependency" >/dev/null 2>&1; then
|
||||
echo "Missing required command: $dependency" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
rendered_service="$(mktemp)"
|
||||
trap 'rm -f -- "$rendered_service"' EXIT
|
||||
sed "s/@TARGET_GID@/$target_gid/g" \
|
||||
"$project_dir/packaging/$service_name.service.in" >"$rendered_service"
|
||||
|
||||
install -Dm0755 \
|
||||
"$project_dir/scripts/collect_raw.sh" \
|
||||
"/usr/local/libexec/$service_name/collect_raw.sh"
|
||||
install -Dm0755 \
|
||||
"$project_dir/packaging/smart-action.sh" \
|
||||
"/usr/local/libexec/$service_name/smart-action.sh"
|
||||
install -Dm0644 \
|
||||
"$rendered_service" \
|
||||
"/etc/systemd/system/$service_name.service"
|
||||
install -Dm0644 \
|
||||
"$project_dir/packaging/$service_name.timer" \
|
||||
"/etc/systemd/system/$service_name.timer"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now "$service_name.timer"
|
||||
systemctl start "$service_name.service"
|
||||
|
||||
echo "Installed the read-only SMART collector."
|
||||
echo "Cache: /run/$service_name/raw.json"
|
||||
@@ -0,0 +1,36 @@
|
||||
[Unit]
|
||||
Description=Collect read-only SMART data for Noctalia Drive Health
|
||||
Documentation=man:smartctl(8)
|
||||
After=local-fs.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/sh /usr/local/libexec/noctalia-drive-health/collect_raw.sh --output /run/noctalia-drive-health/raw.json
|
||||
Group=@TARGET_GID@
|
||||
RuntimeDirectory=noctalia-drive-health
|
||||
RuntimeDirectoryMode=0750
|
||||
RuntimeDirectoryPreserve=yes
|
||||
UMask=0027
|
||||
StandardOutput=null
|
||||
StandardError=journal
|
||||
TimeoutStartSec=60s
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
PrivateNetwork=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ProtectHostname=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
ProtectClock=true
|
||||
RestrictAddressFamilies=AF_UNIX
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
RestrictSUIDSGID=true
|
||||
SystemCallArchitectures=native
|
||||
LockPersonality=true
|
||||
MemoryDenyWriteExecute=true
|
||||
CapabilityBoundingSet=CAP_DAC_OVERRIDE CAP_SYS_ADMIN CAP_SYS_RAWIO
|
||||
ReadWritePaths=/run/noctalia-drive-health
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Refresh SMART data for Noctalia
|
||||
|
||||
[Timer]
|
||||
OnBootSec=20s
|
||||
OnUnitActiveSec=30s
|
||||
AccuracySec=5s
|
||||
Unit=noctalia-drive-health.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Run this SMART action as root." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
action=${1:-}
|
||||
device=${2:-}
|
||||
case "$action" in
|
||||
short|long) ;;
|
||||
*)
|
||||
echo "usage: $0 {short|long} DEVICE" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$device" in
|
||||
/dev/nvme[0-9]* )
|
||||
[ -c "$device" ] || { echo "Not an NVMe controller: $device" >&2; exit 2; }
|
||||
;;
|
||||
/dev/* )
|
||||
[ -b "$device" ] || { echo "Not a block device: $device" >&2; exit 2; }
|
||||
[ "$(lsblk --nodeps --noheadings --output TYPE "$device" 2>/dev/null | tr -d ' ')" = "disk" ] \
|
||||
|| { echo "SMART tests require a whole disk: $device" >&2; exit 2; }
|
||||
;;
|
||||
*)
|
||||
echo "Device must be an absolute /dev path." >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Starting the $action SMART self-test on $device"
|
||||
exec smartctl --test="$action" "$device"
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if (( EUID != 0 )); then
|
||||
echo "Run this uninstaller with sudo." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
service_name="noctalia-drive-health"
|
||||
|
||||
systemctl disable --now "$service_name.timer" 2>/dev/null || true
|
||||
systemctl stop "$service_name.service" 2>/dev/null || true
|
||||
|
||||
rm -f \
|
||||
"/etc/systemd/system/$service_name.service" \
|
||||
"/etc/systemd/system/$service_name.timer"
|
||||
rm -rf \
|
||||
"/usr/local/libexec/$service_name" \
|
||||
"/run/$service_name"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl reset-failed "$service_name.service" 2>/dev/null || true
|
||||
|
||||
echo "Removed the Noctalia Drive Health system collector."
|
||||
Reference in New Issue
Block a user