at master 22 kB view raw
1#! @perl@ 2 3use strict; 4use Cwd 'abs_path'; 5use File::Spec; 6use File::Path; 7use File::Basename; 8use File::Slurp; 9use File::stat; 10use Config::IniFiles; 11 12umask(0022); 13 14sub uniq { 15 my %seen; 16 my @res = (); 17 foreach my $s (@_) { 18 if (!defined $seen{$s}) { 19 $seen{$s} = 1; 20 push @res, $s; 21 } 22 } 23 return @res; 24} 25 26sub runCommand { 27 my ($cmd) = @_; 28 open FILE, "$cmd 2>&1 |" or die "Failed to execute: $cmd\n"; 29 my @ret = <FILE>; 30 close FILE; 31 return ($?, @ret); 32} 33 34# Process the command line. 35my $outDir = "/etc/nixos"; 36my $rootDir = ""; # = / 37my $force = 0; 38my $noFilesystems = 0; 39my $flake = 0; 40my $showHardwareConfig = 0; 41my $kernel = "lts"; 42 43if (-e "/etc/nixos-generate-config.conf") { 44 my $cfg = new Config::IniFiles -file => "/etc/nixos-generate-config.conf"; 45 $outDir = $cfg->val("Defaults", "Directory") // $outDir; 46 if (defined $cfg->val("Defaults", "RootDirectory")) { 47 $rootDir = $cfg->val("Defaults", "RootDirectory"); 48 $rootDir =~ s/\/*$//; # remove trailing slashes 49 $rootDir = File::Spec->rel2abs($rootDir); # resolve absolute path 50 } 51 $kernel = $cfg->val("Defaults", "Kernel") // $kernel; 52 $flake = $cfg->val("Defaults", "Flake") // $flake; 53} 54 55for (my $n = 0; $n < scalar @ARGV; $n++) { 56 my $arg = $ARGV[$n]; 57 if ($arg eq "--help") { 58 exec "man nixos-generate-config" or die; 59 } 60 elsif ($arg eq "--dir") { 61 $n++; 62 $outDir = $ARGV[$n]; 63 die "$0: ‘--dir’ requires an argument\n" unless defined $outDir; 64 } 65 elsif ($arg eq "--root") { 66 $n++; 67 $rootDir = $ARGV[$n]; 68 die "$0: ‘--root’ requires an argument\n" unless defined $rootDir; 69 die "$0: no need to specify `/` with `--root`, it is the default\n" if $rootDir eq "/"; 70 $rootDir =~ s/\/*$//; # remove trailing slashes 71 $rootDir = File::Spec->rel2abs($rootDir); # resolve absolute path 72 } 73 elsif ($arg eq "--force") { 74 $force = 1; 75 } 76 elsif ($arg eq "--no-filesystems") { 77 $noFilesystems = 1; 78 } 79 elsif ($arg eq "--show-hardware-config") { 80 $showHardwareConfig = 1; 81 } 82 elsif ($arg eq "--flake") { 83 $flake = 1; 84 } 85 elsif ($arg eq "--kernel") { 86 $n++; 87 $kernel = $ARGV[$n]; 88 die "$0: ‘--kernel’ requires an argument\n" unless defined $kernel; 89 } 90 else { 91 die "$0: unrecognized argument ‘$arg’\n"; 92 } 93} 94 95die "$0: invalid kernel: '$kernel'" unless $kernel eq "lts" || $kernel eq "latest"; 96 97my @attrs = (); 98my @kernelModules = (); 99my @initrdKernelModules = (); 100my @initrdAvailableKernelModules = (); 101my @modulePackages = (); 102my @imports; 103 104 105sub debug { 106 return unless defined $ENV{"DEBUG"}; 107 print STDERR @_; 108} 109 110 111# nixpkgs.system 112push @attrs, "nixpkgs.hostPlatform = lib.mkDefault \"@hostPlatformSystem@\";"; 113 114 115my $cpuinfo = read_file "/proc/cpuinfo"; 116 117 118sub hasCPUFeature { 119 my $feature = shift; 120 return $cpuinfo =~ /^flags\s*:.* $feature( |$)/m; 121} 122 123 124sub cpuManufacturer { 125 my $id = shift; 126 return $cpuinfo =~ /^vendor_id\s*:.* $id$/m; 127} 128 129# Virtualization support? 130push @kernelModules, "kvm-intel" if hasCPUFeature "vmx"; 131push @kernelModules, "kvm-amd" if hasCPUFeature "svm"; 132 133 134# Look at the PCI devices and add necessary modules. Note that most 135# modules are auto-detected so we don't need to list them here. 136# However, some are needed in the initrd to boot the system. 137 138my $videoDriver; 139 140sub pciCheck { 141 my $path = shift; 142 my $vendor = read_file "$path/vendor"; chomp $vendor; 143 my $device = read_file "$path/device"; chomp $device; 144 my $class = read_file "$path/class"; chomp $class; 145 146 my $module; 147 if (-e "$path/driver/module") { 148 $module = basename `readlink -f $path/driver/module`; 149 chomp $module; 150 } 151 152 debug "$path: $vendor $device $class"; 153 debug " $module" if defined $module; 154 debug "\n"; 155 156 if (defined $module) { 157 # See the bottom of https://pciids.sourceforge.net/pci.ids for 158 # device classes. 159 if (# Mass-storage controller. Definitely important. 160 $class =~ /^0x01/ || 161 162 # Firewire controller. A disk might be attached. 163 $class =~ /^0x0c00/ || 164 165 # USB controller. Needed if we want to use the 166 # keyboard when things go wrong in the initrd. 167 $class =~ /^0x0c03/ 168 ) 169 { 170 push @initrdAvailableKernelModules, $module; 171 } 172 } 173 174 # broadcom FullMac driver 175 # list taken from 176 # https://wireless.wiki.kernel.org/en/users/Drivers/brcm80211#brcmfmac 177 if ($vendor eq "0x14e4" && 178 ($device eq "0x43a3" || $device eq "0x43df" || $device eq "0x43ec" || 179 $device eq "0x43d3" || $device eq "0x43d9" || $device eq "0x43e9" || 180 $device eq "0x43ba" || $device eq "0x43bb" || $device eq "0x43bc" || 181 $device eq "0xaa52" || $device eq "0x43ca" || $device eq "0x43cb" || 182 $device eq "0x43cc" || $device eq "0x43c3" || $device eq "0x43c4" || 183 $device eq "0x43c5" 184 ) ) 185 { 186 # we need e.g. brcmfmac43602-pcie.bin 187 push @imports, "(modulesPath + \"/hardware/network/broadcom-43xx.nix\")"; 188 } 189 190 # In case this is a virtio scsi device, we need to explicitly make this available. 191 if ($vendor eq "0x1af4" && ($device eq "0x1004" || $device eq "0x1048") ) { 192 push @initrdAvailableKernelModules, "virtio_scsi"; 193 } 194 195 # Can't rely on $module here, since the module may not be loaded 196 # due to missing firmware. Ideally we would check modules.pcimap 197 # here. 198 push @attrs, "networking.enableIntel2200BGFirmware = true;" if 199 $vendor eq "0x8086" && 200 ($device eq "0x1043" || $device eq "0x104f" || $device eq "0x4220" || 201 $device eq "0x4221" || $device eq "0x4223" || $device eq "0x4224"); 202 203 push @attrs, "networking.enableIntel3945ABGFirmware = true;" if 204 $vendor eq "0x8086" && 205 ($device eq "0x4229" || $device eq "0x4230" || 206 $device eq "0x4222" || $device eq "0x4227"); 207 208 # Assume that all NVIDIA cards are supported by the NVIDIA driver. 209 # There may be exceptions (e.g. old cards). 210 # FIXME: do we want to enable an unfree driver here? 211 #$videoDriver = "nvidia" if $vendor eq "0x10de" && $class =~ /^0x03/; 212} 213 214foreach my $path (glob "/sys/bus/pci/devices/*") { 215 pciCheck $path; 216} 217 218# Idem for USB devices. 219 220sub usbCheck { 221 my $path = shift; 222 my $class = read_file "$path/bInterfaceClass"; chomp $class; 223 my $subclass = read_file "$path/bInterfaceSubClass"; chomp $subclass; 224 my $protocol = read_file "$path/bInterfaceProtocol"; chomp $protocol; 225 226 my $module; 227 if (-e "$path/driver/module") { 228 $module = basename `readlink -f $path/driver/module`; 229 chomp $module; 230 } 231 232 debug "$path: $class $subclass $protocol"; 233 debug " $module" if defined $module; 234 debug "\n"; 235 236 if (defined $module) { 237 if (# Mass-storage controller. Definitely important. 238 $class eq "08" || 239 240 # Keyboard. Needed if we want to use the 241 # keyboard when things go wrong in the initrd. 242 ($class eq "03" && $protocol eq "01") 243 ) 244 { 245 push @initrdAvailableKernelModules, $module; 246 } 247 } 248} 249 250foreach my $path (glob "/sys/bus/usb/devices/*") { 251 if (-e "$path/bInterfaceClass") { 252 usbCheck $path; 253 } 254} 255 256 257# Add the modules for all block and MMC devices. 258foreach my $path (glob "/sys/class/{block,mmc_host}/*") { 259 my $module; 260 if (-e "$path/device/driver/module") { 261 $module = basename `readlink -f $path/device/driver/module`; 262 chomp $module; 263 push @initrdAvailableKernelModules, $module; 264 } 265} 266 267# Add bcache module, if needed. 268my @bcacheDevices = glob("/dev/bcache*"); 269@bcacheDevices = grep(!m#dev/bcachefs.*#, @bcacheDevices); 270if (scalar @bcacheDevices > 0) { 271 push @initrdAvailableKernelModules, "bcache"; 272} 273 274# Prevent unbootable systems if LVM snapshots are present at boot time. 275if (`lsblk -o TYPE` =~ "lvm") { 276 push @initrdKernelModules, "dm-snapshot"; 277} 278 279my $virt = `@detectvirt@`; 280chomp $virt; 281 282 283# Check if we're a VirtualBox guest. If so, enable the guest 284# additions. 285if ($virt eq "oracle") { 286 push @attrs, "virtualisation.virtualbox.guest.enable = true;" 287} 288 289# Check if we're a Parallels guest. If so, enable the guest additions. 290# It is blocked by https://github.com/systemd/systemd/pull/23859 291if ($virt eq "parallels") { 292 push @attrs, "hardware.parallels.enable = true;"; 293 push @attrs, "nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ \"prl-tools\" ];"; 294} 295 296# Likewise for QEMU. 297if ($virt eq "qemu" || $virt eq "kvm" || $virt eq "bochs") { 298 push @imports, "(modulesPath + \"/profiles/qemu-guest.nix\")"; 299} 300 301# Also for Hyper-V. 302if ($virt eq "microsoft") { 303 push @attrs, "virtualisation.hypervGuest.enable = true;" 304} 305 306 307# Pull in NixOS configuration for containers. 308if ($virt eq "systemd-nspawn") { 309 push @attrs, "boot.isContainer = true;"; 310} 311 312 313# Check if we're on bare metal, not in a VM/container. 314if ($virt eq "none") { 315 # Provide firmware for devices that are not detected by this script. 316 push @imports, "(modulesPath + \"/installer/scan/not-detected.nix\")"; 317 318 # Update the microcode. 319 push @attrs, "hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;" if cpuManufacturer "AuthenticAMD"; 320 push @attrs, "hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;" if cpuManufacturer "GenuineIntel"; 321} 322 323# For a device name like /dev/sda1, find a more stable path like 324# /dev/disk/by-uuid/X or /dev/disk/by-label/Y. 325sub findStableDevPath { 326 my ($dev) = @_; 327 return $dev if substr($dev, 0, 1) ne "/"; 328 return $dev unless -e $dev; 329 330 my $st = stat($dev) or return $dev; 331 332 foreach my $dev2 ( 333 glob("/dev/stratis/*/*"), 334 glob("/dev/mapper/*"), 335 glob("/dev/disk/by-uuid/*"), 336 glob("/dev/disk/by-label/*"), 337 ) { 338 my $st2 = stat($dev2) or next; 339 return $dev2 if $st->rdev == $st2->rdev; 340 } 341 342 return $dev; 343} 344 345push @attrs, "services.xserver.videoDrivers = [ \"$videoDriver\" ];" if $videoDriver; 346 347# Generate the swapDevices option from the currently activated swap 348# devices. 349my @swaps = read_file("/proc/swaps", err_mode => 'carp'); 350my @swapDevices; 351if (@swaps) { 352 shift @swaps; 353 foreach my $swap (@swaps) { 354 my @fields = split ' ', $swap; 355 my $swapFilename = $fields[0]; 356 my $swapType = $fields[1]; 357 next unless -e $swapFilename; 358 my $dev = findStableDevPath $swapFilename; 359 if ($swapType =~ "partition") { 360 # zram devices are more likely created by configuration.nix, so 361 # ignore them here 362 next if ($swapFilename =~ /^\/dev\/zram/); 363 push @swapDevices, "{ device = \"$dev\"; }"; 364 } elsif ($swapType =~ "file") { 365 # swap *files* are more likely specified in configuration.nix, so 366 # ignore them here. 367 } else { 368 die "Unsupported swap type: $swapType\n"; 369 } 370 } 371} 372 373 374# Generate the fileSystems option from the currently mounted 375# filesystems. 376sub in { 377 my ($d1, $d2) = @_; 378 return $d1 eq $d2 || substr($d1, 0, length($d2) + 1) eq "$d2/"; 379} 380 381my $fileSystems; 382my %fsByDev; 383my $useSwraid = 0; 384foreach my $fs (read_file("/proc/self/mountinfo")) { 385 chomp $fs; 386 my @fields = split / /, $fs; 387 my $mountPoint = $fields[4]; 388 $mountPoint =~ s/\\040/ /g; # account for mount points with spaces in the name (\040 is the escape character) 389 $mountPoint =~ s/\\011/\t/g; # account for mount points with tabs in the name (\011 is the escape character) 390 next unless -d $mountPoint; 391 my @mountOptions = split /,/, $fields[5]; 392 393 next if !in($mountPoint, $rootDir); 394 $mountPoint = substr($mountPoint, length($rootDir)); # strip the root directory (e.g. /mnt) 395 $mountPoint = "/" if $mountPoint eq ""; 396 397 # Skip special filesystems. 398 next if in($mountPoint, "/proc") || in($mountPoint, "/dev") || in($mountPoint, "/sys") || in($mountPoint, "/run") || $mountPoint eq "/var/lib/nfs/rpc_pipefs"; 399 400 # Skip the optional fields. 401 my $n = 6; $n++ while $fields[$n] ne "-"; $n++; 402 my $fsType = $fields[$n]; 403 my $device = $fields[$n + 1]; 404 my @superOptions = split /,/, $fields[$n + 2]; 405 $device =~ s/\\040/ /g; # account for devices with spaces in the name (\040 is the escape character) 406 $device =~ s/\\011/\t/g; # account for mount points with tabs in the name (\011 is the escape character) 407 408 # Skip the read-only bind-mount on /nix/store. 409 next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions) && (grep { $_ eq "ro" } @mountOptions); 410 411 # Maybe this is a bind-mount of a filesystem we saw earlier? 412 if (defined $fsByDev{$fields[2]}) { 413 # Make sure this isn't a btrfs subvolume. 414 my $msg = `@btrfs@ subvol show $rootDir$mountPoint`; 415 if ($? != 0 || $msg =~ /ERROR:/s) { 416 my $path = $fields[3]; $path = "" if $path eq "/"; 417 my $base = $fsByDev{$fields[2]}; 418 $base = "" if $base eq "/"; 419 $fileSystems .= <<EOF; 420 fileSystems.\"$mountPoint\" = 421 { device = \"$base$path\"; 422 fsType = \"none\"; 423 options = \[ \"bind\" \]; 424 }; 425 426EOF 427 next; 428 } 429 } 430 $fsByDev{$fields[2]} = $mountPoint; 431 432 # We don't know how to handle FUSE filesystems. 433 if ($fsType eq "fuseblk" || $fsType eq "fuse") { 434 print STDERR "warning: don't know how to emit ‘fileSystem’ option for FUSE filesystem ‘$mountPoint’\n"; 435 next; 436 } 437 438 # Is this a mount of a loopback device? 439 my @extraOptions; 440 if ($device =~ /\/dev\/loop(\d+)/) { 441 my $loopnr = $1; 442 my $backer = read_file "/sys/block/loop$loopnr/loop/backing_file"; 443 if (defined $backer) { 444 chomp $backer; 445 $device = $backer; 446 push @extraOptions, "loop"; 447 } 448 } 449 450 # Is this a btrfs filesystem? 451 if ($fsType eq "btrfs") { 452 my ($status, @info) = runCommand("@btrfs@ subvol show $rootDir$mountPoint"); 453 if ($status != 0 || join("", @info) =~ /ERROR:/) { 454 die "Failed to retrieve subvolume info for $mountPoint\n"; 455 } 456 my @ids = join("\n", @info) =~ m/^(?!\/\n).*Subvolume ID:[ \t\n]*([0-9]+)/s; 457 if ($#ids > 0) { 458 die "Btrfs subvol name for $mountPoint listed multiple times in mount\n" 459 } elsif ($#ids == 0) { 460 my @paths = join("", @info) =~ m/^([^\n]*)/; 461 if ($#paths > 0) { 462 die "Btrfs returned multiple paths for a single subvolume id, mountpoint $mountPoint\n"; 463 } elsif ($#paths != 0) { 464 die "Btrfs did not return a path for the subvolume at $mountPoint\n"; 465 } 466 push @extraOptions, "subvol=$paths[0]"; 467 } 468 } 469 470 # Preserve umask (fmask, dmask) settings for vfat filesystems. 471 # (The default is to mount these world-readable, but that's a security risk 472 # for the EFI System Partition.) 473 if ($fsType eq "vfat") { 474 for (@superOptions) { 475 if ($_ =~ /fmask|dmask/) { 476 push @extraOptions, $_; 477 } 478 } 479 } 480 481 # is this a stratis fs? 482 my $stableDevPath = findStableDevPath $device; 483 my $stratisPool; 484 if ($stableDevPath =~ qr#/dev/stratis/(.*)/.*#) { 485 my $poolName = $1; 486 my ($header, @lines) = split "\n", qx/stratis pool list/; 487 my $uuidIndex = index $header, 'UUID'; 488 my ($line) = grep /^$poolName /, @lines; 489 $stratisPool = substr $line, $uuidIndex - 32, 36; 490 } 491 492 # Don't emit tmpfs entry for /tmp, because it most likely comes from the 493 # boot.tmp.useTmpfs option in configuration.nix (managed declaratively). 494 next if ($mountPoint eq "/tmp" && $fsType eq "tmpfs"); 495 496 # This should work for single and multi-device systems. 497 # still needs subvolume support 498 if ($fsType eq "bcachefs") { 499 my ($status, @info) = runCommand("bcachefs fs usage $rootDir$mountPoint"); 500 my $UUID = $info[0]; 501 502 if ($status == 0 && $UUID =~ /^Filesystem:[ \t\n]*([0-9a-z-]+)/) { 503 $stableDevPath = "UUID=$1"; 504 } else { 505 print STDERR "warning: can't find bcachefs mount UUID falling back to device-path"; 506 } 507 } 508 509 # Emit the filesystem. 510 $fileSystems .= <<EOF; 511 fileSystems.\"$mountPoint\" = 512 { device = \"$stableDevPath\"; 513 fsType = \"$fsType\"; 514EOF 515 516 if (scalar @extraOptions > 0) { 517 $fileSystems .= <<EOF; 518 options = \[ ${\join " ", map { "\"" . $_ . "\"" } uniq(@extraOptions)} \]; 519EOF 520 } 521 522 if ($stratisPool) { 523 $fileSystems .= <<EOF; 524 stratis.poolUuid = "$stratisPool"; 525EOF 526 } 527 528 $fileSystems .= <<EOF; 529 }; 530 531EOF 532 533 # If this filesystem is on a LUKS device, then add a 534 # boot.initrd.luks.devices entry. 535 if (-e $device) { 536 my $deviceName = basename(abs_path($device)); 537 my $dmUuid = read_file("/sys/class/block/$deviceName/dm/uuid", err_mode => 'quiet'); 538 if ($dmUuid =~ /^CRYPT-LUKS/) 539 { 540 my @slaves = glob("/sys/class/block/$deviceName/slaves/*"); 541 if (scalar @slaves == 1) { 542 my $slave = "/dev/" . basename($slaves[0]); 543 if (-e $slave) { 544 my $dmName = read_file("/sys/class/block/$deviceName/dm/name"); 545 chomp $dmName; 546 # Ensure to add an entry only once 547 my $luksDevice = " boot.initrd.luks.devices.\"$dmName\".device"; 548 if ($fileSystems !~ /^\Q$luksDevice\E/m) { 549 $fileSystems .= "$luksDevice = \"${\(findStableDevPath $slave)}\";\n\n"; 550 } 551 } 552 } 553 } 554 if (-e "/sys/class/block/$deviceName/md/uuid") { 555 $useSwraid = 1; 556 } 557 } 558} 559if ($useSwraid) { 560 push @attrs, "boot.swraid.enable = true;\n\n"; 561} 562 563 564# Generate the hardware configuration file. 565 566sub toNixStringList { 567 my $res = ""; 568 foreach my $s (@_) { 569 $res .= " \"$s\""; 570 } 571 return $res; 572} 573sub toNixList { 574 my $res = ""; 575 foreach my $s (@_) { 576 $res .= " $s"; 577 } 578 return $res; 579} 580 581sub multiLineList { 582 my $indent = shift; 583 return " [ ]" if !@_; 584 my $res = "\n${indent}[ "; 585 my $first = 1; 586 foreach my $s (@_) { 587 $res .= "$indent " if !$first; 588 $first = 0; 589 $res .= "$s\n"; 590 } 591 $res .= "$indent]"; 592 return $res; 593} 594 595my $initrdAvailableKernelModules = toNixStringList(uniq @initrdAvailableKernelModules); 596my $initrdKernelModules = toNixStringList(uniq @initrdKernelModules); 597my $kernelModules = toNixStringList(uniq @kernelModules); 598my $modulePackages = toNixList(uniq @modulePackages); 599 600my $fsAndSwap = ""; 601if (!$noFilesystems) { 602 $fsAndSwap = "\n$fileSystems "; 603 $fsAndSwap .= "swapDevices =" . multiLineList(" ", @swapDevices) . ";\n"; 604} 605 606my $hwConfig = <<EOF; 607# Do not modify this file! It was generated by ‘nixos-generate-config’ 608# and may be overwritten by future invocations. Please make changes 609# to /etc/nixos/configuration.nix instead. 610{ config, lib, pkgs, modulesPath, ... }: 611 612{ 613 imports =${\multiLineList(" ", @imports)}; 614 615 boot.initrd.availableKernelModules = [$initrdAvailableKernelModules ]; 616 boot.initrd.kernelModules = [$initrdKernelModules ]; 617 boot.kernelModules = [$kernelModules ]; 618 boot.extraModulePackages = [$modulePackages ]; 619$fsAndSwap 620${\join "", (map { " $_\n" } (uniq @attrs))}} 621EOF 622 623sub generateXserverConfig { 624 my $xserverEnabled = "@xserverEnabled@"; 625 626 my $config = ""; 627 if ($xserverEnabled eq "1") { 628 $config = <<EOF; 629 # Enable the X11 windowing system. 630 services.xserver.enable = true; 631EOF 632 } else { 633 $config = <<EOF; 634 # Enable the X11 windowing system. 635 # services.xserver.enable = true; 636EOF 637 } 638} 639 640if ($showHardwareConfig) { 641 print STDOUT $hwConfig; 642} else { 643 if ($outDir eq "/etc/nixos") { 644 $outDir = "$rootDir$outDir"; 645 } else { 646 $outDir = File::Spec->rel2abs($outDir); 647 $outDir =~ s/\/*$//; # remove trailing slashes 648 } 649 650 my $fn = "$outDir/hardware-configuration.nix"; 651 print STDERR "writing $fn...\n"; 652 mkpath($outDir, 0, 0755); 653 write_file($fn, $hwConfig); 654 655 $fn = "$outDir/flake.nix"; 656 if ($flake) { 657 if ($force || ! -e $fn) { 658 print STDERR "writing $fn...\n"; 659 mkpath($outDir, 0, 0755); 660 write_file($fn, <<EOF); 661@flake@ 662EOF 663 } else { 664 print STDERR "warning: not overwriting existing $fn\n"; 665 } 666 } 667 668 # Generate a basic configuration.nix, unless one already exists. 669 $fn = "$outDir/configuration.nix"; 670 if ($force || ! -e $fn) { 671 print STDERR "writing $fn...\n"; 672 673 my $bootLoaderConfig = ""; 674 if (-e "/sys/firmware/efi/efivars") { 675 $bootLoaderConfig = <<EOF; 676 # Use the systemd-boot EFI boot loader. 677 boot.loader.systemd-boot.enable = true; 678 boot.loader.efi.canTouchEfiVariables = true; 679EOF 680 } elsif (-e "/boot/extlinux") { 681 $bootLoaderConfig = <<EOF; 682 # Use the extlinux boot loader. (NixOS wants to enable GRUB by default) 683 boot.loader.grub.enable = false; 684 # Enables the generation of /boot/extlinux/extlinux.conf 685 boot.loader.generic-extlinux-compatible.enable = true; 686EOF 687 } elsif ($virt ne "systemd-nspawn") { 688 $bootLoaderConfig = <<EOF; 689 # Use the GRUB 2 boot loader. 690 boot.loader.grub.enable = true; 691 # boot.loader.grub.efiSupport = true; 692 # boot.loader.grub.efiInstallAsRemovable = true; 693 # boot.loader.efi.efiSysMountPoint = "/boot/efi"; 694 # Define on which hard drive you want to install Grub. 695 # boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only 696EOF 697 } 698 699 if ($kernel eq "latest") { 700 $bootLoaderConfig .= <<EOF; 701 702 # Use latest kernel. 703 boot.kernelPackages = pkgs.linuxPackages_latest; 704EOF 705 } 706 707 my $xserverConfig = generateXserverConfig(); 708 709 (my $desktopConfiguration = <<EOF)=~s/^/ /gm; 710@desktopConfiguration@ 711EOF 712 713 write_file($fn, <<EOF); 714@configuration@ 715EOF 716 print STDERR "For more hardware-specific settings, see https://github.com/NixOS/nixos-hardware.\n" 717 } else { 718 print STDERR "warning: not overwriting existing $fn\n"; 719 } 720} 721 722# workaround for a bug in substituteAll