system-control, systemctl, initctl, svcadm — process system control jobs, sending commands to the system manager and service manager
system-control
{command
} [arguments or options
]
systemctl
{command
} [arguments or options
]
initctl
{command
} [arguments or options
]
svcadm
{command
} [arguments or options
]
system-control takes a subcommand as
command
that instructs it on what to do.
For limited systemd compatibility, it is also available as systemctl.
Not all subcommands are supported, nor is placing subcommand options before the command
.
For similarly limited upstart compatibility, it is also available as initctl.
For similarly limited SunOS compatibility, it is also available as svcadm.
It operates in one of two modes, controlled by the {--user} command line option:
In "system" mode it operates on system-wide state and services.
It potentially communicates with a System Manager process, which must be process #1 and which it expects to recognize the same signals as system-manager(1) does.
It potentially communicates with a Service Manager process, such as service-manager(1) via a local domain socket at /run/service-manager/control
and via the control/status API of the individual services.
In "user" mode it operates on per-user state and services.
It potentially communicates with a Session Manager process, which again it expects to recognize the same signals as per-user-manager(1) does.
It potentially communicates with a Service Manager process, such as service-manager(1) via a local domain socket at /run/user/
and via the control/status API of the individual services.
$USER
/service-manager/control
Services and targets are defined by bundle directories.
Although there is no constraint enforced, and system-control simply follows symbolic links, by convention service bundle directories generally live under /etc/service-bundles/services
, /run/service-bundles/services
, or /var/sv
; and target bundle directories generally live under /etc/service-bundles/targets
.
A service is generally a dæmon process that runs. A target is generally a collection of services that are started/stopped together.
The start and stop subcommands construct jobs, which comprise a set of actions. Each action is a start or a stop command to the control API of a service/target. Jobs are composed by starting with an action on a named service, and then following information in the service bundles to related services and targets. The service bundles also determine the order in which the actions are taken.
A start action simply requests that the service manager bring the service/target to the "running" state, if it isn't already there.
A stop action, however, is more complex.
Initially it requests that the service manager bring the service/target to the "stopped" state (if it isn't already there).
However, if that does not happen within 60 seconds, it requests that the service manager send the SIGKILL
signal to the service/target.
A bundle directory contains the command information, dependency information, relationship information, and control/status API for a service. It contains various subdirectories (which can be symbolic links to directories elsewhere):
The service/
and supervise/
subdirectories are (respectively) the service and supervise directories for the service, comprising the command information and the control/status API.
See service-manager(1) for what service and supervise directories contain.
(service-dt-scanner(1) implements a slight extension here, for compatibility.)
When bundles are on a read-only filesystem, such as a CD-ROM, supervise
must be a symbolic link pointing to a directory on a read-write filesystem, since supervise directories must be writable.
One might choose a subdirectory of /run/service-bundles/early-supervise/
for example.
system-control attempts to create the target of such a symbolic link before attempting to load the service, to avoid a chicken-and-egg situation with "sysinit" services that are set up this way.
The wants/
, requires/
, conflicts/
, wanted-by/
, stopped-by/
, and required-by/
subdirectories comprise dependency or dependency installation information.
Each contains a set of symbolic links to other bundle directories for other services.
wants/
contains links to services that the current service "wants".
Starting the current service implies starting the linked-to service as well.
requires/
contains links to services that should be "required-by" the current service when it is enabled.
Enabling the service places it in the targets' "required-by" lists, and disabling the service removes it.
conflicts/
contains links to services that "conflict" with the current service.
Starting the current service implies stopping the linked-to services.
required-by/
contains links to services that "require" the current service.
Stopping the current service implies stopping the linked-to services as well.
wanted-by/
contains links to (standard) targets that should "want" the current service when it is enabled.
Enabling the service places it in the targets' "wants" lists, and disabling the service removes it.
stopped-by/
contains links to (standard) targets that should "conflict" with the current service when it is enabled.
Enabling the service places it in the targets' "conflicts" lists, and disabling the service removes it.
The after/
and before/
subdirectories comprise relationship information.
Relationships govern the ordering between the individual actions in a start/stop job.
after/
contains links to services that should be started
after/stopped before the current service when executing a start/stop job.
before/
contains links to services that should be started
before/stopped after the current service when executing a start/stop job.
Relationships are not the same as dependencies.
A service can "want" another service without having any ordering against it with respect to start/stop actions.
Indeed, this is a common case for system targets.
The normal
target, for example, "wants" the server
, workstation
, multi-user
, static-networking
, and users
targets (and by extension everything that they in their turn "want"), but all of the wanted services are started in parallel with the normal
target itself.
Similarly, a service can be ordered with respect to another service without having a dependency from it.
For example, both "log" and "main" services are "wanted" by the server
and workstation
targets, explicitly.
The individual "main" services, therefore, only need to be ordered after their corresponding "log" services, and do not "want" them.
("log" services are first-class citizens in this respect.)
There are no implicit relationships or dependencies in a bundle. The relationships and dependencies are exactly what is explicitly in the filesystem. system-control will fail if the recorded relationships and dependencies are self-contradictory or impossible (such as a service that conflicts with itself, for example).
Several subcommands take a list of bundle names
... .
Each name
can be the full absolute pathname of a bundle directory or a relative pathname with a directory prefix, in which case it is used as-is, or a bundle directory name without any directory prefix, in which case a set of standard locations is searched for a bundle directory by that name.
The search algorithm is as follows:
A name
that ends in .target
is searched for (sans the .target
suffix) in the standard locations for target bundles:
System-wide target directories:
/run/service-bundles/targets/
/usr/local/etc/service-bundles/targets/
/etc/service-bundles/targets/
/usr/local/share/service-bundles/targets/
/usr/share/service-bundles/targets/
/var/service-bundles/targets/
Per-user target directories:
$XDG_RUNTIME_DIR
/service-bundles/targets/
$HOME
/.config/service-bundles/targets/
A name
that ends in .service
or .socket
is searched for (sans those suffixes) in the standard locations for service bundles:
System-wide service directories:
/run/service-bundles/services/
/usr/local/etc/service-bundles/services/
/etc/service-bundles/services/
/usr/local/share/service-bundles/services/
/var/local/service-bundles/services/
/var/local/sv/
/usr/share/service-bundles/services/
/var/service-bundles/services/
/var/sv/
/var/svc.d/
/service/
Per-user service directories:
$XDG_RUNTIME_DIR
/service-bundles/services/
$HOME
/.config/service-bundles/services/
Any other name
is searched for (as-is) in the standard locations for service and for target bundles.
If the path search fails, the name
is simply assumed to name a bundle directory in the current directory.
system-control
{version}
For compatibility with uses of initctl, the version subcommand displays the (compiled-in) version of the toolset. It does not contain the string "upstart".
system-control
{reboot} [ -f | --force ]
system-control
{halt} [ -f | --force ]
system-control
{powercycle} [ -f | --force ]
system-control
{poweroff} [ -f | --force ]
system-control
{emergency}
system-control
{rescue}
system-control
{normal}
system-control
{init} [--user] [ -o | --update ] [ -s | --single ] [ -b | --emergency ] [-a] [-f] [-z string
] [runlevel(s)
...]
Those subcommands communicate with the system manager to change system state. system-control sends a signal to process #1 using the kill(2) system call. It will fail if it does not have the necessary privileges for sending a signal to that process.
command | signal | |
---|---|---|
on BSD | on Linux | |
halt | SIGUSR1 | SIGRTMIN + 3 |
halt -f | SIGRTMIN + 13 | |
poweroff | SIGUSR2 | SIGRTMIN + 4 |
poweroff -f | SIGRTMIN + 14 | |
reboot | SIGINT | SIGRTMIN + 5 |
reboot -f | SIGRTMIN + 15 | |
powercycle | SIGWINCH | SIGRTMIN + 7 |
powercycle -f | SIGRTMIN + 17 | |
emergency | SIGRTMIN + 2 | |
rescue | SIGRTMIN + 1 | |
normal | SIGRTMIN + 0 | |
init [ 2 | 3 | 4 | 5 | m | auto ] | SIGRTMIN + 10 | |
SIGRTMIN + 0 | ||
init 1 | S | s | single | SIGRTMIN + 10 | |
SIGRTMIN + 1 | ||
init -s | SIGRTMIN + 2 | SIGRTMIN + 10 |
SIGRTMIN + 1 | ||
init -b | b | emergency | SIGRTMIN + 2 | |
init H | h | SIGUSR1 | SIGRTMIN + 3 |
init C | c | SIGWINCH | SIGRTMIN + 7 |
init 0 | SIGUSR2 | SIGRTMIN + 4 |
init 6 | SIGINT | SIGRTMIN + 5 |
Exactly how the system power cycles, powers off, halts, reboots, switches to normal, emergency, or rescue modes, and so forth is entirely up to whatever is running as process #1, which is expected to be in charge of system state. These subcommands do nothing except send the signals to command the system manager. They do not directly enact any system state change themselves. In part this is because that would open up the possibility of the service manager killing the process that was (partway through) enacting the state changes, if a state change happened to affect the service running the system-control command.
The [--force] command line argument is used within the various targets and is intended to cause the system manager to proceed directly to the finalization action.
The init subcommand is spawned by system-manager(8) and per-user-manager(8) as their initial action. They pass it the command line arguments that they themselves were invoked with. As such, its command line syntax is modelled on what boot loaders and kernels tend to supply to process #1, which is a largely undocumented and non-standardized mixture of old-style runlevels and options.
In normal and rescue modes it sends two signals to process #1, instituting a two-phase initialization sequence similar to the FILESYSTEMS
milestone mechanism in BSD operating systems.
The first phase, the sysinit
target, is expected to initialize as much of the system as necessary so that the second phase, the normal
or rescue
target, can find all service and target bundles, including those that are not on the root filesystem.
There is no q runlevel.
This is deliberate.
Its use case is running telinit q after updating /etc/ttys
or /etc/inittab
.
Any script that is updating those files and then expecting the system manager to re-read them is not targetting the correct configuration mechanisms, and is in error.
LILO, the FreeBSD loader(8), GRUB, and others may cause -a or -f options to be passed. Their meanings are non-standard, largely or even wholly undocumented, inconsistent across platforms and toolsets, considered obsolete in their original forms, and without application here. The -z option is a dummy space-taker that is also used by such systems. All three options are ignored. The --update command line option is reserved for future use.
system-control
{ start | activate } [--colour] [--verbose] [--pretend] [names
...]
system-control
{ stop | deactivate } [--colour] [--verbose] [--pretend] [names
...]
system-control
{isolate} [--colour] [--verbose] [--pretend] [names
...]
system-control
{reset} [--colour] [--verbose] [--pretend] [names
...]
These subcommands process one or more jobs, sending messages to the service manager to start or to stop one or more services. Jobs may also involve invoking any number of configurable actions. Jobs processing tries to ensure that service dependencies are correctly maintained and processed. To control services directly and individually without regard for dependencies, use service-control(8).
The --verbose command line option cause information about actions taken and blocked/unblocked services to be written to standard error as jobs are processed. If the standard error is a terminal, system-control uses whatever it can find via the terminfo library to display various parts of the output in different colours, highlighting different events in different colours. The --colour command line option tells it to do this unconditionally, even if its standard error is not a terminal. The --pretend command line option tells it to only pretend that it is taking actions, and not actually take them.
The reset command is intended to be used by package installer programs. It is translated into either start or stop according to whether the service is enabled or disabled; and can be thought of, if one likes, as "reset to however the service is configured to be at bootstrap". This allows package installers to remain in blissful ignorance of whether a service should be started or stopped after installing the package for it. Instead, the package installer simply executes the preset command and then the reset command and the service is started or stopped according to whatever the administrator has chosen.
The isolate subcommand exists for compatibility, and is equivalent to start.
system-control
{enable} [names
...]
system-control
{disable} [names
...]
system-control
{preset} [--prefix prefix
] [--no-system] [--no-rcconf] [--rcconf-file filename
] [--ttys] [--dry-run] [names
...]
These subcommands enable or disable one or more services or targets, so that they do or do not automatically start when one of the standard targets is started and automatically stop when the shutdown standard target is started.
Each service bundle specifies a (symbolically linked) list of target bundles in its wanted-by/
directory.
Usually these will be the workstation
, server
, users
, or multi-user
standard targets.
For each bundle, enabling the service involves symbolically linking its bundle directory into the target bundle's wants/
list, and disabling the service involves removing that link.
Each service bundle also specifies a (symbolically linked) list of target bundles in its stopped-by/
directory.
Usually these will be the shutdown
standard target.
For each bundle, enabling the service involves symbolically linking its bundle directory into the target bundle's conflicts/
and after/
lists, and disabling the service involves removing those links.
The preset command is intended to be used by package installer programs. It is translated into either enable or disable according to a system/administrator-supplied preset flag (unless the --dry-run command line argument is used, causing it to take no actual action). This allows package installers to remain in blissful ignorance of whether a service should be enabled or disabled after installing the package for it. Instead, the package installer simply executes the preset command and the service is set to whatever enabled or disabled status the administrator has chosen.
The service/socket/target that is preset is prefix
name
, with prefix
specifiable via the --prefix command line argument.
Preset information can be taken from one of several sources:
(unless the --no-system command line option is set) systemd and system-manager preset information given in *.preset
files.
There are different sets of files for per-user and system-wide service management.
System-wide preset files are located in the following directories:
/usr/local/etc/system-control/presets/
/etc/system-control/presets/
/etc/systemd/system-preset/
/usr/local/share/system-control/presets/
/usr/local/lib/systemd/system-preset/
/usr/share/system-control/presets/
/usr/lib/systemd/system-preset/
/lib/systemd/system-preset/
Per-user preset files are located in the following directories:
/usr/local/etc/system-control/user-presets/
/etc/system-control/user-presets/
/etc/systemd/user-preset/
$HOME
/.config/system-control/presets/
/usr/local/share/system-control/user-presets/
/usr/local/lib/systemd/user-preset/
/usr/share/system-control/user-presets/
/usr/lib/systemd/user-preset/
/lib/systemd/user-preset/
Contrary to its doco, systemd has four places for system-wide/user-level preset files, which form part of these lists.
In addition to those locations, preset looks in extra directories where systemd presets can be overridden by system-control-specific information; allowing a system administrator or package writer to preset things one way for systemd and another way for the preset command.
These extra directories follow the more conventional scheme of /etc
, /usr/share
, and /usr/local/etc
for administrator-set, operating-system-set, and application-software-set stuff.
As with systemd, earlier preset directories override later ones; the contents of files with lexically earlier names override the contents of files with lexically later names; and the default state, in the absence of an explicit preset, is "enabled".
Directives are matched against prefix
name
.
(unless the --no-rcconf command line option is set) rc.conf(5) preset information, specifically the
variable, interpreting the values name
_enabletrue
, 1
, yes
, and on
as enable, and any other values (including specifically false
, 0
, no
, and off
) as disable.
By default in system-wide mode the /etc/defaults/rc.conf
, /etc/rc.conf
, and /etc/rc.conf.local
files are used, but the --rcconf-file command line option overrides that list with the single replacement file filename
.
The default for per-user mode is the
file.
$HOME
/.config/rc.conf
The variable names are matched against just name
to allow one to use a main service name as name
and combine it with a log service template prefix
such as cyclog@
or s6-multilog@
, on the grounds that traditional /etc/defaults/rc.conf
, /etc/rc.conf
, and /etc/rc.conf.local
contents do not make explicit provision for separate logging services.
(if the --ttys command line option is set) /etc/ttys
preset information, specifically the on
and off
flags as enable and disable, respectively.
The onifconsole
flag is also recognized and processed with reference to the currently active console device (on BSD systems only).
If /etc/ttys
does not exist, as is usually the case on Linux operating systems, all TTYs default to preset disabled.
The terminal names are matched against just name
.
This allows one to use an ordinary TTY device name as name
and combine it with a "templatized" bundle name prefix
such as ttylogin@
, getty@
, or agetty@
.
(if the --fstab command line option is set)
/etc/fstab
preset information, specifically the noauto
flag as disable.
The device and directory names are matched against just name
, after unescaping it.
This allows one to use an ordinary device or directory name as name
and combine it with a "templatized" bundle name prefix
such as mount@
, fsck@
, swap@
, or dump@
.
This is designed in particular for use with service bundles generated by the convert-fstab-services subcommand.
system-control
{status} [names
...]
system-control
{show} [names
...]
system-control
{find} [names
...]
system-control
{ try-restart | try-reload-or-restart | condrestart | force-reload } [names
...]
system-control
{hangup} [names
...]
system-control
{is-active} [names
...]
system-control
{is-loaded} [names
...]
system-control
{is-enabled} [names
...]
system-control
{unload-when-stopped} [names
...]
system-control takes each of the [names
...], searches for the corresponding service bundle directory, constructs a list of directory names, and chains to other commands with those directory names as arguments:
subcommand | chains to |
status | service-status(1) |
show | service-show(1) |
show-json | service-show(1) --json |
find | ls(1) -1d |
try-restart | service-control(1) --terminate |
try-reload-or-restart | |
force-reload | |
condrestart | |
hangup | service-control(1) --hangup-main |
unload-when-stopped | service-control(1) --exit |
is-active | service-is-up(1) |
is-loaded | service-is-ok(1) |
is-enabled | service-is-enabled(1) |
system-control
{convert-systemd-units} [--bundle-root root
] [--alt-escape] [--etc-bundle] [--escape-instance] [--escape-prefix] [--no-systemd-quirks] [--no-generation-comment] { name
.target | name
@parameter
.target | name
.socket | name
@parameter
.socket | name
.timer | name
@parameter
.timer | name
.service | name
@parameter
.service }
This subcommand takes some systemd unit files and generates from them a service bundle in the current directory (or in the root
directory) that contains scripts, dependencies, and autoboot dependency configuration information.
The bundle is not enabled by the conversion process, but can be started and enabled as it stands, with the start and preset subcommands, just like any other service bundle.
The systemd unit files are determined from the argument. They comprise the main unit file and a collection of snippet files in a related subdirectory whose contents are applied on top of it before conversion.
If
is specified, then that service unit file is converted into a service bundle directory named name
.service
.
Snippet files are in name
/
.
name
.service.d/snippet
.conf
If
is specified, then the name
@parameter
.service
service unit file is converted using name
@.serviceparameter
for parameter substitution into a service bundle directory named
.
Snippet files are in name
@parameter
/
and name
@.service.d/snippet
.conf
.
name
@parameter
.service.d/snippet
.conf
If
is specified, then that target unit file is converted into a target bundle directory named name
.target
.
Snippet files are in name
/
.
name
.target.d/snippet
.conf
If
is specified, then the name
@parameter
.target
target unit file is converted using name
@.targetparameter
for parameter substitution into a target bundle directory named
.
Snippet files are in name
@parameter
/
and name
@.target.d/snippet
.conf
.
name
@parameter
.target.d/snippet
.conf
If
is specified, then it is combined with a name
.timer
service unit file to make a service bundle directory named name
.service
.
Snippet files are in name
/
and name
.timer.d/snippet
.conf
.
name
.service.d/snippet
.conf
If
is specified, then the name
@parameter
.timer
timer unit file is combined with a name
@.timer
service unit file and converted using name
.serviceparameter
for parameter substitution into a service bundle directory named
.
Snippet files are in name
@parameter
/
, name
@.timer.d/snippet
.conf
, and name
@parameter
.timer.d/snippet
.conf
.
name
.service.d/snippet
.conf
If
is specified, and it has name
.socketAccept=true
, then it is combined with a
service unit file to make a service bundle directory named name
@.service
.
Snippet files are in name
/
and name
.socket.d/snippet
.conf
.
name
@.service.d/snippet
.conf
If
is specified, and it has name
.socketAccept=false
, then it is combined with a
service unit file to make a service bundle directory named name
.service
.
Snippet files are in name
/
and name
.socket.d/snippet
.conf
.
name
.service.d/snippet
.conf
If
is specified, and it has name
@parameter
.socketAccept=true
, then the
socket unit file is combined with a name
@.socket
service unit file and converted using name
@.serviceparameter
for parameter substitution into a service bundle directory named
.
Snippet files are in name
@parameter
/
, name
@.socket.d/snippet
.conf
, and name
@parameter
.socket.d/snippet
.conf
.
name
@.service.d/snippet
.conf
If
is specified, and it has name
@parameter
.socketAccept=false
, then the
socket unit file is combined with a name
@.socket
service unit file and converted using name
.serviceparameter
for parameter substitution into a service bundle directory named
.
Snippet files are in name
@parameter
/
, name
@.socket.d/snippet
.conf
, and name
@parameter
.socket.d/snippet
.conf
.
name
.service.d/snippet
.conf
Files found upon opening to be other than regular files are errors.
snippet
files that begin with a dot are skipped, and not opened, per the usual convention.
There is no defined ordering for snippet files relative to one another.
The snippet subdirectory is required to be in the same location as the associated unit files.
Unit files can reference other services.
The assumption is that all service bundles are under one common root
and all target bundles under another; so service-to-service dependencies and orderings can be relative pathnames whilst service-to-target and target-to-service dependencies and orderings have to be absolute pathnames.
The --etc-bundle option changes this assumption, such that target bundles are now assumed to be reachable with relative pathnames from the converted service bundle; as is the case for special early bootstrap service bundles that live in /etc/service-bundles/services/
.
It also forces the bundle to be marked as an EarlySupervise
bundle whose supervise/
directory lives in a tmpfs.
The systemd dual escaped+unescaped forms are available in parameter substitution.
Normally parameter
is taken to be the escaped form and is unescaped during parameter substitution.
This is generally used where parameter
represents something in the filesystem, but has had to be pre-escaped in order to result in a service name without pathname components.
If the --escape-instance option is used, then parameter
is instead taken to be the original, unescaped, form and will be escaped into its service name form.
Normally name
is taken to be the escaped form and is unescaped during parameter substitution.
If the --escape-prefix option is used, then name
is instead taken to be the unescaped form and will be escaped into its service name form.
The normal escaping algorithm is the conventional systemd one that escapes /
and -
.
If the --alt-escape option is used, then an alternative escaping algorithm that escapes /
, \
, ,
, :
, and @
is used instead.
The --alt-escape and --escape-instance options are generally used together, such that the parameter
is the unescaped service bundle directory name and the escaped form is (for example) an account name in an account database.
(e.g. The account name ossec_aagentd-log
being the scaped form of the parameter
in cyclog@ossec@agentd/
.)
Conversion of every possible systemd unit file to a service bundle requires a human being. This subcommand converts systemd units that fall within certain bounds, which (given that most services are fairly simple) should be the majority of systemd units in existence. These bounds are:
The service must be a simple, forking, oneshot, or dbus service. Notify services are not converted. For best results, avoid having forking services in the first place, and change them into simple services wherever possible. service-manager(1) has no dealings with a Desktop Bus, so dbus services are treated as simple services.
Only TCP, UDP, local domain datagram, local domain stream, local domain sequential packet, FIFO, and netlink datagram sockets are converted.
The run
/service
script makes use of udp-socket-listen(1), tcp-socket-listen(1), local-datagram-socket-listen(1), local-stream-socket-listen(1), local-seqpacket-socket-listen(1), fifo-listen(1), netlink-datagram-socket-listen(1), tcp-socket-accept(1), local-stream-socket-accept(1), and local-seqpacket-socket-accept(1) to spawn services, either to listen to the accepting socket or to respond on connecting sockets.
Some of the more esoteric mechanisms, and any undocumented settings, in systemd are not converted. The converter will print a warning for any setting in the unit files that it does not use for conversion. These will include:
Specialized options for conditionally enabling the service, such as conditionpathexists
and conditiondirectorynotempty
, are not converted.
These are almost always in practice used to make services run on specific platforms and not on others, or dependent from the presence of installed packages, and should be replaced with hooks into the preset mechanism.
Other highly specialized options that even systemd recommends against, such as fsckpassno
, are not converted.
Specialized options for TTY management, such as standardinput=tty-force
, are not converted.
Instead of these, employ the vc-get-tty(1), open-controlling-tty(1), and related utilities in the run
script.
Only the SIGHUP
substitute for SIGTERM
via killsignal
is converted.
In practice, this is the primary use case in services that are interactive login shells.
Linux-only mechanisms such as capabilityboundingset
and I/O scheduling are not converted.
This is merely down to a lack of known chaining commands for manipulating those mechanisms.
Import can operate in either "ideal" mode or "quirks" mode. The default is quirks mode, which is the better mode for real systemd unit files. It replicates several quirks of systemd:
It was undocumented for a long time that systemd always sets the HOME
, USER
, and LOGNAME
environment variables whenever a User=
directive says to change the user account.
To this, quirks mode adds the SHELL
environment variable, even though systemd has not customarily implicitly set that variable too.
Ideal mode does not set these environment variables implicitly, since dedicated user accounts for running services do not necessarily have home directories and suchlike.
A User=
directive specifies setting all of the supplementary groups for a user account in addition to its primary group.
The daemontools convention is to just set the primary group when switching to the dedicated unprivileged account for a service, which is the case in ideal mode.
It's not documented, but systemd always changes directory when it starts a service.
It explicitly changes to the root directory when no WorkingDirectory=
directive is given.
The daemontools convention is for services to be run in their service directories, which is the case in ideal mode.
A small number of dæmons have been found to rely upon the undocumented systemd behaviour of being in the root directory.
A fair few directives can occur in both a socket unit or its associated service unit.
The default behaviour in systemd in the absence of a Restart=
directive is to never auto-restart a service.
The daemontools convention is for services to always auto-restart, this having been the norm since the 1990s; and this is the default in ideal mode.
For an Accept=no
(i.e. listening) socket service, systemd implicitly applies any redirection that is applied to standard output to standard error as well.
So (say) StandardOutput=socket
attaches both standard output and standard error to the listening socket.
This coupling is usually not what one wants.
The UCSPI and daemontools norm is for standard error to be independent from standard output and to require its own explicit redirection, which is the case in ideal mode.
When one is using StandardInput=tty
, systemd requires that standard output and error be explicitly directed to the terminal device.
Usually, terminal login services being a very common example of this, one wants all three directed to a terminal.
In ideal mode, the redirection of standard input implies redirecting standard output and error as well.
(Standard error can be retained at its original place with the StandardError=log
extension.)
The --no-systemd-quirks command line option turns off these systemd quirks and sets "ideal" mode. Alternatively, one can turn off some quirks with various unit file directives:
The systemdWorkingDirectory=
setting (defaulting to true
in quirks mode) if false
causes the generated bundle to not bother changing directory to the root.
Set this on services and targets where the dæmon program is happy to run in the service
directory.
The systemdUserEnvironment=
setting (defaulting to true
in quirks mode) if false
causes the generated bundle to not bother setting the user environment variables.
Set this on services and targets where the dæmon program has no need for the HOME
, USER
, LOGNAME
, or SHELL
environment variables.
This is the case for most dæmon programs.
The systemdUserGroups=
setting (defaulting to true
in quirks mode) if false
causes the generated bundle to not bother setting the suplementary user groups.
Set this on services and targets where the dæmon program has no need for supplementary group access.
This is the case for almost all dæmon programs.
There are several extensions to the systemd unit specification provided by the conversion process, to allow a unit file to specify things that systemd doesn't have but that service bundles have:
The ExecStart=
setting does not require that the program be named with an absolute pathname, unlike systemd.
Generated run
scripts will use nosh(1), which searches the PATH
.
(systemd does not search PATH
.)
This makes it possible, for example, for a single service unit file to just say ExecStart=cupsd
without needing to have two different unit files, one saying ExecStart=/usr/sbin/cupsd
for Linux systems and one saying ExecStart=/usr/local/sbin/cupsd
for BSD systems.
The LimitMemory=
setting translates to the -m option of softlimit(1), for setting multiple "memory" resource limits in one go.
The MachineEnvironment=
setting (defaulting to false
) if true
causes the generated bundle to set the machine environment variables with machineenv(1).
The EnvironmentAppendPath=
setting acts like Environment
except that the specified environment variables are augmented with appendpath(1) rather than replaced.
The EnvironmentDirectory=
setting specifies a directory to be read by envdir(1).
Set this on a service that is configured via an envdir
environment directory.
The FullEnvironmentDirectory=
setting specifies that the --full command line option to envdir(1) be applied when reading the environment directory.
The EnvironmentUserOnly=
setting (defaulting to false
) if true
causes the generated bundle to call envuidgid(1) but not setuidgid(1).
Set this on a service where the main dæmon program changes its own process UID and GID, but expects to be told via environment variables what UID and GID to run as.
The EarlySupervise=
setting (defaulting to true
for "etc" bundles and false
for others) if true
causes the generated bundle to use a supervise
directory in /run/service-bundles/early-supervise/
.
This is for avoiding access to /var
before it is mounted, during the bootstrap process, and is mainly used for "sysinit" services and system targets that are in /etc
.
The StoppedBy=
setting defines a stopped-by
relationship to other services, stored in the generated bundle.
This is the inverse of the conflicts
relationship.
By default, unless the DefaultDependencies=false
setting is used, services are stopped by the "shutdown" target in addition to anything specified in this setting.
The JailID=
setting specifies the ID of a jail in which to run the service, as if by jexec(1).
The ProcessGroupLeader=
setting (defaulting to false
) if true
causes the generated bundle to run the dæmon as a process group leader with setpgrp(1).
The SessionLeader=
setting (defaulting to false
) if true
causes the generated bundle to run the dæmon as a session leader with setsid(1).
The TTYPrompt=
setting (defaulting to false
) if true
causes the generated bundle to invoke login-prompt(1).
The BannerLine=
setting causes the generated bundle to invoke line-banner(1) to write the specified banner line before dæmon invocation.
The BannerFile=
setting causes the generated bundle to invoke login-banner(1) to process the specified banner file(s) before dæmon invocation.
The ExecRestartPre=
setting allows one to specify extra commands to be run in the (automatically generated) restart
script.
The UCSPIRules=
setting (defaulting to false
) applies ucspi-socket-rules-check(1) to all accepted connections.
The LogUCSPIRules=
setting (defaulting to false
) causes ucspi-socket-rules-check(1) to print information about access failures.
The NUMAInterleave=
, NUMAMemBind=
, NUMACPUNodeBind=
, NUMAPhysCPUBind=
, NUMALocalAlloc=
, and NUMAPreferred=
settings cause the generated bundle to invoke numactl(1).
The JVMVersions=
, JVMOperatingSystems=
, and JVMManufacturers=
settings cause the generated bundle to invoke find-matching-jvm(1).
Each setting's value is a space-separated list, which is turned into zero or more equivalent command-line options.
The JVMDefault=
setting (defaulting to false
) if true
causes the generated bundle to invoke find-default-jvm(1).
The StandardError=log
setting prevents StandardInput=tty
from redirecting standard error.
The RuntimeDirectoryOwner=
and user
RuntimeDirectoryGroup=
settings specify the owning user and group of the runtime directory.
group
The AfterMountsFor=
setting defines an directories
after
relationship to the mount@
services for each directory
and its parents up to but not including the root directory, stored in the generated bundle.
The WantsMountsFor=
setting defines an directories
wants
relationship to the mount@
services for each directory
and its parents up to but not including the root directory, stored in the generated bundle.
system-control
{convert-fstab-services} [--etc-bundle] [--bundle-root root
]
system-control
{write-volume-service-bundle} [--etc-bundle] [--want-fsck] [--bundle-root root
] {fstype
} {source
} {directory
} {options
}
The convert-fstab-services subcommand takes the entries in /etc/fstab
and generates from them a set of service bundles.
For each non-swap entry:
It acts as if it had run write-volume-service-bundles with the values from the entry.
If the entry specifies a "pass" number that is greater than zero, it creates a fsck@
bundle.
directory
For each swap entry:
It always creates a swap@
bundle.
The bundle is created as device
wanted-by/
either the system swapauto.target
or the system swaplate.target
, so that it is started during autoboot when it is enabled.
The choice depends from whether the entry is marked late
.
If the entry is marked discard
then it creates a bundle that passes the --discard flag to swapon(8).
If the entry is marked pri=
then it creates a bundle that passes the --priority N
N
flag.
It always creates a dump@
bundle.
The bundle is created as device
wanted-by/
the system dumpauto.target
, so that it is started during autoboot when it is enabled.
The write-volume-service-bundles subcommand writes service bundles that contain scripts, dependencies, and autoboot dependency configuration information appropriate for mounting, unmounting, and checking a volume.
It always creates a mount@
bundle that at service startup mounts directory
source
there with the options options
(if any) and at service shutdown unmounts it.
(The auto
, noauto
, nofail
, and _netdev
options have no meaning to the actual mount process and are not passed through to the mount options used in the service bundle.)
The bundle is created as wanted-by/
the system local-fs.target
or the system remote-fs.target
, depending from the filesystem type fstype
and whether the options
contains _netdev
.
This so that it is started during autoboot when it is enabled.
The list of types that are considered to be "remote" is a superset of the old Debian list from mountall.sh
, with a few additions from the BSDs.
The _netdev
option overrides this list and forces a bundle to be unconditionally considered "remote".
If it detects a FUSE mount, it makes the bundle wants/
and after/
a bundle to load the FUSE kernel module.
Similarly, if the fstype
is efivarfs
, it makes the bundle wants/
and after/
a bundle to load that kernel module.
"API" filesystems (see system-control(1)) and the root filesystem are specially handled:
They are assumed already mounted by the time that service management starts, and are thus mounted with the "remount"/"update" flag.
The root is required to remain mounted beyond service management termination, and thus it is merely remounted/updated to read-write at start and to read-only at stop.
It creates a fsck@
bundle if one is wanted.
Any directory
fsck@
bundle that is created is ordered directory
before/
the respective mount@
bundle, and is directory
wanted-by/
it.
So when the bundle is enabled fsck(1) is run (on source
) before the volume is actually mounted.
It creates a gbde@
bundle if source
source
ends in .bde
, removing that suffix to generate the bundle.
Any gbde@
bundle that is created is ordered directory
before/
the respective fsck@
and directory
mount@
bundle, and is directory
wanted-by/
them.
So when the bundle is enabled gbde(1) is run (to attach
to source
) before the volume is actually checked and mounted.
source
.bde
It creates a geli@
bundle if source
source
ends in .eli
, removing that suffixe to generate the bundle.
Any geli@
bundle that is created is ordered directory
before/
the respective fsck@
and directory
mount@
bundle, and is directory
wanted-by/
them.
So when the bundle is enabled geli(1) is run (to attach
to source
) before the volume is actually checked and mounted.
source
.eli
The bundles generated by these subcommands are written in the current directory (or in the root
directory).
They are not enabled by the conversion process, but can be started and enabled as they stand, with the start and preset subcommands, just like any other service bundle.
With preset the --fstab option is appropriate of course.
(It is preset that handles the noauto
option.)
The assumption is that all service bundles are under one common root
and all target bundles under another; so service-to-service dependencies and orderings can be relative pathnames whilst service-to-target and target-to-service dependencies and orderings have to be absolute pathnames.
The --etc-bundle option changes this assumption, such that target bundles are now assumed to be reachable with relative pathnames from the converted service bundle; as is the case for special early bootstrap service bundles that live in /etc/service-bundles/services/
.
It also forces the bundle to be marked as an EarlySupervise
bundle whose supervise/
directory lives in a tmpfs.
system-control
{escape} [--alt-escape] [--prefix prefix
] {name
...}
The escape subcommand takes each name
and converts it using the escaping rules used in the convert-systemd-units subcommand.
Each escaped name
is written to standard output, separated from its predecessor (if any) by a space and prefixed with prefix
(which is not escaped).
The --alt-escape option causes the same selection of an alternative escaping algorithm as with the command line option of the same name for the convert-systemd-units subcommand.
system-control
{nagios-check-service} [--min-seconds seconds
] [--critical-if-below-min] {name
...}
This subcommand is intended for use as a Nagios plug-in.
It queries the status API in the bundle directory for service/target name
.
If the service is up for longer than seconds
seconds it returns a Nagios "OK" status.
If the service is up, but for less than seconds
seconds it returns a Nagios "WARNING" status and prints a line containing the service bundle directory name.
It does the same if the service is still in the process of being loaded by the service manager, or in the starting or stopping states.
The --critical-if-below-min command line option changes the status returned for such up services to "CRITICAL", but does not alter the treatment of starting or stopping services.
If the service is unexpectedly down or unloaded, if the status API reports the service running in the future (because of clock skew somewhere), or if the service is in the failing state, it returns a Nagios "CRITICAL" status and prints a line containing the service bundle directory name.
system-control
{load-kernel-module} {module
...}
system-control
{unload-kernel-module} {module
...}
These subcommands provide a minimal operating-system-neutral kernel module loading and unloading mechanism, for use in cross-platform service bundles. They devolve to the appropriate operating system commands, which are kldload(8) and kldunload(8) on BSD and modprobe(8) (without or with the --remove option) on Linux.
system-control
{cat} [names
...]
system-control takes each of the [names
...], searches for the corresponding service bundle directory, changes to the corresponding service directory, and runs grep(1) to dump the contents of the start
, stop
, run
, and restart
files.
system-control
{set-service-env} [--full] {name
} {var
} [value
]
system-control
{print-service-env} [--full] {name
} [var
]
If the name
service has an environment template subdirectory named env/
(in the format understood by envdir(1)), these subcommands can be used to manipulate that template.
set-service-env name
var
value
sets var
to value
in the template, the change not (of course) affecting any currently running service.
set-service-env name
var
specifies that the template unset var
, the change not (of course) affecting any currently running service.
print-service-env name
var
prints (only) the value of var
from the template.
print-service-env name
prints the whole template as list of var
=value
entries.
The --full command-line option switches to an alternative format for the environment template subdirectory, as understood by envdir(1) when its option of the same name is used.
system-control
{get-mount-what} [where
]
system-control
{get-mount-where} [what
]
These subcommands query the /etc/fstab
database.
They fill a gap left by the getent(1) command, which has no subcommand for reading the filesystem table.
Like that command, they query the on-disc administrative database of what is configured to be mounted; not the kernel's list of currently active mounts.
For a given mount-point where
get-mount-what prints the volume that is configured to be mounted upon it.
For a given volume what
get-mount-where prints the point where it is configured to be mounted.
Several standard targets are defined.
They conventionally live in the /etc/service-bundles/targets/
directory.
These standard targets are (indirectly) started by the init subcommand.
normal
This target is the normal target started by the init subcommand. This should bring up with it all of the services involved in the normal operation of the system, and an administrator-defined set of multiple login user interfaces that may include both TUI and GUI login prompts.
It "wants" the workstation
, server
, and multi-user
targets.
Thus starting it starts the union of all services wanted by those targets.
It is not ordered with respect to those targets.
So in the absence of orderings in between the individual services wanted by those targets, defined in their bundles, all wanted workstation, server, and multi-user services are brought up in parallel.
emergency
This target is the target started by the init subcommand with the -b option. Starting it is intended to bring up the system in "emergency mode", bringing up no services, mounting no (non-system) volumes, and bringing up just "emergency mode" services, such as a secure login on the default terminal.
It "wants" no other targets or services. So in "emergency mode" (if nothing else has been started) only the system filesystems are available, and not necessarily even read-write.
rescue
This target is the target started by the init subcommand with the -s option. Starting it is intended to bring up the system in "rescue mode", bringing up with it the fundamental system initialization services and a secure login user interface.
It "wants" the sysinit
target, but not the basic
target.
update
This target is the target started by the init subcommand with the --update option. Starting it is intended to bring up the system in "update mode", bringing up with it the fundamental system initialization services and the system update utility.
It "wants" the sysinit
target, but not the basic
target.
The poweroff, powercycle, halt, and reboot subcommands invoke several standard targets indirectly.
poweroff
, powercycle
, halt
, reboot
These four targets both "want" the shutdown
target and order themselves to start after it.
Thus starting them shuts down all services and then, once this has been done, starts these targets.
They are usually started by the System Manager, in response to system control commands requesting system reboot, halt, or power off.
When they (finally) start, they invoke the reboot, halt, powercycle, and poweroff subcommands of system-control with the {-f} command-line option.
This signals the System Manager to enact the actual reboot, halt, power-cycle, or power-off action.
For example: When system-manager(8) is process #1, system halt operates as follows:
The superuser runs system-control {halt}.
This sends SIGUSR1
(on BSD) or SIGRTMIN + 3
(on Linux) to the system manager process.
In response to that signal, the system manager runs system-control {activate} halt .
system-control does everything necessary for activating the halt
target, including stopping all other (conflicting) services and targets.
In the service control ordering starting the halt
target comes after processing every other service, because of the ordering between halt
and shutdown
and between shutdown
and everything else.
When the halt
target is finally started it runs system-control {halt} {-f}.
This sends SIGRTMIN + 13
to the system manager process.
In response to that signal, the system manager performs the finalization action of actually telling the operating system kernel to halt the system, after various standard system shutdown actions such as flushing the filesystem cache.
Other standard targets are started by telinit(1).
User-supplied services and targets that are auto-started at system bootstrap should list themselves in the wants/
and conflicts/
lists of subordinate targets (via the enable and disable subcommands).
These targets are usually not started explicitly.
workstation
All services that normally form part of bringing the system up as a "workstation" should be listed in this target's wants/
list.
Such services will include things such as the cron(1) dæmon.
This target "wants" the basic
target, so starting it (directly or indirectly) will bring the basic system up.
It is a collection that is used to group services, but is not an ordering milestone and has no before/
or after/
relationships.
server
All services that normally form part of bringing the system up as a "server" should be listed in this target's wants/
list.
Such services will include things such as HTTP/FTP/SMTP dæmons, and dæmons that provide services over the network.
This target "wants" the basic
target, so starting it (directly or indirectly) will bring the basic system up.
It is a collection that is used to group services, but is not an ordering milestone and has no before/
or after/
relationships.
multi-user
All services that normally form part of bringing up multi-user logins should be listed in this target's wants/
list.
Such services will include things such as the login services for terminals (real and virtual) and X.
This target "wants" the basic
target, so starting it (directly or indirectly) will bring the basic system up.
It is a collection that is used to group services, but is not an ordering milestone and has no before/
or after/
relationships.
shutdown
Starting this target is intended to shut down all running normal services.
All normal services should be in this target's conflicts/
list.
It is also an ordering milestone, in that all services listed in its conflicts/
list should also be listed in its after/
list.
shutdown
is then listed in the after/
list of the poweroff
, powercycle
, halt
, and reboot
target to ensure that they are only started after the system has entered "shutdown mode".
unmount
Starting this target is intended to unmount all filesystems, both local and remote.
All mount@*
services should be in this target's conflicts/
list.
unmount
is then listed in the after/
list of the poweroff
, powercycle
, halt
, and reboot
target to ensure that they are only started after the system has unmounted all filesystems.
Core services and targets are incorporated into a set of further subordinate targets.
basic
This target implies the "basic" system, excluding all workstation, server, and multi-user services.
It "wants" the sysinit
target.
It is a collection that is used to group services, but is not an ordering milestone and has no before/
or after/
relationships.
static-networking
This target implies the static setup/teardown of network interfaces and routing.
It "wants" all of the generated static_
services.
It is a collection that is used to group services, but is not an ordering milestone and has no protocol
@id
before/
or after/
relationships.
sysinit
All fundamental system initialization services and steps should be listed in this target's wants/
list.
Such services will include things such as the hostname
service that runs set-dynamic-hostname(1), the machine-id
service that runs setup-machine-id(1), the local-fs
target, and the remote-fs
target.
It is a collection that is used to group all such services, but is not an ordering milestone and has no before/
or after/
relationships.
local-fs
This "local filesystems" target is an ordering milestone and a collection, in that all services listed in its wants/
list should also be listed in its after/
list.
All system initialization services and steps for checking and mounting local filesystems, including remounting the root filesystem in read-write mode, should be in those lists.
One can thus list local-fs
in the after/
list of a service or target to ensure that it is only brought up after local filesystems have been mounted and checked.
Note that services encompassed by this target may not rely upon filesystems being checked and mounted, nor upon the root filesystem being mounted read-write.
To handle the latter, in particular, their supervise/
subdirectories should be symbolic links to a suitable subdirectory of /run/service-bundles/early-supervise
.
remote-fs
This "remote filesystems" target is an ordering milestone and a collection, in that all services listed in its wants/
list should also be listed in its after/
list.
All system initialization services and steps for checking and mounting remote filesystems should be in those lists.
One can thus list remote-fs
in the after/
list of a service or target to ensure that it is only brought up after remote filesystems have been mounted and checked.
local-fs-pre
This "local filesystems precursor" target is not a collection; its wants/
list should be empty.
It is solely an ordering milestone, that is brought in only if the services that want to order before it are themselves brought in.
It exists because system initialization services that need to occur before any filesystem checks or mounts, usually special services that initialize an interactive UI for fsck(1), do not have another way to hold the checks/mounts from commencing until they are done.
Such services should list this target in their before/
and wants/
lists.
Local filesystem checks, decryptions, and mounts should list this target (only) in their after/
lists, so that they order relative to it if the target is brought in but do not themselves bring it in.
fs-servers
This "filesystems servers" target is not a collection; its wants/
list should be empty.
It is solely an ordering milestone, that is brought in only if the services that want to order after it are themselves brought in.
It exists in order to ensure that remote filesystem mounts of volumes on the local machine work, by ordering them after the startup of any filesystem servers (e.g. SAMBA or NFS server dæmons).
Such server services should list this target (only) in their before/
and wants/
lists.
Remote filesystem mounts should list this target (only) in their after/
lists, so that they order relative to it if the target is brought in but do not themselves bring it in.
multi-user-pre
This "multi-user precursor" target is not a collection; its wants/
list should be empty.
It is solely an ordering milestone, that is brought in only if the multi-user
target is brought in.
It exists for services that need to start/execute before any multi-user login.
Such services should list this target (only) in their before/
lists.
Login services should list this target (only) in their after/
lists.
This is so that they order relative to it if the target is brought in but do not themselves bring it in.
name-services
This target is not a collection.
It is solely an ordering milestone, that is brought in only when the services that want to order before it are themselves brought in.
It exists because some name/address services lookup clients cannot be caused via the client-server communications mechanism itself to block indefinitely until the server is ready; and so have to have an explicit ordering to order them after any respective servers.
One lists name-services
in the after/
list of a service or target to ensure that it is only brought up after such name/address lookup services are available.
By not including it in their wants/
lists, however, they do not themselves being it in if there are no name/address lookup services that require hard ordering.
All services that are involved in providing local name/address lookup services should be listed in its after/
and its wants/
lists.
databases
This "database servers" target is not a collection; its wants/
list should be empty.
It is solely an ordering milestone, that is brought in only when the services that want to order after it are themselves brought in.
It exists because some database clients cannot be caused via the client-server communications mechanism itself to block indefinitely until the server is ready; and so have to have an explicit ordering to order them after any respective servers.
One lists databases
in the wants/
and after/
lists of a service or target.
The former ensures that they themselves bring it in if there are database services that require hard ordering.
The latter ensures that they are only brought up after such database services are available.
All services that are involved in providing database services should list it in their before/
lists.
swapauto
This target is a collection that is wanted by "sysinit"; it is not an ordering milestone.
All "auto" "swap" services should be listed in its wants/
lists.
swaplate
This target is a collection that is wanted by "sysinit"; it is not an ordering milestone.
All "late" "swap" services should be listed in its wants/
lists.
dumpauto
This target is a collection that is wanted by "sysinit"; it is not an ordering milestone.
All "dump" services should be listed in its wants/
lists.
finish-install
, finish-update
These targets "wants" the various services that finish a system install or a system upgrade. They are collections that are used to group services, but are not ordering milestones.
reboot-after-install
, reboot-after-update
These target wants/
the reboot
target.
They are ordering milestones, with all finish-install
/finish-update
services expected to order themselves before/
these targets.