From 0eb512f90d1707d843ef5d374ae4f593abd409d7 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 24 Dec 2025 19:40:12 +0000 Subject: [PATCH] feat: Add SysV init support for legacy systems. Related to #894 Adds support for systems that use SysV init (like Asustor NAS) that don't have systemd, OpenRC, or launchd. The installer now: - Detects /etc/init.d as a fallback when no other init system is found - Creates an LSB-compliant init script with start/stop/restart/status - Uses update-rc.d (Debian) or chkconfig (RHEL) to enable on boot - Falls back to manual rc.d symlink creation if neither tool is available - Properly cleans up on uninstall --- scripts/install.sh | 195 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 193 insertions(+), 2 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index 266fd5a36..9b4472ca0 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # # Pulse Unified Agent Installer -# Supports: Linux (systemd, OpenRC), macOS (launchd), Synology DSM (6.x/7+), Unraid +# Supports: Linux (systemd, OpenRC, SysV init), macOS (launchd), Synology DSM (6.x/7+), Unraid # # Usage: # curl -fsSL http://pulse/install.sh | bash -s -- --url http://pulse --token [options] @@ -389,6 +389,25 @@ if [[ "$UNINSTALL" == "true" ]]; then rm -f "/etc/init.d/${AGENT_NAME}" fi + # SysV init (legacy systems like Asustor, older Debian/RHEL, etc.) + if [[ -f "/etc/init.d/${AGENT_NAME}" ]]; then + "/etc/init.d/${AGENT_NAME}" stop 2>/dev/null || true + # Remove using available tools + if command -v update-rc.d >/dev/null 2>&1; then + update-rc.d -f "${AGENT_NAME}" remove >/dev/null 2>&1 || true + elif command -v chkconfig >/dev/null 2>&1; then + chkconfig "${AGENT_NAME}" off >/dev/null 2>&1 || true + chkconfig --del "${AGENT_NAME}" >/dev/null 2>&1 || true + fi + # Remove rc.d symlinks manually (in case tools weren't available) + for RL in 0 1 2 3 4 5 6; do + rm -f "/etc/rc${RL}.d/S99${AGENT_NAME}" 2>/dev/null || true + rm -f "/etc/rc${RL}.d/K01${AGENT_NAME}" 2>/dev/null || true + done + rm -f "/etc/init.d/${AGENT_NAME}" + rm -f "/var/run/${AGENT_NAME}.pid" + fi + rm -f "${INSTALL_DIR}/${BINARY_NAME}" log_info "Uninstallation complete." exit 0 @@ -1143,7 +1162,179 @@ EOF exit 0 fi -fail "Could not detect a supported service manager (systemd, OpenRC, launchd, or Unraid)." +# 6. SysV Init (legacy systems like Asustor, older Debian/RHEL, etc.) +# This is a fallback for systems that have /etc/init.d but no systemd/OpenRC +if [[ -d /etc/init.d ]] && [[ -w /etc/init.d ]]; then + INITSCRIPT="/etc/init.d/${AGENT_NAME}" + log_info "Configuring SysV init script at $INITSCRIPT..." + + # Build command line args + build_exec_args + + # Create SysV init script following LSB conventions + cat > "$INITSCRIPT" <<'INITEOF' +#!/bin/sh +### BEGIN INIT INFO +# Provides: pulse-agent +# Required-Start: $network $remote_fs +# Required-Stop: $network $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Pulse Unified Agent +# Description: Pulse monitoring agent for host metrics, Docker, and Kubernetes +### END INIT INFO + +# Pulse Unified Agent SysV init script + +NAME="pulse-agent" +DAEMON="INSTALL_DIR_PLACEHOLDER/BINARY_NAME_PLACEHOLDER" +DAEMON_ARGS="EXEC_ARGS_PLACEHOLDER" +PIDFILE="/var/run/${NAME}.pid" +LOGFILE="/var/log/${NAME}.log" + +# Exit if the binary is not installed +[ -x "$DAEMON" ] || exit 0 + +do_start() { + if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then + echo "$NAME is already running." + return 1 + fi + echo "Starting $NAME..." + # Start daemon in background, redirect output to log file + nohup $DAEMON $DAEMON_ARGS >> "$LOGFILE" 2>&1 & + echo $! > "$PIDFILE" + sleep 1 + if kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then + echo "$NAME started." + return 0 + else + echo "Failed to start $NAME." + rm -f "$PIDFILE" + return 1 + fi +} + +do_stop() { + if [ ! -f "$PIDFILE" ]; then + echo "$NAME is not running (no PID file)." + return 0 + fi + PID=$(cat "$PIDFILE") + if ! kill -0 "$PID" 2>/dev/null; then + echo "$NAME is not running (stale PID file)." + rm -f "$PIDFILE" + return 0 + fi + echo "Stopping $NAME..." + kill "$PID" + # Wait for process to stop + for i in 1 2 3 4 5; do + if ! kill -0 "$PID" 2>/dev/null; then + break + fi + sleep 1 + done + # Force kill if still running + if kill -0 "$PID" 2>/dev/null; then + echo "Force killing $NAME..." + kill -9 "$PID" 2>/dev/null || true + fi + rm -f "$PIDFILE" + echo "$NAME stopped." + return 0 +} + +do_status() { + if [ -f "$PIDFILE" ]; then + PID=$(cat "$PIDFILE") + if kill -0 "$PID" 2>/dev/null; then + echo "$NAME is running (PID $PID)." + return 0 + else + echo "$NAME is not running (stale PID file)." + return 1 + fi + else + echo "$NAME is not running." + return 3 + fi +} + +case "$1" in + start) + do_start + ;; + stop) + do_stop + ;; + restart|reload|force-reload) + do_stop + sleep 1 + do_start + ;; + status) + do_status + ;; + *) + echo "Usage: $0 {start|stop|restart|status}" >&2 + exit 3 + ;; +esac + +exit $? +INITEOF + + # Replace placeholders with actual values + sed -i "s|INSTALL_DIR_PLACEHOLDER|${INSTALL_DIR}|g" "$INITSCRIPT" + sed -i "s|BINARY_NAME_PLACEHOLDER|${BINARY_NAME}|g" "$INITSCRIPT" + sed -i "s|EXEC_ARGS_PLACEHOLDER|${EXEC_ARGS}|g" "$INITSCRIPT" + + chmod +x "$INITSCRIPT" + + # Try to enable on boot using available tools + if command -v update-rc.d >/dev/null 2>&1; then + # Debian-based systems + update-rc.d "${AGENT_NAME}" defaults >/dev/null 2>&1 || true + log_info "Enabled service with update-rc.d." + elif command -v chkconfig >/dev/null 2>&1; then + # RHEL-based systems + chkconfig --add "${AGENT_NAME}" >/dev/null 2>&1 || true + chkconfig "${AGENT_NAME}" on >/dev/null 2>&1 || true + log_info "Enabled service with chkconfig." + else + # Manual symlink creation for systems without tools + # Try to create rc.d symlinks manually + for RL in 2 3 4 5; do + if [[ -d "/etc/rc${RL}.d" ]]; then + ln -sf "$INITSCRIPT" "/etc/rc${RL}.d/S99${AGENT_NAME}" 2>/dev/null || true + fi + done + for RL in 0 1 6; do + if [[ -d "/etc/rc${RL}.d" ]]; then + ln -sf "$INITSCRIPT" "/etc/rc${RL}.d/K01${AGENT_NAME}" 2>/dev/null || true + fi + done + log_info "Created rc.d symlinks manually." + fi + + # Stop existing agent if running + "$INITSCRIPT" stop 2>/dev/null || true + sleep 1 + + # Start the agent + "$INITSCRIPT" start + if [[ "$UPGRADE_MODE" == "true" ]]; then + log_info "Upgrade complete! Agent restarted with new configuration." + else + log_info "Installation complete! Agent service started." + fi + log_info "To check status: $INITSCRIPT status" + log_info "To view logs: tail -f /var/log/${AGENT_NAME}.log" + exit 0 +fi + +fail "Could not detect a supported service manager (systemd, OpenRC, SysV init, launchd, or Unraid)." }