From 5b8549c1d3dad4af20292b406f6b774b8922eb2d Mon Sep 17 00:00:00 2001 From: Andre Brait Date: Sat, 10 Oct 2026 17:57:12 +0000 Subject: [PATCH 1/2] fanctrlplus2: stop rewriting the config lock on flash every 10 s (#19) array_monitor.sh opened .config.lock with '>', which truncates the file and updates its mtime on every 10-second pass while the array is started: a write to the USB boot device each time. Append mode takes the same flock without touching the file. The install script also started array_monitor.sh after 'rc.fanctrlplus2 restart', whose start() already launches it, so two monitors ran after every install and boot. --- plugin/plugin.j2 | 6 +----- .../emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/plugin/plugin.j2 b/plugin/plugin.j2 index 5756391..640524d 100644 --- a/plugin/plugin.j2 +++ b/plugin/plugin.j2 @@ -94,15 +94,11 @@ mkdir -p /var/tmp/fanctrlplus2 rm -f /var/tmp/fanctrlplus2/* pkill -f "/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh" +# start() launches array_monitor.sh (pgrep-guarded); do not start it again here. if [[ -x "$dst" ]]; then "$dst" restart fi -script="/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh" -if [[ -x "$script" ]]; then - nohup "$script" >/dev/null 2>&1 & -fi - echo "" echo "------------------------------------------------" echo " FanCtrl Plus 2 is installed." diff --git a/src/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh b/src/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh index 2360543..d4ba8fa 100644 --- a/src/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh +++ b/src/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh @@ -45,7 +45,7 @@ while true; do log "FanCtrlPlus not running after array start → launching" "$rc_script" start 9>&- fi - ) 9>"$config_lock" + ) 9>>"$config_lock" # append: '>' would rewrite the file on the flash drive every pass fi sleep "$CHECK_INTERVAL" From 915fa6a12ecae3c188ff00912d7ccb98d7a521d2 Mon Sep 17 00:00:00 2001 From: Andre Brait Date: Sat, 10 Oct 2026 18:40:09 +0000 Subject: [PATCH 2/2] fanctrlplus2: keep the config lock in /var/run (#19) flock state lives in the kernel, so the lock file only needs a path both sides agree on. /var/run is RAM on Unraid and root-only, so taking the lock never touches the flash drive, not even to create the file. The install script removes the old lock from /boot. --- plugin/plugin.j2 | 1 + .../local/emhttp/plugins/fanctrlplus2/include/ConfigBackup.php | 3 ++- .../local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh | 2 +- tests/config_backup_test.php | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugin/plugin.j2 b/plugin/plugin.j2 index 640524d..abb57e7 100644 --- a/plugin/plugin.j2 +++ b/plugin/plugin.j2 @@ -93,6 +93,7 @@ fi mkdir -p /var/tmp/fanctrlplus2 rm -f /var/tmp/fanctrlplus2/* pkill -f "/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh" +rm -f /boot/config/plugins/fanctrlplus2/.config.lock # the lock now lives in /var/run # start() launches array_monitor.sh (pgrep-guarded); do not start it again here. if [[ -x "$dst" ]]; then diff --git a/src/usr/local/emhttp/plugins/fanctrlplus2/include/ConfigBackup.php b/src/usr/local/emhttp/plugins/fanctrlplus2/include/ConfigBackup.php index 823ce64..a1dbc56 100644 --- a/src/usr/local/emhttp/plugins/fanctrlplus2/include/ConfigBackup.php +++ b/src/usr/local/emhttp/plugins/fanctrlplus2/include/ConfigBackup.php @@ -5,7 +5,8 @@ function fcp_config_lock(string $dir, int $mode = LOCK_EX) { if (is_link($dir) || (!is_dir($dir) && !@mkdir($dir, 0700, true))) throw new RuntimeException('Configuration directory is unavailable.'); - $path = "$dir/.config.lock"; + // In RAM, so taking the lock never writes to the flash drive (#19). Shared with array_monitor.sh. + $path = getenv('FCP_CONFIG_LOCK') ?: '/var/run/fanctrlplus2.config.lock'; if (is_link($path) || (file_exists($path) && !is_file($path))) throw new RuntimeException('Unsafe configuration lock.'); // Service daemons must never inherit the request's flock descriptor. $lock = @fopen($path, 'ce'); diff --git a/src/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh b/src/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh index d4ba8fa..0f737f1 100644 --- a/src/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh +++ b/src/usr/local/emhttp/plugins/fanctrlplus2/scripts/array_monitor.sh @@ -7,7 +7,7 @@ rc_script="/etc/rc.d/rc.${plugin}" pidfile="/var/run/fanctrlplus2.user_stopped" # Shared with the settings page; a configuration restore holds it while it # swaps files. -config_lock="/boot/config/plugins/${plugin}/.config.lock" +config_lock="/var/run/${plugin}.config.lock" last_md_state="" last_fanctrl_state=0 diff --git a/tests/config_backup_test.php b/tests/config_backup_test.php index f14658c..8402aa1 100644 --- a/tests/config_backup_test.php +++ b/tests/config_backup_test.php @@ -4,6 +4,7 @@ require_once $module; $root = sys_get_temp_dir().'/fcp_backup_'.getmypid(); mkdir($root, 0700, true); +putenv("FCP_CONFIG_LOCK=$root/.config.lock"); $failures = []; $check = function ($condition, string $message) use (&$failures) { if (!$condition) $failures[] = $message; }; $fan = <<<'CFG'