ANOPA(1)

NAME
anopa - init system/service manager build around s6 supervision suite

DESCRIPTION
anopa is an collection of tools and scripts aimed to provide an init system and service manager for Linux systems, based around the s6 supervision suite[1].

It provides some execline[2] scripts that can be used as init for different stage of the boot process, leaving stage 2 to be handled by s6-svscan, as well as tools that can be used to create a runtime repository of servicedirs, start/stop them and other related functions.

WHAT DOES INIT (PID 1) DO ?
Paraphrasing s6's author, Laurent Bercot, there are really three stages for the init process of a Unix system :

Stage 1: Booting up phase
Stage 2: Supervision phase
Stage 3: Shutting down phase

Stage 1 starts when the kernel launches the first userland process, traditionally called init. The goal is to prepare the system: mounting file systems, setting system clock, configuring the network, and other similar tasks are to be performed, to be ready to start long-running processes, that will be expected to stay running for as long as the system is up.

Stage 2 starts with the launch of all long-running processes (getty-s, ssh server, etc) and continues - as you're using the system - with supervising said processes, making sure they stay up, and restarting them should they not. init's job here also includes reaping any orphaned zombies.

Stage 3 starts when a shutdown (or reboot) is initiated. init then needs to "undo" what was done prior: stop all long-running processes, clean up, unmount file systems, etc

s6-svscan is perfectly suited to be in charge of stage 2, supervising long-running processes. anopa provides tools to take care of the other stages.

Because the init process launched by the kernel, also known as PID 1, cannot die and has to be the one process to exist from start to finish, lots of init system include all functionalities into a single binary. Instead, since PID 1 is allowed to execute into another binary, this is what anopa makes uses of.

NOTION OF SERVICES
s6 works with services, defined under what's called a service directory, or servicedir. Since it is build around it, anopa uses the same principle; However, a service from anopa's point-of-view can either be one-shot, i.e. a process to start on boot (during stage 1) and that's it (possibly with a counter-part one to be run on shutdown, during stage 3), or a long-run, i.e. a process to be started during phase 2, and to stay up until stage 3 is initiated.

Therefore, you can have two kinds of services, and servicedir: one-shot, and long-run. A servicedir is simply a directory, in which the definition of the service is held.

Long-run services requires a file run to be present, which will be the long-running process launched & supervised (or, more likely, is a small script executing into said process). Therefore, the rule is that if a servicedir contains a file run it is of a long-run service, else of a one-shot one.

  LONG-RUN SERVICES
Long-run services will be launched & supervised by s6-svscan, therefore you should refer to its official documentation[3] when it comes to that, but such servicedirs contain:

An executable file named run
    It can be any executable file (binary or script), but usually will be a small script containing the command setting up the services, before executing into it.

An optional executable file named finish
    Like run, it can be any executable file. If present, it is executed every time the run script dies. Generally, its main purpose is to clean up non-volatile data such as the file system after the supervised process has been killed.

    Note that it must do its work and exit in less than 5 seconds, else it'll be killed.

An optional, empty, regular file named nosetsid
    If such a file exists, s6-supervise will not make the service a process group and session leader; the service will be run in the same process group as s6-supervise. If no nosetsid file exists, the service has its own process group and is started as a session leader.

An optional service directory named log
    If it exists then two services will be monitored: the actual service (./run) as well as its logger (./log/run). A pipe is open and maintained between the two, i.e. everything that ./run writes to its stdout will appear on ./log/run's stdin. The service is said to be logged; the log service is called the service's logger.

    See aa-enable(1) for how you can use a file instead, to automatically use the same logger for all services.

    Note that by default, aa-status(1) only list oneshots & longruns, excluding such loggers. Refer to its option --filter to include/list them.

An optional regular file named notification-fd
    If such a file exists, it means that the service supports readiness notification. The file must only contain an unsigned integer, which is the number of the file descriptor that the service writes its readiness notification to, as per s6-supervise requirements.

    This is used by aa-start(1) to determine whether to wait for event 'U' instead of 'u' when starting the service.

