While most Linux administrators are familiar with standard runlevels (0-6), Debian-based systems introduce a special runlevel 'S' that behaves differently from traditional single-user mode (runlevel 1). This runlevel serves as the system's initialization phase before transitioning to other runlevels.
In Debian's implementation:
# Typical runlevel S script example
/etc/rcS.d/S01mountkernfs.sh
/etc/rcS.d/S02hostname.sh
/etc/rcS.d/S03checkroot.sh
These scripts execute before any other runlevel-specific scripts, performing critical early system initialization.
Unlike traditional single-user mode (runlevel 1):
- Runlevel S runs before any other runlevel
- It's not interactive (no root shell provided)
- Used for mounting filesystems and other low-level initialization
Services like Firestarter and Shorewall use rcS.d because:
# Example firewall rule in rcS.d
#!/bin/sh
# /etc/rcS.d/S20firewall
iptables -P INPUT DROP
iptables -A INPUT -i lo -j ACCEPT
This ensures firewall rules load before networking starts, providing early security.
Consider putting services in rcS.d when they need to:
- Run before any other services
- Initialize critical system components
- Set up security measures early
For most services, traditional runlevel directories (rc2.d, rc3.d, etc.) remain appropriate.
While systemd replaces traditional init systems, it maintains compatibility:
# systemd equivalent for rcS.d functionality
[Unit]
Description=Early firewall rules
DefaultDependencies=no
Before=sysinit.target
The principles remain relevant even in systemd-based systems.
In traditional Unix systems, runlevel 'S' typically refers to Single-User Mode, similar to runlevel 1. However, in Debian and Ubuntu-based systems, this interpretation doesn't quite hold true. Through examining system behavior and package implementations (like Shorewall and Firestarter), we can see runlevel 'S' serves a different purpose.
Debian's init system (both sysvinit and systemd-compat) uses runlevel 'S' as a special transitional state during system initialization. This becomes clear when we examine the boot sequence:
# Typical Debian boot sequence
/etc/init.d/rc S
/etc/init.d/rc 2 # Default runlevel
The key differences from standard implementations:
- Not a persistent runlevel like traditional 'S'
- Executes before any other runlevel
- Used for fundamental system initialization
Packages like Shorewall place their startup scripts in /etc/rcS.d
because:
- They need to initialize before networking services start
- They provide foundational system services
Here's a typical firewall script example that belongs in rcS.d:
#!/bin/sh
### BEGIN INIT INFO
# Provides: firewall
# Required-Start: $local_fs
# Required-Stop: $local_fs
# Default-Start: S
# Default-Stop: 0 1 6
# Short-Description: Firewall rules
### END INIT INFO
iptables -F
iptables -A INPUT -i lo -j ACCEPT
# ... more rules ...
When deciding where to place your startup script:
Location | When to Use |
---|---|
rcS.d | System-critical services that must initialize before other runlevels |
rc2.d | Normal multi-user services (default runlevel) |
rc1.d | Single-user mode maintenance scripts |
To troubleshoot scripts in the S runlevel:
# Check boot messages
dmesg | grep -i rcS
# Manually test script execution
sudo /etc/init.d/rc S
Remember that scripts in rcS.d should be lightweight and avoid dependencies on services that start in normal runlevels.