Table of Contents

Currently viewing version: 0.8.1.1

The frontend service file

The s6 programs use different files. It is quite complex to understand and manage the relationship between all those files. If you're interested in the details you should read the documentation for the s6 servicedir and also about classic and module services. The frontend service file of 66 program allows you to deal with all these different services in a centralized manner and in one single location.

By default 66 program expects to find service files in /usr/share/66/service and /etc/66/service for root user, /usr/share/66/service/user and /etc/66/service/user for regular accounts. For regular accounts, $HOME/.66/service will take priority over the previous ones. Although this can be changed at compile time by passing the --with-system-service=DIR, --with-sysadmin-service=DIR and --with-user-service=DIR option to ./configure.

The frontend service file has a format of INI with a specific syntax on the key field. The name of the file usually corresponds to the name of the daemon and does not have any extension or prefix.

The file is made of sections which can contain one or more key = value pairs where the key name can contain special characters like - (hyphen) or _ (low line) except the character @ (commercial at) which is reserved.

You can find a prototype with all valid section and all valid key=value pair at the end of this document.

File names examples

/usr/share/66/service/dhcpcd
/usr/share/66/service/very_long_name_which_make_no_sense

File content example

[Main]
Type = classic
Description = "ntpd daemon"
Version = 0.1.0
User = ( root )

[Start]
Execute = (
    foreground { mkdir -p  -m 0755 ${RUNDIR} }
    execl-cmdline -s { ntpd ${CMD_ARGS} }
)

[Environment]
RUNDIR=!/run/openntpd
CMD_ARGS=!-d -s

The parser will not accept an empty value. If a key is set then the value can not be empty. Comments are allowed using the number sign #. Empty lines are also allowed.

Key names are case sensitive and can not be modified. Most names should be specific enough to avoid confusion.

Sections

All sections need to be declared with the name written between square brackets [] and must begins with a uppercase followed by lowercase letters only. This means that special characters and numbers are not allowed in the name of a section.

The [Main] section must be declared first.

The frontend service file allows the following section names:

Although a section can be mandatory not all of its key fields must be necessarily so.

Syntax legend

The value of a key is parsed in a specific format depending on the key. The following is a break down of how to write these syntaxes.

inline

An inline value. Must be on the same line with its corresponding key.

A value between double-quotes. Must be on the same line with its corresponding key.

brackets

Multiple values between parentheses (). Values need to be separated with a space. A line break can be used instead.

uint

A positive whole number. Must be on the same line with its corresponding key.

path

An absolute path beginning with a forward slash /. Must be on the same line with its corresponding key.

pair

Same as inline.

colon

A value between double colons followed by a pair syntax. Must be one by line.

simple-colon

A values separated by a colon. Must be on the same line with its corresponding key.

Section [Main]

This section is mandatory. (!)

Type

Source Snippet:

Type = classic

Defines the service type. Determines how 66 orchestrates startup and supervision.

Version

Source Snippet:

Version = 0.1.0

Specifies the semantic version of the service, following major.minor.patch format. This helps track updates and compatibility.

Description

Source Snippet:

Description = "ntpd daemon"

Provides a concise, human-readable summary of the service’s purpose. Enclosed in double quotes.

User

Source Snippet:

User = ( root )

Lists the system user(s) permitted to manage and run the service. By default, only specified users can start, stop, or interact with the service.

Depends

Source Snippet:

Depends = ( fooA fooB fooC )

Declares the mandatory service dependencies. Each listed service must start successfully before this service launches.

RequiredBy

Source Snippet:

RequiredBy = ( fooX fooY )

Specifies reverse dependencies—services that depend on this service. Starting or enabling this service automatically updates those listed.

OptsDepends

Source Snippet:

OptsDepends = ( fooA fooB )

Lists optional dependencies. 66 will enable the first available service from this list at startup.

Options

Source Snippet:

Options = (log)

Configures optional behaviors for the service. Wrap options in parentheses for multiple entries.

Flags

Source Snippet:

Flags = (down earlier)

Notify

Source Snippet:

Notify = 3

Enables readiness notification. Creates notification-fd containing the specified file descriptor number.

TimeoutStop

Source Snippet:

TimeoutStop = 5000

Specifies the maximum time (ms) to wait for the stop script (finish) to complete before forcibly killing it.

TimeoutStart

Source Snippet:

TimeoutStart = 2000
Defines the grace period (ms) after SIGTERM before sending SIGKILL on stop commands.

MaxDeath

Source Snippet:

MaxDeath = 10

Limits the number of recorded service crashes. Exceeding this resets the oldest record when tallying failures.

DownSignal

Source Snippet:

DownSignal = SIGTERM

Specifies which signal to send when stopping or reloading the service.

CopyFrom

Source Snippet:

CopyFrom = (./config /etc/default/service)

Verbatim copy directories and files on the fly to the main service destination. When dealing with directories, it copies all found files and directories recursively. In case of file, it copy it to the root of the service directory.

InTree

Source Snippet:

InTree = my-tree

Automatically activate the service within a named service tree. If a corresponding seed file exists, it will be applied.

StdIn

Source Snippet:

StdIn = null

Controls standard I/O redirection for the standard input entries.

StdOut

Source Snippet:

StdOut = s6log

Controls standard I/O redirection for the standard output entries.

StdErr

Source Snippet:

StdErr = inherit

Controls standard I/O redirection for the standard error entries.

Provide

Source Snippet:

