1# generate the script used to activate the configuration.
2{ config, lib, pkgs, ... }:
3
4with lib;
5
6let
7
8 addAttributeName = mapAttrs (a: v: v // {
9 text = ''
10 #### Activation script snippet ${a}:
11 ${v.text}
12 '';
13 });
14
15 path = with pkgs; map getBin
16 [ coreutils
17 gnugrep
18 findutils
19 glibc # needed for getent
20 shadow
21 nettools # needed for hostname
22 utillinux # needed for mount and mountpoint
23 ];
24
25in
26
27{
28
29 ###### interface
30
31 options = {
32
33 system.activationScripts = mkOption {
34 default = {};
35
36 example = literalExample ''
37 { stdio = {
38 text = '''
39 # Needed by some programs.
40 ln -sfn /proc/self/fd /dev/fd
41 ln -sfn /proc/self/fd/0 /dev/stdin
42 ln -sfn /proc/self/fd/1 /dev/stdout
43 ln -sfn /proc/self/fd/2 /dev/stderr
44 ''';
45 deps = [];
46 };
47 }
48 '';
49
50 description = ''
51 A set of shell script fragments that are executed when a NixOS
52 system configuration is activated. Examples are updating
53 /etc, creating accounts, and so on. Since these are executed
54 every time you boot the system or run
55 <command>nixos-rebuild</command>, it's important that they are
56 idempotent and fast.
57 '';
58
59 type = types.attrsOf types.unspecified; # FIXME
60
61 apply = set: {
62 script =
63 ''
64 #! ${pkgs.stdenv.shell}
65
66 systemConfig=@out@
67
68 export PATH=/empty
69 for i in ${toString path}; do
70 PATH=$PATH:$i/bin:$i/sbin
71 done
72
73 _status=0
74 trap "_status=1" ERR
75
76 # Ensure a consistent umask.
77 umask 0022
78
79 ${
80 let
81 set' = mapAttrs (n: v: if isString v then noDepEntry v else v) set;
82 withHeadlines = addAttributeName set';
83 in textClosureMap id (withHeadlines) (attrNames withHeadlines)
84 }
85
86 # Make this configuration the current configuration.
87 # The readlink is there to ensure that when $systemConfig = /system
88 # (which is a symlink to the store), /run/current-system is still
89 # used as a garbage collection root.
90 ln -sfn "$(readlink -f "$systemConfig")" /run/current-system
91
92 # Prevent the current configuration from being garbage-collected.
93 ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
94
95 exit $_status
96 '';
97 };
98
99 };
100
101 environment.usrbinenv = mkOption {
102 default = "${pkgs.coreutils}/bin/env";
103 example = literalExample ''
104 "''${pkgs.busybox}/bin/env"
105 '';
106 type = types.nullOr types.path;
107 visible = false;
108 description = ''
109 The env(1) executable that is linked system-wide to
110 <literal>/usr/bin/env</literal>.
111 '';
112 };
113 };
114
115
116 ###### implementation
117
118 config = {
119
120 system.activationScripts.stdio =
121 ''
122 # Needed by some programs.
123 ln -sfn /proc/self/fd /dev/fd
124 ln -sfn /proc/self/fd/0 /dev/stdin
125 ln -sfn /proc/self/fd/1 /dev/stdout
126 ln -sfn /proc/self/fd/2 /dev/stderr
127 '';
128
129 system.activationScripts.var =
130 ''
131 # Various log/runtime directories.
132
133 mkdir -m 0755 -p /run/nix/current-load # for distributed builds
134 mkdir -m 0700 -p /run/nix/remote-stores
135
136 mkdir -m 0755 -p /var/log
137
138 touch /var/log/wtmp /var/log/lastlog # must exist
139 chmod 644 /var/log/wtmp /var/log/lastlog
140
141 mkdir -m 1777 -p /var/tmp
142
143 # Empty, immutable home directory of many system accounts.
144 mkdir -p /var/empty
145 # Make sure it's really empty
146 ${pkgs.e2fsprogs}/bin/chattr -f -i /var/empty || true
147 find /var/empty -mindepth 1 -delete
148 chmod 0555 /var/empty
149 chown root:root /var/empty
150 ${pkgs.e2fsprogs}/bin/chattr -f +i /var/empty || true
151 '';
152
153 system.activationScripts.usrbinenv = if config.environment.usrbinenv != null
154 then ''
155 mkdir -m 0755 -p /usr/bin
156 ln -sfn ${config.environment.usrbinenv} /usr/bin/.env.tmp
157 mv /usr/bin/.env.tmp /usr/bin/env # atomically replace /usr/bin/env
158 ''
159 else ''
160 rm -f /usr/bin/env
161 rmdir --ignore-fail-on-non-empty /usr/bin /usr
162 '';
163
164 system.activationScripts.specialfs =
165 ''
166 specialMount() {
167 local device="$1"
168 local mountPoint="$2"
169 local options="$3"
170 local fsType="$4"
171
172 if mountpoint -q "$mountPoint"; then
173 local options="remount,$options"
174 else
175 mkdir -m 0755 -p "$mountPoint"
176 fi
177 mount -t "$fsType" -o "$options" "$device" "$mountPoint"
178 }
179 source ${config.system.build.earlyMountScript}
180 '';
181
182 };
183
184}