You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

nixos-generate-config.pl 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. #! @perl@
  2. use strict;
  3. use Cwd 'abs_path';
  4. use File::Spec;
  5. use File::Path;
  6. use File::Basename;
  7. use File::Slurp;
  8. use File::stat;
  9. umask(0022);
  10. sub uniq {
  11. my %seen;
  12. my @res = ();
  13. foreach my $s (@_) {
  14. if (!defined $seen{$s}) {
  15. $seen{$s} = 1;
  16. push @res, $s;
  17. }
  18. }
  19. return @res;
  20. }
  21. sub runCommand {
  22. my ($cmd) = @_;
  23. open FILE, "$cmd 2>&1 |" or die "Failed to execute: $cmd\n";
  24. my @ret = <FILE>;
  25. close FILE;
  26. return ($?, @ret);
  27. }
  28. # Process the command line.
  29. my $outDir = "/etc/nixos";
  30. my $rootDir = ""; # = /
  31. my $force = 0;
  32. my $noFilesystems = 0;
  33. my $showHardwareConfig = 0;
  34. for (my $n = 0; $n < scalar @ARGV; $n++) {
  35. my $arg = $ARGV[$n];
  36. if ($arg eq "--help") {
  37. exec "man nixos-generate-config" or die;
  38. }
  39. elsif ($arg eq "--dir") {
  40. $n++;
  41. $outDir = $ARGV[$n];
  42. die "$0: ‘--dir’ requires an argument\n" unless defined $outDir;
  43. }
  44. elsif ($arg eq "--root") {
  45. $n++;
  46. $rootDir = $ARGV[$n];
  47. die "$0: ‘--root’ requires an argument\n" unless defined $rootDir;
  48. $rootDir =~ s/\/*$//; # remove trailing slashes
  49. }
  50. elsif ($arg eq "--force") {
  51. $force = 1;
  52. }
  53. elsif ($arg eq "--no-filesystems") {
  54. $noFilesystems = 1;
  55. }
  56. elsif ($arg eq "--show-hardware-config") {
  57. $showHardwareConfig = 1;
  58. }
  59. else {
  60. die "$0: unrecognized argument ‘$arg’\n";
  61. }
  62. }
  63. my @attrs = ();
  64. my @kernelModules = ();
  65. my @initrdKernelModules = ();
  66. my @initrdAvailableKernelModules = ();
  67. my @modulePackages = ();
  68. my @imports;
  69. sub debug {
  70. return unless defined $ENV{"DEBUG"};
  71. print STDERR @_;
  72. }
  73. my $cpuinfo = read_file "/proc/cpuinfo";
  74. sub hasCPUFeature {
  75. my $feature = shift;
  76. return $cpuinfo =~ /^flags\s*:.* $feature( |$)/m;
  77. }
  78. # Detect the number of CPU cores.
  79. my $cpus = scalar (grep {/^processor\s*:/} (split '\n', $cpuinfo));
  80. # Determine CPU governor to use
  81. if (-e "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") {
  82. my $governors = read_file("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors");
  83. # ondemand governor is not available on sandy bridge or later Intel CPUs
  84. my @desired_governors = ("ondemand", "powersave");
  85. my $e;
  86. foreach $e (@desired_governors) {
  87. if (index($governors, $e) != -1) {
  88. last if (push @attrs, "powerManagement.cpuFreqGovernor = lib.mkDefault \"$e\";");
  89. }
  90. }
  91. }
  92. # Virtualization support?
  93. push @kernelModules, "kvm-intel" if hasCPUFeature "vmx";
  94. push @kernelModules, "kvm-amd" if hasCPUFeature "svm";
  95. # Look at the PCI devices and add necessary modules. Note that most
  96. # modules are auto-detected so we don't need to list them here.
  97. # However, some are needed in the initrd to boot the system.
  98. my $videoDriver;
  99. sub pciCheck {
  100. my $path = shift;
  101. my $vendor = read_file "$path/vendor"; chomp $vendor;
  102. my $device = read_file "$path/device"; chomp $device;
  103. my $class = read_file "$path/class"; chomp $class;
  104. my $module;
  105. if (-e "$path/driver/module") {
  106. $module = basename `readlink -f $path/driver/module`;
  107. chomp $module;
  108. }
  109. debug "$path: $vendor $device $class";
  110. debug " $module" if defined $module;
  111. debug "\n";
  112. if (defined $module) {
  113. # See the bottom of http://pciids.sourceforge.net/pci.ids for
  114. # device classes.
  115. if (# Mass-storage controller. Definitely important.
  116. $class =~ /^0x01/ ||
  117. # Firewire controller. A disk might be attached.
  118. $class =~ /^0x0c00/ ||
  119. # USB controller. Needed if we want to use the
  120. # keyboard when things go wrong in the initrd.
  121. $class =~ /^0x0c03/
  122. )
  123. {
  124. push @initrdAvailableKernelModules, $module;
  125. }
  126. }
  127. # broadcom STA driver (wl.ko)
  128. # list taken from http://www.broadcom.com/docs/linux_sta/README.txt
  129. if ($vendor eq "0x14e4" &&
  130. ($device eq "0x4311" || $device eq "0x4312" || $device eq "0x4313" ||
  131. $device eq "0x4315" || $device eq "0x4327" || $device eq "0x4328" ||
  132. $device eq "0x4329" || $device eq "0x432a" || $device eq "0x432b" ||
  133. $device eq "0x432c" || $device eq "0x432d" || $device eq "0x4353" ||
  134. $device eq "0x4357" || $device eq "0x4358" || $device eq "0x4359" ||
  135. $device eq "0x4331" || $device eq "0x43a0" || $device eq "0x43b1"
  136. ) )
  137. {
  138. push @modulePackages, "config.boot.kernelPackages.broadcom_sta";
  139. push @kernelModules, "wl";
  140. }
  141. # broadcom FullMac driver
  142. # list taken from
  143. # https://wireless.wiki.kernel.org/en/users/Drivers/brcm80211#brcmfmac
  144. if ($vendor eq "0x14e4" &&
  145. ($device eq "0x43a3" || $device eq "0x43df" || $device eq "0x43ec" ||
  146. $device eq "0x43d3" || $device eq "0x43d9" || $device eq "0x43e9" ||
  147. $device eq "0x43ba" || $device eq "0x43bb" || $device eq "0x43bc" ||
  148. $device eq "0xaa52" || $device eq "0x43ca" || $device eq "0x43cb" ||
  149. $device eq "0x43cc" || $device eq "0x43c3" || $device eq "0x43c4" ||
  150. $device eq "0x43c5"
  151. ) )
  152. {
  153. # we need e.g. brcmfmac43602-pcie.bin
  154. push @imports, "<nixpkgs/nixos/modules/hardware/network/broadcom-43xx.nix>";
  155. }
  156. # Can't rely on $module here, since the module may not be loaded
  157. # due to missing firmware. Ideally we would check modules.pcimap
  158. # here.
  159. push @attrs, "networking.enableIntel2200BGFirmware = true;" if
  160. $vendor eq "0x8086" &&
  161. ($device eq "0x1043" || $device eq "0x104f" || $device eq "0x4220" ||
  162. $device eq "0x4221" || $device eq "0x4223" || $device eq "0x4224");
  163. push @attrs, "networking.enableIntel3945ABGFirmware = true;" if
  164. $vendor eq "0x8086" &&
  165. ($device eq "0x4229" || $device eq "0x4230" ||
  166. $device eq "0x4222" || $device eq "0x4227");
  167. # Assume that all NVIDIA cards are supported by the NVIDIA driver.
  168. # There may be exceptions (e.g. old cards).
  169. # FIXME: do we want to enable an unfree driver here?
  170. #$videoDriver = "nvidia" if $vendor eq "0x10de" && $class =~ /^0x03/;
  171. }
  172. foreach my $path (glob "/sys/bus/pci/devices/*") {
  173. pciCheck $path;
  174. }
  175. # Idem for USB devices.
  176. sub usbCheck {
  177. my $path = shift;
  178. my $class = read_file "$path/bInterfaceClass"; chomp $class;
  179. my $subclass = read_file "$path/bInterfaceSubClass"; chomp $subclass;
  180. my $protocol = read_file "$path/bInterfaceProtocol"; chomp $protocol;
  181. my $module;
  182. if (-e "$path/driver/module") {
  183. $module = basename `readlink -f $path/driver/module`;
  184. chomp $module;
  185. }
  186. debug "$path: $class $subclass $protocol";
  187. debug " $module" if defined $module;
  188. debug "\n";
  189. if (defined $module) {
  190. if (# Mass-storage controller. Definitely important.
  191. $class eq "08" ||
  192. # Keyboard. Needed if we want to use the
  193. # keyboard when things go wrong in the initrd.
  194. ($class eq "03" && $protocol eq "01")
  195. )
  196. {
  197. push @initrdAvailableKernelModules, $module;
  198. }
  199. }
  200. }
  201. foreach my $path (glob "/sys/bus/usb/devices/*") {
  202. if (-e "$path/bInterfaceClass") {
  203. usbCheck $path;
  204. }
  205. }
  206. # Add the modules for all block and MMC devices.
  207. foreach my $path (glob "/sys/class/{block,mmc_host}/*") {
  208. my $module;
  209. if (-e "$path/device/driver/module") {
  210. $module = basename `readlink -f $path/device/driver/module`;
  211. chomp $module;
  212. push @initrdAvailableKernelModules, $module;
  213. }
  214. }
  215. # Add bcache module, if needed.
  216. my @bcacheDevices = glob("/dev/bcache*");
  217. if (scalar @bcacheDevices > 0) {
  218. push @initrdAvailableKernelModules, "bcache";
  219. }
  220. # Prevent unbootable systems if LVM snapshots are present at boot time.
  221. if (`lsblk -o TYPE` =~ "lvm") {
  222. push @initrdKernelModules, "dm-snapshot";
  223. }
  224. my $virt = `systemd-detect-virt`;
  225. chomp $virt;
  226. # Check if we're a VirtualBox guest. If so, enable the guest
  227. # additions.
  228. if ($virt eq "oracle") {
  229. push @attrs, "virtualisation.virtualbox.guest.enable = true;"
  230. }
  231. # Likewise for QEMU.
  232. if ($virt eq "qemu" || $virt eq "kvm" || $virt eq "bochs") {
  233. push @imports, "<nixpkgs/nixos/modules/profiles/qemu-guest.nix>";
  234. }
  235. # Also for Hyper-V.
  236. if ($virt eq "microsoft") {
  237. push @attrs, "virtualisation.hypervGuest.enable = true;"
  238. }
  239. # Pull in NixOS configuration for containers.
  240. if ($virt eq "systemd-nspawn") {
  241. push @attrs, "boot.isContainer = true;";
  242. }
  243. # Provide firmware for devices that are not detected by this script,
  244. # unless we're in a VM/container.
  245. push @imports, "<nixpkgs/nixos/modules/installer/scan/not-detected.nix>"
  246. if $virt eq "none";
  247. # For a device name like /dev/sda1, find a more stable path like
  248. # /dev/disk/by-uuid/X or /dev/disk/by-label/Y.
  249. sub findStableDevPath {
  250. my ($dev) = @_;
  251. return $dev if substr($dev, 0, 1) ne "/";
  252. return $dev unless -e $dev;
  253. my $st = stat($dev) or return $dev;
  254. foreach my $dev2 (glob("/dev/disk/by-uuid/*"), glob("/dev/mapper/*"), glob("/dev/disk/by-label/*")) {
  255. my $st2 = stat($dev2) or next;
  256. return $dev2 if $st->rdev == $st2->rdev;
  257. }
  258. return $dev;
  259. }
  260. push @attrs, "services.xserver.videoDrivers = [ \"$videoDriver\" ];" if $videoDriver;
  261. # Generate the swapDevices option from the currently activated swap
  262. # devices.
  263. my @swaps = read_file("/proc/swaps", err_mode => 'carp');
  264. my @swapDevices;
  265. if (@swaps) {
  266. shift @swaps;
  267. foreach my $swap (@swaps) {
  268. my @fields = split ' ', $swap;
  269. my $swapFilename = $fields[0];
  270. my $swapType = $fields[1];
  271. next unless -e $swapFilename;
  272. my $dev = findStableDevPath $swapFilename;
  273. if ($swapType =~ "partition") {
  274. push @swapDevices, "{ device = \"$dev\"; }";
  275. } elsif ($swapType =~ "file") {
  276. # swap *files* are more likely specified in configuration.nix, so
  277. # ignore them here.
  278. } else {
  279. die "Unsupported swap type: $swapType\n";
  280. }
  281. }
  282. }
  283. # Generate the fileSystems option from the currently mounted
  284. # filesystems.
  285. sub in {
  286. my ($d1, $d2) = @_;
  287. return $d1 eq $d2 || substr($d1, 0, length($d2) + 1) eq "$d2/";
  288. }
  289. my $fileSystems;
  290. my %fsByDev;
  291. foreach my $fs (read_file("/proc/self/mountinfo")) {
  292. chomp $fs;
  293. my @fields = split / /, $fs;
  294. my $mountPoint = $fields[4];
  295. $mountPoint =~ s/\\040/ /g; # account for mount points with spaces in the name (\040 is the escape character)
  296. $mountPoint =~ s/\\011/\t/g; # account for mount points with tabs in the name (\011 is the escape character)
  297. next unless -d $mountPoint;
  298. my @mountOptions = split /,/, $fields[5];
  299. next if !in($mountPoint, $rootDir);
  300. $mountPoint = substr($mountPoint, length($rootDir)); # strip the root directory (e.g. /mnt)
  301. $mountPoint = "/" if $mountPoint eq "";
  302. # Skip special filesystems.
  303. next if in($mountPoint, "/proc") || in($mountPoint, "/dev") || in($mountPoint, "/sys") || in($mountPoint, "/run") || $mountPoint eq "/var/lib/nfs/rpc_pipefs";
  304. # Skip the optional fields.
  305. my $n = 6; $n++ while $fields[$n] ne "-"; $n++;
  306. my $fsType = $fields[$n];
  307. my $device = $fields[$n + 1];
  308. my @superOptions = split /,/, $fields[$n + 2];
  309. $device =~ s/\\040/ /g; # account for devices with spaces in the name (\040 is the escape character)
  310. $device =~ s/\\011/\t/g; # account for mount points with tabs in the name (\011 is the escape character)
  311. # Skip the read-only bind-mount on /nix/store.
  312. next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions) && (grep { $_ eq "ro" } @mountOptions);
  313. # Maybe this is a bind-mount of a filesystem we saw earlier?
  314. if (defined $fsByDev{$fields[2]}) {
  315. # Make sure this isn't a btrfs subvolume.
  316. my $msg = `btrfs subvol show $rootDir$mountPoint`;
  317. if ($? != 0 || $msg =~ /ERROR:/s) {
  318. my $path = $fields[3]; $path = "" if $path eq "/";
  319. my $base = $fsByDev{$fields[2]};
  320. $base = "" if $base eq "/";
  321. $fileSystems .= <<EOF;
  322. fileSystems.\"$mountPoint\" =
  323. { device = \"$base$path\";
  324. fsType = \"none\";
  325. options = \[ \"bind\" \];
  326. };
  327. EOF
  328. next;
  329. }
  330. }
  331. $fsByDev{$fields[2]} = $mountPoint;
  332. # We don't know how to handle FUSE filesystems.
  333. if ($fsType eq "fuseblk" || $fsType eq "fuse") {
  334. print STDERR "warning: don't know how to emit ‘fileSystem’ option for FUSE filesystem ‘$mountPoint’\n";
  335. next;
  336. }
  337. # Is this a mount of a loopback device?
  338. my @extraOptions;
  339. if ($device =~ /\/dev\/loop(\d+)/) {
  340. my $loopnr = $1;
  341. my $backer = read_file "/sys/block/loop$loopnr/loop/backing_file";
  342. if (defined $backer) {
  343. chomp $backer;
  344. $device = $backer;
  345. push @extraOptions, "loop";
  346. }
  347. }
  348. # Is this a btrfs filesystem?
  349. if ($fsType eq "btrfs") {
  350. my ($status, @info) = runCommand("btrfs subvol show $rootDir$mountPoint");
  351. if ($status != 0 || join("", @info) =~ /ERROR:/) {
  352. die "Failed to retrieve subvolume info for $mountPoint\n";
  353. }
  354. my @ids = join("\n", @info) =~ m/^(?!\/\n).*Subvolume ID:[ \t\n]*([0-9]+)/s;
  355. if ($#ids > 0) {
  356. die "Btrfs subvol name for $mountPoint listed multiple times in mount\n"
  357. } elsif ($#ids == 0) {
  358. my @paths = join("", @info) =~ m/^([^\n]*)/;
  359. if ($#paths > 0) {
  360. die "Btrfs returned multiple paths for a single subvolume id, mountpoint $mountPoint\n";
  361. } elsif ($#paths != 0) {
  362. die "Btrfs did not return a path for the subvolume at $mountPoint\n";
  363. }
  364. push @extraOptions, "subvol=$paths[0]";
  365. }
  366. }
  367. # Don't emit tmpfs entry for /tmp, because it most likely comes from the
  368. # boot.tmpOnTmpfs option in configuration.nix (managed declaratively).
  369. next if ($mountPoint eq "/tmp" && $fsType eq "tmpfs");
  370. # Emit the filesystem.
  371. $fileSystems .= <<EOF;
  372. fileSystems.\"$mountPoint\" =
  373. { device = \"${\(findStableDevPath $device)}\";
  374. fsType = \"$fsType\";
  375. EOF
  376. if (scalar @extraOptions > 0) {
  377. $fileSystems .= <<EOF;
  378. options = \[ ${\join " ", map { "\"" . $_ . "\"" } uniq(@extraOptions)} \];
  379. EOF
  380. }
  381. $fileSystems .= <<EOF;
  382. };
  383. EOF
  384. # If this filesystem is on a LUKS device, then add a
  385. # boot.initrd.luks.devices entry.
  386. if (-e $device) {
  387. my $deviceName = basename(abs_path($device));
  388. if (-e "/sys/class/block/$deviceName"
  389. && read_file("/sys/class/block/$deviceName/dm/uuid", err_mode => 'quiet') =~ /^CRYPT-LUKS/)
  390. {
  391. my @slaves = glob("/sys/class/block/$deviceName/slaves/*");
  392. if (scalar @slaves == 1) {
  393. my $slave = "/dev/" . basename($slaves[0]);
  394. if (-e $slave) {
  395. my $dmName = read_file("/sys/class/block/$deviceName/dm/name");
  396. chomp $dmName;
  397. # Ensure to add an entry only once
  398. my $luksDevice = " boot.initrd.luks.devices.\"$dmName\".device";
  399. if ($fileSystems !~ /^\Q$luksDevice\E/m) {
  400. $fileSystems .= "$luksDevice = \"${\(findStableDevPath $slave)}\";\n\n";
  401. }
  402. }
  403. }
  404. }
  405. }
  406. }
  407. # For lack of a better way to determine it, guess whether we should use a
  408. # bigger font for the console from the display mode on the first
  409. # framebuffer. A way based on the physical size/actual DPI reported by
  410. # the monitor would be nice, but I don't know how to do this without X :)
  411. my $fb_modes_file = "/sys/class/graphics/fb0/modes";
  412. if (-f $fb_modes_file && -r $fb_modes_file) {
  413. my $modes = read_file($fb_modes_file);
  414. $modes =~ m/([0-9]+)x([0-9]+)/;
  415. my $console_width = $1, my $console_height = $2;
  416. if ($console_width > 1920) {
  417. push @attrs, "# High-DPI console";
  418. push @attrs, 'i18n.consoleFont = lib.mkDefault "${pkgs.terminus_font}/share/consolefonts/ter-u28n.psf.gz";';
  419. }
  420. }
  421. # Generate the hardware configuration file.
  422. sub toNixStringList {
  423. my $res = "";
  424. foreach my $s (@_) {
  425. $res .= " \"$s\"";
  426. }
  427. return $res;
  428. }
  429. sub toNixList {
  430. my $res = "";
  431. foreach my $s (@_) {
  432. $res .= " $s";
  433. }
  434. return $res;
  435. }
  436. sub multiLineList {
  437. my $indent = shift;
  438. return " [ ]" if !@_;
  439. my $res = "\n${indent}[ ";
  440. my $first = 1;
  441. foreach my $s (@_) {
  442. $res .= "$indent " if !$first;
  443. $first = 0;
  444. $res .= "$s\n";
  445. }
  446. $res .= "$indent]";
  447. return $res;
  448. }
  449. my $initrdAvailableKernelModules = toNixStringList(uniq @initrdAvailableKernelModules);
  450. my $initrdKernelModules = toNixStringList(uniq @initrdKernelModules);
  451. my $kernelModules = toNixStringList(uniq @kernelModules);
  452. my $modulePackages = toNixList(uniq @modulePackages);
  453. my $fsAndSwap = "";
  454. if (!$noFilesystems) {
  455. $fsAndSwap = "\n$fileSystems ";
  456. $fsAndSwap .= "swapDevices =" . multiLineList(" ", @swapDevices) . ";\n";
  457. }
  458. my $hwConfig = <<EOF;
  459. # Do not modify this file! It was generated by ‘nixos-generate-config’
  460. # and may be overwritten by future invocations. Please make changes
  461. # to /etc/nixos/configuration.nix instead.
  462. { config, lib, pkgs, ... }:
  463. {
  464. imports =${\multiLineList(" ", @imports)};
  465. boot.initrd.availableKernelModules = [$initrdAvailableKernelModules ];
  466. boot.initrd.kernelModules = [$initrdKernelModules ];
  467. boot.kernelModules = [$kernelModules ];
  468. boot.extraModulePackages = [$modulePackages ];
  469. $fsAndSwap
  470. nix.maxJobs = lib.mkDefault $cpus;
  471. ${\join "", (map { " $_\n" } (uniq @attrs))}}
  472. EOF
  473. sub generateNetworkingDhcpConfig {
  474. my $config = <<EOF;
  475. # The global useDHCP flag is deprecated, therefore explicitly set to false here.
  476. # Per-interface useDHCP will be mandatory in the future, so this generated config
  477. # replicates the default behaviour.
  478. networking.useDHCP = false;
  479. EOF
  480. foreach my $path (glob "/sys/class/net/*") {
  481. my $dev = basename($path);
  482. if ($dev ne "lo") {
  483. $config .= " networking.interfaces.$dev.useDHCP = true;\n";
  484. }
  485. }
  486. return $config;
  487. }
  488. if ($showHardwareConfig) {
  489. print STDOUT $hwConfig;
  490. } else {
  491. $outDir = "$rootDir$outDir";
  492. my $fn = "$outDir/hardware-configuration.nix";
  493. print STDERR "writing $fn...\n";
  494. mkpath($outDir, 0, 0755);
  495. write_file($fn, $hwConfig);
  496. # Generate a basic configuration.nix, unless one already exists.
  497. $fn = "$outDir/configuration.nix";
  498. if ($force || ! -e $fn) {
  499. print STDERR "writing $fn...\n";
  500. my $bootLoaderConfig = "";
  501. if (-e "/sys/firmware/efi/efivars") {
  502. $bootLoaderConfig = <<EOF;
  503. # Use the systemd-boot EFI boot loader.
  504. boot.loader.systemd-boot.enable = true;
  505. boot.loader.efi.canTouchEfiVariables = true;
  506. EOF
  507. } elsif (-e "/boot/extlinux") {
  508. $bootLoaderConfig = <<EOF;
  509. # Use the extlinux boot loader. (NixOS wants to enable GRUB by default)
  510. boot.loader.grub.enable = false;
  511. # Enables the generation of /boot/extlinux/extlinux.conf
  512. boot.loader.generic-extlinux-compatible.enable = true;
  513. EOF
  514. } elsif ($virt ne "systemd-nspawn") {
  515. $bootLoaderConfig = <<EOF;
  516. # Use the GRUB 2 boot loader.
  517. boot.loader.grub.enable = true;
  518. boot.loader.grub.version = 2;
  519. # boot.loader.grub.efiSupport = true;
  520. # boot.loader.grub.efiInstallAsRemovable = true;
  521. # boot.loader.efi.efiSysMountPoint = "/boot/efi";
  522. # Define on which hard drive you want to install Grub.
  523. # boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only
  524. EOF
  525. }
  526. my $networkingDhcpConfig = generateNetworkingDhcpConfig();
  527. write_file($fn, <<EOF);
  528. @configuration@
  529. EOF
  530. } else {
  531. print STDERR "warning: not overwriting existing $fn\n";
  532. }
  533. }
  534. # workaround for a bug in substituteAll