1{ config, lib, ... }:
2
3{
4
5 imports = [ ./etc.nix ];
6
7 config = lib.mkMerge [
8
9 {
10 system.activationScripts.etc =
11 lib.stringAfter [ "users" "groups" ] config.system.build.etcActivationCommands;
12 }
13
14 (lib.mkIf config.system.etc.overlay.enable {
15
16 assertions = [
17 {
18 assertion = config.boot.initrd.systemd.enable;
19 message = "`system.etc.overlay.enable` requires `boot.initrd.systemd.enable`";
20 }
21 {
22 assertion = (!config.system.etc.overlay.mutable) -> config.systemd.sysusers.enable;
23 message = "`system.etc.overlay.mutable = false` requires `systemd.sysusers.enable`";
24 }
25 {
26 assertion = lib.versionAtLeast config.boot.kernelPackages.kernel.version "6.6";
27 message = "`system.etc.overlay.enable requires a newer kernel, at least version 6.6";
28 }
29 {
30 assertion = config.systemd.sysusers.enable -> (config.users.mutableUsers == config.system.etc.overlay.mutable);
31 message = ''
32 When using systemd-sysusers and mounting `/etc` via an overlay, users
33 can only be mutable when `/etc` is mutable and vice versa.
34 '';
35 }
36 ];
37
38 boot.initrd.availableKernelModules = [ "loop" "erofs" "overlay" ];
39
40 boot.initrd.systemd = {
41 mounts = [
42 {
43 where = "/run/etc-metadata";
44 what = "/sysroot${config.system.build.etcMetadataImage}";
45 type = "erofs";
46 options = "loop";
47 unitConfig.RequiresMountsFor = [
48 "/sysroot/nix/store"
49 ];
50 }
51 {
52 where = "/sysroot/etc";
53 what = "overlay";
54 type = "overlay";
55 options = lib.concatStringsSep "," ([
56 "relatime"
57 "redirect_dir=on"
58 "metacopy=on"
59 "lowerdir=/run/etc-metadata::/sysroot${config.system.build.etcBasedir}"
60 ] ++ lib.optionals config.system.etc.overlay.mutable [
61 "rw"
62 "upperdir=/sysroot/.rw-etc/upper"
63 "workdir=/sysroot/.rw-etc/work"
64 ] ++ lib.optionals (!config.system.etc.overlay.mutable) [
65 "ro"
66 ]);
67 wantedBy = [ "initrd-fs.target" ];
68 before = [ "initrd-fs.target" ];
69 requires = lib.mkIf config.system.etc.overlay.mutable [ "rw-etc.service" ];
70 after = lib.mkIf config.system.etc.overlay.mutable [ "rw-etc.service" ];
71 unitConfig.RequiresMountsFor = [
72 "/sysroot/nix/store"
73 "/run/etc-metadata"
74 ];
75 }
76 ];
77 services = lib.mkIf config.system.etc.overlay.mutable {
78 rw-etc = {
79 unitConfig = {
80 DefaultDependencies = false;
81 RequiresMountsFor = "/sysroot";
82 };
83 serviceConfig = {
84 Type = "oneshot";
85 ExecStart = ''
86 /bin/mkdir -p -m 0755 /sysroot/.rw-etc/upper /sysroot/.rw-etc/work
87 '';
88 };
89 };
90 };
91 };
92
93 })
94
95 ];
96}