summary refs log tree commit diff
path: root/nixos/modules/installer
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2018-10-16 20:25:44 +0200
committerEelco Dolstra <edolstra@gmail.com>2018-10-16 20:25:44 +0200
commitb6bac6c144d83d364a5d0ab0bef7d6ffa9efc55b (patch)
treed8ea414a00c575e6994d7dde170d35480e0df9e8 /nixos/modules/installer
parent887bf77621dbd93c3e5296a6b047d00bf3da8b78 (diff)
downloadnixlib-b6bac6c144d83d364a5d0ab0bef7d6ffa9efc55b.tar
nixlib-b6bac6c144d83d364a5d0ab0bef7d6ffa9efc55b.tar.gz
nixlib-b6bac6c144d83d364a5d0ab0bef7d6ffa9efc55b.tar.bz2
nixlib-b6bac6c144d83d364a5d0ab0bef7d6ffa9efc55b.tar.lz
nixlib-b6bac6c144d83d364a5d0ab0bef7d6ffa9efc55b.tar.xz
nixlib-b6bac6c144d83d364a5d0ab0bef7d6ffa9efc55b.tar.zst
nixlib-b6bac6c144d83d364a5d0ab0bef7d6ffa9efc55b.zip
Revert "Merge pull request #48122 from zimbatm/pkg-nixos-rebuild"
This reverts commit 10addad6035034b2b78f3c74ef436cd7146d5231, reversing
changes made to 7786575c6c0e1b010d46ad00b14d0bb5bf08d7d2.

