Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 like svcs/svcadm/svccfg below are the genuine illumos commands.

SMF versus systemd, in one table

If you know systemd, this mapping gets you most of the way:

ConceptsystemdSMF
Service identitysshd.serviceFMRI svc:/network/ssh:default
Definitionunit file (.service)manifest (XML) + method script
List servicessystemctl list-unitssvcs -a
Start / stopsystemctl start/stopsvcadm enable/disable
Restartsystemctl restartsvcadm restart
Why did it fail?systemctl status / journalctlsvcs -x / service log
Boot targetstargets (multi-user.target)milestones (svc:/milestone/multi-user)
Config storeunit files on diskSQLite repository (svc.configd)
Reload configsystemctl daemon-reloadsvccfg import / manifest-import
Auto-restart on crashRestart=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:

StateMeaning
onlineRunning and healthy.
offlineEnabled but a dependency is not yet satisfied.
disabledAdministratively off (persists across reboot).
maintenanceFailed too many times / method error — needs a human.
degradedRunning but not fully functional.
uninitializedNot yet examined by its restarter.
legacy_runAn 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’s sudo-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