Provide = ( network networking )

Defines one or more service aliases—alternate names under which this service can be referenced. These aliases behave like symbolic links, allowing the same service to be managed with different identifiers.

Section [Start]

This section is mandatory. (!)

Build

Source Snippet:

Build = auto

Determines how the service script is generated from the Execute field.

RunAs

Source Snippet:

RunAs = oblive
Drops privileges to the specified user or UID:GID before executing the service.

Execute

Source Snippet:

Execute = ( /usr/bin/auditd -f )
Defines the command(s) executed to start the service. Enclose multiple lines in brackets.

Section [Stop]

This section is optional.

This section is exactly the same as Start and shares the same keys. With the exception that it will handle the stop process of the service.

Section [Logger]

This section is optional and controls the behavior of the default logging system used by 66, which utilizes the excellent s6-log program.

It will only have effects if value log was not prefixed by an exclamation mark to the Options key in the Main section. Additionally, the StdIn or StdOut keys from the Main must be set to s6log, or these keys must not be defined at all.

This section extends the Build, RunAs, and Execute key fields from Start and the TimeoutStop and TimeoutStart key fields from Main . These are also valid keys for Logger and behave the same way they do in the other sections but they can not be specified except for the mandatory key Build—see example below. In such case the default behaviour for those key are apply.

Furthermore there are some keys specific to the log.

The following key names are also valid:

Backup

Source Snippet:

Backup = 3
Number of rotated log files to retain before overwriting the oldest.

MaxSize

Source Snippet:

MaxSize = 1000000
Byte threshold to trigger log rotation when the current file grows too large.

Timestamp

Source Snippet:

Timestamp = iso

Specifies timestamp format prefixed to each log entry.

Section [Environment]

This section is optional.

A file containing the key=value pair(s) will be created by default at /etc/66/conf/name_of_service directory. The default can also be changed at compile-time by passing the --with-sysadmin-service-conf=DIR option to ./configure.

Any key=value pair

Source Snippet:

DirRun=/run/openntpd

ImportFile

Source Snippet:

ImportFile=/etc/66/init.conf

The ImportFile variable is recognized by 66 and treated as a key=value pair, similar to other environment variables. However, ImportFile itself is not exported to the environment.

The target file must adhere to the environment definition syntax specified in the file syntax guidelines.

Section [Regex]

This section is optional.

It will only have an effect when the service is a module type—see the section Module service creation.

identifier are replaced before applying the regex section.

Configure

Source Snippet:

Configure = "--enable-feature"

Arguments passed to the module’s configure script.

Directories

Source Snippet:

Directories = ( DM=sddm )

Regex-based renaming rules for module subdirectories. Each entry is regex=replacement.

Files

Source Snippet:

Directories = ( servicename=newname )

Regex-based renaming rules for files. Each entry is regex=replacement.

InFiles

Source Snippet:

InFiles = ( :mount-tmp:args=-o noexec )

In-file regex replacements for module files. Use :filename:regex=replacement or ::regex=replacement for all files.

A word about the Execute key

As described above the Execute key can be written in any language as long as you define the key Build as custom. For example if you want to write your Execute field with bash:

Build = custom
Execute = (#!/usr/bin/bash
echo "This script displays available services"
for i in $(ls /usr/share/66/service); do
    echo "daemon : ${i} is available"
done
)

This is an unnecessary example but it shows how to construct this use case. The resulting file will be :

#!/usr/bin/bash
echo "This script displays available services"
for i in $(ls /usr/share/66/service); do
    echo "daemon : ${i} is available"
done

The parser duplicates exactly what appears between ( and ), preserving all characters as they are. However, it removes any carriage return (\r), tab (\t), space, or newline (\n) located between the opening parenthesis and the # of the shebang declaration. No other characters are permitted in this span. For instance, if you write

Execute = (

    #!/bin/bash
    echo hello world!
)

the final result will be

#!/bin/bash
    echo hello world!

ensuring that the very first line of the script is the declaration of the shebang to avoid an Exec format error.

Note that with Build=custom, variables will not be replaced by their corresponding environment values within the script, unlike the behavior with the execlineb script format.

identifier is still also interpreted even in custom script.

This same behavior applies to the Logger section. Also, The fields Backup, MaxSize and Timestamp will have no effect in a custom case. You need to explicitly define the program to use the logger and the options for it in your Execute field.

Prototype of a frontend file

The minimal template is e.g.:

[Main]
Type = classic
Version = 0.0.1
Description = "Template example"
User = ( root )

[Start]
Execute = ( /usr/bin/true )

This prototype contain all valid section with all valid key=value pair.

[Main]
Type =
Description = ""
Version =
Depends = ()
RequiredBy = ()
OptsDepends = ()
Options = ()
Flags = ()
Notify =
User = ()
TimeoutStart =
TimeoutStop =
MaxDeath =
DownSignal =
CopyFrom = ()
InTree =
StdIn =
StdOut =
StdErr =
Provide = ()

[Start]
Build =
RunAs =
Execute = ()

[Stop]
Build =
RunAs =
Execute = ()

[Logger]
Build =
RunAs =
Destination =
Backup =
MaxSize =
Timestamp =
TimeoutStart =
TimeoutStop =
Execute = ()

[Environment]
ImportFile=/path/to/file
mykey=myvalue
ANOTHERKEY=!antohervalue

[Regex]
Configure = ""
Directories = ()
Files = ()
InFiles = ()