NixOS scripts should be kept in the NixOS source tree, not in
pkgs. Moving them around is just confusing and creates unnecessary
code/history churn.
Diffstat (limited to 'nixos/modules/installer')
-rw-r--r--nixos/modules/installer/tools/nix-fallback-paths.nix6
-rw-r--r--nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh57
-rw-r--r--nixos/modules/installer/tools/nixos-enter.sh61
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl650
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh144
-rw-r--r--nixos/modules/installer/tools/nixos-option.sh327
-rw-r--r--nixos/modules/installer/tools/nixos-rebuild.sh387
-rw-r--r--nixos/modules/installer/tools/nixos-version.sh14
-rw-r--r--nixos/modules/installer/tools/tools.nix86
9 files changed, 1710 insertions, 22 deletions
diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix
new file mode 100644
index 000000000000..1cfc8ff8612e
--- /dev/null
+++ b/nixos/modules/installer/tools/nix-fallback-paths.nix
@@ -0,0 +1,6 @@
+{
+  x86_64-linux = "/nix/store/cdcia67siabmj6li7vyffgv2cry86fq8-nix-2.1.3";
+  i686-linux = "/nix/store/6q3xi6y5qnsv7d62b8n00hqfxi8rs2xs-nix-2.1.3";
+  aarch64-linux = "/nix/store/2v93d0vimlm28jg0ms6v1i6lc0fq13pn-nix-2.1.3";
+  x86_64-darwin = "/nix/store/dkjlfkrknmxbjmpfk3dg4q3nmb7m3zvk-nix-2.1.3";
+}
diff --git a/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh b/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh
new file mode 100644
index 000000000000..4e981c074a57
--- /dev/null
+++ b/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh
@@ -0,0 +1,57 @@
+#! @shell@ -e
+
+# Shows the usage of this command to the user
+
+showUsage() {
+    exec man nixos-build-vms
+    exit 1
+}
+
+# Parse valid argument options
+
+PARAMS=`getopt -n $0 -o h -l no-out-link,show-trace,help -- "$@"`
+
+if [ $? != 0 ]
+then
+    showUsage
+    exit 1
+fi
+
+eval set -- "$PARAMS"
+
+# Evaluate valid options
+
+while [ "$1" != "--" ]
+do
+    case "$1" in
+	--no-out-link)
+	    noOutLinkArg="--no-out-link"
+	    ;;
+	--show-trace)
+	    showTraceArg="--show-trace"
+	    ;;
+	-h|--help)
+	    showUsage
+	    exit 0
+	    ;;
+    esac
+    
+    shift
+done
+
+shift
+
+# Validate the given options
+
+if [ "$1" = "" ]
+then
+    echo "ERROR: A network expression must be specified!" >&2
+    exit 1
+else
+    networkExpr=$(readlink -f $1)
+fi
+
+# Build a network of VMs
+
+nix-build '<nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix>' \
+    --argstr networkExpr $networkExpr $noOutLinkArg $showTraceArg
diff --git a/nixos/modules/installer/tools/nixos-enter.sh b/nixos/modules/installer/tools/nixos-enter.sh
new file mode 100644
index 000000000000..518dbbbf21e3
--- /dev/null
+++ b/nixos/modules/installer/tools/nixos-enter.sh
@@ -0,0 +1,61 @@
+#! @shell@
+
+set -e
+
+# Re-exec ourselves in a private mount namespace so that our bind
+# mounts get cleaned up automatically.
+if [ -z "$NIXOS_ENTER_REEXEC" ]; then
+    export NIXOS_ENTER_REEXEC=1
+    if [ "$(id -u)" != 0 ]; then
+        extraFlags="-r"
+    fi
+    exec unshare --fork --mount --uts --mount-proc --pid $extraFlags -- "$0" "$@"
+else
+    mount --make-rprivate /
+fi
+
+mountPoint=/mnt
+system=/nix/var/nix/profiles/system
+command=($system/sw/bin/bash "--login")
+
+while [ "$#" -gt 0 ]; do
+    i="$1"; shift 1
+    case "$i" in
+        --root)
+            mountPoint="$1"; shift 1
+            ;;
+        --system)
+            system="$1"; shift 1
+            ;;
+        --help)
+            exec man nixos-enter
+            exit 1
+            ;;
+        --command|-c)
+            command=($system/sw/bin/bash "-c" "$1")
+            shift 1
+            ;;
+        --)
+            command=("$@")
+            break
+            ;;
+        *)
+            echo "$0: unknown option \`$i'"
+            exit 1
+            ;;
+    esac
+done
+
+if [[ ! -e $mountPoint/etc/NIXOS ]]; then
+    echo "$0: '$mountPoint' is not a NixOS installation" >&2
+    exit 126
+fi
+
+mkdir -m 0755 -p "$mountPoint/dev" "$mountPoint/sys"
+mount --rbind /dev "$mountPoint/dev"
+mount --rbind /sys "$mountPoint/sys"
+
+# Run the activation script. Set $LOCALE_ARCHIVE to supress some Perl locale warnings.
+LOCALE_ARCHIVE=$system/sw/lib/locale/locale-archive chroot "$mountPoint" "$system/activate" >&2 || true
+
+exec chroot "$mountPoint" "${command[@]}"
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
new file mode 100644
index 000000000000..b70faa380e54
--- /dev/null
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -0,0 +1,650 @@
+#! @perl@
+
+use strict;
+use Cwd 'abs_path';
+use File::Spec;
+use File::Path;
+use File::Basename;
+use File::Slurp;
+use File::stat;
+
+umask(0022);
+
+sub uniq {
+    my %seen;
+    my @res = ();
+    foreach my $s (@_) {
+        if (!defined $seen{$s}) {
+            $seen{$s} = 1;
+            push @res, $s;
+        }
+    }
+    return @res;
+}
+
+sub runCommand {
+    my ($cmd) = @_;
+    open FILE, "$cmd 2>&1 |" or die "Failed to execute: $cmd\n";
+    my @ret = <FILE>;
+    close FILE;
+    return ($?, @ret);
+}
+
+# Process the command line.
+my $outDir = "/etc/nixos";
+my $rootDir = ""; # = /
+my $force = 0;
+my $noFilesystems = 0;
+my $showHardwareConfig = 0;
+
+for (my $n = 0; $n < scalar @ARGV; $n++) {
+    my $arg = $ARGV[$n];
+    if ($arg eq "--help") {
+        exec "man nixos-generate-config" or die;
+    }
+    elsif ($arg eq "--dir") {
+        $n++;
+        $outDir = $ARGV[$n];
+        die "$0: ‘--dir’ requires an argument\n" unless defined $outDir;
+    }
+    elsif ($arg eq "--root") {
+        $n++;
+        $rootDir = $ARGV[$n];
+        die "$0: ‘--root’ requires an argument\n" unless defined $rootDir;
+        $rootDir =~ s/\/*$//; # remove trailing slashes
+    }
+    elsif ($arg eq "--force") {
+        $force = 1;
+    }
+    elsif ($arg eq "--no-filesystems") {
+        $noFilesystems = 1;
+    }
+    elsif ($arg eq "--show-hardware-config") {
+        $showHardwareConfig = 1;
+    }
+    else {
+        die "$0: unrecognized argument ‘$arg’\n";
+    }
+}
+
+
+my @attrs = ();
+my @kernelModules = ();
+my @initrdKernelModules = ();
+my @initrdAvailableKernelModules = ();
+my @modulePackages = ();
+my @imports;
+
+
+sub debug {
+    return unless defined $ENV{"DEBUG"};
+    print STDERR @_;
+}
+
+
+my $cpuinfo = read_file "/proc/cpuinfo";
+
+
+sub hasCPUFeature {
+    my $feature = shift;
+    return $cpuinfo =~ /^flags\s*:.* $feature( |$)/m;
+}
+
+
+# Detect the number of CPU cores.
+my $cpus = scalar (grep {/^processor\s*:/} (split '\n', $cpuinfo));
+
+
+# Determine CPU governor to use
+if (-e "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") {
+    my $governors = read_file("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors");
+    # ondemand governor is not available on sandy bridge or later Intel CPUs
+    my @desired_governors = ("ondemand", "powersave");
+    my $e;
+
+    foreach $e (@desired_governors) {
+        if (index($governors, $e) != -1) {
+            last if (push @attrs, "powerManagement.cpuFreqGovernor = lib.mkDefault \"$e\";");
+        }
+    }
+}
+
+
+# Virtualization support?
+push @kernelModules, "kvm-intel" if hasCPUFeature "vmx";
+push @kernelModules, "kvm-amd" if hasCPUFeature "svm";
+
+
+# Look at the PCI devices and add necessary modules.  Note that most
+# modules are auto-detected so we don't need to list them here.
+# However, some are needed in the initrd to boot the system.
+
+my $videoDriver;
+
+sub pciCheck {
+    my $path = shift;
+    my $vendor = read_file "$path/vendor"; chomp $vendor;
+    my $device = read_file "$path/device"; chomp $device;
+    my $class = read_file "$path/class"; chomp $class;
+
+    my $module;
+    if (-e "$path/driver/module") {
+        $module = basename `readlink -f $path/driver/module`;
+        chomp $module;
+    }
+
+    debug "$path: $vendor $device $class";
+    debug " $module" if defined $module;
+    debug "\n";
+
+    if (defined $module) {
+        # See the bottom of http://pciids.sourceforge.net/pci.ids for
+        # device classes.
+        if (# Mass-storage controller.  Definitely important.
+            $class =~ /^0x01/ ||
+
+            # Firewire controller.  A disk might be attached.
+            $class =~ /^0x0c00/ ||
+
+            # USB controller.  Needed if we want to use the
+            # keyboard when things go wrong in the initrd.
+            $class =~ /^0x0c03/
+            )
+        {
+            push @initrdAvailableKernelModules, $module;
+        }
+    }
+
+    # broadcom STA driver (wl.ko)
+    # list taken from http://www.broadcom.com/docs/linux_sta/README.txt
+    if ($vendor eq "0x14e4" &&
+        ($device eq "0x4311" || $device eq "0x4312" || $device eq "0x4313" ||
+         $device eq "0x4315" || $device eq "0x4327" || $device eq "0x4328" ||
+         $device eq "0x4329" || $device eq "0x432a" || $device eq "0x432b" ||
+         $device eq "0x432c" || $device eq "0x432d" || $device eq "0x4353" ||
+         $device eq "0x4357" || $device eq "0x4358" || $device eq "0x4359" ||
+         $device eq "0x4331" || $device eq "0x43a0" || $device eq "0x43b1"
+        ) )
+     {
+        push @modulePackages, "config.boot.kernelPackages.broadcom_sta";
+        push @kernelModules, "wl";
+     }
+
+    # broadcom FullMac driver
+    # list taken from
+    # https://wireless.wiki.kernel.org/en/users/Drivers/brcm80211#brcmfmac
+    if ($vendor eq "0x14e4" &&
+        ($device eq "0x43a3" || $device eq "0x43df" || $device eq "0x43ec" ||
+         $device eq "0x43d3" || $device eq "0x43d9" || $device eq "0x43e9" ||
+         $device eq "0x43ba" || $device eq "0x43bb" || $device eq "0x43bc" ||
+         $device eq "0xaa52" || $device eq "0x43ca" || $device eq "0x43cb" ||
+         $device eq "0x43cc" || $device eq "0x43c3" || $device eq "0x43c4" ||
+         $device eq "0x43c5"
+        ) )
+    {
+        # we need e.g. brcmfmac43602-pcie.bin
+        push @imports, "<nixpkgs/nixos/modules/hardware/network/broadcom-43xx.nix>";
+    }
+
+    # Can't rely on $module here, since the module may not be loaded
+    # due to missing firmware.  Ideally we would check modules.pcimap
+    # here.
+    push @attrs, "networking.enableIntel2200BGFirmware = true;" if
+        $vendor eq "0x8086" &&
+        ($device eq "0x1043" || $device eq "0x104f" || $device eq "0x4220" ||
+         $device eq "0x4221" || $device eq "0x4223" || $device eq "0x4224");
+
+    push @attrs, "networking.enableIntel3945ABGFirmware = true;" if
+        $vendor eq "0x8086" &&
+        ($device eq "0x4229" || $device eq "0x4230" ||
+         $device eq "0x4222" || $device eq "0x4227");
+
+    # Assume that all NVIDIA cards are supported by the NVIDIA driver.
+    # There may be exceptions (e.g. old cards).
+    # FIXME: do we want to enable an unfree driver here?
+    #$videoDriver = "nvidia" if $vendor eq "0x10de" && $class =~ /^0x03/;
+}
+
+foreach my $path (glob "/sys/bus/pci/devices/*") {
+    pciCheck $path;
+}
+
+# Idem for USB devices.
+
+sub usbCheck {
+    my $path = shift;
+    my $class = read_file "$path/bInterfaceClass"; chomp $class;
+    my $subclass = read_file "$path/bInterfaceSubClass"; chomp $subclass;
+    my $protocol = read_file "$path/bInterfaceProtocol"; chomp $protocol;
+
+    my $module;
+    if (-e "$path/driver/module") {
+        $module = basename `readlink -f $path/driver/module`;
+        chomp $module;
+    }
+
+    debug "$path: $class $subclass $protocol";
+    debug " $module" if defined $module;
+    debug "\n";
+
+    if (defined $module) {
+        if (# Mass-storage controller.  Definitely important.
+            $class eq "08" ||
+
+            # Keyboard.  Needed if we want to use the
+            # keyboard when things go wrong in the initrd.
+            ($class eq "03" && $protocol eq "01")
+            )
+        {
+            push @initrdAvailableKernelModules, $module;
+        }
+    }
+}
+
+foreach my $path (glob "/sys/bus/usb/devices/*") {
+    if (-e "$path/bInterfaceClass") {
+        usbCheck $path;
+    }
+}
+
+
+# Add the modules for all block and MMC devices.
+foreach my $path (glob "/sys/class/{block,mmc_host}/*") {
+    my $module;
+    if (-e "$path/device/driver/module") {
+        $module = basename `readlink -f $path/device/driver/module`;
+        chomp $module;
+        push @initrdAvailableKernelModules, $module;
+    }
+}
+
+
+my $virt = `systemd-detect-virt`;
+chomp $virt;
+
+
+# Check if we're a VirtualBox guest.  If so, enable the guest
+# additions.
+if ($virt eq "oracle") {
+    push @attrs, "virtualisation.virtualbox.guest.enable = true;"
+}
+
+
+# Likewise for QEMU.
+if ($virt eq "qemu" || $virt eq "kvm" || $virt eq "bochs") {
+    push @imports, "<nixpkgs/nixos/modules/profiles/qemu-guest.nix>";
+}
+
+# Also for Hyper-V.
+if ($virt eq "microsoft") {
+    push @attrs, "virtualisation.hypervGuest.enable = true;"
+}
+
+
+# Pull in NixOS configuration for containers.
+if ($virt eq "systemd-nspawn") {
+    push @attrs, "boot.isContainer = true;";
+}
+
+
+# Provide firmware for devices that are not detected by this script,
+# unless we're in a VM/container.
+push @imports, "<nixpkgs/nixos/modules/installer/scan/not-detected.nix>"
+    if $virt eq "none";
+
+
+# For a device name like /dev/sda1, find a more stable path like
+# /dev/disk/by-uuid/X or /dev/disk/by-label/Y.
+sub findStableDevPath {
+    my ($dev) = @_;
+    return $dev if substr($dev, 0, 1) ne "/";
+    return $dev unless -e $dev;
+
+    my $st = stat($dev) or return $dev;
+
+    foreach my $dev2 (glob("/dev/disk/by-uuid/*"), glob("/dev/mapper/*"), glob("/dev/disk/by-label/*")) {
+        my $st2 = stat($dev2) or next;
+        return $dev2 if $st->rdev == $st2->rdev;
+    }
+
+    return $dev;
+}
+
+push @attrs, "services.xserver.videoDrivers = [ \"$videoDriver\" ];" if $videoDriver;
+
+# Generate the swapDevices option from the currently activated swap
+# devices.
+my @swaps = read_file("/proc/swaps");
+shift @swaps;
+my @swapDevices;
+foreach my $swap (@swaps) {
+    $swap =~ /^(\S+)\s/;
+    next unless -e $1;
+    my $dev = findStableDevPath $1;
+    push @swapDevices, "{ device = \"$dev\"; }";
+}
+
+
+# Generate the fileSystems option from the currently mounted
+# filesystems.
+sub in {
+    my ($d1, $d2) = @_;
+    return $d1 eq $d2 || substr($d1, 0, length($d2) + 1) eq "$d2/";
+}
+
+my $fileSystems;
+my %fsByDev;
+foreach my $fs (read_file("/proc/self/mountinfo")) {
+    chomp $fs;
+    my @fields = split / /, $fs;
+    my $mountPoint = $fields[4];
+    next unless -d $mountPoint;
+    my @mountOptions = split /,/, $fields[5];
+
+    next if !in($mountPoint, $rootDir);
+    $mountPoint = substr($mountPoint, length($rootDir)); # strip the root directory (e.g. /mnt)
+    $mountPoint = "/" if $mountPoint eq "";
+
+    # Skip special filesystems.
+    next if in($mountPoint, "/proc") || in($mountPoint, "/dev") || in($mountPoint, "/sys") || in($mountPoint, "/run") || $mountPoint eq "/var/lib/nfs/rpc_pipefs";
+
+    # Skip the optional fields.
+    my $n = 6; $n++ while $fields[$n] ne "-"; $n++;
+    my $fsType = $fields[$n];
+    my $device = $fields[$n + 1];
+    my @superOptions = split /,/, $fields[$n + 2];
+
+    # Skip the read-only bind-mount on /nix/store.
+    next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions) && (grep { $_ eq "ro" } @mountOptions);
+
+    # Maybe this is a bind-mount of a filesystem we saw earlier?
+    if (defined $fsByDev{$fields[2]}) {
+        # Make sure this isn't a btrfs subvolume.
+        my $msg = `btrfs subvol show $rootDir$mountPoint`;
+        if ($? != 0 || $msg =~ /ERROR:/s) {
+            my $path = $fields[3]; $path = "" if $path eq "/";
+            my $base = $fsByDev{$fields[2]};
+            $base = "" if $base eq "/";
+            $fileSystems .= <<EOF;
+  fileSystems.\"$mountPoint\" =
+    { device = \"$base$path\";
+      fsType = \"none\";
+      options = \[ \"bind\" \];
+    };
+
+EOF
+            next;
+        }
+    }
+    $fsByDev{$fields[2]} = $mountPoint;
+
+    # We don't know how to handle FUSE filesystems.
+    if ($fsType eq "fuseblk" || $fsType eq "fuse") {
+        print STDERR "warning: don't know how to emit ‘fileSystem’ option for FUSE filesystem ‘$mountPoint’\n";
+        next;
+    }
+
+    # Is this a mount of a loopback device?
+    my @extraOptions;
+    if ($device =~ /\/dev\/loop(\d+)/) {
+        my $loopnr = $1;
+        my $backer = read_file "/sys/block/loop$loopnr/loop/backing_file";
+        if (defined $backer) {
+            chomp $backer;
+            $device = $backer;
+            push @extraOptions, "loop";
+        }
+    }
+
+    # Is this a btrfs filesystem?
+    if ($fsType eq "btrfs") {
+        my ($status, @info) = runCommand("btrfs subvol show $rootDir$mountPoint");
+        if ($status != 0 || join("", @info) =~ /ERROR:/) {
+            die "Failed to retrieve subvolume info for $mountPoint\n";
+        }
+        my @ids = join("\n", @info) =~ m/^(?!\/\n).*Subvolume ID:[ \t\n]*([0-9]+)/s;
+        if ($#ids > 0) {
+            die "Btrfs subvol name for $mountPoint listed multiple times in mount\n"
+        } elsif ($#ids == 0) {
+            my @paths = join("", @info) =~ m/^([^\n]*)/;
+            if ($#paths > 0) {
+                die "Btrfs returned multiple paths for a single subvolume id, mountpoint $mountPoint\n";
+            } elsif ($#paths != 0) {
+                die "Btrfs did not return a path for the subvolume at $mountPoint\n";
+            }
+            push @extraOptions, "subvol=$paths[0]";
+        }
+    }
+
+    # Emit the filesystem.
+    $fileSystems .= <<EOF;
+  fileSystems.\"$mountPoint\" =
+    { device = \"${\(findStableDevPath $device)}\";
+      fsType = \"$fsType\";
+EOF
+
+    if (scalar @extraOptions > 0) {
+        $fileSystems .= <<EOF;
+      options = \[ ${\join " ", map { "\"" . $_ . "\"" } uniq(@extraOptions)} \];
+EOF
+    }
+
+    $fileSystems .= <<EOF;
+    };
+
+EOF
+
+    # If this filesystem is on a LUKS device, then add a
+    # boot.initrd.luks.devices entry.
+    if (-e $device) {
+        my $deviceName = basename(abs_path($device));
+        if (-e "/sys/class/block/$deviceName"
+            && read_file("/sys/class/block/$deviceName/dm/uuid",  err_mode => 'quiet') =~ /^CRYPT-LUKS/)
+        {
+            my @slaves = glob("/sys/class/block/$deviceName/slaves/*");
+            if (scalar @slaves == 1) {
+                my $slave = "/dev/" . basename($slaves[0]);
+                if (-e $slave) {
+                    my $dmName = read_file("/sys/class/block/$deviceName/dm/name");
+                    chomp $dmName;
+                    $fileSystems .= "  boot.initrd.luks.devices.\"$dmName\".device = \"${\(findStableDevPath $slave)}\";\n\n";
+                }
+            }
+        }
+    }
+}
+
+
+# Generate the hardware configuration file.
+
+sub toNixStringList {
+    my $res = "";
+    foreach my $s (@_) {
+        $res .= " \"$s\"";
+    }
+    return $res;
+}
+sub toNixList {
+    my $res = "";
+    foreach my $s (@_) {
+        $res .= " $s";
+    }
+    return $res;
+}
+
+sub multiLineList {
+    my $indent = shift;
+    return " [ ]" if !@_;
+    my $res = "\n${indent}[ ";
+    my $first = 1;
+    foreach my $s (@_) {
+        $res .= "$indent  " if !$first;
+        $first = 0;
+        $res .= "$s\n";
+    }
+    $res .= "$indent]";
+    return $res;
+}
+
+my $initrdAvailableKernelModules = toNixStringList(uniq @initrdAvailableKernelModules);
+my $kernelModules = toNixStringList(uniq @kernelModules);
+my $modulePackages = toNixList(uniq @modulePackages);
+
+my $fsAndSwap = "";
+if (!$noFilesystems) {
+    $fsAndSwap = "\n$fileSystems  ";
+    $fsAndSwap .= "swapDevices =" . multiLineList("    ", @swapDevices) . ";\n";
+}
+
+my $hwConfig = <<EOF;
+# Do not modify this file!  It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations.  Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, ... }:
+
+{
+  imports =${\multiLineList("    ", @imports)};
+
+  boot.initrd.availableKernelModules = [$initrdAvailableKernelModules ];
+  boot.kernelModules = [$kernelModules ];
+  boot.extraModulePackages = [$modulePackages ];
+$fsAndSwap
+  nix.maxJobs = lib.mkDefault $cpus;
+${\join "", (map { "  $_\n" } (uniq @attrs))}}
+EOF
+
+
+if ($showHardwareConfig) {
+    print STDOUT $hwConfig;
+} else {
+    $outDir = "$rootDir$outDir";
+
+    my $fn = "$outDir/hardware-configuration.nix";
+    print STDERR "writing $fn...\n";
+    mkpath($outDir, 0, 0755);
+    write_file($fn, $hwConfig);
+
+    # Generate a basic configuration.nix, unless one already exists.
+    $fn = "$outDir/configuration.nix";
+    if ($force || ! -e $fn) {
+        print STDERR "writing $fn...\n";
+
+        my $bootLoaderConfig = "";
+        if (-e "/sys/firmware/efi/efivars") {
+            $bootLoaderConfig = <<EOF;
+  # Use the systemd-boot EFI boot loader.
+  boot.loader.systemd-boot.enable = true;
+  boot.loader.efi.canTouchEfiVariables = true;
+EOF
+        } elsif (-e "/boot/extlinux") {
+            $bootLoaderConfig = <<EOF;
+  # Use the extlinux boot loader. (NixOS wants to enable GRUB by default)
+  boot.loader.grub.enable = false;
+  # Enables the generation of /boot/extlinux/extlinux.conf
+  boot.loader.generic-extlinux-compatible.enable = true;
+EOF
+        } elsif ($virt ne "systemd-nspawn") {
+            $bootLoaderConfig = <<EOF;
+  # Use the GRUB 2 boot loader.
+  boot.loader.grub.enable = true;
+  boot.loader.grub.version = 2;
+  # boot.loader.grub.efiSupport = true;
+  # boot.loader.grub.efiInstallAsRemovable = true;
+  # boot.loader.efi.efiSysMountPoint = "/boot/efi";
+  # Define on which hard drive you want to install Grub.
+  # boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only
+EOF
+        }
+
+        write_file($fn, <<EOF);
+# Edit this configuration file to define what should be installed on
+# your system.  Help is available in the configuration.nix(5) man page
+# and in the NixOS manual (accessible by running ‘nixos-help’).
+
+{ config, pkgs, ... }:
+
+{
+  imports =
+    [ # Include the results of the hardware scan.
+      ./hardware-configuration.nix
+    ];
+
+$bootLoaderConfig
+  # networking.hostName = "nixos"; # Define your hostname.
+  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.
+
+  # Configure network proxy if necessary
+  # networking.proxy.default = "http://user:password\@proxy:port/";
+  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
+
+  # Select internationalisation properties.
+  # i18n = {
+  #   consoleFont = "Lat2-Terminus16";
+  #   consoleKeyMap = "us";
+  #   defaultLocale = "en_US.UTF-8";
+  # };
+
+  # Set your time zone.
+  # time.timeZone = "Europe/Amsterdam";
+
+  # List packages installed in system profile. To search, run:
+  # \$ nix search wget
+  # environment.systemPackages = with pkgs; [
+  #   wget vim
+  # ];
+
+  # Some programs need SUID wrappers, can be configured further or are
+  # started in user sessions.
+  # programs.mtr.enable = true;
+  # programs.gnupg.agent = { enable = true; enableSSHSupport = true; };
+
+  # List services that you want to enable:
+
+  # Enable the OpenSSH daemon.
+  # services.openssh.enable = true;
+
+  # Open ports in the firewall.
+  # networking.firewall.allowedTCPPorts = [ ... ];
+  # networking.firewall.allowedUDPPorts = [ ... ];
+  # Or disable the firewall altogether.
+  # networking.firewall.enable = false;
+
+  # Enable CUPS to print documents.
+  # services.printing.enable = true;
+
+  # Enable sound.
+  # sound.enable = true;
+  # hardware.pulseaudio.enable = true;
+
+  # Enable the X11 windowing system.
+  # services.xserver.enable = true;
+  # services.xserver.layout = "us";
+  # services.xserver.xkbOptions = "eurosign:e";
+
+  # Enable touchpad support.
+  # services.xserver.libinput.enable = true;
+
+  # Enable the KDE Desktop Environment.
+  # services.xserver.displayManager.sddm.enable = true;
+  # services.xserver.desktopManager.plasma5.enable = true;
+
+  # Define a user account. Don't forget to set a password with ‘passwd’.
+  # users.users.guest = {
+  #   isNormalUser = true;
+  #   uid = 1000;
+  # };
+
+  # This value determines the NixOS release with which your system is to be
+  # compatible, in order to avoid breaking some software such as database
+  # servers. You should change this only after NixOS release notes say you
+  # should.
+  system.stateVersion = "${\(qw(@release@))}"; # Did you read the comment?
+
+}
+EOF
+    } else {
+        print STDERR "warning: not overwriting existing $fn\n";
+    }
+}
+
+# workaround for a bug in substituteAll
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
new file mode 100644
index 000000000000..defc46ad2a72
--- /dev/null
+++ b/nixos/modules/installer/tools/nixos-install.sh
@@ -0,0 +1,144 @@
+#! @shell@
+
+set -e
+shopt -s nullglob
+
+export PATH=@path@:$PATH
+
+# Ensure a consistent umask.
+umask 0022
+
+# Parse the command line for the -I flag
+extraBuildFlags=()
+
+mountPoint=/mnt
+channelPath=
+system=
+
+while [ "$#" -gt 0 ]; do
+    i="$1"; shift 1
+    case "$i" in
+        --max-jobs|-j|--cores|-I|--substituters)
+            j="$1"; shift 1
+            extraBuildFlags+=("$i" "$j")
+            ;;
+        --option)
+            j="$1"; shift 1
+            k="$1"; shift 1
+            extraBuildFlags+=("$i" "$j" "$k")
+            ;;
+        --root)
+            mountPoint="$1"; shift 1
+            ;;
+        --system|--closure)
+            system="$1"; shift 1
+            ;;
+        --channel)
+            channelPath="$1"; shift 1
+            ;;
+        --no-channel-copy)
+            noChannelCopy=1
+            ;;
+        --no-root-passwd)
+            noRootPasswd=1
+            ;;
+        --no-bootloader)
+            noBootLoader=1
+            ;;
+        --show-trace)
+            extraBuildFlags+=("$i")
+            ;;
+        --help)
+            exec man nixos-install
+            exit 1
+            ;;
+        --debug)
+            set -x
+            ;;
+        *)
+            echo "$0: unknown option \`$i'"
+            exit 1
+            ;;
+    esac
+done
+
+if ! test -e "$mountPoint"; then
+    echo "mount point $mountPoint doesn't exist"
+    exit 1
+fi
+
+# Get the path of the NixOS configuration file.
+if [[ -z $NIXOS_CONFIG ]]; then
+    NIXOS_CONFIG=$mountPoint/etc/nixos/configuration.nix
+fi
+
+if [[ ${NIXOS_CONFIG:0:1} != / ]]; then
+    echo "$0: \$NIXOS_CONFIG is not an absolute path"
+    exit 1
+fi
+
+if [[ ! -e $NIXOS_CONFIG && -z $system ]]; then
+    echo "configuration file $NIXOS_CONFIG doesn't exist"
+    exit 1
+fi
+
+# A place to drop temporary stuff.
+trap "rm -rf $tmpdir" EXIT
+tmpdir="$(mktemp -d)"
+
+sub="auto?trusted=1"
+
+# Build the system configuration in the target filesystem.
+if [[ -z $system ]]; then
+    echo "building the configuration in $NIXOS_CONFIG..."
+    outLink="$tmpdir/system"
+    nix build --out-link "$outLink" --store "$mountPoint" "${extraBuildFlags[@]}" \
+        --extra-substituters "$sub" \
+        -f '<nixpkgs/nixos>' system -I "nixos-config=$NIXOS_CONFIG"
+    system=$(readlink -f $outLink)
+fi
+
+# Set the system profile to point to the configuration. TODO: combine
+# this with the previous step once we have a nix-env replacement with
+# a progress bar.
+nix-env --store "$mountPoint" "${extraBuildFlags[@]}" \
+        --extra-substituters "$sub" \
+        -p $mountPoint/nix/var/nix/profiles/system --set "$system"
+
+# Copy the NixOS/Nixpkgs sources to the target as the initial contents
+# of the NixOS channel.
+if [[ -z $noChannelCopy ]]; then
+    if [[ -z $channelPath ]]; then
+        channelPath="$(nix-env -p /nix/var/nix/profiles/per-user/root/channels -q nixos --no-name --out-path 2>/dev/null || echo -n "")"
+    fi
+    if [[ -n $channelPath ]]; then
+        echo "copying channel..."
+        mkdir -p $mountPoint/nix/var/nix/profiles/per-user/root
+        nix-env --store "$mountPoint" "${extraBuildFlags[@]}" --extra-substituters "$sub" \
+                -p $mountPoint/nix/var/nix/profiles/per-user/root/channels --set "$channelPath" --quiet
+        install -m 0700 -d $mountPoint/root/.nix-defexpr
+        ln -sfn /nix/var/nix/profiles/per-user/root/channels $mountPoint/root/.nix-defexpr/channels
+    fi
+fi
+
+# Mark the target as a NixOS installation, otherwise switch-to-configuration will chicken out.
+mkdir -m 0755 -p "$mountPoint/etc"
+touch "$mountPoint/etc/NIXOS"
+
+# Switch to the new system configuration.  This will install Grub with
+# a menu default pointing at the kernel/initrd/etc of the new
+# configuration.
+if [[ -z $noBootLoader ]]; then
+    echo "installing the boot loader..."
+    # Grub needs an mtab.
+    ln -sfn /proc/mounts $mountPoint/etc/mtab
+    NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root "$mountPoint" -- /run/current-system/bin/switch-to-configuration boot
+fi
+
+# Ask the user to set a root password, but only if the passwd command
+# exists (i.e. when mutable user accounts are enabled).
+if [[ -z $noRootPasswd ]] && [ -t 0 ]; then
+    nixos-enter --root "$mountPoint" -c '[[ -e /nix/var/nix/profiles/system/sw/bin/passwd ]] && echo "setting root password..." && /nix/var/nix/profiles/system/sw/bin/passwd'
+fi
+
+echo "installation finished!"
diff --git a/nixos/modules/installer/tools/nixos-option.sh b/nixos/modules/installer/tools/nixos-option.sh
new file mode 100644
index 000000000000..327e3e6989f7
--- /dev/null
+++ b/nixos/modules/installer/tools/nixos-option.sh
@@ -0,0 +1,327 @@
+#! @shell@ -e
+
+# FIXME: rewrite this in a more suitable language.
+
+usage () {
+    exec man nixos-option
+    exit 1
+}
+
+#####################
+# Process Arguments #
+#####################
+
+xml=false
+verbose=false
+nixPath=""
+
+option=""
+exit_code=0
+
+argfun=""
+for arg; do
+  if test -z "$argfun"; then
+    case $arg in
+      -*)
+        sarg="$arg"
+        longarg=""
+        while test "$sarg" != "-"; do
+          case $sarg in
+            --*) longarg=$arg; sarg="--";;
+            -I) argfun="include_nixpath";;
+            -*) usage;;
+          esac
+          # remove the first letter option
+          sarg="-${sarg#??}"
+        done
+        ;;
+      *) longarg=$arg;;
+    esac
+    for larg in $longarg; do
+      case $larg in
+        --xml) xml=true;;
+        --verbose) verbose=true;;
+        --help) usage;;
+        -*) usage;;
+        *) if test -z "$option"; then
+             option="$larg"
+           else
+             usage
+           fi;;
+      esac
+    done
+  else
+    case $argfun in
+      set_*)
+        var=$(echo $argfun | sed 's,^set_,,')
+        eval $var=$arg
+        ;;
+      include_nixpath)
+        nixPath="-I $arg $nixPath"
+        ;;
+    esac
+    argfun=""
+  fi
+done
+
+if $verbose; then
+  set -x
+else
+  set +x
+fi
+
+#############################
+# Process the configuration #
+#############################
+
+evalNix(){
+  # disable `-e` flag, it's possible that the evaluation of `nix-instantiate` fails (e.g. due to broken pkgs)
+  set +e
+  result=$(nix-instantiate ${nixPath:+$nixPath} - --eval-only "$@" 2>&1)
+  exit_code=$?
+  set -e
+
+  if test $exit_code -eq 0; then
+      sed '/^warning: Nix search path/d' <<EOF
+$result
+EOF
+      return 0;
+  else
+      sed -n '
+  /^error/ { s/, at (string):[0-9]*:[0-9]*//; p; };
+  /^warning: Nix search path/ { p; };
+' >&2 <<EOF
+$result
+EOF
+    exit_code=1
+  fi
+}
+
+header="let
+  nixos = import <nixpkgs/nixos> {};
+  nixpkgs = import <nixpkgs> {};
+in with nixpkgs.lib;
+"
+
+# This function is used for converting the option definition path given by
+# the user into accessors for reaching the definition and the declaration
+# corresponding to this option.
+generateAccessors(){
+  if result=$(evalNix --strict --show-trace <<EOF
+$header
+
+let
+  path = "${option:+$option}";
+  pathList = splitString "." path;
+
+  walkOptions = attrsNames: result:
+    if attrsNames == [] then
+      result
+    else
+      let name = head attrsNames; rest = tail attrsNames; in
+      if isOption result.options then
+        walkOptions rest {
+          options = result.options.type.getSubOptions "";
+          opt = ''(\${result.opt}.type.getSubOptions "")'';
+          cfg = ''\${result.cfg}."\${name}"'';
+        }
+      else
+        walkOptions rest {
+          options = result.options.\${name};
+          opt = ''\${result.opt}."\${name}"'';
+          cfg = ''\${result.cfg}."\${name}"'';
+        }
+    ;
+
+  walkResult = (if path == "" then x: x else walkOptions pathList) {
+    options = nixos.options;
+    opt = ''nixos.options'';
+    cfg = ''nixos.config'';
+  };
+
+in
+  ''let option = \${walkResult.opt}; config = \${walkResult.cfg}; in''
+EOF
+)
+  then
+      echo $result
+  else
+      # In case of error we want to ignore the error message roduced by the
+      # script above, as it is iterating over each attribute, which does not
+      # produce a nice error message.  The following code is a fallback
+      # solution which is cause a nicer error message in the next
+      # evaluation.
+      echo "\"let option = nixos.options${option:+.$option}; config = nixos.config${option:+.$option}; in\""
+  fi
+}
+
+header="$header
+$(eval echo $(generateAccessors))
+"
+
+evalAttr(){
+  local prefix="$1"
+  local strict="$2"
+  local suffix="$3"
+
+  # If strict is set, then set it to "true".
+  test -n "$strict" && strict=true
+
+  evalNix ${strict:+--strict} <<EOF
+$header
+
+let
+  value = $prefix${suffix:+.$suffix};
+  strict = ${strict:-false};
+  cleanOutput = x: with nixpkgs.lib;
+    if isDerivation x then x.outPath
+    else if isFunction x then "<CODE>"
+    else if strict then
+      if isAttrs x then mapAttrs (n: cleanOutput) x
+      else if isList x then map cleanOutput x
+      else x
+    else x;
+in
+  cleanOutput value
+EOF
+}
+
+evalOpt(){
+  evalAttr "option" "" "$@"
+}
+
+evalCfg(){
+  local strict="$1"
+  evalAttr "config" "$strict"
+}
+
+findSources(){
+  local suffix=$1
+  evalNix --strict <<EOF
+$header
+
+option.$suffix
+EOF
+}
+
+# Given a result from nix-instantiate, recover the list of attributes it
+# contains.
+attrNames() {
+  local attributeset=$1
+  # sed is used to replace un-printable subset by 0s, and to remove most of
+  # the inner-attribute set, which reduce the likelyhood to encounter badly
+  # pre-processed input.
+  echo "builtins.attrNames $attributeset" | \
+    sed 's,<[A-Z]*>,0,g; :inner; s/{[^\{\}]*};/0;/g; t inner;' | \
+    evalNix --strict
+}
+
+# map a simple list which contains strings or paths.
+nixMap() {
+  local fun="$1"
+  local list="$2"
+  local elem
+  for elem in $list; do
+    test $elem = '[' -o $elem = ']' && continue;
+    $fun $elem
+  done
+}
+
+# This duplicates the work made below, but it is useful for processing
+# the output of nixos-option with other tools such as nixos-gui.
+if $xml; then
+  evalNix --xml --no-location <<EOF
+$header
+
+let
+  sources = builtins.map (f: f.source);
+  opt = option;
+  cfg = config;
+in
+
+with nixpkgs.lib;
+
+let
+  optStrict = v:
+    let
+      traverse = x :
+        if isAttrs x then
+          if x ? outPath then true
+          else all id (mapAttrsFlatten (n: traverseNoAttrs) x)
+        else traverseNoAttrs x;
+      traverseNoAttrs = x:
+        # do not continue in attribute sets
+        if isAttrs x then true
+        else if isList x then all id (map traverse x)
+        else true;
+    in assert traverse v; v;
+in
+
+if isOption opt then
+  optStrict ({}
+  // optionalAttrs (opt ? default) { inherit (opt) default; }
+  // optionalAttrs (opt ? example) { inherit (opt) example; }
+  // optionalAttrs (opt ? description) { inherit (opt) description; }
+  // optionalAttrs (opt ? type) { typename = opt.type.description; }
+  // optionalAttrs (opt ? options) { inherit (opt) options; }
+  // {
+    # to disambiguate the xml output.
+    _isOption = true;
+    declarations = sources opt.declarations;
+    definitions = sources opt.definitions;
+    value = cfg;
+  })
+else
+  opt
+EOF
+  exit $?
+fi
+
+if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then
+  echo "Value:"
+  evalCfg 1
+
+  echo
+
+  echo "Default:"
+  if default=$(evalOpt "default" - 2> /dev/null); then
+    echo "$default"
+  else
+    echo "<None>"
+  fi
+  echo
+  if example=$(evalOpt "example" - 2> /dev/null); then
+    echo "Example:"
+    echo "$example"
+    echo
+  fi
+  echo "Description:"
+  echo
+  echo $(evalOpt "description")
+
+  echo $desc;
+
+  printPath () { echo "  $1"; }
+
+  echo "Declared by:"
+  nixMap printPath "$(findSources "declarations")"
+  echo
+  echo "Defined by:"
+  nixMap printPath "$(findSources "files")"
+  echo
+
+else
+  # echo 1>&2 "Warning: This value is not an option."
+
+  result=$(evalCfg "")
+  if names=$(attrNames "$result" 2> /dev/null); then
+    echo 1>&2 "This attribute set contains:"
+    escapeQuotes () { eval echo "$1"; }
+    nixMap escapeQuotes "$names"
+  else
+    echo 1>&2 "An error occurred while looking for attribute names."
+    echo $result
+  fi
+fi
+
+exit $exit_code
diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh
new file mode 100644
index 000000000000..2af73519bc52
--- /dev/null
+++ b/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -0,0 +1,387 @@
+#! @shell@
+
+if [ -x "@shell@" ]; then export SHELL="@shell@"; fi;
+
+set -e
+
+showSyntax() {
+    exec man nixos-rebuild
+    exit 1
+}
+
+
+# Parse the command line.
+origArgs=("$@")
+extraBuildFlags=()
+action=
+buildNix=1
+fast=
+rollback=
+upgrade=
+repair=
+profile=/nix/var/nix/profiles/system
+buildHost=
+targetHost=
+
+while [ "$#" -gt 0 ]; do
+    i="$1"; shift 1
+    case "$i" in
+      --help)
+        showSyntax
+        ;;
+      switch|boot|test|build|dry-build|dry-run|dry-activate|build-vm|build-vm-with-bootloader)
+        if [ "$i" = dry-run ]; then i=dry-build; fi
+        action="$i"
+        ;;
+      --install-grub)
+        echo "$0: --install-grub deprecated, use --install-bootloader instead" >&2
+        export NIXOS_INSTALL_BOOTLOADER=1
+        ;;
+      --install-bootloader)
+        export NIXOS_INSTALL_BOOTLOADER=1
+        ;;
+      --no-build-nix)
+        buildNix=
+        ;;
+      --rollback)
+        rollback=1
+        ;;
+      --upgrade)
+        upgrade=1
+        ;;
+      --repair)
+        repair=1
+        extraBuildFlags+=("$i")
+        ;;
+      --max-jobs|-j|--cores|-I)
+        j="$1"; shift 1
+        extraBuildFlags+=("$i" "$j")
+        ;;
+      --show-trace|--no-build-hook|--keep-failed|-K|--keep-going|-k|--verbose|-v|-vv|-vvv|-vvvv|-vvvvv|--fallback|--repair|--no-build-output|-Q|-j*)
+        extraBuildFlags+=("$i")
+        ;;
+      --option)
+        j="$1"; shift 1
+        k="$1"; shift 1
+        extraBuildFlags+=("$i" "$j" "$k")
+        ;;
+      --fast)
+        buildNix=
+        fast=1
+        extraBuildFlags+=(--show-trace)
+        ;;
+      --profile-name|-p)
+        if [ -z "$1" ]; then
+            echo "$0: ‘--profile-name’ requires an argument"
+            exit 1
+        fi
+        if [ "$1" != system ]; then
+            profile="/nix/var/nix/profiles/system-profiles/$1"
+            mkdir -p -m 0755 "$(dirname "$profile")"
+        fi
+        shift 1
+        ;;
+      --build-host|h)
+        buildHost="$1"
+        shift 1
+        ;;
+      --target-host|t)
+        targetHost="$1"
+        shift 1
+        ;;
+      *)
+        echo "$0: unknown option \`$i'"
+        exit 1
+        ;;
+    esac
+done
+
+
+if [ -z "$buildHost" -a -n "$targetHost" ]; then
+    buildHost="$targetHost"
+fi
+if [ "$targetHost" = localhost ]; then
+    targetHost=
+fi
+if [ "$buildHost" = localhost ]; then
+    buildHost=
+fi
+
+buildHostCmd() {
+    if [ -z "$buildHost" ]; then
+        "$@"
+    elif [ -n "$remoteNix" ]; then
+        ssh $SSHOPTS "$buildHost" PATH="$remoteNix:$PATH" "$@"
+    else
+        ssh $SSHOPTS "$buildHost" "$@"
+    fi
+}
+
+targetHostCmd() {
+    if [ -z "$targetHost" ]; then
+        "$@"
+    else
+        ssh $SSHOPTS "$targetHost" "$@"
+    fi
+}
+
+copyToTarget() {
+    if ! [ "$targetHost" = "$buildHost" ]; then
+        if [ -z "$targetHost" ]; then
+            NIX_SSHOPTS=$SSHOPTS nix-copy-closure --from "$buildHost" "$1"
+        elif [ -z "$buildHost" ]; then
+            NIX_SSHOPTS=$SSHOPTS nix-copy-closure --to "$targetHost" "$1"
+        else
+            buildHostCmd nix-copy-closure --to "$targetHost" "$1"
+        fi
+    fi
+}
+
+nixBuild() {
+    if [ -z "$buildHost" ]; then
+        nix-build "$@"
+    else
+        local instArgs=()
+        local buildArgs=()
+
+        while [ "$#" -gt 0 ]; do
+            local i="$1"; shift 1
+            case "$i" in
+              -o)
+                local out="$1"; shift 1
+                buildArgs+=("--add-root" "$out" "--indirect")
+                ;;
+              -A)
+                local j="$1"; shift 1
+                instArgs+=("$i" "$j")
+                ;;
+              -I) # We don't want this in buildArgs
+                shift 1
+                ;;
+              --no-out-link) # We don't want this in buildArgs
+                ;;
+              "<"*) # nix paths
+                instArgs+=("$i")
+                ;;
+              *)
+                buildArgs+=("$i")
+                ;;
+            esac
+        done
+
+        local drv="$(nix-instantiate "${instArgs[@]}" "${extraBuildFlags[@]}")"
+        if [ -a "$drv" ]; then
+            NIX_SSHOPTS=$SSHOPTS nix-copy-closure --to "$buildHost" "$drv"
+            buildHostCmd nix-store -r "$drv" "${buildArgs[@]}"
+        else
+            echo "nix-instantiate failed"
+            exit 1
+        fi
+  fi
+}
+
+
+if [ -z "$action" ]; then showSyntax; fi
+
+# Only run shell scripts from the Nixpkgs tree if the action is
+# "switch", "boot", or "test". With other actions (such as "build"),
+# the user may reasonably expect that no code from the Nixpkgs tree is
+# executed, so it's safe to run nixos-rebuild against a potentially
+# untrusted tree.
+canRun=
+if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then
+    canRun=1
+fi
+
+
+# If ‘--upgrade’ is given, run ‘nix-channel --update nixos’.
+if [ -n "$upgrade" -a -z "$_NIXOS_REBUILD_REEXEC" ]; then
+    nix-channel --update nixos
+
+    # If there are other channels that contain a file called
+    # ".update-on-nixos-rebuild", update them as well.
+    for channelpath in /nix/var/nix/profiles/per-user/root/channels/*; do
+        if [ -e "$channelpath/.update-on-nixos-rebuild" ]; then
+            nix-channel --update "$(basename "$channelpath")"
+        fi
+    done
+fi
+
+# Make sure that we use the Nix package we depend on, not something
+# else from the PATH for nix-{env,instantiate,build}.  This is
+# important, because NixOS defaults the architecture of the rebuilt
+# system to the architecture of the nix-* binaries used.  So if on an
+# amd64 system the user has an i686 Nix package in her PATH, then we
+# would silently downgrade the whole system to be i686 NixOS on the
+# next reboot.
+if [ -z "$_NIXOS_REBUILD_REEXEC" ]; then
+    export PATH=@nix@/bin:$PATH
+fi
+
+# Re-execute nixos-rebuild from the Nixpkgs tree.
+if [ -z "$_NIXOS_REBUILD_REEXEC" -a -n "$canRun" -a -z "$fast" ]; then
+    if p=$(nix-build --no-out-link --expr 'with import <nixpkgs/nixos> {}; config.system.build.nixos-rebuild' "${extraBuildFlags[@]}"); then
+        export _NIXOS_REBUILD_REEXEC=1
+        exec $p/bin/nixos-rebuild "${origArgs[@]}"
+        exit 1
+    fi
+fi
+
+
+tmpDir=$(mktemp -t -d nixos-rebuild.XXXXXX)
+SSHOPTS="$NIX_SSHOPTS -o ControlMaster=auto -o ControlPath=$tmpDir/ssh-%n -o ControlPersist=60"
+
+cleanup() {
+    for ctrl in "$tmpDir"/ssh-*; do
+        ssh -o ControlPath="$ctrl" -O exit dummyhost 2>/dev/null || true
+    done
+    rm -rf "$tmpDir"
+}
+trap cleanup EXIT
+
+
+
+# If the Nix daemon is running, then use it.  This allows us to use
+# the latest Nix from Nixpkgs (below) for expression evaluation, while
+# still using the old Nix (via the daemon) for actual store access.
+# This matters if the new Nix in Nixpkgs has a schema change.  It
+# would upgrade the schema, which should only happen once we actually
+# switch to the new configuration.
+# If --repair is given, don't try to use the Nix daemon, because the
+# flag can only be used directly.
+if [ -z "$repair" ] && systemctl show nix-daemon.socket nix-daemon.service | grep -q ActiveState=active; then
+    export NIX_REMOTE=${NIX_REMOTE-daemon}
+fi
+
+
+# First build Nix, since NixOS may require a newer version than the
+# current one.
+if [ -n "$rollback" -o "$action" = dry-build ]; then
+    buildNix=
+fi
+
+prebuiltNix() {
+    machine="$1"
+    if [ "$machine" = x86_64 ]; then
+        echo @nix_x86_64_linux@
+    elif [[ "$machine" =~ i.86 ]]; then
+        echo @nix_i686_linux@
+    else
+        echo "$0: unsupported platform"
+        exit 1
+    fi
+}
+
+remotePATH=
+
+if [ -n "$buildNix" ]; then
+    echo "building Nix..." >&2
+    nixDrv=
+    if ! nixDrv="$(nix-instantiate '<nixpkgs/nixos>' --add-root $tmpDir/nix.drv --indirect -A config.nix.package.out "${extraBuildFlags[@]}")"; then
+        if ! nixDrv="$(nix-instantiate '<nixpkgs>' --add-root $tmpDir/nix.drv --indirect -A nix "${extraBuildFlags[@]}")"; then
+            nixStorePath="$(prebuiltNix "$(uname -m)")"
+            if ! nix-store -r $nixStorePath --add-root $tmpDir/nix --indirect \
+                --option extra-binary-caches https://cache.nixos.org/; then
+                echo "warning: don't know how to get latest Nix" >&2
+            fi
+            # Older version of nix-store -r don't support --add-root.
+            [ -e $tmpDir/nix ] || ln -sf $nixStorePath $tmpDir/nix
+            if [ -n "$buildHost" ]; then
+                remoteNixStorePath="$(prebuiltNix "$(buildHostCmd uname -m)")"
+                remoteNix="$remoteNixStorePath/bin"
+                if ! buildHostCmd nix-store -r $remoteNixStorePath \
+                  --option extra-binary-caches https://cache.nixos.org/ >/dev/null; then
+                    remoteNix=
+                    echo "warning: don't know how to get latest Nix" >&2
+                fi
+            fi
+        fi
+    fi
+    if [ -a "$nixDrv" ]; then
+        nix-store -r "$nixDrv"'!'"out" --add-root $tmpDir/nix --indirect >/dev/null
+        if [ -n "$buildHost" ]; then
+            nix-copy-closure --to "$buildHost" "$nixDrv"
+            # The nix build produces multiple outputs, we add them all to the remote path
+            for p in $(buildHostCmd nix-store -r "$(readlink "$nixDrv")" "${buildArgs[@]}"); do
+                remoteNix="$remoteNix${remoteNix:+:}$p/bin"
+            done
+        fi
+    fi
+    PATH="$tmpDir/nix/bin:$PATH"
+fi
+
+
+# Update the version suffix if we're building from Git (so that
+# nixos-version shows something useful).
+if [ -n "$canRun" ]; then
+    if nixpkgs=$(nix-instantiate --find-file nixpkgs "${extraBuildFlags[@]}"); then
+        suffix=$($SHELL $nixpkgs/nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}" || true)
+        if [ -n "$suffix" ]; then
+            echo -n "$suffix" > "$nixpkgs/.version-suffix" || true
+        fi
+    fi
+fi
+
+
+if [ "$action" = dry-build ]; then
+    extraBuildFlags+=(--dry-run)
+fi
+
+
+# Either upgrade the configuration in the system profile (for "switch"
+# or "boot"), or just build it and create a symlink "result" in the
+# current directory (for "build" and "test").
+if [ -z "$rollback" ]; then
+    echo "building the system configuration..." >&2
+    if [ "$action" = switch -o "$action" = boot ]; then
+        pathToConfig="$(nixBuild '<nixpkgs/nixos>' --no-out-link -A system "${extraBuildFlags[@]}")"
+        copyToTarget "$pathToConfig"
+        targetHostCmd nix-env -p "$profile" --set "$pathToConfig"
+    elif [ "$action" = test -o "$action" = build -o "$action" = dry-build -o "$action" = dry-activate ]; then
+        pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A system -k "${extraBuildFlags[@]}")"
+    elif [ "$action" = build-vm ]; then
+        pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A vm -k "${extraBuildFlags[@]}")"
+    elif [ "$action" = build-vm-with-bootloader ]; then
+        pathToConfig="$(nixBuild '<nixpkgs/nixos>' -A vmWithBootLoader -k "${extraBuildFlags[@]}")"
+    else
+        showSyntax
+    fi
+    # Copy build to target host if we haven't already done it
+    if ! [ "$action" = switch -o "$action" = boot ]; then
+        copyToTarget "$pathToConfig"
+    fi
+else # [ -n "$rollback" ]
+    if [ "$action" = switch -o "$action" = boot ]; then
+        targetHostCmd nix-env --rollback -p "$profile"
+        pathToConfig="$profile"
+    elif [ "$action" = test -o "$action" = build ]; then
+        systemNumber=$(
+            targetHostCmd nix-env -p "$profile" --list-generations |
+            sed -n '/current/ {g; p;}; s/ *\([0-9]*\).*/\1/; h'
+        )
+        pathToConfig="$profile"-${systemNumber}-link
+        if [ -z "$targetHost" ]; then
+            ln -sT "$pathToConfig" ./result
+        fi
+    else
+        showSyntax
+    fi
+fi
+
+
+# If we're not just building, then make the new configuration the boot
+# default and/or activate it now.
+if [ "$action" = switch -o "$action" = boot -o "$action" = test -o "$action" = dry-activate ]; then
+    if ! targetHostCmd $pathToConfig/bin/switch-to-configuration "$action"; then
+        echo "warning: error(s) occurred while switching to the new configuration" >&2
+        exit 1
+    fi
+fi
+
+
+if [ "$action" = build-vm ]; then
+    cat >&2 <<EOF
+
+Done.  The virtual machine can be started by running $(echo $pathToConfig/bin/run-*-vm)
+EOF
+fi
diff --git a/nixos/modules/installer/tools/nixos-version.sh b/nixos/modules/installer/tools/nixos-version.sh
new file mode 100644
index 000000000000..190c49a33ec6
--- /dev/null
+++ b/nixos/modules/installer/tools/nixos-version.sh
@@ -0,0 +1,14 @@
+#! @shell@
+
+case "$1" in
+  -h|--help)
+    exec man nixos-version
+    exit 1
+    ;;
+  --hash|--revision)
+    echo "@revision@"
+    ;;
+  *)
+    echo "@version@ (@codeName@)"
+    ;;
+esac
diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix
index 6d9ebf750825..af0a3a2fcc88 100644
--- a/nixos/modules/installer/tools/tools.nix
+++ b/nixos/modules/installer/tools/tools.nix
@@ -6,35 +6,77 @@
 with lib;
 
 let
