- Shell 100%
| completions | ||
| install.sh | ||
| LICENSE | ||
| README.md | ||
| service | ||
service — runit wrapper for Void Linux
A familiar service command that wraps runit, giving you a systemd/sysvinit-style interface with automatic dependency resolution and boot-time ordering. No symlinks, no guesswork.
Install
git clone <repo> && cd runit-wrapper
sudo ./install.sh
This installs:
/usr/local/bin/service— the main command/etc/service.d/— dependency configuration (created empty)/etc/sv.d/— auto-generated boot wrappers (managed by the tool)- Bash tab completion
Quick start
service nginx start # start nginx (and any dependencies)
service nginx stop # stop nginx
service nginx restart # restart nginx
service nginx enable # enable at boot
service nginx disable # disable at boot
service nginx status # show status
That's it for 99% of use cases.
Dependency management
Some services need other services to be running first. Instead of figuring out runit's sv check dance, declare dependencies:
# nginx needs dbus running first
service nginx add-dep dbus
# Show the dependency tree
service nginx deps
# nginx
# └── dbus (running)
# Remove a dependency
service nginx remove-dep dbus
Dependencies are stored as plain text in /etc/service.d/<name>.dep (one dependency per line). You can edit these files directly if you prefer.
What happens at boot
When you enable a service that has dependencies, the tool generates a thin wrapper in /etc/sv.d/<name>/ that waits for each dependency to come up before starting the real service. The wrapper execs into the original run script so runit supervises the actual process, not the wrapper. Your original service files in /etc/sv/ are never modified.
Services without dependencies are linked directly to /etc/sv/ as usual.
What happens interactively
service <name> start resolves the full dependency tree (topological sort with cycle detection), starts everything in the right order, and waits for each service to be up before continuing.
Virtual targets
Some dependencies aren't runit services — they're system states. These are called virtual targets:
| Target | Description |
|---|---|
network-online |
Waits until the network has a default route |
service myapp add-dep network-online
Boot hooks (oneshot scripts)
Need to run a script once per boot after the network comes up? Create a hook:
service create-hook mysetup --after network-online --exec /root/setup.sh
service mysetup enable
The script runs exactly once per boot. If the machine reboots, it runs again. Hooks are regular runit services under the hood, so service mysetup status and service mysetup logs work as expected.
# Remove a hook (also disables it)
service remove-hook mysetup
List services
service list # all services
service list --enabled # only enabled
service list --disabled # only disabled
Environment variables
| Variable | Default | Description |
|---|---|---|
SERVICE_TIMEOUT |
30 |
Seconds to wait for dependencies |
How it maps to runit
| This tool | What it does under the hood |
|---|---|
service X start |
Resolve deps → sv start each in order |
service X stop |
sv stop X |
service X restart |
sv restart X |
service X enable |
ln -s /etc/sv/X /var/service/X (or wrapper) |
service X disable |
rm /var/service/X + cleanup wrapper |
service X status |
sv status X + dep info |
service X logs |
tail -f /var/log/X/current |
File layout
/usr/local/bin/service Main script
/etc/service.d/
├── nginx.dep Dependencies (one per line)
├── mysetup.dep Hook dependency
└── mysetup.hook Marker file (identifies hooks)
/etc/sv.d/
└── nginx/
├── run Generated wrapper (waits for deps, execs real run)
└── log -> /etc/sv/nginx/log
/etc/sv/ Original runit service definitions (untouched)
/var/service/ Active services (symlinks managed by this tool)
Uninstall
sudo rm /usr/local/bin/service
sudo rm -rf /etc/sv.d /etc/service.d
# Bash completion (location may vary):
sudo rm /usr/share/bash-completion/completions/service