about summary refs log tree commit diff
path: root/nixos/modules/system
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/system')
-rw-r--r--nixos/modules/system/activation/activation-script.nix5
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl6
-rw-r--r--nixos/modules/system/activation/top-level.nix5
-rw-r--r--nixos/modules/system/boot/initrd-ssh.nix33
-rw-r--r--nixos/modules/system/boot/kernel.nix2
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix36
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl85
-rw-r--r--nixos/modules/system/boot/loader/raspberrypi/builder.sh12
-rw-r--r--nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix2
-rw-r--r--nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py37
-rw-r--r--nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix18
-rw-r--r--nixos/modules/system/boot/luksroot.nix55
-rw-r--r--nixos/modules/system/boot/networkd.nix8
-rw-r--r--nixos/modules/system/boot/readonly-mountpoint.c20
-rw-r--r--nixos/modules/system/boot/resolved.nix4
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh27
-rw-r--r--nixos/modules/system/boot/stage-1.nix93
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh68
-rw-r--r--nixos/modules/system/boot/stage-2.nix19
-rw-r--r--nixos/modules/system/boot/systemd-lib.nix10
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix12
-rw-r--r--nixos/modules/system/boot/systemd.nix47
22 files changed, 406 insertions, 198 deletions
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index dcf105eb7844..c2ac731d433d 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -19,6 +19,7 @@ let
       glibc # needed for getent
       shadow
       nettools # needed for hostname
+      utillinux # needed for mount and mountpoint
     ];
 
 in
@@ -168,12 +169,12 @@ in
           local options="$3"
           local fsType="$4"
 
-          if ${pkgs.utillinux}/bin/mountpoint -q "$mountPoint"; then
+          if mountpoint -q "$mountPoint"; then
             local options="remount,$options"
           else
             mkdir -m 0755 -p "$mountPoint"
           fi
-          ${pkgs.utillinux}/bin/mount -t "$fsType" -o "$options" "$device" "$mountPoint"
+          mount -t "$fsType" -o "$options" "$device" "$mountPoint"
         }
         source ${config.system.build.earlyMountScript}
       '';
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index 8747c1e3d4ac..88e7847cf8c8 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -41,7 +41,7 @@ if ($action eq "switch" || $action eq "boot") {
 }
 
 # Just in case the new configuration hangs the system, do a sync now.
-system("@coreutils@/bin/sync") unless ($ENV{"NIXOS_NO_SYNC"} // "") eq "1";
+system("@coreutils@/bin/sync", "-f", "/nix/store") unless ($ENV{"NIXOS_NO_SYNC"} // "") eq "1";
 
 exit 0 if $action eq "boot";
 
@@ -383,6 +383,10 @@ system("@systemd@/bin/systemctl", "reset-failed");
 # Make systemd reload its units.
 system("@systemd@/bin/systemctl", "daemon-reload") == 0 or $res = 3;
 
+# Set the new tmpfiles
+print STDERR "setting up tmpfiles\n";
+system("@systemd@/bin/systemd-tmpfiles", "--create", "--remove", "--exclude-prefix=/dev") == 0 or $res = 3;
+
 # Reload units that need it. This includes remounting changed mount
 # units.
 if (scalar(keys %unitsToReload) > 0) {
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index 0c08375da646..e9897cc01b6a 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -45,11 +45,16 @@ let
 
         ln -s ${kernelPath} $out/kernel
         ln -s ${config.system.modulesTree} $out/kernel-modules
+        ${optionalString (pkgs.stdenv.platform.kernelDTB or false) ''
+          ln -s ${config.boot.kernelPackages.kernel}/dtbs $out/dtbs
+        ''}
 
         echo -n "$kernelParams" > $out/kernel-params
 
         ln -s ${config.system.build.initialRamdisk}/initrd $out/initrd
 
+        ln -s ${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets $out
+
         ln -s ${config.hardware.firmware}/lib/firmware $out/firmware
       ''}
 
diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix
index 59ecaf8d5a6d..d78775c27582 100644
--- a/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixos/modules/system/boot/initrd-ssh.nix
@@ -44,9 +44,10 @@ in
       description = ''
         RSA SSH private key file in the Dropbear format.
 
-        WARNING: This key is contained insecurely in the global Nix store. Do NOT
-        use your regular SSH host private keys for this purpose or you'll expose
-        them to regular users!
+        WARNING: Unless your bootloader supports initrd secrets, this key is
+        contained insecurely in the global Nix store. Do NOT use your regular
+        SSH host private keys for this purpose or you'll expose them to
+        regular users!
       '';
     };
 
@@ -56,9 +57,10 @@ in
       description = ''
         DSS SSH private key file in the Dropbear format.
 
-        WARNING: This key is contained insecurely in the global Nix store. Do NOT
-        use your regular SSH host private keys for this purpose or you'll expose
-        them to regular users!
+        WARNING: Unless your bootloader supports initrd secrets, this key is
+        contained insecurely in the global Nix store. Do NOT use your regular
+        SSH host private keys for this purpose or you'll expose them to
+        regular users!
       '';
     };
 
@@ -68,9 +70,10 @@ in
       description = ''
         ECDSA SSH private key file in the Dropbear format.
 
-        WARNING: This key is contained insecurely in the global Nix store. Do NOT
-        use your regular SSH host private keys for this purpose or you'll expose
-        them to regular users!
+        WARNING: Unless your bootloader supports initrd secrets, this key is
+        contained insecurely in the global Nix store. Do NOT use your regular
+        SSH host private keys for this purpose or you'll expose them to
+        regular users!
       '';
     };
 
@@ -97,10 +100,6 @@ in
     boot.initrd.extraUtilsCommands = ''
       copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
       cp -pv ${pkgs.glibc.out}/lib/libnss_files.so.* $out/lib
-
-      ${optionalString (cfg.hostRSAKey != null) "install -D ${cfg.hostRSAKey} $out/etc/dropbear/dropbear_rsa_host_key"}
-      ${optionalString (cfg.hostDSSKey != null) "install -D ${cfg.hostDSSKey} $out/etc/dropbear/dropbear_dss_host_key"}
-      ${optionalString (cfg.hostECDSAKey != null) "install -D ${cfg.hostECDSAKey} $out/etc/dropbear/dropbear_ecdsa_host_key"}
     '';
 
     boot.initrd.extraUtilsCommandsTest = ''
