Skip to content

sysupgrade: a boot that never finished no longer blocks the update - #2797

Merged
openipc-ai merged 1 commit into
masterfrom
sysupgrade-stuck-sysinit
Nov 8, 2026
Merged

openipc-ai merged 1 commit into
masterfrom
sysupgrade-stuck-sysinit

Conversation

@openipc-ai

Copy link
Copy Markdown
Collaborator

Report. An upgrade fails with PID 1 did not hand over; rebooting (nothing was flashed) on a camera whose /etc/rc.local runs a script in the foreground, and fails the same way every time.

Cause. busybox init processes signals only after run_actions(SYSINIT) returns, and that lasts until rcS exits. A foreground loop in rc.local holds the hand-off's SIGQUIT unread, so the updater waits out handoff_wait and reboots.

Change. release_boot_scripts() runs just before kill -QUIT 1: if PID 1 still has an rcS child, it says so in one line and ends it. init is waiting on that pid alone, so it reaches the signal, and the hand-off kills whatever rcS left running. The 30 s guard stays as the backstop. Refusing the update instead would leave the owner still unable to update, and an in-place write is what the hand-off exists to avoid. scr_version goes to 1.0.84 so CLI runs self-update to this.

On hardware (hi3516av300, split NOR, with while :; do sleep 1; done in rc.local):

  • The installed updater reproduced the failure, with nothing written.
  • The patched updater printed the new line and handed over. The follower logged Firmware updated and Unconditional reboot, and the camera rebooted.

That run reinstalled the same build, so the evidence is the updater's log and the reboot, not a version change.

The WebUI's Install runs the updater already on the camera, so it gets this fix only from a firmware that includes it.

.github/scripts/test_sysupgrade.sh has two new checks and passes.

busybox init reads its signals only between inittab stages, and the
sysinit stage lasts until rcS exits. A foreground loop in /etc/rc.local
keeps rcS alive, so the SIGQUIT that hands PID 1 to the RAM root is never
read. The updater waits 30 s and reboots with nothing written, and every
later attempt does the same.

Just before the signal, say so and end PID 1's rcS child. init is waiting
on that pid alone, so it moves on and takes the signal. What rcS left
running would have been killed by the hand-off anyway. The 30 s guard and
its reboot stay as the backstop.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Allow sysupgrade handoff when boot scripts are stuck

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• End PID 1’s stuck rcS child so init can receive the upgrade handoff signal.
• Preserve the 30-second reboot backstop if handoff still fails.
• Add targeted tests and bump the updater version to 1.0.84 for self-update.
Diagram

graph TD
  A["Sysupgrade"] --> B["Proc scan"] --> C{"PID 1 rcS?"} -->|yes| D["Stop rcS"] --> E["Signal PID 1"] --> F{"Handoff succeeds?"} -->|yes| G["RAM flash"]
  C -->|no| E
  F -->|30s timeout| H["Reboot unwritten"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Refuse upgrades while rcS is running
  • ➕ Avoids terminating a boot script.
  • ➖ Leaves affected cameras unable to update while the foreground task persists.
2. Flash without handing off PID 1
  • ➕ Avoids waiting for init to process SIGQUIT.
  • ➖ Risks writing volumes still held by the running system.

Recommendation: Keep the targeted rcS termination before SIGQUIT. It addresses the repeatable failure without abandoning the RAM-root handoff or removing its unwritten-reboot backstop.

Files changed (2) +43 / -1

Bug fix (1) +23 / -1
sysupgradeRelease stuck rcS before signalling PID 1 +23/-1

Release stuck rcS before signalling PID 1

• Adds a helper that finds and kills an rcS process whose parent is PID 1, with a diagnostic explaining why. Calls it immediately before SIGQUIT while retaining the 30-second fallback, and bumps scr_version to 1.0.84.

general/overlay/usr/sbin/sysupgrade

Tests (1) +20 / -0
test_sysupgrade.shTest stuck-boot process selection and handoff ordering +20/-0

Test stuck-boot process selection and handoff ordering

• Adds a simulated proc tree to check that release_boot_scripts ends only init’s rcS child, not a similarly named child or an unrelated process. Also checks that hand_off_pid1 calls the helper.

.github/scripts/test_sysupgrade.sh

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can pick a display mode instead of tweaking every Display option by hand

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@openipc-ai
openipc-ai merged commit 6c74ea3 into master Nov 8, 2026
152 of 153 checks passed
@openipc-ai
openipc-ai deleted the sysupgrade-stuck-sysinit branch November 8, 2026 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant