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