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