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.
/usr/share/66/service/dhcpcd
/usr/share/66/service/very_long_name_which_make_no_sense
[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.
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.
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.
An inline value. Must be on the same line with its corresponding key.
Valid syntax:
Type = classic
Type=classic
(!) Invalid syntax:
Type=
classic
A value between double-quotes. Must be on the same line with its corresponding key.
Valid syntax:
Description = "some awesome description"
Description="some awesome description"
(!) Invalid syntax:
Description=
"some awesome description"
Description = "line break inside a double-quote
is not allowed"
Multiple values between parentheses ()
. Values need to be separated with a space. A line break can be used instead.
Valid syntax:
Depends = ( fooA fooB fooC )
Depends=(fooA fooB fooC)
Depends=(
fooA
fooB
fooC
)
Depends=
(
fooA
fooB
fooC
)
(!) Invalid syntax:
Depends = (fooAfooBfooC)
A positive whole number. Must be on the same line with its corresponding key.
Valid syntax:
Notify = 3
Notify=3
(!) Invalid syntax:
Notify=
3
An absolute path beginning with a forward slash /
. Must be on the same line with its corresponding key.
Valid syntax:
Destination = /etc/66
Destination=/etc/66
(!) Invalid syntax:
Destination=/a/very/
long/path
Same as inline.
Valid syntax:
MYKEY = MYVALUE
anotherkey=anothervalue
anotherkey=where_value=/can_contain/equal/Character
(!) Invalid syntax:
MYKEY=
MYVALUE
A value between double colons followed by a pair syntax. Must be one by line.
Valid syntax:
::key=value
:filename:key=value
(!) Invalid syntax:
::MYKEY=
MYVALUE
::
MYKEY=MYVALUE
::key=value :filename:anotherkey=anothervalue
A values separated by a colon. Must be on the same line with its corresponding key.
Valid syntax:
RunAs = 1000:19
(!) Invalid syntax:
RunAs = 1000:
19
A value specifying a true state for the key. Must be on the same line with its corresponding key. If the key is not defined, it defaults to false
.
Valid syntax:
BlockPrivileges = true
BlockPrivileges = True
BlockPrivileges = TRUE
BlockPrivileges = 1
BlockPrivileges = false
BlockPrivileges = False
BlockPrivileges = FALSE
BlockPrivileges = 0
(!) Invalid syntax:
BlockPrivileges =
true
BlockPrivileges =
note: For code simplicity and rapidity, setting e.g. key = T
is strictly equivalent to key = True
or key = TRUE
as the parser only check the first letter of the string value.
This section is mandatory. (!)
Source Snippet:
Type = classic
Defines the service type. Determines how 66 orchestrates startup and supervision.
mandatory: yes (!)
syntax: inline
valid values :
[Regex]
section for file and directory transformations.Source Snippet:
Version = 0.1.0
Specifies the semantic version of the service. This helps track updates and compatibility. If not specified, defaults to the actual installed version of 66.
mandatory: no
syntax: inline
valid values:
Source Snippet:
Description = "ntpd daemon"
Provides a concise, human-readable summary of the service’s purpose. Enclosed in double quotes. If not specified, defaults to "
mandatory: no
syntax: quote
valid values:
Source Snippet:
User = ( root )
Specifies the system user(s) list allowed to manage and operate the service. If not defined, defaults to the current process owner's username. 66 automatically distinguishes between user services and root services based on their installation paths. By default, only the specified users can start, stop, or interact with the service
mandatory: no
syntax: brackets
valid values :
user
. In that case every user of the system will be able to deal with the service. You can also use the @U
identifier to be more specific.(!) Be aware that root
is not automatically added for a user service. If you don't declare root
in this field, you will not be able to use the service even with root
privileges.
Source Snippet:
Depends = ( fooA fooB fooC )
Declares the mandatory service dependencies. Each listed service must start successfully before this service launches.
mandatory: no
syntax: brackets
valid values:
It is unnecessary to manually define chained sets of dependencies, see 66.
A service can be commented out by placing the number sign #
at the begin of the name like this:
Depends = ( fooA #fooB fooC )
Source Snippet:
RequiredBy = ( fooX fooY )
Specifies reverse dependencies—services that depend on this service. Starting or enabling this service automatically updates those listed.
mandatory: no
syntax: brackets
valid values:
It is unnecessary to manually define chained sets of dependencies, see 66.
A service can be commented out by placing the number sign #
at the begin of the name like this:
Depends = ( fooA #fooB fooC )
Source Snippet:
OptsDepends = ( fooA fooB )
Lists optional dependencies. 66 will enable the first available service from this list at startup.
mandatory: no
syntax: brackets
valid values:
The order is important (!). The first service found will be used and the parse process of the field will be stopped. So, you can considere OptsDepends
field as: "enable one on this service or none".
A service can be commented out by placing the number sign #
at the begin of the name like this:
OptsDepends = ( fooA #fooB fooC )
Source Snippet:
Options = (log)
Configures optional behaviors for the service. Wrap options in parentheses for multiple entries.
mandatory: no
syntax: brackets
valid values:
log : automatically create a logger for the service. This is default. The logger will be created even if this options is not specified. If you want to avoid the creation of the logger, prefix the options with an exclamation mark:
Options = ( !log )
The behavior of the logger can be configured in the corresponding section—see Logger.
Source Snippet:
Flags = (down earlier)
mandatory: no
syntax: brackets
valid values:
Source Snippet:
Notify = 3
Enables readiness notification. Creates notification-fd
containing the specified file descriptor number.
mandatory: no
syntax: uint
valid values:
This will create the file notification-fd. Once this file is created the service supports readiness notification. The value equals the number of the file descriptor that the service writes its readiness notification to. (For instance, it should be 1 if the daemon is s6-ipcserverd run with the -1 option.) When the service reseive signal and this file is present containing a valid descriptor number, 66 command will wait for the notification from the service and broadcast its readiness.
Source Snippet:
TimeoutStop = 5000
Specifies the maximum time (ms) to wait for the stop script (finish
) to complete before forcibly killing it.
mandatory: no
syntax: uint
valid values:
This will create the file timeout-finish. Once this file is created the value will equal the number of milliseconds after which the ./finish script—if it exists—will be killed with a SIGKILL
. The default is 0
allowing finish scripts to run forever.
Source Snippet:
TimeoutStart = 2000
Defines the grace period (ms) after SIGTERM before sending SIGKILL on stop commands.
mandatory: no
syntax: uint
valid values:
This will create the file timeout-kill. Once this file is created and the value is not 0
, then on reception of a stop command—which sends a SIGTERM
and a SIGCONT
to the service — a timeout of value in milliseconds is set. If the service is still not dead, after value in milliseconds, it will receive a SIGKILL
. If the file does not exist, or contains 0
, or an invalid value, then the service is never forcibly killed.
Source Snippet:
MaxDeath = 10
Limits the number of recorded service crashes. Exceeding this resets the oldest record when tallying failures.
mandatory: no
syntax: uint
valid value:
This will create the file max-death-tally. Once this file was created the value will equal the maximum number of service death events that the supervisor will keep track of. If the service dies more than this number of times, the oldest event will be forgotten and the transition (start or stop) will be declared as failed. Tracking death events is useful, for example, when throttling service restarts. The value cannot be greater than 4096. Without this file a default of 10 is used.
Source Snippet:
DownSignal = SIGTERM
Specifies which signal to send when stopping or reloading the service.
mandatory: no
syntax: uint
valid value:
This will create the file down-signal which is used to kill the supervised process when a reload, restart or stop command is used. If the file does not exist SIGTERM
will be used by default.
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.
mandatory: no
valid values:
Any files or directories. It accepts absolute or relative path.
CopyFrom = ( data
./.env
/etc/resolv.conf)
Note: 66
version must be higher than 0.3.0.1.
Source Snippet:
InTree = my-tree
Automatically activate the service within a named service tree. If a corresponding seed file exists, it will be applied.
mandatory: no
syntax: inline
valid values :
The service will automatically be activated at the tree name set in the InTree key value.
Note: If a corresponding seed file exist on your system, its will be used to create and configure the tree.
Source Snippet:
StdIn = null
Controls standard I/O redirection for the standard input entries.
mandatory: no
syntax: inline,simple-colon
valid values:
/dev/null
s6-supervise
program.Please see Standard IO redirection documentation for further information.
Source Snippet:
StdOut = s6log
Controls standard I/O redirection for the standard output entries.
mandatory: no
syntax: inline,simple-colon
valid values:
0755
permissions and the file will be set with 0666
permissions.s6-log
program. This is the default./dev/log
socket./dev/null
.s6-supervise
program.Please see Standard IO redirection documentation for further information.
Source Snippet:
StdErr = inherit
Controls standard I/O redirection for the standard error entries.
mandatory: no
syntax: inline,simple-colon
valid values:
0755
as permissions and the file is set with 0666
as permissions./dev/log
socket./dev/null
.s6-supervise
program.Please see Standard IO redirection documentation for further information.
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 name.
mandatory: no
syntax: brackets
valid values:
Source Snippet:
Conflict = ( connmand networkmanager )
Defines one or more services that cannot run or be enabled simultaneously with this service. If a conflicting service is running, attempts to start this service will fail. Similarly, if a conflicting service is enabled, attempts to enable this service will be rejected.
mandatory: no
syntax: brackets
valid values:
This section is mandatory. (!)
Source Snippet:
Build = auto
Determines how the service script is generated from the Execute
field.
mandatory: no
syntax: inline
valid value:
auto : creates a service script by copying the Execute
field verbatim and prepending an execline shebang to the beginning of the script. This is the default.
custom : Creates a service script by copying the Execute
field verbatim and applying the specified shebang to execute the script. Do not forget to set the shebang at Execute
key field.
Source Snippet:
RunAs = oblive
Drops privileges to the specified user or UID:GID before executing the service.
mandatory: no
syntax: inline,simple-colon
valid value:
Any valid user name set on the system or valid uid:gid number.
RunAs = oblive
RunAs = 1000:19
# if uid is not specified,
# the uid of the owner of the process
# is pick by default
RunAs = :19
# if gid is not specified,
# the gid of the owner of the process
# is pick by default
RunAs = 1000:
This will pass the privileges of the service to the given user before starting the run script of the service.
Note: (!) The service needs to be first started with root if you want to hand over priviliges to a user. Only root can pass on privileges. This field has no effect for other use cases.
Source Snippet:
Execute = ( /usr/bin/auditd -f )
Defines the command(s) executed to start the service. Enclose multiple lines in brackets.
mandatory: yes (!)
syntax: brackets
valid value:
Note: The field will be used as is. No changes will be applied at all except in custom
case(see A word about the execute key). It's the responsability of the author to make sure that the content of this field is correct.
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.
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:
Source Snippet:
Backup = 3
Number of rotated log files to retain before overwriting the oldest.
mandatory: no
syntax: uint
valid value:
Any valid number.
The log directory will keep value files. The next log to be saved will replace the oldest file present. By default 3
files are kept.
Source Snippet:
MaxSize = 1000000
Byte threshold to trigger log rotation when the current file grows too large.
mandatory: no
syntax: uint
valid value:
Any valid number.
A new log file will be created every time the current one approaches value bytes. By default, filesize is 1000000
; it cannot be set lower than 4096
or higher than 268435455
.
Source Snippet:
Timestamp = iso
Specifies timestamp format prefixed to each log entry.
mandatory: no
syntax: inline
valid value:
tai
The logged line will be preceded by a TAI64N timestamp (and a space) before being processed by the next action directive.
iso
The selected line will be preceded by a ISO 8601 timestamp for combined date and time representing local time according to the systems timezone, with a space (not a T
) between the date and the time and two spaces after the time, before being processed by the next action directive.
none
The logged line will not be preceded by any timestamp.
The following are two possible examples for the Logger section definition.
[Logger]
RunAs = user
TimeoutStop = 10000
Backup = 10
Timestamp = iso
[Logger]
Backup = 10
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
.
key=value
pairSource Snippet:
DirRun=/run/openntpd
mandatory: no
syntax: pair
valid value:
You can define any variables that you want to add to the environment of the service. For example:
[Environment]
dir_run=/run/openntpd
cmd_args=-d -s
The !
character can precede the value. Ensure no space exists between the exclamation mark and the value. This action explicitly avoids setting the value of the key for the runtime process but only applies it at the start of the service. For intance, the following valid example unset the key=value
pair dir_run=!/run/openntpd
from the general environment variables of the service.
the following syntax is valid
[Environment]
dir_run=!/run/openntpd
cmd_args = !-d -s
where this one is not
[Environment]
dir_run=! /run/openntpd
cmd_args = ! -d -s
Refers to execl-envfile for futhers information.
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.
mandatory: no
syntax: path
valid value:
Any valid absolute file path can be specified. The ImportFile
variable can be defined multiple times. For example:
[Environment]
dir_run=/run/openntpd
ImportFile=/etc/66/init.conf
The !
character has no effect on ImportFile
.
ImportFile
processing occurs at the end of the environment setup. If a key is defined both in the [Environment]
section and in a file specified by ImportFile
, the value from the ImportFile
takes precedence.
For multiple ImportFile
declarations, the last declared file takes precedence for any duplicate keys found across the specified files.
identifier is still also interpreted. For example:
[Environment]
dir_run=/run/openntpd
ImportFile=/etc/66/init.conf
ImportFile=@H/.66/environment/my.conf
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.
Source Snippet:
Configure = "--enable-feature"
Arguments passed to the module’s configure
script.
mandatory: no
syntax: quotes
valid value:
Source Snippet:
Directories = ( DM=sddm )
Regex-based renaming rules for module subdirectories. Each entry is regex=replacement
.
mandatory: no
valid value:
Any key=value
pair where key is the regex to search on the directory name and value the replacement of that regex. For example:
Directories = ( DM=sddm TRACKER=consolekit )
Where the module directory contains two sub-directories named use-DM and by-TRACKER directories. It will be renamed as use-sddm and by-consolekit respectively.
Source Snippet:
Directories = ( servicename=newname )
Regex-based renaming rules for files. Each entry is regex=replacement
.
mandatory: no
valid value:
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.
mandatory: no
valid value:
Any valid filename between the double colon with any key=value
pair where key is the regex to search inside the file and value the replacement of that regex. The double colon must be present but the name between it can be omitted. In that case, the key=value
pair will apply to all files contained on the module directories and to all keys (regex) found inside the same file.For example:
InFiles = ( :mount-tmp:args=-o noexec
::user=@I )
@I
by the name of the module.This section is optional.
This section configures tasks executed just before calling exec
for the service’s start and stop processes.
Resource limits (e.g., LimitNICE
, LimitAS
) sets soft (rlim_cur) and hard (rlim_max) limits by retrieving current limits with getrlimit()
, adjusting the hard limit for root-owned services if needed, capping the soft limit to the hard limit for non-root services, and applying the new limits with setrlimit()
. If a limit is zero, no changes are made.
All LimitXXX keys accept the value unlimited
to set the corresponding RLIMIT_*
resource to RLIM_INFINITY
, allowing unrestricted use of that resource. For unprivileged services (non-root users), unlimited
or values exceeding the current hard limit (rlim_max
) are capped at rlim_max
to prevent errors. Setting unlimited
or raising limits beyond rlim_max
requires root privileges or CAP_SYS_RESOURCE
. Linux-specific limits (e.g., LimitNICE, LimitRTPRIO) are ignored on systems where they are not supported.
Source Snippet:
LimitAS = unlimited
Specifies the maximum address space (virtual memory) for the service process, in bytes. Corresponds to the RLIMIT_AS
resource limit.
mandatory: no
syntax: uint
valid values:
Source Snippet:
LimitCORE = 0
Specifies the maximum size of core dump files generated by the service process, in bytes. Corresponds to the RLIMIT_CORE
resource limit.
mandatory: no
syntax: uint
valid values:
notes:
Setting to 0 disables core dumps.
Source Snippet:
LimitCPU = unlimited
Specifies the maximum CPU time the service process can use, in seconds. Corresponds to the RLIMIT_CPU
resource limit.
mandatory: no
syntax: uint
valid values:
notes:
Exceeding the limit sends SIGXCPU to the process.
Source Snippet:
LimitDATA = 5242880
Specifies the maximum size of the service process’s data segment, in bytes. Corresponds to the RLIMIT_DATA
resource limit.
mandatory: no
syntax: uint
valid values:
notes:
Affects memory allocations (e.g., malloc()).
Source Snippet:
LimitFSIZE = unlimited
Specifies the maximum size of files the service process can create, in bytes. Corresponds to the RLIMIT_FSIZE
resource limit.
mandatory: no
syntax: uint
valid values:
notes:
Exceeding the limit sends SIGXFSZ to the process.
Source Snippet:
LimitLOCKS = 1024
Specifies the maximum number of file locks the service process can hold. Corresponds to the RLIMIT_LOCKS
resource limit (Linux-specific).
mandatory: no
syntax: uint
valid values:
notes:
Only available on Linux; ignored on systems lacking RLIMIT_LOCKS.
Source Snippet:
LimitMEMLOCK = 65536
Specifies the maximum amount of memory the service process can lock into RAM, in bytes. Corresponds to the RLIMIT_MEMLOCK
resource limit.
mandatory: no
syntax: uint
valid values:
notes:
Affects mlock() and similar calls.
Source Snippet:
LimitMSGQUEUE = 819200
Specifies the maximum size of POSIX message queues the service process can create, in bytes. Corresponds to the RLIMIT_MSGQUEUE
resource limit (Linux-specific).
mandatory: no
syntax: uint
valid values:
notes:
Only available on Linux; ignored on systems lacking RLIMIT_MSGQUEUE
.
Source Snippet:
LimitNICE = -20
Specifies the maximum nice value (scheduling priority) the service process can set. Corresponds to the RLIMIT_NICE
resource limit (Linux-specific).
mandatory: no
syntax: uint
valid values:
-20
and 19
(e.g., -20
for highest priority, 19
for lowest).notes:
Lower values (e.g., 0
) give higher CPU priority; higher values (e.g., 19
) give lower priority.
Only available on Linux; ignored on systems lacking RLIMIT_NICE.
Numeric values are adjusted to the hard limit if exceeded (e.g., -20
may be capped to 0 if ulimit -He
is 20
).
Setting negative nice values may require CAP_SYS_NICE
for unprivileged processes.
Source Snippet:
LimitNOFILE = 1024
Specifies the maximum number of open file descriptors the service process can have. Corresponds to the RLIMIT_NOFILE
resource limit.
mandatory: no
syntax: uint
valid values:
notes:
Affects files, sockets, and pipes.
Source Snippet:
LimitNPROC = 4096
Specifies the maximum number of processes the service process’s user can create. Corresponds to the RLIMIT_NPROC
resource limit.
mandatory: no
syntax: uint
valid values:
notes:
Applies to the user’s total processes, not just the service.
Source Snippet:
LimitRTPRIO = 50
Specifies the maximum real-time priority the service process can set. Corresponds to the RLIMIT_RTPRIO
resource limit (Linux-specific).
mandatory: no
syntax: uint
valid values:
notes:
Higher values give higher real-time scheduling priority. Only available on Linux; ignored on systems lacking RLIMIT_RTPRIO.
Source Snippet:
LimitRTTIME = unlimited
Specifies the maximum real-time CPU time the service process can use, in microseconds. Corresponds to the RLIMIT_RTTIME
resource limit (Linux-specific).
mandatory: no
syntax: uint
valid values:
notes:
Only available on Linux; ignored on systems lacking RLIMIT_RTTIME.
Source Snippet:
LimitSIGPENDING = 8192
Specifies the maximum number of queued signals the service process can have. Corresponds to the RLIMIT_SIGPENDING
resource limit (Linux-specific).
mandatory: no
syntax: uint
valid values:
notes:
Only available on Linux; ignored on systems lacking RLIMIT_SIGPENDING
.
Source Snippet:
LimitSTACK = 8388608
Specifies the maximum stack size for the service process, in bytes. Corresponds to the RLIMIT_STACK resource limit.
mandatory: no
syntax: uint
valid values:
notes:
Affects thread stacks and recursion depth.
Source Snippet:
BlockPrivileges = true
Enables the Linux PR_SET_NO_NEW_PRIVS
flag via prctl()
, preventing the service process and its children from gaining additional privileges (e.g., via setuid
binaries or capability inheritance).
mandatory: no
syntax: boolean
valid values:
notes:
Only available on Linux; ignored on other systems.
Once set, cannot be unset for the process or its children.
Source Snippet:
UMask = 022
Sets the file creation mask for the service process via umask()
, controlling default permissions for newly created files and directories. The value is specified in octal notation, determining which permission bits are masked from the default mode.
mandatory: no
syntax: uint
valid values:
An octal number between 000
and 777
(e.g., 022
, 002
, 077
).
Undefined: Defaults to system-wide configuration.
Source Snippet:
Nice = -10
Sets the CPU scheduling priority (nice value) for the service process via setpriority()
, affecting how the kernel allocates CPU time. Lower values increase priority; higher values decrease it.
mandatory: no
syntax: uint
valid values:
An integer between -20
(highest priority) and 19
(lowest priority).
Undefined: Defaults to system-wide configuration.
notes:
Negative values (e.g., -10
) require CAP_SYS_NICE
for unprivileged services (non-root users) or root privileges.
Must be within the RLIMIT_NICE
limit set by LimitNICE
.
Affects the service process and its children.
Source Snippet:
ChangeDirectory = /var/lib/myservice
Sets the working directory for the service process via chdir()
, affecting the default directory for file operations (e.g., opening files with relative paths).
mandatory: no
syntax: path
valid values:
Any valid absolute file path can be specified.
Undefined: Inherits the working directory from the parent process (default, typically the supervision directory).
notes:
The directory must exist and be accessible (readable and executable) by the service’s user. Permission or non-existent directory errors cause the service to fail with a logged warning.
Affects the service process and its children.
Source Snippet:
CapsBound = (CAP_SYS_NICE CAP_CHOWN)
Defines the Linux capabilities allowed in the capability bounding set for a root-owned service’s process. This setting controls which special permissions (like adjusting process priorities or changing file ownership) the service can use, restricting it to only the listed capabilities or excluding specific ones.
mandatory: no
syntax: brackets
valid values:
A space-separated list of capability names in parentheses, such as (CAP_SYS_NICE
CAP_CHOWN
CAP_DAC_OVERRIDE
).
Capability names can be prefixed with !
to exclude them, allowing all other capabilities. For example, (CAP_NET_ADMIN
!CAP_SYS_ADMIN
CAP_MAC_OVERRIDE
!CAP_SYS_RESOURCE
) allows all capabilities except CAP_SYS_ADMIN
and CAP_SYS_RESOURCE
.
Valid capability names include CAP_SYS_NICE
, CAP_CHOWN
, CAP_DAC_OVERRIDE
, CAP_SYS_ADMIN
, and others (see Linux documentation for the full list).
Undefined: No changes are made to the bounding set, and the service uses the system’s default permissions.
notes:
Only applies to services running as the root user. For non-root services, this setting is silently ignored.
Clears all existing capabilities in the bounding set before applying the listed ones, ensuring only specified capabilities are allowed.
If any capability name is prefixed with !
, the list is interpreted as allowing all capabilities except those marked with !
. For example, (CAP_NET_ADMIN
!CAP_SYS_ADMIN
) allows all capabilities except CAP_SYS_ADMIN
. Where doing, (CAP_SYS_NICE
CAP_CHOWN
) restricts the bounding set to only CAP_SYS_NICE
and CAP_CHOWN
.
Invalid capability names are ignored, and a warning is logged when the service configuration is parsed.
Requires Linux kernel version 5.6
or later.
Source Snippet:
CapsAmbient = (CAP_SYS_NICE)
Specifies Linux capabilities that a service and its child processes automatically retain, even when starting new programs. This allows permissions, such as adjusting process priorities, to be passed to child processes without requiring root privileges.
mandatory: no
syntax: brackets
valid values:
A space-separated list of capability names in parentheses, such as (CAP_SYS_NICE CAP_CHOWN CAP_DAC_OVERRIDE)
.
Capability names can be prefixed with !
to exclude them, allowing all other capabilities. For example, (CAP_SYS_NICE !CAP_SYS_ADMIN)
includes all capabilities except CAP_SYS_ADMIN
.
Undefined: No ambient capabilities are set, and child processes inherit no special permissions.
notes:
Applies to both root-owned services and non-root services.
The bounding set must contain at least CAP_SETPCAT
capability and each listed capability. If not, it is skipped, and a warning is logged. If CAP_SETPCAT
is not in bounding set, the process die.
For root-owned services, if CapsBound
is not set, the service checks the system’s current set of allowed permissions to decide which capabilities can be used. If CapsBound
is set, only the capabilities listed in CapsBound
are considered. For example, if CapsBound = (CAP_SYS_NICE)
and CapsAmbient = (CAP_DAC_OVERRIDE)
, the CAP_DAC_OVERRIDE
capability will be skipped because it is not in the CapsBound
list, and a warning will be logged.
Requires Linux kernel version 5.6
or later.
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.
The Version
key supports formats inspired by semantic versioning (e.g., "1.0.0"
) but is flexible enough to handle any number of components separated by dots or other non-alphanumeric characters, pre-release tags (e.g., "1.0.0-alpha"
), mixed components (e.g., "0ab"
), and complex strings (e.g., "1.0ab.01-1"
). This following explains what constitutes a valid version string and what does not, helping users effectively utilize the field.
The Version
key accepts version strings composed of components separated by any number of non-alphanumeric characters (e.g., dots, hyphens). Components can be numeric (e.g., "123"
), alphabetic (e.g., "alpha"
), or mixed (e.g., "123abc"
). The function handles leading zeros, pre-release tags, letter suffixes, and any number of components (not limited to three dots). Below are the characteristics of valid version strings:
Numeric Versions with Any Number of Components:
- Strings like "1"
, "1.0"
, "1.0.0"
, "1.0.0.0"
, or "10.0.1.2.3"
.
- The number of dots (or other separators) is not restricted to three; you can have zero, one, two, three, four, or more components (e.g., "1.0"
or "1.0.0.0.0"
).
- Numbers can include leading zeros, which are ignored during comparison (e.g., "01.00.00"
is equivalent to "1.0.0"
).
- Components are separated by any non-alphanumeric characters (e.g., "1-0-0"
, "1..0--0"
, "1.0.0.0_0"
).
Pre-release Versions:
- Versions with alphabetic pre-release tags, such as "1.0.0-alpha"
, "2.0.0-beta"
, or "1.0.0.0-rc1"
.
- Pre-release tags (e.g., "alpha"
, "beta"
) are treated as higher precedence than stable versions (e.g., "1.0.0-alpha" < "1.0.0"
).
- Tags are case-insensitive (e.g., "1.0.0-ALPHA"
is equivalent to "1.0.0-alpha"
).
- Only the first letter is taken into account whatever le lenght of the string.
Mixed Components:
- Components that combine numeric and alphabetic parts without a separator, such as "123abc"
or "0ab"
, are valid.
- These are parsed as a numeric component followed by an alphabetic suffix:
- "123abc"
splits into numeric "123"
and alphabetic "abc"
.
- "0ab"
splits into numeric "0"
and alphabetic "ab"
.
- Example: "1.0.0-123abc"
is parsed as numeric "123"
followed by an alphabetic suffix "abc"
.
- Only the first letter is taken into account whatever le lenght of the string.
Letter Suffixes:
- Versions with an alphabetic suffix after a pre-release tag or mixed component, such as "1.0.0-alpha.1"
, "1.0.0-beta.patch"
, or "1.0ab.01-1"
.
- The alphabetic part is treated as a separate component with lower precedence than numeric components.
Complex Version Strings:
- Strings combining multiple component types with any number of separators, such as "1.0ab.01-1"
or "1.0.0.0.0-alpha.2"
, are valid.
- Example breakdown of "1.0ab.01-1"
:
- "1"
: Numeric component.
- "0ab"
: Numeric "0"
+ alphabetic suffix "ab"
.
- "01"
: Numeric component (equivalent to "1"
).
- "1"
: Numeric component.
Shortened or Extended Versions:
- Versions with any number of components are valid, from a single component (e.g., "1"
) to many (e.g., "1.0.0.0.0"
).
- Shorter versions are treated as equivalent to versions padded with zeros (e.g., "1.0"
is equivalent to "1.0.0"
, "1"
is equivalent to "1.0.0.0"
).
- Extended versions with more components are compared component-by-component (e.g., "1.0.0.0" == "1.0.0"
).
Empty Strings:
- An empty string (""
) is valid and treated as a version with a single zero component (equivalent to "0"
).
Separators:
- Any non-alphanumeric character (e.g., .
, -
, _
, +
) can act as a separator, and any number of consecutive separators is allowed and ignored (e.g., "1..0"
is equivalent to "1.0"
, "1---0..0"
is equivalent to "1.0.0"
).
- Separators are flexible, so "1-0-0"
, "1_0_0"
, and "1.0.0"
are equivalent.
Examples of Valid Version Strings:
- "1"
- "1.0"
- "1.0.0"
- "1.0.0.0"
- "1.0.0.0.0"
- "2.0.0-alpha"
- "1.0.0-beta.1"
- "01.00.00"
- "1-0-0"
- "1.0.0-rc.2"
- "1.0ab.01-1"
- "1.0.0-123abc"
- ""
- "2.0.0--alpha..patch"
- "1-0ab-01--1"
- "10.0.1.2.3"
While the Version
key is robust, certain inputs are invalid or problematic. Users should avoid the following:
Special Characters in Components:
- Components should consist of numeric (0-9
) or alphabetic (a-z
, A-Z
) characters. Special characters like @
, #
, or $
within components (not as separators) are not supported and may lead to incorrect parsing.
- Example: "1.0.0@alpha"
is invalid because @alpha
contains an unsupported character in the component.
Whitespace in Components:
- Whitespace within components (e.g., "1.0.0 alpha"
) is treated as a separator, which may split components unexpectedly. Use hyphens or dots for pre-release tags (e.g., "1.0.0-alpha"
).
- Example: "1.0.0 alpha"
is valid from an algorithm point of view but the parsed will only consider the first element.
Excessively Long Strings: - Extremely long version strings (e.g., thousands of characters or hundreds of components) may cause performance issues or stack overflows due to the fixed-size arrays in the function. Keep version strings reasonably short (e.g., under 50 characters). - Example: A string with hundreds of components is technically valid but impractical.
Examples of Invalid or Problematic Version Strings:
- NULL
(causes undefined behavior).
- "1.0.0@alpha"
(invalid character @
in component).
- "1.0.0#patch"
(invalid character #
in component).
- "1.0.0 alpha"
(whitespace splits components unexpectedly, likely not intended).
- A 51-character or higher string is invalid.
The minimal template is e.g.:
[Main]
Type = classic
[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 = ()
[Execute]
LimitAS =
LimitCORE =
LimitCPU =
LimitDATA =
LimitFSIZE =
LimitLOCKS =
LimitMEMLOCK =
LimitMSGQUEUE =
LimitNICE =
LimitNOFILE =
LimitNPROC =
LimitRTPRIO =
LimitRTTIME =
LimitSIGPENDING =
LimitSTACK =
BlockPrivileges =
UMask =
ChangeDirectory = /directory/path
CapsBound = ()
CapsAmbient = ()