Table of Contents

Currently viewing version: 0.8.0.0

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 %%service_adm/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=DIRoption 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.

The [Main] section must be declared first.

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 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.


quotes

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. (!)

Valid key names:


Section [Start]

This section is mandatory. (!)

Valid key names:


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.

Valid key names:


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.

Valid key names:


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.

You can use the @I string as key field. It will be replaced by the module name as you do for instantiated service before applying the regex section.

Valid key names:


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 creates an exact copy of what it finds between ( and ). This means that regardless of the character found, it retains it. For instance, if you write

    Execute = (
    #!/bin/bash echo hello world!
    )
the final result will contain a newline at the very beginning corresponding to the newline found between ( and the definition of the shebang #!/bin/bash. In this case, when executing the service, you'll encounter an Exec format error because the very first line corresponds to a newline instead of the shebang declaration.

To avoid this issue, ALWAYS declare the shebang of your script directly after ( and without any spaces, tabs, newlines, etc. For example,

    Execute = (#!/bin/bash
    echo hello world!
    )

When using this sort of custom function RunAs has no effect. You must define with care what you want to happen in a custom case.

Furthermore when you set Build to auto the parser will take care about the redirection of the ouput of the service when the logger is activated. When setting Build to custom though the parser will not do this automatically. You need to explicitly tell it to:

    #!/usr/bin/bash
    exec 2>&1
    echo "This script redirects file descriptor 2 to the file descriptor 1"
    echo "Then the logger reads the file descriptor 1 and you have"
    echo "the error of the daemon written into the appropriate file"

Finally you need to take care about how you define your environment variable in the section Environment. When setting Build to auto the parser will also take care about the ! character if you use it. This character will have no effect in the case of custom.

This same behavior applies to the Logger section. The fields Destination, 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 =

    [Start]
    Build =
    RunAs =
    Execute = ()

    [Stop]
    Build =
    RunAs =
    Execute = ()

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

    [Environment]
    mykey=myvalue
    ANOTHERKEY=!antohervalue

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