-  nixos-build-vms = pkgs.nixos-build-vms;
-  nixos-enter = pkgs.nixos-enter;
-  nixos-generate-config = pkgs.nixos-generate-config.override { inherit (config.system.nixos) release; };
-  nixos-install = pkgs.nixos-install.override { nix = config.nix.package; };
-  nixos-option = pkgs.nixos-option;
-  nixos-rebuild = pkgs.nixos-rebuild.override { nix = config.nix.package; };
-  nixos-version = pkgs.nixos-version.override { inherit (config.system.nixos) version codeName revision; };
+  makeProg = args: pkgs.substituteAll (args // {
+    dir = "bin";
+    isExecutable = true;
+  });
+
+  nixos-build-vms = makeProg {
+    name = "nixos-build-vms";
+    src = ./nixos-build-vms/nixos-build-vms.sh;
+  };
+
+  nixos-install = makeProg {
+    name = "nixos-install";
+    src = ./nixos-install.sh;
+    nix = config.nix.package.out;
+    path = makeBinPath [ nixos-enter ];
+  };
+
+  nixos-rebuild =
+    let fallback = import ./nix-fallback-paths.nix; in
+    makeProg {
+      name = "nixos-rebuild";
+      src = ./nixos-rebuild.sh;
+      nix = config.nix.package.out;
+      nix_x86_64_linux = fallback.x86_64-linux;
+      nix_i686_linux = fallback.i686-linux;
+    };
+
+  nixos-generate-config = makeProg {
+    name = "nixos-generate-config";
+    src = ./nixos-generate-config.pl;
+    path = [ pkgs.btrfs-progs ];
+    perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
+    inherit (config.system.nixos) release;
+  };
+
+  nixos-option = makeProg {
+    name = "nixos-option";
+    src = ./nixos-option.sh;
+  };
+
+  nixos-version = makeProg {
+    name = "nixos-version";
+    src = ./nixos-version.sh;
+    inherit (config.system.nixos) version codeName revision;
+  };
+
+  nixos-enter = makeProg {
+    name = "nixos-enter";
+    src = ./nixos-enter.sh;
+  };
+
 in
 
 {
+
   config = {
-    environment.systemPackages = [
-      nixos-build-vms
-      nixos-enter
-      nixos-generate-config
-      nixos-install
-      nixos-option
-      nixos-rebuild
-      nixos-version
-    ];
 
-    system.build = {
-      inherit
-        nixos-enter
-        nixos-generate-config
+    environment.systemPackages =
+      [ nixos-build-vms
         nixos-install
-        nixos-option
         nixos-rebuild
-        ;
+        nixos-generate-config
+        nixos-option
+        nixos-version
+        nixos-enter
+      ];
+
+    system.build = {
+      inherit nixos-install nixos-generate-config nixos-option nixos-rebuild nixos-enter;
     };
+
   };
+
 }