Linux Init Systems: From SysV to systemd

18 min

Compare Linux init systems through interactive visualizations. Understand the evolution from SysV Init to systemd, service management, and boot orchestration.

Best viewed on desktop for optimal interactive experience

The Heartbeat of Linux

At the very core of every Linux system beats a special process - PID 1, the init system. This is the first process started by the kernel and the last one to die when the system shuts down. It's the ancestor of all other processes, the supervisor of system services, and the orchestrator of your system's lifecycle.

Think of the init system as the conductor of an orchestra. While the kernel provides the instruments (hardware resources), the init system coordinates when each musician (service) plays, ensuring they work in harmony. Some conductors (SysV Init) follow a strict, sequential score, while others (systemd) allow sections to play simultaneously for a faster, more dynamic performance.

The evolution from SysV Init to systemd represents one of the most significant changes in Linux history, transforming how we think about system initialization and service management.

Interactive Init Systems Comparison

Explore the differences between major init systems and how they manage your Linux system:

Linux Init Systems Comparison

systemd

Modern init system with parallel startup

Pros
Fast boot times
Feature-rich
Active development
Good documentation
Cons
Complex
Large codebase
Controversial design
Binary logs
Key Features
Parallel service startupOn-demand service activationDependency managementUnified logging (journald)

SysV Init

Traditional sequential init system

OpenRC

Dependency-based init system

Upstart

Event-based init replacement

FeaturesystemdSysV InitOpenRCUpstart
Boot Speed✅ Fast❌ Slow⚡ Medium⚡ Medium
Parallel Start✅ Yes❌ No✅ Yes✅ Yes
Dependencies✅ Automatic❌ Manual✅ Automatic✅ Event-based
Complexity🔴 High🟢 Low🟡 Medium🟡 Medium

The Init Process Hierarchy

PID 1: The Immortal Process

// The kernel's handoff to init // kernel/init/main.c static int __ref kernel_init(void *unused) { // ... kernel initialization ... // Try to execute init programs if (!try_to_run_init_script("/sbin/init") || !try_to_run_init_script("/etc/init") || !try_to_run_init_script("/bin/init") || !try_to_run_init_script("/bin/sh")) return 0; panic("No working init found!"); }

Process Tree Structure

# View process tree pstree -p systemd(1)─┬─systemd-journal(289) ├─systemd-udevd(315) ├─systemd-network(420) ├─systemd-resolve(421) ├─sshd(890)───sshd(1234)───bash(1235) ├─nginx(1001)─┬─nginx(1002) │ └─nginx(1003) └─cron(1100)

SysV Init: The Traditional Approach

Architecture

# /etc/inittab - The master control file # Format: id:runlevels:action:process # Default runlevel id:3:initdefault: # System initialization si::sysinit:/etc/rc.d/rc.sysinit # Runlevel scripts l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 l6:6:wait:/etc/rc.d/rc 6 # Terminal gettys 1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2

Runlevels

# Standard runlevels 0 - Halt/Shutdown 1 - Single user mode 2 - Multiuser without network 3 - Full multiuser with network 4 - Unused/Custom 5 - Multiuser with GUI 6 - Reboot # Change runlevel init 3 # Switch to runlevel 3 telinit 5 # Alternative command # Check current runlevel runlevel who -r

Service Scripts

#!/bin/bash # /etc/init.d/myservice # chkconfig: 345 85 15 # description: My custom service # Source functions . /etc/rc.d/init.d/functions case "$1" in start) echo -n "Starting myservice: " daemon /usr/bin/myservice touch /var/lock/subsys/myservice echo ;; stop) echo -n "Stopping myservice: " killproc myservice rm -f /var/lock/subsys/myservice echo ;; status) status myservice ;; restart) $0 stop $0 start ;; *) echo "Usage: $0 {start|stop|status|restart}" exit 1 esac exit 0

Service Management

# Start/stop services service httpd start service httpd stop service httpd restart service httpd status # Enable/disable at boot chkconfig httpd on chkconfig httpd off chkconfig --list # Update RC scripts update-rc.d apache2 enable update-rc.d apache2 disable

systemd: The Modern Powerhouse

Unit Files

