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