An optional, empty, regular file named gets-ready
    This is anopa-specific, and if present indicates to aa-start(1) that the service supports readiness, so it will wait for event 'U' (instead of 'u') when starting it.

    This can be used for services that support readiness outside of the notification-fd file interface (e.g. via aa-setready(1) triggered on a log event).

An optional regular file named timeout
    If such a file exists, it should contain the number of seconds before the service is considered to be in time out; i.e. aa-start(1)/aa-stop(1) will stop waiting for them.

For completeness, the following "internals" are also supported.

A directory named supervise
    It is automatically created by s6-supervise if it does not exist. This is where s6-supervise stores its information. The directory must be writable. It is automatically created by aa-enable(1) with permissions 0711, to allow reading the status file as a user.

A fifodir named event
    It is automatically created by s6-supervise if it does not exist. This is used to send notifications when the service goes up/down.

An optional, empty, regular file named down
    If such a file exists, the default state of the service is considered down, not up, and it isn't automatically started by s6-supervise. It is automatically created by aa-enable(1), except for the service specified with --skip-down.

  ONE-SHOT SERVICES
One-shot services are simply binaries that will be executed by aa-start(1) or aa-stop(1). Such servicedirs contain:

An optional executable file named start
    It can be any executable file (binary or script), that will be executed by aa-start when starting the service. It if exits with 0 the service will be considered started, else failed. If no such file exists, the service will be considered started instantly.

An optional executable file named stop
    It can be any executable file (binary or script), that will be executed by aa-stop when stopping the service. It if exits with 0 the service will be considered stopped, else stopped-failed. If no such file exists, the service will be considered stopped instantly.

An optional, empty, regular file named essential
    If present and the service fails to be started, when it exits aa-start will return 1. It will only return 0 if no essential services failed to be started. This can be used by init, e.g. to launch an emergency shell if aa-start end successfully (return non-zero).

    You would usually use such a file for the service mounting the root filesystem in initramfs, or launching getty.

An optional regular file timeout
    If such a file exists, it should contain the number of seconds before the service is considered to be in time out; i.e. aa-start(1)/aa-stop(1) will stop waiting for them, killing the process. See aa-start(1) for more.

Note that a one-shot service can have only a start script, only a stop script, both, or none. In the later case, it can be used simply to order things.

For example, you could use a service sysinit, making sure all very early services (e.g. mounting file systems or setting up console) are started before it, and starting everything else after it.

(Similarly, it would get everything stopped before those services are stopped, obviously.)

  SERVICE DEPENDENCIES
Common to long-run and one-shot services, therefore supported in both types of servicedirs, are the notion of dependencies and ordering introduced by anopa.

The idea is that on boot, all long-run servicedirs will actually contain an empty file down so that they aren't automatically started by s6-svscan. Instead, aa-start(1) will be used to start everything (during stage 2), both one-shot and long-run services; It will also be used by aa-stop(1) to order stopping.

(If you create your runtime service repository using aa-enable(1) this is done automatically.)

Four additional directories can be found inside servicedirs, used by aa-start(1) and aa-stop(1) to determine when to start/stop what.

An optional directory named needs
    This directory can contain empty regular files, whose name is the name of a service to be marked as dependency of the current service. Such services will be auto-started by aa-start(1) and the current service will automatically be marked to be started after it.

    Additionally, should the dependency service fail to start, the current service will not be started, but placed into a failed state (for dependency error).

    aa-stop(1) will process those as if they were in directory after.

An optional directory named wants
    This directory can contain empty regular files, whose name is the name of a service to be auto-started by aa-start(1). This is not a dependency, and there's no ordering associated either.

    This is ignored by aa-stop(1).

An optional directory named after
    This directory can contain empty regular files. The current service will only be started after those services have been started by aa-start(1); And the other way around for aa-stop(1), i.e. those services will be stopped after the current service has been (or, the current service before them).

    It is important to note that this is only an ordering directive, i.e. if the service isn't actually being started, then the directive is simply ignored. And if it is, but fails to start, the current service will still be started regardless.

