Making modular my previous changes for armv5tel. I updated the way to use

grub. Its options are no more inside 'boot', but inside 'boot.loader.grub'.
I added a new bootloader configuration for nixos, generationsDir. It creates
/boot/default/{init,initrd,kernel,system} symlinks, and the same for the generations
in /boot/system-$gen/{init,initrd,kernel,system}.

I can program the u-boot loader to load /boot/default files always, and have
a minimal nixos boot loader installer functionality. Additionally, I can refer
to the other system generations easily, with a simple 'ls' in /boot.

svn path=/nixos/trunk/; revision=17460
This commit is contained in:
Lluís Batlle i Rossell 2009-09-27 21:51:37 +00:00
parent 852478ff79
commit 75f6cd20da
7 changed files with 303 additions and 94 deletions

View file

@ -60,7 +60,7 @@ let
pkgs.usbutils
pkgs.utillinux
pkgs.wirelesstools
] ++ optional (pkgs.stdenv.system != "armv5tel-linux") [ pkgs.grub ]
]
++ config.environment.extraPackages;

View file

@ -0,0 +1,105 @@
#! @bash@/bin/sh -e
shopt -s nullglob
export PATH=/empty
for i in @path@; do PATH=$PATH:$i/bin; done
default=$1
if test -z "$1"; then
echo "Syntax: generations-dir-builder.sh <DEFAULT-CONFIG>"
exit 1
fi
echo "updating the boot generations directory..."
mkdir -p /boot
rm -Rf /boot/system* || true
target=/boot/grub/menu.lst
tmp=$target.tmp
# Convert a path to a file in the Nix store such as
# /nix/store/<hash>-<name>/file to <hash>-<name>-<file>.
cleanName() {
local path="$1"
echo "$path" | sed 's|^/nix/store/||' | sed 's|/|-|g'
}
# Copy a file from the Nix store to /boot/kernels.
declare -A filesCopied
copyToKernelsDir() {
local src="$1"
local dst="/boot/kernels/$(cleanName $src)"
# Don't copy the file if $dst already exists. This means that we
# have to create $dst atomically to prevent partially copied
# kernels or initrd if this script is ever interrupted.
if ! test -e $dst; then
local dstTmp=$dst.tmp.$$
cp $src $dstTmp
mv $dstTmp $dst
fi
filesCopied[$dst]=1
result=$dst
}
# Add an entry for a configuration to the Grub menu, and if
# appropriate, copy its kernel and initrd to /boot/kernels.
addEntry() {
local path="$1"
local generation="$2"
local outdir=/boot/system-$generation
if ! test -e $path/kernel -a -e $path/initrd; then
return
fi
local kernel=$(readlink -f $path/kernel)
local initrd=$(readlink -f $path/initrd)
if test -n "@copyKernels@"; then
copyToKernelsDir $kernel; kernel=$result
copyToKernelsDir $initrd; initrd=$result
fi
mkdir -p $outdir
ln -sf $(readlink -f $path) $outdir/system
ln -sf $(readlink -f $path/init) $outdir/init
ln -sf $(readlink -f $path/initrd) $outdir/initrd
ln -sf $(readlink -f $path/kernel) $outdir/kernel
if test $(readlink -f "$path") = "$default"; then
cp "$kernel" /boot/nixos-kernel
cp "$initrd" /boot/nixos-initrd
cp "$(readlink -f "$path/init")" /boot/nixos-init
mkdir -p /boot/default
ln -sf $(readlink -f $path) /boot/default/system
ln -sf $(readlink -f $path/init) /boot/default/init
ln -sf $(readlink -f $path/initrd) /boot/default/initrd
ln -sf $(readlink -f $path/kernel) /boot/default/kernel
fi
}
if test -n "@copyKernels@"; then
mkdir -p /boot/kernels
fi
# Add all generations of the system profile to the menu, in reverse
# (most recent to least recent) order.
for generation in $(
(cd /nix/var/nix/profiles && ls -d system-*-link) \
| sed 's/system-\([0-9]\+\)-link/\1/' \
| sort -n -r); do
link=/nix/var/nix/profiles/system-$generation-link
addEntry $link $generation
done
# Remove obsolete files from /boot/kernels.
for fn in /boot/kernels/*; do
if ! test "${filesCopied[$fn]}" = 1; then
rm -vf -- "$fn"
fi
done

View file

@ -0,0 +1,60 @@
{pkgs, config, ...}:
###### interface
let
inherit (pkgs.lib) mkOption mkIf;
options = {
boot = {
loader = {
generationsDir = {
enable = mkOption {
default = false;
description = ''
Whether to enable the simple preparation of symlinks to the system
generations in /boot.
'';
};
copyKernels = mkOption {
default = false;
description = "
Whether copy the necessary boot files into /boot, so
/nix/store is not needed by the boot loadear.
";
};
};
};
};
};
in
###### implementation
let
generationsDirBuilder = pkgs.substituteAll {
src = ./generations-dir-builder.sh;
isExecutable = true;
inherit (pkgs) bash;
path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
inherit (config.boot.loader.generationsDir) copyKernels;
};
in
{
require = [
options
# config.system.build
# ../system/system-options.nix
];
system = mkIf config.boot.loader.generationsDir.enable {
build = {
menuBuilder = generationsDirBuilder;
};
boot.loader.id = "generationsDir";
boot.loader.kernelFile = "uImage";
};
}

View file

@ -2,90 +2,100 @@
###### interface
let
inherit (pkgs.lib) mkOption;
inherit (pkgs.lib) mkOption mkIf;
options = {
boot = {
loader = {
grub = {
grubDevice = mkOption {
default = "";
example = "/dev/hda";
description = "
The device on which the boot loader, Grub, will be installed.
If empty, Grub won't be installed and it's your responsibility
to make the system bootable.
";
};
enable = mkOption {
default = true;
description = ''
Whether to enable the GRUB boot loader.
'';
};
bootMount = mkOption {
default = "";
example = "(hd0,0)";
description = "
If the system partition may be wiped on reinstall, it is better
to have /boot on a small partition. To do it, we need to explain
to GRUB where the kernels live. Specify the partition here (in
GRUB notation.
";
};
grubDevice = mkOption {
default = "";
example = "/dev/hda";
description = "
The device on which the boot loader, Grub, will be installed.
If empty, Grub won't be installed and it's your responsibility
to make the system bootable.
";
};
configurationName = mkOption {
default = "";
example = "Stable 2.6.21";
description = "
Grub entry name instead of default.
";
};
bootMount = mkOption {
default = "";
example = "(hd0,0)";
description = "
If the system partition may be wiped on reinstall, it is better
to have /boot on a small partition. To do it, we need to explain
to GRUB where the kernels live. Specify the partition here (in
GRUB notation.
";
};
extraGrubEntries = mkOption {
default = "";
example = "
title Windows
chainloader (hd0,1)+1
";
description = "
Any additional entries you want added to the Grub boot menu.
";
};
configurationName = mkOption {
default = "";
example = "Stable 2.6.21";
description = "
Grub entry name instead of default.
";
};
extraGrubEntriesBeforeNixos = mkOption {
default = false;
description = "
Wheter extraGrubEntries are put before the Nixos-default option
";
};
extraGrubEntries = mkOption {
default = "";
example = "
title Windows
chainloader (hd0,1)+1
";
description = "
Any additional entries you want added to the Grub boot menu.
";
};
grubSplashImage = mkOption {
default = pkgs.fetchurl {
url = http://www.gnome-look.org/CONTENT/content-files/36909-soft-tux.xpm.gz;
sha256 = "14kqdx2lfqvh40h6fjjzqgff1mwk74dmbjvmqphi6azzra7z8d59";
extraGrubEntriesBeforeNixos = mkOption {
default = false;
description = "
Wheter extraGrubEntries are put before the Nixos-default option
";
};
grubSplashImage = mkOption {
default = pkgs.fetchurl {
url = http://www.gnome-look.org/CONTENT/content-files/36909-soft-tux.xpm.gz;
sha256 = "14kqdx2lfqvh40h6fjjzqgff1mwk74dmbjvmqphi6azzra7z8d59";
};
example = null;
description = "
Background image used for Grub. It must be a 640x480,
14-colour image in XPM format, optionally compressed with
<command>gzip</command> or <command>bzip2</command>. Set to
<literal>null</literal> to run Grub in text mode.
";
};
configurationLimit = mkOption {
default = 100;
example = 120;
description = "
Maximum of configurations in boot menu. GRUB has problems when
there are too many entries.
";
};
copyKernels = mkOption {
default = false;
description = "
Whether the Grub menu builder should copy kernels and initial
ramdisks to /boot. This is necessary when /nix is on a
different file system than /boot.
";
};
};
example = null;
description = "
Background image used for Grub. It must be a 640x480,
14-colour image in XPM format, optionally compressed with
<command>gzip</command> or <command>bzip2</command>. Set to
<literal>null</literal> to run Grub in text mode.
";
};
configurationLimit = mkOption {
default = 100;
example = 120;
description = "
Maximum of configurations in boot menu. GRUB has problems when
there are too many entries.
";
};
copyKernels = mkOption {
default = false;
description = "
Whether the Grub menu builder should copy kernels and initial
ramdisks to /boot. This is necessary when /nix is on a
different file system than /boot.
";
};
};
};
in
@ -99,7 +109,7 @@ let
isExecutable = true;
inherit (pkgs) bash;
path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
inherit (config.boot) copyKernels extraGrubEntries extraGrubEntriesBeforeNixos
inherit (config.boot.loader.grub) copyKernels extraGrubEntries extraGrubEntriesBeforeNixos
grubSplashImage bootMount configurationLimit;
};
in
@ -112,11 +122,18 @@ in
# ../system/system-options.nix
];
system = {
system = mkIf config.boot.loader.grub.enable {
build = {
inherit grubMenuBuilder;
menuBuilder = grubMenuBuilder;
};
# Common attribute for boot loaders so only one of them can be
# set at once
boot.loader.id = "grub";
boot.loader.kernelFile = "vmlinuz";
};
environment.extraPackages = mkIf config.boot.loader.grub.enable [ pkgs.grub ];
# and many other things that have to be moved inside this file.
}

View file

@ -13,6 +13,7 @@
./hardware/network/rt73.nix
./hardware/pcmcia.nix
./installer/grub/grub.nix
./installer/generations-dir/generations-dir.nix
./installer/tools/nixos-checkout.nix
./installer/tools/tools.nix
./misc/assertions.nix

View file

@ -22,14 +22,20 @@ EOF
fi
if test "$action" = "switch" -o "$action" = "boot"; then
if test -n "@grubDevice@"; then
mkdir -m 0700 -p /boot/grub
@grubMenuBuilder@ @out@
if test "$NIXOS_INSTALL_GRUB" = 1; then
@grub@/sbin/grub-install "@grubDevice@" --no-floppy --recheck
fi
if [ "@bootLoader@" == "grub" ]; then
if test -n "@grubDevice@"; then
mkdir -m 0700 -p /boot/grub
@menuBuilder@ @out@
if test "$NIXOS_INSTALL_GRUB" = 1; then
@grub@/sbin/grub-install "@grubDevice@" --no-floppy --recheck
fi
else
echo "Warning: don't know how to make this configuration bootable; please set \`boot.grubDevice'." 1>&2
fi
elif [ "@bootLoader@" == "generationsDir" ]; then
@menuBuilder@ @out@
else
echo "Warning: don't know how to make this configuration bootable; please set \`boot.grubDevice'." 1>&2
echo "Warning: don't know how to make this configuration bootable; please enable a boot loader." 1>&2
fi
fi

View file

@ -17,6 +17,20 @@ let
Additional configurations to build.
'';
};
system.boot.loader.id = pkgs.lib.mkOption {
default = "";
description = ''
Id string of the used bootloader.
'';
};
system.boot.loader.kernelFile = pkgs.lib.mkOption {
default = "";
description = ''
Name of the kernel file to be passed to the bootloader.
'';
};
};
@ -33,13 +47,17 @@ let
systemBuilder = let
kernelfile = if (pkgs.stdenv.system == "armv5tel-linux")
then "${config.boot.kernelPackages.kernel}/uImage"
else "${config.boot.kernelPackages.kernel}/vmlinuz";
in ''
kernelPath = "${config.boot.kernelPackages.kernel}/" +
"${config.system.boot.loader.kernelFile}";
in
''
ensureDir $out
ln -s ${kernelfile} $out/kernel
if [ ! -f ${kernelPath} ]; then
echo "The bootloader cannot find the proper kernel image."
echo "(Expecting ${kernelPath})"
fi
ln -s ${kernelPath} $out/kernel
if [ -n "$grub" ]; then
ln -s $grub $out/grub
fi
@ -76,13 +94,9 @@ let
name = "system";
buildCommand = systemBuilder;
inherit children;
grub = if (pkgs.stdenv.system != "armv5tel-linux") then pkgs.grub
else null;
grubDevice = config.boot.grubDevice;
kernelParams =
config.boot.kernelParams ++ config.boot.extraKernelParams;
grubMenuBuilder = config.system.build.grubMenuBuilder;
configurationName = config.boot.configurationName;
menuBuilder = config.system.build.menuBuilder;
# Most of these are needed by grub-install.
path = [
pkgs.coreutils
@ -92,6 +106,12 @@ let
pkgs.diffutils
pkgs.upstart # for initctl
];
# Boot loaders
bootLoader = config.system.boot.loader.id;
grub = if config.boot.loader.grub.enable then pkgs.grub else null;
grubDevice = config.boot.loader.grub.grubDevice;
configurationName = config.boot.loader.grub.configurationName;
};