     [file version.texi not included]

Copyright © 2002, 2003 Wolfgang Jährling

Copyright © 2013, 2016 Ludovic Courtès

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A copy of the license is included in the section entitled ``GNU Free Documentation License''.

The GNU Shepherd Manual
***********************

This manual documents the GNU Shepherd version VERSION, a service manager for the GNU system.

Introduction
************

This manual documents the GNU Daemon Shepherd, or GNU Shepherd for short.  The Shepherd looks after system services, typically daemons. It is used to start and stop them in a reliable fashion.  For instance it will dynamically determine and start any other services that our desired service depends upon.  As another example, the Shepherd might detect conflicts among services.  In this situation it would simply prevent the conflicting services from running concurrently.

The Shepherd is the init system of the GNU operating system---it is the first user process that gets started, typically with PID 1, and runs as root.  Normally the purpose of init systems is to manage all system-wide services, but the Shepherd can also be a useful tool assisting unprivileged users in the management of their own daemons.

Flexible software requires some time to master and the Shepherd is no different.  But don't worry: this manual should allow you to get started quickly.  Its first chapter is designed as a practical introduction to the Shepherd and should be all you need for everyday use (see Jump Start).  In chapter two we will describe the herd and shepherd programs, and their relationship, in more detail (herd and shepherd).  Subsequent chapters provide a full reference manual and plenty of examples, covering all of Shepherd's capabilities.  Finally, the last chapter provides information for those souls brave enough to hack the Shepherd itself.

The Shepherd was formerly known as ``dmd'', which stands for Daemon Managing Daemons (or Daemons-Managing Daemon?).

This program is written in Guile, an implementation of the Scheme programming language, using the GOOPS extension for object-orientation.  Guile is also the Shepherd's configuration language. See Introduction (GNU Guile Reference Manual), for an introduction to Guile.  We have tried to make the Shepherd's basic features as accessible as possible---you should be able to use these even if you do not know how to program in Scheme.  A basic grasp of Guile and GOOPS is required only if you wish to make use of the Shepherd's more advanced features.

Jump Start
**********

This chapter gives a short overview of the Shepherd.  It is enough if you just need the basic features of it.  As it is not assumed that readers are familiar with all the involved issues, a very experienced user might be annoyed by the often very detailed descriptions in this introduction.  Those users are encouraged to just skip to the reference section.

Note that all the full file names in the following text are based on the assumption that you have installed the Shepherd with an empty prefix.  If your the Shepherd installation for example resides in /usr/local instead, add this directory name in front of the absolute file names mentioned below.

When shepherd gets started, it reads and evaluates a configuration file.  When it is started with superuser priviledges, it tries to use /etc/shepherd.scm.  When started as normal user, it looks for a file called $XDG_CONFIG_HOME/shepherd/init.scm.  If the XDG_CONFIG_HOME environment variable is not defined, $HOME/.config/shepherd/init.scm is used instead.  With the option --config (or, for short, -c), you can specify where to look instead.  So if you want to start shepherd with an alternative file, use one of the following commands:

     shepherd --config=/etc/shepherd.scm.old
     shepherd -c /etc/shepherd.scm.old

As the final ``d'' suggests, shepherd is just a daemon that (usually) runs in the background, so you will not interact with it directly.  After it is started, shepherd will listen on a socket special file, usually /var/run/shepherd/socket, for further commands.  You use the tool herd to send these commands to shepherd.  Usage of herd is simple and straightforward: To start a service called apache, you use:

     herd start apache

When you do this, all its dependencies will get resolved.  For example, a webserver is quite likely to depend on working networking, thus it will depend on a service called networking.  So if you want to start apache, and networking is not yet running, it will automatically be started as well.  The current status of all the services defined in the configuration file can be queried like this:

     herd status

Or, to get additional details about each service, run:

     herd detailed-status

In this example, this would show the networking and apache services as started.  If you just want to know the status of the apache service, run:

     herd status apache

You can stop a service and all the services that depend on it will be stopped. Using the example above, if you stop networking, the service apache will be stopped as well---which makes perfect sense, as it cannot work without the network being up.  To actually stop a service, you use the following, probably not very surprising, command:

     herd stop networking

There are two more actions you can perform on every service: The actions enable and disable are used to prevent and allow starting of the particular service.  If a service is intended to be restarted whenever it terminates (how this can be done will not be covered in this introduction), but it is respawning too often in a short period of time (by default 5 times in 5 seconds), it will automatically be disabled.  After you have fixed the problem that caused it from being respawned too fast, you can start it again with the commands:

     herd enable foo
     herd start foo

But there is far more you can do than just that.  Services can not only simply depend on other services, they can also depend on virtual services.  A virtual service is a service that is provided by one or more service additionally.  For instance, a service called exim might provide the virtual service mailer-daemon.  That could as well be provided by a service called smail, as both are mailer-daemons.  If a service needs any mailer-daemon, no matter which one, it can just depend on mailer-daemon, and one of those who provide it gets started (if none is running yet) when resolving dependencies.  The nice thing is that, if trying to start one of them fails, shepherd will go on and try to start the next one, so you can also use virtual services for specifying fallbacks.

