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.

iso-image.nix 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. # This module creates a bootable ISO image containing the given NixOS
  2. # configuration. The derivation for the ISO image will be placed in
  3. # config.system.build.isoImage.
  4. { config, lib, pkgs, ... }:
  5. with lib;
  6. let
  7. /**
  8. * Given a list of `options`, concats the result of mapping each options
  9. * to a menuentry for use in grub.
  10. *
  11. * * defaults: {name, image, params, initrd}
  12. * * options: [ option... ]
  13. * * option: {name, params, class}
  14. */
  15. menuBuilderGrub2 =
  16. defaults: options: lib.concatStrings
  17. (
  18. map
  19. (option: ''
  20. menuentry '${defaults.name} ${
  21. # Name appended to menuentry defaults to params if no specific name given.
  22. option.name or (if option ? params then "(${option.params})" else "")
  23. }' ${if option ? class then " --class ${option.class}" else ""} {
  24. linux ${defaults.image} \''${isoboot} ${defaults.params} ${
  25. option.params or ""
  26. }
  27. initrd ${defaults.initrd}
  28. }
  29. '')
  30. options
  31. )
  32. ;
  33. /**
  34. * Given a `config`, builds the default options.
  35. */
  36. buildMenuGrub2 = config:
  37. buildMenuAdditionalParamsGrub2 config ""
  38. ;
  39. /**
  40. * Given a `config` and params to add to `params`, build a set of default options.
  41. * Use this one when creating a variant (e.g. hidpi)
  42. */
  43. buildMenuAdditionalParamsGrub2 = config: additional:
  44. let
  45. finalCfg = {
  46. name = "NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}";
  47. params = "init=${config.system.build.toplevel}/init ${additional} ${toString config.boot.kernelParams}";
  48. image = "/boot/${config.system.boot.loader.kernelFile}";
  49. initrd = "/boot/initrd";
  50. };
  51. in
  52. menuBuilderGrub2
  53. finalCfg
  54. [
  55. { class = "installer"; }
  56. { class = "nomodeset"; params = "nomodeset"; }
  57. { class = "copytoram"; params = "copytoram"; }
  58. { class = "debug"; params = "debug"; }
  59. ]
  60. ;
  61. # Timeout in syslinux is in units of 1/10 of a second.
  62. # 0 is used to disable timeouts.
  63. syslinuxTimeout = if config.boot.loader.timeout == null then
  64. 0
  65. else
  66. max (config.boot.loader.timeout * 10) 1;
  67. max = x: y: if x > y then x else y;
  68. # The configuration file for syslinux.
  69. # Notes on syslinux configuration and UNetbootin compatiblity:
  70. # * Do not use '/syslinux/syslinux.cfg' as the path for this
  71. # configuration. UNetbootin will not parse the file and use it as-is.
  72. # This results in a broken configuration if the partition label does
  73. # not match the specified config.isoImage.volumeID. For this reason
  74. # we're using '/isolinux/isolinux.cfg'.
  75. # * Use APPEND instead of adding command-line arguments directly after
  76. # the LINUX entries.
  77. # * COM32 entries (chainload, reboot, poweroff) are not recognized. They
  78. # result in incorrect boot entries.
  79. baseIsolinuxCfg = ''
  80. SERIAL 0 115200
  81. TIMEOUT ${builtins.toString syslinuxTimeout}
  82. UI vesamenu.c32
  83. MENU TITLE NixOS
  84. MENU BACKGROUND /isolinux/background.png
  85. MENU RESOLUTION 800 600
  86. MENU CLEAR
  87. MENU ROWS 6
  88. MENU CMDLINEROW -4
  89. MENU TIMEOUTROW -3
  90. MENU TABMSGROW -2
  91. MENU HELPMSGROW -1
  92. MENU HELPMSGENDROW -1
  93. MENU MARGIN 0
  94. # FG:AARRGGBB BG:AARRGGBB shadow
  95. MENU COLOR BORDER 30;44 #00000000 #00000000 none
  96. MENU COLOR SCREEN 37;40 #FF000000 #00E2E8FF none
  97. MENU COLOR TABMSG 31;40 #80000000 #00000000 none
  98. MENU COLOR TIMEOUT 1;37;40 #FF000000 #00000000 none
  99. MENU COLOR TIMEOUT_MSG 37;40 #FF000000 #00000000 none
  100. MENU COLOR CMDMARK 1;36;40 #FF000000 #00000000 none
  101. MENU COLOR CMDLINE 37;40 #FF000000 #00000000 none
  102. MENU COLOR TITLE 1;36;44 #00000000 #00000000 none
  103. MENU COLOR UNSEL 37;44 #FF000000 #00000000 none
  104. MENU COLOR SEL 7;37;40 #FFFFFFFF #FF5277C3 std
  105. DEFAULT boot
  106. LABEL boot
  107. MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}
  108. LINUX /boot/${config.system.boot.loader.kernelFile}
  109. APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
  110. INITRD /boot/${config.system.boot.loader.initrdFile}
  111. # A variant to boot with 'nomodeset'
  112. LABEL boot-nomodeset
  113. MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (nomodeset)
  114. LINUX /boot/${config.system.boot.loader.kernelFile}
  115. APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} nomodeset
  116. INITRD /boot/${config.system.boot.loader.initrdFile}
  117. # A variant to boot with 'copytoram'
  118. LABEL boot-copytoram
  119. MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (copytoram)
  120. LINUX /boot/${config.system.boot.loader.kernelFile}
  121. APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} copytoram
  122. INITRD /boot/${config.system.boot.loader.initrdFile}
  123. # A variant to boot with verbose logging to the console
  124. LABEL boot-debug
  125. MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug)
  126. LINUX /boot/${config.system.boot.loader.kernelFile}
  127. APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7
  128. INITRD /boot/${config.system.boot.loader.initrdFile}
  129. '';
  130. isolinuxMemtest86Entry = ''
  131. LABEL memtest
  132. MENU LABEL Memtest86+
  133. LINUX /boot/memtest.bin
  134. APPEND ${toString config.boot.loader.grub.memtest86.params}
  135. '';
  136. isolinuxCfg = concatStringsSep "\n"
  137. ([ baseIsolinuxCfg ] ++ optional config.boot.loader.grub.memtest86.enable isolinuxMemtest86Entry);
  138. # Setup instructions for rEFInd.
  139. refind =
  140. if targetArch == "x64" then
  141. ''
  142. # Adds rEFInd to the ISO.
  143. cp -v ${pkgs.refind}/share/refind/refind_x64.efi $out/EFI/boot/
  144. ''
  145. else
  146. "# No refind for ${targetArch}"
  147. ;
  148. grubPkgs = if config.boot.loader.grub.forcei686 then pkgs.pkgsi686Linux else pkgs;
  149. grubMenuCfg = ''
  150. #
  151. # Menu configuration
  152. #
  153. insmod gfxterm
  154. insmod png
  155. set gfxpayload=keep
  156. # Fonts can be loaded?
  157. # (This font is assumed to always be provided as a fallback by NixOS)
  158. if loadfont (hd0)/EFI/boot/unicode.pf2; then
  159. # Use graphical term, it can be either with background image or a theme.
  160. # input is "console", while output is "gfxterm".
  161. # This enables "serial" input and output only when possible.
  162. # Otherwise the failure mode is to not even enable gfxterm.
  163. if test "\$with_serial" == "yes"; then
  164. terminal_output gfxterm serial
  165. terminal_input console serial
  166. else
  167. terminal_output gfxterm
  168. terminal_input console
  169. fi
  170. else
  171. # Sets colors for the non-graphical term.
  172. set menu_color_normal=cyan/blue
  173. set menu_color_highlight=white/blue
  174. fi
  175. ${ # When there is a theme configured, use it, otherwise use the background image.
  176. if config.isoImage.grubTheme != null then ''
  177. # Sets theme.
  178. set theme=(hd0)/EFI/boot/grub-theme/theme.txt
  179. # Load theme fonts
  180. $(find ${config.isoImage.grubTheme} -iname '*.pf2' -printf "loadfont (hd0)/EFI/boot/grub-theme/%P\n")
  181. '' else ''
  182. if background_image (hd0)/EFI/boot/efi-background.png; then
  183. # Black background means transparent background when there
  184. # is a background image set... This seems undocumented :(
  185. set color_normal=black/black
  186. set color_highlight=white/blue
  187. else
  188. # Falls back again to proper colors.
  189. set menu_color_normal=cyan/blue
  190. set menu_color_highlight=white/blue
  191. fi
  192. ''}
  193. '';
  194. # The EFI boot image.
  195. # Notes about grub:
  196. # * Yes, the grubMenuCfg has to be repeated in all submenus. Otherwise you
  197. # will get white-on-black console-like text on sub-menus. *sigh*
  198. efiDir = pkgs.runCommand "efi-directory" {} ''
  199. mkdir -p $out/EFI/boot/
  200. # ALWAYS required modules.
  201. MODULES="fat iso9660 part_gpt part_msdos \
  202. normal boot linux configfile loopback chain halt \
  203. efifwsetup efi_gop \
  204. ls search search_label search_fs_uuid search_fs_file \
  205. gfxmenu gfxterm gfxterm_background gfxterm_menu test all_video loadenv \
  206. exfat ext2 ntfs btrfs hfsplus udf \
  207. videoinfo png \
  208. echo serial \
  209. "
  210. echo "Building GRUB with modules:"
  211. for mod in $MODULES; do
  212. echo " - $mod"
  213. done
  214. # Modules that may or may not be available per-platform.
  215. echo "Adding additional modules:"
  216. for mod in efi_uga; do
  217. if [ -f ${grubPkgs.grub2_efi}/lib/grub/${grubPkgs.grub2_efi.grubTarget}/$mod.mod ]; then
  218. echo " - $mod"
  219. MODULES+=" $mod"
  220. fi
  221. done
  222. # Make our own efi program, we can't rely on "grub-install" since it seems to
  223. # probe for devices, even with --skip-fs-probe.
  224. ${grubPkgs.grub2_efi}/bin/grub-mkimage -o $out/EFI/boot/boot${targetArch}.efi -p /EFI/boot -O ${grubPkgs.grub2_efi.grubTarget} \
  225. $MODULES
  226. cp ${grubPkgs.grub2_efi}/share/grub/unicode.pf2 $out/EFI/boot/
  227. cat <<EOF > $out/EFI/boot/grub.cfg
  228. # If you want to use serial for "terminal_*" commands, you need to set one up:
  229. # Example manual configuration:
  230. # → serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
  231. # This uses the defaults, and makes the serial terminal available.
  232. set with_serial=no
  233. if serial; then set with_serial=yes ;fi
  234. export with_serial
  235. clear
  236. set timeout=10
  237. ${grubMenuCfg}
  238. # If the parameter iso_path is set, append the findiso parameter to the kernel
  239. # line. We need this to allow the nixos iso to be booted from grub directly.
  240. if [ \''${iso_path} ] ; then
  241. set isoboot="findiso=\''${iso_path}"
  242. fi
  243. #
  244. # Menu entries
  245. #
  246. ${buildMenuGrub2 config}
  247. submenu "HiDPI, Quirks and Accessibility" --class hidpi --class submenu {
  248. ${grubMenuCfg}
  249. submenu "Suggests resolution @720p" --class hidpi-720p {
  250. ${grubMenuCfg}
  251. ${buildMenuAdditionalParamsGrub2 config "video=1280x720@60"}
  252. }
  253. submenu "Suggests resolution @1080p" --class hidpi-1080p {
  254. ${grubMenuCfg}
  255. ${buildMenuAdditionalParamsGrub2 config "video=1920x1080@60"}
  256. }
  257. # If we boot into a graphical environment where X is autoran
  258. # and always crashes, it makes the media unusable. Allow the user
  259. # to disable this.
  260. submenu "Disable display-manager" --class quirk-disable-displaymanager {
  261. ${grubMenuCfg}
  262. ${buildMenuAdditionalParamsGrub2 config "systemd.mask=display-manager.service"}
  263. }
  264. # Some laptop and convertibles have the panel installed in an
  265. # inconvenient way, rotated away from the keyboard.
  266. # Those entries makes it easier to use the installer.
  267. submenu "" {return}
  268. submenu "Rotate framebuffer Clockwise" --class rotate-90cw {
  269. ${grubMenuCfg}
  270. ${buildMenuAdditionalParamsGrub2 config "fbcon=rotate:1"}
  271. }
  272. submenu "Rotate framebuffer Upside-Down" --class rotate-180 {
  273. ${grubMenuCfg}
  274. ${buildMenuAdditionalParamsGrub2 config "fbcon=rotate:2"}
  275. }
  276. submenu "Rotate framebuffer Counter-Clockwise" --class rotate-90ccw {
  277. ${grubMenuCfg}
  278. ${buildMenuAdditionalParamsGrub2 config "fbcon=rotate:3"}
  279. }
  280. # As a proof of concept, mainly. (Not sure it has accessibility merits.)
  281. submenu "" {return}
  282. submenu "Use black on white" --class accessibility-blakconwhite {
  283. ${grubMenuCfg}
  284. ${buildMenuAdditionalParamsGrub2 config "vt.default_red=0xFF,0xBC,0x4F,0xB4,0x56,0xBC,0x4F,0x00,0xA1,0xCF,0x84,0xCA,0x8D,0xB4,0x84,0x68 vt.default_grn=0xFF,0x55,0xBA,0xBA,0x4D,0x4D,0xB3,0x00,0xA0,0x8F,0xB3,0xCA,0x88,0x93,0xA4,0x68 vt.default_blu=0xFF,0x58,0x5F,0x58,0xC5,0xBD,0xC5,0x00,0xA8,0xBB,0xAB,0x97,0xBD,0xC7,0xC5,0x68"}
  285. }
  286. # Serial access is a must!
  287. submenu "" {return}
  288. submenu "Serial console=ttyS0,115200n8" --class serial {
  289. ${grubMenuCfg}
  290. ${buildMenuAdditionalParamsGrub2 config "console=ttyS0,115200n8"}
  291. }
  292. }
  293. menuentry 'rEFInd' --class refind {
  294. # UUID is hard-coded in the derivation.
  295. search --set=root --no-floppy --fs-uuid 1234-5678
  296. chainloader (\$root)/EFI/boot/refind_x64.efi
  297. }
  298. menuentry 'Firmware Setup' --class settings {
  299. fwsetup
  300. clear
  301. echo ""
  302. echo "If you see this message, your EFI system doesn't support this feature."
  303. echo ""
  304. }
  305. menuentry 'Shutdown' --class shutdown {
  306. halt
  307. }
  308. EOF
  309. ${refind}
  310. '';
  311. efiImg = pkgs.runCommand "efi-image_eltorito" { buildInputs = [ pkgs.mtools pkgs.libfaketime ]; }
  312. # Be careful about determinism: du --apparent-size,
  313. # dates (cp -p, touch, mcopy -m, faketime for label), IDs (mkfs.vfat -i)
  314. ''
  315. mkdir ./contents && cd ./contents
  316. cp -rp "${efiDir}"/EFI .
  317. mkdir ./boot
  318. cp -p "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}" \
  319. "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}" ./boot/
  320. touch --date=@0 ./EFI ./boot
  321. usage_size=$(du -sb --apparent-size . | tr -cd '[:digit:]')
  322. # Make the image 110% as big as the files need to make up for FAT overhead
  323. image_size=$(( ($usage_size * 110) / 100 ))
  324. # Make the image fit blocks of 1M
  325. block_size=$((1024*1024))
  326. image_size=$(( ($image_size / $block_size + 1) * $block_size ))
  327. echo "Usage size: $usage_size"
  328. echo "Image size: $image_size"
  329. truncate --size=$image_size "$out"
  330. ${pkgs.libfaketime}/bin/faketime "2000-01-01 00:00:00" ${pkgs.dosfstools}/sbin/mkfs.vfat -i 12345678 -n EFIBOOT "$out"
  331. mcopy -psvm -i "$out" ./EFI ./boot ::
  332. # Verify the FAT partition.
  333. ${pkgs.dosfstools}/sbin/fsck.vfat -vn "$out"
  334. ''; # */
  335. # Name used by UEFI for architectures.
  336. targetArch =
  337. if pkgs.stdenv.isi686 || config.boot.loader.grub.forcei686 then
  338. "ia32"
  339. else if pkgs.stdenv.isx86_64 then
  340. "x64"
  341. else if pkgs.stdenv.isAarch64 then
  342. "aa64"
  343. else
  344. throw "Unsupported architecture";
  345. # Syslinux (and isolinux) only supports x86-based architectures.
  346. canx86BiosBoot = pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64;
  347. in
  348. {
  349. options = {
  350. isoImage.isoName = mkOption {
  351. default = "${config.isoImage.isoBaseName}.iso";
  352. description = ''
  353. Name of the generated ISO image file.
  354. '';
  355. };
  356. isoImage.isoBaseName = mkOption {
  357. default = "nixos";
  358. description = ''
  359. Prefix of the name of the generated ISO image file.
  360. '';
  361. };
  362. isoImage.compressImage = mkOption {
  363. default = false;
  364. description = ''
  365. Whether the ISO image should be compressed using
  366. <command>bzip2</command>.
  367. '';
  368. };
  369. isoImage.volumeID = mkOption {
  370. default = "NIXOS_BOOT_CD";
  371. description = ''
  372. Specifies the label or volume ID of the generated ISO image.
  373. Note that the label is used by stage 1 of the boot process to
  374. mount the CD, so it should be reasonably distinctive.
  375. '';
  376. };
  377. isoImage.contents = mkOption {
  378. example = literalExample ''
  379. [ { source = pkgs.memtest86 + "/memtest.bin";
  380. target = "boot/memtest.bin";
  381. }
  382. ]
  383. '';
  384. description = ''
  385. This option lists files to be copied to fixed locations in the
  386. generated ISO image.
  387. '';
  388. };
  389. isoImage.storeContents = mkOption {
  390. example = literalExample "[ pkgs.stdenv ]";
  391. description = ''
  392. This option lists additional derivations to be included in the
  393. Nix store in the generated ISO image.
  394. '';
  395. };
  396. isoImage.includeSystemBuildDependencies = mkOption {
  397. default = false;
  398. description = ''
  399. Set this option to include all the needed sources etc in the
  400. image. It significantly increases image size. Use that when
  401. you want to be able to keep all the sources needed to build your
  402. system or when you are going to install the system on a computer
  403. with slow or non-existent network connection.
  404. '';
  405. };
  406. isoImage.makeEfiBootable = mkOption {
  407. default = false;
  408. description = ''
  409. Whether the ISO image should be an efi-bootable volume.
  410. '';
  411. };
  412. isoImage.makeUsbBootable = mkOption {
  413. default = false;
  414. description = ''
  415. Whether the ISO image should be bootable from CD as well as USB.
  416. '';
  417. };
  418. isoImage.efiSplashImage = mkOption {
  419. default = pkgs.fetchurl {
  420. url = https://raw.githubusercontent.com/NixOS/nixos-artwork/a9e05d7deb38a8e005a2b52575a3f59a63a4dba0/bootloader/efi-background.png;
  421. sha256 = "18lfwmp8yq923322nlb9gxrh5qikj1wsk6g5qvdh31c4h5b1538x";
  422. };
  423. description = ''
  424. The splash image to use in the EFI bootloader.
  425. '';
  426. };
  427. isoImage.splashImage = mkOption {
  428. default = pkgs.fetchurl {
  429. url = https://raw.githubusercontent.com/NixOS/nixos-artwork/a9e05d7deb38a8e005a2b52575a3f59a63a4dba0/bootloader/isolinux/bios-boot.png;
  430. sha256 = "1wp822zrhbg4fgfbwkr7cbkr4labx477209agzc0hr6k62fr6rxd";
  431. };
  432. description = ''
  433. The splash image to use in the legacy-boot bootloader.
  434. '';
  435. };
  436. isoImage.grubTheme = mkOption {
  437. default = pkgs.nixos-grub2-theme;
  438. type = types.nullOr (types.either types.path types.package);
  439. description = ''
  440. The grub2 theme used for UEFI boot.
  441. '';
  442. };
  443. isoImage.appendToMenuLabel = mkOption {
  444. default = " Installer";
  445. example = " Live System";
  446. description = ''
  447. The string to append after the menu label for the NixOS system.
  448. This will be directly appended (without whitespace) to the NixOS version
  449. string, like for example if it is set to <literal>XXX</literal>:
  450. <para><literal>NixOS 99.99-pre666XXX</literal></para>
  451. '';
  452. };
  453. };
  454. config = {
  455. boot.loader.grub.version = 2;
  456. # Don't build the GRUB menu builder script, since we don't need it
  457. # here and it causes a cyclic dependency.
  458. boot.loader.grub.enable = false;
  459. environment.systemPackages = [ grubPkgs.grub2 grubPkgs.grub2_efi ]
  460. ++ optional canx86BiosBoot pkgs.syslinux
  461. ;
  462. # In stage 1 of the boot, mount the CD as the root FS by label so
  463. # that we don't need to know its device. We pass the label of the
  464. # root filesystem on the kernel command line, rather than in
  465. # `fileSystems' below. This allows CD-to-USB converters such as
  466. # UNetbootin to rewrite the kernel command line to pass the label or
  467. # UUID of the USB stick. It would be nicer to write
  468. # `root=/dev/disk/by-label/...' here, but UNetbootin doesn't
  469. # recognise that.
  470. boot.kernelParams =
  471. [ "root=LABEL=${config.isoImage.volumeID}"
  472. "boot.shell_on_fail"
  473. ];
  474. fileSystems."/" =
  475. { fsType = "tmpfs";
  476. options = [ "mode=0755" ];
  477. };
  478. # Note that /dev/root is a symlink to the actual root device
  479. # specified on the kernel command line, created in the stage 1
  480. # init script.
  481. fileSystems."/iso" =
  482. { device = "/dev/root";
  483. neededForBoot = true;
  484. noCheck = true;
  485. };
  486. # In stage 1, mount a tmpfs on top of /nix/store (the squashfs
  487. # image) to make this a live CD.
  488. fileSystems."/nix/.ro-store" =
  489. { fsType = "squashfs";
  490. device = "/iso/nix-store.squashfs";
  491. options = [ "loop" ];
  492. neededForBoot = true;
  493. };
  494. fileSystems."/nix/.rw-store" =
  495. { fsType = "tmpfs";
  496. options = [ "mode=0755" ];
  497. neededForBoot = true;
  498. };
  499. fileSystems."/nix/store" =
  500. { fsType = "unionfs-fuse";
  501. device = "unionfs";
  502. options = [ "allow_other" "cow" "nonempty" "chroot=/mnt-root" "max_files=32768" "hide_meta_files" "dirs=/nix/.rw-store=rw:/nix/.ro-store=ro" ];
  503. };
  504. boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "uas" ];
  505. boot.initrd.kernelModules = [ "loop" ];
  506. # Closures to be copied to the Nix store on the CD, namely the init
  507. # script and the top-level system configuration directory.
  508. isoImage.storeContents =
  509. [ config.system.build.toplevel ] ++
  510. optional config.isoImage.includeSystemBuildDependencies
  511. config.system.build.toplevel.drvPath;
  512. # Create the squashfs image that contains the Nix store.
  513. system.build.squashfsStore = pkgs.callPackage ../../../lib/make-squashfs.nix {
  514. storeContents = config.isoImage.storeContents;
  515. };
  516. # Individual files to be included on the CD, outside of the Nix
  517. # store on the CD.
  518. isoImage.contents =
  519. [
  520. { source = config.boot.kernelPackages.kernel + "/" + config.system.boot.loader.kernelFile;
  521. target = "/boot/" + config.system.boot.loader.kernelFile;
  522. }
  523. { source = config.system.build.initialRamdisk + "/" + config.system.boot.loader.initrdFile;
  524. target = "/boot/" + config.system.boot.loader.initrdFile;
  525. }
  526. { source = config.system.build.squashfsStore;
  527. target = "/nix-store.squashfs";
  528. }
  529. { source = config.isoImage.efiSplashImage;
  530. target = "/EFI/boot/efi-background.png";
  531. }
  532. { source = config.isoImage.splashImage;
  533. target = "/isolinux/background.png";
  534. }
  535. { source = pkgs.writeText "version" config.system.nixos.label;
  536. target = "/version.txt";
  537. }
  538. ] ++ optionals canx86BiosBoot [
  539. { source = pkgs.substituteAll {
  540. name = "isolinux.cfg";
  541. src = pkgs.writeText "isolinux.cfg-in" isolinuxCfg;
  542. bootRoot = "/boot";
  543. };
  544. target = "/isolinux/isolinux.cfg";
  545. }
  546. { source = "${pkgs.syslinux}/share/syslinux";
  547. target = "/isolinux";
  548. }
  549. ] ++ optionals config.isoImage.makeEfiBootable [
  550. { source = efiImg;
  551. target = "/boot/efi.img";
  552. }
  553. { source = "${efiDir}/EFI";
  554. target = "/EFI";
  555. }
  556. { source = pkgs.writeText "loopback.cfg" "source /EFI/boot/grub.cfg";
  557. target = "/boot/grub/loopback.cfg";
  558. }
  559. ] ++ optionals (config.boot.loader.grub.memtest86.enable && canx86BiosBoot) [
  560. { source = "${pkgs.memtest86plus}/memtest.bin";
  561. target = "/boot/memtest.bin";
  562. }
  563. ] ++ optionals (config.isoImage.grubTheme != null) [
  564. { source = config.isoImage.grubTheme;
  565. target = "/EFI/boot/grub-theme";
  566. }
  567. ];
  568. boot.loader.timeout = 10;
  569. # Create the ISO image.
  570. system.build.isoImage = pkgs.callPackage ../../../lib/make-iso9660-image.nix ({
  571. inherit (config.isoImage) isoName compressImage volumeID contents;
  572. bootable = canx86BiosBoot;
  573. bootImage = "/isolinux/isolinux.bin";
  574. syslinux = if canx86BiosBoot then pkgs.syslinux else null;
  575. } // optionalAttrs (config.isoImage.makeUsbBootable && canx86BiosBoot) {
  576. usbBootable = true;
  577. isohybridMbrImage = "${pkgs.syslinux}/share/syslinux/isohdpfx.bin";
  578. } // optionalAttrs config.isoImage.makeEfiBootable {
  579. efiBootable = true;
  580. efiBootImage = "boot/efi.img";
  581. });
  582. boot.postBootCommands =
  583. ''
  584. # After booting, register the contents of the Nix store on the
  585. # CD in the Nix database in the tmpfs.
  586. ${config.nix.package.out}/bin/nix-store --load-db < /nix/store/nix-path-registration
  587. # nixos-rebuild also requires a "system" profile and an
  588. # /etc/NIXOS tag.
  589. touch /etc/NIXOS
  590. ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
  591. '';
  592. # Add vfat support to the initrd to enable people to copy the
  593. # contents of the CD to a bootable USB stick.
  594. boot.initrd.supportedFilesystems = [ "vfat" ];
  595. };
  596. }