# /etc/systemd/system/myapp.service [Unit] Description=My Application Service Documentation=https://myapp.example.com/docs After=network.target postgresql.service Requires=postgresql.service Wants=redis.service [Service] Type=notify ExecStartPre=/usr/bin/myapp-check ExecStart=/usr/bin/myapp --config /etc/myapp/config.yaml ExecReload=/bin/kill -HUP $MAINPID ExecStop=/usr/bin/myapp-shutdown Restart=on-failure RestartSec=5s User=myapp Group=myapp WorkingDirectory=/var/lib/myapp # Security settings PrivateTmp=true NoNewPrivileges=true ReadOnlyPaths=/etc ReadWritePaths=/var/lib/myapp ProtectSystem=strict ProtectHome=true # Resource limits LimitNOFILE=65536 LimitNPROC=4096 MemoryLimit=2G CPUQuota=50% [Install] WantedBy=multi-user.target

Unit Types

# Service units (.service) - System services systemd-networkd.service # Socket units (.socket) - Network sockets sshd.socket # Target units (.target) - Group of units multi-user.target # Mount units (.mount) - Filesystem mount points home.mount # Timer units (.timer) - Scheduled tasks backup.timer # Path units (.path) - Path monitoring config-monitor.path # Slice units (.slice) - Resource control groups user.slice # Device units (.device) - Device activation dev-sda1.device # Swap units (.swap) - Swap space swap.swap # Automount units (.automount) - On-demand mounting mnt-backup.automount

systemd Commands

# Service management systemctl start nginx systemctl stop nginx systemctl restart nginx systemctl reload nginx systemctl status nginx # Enable/disable services systemctl enable nginx systemctl disable nginx systemctl is-enabled nginx # System state systemctl is-system-running systemctl list-units systemctl list-units --failed systemctl list-unit-files # Targets (similar to runlevels) systemctl get-default systemctl set-default graphical.target systemctl isolate multi-user.target # Dependencies systemctl list-dependencies nginx systemctl show nginx # Logs journalctl -u nginx journalctl -f # Follow mode journalctl -b # Current boot journalctl --since "2024-01-01" journalctl -p err # Error priority # Analyze boot systemd-analyze systemd-analyze blame systemd-analyze critical-chain systemd-analyze plot > boot.svg

Timer Units (cron replacement)

# /etc/systemd/system/backup.timer [Unit] Description=Daily Backup Timer Requires=backup.service [Timer] OnCalendar=daily OnCalendar=*-*-* 02:00:00 Persistent=true RandomizedDelaySec=30min [Install] WantedBy=timers.target # /etc/systemd/system/backup.service [Unit] Description=System Backup [Service] Type=oneshot ExecStart=/usr/local/bin/backup.sh

Socket Activation

# /etc/systemd/system/myapp.socket [Unit] Description=MyApp Socket [Socket] ListenStream=8080 Accept=false [Install] WantedBy=sockets.target # Service starts on-demand when socket receives connection

OpenRC: The Elegant Alternative

Service Scripts

#!/sbin/openrc-run # /etc/init.d/myservice description="My custom service" command="/usr/bin/myservice" command_args="--config /etc/myservice/config" pidfile="/run/myservice.pid" command_background=true command_user="myservice:myservice" depend() { need net use logger after firewall before nginx } start_pre() { checkpath --directory --owner myservice:myservice /var/lib/myservice } stop_post() { rm -f /var/cache/myservice/* } reload() { ebegin "Reloading ${RC_SVCNAME}" start-stop-daemon --signal HUP --pidfile "${pidfile}" eend $? }

Runlevel Management

# Runlevels structure /etc/runlevels/ ├── boot/ # Boot-time services ├── default/ # Default runlevel ├── nonetwork/ # No network runlevel ├── shutdown/ # Shutdown services └── sysinit/ # System initialization # Add service to runlevel rc-update add nginx default rc-update del nginx default # List services rc-status rc-status --all # Service control rc-service nginx start rc-service nginx stop rc-service nginx restart

Comparison: SysV vs systemd vs OpenRC

Boot Performance

# Measure boot time # SysV Init: Sequential startup Boot time: ~30-60 seconds (typical) # systemd: Parallel startup systemd-analyze Startup finished in 3.241s (firmware) + 2.123s (loader) + 4.567s (kernel) + 8.234s (userspace) = 18.165s # OpenRC: Dependency-based parallel rc-status --time

Service Dependencies

# SysV Init: Numeric ordering /etc/rc3.d/ S01networking -> ../init.d/networking S02postgresql -> ../init.d/postgresql S03nginx -> ../init.d/nginx # systemd: Explicit dependencies After=network.target postgresql.service Requires=postgresql.service Wants=redis.service # OpenRC: Dependency functions depend() { need net postgresql want redis after firewall }

Resource Control