@@ -116,9 +115,6 @@ in
       touch /var/log/lastlog
 
       mkdir -p /etc/dropbear
-      ${optionalString (cfg.hostRSAKey != null) "ln -s $extraUtils/etc/dropbear/dropbear_rsa_host_key /etc/dropbear/dropbear_rsa_host_key"}
-      ${optionalString (cfg.hostDSSKey != null) "ln -s $extraUtils/etc/dropbear/dropbear_dss_host_key /etc/dropbear/dropbear_dss_host_key"}
-      ${optionalString (cfg.hostECDSAKey != null) "ln -s $extraUtils/etc/dropbear/dropbear_ecdsa_host_key /etc/dropbear/dropbear_ecdsa_host_key"}
 
       mkdir -p /root/.ssh
       ${concatStrings (map (key: ''
@@ -128,6 +124,11 @@ in
       dropbear -s -j -k -E -m -p ${toString cfg.port}
     '';
 
+    boot.initrd.secrets =
+     (optionalAttrs (cfg.hostRSAKey != null) { "/etc/dropbear/dropbear_rsa_host_key" = cfg.hostRSAKey; }) //
+     (optionalAttrs (cfg.hostDSSKey != null) { "/etc/dropbear/dropbear_dss_host_key" = cfg.hostDSSKey; }) //
+     (optionalAttrs (cfg.hostECDSAKey != null) { "/etc/dropbear/dropbear_ecdsa_host_key" = cfg.hostECDSAKey; });
+
   };
 
 }
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index e751ff141f70..cf70a891c0ca 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -176,7 +176,7 @@ in
 
     boot.initrd.availableKernelModules =
       [ # Note: most of these (especially the SATA/PATA modules)
-        # shouldn't be included by default since nixos-hardware-scan
+        # shouldn't be included by default since nixos-generate-config
         # detects them, but I'm keeping them for now for backwards
         # compatibility.
 
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index 294fc1988e9f..cf47aed9fa99 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -53,12 +53,14 @@ let
       inherit (args) devices;
       inherit (efi) canTouchEfiVariables;
       inherit (cfg)
-        version extraConfig extraPerEntryConfig extraEntries forceInstall 
-        extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels
+        version extraConfig extraPerEntryConfig extraEntries forceInstall useOSProber
+        extraEntriesBeforeNixOS extraPrepareConfig extraInitrd configurationLimit copyKernels
         default fsIdentifier efiSupport efiInstallAsRemovable gfxmodeEfi gfxmodeBios;
       path = (makeBinPath ([
         pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfs-progs
-        pkgs.utillinux ] ++ (if cfg.efiSupport && (cfg.version == 2) then [pkgs.efibootmgr ] else [])
+        pkgs.utillinux ]
+        ++ (optional (cfg.efiSupport && (cfg.version == 2)) pkgs.efibootmgr)
+        ++ (optionals cfg.useOSProber [pkgs.busybox pkgs.os-prober])
       )) + ":" + (makeSearchPathOutput "bin" "sbin" [
         pkgs.mdadm pkgs.utillinux
       ]);
@@ -237,6 +239,12 @@ in
           menuentry "Windows 7" {
             chainloader (hd0,4)+1
           }
+
+          # GRUB 2 with UEFI example, chainloading another distro
+          menuentry "Fedora" {
+            set root=(hd1,1)
+            chainloader /efi/fedora/grubx64.efi
+          }
         '';
         description = ''
           Any additional entries you want added to the GRUB boot menu.
@@ -265,6 +273,27 @@ in
         '';
       };
 
