From 49e882905368f495bf984b7e3b18eec869f842bc Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 24 Jan 2008 16:56:09 +0000 Subject: [PATCH] * Use unionfs to provide a real Live CD, i.e., the files on the CD appear writable (though all writes go to a tmpfs). This allows you to run Nix operations on the Live CD. However, we're not quite there yet since the CD doesn't have a valid Nix database. So for instance a garbage collect will cause everything to be deleted, hanging the system. svn path=/nixos/trunk/; revision=10276 --- boot/boot-stage-1-init.sh | 15 ++++++++++++++- boot/boot-stage-1.nix | 10 +++++++--- boot/boot-stage-2-init.sh | 33 ++++++++++++-------------------- boot/boot-stage-2.nix | 8 ++++---- configuration/rescue-cd.nix | 25 ++++++++++++------------ helpers/make-iso9660-image.sh | 4 ++-- system/activate-configuration.sh | 24 ++++++++++++----------- system/options.nix | 8 +++++--- system/system.nix | 8 +++----- 9 files changed, 72 insertions(+), 63 deletions(-) diff --git a/boot/boot-stage-1-init.sh b/boot/boot-stage-1-init.sh index e49759814139..02de35e0ceea 100644 --- a/boot/boot-stage-1-init.sh +++ b/boot/boot-stage-1-init.sh @@ -211,6 +211,19 @@ else fi + +# If this is a live-CD/DVD, then union-mount a tmpfs on top of the +# original root. +targetRoot=/mnt/root +if test -n "@isLiveCD@"; then + mkdir /mnt/tmpfs + mount -n -t tmpfs -o "mode=755" none /mnt/tmpfs + mkdir /mnt/union + mount -t unionfs -o dirs=/mnt/tmpfs=rw:$targetRoot=ro none /mnt/union + targetRoot=/mnt/union +fi + + if test -n "$debug1mounts"; then fail; fi @@ -218,7 +231,7 @@ if test -n "$debug1mounts"; then fail; fi # !!! Note: we can't use pivot_root here (the kernel gods have # decreed), but we could use run-init from klibc, which deletes all # files in the initramfs, remounts the target root on /, and chroots. -cd /mnt/root +cd "$targetRoot" mount --move . / umount /proc # cleanup umount /sys diff --git a/boot/boot-stage-1.nix b/boot/boot-stage-1.nix index 7417ab5b2cfb..0c504e86469b 100644 --- a/boot/boot-stage-1.nix +++ b/boot/boot-stage-1.nix @@ -20,8 +20,12 @@ # must at least be a file system for the / mount point in this list. fileSystems ? [] - # If scanning, we need a disk label. -, rootLabel +, # If scanning, we need a disk label. + rootLabel + +, # Whether the root device is read-only and should be made writable + # through a unionfs. + isLiveCD , # The path of the stage 2 init to call once we've mounted the root # device. @@ -44,7 +48,7 @@ substituteAll { src = ./boot-stage-1-init.sh; isExecutable = true; inherit staticShell modules modulesDir; - inherit autoDetectRootDevice mountPoints devices fsTypes optionss; + inherit autoDetectRootDevice isLiveCD mountPoints devices fsTypes optionss; rootLabel = if autoDetectRootDevice then rootLabel else ""; path = [ staticTools diff --git a/boot/boot-stage-2-init.sh b/boot/boot-stage-2-init.sh index 2c7e3532006d..5e2754fcdd70 100644 --- a/boot/boot-stage-2-init.sh +++ b/boot/boot-stage-2-init.sh @@ -25,19 +25,9 @@ setPath "@path@" # Mount special file systems. - -needWritableDir() { - if test -n "@readOnlyRoot@"; then - mount -t tmpfs -o "mode=$2" none $1 $3 - else - mkdir -m $2 -p $1 - fi -} - -needWritableDir /etc 0755 -n # to shut up mount - -test -e /etc/fstab || touch /etc/fstab # idem - +mkdir -m 0755 -p /etc +test -e /etc/fstab || touch /etc/fstab # to shut up mount +mkdir -m 0755 -p /proc mount -n -t proc none /proc cat /proc/mounts > /etc/mtab @@ -71,19 +61,20 @@ done # More special file systems, initialise required directories. +mkdir -m 0755 -p /sys mount -t sysfs none /sys +mkdir -m 0755 -p /dev mount -t tmpfs -o "mode=0755" none /dev mkdir -m 0755 -p /dev/pts mount -t devpts none /dev/pts mount -t usbfs none /proc/bus/usb -needWritableDir /tmp 01777 -needWritableDir /var 0755 -needWritableDir /nix/var 0755 -needWritableDir /root 0700 -needWritableDir /bin 0755 # for the /bin/sh symlink -if test -d /home ; then - needWritableDir /home 0777 -fi +mkdir -m 01777 /tmp +mkdir -m 0755 /var +mkdir -m 0755 /nix/var +mkdir -m 0700 /root +mkdir -m 0755 /bin # for the /bin/sh symlink +mkdir -m 0755 /home + # Miscellaneous boot time cleanup. rm -rf /var/run diff --git a/boot/boot-stage-2.nix b/boot/boot-stage-2.nix index bdccabc3605c..5d0ac24be6fe 100644 --- a/boot/boot-stage-2.nix +++ b/boot/boot-stage-2.nix @@ -2,9 +2,9 @@ , utillinux, kernel, udev, upstart , activateConfiguration -, # Whether the root device is root only. If so, we'll mount a - # ramdisk on /etc, /var and so on. - readOnlyRoot +, # Whether the root device is read-only and should be made writable + # through a unionfs. + isLiveCD , # Path for Upstart jobs. Should be quite minimal. upstartPath @@ -16,7 +16,7 @@ substituteAll { src = ./boot-stage-2-init.sh; isExecutable = true; - inherit kernel upstart readOnlyRoot activateConfiguration upstartPath; + inherit kernel upstart isLiveCD activateConfiguration upstartPath; path = [ coreutils utillinux diff --git a/configuration/rescue-cd.nix b/configuration/rescue-cd.nix index 25821fd20cb7..435da04db16f 100644 --- a/configuration/rescue-cd.nix +++ b/configuration/rescue-cd.nix @@ -11,10 +11,15 @@ rec { boot = { autoDetectRootDevice = true; - readOnlyRoot = true; + isLiveCD = true; # The label used to identify the installation CD. rootLabel = "NIXOS"; extraTTYs = [7 8]; # manual, rogue + initrd = { + extraKernelModules = [ + "unionfs" # needed for live-CD operation + ]; + }; }; services = { @@ -48,6 +53,7 @@ rec { # Show the NixOS manual on tty7. { name = "manual"; job = " + env HOME=/root start on udev stop on shutdown respawn ${pkgs.w3m}/bin/w3m ${manual} < /dev/tty7 > /dev/tty7 2>&1 @@ -58,6 +64,7 @@ rec { # for the installation to finish. { name = "rogue"; job = " + env HOME=/root start on udev stop on shutdown respawn ${pkgs.rogue}/bin/rogue < /dev/tty8 > /dev/tty8 2>&1 @@ -112,6 +119,7 @@ rec { pkgs.vim pkgs.subversion # for nixos-checkout pkgs.w3m # needed for the manual anyway + pkgs.gdb # for debugging Nix ]; }; @@ -135,15 +143,6 @@ rec { else pkgs.writeText "dummy-manual" "Manual not included in this build!"; - # Since the CD is read-only, the mount points must be on disk. - cdMountPoints = pkgs.runCommand "mount-points" {} " - ensureDir $out - cd $out - mkdir proc sys tmp etc dev var mnt nix nix/var root bin - touch $out/${configuration.boot.rootLabel} - "; - - # We need a copy of the Nix expressions for Nixpkgs and NixOS on the # CD. We put them in a tarball because accessing that many small # files from a slow device like a CD-ROM takes too long. @@ -213,15 +212,15 @@ rec { { source = system.config.boot.grubSplashImage; target = "boot/background.xpm.gz"; } - { source = cdMountPoints; - target = "/"; - } { source = nixosTarball + "/" + nixosTarball.tarName; target = "/" + nixosTarball.tarName; } { source = nixpkgsTarball; target = "/nixpkgs.tar.bz2"; } + { source = pkgs.writeText "label" ""; + target = "/${configuration.boot.rootLabel}"; + } ]; # Closures to be copied to the Nix store on the CD. diff --git a/helpers/make-iso9660-image.sh b/helpers/make-iso9660-image.sh index aa8cb291a3e1..6f18f0e3e5b7 100644 --- a/helpers/make-iso9660-image.sh +++ b/helpers/make-iso9660-image.sh @@ -20,7 +20,7 @@ if test -n "$bootable"; then fi done - bootFlags="-b $bootImage -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table" + bootFlags="-b $bootImage -c .boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table" fi touch pathlist @@ -59,7 +59,7 @@ cat pathlist # !!! -f is a quick hack. ensureDir $out/iso genisoimage -r -J -o $out/iso/$isoName $bootFlags \ - -graft-points -path-list pathlist + -hide-rr-moved -graft-points -path-list pathlist ensureDir $out/nix-support echo $system > $out/nix-support/system diff --git a/system/activate-configuration.sh b/system/activate-configuration.sh index 2ed025e18036..4e35785f9816 100644 --- a/system/activate-configuration.sh +++ b/system/activate-configuration.sh @@ -104,22 +104,24 @@ fi # Set up Nix. -if test -z "@readOnlyRoot@"; then - mkdir -p /nix/etc/nix - ln -sfn /etc/nix.conf /nix/etc/nix/nix.conf - chown root.nixbld /nix/store - chmod 1775 /nix/store -fi +mkdir -p /nix/etc/nix +ln -sfn /etc/nix.conf /nix/etc/nix/nix.conf +chown root.nixbld /nix/store +chmod 1775 /nix/store # Nix initialisation. -mkdir -m 0755 -p /nix/var/nix/db -mkdir -m 0755 -p /nix/var/nix/gcroots +mkdir -m 0755 -p \ + /nix/var/nix/gcroots \ + /nix/var/nix/temproots \ + /nix/var/nix/manifests \ + /nix/var/nix/userpool \ + /nix/var/nix/profiles \ + /nix/var/nix/db \ + /nix/var/log/nix/drvs \ + /nix/var/nix/channel-cache mkdir -m 1777 -p /nix/var/nix/gcroots/per-user -mkdir -m 0755 -p /nix/var/nix/temproots -mkdir -m 0755 -p /nix/var/nix/profiles mkdir -m 1777 -p /nix/var/nix/profiles/per-user -mkdir -m 0755 -p /nix/var/nix/channel-cache ln -sf /nix/var/nix/profiles /nix/var/nix/gcroots/ ln -sf /nix/var/nix/manifests /nix/var/nix/gcroots/ diff --git a/system/options.nix b/system/options.nix index fc5c5c116dd4..3f2197a40d48 100644 --- a/system/options.nix +++ b/system/options.nix @@ -25,11 +25,13 @@ "; }; - readOnlyRoot = mkOption { + isLiveCD = mkOption { default = false; description = " - Whether the root device is read-only. This should be set when - booting from CD-ROM. + If set to true, the root device will be mounted read-only and + a ramdisk will be mounted on top of it using unionfs to + provide a writable root. This is used for the NixOS + Live-CD/DVD. "; }; diff --git a/system/system.nix b/system/system.nix index d4c4cc505c35..72cd8dfedc89 100644 --- a/system/system.nix +++ b/system/system.nix @@ -78,7 +78,7 @@ rec { inherit (pkgs) substituteAll; inherit (pkgsDiet) module_init_tools; inherit extraUtils; - autoDetectRootDevice = config.boot.autoDetectRootDevice; + inherit (config.boot) autoDetectRootDevice isLiveCD; fileSystems = pkgs.lib.filter (fs: fs.mountPoint == "/" || (fs ? neededForBoot && fs.neededForBoot)) @@ -298,7 +298,6 @@ rec { isExecutable = true; inherit etc wrapperDir systemPath modprobe defaultShell kernel; - readOnlyRoot = config.boot.readOnlyRoot; hostName = config.networking.hostName; setuidPrograms = config.security.setuidPrograms ++ @@ -323,7 +322,7 @@ rec { inherit (pkgs) substituteAll writeText coreutils utillinux udev upstart; inherit kernel activateConfiguration; - readOnlyRoot = config.boot.readOnlyRoot; + inherit (config.boot) isLiveCD; upstartPath = [ pkgs.coreutils pkgs.findutils @@ -359,8 +358,7 @@ rec { inherit (pkgs) grub coreutils gnused gnugrep diffutils findutils upstart; grubDevice = config.boot.grubDevice; kernelParams = - (config.boot.kernelParams) ++ - (config.boot.extraKernelParams); + config.boot.kernelParams ++ config.boot.extraKernelParams; inherit bootStage2; inherit activateConfiguration; inherit grubMenuBuilder;