# SysV Init: Limited (via ulimit) ulimit -n 65536 # File descriptors nice -n 10 /usr/bin/myapp # Priority # systemd: Comprehensive cgroup integration CPUQuota=50% MemoryLimit=2G TasksMax=4096 IOWeight=100 # OpenRC: Basic cgroup support rc_cgroup_mode="unified" rc_cgroup_memory="2G" rc_cgroup_cpu="50%"

Process Supervision

systemd Restart Policies

[Service] Restart=always # Always restart Restart=on-failure # Restart on non-zero exit Restart=on-abnormal # Restart on signal/timeout Restart=on-abort # Restart on unclean signal Restart=on-watchdog # Restart on watchdog timeout RestartSec=5s # Delay between restarts StartLimitBurst=5 # Max restarts in interval StartLimitIntervalSec=60s

Watchdog Support

// Application with systemd watchdog #include <systemd/sd-daemon.h> int main() { // Notify systemd we're ready sd_notify(0, "READY=1"); // Get watchdog interval uint64_t usec; if (sd_watchdog_enabled(0, &usec) > 0) { uint64_t interval = usec / 2; // Ping at half interval while (running) { // Do work... // Ping watchdog sd_notify(0, "WATCHDOG=1"); usleep(interval); } } // Notify stopping sd_notify(0, "STOPPING=1"); return 0; }

Advanced Features

systemd Generators

# Generators create unit files dynamically at boot /usr/lib/systemd/system-generators/ ├── systemd-fstab-generator # Creates mount units from /etc/fstab ├── systemd-cryptsetup-generator # Encrypted volumes └── systemd-gpt-auto-generator # GPT partition discovery # Custom generator #!/bin/bash # /etc/systemd/system-generators/custom-generator UNIT_DIR="$1" cat > "$UNIT_DIR/generated.service" <<EOF [Unit] Description=Generated Service [Service] ExecStart=/usr/bin/generated-app EOF

Drop-in Directories

# Override or extend unit files without modifying originals /etc/systemd/system/nginx.service.d/ └── override.conf # Create drop-in systemctl edit nginx # Contents of override.conf [Service] # Override specific settings MemoryLimit=4G Environment="CUSTOM_VAR=value" # View effective configuration systemctl cat nginx

Template Units

# /etc/systemd/system/app@.service [Unit] Description=App Instance %i [Service] ExecStart=/usr/bin/app --instance %i User=app-%i [Install] WantedBy=multi-user.target # Usage systemctl start app@web.service systemctl start app@api.service systemctl enable app@{web,api,worker}.service

Migration Guide

Converting SysV to systemd

# SysV Init script #!/bin/bash # /etc/init.d/oldservice case "$1" in start) /usr/bin/oldservice --daemon ;; stop) killall oldservice ;; esac # Equivalent systemd unit # /etc/systemd/system/oldservice.service [Unit] Description=Old Service (migrated) After=network.target [Service] Type=forking ExecStart=/usr/bin/oldservice --daemon ExecStop=/usr/bin/killall oldservice PIDFile=/var/run/oldservice.pid [Install] WantedBy=multi-user.target

Troubleshooting

Common Issues

# Service fails to start systemctl status failed-service journalctl -u failed-service -n 50 systemctl reset-failed # Dependency issues systemctl list-dependencies --reverse service systemd-analyze verify /etc/systemd/system/*.service # Boot hangs # Add to kernel parameters: systemd.log_level=debug systemd.log_target=console # Emergency/Rescue mode systemctl emergency # Minimal environment systemctl rescue # Single user mode # Mask problematic services systemctl mask problem.service

Best Practices

  1. Use native unit files - Avoid SysV compatibility mode
  2. Set proper dependencies - Define After/Requires correctly
  3. Implement graceful shutdown - Handle SIGTERM properly
  4. Use security features - Sandboxing, namespaces, capabilities
  5. Monitor with journald - Centralized, structured logging
  6. Test unit files - Use systemd-analyze verify
  7. Document services - Add Description and Documentation
  8. Handle failures - Configure restart policies

Conclusion

The init system is the backbone of your Linux system, orchestrating the complex dance of services that bring your machine to life. While SysV Init served us well for decades with its simple, script-based approach, systemd has revolutionized system management with parallel startup, sophisticated dependency handling, and integrated logging.

Our interactive visualization demonstrated how these different philosophies translate into real-world boot sequences and service management. Whether you prefer the simplicity of SysV, the power of systemd, or the elegance of OpenRC, understanding your init system is crucial for effective Linux administration.

Remember: the best init system is the one that meets your needs and that you understand well enough to troubleshoot at 3 AM.

Next: Kernel Modules → ← Back to Boot Process

If you found this explanation helpful, consider sharing it with others.

Mastodon