INITCTL(8) Linux System Admininstrator's Manual INITCTL(8)
NAME
initctl - utility to control simpleinit(8)
SYNOPSIS
initctl [ -c | -d | -n | -p | -r ] [ -f ] [ -u ] service
need [ -f ] [ -r ] service
provide service
display-services
initctl service
initctl -c service
OVERVIEW
Simpleinit(8) offers a service and dependency management scheme to help
improve the robustness, scalability and readability of system boot
scripts. It is now possible to write(1,2) a modularised set(7,n,1 builtins) of boot scripts
without the complex and fragile numbered symlink scheme used by the
SysV boot concept. Simpleinit(8) uses combined start/stop scripts that
determine their function by the 1st argument passed to them. Combined
start/stop scripts from SysV installations can be reused almost
unchanged most of the time. Calling those scripts in(1,8) the proper order
is handled automatically. Scripts simply declare, using need(8), what
must run before them and the need -r function will stop them in(1,8) reverse
order.
Note: For the rest of this document, a script started with the argument
'start' will be referred to as a 'start script' and when started with
the argument 'stop' it will be referred to as a 'stop script', even
though both functions are combined in(1,8) a single script.
DESCRIPTION for need
When invoked as need or with the -n switch(1,n), initctl(8) tells sim-
pleinit(8) to start a service. Services come in(1,8) 2 flavours. Primary
services are executable programs, usually scripts, that init will call
with the argument 'start'. Secondary services are those linked to a
primary service with provide(8) (see below). If the requested service
is already available, need will return immediately without starting it
again.
If the requested service is not yet available (i.e. it was never
started or failed the last time(1,2,n)), need will look(1,8,3 Search::Dict) for a primary service
of the specified name. If a full pathname is not specified, it will
look(1,8,3 Search::Dict) in(1,8) the directories specified via INIT_PATH in(1,8) /etc/inittab (see
simpleinit(8)) and run it with the 'start' argument. It will return
when the respective program has terminated. It is also possible that
the requested service is not yet available but is currently being
started (one or more parallel processes may be trying to provide it).
In that case need(8) will wait until the service is either available or
all programs trying to provide the service have failed.
The service to start may also be the name of a directory instead of a
script. In this case, the fileprefix/bootprog program as specified in(1,8)
inittab(5) will be executed with a 1st argument 'start-dir' and the
full path to the directory as 2nd argument. The boot program is
expected to behave as if(3,n) it was a start script in(1,8) this case, which
means it must exit(3,n,1 builtins) with a proper exit(3,n,1 builtins) code as described in(1,8) the BOOT
SCRIPT GUIDELINES further below.
DESCRIPTION for need -r
The -r option is used to tell simpleinit(8) to "roll back" (stop) ser-
vices up to (but not including) service by running the respective
scripts with the 'stop' parameter. If a service refers to a directory,
rather than an actual script (see DESCRIPTION for need above) filepre-
fix/bootprog will be called with 'stop-dir' as 1st argument and the
full path to the directory as 2nd argument. The boot program must
behave like a stop script in(1,8) this case, which means it must exit(3,n,1 builtins) with a
proper exit(3,n,1 builtins) code as described in(1,8) the BOOT SCRIPT GUIDELINES further
below.
If service is not specified, all services are stopped. The -r option
thus allows the system to be partially or wholly shut down in(1,8) an
orderly fashion. The shutdown(2,8)(8) program automatically calls initctl -r
-f as part of its operation.
If a rollback is already in(1,8) progress when another one is requested
(e.g. if(3,n) a stop script uses need -r), the new request will be ignored
if(3,n) it requests rolling back fewer services. If it requests rolling back
more services, the rollback will be extended. It is not possible to
activate or deactivate the -f switch(1,n) (see below) setting of a rollback
in(1,8) progress.
The -f option forces the rollback to succeed. All stop scripts will be
assumed to successfully terminate regardless of their exit(3,n,1 builtins) codes. A
watchdog(5,8) will also be set(7,n,1 builtins) for every stop script that will kill(1,2,1 builtins) (SIGTERM
followed by SIGKILL) the stop script if(3,n) it does not terminate within 5
minutes after being started. This option is intended only for use by
shutdown(2,8)(8) to ensure that the system will never hang indefinitely dur-
ing shut down even if(3,n) services are messed up badly.
DESCRIPTION for provide
When invoked as provide, initctl(8) tells simpleinit(8) that the parent
(calling) process will be providing service. If the calling process
exits successfully (status 0) the service is deemed to be available.
Only one instance of service may be started, so alternate providers
will block and may fail.
Using provide it is possible to have multiple potential providers for
the same (generic) service (e.g. sendmail(1,8) and qmail both provide a mta
service), where only one actually provides the service. This may be
used by service startup scripts which check for configuration files.
DESCRIPTION for display-services
When invoked as display-services or with the -d switch(1,n), initctl(8) will
write(1,2) the list of currently available services, primary services just
being started and the list of failed services to the standard output.
When invoked as initctl without a switch(1,n) it will test for the status of
service (see EXIT CODE below)
DESCRIPTION for initctl -c
initctl -c service will clear(1,3x,3x clrtobot) service from simpleinit(8)'s service
accounting lists without actually stopping the service. It affects the
services that are available as well as those that have failed. It does
not affect services currently being started. If a primary service is
cleared then all secondary services linked to it will be removed, too.
This function should be used with care. Once a service has been removed
from simpleinit(8)'s lists, it is treated as if(3,n) it had never been run.
Only use this function if(3,n) you know what you're doing!
USER SPACE EXECUTION
The -u switch(1,n) tells initctl(8) that it is to communicate with a sim-
pleinit(8) run in(1,8) user space instead of the main system init. If the
user invoking initctl(8) does not have permission to write(1,2) to
/dev/initctl or the environment variable USERSPACE_INIT exists, user
space mode will be set(7,n,1 builtins) automatically. The -u switch(1,n) is only necessary
if(3,n) a privileged user wants to communicate with a user space sim-
pleinit(8). Note that in(1,8) this case, indirect calls to initctl(8) made
in(1,8) scripts started via need -u will inherit the -u switch. For user
space communication initctl(8) will use the $INIT_ROOT/dev/initctl FIFO
rather than /dev/initctl. If the INIT_ROOT environment variable is not
set(7,n,1 builtins), it will default to the current working directory.
Even if(3,n) the INIT_ROOT environment variable is set(7,n,1 builtins) correctly and the -u
switch(1,n) is supplied, communication may not be possible. If the user who
started the user space init does not have permission to send(2,n) signals to
the user running initctl(8), or the other way around, initctl(8) will
wait forever for an answer and has to be terminated manually. The same
problem occurs if(3,n) one of the 2 does not have write(1,2) permission to files
created by the other one. This means that even with the -u switch(1,n), a
user can usually only communicate with a user space init launched by
himself.
EXIT CODE
The exit(3,n,1 builtins) code from need is 0 if(3,n) the service was successfully started, 1
if(3,n) the service failed badly, and 2 if(3,n) the service is unavailable (i.e.
disabled in(1,8) configuration files). These exit(3,n,1 builtins) codes reflect the exit(3,n,1 builtins)
codes from the service startup scripts (see BOOT SCRIPT GUIDELINES
below). Exit code 3 will be returned if(3,n) a rollback is currently in(1,8)
progress, unless the service is available. If a script calls need for
itself, 0 will be returned.
The exit(3,n,1 builtins) code from need -r is 0 if(3,n) the requested services were success-
fully stopped, 1 if(3,n) they could not (all) be stopped, and 2 if(3,n) the ser-
vice to roll back to was not available to start with. Note that if(3,n) no
service is specified (i.e rolling back everything) and no services are
available, the exit(3,n,1 builtins) code will be 0, not 2. Exit code 3 will be
returned if(3,n) a rollback is already in(1,8) progress.
The exit(3,n,1 builtins) code from provide is 0 if(3,n) the service may be provided, 1 if(3,n) it
may not. Exit code 2 will be returned if(3,n) the process calling provide is
not a child of init (i.e. not started at boot-up or via a manual
need(8)) or an error(8,n) has occurred during the call. Exit code 3 will be
returned if(3,n) a roll back is currently in(1,8) progress. provide may block
waiting till another provider trying to initialise the service has fin-
ished.
The exit(3,n,1 builtins) code from initctl -c is 0 if(3,n) the service was removed from the
list of available services, 1 if(3,n) the service was removed from the list
of unavailable services, and 2 if(3,n) the service was not found in(1,8) either
of these lists.
The exit(3,n,1 builtins) code from initctl (without switches) is 0 if(3,n) the service is
available, 1 if(3,n) the service failed badly, and 2 if(3,n) the service is
unavailable. These exit(3,n,1 builtins) codes are the same as would be returned by need
service. Exit code 3 will be returned if(3,n) information about the ser-
vice's status is not available. This is the case if(3,n) it is currently
starting (i.e. the start script has not terminated, yet), has never
been run at all, or if(3,n) the service has been stopped or cleared. Note
that during a rollback in(1,8) progress a service's status will remain
available until the service's stop script has actually terminated. So
if(3,n) a service's stop script tests the status of its own service, 0 will
be returned if(3,n) the service was started successfully (the usual case
unless the stop script was executed manually by the user without using
need first).
The exit(3,n,1 builtins) code for display-services is 0 unless communication with init
fails for some reason.
BOOT SCRIPT GUIDELINES
The scripts used with simpleinit(8)/initctl(8) have to follow certain
rules to ensure proper service management. The requirements are as fol-
lows:
Every script must understand 'start' and 'stop' passed to it as the 1st
argument. If the argument is not applicable (e.g. for a service that
doesn't require stopping) it must be handled gracefully.
Start scripts may only return the exit(3,n,1 builtins) codes 0, 1 and 2. Their mean-
ings are as follows:
0 The service was successfully started and is now available.
1 An error(8,n) has occurred when starting the service. The service is
not made available.
2 The service may be able to start successfully but is not config-
ured to be started (e.g. disabled in(1,8) a config(1,5) file(1,n)). The ser-
vice is not made available.
The use of exit(3,n,1 builtins) code 2 is optional. Exit code 1 may be used instead. It
is important to note that in(1,8) both cases the service is not made avail-
able. Exit code 2 does not mean that the script may or may not have
provided the service. Every service must either be started successfully
or not started all. Scripts that return a non-zero exit(3,n,1 builtins) code must be
prepared to be called again. need(8) only ensures that services that
have started successfully will not be started again.
Stop scripts may only return the exit(3,n,1 builtins) codes 0 and 1. Their meanings
are as follows:
0 The service was stopped successfully (or did not need to be
stopped) and is not available anymore.
1 An error(8,n) has occurred stopping the service. The service is still
available.
If one of the stop scripts returns a non-zero exit(3,n,1 builtins) code, rolling back
will be stopped and the service whose stop script failed will be con-
sidered still available. Make sure that your stop scripts do not
return a non-zero exit(3,n,1 builtins) code if(3,n) the service is no longer available!
A script providing a secondary service must check the exit(3,n,1 builtins) code from
provide to see if(3,n) it is allowed to provide the service, before attempt-
ing to do so. If the service may not be provided, it is recommended
that the script terminate with exit(3,n,1 builtins) code 2 (see start script exit(3,n,1 builtins) codes
above). However, a script may try to provide several services. If it
returns with exit(3,n,1 builtins) code 0, the script's primary service will be deemed
available, as will any secondary services for which the provide call
returned 0.
When a script provides multiple services, it is recommended (but not
required) that it lists them in(1,8) alphabetical order to prevent deadlocks
when parallel execution is used (see DEADLOCKS below).
DEADLOCKS
It is possible to create a variety of deadlock situations with need and
provide, especially when executing several start scripts in(1,8) parallel.
Simpleinit(8) detects deadlocks and breaks them by having some needs
and/or provides return an error(8,n) condition. The only exception is when
a script uses need on itself. In this case of a minimal deadlock, need
will be successful. This helps when you merge(1,8) several scripts into one
and want to preserve the dependency statement.
Note that deadlock detection only works for scripts that call
initctl(8) directly, i.e. not via a subshell. So if(3,n) you create a script
need-service for instance, and only call need via this script, deadlock
detection is impossible. You should implement need-service as a shell
function instead, to prevent that it is executed in(1,8) a subshell.
Whenever a deadlock is detected, simpleinit(8) will write(1,2) the names of
the conflicting scripts to the console. In most cases the culprit is a
circular dependency like "a provides b, a needs c, c needs b". This is
a bug in(1,8) your boot scripts. In the above case it would be required to
make sure that an alternate provider of service b is started before
service a.
One deadlock case deserves special discussion. This is a case like the
following:
script 1:
provide a
sleep(1,3) 10
provide b
script 2:
provide b
sleep(1,3) 10
provide a
When executing these scripts in(1,8) parallel, a race condition exists that
can end in(1,8) a deadlock (script 1 gets(3,n) permission to provide a and script
2 gets(3,n) permission to provide b, both block on the 2nd provide while
waiting for the other script to finish). Again this is a bug in(1,8) your
boot scripts which simpleinit(8) will detect and output. However, this
one is different in(1,8) that the race condition is easy to avoid without
changing the meaning of the scripts. All you have to do is to make sure
that whenever a script provides multiple services, it does so in(1,8) alpha-
betical order. In the above case script 2 would have to be changed to
begin with "provide a" rather than "provide b".
In general it is best to avoid parallel execution of start scripts.
Unlike util-linux's version(1,3,5), simpleinit-msb does not have built-in sup-
port for parallel execution anymore but using your shell's background-
ing abilities, you could still cause parallel execution of scripts.
SIGNALS
initctl(8) uses SIGUSR1, SIGUSR2, SIGURG and SIGPOLL for communication
with simpleinit(8). Don't send(2,n) these signals to it (why would you want
to, anyway?).
BUGS
initctl(8) currently treats service and /full/path/service as 2 dis-
tinct services, even if(3,n) service resolves (via INIT_PATH) to the same
script. Different pathnames that refer to the same script are also
taken as distinct. If you are not careful this can lead to scripts
being executed multiple times even if(3,n) they're not supposed to be.
Assuming that the service fsck is in(1,8) filesys/ and filesys/ is in(1,8)
INIT_PATH, a possible error(8,n) would be
need fsck || exit(3,n,1 builtins) 1
for service in(1,8) filesys/*; do need $service; done
To work around this problem you should never use absolute paths with
initctl(8). Avoiding absolute paths also makes it easier to move(3x,7,3x curs_move) your
boot scripts to a different location. In any case you should not rely
on the above behaviour as it might change in(1,8) future versions.
When need svc is issued while a script scp attempting to provide svc as
a secondary service still hasn't finished, the primary service svc will
never be attempted, even if(3,n) the script scp fails. This means that if(3,n)
parallel execution is used and you have a service svc that exists both
as primary and secondary service, then you always have a race-condi-
tion. As a workaround you should use different names for primary and
secondary services.
When running boot scripts in(1,8) sequence (the only way directly supported
by this version(1,3,5) of simpleinit), a need svc while a provide svc is still
pending is an error(8,n) in(1,8) the boot script setup(2,8) (circular dependency, see
DEADLOCKS above) so the above issue does not apply to (correct) sequen-
tial setups.
need(8) will start a service even if(3,n) the name ends in(1,8) "~". This is not
a bug but it is something to keep in(1,8) mind when using loops like
cd dir
for service in(1,8) *; do need $service; done
This loop will also execute backup files that end in(1,8) "~".
FILES
/dev/initctl This is the control FIFO, created by simpleinit(8),
which initctl(8) writes commands to.
$INIT_ROOT/dev/init.pid
This file(1,n) is used to determine the pid of init when
run in(1,8) user space. See simpleinit(8) for details.
/etc/inittab Settings in(1,8) this file(1,n) control the behaviour of some
aspects of initctl(8). See simpleinit(8) and init-
tab(5) for details.
AUTHOR
Richard Gooch (rgooch@atnf.csiro.au)
This version(1,3,5) was modified by Matthias Benkmann <m.s.b@gmx.net>. Contact
me if(3,n) you have any problems with this version.
SEE ALSO
simpleinit(8), init(8), shutdown(2,8)(8), inittab(5)
8 Sep 2001 INITCTL(8)