=head1 NAME

aa-start - Start services

=head1 SYNOPSIS

B<aa-start> [B<-D>] [B<-r> I<repodir>] [B<-l> I<listdir>] [B<-W>]
[B<-t> I<timeout>] [B<-n>] [B<-v>] [I<service...>]

=head1 OPTIONS

=over

=item B<-D, --double-output>

Enable double-output mode. Instead of using stdout for regular output, and
stderr for warnings and errors, everything is sent both to stdout and stderr.
This is intended to redirect stderr to a log file, so full output can be both
shown on console and logged.

=item B<-h, --help>

Show help screen and exit.

=item B<-l, --listdir> I<dir>

Use I<dir> to list services to start. Only one can be set, if specified more
than once the last one will be used.

If I<dir> doesn't start with a slash or dot, it will be prefixed with
I</etc/anopa/listdirs/>

=item B<-n, --dry-list>

Only print the name of the services, but do not start anything.

Specify a second time to list services that need to be up instead of those that
would be started, i.e. include those already up.

=item B<-r, --repodir> I<dir>

Use I<dir> as repository directory. This is where servicedirs will be looked
for.

=item B<-t, --timeout> I<timeout>

Set default timeout to I<timeout> seconds. You can use 0 for no timeout.
Timeout can also be set in service in a file I<timeout> in its servicedir.

=item B<-V, --version>

Show version information and exit.

=item B<-v, --verbose>

Print auto-added dependencies (from "needs" and "wants"). Note that due to
recursion they'll be printed in reverse order, e.g. "B needs C" then "A needs B"
when starting A.

This will be printed on stdout unless B<--dry-list> was used, then it goes to
stderr.

=item B<-W, --no-wants>

Don't auto-start any services listed under directory I<wants> of a service
being (auto-)started.

=back

=head1 DESCRIPTION

B<aa-start>(1) allows to start one or more services. By default, any services
found in directories I<needs> or I<wants> are also auto-started, though it is
possible not to auto-start the ones from I<wants> via B<--no-wants>.

You can use B<-> as service name to read actual service names from stdin, where
there must be one name per line.

Refer to B<anopa>(1) for descriptions of servicedirs and service dependencies.

=head1 TIMEOUTS

When starting a service, a timestamp is collected. If the service fails to be
started/ready before the number of seconds specified either in a file I<timeout>
in its servicedir or using the default value (300 (5 min) by default, unless
set via B<--timeout>), the service is considered to have timed out.

For long-run services, B<aa-start>(1) will simply stop waiting for event and
mark the service as timed out.

For one-shot services, signal TERM will be sent to the process, which is then
given up to 2 seconds to react. If it exits during that time, it will be
processed as usual, with the exception that if SIGTERM is the cause the service
will then be marked as timed out (i.e. it could exit with a specified exit code,
and be then marked failed, or even return 0 and be successfully started).

If the process hasn't ended after those 2 seconds, signal KILL is sent to the
process and the service marked as timed out.

Note that using a value of 0 as time out (either via I<timeout> file or
B<--timeout> option) means it never times out, and B<aa-start>(1) will wait for
it forever; Use with caution.

=head2 Which services are we waiting for?

When waiting for a service, and if there is no other activity (i.e. no services
being started or showing messages, etc) then B<aa-start>(1) will show an
indication of the service being waited for, including how much time has elapsed
since it was started and its timeout, e.g:

    [23s/5m] foobar

Indicates that service I<foobar> is being waited for, it was started 23 seconds
ago and will timeout when reaching 5 minutes. In case more than one service is
being waited for, the "index" of the service and the number of services being
waited for will be prefixed, and it will go through all services, e.g:

    [1/2; 23s/5m] foo

for a couple of seconds, then:

    [2/2; 42s/2m30] bar

Looping through them again until some activity occurs. The service whose name is
currently being shown is called the "active" service.

=head2 Manual trigger of time out

When the name of the "active" service is shown, if B<aa-start>(1) receives
signal INT (e.g. you pressed Ctrl+C) it will then reset the service's timeout
to 1 second, effectively causing it to be processed as timed out immediately.

This could be useful if you know a service won't work and eventually time out,
and do not wish to wait until it actually gets there. This also works for
services with an infinite timeout (i.e. set to 0).

=head1 STARTING A LONG-RUN SERVICE

When starting a long-run service, B<aa-start>(1) first connects to the I<event>
fifodir of the service, then checks (with B<s6>) if the service is already up or
not. If so, it disconnects and the service is announced as already up and
process continues as expected.

If not, B<aa-start>(1) then checks whether there's a file I<gets-ready> in the
servicedir, and if not whether there is a file I<notification-fd> containing a
number. It then sends the command to bring it up and removes the I<down> file
(if present).

If there was no I<gets-ready>/valid I<notification-fd> file, it waits for event
'u' to be triggered, then (disconnects from the fifodir and) announce the
service as started. If there was one, it will then wait for event 'U' to be
triggered instead, announcing the service as ready instead. (A message will be
shown on event 'u' as information only. Note that should event 'd' occur, a
message will also be shown, but B<aa-start>(1) will still keep waiting for event
'U'.)

=head1 STARTING A ONE-SHOT SERVICE

When starting a one-shot service, if no file I<start> exists the service is
simply announced as started right away. Else, B<aa-start>(1) forks and the child
goes into the servicedir (making it its current working directory) then executes
into I<start>.

Pipes are set up, so the script's stdin (fd 0) is a pipe connected to
B<aa-start>(1), as are its stdout & stderr (fd 1 & 2), and lastly another pipe
is set up on file descriptor 3.

Any and all lines written on fd 1 and 2 will be printed on console by
B<aa-start>(1), prefixed with the service name.

This last fd can be used by the service for special cases.

=head2 Showing progress bars

A service might want to show the user a progress bar as they perform long
operations. This can be done simply by writing LF-terminated lines to fd 3
made of the following space-separated fields :

=over

=item 1. Step number

In case more than one steps will be performed, each having its own progress bar.
If only one progress bar will be used, use 0.

=item 2. Current value

The current value. This is an integer representing the current value of the
operation, from 0 to the maximum value (next field).

=item 3. Maximum value

The maximum value. Note that when the current value and the maximum value are
the same, a progress bar filled to 100% will be shown; It is only removed from
the screen once the process execution is over (or when the fd is closed).

=item 4. Description

This last field can include spaces, as it goes until the LF. It is an optional
(small) description to be added alongside the progress bar, e.g. to indicate
what is being performed.

=back

The knowledgeable reader will have noticed that this format correspond to that
used by B<fsck>(8) and its B<-C> option; This is no coincidence. To have
progress bars shown for a service performing an fsck, simply run it with `-C3`
as option.

=head2 Asking user for a password

A service might need to ask the user to input a password, e.g. to open an
encrypted device. This can also be done with a little help from our friend, in
file descriptor 3.

First, the service needs to write an LF-terminated line to its fd 3, the message
asking the user, prefixed with "< " (less than sign and a space). For example,
write "< Please enter passphrase to open /dev/sda2" (ending with a LF).

Then, simply read on stdin (fd 0) what the user inputed. B<aa-start>(1) takes
care of showing the message to the user (prefixed with the service name) and
disabling echoing input on the terminal.

It is possible to ask again for another input (e.g. if password failed) by
simply doing the same again.

Note that it is not possible to show a progress bar while asking for user input,
not that there should be a need for it anyways.

Also note that once B<aa-start>(1) received a demand of password input, it will
disable the service's timeout, restoring it once it has been processed (e.g.
user input has been written to the service's stdin) and resetting its timer.
