diff --git a/pkgs/build-support/kernel/make-initrd.sh b/pkgs/build-support/kernel/make-initrd.sh index f6cadaf028190..b1fef482b202a 100644 --- a/pkgs/build-support/kernel/make-initrd.sh +++ b/pkgs/build-support/kernel/make-initrd.sh @@ -37,6 +37,8 @@ storePaths=$(perl $pathsFromGraph closure-*) # Put the closure in a gzipped cpio archive. mkdir -p $out (cd root && find * -print0 | cpio -o -H newc --null | $compressor > $out/initrd) +mkdir $out/depends +ln -s $storePaths -t $out/depends if [ -n "$makeUInitrd" ]; then mv $out/initrd $out/initrd.gz diff --git a/pkgs/build-support/release/rpm-build.nix b/pkgs/build-support/release/rpm-build.nix index 9a1c7eeee6262..43353d0ff77f3 100644 --- a/pkgs/build-support/release/rpm-build.nix +++ b/pkgs/build-support/release/rpm-build.nix @@ -30,12 +30,12 @@ vmTools.buildRPM ( done echo "installing ''${rpms[*]}..." - rpm -Up ''${rpms[*]} --excludepath /nix/store + rpm -Up ''${rpms[*]} --excludepath /nix/store || touch $out/nix-support/failed eval "$postRPMInstall" echo "uninstalling ''${rpmNames[*]}..." - rpm -e ''${rpmNames[*]} --nodeps + rpm -e ''${rpmNames[*]} --nodeps || touch $out/nix-support/failed for i in $out/rpms/*/*.src.rpm; do echo "file srpm $i" >> $out/nix-support/hydra-build-products diff --git a/pkgs/build-support/vm/default.nix b/pkgs/build-support/vm/default.nix index b1eb82ed83038..a8c690ba0e62c 100644 --- a/pkgs/build-support/vm/default.nix +++ b/pkgs/build-support/vm/default.nix @@ -14,13 +14,14 @@ rec { # The 15 second CIFS timeout is too short if the host if heavily # loaded (e.g., in the Hydra build farm when it's running many jobs # in parallel). So apply a patch to increase the timeout to 120s. - kernel = assert pkgs.linux.features.cifsTimeout; linuxKernel; + nixpkgsKernel = assert pkgs.linux.features.cifsTimeout; linuxKernel; kvm = pkgs.qemu_kvm; - modulesClosure = makeModulesClosure { + modulesClosure = kernel: makeModulesClosure { inherit kernel rootModules; + allowMissing = true; }; @@ -29,10 +30,11 @@ rec { initrdUtils = runCommand "initrd-utils" { buildInputs = [ nukeReferences ]; - allowedReferences = [ "out" modulesClosure ]; # prevent accidents like glibc being included in the initrd + allowedReferences = [ "out" ]; # prevent accidents like glibc being included in the initrd } '' mkdir -p $out/bin + mkdir -p $out/sbin mkdir -p $out/lib # Copy what we need from Glibc. @@ -42,11 +44,12 @@ rec { # Copy BusyBox. cp -pd ${pkgs.busybox}/bin/* ${pkgs.busybox}/sbin/* $out/bin + cp ${cifs_utils}/sbin/mount.cifs $out/sbin # Run patchelf to make the programs refer to the copied libraries. for i in $out/bin/* $out/lib/*; do if ! test -L $i; then nuke-refs $i; fi; done - for i in $out/bin/*; do + for i in $out/bin/* $out/sbin/*; do if [ -f "$i" -a ! -L "$i" ]; then echo "patching $i..." patchelf --set-interpreter $out/lib/ld-linux*.so.? --set-rpath $out/lib $i || true @@ -57,18 +60,26 @@ rec { createDeviceNodes = dev: '' - mknod ${dev}/null c 1 3 - mknod ${dev}/zero c 1 5 - mknod ${dev}/random c 1 8 - mknod ${dev}/urandom c 1 9 - mknod ${dev}/tty c 5 0 - . /sys/class/block/${hd}/uevent - mknod ${dev}/${hd} b $MAJOR $MINOR + for type in b c; do + for f in /sys/dev/$type*/*; do + (. $f/uevent + mkdir -p `dirname "${dev}/$DEVNAME"` + mknod ${dev}/$DEVNAME $type $MAJOR $MINOR) + done + done ''; + teardown = writeScript "vm-teardown" '' + #! ${initrdUtils}/bin/ash + echo $1 > ./tmp/xchg/in-vm-exit + mount -o remount,ro dummy . + echo DONE + halt -d -p -f + ''; - stage1Init = writeScript "vm-run-stage1" '' + stage1Init = kernel: writeScript "vm-run-stage1" '' #! ${initrdUtils}/bin/ash -e + echo START export PATH=${initrdUtils}/bin @@ -94,7 +105,7 @@ rec { esac done - for i in $(cat ${modulesClosure}/insmod-list); do + for i in $(cat ${modulesClosure kernel}/insmod-list); do args= case $i in */cifs.ko) @@ -119,18 +130,19 @@ rec { fi mkdir -p /fs/dev - mount -o bind /dev /fs/dev + mount --move /dev /fs/dev echo "mounting Nix store..." mkdir -p /fs/nix/store - mount -t cifs //10.0.2.4/store /fs/nix/store -o guest,sec=none,sec=ntlm + ${initrdUtils}/sbin/mount.cifs //10.0.2.4/store /fs/nix/store -o guest,sec=ntlm mkdir -p /fs/tmp - mount -t tmpfs -o "mode=755" none /fs/tmp + # tmpfs may be faster, but there's a tendency to run out of RAM on 32b systems + # mount -t tmpfs -o "mode=755" none /fs/tmp echo "mounting host's temporary directory..." mkdir -p /fs/tmp/xchg - mount -t cifs //10.0.2.4/xchg /fs/tmp/xchg -o guest,sec=none,sec=ntlm + ${initrdUtils}/sbin/mount.cifs //10.0.2.4/xchg /fs/tmp/xchg -o guest,sec=ntlm mkdir -p /fs/proc mount -t proc none /fs/proc @@ -141,22 +153,20 @@ rec { mkdir -p /fs/etc ln -sf /proc/mounts /fs/etc/mtab + mkdir -p /fs/run + echo "Now running: $command" test -n "$command" - set +e - chroot /fs $command $out - echo $? > /fs/tmp/xchg/in-vm-exit - - mount -o remount,ro dummy /fs - - poweroff -f + exec switch_root /fs ${bash}/bin/bash -c "cd / ; $command $out ; ${teardown} \$?" + ${teardown} $? ''; + definitrd = initrd linuxKernel; - initrd = makeInitrd { + initrd = kernel: makeInitrd { contents = [ - { object = stage1Init; + { object = stage1Init kernel; symlink = "/init"; } ]; @@ -194,7 +204,7 @@ rec { ''; - qemuCommandLinux = '' + qemuCommandLinux = kernel: '' ${kvm}/bin/qemu-kvm \ ${lib.optionalString (pkgs.stdenv.system == "x86_64-linux") "-cpu kvm64"} \ -nographic -no-reboot \ @@ -203,7 +213,7 @@ rec { -net user,guestfwd=tcp:10.0.2.4:445-chardev:samba \ -drive file=$diskImage,if=virtio,cache=writeback,werror=report \ -kernel ${kernel}/${img} \ - -initrd ${initrd}/initrd \ + -initrd ${initrd kernel}/initrd \ -append "console=ttyS0 panic=1 command=${stage2Init} out=$out mountDisk=$mountDisk" \ $QEMU_OPTS ''; @@ -328,14 +338,16 @@ rec { `run-vm' will be left behind in the temporary build directory that allows you to boot into the VM and debug it interactively. */ - runInLinuxVM = drv: lib.overrideDerivation drv (attrs: { - requiredSystemFeatures = [ "kvm" ]; - builder = "${bash}/bin/sh"; - args = ["-e" (vmRunCommand qemuCommandLinux)]; - origArgs = attrs.args; - origBuilder = attrs.builder; - QEMU_OPTS = "-m ${toString (if attrs ? memSize then attrs.memSize else 256)}"; - }); + runInLinuxVM = drv: let + kernel = if drv ? kernel then drv.kernel else nixpkgsKernel; + in lib.overrideDerivation drv (attrs: { + requiredSystemFeatures = [ "kvm" ]; + builder = "${bash}/bin/sh"; + args = ["-e" (vmRunCommand (qemuCommandLinux kernel))]; + origArgs = attrs.args; + origBuilder = attrs.builder; + QEMU_OPTS = "-m ${toString (if attrs ? memSize then attrs.memSize else 256)}"; + }); extractFs = {file, fs ? null} : @@ -478,8 +490,7 @@ rec { fillDiskWithRPMs = { size ? 4096, rpms, name, fullName, preInstall ? "", postInstall ? "" - , runScripts ? true, createRootFS ? defaultCreateRootFS - , unifiedSystemDir ? false + , runScripts ? true, createRootFS ? defaultCreateRootFS, mergeUsr ? false }: runInLinuxVM (stdenv.mkDerivation { @@ -496,23 +507,19 @@ rec { mkdir -p /mnt/nix/store ${utillinux}/bin/mount -o bind /nix/store /mnt/nix/store - # Newer distributions like Fedora 18 require /lib etc. to be - # symlinked to /usr. - ${lib.optionalString unifiedSystemDir '' - mkdir -p /mnt/usr/bin /mnt/usr/sbin /mnt/usr/lib /mnt/usr/lib64 - ln -s /usr/bin /mnt/bin - ln -s /usr/sbin /mnt/sbin - ln -s /usr/lib /mnt/lib - ln -s /usr/lib64 /mnt/lib64 - ${utillinux}/bin/mount -t proc none /mnt/proc - ''} - echo "unpacking RPMs..." for i in $rpms; do echo "$i..." ${rpm}/bin/rpm2cpio "$i" | (chroot /mnt ${cpio}/bin/cpio -i --make-directories) done + ${if mergeUsr then "true" else "false"} && for d in bin sbin lib lib64; do + test -d /mnt/$d || continue + test -L /mnt/$d && continue + find /mnt/$d/ -maxdepth 1 -mindepth 1 | xargs --no-run-if-empty mv -t /mnt/usr/$d/ + rmdir /mnt/$d + ln -Ts /usr/$d /mnt/$d + done eval "$preInstall" echo "initialising RPM DB..." @@ -560,7 +567,7 @@ rec { mkdir $TMPDIR/xchg export > $TMPDIR/xchg/saved-env mountDisk=1 - ${qemuCommandLinux} + ${qemuCommandLinux nixpkgsKernel} ''; @@ -593,21 +600,26 @@ rec { buildPhase = '' eval "$preBuild" - # Hacky: RPM looks for .spec inside the tarball, so - # strip off the hash. - stripHash "$src" - srcName="$strippedName" - cp "$src" "$srcName" # `ln' doesn't work always work: RPM requires that the file is owned by root - export HOME=/tmp/home mkdir $HOME rpmout=/tmp/rpmout - mkdir $rpmout $rpmout/SPECS $rpmout/BUILD $rpmout/RPMS $rpmout/SRPMS + mkdir $rpmout $rpmout/SPECS $rpmout/BUILD $rpmout/RPMS $rpmout/SRPMS $rpmout/SOURCES + + # Hacky: RPM looks for .spec inside the tarball; strip the hash. + stripHash "$src" + srcName="$strippedName" + # `ln' doesn't work always work: RPM requires that the file is owned by root + cp "$src" $rpmout/SOURCES/"$srcName" echo "%_topdir $rpmout" >> $HOME/.rpmmacros - rpmbuild -vv -ta "$srcName" + mkdir /tmp/build && cd /tmp/build + # this is less efficient than rpmbuild -ta but it actually works + tar xvzf "$rpmout/SOURCES/$srcName" + cd * + chown root:root -R . + rpmbuild -vv -ba *.spec eval "$postBuild" ''; @@ -738,17 +750,51 @@ rec { , packagesList ? "", packagesLists ? [packagesList] , packages, extraPackages ? [] , preInstall ? "", postInstall ? "", archs ? ["noarch" "i386"] - , runScripts ? true, createRootFS ? defaultCreateRootFS - , unifiedSystemDir ? false }: + , runScripts ? true, createRootFS ? defaultCreateRootFS, mergeUsr ? false }: fillDiskWithRPMs { - inherit name fullName size preInstall postInstall runScripts createRootFS unifiedSystemDir; + inherit name fullName size preInstall postInstall runScripts createRootFS mergeUsr; rpms = import (rpmClosureGenerator { inherit name packagesLists urlPrefixes archs; packages = packages ++ extraPackages; }) { inherit fetchurl; }; }; + rpm2kernel = rpms: stdenv.mkDerivation { + name = "rpm2kernel"; + inherit rpms; + builder = writeScript "rpm2kernel-builder" '' + source $stdenv/setup + ensureDir $out + cd $out + for r in $rpms; do + echo $r | grep "kernel-[0-9]" || continue + ${rpm}/bin/rpm2cpio $r | ${cpio}/bin/cpio -i --make-directories + done + cd $out + ln -s boot/vmlinuz* bzImage + ln -s boot/System.map* System.map + ln -s boot/config* config + cd lib/modules + ver=`echo *` + cd $ver + ${module_init_tools}/sbin/depmod -ae -F $out/System.map $ver -b $out + ''; + }; + + makeKernelFromRPMDist = + { urlPrefix ? "", urlPrefixes ? [urlPrefix] + , packagesList ? "", packagesLists ? [packagesList] + , archs ? ["noarch" "i386"] + , ...}: + + rpm2kernel ( + import (rpmClosureGenerator { + inherit packagesLists urlPrefixes archs; + name = "kernel"; + packages = "kernel"; + }) { inherit fetchurl; }); + /* Like `rpmClosureGenerator', but now for Debian/Ubuntu releases (i.e. generate a closure from a Packages.bz2 file). */ @@ -995,6 +1041,32 @@ rec { packages = commonFedoraPackages ++ [ "cronie" "util-linux" ]; }; + fedora17i386 = { + name = "fedora-17-i386"; + fullName = "Fedora 17 (i386)"; + packagesList = fetchurl { + url = mirror://fedora/linux/releases/17/Everything/i386/os/repodata/82dc1ea6d26e53a367dc6e7472113c4454c9a8ac7c98d4bfb11fd0b6f311450f-primary.xml.gz; + sha256 = "03s527rvdl0zn6zx963wmjlcjm247h8p4x3fviks6lvfsak1xp42"; + }; + urlPrefix = mirror://fedora/linux/releases/17/Everything/i386/os; + archs = ["noarch" "i386" "i586" "i686"]; + packages = commonFedoraPackages ++ [ "cronie" "util-linux" ]; + mergeUsr = true; + }; + + fedora17x86_64 = { + name = "fedora-17-x86_64"; + fullName = "Fedora 17 (x86_64)"; + packagesList = fetchurl { + url = mirror://fedora/linux/releases/17/Everything/x86_64/os/repodata/7009de56f1a1c399930fa72094a310a40d38153c96d0b5af443914d3d6a7d811-primary.xml.gz; + sha256 = "04fqlzbd651r8jpvbl4n7hakh3d422ir88571y9rkhx1y5bdw2bh"; + }; + urlPrefix = mirror://fedora/linux/releases/17/Everything/x86_64/os; + archs = ["noarch" "x86_64"]; + packages = commonFedoraPackages ++ [ "cronie" "util-linux" ]; + mergeUsr = true; + }; + fedora18i386 = { name = "fedora-18-i386"; fullName = "Fedora 18 (i386)"; @@ -1005,7 +1077,7 @@ rec { urlPrefix = mirror://fedora/linux/releases/18/Everything/i386/os; archs = ["noarch" "i386" "i586" "i686"]; packages = commonFedoraPackages ++ [ "cronie" "util-linux" ]; - unifiedSystemDir = true; + mergeUsr = true; }; fedora18x86_64 = { @@ -1018,7 +1090,8 @@ rec { urlPrefix = mirror://fedora/linux/releases/18/Everything/x86_64/os; archs = ["noarch" "x86_64"]; packages = commonFedoraPackages ++ [ "cronie" "util-linux" ]; - unifiedSystemDir = true; + mergeUsr = true; + }; opensuse103i386 = { @@ -1507,6 +1580,7 @@ rec { "rpm-build" "tar" "unzip" + "kernel" ];