build: the unix paths retire — configuration, logs, and volumes move into the danos tree

/etc/init.csv and /etc/devices.csv become /system/configuration/*.csv (the
repo's etc/ moves to system/configuration/, mirroring the runtime tree),
/var/log becomes /system/logs, and /mnt/usb becomes /volumes/usb. The
kernel VFS gains a carve-out so FAT may serve exactly /system/configuration
and /system/logs beneath the initrd-backed /system while /system and /test
themselves stay unshadowable; FAT's single /var mount splits into those two
rewritten mounts. The kvfs readdir check learns /system's third child and
the ramdisk spawn sweep skips the configuration tree.

Suite 106/106.
This commit is contained in:
Daniel Samson
2026-07-31 19:41:35 +01:00
parent e4da4e0610
commit c4f16a5448
31 changed files with 161 additions and 128 deletions
+10 -10
View File
@@ -29,17 +29,17 @@ const fs = @import("file-system");
const csv = @import("csv");
/// The system services init brings up at boot are init's policy, not the kernel's —
/// and that policy is now data: `/etc/init.csv` (see `loadServices`), read at
/// and that policy is now data: `/system/configuration/init.csv` (see `loadServices`), read at
/// startup instead of a hardcoded list. Drivers are absent on purpose: the device
/// manager owns those.
///
/// The most services `/etc/init.csv` can list, and the most argv entries (beyond the
/// The most services `/system/configuration/init.csv` can list, and the most argv entries (beyond the
/// path) each may carry. Fixed caps because init parses the list into static storage —
/// the freestanding, no-allocator counterpart to the device manager's registry table.
const max_services = 16;
const max_service_args = 4;
/// One service init starts, parsed from a row of `/etc/init.csv`: its binary path
/// One service init starts, parsed from a row of `/system/configuration/init.csv`: its binary path
/// and argv, both slices into `init_csv` (held for the life of the process).
const Service = struct {
path: []const u8 = "",
@@ -50,7 +50,7 @@ const Service = struct {
}
};
/// The `/etc/init.csv` bytes, held because the parsed services slice into them.
/// The `/system/configuration/init.csv` bytes, held because the parsed services slice into them.
var init_csv: [4096]u8 = undefined;
var services: [max_services]Service = .{Service{}} ** max_services;
var service_count: usize = 0;
@@ -65,16 +65,16 @@ var restart_counts: [max_services]u32 = .{0} ** max_services;
var shutting_down = false;
var supervision_endpoint: ipc.Handle = 0;
/// Parse `/etc/init.csv` into `services`, in file order (startup order; shutdown is
/// Parse `/system/configuration/init.csv` into `services`, in file order (startup order; shutdown is
/// the reverse). Each row is a binary path followed by its argv, comma-separated;
/// `#` comments and blank lines are ignored. The file lives in the initial ramdisk,
/// which the kernel serves directly, so init — PID 1, running before any filesystem
/// service — reads it with a plain fs.open, the same mechanism the device manager
/// uses for /etc/devices.csv. A missing file means no services (the no-ramdisk
/// uses for /system/configuration/devices.csv. A missing file means no services (the no-ramdisk
/// isolation test): loud, but not fatal.
fn loadServices() void {
var file = fs.open("/etc/init.csv", .{}) orelse {
_ = logging.write("/system/services/init: /etc/init.csv missing — no services started\n");
var file = fs.open("/system/configuration/init.csv", .{}) orelse {
_ = logging.write("/system/services/init: /system/configuration/init.csv missing — no services started\n");
return;
};
defer file.close();
@@ -89,7 +89,7 @@ fn loadServices() void {
const body = csv.stripComment(line);
if (body.len == 0) continue;
if (service_count >= services.len) {
_ = logging.write("/system/services/init: /etc/init.csv has more services than the table holds\n");
_ = logging.write("/system/services/init: /system/configuration/init.csv has more services than the table holds\n");
break;
}
var it = csv.fields(body);
@@ -137,7 +137,7 @@ pub fn main() void {
// Load the service list, then bring each up supervised so init can stop them
// cleanly. Best-effort and silent: each service announces its own readiness,
// and with no /etc/init.csv (an isolation test) the loop starts nothing.
// and with no /system/configuration/init.csv (an isolation test) the loop starts nothing.
loadServices();
for (services[0..service_count], 0..) |*service, i| {
if (process.spawnSupervised(service.path, service.arguments(), supervision_endpoint)) |id| child_ids[i] = id;