Debian systemd ==> sysvinit Migration Toolkit Version 1.0 | 2026-07-31 | MIT License | © 2026 Tangent Networks
- Overview
- Prerequisites
- Installation
- Migration Process
- Script Reference
- State and Log Files
- Error Recovery
- Troubleshooting
- Safety Guarantees
- Architecture Notes
- Migration Checklist
- License
- Support
This toolkit migrates Debian-based systems from systemd to sysvinit with full support for LUKS encryption and LVM configurations. The migration is structured as five sequential phases to ensure safety, provide recovery options at each stage, and maintain data integrity throughout.
PHASE 1: PREP REBOOT GATE PHASE 2: MIGRATE
(systemd) --> (manual yes) --> (sysvinit)
|
v
PHASE 3: AUTOFIX
(repair post-migrate issues)
|
v
PHASE 4: CHECK LOGS
(automated log analysis)
|
v
PHASE 5: VERIFY
(final health check)
- Automatic encryption detection (LUKS, LVM, LUKS+LVM)
- Safe package removal with dry-run simulation before purge
- Critical package protection (kernel, cryptsetup, LVM, initramfs)
- Idempotent stages -- every script is safe to re-run
- Surgical LSB header patching with insserv dependency graph rebuild
- Automated log scanning for known failure patterns
- Comprehensive logging to
/var/lib/tn-sysvinit-migrate/
| Requirement | Details |
|---|---|
| Operating System | Debian (tested on Debian 13 / Trixie) |
| Architecture | amd64 (x86_64) |
| Init System | Currently running systemd |
| Package Manager | apt / dpkg |
Root access is mandatory. All scripts check id -u at startup and exit immediately if not run as root.
| Location | Minimum Required |
|---|---|
/boot |
500 MB free (for initramfs rebuilds) |
/ |
2 GB free (for package operations) |
Internet access is required for Phase 1 only. Phases 2 through 5 are fully offline.
Clone the repository and make all scripts executable:
git clone https://github.com/tangentnetworks/tn_sysvinit.git
cd tn_sysvinit
chmod +x *.shRun the scripts in this order:
01. sudo ./tn_sysvinit_prep.sh
02. sudo ./tn_sysvinit_migrate.sh
03. sudo ./tn_sysvinit_autofix.sh
04. sudo ./tn_sysvinit_check_logs.sh
05. sudo ./tn_sysvinit_verify.sh
| Attribute | Details |
|---|---|
| Runs on | systemd (before reboot) |
| Purpose | Detects encryption, installs sysvinit, rebuilds initramfs |
| Duration | 2–5 minutes |
| Destructive | No -- safe to re-run |
| State file | /var/lib/tn-sysvinit-migrate/state.prep |
| Log file | /var/lib/tn-sysvinit-migrate/phase1.log |
| Stage | Description | Critical |
|---|---|---|
00 |
Checks root access, Debian version, required tools | Yes |
10 |
Detects LUKS/LVM configuration, writes crypto.profile |
Yes |
20 |
Places apt holds on essential packages | Yes |
30 |
Updates package lists | No |
40 |
Removes the systemd-sysv bridge package |
Yes |
50 |
Installs initscripts (checkroot.sh, mountkernfs.sh) |
Yes |
60 |
Installs sysvinit-core and dependencies |
Yes |
61 |
Installs BIOS-compatible GRUB (only if LUKS detected) | Conditional |
70 |
Strips stale urandom/checkroot LSB header references, runs insserv |
Yes |
80 |
Rebuilds initramfs with cryptroot hook (if LUKS detected) |
Yes |
90 |
Confirms sysvinit-core is installed before reboot gate |
Yes |
The script automatically identifies your storage configuration and saves the result to crypto.profile:
| Configuration | Detection Method | Protected Packages |
|---|---|---|
| No encryption | No LUKS/LVM detected | linux-image, linux-headers, initramfs-tools |
| LUKS only | /etc/crypttab entries or /dev/mapper root |
+ cryptsetup, cryptsetup-initramfs, cryptsetup-bin |
| LVM only | Active LVM via dmsetup or lsblk |
+ lvm2, dmsetup |
| LUKS + LVM | Both detected | + both stacks |
sudo ./tn_sysvinit_prep.shAt the end of Phase 1 you will see a reboot prompt. Type yes to reboot immediately, or no to reboot manually later. Do not skip the reboot -- Phase 2 requires sysvinit to be PID 1.
| Attribute | Details |
|---|---|
| Runs on | sysvinit (after reboot from Phase 1) |
| Purpose | Verifies the init switch, then removes systemd |
| Duration | 1–2 minutes |
| Destructive | Yes -- removes systemd packages |
| State file | /var/lib/tn-sysvinit-migrate/state.migration |
| Log file | /var/lib/tn-sysvinit-migrate/phase2.log |
| Simulation log | /var/lib/tn-sysvinit-migrate/purge-simulation.log |
| Stage | Description | Critical |
|---|---|---|
00 |
Confirms PID 1 is init, not systemd |
Yes |
10 |
Loads encryption profile written by Phase 1 | Yes |
20 |
Verifies LUKS decryption is active (if applicable) | Yes |
30 |
Simulates the systemd purge with apt-get -s purge and checks for forbidden removals |
Yes |
40 |
Performs the actual systemd purge | Yes |
50 |
Runs apt-get -f install, removes orphans, writes apt pin to block systemd reinstall |
Yes |
60 |
Final verification: PID 1, /sbin/init target, systemd removal |
Yes |
Rather than parsing initramfs contents with fragile tooling, the script uses a provability argument: if the system successfully booted to sysvinit with an encrypted root device, then cryptroot decryption must have completed in the initramfs. The check is:
# Root mounted from an encrypted device means cryptroot is working
root_src=$(findmnt -no SOURCE / 2>/dev/null || echo "")
if [[ "$root_src" == /dev/mapper/* ]]; then
info "LUKS decryption provably occurred in initramfs"
fisystemd, systemd-sysv, systemd-cryptsetup, systemd-standalone-sysusers, systemd-timesyncd, dbus-user-session, libnss-systemd, libpam-systemd
Stage 30 simulates this removal first. If the simulation detects that any critical package (linux-image-*, linux-headers-*, openssh, udev, grub-*, cryptsetup*, initramfs-tools, busybox, util-linux, psmisc) would be pulled in as a dependency removal, the script aborts before touching anything.
After rebooting from Phase 1, log in as root and run:
sudo ./tn_sysvinit_migrate.shDo not reboot again after Phase 2 completes. The migration is live; systemd is gone.
| Attribute | Details |
|---|---|
| Runs on | sysvinit (after Phase 2) |
| Purpose | Inspects and repairs common post-migration configuration issues |
| Duration | 30–90 seconds |
| Destructive | No -- all changes are additive or corrective; nothing is removed |
| Log file | /var/lib/tn-sysvinit-migrate/autofix.log |
The autofix script works through four inspection-and-repair modules in sequence. Each module checks for a known class of post-migration problem and fixes it in-place, logging every action taken.
1. Logging Subsystem (fix_logging)
Ensures rsyslog and bootlogd are installed, running, and producing output.
- Installs
rsyslogandbootlogdif either is missing - Creates
/var/log/bootand/var/log/syslogif absent - Enables
BOOTLOGD_ENABLE=Yesin/etc/default/bootlogdif not already set - Starts
rsyslogviaupdate-rc.dandserviceif it is not running
2. Filesystem Mount Configuration (fix_fstab)
Sysvinit requires /run, /run/lock, and /tmp to be declared as tmpfs mounts in /etc/fstab. These entries are created by systemd automatically when it is the init system but must be explicit for sysvinit.
- Adds a
tmpfs /runentry if missing (size 20%, mode 755) - Adds a
tmpfs /run/lockentry if missing (size 5 MB, noexec) - Adds a
tmpfs /tmpentry if missing (mode 1777) - Calls
mount -ato apply any newly added entries immediately
3. Init Configuration (fix_configs)
Validates /etc/default/rcS and the inittab directory.
- Sets
RAMRUN=yes,RAMLOCK=yes, andRAMTMP=yesin/etc/default/rcSif any are missing or incorrect - Creates
/etc/inittab.d/if the directory is absent (required by some init scripts)
4. LSB Header Patching and insserv Rebuild (fix_insserv_bootclean)
This is the most surgical module. It resolves insserv dependency graph failures caused by stale LSB header references that accumulate during migration.
- Strips stale
-bootcleandependency references from LSB headers inmountall.sh,checkroot.sh, andcheckfs.sh - Adds a
bootcleanentry to theProvides:field incheckroot-bootclean.shandmountall-bootclean.shif missing - Purges stale insserv cache files (
.depend.boot,.depend.start,.depend.stop) to force a fresh dependency calculation - Rebuilds the insserv dependency graph with
insserv -v; if that fails, falls back todpkg-reconfigure initscripts
After the four modules complete, the script clears /var/log/boot and restarts bootlogd so that the next boot produces a clean log with no residual entries from migration.
The script uses three output prefixes:
| Marker | Meaning |
|---|---|
[OK] |
Check passed, no action needed |
[WARN] |
Anomaly noted, not necessarily blocking |
[FIXING] |
A corrective action was taken and logged |
sudo ./tn_sysvinit_autofix.shAfter it completes, proceed immediately to Phase 4 to confirm the fixes took effect.
| Attribute | Details |
|---|---|
| Runs on | sysvinit (after Phase 3) |
| Purpose | Automated diagnostic verification of system state and log content |
| Duration | 5–15 seconds |
| Destructive | No -- read-only except for a temporary file under /tmp |
| Exit code | 0 on clean pass, 1 if any errors are found |
The script runs five verification passes in sequence, accumulating error and warning counts and reporting a final pass/fail at the end.
1. System State Verification
- Confirms PID 1 is
init(sysvinit); fails if it is anything else - Checks that the
systemdpackage is not present indpkg -l
2. Logging Service Verification
- Checks
rsyslogstatus via bothserviceand/etc/init.d/rsyslog - Confirms
/var/log/syslogexists and is non-empty
3. Runtime Mount Verification
- Confirms
/runand/run/lockentries exist in/etc/fstab - These entries are written by Phase 3; their absence here means autofix did not run or failed
4. Boot-clean Symlink Verification
- Confirms
checkroot-bootcleansymlinks exist in/etc/rcS.d/ - A missing symlink means insserv failed to register the script during Phase 1 or autofix
5. insserv Dependency Graph Verification
- Runs
insserv -dand checks for fatal errors - Dumps the insserv output on failure so you can see exactly which dependency is broken
6. Log File Pattern Scanning
Scans /var/log/boot, /var/log/syslog, and /var/log/messages for a set of known failure strings:
| Pattern searched | What it indicates |
|---|---|
failed! |
Generic init.d script failure |
checkroot-bootclean.sh ... failed |
Boot-clean script not properly linked |
Cleaning up temporary files... /run /run/lock failed |
Missing fstab tmpfs entries |
insserv: FATAL |
Dependency graph calculation error |
No inittab.d directory found |
Missing /etc/inittab.d/ directory |
Log files are passed through strings before pattern matching to strip binary NUL bytes and escape sequences that can accumulate in raw boot logs and cause false negatives.
+-------------------------------------------------------------------+
Automated Analysis Results: 0 Error(s), 0 Warning(s)
+-------------------------------------------------------------------+
RESULT: SUCCESS - System is fully configured, clean, and logged!
If any errors are found, the exit code is 1 and the failing checks are listed above the summary. This makes the script suitable for use in automated pipelines or boot-time health checks.
sudo ./tn_sysvinit_check_logs.shA clean exit (code 0) means the system is correctly configured and the log files show no failure patterns. Proceed to Phase 5 for a full package-level verification.
| Attribute | Details |
|---|---|
| Runs on | sysvinit (anytime after Phase 2) |
| Purpose | Non-destructive, comprehensive health check of the migration |
| Duration | 5–10 seconds |
| Destructive | No -- read-only |
| Log file | /var/lib/tn-sysvinit-migrate/verification-report.txt |
Phase 5 performs a broad set of read-only checks across seven categories:
Init System -- PID 1 is init, /sbin/init target points to sysvinit, systemd package is removed, sysvinit-core is installed.
Boot Framework -- Required init.d scripts exist (checkroot.sh, mountkernfs.sh), runlevel directories exist under /etc/rc*.d/, insserv is available.
Kernel and Initramfs -- Running kernel version, initramfs exists for current kernel, initramfs contains essential files (init, modules), GRUB can locate the kernel.
Encryption -- Loads crypto profile from Phase 1, verifies /etc/crypttab entries (if LUKS), checks cryptsetup hook configuration, confirms root is mounted from an encrypted device, checks LVM devices (if LVM).
Critical Packages -- Essential packages are installed and apt-held where required. Kernel image packages are held. cryptsetup packages are held if LUKS was detected. LVM packages are held if LVM was detected.
Filesystem -- Root (/) and boot (/boot) mounts are valid, fsck is available.
Log Analysis -- Scans Phase 1 and Phase 2 log files for errors and warnings.
sudo ./tn_sysvinit_verify.shRun this immediately after Phase 2 (or after Phase 4 if you ran autofix and check_logs). It can also be run at any time afterward to check ongoing system health.
| Result | Meaning | Action Required |
|---|---|---|
| SYSTEM HEALTHY | All checks passed | None -- migration complete |
| Warnings present | Some checks warned | Review warnings; system is functional |
| FAILED | One or more critical checks failed | Review failures; re-run relevant phase |
| Script | Phase | Runs On | Destructive | Network | Idempotent | Duration |
|---|---|---|---|---|---|---|
tn_sysvinit_prep.sh |
1 | systemd | No | Yes | Yes | 2–5 min |
tn_sysvinit_migrate.sh |
2 | sysvinit | Yes | No | Yes | 1–2 min |
tn_sysvinit_autofix.sh |
3 | sysvinit | No | No | Yes | 30–90 sec |
tn_sysvinit_check_logs.sh |
4 | sysvinit | No | No | Yes | 5–15 sec |
tn_sysvinit_verify.sh |
5 | sysvinit | No | No | Yes | 5–10 sec |
All migration state and logs are stored in /var/lib/tn-sysvinit-migrate/:
/var/lib/tn-sysvinit-migrate/
├── state.prep # Phase 1: completed stage markers
├── state.migration # Phase 2: completed stage markers
├── phase1.log # Phase 1: detailed execution log
├── phase2.log # Phase 2: detailed execution log
├── autofix.log # Phase 3: all inspection and repair actions
├── verification-report.txt # Phase 5: full verification results
├── crypto.profile # Auto-detected encryption configuration
└── purge-simulation.log # Phase 2: apt purge dry-run output
Phase 4 does not write a persistent log of its own; it reads the logs written by the other phases and writes temporary working files under /tmp that are cleaned up on exit.
Phase 1 is idempotent. Re-run it and it will skip completed stages:
sudo ./tn_sysvinit_prep.shCheck /var/lib/tn-sysvinit-migrate/phase1.log for the specific error.
- Boot into GRUB recovery mode (hold Shift during boot)
- Select a previous kernel or recovery entry
- Log in as root
- Check the Phase 1 log:
cat /var/lib/tn-sysvinit-migrate/phase1.log - Re-run Phase 1 to rebuild initramfs, then reboot again
Phase 2 is also idempotent. Re-run it; completed stages are skipped:
sudo ./tn_sysvinit_migrate.shIf Stage 30 (purge simulation) fails, it means removing systemd would break a critical dependency. Do not force the purge. Review purge-simulation.log to identify the conflicting package.
Re-run Phase 3 first to apply any remaining fixes, then re-run Phase 4 to confirm:
sudo ./tn_sysvinit_autofix.sh
sudo ./tn_sysvinit_check_logs.shIf Phase 4 still reports insserv: FATAL, check /etc/init.d/ for scripts referencing services that no longer exist. The most common culprits after systemd removal are urandom and stale checkroot cross-references in LSB headers.
The apt pin placed by Phase 2 should prevent this. If it happens:
# Verify the pin is in place
apt-cache policy systemd # should show Pin-Priority: -1
# If missing, reinstall the pin
cat > /etc/apt/preferences.d/00-no-systemd <<'EOF'
Package: systemd*
Pin: release *
Pin-Priority: -1
EOF
# Purge systemd again
apt-get remove --purge systemd systemd-sysvHow do I know if the migration worked?
Run sudo ./tn_sysvinit_verify.sh. A SYSTEM HEALTHY result with zero failures confirms a successful migration.
Can I downgrade back to systemd?
Not easily, and it is not officially supported. The migration removes systemd packages and places an apt pin to block reinstall. If you need to reverse: remove /etc/apt/preferences.d/00-no-systemd, run apt-get install systemd systemd-sysv, and reboot. This path is untested and may produce an inconsistent system state.
What if I have encrypted LVM? The toolkit handles this automatically. If both LVM and LUKS are detected, all phases protect and verify both stacks.
What if I use a custom LUKS key file?
Ensure it is referenced correctly in /etc/crypttab:
vda3_crypt UUID=<uuid> /path/to/keyfile luks,discard
Phase 1 will detect the crypttab entry and include the key file path in the initramfs rebuild.
Can I use this on non-Debian systems?
No. The toolkit checks for /etc/debian_version and uses apt-get/dpkg throughout. Ubuntu may have similar structures but carries additional systemd dependencies that are not accounted for.
Why does Phase 1 print insserv: FATAL warnings during install?
These are expected during initial sysvinit package installation. Phase 1 Stage 70 (fix_boot_deps) explicitly strips the stale LSB header references that cause them and then rebuilds the dependency graph cleanly. If you still see them after Stage 70, run Phase 3 autofix.
The toolkit will never do any of the following:
| Guarantee | How It Is Enforced |
|---|---|
| Remove kernel packages | Holds linux-image-* and linux-headers-* via apt-mark hold |
| Remove cryptsetup (if LUKS) | Holds cryptsetup, cryptsetup-initramfs, cryptsetup-bin |
| Remove LVM tools (if LVM) | Holds lvm2, dmsetup |
| Remove essential boot tooling | Holds initramfs-tools, busybox, grub*, openssh-server |
| Purge without safety check | Runs apt-get -s purge and inspects output before any real removal |
| Proceed through reboot without consent | Requires explicit yes at the reboot gate in Phase 1 |
A single monolithic script cannot safely handle this migration because the init switch happens at reboot. Running everything before reboot means you cannot verify PID 1 is init. Running everything after means you cannot use systemctl for the reboot gate. The five-script structure maps cleanly onto the five logical states of the migration:
- Phase 1 runs under systemd and stops before the point of no return
- Phase 2 runs under sysvinit and performs the destructive purge
- Phase 3 repairs known post-purge configuration drift in a targeted way
- Phase 4 provides machine-readable verification of the repair
- Phase 5 provides a comprehensive human-readable health report
Each phase is independently idempotent, meaning any phase can be re-run after a failure without repeating work that has already succeeded.
apt-get purge resolves dependency removals automatically. Without holds, a poorly specified dependency in a third-party package could cause it to pull out cryptsetup or a kernel module alongside systemd. The hold list is constructed dynamically based on what the encryption detector found, so only what is actually needed on this specific system is held.
insserv builds a strict dependency graph from the Required-Start and Required-Stop fields in init.d script LSB headers. If any script references a facility (urandom, checkroot) that is not declared as Provides in another script, insserv exits fatally. After systemd removal, several of those facility providers disappear. Stripping the references before running insserv prevents the fatal exit and allows the dependency graph to be built correctly.
Keeping Phase 3 separate from Phase 2 means the destructive purge stage (Phase 2) is as small and auditable as possible. It also means autofix can be re-run independently without re-triggering the package removal logic.
- Download all five scripts
- Make scripts executable with
chmod +x *.sh - Confirm scripts have MIT license headers
- Run Phase 1:
sudo ./tn_sysvinit_prep.sh - Confirm reboot prompt with
yes - System reboots into sysvinit
- Log in after reboot
- Run Phase 2:
sudo ./tn_sysvinit_migrate.sh - Phase 2 completes without errors
- Run Phase 3:
sudo ./tn_sysvinit_autofix.sh - Run Phase 4:
sudo ./tn_sysvinit_check_logs.sh-- confirm exit code 0 - Run Phase 5:
sudo ./tn_sysvinit_verify.sh-- confirm SYSTEM HEALTHY - Review logs in
/var/lib/tn-sysvinit-migrate/if any phase reported warnings
SPDX-License-Identifier: MIT
Copyright (c) 2026 David Peter, Tangent Networks
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
For bugs, issues, or improvements:
- Check the logs in
/var/lib/tn-sysvinit-migrate/ - Run Phase 5 to identify specific failures
- Review the stage that failed in the relevant log file
- Re-run the specific phase that failed
Author: David Peter Organization: Tangent Networks Web: https://tangentnet.top Email: tangent.net@zohomail.in
End of README.md