1 # generate the script used to activate the configuration.
2 { config, lib, pkgs, ... }:
8 addAttributeName = mapAttrs (a: v: v // {
10 #### Activation script snippet ${a}:
14 if (( _localstatus > 0 )); then
15 printf "Activation script snippet '%s' failed (%s)\n" "${a}" "$_localstatus"
20 systemActivationScript = set: onlyDry: let
21 set' = mapAttrs (_: v: if isString v then (noDepEntry v) // { supportsDryActivation = false; } else v) set;
22 withHeadlines = addAttributeName set';
23 # When building a dry activation script, this replaces all activation scripts
24 # that do not support dry mode with a comment that does nothing. Filtering these
25 # activation scripts out so they don't get generated into the dry activation script
26 # does not work because when an activation script that supports dry mode depends on
27 # an activation script that does not, the dependency cannot be resolved and the eval
29 withDrySnippets = mapAttrs (a: v: if onlyDry && !v.supportsDryActivation then v // {
30 text = "#### Activation script snippet ${a} does not support dry activation.";
31 } else v) withHeadlines;
34 #!${pkgs.runtimeShell}
36 source ${./lib/lib.sh}
41 for i in ${toString path}; do
42 PATH=$PATH:$i/bin:$i/sbin
46 trap "_status=1 _localstatus=\$?" ERR
48 # Ensure a consistent umask.
51 ${textClosureMap id (withDrySnippets) (attrNames withDrySnippets)}
53 '' + optionalString (!onlyDry) ''
54 # Make this configuration the current configuration.
55 # The readlink is there to ensure that when $systemConfig = /system
56 # (which is a symlink to the store), /run/current-system is still
57 # used as a garbage collection root.
58 ln -sfn "$(readlink -f "$systemConfig")" /run/current-system
63 path = with pkgs; map getBin
68 stdenv.cc.libc # nscd in update-users-groups.pl
70 nettools # needed for hostname
71 util-linux # needed for mount and mountpoint
74 scriptType = withDry: with types;
77 { type = types.listOf types.str;
79 description = "List of dependencies. The script will run after these.";
83 description = "The content of the script.";
85 } // optionalAttrs withDry {
86 supportsDryActivation = mkOption
90 Whether this activation script supports being dry-activated.
91 These activation scripts will also be executed on dry-activate
92 activations with the environment variable
93 `NIXOS_ACTION` being set to `dry-activate`.
94 it's important that these activation scripts don't
95 modify anything about the system when the variable is set.
99 in either str (submodule { options = scriptOptions; });
109 system.activationScripts = mkOption {
112 example = literalExpression ''
115 # Needed by some programs.
116 ln -sfn /proc/self/fd /dev/fd
117 ln -sfn /proc/self/fd/0 /dev/stdin
118 ln -sfn /proc/self/fd/1 /dev/stdout
119 ln -sfn /proc/self/fd/2 /dev/stderr
125 A set of shell script fragments that are executed when a NixOS
126 system configuration is activated. Examples are updating
127 /etc, creating accounts, and so on. Since these are executed
128 every time you boot the system or run
129 {command}`nixos-rebuild`, it's important that they are
133 type = types.attrsOf (scriptType true);
134 apply = set: set // {
135 script = systemActivationScript set false;
139 system.dryActivationScript = mkOption {
140 description = "The shell script that is to be run when dry-activating a system.";
143 default = systemActivationScript (removeAttrs config.system.activationScripts [ "script" ]) true;
144 defaultText = literalMD "generated activation script";
147 system.userActivationScripts = mkOption {
150 example = literalExpression ''
153 ''${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5"
161 A set of shell script fragments that are executed by a systemd user
162 service when a NixOS system configuration is activated. Examples are
163 rebuilding the .desktop file cache for showing applications in the menu.
164 Since these are executed every time you run
165 {command}`nixos-rebuild`, it's important that they are
169 type = with types; attrsOf (scriptType false);
174 for i in ${toString path}; do
175 PATH=$PATH:$i/bin:$i/sbin
179 trap "_status=1 _localstatus=\$?" ERR
183 set' = mapAttrs (n: v: if isString v then noDepEntry v else v) set;
184 withHeadlines = addAttributeName set';
185 in textClosureMap id (withHeadlines) (attrNames withHeadlines)
194 environment.usrbinenv = mkOption {
195 default = "${pkgs.coreutils}/bin/env";
196 defaultText = literalExpression ''"''${pkgs.coreutils}/bin/env"'';
197 example = literalExpression ''"''${pkgs.busybox}/bin/env"'';
198 type = types.nullOr types.path;
201 The env(1) executable that is linked system-wide to
206 system.build.installBootLoader = mkOption {
208 default = pkgs.writeShellScript "no-bootloader" ''
209 echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2
211 defaultText = lib.literalExpression ''
212 pkgs.writeShellScript "no-bootloader" '''
213 echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2
217 A program that writes a bootloader installation script to the path passed in the first command line argument.
219 See `nixos/modules/system/activation/switch-to-configuration.pl`.
221 type = types.unique {
223 Only one bootloader can be enabled at a time. This requirement has not
224 been checked until NixOS 22.05. Earlier versions defaulted to the last
225 definition. Change your configuration to enable only one bootloader.
227 } (types.either types.str types.package);
233 ###### implementation
237 system.activationScripts.stdio = ""; # obsolete
238 system.activationScripts.var = ""; # obsolete
240 systemd.tmpfiles.rules = [
241 "D /var/empty 0555 root root -"
242 "h /var/empty - - - - +i"
243 ] ++ lib.optionals config.nix.enable [
244 # Prevent the current configuration from being garbage-collected.
245 "d /nix/var/nix/gcroots -"
246 "L+ /nix/var/nix/gcroots/current-system - - - - /run/current-system"
249 system.activationScripts.usrbinenv = if config.environment.usrbinenv != null
253 ln -sfn ${config.environment.usrbinenv} /usr/bin/.env.tmp
254 mv /usr/bin/.env.tmp /usr/bin/env # atomically replace /usr/bin/env
258 rmdir --ignore-fail-on-non-empty /usr/bin /usr
261 system.activationScripts.specialfs =
265 local mountPoint="$2"
269 if mountpoint -q "$mountPoint"; then
270 local options="remount,$options"
272 mkdir -p "$mountPoint"
273 chmod 0755 "$mountPoint"
275 mount -t "$fsType" -o "$options" "$device" "$mountPoint"
277 source ${config.system.build.earlyMountScript}
281 services.nixos-activation = {
282 description = "Run user-specific NixOS activation";
283 script = config.system.userActivationScripts.script;
284 unitConfig.ConditionUser = "!@system";
285 serviceConfig.Type = "oneshot";
286 wantedBy = [ "default.target" ];