#!/bin/bash # ============================================================================================== # ================================= Unraid Platform Adapter ==================================== # ============================================================================================== # Sourced by load_config.sh when PLATFORM=unraid. # Provides the platform_*() API — bash scripts call these instead of OS-specific commands. # # ── API CONTRACT ────────────────────────────────────────────────────────────────────────────── # Every function returns 0 on success / 1 on failure unless noted. # Functions that produce output write to stdout; callers capture with $(). # No function calls exit — callers decide what failure means for their flow. # # ── ADDING A PLATFORM ───────────────────────────────────────────────────────────────────────── # Create Plugin/truenas/adapter.sh (or ubuntu/adapter.sh) implementing the same function names. # load_config.sh sources Plugin/$PLATFORM/adapter.sh — no other changes needed. # # ── FUNCTIONS ───────────────────────────────────────────────────────────────────────────────── # platform_require_cmd — verify a platform command exists and is executable # platform_storage_healthy — array mounted and shfs active on /mnt/user # platform_get_disk_states — raw disks.ini content from emhttp state # platform_get_temp_thresholds — disk warn/crit °C from dynamix.cfg # platform_is_maintenance_running — parity check/sync in progress # platform_is_service_enabled — docker or libvirt enabled in boot config # platform_restart_service — restart a named service via rc.d # platform_stop_service — stop a named service via rc.d # platform_is_service_running — check if a named service process is alive # platform_is_mover_running — unRAID mover process check # platform_stop_user_scripts — kill all user.scripts background processes # platform_send_os_notification — native unRAID notify (dynamix) # ============================================================================================== # ────────────────────────────────────────────────────────────────────────────────────────────── # Internal: map a logical service name → its rc.d script path # ────────────────────────────────────────────────────────────────────────────────────────────── _platform_rc_script() { case "$1" in docker) echo "/etc/rc.d/rc.docker" ;; sshd) echo "/etc/rc.d/rc.sshd" ;; libvirt) echo "/etc/rc.d/rc.libvirt" ;; rsyslog) echo "/etc/rc.d/rc.rsyslogd" ;; nginx) echo "/etc/rc.d/rc.nginx" ;; php-fpm) echo "/etc/rc.d/rc.php-fpm" ;; emhttp) echo "/etc/rc.d/rc.emhttp" ;; *) echo "/etc/rc.d/rc.$1" ;; esac } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_require_cmd [test_arg] [expected_output] [label] # Replaces platform_require_cmd. Returns 0 if the command exists and (optionally) its output # matches expected_output. Returns 1 and prints a warning if not. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_require_cmd() { local cmd="$1" local test_arg="${2:-}" local expected="${3:-}" local label="${4:-$cmd}" if [[ ! -x "$cmd" ]]; then return 1 fi if [[ -n "$test_arg" && -n "$expected" ]]; then "$cmd" $test_arg 2>&1 | grep -q "$expected" || return 1 fi return 0 } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_storage_healthy # Returns 0 if /mnt/user is mounted as shfs (array is up and healthy). # Returns 1 if the mount is absent or is not shfs (array stopped / degraded). # ────────────────────────────────────────────────────────────────────────────────────────────── platform_storage_healthy() { df --output=fstype /mnt/user 2>/dev/null | grep -q shfs } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_get_disk_states # Writes raw /var/local/emhttp/disks.ini to stdout. # Returns 1 if the file is absent (array not started or emhttp not running). # ────────────────────────────────────────────────────────────────────────────────────────────── platform_get_disk_states() { local disks_ini="/var/local/emhttp/disks.ini" [[ -f "$disks_ini" ]] || return 1 cat "$disks_ini" } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_get_temp_thresholds # Writes two space-separated values to stdout: WARN_TEMP CRIT_TEMP (°C integers). # Falls back to 45 55 if dynamix.cfg is absent or the keys are missing. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_get_temp_thresholds() { local cfg="/boot/config/plugins/dynamix/dynamix.cfg" local warn crit warn=$(grep -m1 '^diskWarn=' "$cfg" 2>/dev/null | cut -d= -f2 | tr -d '"') crit=$(grep -m1 '^diskCrit=' "$cfg" 2>/dev/null | cut -d= -f2 | tr -d '"') echo "${warn:-45} ${crit:-55}" } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_is_maintenance_running # Returns 0 if a parity check or sync is currently in progress. # Checks var.ini (Unraid 7.3+) then falls back to parity-date.txt (older). # ────────────────────────────────────────────────────────────────────────────────────────────── platform_is_maintenance_running() { local resync resync=$(awk -F'"' '/^mdResync=/{print $2}' /var/local/emhttp/var.ini 2>/dev/null) if [[ -n "$resync" && "$resync" != "0" ]]; then return 0 fi grep -q "progress" /var/local/emhttp/parity-date.txt 2>/dev/null } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_is_service_enabled # service: docker | libvirt # Returns 0 if the service is enabled in the Unraid boot config. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_is_service_enabled() { case "$1" in docker) grep -q '^DOCKER_ENABLED=yes' /boot/config/docker.cfg 2>/dev/null ;; libvirt) grep -q '^DOMAIN_ENABLE=yes' /boot/config/domain.cfg 2>/dev/null ;; *) return 1 ;; esac } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_restart_service # Restarts the named service via its rc.d script. # Returns 1 if the rc.d script does not exist or is not executable. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_restart_service() { local rc rc=$(_platform_rc_script "$1") [[ -x "$rc" ]] || return 1 "$rc" restart >/dev/null 2>&1 } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_stop_service # Stops the named service via its rc.d script. # Returns 1 if the rc.d script does not exist or is not executable. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_stop_service() { local rc rc=$(_platform_rc_script "$1") [[ -x "$rc" ]] || return 1 "$rc" stop >/dev/null 2>&1 } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_is_service_running # Returns 0 if the service's main process is alive. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_is_service_running() { case "$1" in docker) pgrep -x dockerd >/dev/null 2>&1 ;; emhttp) pgrep -x emhttpd >/dev/null 2>&1 ;; nginx) pgrep -x nginx >/dev/null 2>&1 ;; php-fpm) pgrep -x php-fpm >/dev/null 2>&1 ;; sshd) pgrep -x sshd >/dev/null 2>&1 ;; rsyslog) pgrep -x rsyslogd >/dev/null 2>&1 ;; libvirt) pgrep -x libvirtd >/dev/null 2>&1 ;; *) pgrep -x "$1" >/dev/null 2>&1 ;; esac } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_is_mover_running # Returns 0 if the Unraid mover is currently active. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_is_mover_running() { pgrep -f "emhttp.*Mover" >/dev/null 2>&1 } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_get_mover_pid # Writes the mover's PID to stdout. Returns 1 if the mover is not running. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_get_mover_pid() { local pid pid=$(pgrep -f "emhttp.*Mover" | head -1) [[ -n "$pid" ]] || return 1 echo "$pid" } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_stop_user_scripts # Kills all Unraid user.scripts background processes. # Returns 0 whether or not any processes were found (pkill exits 1 on no match). # ────────────────────────────────────────────────────────────────────────────────────────────── platform_stop_user_scripts() { pkill -f "/tmp/user.scripts" 2>/dev/null || true } # ────────────────────────────────────────────────────────────────────────────────────────────── # platform_send_os_notification [subject] [severity] # Sends a native Unraid notification via the dynamix notify script. # severity: normal | warning | alert (default: normal) # Returns 1 if the notify script is absent. # ────────────────────────────────────────────────────────────────────────────────────────────── platform_send_os_notification() { local message="$1" local subject="${2:-Varaverk}" local severity="${3:-normal}" local notify_script="/usr/local/emhttp/plugins/dynamix/scripts/notify" [[ -x "$notify_script" ]] || return 1 "$notify_script" -e "Varaverk" -s "$subject" -d "$message" -i "$severity" 2>/dev/null }