SMF services
On illumos the init system is the Service Management Facility (SMF) — not
systemd, not SysV rc, not BSD rc.conf. If you come from NixOS you will reach
for systemd.services.*; on solnix the equivalent is smf.services.*. This
page explains what SMF is, the concepts you need (FMRIs, states, milestones,
manifests), the commands you use day to day (svcs, svcadm, svccfg), and
how solnix layers a declarative Nix module on top.
On illumos generally SMF has been the init and service supervisor since Solaris 10 (2005) and is mature and load-bearing. On solnix the
smf.services.*module that renders manifests from Nix is planned (roadmap T1.11/T1.12); SMF itself is inherited from the illumos userland and is real. Commands likesvcs/svcadm/svccfgbelow are the genuine illumos commands.
SMF versus systemd, in one table
If you know systemd, this mapping gets you most of the way:
| Concept | systemd | SMF |
|---|---|---|
| Service identity | sshd.service | FMRI svc:/network/ssh:default |
| Definition | unit file (.service) | manifest (XML) + method script |
| List services | systemctl list-units | svcs -a |
| Start / stop | systemctl start/stop | svcadm enable/disable |
| Restart | systemctl restart | svcadm restart |
| Why did it fail? | systemctl status / journalctl | svcs -x / service log |
| Boot targets | targets (multi-user.target) | milestones (svc:/milestone/multi-user) |
| Config store | unit files on disk | SQLite repository (svc.configd) |
| Reload config | systemctl daemon-reload | svccfg import / manifest-import |
| Auto-restart on crash | Restart= | restarter policy + fault boundary |
The biggest conceptual difference: SMF keeps live service configuration in a
repository (a SQLite database owned by svc.configd), not only in flat
files. Manifests seed the repository; running config can be changed with
svccfg without editing the manifest. solnix treats the manifest as the source
of truth and re-imports on activation — the Nix way.
Ground truth: the concepts
FMRIs
Every service is named by a Fault Managed Resource Identifier (FMRI):
svc:/<category>/<name>:<instance>
For example svc:/network/ssh:default or svc:/system/console-login:default.
You can usually abbreviate to the shortest unambiguous suffix, so svcs ssh
works. A service can have multiple instances (:default, :vt2, …);
each instance runs and is enabled/disabled independently.
Service states
An instance is always in exactly one state. svcs shows it in the STATE
column:
| State | Meaning |
|---|---|
online | Running and healthy. |
offline | Enabled but a dependency is not yet satisfied. |
disabled | Administratively off (persists across reboot). |
maintenance | Failed too many times / method error — needs a human. |
degraded | Running but not fully functional. |
uninitialized | Not yet examined by its restarter. |
legacy_run | An old rc-style script, tracked but not managed. |
maintenance is the one you will care about most — it means SMF gave up
restarting the service because it kept failing. See Debugging.
Milestones
Milestones are pseudo-services that group other services, like systemd targets:
svc:/milestone/single-user— single-user mode.svc:/milestone/multi-user— normal multi-user, no network servers.svc:/milestone/multi-user-server— multi-user plus network services.
The solnix Phase-1 target is multi-user-server. You can boot to a milestone
(boot -m milestone=single-user) or move the running system with
svcadm milestone.
Manifests and method scripts
A manifest is an XML file describing a service — its FMRI, dependencies,
start/stop methods, and default properties — conforming to
service_bundle.dtd.1. Manifests live under:
/lib/svc/manifest/<category>/<name>.xml
The commands SMF runs to start/stop/refresh a service are method scripts,
conventionally under /lib/svc/method/. A start method exits 0 on success;
SMF watches the process and applies the restart policy if it dies.
At boot, svc:/system/manifest-import:default scans the manifest directories
and imports anything new or changed into the repository. You can do it by hand:
pfexec svccfg import /lib/svc/manifest/network/ssh.xml
Note: solnix uses
pfexec(illumos’ssudo-equivalent, backed by RBAC profiles) for privileged commands throughout this handbook.
The repository
Live configuration lives in a SQLite database at
/etc/svc/repository.db, owned by the svc.configd daemon. You never edit it
directly — you go through svccfg. svc.startd is the master restarter that
actually runs services and enforces dependencies.
Commands you use every day
svcs — list and inspect
svcs # all enabled instances and their state
svcs -a # include disabled instances
svcs ssh # one service
svcs -x # explain anything not running that should be
svcs -p svc:/network/ssh:default # show the processes of a service
svcs -l svc:/network/ssh:default # long form: deps, method, log location
svcs -d svc:/network/ssh:default # dependencies
svcs -D svc:/network/ssh:default # dependents
svcs -x is the single most useful command when something is wrong — it walks
the dependency graph and tells you which service is blocking and where its log
is.
svcadm — change state
pfexec svcadm enable svc:/network/ssh:default # start now + on boot
pfexec svcadm enable -t svc:/network/ssh:default # start now, not persistent (-t = temporary)
pfexec svcadm disable svc:/network/ssh:default # stop now + on boot
pfexec svcadm restart svc:/network/ssh:default # restart
pfexec svcadm refresh svc:/network/ssh:default # reread config (like SIGHUP)
pfexec svcadm clear svc:/network/ssh:default # clear maintenance, retry
pfexec svcadm milestone milestone/multi-user-server # move the whole system
svcadm clear is how you retry a service that landed in maintenance after you
have fixed the cause.
svccfg — edit configuration and manifests
pfexec svccfg import /path/to/service.xml # import/update a manifest
pfexec svccfg export svc:/network/ssh:default # dump current config as XML
svccfg -s svc:/network/ssh:default listprop # list an instance's properties
pfexec svccfg -s svc:/network/ssh:default \
setprop config/listen_port = integer: 2222 # change a property
pfexec svcadm refresh svc:/network/ssh:default # make the change take effect
Logs
Each service instance has its own log — this is where a start-method’s stdout and stderr go:
/var/svc/log/<fmri-with-slashes-as-dashes>.log
# e.g. /var/svc/log/network-ssh:default.log
svcs -l <fmri> prints the exact logfile path. The workflow for a failed
service is almost always:
svcs -x # 1. what is broken and why
svcs -l svc:/network/ssh:default # 2. find its log
tail /var/svc/log/network-ssh:default.log # 3. read the actual error
The system-wide boot/service log is /var/svc/log/svc.startd.log.
How solnix manages services
The NixOS module system is reused verbatim, but the service layer is replaced.
Where NixOS has systemd.services.<name>, solnix has:
smf.services.<name> = {
# declarative description: command, dependencies, environment, restart policy
};
The module renders the SMF XML manifest and the method script from that
declaration into the system closure, and the activation step runs
svccfg import followed by svcadm to bring the system to the target milestone
(multi-user-server). This is the direct analog of nixbsd rendering rc.conf +
/etc/rc.d entries and driving the FreeBSD rc system.
The key asymmetry with NixOS on Linux: SMF is already running when the
activation script executes. solnix is not the init system — svc.startd is.
solnix feeds the init system a manifest and asks it to converge. That keeps
the module small and means a solnix generation switch is “import the new
manifests, converge to the milestone,” not “become PID 1.”
Further reading
- SMF
smf(7)— the concept manual page. svcs(1),svcadm(8),svccfg(8)— command references.- See Debugging for diagnosing failed services with
svcs -x. - See Further reading & resources for the canonical SMF admin guides.