@@ -1,13 +1,15 @@
# This module creates a bootable ISO image containing the given NixOS
# configuration. The derivation for the ISO image will be placed in
# config.system.build.isoImage.
{ config , lib , pkgs , . . . }:
with lib ;
let
/* *
{
config ,
lib ,
pkgs ,
. . .
}:
with lib ; let
/*
*
* G i v e n a l i s t o f ` o p t i o n s ` , c o n c a t s t h e r e s u l t o f m a p p i n g e a c h o p t i o n s
* t o a m e n u e n t r y f o r u s e i n g r u b .
*
@@ -15,8 +17,8 @@ let
* * o p t i o n s : [ o p t i o n . . . ]
* * o p t i o n : { n a m e , p a r a m s , c l a s s }
*/
menuBuilderGrub2 =
defaults : options : lib . concatStrings
menuBuilderGrub2 = defaults : options :
lib . concatStrings
(
map
( option : ''
@@ -34,56 +36,53 @@ let
}
'' )
options
)
;
) ;
/* *
/*
*
* B u i l d s t h e d e f a u l t o p t i o n s .
*/
buildMenuGrub2 = buildMenuAdditionalParamsGrub2 " " ;
targetArch =
if config . boot . loader . grub . forcei686 then
" i a 3 2 "
else
pkgs . stdenv . hostPlatform . efiArch ;
if config . boot . loader . grub . forcei686
then " i a 3 2 "
else pkgs . stdenv . hostPlatform . efiArch ;
/* *
/*
*
* G i v e n p a r a m s t o a d d t o ` p a r a m s ` , b u i l d a s e t o f d e f a u l t o p t i o n s .
* U s e t h i s o n e w h e n c r e a t i n g a v a r i a n t ( e . g . h i d p i )
*/
buildMenuAdditionalParamsGrub2 = additional :
let
buildMenuAdditionalParamsGrub2 = additional : let
finalCfg = {
name = " ${ config . isoImage . prependToMenuLabel } ${ config . system . nixos . distroName } ${ config . system . nixos . label } ${ config . isoImage . appendToMenuLabel } " ;
params = " i n i t = ${ config . system . build . toplevel } / i n i t ${ additional } ${ toString config . boot . kernelParams } " ;
image = " / b o o t / ${ config . system . boot . loader . kernelFile } " ;
initrd = " / b o o t / i n i t r d " ;
} ;
in
menuBuilderGrub2
finalCfg
[
{ class = " i n s t a l l e r " ; }
]
;
] ;
# Timeout in syslinux is in units of 1/10 of a second.
# null means max timeout (35996, just under 1h in 1/10 seconds)
# 0 means disable timeout
syslinuxTimeout = if config . boot . loader . timeout = = null then
35996
else
config . boot . loader . timeout * 10 ;
syslinuxTimeout =
if config . boot . loader . timeout = = null
then 35996
else config . boot . loader . timeout * 10 ;
# Timeout in grub is in seconds.
# null means max timeout (infinity)
# 0 means disable timeout
grubEfiTimeout = if config . boot . loader . timeout = = null then
-1
else
config . boot . loader . timeout ;
grubEfiTimeout =
if config . boot . loader . timeout = = null
then -1
else config . boot . loader . timeout ;
# The configuration file for syslinux.
@@ -122,23 +121,28 @@ let
A P P E N D ${ toString config . boot . loader . grub . memtest86 . params }
'' ;
isolinuxCfg = concatStringsSep " \n "
isolinuxCfg =
concatStringsSep " \n "
( [ baseIsolinuxCfg ] ++ optional config . boot . loader . grub . memtest86 . enable isolinuxMemtest86Entry ) ;
refindBinary = if targetArch = = " x 6 4 " || targetArch = = " a a 6 4 " then " r e f i n d _ ${ targetArch } . e f i " else null ;
refindBinary =
if targetArch = = " x 6 4 " || targetArch = = " a a 6 4 "
then " r e f i n d _ ${ targetArch } . e f i "
else null ;
# Setup instructions for rEFInd.
refind =
if refindBinary != null then
''
if refindBinary != null
then ''
# A d d s r E F I n d t o t h e I S O .
c p - v ${ pkgs . refind } / s h a r e / r e f i n d / ${ refindBinary } $o u t / E F I / b o o t /
''
else
" # N o r e f i n d f o r ${ targetArch } "
;
else " # N o r e f i n d f o r ${ targetArch } " ;
grubPkgs = if config . boot . loader . grub . forcei686 then pkgs . pkgsi686Linux else pkgs ;
grubPkgs =
if config . boot . loader . grub . forcei686
then pkgs . pkgsi686Linux
else pkgs ;
grubMenuCfg = ''
#
@@ -181,12 +185,14 @@ let
f i
${ # When there is a theme configured, use it, otherwise use the background image.
if config . isoImage . grubTheme != null then ''
if config . isoImage . grubTheme != null
then ''
# S e t s t h e m e .
s e t t h e m e = ( \ $r o o t ) / E F I / b o o t / g r u b - t h e m e / t h e m e . t x t
# L o a d t h e m e f o n t s
$( f i n d ${ config . isoImage . grubTheme } - i n a m e ' * . p f 2 ' - p r i n t f " l o a d f o n t ( \ $r o o t ) / E F I / b o o t / g r u b - t h e m e / % P \ n " )
'' else ''
''
else ''
i f b a c k g r o u n d _ i m a g e ( \ $r o o t ) / E F I / b o o t / e f i - b a c k g r o u n d . p n g ; t h e n
# B l a c k b a c k g r o u n d m e a n s t r a n s p a r e n t b a c k g r o u n d w h e n t h e r e
# i s a b a c k g r o u n d i m a g e s e t . . . T h i s s e e m s u n d o c u m e n t e d : (
@@ -197,14 +203,16 @@ let
s e t m e n u _ c o l o r _ n o r m a l = c y a n / b l u e
s e t m e n u _ c o l o r _ h i g h l i g h t = w h i t e / b l u e
f i
'' }
''
}
'' ;
# The EFI boot image.
# Notes about grub:
# * Yes, the grubMenuCfg has to be repeated in all submenus. Otherwise you
# will get white-on-black console-like text on sub-menus. *sigh*
efiDir = pkgs . runCommand " e f i - d i r e c t o r y " {
efiDir =
pkgs . runCommand " e f i - d i r e c t o r y " {
nativeBuildInputs = [ pkgs . buildPackages . grub2_efi ] ;
strictDeps = true ;
} ''
@@ -405,7 +413,8 @@ let
${ refind }
'' ;
efiImg = pkgs . runCommand " e f i - i m a g e _ e l t o r i t o " {
efiImg =
pkgs . runCommand " e f i - i m a g e _ e l t o r i t o " {
nativeBuildInputs = [ pkgs . buildPackages . mtools pkgs . buildPackages . libfaketime pkgs . buildPackages . dosfstools ] ;
strictDeps = true ;
}
@@ -443,12 +452,8 @@ let
# V e r i f y t h e F A T p a r t i t i o n .
f s c k . v f a t - v n " $o u t "
'' ; # */
in
{
in {
options = {
isoImage . isoName = mkOption {
default = " ${ config . isoImage . isoBaseName } . i s o " ;
type = lib . types . str ;
@@ -475,12 +480,13 @@ in
} ;
isoImage . squashfsCompression = mkOption {
default = with pkgs . stdenv . hostPlatform ; " x z - X d i c t - s i z e 1 0 0 % "
default = with pkgs . stdenv . hostPlatform ;
" x z - X d i c t - s i z e 1 0 0 % "
+ lib . optionalString isx86 " - X b c j x 8 6 "
# Untested but should also reduce size for these platforms
+ lib . optionalString isAarch " - X b c j a r m "
+ lib . optionalString ( isPower && is32bit && isBigEndian ) " - X b c j p o w e r p c "
+ lib . optionalString ( isSparc ) " - X b c j s p a r c " ;
+ lib . optionalString isSparc " - X b c j s p a r c " ;
type = lib . types . nullOr lib . types . str ;
description = ''
C o m p r e s s i o n s e t t i n g s t o u s e f o r t h e s q u a s h f s n i x s t o r e .
@@ -674,13 +680,13 @@ in
I f t e x t m o d e i s r e q u i r e d o f f - h a n d e d l y ( e . g . f o r s e r i a l u s e ) y o u c a n u s e t h e ` T ` k e y , a f t e r b e i n g p r o m p t e d , t o u s e t e x t m o d e f o r t h e c u r r e n t b o o t .
'' ;
} ;
} ;
# store them in lib so we can mkImageMediaOverride the
# entire file system layout in installation media (only)
config . lib . isoFileSystems = {
" / " = mkImageMediaOverride
" / " =
mkImageMediaOverride
{
fsType = " t m p f s " ;
options = [ " m o d e = 0 7 5 5 " ] ;
@@ -689,29 +695,37 @@ in
# Note that /dev/root is a symlink to the actual root device
# specified on the kernel command line, created in the stage 1
# init script.
" / i s o " = mkImageMediaOverride
{ device = " / d e v / r o o t " ;
" / i s o " =
mkImageMediaOverride
{
device = " / d e v / r o o t " ;
neededForBoot = true ;
noCheck = true ;
} ;
# In stage 1, mount a tmpfs on top of /nix/store (the squashfs
# image) to make this a live CD.
" / n i x / . r o - s t o r e " = mkImageMediaOverride
{ fsType = " s q u a s h f s " ;
" / n i x / . r o - s t o r e " =
mkImageMediaOverride
{
fsType = " s q u a s h f s " ;
device = " / i s o / n i x - s t o r e . s q u a s h f s " ;
options = [ " l o o p " ] ;
neededForBoot = true ;
} ;
" / n i x / . r w - s t o r e " = mkImageMediaOverride
{ fsType = " t m p f s " ;
" / n i x / . r w - s t o r e " =
mkImageMediaOverride
{
fsType = " t m p f s " ;
options = [ " m o d e = 0 7 5 5 " ] ;
neededForBoot = true ;
} ;
" / n i x / s t o r e " = mkImageMediaOverride
{ fsType = " o v e r l a y " ;
" / n i x / s t o r e " =
mkImageMediaOverride
{
fsType = " o v e r l a y " ;
device = " o v e r l a y " ;
options = [
" l o w e r d i r = / n i x / . r o - s t o r e "
@@ -741,8 +755,7 @@ in
length = stringLength config . isoImage . volumeID ;
howmany = toString length ;
toomany = toString ( length - 32 ) ;
in
" i s o I m a g e . v o l u m e I D ${ config . isoImage . volumeID } i s ${ howmany } c h a r a c t e r s . T h a t i s ${ toomany } c h a r a c t e r s l o n g e r t h a n t h e l i m i t o f 3 2 . " ;
in " i s o I m a g e . v o l u m e I D ${ config . isoImage . volumeID } i s ${ howmany } c h a r a c t e r s . T h a t i s ${ toomany } c h a r a c t e r s l o n g e r t h a n t h e l i m i t o f 3 2 . " ;
}
] ;
@@ -750,9 +763,9 @@ in
# here and it causes a cyclic dependency.
boot . loader . grub . enable = false ;
environment . systemPackages = [ grubPkgs . grub2 grubPkgs . grub2_efi ]
++ optional ( config . isoImage . makeBiosBootable ) pkgs . syslinux
;
environment . systemPackages =
[ grubPkgs . grub2 grubPkgs . grub2_efi ]
++ optional ( config . isoImage . makeBiosBootable ) pkgs . syslinux ;
# In stage 1 of the boot, mount the CD as the root FS by label so
# that we don't need to know its device. We pass the label of the
@@ -762,8 +775,8 @@ in
# UUID of the USB stick. It would be nicer to write
# `root=/dev/disk/by-label/...' here, but UNetbootin doesn't
# recognise that.
boot . kernelParams =
[ " r o o t = L A B E L = ${ config . isoImage . volumeID } "
boot . kernelParams = [
" r o o t = L A B E L = ${ config . isoImage . volumeID } "
" b o o t . s h e l l _ o n _ f a i l "
] ;
@@ -776,56 +789,72 @@ in
# Closures to be copied to the Nix store on the CD, namely the init
# script and the top-level system configuration directory.
isoImage . storeContents =
[ config . system . build . toplevel ] ++
optional config . isoImage . includeSystemBuildDependencies
[ config . system . build . toplevel ]
++ optional config . isoImage . includeSystemBuildDependencies
config . system . build . toplevel . drvPath ;
# Individual files to be included on the CD, outside of the Nix
# store on the CD.
isoImage . contents =
[
{ source = config . boot . kernelPackages . kernel + " / " + config . system . boot . loader . kernelFile ;
{
source = config . boot . kernelPackages . kernel + " / " + config . system . boot . loader . kernelFile ;
target = " / b o o t / " + config . system . boot . loader . kernelFile ;
}
{ source = config . system . build . initialRamdisk + " / " + config . system . boot . loader . initrdFile ;
{
source = config . system . build . initialRamdisk + " / " + config . system . boot . loader . initrdFile ;
target = " / b o o t / " + config . system . boot . loader . initrdFile ;
}
{ source = pkgs . writeText " v e r s i o n " config . system . nixos . label ;
{
source = pkgs . writeText " v e r s i o n " config . system . nixos . label ;
target = " / v e r s i o n . t x t " ;
}
] ++ optionals ( config . isoImage . makeBiosBootable ) [
{ source = config . isoImage . splashImage ;
]
++ optionals ( config . isoImage . makeBiosBootable ) [
{
source = config . isoImage . splashImage ;
target = " / i s o l i n u x / b a c k g r o u n d . p n g " ;
}
{ source = pkgs . substituteAll {
{
source = pkgs . substituteAll {
name = " i s o l i n u x . c f g " ;
src = pkgs . writeText " i s o l i n u x . c f g - i n " isolinuxCfg ;
bootRoot = " / b o o t " ;
} ;
target = " / i s o l i n u x / i s o l i n u x . c f g " ;
}
{ source = " ${ pkgs . syslinux } / s h a r e / s y s l i n u x " ;
{
source = " ${ pkgs . syslinux } / s h a r e / s y s l i n u x " ;
target = " / i s o l i n u x " ;
}
] ++ optionals config . isoImage . makeEfiBootable [
{ source = efiImg ;
]
++ optionals config . isoImage . makeEfiBootable [
{
source = efiImg ;
target = " / b o o t / e f i . i m g " ;
}
{ source = " ${ efiDir } / E F I " ;
{
source = " ${ efiDir } / E F I " ;
target = " / E F I " ;
}
{ source = ( pkgs . writeTextDir " g r u b / l o o p b a c k . c f g " " s o u r c e / E F I / b o o t / g r u b . c f g " ) + " / g r u b " ;
{
source = ( pkgs . writeTextDir " g r u b / l o o p b a c k . c f g " " s o u r c e / E F I / b o o t / g r u b . c f g " ) + " / g r u b " ;
target = " / b o o t / g r u b " ;
}
{ source = config . isoImage . efiSplashImage ;
{
source = config . isoImage . efiSplashImage ;
target = " / E F I / b o o t / e f i - b a c k g r o u n d . p n g " ;
}
] ++ optionals ( config . boot . loader . grub . memtest86 . enable && config . isoImage . makeBiosBootable ) [
{ source = " ${ pkgs . memtest86plus } / m e m t e s t . b i n " ;
]
++ optionals ( config . boot . loader . grub . memtest86 . enable && config . isoImage . makeBiosBootable ) [
{
source = " ${ pkgs . memtest86plus } / m e m t e s t . b i n " ;
target = " / b o o t / m e m t e s t . b i n " ;
}
] ++ optionals ( config . isoImage . grubTheme != null ) [
{ source = config . isoImage . grubTheme ;
]
++ optionals ( config . isoImage . grubTheme != null ) [
{
source = config . isoImage . grubTheme ;
target = " / E F I / b o o t / g r u b - t h e m e " ;
}
] ;
@@ -837,19 +866,23 @@ in
inherit ( config . isoImage ) isoName compressImage volumeID contents ;
bootable = config . isoImage . makeBiosBootable ;
bootImage = " / i s o l i n u x / i s o l i n u x . b i n " ;
syslinux = if config . isoImage . makeBiosBootable then pkgs . syslinux else null ;
syslinux =
if config . isoImage . makeBiosBootable
then pkgs . syslinux
else null ;
squashfsContents = config . isoImage . storeContents ;
squashfsCompression = config . isoImage . squashfsCompression ;
} // optionalAttrs ( config . isoImage . makeUsbBootable && config . isoImage . makeBiosBootable ) {
}
// optionalAttrs ( config . isoImage . makeUsbBootable && config . isoImage . makeBiosBootable ) {
usbBootable = true ;
isohybridMbrImage = " ${ pkgs . syslinux } / s h a r e / s y s l i n u x / i s o h d p f x . b i n " ;
} // optionalAttrs config . isoImage . makeEfiBootable {
}
// optionalAttrs config . isoImage . makeEfiBootable {
efiBootable = true ;
efiBootImage = " b o o t / e f i . i m g " ;
} ) ;
boot . postBootCommands =
''
boot . postBootCommands = ''
# A f t e r b o o t i n g , r e g i s t e r t h e c o n t e n t s o f t h e N i x s t o r e o n t h e
# C D i n t h e N i x d a t a b a s e i n t h e t m p f s .
${ config . nix . package . out } / b i n / n i x - s t o r e - - l o a d - d b < / n i x / s t o r e / n i x - p a t h - r e g i s t r a t i o n
@@ -863,7 +896,5 @@ in
# Add vfat support to the initrd to enable people to copy the
# contents of the CD to a bootable USB stick.
boot . initrd . supportedFilesystems = [ " v f a t " ] ;
} ;
}