An optional directory named before
    This directory can contain empty regular files. If those services are being started, then they'll only be started after the current service by aa-start(1); And the other way around for aa-stop(1), i.e. the current service will be stopped after they have been.

    It is important to note that this is only an ordering directive, i.e. if the service isn't being started then it is simply ignored. And if it is, but the current service fails to start, it will still be started regardless.

It should also be noted that a long-run service will be considered started once the event 'u' is received; Should the service actually fail right after will have no consequences on the rest of the aa-start(1) process.

Dependencies and Loggers

Loggers (*/log services) are special in that they're not in the repodir/scandir directly, and also not listed by aa-status(1) by default (See its --filter for more).

However, they're not ignored by anopa, and every longrun service with a logger will automatically have a dependency ("needs") on its logger. This means that e.g. to start foobar, foobar/log will first be started, as expected.

They can also contain user-defined dependencies, exactly as with any other services. It is not, however, possible to add a dependency onto such a logger (due to the slash in its name).

SERVICE REPOSITORY (AND SCANDIR)
s6-svscan will supervise all services found in its scandir. Obviously, because it has no notion of one-shot services, only servicedir for long-run services should be found there.

The way this works in anopa is to use aa-enable(1) to create the service repository, as well as the scandir. This is done by using source directories, and optionally merging in configuration directories. The idea is that you will not create your service repository manually, but instead using aa-enable(1) from pre-established definitions.

The service repository will contain all (enabled) servicedirs, both one-shots and long-runs. For long-run servicedirs, symlinks will be put into directory .scandir which will be used by s6-svscan as its scandir.

A typical organization would work like the following :

/usr/lib/services
    Source directory containing available servicedirs. This is where servicedirs from packages would be installed. Used by aa-enable(1).

/etc/anopa/services
    Source directory containing available servicedirs. This is where the administrator can define its own servicedirs, either because they're not provided by packages, or to be used instead. Used by aa-enable(1).

/etc/anopa/enabled
    List directory containing either empty regular files, whose name is the name of a service to enable on boot, or directories, whose name is the name of a service to enable on boot.

    In the later case, the content of the folder will also be merged/copied over into the servicedir.

    Used by aa-enable(1) from aa-stage1(1).

/etc/anopa/listdirs/onboot
    List directory containing empty regular files, whose name is the name of a service to start on boot. Used by aa-start(1) from aa-stage2(1).

/run/services
    Runtime repository, the service repository for the current system, containing a directory .scandir, with symlinks for all long-run services, used by s6-svscan as its scandir. Used by aa-enable(1), aa-start(1) and aa-stop(1).

On boot, aa-enable(1) is used to create the runtime repository. To do so, it reads the content of the listdir, and for each service named there copies the corresponding servicedir from a source directory into the runtime repository. If listdir contained a directory, its content is then merged/copied over into the newlu created servicedir, allowing easy custom service-specific configuration.

Source directories are looked up in order, thus allowing the administrator to provide not only its own servicedirs, but its own version of a given servicedir.

Refer to aa-enable(1) for more on how it works and how the copy operation takes place.

Then, aa-start(1) is used to start all services in order, getting the system up & ready. Refer to aa-start(1) for more on how it works; Refer to aa-stage1(1) and aa-stage2(1) for more on this init process on boot works.

You can also see aa-stage0(1) and aa-stage4(1) for how to use anopa in your initramfs.

Note that this is of course only a possible solution to set up your system, you are of course free to organize things differently, using only the tool(s) you need from anopa however you wish.

LINKS

[1] s6 supervision suite
    <http://skarnet.org/software/s6/>

[2] execline
    <http://skarnet.org/software/execline/>

[3] s6 service directories
    <http://skarnet.org/software/s6/servicedir.html>

BUGS
They're probably crawling somewhere in there... if you happen to catch one, (or more) report it and I'll do my best to squash it.

REPOSITORY
You can find the latest source code of anopa as well as report bugs and/or suggest features on its GitHub repository, available at <https://github.com/jjk-jacky/anopa>; or visit its official website at <https://jjacky.com/anopa>

AUTHOR

Olivier Brunel <jjk@jjacky.com>