- concurrent startup; run system startup tasks in parallel

all start|stop
xlate start|stop
show start|stop

ln -s ./name
./name start|stop|restart

is a modern replacement for rc scripts/etc/rc.d/*   /etc/rc* and the interpreting shells, designed for startup performance and faster boot times.  The set of system startup tasks are listed in a config file start.conf .  Anytime after config changes, can be run to translate a config file into a binary format start.bin .  A .bin file can be generated locally or installed to a target root filesystem.  During boot or kexec, start.bin is read and multiple threads will execute tasks in parallel as directed.  Some tasks are required to start after others have finished; those tasks can be configured as prerequisites (see label= and pre= below).  A second config file stop.conf is translated to stop.bin for system shutdown tasks.  has 4 operating modes:

[translate] – read one of [start.conf or stop.conf] and generate [start.bin or stop.bin]; some of the performance benefits originate here; translating into start.bin anytime before booting replaces common overhead during system startup like runtime interpreting several scripts; command examples:

xlate start
xlate stop

[display] – read one of [start.bin or stop.bin] and display configured tasks; various options are shown in numeric form; command examples:

show start
show stop

[parallel] – read one of [start.bin or stop.bin], create N worker threads, and run all configured tasks; for performance, N threads execute tasks in parallel as directed; most often is executed by an early user process (eg init(8) or similar) after reading a config file like /etc/inittab; command examples:

all start
all stop

[serial] – when is executed by any other name via symlink, run tasks only from the matching named section in start.bin, stop.bin, or both; this provides backward compatibility similar to running a single rc script/etc/rc.d/*   /etc/rc*; these section-based tasks are run serially; command examples:

ln -s ./network
./network start|stop|restart

config files are comprised of named sections and each section contains any number of tasks.  Task entries describe a process or internal function to execute.  Config file entries contain required or optional fields of the form keyword=value .  Fields are separated by a TAB.  Multiple items within a value are entered as a comma-separated list sans whitespace (see args= and pre= below).  The only special characters are [ $ and , ] – all other characters are interpreted literally.  Blank lines and any line starting with a # are treated as comments and skipped.  Config file entries and options are documented here:

set thread count; when executed in parallel mode, will create N worker threads to execute tasks from [start.bin or stop.bin]; an optional threads= entry is global and should appear once before any section= entries; default thread count is 8

bind a /pathname to a SYMBOL; by convention SYMBOL is an UPPERCASE string, length 2-13 bytes  (regex: "^[A-Z][A-Z_]{1,12}$");  /pathname is an absolute pathname for an executable; within any config sections that follow, any proc= entries can reference this /pathname with $SYMBOL; support for $SYMBOL was added for frequent use of various user programs during system startup (eg /etc/modprobe); multiple entries that reference the same $SYMBOL eliminate redundant string-table content in a .bin file; define= entries are global and should appear before any section= entries

starts a new group of processes and functions; all proc= and func= entries that follow are attached to this section; grouping continues until the next section= entry or end-of-file; the name of a section is often copied from a prior rc script/etc/rc.d/*   /etc/rc* filename; note that a section name cannot match the program name , see [serial] above; name follows the same regex as shown with label= below

proc=/pathname|$SYMBOL  TAB  [options]
describes a process to execute; /pathname is an absolute pathame for an executable and can be either a plain string or a reference with $SYMBOL that was previously defined with define=

[optional fields]

args=string[,str2,str3...]    command-line args, comma delimited, maximum arg count is 11 (executable + 10); note that whitespace within args is not supported and would yield additional config fields that are not recognized; while ',' chars are used as delimiters, all other chars are interpreted literally

label=string    the unique unquoted string labels this task symbolically; a future entry can reference this task as a prerequisite with pre= and a matching string; by convention string is similar to a lowercase symbol in C, length 2-13  (regex: "^[a-z][0-9_a-z]{1,12}$")

pre=string[,str2,str3,str4]    prerequisite references, comma delimited, maximum 4; each unique unquoted string references another task symbolically and must be a match from the label= on a previous entry; each labeled task with a matched string is now a prerequisite; a worker thread will first wait for the specified prereqs to finish before executing this task; tasks can combine label= and pre=, establishing a chain of prereqs (see config examples below)

any task configured with pre= normally references a labeled task placed within the same section=; referencing a labeled task from an external section only works when running all tasks (see [parallel] mode above); since [serial] mode runs tasks only from a named section, waiting for an external prerequisite task is skipped and a message is generated

wait=0    do not wait for this process to finish, similar to a shell background job; useful for launching a process when the completion doesn't matter to other tasks; use infrequently to avoid CPU overloading; the default is wait=1, each thread normally waits for a task to finish; note this option is not needed for processes like network daemons that auto-background or "daemonize" themselves (fork and parent exit); also wait=0 cannot be combined with a label=

null=[out,err]    redirect file descriptors [1,2,both] to /dev/null for this task; value can be out, err, or out,err  (similar to shell >, 2>, &>)

daemon=yes|full    mark this proc as a daemon and do not redirect process output (fd 1&2); most daemons normally send any output to syslog or their own log file; for non-daemon / regular procs, output is redirected to private log files along with timing and other proc related data

while processes are always executed by their absolute pathname, arg #0 can be anything and most often the filename is used; /usr/sbin/sshd is a unique case that exits with an error when arg #0 is not an absolute (or full) pathname; daemon=full means the same as daemon=yes plus the full pathname is used for arg #0

func=name  TAB  [custom fields]  TAB  [options]
name refers to a named service within ; these are implemented as custom internal functions for a variety of tasks where a process is too simple, high-overhead, or otherwise unsuitable; various functions are also used for conditional execution based on misc runtime data; some functions replace a collection of processes with system calls; eg: a function that loops with mknod() instead of the higher overhead from several /bin/mknod processes

optional fields label= and pre= are supported the same as proc= entries, see above

for performance, ideally all system startup activity could be done with internal functions; services from time-consuming processes are often candidates for optimization as custom internal functions

(chained prereqs):
proc=/bin/larry  TAB  label=first
proc=/bin/curly  TAB  label=second  TAB  pre=first
proc=/bin/moe  TAB  pre=second

func=sysopt  TAB  file=kernel/printk  TAB  data=4

sets a system option, similar to:
bash# echo 4 > /proc/sys/kernel/printk

proc=/sbin/insmod  TAB  args=rok ...
func=dev_setup  TAB  devname=rok  TAB  filename=rok  TAB  mode=0600  TAB  ndevs=1  TAB  [adigs=0]

After running a driver's init routine, dev_setup will lookup the device major number for the devname=, then create 1+ nodes in /dev, similar to:  bash# mknod -m 0600 /dev/rok0 c 96 0

[option]  adigs=0  do not append digit(s) to /dev filenames; by default dev_setup normally appends digit(s)

For top performance, ideally all system startup tasks could run in parallel and start at any time; however there are many tasks that require others to complete first.  Common prerequisites are first loading driver modules, some needed to generate a major device number before /dev nodes can be created, or register a network intf before it can be configured.  An example with inter-related elements is shown here:

proc=$MODPROBE  TAB  args=ktk  TAB  label=load_ktk
proc=$MODPROBE  TAB  args=max  TAB  pre=load_ktk
proc=$MODPROBE  TAB  args=coco  TAB  pre=load_ktk

The module ktk contains (C or assembly) symbols referenced by other modules; the (Linux) file modules.dep contains ktk as a dependency for both max and coco.  When "modprobe max" and "modprobe coco" run in parallel, both would find ktk is absent and both would attempt loading ktk; one process would succeed and the other exits with an error – and without loading the referencing module.  To resolve the race condition, a proc= task is first configured to load ktk and labeled with label=load_ktk, then the 2 tasks that follow are configured with pre=load_ktk.  Now the ktk task is a prerequisite for both the max and coco tasks.  Threads will first wait for the prerequisite task ktk to finish before starting the referencing tasks (loading max or coco).  The result is that when those 2 tasks start, both will find ktk is already loaded and immediately proceed to loading their specified module (max or coco).  After configuring any needed prerequisite(s), alternately the simpler insmod(8) could be run in place of modprobe(8).

creates a private log file in /var/log/ for each thread during regular boot; these are named numerically, eg 1–24.  Log files contain a series of task runtime results and other info, an example is shown here:

/usr/sbin/vkt -a 40
prereq wait: 180 ms
start 1869 ms, run 191 ms, finis 2060 ms, status 0, sig 0, cores 15:15

[first line]  process and args or internal function name
[next line]  time waiting for a prerequisite if present, or conditionally: wait=0
[last line]  task start/run/finis times, exit status, exit signal, start-core : end-core

When is executed the current system time is saved as Time-Zero (T0).  Task start/finis times are relative to T0 and are independent of any prerequisite wait time.  start-core and end-core record the CPU/core # where each thread is running immediately before and after executing a process or internal function.  On some systems, any child process tends to start on the same core as the calling thread.

0   success, no errors
1   usage, bad command line args
2   error in config file, after message to fd 2
3   misc file, I/O, allocation errors