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 a modularised set 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 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 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 a single script.

DESCRIPTION for need
When invoked as need or with the -n switch, initctl(8) tells simpleinit(8) to start a service. Services come in 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), need will look for a primary service of the specified name. If a full pathname is not specified, it will look in the directories specified via INIT_PATH in /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 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 it was a start script in this case, which means it must exit with a proper exit code as described in the BOOT SCRIPT GUIDELINES further below.

DESCRIPTION for need -r
The -r option is used to tell simpleinit(8) to "roll back" (stop) services 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) fileprefix/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 this case, which means it must exit with a proper exit code as described in 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 an orderly fashion. The shutdown(8) program automatically calls initctl -r -f as part of its operation. If a rollback is already in progress when another one is requested (e.g. if a stop script uses need -r), the new request will be ignored if 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 (see below) setting of a rollback in progress. The -f option forces the rollback to succeed. All stop scripts will be assumed to successfully terminate regardless of their exit codes. A watchdog will also be set for every stop script that will kill (SIGTERM followed by SIGKILL) the stop script if it does not terminate within 5 minutes after being started. This option is intended only for use by shutdown(8) to ensure that the system will never hang indefinitely during shut down even if 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 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, initctl(8) will write 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 it will test for the status of service (see EXIT CODE below)

DESCRIPTION for initctl -c
initctl -c service will clear 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 it had never been run. Only use this function if you know what you're doing!

USER SPACE EXECUTION
The -u switch tells initctl(8) that it is to communicate with a simpleinit(8) run in user space instead of the main system init. If the user invoking initctl(8) does not have permission to write to /dev/initctl or the environment variable USERSPACE_INIT exists, user space mode will be set automatically. The -u switch is only necessary if a privileged user wants to communicate with a user space simpleinit(8). Note that in this case, indirect calls to initctl(8) made in 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, it will default to the current working directory. Even if the INIT_ROOT environment variable is set correctly and the -u switch is supplied, communication may not be possible. If the user who started the user space init does not have permission to send 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 one of the 2 does not have write permission to files created by the other one. This means that even with the -u switch, a user can usually only communicate with a user space init launched by himself.

EXIT CODE
The exit code from need is 0 if the service was successfully started, 1 if the service failed badly, and 2 if the service is unavailable (i.e. disabled in configuration files). These exit codes reflect the exit codes from the service startup scripts (see BOOT SCRIPT GUIDELINES below). Exit code 3 will be returned if a rollback is currently in progress, unless the service is available. If a script calls need for itself, 0 will be returned. The exit code from need -r is 0 if the requested services were successfully stopped, 1 if they could not (all) be stopped, and 2 if the service to roll back to was not available to start with. Note that if no service is specified (i.e rolling back everything) and no services are available, the exit code will be 0, not 2. Exit code 3 will be returned if a rollback is already in progress. The exit code from provide is 0 if the service may be provided, 1 if it may not. Exit code 2 will be returned if 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 has occurred during the call. Exit code 3 will be returned if a roll back is currently in progress. provide may block waiting till another provider trying to initialise the service has finished. The exit code from initctl -c is 0 if the service was removed from the list of available services, 1 if the service was removed from the list of unavailable services, and 2 if the service was not found in either of these lists. The exit code from initctl (without switches) is 0 if the service is available, 1 if the service failed badly, and 2 if the service is unavailable. These exit codes are the same as would be returned by need service. Exit code 3 will be returned if information about the service's status is not available. This is the case if it is currently starting (i.e. the start script has not terminated, yet), has never been run at all, or if the service has been stopped or cleared. Note that during a rollback in progress a service's status will remain available until the service's stop script has actually terminated. So if a service's stop script tests the status of its own service, 0 will be returned if the service was started successfully (the usual case unless the stop script was executed manually by the user without using need first). The exit 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 follows: 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 codes 0, 1 and 2. Their meanings are as follows:

0   The service was successfully started and is now available.

1   An error has occurred when starting the service. The service is not made available.

2   The service may be able to start successfully but is not configured to be started (e.g. disabled in a config file). The service is not made available.

The use of exit code 2 is optional. Exit code 1 may be used instead. It is important to note that in both cases the service is not made available. 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 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 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 has occurred stopping the service. The service is still available.

If one of the stop scripts returns a non-zero exit code, rolling back will be stopped and the service whose stop script failed will be considered still available. Make sure that your stop scripts do not return a non-zero exit code if the service is no longer available! A script providing a secondary service must check the exit code from provide to see if it is allowed to provide the service, before attempting to do so. If the service may not be provided, it is recommended that the script terminate with exit code 2 (see start script exit codes above). However, a script may try to provide several services. If it returns with exit 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 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 parallel. Simpleinit(8) detects deadlocks and breaks them by having some needs and/or provides return an error 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 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 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 a subshell. Whenever a deadlock is detected, simpleinit(8) will write 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 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 10
    provide b
script 2:
    provide b
    sleep 10
    provide a
When executing these scripts in parallel, a race condition exists that can end in a deadlock (script 1 gets permission to provide a and script 2 gets permission to provide b, both block on the 2nd provide while waiting for the other script to finish). Again this is a bug in your boot scripts which simpleinit(8) will detect and output. However, this one is different in 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 alphabetical 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, simpleinit-msb does not have built-in support for parallel execution anymore but using your shell's backgrounding 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 these signals to it (why would you want to, anyway?).

BUGS
initctl(8) currently treats service and /full/path/service as 2 distinct services, even if 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 they're not supposed to be. Assuming that the service fsck is in filesys/ and filesys/ is in INIT_PATH, a possible error would be
    need fsck || exit 1
    for service in 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 your boot scripts to a different location. In any case you should not rely on the above behaviour as it might change in 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 the script scp fails. This means that if parallel execution is used and you have a service svc that exists both as primary and secondary service, then you always have a race-condition. As a workaround you should use different names for primary and secondary services.
When running boot scripts in sequence (the only way directly supported by this version of simpleinit), a need svc while a provide svc is still pending is an error in the boot script setup (circular dependency, see DEADLOCKS above) so the above issue does not apply to (correct) sequential setups. need(8) will start a service even if the name ends in "~". This is not a bug but it is something to keep in mind when using loops like
    cd dir
    for service in *; do need $service; done
This loop will also execute backup files that end in "~".

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 is used to determine the pid of init when run in user space. See simpleinit(8) for details.
/etc/inittab
    Settings in this file control the behaviour of some aspects of initctl(8). See simpleinit(8) and inittab(5) for details.

AUTHOR
Richard Gooch (rgooch@atnf.csiro.au) This version was modified by Matthias Benkmann <m.s.b@gmx.net>. Contact me if you have any problems with this version.

SEE ALSO
simpleinit(8), init(8), shutdown(8), inittab(5)