commit cb48a676e982768646c10e1cb4b149d77edb618c Author: Jason Ross Date: Sun Jul 19 19:06:43 2026 -0500 Add Lua-ported s6/s6-rc service definitions Ports the community s6/s6-rc service catalog (early-boot mounts, udev, dbus, session/power, networking, display managers, peripheral daemons) to Lua-based service definitions. - src/lua/s6lua.lua: shared helper library (exec, logging, fstab parsing, oneshot shell runner, readiness notification) - src/native/s6exec.c: minimal execvp() binding so longrun `run` scripts can replace their own process image with the real daemon, since stock Lua has no exec() and os.execute("exec ...") does not solve it (the interpreter stays alive as an unsupervised parent) - tools/catalog.lua + gen-services.lua: table-driven generator for the structurally identical -srv/-log daemon pairs and agetty ttys - tools/lint.lua, check-syntax.ps1, set-exec-bits.ps1: local verification (no live s6/Linux target available this session) - services/: 50 service directories (14 early-boot oneshots, 12 daemon srv/log pairs, 6 agetty ttys, boot/mount/setup/ttys/ graphical/default bundles) Authored and syntax/structurally validated only. Native module is unbuilt and daemon flags are unverified against Artix's real catalog (gitea was unreachable during research) -- see docs/CONVENTIONS.md. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/README.md b/README.md new file mode 100644 index 0000000..b376e38 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# s6-lua + +A port of the community s6/s6-rc service catalog (the kind Artix Linux/Obarun use in place of +systemd units) into Lua-based service definitions. + +Stock Lua has no `exec()` binding, and `os.execute("exec daemon")` doesn't solve the problem +either — it forks a shell that execs, but the Lua process itself stays alive blocked in +`waitpid()`, so s6 ends up supervising the interpreter instead of the daemon. `longrun` services +here hand off to the real daemon through a tiny vendored C module (`src/native/s6exec.c`, +`execvp()`); `oneshot` and `finish` scripts don't need it since they run to completion rather than +persisting. See `docs/CONVENTIONS.md` for the full rationale and naming rules. + +## Layout + +``` +services/ the s6-rc source-definition tree (deploys verbatim to /etc/s6/sv) +src/lua/ shared helper library (s6lua.lua) every service script requires +src/native/ native exec binding (s6exec.c) + Makefile, Linux-only build +tools/ generator, structural linter, syntax checker, exec-bit fixer, installer +docs/ conventions and naming rules +``` + +`services/default` is the top-level bundle (boots to graphical target with SDDM); `services/boot` +is the multi-user/console-only target. + +## Status + +Authored and syntax-checked only — there is no live s6/s6-rc install in this environment to boot- +test against. See `docs/CONVENTIONS.md` for known unverified gaps (daemon flags reconstructed from +convention, not confirmed against Artix's actual catalog) and the recommended next step (install +s6/s6-rc/s6-linux-init on a Linux host — Arch is the closest packaging match — and boot-test the +`boot` bundle before enabling `graphical`). + +## Local tooling + +Requires `lua55`/`luac55` (this repo was authored against Lua 5.5, written to a subset valid under +5.4 too — see `docs/CONVENTIONS.md`). + +```powershell +lua55 tools/gen-services.lua # regenerate the -srv/-log pairs + agetty ttys from tools/catalog.lua +lua55 tools/lint.lua # structural validation of services/ +tools/check-syntax.ps1 # luac55 -p over every script +tools/set-exec-bits.ps1 # fix the git executable bit before committing (Windows checkout) +``` + +`tools/install.sh` deploys everything to a real Linux target (untested this session). diff --git a/docs/CONVENTIONS.md b/docs/CONVENTIONS.md new file mode 100644 index 0000000..d859570 --- /dev/null +++ b/docs/CONVENTIONS.md @@ -0,0 +1,62 @@ +# Conventions + +## Lua version target + +Author against a subset valid under **both Lua 5.4 and 5.5**: Arch/Artix currently package Lua +5.4, while this repo is authored/syntax-checked locally with `lua55`. Avoid 5.5-only stdlib +additions. `docs/CONVENTIONS.md` (this file) is the one place a Windows-side checker and a +Linux-side interpreter could silently diverge — if you're unsure whether something is 5.4-safe, +don't use it. + +## Naming + +Service directories under `services/` follow Artix's own `s6-scripts` catalog convention: + +- A daemon's directory is named `-srv` (e.g. `dbus-srv`). +- Its logger is named `-log` (e.g. `dbus-log`), wired via `producer-for`/`consumer-for`. +- Logs land in `/var/log/` (not `/var/log/-srv`). +- Early-boot oneshots (category 1) and one-off oneshots (`coldplug`, `net-lo`, etc.) are named + after the action they perform, no suffix (e.g. `mount-cgroups`, `hostname`). +- Bundles are named after the target they represent (`boot`, `mount`, `setup`, `ttys`, + `graphical`, `default`), not suffixed. + +## Adding a new `-srv`/`-log` daemon pair + +Don't hand-author a new service directory pair. Add a row to `tools/catalog.lua` and rerun: + +``` +lua55 tools/gen-services.lua +``` + +This regenerates every entry in the catalog (idempotent — safe to rerun after editing one row). + +## Swapping the default display manager + +`services/default/contents.d/` currently includes `sddm-srv`/`sddm-log` (Artix's own flagship +display manager). To switch to GDM or LightDM, remove the `sddm-*` entries from +`services/default/contents.d/` and add `gdm-srv`/`gdm-log` or `lightdm-srv`/`lightdm-log` instead +— all three are already generated and ready to enable. + +## Exec strategy + +- `longrun` `run` scripts **must** end with `s6.exec({...})` (from `src/lua/s6lua.lua`, backed by + the native `s6exec.so` module) as their last statement. This is what makes the supervised + process the real daemon rather than a lingering Lua interpreter — see the root README and the + plan history for why `os.execute("exec ...")` does not work here. +- `oneshot` `up`/`down` scripts and longrun `finish` scripts do **not** need `s6.exec` — they run + to completion and exit, so `s6.run`/`os.execute` is safe and preferred (simpler, no native + dependency). + +## Git executable bit + +Windows checkouts don't set the tree's executable-bit metadata on `git add`. Run +`tools/set-exec-bits.ps1` before committing any new `run`/`up`/`down`/`finish`/`reload`/`check` +file — the syntax and lint checks won't catch a missing exec bit, but `s6-supervise` will fail +silently on the real target. + +## Known unverified gaps + +Artix's `s6-scripts` gitea repo blocked automated fetches during research, so the daemon +argv/flags in `tools/catalog.lua` (chronyd, bluetoothd, acpid, cupsd in particular) are +reconstructed from each daemon's documented foreground-mode flag rather than confirmed +byte-for-byte against a reference script. Spot-check before relying on this in production. diff --git a/services/acpid-log/consumer-for b/services/acpid-log/consumer-for new file mode 100644 index 0000000..d484b7d --- /dev/null +++ b/services/acpid-log/consumer-for @@ -0,0 +1 @@ +acpid-srv diff --git a/services/acpid-log/pipeline-name b/services/acpid-log/pipeline-name new file mode 100644 index 0000000..ebb0f96 --- /dev/null +++ b/services/acpid-log/pipeline-name @@ -0,0 +1 @@ +acpid diff --git a/services/acpid-log/run b/services/acpid-log/run new file mode 100755 index 0000000..9916015 --- /dev/null +++ b/services/acpid-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/acpid") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/acpid" }) diff --git a/services/acpid-log/type b/services/acpid-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/acpid-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/acpid-srv/dependencies.d/mount-procfs b/services/acpid-srv/dependencies.d/mount-procfs new file mode 100644 index 0000000..e69de29 diff --git a/services/acpid-srv/finish b/services/acpid-srv/finish new file mode 100755 index 0000000..963ed8a --- /dev/null +++ b/services/acpid-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("acpid", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/acpid-srv/producer-for b/services/acpid-srv/producer-for new file mode 100644 index 0000000..c5fe510 --- /dev/null +++ b/services/acpid-srv/producer-for @@ -0,0 +1 @@ +acpid-log diff --git a/services/acpid-srv/run b/services/acpid-srv/run new file mode 100755 index 0000000..5ad9012 --- /dev/null +++ b/services/acpid-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/sbin/acpid", "-f" }) diff --git a/services/acpid-srv/type b/services/acpid-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/acpid-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/agetty-tty1/run b/services/agetty-tty1/run new file mode 100755 index 0000000..84a38bb --- /dev/null +++ b/services/agetty-tty1/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/sbin/agetty", "tty1", "38400", "linux" }) diff --git a/services/agetty-tty1/type b/services/agetty-tty1/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/agetty-tty1/type @@ -0,0 +1 @@ +longrun diff --git a/services/agetty-tty2/run b/services/agetty-tty2/run new file mode 100755 index 0000000..fe53bcd --- /dev/null +++ b/services/agetty-tty2/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/sbin/agetty", "tty2", "38400", "linux" }) diff --git a/services/agetty-tty2/type b/services/agetty-tty2/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/agetty-tty2/type @@ -0,0 +1 @@ +longrun diff --git a/services/agetty-tty3/run b/services/agetty-tty3/run new file mode 100755 index 0000000..d6ec163 --- /dev/null +++ b/services/agetty-tty3/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/sbin/agetty", "tty3", "38400", "linux" }) diff --git a/services/agetty-tty3/type b/services/agetty-tty3/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/agetty-tty3/type @@ -0,0 +1 @@ +longrun diff --git a/services/agetty-tty4/run b/services/agetty-tty4/run new file mode 100755 index 0000000..3999690 --- /dev/null +++ b/services/agetty-tty4/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/sbin/agetty", "tty4", "38400", "linux" }) diff --git a/services/agetty-tty4/type b/services/agetty-tty4/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/agetty-tty4/type @@ -0,0 +1 @@ +longrun diff --git a/services/agetty-tty5/run b/services/agetty-tty5/run new file mode 100755 index 0000000..0ed0449 --- /dev/null +++ b/services/agetty-tty5/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/sbin/agetty", "tty5", "38400", "linux" }) diff --git a/services/agetty-tty5/type b/services/agetty-tty5/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/agetty-tty5/type @@ -0,0 +1 @@ +longrun diff --git a/services/agetty-tty6/run b/services/agetty-tty6/run new file mode 100755 index 0000000..bfc8c29 --- /dev/null +++ b/services/agetty-tty6/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/sbin/agetty", "tty6", "38400", "linux" }) diff --git a/services/agetty-tty6/type b/services/agetty-tty6/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/agetty-tty6/type @@ -0,0 +1 @@ +longrun diff --git a/services/bluez-log/consumer-for b/services/bluez-log/consumer-for new file mode 100644 index 0000000..38ab9a2 --- /dev/null +++ b/services/bluez-log/consumer-for @@ -0,0 +1 @@ +bluez-srv diff --git a/services/bluez-log/pipeline-name b/services/bluez-log/pipeline-name new file mode 100644 index 0000000..8d0fe91 --- /dev/null +++ b/services/bluez-log/pipeline-name @@ -0,0 +1 @@ +bluetoothd diff --git a/services/bluez-log/run b/services/bluez-log/run new file mode 100755 index 0000000..96ca1d9 --- /dev/null +++ b/services/bluez-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/bluez") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/bluez" }) diff --git a/services/bluez-log/type b/services/bluez-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/bluez-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/bluez-srv/dependencies.d/dbus-srv b/services/bluez-srv/dependencies.d/dbus-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/bluez-srv/finish b/services/bluez-srv/finish new file mode 100755 index 0000000..3e5a3dc --- /dev/null +++ b/services/bluez-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("bluetoothd", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/bluez-srv/producer-for b/services/bluez-srv/producer-for new file mode 100644 index 0000000..b8a0823 --- /dev/null +++ b/services/bluez-srv/producer-for @@ -0,0 +1 @@ +bluez-log diff --git a/services/bluez-srv/run b/services/bluez-srv/run new file mode 100755 index 0000000..672c8a1 --- /dev/null +++ b/services/bluez-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/lib/bluetooth/bluetoothd", "-n" }) diff --git a/services/bluez-srv/type b/services/bluez-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/bluez-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/boot/contents.d/coldplug b/services/boot/contents.d/coldplug new file mode 100644 index 0000000..e69de29 diff --git a/services/boot/contents.d/mount b/services/boot/contents.d/mount new file mode 100644 index 0000000..e69de29 diff --git a/services/boot/contents.d/setup b/services/boot/contents.d/setup new file mode 100644 index 0000000..e69de29 diff --git a/services/boot/contents.d/udevd-log b/services/boot/contents.d/udevd-log new file mode 100644 index 0000000..e69de29 diff --git a/services/boot/contents.d/udevd-srv b/services/boot/contents.d/udevd-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/boot/type b/services/boot/type new file mode 100644 index 0000000..757b422 --- /dev/null +++ b/services/boot/type @@ -0,0 +1 @@ +bundle diff --git a/services/chronyd-log/consumer-for b/services/chronyd-log/consumer-for new file mode 100644 index 0000000..efab2c2 --- /dev/null +++ b/services/chronyd-log/consumer-for @@ -0,0 +1 @@ +chronyd-srv diff --git a/services/chronyd-log/pipeline-name b/services/chronyd-log/pipeline-name new file mode 100644 index 0000000..1b78e59 --- /dev/null +++ b/services/chronyd-log/pipeline-name @@ -0,0 +1 @@ +chronyd diff --git a/services/chronyd-log/run b/services/chronyd-log/run new file mode 100755 index 0000000..8a6e504 --- /dev/null +++ b/services/chronyd-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/chronyd") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/chronyd" }) diff --git a/services/chronyd-log/type b/services/chronyd-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/chronyd-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/chronyd-srv/dependencies.d/mount-filesystems b/services/chronyd-srv/dependencies.d/mount-filesystems new file mode 100644 index 0000000..e69de29 diff --git a/services/chronyd-srv/finish b/services/chronyd-srv/finish new file mode 100755 index 0000000..d1b0c8c --- /dev/null +++ b/services/chronyd-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("chronyd", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/chronyd-srv/producer-for b/services/chronyd-srv/producer-for new file mode 100644 index 0000000..d1c93e7 --- /dev/null +++ b/services/chronyd-srv/producer-for @@ -0,0 +1 @@ +chronyd-log diff --git a/services/chronyd-srv/run b/services/chronyd-srv/run new file mode 100755 index 0000000..1ce5e46 --- /dev/null +++ b/services/chronyd-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/bin/chronyd", "-n" }) diff --git a/services/chronyd-srv/type b/services/chronyd-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/chronyd-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/cleanup/dependencies.d/mount-filesystems b/services/cleanup/dependencies.d/mount-filesystems new file mode 100644 index 0000000..e69de29 diff --git a/services/cleanup/type b/services/cleanup/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/cleanup/type @@ -0,0 +1 @@ +oneshot diff --git a/services/cleanup/up b/services/cleanup/up new file mode 100755 index 0000000..c5b1846 --- /dev/null +++ b/services/cleanup/up @@ -0,0 +1,5 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +s6.run("find /tmp -mindepth 1 -xdev -delete") +s6.run_or_die("chmod 1777 /tmp") diff --git a/services/coldplug/dependencies.d/udevd-srv b/services/coldplug/dependencies.d/udevd-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/coldplug/type b/services/coldplug/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/coldplug/type @@ -0,0 +1 @@ +oneshot diff --git a/services/coldplug/up b/services/coldplug/up new file mode 100755 index 0000000..648627a --- /dev/null +++ b/services/coldplug/up @@ -0,0 +1,5 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +s6.run_or_die("udevadm trigger --action=add") +s6.run_or_die("udevadm settle") diff --git a/services/console-setup/type b/services/console-setup/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/console-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/services/console-setup/up b/services/console-setup/up new file mode 100755 index 0000000..d87abed --- /dev/null +++ b/services/console-setup/up @@ -0,0 +1,16 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +-- Loads the console font from /etc/vconsole.conf's FONT= line. +local f = io.open("/etc/vconsole.conf", "r") +if not f then + os.exit(0) +end +for line in f:lines() do + local font = line:match('^FONT=(.+)$') + if font then + font = font:gsub('^"(.*)"$', "%1") + s6.run(string.format("setfont %q", font)) + end +end +f:close() diff --git a/services/cupsd-log/consumer-for b/services/cupsd-log/consumer-for new file mode 100644 index 0000000..d1efddf --- /dev/null +++ b/services/cupsd-log/consumer-for @@ -0,0 +1 @@ +cupsd-srv diff --git a/services/cupsd-log/pipeline-name b/services/cupsd-log/pipeline-name new file mode 100644 index 0000000..d3e119f --- /dev/null +++ b/services/cupsd-log/pipeline-name @@ -0,0 +1 @@ +cupsd diff --git a/services/cupsd-log/run b/services/cupsd-log/run new file mode 100755 index 0000000..c02af61 --- /dev/null +++ b/services/cupsd-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/cupsd") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/cupsd" }) diff --git a/services/cupsd-log/type b/services/cupsd-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/cupsd-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/cupsd-srv/dependencies.d/dbus-srv b/services/cupsd-srv/dependencies.d/dbus-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/cupsd-srv/finish b/services/cupsd-srv/finish new file mode 100755 index 0000000..219ce6f --- /dev/null +++ b/services/cupsd-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("cupsd", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/cupsd-srv/producer-for b/services/cupsd-srv/producer-for new file mode 100644 index 0000000..7a53450 --- /dev/null +++ b/services/cupsd-srv/producer-for @@ -0,0 +1 @@ +cupsd-log diff --git a/services/cupsd-srv/run b/services/cupsd-srv/run new file mode 100755 index 0000000..2dc6f22 --- /dev/null +++ b/services/cupsd-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/sbin/cupsd", "-f" }) diff --git a/services/cupsd-srv/type b/services/cupsd-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/cupsd-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/dbus-log/consumer-for b/services/dbus-log/consumer-for new file mode 100644 index 0000000..3821a13 --- /dev/null +++ b/services/dbus-log/consumer-for @@ -0,0 +1 @@ +dbus-srv diff --git a/services/dbus-log/pipeline-name b/services/dbus-log/pipeline-name new file mode 100644 index 0000000..e2182f1 --- /dev/null +++ b/services/dbus-log/pipeline-name @@ -0,0 +1 @@ +dbus diff --git a/services/dbus-log/run b/services/dbus-log/run new file mode 100755 index 0000000..79e7f2c --- /dev/null +++ b/services/dbus-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/dbus") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/dbus" }) diff --git a/services/dbus-log/type b/services/dbus-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/dbus-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/dbus-srv/dependencies.d/mount-procfs b/services/dbus-srv/dependencies.d/mount-procfs new file mode 100644 index 0000000..e69de29 diff --git a/services/dbus-srv/dependencies.d/mount-sysfs b/services/dbus-srv/dependencies.d/mount-sysfs new file mode 100644 index 0000000..e69de29 diff --git a/services/dbus-srv/finish b/services/dbus-srv/finish new file mode 100755 index 0000000..96916b1 --- /dev/null +++ b/services/dbus-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("dbus", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/dbus-srv/producer-for b/services/dbus-srv/producer-for new file mode 100644 index 0000000..7be2401 --- /dev/null +++ b/services/dbus-srv/producer-for @@ -0,0 +1 @@ +dbus-log diff --git a/services/dbus-srv/run b/services/dbus-srv/run new file mode 100755 index 0000000..c6ed044 --- /dev/null +++ b/services/dbus-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/bin/dbus-daemon", "--system", "--nofork", "--nopidfile" }) diff --git a/services/dbus-srv/type b/services/dbus-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/dbus-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/default/contents.d/graphical b/services/default/contents.d/graphical new file mode 100644 index 0000000..e69de29 diff --git a/services/default/contents.d/sddm-log b/services/default/contents.d/sddm-log new file mode 100644 index 0000000..e69de29 diff --git a/services/default/contents.d/sddm-srv b/services/default/contents.d/sddm-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/default/type b/services/default/type new file mode 100644 index 0000000..757b422 --- /dev/null +++ b/services/default/type @@ -0,0 +1 @@ +bundle diff --git a/services/elogind-log/consumer-for b/services/elogind-log/consumer-for new file mode 100644 index 0000000..3c6a11d --- /dev/null +++ b/services/elogind-log/consumer-for @@ -0,0 +1 @@ +elogind-srv diff --git a/services/elogind-log/pipeline-name b/services/elogind-log/pipeline-name new file mode 100644 index 0000000..68771e1 --- /dev/null +++ b/services/elogind-log/pipeline-name @@ -0,0 +1 @@ +elogind diff --git a/services/elogind-log/run b/services/elogind-log/run new file mode 100755 index 0000000..12c97c5 --- /dev/null +++ b/services/elogind-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/elogind") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/elogind" }) diff --git a/services/elogind-log/type b/services/elogind-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/elogind-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/elogind-srv/dependencies.d/dbus-srv b/services/elogind-srv/dependencies.d/dbus-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/elogind-srv/finish b/services/elogind-srv/finish new file mode 100755 index 0000000..8e50bcd --- /dev/null +++ b/services/elogind-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("elogind", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/elogind-srv/producer-for b/services/elogind-srv/producer-for new file mode 100644 index 0000000..93e3c74 --- /dev/null +++ b/services/elogind-srv/producer-for @@ -0,0 +1 @@ +elogind-log diff --git a/services/elogind-srv/run b/services/elogind-srv/run new file mode 100755 index 0000000..485d85b --- /dev/null +++ b/services/elogind-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/lib/elogind/elogind" }) diff --git a/services/elogind-srv/type b/services/elogind-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/elogind-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/gdm-log/consumer-for b/services/gdm-log/consumer-for new file mode 100644 index 0000000..bd5502f --- /dev/null +++ b/services/gdm-log/consumer-for @@ -0,0 +1 @@ +gdm-srv diff --git a/services/gdm-log/pipeline-name b/services/gdm-log/pipeline-name new file mode 100644 index 0000000..47b4fa5 --- /dev/null +++ b/services/gdm-log/pipeline-name @@ -0,0 +1 @@ +gdm diff --git a/services/gdm-log/run b/services/gdm-log/run new file mode 100755 index 0000000..8cddd20 --- /dev/null +++ b/services/gdm-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/gdm") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/gdm" }) diff --git a/services/gdm-log/type b/services/gdm-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/gdm-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/gdm-srv/dependencies.d/dbus-srv b/services/gdm-srv/dependencies.d/dbus-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/gdm-srv/dependencies.d/elogind-srv b/services/gdm-srv/dependencies.d/elogind-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/gdm-srv/finish b/services/gdm-srv/finish new file mode 100755 index 0000000..ab05f7a --- /dev/null +++ b/services/gdm-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("gdm", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/gdm-srv/producer-for b/services/gdm-srv/producer-for new file mode 100644 index 0000000..be620b0 --- /dev/null +++ b/services/gdm-srv/producer-for @@ -0,0 +1 @@ +gdm-log diff --git a/services/gdm-srv/run b/services/gdm-srv/run new file mode 100755 index 0000000..0b9aac6 --- /dev/null +++ b/services/gdm-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/bin/gdm" }) diff --git a/services/gdm-srv/type b/services/gdm-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/gdm-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/graphical/contents.d/boot b/services/graphical/contents.d/boot new file mode 100644 index 0000000..e69de29 diff --git a/services/graphical/contents.d/dbus-log b/services/graphical/contents.d/dbus-log new file mode 100644 index 0000000..e69de29 diff --git a/services/graphical/contents.d/dbus-srv b/services/graphical/contents.d/dbus-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/graphical/contents.d/elogind-log b/services/graphical/contents.d/elogind-log new file mode 100644 index 0000000..e69de29 diff --git a/services/graphical/contents.d/elogind-srv b/services/graphical/contents.d/elogind-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/graphical/contents.d/networkmanager-log b/services/graphical/contents.d/networkmanager-log new file mode 100644 index 0000000..e69de29 diff --git a/services/graphical/contents.d/networkmanager-srv b/services/graphical/contents.d/networkmanager-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/graphical/contents.d/ttys b/services/graphical/contents.d/ttys new file mode 100644 index 0000000..e69de29 diff --git a/services/graphical/type b/services/graphical/type new file mode 100644 index 0000000..757b422 --- /dev/null +++ b/services/graphical/type @@ -0,0 +1 @@ +bundle diff --git a/services/hostname/type b/services/hostname/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/hostname/type @@ -0,0 +1 @@ +oneshot diff --git a/services/hostname/up b/services/hostname/up new file mode 100755 index 0000000..7f837e7 --- /dev/null +++ b/services/hostname/up @@ -0,0 +1,13 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +local f = io.open("/etc/hostname", "r") +if not f then + os.exit(0) +end +local name = f:read("*l") +f:close() + +if name and name ~= "" then + s6.run_or_die(string.format("hostname %q", name)) +end diff --git a/services/hwclock/dependencies.d/mount-devfs b/services/hwclock/dependencies.d/mount-devfs new file mode 100644 index 0000000..e69de29 diff --git a/services/hwclock/type b/services/hwclock/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/hwclock/type @@ -0,0 +1 @@ +oneshot diff --git a/services/hwclock/up b/services/hwclock/up new file mode 100755 index 0000000..2ee1250 --- /dev/null +++ b/services/hwclock/up @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +s6.run_or_die("hwclock --hctosys --utc") diff --git a/services/kmod-static-nodes/dependencies.d/mount-devfs b/services/kmod-static-nodes/dependencies.d/mount-devfs new file mode 100644 index 0000000..e69de29 diff --git a/services/kmod-static-nodes/type b/services/kmod-static-nodes/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/kmod-static-nodes/type @@ -0,0 +1 @@ +oneshot diff --git a/services/kmod-static-nodes/up b/services/kmod-static-nodes/up new file mode 100755 index 0000000..06f76c5 --- /dev/null +++ b/services/kmod-static-nodes/up @@ -0,0 +1,5 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +s6.mkdirp("/run/tmpfiles.d") +s6.run_or_die("kmod static-nodes --format=tmpfiles --output=/run/tmpfiles.d/kmod.conf") diff --git a/services/lightdm-log/consumer-for b/services/lightdm-log/consumer-for new file mode 100644 index 0000000..5764f09 --- /dev/null +++ b/services/lightdm-log/consumer-for @@ -0,0 +1 @@ +lightdm-srv diff --git a/services/lightdm-log/pipeline-name b/services/lightdm-log/pipeline-name new file mode 100644 index 0000000..398d75f --- /dev/null +++ b/services/lightdm-log/pipeline-name @@ -0,0 +1 @@ +lightdm diff --git a/services/lightdm-log/run b/services/lightdm-log/run new file mode 100755 index 0000000..5f13de9 --- /dev/null +++ b/services/lightdm-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/lightdm") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/lightdm" }) diff --git a/services/lightdm-log/type b/services/lightdm-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/lightdm-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/lightdm-srv/dependencies.d/dbus-srv b/services/lightdm-srv/dependencies.d/dbus-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/lightdm-srv/dependencies.d/elogind-srv b/services/lightdm-srv/dependencies.d/elogind-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/lightdm-srv/finish b/services/lightdm-srv/finish new file mode 100755 index 0000000..9a1391b --- /dev/null +++ b/services/lightdm-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("lightdm", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/lightdm-srv/producer-for b/services/lightdm-srv/producer-for new file mode 100644 index 0000000..2ad054c --- /dev/null +++ b/services/lightdm-srv/producer-for @@ -0,0 +1 @@ +lightdm-log diff --git a/services/lightdm-srv/run b/services/lightdm-srv/run new file mode 100755 index 0000000..47c350a --- /dev/null +++ b/services/lightdm-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/sbin/lightdm" }) diff --git a/services/lightdm-srv/type b/services/lightdm-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/lightdm-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/locale/type b/services/locale/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/locale/type @@ -0,0 +1 @@ +oneshot diff --git a/services/locale/up b/services/locale/up new file mode 100755 index 0000000..3b61c65 --- /dev/null +++ b/services/locale/up @@ -0,0 +1,16 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +-- Loads the console keymap from /etc/vconsole.conf's KEYMAP= line. +local f = io.open("/etc/vconsole.conf", "r") +if not f then + os.exit(0) +end +for line in f:lines() do + local keymap = line:match('^KEYMAP=(.+)$') + if keymap then + keymap = keymap:gsub('^"(.*)"$', "%1") + s6.run(string.format("loadkeys %q", keymap)) + end +end +f:close() diff --git a/services/modules/dependencies.d/mount-procfs b/services/modules/dependencies.d/mount-procfs new file mode 100644 index 0000000..e69de29 diff --git a/services/modules/dependencies.d/mount-sysfs b/services/modules/dependencies.d/mount-sysfs new file mode 100644 index 0000000..e69de29 diff --git a/services/modules/type b/services/modules/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/modules/type @@ -0,0 +1 @@ +oneshot diff --git a/services/modules/up b/services/modules/up new file mode 100755 index 0000000..96814ba --- /dev/null +++ b/services/modules/up @@ -0,0 +1,14 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +-- Loads modules listed in /etc/modules-load.conf and /etc/modules-load.d/*.conf, +-- one modprobe per line, best-effort (a missing module shouldn't block boot). +local ok = s6.run([=[ +for f in /etc/modules-load.conf /etc/modules-load.d/*.conf; do + [ -f "$f" ] || continue + grep -Ev '^[[:space:]]*(#|$)' "$f" | while read -r mod; do modprobe -q "$mod" || true; done +done +]=]) +if not ok then + s6.log("modules", "module load pass reported errors (continuing)") +end diff --git a/services/mount-cgroups/dependencies.d/mount-sysfs b/services/mount-cgroups/dependencies.d/mount-sysfs new file mode 100644 index 0000000..e69de29 diff --git a/services/mount-cgroups/type b/services/mount-cgroups/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/mount-cgroups/type @@ -0,0 +1 @@ +oneshot diff --git a/services/mount-cgroups/up b/services/mount-cgroups/up new file mode 100755 index 0000000..2589dab --- /dev/null +++ b/services/mount-cgroups/up @@ -0,0 +1,8 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +if s6.is_mounted("/sys/fs/cgroup") then + os.exit(0) +end + +s6.run_or_die("mkdir -p /sys/fs/cgroup && mount -t cgroup2 cgroup2 /sys/fs/cgroup") diff --git a/services/mount-devfs/type b/services/mount-devfs/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/mount-devfs/type @@ -0,0 +1 @@ +oneshot diff --git a/services/mount-devfs/up b/services/mount-devfs/up new file mode 100755 index 0000000..0ec90c6 --- /dev/null +++ b/services/mount-devfs/up @@ -0,0 +1,8 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +if s6.is_mounted("/dev") then + os.exit(0) +end + +s6.run_or_die("mount -t devtmpfs -o mode=0755,nosuid devtmpfs /dev") diff --git a/services/mount-filesystems/dependencies.d/mount-procfs b/services/mount-filesystems/dependencies.d/mount-procfs new file mode 100644 index 0000000..e69de29 diff --git a/services/mount-filesystems/dependencies.d/mount-sysfs b/services/mount-filesystems/dependencies.d/mount-sysfs new file mode 100644 index 0000000..e69de29 diff --git a/services/mount-filesystems/type b/services/mount-filesystems/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/mount-filesystems/type @@ -0,0 +1 @@ +oneshot diff --git a/services/mount-filesystems/up b/services/mount-filesystems/up new file mode 100755 index 0000000..6877599 --- /dev/null +++ b/services/mount-filesystems/up @@ -0,0 +1,14 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +local skip_file = { ["/"] = true, ["none"] = true } +local skip_type = { proc = true, sysfs = true, devtmpfs = true, tmpfs = true, swap = true } + +for _, entry in ipairs(s6.parse_fstab("/etc/fstab")) do + if not skip_file[entry.file] and not skip_type[entry.vfstype] and entry.mntops ~= "noauto" then + local ok = s6.run(string.format("mount %q", entry.file)) + if not ok then + s6.log("mount-filesystems", "failed to mount %s", entry.file) + end + end +end diff --git a/services/mount-procfs/type b/services/mount-procfs/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/mount-procfs/type @@ -0,0 +1 @@ +oneshot diff --git a/services/mount-procfs/up b/services/mount-procfs/up new file mode 100755 index 0000000..ca63d9a --- /dev/null +++ b/services/mount-procfs/up @@ -0,0 +1,8 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +if s6.is_mounted("/proc") then + os.exit(0) +end + +s6.run_or_die("mount -t proc -o nosuid,noexec,nodev proc /proc") diff --git a/services/mount-sysfs/type b/services/mount-sysfs/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/mount-sysfs/type @@ -0,0 +1 @@ +oneshot diff --git a/services/mount-sysfs/up b/services/mount-sysfs/up new file mode 100755 index 0000000..9e947fe --- /dev/null +++ b/services/mount-sysfs/up @@ -0,0 +1,8 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +if s6.is_mounted("/sys") then + os.exit(0) +end + +s6.run_or_die("mount -t sysfs -o nosuid,noexec,nodev sysfs /sys") diff --git a/services/mount/contents.d/mount-cgroups b/services/mount/contents.d/mount-cgroups new file mode 100644 index 0000000..e69de29 diff --git a/services/mount/contents.d/mount-devfs b/services/mount/contents.d/mount-devfs new file mode 100644 index 0000000..e69de29 diff --git a/services/mount/contents.d/mount-filesystems b/services/mount/contents.d/mount-filesystems new file mode 100644 index 0000000..e69de29 diff --git a/services/mount/contents.d/mount-procfs b/services/mount/contents.d/mount-procfs new file mode 100644 index 0000000..e69de29 diff --git a/services/mount/contents.d/mount-sysfs b/services/mount/contents.d/mount-sysfs new file mode 100644 index 0000000..e69de29 diff --git a/services/mount/type b/services/mount/type new file mode 100644 index 0000000..757b422 --- /dev/null +++ b/services/mount/type @@ -0,0 +1 @@ +bundle diff --git a/services/networkmanager-log/consumer-for b/services/networkmanager-log/consumer-for new file mode 100644 index 0000000..3294f9f --- /dev/null +++ b/services/networkmanager-log/consumer-for @@ -0,0 +1 @@ +networkmanager-srv diff --git a/services/networkmanager-log/pipeline-name b/services/networkmanager-log/pipeline-name new file mode 100644 index 0000000..08bdf02 --- /dev/null +++ b/services/networkmanager-log/pipeline-name @@ -0,0 +1 @@ +networkmanager diff --git a/services/networkmanager-log/run b/services/networkmanager-log/run new file mode 100755 index 0000000..4b743a0 --- /dev/null +++ b/services/networkmanager-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/networkmanager") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/networkmanager" }) diff --git a/services/networkmanager-log/type b/services/networkmanager-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/networkmanager-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/networkmanager-srv/dependencies.d/dbus-srv b/services/networkmanager-srv/dependencies.d/dbus-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/networkmanager-srv/finish b/services/networkmanager-srv/finish new file mode 100755 index 0000000..18db9d4 --- /dev/null +++ b/services/networkmanager-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("networkmanager", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/networkmanager-srv/producer-for b/services/networkmanager-srv/producer-for new file mode 100644 index 0000000..d2e331f --- /dev/null +++ b/services/networkmanager-srv/producer-for @@ -0,0 +1 @@ +networkmanager-log diff --git a/services/networkmanager-srv/run b/services/networkmanager-srv/run new file mode 100755 index 0000000..238f063 --- /dev/null +++ b/services/networkmanager-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/bin/NetworkManager", "--no-daemon" }) diff --git a/services/networkmanager-srv/type b/services/networkmanager-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/networkmanager-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/rc-local/dependencies.d/cleanup b/services/rc-local/dependencies.d/cleanup new file mode 100644 index 0000000..e69de29 diff --git a/services/rc-local/dependencies.d/mount-filesystems b/services/rc-local/dependencies.d/mount-filesystems new file mode 100644 index 0000000..e69de29 diff --git a/services/rc-local/type b/services/rc-local/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/services/rc-local/type @@ -0,0 +1 @@ +oneshot diff --git a/services/rc-local/up b/services/rc-local/up new file mode 100755 index 0000000..96e8ffe --- /dev/null +++ b/services/rc-local/up @@ -0,0 +1,11 @@ +#!/usr/bin/lua +local s6 = require("s6lua") + +local path = "/etc/rc.local" +local f = io.open(path, "r") +if not f then + os.exit(0) +end +f:close() + +s6.run_or_die(string.format("[ -x %q ] && %q", path, path)) diff --git a/services/sddm-log/consumer-for b/services/sddm-log/consumer-for new file mode 100644 index 0000000..bf97ee2 --- /dev/null +++ b/services/sddm-log/consumer-for @@ -0,0 +1 @@ +sddm-srv diff --git a/services/sddm-log/pipeline-name b/services/sddm-log/pipeline-name new file mode 100644 index 0000000..effea0f --- /dev/null +++ b/services/sddm-log/pipeline-name @@ -0,0 +1 @@ +sddm diff --git a/services/sddm-log/run b/services/sddm-log/run new file mode 100755 index 0000000..2aa938d --- /dev/null +++ b/services/sddm-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/sddm") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/sddm" }) diff --git a/services/sddm-log/type b/services/sddm-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/sddm-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/sddm-srv/dependencies.d/dbus-srv b/services/sddm-srv/dependencies.d/dbus-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/sddm-srv/dependencies.d/elogind-srv b/services/sddm-srv/dependencies.d/elogind-srv new file mode 100644 index 0000000..e69de29 diff --git a/services/sddm-srv/finish b/services/sddm-srv/finish new file mode 100755 index 0000000..eba6a06 --- /dev/null +++ b/services/sddm-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("sddm", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/sddm-srv/producer-for b/services/sddm-srv/producer-for new file mode 100644 index 0000000..2350659 --- /dev/null +++ b/services/sddm-srv/producer-for @@ -0,0 +1 @@ +sddm-log diff --git a/services/sddm-srv/run b/services/sddm-srv/run new file mode 100755 index 0000000..1169908 --- /dev/null +++ b/services/sddm-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/bin/sddm" }) diff --git a/services/sddm-srv/type b/services/sddm-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/sddm-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/seatd-log/consumer-for b/services/seatd-log/consumer-for new file mode 100644 index 0000000..5639fee --- /dev/null +++ b/services/seatd-log/consumer-for @@ -0,0 +1 @@ +seatd-srv diff --git a/services/seatd-log/pipeline-name b/services/seatd-log/pipeline-name new file mode 100644 index 0000000..fd6b59e --- /dev/null +++ b/services/seatd-log/pipeline-name @@ -0,0 +1 @@ +seatd diff --git a/services/seatd-log/run b/services/seatd-log/run new file mode 100755 index 0000000..58285db --- /dev/null +++ b/services/seatd-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/seatd") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/seatd" }) diff --git a/services/seatd-log/type b/services/seatd-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/seatd-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/seatd-srv/finish b/services/seatd-srv/finish new file mode 100755 index 0000000..5a4dae9 --- /dev/null +++ b/services/seatd-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("seatd", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/seatd-srv/producer-for b/services/seatd-srv/producer-for new file mode 100644 index 0000000..c2c15c5 --- /dev/null +++ b/services/seatd-srv/producer-for @@ -0,0 +1 @@ +seatd-log diff --git a/services/seatd-srv/run b/services/seatd-srv/run new file mode 100755 index 0000000..fd4d672 --- /dev/null +++ b/services/seatd-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/bin/seatd", "-g", "seat" }) diff --git a/services/seatd-srv/type b/services/seatd-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/seatd-srv/type @@ -0,0 +1 @@ +longrun diff --git a/services/setup/contents.d/cleanup b/services/setup/contents.d/cleanup new file mode 100644 index 0000000..e69de29 diff --git a/services/setup/contents.d/console-setup b/services/setup/contents.d/console-setup new file mode 100644 index 0000000..e69de29 diff --git a/services/setup/contents.d/hostname b/services/setup/contents.d/hostname new file mode 100644 index 0000000..e69de29 diff --git a/services/setup/contents.d/hwclock b/services/setup/contents.d/hwclock new file mode 100644 index 0000000..e69de29 diff --git a/services/setup/contents.d/kmod-static-nodes b/services/setup/contents.d/kmod-static-nodes new file mode 100644 index 0000000..e69de29 diff --git a/services/setup/contents.d/locale b/services/setup/contents.d/locale new file mode 100644 index 0000000..e69de29 diff --git a/services/setup/contents.d/modules b/services/setup/contents.d/modules new file mode 100644 index 0000000..e69de29 diff --git a/services/setup/contents.d/rc-local b/services/setup/contents.d/rc-local new file mode 100644 index 0000000..e69de29 diff --git a/services/setup/type b/services/setup/type new file mode 100644 index 0000000..757b422 --- /dev/null +++ b/services/setup/type @@ -0,0 +1 @@ +bundle diff --git a/services/ttys/contents.d/agetty-tty1 b/services/ttys/contents.d/agetty-tty1 new file mode 100644 index 0000000..e69de29 diff --git a/services/ttys/contents.d/agetty-tty2 b/services/ttys/contents.d/agetty-tty2 new file mode 100644 index 0000000..e69de29 diff --git a/services/ttys/contents.d/agetty-tty3 b/services/ttys/contents.d/agetty-tty3 new file mode 100644 index 0000000..e69de29 diff --git a/services/ttys/contents.d/agetty-tty4 b/services/ttys/contents.d/agetty-tty4 new file mode 100644 index 0000000..e69de29 diff --git a/services/ttys/contents.d/agetty-tty5 b/services/ttys/contents.d/agetty-tty5 new file mode 100644 index 0000000..e69de29 diff --git a/services/ttys/contents.d/agetty-tty6 b/services/ttys/contents.d/agetty-tty6 new file mode 100644 index 0000000..e69de29 diff --git a/services/ttys/type b/services/ttys/type new file mode 100644 index 0000000..757b422 --- /dev/null +++ b/services/ttys/type @@ -0,0 +1 @@ +bundle diff --git a/services/udevd-log/consumer-for b/services/udevd-log/consumer-for new file mode 100644 index 0000000..867667b --- /dev/null +++ b/services/udevd-log/consumer-for @@ -0,0 +1 @@ +udevd-srv diff --git a/services/udevd-log/pipeline-name b/services/udevd-log/pipeline-name new file mode 100644 index 0000000..45bd63d --- /dev/null +++ b/services/udevd-log/pipeline-name @@ -0,0 +1 @@ +udevd diff --git a/services/udevd-log/run b/services/udevd-log/run new file mode 100755 index 0000000..ebccfe2 --- /dev/null +++ b/services/udevd-log/run @@ -0,0 +1,4 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.mkdirp("/var/log/udevd") +s6.exec({ "/usr/bin/s6-log", "-b", "n20", "s10000000", "/var/log/udevd" }) diff --git a/services/udevd-log/type b/services/udevd-log/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/udevd-log/type @@ -0,0 +1 @@ +longrun diff --git a/services/udevd-srv/dependencies.d/mount-devfs b/services/udevd-srv/dependencies.d/mount-devfs new file mode 100644 index 0000000..e69de29 diff --git a/services/udevd-srv/finish b/services/udevd-srv/finish new file mode 100755 index 0000000..6f02abf --- /dev/null +++ b/services/udevd-srv/finish @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.log("udevd", "exited (code=%s signal=%s)", arg[1], arg[2]) diff --git a/services/udevd-srv/producer-for b/services/udevd-srv/producer-for new file mode 100644 index 0000000..5a7694f --- /dev/null +++ b/services/udevd-srv/producer-for @@ -0,0 +1 @@ +udevd-log diff --git a/services/udevd-srv/run b/services/udevd-srv/run new file mode 100755 index 0000000..6917fc3 --- /dev/null +++ b/services/udevd-srv/run @@ -0,0 +1,3 @@ +#!/usr/bin/lua +local s6 = require("s6lua") +s6.exec({ "/usr/lib/udev/udevd" }) diff --git a/services/udevd-srv/type b/services/udevd-srv/type new file mode 100644 index 0000000..5883cff --- /dev/null +++ b/services/udevd-srv/type @@ -0,0 +1 @@ +longrun diff --git a/src/lua/s6lua.lua b/src/lua/s6lua.lua new file mode 100644 index 0000000..1dfcb95 --- /dev/null +++ b/src/lua/s6lua.lua @@ -0,0 +1,122 @@ +-- Shared helper library for s6-lua service scripts. +-- Deploy to Lua's default LUA_PATH root (e.g. /usr/local/share/lua/5.4/s6lua.lua) +-- so every run/up/down/finish script can `require("s6lua")` with no path setup. +-- Written against the Lua 5.1 stdlib subset so it parses/runs unmodified under 5.4 and 5.5. + +local s6 = {} + +function s6.log(tag, fmt, ...) + io.stderr:write(string.format("[%s] %s\n", tag, string.format(fmt, ...))) +end + +function s6.die(fmt, ...) + io.stderr:write(string.format(fmt, ...) .. "\n") + os.exit(1) +end + +-- Process replacement for longrun `run` scripts. Wraps the native s6exec.so +-- binding; require()d lazily so oneshot-only scripts that never call exec +-- don't force-load the native module. argv is a 1-indexed array of strings; +-- argv[1] is both the PATH-searched program and the argv[0] the process sees. +function s6.try_exec(argv) + local s6exec = require("s6exec") + return s6exec.exec(argv) +end + +-- Same as try_exec, but dies instead of returning on failure. This is the +-- last line of every longrun `run` script. +function s6.exec(argv) + local ok, err, errno = s6.try_exec(argv) + s6.die("exec %s failed: %s (errno %s)", tostring(argv[1]), tostring(err), tostring(errno)) +end + +-- Oneshot-only helper: runs to completion and returns, never needs to +-- persist as the supervised process, so plain os.execute is safe here. +function s6.run(cmd) + local ok, how, code = os.execute(cmd) + if ok == true then + return true, 0 + end + -- Lua 5.1 returns a numeric exit code directly as `ok`; 5.2+ returns + -- (nil/false, "exit"|"signal", code). Normalize both. + if type(ok) == "number" then + return ok == 0, ok + end + return false, code or 1 +end + +function s6.run_or_die(cmd) + local ok, code = s6.run(cmd) + if not ok then + s6.die("command failed (exit %s): %s", tostring(code), cmd) + end +end + +-- Opt-in readiness notification for longrun services with a notification-fd +-- file. Pure Lua, no native code needed: on Linux, /proc/self/fd/ is a +-- writable alias for the fd s6-supervise opened before exec-ing `run`. +-- NOT wired into any default generated template — call this only from a +-- purpose-built readiness check, never from `run` before the real exec, +-- since that would falsely signal readiness before the daemon initializes. +function s6.notify_ready(fd) + local f, err = io.open("/proc/self/fd/" .. tostring(fd), "w") + if not f then + return nil, err + end + f:write("\n") + f:close() + return true +end + +function s6.is_mounted(path) + local f = io.open("/proc/mounts", "r") + if not f then + return false + end + for line in f:lines() do + local mountpoint = line:match("^%S+%s+(%S+)%s") + if mountpoint == path then + f:close() + return true + end + end + f:close() + return false +end + +function s6.mkdirp(path) + return s6.run(string.format('mkdir -p "%s"', path)) +end + +-- Parses an fstab-format file. Returns an array of +-- {spec=, file=, vfstype=, mntops=, freq=, passno=}, skipping blank lines +-- and comments. +function s6.parse_fstab(path) + path = path or "/etc/fstab" + local entries = {} + local f = io.open(path, "r") + if not f then + return entries + end + for line in f:lines() do + local trimmed = line:match("^%s*(.-)%s*$") + if trimmed ~= "" and trimmed:sub(1, 1) ~= "#" then + local spec, file, vfstype, mntops, freq, passno = + trimmed:match("^(%S+)%s+(%S+)%s+(%S+)%s+(%S+)%s*(%S*)%s*(%S*)") + if spec then + table.insert(entries, { + spec = spec, + file = file, + vfstype = vfstype, + mntops = mntops, + freq = freq ~= "" and freq or "0", + passno = passno ~= "" and passno or "0", + }) + end + end + end + f:close() + return entries +end + +return s6 diff --git a/src/native/Makefile b/src/native/Makefile new file mode 100644 index 0000000..5333d8d --- /dev/null +++ b/src/native/Makefile @@ -0,0 +1,22 @@ +# Linux-only. Not runnable on the Windows authoring machine -- no C +# toolchain confirmed there, and s6exec.so only means anything under a real +# Linux/Lua install. Build for real on the target: +# make LUA_VERSION=5.4 +# sudo make install LUA_VERSION=5.4 + +LUA_VERSION ?= 5.4 +LUA_INC ?= /usr/include/lua$(LUA_VERSION) +PREFIX ?= /usr/local +CC ?= cc +CFLAGS ?= -O2 -fPIC -Wall -Wextra -I$(LUA_INC) + +s6exec.so: s6exec.c + $(CC) $(CFLAGS) -shared -o $@ $< + +install: s6exec.so + install -Dm755 s6exec.so $(DESTDIR)$(PREFIX)/lib/lua/$(LUA_VERSION)/s6exec.so + +clean: + rm -f s6exec.so + +.PHONY: install clean diff --git a/src/native/s6exec.c b/src/native/s6exec.c new file mode 100644 index 0000000..7bc0a50 --- /dev/null +++ b/src/native/s6exec.c @@ -0,0 +1,63 @@ +/* s6exec: minimal Lua binding for execvp(2). + * + * s6-supervise tracks/signals whatever PID it directly forks for a longrun + * service. Stock Lua has no exec() binding, and os.execute("exec ...") + * does not solve this: it forks a shell that execs, but the parent Lua + * process stays alive blocked in waitpid(), so s6 ends up supervising the + * Lua interpreter instead of the real daemon. This module lets a `run` + * script replace its own process image directly, the same way a shell + * script's final `exec daemon args...` would. + * + * Only execvp is bound (PATH-searched, no env argument): s6-supervise + * already applies a service's env/ directory to the environment before + * exec-ing `run`, so Lua doesn't need to touch env vars itself. + * + * Linux-only build. Not compiled or tested on the Windows authoring + * machine -- there is no C toolchain confirmed there, and this module only + * means anything under a real Linux/Lua install. Build for real on the + * target with `make -C src/native install`. + */ + +#include +#include +#include +#include + +#include +#include + +static int l_exec(lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_Integer n = luaL_len(L, 1); + if (n < 1) { + return luaL_error(L, "s6exec.exec: argv must have at least 1 element"); + } + + char **argv = calloc((size_t)n + 1, sizeof(char *)); + if (!argv) { + return luaL_error(L, "s6exec.exec: out of memory"); + } + for (lua_Integer i = 1; i <= n; i++) { + lua_geti(L, 1, i); + argv[i - 1] = strdup(luaL_checkstring(L, -1)); + lua_pop(L, 1); + } + argv[n] = NULL; + + execvp(argv[0], argv); /* only returns on failure */ + int err = errno; + lua_pushnil(L); + lua_pushstring(L, strerror(err)); + lua_pushinteger(L, err); + return 3; +} + +static const luaL_Reg s6exec_funcs[] = { + {"exec", l_exec}, + {NULL, NULL}, +}; + +int luaopen_s6exec(lua_State *L) { + luaL_newlib(L, s6exec_funcs); + return 1; +} diff --git a/tools/catalog.lua b/tools/catalog.lua new file mode 100644 index 0000000..3dabc62 --- /dev/null +++ b/tools/catalog.lua @@ -0,0 +1,93 @@ +-- Data table consumed by gen-services.lua to stamp out the structurally +-- identical -srv/-log longrun pairs and agetty-tty1..6, instead of hand- +-- authoring ~40 near-duplicate service directories. +-- +-- KNOWN GAP: Artix's own `s6-scripts` gitea repo blocked automated fetches +-- during research for this catalog, so argv/flags below are reconstructed +-- from each daemon's own documented foreground-mode flag (dbus-daemon +-- --nofork, NetworkManager --no-daemon, chronyd/bluetoothd/acpid/cupsd -n/-f) +-- rather than confirmed byte-for-byte against a reference script. Spot-check +-- against the real Artix catalog (or the daemon's man page) before relying +-- on this in production; this table is the single place to correct it. +-- +-- To add a new daemon: append a row to `daemons` and rerun +-- `lua55 tools/gen-services.lua`. + +return { + daemons = { + { + key = "udevd", srv = "udevd-srv", log = "udevd-log", + argv = { "/usr/lib/udev/udevd" }, + log_dir = "/var/log/udevd", + deps = { "mount-devfs" }, + }, + { + key = "dbus", srv = "dbus-srv", log = "dbus-log", + argv = { "/usr/bin/dbus-daemon", "--system", "--nofork", "--nopidfile" }, + log_dir = "/var/log/dbus", + deps = { "mount-procfs", "mount-sysfs" }, + }, + { + key = "elogind", srv = "elogind-srv", log = "elogind-log", + argv = { "/usr/lib/elogind/elogind" }, + log_dir = "/var/log/elogind", + deps = { "dbus-srv" }, + }, + { + key = "seatd", srv = "seatd-srv", log = "seatd-log", + argv = { "/usr/bin/seatd", "-g", "seat" }, + log_dir = "/var/log/seatd", + deps = {}, + }, + { + key = "networkmanager", srv = "networkmanager-srv", log = "networkmanager-log", + argv = { "/usr/bin/NetworkManager", "--no-daemon" }, + log_dir = "/var/log/networkmanager", + deps = { "dbus-srv" }, + }, + { + key = "chronyd", srv = "chronyd-srv", log = "chronyd-log", + argv = { "/usr/bin/chronyd", "-n" }, + log_dir = "/var/log/chronyd", + deps = { "mount-filesystems" }, + }, + { + key = "bluetoothd", srv = "bluez-srv", log = "bluez-log", + argv = { "/usr/lib/bluetooth/bluetoothd", "-n" }, + log_dir = "/var/log/bluez", + deps = { "dbus-srv" }, + }, + { + key = "acpid", srv = "acpid-srv", log = "acpid-log", + argv = { "/usr/sbin/acpid", "-f" }, + log_dir = "/var/log/acpid", + deps = { "mount-procfs" }, + }, + { + key = "cupsd", srv = "cupsd-srv", log = "cupsd-log", + argv = { "/usr/sbin/cupsd", "-f" }, + log_dir = "/var/log/cupsd", + deps = { "dbus-srv" }, + }, + { + key = "gdm", srv = "gdm-srv", log = "gdm-log", + argv = { "/usr/bin/gdm" }, + log_dir = "/var/log/gdm", + deps = { "dbus-srv", "elogind-srv" }, + }, + { + key = "sddm", srv = "sddm-srv", log = "sddm-log", + argv = { "/usr/bin/sddm" }, + log_dir = "/var/log/sddm", + deps = { "dbus-srv", "elogind-srv" }, + }, + { + key = "lightdm", srv = "lightdm-srv", log = "lightdm-log", + argv = { "/usr/sbin/lightdm" }, + log_dir = "/var/log/lightdm", + deps = { "dbus-srv", "elogind-srv" }, + }, + }, + + ttys = { 1, 2, 3, 4, 5, 6 }, +} diff --git a/tools/check-syntax.ps1 b/tools/check-syntax.ps1 new file mode 100644 index 0000000..b559e0d --- /dev/null +++ b/tools/check-syntax.ps1 @@ -0,0 +1,35 @@ +# Runs luac55 -p (parse-only) over every service script and every Lua +# source file, since this Windows box has no way to actually load/execute +# anything that touches POSIX (require("s6exec"), /proc, etc.). +param() + +$ErrorActionPreference = "Stop" +$repoRoot = Split-Path -Parent $PSScriptRoot + +$luac = (Get-Command luac55 -ErrorAction SilentlyContinue).Source +if (-not $luac) { $luac = "C:\Program Files\lua-5.5.0_Win64_bin\luac55.exe" } + +$scriptNames = @('run', 'up', 'down', 'finish', 'reload', 'check') + +$targets = @() +$targets += Get-ChildItem -Path (Join-Path $repoRoot 'services') -Recurse -File | + Where-Object { $scriptNames -contains $_.Name } +$targets += Get-ChildItem -Path (Join-Path $repoRoot 'src') -Recurse -File -Filter '*.lua' +$targets += Get-ChildItem -Path (Join-Path $repoRoot 'tools') -Recurse -File -Filter '*.lua' + +$failed = @() +foreach ($t in $targets) { + & $luac -p $t.FullName + if ($LASTEXITCODE -ne 0) { + $failed += $t.FullName + } +} + +Write-Host "" +Write-Host "Checked $($targets.Count) file(s)." +if ($failed.Count -gt 0) { + Write-Host "FAILED syntax check on $($failed.Count) file(s):" -ForegroundColor Red + $failed | ForEach-Object { Write-Host " $_" -ForegroundColor Red } + exit 1 +} +Write-Host "All files parsed OK." -ForegroundColor Green diff --git a/tools/gen-services.lua b/tools/gen-services.lua new file mode 100644 index 0000000..17c7f03 --- /dev/null +++ b/tools/gen-services.lua @@ -0,0 +1,109 @@ +-- Reads tools/catalog.lua and stamps out the -srv/-log longrun pairs and +-- agetty-tty1..6 under services/. Authored/run on the Windows box with +-- lua55; portable enough to rerun on a real Linux target later. Files are +-- written with explicit "\n" line endings in binary mode so Windows doesn't +-- translate them to CRLF. +-- +-- Usage: lua55 tools/gen-services.lua + +local script_dir = arg[0]:match("^(.*)[/\\][^/\\]*$") or "." +local repo_root = script_dir .. "/.." +local services_dir = repo_root .. "/services" + +local catalog = dofile(script_dir .. "/catalog.lua") + +local function is_windows() + return package.config:sub(1, 1) == "\\" +end + +local function mkdir_p(path) + if is_windows() then + local winpath = path:gsub("/", "\\") + os.execute('if not exist "' .. winpath .. '" mkdir "' .. winpath .. '" >nul 2>nul') + else + os.execute('mkdir -p "' .. path .. '"') + end +end + +local function dirname(path) + return path:match("^(.*)[/\\][^/\\]*$") or "." +end + +local function write_file(path, content) + mkdir_p(dirname(path)) + local f = assert(io.open(path, "wb")) + f:write(content) + f:close() +end + +local function touch(path) + write_file(path, "") +end + +local function lua_array_literal(items) + local parts = {} + for i, v in ipairs(items) do + parts[i] = string.format("%q", v) + end + return "{ " .. table.concat(parts, ", ") .. " }" +end + +local function render_srv_run(argv) + return string.format( + "#!/usr/bin/lua\nlocal s6 = require(\"s6lua\")\ns6.exec(%s)\n", + lua_array_literal(argv) + ) +end + +local function render_finish(tag) + return string.format( + "#!/usr/bin/lua\nlocal s6 = require(\"s6lua\")\ns6.log(%q, \"exited (code=%%s signal=%%s)\", arg[1], arg[2])\n", + tag + ) +end + +local function render_log_run(log_dir) + return string.format( + "#!/usr/bin/lua\nlocal s6 = require(\"s6lua\")\ns6.mkdirp(%q)\ns6.exec({ \"/usr/bin/s6-log\", \"-b\", \"n20\", \"s10000000\", %q })\n", + log_dir, log_dir + ) +end + +local function render_agetty_run(n) + return render_srv_run({ "/sbin/agetty", "tty" .. tostring(n), "38400", "linux" }) +end + +for _, d in ipairs(catalog.daemons) do + local srv_dir = services_dir .. "/" .. d.srv + local log_svc_dir = services_dir .. "/" .. d.log + + write_file(srv_dir .. "/type", "longrun\n") + write_file(srv_dir .. "/run", render_srv_run(d.argv)) + write_file(srv_dir .. "/finish", render_finish(d.key)) + write_file(srv_dir .. "/producer-for", d.log .. "\n") + for _, dep in ipairs(d.deps) do + touch(srv_dir .. "/dependencies.d/" .. dep) + end + + write_file(log_svc_dir .. "/type", "longrun\n") + write_file(log_svc_dir .. "/run", render_log_run(d.log_dir)) + write_file(log_svc_dir .. "/consumer-for", d.srv .. "\n") + write_file(log_svc_dir .. "/pipeline-name", d.key .. "\n") + + print("generated " .. d.srv .. " / " .. d.log) +end + +if catalog.ttys and #catalog.ttys > 0 then + local ttys_dir = services_dir .. "/ttys" + write_file(ttys_dir .. "/type", "bundle\n") + for _, n in ipairs(catalog.ttys) do + local name = "agetty-tty" .. tostring(n) + local dir = services_dir .. "/" .. name + write_file(dir .. "/type", "longrun\n") + write_file(dir .. "/run", render_agetty_run(n)) + touch(ttys_dir .. "/contents.d/" .. name) + print("generated " .. name) + end +end + +print("done") diff --git a/tools/install.sh b/tools/install.sh new file mode 100644 index 0000000..251cb82 --- /dev/null +++ b/tools/install.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# Linux-only. Deploys the shared Lua library, builds+installs the native +# exec module, copies service definitions into place, and compiles the +# s6-rc database. +# +# NOT run this session -- no s6/s6-rc install available to test against. +# Reviewed by inspection only; exercise for real on the target (the Arch +# WSL distro is the recommended first target, see docs/CONVENTIONS.md) +# before trusting it. +set -e + +PREFIX=${PREFIX:-/usr/local} +LUA_VERSION=${LUA_VERSION:-5.4} +SERVICE_SRC=${SERVICE_SRC:-/etc/s6/sv} +SERVICE_COMPILED=${SERVICE_COMPILED:-/etc/s6-rc/compiled} + +repo_root=$(cd "$(dirname "$0")/.." && pwd) + +echo "==> installing shared Lua library" +install -Dm644 "$repo_root/src/lua/s6lua.lua" \ + "$PREFIX/share/lua/$LUA_VERSION/s6lua.lua" + +echo "==> building + installing native exec module" +make -C "$repo_root/src/native" LUA_VERSION="$LUA_VERSION" PREFIX="$PREFIX" install + +echo "==> installing service definitions to $SERVICE_SRC" +mkdir -p "$SERVICE_SRC" +cp -a "$repo_root"/services/. "$SERVICE_SRC"/ + +echo "==> compiling s6-rc database" +rm -rf "$SERVICE_COMPILED.new" +s6-rc-compile "$SERVICE_COMPILED.new" "$SERVICE_SRC" +mv "$SERVICE_COMPILED.new" "$SERVICE_COMPILED" + +echo "done. Boot-test the 'boot' bundle before enabling 'graphical'." diff --git a/tools/lint.lua b/tools/lint.lua new file mode 100644 index 0000000..1627280 --- /dev/null +++ b/tools/lint.lua @@ -0,0 +1,131 @@ +-- Pure-Lua structural linter over services/. Validates that every service +-- directory has the files its `type` requires, that every +-- dependencies.d/contents.d entry names a real sibling service, and that +-- producer-for/consumer-for pairs are mutually consistent. +-- +-- No lfs/posix available, so directory listing shells out to `dir /b` on +-- Windows or `ls -1a` on Unix. +-- +-- Usage: lua55 tools/lint.lua + +local function is_windows() + return package.config:sub(1, 1) == "\\" +end + +local function list_dir(path) + local cmd + if is_windows() then + cmd = 'dir /b "' .. path:gsub("/", "\\") .. '" 2>nul' + else + cmd = 'ls -1a "' .. path .. '" 2>/dev/null' + end + local entries = {} + local p = io.popen(cmd) + if not p then + return entries + end + for line in p:lines() do + if line ~= "." and line ~= ".." and line ~= "" then + table.insert(entries, line) + end + end + p:close() + return entries +end + +local function read_file(path) + local f = io.open(path, "r") + if not f then + return nil + end + local content = f:read("*a") + f:close() + return content +end + +local function trim(s) + return s:match("^%s*(.-)%s*$") +end + +local script_dir = arg[0]:match("^(.*)[/\\][^/\\]*$") or "." +local repo_root = script_dir .. "/.." +local services_dir = repo_root .. "/services" + +local errors = {} +local function fail(fmt, ...) + table.insert(errors, string.format(fmt, ...)) +end + +local names = list_dir(services_dir) +local svc_type = {} + +for _, name in ipairs(names) do + local dir = services_dir .. "/" .. name + local t = read_file(dir .. "/type") + if not t then + fail("%s: missing 'type' file", name) + else + t = trim(t) + svc_type[name] = t + if t ~= "oneshot" and t ~= "longrun" and t ~= "bundle" then + fail("%s: type must be oneshot|longrun|bundle, got %q", name, t) + elseif t == "oneshot" and not read_file(dir .. "/up") then + fail("%s: oneshot missing 'up'", name) + elseif t == "longrun" and not read_file(dir .. "/run") then + fail("%s: longrun missing 'run'", name) + elseif t == "bundle" and #list_dir(dir .. "/contents.d") == 0 then + fail("%s: bundle has empty/missing contents.d", name) + end + end +end + +local function exists(name) + return svc_type[name] ~= nil +end + +for _, name in ipairs(names) do + local dir = services_dir .. "/" .. name + + for _, dep in ipairs(list_dir(dir .. "/dependencies.d")) do + if not exists(dep) then + fail("%s: dependencies.d references unknown service %q", name, dep) + end + end + + for _, member in ipairs(list_dir(dir .. "/contents.d")) do + if not exists(member) then + fail("%s: contents.d references unknown service %q", name, member) + end + end + + local producer = read_file(dir .. "/producer-for") + if producer then + producer = trim(producer) + if not exists(producer) then + fail("%s: producer-for references unknown service %q", name, producer) + else + local consumer = read_file(services_dir .. "/" .. producer .. "/consumer-for") + if not consumer or trim(consumer) ~= name then + fail("%s: producer-for %s but %s's consumer-for does not point back", name, producer, producer) + end + if not read_file(services_dir .. "/" .. producer .. "/pipeline-name") then + fail("%s: logger %s missing pipeline-name", name, producer) + end + end + end + + local nfd = read_file(dir .. "/notification-fd") + if nfd and not trim(nfd):match("^%d+$") then + fail("%s: notification-fd must be a bare integer, got %q", name, trim(nfd)) + end +end + +if #errors > 0 then + for _, e in ipairs(errors) do + io.stderr:write("LINT: " .. e .. "\n") + end + io.stderr:write(string.format("%d lint error(s)\n", #errors)) + os.exit(1) +end + +print(string.format("lint OK: %d service directories checked", #names)) diff --git a/tools/set-exec-bits.ps1 b/tools/set-exec-bits.ps1 new file mode 100644 index 0000000..2f50696 --- /dev/null +++ b/tools/set-exec-bits.ps1 @@ -0,0 +1,22 @@ +# Git tracks the executable bit in the tree object mode (100755 vs 100644) +# independent of the filesystem, but a Windows checkout won't set it for +# you on `git add`. Without this, s6-supervise fails to exec these scripts +# on the real target, and nothing in the syntax/lint checks would catch it. +param() + +$ErrorActionPreference = "Stop" +$repoRoot = Split-Path -Parent $PSScriptRoot +Set-Location $repoRoot + +$scriptNames = @('run', 'up', 'down', 'finish', 'reload', 'check') + +$files = Get-ChildItem -Path (Join-Path $repoRoot 'services') -Recurse -File | + Where-Object { $scriptNames -contains $_.Name } + +foreach ($f in $files) { + $relPath = (Resolve-Path -Relative $f.FullName) -replace '\\', '/' + git add -- $relPath | Out-Null + git update-index --chmod=+x -- $relPath +} + +Write-Host "Set executable bit on $($files.Count) file(s)."