12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523 |
- \input texinfo @c -*- texinfo -*-
- @c shepherd.texi -- The documentation in Texinfo format.
- @documentencoding UTF-8
- @setfilename shepherd.info
- @settitle The GNU Shepherd Manual
- @include version.texi
- @set OLD-YEARS 2002, 2003
- @set NEW-YEARS 2013, 2016, 2018, 2019, 2020
- @copying
- Copyright @copyright{} @value{OLD-YEARS} Wolfgang J@"ahrling@*
- Copyright @copyright{} @value{NEW-YEARS} Ludovic Courtès@*
- Copyright @copyright{} 2020 Brice Waegeneire@*
- Copyright @copyright{} 2020 Oleg Pykhalov
- Copyright @copyright{} 2020 Jan (janneke) Nieuwenhuizen@*
- 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''.
- @end copying
- @dircategory System software
- @direntry
- * shepherd: (shepherd). The Shepherd service manager.
- * herd: (shepherd)Invoking herd
- Controlling the Shepherd service manager.
- * reboot: (shepherd)Invoking reboot
- Rebooting a Shepherd-controlled system.
- * halt: (shepherd)Invoking halt
- Turning off a Shepherd-controlled system.
- @end direntry
- @titlepage
- @title The GNU Shepherd Manual
- @subtitle For use with the GNU Shepherd @value{VERSION}
- @subtitle Last updated @value{UPDATED}
- @author Wolfgang J@"ahrling
- @author Ludovic Courtès
- @insertcopying
- @end titlepage
- @contents
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @ifnottex
- @node Top
- @top The GNU Shepherd Manual
- This manual documents the GNU@tie{}Shepherd version @value{VERSION}, a
- service manager for the GNU system.
- @menu
- * Introduction:: Introduction to the Shepherd service manager.
- * Jump Start:: How to do simple things with the Shepherd.
- * herd and shepherd:: User interface to service management.
- * Services:: Details on services.
- * Misc Facilities:: Generally useful things provided by the Shepherd.
- * Internals:: Hacking shepherd.
- * GNU Free Documentation License:: The license of this manual.
- * Concept Index::
- * Procedure and Macro Index::
- * Variable Index::
- * Type Index::
- @end menu
- @end ifnottex
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Introduction
- @chapter Introduction
- @cindex service manager
- This manual documents the GNU@tie{}Daemon Shepherd, or GNU@tie{}Shepherd
- for short. The Shepherd looks after system services, typically @dfn{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 @dfn{init system} of the GNU operating system---it is the
- first user process that gets started, typically with PID 1, and runs
- as @code{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
- (@pxref{Jump Start}). In chapter two we will describe the
- @command{herd} and @command{shepherd} programs, and their relationship, in
- more detail (@ref{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.
- @cindex dmd
- The Shepherd was formerly known as ``dmd'', which stands for @dfn{Daemon
- Managing Daemons} (or @dfn{Daemons-Managing Daemon}?).
- @cindex Guile
- @cindex Scheme
- @cindex GOOPS
- 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.
- @xref{Introduction,,, guile, 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.
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Jump Start
- @chapter Jump Start
- @cindex prefix
- 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 Shepherd installation for example resides in @code{/usr/local}
- instead, add this directory name in front of the absolute file names
- mentioned below.
- @cindex Configuration file
- When @command{shepherd} gets started, it reads and evaluates a
- configuration file. When it is started with superuser privileges, it
- tries to use @code{/etc/shepherd.scm}. When started as normal user, it
- looks for a file called @code{$XDG_CONFIG_HOME/shepherd/init.scm}. If
- the @code{XDG_CONFIG_HOME} environment variable is not defined,
- @code{$HOME/.config/shepherd/init.scm} is used instead (@pxref{Managing
- User Services }). With the option @code{--config} (or, for short,
- @code{-c}), you can specify where to look instead. So if you want to
- start @command{shepherd} with an alternative file, use one of the
- following commands:
- @example
- shepherd --config=/etc/shepherd.scm.old
- shepherd -c /etc/shepherd.scm.old
- @end example
- @cindex Starting a service
- As the final ``d'' suggests, @command{shepherd} is just
- a daemon that (usually) runs in the
- background, so you will not interact with it directly. After it is
- started, @command{shepherd} will listen on a socket special file, usually
- @code{/var/run/shepherd/socket}, for further commands. You use the tool
- @dfn{herd} to send these commands to @command{shepherd}. Usage of herd is simple and
- straightforward: To start a service called @code{apache}, you use:
- @example
- herd start apache
- @end example
- @cindex Status (of services)
- @cindex Service status
- 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 @code{networking}. So if you
- want to start @code{apache}, and @code{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:
- @example
- herd status
- @end example
- @noindent
- Or, to get additional details about each service, run:
- @example
- herd detailed-status
- @end example
- @noindent
- In this example, this would show the @code{networking} and @code{apache}
- services as started. If you just want to know the status of the
- @code{apache} service, run:
- @example
- herd status apache
- @end example
- @cindex Stopping a service
- You can stop
- a service and all the services that depend on it will be stopped.
- Using the example above, if you stop @code{networking}, the service
- @code{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:
- @example
- herd stop networking
- @end example
- There are two more actions you can perform on every service: the
- actions @code{enable} and @code{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:
- @example
- herd enable foo
- herd start foo
- @end example
- @cindex virtual services
- @cindex fallback services
- 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
- @emph{virtual} services. A virtual service is a service that is
- provided by one or more service additionally. For instance, a service
- called @code{exim} might provide the virtual service
- @code{mailer-daemon}. That could as well be provided by a service
- called @code{smail}, as both are mailer-daemons. If a service needs
- any mailer-daemon, no matter which one, it can just depend on
- @code{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, @command{shepherd} will go on and try to
- start the next one, so you can also use virtual services for
- specifying @emph{fallbacks}.
- Additionally to all that, you can perform service-specific actions.
- Coming back to our original example, @code{apache} is able to
- reload its modules, therefore the action @code{reload-modules} might
- be available:
- @example
- herd reload-modules apache
- @end example
- 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 @command{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 @code{restart} and @code{status}. The default
- implementation of @code{restart} calls @code{stop} and @code{start} on the
- affected service, taking care to also restart any dependent services. The
- default implementation of @code{status} 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).
- A special service is @code{root}, which is used for controlling the
- Shepherd itself. You can also reference to this service as
- @code{shepherd}. It implements various actions. For example, the
- @code{status} action displays which services are started and which ones
- are stopped, whereas @code{detailed-status} has the effect of applying
- the default implementation of @code{status} to all services one after
- another. The @code{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 @code{load}
- to load arbitrary code into the Shepherd at runtime, like this:
- @example
- herd load shepherd ~/additional-services.scm
- @end example
- In the same vein the special action @code{doc} describes its service
- when called without an argument or describes a service-specific action
- when called with the action as the additional arguments. You can even
- get the list of the service-specific actions a service provides when
- using with the additional argument @code{list-actions}.
- @example
- $ herd doc root
- The root service is used to operate on shepherd itself.
- $ herd doc root list-actions
- root (help status halt power-off load eval unload reload daemonize persistency no-persistency cd restart)
- $ herd doc root action power-off
- power-off: Halt the system and turn it off.
- @end example
- This is enough now about the @command{herd} and @command{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 @code{doc/examples/} subdirectory.
- @example
- ...
- @end example
- Ok, to summarize:
- @itemize @bullet
- @item
- @command{shepherd} is a daemon, @command{herd} the program that controls it.
- @item
- You can start, stop, restart, enable and disable every service, as
- well as display its status.
- @item
- You can perform additional service-specific actions, which you can
- also list.
- @item
- Actions can have arguments.
- @item
- 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.
- @item
- The @code{root}/@code{shepherd} service is used to control
- @command{shepherd} itself.
- @end itemize
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node herd and shepherd
- @chapter @command{herd} and @command{shepherd}
- @cindex herd
- @cindex shepherd
- @cindex daemon
- @cindex daemon controller
- @cindex relative file names
- @cindex herding, of daemons
- The daemon that runs in the background and is responsible for
- controlling the services is @command{shepherd}, while the user interface
- tool is called @command{herd}: it's the command that allows you to
- actually @emph{herd} your daemons@footnote{
- @cindex deco, daemon controller
- In the past, when the
- GNU@tie{}Shepherd was known as GNU@tie{}dmd, the @command{herd} command
- was called @code{deco}, for @dfn{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 @command{shepherd} once, and then always use herd whenever you want
- to do something service-related. Since herd passes its current
- working directory to @command{shepherd}, you can pass relative file names without
- trouble. Both @command{shepherd} and herd understand the standard arguments
- @code{--help}, @code{--version} and @code{--usage}.
- @menu
- * Invoking shepherd:: How to start the service damon.
- * Invoking herd:: Controlling daemons.
- * Invoking reboot:: Rebooting a shepherd-controlled system.
- * Invoking halt:: Turning off a shepherd-controlled system.
- @end menu
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Invoking shepherd
- @section Invoking @command{shepherd}
- @cindex @command{shepherd} Invocation
- @cindex invoking @command{shepherd}
- The @code{shepherd} program has the following synopsis:
- @example
- shepherd [@var{option}@dots{}]
- @end example
- It accepts the following options:
- @table @samp
- @item -c @var{file}
- @itemx --config=@var{file}
- Read and evaluate @var{file} as the configuration script on startup.
- @var{file} is evaluated in the context of a fresh module where bindings
- from the @code{(shepherd service)} module and Guile's @code{(oop goops)} are
- available, in addition to the default set of Guile bindings. In
- particular, this means that code in @var{file} may use
- @code{register-services}, the @code{<service>} class, and related tools
- (@pxref{Services}).
- @item -I
- @itemx --insecure
- @cindex security
- @cindex insecure
- Do not check if the directory where the socket---our communication
- rendez-vous with @command{herd}---is located has permissions @code{700}.
- If this option is not specified, @command{shepherd} will abort if the
- permissions are not as expected.
- @item -l [@var{file}]
- @itemx --logfile[=@var{file}]
- @cindex logging
- @cindex log file
- Log output into @var{file}.
- For unprivileged users, the default log file is
- @file{$XDG_DATA_DIR/.local/share/shepherd/shepherd.log}.
- @cindex syslog
- When running as root, the default behavior is to connect to
- @file{/dev/log}, the @dfn{syslog} socket (@pxref{Overview of Syslog,,,
- libc, The GNU C Library Reference Manual}). A syslog daemon,
- @command{syslogd}, is expected to read messages from there
- (@pxref{syslogd invocation, syslogd,, libc, GNU Inetutils}).
- When @file{/dev/log} is unavailable, for instance because
- @command{syslogd} is not running, as is the case during system startup
- and shutdown, @command{shepherd} falls back to the Linux kernel
- @dfn{ring buffer}, @file{/dev/kmsg}. If @file{/dev/kmsg} is missing, as
- is the case on other operating systems, it falls back to
- @file{/dev/console}.
- @item --pid[=@var{file}]
- When @command{shepherd} is ready to accept connections, write its PID to @var{file} or
- to the standard output if @var{file} is omitted.
- @item -p [@var{file}]
- @itemx --persistency[=@var{file}]
- @c FIXME-CRITICAL
- @item -s @var{file}
- @itemx --socket=@var{file}
- @cindex socket special file
- @vindex XDG_RUNTIME_DIR
- Receive further commands on the socket special file @var{file}. If this
- option is not specified, @file{@var{localstatedir}/run/shepherd/socket} is
- taken when running as @code{root}; when running as an unprivileged
- user, @command{shepherd} listens to @file{/run/user/@var{uid}/shepherd/socket},
- where @var{uid} is the user's numerical ID@footnote{On GNU/Linux, the
- @file{/run/user/@var{uid}} directory is typically created by elogind or by
- systemd, which are available in most distributions.}, or to
- @file{$XDG_RUNTIME_DIR/shepherd} when the @code{XDG_RUNTIME_DIR}
- environment variable is defined.
- If @code{-} is specified as file name, commands will be read from
- standard input, one per line, as would be passed on a @command{herd}
- command line (@pxref{Invoking herd}).
- @item --quiet
- Synonym for @code{--silent}.
- @end table
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Invoking herd
- @section Invoking @command{herd}
- @cindex herd
- The @command{herd} command is a generic client program to control a
- running instance of @command{shepherd} (@pxref{Invoking shepherd}). It has the
- following synopsis:
- @example
- herd [@var{option}@dots{}] @var{action} [@var{service} [@var{arg}@dots{}]]
- @end example
- It causes the @var{action} of the @var{service} to be invoked. When
- @var{service} is omitted and @var{action} is @code{status} or
- @code{detailed-status}, the @code{root} service is used@footnote{This
- shorthand does not work for other actions such as @code{stop}, because
- inadvertently typing @code{herd stop} would stop all the services, which
- could be pretty annoying.} (@pxref{The root and unknown services}, for
- more information on the @code{root} service.)
- For each action, you should pass the appropriate @var{arg}s. Actions
- that are available for every service are @code{start}, @code{stop},
- @code{restart}, @code{status}, @code{enable}, @code{disable}, and
- @code{doc}.
- If you pass a file name as an @var{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 @command{shepherd}, not to herd.
- The @code{herd} command understands the following option:
- @table @samp
- @item -s @var{file}
- @itemx --socket=@var{file}
- Send commands to the socket special file @var{file}. If this option is
- not specified, @file{@var{localstatedir}/run/shepherd/socket} is taken.
- @end table
- The @code{herd} command returns zero on success, and a non-zero exit
- code on failure. In particular, it returns a non-zero exit code when
- @var{action} or @var{service} does not exist and when the given action
- failed.
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Invoking reboot
- @section Invoking @command{reboot}
- @cindex herd
- The @command{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:
- @example
- reboot [@var{option}@dots{}]
- @end example
- It is equivalent to running @command{herd stop shepherd}. The
- @code{reboot} command understands the following option:
- @table @samp
- @item -s @var{file}
- @itemx --socket=@var{file}
- Send commands to the socket special file @var{file}. If this option is
- not specified, @file{@var{localstatedir}/run/shepherd/socket} is taken.
- @end table
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Invoking halt
- @section Invoking @command{halt}
- @cindex herd
- The @command{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:
- @example
- halt [@var{option}@dots{}]
- @end example
- It is equivalent to running @command{herd power-off shepherd}. As
- usual, the @code{halt} command understands the following option:
- @table @samp
- @item -s @var{file}
- @itemx --socket=@var{file}
- Send commands to the socket special file @var{file}. If this option is
- not specified, @file{@var{localstatedir}/run/shepherd/socket} is taken.
- @end table
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Services
- @chapter Services
- @cindex service
- @tindex <service>
- The @dfn{service} is obviously a very important concept of the Shepherd. On the
- Guile level, a service is represented as an instance of
- @code{<service>}, a GOOPS class (@pxref{GOOPS,,, guile, 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 @code{<service>} class and its associated procedures and methods are
- defined in the @code{(shepherd service)} module.
- @menu
- * Slots of services:: What a <service> object consists of.
- * Methods of services:: What you can do with a <service> object.
- * Service Convenience:: How to conveniently work with services.
- * Service De- and Constructors:: Commonly used ways of starting and
- stopping services.
- * Service Examples:: Examples that show how services are used.
- * Managing User Services:: Running the Shepherd as a user.
- * The root and unknown services:: Special services in the Shepherd.
- @end menu
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Slots of services
- @section Slots of services
- @cindex <service>, slots of
- @cindex slots of <service>
- A service has the following slots, all of which can be initialized
- with a keyword (i.e. @code{#:provides}, used when creating the object)
- of the same name, except where stated otherwise. You should not
- access them directly with @code{slot-ref} or @code{slot-set!}
- usually, use the methods of the service class @ref{Methods of
- services} instead.
- @itemize @bullet
- @item
- @vindex provides (slot of <service>)
- @cindex canonical names of services
- @code{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.
- @item
- @vindex requires (slot of <service>)
- @code{requires} is, like @code{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.
- @item
- @vindex running (slot of <service>)
- @cindex Hook for individual services
- @code{running} is a hook that can be used by each service in its own
- way. The default value is @code{#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 @code{start} slot.
- It will also be passed as an argument to the procedure in the
- @code{stop} slot. If it is set a value that is an integer, it is
- assumed to be a process id, and shepherd will monitor the process for
- unexpected exits. This slot can not be initialized with a keyword.
- @item
- @vindex respawn? (slot of <service>)
- @cindex Respawning services
- @code{respawn?} specifies whether the service should be respawned by
- the Shepherd. If this slot has the value @code{#t}, then assume the
- @code{running} slot specifies a child process PID and restart the
- service if that process terminates. Otherwise this slot is @code{#f},
- which is the default. See also the @code{last-respawns} slot.
- @item
- @vindex one-shot? (slot of <service>)
- @cindex one-shot services
- The @code{one-shot?} slot determines whether the service is a @dfn{one-shot
- service}. A one-shot service is a service that, as soon as it has been
- successfully started, is marked as ``stopped.'' Other services can
- nonetheless require one-shot services. One-shot services are useful to
- trigger an action before other services are started, such as a cleanup or an
- initialization action.
- As for other services, the @code{start} method of a one-shot service must
- return a truth value to indicate success, and false to indicate failure.
- @item
- @vindex start (slot of <service>)
- @cindex Starting a service
- @cindex Service constructor
- @code{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 @code{<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 @code{#f}. The
- value will be stored in the @code{running} slot. The default value is
- a procedure that returns @code{#t} and performs no further actions,
- therefore it is desirable to specify a different one usually.
- @item
- @vindex stop (slot of <service>)
- @cindex Stopping a service
- @cindex Service destructor
- @code{stop} is, similar to @code{start}, a slot containing a
- procedure. But in this case, it gets the current value of the
- @code{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 @code{running} slot, so that it
- should return @code{#f} if it is now possible again to start the
- service at a later point. The default value is a procedure that
- returns @code{#f} and performs no further actions.
- @item
- @vindex actions (slot of <service>)
- @cindex Actions of services
- @cindex Service actions
- @code{actions} specifies the additional actions that can be performed
- on a service when it is running. A typical example for this is the
- @code{restart} action. The macro @code{make-actions} @ref{Service
- Convenience} is provided to abstract the actual data representation
- format for this slot. (It actually is a hash currently.)
- @item
- @vindex enabled? (slot of <service>)
- @code{enabled?} cannot be initialized with a keyword, and contains
- @code{#t} by default. When the value becomes @code{#f} at some point,
- this will prevent the service from getting started. A service can be
- enabled and disabled with the methods @code{enable} and
- @code{disable}, respectively @ref{Methods of services}.
- @item
- @vindex last-respawns (slot of <service>)
- @code{last-respawns} cannot be initialized with a keyword and is only
- ever used when the @code{respawn?} slot contains @code{#t}; it is a
- circular list with @code{(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.
- @item
- @vindex stop-delay? (slot of <service>)
- @code{stop-delay?} being false causes the @code{stop} slot to be
- unused; instead, stopping the service will just cause the
- @code{waiting-for-termination?} slot be set to @code{#t}.
- @item
- @vindex waiting-for-termination? (slot of <service>)
- @code{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 @code{stop-delay?} slot contains a true
- value. @code{waiting-for-termination?} contains @code{#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 @code{#f}.
- @item
- @vindex replacement (slot of <service>)
- @code{replacement} specifies a service to be used to replace this one
- when it is stopped. This service will continue to function normally
- until the @code{stop} action is invoked. After the service has been
- successfully stopped, its definition will be replaced by the value of
- this slot, which must itself be a service. This slot is ignored if
- its value is @code{#f}.
- @end itemize
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Methods of services
- @section Methods of services
- @deffn {method} start (obj <service>)
- Start the service @var{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 practice the current strategy already works very well.
- This method returns the new value of the @code{running} slot
- @ref{Slots of services}, which is @code{#f} if the service could not
- be started.
- @end deffn
- @deffn {method} stop (obj <service>)
- This will stop the service @var{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
- @code{start} method. The return value is also the new @code{running}
- value, thus @code{#f} if the service was stopped.
- @end deffn
- @deffn {method} action (obj <service>) the-action . args
- Calls the action @var{the-action} (a symbol) of the service @var{obj},
- with the specified @var{args}, which have a meaning depending on the
- particular action.
- @end deffn
- @deffn {method} conflicts-with (obj <service>)
- Returns a list of the canonical names of services that conflict with
- the service @var{obj}.
- @end deffn
- @deffn {method} canonical-name (obj <service>)
- Returns the canonical name of @var{obj}, which is the first element of
- the @code{provides} list.
- @end deffn
- @deffn {method} provided-by (obj <service>)
- Returns which symbols are provided by @var{obj}.
- @end deffn
- @deffn {method} required-by (obj <service>)
- Returns which symbols are required by @var{obj}.
- @end deffn
- @deffn {method} one-shot? (obj <service>)
- Returns whether the service @var{obj} is a one-shot service.
- @end deffn
- @deffn {method} running? (obj <service>)
- Returns whether the service @var{obj} is running.
- @end deffn
- @deffn {method} respawn? (obj <service>)
- Returns whether the service @var{obj} should be respawned if it
- terminates.
- @end deffn
- @deffn {method} default-display-status (obj <service>)
- Display status information about @var{obj}. This method is called
- when the user performs the action @code{status} on @var{obj}, but
- there is no specific implementation given for it. It is also called
- when @code{detailed-status} is applied on the @code{root} service.
- @end deffn
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Service Convenience
- @section Service Convenience
- In addition to the facilities listed below, there are also some
- procedures that provide commonly needed constructors and destructors
- for services @ref{Service De- and Constructors}.
- @deffn {procedure} register-services . services
- Register all @var{services}, so that they can be taken into account
- when trying to resolve dependencies.
- @end deffn
- @deffn {procedure} lookup-services name
- Return a list of all registered services which provide the symbol
- @var{name}.
- @end deffn
- @deffn {macro} make-actions (name proc) ...
- This macro is used to create a value for the @code{actions} slot of a
- service object @ref{Slots of services}. Each @var{name} is a symbol
- and each @var{proc} the corresponding procedure that will be called to
- perform the action. A @var{proc} has one argument, which will be the
- current value of the @code{running} slot of the service.
- @end deffn
- @deffn {method} start (obj <symbol>)
- Start a registered service providing @var{obj}.
- @end deffn
- @deffn {method} stop (obj <symbol>)
- Stop a registered service providing @var{obj}.
- @end deffn
- @deffn {method} action (obj <symbol>) the-action . args
- The same as the @code{action} method of class @code{<service>}, but
- uses a service that provides @var{obj} and is running.
- @end deffn
- @deffn {procedure} for-each-service proc
- Call @var{proc}, a procedure taking one argument, once for each
- registered service.
- @end deffn
- @deffn {procedure} find-running services
- Check if any of @var{services} is running. If this is the case,
- return its canonical name. If not, return @code{#f}. Only the first
- one will be returned; this is because this is mainly intended to be
- applied on the return value of @code{lookup-services}.
- @end deffn
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Service De- and Constructors
- @section Service De- and Constructors
- @cindex generating constructors
- @cindex generating destructors
- @cindex constructors, generation of
- @cindex destructors, generation of
- 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.
- @deffn {procedure} make-system-constructor @var{command}@dots{}
- The returned procedure will execute @var{command} in a shell and
- return @code{#t} if execution was successful, otherwise @code{#f}.
- For convenience, it takes multiple arguments which will be
- concatenated first.
- @end deffn
- @deffn {procedure} make-system-destructor @var{command}@dots{}
- Similar to @code{make-system-constructor}, but returns @code{#f} if
- execution of the @var{command} was successful, @code{#t} if not.
- @end deffn
- @deffn {procedure} make-forkexec-constructor @var{command} @
- [#:user #f] @
- [#:group #f] @
- [#:supplementary-groups '()] @
- [#:pid-file #f] [#:pid-file-timeout (default-pid-file-timeout)] @
- [#:log-file #f] @
- [#:directory (default-service-directory)] @
- [#:file-creation-mask #f] @
- [#: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 @var{directory}, sets the umask to
- @var{file-creation-mask} unless it is @code{#f}, changes the environment
- to @var{environment-variables} (using the @code{environ} procedure),
- sets the current user to @var{user} the current group to @var{group}
- unless they are @code{#f} and supplementary groups to
- @var{supplementary-groups} unless they are @code{'()}, and executes
- @var{command} (a list of strings.) The result of the procedure will be
- the PID of the child process. Note that this will not work as expected
- if the process ``daemonizes'' (forks); in that case, you will need to
- pass @code{#:pid-file}, as explained below.
- When @var{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
- once that file has been created. If @var{pid-file} does not show up in less
- than @var{pid-file-timeout} seconds, the service is considered as failing to
- start.
- When @var{log-file} is true, it names the file to which the service's
- standard output and standard error are redirected. @var{log-file} is
- created if it does not exist, otherwise it is appended to.
- @end deffn
- @deffn {procedure} make-kill-destructor [@var{signal}]
- Return a procedure that sends @var{signal} to the process group of the
- PID given as argument, where @var{signal} defaults to @code{SIGTERM}.
- This @emph{does} work together with respawning services,
- because in that case the @code{stop} method of the @code{<service>}
- class sets the @code{running} slot to @code{#f} before actually
- calling the destructor; if it would not do that, killing the process
- in the destructor would immediately respawn the service.
- @end deffn
- The @code{make-forkexec-constructor} procedure builds upon the following
- procedures.
- @deffn {procedure} exec-command @var{command} @
- [#:user #f] @
- [#:group #f] @
- [#:supplementary-groups '()] @
- [#:log-file #f] @
- [#:directory (default-service-directory)] @
- [#:file-creation-mask #f] @
- [#:environment-variables (default-environment-variables)]
- @deffnx {procedure} fork+exec-command @var{command} @
- [#:user #f] @
- [#:group #f] @
- [#:supplementary-groups '()] @
- [#:directory (default-service-directory)] @
- [#:file-creation-mask #f] @
- [#:environment-variables (default-environment-variables)]
- Run @var{command} as the current process from @var{directory}, with
- @var{file-creation-mask} if it's true, and with
- @var{environment-variables} (a list of strings like @code{"PATH=/bin"}.)
- File descriptors 1 and 2 are kept as is or redirected to @var{log-file}
- if it's true, whereas file descriptor 0
- (standard input) points to @file{/dev/null}; all other file descriptors
- are closed prior to yielding control to @var{command}.
- By default, @var{command} is run as the current user. If the @var{user}
- keyword argument is present and not false, change to @var{user}
- immediately before invoking @var{command}. @var{user} may be a string,
- indicating a user name, or a number, indicating a user ID. Likewise,
- @var{command} will be run under the current group, unless the
- @var{group} keyword argument is present and not false, and
- @var{supplementary-groups} is not @code{'()}.
- @code{fork+exec-command} does the same as @code{exec-command}, but in
- a separate process whose PID it returns.
- @end deffn
- @defvr {Scheme Variable} default-environment-variables
- This parameter (@pxref{Parameters,,, guile, GNU Guile Reference Manual})
- specifies the default list of environment variables to be defined when
- the procedures above create a new process.
- It must be a list of strings where each string has the format
- @code{@var{name}=@var{value}}. It defaults to what @code{environ}
- returns when the program starts (@pxref{Runtime Environment,
- @code{environ},, guile, GNU Guile Reference Manual}).
- @end defvr
- @defvr {Scheme Variable} default-pid-file-timeout
- This parameter (@pxref{Parameters,,, guile, GNU Guile Reference Manual})
- specified the default PID file timeout in seconds, when
- @code{#:pid-file} is used (see above). It defaults to 5 seconds.
- @end defvr
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Service Examples
- @section Service Examples
- FIXME: This needs a lot of work.
- You can create a service and then register it this way:
- @lisp
- (define apache (make <service>
- #:provides '(apache)
- #:start (...)
- #:stop (...)))
- (register-services apache)
- @end lisp
- However, as you usually won't need a variable for the service, you can
- pass it directly to @code{register-services}. Here is an example that
- also specifies some more initial values for the slots:
- @lisp
- (register-services
- (make <service>
- #:provides '(apache-2.0 apache httpd)
- #:requires '()
- #:start (...)
- #:stop (...)
- #:actions (make-actions
- (reload-modules (...))
- (restart (...)))))
- @end lisp
- @node Managing User Services
- @section Managing User Services
- The Shepherd can be used to manage services for an unprivileged user.
- First, you may want to ensure it is up and running every time you log
- in. One way to accomplish that is by adding the following lines to
- @file{~/.bash_profile} (@pxref{Bash Startup Files,,, bash, The GNU Bash
- Reference Manual}):
- @verbatim
- if [[ ! -S ${XDG_RUNTIME_DIR-$HOME/.cache}/shepherd/socket ]]; then
- shepherd
- fi
- @end verbatim
- Then, we suggest the following top-level
- @file{$XDG_CONFIG_HOME/shepherd/init.scm} file, which will automatically
- load individual service definitions from
- @file{~/.config/shepherd/init.d}:
- @lisp
- (use-modules (shepherd service)
- ((ice-9 ftw) #:select (scandir)))
- ;; Load all the files in the directory 'init.d' with a suffix '.scm'.
- (for-each
- (lambda (file)
- (load (string-append "init.d/" file)))
- (scandir (string-append (dirname (current-filename)) "/init.d")
- (lambda (file)
- (string-suffix? ".scm" file))))
- ;; Send shepherd into the background
- (action 'shepherd 'daemonize)
- @end lisp
- Then, individual user services can be put in
- @code{$XDG_CONFIG_HOME/shepherd/init.d/}, e.g., for @command{ssh-agent}.
- @lisp
- ;;; Commentary:
- ;;;
- ;;; Add to your ~/.bash_profile:
- ;;;
- ;;; SSH_AUTH_SOCK=$@{XDG_RUNTIME_DIR-$HOME/.cache@}/ssh-agent/socket
- ;;; export SSH_AUTH_SOCK
- ;;;
- ;;; Code:
- (use-modules (shepherd support))
- (define ssh-agent
- (make <service>
- #:provides '(ssh-agent)
- #:docstring "Run `ssh-agent'"
- #:start (lambda ()
- (let ((socket-dir (string-append %user-runtime-dir "/ssh-agent")))
- (unless (file-exists? socket-dir)
- (mkdir-p socket-dir)
- (chmod socket-dir #o700))
- (fork+exec-command
- `("ssh-agent" "-D" "-a" ,(string-append socket-dir "/socket"))
- #:log-file (string-append %user-log-dir "/ssh-agent.log"))))
- #:stop (make-kill-destructor)
- #:respawn? #t))
- (register-services ssh-agent)
- (start ssh-agent)
- @end lisp
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node The root and unknown services
- @section The @code{root} and @code{unknown} services
- @cindex root service
- @cindex special services
- The service @code{root} is special, because it is used to control the
- Shepherd itself. It has an alias @code{shepherd}. It provides the
- following actions (in addition to @code{enable}, @code{disable} and
- @code{restart} which do not make sense here).
- @table @code
- @item status
- Displays which services are started and which ones are not.
- @item detailed-status
- Displays detailed information about every registered service.
- @item load @var{file}
- Evaluate the Scheme code in @var{file} in a fresh module that uses the
- @code{(oop goops)} and @code{(shepherd services)} modules---as with the
- @code{--config} option of @command{shepherd} (@pxref{Invoking shepherd}).
- @item eval @var{exp}
- Likewise, evaluate Scheme expression @var{exp} in a fresh module with
- all the necessary bindings.
- @item unload @var{service-name}
- Attempt to remove the service identified by @var{service-name}.
- @command{shepherd} will first stop the service, if necessary, and then
- remove it from the list of registered services. Any services
- depending upon @var{service-name} will be stopped as part of this
- process.
- If @var{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 @code{web-server}, which might be provided by both
- @code{apache} and @code{nginx}. If @var{service-name} is the special
- string and @code{all}, attempt to remove all services except for the Shepherd
- itself.
- @item reload @var{file-name}
- Unload all known optional services using unload's @code{all} option,
- then load @var{file-name} using @code{load} functionality. If
- file-name does not exist or @code{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 @code{unload} stage
- fails, @code{reload} will not attempt to load @var{file-name}.
- @item daemonize
- Fork and go into the background. This should be called before
- respawnable services are started, as otherwise we would not get the
- @code{SIGCHLD} signals when they terminate.
- @item enable-persistency
- When terminating, save the list of running services in a file.
- @c FIXME-CRITICAL: How can we specify which one?
- @item disable-persistency
- Don't save the list of running services when terminating.
- @end table
- @cindex unknown service
- @cindex fallback service
- The @code{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.
- @c FIXME-CRITICAL: finish
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Misc Facilities
- @chapter 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.
- @menu
- * Errors:: Signalling, handling and ignoring errors.
- * Communication:: Input/Output in various ways.
- * Others:: Stuff that is useful, but is homeless.
- @end menu
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Errors
- @section Errors
- @cindex assertions
- @deffn {macro} assert expr
- If @var{expr} yields @code{#f}, display an appropriate error
- message and throw an @code{assertion-failed} exception.
- @end deffn
- @deffn {procedure} caught-error key args
- Tell the Shepherd that a @var{key} error with @var{args} has occurred. This is
- the simplest way to cause caught error result in uniformly formatted
- warning messages. The current implementation is not very good,
- though.
- @end deffn
- @cindex system errors
- @deffn {macro} without-system-error expr@dots{}
- Evaluates the @var{expr}s, not going further if a system error occurs,
- but also doing nothing about it.
- @end deffn
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Communication
- @section Communication
- The @code{(shepherd comm)} module provides primitives that allow clients such
- as @command{herd} to connect to @command{shepherd} and send it commands to
- control or change its behavior (@pxref{Slots of services, actions of
- services}).
- @tindex <shepherd-command>
- Currently, clients may only send @dfn{commands}, represented by the
- @code{<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
- @code{shepherd-command}:
- @deffn {procedure} shepherd-command @var{action} @var{service} @
- [#:@var{arguments} '()] [#:@var{directory} (getcwd)]
- Return a new command (a @code{<shepherd-command>}) object for
- @var{action} on @var{service}.
- @end deffn
- @noindent
- Commands may then be written to or read from a communication channel
- with the following procedures:
- @deffn {procedure} write-command @var{command} @var{port}
- Write @var{command} to @var{port}.
- @end deffn
- @deffn {procedure} read-command @var{port}
- Receive a command from @var{port} and return it.
- @end deffn
- In practice, communication with @command{shepherd} takes place over a
- Unix-domain socket, as discussed earlier (@pxref{Invoking shepherd}).
- Clients may open a connection with the procedure below.
- @deffn {procedure} open-connection [@var{file}]
- Open a connection to the daemon, using the Unix-domain socket at
- @var{file}, and return the socket.
- When @var{file} is omitted, the default socket is used.
- @end deffn
- @cindex output
- The daemon writes output to be logged or passed to the
- currently-connected client using @code{local-output}:
- @deffn {procedure} local-output format-string . args
- This procedure should be used for all output operations in the Shepherd. It
- outputs the @var{args} according to the @var{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.
- @end deffn
- @cindex protocol, between @command{shepherd} and its clients
- Under the hood, @code{write-command} and @code{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 @command{herd}. For instance,
- when you type @command{herd status}, what is sent over the wire is the
- following sexp:
- @lisp
- (shepherd-command
- (version 0)
- (action status) (service root)
- (arguments ()) (directory "/data/src/dmd"))
- @end lisp
- The reply is also an sexp, along these lines:
- @lisp
- (reply (version 0)
- (result (((service @dots{}) @dots{})))
- (error #f) (messages ()))
- @end lisp
- This reply indicates that the @code{status} action was successful,
- because @code{error} is @code{#f}, and gives a list of sexps denoting
- the status of services as its @code{result}. The @code{messages} field
- is a possibly-empty list of strings meant to be displayed as is to the
- user.
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Others
- @section Others
- @cindex hashes
- @deffn {procedure} copy-hashq-table table new-size
- Create a hash-table with size @var{new-size}, and insert all values
- from @var{table} into it, using @code{eq?} when inserting. This
- procedure is mainly used internally, but is a generally useful
- utillity, so it can by used by everyone.
- @end deffn
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Internals
- @chapter Internals
- This chapter contains information about the design and the
- implementation details of the Shepherd for people who want to hack it.
- The GNU@tie{}Shepherd is developed by a group of people in connection
- with @uref{https://www.gnu.org/software/guix/, Guix System}, 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
- @email{bug-guix@@gnu.org} and send patches or suggestions to
- @email{guix-devel@@gnu.org}.
- @menu
- * Coding standards:: How to properly hack the Shepherd.
- * Design decisions:: Why the Shepherd is what it is.
- * Service Internals:: How services actually work.
- @end menu
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Coding standards
- @section 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. @xref{Coding
- Style,,, guix, GNU Guix Reference Manual}, for more info.
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Design decisions
- @section Design decisions
- @quotation Note
- This section was written by Wolfgang Jährling back in 2003 and documents
- the original design of what was then known as GNU@tie{}dmd. The main
- ideas remain valid but some implementation details and goals have
- changed.
- @end quotation
- 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 @emph{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, @code{init} will not know about it, and use the runlevel
- configuration as its source of information, opening the door for
- inconsistencies (which fortunately 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
- improperly 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. Fortunately, 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 separate 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, @emph{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:
- @itemize @bullet
- @item
- 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.
- @item
- 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
- @emph{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.
- @item
- 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:
- @item
- 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).
- @end itemize
- 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 @emph{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@dots{}
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Service Internals
- @section Service Internals
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node GNU Free Documentation License
- @appendix GNU Free Documentation License
- @include fdl-1.3.texi
- @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @node Concept Index
- @unnumbered Concept Index
- @printindex cp
- @node Procedure and Macro Index
- @unnumbered Procedure and Macro Index
- @printindex fn
- @node Variable Index
- @unnumbered Variable Index
- @printindex vr
- @node Type Index
- @unnumbered Type Index
- @printindex tp
- @bye
|