CrisOS v2 includes a lightweight service manager inspired by systemd. At boot,Documentation Index
Fetch the complete documentation index at: https://mintlify.com/CRISTOP-bot/cris-os-v2/llms.txt
Use this file to discover all available pages before exploring further.
systemd_init() scans every file in the CRFS image whose path begins with systemd/, parses any that end in .service, and registers them in a static table of up to MAX_UNITS = 16 service units. After loading, it automatically activates every unit whose WantedBy field begins with default.target. The shell then exposes the service table through the systemctl command, which delegates to systemd_handle_command().
Unit File Format
Unit files follow a subset of the INI-like systemd format. The parser recognizes three sections —[Unit], [Service], and [Install] — and three key-value fields. Section headers are detected by checking if a line starts with [; they are skipped without further processing. Key-value lines are matched by prefix.
Example — rootfs/systemd/hello.service
Supported Fields
| Section | Key | Max length | Description |
|---|---|---|---|
[Unit] | Description= | 64 bytes | Human-readable unit description |
[Service] | ExecStart= | 128 bytes | Command string (recorded, not executed) |
[Unit] | WantedBy= | 64 bytes | Target that triggers auto-start at boot |
[ are silently skipped. There is no support for comments (#), multi-line values, or section-qualified key lookups — the parser simply matches whichever key appears first anywhere in the file.
Service Unit Structure
Each loaded unit is stored in ansd_unit_t struct:
name field is the basename extracted from the CRFS file path (e.g. "hello.service"). All string fields are copied with a null-safe sd_strncpy() that always writes a terminating '\0'.
Initialization — systemd_init()
Reset unit table
unit_count is set to 0. The existing units[] array is reused; no dynamic allocation is performed.Scan the CRFS image
systemd_init() calls fs_file_count() and iterates every entry with fs_file_at(i). For each file whose name begins with "systemd/", it calls the internal sd_parse_unit() function.Filter by extension
sd_parse_unit() extracts the basename using sd_get_basename() and checks whether the extension portion starts with ".service". Files that do not match are skipped.Parse key-value pairs
The file content is read line by line. Each line is trimmed of leading and trailing whitespace. Lines starting with
[ (section headers) and empty lines are skipped. The remaining lines are matched against the three supported prefixes using sd_starts_with():"Description="→unit->description"ExecStart="→unit->exec_start"WantedBy="→unit->wanted_by
systemctl Commands
The shell passes everything after the systemctl token to systemd_handle_command(rest). The function splits rest into a sub-command and an optional unit name.
systemctl list-units
systemctl list-units
Prints every registered unit with its current active/inactive state.Internally calls
sd_print_unit() for each entry in units[0..unit_count).systemctl status <unit>
systemctl status <unit>
Prints the unit name, active state, description, and
ExecStart command.systemctl start <unit>
systemctl start <unit>
Sets
unit->active = true. If the unit is already active, prints "Unit already active." If the unit has a non-empty ExecStart, it is printed to the console — but not executed.systemctl stop <unit>
systemctl stop <unit>
Sets
unit->active = false. If the unit is already inactive, prints "Unit not active."systemctl help
systemctl help
Calling
systemctl with no arguments or with help prints the available sub-commands:Example Shell Session
Adding a Custom Service
To add a service to the rootfs, create a file underrootfs/systemd/ with a .service extension, rebuild the CRFS image with tools/build_rootfs.py, and reboot.
systemctl list-units after the next boot and will be auto-started if WantedBy=default.target is set.
Services are not real processes. CrisOS v2 has no scheduler and no process isolation —
active is a boolean flag stored in a static C struct. The ExecStart string is parsed and displayed but never passed to any execution engine. systemctl enable is not implemented; the equivalent is setting WantedBy=default.target in the unit file.