Additionally to all that, you can perform service-specific actions. Coming back to our original example, apache is able to reload its modules, therefore the action reload-modules might be available:

     herd reload-modules apache

The service-specific actions can only be used when the service is started, i.e. the only thing you can do to a stopped service is starting it.  An exception exists, see below.  (If you may at some point find this too restrictive because you want to use variants of the same service which are started in different ways, consider using different services for those variants instead, which all provide the same virtual service and thus conflict with each other, if this is desired.  That's one of the reasons why virtual services exist, after all.)

There are two actions which are special, because even if services can implement them on their own, a default implementation is provided by shepherd (another reason why they are special is that the default implementations can be called even when the service is not running; this inconsistency is just to make it more intuitive to get information about the status of a service, see below).

These actions are restart and status.  The default implementation of restart calls stop and start on the affected service in order, the status action displays some general information about the service, like what it provides, what it depends on and with which other services it conflicts (because they provide a virtual service that is also provided by that particular service).

Another special action is list-actions, which displays a list of the additional actions a service provides; obviously, it can also be called when the service is not running.  Services cannot provide their own implementation of list-actions.

A special service is root, which is used for controlling the Shepherd itself.  You can also reference to this service as shepherd.  It implements various actions.  For example, the status action displays which services are started and which ones are stopped, whereas detailed-status has the effect of applying the default implementation of status to all services one after another.  The load action is unusual insofar as it shows a feature that is actually available to all services, but which we have not seen yet: It takes an additional argument.  You can use load to load arbitrary code into the Shepherd at runtime, like this:

     herd load shepherd ~/additional-services.scm

This is enough now about the herd and shepherd programs, we will now take a look at how to configure the Shepherd.  In the configuration file, we need mainly the definition of services.  We can also do various other things there, like starting a few services already.

FIXME: Finish.  For now, look at the examples/ subdirectory.

     ...

Ok, to summarize:

  * shepherd is a daemon, herd the program that controls it.

  * You can start, stop, restart, enable and disable every service, as well as display its status.

  * You can perform additional service-specific actions, which you can also list.

  * Actions can have arguments.

  * You can display the status of a service, even if the service does not provide a specific implementation for this action.  The same is true for restarting.

  * The root/shepherd service is used to control shepherd itself.

herd and shepherd
*****************

The daemon that runs in the background and is responsible for controlling the services is shepherd, while the user interface tool is called herd: it's the command that allows you to actually herd your daemons (In the past, when the GNU Shepherd was known as GNU dmd, the herd command was called deco, for DaEmon COntroller.).  To perform an action, like stopping a service or calling an action of a service, you use the herd program.  It will communicate with shepherd over a Unix Domain Socket.

Thus, you start shepherd once, and then always use herd whenever you want to do something service-related.  Since herd passes its current working directory to shepherd, you can pass relative file names without trouble.  Both shepherd and herd understand the standard arguments --help, --version and --usage.

Invoking shepherd
=================

The shepherd program has the following synopsis:

     shepherd [OPTION...]

It accepts the following options:

-c FILE
--config=FILE
     Read and evaluate FILE as the configuration script on startup.

     FILE is evaluated in the context of a fresh module where bindings from the (shepherd service) module and Guile's (oop goops) are available, in addition to the default set of Guile bindings.  In particular, this means that code in FILE may use register-services, the <service> class, and related tools (see Services).

-I
--insecure
     Do not check if the directory where the socket---our communication rendez-vous with herd---is located has permissions 700. If this option is not specified, shepherd will abort if the permissions are not as expected.

-l [FILE]
--logfile[=FILE]
     Log output into FILE, or if FILE is not given, /var/log/shepherd.log when running as superuser, $XDG_CONFIG_HOME/shepherd/shepherd.log otherwise.

--pid[=FILE]
     When shepherd is ready to accept connections, write its PID to FILE or to the standard output if FILE is omitted.

-p [FILE]
--persistency[=FILE]

-s FILE
--socket=FILE
     Receive further commands on the socket special file FILE.  If this option is not specified, LOCALSTATEDIR/run/shepherd/socket is taken.

     If - is specified as file name, commands will be read from standard input, one per line, as would be passed on a herd command line (see Invoking herd).

--quiet
     Synonym for --silent.

Invoking herd
=============

The herd command is a generic client program to control a running instance of shepherd (see Invoking shepherd).  It has the following synopsis:

     herd [OPTION...] ACTION [SERVICE [ARG...]]

It causes the ACTION of the SERVICE to be invoked.  When SERVICE is omitted and ACTION is status or detailed-status, the root service is used (This shorthand does not work for other actions such as stop, because inadvertently typing herd stop would stop all the services, which could be pretty annoying.) (see The root and unknown services, for more information on the root service.)

For each action, you should pass the appropriate ARGs.  Actions that are available for every service are start, stop, restart, status, enable, disable, and doc.

If you pass a file name as an ARG, it will be passed as-is to the Shepherd, thus if it is not an absolute name, it is local to the current working directory of shepherd, not to herd.

The herd command understands the following option:

-s FILE
--socket=FILE
     Send commands to the socket special file FILE. If this option is not specified, LOCALSTATEDIR/run/shepherd/socket is taken.

The herd command returns zero on success, and a non-zero exit code on failure.  In particular, it returns a non-zero exit code when ACTION or SERVICE does not exist and when the given action failed.

Invoking reboot
===============

The reboot command is a convenience client program to instruct the Shepherd (when used as an init system) to stop all running services and reboot the system.  It has the following synopsis:

     reboot [OPTION...]

It is equivalent to running herd stop shepherd.  The reboot command understands the following option:

-s FILE
--socket=FILE
     Send commands to the socket special file FILE. If this option is not specified, LOCALSTATEDIR/run/shepherd/socket is taken.

Invoking halt
=============

The halt command is a convenience client program to instruct the Shepherd (when used as an init system) to stop all running services and turn off the system.  It has the following synopsis:

     halt [OPTION...]

It is equivalent to running herd power-off shepherd.  As usual, the halt command understands the following option:

-s FILE
--socket=FILE
     Send commands to the socket special file FILE. If this option is not specified, LOCALSTATEDIR/run/shepherd/socket is taken.

Services
********

The service is obviously a very important concept of the Shepherd.  On the Guile level, a service is represented as an instance of <service>, a GOOPS class (see GOOPS (GNU Guile Reference Manual)).  When creating an instance of it, you can specify the initial values of its slots, and you actually must do this for some of the slots.

The <service> class and its associated procedures and methods are defined in the (shepherd service) module.

Slots of services
=================

A service has the following slots, all of which can be initialized with a keyword (i.e. #:provides, used when creating the object) of the same name, except where stated otherwise.  You should not access them directly with slot-ref or slot-set! usually, use the methods of the service class Methods of services instead.

  * provides is a list of symbols that are provided by the service. A symbol can only be provided by one service running at a time, i.e. if two services provide the same symbol, only one of them can run, starting the other one will fail.  Therefore, these symbols are mainly used to denote conflicting services.  The first symbol in the list is the canonical name for the service, thus it must be unique. This slot has no default value and must therefore be initialized.

  * requires is, like provides, a list of symbols that specify services.  In this case, they name what this service depends on, i.e. before the service can be started, services that provide those symbols must be started.  If a required symbol is provided by several services, one will be started.  By default, this slot contains the empty list.

  * running is a hook that can be used by each service in its own way.  The default value is #f, which indicates that the service is not running. When an attempt is made to start the service, it will be set to the return value of the procedure in the start slot. It will also be passed as an argument to the procedure in the stop slot.  This slot can not be initialized with a keyword.

  * respawn? specifies whether the service should be respawned by the Shepherd.  If this slot has the value #t, then assume the running slot specifies a child process PID and restart the service if that process terminates.  Otherwise this slot is #f, which is the default.  See also the last-respawns slot.

  * start contains the ``constructor'' for the service, which will be called to start the service.  (Therefore, it is not a constructor in the sense that it initializes the slots of a <service> object.)  This must be a procedure that accepts any amount of arguments, which will be the additional arguments supplied by the user.  If the starting attempt failed, it must return #f.  The value will be stored in the running slot.  The default value is a procedure that returns #t and performs no further actions, therefore it is desirable to specify a different one usually.

  * stop is, similar to start, a slot containing a procedure.  But in this case, it gets the current value of the running slot as first argument and the user-supplied arguments as further arguments; it gets called to stop the service.  Its return value will again be stored in the running slot, so that it should return #f if it is now possible again to start the service at a later point.  The default value is a procedure that returns #f and performs no further actions.

  * actions specifies the additional actions that can be performed on a service when it is running.  A typical example for this is the restart action.  The macro make-actions Service Convenience is provided to abstract the actual data representation format for this slot.  (It actually is a hash currently.)

  * enabled? cannot be initialized with a keyword, and contains #t by default.  When the value becomes #f at some point, this will prevent the service from getting started.  A service can be enabled and disabled with the methods enable and disable, respectively Methods of services.

  * last-respawns cannot be initialized with a keyword and is only ever used when the respawn? slot contains #t; it is a circular list with (car respawn-limit) elements, where each element contains the time when it was restarted, initially all 0, later a time in seconds since the Epoch.  The first element is the one that contains the oldest one, the last one the newest.

  * stop-delay? being false causes the stop slot to be unused; instead, stopping the service will just cause the waiting-for-termination? slot be set to #t.

  * waiting-for-termination? cannot be initialized with a keyword and should not be used by others, it is only used internally for respawnable services when the stop-delay? slot contains a true value.  waiting-for-termination? contains #t if the service is still running, but the user requested that it be stopped, in which case if the service terminates the next time, the respawn handler will not start it again.

     otherwise #f.

Methods of services
===================

 -- method: start (obj <service>)
     Start the service OBJ, including all the services it depends on. It tries quite hard to do this: When a service that provides a required symbol can not be started, it will look for another service that also provides this symbol, until starting one such service succeeds.  There is some room for theoretical improvement here, of course, but in pratice the current strategy already works very well. This method returns the new value of the running slot Slots of services, which is #f if the service could not be started.

 -- method: stop (obj <service>)
     This will stop the service OBJ, trying to stop services that depend in it first, so they can be shutdown cleanly.  If this will fail, it will continue anyway.  Stopping of services should usually succeed, though.  Otherwise, the behaviour is very similar to the start method.  The return value is also the new running value, thus #f if the service was stopped.

 -- method: action (obj <service>) the-action . args
     Calls the action THE-ACTION (a symbol) of the service OBJ, with the specified ARGS, which have a meaning depending on the particular action.

 -- method: conflicts-with (obj <service>)
     Returns a list of the canonical names of services that conflict with the service OBJ.

 -- method: canonical-name (obj <service>)
     Returns the canonical name of OBJ, which is the first element of the provides list.

 -- method: provided-by (obj <service>)
     Returns which symbols are provided by OBJ.

 -- method: required-by (obj <service>)
     Returns which symbols are required by OBJ.

 -- method: running? (obj <service>)
     Returns whether the service OBJ is running.

 -- method: respawn? (obj <service>)
     Returns whether the service OBJ should be respawned if it terminates.

 -- method: default-display-status (obj <service>)
     Display status information about OBJ.  This method is called when the user performs the action status on OBJ, but there is no specific implementation given for it.  It is also called when detailed-status is applied on the root service.

Service Convenience
===================

In addition to the facilities listed below, there are also some procedures that provide commonly needed constructors and destructors for services Service De- and Constructors.

 -- procedure: register-services . services
     Register all SERVICES, so that they can be taken into account when trying to resolve dependencies.

 -- procedure: lookup-services name
     Return a list of all registered services which provide the symbol NAME.

 -- macro: make-actions (name proc) ...
     This macro is used to create a value for the actions slot of a service object Slots of services.  Each NAME is a symbol and each PROC the corresponding procedure that will be called to perform the action.  A PROC has one argument, which will be the current value of the running slot of the service.

 -- method: start (obj <symbol>)
     Start a registered service providing OBJ.

 -- method: stop (obj <symbol>)
     Stop a registered service providing OBJ.

 -- method: action (obj <symbol>) the-action . args
     The same as the action method of class <service>, but uses a service that provides OBJ and is running.

 -- procedure: for-each-service proc
     Call PROC, a procedure taking one argument, once for each registered service.

 -- procedure: find-running services
     Check if any of SERVICES is running.  If this is the case, return its canonical name.  If not, return #f.  Only the first one will be returned; this is because this is mainly intended to be applied on the return value of lookup-services.

Service De- and Constructors
============================

All of the procedures listed below return procedures generated from the supplied arguments.  These procedures take one argument in the case of destructors and no arguments in the case of constructors.

 -- procedure: make-system-constructor COMMAND...
     The returned procedure will execute COMMAND in a shell and return #t if execution was successful, otherwise #f. For convenience, it takes multiple arguments which will be concatenated first.

 -- procedure: make-system-destructor COMMAND...
     Similar to make-system-constructor, but returns #f if execution of the COMMAND was successful, #t if not.

 -- procedure: make-forkexec-constructor COMMAND
     [#:user #f]
     [#:group #f]
     [#:pid-file #f]
     [#:directory (default-service-directory)]
     [#:environment-variables (default-environment-variables)]
     Return a procedure that forks a child process, closes all file descriptors except the standard output and standard error descriptors, sets the current directory to DIRECTORY, changes the environment to ENVIRONMENT-VARIABLES (using the environ procedure), sets the current user to USER and the current group to GROUP unless they are #f, and executes COMMAND (a list of strings.)  The result of the procedure will be the PID of the child process.

     When PID-FILE is true, it must be the name of a PID file associated with the process being launched; the return value is the PID read from that file, once that file has been created.

 -- procedure: make-kill-destructor [SIGNAL]
     Returns a procedure that sends SIGNAL to the pid which it takes as argument.  This does work together with respawning services, because in that case the stop method of the <service> class sets the running slot to #f before actually calling the destructor; if it would not do that, killing the process in the destructor would immediately respawn the service.

The make-forkexec-constructor procedure builds upon the following procedures.

 -- procedure: exec-command COMMAND
     [#:user #f]
     [#:group #f]
     [#:directory (default-service-directory)]
     [#:environment-variables (default-environment-variables)]
 -- procedure: fork+exec-command COMMAND
     [#:user #f]
     [#:group #f]
     [#:directory (default-service-directory)]
     [#:environment-variables (default-environment-variables)]
     Run COMMAND as the current process from DIRECTORY, and with ENVIRONMENT-VARIABLES (a list of strings like "PATH=/bin".) File descriptors 1 and 2 are kept as is, whereas file descriptor 0 (standard input) points to /dev/null; all other file descriptors are closed prior to yielding control to COMMAND.

     By default, COMMAND is run as the current user.  If the USER keyword argument is present and not false, change to USER immediately before invoking COMMAND.  USER may be a string, indicating a user name, or a number, indicating a user ID.  Likewise, COMMAND will be run under the current group, unless the GROUP keyword argument is present and not false.

     fork+exec-command does the same as exec-command, but in a separate process whose PID it returns.

Service Examples
================

FIXME: This needs a lot of work.

You can create a service and then register it this way:

     (define apache (make <service>
                          #:provides '(apache)
                          #:start (...)
                          #:stop (...)))
     (register-services apache)

However, as you usually won't need a variable for the service, you can pass it directly to register-services.  Here is an example that also specifies some more initial values for the slots:

     (register-services
       (make <service>
             #:provides '(apache-2.0 apache httpd)
             #:requires '()
             #:start (...)
             #:stop (...)
             #:actions (make-actions
                        (reload-modules (...))
                        (restart (...)))))

The root and unknown services
=============================

The service root is special, because it is used to control the Shepherd itself.  It has an alias shepherd.  It provides the following actions (in addition to enable, disable and restart which do not make sense here).

status
     Displays which services are started and which ones are not.

detailed-status
     Displays detailed information about every registered service.

load FILE
     Evaluate the Scheme code in FILE in a fresh module that uses the (oop goops) and (shepherd services) modules---as with the --config option of shepherd (see Invoking shepherd).

unload SERVICE-NAME
     Attempt to remove the service identified by SERVICE-NAME. shepherd will first stop the service, if necessary, and then remove it from the list of registered services.  Any services depending upon SERVICE-NAME will be stopped as part of this process.

     If SERVICE-NAME simply does not exist, output a warning and do nothing.  If it exists, but is provided by several services, output a warning and do nothing.  This latter case might occur for instance with the fictional service web-server, which might be provided by both apache and nginx.  If SERVICE-NAME is the special string and all, attempt to remove all services except for the Shepherd itself.

reload FILE-NAME
     Unload all known optional services using unload's all option, then load FILE-NAME using load functionality.  If file-name does not exist or load encounters an error, you may end up with no defined services.  As these can be reloaded at a later stage this is not considered a problem.  If the unload stage fails, reload will not attempt to load FILE-NAME.

daemonize
     Fork and go into the background.  This should be called before respawnable services are started, as otherwise we would not get the SIGCHLD signals when they terminate.

enable-persistency
     When terminating, safe the list of running services in a file.

disable-persistency
     Don't safe the list of running services when terminating.

The unknown service must be defined by the user and if it exists, is used as a fallback whenever we try to invoke an unknown action of an existing service or use a service that does not exist. This is useful only in few cases, but enables you to do various sorts of unusual things.

Runlevels
*********

RUNLEVELS DO NOT WORK YET! Do not use them! Ignore this section!

A runlevel makes it easier to start and stop groups of services, to bring the system into a certain state.  An object of class <runlevel> is an abstract runlevel, and has the following methods:

 -- method: enter (rl <runlevel>) services
     This will be called when the runlevel should be entered. SERVICES is the list of the currently running services.

Misc Facilities
***************

This is a list of facilities which are available to code running inside of the Shepherd and is considered generally useful, but is not directly related to one of the other topic covered in this manual.

Errors
======

 -- macro: assert expr
     If EXPR yields #f, display an appropriate error message and throw an assertion-failed exception.

 -- procedure: caught-error key args
     Tell the Shepherd that a KEY error with ARGS has occured.  This is the simplest way to cause caught error result in uniformly formated warning messages.  The current implementation is not very good, though.

 -- procedure: call/cc proc
     An alias for call-with-current-continuation.

 -- procedure: call/ec proc
     A simplistic implementation of the nonstandard, but popular procedure call-with-escape-continuation, i.e. a call/cc for outgoing continuations only.  Note that the variant included in the Shepherd is not aware of dynamic-wind at all and does not yet support returning multiple values.

 -- macro: without-system-error expr...
     Evaluates the EXPRs, not going further if a system error occurs, but also doing nothing about it.

Communication
=============

The (shepherd comm) module provides primitives that allow clients such as herd to connect to shepherd and send it commands to control or change its behavior (see actions of services).

Currently, clients may only send commands, represented by the <shepherd-command> type.  Each command specifies a service it applies to, an action name, a list of strings to be used as arguments, and a working directory.  Commands are instantiated with shepherd-command:

 -- procedure: shepherd-command ACTION SERVICE
     [#:ARGUMENTS '()] [#:DIRECTORY (getcwd)]
     Return a new command (a <shepherd-command>) object for ACTION on SERVICE.

Commands may then be written to or read from a communication channel with the following procedures:

 -- procedure: write-command COMMAND PORT
     Write COMMAND to PORT.

 -- procedure: read-command PORT
     Receive a command from PORT and return it.

In practice, communication with shepherd takes place over a Unix-domain socket, as discussed earlier (see Invoking shepherd). Clients may open a connection with the procedure below.

 -- procedure: open-connection [FILE]
     Open a connection to the daemon, using the Unix-domain socket at FILE, and return the socket.

     When FILE is omitted, the default socket is used.

The daemon writes output to be logged or passed to the currently-connected client using local-output:

 -- procedure: local-output format-string . args
     This procedure should be used for all output operations in the Shepherd.  It outputs the ARGS according to the FORMAT-STRING, then inserts a newline.  It writes to whatever is the main output target of the Shepherd, which might be multiple at the same time in future versions.

Under the hood, write-command and read-command write/read commands as s-expressions (sexps).  Each sexp is intelligible and specifies a protocol version.  The idea is that users can write their own clients rather than having to invoke herd.  For instance, when you type herd status, what is sent over the wire is the following sexp:

     (shepherd-command
       (version 0)
       (action status) (service root)
       (arguments ()) (directory "/data/src/dmd"))

The reply is also an sexp, along these lines:

     (reply (version 0)
            (result (((service ...) ...)))
            (error #f) (messages ()))

This reply indicates that the status action was successful, because error is #f, and gives a list of sexps denoting the status of services as its result.  The messages field is a possibly-empty list of strings meant to be displayed as is to the user.

Others
======

 -- procedure: copy-hashq-table table new-size
     Create a hash-table with size NEW-SIZE, and insert all values from TABLE into it, using eq? when inserting.  This procedure is mainly used internally, but is a generally useful utillity, so it can by used by everyone.

Internals
*********

This chapter contains information about the design and the implementation details of the Shepherd for people who want to hack it.

The GNU Shepherd is developed by a group of people in connection with GuixSD (https://www.gnu.org/software/guix/), GNU's advanced distribution, but it can be used on other distros as well.  You're very much welcome to join us!  You can report bugs to bug-guix@gnu.org and send patches or suggestions to guix-devel@gnu.org.

Coding standards
================

About formatting: Use common sense and GNU Emacs (which actually is the same, of course), and you almost can't get the formatting wrong. Formatting should be as in Guile and Guix, basically.  See Coding Style (GNU Guix Reference Manual), for more info.

Design decisions
================

     This section was written by Wolfgang Jährling back in 2003 and documents the original design of what was then known as GNU dmd.  The main ideas remain valid but some implementation details and goals have changed.

The general idea of a service manager that uses dependencies, similar to those of a Makefile, came from the developers of the GNU Hurd, but as few people are satisfied with System V Init, many other people had the same idea independently.  Nevertheless, the Shepherd was written with the goal of becoming a replacement for System V Init on GNU/Hurd, which was one of the reasons for choosing the extension language of the GNU project, Guile, for implementation (another reason being that it makes it just so much easier).

The runlevel concept (i.e. thinking in groups of services) is sometimes useful, but often one also wants to operate on single services.  System V Init makes this hard: While you can start and stop a service, init will not know about it, and use the runlevel configuration as its source of information, opening the door for inconsistencies (which fortunatly are not a practical problem usually).  In the Shepherd, this was avoided by having a central entity that is responsible for starting and stopping the services, which therefore knows which services are actually started (if not completely inproperly used, but that is a requirement which is impossible to avoid anyway).  While runlevels are not implemented yet, it is clear that they will sit on top of the service concept, i.e. runlevels will merely be an optional extension that the service concept does not rely on.  This also makes changes in the runlevel design easier when it may become necessary.

The consequence of having a daemon running that controls the services is that we need another program as user interface which communicates with the daemon.  Fortunatly, this makes the commands necessary for controlling services pretty short and intuitive, and gives the additional bonus of adding some more flexibility.  For example, it is easiely possible to grant password-protected control over certain services to unprivileged users, if desired.

An essential aspect of the design of the Shepherd (which was already mentioned above) is that it should always know exactly what is happening, i.e. which services are started and stopped.  The alternative would have been to not use a daemon, but to save the state on the file system, again opening the door for inconsistencies of all sorts. Also, we would have to use a seperate program for respawning a service (which just starts the services, waits until it terminates and then starts it again).  Killing the program that does the respawning (but not the service that is supposed to be respawned) would cause horrible confusion.  My understanding of ``The Right Thing'' is that this conceptionally limited strategy is exactly what we do not want.

The way dependencies work in the Shepherd took a while to mature, as it was not easy to figure out what is appropriate.  I decided to not make it too sophisticated by trying to guess what the user might want just to theoretically fulfill the request we are processing.  If something goes wrong, it is usually better to tell the user about the problem and let her fix it, taking care to make finding solutions or workarounds for problems (like a misconfigured service) easy.  This way, the user is in control of what happens and we can keep the implementation simple.  To make a long story short, we don't try to be too clever, which is usually a good idea in developing software.

If you wonder why I was giving a ``misconfigured service'' as an example above, consider the following situation, which actually is a wonderful example for what was said in the previous paragraph: Service X depends on symbol S, which is provided by both A and B.  A depends on AA, B depends on BB.  AA and BB conflict with each other.  The configuration of A contains an error, which will prevent it from starting; no service is running, but we want to start X now.  In resolving its dependencies, we first try to start A, which will cause AA to be started.  After this is done, the attempt of starting A fails, so we go on to B, but its dependency BB will fail to start because it conflicts with the running service AA.  So we fail to provide S, thus X cannot be started.  There are several possibilities to deal with this:

  * When starting A fails, terminate those services which have been started in order to fulfill its dependencies (directly and indirectly).  In case AA was running already, we would not want to terminate it.  Well, maybe we would, to avoid the conflict with BB. But even if we would find out somehow that we need to terminate AA to eventually start X, is the user aware of this and wants this to happen (assuming AA was running already)?  Probably not, she very likely has assumed that starting A succeeds and thus terminating AA is not necessary.  Remember, unrelated (running) services might depend in AA. Even if we ignore this issue, this strategy is not only complicated, but also far from being perfect: Let's assume starting A succeeds, but X also depends on a service Z, which requires BB.  In that case, we would need to detect in the first place that we should not even try to start A, but directly satisfy X's dependency on S with B.

  * We could do it like stated above, but stop AA only if we know we won't need it anymore (for resolving further dependencies), and start it only when it does not conflict with anything that needs to get started.  But should we stop it if it conflicts with something that might get started?  (We do not always know for sure what we will start, as starting a service might fail and we want to fall back to a service that also provides the particular required symbol in that case.)  I think that either decision will be bad in one case or another, even if this solution is already horribly complicated.

  * When we are at it, we could just calculate a desired end-position, and try to get there by starting (and stopping!) services, recalculating what needs to be done whenever starting a service fails, also marking that particular service as unstartable, except if it fails to start because a dependency could not be resolved (or maybe even then?). This is even more complicated.  Instead of implementing this and thereby producing code that (a) nobody understands, (b) certainly has a lot of bugs, (c) will be unmaintainable and (d) causes users to panic because they won't understand what will happen, I decided to do the following instead:

  * Just report the error, and let the user fix it (in this case, fix the configuration of A) or work around it (in this case, disable A so that we won't start AA but directly go on to starting B).

I hope you can agree that the latter solution after all is the best one, because we can be sure to not do something that the user does not want us to do.  Software should not run amok.  This explanation was very long, but I think it was necessary to justify why the Shepherd uses a very primitive algorithm to resolve dependencies, despite the fact that it could theoretically be a bit more clever in certain situations.

One might argue that it is possible to ask the user if the planned actions are ok with her, and if the plan changes ask again, but especially given that services are supposed to usually work, I see few reasons to make the source code of the Shepherd more complicated than necessary.  If you volunteer to write and maintain a more clever strategy (and volunteer to explain it to everyone who wants to understand it), you are welcome to do so, of course...

Service Internals
=================

Runlevel evolution
==================

     This section was written by Wolfgang Jährling back in 2003 and is kept mostly for historians to read.

This section describes how the runlevel concept evolved over time. This is basically a collection of mistakes, but is provided here for your information, and possibly for your amusement, but I'm not sure if all this weird dependency stuff is really that funny.

Runlevel assumptions
--------------------

A runlevel is a system state, i.e. it consists of the information about which services are supposed to be available and which not.  This vague definition implies that several different runlevel styles can be implemented in a service manager.

For example, you can do it like System V Init, specifying which services should be started when we enter a runlevel and which ones should be stopped when leaving it.  But one could also specify for every service in which runlevels it should be running.

In the Shepherd, we do not want to limit ourselfes to a single runlevel style. We allow for all possible strategies to be implemented, providing the most useful ones as defaults.  We also want to make it possible to combine the different styles arbitrariely.

Therefore, when entering a runlevel, we call a user-defined piece of code, passing it the list of currently active services and expecting as the result a list of service symbols which tell us which services we want to have running.  This interface makes it very easy to implement runlevel styles, but makes it not-so-easy for the runlevel implementation itself, because we have to get from the current state into a desired state, which might be more or less vague (since it is not required to be a list of canonical names).  Obviously service conflicts and already running services need to be taken into account when deciding which services should be used to provide the various symbols.

Also, the runlevel implementation should be implemented completely on top of the service concept, i.e. the service part should not depend on the idea of runlevels or care about them at all.  Otherwise understanding the service part (which is the most essential aspect of the Shepherd) would become harder than necessary.

Runlevels, part one
-------------------

I came up with the following method (here in Pseudo-Scheme), which is possibly slightly buggy, but should give you the idea:

     ;; Beginning with the canonical names in CURRENT-SERVICES, start and
     ;; stop services until getting into a state where everything requested
     ;; in TARGET-SERVICES (which does not only consist of canonical names)
     ;; is provided, and the things they depends on, but no more.
     (define (switch-runlevel current-services target-services)
       (let ((target-services-backup target-services)
     	(unstartable '()))
         (let retry ()
           (repeat-until-none-of-these-changes-annythig
            ;; Replace all of them with canonical names which provide them.
            (canonicalize-names! target-services unstartable current-services)
            ;; Add what we need additionally.
            (add-dependencies! target-services unstartable current-services))
           (remove-redundancy! target-services)
           (stop-all-unneeded target-services)
           (catch 'service-could-not-be-started
     	     (lambda ()
     	       ;; Iterate over the list, starting only those which
     	       ;; have all dependencies already resolved, so nothing
     	       ;; we don't want will be started.  Repeat until done.
     	       (carefully-start target-services))
     	     (lambda (key service)
     	       (set! unstartable (cons service unstartable))
     	       (set! target-services backup-target-services)
     	       (set! current-services (compute-current-services))
     	       (retry))))))

This indeed looks like a nice way to get what we want.  However, the details of this are not as easy as it looks like.  When replacing virtual services with canonical names, we have to be very careful. Consider the following situation:

The virtual service X is provided by both A and B, while Y is provided only by B.  We want to start C (which depends on X) and D (which depends on Y).  Obviously we should use B to fulfill the dependency of C and D on X and Y, respectively.  But when we see that we need something that provides X, we are likely to do the wrong thing: Select A.  Thus, we need to clean this up later. I wanted to do this as follows:

While substituting virtual services with canonical names, we also safe which one we selected to fulfill what, like this:

     ((A . (X))
      (B . (Y)))

Later we look for conflicts, and as A and B conflict, we look which one can be removed (things they provide but are not required by anyone should be ignored, thus we need to create a list like the above).  In this case, we can replace A with B as B also provides X (but A does not provide Y, thus the reverse is impossible).  If both could be used, we probably should decide which one to use by looking at further conflicts, which gets pretty hairy.  But, in this case, we are lucky and end up with this:

     ((B . (X Y)))

This way of finding out which service we should use in case of conflicts sounds pretty sane, but if you think it will work well, you have been fooled, because actually it breaks horribly in the following situation:

Service   Provides
A   W X Y -
B   W X - Z
C   - X Y Z
D   W - - -

If we need all of W, X, Y and Z, then obviously we need to take C and D.  But if we have a list like this, we cannot fix it:

     ((A . (W X Y))
      (B . (Z)))

Thus, we cannot do it this way.

Runlevels, part two
-------------------

Let's look again at the table at the end of part two:

Service   Provides
A   W X Y -
B   W X - Z
C   - X Y Z
D   W - - -

If from this table it is so obvious for us what we should do, then it should also be possible to calculate it for a computer, given such a table as input.  Ok, we have to take into account conflicts that are not visible in this table, but the general idea is usable.  But how do we find which combination works?  I found only one way yet: Kind of a brute force attack: Try combinations until we find one that works.

This alone would be too slow.  With 20 services we would have 2^20 possible combinations, that is a bit more than a million.  Fortunatly, we can optimize this.  First I thought we could remove all services from the list that do not provide any symbol we need, but that is obviously a stupid idea, as we might need them for dependencies, in which case we need to take into account their conflicts.  But the following method would work:

Very often a symbol that is required will be a canonical name already, i.e. be provided only by a single service.  Using our example above, let's suppose we also need the symbol V, which is provided only by D. The first step we do is to look which (required) symbols are provided only by a single service, as we will need this service for sure.  In this case, we would need D.  But by using it, we would also get the other symbols it provides, W in this case.  This means that we don't need to bother looking at other services that provide W, as we cannot use them because they conflict with a service that we definitely need. In this case, we can remove A and B from the list this way.  Note that we can remove them entirely, as all their conflicts become irrelevant to us now.  In this simple case we would not even have to do much else, C is the only remaining service.

After this first step, there remain the symbols that are provided by two or more services.  In every combination we try, exactly one of them must be used (and somehow we should take into account which services are running already).  This also reduces the amount of possible combinations a lot.  So what remains after that are the services we might need for fulfilling dependencies.  For them, we could try all combinations (2^n), making sure that we always try subsets before any of their supersets to avoid starting unneeded services.  We should take into account which services are already running as well.

The remaining question is, what to do if starting a service fails.  A simple solution would be to recursively remove all services that depend on it directly or indirectly.  That might cause undesired side-effects, if a service was running but it had to be stopped because one of the services that provides something it depends on gets exchanged for another service that provides the same symbol, but fails to start.  The fact that we would have to stop the (first) service is a problem on its own, though.

GNU Free Documentation License
******************************

     [file fdl-1.3.texi not included]