diff --git a/system/activate-configuration.nix b/system/activate-configuration.nix index 65591c2d2b84..25510aa26bde 100644 --- a/system/activate-configuration.nix +++ b/system/activate-configuration.nix @@ -2,15 +2,26 @@ {pkgs, config, ...}: let - inherit (pkgs.stringsWithDeps) textClosureOverridable; - inherit (pkgs.lib) mkOption mergeTypedOption mergeAttrs mapRecordFlatten id; + inherit (pkgs.stringsWithDeps) textClosureOverridable noDepEntry; + inherit (pkgs.lib) mkOption mergeTypedOption mergeAttrs mapRecordFlatten mapAttrs; textClosure = steps: - textClosureOverridable steps - (["#!/bin/sh"] ++ (mapRecordFlatten (a: v: v) steps)); + textClosureOverridable steps ( + [(noDepEntry "#!/bin/sh")] + ++ (mapRecordFlatten (a: v: v) steps) + ); aggregateScripts = name: steps: pkgs.writeScript name (textClosure steps); + + addAttributeName = mapAttrs (a: v: { + text = '' + #### ${a} begin + ${v.text} + #### ${a} end + ''; + inherit (v) deps; + }); in { @@ -34,7 +45,7 @@ in and so on). ''; merge = mergeTypedOption "script" builtins.isAttrs mergeAttrs; - apply = lib: { + apply = set: let lib = addAttributeName set; in { inherit lib; # used to fetch dependencies. script = aggregateScripts "activationScript" lib; }; diff --git a/system/activate-configuration.sh b/system/activate-configuration.sh deleted file mode 100644 index 7b3bf5d25322..000000000000 --- a/system/activate-configuration.sh +++ /dev/null @@ -1,58 +0,0 @@ -#! @shell@ - -source @newActivationScript@ - - -# Make a few setuid programs work. -PATH=@systemPath@/bin:@systemPath@/sbin:$PATH -save_PATH="$PATH" - -# Add the default profile to the search path for setuid executables. -PATH="/nix/var/nix/profiles/default/sbin:$PATH" -PATH="/nix/var/nix/profiles/default/bin:$PATH" - -wrapperDir=@wrapperDir@ -if test -d $wrapperDir; then rm -f $wrapperDir/*; fi -mkdir -p $wrapperDir -for i in @setuidPrograms@; do - program=$(type -tp $i) - if test -z "$program"; then - # XXX: It would be preferable to detect this problem before - # `activate-configuration' is invoked. - #echo "WARNING: No executable named \`$i' was found" >&2 - #echo "WARNING: but \`$i' was specified as a setuid program." >&2 - true - else - cp "$(type -tp setuid-wrapper)" $wrapperDir/$i - echo -n "$program" > $wrapperDir/$i.real - chown root.root $wrapperDir/$i - chmod 4755 $wrapperDir/$i - fi -done - -@adjustSetuidOwner@ - -PATH="$save_PATH" - -# Set the host name. Don't clear it if it's not configured in the -# NixOS configuration, since it may have been set by dhclient in the -# meantime. -if test -n "@hostName@"; then - hostname @hostName@ -else - # dhclient won't do anything if the hostname isn't empty. - if test "$(hostname)" = "(none)"; then - hostname '' - fi -fi - - -# Make this configuration the current configuration. -# The readlink is there to ensure that when $systemConfig = /system -# (which is a symlink to the store), /var/run/current-system is still -# used as a garbage collection root. -ln -sfn "$(readlink -f "$systemConfig")" /var/run/current-system - - -# Prevent the current configuration from being garbage-collected. -ln -sfn /var/run/current-system /nix/var/nix/gcroots/current-system diff --git a/system/system-options.nix b/system/system-options.nix index 3ff76210b84a..650a08e0a762 100644 --- a/system/system-options.nix +++ b/system/system-options.nix @@ -1,4 +1,5 @@ # this file contains all extendable options originally defined in system.nix +# TODO: split it to make it readable. {pkgs, config, ...}: ###### interface @@ -73,6 +74,7 @@ in ###### implementation let inherit (pkgs.stringsWithDeps) noDepEntry FullDepEntry PackEntry; + inherit (pkgs.lib) mapRecordFlatten; activateLib = config.system.activationScripts.lib; in @@ -120,7 +122,7 @@ in # Create the required /bin/sh symlink; otherwise lots of things # (notably the system() function) won't work. mkdir -m 0755 -p $mountPoint/bin - ln -sfn @bash@/bin/sh $mountPoint/bin/sh + ln -sfn ${pkgs.bash}/bin/sh $mountPoint/bin/sh '' [ activateLib.defaultPath # path to ln & mkdir activateLib.stdio # ? @@ -132,7 +134,7 @@ in # when the kernel (or some module) auto-loads a module. # !!! maybe this should only happen at boot time, since we shouldn't # use modules that don't match the running kernel. - echo @modprobe@/sbin/modprobe > /proc/sys/kernel/modprobe + echo ${config.system.sbin.modprobe}/sbin/modprobe > /proc/sys/kernel/modprobe '' [ # ? ]; @@ -175,7 +177,7 @@ in touch /etc/shadow; chmod 0600 /etc/shadow # Can't use useradd, since it complains that it doesn't know us # (bootstrap problem!). - echo "root:x:0:0:System administrator:$rootHome:@defaultShell@" >> /etc/passwd + echo "root:x:0:0:System administrator:$rootHome:${config.system.shell}" >> /etc/passwd echo "root::::::::" >> /etc/shadow echo | passwd --stdin root fi @@ -213,6 +215,101 @@ in activateLib.etc # /etc/nix.conf activateLib.users # nixbld group ]; + + path = FullDepEntry '' + PATH=${config.system.path}/bin:${config.system.path}/sbin:$PATH + '' [ + activateLib.defaultPath + ]; + + setuid = + let + setuidPrograms = builtins.toString ( + config.security.setuidPrograms ++ + config.security.extraSetuidPrograms ++ + map (x: x.program) config.security.setuidOwners + ); + + adjustSetuidOwner = pkgs.lib.concatStrings (map + (_entry: let entry = { + owner = "nobody"; + group = "nogroup"; + setuid = false; + setgid = false; + } //_entry; in + '' + chown ${entry.owner}.${entry.group} $wrapperDir/${entry.program} + chmod u${if entry.setuid then "+" else "-"}s $wrapperDir/${entry.program} + chmod g${if entry.setgid then "+" else "-"}s $wrapperDir/${entry.program} + '') + config.security.setuidOwners); + + in FullDepEntry '' + # Make a few setuid programs work. + save_PATH="$PATH" + + # Add the default profile to the search path for setuid executables. + PATH="/nix/var/nix/profiles/default/sbin:$PATH" + PATH="/nix/var/nix/profiles/default/bin:$PATH" + + wrapperDir=${config.system.wrapperDir} + if test -d $wrapperDir; then rm -f $wrapperDir/*; fi # */ + mkdir -p $wrapperDir + for i in ${setuidPrograms}; do + program=$(type -tp $i) + if test -z "$program"; then + # XXX: It would be preferable to detect this problem before + # `activate-configuration' is invoked. + #echo "WARNING: No executable named \`$i' was found" >&2 + #echo "WARNING: but \`$i' was specified as a setuid program." >&2 + true + else + cp "$(type -tp setuid-wrapper)" $wrapperDir/$i + echo -n "$program" > $wrapperDir/$i.real + chown root.root $wrapperDir/$i + chmod 4755 $wrapperDir/$i + fi + done + + ${adjustSetuidOwner} + + PATH="$save_PATH" + '' [ + activateLib.path + activateLib.users + ]; + + hostname = FullDepEntry '' + # Set the host name. Don't clear it if it's not configured in the + # NixOS configuration, since it may have been set by dhclient in the + # meantime. + ${if config.networking.hostName == "" then + ''hostname "${config.networking.hostName}"'' + else '' + # dhclient won't do anything if the hostname isn't empty. + if test "$(hostname)" = "(none)"; then + hostname "" + fi + ''} + '' [ + activateLib.path + ]; + + # The activation have to be done at the end. Therefore, this entry + # depends on all scripts declared in the activation library. + activate = FullDepEntry '' + # Make this configuration the current configuration. + # The readlink is there to ensure that when $systemConfig = /system + # (which is a symlink to the store), /var/run/current-system is still + # used as a garbage collection root. + ln -sfn "$(readlink -f "$systemConfig")" /var/run/current-system + + # Prevent the current configuration from being garbage-collected. + ln -sfn /var/run/current-system /nix/var/nix/gcroots/current-system + '' (mapRecordFlatten (a: v: v) + # should be removed if this does not cause an infinite recursion. + (activateLib // { activate = { text = ""; deps = []; }; }) + ); }; }; } diff --git a/system/system.nix b/system/system.nix index 6816f582edf0..e6dc5c6d53e2 100644 --- a/system/system.nix +++ b/system/system.nix @@ -186,36 +186,7 @@ rec { # The script that activates the configuration, i.e., it sets up # /etc, accounts, etc. It doesn't do anything that can only be done # at boot time (such as start `init'). - # DO NOT EXTEND THIS. You should use the option system-option.nix - activateConfiguration = pkgs.substituteAll rec { - src = ./activate-configuration.sh; - isExecutable = true; - - newActivationScript = config.system.activationScripts.script; - - inherit wrapperDir systemPath modprobe defaultShell kernel; - hostName = config.networking.hostName; - setuidPrograms = - config.security.setuidPrograms ++ - config.security.extraSetuidPrograms ++ - map ( x : x.program ) config.security.setuidOwners; - - bash = pkgs.bashInteractive; - - adjustSetuidOwner = pkgs.lib.concatStrings (map - (_entry: let entry = { - owner = "nobody"; - group = "nogroup"; - setuid = false; - setgid = false; - } //_entry; in - '' - chown ${entry.owner}.${entry.group} $wrapperDir/${entry.program} - chmod u${if entry.setuid then "+" else "-"}s $wrapperDir/${entry.program} - chmod g${if entry.setgid then "+" else "-"}s $wrapperDir/${entry.program} - '') - config.security.setuidOwners); - }; + activateConfiguration = config.system.activationScripts.script; # The init script of boot stage 2, which is supposed to do