diff options
Diffstat (limited to 'nixpkgs/nixos/modules/installer/tools')
11 files changed, 1869 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/installer/tools/get-version-suffix b/nixpkgs/nixos/modules/installer/tools/get-version-suffix new file mode 100644 index 000000000000..b8972cd57d22 --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/get-version-suffix @@ -0,0 +1,22 @@ +getVersion() { + local dir="$1" + rev= + if [ -e "$dir/.git" ]; then + if [ -z "$(type -P git)" ]; then + echo "warning: Git not found; cannot figure out revision of $dir" >&2 + return + fi + cd "$dir" + rev=$(git rev-parse --short HEAD) + if git describe --always --dirty | grep -q dirty; then + rev+=M + fi + fi +} + +if nixpkgs=$(nix-instantiate --find-file nixpkgs "$@"); then + getVersion $nixpkgs + if [ -n "$rev" ]; then + echo ".git.$rev" + fi +fi diff --git a/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix new file mode 100644 index 000000000000..b9ab2053c41f --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix @@ -0,0 +1,6 @@ +{ + x86_64-linux = "/nix/store/hbhdjn5ik3byg642d1m11k3k3s0kn3py-nix-2.2.2"; + i686-linux = "/nix/store/fz5cikwvj3n0a6zl44h6l2z3cin64mda-nix-2.2.2"; + aarch64-linux = "/nix/store/2gba4cyl4wvxzfbhmli90jy4n5aj0kjj-nix-2.2.2"; + x86_64-darwin = "/nix/store/87i4fp46jfw9yl8c7i9gx75m5yph7irl-nix-2.2.2"; +} diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix b/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix new file mode 100644 index 000000000000..c1028a0ad7e9 --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix @@ -0,0 +1,13 @@ +{ system ? builtins.currentSystem +, config ? {} +, networkExpr +}: + +let nodes = import networkExpr; in + +with import ../../../../lib/testing.nix { + inherit system; + pkgs = import ../../../../.. { inherit system config; }; +}; + +(makeTest { inherit nodes; testScript = ""; }).driver diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh b/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh new file mode 100644 index 000000000000..25106733087e --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh @@ -0,0 +1,52 @@ +#! @shell@ -e + +# Shows the usage of this command to the user + +showUsage() { + exec man nixos-build-vms + exit 1 +} + +# Parse valid argument options + +nixBuildArgs=() +networkExpr= + +while [ $# -gt 0 ]; do + case "$1" in + --no-out-link) + nixBuildArgs+=("--no-out-link") + ;; + --show-trace) + nixBuildArgs+=("--show-trace") + ;; + -h|--help) + showUsage + exit 0 + ;; + --option) + shift + nixBuildArgs+=("--option" "$1" "$2"); shift + ;; + *) + if [ ! -z "$networkExpr" ]; then + echo "Network expression already set!" + showUsage + exit 1 + fi + networkExpr="$(readlink -f $1)" + ;; + esac + + shift +done + +if [ -z "$networkExpr" ] +then + echo "ERROR: A network expression must be specified!" >&2 + exit 1 +fi + +# Build a network of VMs +nix-build '<nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix>' \ + --argstr networkExpr $networkExpr "${nixBuildArgs[@]}" diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-enter.sh b/nixpkgs/nixos/modules/installer/tools/nixos-enter.sh new file mode 100644 index 000000000000..4680cd8ae95a --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/nixos-enter.sh @@ -0,0 +1,74 @@ +#! @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") +silent=0 + +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 + ;; + --silent) + silent=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 -p "$mountPoint/dev" "$mountPoint/sys" +chmod 0755 "$mountPoint/dev" "$mountPoint/sys" +mount --rbind /dev "$mountPoint/dev" +mount --rbind /sys "$mountPoint/sys" + +# If silent, write both stdout and stderr of activation script to /dev/null +# otherwise, write both streams to stderr of this process +if [ "$silent" -eq 0 ]; then + PIPE_TARGET="/dev/stderr" +else + PIPE_TARGET="/dev/null" +fi + +# 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" >>$PIPE_TARGET 2>&1 || true + +exec chroot "$mountPoint" "${command[@]}" diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl new file mode 100644 index 000000000000..cfdbdaabf5c5 --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl @@ -0,0 +1,617 @@ +#! @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; + } +} + +# Add bcache module, if needed. +my @bcacheDevices = glob("/dev/bcache*"); +if (scalar @bcacheDevices > 0) { + push @initrdAvailableKernelModules, "bcache"; +} + +# Prevent unbootable systems if LVM snapshots are present at boot time. +if (`lsblk -o TYPE` =~ "lvm") { + push @initrdKernelModules, "dm-snapshot"; +} + +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", err_mode => 'carp'); +my @swapDevices; +if (@swaps) { + shift @swaps; + foreach my $swap (@swaps) { + my @fields = split ' ', $swap; + my $swapFilename = $fields[0]; + my $swapType = $fields[1]; + next unless -e $swapFilename; + my $dev = findStableDevPath $swapFilename; + if ($swapType =~ "partition") { + push @swapDevices, "{ device = \"$dev\"; }"; + } elsif ($swapType =~ "file") { + # swap *files* are more likely specified in configuration.nix, so + # ignore them here. + } else { + die "Unsupported swap type: $swapType\n"; + } + } +} + + +# 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]; + $mountPoint =~ s/\\040/ /g; # account for mount points with spaces in the name (\040 is the escape character) + $mountPoint =~ s/\\011/\t/g; # account for mount points with tabs in the name (\011 is the escape character) + 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]; + $device =~ s/\\040/ /g; # account for devices with spaces in the name (\040 is the escape character) + $device =~ s/\\011/\t/g; # account for mount points with tabs in the name (\011 is the escape character) + + # 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]"; + } + } + + # Don't emit tmpfs entry for /tmp, because it most likely comes from the + # boot.tmpOnTmpfs option in configuration.nix (managed declaratively). + next if ($mountPoint eq "/tmp" && $fsType eq "tmpfs"); + + # 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; + # Ensure to add an entry only once + my $luksDevice = " boot.initrd.luks.devices.\"$dmName\".device"; + if ($fileSystems !~ /^\Q$luksDevice\E/m) { + $fileSystems .= "$luksDevice = \"${\(findStableDevPath $slave)}\";\n\n"; + } + } + } + } + } +} + +# For lack of a better way to determine it, guess whether we should use a +# bigger font for the console from the display mode on the first +# framebuffer. A way based on the physical size/actual DPI reported by +# the monitor would be nice, but I don't know how to do this without X :) +my $fb_modes_file = "/sys/class/graphics/fb0/modes"; +if (-f $fb_modes_file && -r $fb_modes_file) { + my $modes = read_file($fb_modes_file); + $modes =~ m/([0-9]+)x([0-9]+)/; + my $console_width = $1, my $console_height = $2; + if ($console_width > 1920) { + push @attrs, "# High-DPI console"; + push @attrs, 'i18n.consoleFont = lib.mkDefault "${pkgs.terminus_font}/share/consolefonts/ter-u28n.psf.gz";'; + } +} + + +# 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 $initrdKernelModules = toNixStringList(uniq @initrdKernelModules); +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.initrd.kernelModules = [$initrdKernelModules ]; + 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); +@configuration@ +EOF + } else { + print STDERR "warning: not overwriting existing $fn\n"; + } +} + +# workaround for a bug in substituteAll diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-install.sh b/nixpkgs/nixos/modules/installer/tools/nixos-install.sh new file mode 100644 index 000000000000..8685cb345e1e --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/nixos-install.sh @@ -0,0 +1,155 @@ +#! @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 + if nixos-enter --root "$mountPoint" -c 'test -e /nix/var/nix/profiles/system/sw/bin/passwd'; then + set +e + nixos-enter --root "$mountPoint" -c 'echo "setting root password..." && /nix/var/nix/profiles/system/sw/bin/passwd' + exit_code=$? + set -e + + if [[ $exit_code != 0 ]]; then + echo "Setting a root password failed with the above printed error." + echo "You can set the root password manually by executing \`nixos-enter --root ${mountPoint@Q}\` and then running \`passwd\` in the shell of the new system." + exit $exit_code + fi + fi +fi + +echo "installation finished!" diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-option.sh b/nixpkgs/nixos/modules/installer/tools/nixos-option.sh new file mode 100644 index 000000000000..4560e9c7403a --- /dev/null +++ b/nixpkgs/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 [ ! -z "$result" ]; then + names=$(attrNames "$result" 2> /dev/null) + 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. Are you sure that '$option' exists?" + fi +fi + +exit $exit_code diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-rebuild.sh b/nixpkgs/nixos/modules/installer/tools/nixos-rebuild.sh new file mode 100644 index 000000000000..6a08c9b4c6c6 --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/nixos-rebuild.sh @@ -0,0 +1,404 @@ +#! @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|edit|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|--builders) + j="$1"; shift 1 + extraBuildFlags+=("$i" "$j") + ;; + --show-trace|--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 + +# Find configuration.nix and open editor instead of building. +if [ "$action" = edit ]; then + NIXOS_CONFIG=${NIXOS_CONFIG:-$(nix-instantiate --find-file nixos-config)} + exec "${EDITOR:-nano}" "$NIXOS_CONFIG" + exit 1 +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 + +nixSystem() { + machine="$(uname -m)" + if [[ "$machine" =~ i.86 ]]; then + machine=i686 + fi + echo $machine-linux +} + +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 + if ! nixStorePath="$(nix-instantiate --eval '<nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix>' -A $(nixSystem) | sed -e 's/^"//' -e 's/"$//')"; then + nixStorePath="$(prebuiltNix "$(uname -m)")" + fi + 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/nixpkgs/nixos/modules/installer/tools/nixos-version.sh b/nixpkgs/nixos/modules/installer/tools/nixos-version.sh new file mode 100644 index 000000000000..190c49a33ec6 --- /dev/null +++ b/nixpkgs/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/nixpkgs/nixos/modules/installer/tools/tools.nix b/nixpkgs/nixos/modules/installer/tools/tools.nix new file mode 100644 index 000000000000..05add59117d1 --- /dev/null +++ b/nixpkgs/nixos/modules/installer/tools/tools.nix @@ -0,0 +1,185 @@ +# This module generates nixos-install, nixos-rebuild, +# nixos-generate-config, etc. + +{ config, lib, pkgs, ... }: + +with lib; + +let + 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 = lib.optionals (lib.elem "btrfs" config.boot.supportedFilesystems) [ pkgs.btrfs-progs ]; + perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/${pkgs.perl.libPrefix}"; + inherit (config.system.nixos-generate-config) configuration; + }; + + 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 + +{ + + options.system.nixos-generate-config.configuration = mkOption { + internal = true; + type = types.str; + description = '' + The NixOS module that <literal>nixos-generate-config</literal> + saves to <literal>/etc/nixos/configuration.nix</literal>. + + This is an internal option. No backward compatibility is guaranteed. + Use at your own risk! + + Note that this string gets spliced into a Perl script. The perl + variable <literal>$bootLoaderConfig</literal> can be used to + splice in the boot loader configuration. + ''; + }; + + config = { + + system.nixos-generate-config.configuration = mkDefault '' + # 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.jane = { + # isNormalUser = true; + # extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. + # }; + + # 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 = "${config.system.nixos.release}"; # Did you read the comment? + + } + ''; + + environment.systemPackages = + [ nixos-build-vms + nixos-install + 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; + }; + + }; + +} |