+      extraInitrd = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/boot/extra_initrafms.gz";
+        description = ''
+          The path to a second initramfs to be supplied to the kernel.
+          This ramfs will not be copied to the store, so that it can
+          contain secrets such as LUKS keyfiles or ssh keys.
+          This implies that rolling back to a previous configuration
+          won't rollback the state of this file.
+        '';
+      };
+
+      useOSProber = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          If set to true, append entries for other OSs detected by os-prober.
+        '';
+      };
+
       splashImage = mkOption {
         type = types.nullOr types.path;
         example = literalExample "./my-background.png";
@@ -358,7 +387,6 @@ in
 
       efiInstallAsRemovable = mkOption {
         default = false;
-        example = true;
         type = types.bool;
         description = ''
           Whether to invoke <literal>grub-install</literal> with
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
index 24442ca12a30..5fcac5c8c6a4 100644
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -49,6 +49,7 @@ my $extraPrepareConfig = get("extraPrepareConfig");
 my $extraPerEntryConfig = get("extraPerEntryConfig");
 my $extraEntries = get("extraEntries");
 my $extraEntriesBeforeNixOS = get("extraEntriesBeforeNixOS") eq "true";
+my $extraInitrd = get("extraInitrd");
 my $splashImage = get("splashImage");
 my $configurationLimit = int(get("configurationLimit"));
 my $copyKernels = get("copyKernels") eq "true";
@@ -226,6 +227,13 @@ my $grubStore;
 if ($copyKernels == 0) {
     $grubStore = GrubFs($storePath);
 }
+my $extraInitrdPath;
+if ($extraInitrd) {
+    if (! -f $extraInitrd) {
+        print STDERR "Warning: the specified extraInitrd " . $extraInitrd . " doesn't exist. Your system won't boot without it.\n";
+    }
+    $extraInitrdPath = GrubFs($extraInitrd);
+}
 
 # Generate the header.
 my $conf .= "# Automatically generated.  DO NOT EDIT THIS FILE!\n";
@@ -256,8 +264,6 @@ else {
         # ‘grub-reboot’ sets a one-time saved entry, which we process here and
         # then delete.
         if [ \"\${next_entry}\" ]; then
-          # FIXME: KDM expects the next line to be present.
-          set default=\"\${saved_entry}\"
           set default=\"\${next_entry}\"
           set next_entry=
           save_env next_entry
@@ -338,6 +344,9 @@ sub addEntry {
 
     my $kernel = copyToKernelsDir(Cwd::abs_path("$path/kernel"));
     my $initrd = copyToKernelsDir(Cwd::abs_path("$path/initrd"));
+    if ($extraInitrd) {
+        $initrd .= " " .$extraInitrdPath->path;
+    }
     my $xen = -e "$path/xen.gz" ? copyToKernelsDir(Cwd::abs_path("$path/xen.gz")) : undef;
 
     # FIXME: $confName
@@ -360,6 +369,9 @@ sub addEntry {
         if ($copyKernels == 0) {
             $conf .= $grubStore->search . "\n";
         }
+        if ($extraInitrd) {
+            $conf .= $extraInitrdPath->search . "\n";
+        }
         $conf .= "  $extraPerEntryConfig\n" if $extraPerEntryConfig;
         $conf .= "  multiboot $xen $xenParams\n" if $xen;
         $conf .= "  " . ($xen ? "module" : "linux") . " $kernel $kernelParams\n";
@@ -426,10 +438,48 @@ if ($extraPrepareConfig ne "") {
   system((get("shell"), "-c", $extraPrepareConfig));
 }
 
-# Atomically update the GRUB config.
+# write the GRUB config.
 my $confFile = $grubVersion == 1 ? "$bootPath/grub/menu.lst" : "$bootPath/grub/grub.cfg";
 my $tmpFile = $confFile . ".tmp";
 writeFile($tmpFile, $conf);
+
+
+# check whether to install GRUB EFI or not
+sub getEfiTarget {
+    if ($grubVersion == 1) {
+        return "no"
+    } elsif (($grub ne "") && ($grubEfi ne "")) {
+        # EFI can only be installed when target is set;
+        # A target is also required then for non-EFI grub
+        if (($grubTarget eq "") || ($grubTargetEfi eq "")) { die }
+        else { return "both" }
+    } elsif (($grub ne "") && ($grubEfi eq "")) {
+        # TODO: It would be safer to disallow non-EFI grub installation if no taget is given.
+        #       If no target is given, then grub auto-detects the target which can lead to errors.
+        #       E.g. it seems as if grub would auto-detect a EFI target based on the availability
+        #       of a EFI partition.
+        #       However, it seems as auto-detection is currently relied on for non-x86_64 and non-i386
+        #       architectures in NixOS. That would have to be fixed in the nixos modules first.
+        return "no"
+    } elsif (($grub eq "") && ($grubEfi ne "")) {
+        # EFI can only be installed when target is set;
+        if ($grubTargetEfi eq "") { die }
+        else {return "only" }
+    } else {
+        # prevent an installation if neither grub nor grubEfi is given
+        return "neither"
+    }
+}
+
+my $efiTarget = getEfiTarget();
+
+# Append entries detected by os-prober
+if (get("useOSProber") eq "true") {
+    my $targetpackage = ($efiTarget eq "no") ? $grub : $grubEfi;
+    system(get("shell"), "-c", "pkgdatadir=$targetpackage/share/grub $targetpackage/etc/grub.d/30_os-prober >> $tmpFile");
+}
+
+# Atomically switch to the new config
 rename $tmpFile, $confFile or die "cannot rename $tmpFile to $confFile\n";
 
 
@@ -479,36 +529,7 @@ sub getDeviceTargets {
     }
     return @devices;
 }
-
-# check whether to install GRUB EFI or not
-sub getEfiTarget {
-    if ($grubVersion == 1) {
-        return "no"
-    } elsif (($grub ne "") && ($grubEfi ne "")) {
-        # EFI can only be installed when target is set;
-        # A target is also required then for non-EFI grub
-        if (($grubTarget eq "") || ($grubTargetEfi eq "")) { die }
-        else { return "both" }
-    } elsif (($grub ne "") && ($grubEfi eq "")) {
-        # TODO: It would be safer to disallow non-EFI grub installation if no taget is given.
-        #       If no target is given, then grub auto-detects the target which can lead to errors.
-        #       E.g. it seems as if grub would auto-detect a EFI target based on the availability
-        #       of a EFI partition.
-        #       However, it seems as auto-detection is currently relied on for non-x86_64 and non-i386
-        #       architectures in NixOS. That would have to be fixed in the nixos modules first.
-        return "no"
-    } elsif (($grub eq "") && ($grubEfi ne "")) {
-        # EFI can only be installed when target is set;
-        if ($grubTargetEfi eq "") { die }
-        else {return "only" }
-    } else {
-        # prevent an installation if neither grub nor grubEfi is given
-        return "neither"
-    }
-}
-
 my @deviceTargets = getDeviceTargets();
-my $efiTarget = getEfiTarget();
 my $prevGrubState = readGrubState();
 my @prevDeviceTargets = split/,/, $prevGrubState->devices;
 
diff --git a/nixos/modules/system/boot/loader/raspberrypi/builder.sh b/nixos/modules/system/boot/loader/raspberrypi/builder.sh
index ccb88ca1c529..f627d093eafb 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/builder.sh
+++ b/nixos/modules/system/boot/loader/raspberrypi/builder.sh
@@ -61,12 +61,13 @@ addEntry() {
 
     local kernel=$(readlink -f $path/kernel)
     local initrd=$(readlink -f $path/initrd)
+    local dtb_path=$(readlink -f $path/kernel-modules/dtbs)
 
     if test -n "@copyKernels@"; then
         copyToKernelsDir $kernel; kernel=$result
         copyToKernelsDir $initrd; initrd=$result
     fi
-    
+
     echo $(readlink -f $path) > $outdir/$generation-system
     echo $(readlink -f $path/init) > $outdir/$generation-init
     cp $path/kernel-params $outdir/$generation-cmdline.txt
@@ -80,6 +81,11 @@ addEntry() {
         copyForced $kernel /boot/kernel7.img
       fi
       copyForced $initrd /boot/initrd
+      for dtb in $dtb_path/bcm*.dtb; do
+        dst="/boot/$(basename $dtb)"
+        copyForced $dtb "$dst"
+        filesCopied[$dst]=1
+      done
       cp "$(readlink -f "$path/init")" /boot/nixos-init
       echo "`cat $path/kernel-params` init=$path/init" >/boot/cmdline.txt
 
@@ -108,8 +114,8 @@ copyForced $fwdir/start_cd.elf  /boot/start_cd.elf
 copyForced $fwdir/start_db.elf  /boot/start_db.elf
 copyForced $fwdir/start_x.elf   /boot/start_x.elf
 
-# Remove obsolete files from /boot/old.
-for fn in /boot/old/*linux* /boot/old/*initrd*; do
+# Remove obsolete files from /boot and /boot/old.
+for fn in /boot/old/*linux* /boot/old/*initrd-initrd* /boot/bcm*.dtb; do
     if ! test "${filesCopied[$fn]}" = 1; then
         rm -vf -- "$fn"
     fi
diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
index eb8ea6130972..f246d04284ca 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
+++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
@@ -33,7 +33,7 @@ in
 
     boot.loader.raspberryPi.version = mkOption {
       default = 2;
-      type = types.enum [ 1 2 ];
+      type = types.enum [ 1 2 3 ];
       description = ''
       '';
     };
diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index 515136c904c5..704c574b822e 100644
--- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -1,4 +1,4 @@
-#! @python3@/bin/python3
+#! @python3@/bin/python3 -B
 import argparse
 import shutil
 import os
@@ -28,10 +28,15 @@ def write_loader_conf(generation):
         if "@timeout@" != "":
             f.write("timeout @timeout@\n")
         f.write("default nixos-generation-%d\n" % generation)
+        if not @editor@:
+            f.write("editor 0");
     os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
 
+def profile_path(generation, name):
+    return os.readlink("%s/%s" % (system_dir(generation), name))
+
 def copy_from_profile(generation, name, dry_run=False):
-    store_file_path = os.readlink("%s/%s" % (system_dir(generation), name))
+    store_file_path = profile_path(generation, name)
     suffix = os.path.basename(store_file_path)
     store_dir = os.path.basename(os.path.dirname(store_file_path))
     efi_file_path = "/efi/nixos/%s-%s.efi" % (store_dir, suffix)
@@ -42,6 +47,11 @@ def copy_from_profile(generation, name, dry_run=False):
 def write_entry(generation, machine_id):
     kernel = copy_from_profile(generation, "kernel")
     initrd = copy_from_profile(generation, "initrd")
+    try:
+        append_initrd_secrets = profile_path(generation, "append-initrd-secrets")
+        subprocess.check_call([append_initrd_secrets, "@efiSysMountPoint@%s" % (initrd)])
+    except FileNotFoundError:
+        pass
     entry_file = "@efiSysMountPoint@/loader/entries/nixos-generation-%d.conf" % (generation)
     generation_dir = os.readlink(system_dir(generation))
     tmp_path = "%s.tmp" % (entry_file)
@@ -99,11 +109,27 @@ def main():
     parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default NixOS config to boot')
     args = parser.parse_args()
 
+    try:
+        with open("/etc/machine-id") as machine_file:
+            machine_id = machine_file.readlines()[0]
+    except IOError as e:
+        if e.errno != errno.ENOENT:
+            raise
+        # Since systemd version 232 a machine ID is required and it might not
+        # be there on newly installed systems, so let's generate one so that
+        # bootctl can find it and we can also pass it to write_entry() later.
+        cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"]
+        machine_id = subprocess.check_output(cmd).rstrip()
+
     if os.getenv("NIXOS_INSTALL_GRUB") == "1":
         warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
         os.environ["NIXOS_INSTALL_BOOTLOADER"] = "1"
 
     if os.getenv("NIXOS_INSTALL_BOOTLOADER") == "1":
+        # bootctl uses fopen() with modes "wxe" and fails if the file exists.
+        if os.path.exists("@efiSysMountPoint@/loader/loader.conf"):
+            os.unlink("@efiSysMountPoint@/loader/loader.conf")
+
         if "@canTouchEfiVariables@" == "1":
             subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "install"])
         else:
@@ -111,13 +137,6 @@ def main():
 
     mkdir_p("@efiSysMountPoint@/efi/nixos")
     mkdir_p("@efiSysMountPoint@/loader/entries")
-    try:
-        with open("/etc/machine-id") as machine_file:
-            machine_id = machine_file.readlines()[0]
-    except IOError as e:
-        if e.errno != errno.ENOENT:
-            raise
-        machine_id = None
 
     gens = get_generations("system")
     remove_old_entries(gens)
diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
index cc43fb8bab4c..a5a88a99be8f 100644
--- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
@@ -20,6 +20,8 @@ let
 
     timeout = if config.boot.loader.timeout != null then config.boot.loader.timeout else "";
 
+    editor = if cfg.editor then "True" else "False";
+
     inherit (efi) efiSysMountPoint canTouchEfiVariables;
   };
 in {
@@ -36,6 +38,20 @@ in {
 
       description = "Whether to enable the systemd-boot (formerly gummiboot) EFI boot manager";
     };
+
+    editor = mkOption {
+      default = true;
+
+      type = types.bool;
+
+      description = ''
+        Whether to allow editing the kernel command-line before
+        boot. It is recommended to set this to false, as it allows
+        gaining root access by passing init=/bin/sh as a kernel
+        parameter. However, it is enabled by default for backwards
+        compatibility.
+      '';
+    };
   };
 
   config = mkIf cfg.enable {
@@ -49,6 +65,8 @@ in {
 
     boot.loader.grub.enable = mkDefault false;
 
+    boot.loader.supportsInitrdSecrets = true;
+
     system = {
       build.installBootLoader = gummibootBuilder;
 
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index 1f412fe2d8f2..6e867b674398 100644
--- a/nixos/modules/system/boot/luksroot.nix
+++ b/nixos/modules/system/boot/luksroot.nix
@@ -6,29 +6,38 @@ let
   luks = config.boot.initrd.luks;
 
   openCommand = name': { name, device, header, keyFile, keyFileSize, allowDiscards, yubikey, ... }: assert name' == name; ''
-    # Wait for luksRoot to appear, e.g. if on a usb drive.
-    # XXX: copied and adapted from stage-1-init.sh - should be
-    # available as a function.
-    if ! test -e ${device}; then
-        echo -n "waiting 10 seconds for device ${device} to appear..."
-        for try in $(seq 10); do
-            sleep 1
-            if test -e ${device}; then break; fi
-            echo -n .
-        done
-        echo "ok"
-    fi
+
+    # Wait for a target (e.g. device, keyFile, header, ...) to appear.
+    wait_target() {
+        local name="$1"
+        local target="$2"
+
+        if [ ! -e $target ]; then
+            echo -n "Waiting 10 seconds for $name $target to appear"
+            local success=false;
+            for try in $(seq 10); do
+                echo -n "."
+                sleep 1
+                if [ -e $target ]; then success=true break; fi
+            done
+            if [ $success = true ]; then
+                echo " - success";
+            else
+                echo " - failure";
+            fi
+        fi
+    }
+
+    # Wait for luksRoot (and optionally keyFile and/or header) to appear, e.g.
+    # if on a USB drive.
+    wait_target "device" ${device}
 
     ${optionalString (keyFile != null) ''
-    if ! test -e ${keyFile}; then
-        echo -n "waiting 10 seconds for key file ${keyFile} to appear..."
-        for try in $(seq 10); do
-            sleep 1
-            if test -e ${keyFile}; then break; fi
-            echo -n .
-        done
-        echo "ok"
-    fi
+      wait_target "key file" ${keyFile}
+    ''}
+
+    ${optionalString (header != null) ''
+      wait_target "header" ${header}
     ''}
 
     open_normally() {
@@ -434,8 +443,8 @@ in
       chmod +x $out/bin/cryptsetup-askpass
 
       ${optionalString luks.yubikeySupport ''
-        copy_bin_and_libs ${pkgs.ykpers}/bin/ykchalresp
-        copy_bin_and_libs ${pkgs.ykpers}/bin/ykinfo
+        copy_bin_and_libs ${pkgs.yubikey-personalization}/bin/ykchalresp
+        copy_bin_and_libs ${pkgs.yubikey-personalization}/bin/ykinfo
         copy_bin_and_libs ${pkgs.openssl.bin}/bin/openssl
 
         cc -O3 -I${pkgs.openssl.dev}/include -L${pkgs.openssl.out}/lib ${./pbkdf2-sha512.c} -o pbkdf2-sha512 -lcrypto
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index b828ad53dc58..f96dde153610 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -79,7 +79,7 @@ let
   checkBond = checkUnitConfig "Bond" [
     (assertOnlyFields [
       "Mode" "TransmitHashPolicy" "LACPTransmitRate" "MIIMonitorSec"
-      "UpDelaySec" "DownDelaySec"
+      "UpDelaySec" "DownDelaySec" "GratuitousARP"
     ])
     (assertValueOneOf "Mode" [
       "balance-rr" "active-backup" "balance-xor"
@@ -667,8 +667,10 @@ in
 
   config = mkIf config.systemd.network.enable {
 
-    systemd.additionalUpstreamSystemUnits =
-      [ "systemd-networkd.service" "systemd-networkd-wait-online.service" ];
+    systemd.additionalUpstreamSystemUnits = [
+      "systemd-networkd.service" "systemd-networkd-wait-online.service"
+      "org.freedesktop.network1.busname"
+    ];
 
     systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links
       // mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs
diff --git a/nixos/modules/system/boot/readonly-mountpoint.c b/nixos/modules/system/boot/readonly-mountpoint.c
deleted file mode 100644
index 27b666873821..000000000000
--- a/nixos/modules/system/boot/readonly-mountpoint.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <sys/statvfs.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char ** argv) {
-	struct statvfs stat;
-	if (argc != 2) {
-		fprintf(stderr, "Usage: %s PATH", argv[0]);
-		exit(2);
-	}
-	if (statvfs(argv[1], &stat) != 0) {
-		perror("statvfs");
-		exit(3);
-	}
-	if (stat.f_flag & ST_RDONLY)
-		exit(0);
-	else
-		exit(1);
-}
-
diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix
index 4b7c545dcc0d..a3fb733c289d 100644
--- a/nixos/modules/system/boot/resolved.nix
+++ b/nixos/modules/system/boot/resolved.nix
@@ -71,7 +71,9 @@ in
 
   config = mkIf cfg.enable {
 
-    systemd.additionalUpstreamSystemUnits = [ "systemd-resolved.service" ];
+    systemd.additionalUpstreamSystemUnits = [
+      "systemd-resolved.service" "org.freedesktop.resolve1.busname"
+    ];
 
     systemd.services.systemd-resolved = {
       wantedBy = [ "multi-user.target" ];
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index f0699ad9832b..9a125dcb0aeb 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -8,6 +8,14 @@ export LD_LIBRARY_PATH=@extraUtils@/lib
 export PATH=@extraUtils@/bin
 ln -s @extraUtils@/bin /bin
 
+# Copy the secrets to their needed location
+if [ -d "@extraUtils@/secrets" ]; then
+    for secret in $(cd "@extraUtils@/secrets"; find . -type f); do
+        mkdir -p $(dirname "/$secret")
+        ln -s "@extraUtils@/secrets/$secret" "$secret"
+    done
+fi
+
 # Stop LVM complaining about fd3
 export LVM_SUPPRESS_FD_WARNINGS=true
 
@@ -146,6 +154,9 @@ for o in $(cat /proc/cmdline); do
             fi
             ln -s "$root" /dev/root
             ;;
+        copytoram)
+            copytoram=1
+            ;;
     esac
 done
 
@@ -466,6 +477,22 @@ while read -u 3 mountPoint; do
     # doing something with $device right now.
     udevadm settle
 
+    # If copytoram is enabled: skip mounting the ISO and copy its content to a tmpfs.
+    if [ -n "$copytoram" ] && [ "$device" = /dev/root ] && [ "$mountPoint" = /iso ]; then
+      fsType=$(blkid -o value -s TYPE "$device")
+      fsSize=$(blockdev --getsize64 "$device")
+
+      mkdir -p /tmp-iso
+      mount -t "$fsType" /dev/root /tmp-iso
+      mountFS tmpfs /iso size="$fsSize" tmpfs
+
+      cp -r /tmp-iso/* /mnt-root/iso/
+
+      umount /tmp-iso
+      rmdir /tmp-iso
+      continue
+    fi
+
     mountFS "$device" "$mountPoint" "$options" "$fsType"
 done
 
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 61def24efd88..e3a3b6f88cf2 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -82,6 +82,17 @@ let
         copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs
       ''}
 
+      # Copy secrets if needed.
+      ${optionalString (!config.boot.loader.supportsInitrdSecrets)
+          (concatStringsSep "\n" (mapAttrsToList (dest: source:
+             let source' = if source == null then dest else source; in
+               ''
+                  mkdir -p $(dirname "$out/secrets/${dest}")
+                  cp -a ${source'} "$out/secrets/${dest}"
+                ''
+          ) config.boot.initrd.secrets))
+       }
+
       ${config.boot.initrd.extraUtilsCommands}
 
       # Copy ld manually since it isn't detected correctly
@@ -242,6 +253,52 @@ let
       ];
   };
 
+  # Script to add secret files to the initrd at bootloader update time
+  initialRamdiskSecretAppender =
+    pkgs.writeScriptBin "append-initrd-secrets"
+      ''
+        #!${pkgs.bash}/bin/bash -e
+        function usage {
+          echo "USAGE: $0 INITRD_FILE" >&2
+          echo "Appends this configuration's secrets to INITRD_FILE" >&2
+        }
+
+        if [ $# -ne 1 ]; then
+          usage
+          exit 1
+        fi
+
+        if [ "$1"x = "--helpx" ]; then
+          usage
+          exit 0
+        fi
+
+        ${lib.optionalString (config.boot.initrd.secrets == {})
+            "exit 0"}
+
+        export PATH=${pkgs.coreutils}/bin:${pkgs.cpio}/bin:${pkgs.gzip}/bin:${pkgs.findutils}/bin
+
+        function cleanup {
+          if [ -n "$tmp" -a -d "$tmp" ]; then
+            rm -fR "$tmp"
+          fi
+        }
+        trap cleanup EXIT
+
+        tmp=$(mktemp -d initrd-secrets.XXXXXXXXXX)
+
+        ${lib.concatStringsSep "\n" (mapAttrsToList (dest: source:
+            let source' = if source == null then dest else toString source; in
+              ''
+                mkdir -p $(dirname "$tmp/${dest}")
+                cp -a ${source'} "$tmp/${dest}"
+              ''
+          ) config.boot.initrd.secrets)
+         }
+
+        (cd "$tmp" && find . | cpio -H newc -o) | gzip >>"$1"
+      '';
+
 in
 
 {
@@ -370,6 +427,25 @@ in
       example = "xz";
     };
 
+    boot.initrd.secrets = mkOption
+      { internal = true;
+        default = {};
+        type = types.attrsOf (types.nullOr types.path);
+        description =
+          ''
+            Secrets to append to the initrd. The attribute name is the
+            path the secret should have inside the initrd, the value
+            is the path it should be copied from (or null for the same
+            path inside and out).
+          '';
+        example = literalExample
+          ''
+            { "/etc/dropbear/dropbear_rsa_host_key" =
+                ./secret-dropbear-key;
+            }
+          '';
+      };
+
     boot.initrd.supportedFilesystems = mkOption {
       default = [ ];
       example = [ "btrfs" ];
@@ -377,6 +453,18 @@ in
       description = "Names of supported filesystem types in the initial ramdisk.";
     };
 
+    boot.loader.supportsInitrdSecrets = mkOption
+      { internal = true;
+        default = false;
+        type = types.bool;
+        description =
+          ''
+            Whether the bootloader setup runs append-initrd-secrets.
+            If not, any needed secrets must be copied into the initrd
+            and thus added to the store.
+          '';
+      };
+
     fileSystems = mkOption {
       options.neededForBoot = mkOption {
         default = false;
@@ -404,9 +492,8 @@ in
       }
     ];
 
-    system.build.bootStage1 = bootStage1;
-    system.build.initialRamdisk = initialRamdisk;
-    system.build.extraUtils = extraUtils;
+    system.build =
+      { inherit bootStage1 initialRamdisk initialRamdiskSecretAppender extraUtils; };
 
     system.requiredKernelConfig = with config.lib.kernelConfig; [
       (isYes "TMPFS")
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index f827e530f877..46aed44bf10f 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -2,7 +2,22 @@
 
 systemConfig=@systemConfig@
 
-export HOME=/root
+export HOME=/root PATH="@path@"
+
+
+# Process the kernel command line.
+for o in $(</proc/cmdline); do
+    case $o in
+        boot.debugtrace)
+            # Show each command.
+            set -x
+            ;;
+        resume=*)
+            set -- $(IFS==; echo $o)
+            resumeDevice=$2
+            ;;
+    esac
+done
 
 
 # Print a greeting.
@@ -11,21 +26,6 @@ echo -e "\e[1;32m<<< NixOS Stage 2 >>>\e[0m"
 echo
 
 
-# Set the PATH.
-setPath() {
-    local dirs="$1"
-    export PATH=/empty
-    for i in $dirs; do
-        PATH=$PATH:$i/bin
-        if test -e $i/sbin; then
-            PATH=$PATH:$i/sbin
-        fi
-    done
-}
-
-setPath "@path@"
-
-
 # Normally, stage 1 mounts the root filesystem read/writable.
 # However, in some environments, stage 2 is executed directly, and the
 # root is read-only.  So make it writable here.
@@ -61,7 +61,9 @@ echo "booting system configuration $systemConfig" > /dev/kmsg
 chown -f 0:30000 /nix/store
 chmod -f 1775 /nix/store
 if [ -n "@readOnlyStore@" ]; then
-    if ! readonly-mountpoint /nix/store; then
+    if ! [[ "$(findmnt --noheadings --output OPTIONS /nix/store)" =~ ro(,|$) ]]; then
+        # FIXME when linux < 4.5 is EOL, switch to atomic bind mounts
+        #mount /nix/store /nix/store -o bind,remount,ro
         mount --bind /nix/store /nix/store
         mount -o remount,ro,bind /nix/store
     fi
@@ -75,31 +77,12 @@ rm -f /etc/mtab* # not that we care about stale locks
 ln -s /proc/mounts /etc/mtab
 
 
-# Process the kernel command line.
-for o in $(cat /proc/cmdline); do
-    case $o in
-        boot.debugtrace)
-            # Show each command.
-            set -x
-            ;;
-        resume=*)
-            set -- $(IFS==; echo $o)
-            resumeDevice=$2
-            ;;
-    esac
-done
-
-
 # More special file systems, initialise required directories.
 [ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default
 mkdir -m 01777 -p /tmp
-mkdir -m 0755 -p /var /var/log /var/lib /var/db
-mkdir -m 0755 -p /nix/var
-mkdir -m 0700 -p /root
-chmod 0700 /root
-mkdir -m 0755 -p /bin # for the /bin/sh symlink
-mkdir -m 0755 -p /home
-mkdir -m 0755 -p /etc/nixos
+mkdir -m 0755 -p /var/{log,lib,db} /nix/var /etc/nixos/ \
+    /run/lock /home /bin # for the /bin/sh symlink
+install -m 0700 -d /root
 
 
 # Miscellaneous boot time cleanup.
@@ -111,9 +94,6 @@ rm -f /etc/{group,passwd,shadow}.lock
 rm -rf /nix/var/nix/gcroots/tmp /nix/var/nix/temproots
 
 
-mkdir -m 0755 -p /run/lock
-
-
 # For backwards compatibility, symlink /var/run to /run, and /var/lock
 # to /run/lock.
 ln -s /run /var/run
@@ -127,8 +107,8 @@ fi
 
 
 # Use /etc/resolv.conf supplied by systemd-nspawn, if applicable.
-if [ -n "@useHostResolvConf@" -a -e /etc/resolv.conf ]; then
-    cat /etc/resolv.conf | resolvconf -m 1000 -a host
+if [ -n "@useHostResolvConf@" ] && [ -e /etc/resolv.conf ]; then
+    resolvconf -m 1000 -a host </etc/resolv.conf
 fi
 
 # Log the script output to /dev/kmsg or /run/log/stage-2-init.log.
diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix
index 7e4ec2a4a670..8db6d2d2f734 100644
--- a/nixos/modules/system/boot/stage-2.nix
+++ b/nixos/modules/system/boot/stage-2.nix
@@ -7,15 +7,6 @@ let
   kernel = config.boot.kernelPackages.kernel;
   activateConfiguration = config.system.activationScripts.script;
 
-  readonlyMountpoint = pkgs.stdenv.mkDerivation {
-    name = "readonly-mountpoint";
-    unpackPhase = "true";
-    installPhase = ''
-      mkdir -p $out/bin
-      cc -O3 ${./readonly-mountpoint.c} -o $out/bin/readonly-mountpoint
-    '';
-  };
-
   bootStage2 = pkgs.substituteAll {
     src = ./stage-2-init.sh;
     shellDebug = "${pkgs.bashInteractive}/bin/bash";
@@ -23,11 +14,11 @@ let
     inherit (config.nix) readOnlyStore;
     inherit (config.networking) useHostResolvConf;
     inherit (config.system.build) earlyMountScript;
-    path =
-      [ pkgs.coreutils
-        pkgs.utillinux
-        pkgs.openresolv
-      ] ++ optional config.nix.readOnlyStore readonlyMountpoint;
+    path = lib.makeBinPath [
+      pkgs.coreutils
+      pkgs.utillinux
+      pkgs.openresolv
+    ];
     postBootCommands = pkgs.writeText "local-cmds"
       ''
         ${config.boot.postBootCommands}
diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix
index 997770b8beca..7c01f8ea9b7f 100644
--- a/nixos/modules/system/boot/systemd-lib.nix
+++ b/nixos/modules/system/boot/systemd-lib.nix
@@ -10,7 +10,7 @@ rec {
 
   makeUnit = name: unit:
     let
-      pathSafeName = lib.replaceChars ["@" ":" "\\"] ["-" "-" "-"] name;
+      pathSafeName = lib.replaceChars ["@" ":" "\\" "[" "]"] ["-" "-" "-" "" ""] name;
     in
     if unit.enable then
       pkgs.runCommand "unit-${pathSafeName}"
@@ -159,7 +159,13 @@ rec {
         fi
       done
 
-      # Created .wants and .requires symlinks from the wantedBy and
+      # Create service aliases from aliases option.
+      ${concatStrings (mapAttrsToList (name: unit:
+          concatMapStrings (name2: ''
+            ln -sfn '${name}' $out/'${name2}'
+          '') unit.aliases) units)}
+
+      # Create .wants and .requires symlinks from the wantedBy and
       # requiredBy options.
       ${concatStrings (mapAttrsToList (name: unit:
           concatMapStrings (name2: ''
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
index 69af23981485..9be10a8283ed 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -52,6 +52,12 @@ in rec {
       description = "Units that want (i.e. depend on) this unit.";
     };
 
+    aliases = mkOption {
+      default = [];
+      type = types.listOf types.str;
+      description = "Aliases of that unit.";
+    };
+
   };
 
   concreteUnitOptions = sharedOptions // {
@@ -322,7 +328,7 @@ in rec {
         Automatically start this unit at the given date/time, which
         must be in the format described in
         <citerefentry><refentrytitle>systemd.time</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry>.  This is equivalent
+        <manvolnum>7</manvolnum></citerefentry>.  This is equivalent
         to adding a corresponding timer unit with
         <option>OnCalendar</option> set to the value given here.
       '';
@@ -369,9 +375,9 @@ in rec {
         Each attribute in this set specifies an option in the
         <literal>[Timer]</literal> section of the unit.  See
         <citerefentry><refentrytitle>systemd.timer</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> and
+        <manvolnum>7</manvolnum></citerefentry> and
         <citerefentry><refentrytitle>systemd.time</refentrytitle>
-        <manvolnum>5</manvolnum></citerefentry> for details.
+        <manvolnum>7</manvolnum></citerefentry> for details.
       '';
     };
 
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index a2ee51669715..f798862513cb 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -17,6 +17,7 @@ let
       "busnames.target"
       "sysinit.target"
       "sockets.target"
+      "exit.target"
       "graphical.target"
       "multi-user.target"
       "network.target"
@@ -41,11 +42,14 @@ let
       "systemd-udevd.service"
       "systemd-udev-settle.service"
       "systemd-udev-trigger.service"
+      # hwdb.bin is managed by NixOS
+      # "systemd-hwdb-update.service"
 
       # Consoles.
       "getty.target"
       "getty@.service"
       "serial-getty@.service"
+      "console-getty.service"
       "container-getty@.service"
       "systemd-vconsole-setup.service"
 
@@ -58,7 +62,6 @@ let
       # Login stuff.
       "systemd-logind.service"
       "autovt@.service"
-      #"systemd-vconsole-setup.service"
       "systemd-user-sessions.service"
       "dbus-org.freedesktop.login1.service"
       "dbus-org.freedesktop.machine1.service"
@@ -72,6 +75,7 @@ let
       "systemd-journal-flush.service"
       "systemd-journal-gatewayd.socket"
       "systemd-journal-gatewayd.service"
+      "systemd-journal-catalog-update.service"
       "systemd-journald-audit.socket"
       "systemd-journald-dev-log.socket"
       "syslog.socket"
@@ -104,6 +108,7 @@ let
       "systemd-random-seed.service"
       "systemd-backlight@.service"
       "systemd-rfkill.service"
+      "systemd-rfkill.socket"
 
       # Hibernate / suspend.
       "hibernate.target"
@@ -111,8 +116,8 @@ let
       "sleep.target"
       "hybrid-sleep.target"
       "systemd-hibernate.service"
-      "systemd-suspend.service"
       "systemd-hybrid-sleep.service"
+      "systemd-suspend.service"
 
       # Reboot stuff.
       "reboot.target"
@@ -136,10 +141,10 @@ let
 
       # Slices / containers.
       "slices.target"
-      "-.slice"
       "system.slice"
       "user.slice"
       "machine.slice"
+      "machines.target"
       "systemd-machined.service"
       "systemd-nspawn@.service"
 
@@ -162,12 +167,12 @@ let
       "systemd-localed.service"
       "systemd-hostnamed.service"
       "systemd-binfmt.service"
+      "systemd-exit.service"
     ]
     ++ cfg.additionalUpstreamSystemUnits;
 
   upstreamSystemWants =
-    [ #"basic.target.wants"
-      "sysinit.target.wants"
+    [ "sysinit.target.wants"
       "sockets.target.wants"
       "local-fs.target.wants"
       "multi-user.target.wants"
@@ -176,11 +181,18 @@ let
 
   upstreamUserUnits =
     [ "basic.target"
+      "bluetooth.target"
+      "busnames.target"
       "default.target"
       "exit.target"
+      "graphical-session-pre.target"
+      "graphical-session.target"
       "paths.target"
+      "printer.target"
       "shutdown.target"
+      "smartcard.target"
       "sockets.target"
+      "sound.target"
       "systemd-exit.service"
       "timers.target"
     ];
@@ -301,7 +313,7 @@ let
     '';
 
   targetToUnit = name: def:
-    { inherit (def) wantedBy requiredBy enable;
+    { inherit (def) aliases wantedBy requiredBy enable;
       text =
         ''
           [Unit]
@@ -310,14 +322,14 @@ let
     };
 
   serviceToUnit = name: def:
-    { inherit (def) wantedBy requiredBy enable;
+    { inherit (def) aliases wantedBy requiredBy enable;
       text = commonUnitText def +
         ''
           [Service]
           ${let env = cfg.globalEnvironment // def.environment;
             in concatMapStrings (n:
               let s = optionalString (env."${n}" != null)
-                "Environment=\"${n}=${env.${n}}\"\n";
+                "Environment=${builtins.toJSON "${n}=${env.${n}}"}\n";
               in if stringLength s >= 2048 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env)}
           ${if def.reloadIfChanged then ''
             X-ReloadIfChanged=true
@@ -330,7 +342,7 @@ let
     };
 
   socketToUnit = name: def:
-    { inherit (def) wantedBy requiredBy enable;
+    { inherit (def) aliases wantedBy requiredBy enable;
       text = commonUnitText def +
         ''
           [Socket]
@@ -340,7 +352,7 @@ let
     };
 
   timerToUnit = name: def:
-    { inherit (def) wantedBy requiredBy enable;
+    { inherit (def) aliases wantedBy requiredBy enable;
       text = commonUnitText def +
         ''
           [Timer]
@@ -349,7 +361,7 @@ let
     };
 
   pathToUnit = name: def:
-    { inherit (def) wantedBy requiredBy enable;
+    { inherit (def) aliases wantedBy requiredBy enable;
       text = commonUnitText def +
         ''
           [Path]
@@ -358,7 +370,7 @@ let
     };
 
   mountToUnit = name: def:
-    { inherit (def) wantedBy requiredBy enable;
+    { inherit (def) aliases wantedBy requiredBy enable;
       text = commonUnitText def +
         ''
           [Mount]
@@ -367,7 +379,7 @@ let
     };
 
   automountToUnit = name: def:
-    { inherit (def) wantedBy requiredBy enable;
+    { inherit (def) aliases wantedBy requiredBy enable;
       text = commonUnitText def +
         ''
           [Automount]
@@ -376,7 +388,7 @@ let
     };
 
   sliceToUnit = name: def:
-    { inherit (def) wantedBy requiredBy enable;
+    { inherit (def) aliases wantedBy requiredBy enable;
       text = commonUnitText def +
         ''
           [Slice]
@@ -741,7 +753,8 @@ in
 
         # Keep a persistent journal. Note that systemd-tmpfiles will
         # set proper ownership/permissions.
-        mkdir -m 0700 -p /var/log/journal
+        # FIXME: revert to 0700 with systemd v233.
+        mkdir -m 0750 -p /var/log/journal
       '';
 
     users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network;
@@ -816,7 +829,8 @@ in
 
     # Some overrides to upstream units.
     systemd.services."systemd-backlight@".restartIfChanged = false;
-    systemd.services."systemd-rfkill@".restartIfChanged = false;
+    systemd.services."systemd-fsck@".restartIfChanged = false;
+    systemd.services."systemd-fsck@".path = [ config.system.path ];
     systemd.services."user@".restartIfChanged = false;
     systemd.services.systemd-journal-flush.restartIfChanged = false;
     systemd.services.systemd-random-seed.restartIfChanged = false;
@@ -829,6 +843,7 @@ in
     systemd.services.systemd-journald.stopIfChanged = false;
     systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true;
     systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
+    systemd.targets.network-online.wantedBy = [ "multi-user.target" ];
     systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.automount" ];
 
     # Don't bother with certain units in containers.