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