From 66a9d53e48f14d7fe1d9f4b801a1c5582d83efa6 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 3 Dec 2010 13:17:00 +0000 Subject: [PATCH] Rewrite febootstrap as a general supermin appliance building tool. This complete rewrite of the building tools turns febootstrap into a general purpose, cross-distro, supermin appliance only build tool. There is now only one program 'febootstrap' which is used to build a supermin appliance from a list of packages. Normal appliances are not supported. The tools are incompatible with febootstrap 2.x (use the febootstrap-2.x branch from git to get the old package). --- .depend | 25 +++ .gitignore | 11 +- Makefile.am | 171 ++++++----------- README | 83 +++------ TODO | 15 -- config.ml.in | 27 +++ configure.ac | 37 ++-- examples/Makefile.am | 23 --- examples/README | 10 - examples/guestfs-test.sh | 73 -------- examples/minimal-filesystem.sh | 66 ------- f10.log.gz | Bin 9196 -> 0 bytes fakechroot-2.8-relchroot.patch | 63 ------- fakechroot-2.9-cmdsubst.patch | 262 -------------------------- fakechroot-svn-no-dup-envs.patch | 38 ---- febootstrap-install.pod | 49 ----- febootstrap-install.sh | 45 ----- febootstrap-minimize.pod | 173 ----------------- febootstrap-minimize.sh | 281 ---------------------------- febootstrap-run.pod | 95 ---------- febootstrap-run.sh | 88 --------- febootstrap-to-initramfs.pod | 114 ----------- febootstrap-to-initramfs.sh | 98 ---------- febootstrap-to-supermin.pod | 206 -------------------- febootstrap-to-supermin.sh | 174 ----------------- febootstrap.ml | 394 +++++++++++++++++++++++++++++++++++++++ febootstrap.pod | 329 ++++++++++++-------------------- febootstrap.sh | 245 ------------------------ febootstrap_cmdline.ml | 82 ++++++++ febootstrap_cmdline.mli | 39 ++++ febootstrap_debian.ml | 132 +++++++++++++ febootstrap_package_handlers.ml | 79 ++++++++ febootstrap_package_handlers.mli | 65 +++++++ febootstrap_utils.ml | 145 ++++++++++++++ febootstrap_utils.mli | 73 ++++++++ febootstrap_yum_rpm.ml | 222 ++++++++++++++++++++++ helper/Makefile.am | 9 +- m4/ocaml.m4 | 240 ++++++++++++++++++++++++ 38 files changed, 1755 insertions(+), 2526 deletions(-) create mode 100644 .depend delete mode 100644 TODO create mode 100644 config.ml.in delete mode 100644 examples/Makefile.am delete mode 100644 examples/README delete mode 100755 examples/guestfs-test.sh delete mode 100755 examples/minimal-filesystem.sh delete mode 100644 f10.log.gz delete mode 100644 fakechroot-2.8-relchroot.patch delete mode 100644 fakechroot-2.9-cmdsubst.patch delete mode 100644 fakechroot-svn-no-dup-envs.patch delete mode 100644 febootstrap-install.pod delete mode 100755 febootstrap-install.sh delete mode 100644 febootstrap-minimize.pod delete mode 100755 febootstrap-minimize.sh delete mode 100644 febootstrap-run.pod delete mode 100755 febootstrap-run.sh delete mode 100644 febootstrap-to-initramfs.pod delete mode 100755 febootstrap-to-initramfs.sh delete mode 100644 febootstrap-to-supermin.pod delete mode 100755 febootstrap-to-supermin.sh create mode 100644 febootstrap.ml delete mode 100755 febootstrap.sh create mode 100644 febootstrap_cmdline.ml create mode 100644 febootstrap_cmdline.mli create mode 100644 febootstrap_debian.ml create mode 100644 febootstrap_package_handlers.ml create mode 100644 febootstrap_package_handlers.mli create mode 100644 febootstrap_utils.ml create mode 100644 febootstrap_utils.mli create mode 100644 febootstrap_yum_rpm.ml create mode 100644 m4/ocaml.m4 diff --git a/.depend b/.depend new file mode 100644 index 0000000..9f90bab --- /dev/null +++ b/.depend @@ -0,0 +1,25 @@ +config.cmo: +config.cmx: +febootstrap_utils.cmi: +febootstrap_utils.cmo: febootstrap_utils.cmi +febootstrap_utils.cmx: febootstrap_utils.cmi +febootstrap_cmdline.cmi: +febootstrap_cmdline.cmo: config.cmo febootstrap_cmdline.cmi +febootstrap_cmdline.cmx: config.cmx febootstrap_cmdline.cmi +febootstrap_package_handlers.cmi: +febootstrap_package_handlers.cmo: febootstrap_utils.cmi \ + febootstrap_cmdline.cmi febootstrap_package_handlers.cmi +febootstrap_package_handlers.cmx: febootstrap_utils.cmx \ + febootstrap_cmdline.cmx febootstrap_package_handlers.cmi +febootstrap_yum_rpm.cmo: febootstrap_utils.cmi \ + febootstrap_package_handlers.cmi febootstrap_cmdline.cmi config.cmo +febootstrap_yum_rpm.cmx: febootstrap_utils.cmx \ + febootstrap_package_handlers.cmx febootstrap_cmdline.cmx config.cmx +febootstrap_debian.cmo: febootstrap_utils.cmi \ + febootstrap_package_handlers.cmi febootstrap_cmdline.cmi config.cmo +febootstrap_debian.cmx: febootstrap_utils.cmx \ + febootstrap_package_handlers.cmx febootstrap_cmdline.cmx config.cmx +febootstrap.cmo: febootstrap_utils.cmi febootstrap_package_handlers.cmi \ + febootstrap_cmdline.cmi config.cmo +febootstrap.cmx: febootstrap_utils.cmx febootstrap_package_handlers.cmx \ + febootstrap_cmdline.cmx config.cmx diff --git a/.gitignore b/.gitignore index 22e1175..b8a4aea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ *~ +*.cmi +*.cmo +*.cmx *.o *.a .deps @@ -13,21 +16,17 @@ config.guess config.h.in config.h config.log +config.ml config.status config.sub configure cscope.out depcomp febootstrap -febootstrap-run -febootstrap-install -febootstrap-minimize -febootstrap-to-initramfs -febootstrap-to-supermin -febootstrap-supermin-helper febootstrap*.8 febootstrap*.txt febootstrap-*.tar.gz +helper/febootstrap-supermin-helper helper/init lib/alloca.h lib/arg-nonnull.h diff --git a/Makefile.am b/Makefile.am index 02bc3f3..3dcbe1f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,141 +19,78 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = lib helper examples - -bin_SCRIPTS = \ - febootstrap \ - febootstrap-run \ - febootstrap-install \ - febootstrap-minimize \ - febootstrap-to-initramfs \ - febootstrap-to-supermin -DISTCLEANFILES = $(bin_SCRIPTS) - -febootstrap: febootstrap.sh - rm -f $@ - cp $< $@-t - chmod 0555 $@-t - mv $@-t $@ - -febootstrap-run: febootstrap-run.sh - rm -f $@ - cp $< $@-t - chmod 0555 $@-t - mv $@-t $@ - -febootstrap-install: febootstrap-install.sh - rm -f $@ - cp $< $@-t - chmod 0555 $@-t - mv $@-t $@ - -febootstrap-minimize: febootstrap-minimize.sh - rm -f $@ - cp $< $@-t - chmod 0555 $@-t - mv $@-t $@ - -febootstrap-to-initramfs: febootstrap-to-initramfs.sh - rm -f $@ - cp $< $@-t - chmod 0555 $@-t - mv $@-t $@ +SUBDIRS = lib helper + +# Note these must be in build dependency order. +SOURCES = \ + config.ml \ + febootstrap_utils.mli \ + febootstrap_utils.ml \ + febootstrap_cmdline.mli \ + febootstrap_cmdline.ml \ + febootstrap_package_handlers.mli \ + febootstrap_package_handlers.ml \ + febootstrap_yum_rpm.ml \ + febootstrap_debian.ml \ + febootstrap.ml + +CLEANFILES = *~ *.cmi *.cmo *.cmx *.o febootstrap -febootstrap-to-supermin: febootstrap-to-supermin.sh - rm -f $@ - cp $< $@-t - chmod 0555 $@-t - mv $@-t $@ +EXTRA_DIST = \ + .gitignore \ + .gitmodules \ + autogen.sh \ + febootstrap.8 \ + febootstrap.pod \ + m4/gnulib-cache.m4 \ + $(SOURCES) man_MANS = \ - febootstrap.8 \ - febootstrap-run.8 \ - febootstrap-install.8 \ - febootstrap-minimize.8 \ - febootstrap-to-initramfs.8 \ - febootstrap-to-supermin.8 + febootstrap.8 -if HAVE_PERLDOC +bin_SCRIPTS = febootstrap -febootstrap.8: febootstrap.pod - pod2man \ - --section 8 \ - -c "Virtualization Support" \ - --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ - $< > $@ +SOURCES_ML = $(filter %.ml,$(SOURCES)) +BOBJECTS = $(SOURCES_ML:.ml=.cmo) +XOBJECTS = $(SOURCES_ML:.ml=.cmx) -febootstrap.txt: febootstrap.pod - pod2text $< > $@ +if !HAVE_OCAMLOPT +OBJECTS = $(BOBJECTS) +else +OBJECTS = $(XOBJECTS) +endif -febootstrap-run.8: febootstrap-run.pod - pod2man \ - --section 8 \ - -c "Virtualization Support" \ - --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ - $< > $@ +OCAMLPACKAGES = -package unix,str +OCAMLFLAGS = -warn-error CDEFLMPSUVXYZ -febootstrap-run.txt: febootstrap-run.pod - pod2text $< > $@ +febootstrap: $(OBJECTS) + $(OCAMLFIND) $(OCAMLBEST) $(OCAMLFLAGS) $(OCAMLPACKAGES) -linkpkg \ + $^ -o $@ -febootstrap-install.8: febootstrap-install.pod - pod2man \ - --section 8 \ - -c "Virtualization Support" \ - --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ - $< > $@ +.mli.cmi: + $(OCAMLFIND) ocamlc $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@ +.ml.cmo: + $(OCAMLFIND) ocamlc $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@ +.ml.cmx: + $(OCAMLFIND) ocamlopt $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@ -febootstrap-install.txt: febootstrap-install.pod - pod2text $< > $@ +depend: .depend -febootstrap-minimize.8: febootstrap-minimize.pod - pod2man \ - --section 8 \ - -c "Virtualization Support" \ - --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ - $< > $@ +.depend: $(SOURCES) + rm -f $@ $@-t + $(OCAMLFIND) ocamldep $^ > $@-t + mv $@-t $@ -febootstrap-minimize.txt: febootstrap-minimize.pod - pod2text $< > $@ +include .depend -febootstrap-to-initramfs.8: febootstrap-to-initramfs.pod - pod2man \ - --section 8 \ - -c "Virtualization Support" \ - --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ - $< > $@ +SUFFIXES = .cmo .cmi .cmx .ml .mli .mll .mly -febootstrap-to-initramfs.txt: febootstrap-to-initramfs.pod - pod2text $< > $@ +if HAVE_PERLDOC -febootstrap-to-supermin.8: febootstrap-to-supermin.pod +febootstrap.8: febootstrap.pod pod2man \ --section 8 \ -c "Virtualization Support" \ --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ $< > $@ - -febootstrap-to-supermin.txt: febootstrap-to-supermin.pod - pod2text $< > $@ - endif - -EXTRA_DIST = \ - fakechroot-2.8-relchroot.patch \ - fakechroot-svn-no-dup-envs.patch \ - febootstrap.8 febootstrap.txt febootstrap.pod \ - febootstrap.sh \ - febootstrap-run.8 febootstrap-run.txt febootstrap-run.pod \ - febootstrap-run.sh \ - febootstrap-install.8 febootstrap-install.txt febootstrap-install.pod \ - febootstrap-install.sh \ - febootstrap-minimize.8 febootstrap-minimize.txt \ - febootstrap-minimize.pod \ - febootstrap-minimize.sh \ - febootstrap-to-initramfs.8 febootstrap-to-initramfs.txt \ - febootstrap-to-initramfs.pod \ - febootstrap-to-initramfs.sh \ - febootstrap-to-supermin.8 febootstrap-to-supermin.txt \ - febootstrap-to-supermin.pod \ - febootstrap-to-supermin.sh \ - m4/gnulib-cache.m4 diff --git a/README b/README index 5383dcb..ee28067 100644 --- a/README +++ b/README @@ -1,32 +1,29 @@ -febootstrap - Bootstrap a basic Fedora system +febootstrap - Bootstrapping tool for creating supermin appliances by Richard W.M. Jones (rjones@redhat.com) http://people.redhat.com/~rjones/febootstrap ---------------------------------------------------------------------- -febootstrap is a Fedora equivalent to Debian's debootstrap. You can -use it to create a basic Fedora filesystem. +febootstrap is a tool for building supermin appliances. These are +tiny appliances [similar to virtual machines], usually around 100KB in +size, which get fully instantiated on-the-fly in a fraction of a +second when you need to boot one of them. -There are currently some restrictions compared to debootstrap. +A complete description is in the febootstrap(8) man page. -For instructions, restrictions, examples etc. please read the manpage -febootstrap(8). +IMPORTANT NOTE FOR USERS OF FEBOOTSTRAP 2.x: + febootstrap 3.x is a complete rewrite. febootstrap 2.x could only + build Fedora distributions. This version can build many varieties + of Linux distros. 3.x only builds supermin appliances, it does not + build chroots. 3.x does not build cross-distro, cross-release or + cross-architecture systems. If you want febootstrap 2.x, please use + the 'febootstrap-2.x' branch from the git repository. Requirements ------------ - fakeroot - - Tested with version 1.11. + ocaml - fakechroot >= 2.9 or 2.8 + patch - - **** NB. KNOWN NOT TO WORK WITH 2.8 ***** You MUST apply - the patch 'fakechroot-2.8-relchroot.patch' to the fakechroot - sources and recompile. Hopefully this patch will be included - in future versions of fakechroot. - - yum - - Tested with version 3.2 (works best with 3.2.21 or above) - - Needs network access to a Fedora repository, or a local - Fedora mirror. + ocaml findlib ("ocamlfind" program) perldoc - This is just used to generate the manpage. @@ -36,12 +33,21 @@ Requirements gcc qemu - - If you want to test-run your systems. + - Only if you need to test-boot appliances. libext2fs /sbin/mke2fs - These are part of e2fsprogs. +Optional +-------- +(but you will need a package manager for your Linux distro) + + yum + rpm + apt-get + dpkg + Building and installing ----------------------- @@ -49,42 +55,9 @@ Building and installing make sudo make install -Note, if you want to run the scripts locally without installing, -you have to set the $PATH to the current directory, ie: - - PATH=$(pwd):$PATH - febootstrap [...] - -Debugging ---------- - -If you get segfaults while running febootstrap or errors in the %post -scripts, these are often caused by some incompatibility in the -emulation provided by fakeroot/fakechroot. You can track them down by -running the yum command explicitly. Try: - - fakeroot fakechroot -s \ - yum -y -c /tmp/repo \ - --disablerepo=\* --enablerepo=febootstrap \ - --noplugins --nogpgcheck \ - --installroot=/tmp/root \ - install "@Core" - -where /tmp/repo would be a file like this (change repo and arch -parameters as appropriate): - - [febootstrap] - name=febootstrap - failovermethod=priority - enabled=1 - gpgcheck=0 - mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=rawhide&arch=x86_64 - -You can insert gdb in the appropriate place in the fakeroot / -fakechroot / yum command. - Feedback and bugs ----------------- -Send feedback to rjones@redhat.com. You can file bugs in -http://bugzilla.redhat.com/ +Send feedback to libguestfs@redhat.com. You can file bugs in +https://bugzilla.redhat.com/ (under "Fedora", "febootstrap") + diff --git a/TODO b/TODO deleted file mode 100644 index 901e607..0000000 --- a/TODO +++ /dev/null @@ -1,15 +0,0 @@ -- More files in the root, eg: fstab, mtab, resolv.conf - -- Configurable stuff in the febootstrap repo, eg. proxies, extra repos - -- Update to latest fakechroot release - -- 32-on-64 support in fakechroot/fakeroot - -- febootstrap on Debian etc (to bootstrap Fedora on Debian of course) - - - -For more to-do ideas, see: - -http://rwmj.wordpress.com/2009/03/19/febootstrap-fedora-equivalent-of-debootstrap/#comments diff --git a/config.ml.in b/config.ml.in new file mode 100644 index 0000000..ebda655 --- /dev/null +++ b/config.ml.in @@ -0,0 +1,27 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * @configure_input@ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +let package_name = "@PACKAGE_NAME@" +let package_version = "@PACKAGE_VERSION@" +let yum = "@YUM@" +let rpm = "@RPM@" +let yumdownloader = "@YUMDOWNLOADER@" +let aptitude = "@APTITUDE@" +let dpkg = "@DPKG@" +let host_cpu = "@host_cpu@" diff --git a/configure.ac b/configure.ac index 509db2c..d1b334d 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. dnl dnl Written by Richard W.M. Jones -AC_INIT(febootstrap,2.11) +AC_INIT(febootstrap,3.0) AM_INIT_AUTOMAKE dnl Check for basic C environment. @@ -37,27 +37,34 @@ AC_SYS_LARGEFILE gl_INIT +# OCaml and ocamlfind are required to compile. +AC_PROG_OCAML +if test "$OCAMLC" = "no"; then + AC_MSG_ERROR([You must install the OCaml compiler]) +fi +AM_CONDITIONAL([HAVE_OCAMLOPT],[test "$OCAMLBEST" = "opt"]) +AC_PROG_FINDLIB +if test "$OCAMLFIND" = "no"; then + AC_MSG_ERROR([You must install OCaml findlib (the ocamlfind command)]) +fi + +dnl Optional programs. AC_CHECK_PROG(PERLDOC,[perldoc],[perldoc],[no]) if test "x$PERLDOC" = "xno" ; then AC_MSG_WARN([perldoc not found - install perl to make man pages]) fi AM_CONDITIONAL(HAVE_PERLDOC,[test "$perldoc" != "no"]) -AC_CHECK_PROG(FAKEROOT,[fakeroot],[fakeroot],[no]) -if test "x$FAKEROOT" = "xno" ; then - AC_MSG_FAILURE([fakeroot program not found]) -fi - -AC_CHECK_PROG(FAKECHROOT,[fakechroot],[fakechroot],[no]) -if test "x$FAKECHROOT" = "xno" ; then - AC_MSG_FAILURE([fakechroot program not found]) -fi - +dnl For yum-rpm handler. AC_CHECK_PROG(YUM,[yum],[yum],[no]) -if test "x$YUM" = "xno" ; then - AC_MSG_FAILURE([yum program not found]) -fi +AC_CHECK_PROG(RPM,[rpm],[rpm],[no]) +AC_CHECK_PROG(YUMDOWNLOADER,[yumdownloader],[yumdownloader],[no]) + +dnl For Debian handler. +AC_CHECK_PROG(APTITUDE,[aptitude],[aptitude],[no]) +AC_CHECK_PROG(DPKG,[dpkg],[dpkg],[no]) +dnl Required e2fsprogs, libs. AC_PATH_PROG([MKE2FS],[mke2fs],[no]) if test "x$MKE2FS" = "xno" ; then AC_MSG_FAILURE([mke2fs program not found (is /sbin in your current path?)]) @@ -82,5 +89,5 @@ AC_CHECK_HEADER([ext2fs/ext2fs.h],[],[ ]) AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_FILES([Makefile lib/Makefile helper/Makefile examples/Makefile]) +AC_CONFIG_FILES([config.ml Makefile lib/Makefile helper/Makefile]) AC_OUTPUT diff --git a/examples/Makefile.am b/examples/Makefile.am deleted file mode 100644 index 08fb42b..0000000 --- a/examples/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# febootstrap Makefile.am -# (C) Copyright 2009 Red Hat Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Written by Richard W.M. Jones - -EXTRA_DIST = \ - README \ - minimal-filesystem.sh \ - guestfs-test.sh diff --git a/examples/README b/examples/README deleted file mode 100644 index c52e7b0..0000000 --- a/examples/README +++ /dev/null @@ -1,10 +0,0 @@ -You should read and edit these scripts before running them! - -You don't need to be root, in fact, you *shouldn't* be root -when running these scripts! - -If you want to run the scripts without installing febootstrap, -then you need to make your $PATH point to the top build -directory, eg: - - PATH=$(pwd)/..:$PATH diff --git a/examples/guestfs-test.sh b/examples/guestfs-test.sh deleted file mode 100755 index f253969..0000000 --- a/examples/guestfs-test.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/sh - - -# Before running, make sure 'vmlinuz' in this examples directory is a -# bootable Linux kernel or a symlink to one. You can just use any -# kernel out of the /boot directory for this. -# -# eg: -# cd examples -# ln -s /boot/vmlinuz-NNN vmlinuz -# -# Also make 'guest-image' be a symlink to a virtual machine disk image. - -# This is a realistic example for 'libguestfs', which contains a -# selection of command-line tools, LVM, NTFS and an NFS server. - -set -e - -if [ $(id -u) -eq 0 ]; then - echo "Don't run this script as root. Read instructions in script first." - exit 1 -fi - -if [ ! -e vmlinuz -o ! -e guest-image ]; then - echo "Read instructions in script first." - exit 1 -fi - -febootstrap \ - -i bash \ - -i coreutils \ - -i lvm2 \ - -i ntfs-3g \ - -i nfs-utils \ - -i util-linux-ng \ - -i MAKEDEV \ - fedora-10 ./guestfs $1 - -echo -n "Before minimization: "; du -sh guestfs -febootstrap-minimize --all ./guestfs -echo -n "After minimization: "; du -sh guestfs - -# Create the /init which will scan for and enable all LVM volume groups. - -create_init () -{ - cat > /init <<'__EOF__' -#!/bin/sh -PATH=/sbin:/usr/sbin:$PATH -MAKEDEV mem null port zero core full ram tty console fd \ - hda hdb hdc hdd sda sdb sdc sdd loop sd -mount -t proc /proc /proc -mount -t sysfs /sys /sys -mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts -modprobe sata_nv pata_acpi ata_generic -lvm vgscan --ignorelockingfailure -lvm vgchange -ay --ignorelockingfailure -/bin/bash -i -__EOF__ - chmod +x init -} -export -f create_init -febootstrap-run ./guestfs -- bash -c create_init - -# Convert the filesystem to an initrd image. - -febootstrap-to-initramfs ./guestfs > guestfs-initrd.img - -# Now run qemu to boot this guestfs system. - -qemu-system-$(arch) \ - -m 256 \ - -kernel vmlinuz -initrd guestfs-initrd.img \ - -hda guest-image -boot c diff --git a/examples/minimal-filesystem.sh b/examples/minimal-filesystem.sh deleted file mode 100755 index e1766a9..0000000 --- a/examples/minimal-filesystem.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh - - -# Before running, make sure 'vmlinuz' in this examples directory is a -# bootable Linux kernel or a symlink to one. You can just use any -# kernel out of the /boot directory for this. -# -# eg: -# cd examples -# ln -s /boot/vmlinuz-NNN vmlinuz - -# This creates a very minimal filesystem, just containing bash and a -# few command line utilities. One of the joys of Fedora is that even -# this minimal install is still 200 MB ... - -set -e - -if [ $(id -u) -eq 0 ]; then - echo "Don't run this script as root. Read instructions in script first." - exit 1 -fi - -if [ ! -e vmlinuz ]; then - echo "Read instructions in script first." - exit 1 -fi - -febootstrap -i bash -i coreutils fedora-10 ./minimal $1 - -# ... but let's minimize it aggressively. - -echo -n "Before minimization: "; du -sh minimal -febootstrap-minimize --all --pack-executables ./minimal -echo -n "After minimization: "; du -sh minimal - -# Create the /init which is just a simple script to give users an -# interactive shell. - -create_init () -{ - cat > /init <<'__EOF__' -#!/bin/sh -echo; echo; echo -echo "Welcome to the minimal filesystem example" -echo; echo; echo -/bin/bash -i -__EOF__ - chmod +x /init -} -export -f create_init -febootstrap-run ./minimal -- bash -c create_init - -# Convert the filesystem to an initrd image. - -febootstrap-to-initramfs ./minimal > minimal-initrd.img - -# This is needed because of crappiness with qemu. - -rm -f zero -dd if=/dev/zero of=zero bs=2048 count=1 - -# Now run qemu to boot this minimal system. - -qemu-system-$(arch) \ - -m 256 \ - -kernel vmlinuz -initrd minimal-initrd.img \ - -hda zero -boot c diff --git a/f10.log.gz b/f10.log.gz deleted file mode 100644 index 3acdd494ff45935660ca6f44e4e2fc069f7eb31c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9196 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 diff --git a/fakechroot-2.8-relchroot.patch b/fakechroot-2.8-relchroot.patch deleted file mode 100644 index 4d2b093..0000000 --- a/fakechroot-2.8-relchroot.patch +++ /dev/null @@ -1,63 +0,0 @@ -This patch must be applied to fakechroot 2.8 or SVN in order to -enable correct handling of relative chroots, for rpm and yum. - -Note this patch has been included in upstream fakechroot >= 2.9 - -Index: src/libfakechroot.c -=================================================================== ---- src/libfakechroot.c (revision 311) -+++ src/libfakechroot.c (working copy) -@@ -1147,7 +1147,7 @@ - { - char *ptr, *ld_library_path, *tmp, *fakechroot_path; - int status, len; -- char dir[FAKECHROOT_MAXPATH], cwd[FAKECHROOT_MAXPATH], full_path[FAKECHROOT_MAXPATH]; -+ char dir[FAKECHROOT_MAXPATH], cwd[FAKECHROOT_MAXPATH]; - #if !defined(HAVE_SETENV) - char *envbuf; - #endif -@@ -1162,7 +1162,9 @@ - return -1; - } - if (*path != '/') { -- if (getcwd(cwd, FAKECHROOT_MAXPATH) == NULL) { -+ if (next_getcwd == NULL) fakechroot_init(); -+ -+ if (next_getcwd(cwd, FAKECHROOT_MAXPATH) == NULL) { - errno = ENAMETOOLONG; - return -1; - } -@@ -1171,24 +1173,22 @@ - return -1; - } - if (strcmp(cwd, "/") == 0) { -- snprintf(full_path, FAKECHROOT_MAXPATH, "/%s", path); -+ snprintf(dir, FAKECHROOT_MAXPATH, "/%s", path); - } - else { -- snprintf(full_path, FAKECHROOT_MAXPATH, "%s/%s", cwd, path); -+ snprintf(dir, FAKECHROOT_MAXPATH, "%s/%s", cwd, path); - } - } - else { -- snprintf(full_path, FAKECHROOT_MAXPATH, "%s", path); -- } -+ fakechroot_path = getenv("FAKECHROOT_BASE"); - -- fakechroot_path = getenv("FAKECHROOT_BASE"); -- -- if (fakechroot_path != NULL) { -- snprintf(dir, FAKECHROOT_MAXPATH, "%s%s", fakechroot_path, full_path); -+ if (fakechroot_path != NULL) { -+ snprintf(dir, FAKECHROOT_MAXPATH, "%s%s", fakechroot_path, path); -+ } -+ else { -+ snprintf(dir, FAKECHROOT_MAXPATH, "%s", path); -+ } - } -- else { -- snprintf(dir, FAKECHROOT_MAXPATH, "%s", full_path); -- } - - #if defined(HAVE___XSTAT) && defined(_STAT_VER) - if ((status = next___xstat(_STAT_VER, dir, &sb)) != 0) { diff --git a/fakechroot-2.9-cmdsubst.patch b/fakechroot-2.9-cmdsubst.patch deleted file mode 100644 index 0d40cd7..0000000 --- a/fakechroot-2.9-cmdsubst.patch +++ /dev/null @@ -1,262 +0,0 @@ -Index: test/cmd-subst-pwd.sh -=================================================================== ---- test/cmd-subst-pwd.sh (revision 0) -+++ test/cmd-subst-pwd.sh (revision 0) -@@ -0,0 +1,3 @@ -+#!/bin/sh -+ -+echo substituted - -Property changes on: test/cmd-subst-pwd.sh -___________________________________________________________________ -Added: svn:executable - + * - -Index: test/cmd-subst.t -=================================================================== ---- test/cmd-subst.t (revision 0) -+++ test/cmd-subst.t (revision 0) -@@ -0,0 +1,37 @@ -+#!/bin/sh -+ -+. ./tap.sh -+ -+plan 5 -+ -+rm -rf testtree -+ -+./testtree.sh testtree -+test "`cat testtree/CHROOT`" = "testtree" || not -+ok "testtree" -+ -+t=`./fakechroot.sh testtree /bin/pwd` -+test "$t" = "/" || not -+ok "fakechroot pwd is /" -+ -+export FAKECHROOT_CMD_SUBST="/bin/pwd=$(pwd)/cmd-subst-pwd.sh" -+ -+t=`./fakechroot.sh testtree /bin/pwd` -+test "$t" = "substituted" || not -+ok "fakechroot substituted pwd (1)" -+ -+export FAKECHROOT_CMD_SUBST="/no/file=foo:/bin/pwd=$(pwd)/cmd-subst-pwd.sh" -+ -+t=`./fakechroot.sh testtree /bin/pwd` -+test "$t" = "substituted" || not -+ok "fakechroot substituted pwd (2)" -+ -+export FAKECHROOT_CMD_SUBST="/no/file=foo:/other/file=bar" -+ -+t=`./fakechroot.sh testtree /bin/pwd` -+test "$t" = "/" || not -+ok "fakechroot not substituted pwd is /" -+ -+rm -rf testtree -+ -+end - -Property changes on: test/cmd-subst.t -___________________________________________________________________ -Added: svn:executable - + * - -Index: test/Makefile.am -=================================================================== ---- test/Makefile.am (revision 323) -+++ test/Makefile.am (working copy) -@@ -1,6 +1,6 @@ - SUBDIRS = src - --TESTS = chroot.t escape-nested-chroot.t pwd.t touch.t -+TESTS = chroot.t cmd-subst.t escape-nested-chroot.t pwd.t touch.t - - suffix = - -Index: src/libfakechroot.c -=================================================================== ---- src/libfakechroot.c (revision 323) -+++ src/libfakechroot.c (working copy) -@@ -1467,7 +1467,38 @@ - return execve (path, argv, environ); - } - -+/* Parse the FAKECHROOT_CMD_SUBST environment variable (the first -+ * parameter) and if there is a match with filename, return the -+ * substitution in cmd_subst. Returns non-zero if there was a match. -+ * -+ * FAKECHROOT_CMD_SUBST=cmd=subst:cmd=subst:... -+ */ -+static int -+try_cmd_subst (char *env, const char *filename, char *cmd_subst) -+{ -+ int len = strlen (filename), len2; -+ char *p; - -+ if (env == NULL) return 0; -+ -+ do { -+ p = strchrnul (env, ':'); -+ -+ if (strncmp (env, filename, len) == 0 && env[len] == '=') { -+ len2 = p - &env[len+1]; -+ if (len2 >= FAKECHROOT_MAXPATH) -+ len2 = FAKECHROOT_MAXPATH - 1; -+ strncpy (cmd_subst, &env[len+1], len2); -+ cmd_subst[len2] = '\0'; -+ return 1; -+ } -+ -+ env = p; -+ } while (*env++ != '\0'); -+ -+ return 0; -+} -+ - /* #include */ - int execve (const char *filename, char *const argv [], char *const envp[]) - { -@@ -1479,32 +1510,16 @@ - char *env; - char tmp[FAKECHROOT_MAXPATH], newfilename[FAKECHROOT_MAXPATH], argv0[FAKECHROOT_MAXPATH]; - char *ptr; -- unsigned int i, j, n, len; -+ unsigned int i, j, n, len, r, newenvppos; - size_t sizeenvp; - char c; - char *fakechroot_path, *fakechroot_ptr, fakechroot_buf[FAKECHROOT_MAXPATH]; - char *envkey[] = { "FAKECHROOT", "FAKECHROOT_BASE", - "FAKECHROOT_VERSION", "FAKECHROOT_EXCLUDE_PATH", -+ "FAKECHROOT_CMD_SUBST", - "LD_LIBRARY_PATH", "LD_PRELOAD" }; -+ const int nr_envkey = sizeof envkey / sizeof envkey[0]; - -- strncpy(argv0, filename, FAKECHROOT_MAXPATH); -- -- expand_chroot_path(filename, fakechroot_path, fakechroot_ptr, fakechroot_buf); -- strcpy(tmp, filename); -- filename = tmp; -- -- if ((file = open(filename, O_RDONLY)) == -1) { -- errno = ENOENT; -- return -1; -- } -- -- i = read(file, hashbang, FAKECHROOT_MAXPATH-2); -- close(file); -- if (i == -1) { -- errno = ENOENT; -- return -1; -- } -- - if (next_execve == NULL) fakechroot_init(); - - /* Scan envp and check its size */ -@@ -1514,39 +1529,69 @@ - } - - /* Copy envp to newenvp */ -- newenvp = malloc( sizeenvp * sizeof (char *) + sizeof(envkey) ); -+ newenvp = malloc( (sizeenvp + 1) * sizeof (char *) ); - if (newenvp == NULL) { - errno = ENOMEM; - return -1; - } -- for (ep = envp, i = 0; *ep != NULL; ++ep) { -- for (j = 0; j < sizeof (envkey) / sizeof (char *); j++) { -+ for (ep = envp, newenvppos = 0; *ep != NULL; ++ep) { -+ for (j = 0; j < nr_envkey; j++) { - len = strlen (envkey[j]); - if (strncmp (*ep, envkey[j], len) == 0 && (*ep)[len] == '=') - goto skip; - } -- newenvp[i] = *ep; -- i++; -+ newenvp[newenvppos] = *ep; -+ newenvppos++; - skip: ; - } -+ newenvp[newenvppos] = NULL; - -+ strncpy(argv0, filename, FAKECHROOT_MAXPATH); -+ -+ r = try_cmd_subst (getenv ("FAKECHROOT_CMD_SUBST"), filename, tmp); -+ if (r) { -+ filename = tmp; -+ -+ /* FAKECHROOT_CMD_SUBST escapes the chroot. newenvp here does -+ * not contain LD_PRELOAD and the other special environment -+ * variables. -+ */ -+ return next_execve(filename, argv, newenvp); -+ } -+ -+ expand_chroot_path(filename, fakechroot_path, fakechroot_ptr, fakechroot_buf); -+ strcpy(tmp, filename); -+ filename = tmp; -+ -+ if ((file = open(filename, O_RDONLY)) == -1) { -+ errno = ENOENT; -+ return -1; -+ } -+ -+ i = read(file, hashbang, FAKECHROOT_MAXPATH-2); -+ close(file); -+ if (i == -1) { -+ errno = ENOENT; -+ return -1; -+ } -+ - /* Add our variables to newenvp */ -- newenvp = realloc( newenvp, i * sizeof(char *) + sizeof(envkey) ); -+ newenvp = realloc( newenvp, (newenvppos + nr_envkey + 1) * sizeof(char *) ); - if (newenvp == NULL) { - errno = ENOMEM; - return -1; - } -- for (j = 0; j < sizeof(envkey) / sizeof(char *); j++) { -+ for (j = 0; j < nr_envkey; j++) { - env = getenv(envkey[j]); - if (env != NULL) { -- newenvp[i] = malloc(strlen(envkey[j]) + strlen(env) + 3); -- strcpy(newenvp[i], envkey[j]); -- strcat(newenvp[i], "="); -- strcat(newenvp[i], env); -- i++; -+ newenvp[newenvppos] = malloc(strlen(envkey[j]) + strlen(env) + 3); -+ strcpy(newenvp[newenvppos], envkey[j]); -+ strcat(newenvp[newenvppos], "="); -+ strcat(newenvp[newenvppos], env); -+ newenvppos++; - } - } -- newenvp[i] = NULL; -+ newenvp[newenvppos] = NULL; - - /* No hashbang in argv */ - if (hashbang[0] != '#' || hashbang[1] != '!') -Index: man/fakechroot.pod -=================================================================== ---- man/fakechroot.pod (revision 323) -+++ man/fakechroot.pod (working copy) -@@ -139,6 +139,21 @@ - The list of directories which are excluded from being chrooted. The elements - of list are separated with colon. - -+=item B -+ -+A list of command substitutions. If a program tries to execute one of -+the commands given (path relative to the chroot) then the substitute -+command runs instead (path to substitute command is not chrooted). -+ -+For example: -+ -+ FAKECHROOT_CMD_SUBST=/sbin/ldconfig=/tmp/ldconfig-wrapper -+ -+will substitute C for C. -+ -+Give as many substitute commands as you want, separated by C<:> -+(colon) characters. -+ - =item B, B - - Fakechroot is implemented by wrapping system calls. This is accomplished by diff --git a/fakechroot-svn-no-dup-envs.patch b/fakechroot-svn-no-dup-envs.patch deleted file mode 100644 index 87f8e6f..0000000 --- a/fakechroot-svn-no-dup-envs.patch +++ /dev/null @@ -1,38 +0,0 @@ -Note, this patch has been included in upstream fakechroot >= 2.9 - -Index: src/libfakechroot.c -=================================================================== ---- src/libfakechroot.c (revision 311) -+++ src/libfakechroot.c (working copy) -@@ -1479,7 +1479,7 @@ - char *env; - char tmp[FAKECHROOT_MAXPATH], newfilename[FAKECHROOT_MAXPATH], argv0[FAKECHROOT_MAXPATH]; - char *ptr; -- unsigned int i, j, n; -+ unsigned int i, j, n, len; - size_t sizeenvp; - char c; - char *fakechroot_path, *fakechroot_ptr, fakechroot_buf[FAKECHROOT_MAXPATH]; -@@ -1519,12 +1519,19 @@ - errno = ENOMEM; - return -1; - } -- for (ep = envp, i = 0; *ep != NULL; ++ep, ++i) { -- newenvp[i] = *ep; -+ for (ep = envp, i = 0; *ep != NULL; ++ep) { -+ for (j = 0; j < sizeof (envkey) / sizeof (char *); j++) { -+ len = strlen (envkey[j]); -+ if (strncmp (*ep, envkey[j], len) == 0 && (*ep)[len] == '=') -+ goto skip; -+ } -+ newenvp[i] = *ep; -+ i++; -+ skip: ; - } - - /* Add our variables to newenvp */ -- newenvp = realloc( newenvp, ((sizeenvp + 1) * sizeof(char *) + sizeof(envkey)) ); -+ newenvp = realloc( newenvp, i * sizeof(char *) + sizeof(envkey) ); - if (newenvp == NULL) { - errno = ENOMEM; - return -1; diff --git a/febootstrap-install.pod b/febootstrap-install.pod deleted file mode 100644 index 5035fee..0000000 --- a/febootstrap-install.pod +++ /dev/null @@ -1,49 +0,0 @@ -=head1 NAME - -febootstrap-install - Install a file in an febootstrap root filesystem - -=head1 SYNOPSIS - - febootstrap-install ROOT LOCALFILE TARGETPATH MODE OWNER[.GROUP] - -=head1 DESCRIPTION - -This can be used to safely install a new file in an febootstrap -root filesystem. - -Just copying a file in isn't usually safe, for reasons which are to do -with the L command. - -=head1 EXAMPLE - - febootstrap-install initramfs new-fstab /etc/fstab ugo=rw root.root - -=head1 SEE ALSO - -L, -L, -L, -L. - -=head1 AUTHORS - -Richard W.M. Jones - -=head1 COPYRIGHT - -(C) Copyright 2009 Red Hat Inc., -L. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/febootstrap-install.sh b/febootstrap-install.sh deleted file mode 100755 index 76b99b7..0000000 --- a/febootstrap-install.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# febootstrap-install -# (C) Copyright 2009 Red Hat Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Written by Richard W.M. Jones - -unset CDPATH - -usage () -{ - echo "Usage: febootstrap-install ROOT LOCALFILE TARGETPATH MODE OWNER[.GROUP]" - echo "Please read febootstrap-install(8) man page for more information." -} - -if [ $# != 5 ]; then - usage - exit 1 -fi - -set -e - -# This is a carefully chosen sequence of commands which -# tries not to disturb any inode numbers apart from the -# one for the new file. -cp "$2" "$1"/"$3" -ino=$(ls -i "$1"/"$3" | awk '{print $1}') -cp "$1"/fakeroot.log "$1"/fakeroot.log.old -grep -v "ino=$ino," "$1"/fakeroot.log.old > "$1"/fakeroot.log -rm "$1"/fakeroot.log.old -febootstrap-run "$1" -- chmod "$4" "$3" -febootstrap-run "$1" -- chown "$5" "$3" diff --git a/febootstrap-minimize.pod b/febootstrap-minimize.pod deleted file mode 100644 index 4665d87..0000000 --- a/febootstrap-minimize.pod +++ /dev/null @@ -1,173 +0,0 @@ -=head1 NAME - -febootstrap-minimize - Minimize an febootstrap image - -=head1 SYNOPSIS - - febootstrap-minimize [--options] DIR - -=head1 DESCRIPTION - -I minimizes an L-created -filesystem. This means that unneeded files and cruft are removed from -the image. - -If no options are given, the default is to minimize the image as much -as possible. This means, for example, that locales are removed so the -image will only be usable in US-English, there will be no -documentation or manual pages, and the image will only work in a UTC -timezone. - -Note that image minimization involves deleting files that have been -installed by RPM. Thus after minimization, it is no longer guaranteed -that RPM will function correctly on the image. You should only do -this as a final step for "throwaway" appliances that do not need to be -modified or upgraded in future. - -=head1 OPTIONS - -=over 4 - -=item B<--all> - -Perform all minimization operations, to produce the smallest possible -image. Note in particular that locales are discarded. - -You can perform all minimization operations I X, Y and Z by -doing: - - febootstrap-minimize --all --keep-X --keep-Y --keep-Z ... - -(C<--all> can be omitted since it is the default). - -=item B<--none> - -Start with no minimization operations. You can specify I -minimization operations X, Y and Z like this: - - febootstrap-minimize --none --drop-X --drop-Y --drop-Z ... - -=item B<--keep-locales> - -=item B<--drop-locales> - -Keep or drop locale support. - -=item B<--keep-docs> - -=item B<--drop-docs> - -Keep or drop documentation, man pages and info files. - -=item B<--keep-cracklib> - -=item B<--drop-cracklib> - -Keep or drop cracklib libraries. - -=item B<--keep-i18n> - -=item B<--drop-i18n> - -Keep or drop C. - -=item B<--keep-zoneinfo> - -=item B<--drop-zoneinfo> - -Keep or drop all timezones (except UTC which is never deleted). - -=item B<--keep-rpmdb> - -=item B<--drop-rpmdb> - -Keep or drop the RPM and YUM package databases. Obviously RPM and YUM will be -completely non-functional if you drop these. - -=item B<--keep-yum-cache> - -=item B<--drop-yum-cache> - -Keep or drop the yum cache. Note that L has already -deleted this directory unless you ran it with the C<--no-clean> -option. - -=item B<--keep-services> - -=item B<--drop-services> - -Keep or drop the C file. If dropped, this file is -replaced with a very minimal one which just lists the most common -services. For less common services you will have to refer to them by -port number instead of name. - -=item B<--keep-sln> - -=item B<--drop-sln> - -Keep or drop C (statically linked C). This is not -really required in minimal appliances. - -=item B<--keep-ldconfig> - -=item B<--drop-ldconfig> - -Keep or drop C, C and -C (the dynamic linking cache). This is not -needed. Dynamic linking during program execution will be marginally -slower. - -=item B<--pack-executables> - -This option has been removed in febootstrap 2.5. In previous versions -it was used to pack executables using the external C program. -However it was not enabled by default and never worked very -effectively. - -=back - -=head1 TODO - -=over 4 - -=item * - -Deduplicate files with the same content (by hardlinking them). -See the program L. - -=item * - -Remove unused binaries. - -=item * - -Remove unused libraries. - -=back - -=head1 SEE ALSO - -L. - -=head1 AUTHORS - -Richard W.M. Jones - -=head1 COPYRIGHT - -(C) Copyright 2009 Red Hat Inc., -L. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/febootstrap-minimize.sh b/febootstrap-minimize.sh deleted file mode 100755 index 15782f7..0000000 --- a/febootstrap-minimize.sh +++ /dev/null @@ -1,281 +0,0 @@ -#!/bin/bash - -# febootstrap minimize -# (C) Copyright 2009 Red Hat Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Written by Richard W.M. Jones - -unset CDPATH - -TEMP=`getopt \ - -o '' \ - --long help,all,none,keep-locales,drop-locales,keep-docs,drop-docs,keep-cracklib,drop-cracklib,keep-i18n,drop-i18n,keep-zoneinfo,drop-zoneinfo,keep-rpmdb,drop-rpmdb,keep-yum-cache,drop-yum-cache,keep-services,drop-services,keep-sln,drop-sln,keep-ldconfig,drop-ldconfig \ - -n febootstrap-minimize -- "$@"` -if [ $? != 0 ]; then - echo "febootstrap-minimize: problem parsing the command line arguments" - exit 1 -fi -eval set -- "$TEMP" - -set_all () -{ - keep_locales=no - keep_docs=no - keep_cracklib=no - keep_i18n=no - keep_zoneinfo=no - keep_rpmdb=no -keep_yum_cache=no - keep_services=no - keep_sln=no - keep_ldconfig=no -} - -set_none () -{ - keep_locales=yes - keep_docs=yes - keep_cracklib=yes - keep_i18n=yes - keep_zoneinfo=yes - keep_rpmdb=yes -keep_yum_cache=yes - keep_services=yes - keep_sln=yes - keep_ldconfig=yes -} - -set_all - -usage () -{ - echo "Usage: febootstrap-minimize [--options] DIR" - echo "Please read febootstrap-minimize(8) man page for more information." -} - -while true; do - case "$1" in - --all) - set_all - shift;; - --none) - set_none - shift;; - --keep-locales) - keep_locales=yes - shift;; - --drop-locales) - keep_locales=no - shift;; - --keep-docs) - keep_docs=yes - shift;; - --drop-docs) - keep_docs=no - shift;; - --keep-cracklib) - keep_cracklib=yes - shift;; - --drop-cracklib) - keep_cracklib=no - shift;; - --keep-i18n) - keep_i18n=yes - shift;; - --drop-i18n) - keep_i18n=no - shift;; - --keep-zoneinfo) - keep_zoneinfo=yes - shift;; - --drop-zoneinfo) - keep_zoneinfo=no - shift;; - --keep-rpmdb) - keep_rpmdb=yes - shift;; - --drop-rpmdb) - keep_rpmdb=no - shift;; - --keep-yum-cache) - keep_yum_cache=yes - shift;; - --drop-yum-cache) - keep_yum_cache=no - shift;; - --keep-services) - keep_services=yes - shift;; - --drop-services) - keep_services=no - shift;; - --keep-sln) - keep_sln=yes - shift;; - --drop-sln) - keep_sln=no - shift;; - --keep-ldconfig) - keep_ldconfig=yes - shift;; - --drop-ldconfig) - keep_ldconfig=no - shift;; - --help) - usage - exit 0;; - --) - shift - break;; - *) - echo "Internal error!" - exit 1;; - esac -done - -if [ $# -lt 1 ]; then - usage - exit 1 -fi - -target="$1" - -if [ ! -d "$target" ]; then - echo "febootstrap-minimize: $target: target directory not found" - exit 1 -fi - -# Create a temporary directory, make sure it gets cleaned up at the end. -tmpdir=$(mktemp -d) -remove_tmpdir () -{ - status=$? - rm -rf "$tmpdir" && exit $status -} -trap remove_tmpdir EXIT - -#---------------------------------------------------------------------- - -# ***NOTE*** Wildcards cannot be passed to febootstrap-run. - -if [ "$keep_locales" != "yes" ]; then - febootstrap-run "$target" -- rm -rf usr/lib/locale - febootstrap-run "$target" -- rm -rf usr/share/locale - febootstrap-run "$target" -- rm -rf usr/lib/gconv usr/lib64/gconv - febootstrap-run "$target" -- rm -f usr/bin/localedef - febootstrap-run "$target" -- rm -f usr/sbin/build-locale-archive -fi - -if [ "$keep_docs" != "yes" ]; then - febootstrap-run "$target" -- rm -rf usr/share/man - febootstrap-run "$target" -- rm -rf usr/share/doc - febootstrap-run "$target" -- rm -rf usr/share/info - febootstrap-run "$target" -- rm -rf usr/share/gnome/help -fi - -if [ "$keep_cracklib" != "yes" ]; then - febootstrap-run "$target" -- rm -rf usr/share/cracklib -fi - -if [ "$keep_i18n" != "yes" ]; then - febootstrap-run "$target" -- rm -rf usr/share/i18n -fi - -if [ "$keep_zoneinfo" != "yes" ]; then - mv "$target"/usr/share/zoneinfo/{UCT,UTC,Universal,Zulu,GMT*,*.tab} \ - "$target" - febootstrap-run "$target" -- rm -rf usr/share/zoneinfo - febootstrap-run "$target" -- mkdir -p --mode=0755 usr/share/zoneinfo - mv "$target"/{UCT,UTC,Universal,Zulu,GMT*,*.tab} \ - "$target"/usr/share/zoneinfo/ -fi - -if [ "$keep_rpmdb" != "yes" ]; then - febootstrap-run "$target" -- rm -rf var/lib/rpm - febootstrap-run "$target" -- mkdir -p --mode=0755 var/lib/rpm - febootstrap-run "$target" -- rm -rf var/lib/yum - febootstrap-run "$target" -- mkdir -p --mode=0755 var/lib/yum -fi - -if [ "$keep_yum_cache" != "yes" ]; then - febootstrap-run "$target" -- rm -rf var/cache/yum - febootstrap-run "$target" -- mkdir -p --mode=0755 var/cache/yum -fi - -if [ "$keep_services" != "yes" ]; then - # NB: Overwrite the same file so that we have the same inode, - # since fakeroot tracks files by inode number. - cat > "$target"/etc/services <<'__EOF__' -tcpmux 1/tcp -tcpmux 1/udp -echo 7/tcp -echo 7/udp -discard 9/tcp sink null -discard 9/udp sink null -ftp 21/tcp -ftp 21/udp fsp fspd -ssh 22/tcp -ssh 22/udp -telnet 23/tcp -telnet 23/udp -smtp 25/tcp mail -smtp 25/udp mail -time 37/tcp timserver -time 37/udp timserver -nameserver 42/tcp name -nameserver 42/udp name -domain 53/tcp -domain 53/udp -bootps 67/tcp -bootps 67/udp -bootpc 68/tcp dhcpc -bootpc 68/udp dhcpc -tftp 69/tcp -tftp 69/udp -finger 79/tcp -finger 79/udp -http 80/tcp www www-http -http 80/udp www www-http -http 80/sctp -kerberos 88/tcp kerberos5 krb5 -kerberos 88/udp kerberos5 krb5 -pop3 110/tcp pop-3 -pop3 110/udp pop-3 -sunrpc 111/tcp portmapper rpcbind -sunrpc 111/udp portmapper rpcbind -auth 113/tcp authentication tap ident -auth 113/udp authentication tap ident -ntp 123/tcp -ntp 123/udp -imap 143/tcp imap2 -imap 143/udp imap2 -snmp 161/tcp -snmp 161/udp -snmptrap 162/tcp -snmptrap 162/udp snmp-trap -__EOF__ -fi - -if [ "$keep_sln" != "yes" ]; then - febootstrap-run "$target" -- rm -f sbin/sln -fi - -if [ "$keep_ldconfig" != "yes" ]; then - febootstrap-run "$target" -- rm -f sbin/ldconfig - febootstrap-run "$target" -- rm -f etc/ld.so.cache - febootstrap-run "$target" -- rm -rf var/cache/ldconfig - febootstrap-run "$target" -- mkdir -p --mode=0755 var/cache/ldconfig -fi diff --git a/febootstrap-run.pod b/febootstrap-run.pod deleted file mode 100644 index 0e5d1f3..0000000 --- a/febootstrap-run.pod +++ /dev/null @@ -1,95 +0,0 @@ -=head1 NAME - -febootstrap-run - Run extra commands in febootstrap root filesystem - -=head1 SYNOPSIS - - febootstrap-run [--options] DIR [--] [CMD ...] - -=head1 DESCRIPTION - -This can be used to run extra commands in the febootstrap root -filesystem. It is just a simple wrapper around the standard -C and C commands. - -If given, the C is run inside the root filesystem. The -command acts as if it was run as root and chrooted into the root -filesystem. - -If the command is omitted, then we start a shell. - -If C could contain anything starting with a C<-> character -then use C<--> to separate C parameters from the -command: - - febootstrap-run ./f10 -- ls -l - -=head1 OPTIONS - -=over 4 - -=item B<--ro> - -Usually any changes to permissions made by the command are recorded in -the C file. However if C<--ro> flag is given, then -changes to permissions are not recorded. (Note: changes to file -contents still happen). - -=back - -=head1 EXAMPLES - -Remove a directory subtree safely: - - febootstrap-run initramfs -- rm -r /etc - -(This requires that you have a compatible 'rm' command in the root). - -Another way to do complex operations from a script is to export a -function: - - #!/bin/bash - - do_stuff () - { - # complex operations inside the root - } - export -f do_stuff - febootstrap-run root -- bash -c do_stuff - -=head1 ENVIRONMENT VARIABLES - -Some L environment variables are applicable. In -particular you may want to set: - - export FAKECHROOT_EXCLUDE_PATH=/proc - -=head1 SEE ALSO - -L, -L, -L, -L. - -=head1 AUTHORS - -Richard W.M. Jones - -=head1 COPYRIGHT - -(C) Copyright 2009 Red Hat Inc., -L. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/febootstrap-run.sh b/febootstrap-run.sh deleted file mode 100755 index 6c5e9b9..0000000 --- a/febootstrap-run.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash - -# febootstrap-run -# (C) Copyright 2009 Red Hat Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Written by Richard W.M. Jones - -unset CDPATH - -TEMP=`getopt \ - -o '' \ - --long help,ro \ - -n febootstrap-run -- "$@"` -if [ $? != 0 ]; then - echo "febootstrap-run: problem parsing the command line arguments" - exit 1 -fi -eval set -- "$TEMP" - -readonly=no - -usage () -{ - echo "Usage: febootstrap-run [--options] DIR [CMD]" - echo "Please read febootstrap-run(8) man page for more information." -} - -while true; do - case "$1" in - --ro) - readonly=yes - shift;; - --help) - usage - exit 0;; - --) - shift - break;; - *) - echo "Internal error!" - exit 1;; - esac -done - -if [ $# -lt 1 ]; then - usage - exit 1 -fi - -target="$1" -shift - -if [ $(id -u) -eq 0 ]; then - chroot "$target" "$@" - exit 0 -fi - -if [ $(id -u) -ne 0 -a ! -f "$target"/fakeroot.log ]; then - echo "febootstrap-run: $target: not a root filesystem" - exit 1 -fi - -if [ "$readonly" = "no" ]; then - if [ $(id -u) -ne 0 ]; then - fakeroot -i "$target"/fakeroot.log -s "$target"/fakeroot.log \ - fakechroot -s \ - chroot "$target" "$@" - else - chroot "$target" "$@" - fi -else - fakeroot -i "$target"/fakeroot.log \ - fakechroot -s \ - chroot "$target" "$@" -fi diff --git a/febootstrap-to-initramfs.pod b/febootstrap-to-initramfs.pod deleted file mode 100644 index c3eab0a..0000000 --- a/febootstrap-to-initramfs.pod +++ /dev/null @@ -1,114 +0,0 @@ -=head1 NAME - -febootstrap-to-initramfs - Convert febootstrap root to initramfs (cpio) file. - -=head1 SYNOPSIS - - febootstrap-to-initramfs [--files=filelist] DIR > initrd.img - -=head1 DESCRIPTION - -I converts the filesystem created by -L into an initramfs image. This allows the new system -to be booted on real hardware or inside a QEMU-based virtual machine. - -An initramfs image is just a compressed cpio file, so you could -uncompress it with L and use L to convert it into -other formats. - -The permissions inside the initrd image are corrected automatically -(see the discussion of fakeroot logfile in the L -page). You do I need to run this command as root. - -=head1 OPTIONS - -=over 4 - -=item --files=filelist - -C should be a file containing a list of the files to be -added to the initramfs (one per line). Only those files are added and -any others are ignored. - -When the C<--files> option is not given, all files in C are added -to the initramfs image. - -=item --nocompress - -This prevents the initramfs image from being compressed. - -Linux can boot from uncompressed initramfs images (in fact, faster), -but they take up a lot more space on disk. - -=back - -=head1 /init - -Normal initramfs images start by executing the program or script -called C. febootstrap does not create this script, so you may -wish to, particularly for very minimal bootstraps that don't have the -normal SysVinit/upstart machinery. It's also required if the kernel -cannot find a "real" root filesystem (the root filesystem that we -built and placed in an initramfs doesn't count). - -Linux will try to run the following commands in turn, unless you -override it using the C> kernel option: - -=over 4 - -=item * - -/init - -=item * - -/sbin/init - -=item * - -/etc/init - -=item * - -/bin/init - -=item * - -/bin/sh - -=back - -=head1 MEMORY REQUIREMENTS - -Initramfs images are uncompressed by the kernel into memory. When -booting the new system you will need at least enough free RAM to store -the B filesystem plus extra to run any programs. Bear -this in mind when creating very large filesystems. - -=head1 SEE ALSO - -L, -L. - -=head1 AUTHORS - -Richard W.M. Jones - -=head1 COPYRIGHT - -(C) Copyright 2009 Red Hat Inc., -L. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/febootstrap-to-initramfs.sh b/febootstrap-to-initramfs.sh deleted file mode 100755 index dc72963..0000000 --- a/febootstrap-to-initramfs.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash - -# febootstrap-to-initramfs -# (C) Copyright 2009 Red Hat Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Written by Richard W.M. Jones - -unset CDPATH - -TEMP=`getopt \ - -o '' \ - --long files:,nocompress,help \ - -n febootstrap-to-initramfs -- "$@"` -if [ $? != 0 ]; then - echo "febootstrap-to-initramfs: problem parsing the command line arguments" - exit 1 -fi -eval set -- "$TEMP" - -compress=yes -files= - -usage () -{ - echo "Usage: febootstrap-to-initramfs [--files=filelist] [--nocompress] DIR" - echo "Please read febootstrap-to-initramfs(8) man page for more information." -} - -while true; do - case "$1" in - --files) - files=$2 - shift 2;; - --help) - usage - exit 0;; - --nocompress) - compress=no - shift;; - --) - shift - break;; - *) - echo "Internal error!" - exit 1;; - esac -done - -if [ $# -ne 1 ]; then - usage - exit 1 -fi - -cd "$1" > /dev/null - -if [ ! -f fakeroot.log -a $(id -u) -ne 0 ]; then - echo "no fakeroot.log and not running as root" - exit 1 -fi - -set -e - -( -if [ -f fakeroot.log ]; then - if [ -z "$files" ]; then - fakeroot -i fakeroot.log \ - sh -c 'find -not -name fakeroot.log -a -print0 | cpio --quiet -o -0 -H newc' - else - fakeroot -i fakeroot.log \ - sh -c 'cpio --quiet -o -H newc' < $files - fi -else - if [ -z "$files" ]; then - find -not -name fakeroot.log -a -print0 | cpio --quiet -o -0 -H newc - else - cpio --quiet -o -H newc < $files - fi -fi -) | ( -if [ "$compress" = "yes" ]; then - gzip --best -else - cat -fi -) diff --git a/febootstrap-to-supermin.pod b/febootstrap-to-supermin.pod deleted file mode 100644 index 123327c..0000000 --- a/febootstrap-to-supermin.pod +++ /dev/null @@ -1,206 +0,0 @@ -=head1 NAME - -febootstrap-to-supermin - Convert febootstrap root to supermin appliance. - -=head1 SYNOPSIS - - febootstrap-to-supermin DIR supermin.img hostfiles.txt - -=head1 DESCRIPTION - -I converts the filesystem created by -L into a supermin appliance. The term "supermin -appliance" is described in the documentation below. First you should -be familiar with L and L. - -=head1 PARAMETERS - -C is the directory created by febootstrap (ie. the output of -febootstrap and the input to this program). - -C is the name of the supermin appliance that this -program creates, and C is the name of the list of -hostfiles that this program creates. (ie. the outputs of this -program). - -=head1 SUPERMIN APPLIANCE - -A supermin appliance is a very specialized, highly minimized -appliance which can be reconstructed on-the-fly at runtime into -an ordinary (initramfs) appliance. - -The normal appliance is a self-contained Linux operating system, based -on the Fedora/RHEL/CentOS Linux distro. So it contains a complete -copy of all the libraries and programs needed, like kernel, libc, -bash, coreutils etc etc. - -The supermin appliance removes the kernel and all the executable -libraries and programs from the appliance. That just leaves a -skeleton of directories, config files and some data files, which is -obviously massively smaller than the normal appliance. At runtime we -rebuild the appliance on-the-fly from the libraries and programs on -the host (eg. pulling in the real /lib/libc.so, the real /bin/bash -etc.) - -Although this process of rebuilding the appliance each time sounds -slow, it turns out to be faster than using a prebuilt appliance. -(Most of the saving comes from not compressing the appliance - it -transpires that decompressing the appliance is the slowest part of the -whole boot sequence). On my machine, a new appliance can be built in -under a fifth of a second, and the boot time is several seconds -shorter. - -The big advantage of the supermin appliance for distributions like -Fedora is that it gets security fixes automatically from the host, so -there is no need to rebuild the whole appliance for a security update -in some underlying library. - -There are several I: - -It won't work at all except in very narrow, controlled cases like the -Fedora packaging case. We control the dependencies of the appliance -RPM tightly to ensure that the required binaries are actually present -on the host. - -Furthermore there are certain unlikely changes in the packages on the -host which could break a supermin appliance, eg. an updated library -which depends on an additional data file. - -Also supermin appliances are subjected to changes in the host kernel -which might break compatibility with qemu -- these are, of course, -real bugs in any case. - -Lastly, supermin appliances really can't be moved between branches of -distributions (eg. built on Fedora 12 and moved to Fedora 10) because -they are not self-contained and they rely on certain libraries being -around. You shouldn't do this anyway. - -Use supermin appliances with caution. - -=head2 ANATOMY OF A SUPERMIN APPLIANCE - -A supermin appliance consists usually of just two files, but can -contain several files and directories from the list below: - -=over 4 - -=item supermin.img - -The image file (conventionally called C, but you can -call it anything you want) is the skeleton initramfs. This is like an -initramfs built by L, but all libraries -and binaries are removed. - -Note that this file is a cpio file in cpio "newc" format, and is -I compressed (unlike initramfs files which are compressed cpio -files). - -=item hostfiles.txt - -This plain text file contains a list of files that we need to add back -from the host at runtime. ie. It's the list of libraries and binaries -that we removed when we constructed C. - -This file usually contains wildcards. This is because we don't -want the file to break on minor updates to libraries, so for example -instead of listing - - lib64/libreadline.so.6.1.2 - -the file contains - - lib64/libreadline.so.6.* - -=item any directory - -You can specify a directory which should contain image file(s) -and hostfile(s). - -Using a directory is useful either to keep the appliance-related files -together, or to make more complex appliances containing optional bits. - -=back - -=head2 RECONSTRUCTING AN INITRAMFS FROM A SUPERMIN APPLIANCE - -The program L can be used to -reconstruct a full initramfs from C and C -(plus, naturally, the required programs and libraries in the host -filesystem). - -See that man page for details. - -=head2 RESTRICTION: UNREADABLE BINARIES ON THE HOST - -Some binaries on the host are not publically readable. For example: - - $ ll /usr/libexec/pt_chown - -rws--x--x 1 root root 28418 2009-09-28 13:42 /usr/libexec/pt_chown - $ ll /usr/bin/chsh - -rws--x--x 1 root root 18072 2009-10-05 16:28 /usr/bin/chsh - -These binaries cause a problem when reconstructing the supermin -appliance, because we'd like to copy them into the final appliance, -and usually that process is done as non-root. Currently the only -solution is that you should remove these problematic binaries from the -appliance. - -=head1 EXAMPLE - -Create a basic Fedora directory and turn it into a supermin image. - -I You must only build "Rawhide on Rawhide". If using another -Fedora branch, you must change C below as appropriate, eg to -C. - - $ febootstrap rawhide /tmp/fedora - $ febootstrap-to-supermin /tmp/fedora supermin.img hostfiles.txt - -Examine the resulting files: - - $ cpio -itv < supermin.img | less - $ less hostfiles.txt - -Reconstruct the final kernel and initramfs. - -I The first time you run this, it will be slow because the -required host files are not in cache. With a "hot cache" it should be -lightning fast. Run it several times to get representative timings. - - $ febootstrap-supermin-helper supermin.img hostfiles.txt \ - /tmp/kernel /tmp/initrd - -You would boot the final image like this, although in this example it -probably won't work unless you add a C file to the appliance -(see the discussion in L). - - $ qemu -m 1024 -kernel /tmp/kernel -initrd /tmp/initrd [etc...] - -=head1 SEE ALSO - -L, -L, -L. - -=head1 AUTHORS - -Richard W.M. Jones - -=head1 COPYRIGHT - -(C) Copyright 2009-2010 Red Hat Inc., -L. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/febootstrap-to-supermin.sh b/febootstrap-to-supermin.sh deleted file mode 100755 index b6a2fd9..0000000 --- a/febootstrap-to-supermin.sh +++ /dev/null @@ -1,174 +0,0 @@ -#!/bin/bash - -# febootstrap-to-supermin -# (C) Copyright 2009 Red Hat Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Written by Richard W.M. Jones - -unset CDPATH - -TEMP=`getopt \ - -o '' \ - --long help \ - -n febootstrap-to-supermin -- "$@"` -if [ $? != 0 ]; then - echo "febootstrap-to-supermin: problem parsing the command line arguments" - exit 1 -fi -eval set -- "$TEMP" - -usage () -{ - echo "Usage: febootstrap-to-supermin DIR supermin.img hostfiles.txt" - echo "Please read febootstrap-to-supermin(8) man page for more information." -} - -while true; do - case "$1" in - --help) - usage - exit 0;; - --) - shift - break;; - *) - echo "Internal error!" - exit 1;; - esac -done - -if [ $# -ne 3 ]; then - usage - exit 1 -fi - -set -e - -# Create a temporary directory, make sure it gets cleaned up at the end. -tmpdir=$(mktemp -d) -remove_tmpdir () -{ - status=$? - rm -rf "$tmpdir" && exit $status -} -trap remove_tmpdir EXIT - -# Get the complete list of files and directories in the appliance. -(cd "$1" > /dev/null && find) > "$tmpdir/files" - -exec 5>"$tmpdir/keep" # Files/dirs we will keep in supermin.img -exec 6>$3 # hostfiles.txt (output) -exec 7<"$tmpdir/files" - -while read path <&7; do - dir=$(dirname "$path") - file=$(basename "$path") - - # For quoting problems with the bash =~ operator, see bash FAQ - # question E14 here http://tiswww.case.edu/php/chet/bash/FAQ and - # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=487387#25 - # (RHBZ#566511). - p_etc='^\./etc' - p_dev='^\./dev' - p_var='^\./var' - p_lib_modules='^\./lib/modules/' - p_builddir='^\./builddir' - p_ld_so='^ld-[.0-9]+\.so$' - p_libbfd='^libbfd-.*\.so$' - p_libgcc='^libgcc_s-.*\.so\.([0-9]+)$' - p_libntfs3g='^libntfs-3g\.so\..*$' - p_lib123so='^lib(.*)-[-.0-9]+\.so$' - p_lib123so123='^lib(.*)-[-.0-9]+\.so\.([0-9]+)\.' - p_libso123='^lib(.*)\.so\.([0-9]+)\.' - - # Ignore fakeroot.log. - if [ "$path" = "./fakeroot.log" ]; then - : - - # All we're going to keep are the special files /init, - # configuration files (/etc), devices and modifiable stuff (/var). - elif [ "$path" = "./init" ]; then - echo "$path" >&5 - - # Get timezone configuration from local system. - elif [ "$path" = "./etc/localtime" ]; then - echo "$path" >&6 - - elif [[ "$path" =~ $p_etc || "$path" =~ $p_dev || "$path" =~ $p_var ]] - then - echo "$path" >&5 - - # Kernel modules are always copied in from the host, including all - # the dependency information files. - elif [[ "$path" =~ $p_lib_modules ]]; then - : - - # On mock/Koji, exclude bogus /builddir directory which for some - # reason contains some yum temporary files (RHBZ#566512). - elif [[ "$path" =~ $p_builddir ]]; then - : - - # Always write directory names to both output files. - elif [ -d "$path" ]; then - echo "$path" >&5 - echo "$path" >&6 - - # Some libraries need fixed version numbers replaced by wildcards. - - elif [[ "$file" =~ $p_ld_so ]]; then - echo "$dir/ld-*.so" >&6 - - # Special case for libbfd - elif [[ "$file" =~ $p_libbfd ]]; then - echo "$dir/libbfd-*.so" >&6 - - # Special case for libgcc_s--.so.N - elif [[ "$file" =~ $p_libgcc ]]; then - echo "$dir/libgcc_s-*.so.${BASH_REMATCH[1]}" >&6 - - # Special case for libntfs-3g.so.* - elif [[ "$file" =~ $p_libntfs3g ]]; then - [ -n "$libntfs3g_once" ] || echo "$dir/libntfs-3g.so.*" >&6 - libntfs3g_once=1 - - # libfoo-1.2.3.so - elif [[ "$file" =~ $p_lib123so ]]; then - echo "$dir/lib${BASH_REMATCH[1]}-*.so" >&6 - - # libfoo-1.2.3.so.1.2.3 (but NOT '*.so.N') - elif [[ "$file" =~ $p_lib123so123 ]]; then - echo "$dir/lib${BASH_REMATCH[1]}-*.so.${BASH_REMATCH[2]}.*" >&6 - - # libfoo.so.1.2.3 (but NOT '*.so.N') - elif [[ "$file" =~ $p_libso123 ]]; then - echo "$dir/lib${BASH_REMATCH[1]}.so.${BASH_REMATCH[2]}.*" >&6 - - else - # Anything else comes from the host directly. - echo "$path" >&6 - fi -done - -# Close output files. -exec 5>&- -exec 6>&- - -# Now run febootstrap-to-initramfs to construct the supermin -# appliance. -if ! febootstrap-to-initramfs --nocompress --files="$tmpdir/keep" "$1" > "$2" -then - rm -f "$2" -fi diff --git a/febootstrap.ml b/febootstrap.ml new file mode 100644 index 0000000..966a316 --- /dev/null +++ b/febootstrap.ml @@ -0,0 +1,394 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +open Unix +open Printf + +open Febootstrap_package_handlers +open Febootstrap_utils +open Febootstrap_cmdline + +(* Create a temporary directory for use by all the functions in this file. *) +let tmpdir = tmpdir () + +let () = + debug "%s %s" Config.package_name Config.package_version; + + (* Instead of printing out warnings as we go along, accumulate them + * in lists and print them all out at the end. + *) + let warn_unreadable = ref [] in + + (* Determine which package manager this system uses. *) + check_system (); + let ph = get_package_handler () in + + debug "selected package handler: %s" (get_package_handler_name ()); + + (* Not --names: check files exist. *) + if not names_mode then ( + List.iter ( + fun pkg -> + if not (file_exists pkg) then ( + eprintf "febootstrap: %s: no such file (did you miss out the --names option?)\n" pkg; + exit 1 + ) + ) packages + ); + + (* --names: resolve the package list to a full list of package names + * (including dependencies). + *) + let packages = + if names_mode then ( + let packages = ph.ph_resolve_dependencies_and_download packages in + debug "resolved packages: %s" (String.concat " " packages); + packages + ) + else packages in + + (* Get the list of files. *) + let files = + List.flatten ( + List.map ( + fun pkg -> + let files = ph.ph_list_files pkg in + List.map (fun (filename, ft) -> filename, ft, pkg) files + ) packages + ) in + + (* Sort and combine duplicate files. *) + let files = + let files = List.sort compare files in + + let combine (name1, ft1, pkg1) (name2, ft2, pkg2) = + (* Rules for combining files. *) + if ft1.ft_config || ft2.ft_config then ( + eprintf "febootstrap: error: %s is a config file which is listed in two packages (%s, %s)\n" + name1 pkg1 pkg2; + exit 1 + ); + if (ft1.ft_dir || ft2.ft_dir) && (not (ft1.ft_dir && ft2.ft_dir)) then ( + eprintf "febootstrap: error: %s appears as both directory and ordinary file (%s, %s)\n" + name1 pkg1 pkg2; + exit 1 + ); + if ft1.ft_ghost then + (name2, ft2, pkg2) + else + (name1, ft1, pkg1) + in + + let rec loop = function + | [] -> [] + | (name1, _, _ as f1) :: (name2, _, _ as f2) :: fs when name1 = name2 -> + let f = combine f1 f2 in loop (f :: fs) + | f :: fs -> f :: loop fs + in + loop files in + + (* Because we may have excluded some packages, and also because of + * distribution packaging errors, it's not necessarily true that a + * directory is created before each file in that directory. + * Determine those missing directories and add them now. + *) + let files = + let insert_dir, dir_seen = + let h = Hashtbl.create (List.length files) in + let insert_dir dir = Hashtbl.replace h dir true in + let dir_seen dir = Hashtbl.mem h dir in + insert_dir, dir_seen + in + let files = + List.map ( + fun (path, { ft_dir = is_dir }, _ as f) -> + if is_dir then + insert_dir path; + + let rec loop path = + let parent = Filename.dirname path in + if dir_seen parent then [] + else ( + insert_dir parent; + let newdir = (parent, { ft_dir = true; ft_config = false; + ft_ghost = false; ft_mode = 0o40755 }, + "") in + newdir :: loop parent + ) + in + List.rev (f :: loop path) + ) files in + List.flatten files in + + (* Debugging. *) + debug "%d files and directories" (List.length files); + if false then ( + List.iter ( + fun (name, { ft_dir = dir; ft_ghost = ghost; ft_config = config; + ft_mode = mode }, pkg) -> + printf "%s [%s%s%s%o] from %s\n" name + (if dir then "dir " else "") + (if ghost then "ghost " else "") + (if config then "config " else "") + mode + pkg + ) files + ); + + (* Split the list of files into ones for hostfiles and ones for base image. *) + let p_hmac = Str.regexp "/\\.*\\.hmac$" in + + let hostfiles = ref [] + and baseimgfiles = ref [] in + List.iter ( + fun (path, {ft_dir = dir; ft_ghost = ghost; ft_config = config} ,_ as f) -> + (* Ignore boot files, kernel, kernel modules. Supermin appliances + * are booted from external kernel and initrd, and + * febootstrap-supermin-helper copies the host kernel modules. + * Note we want to keep the /boot and /lib/modules directory entries. + *) + if string_prefix "/boot/" path then () + else if string_prefix "/lib/modules/" path then () + + (* Always write directory names to both output files. *) + else if dir then ( + hostfiles := f :: !hostfiles; + baseimgfiles := f :: !baseimgfiles; + ) + + (* Timezone configuration is config, but copy it from host system. *) + else if path = "/etc/localtime" then + hostfiles := f :: !hostfiles + + (* Ignore FIPS files (.*.hmac) (RHBZ#654638). *) + else if Str.string_match p_hmac path 0 then () + + (* Ghost files are created empty in the base image. *) + else if ghost then + baseimgfiles := f :: !baseimgfiles + + (* For config files we can't rely on the host-installed copy + * since the admin may have modified then. We have to get the + * original file from the package and put it in the base image. + *) + else if config then + baseimgfiles := f :: !baseimgfiles + + (* Anything else comes from the host. *) + else + hostfiles := f :: !hostfiles + ) files; + let hostfiles = List.rev !hostfiles + and baseimgfiles = List.rev !baseimgfiles in + + (* Write hostfiles. *) + + (* Regexps used below. *) + let p_ld_so = Str.regexp "^ld-[.0-9]+\\.so$" in + let p_libbfd = Str.regexp "^libbfd-.*\\.so$" in + let p_libgcc = Str.regexp "^libgcc_s-.*\\.so\\.\\([0-9]+\\)$" in + let p_libntfs3g = Str.regexp "^libntfs-3g\\.so\\..*$" in + let p_lib123so = Str.regexp "^lib\\(.*\\)-[-.0-9]+\\.so$" in + let p_lib123so123 = + Str.regexp "^lib\\(.*\\)-[-.0-9]+\\.so\\.\\([0-9]+\\)\\." in + let p_libso123 = Str.regexp "^lib\\(.*\\)\\.so\\.\\([0-9]+\\)\\." in + let ntfs3g_once = ref false in + + let chan = open_out (tmpdir // "hostfiles") in + List.iter ( + fun (path, {ft_dir = is_dir; ft_ghost = ghost; ft_config = config; + ft_mode = mode }, _) -> + let dir = Filename.dirname path in + let file = Filename.basename path in + + if is_dir then + fprintf chan "%s\n" path + + (* Warn about hostfiles which are unreadable by non-root. We + * won't be able to add those to the appliance at run time, but + * there's not much else we can do about it except get the + * distros to fix this nonsense. + *) + else if mode land 0o004 = 0 then + warn_unreadable := path :: !warn_unreadable + + (* Replace fixed numbers in some library names by wildcards. *) + else if Str.string_match p_ld_so file 0 then + fprintf chan "%s/ld-*.so\n" dir + + (* Special case for libbfd. *) + else if Str.string_match p_libbfd file 0 then + fprintf chan "%s/libbfd-*.so\n" dir + + (* Special case for libgcc_s--.so.N *) + else if Str.string_match p_libgcc file 0 then + fprintf chan "%s/libgcc_s-*.so.%s\n" dir (Str.matched_group 1 file) + + (* Special case for libntfs-3g.so.* *) + else if Str.string_match p_libntfs3g file 0 then ( + if not !ntfs3g_once then ( + fprintf chan "%s/libntfs-3g.so.*\n" dir; + ntfs3g_once := true + ) + ) + + (* libfoo-1.2.3.so *) + else if Str.string_match p_lib123so file 0 then + fprintf chan "%s/lib%s-*.so\n" dir (Str.matched_group 1 file) + + (* libfoo-1.2.3.so.123 (but NOT '*.so.N') *) + else if Str.string_match p_lib123so123 file 0 then + fprintf chan "%s/lib%s-*.so.%s.*\n" dir + (Str.matched_group 1 file) (Str.matched_group 2 file) + + (* libfoo.so.1.2.3 (but NOT '*.so.N') *) + else if Str.string_match p_libso123 file 0 then + fprintf chan "%s/lib%s.so.%s.*\n" dir + (Str.matched_group 1 file) (Str.matched_group 2 file) + + (* Anything else comes from the host. *) + else + fprintf chan "%s\n" path + ) hostfiles; + close_out chan; + + (* Write base.img. + * + * We have to create directories and copy files to tmpdir/root + * and then call out to cpio to construct the initrd. + *) + let rootdir = tmpdir // "root" in + mkdir rootdir 0o755; + List.iter ( + fun (path, { ft_dir = is_dir; ft_ghost = ghost; ft_config = config; + ft_mode = mode }, pkg) -> + (* Always write directory names to both output files. *) + if is_dir then ( + (* Directory permissions are fixed up below. *) + if path <> "/" then mkdir (rootdir // path) 0o755 + ) + + (* Ghost files are just touched with the correct perms. *) + else if ghost then ( + let chan = open_out (rootdir // path) in + close_out chan; + chmod (rootdir // path) (mode land 0o777 lor 0o400) + ) + + (* For config files we can't rely on the host-installed copy + * since the admin may have modified it. We have to get the + * original file from the package. + *) + else if config then ( + let outfile = ph.ph_get_file_from_package pkg path in + + (* Note that the output config file might not be a regular file. *) + let statbuf = lstat outfile in + + let destfile = rootdir // path in + + (* Depending on the file type, copy it to destination. *) + match statbuf.st_kind with + | S_REG -> + (* Unreadable files (eg. /etc/gshadow). Make readable. *) + if statbuf.st_perm = 0 then chmod outfile 0o400; + let cmd = + sprintf "cp %s %s" + (Filename.quote outfile) (Filename.quote destfile) in + run_command cmd; + chmod destfile (mode land 0o777 lor 0o400) + | S_LNK -> + let link = readlink outfile in + symlink link destfile + | S_DIR -> assert false + | S_CHR + | S_BLK + | S_FIFO + | S_SOCK -> + eprintf "febootstrap: error: %s: don't know how to handle this type of file\n" path; + exit 1 + ) + + else + assert false (* should not be reached *) + ) baseimgfiles; + + (* Fix up directory permissions, in reverse order. Since we don't + * want to have a read-only directory that we can't write into above. + *) + List.iter ( + fun (path, { ft_dir = is_dir; ft_mode = mode }, _) -> + if is_dir then chmod (rootdir // path) (mode land 0o777 lor 0o700) + ) (List.rev baseimgfiles); + + (* Construct the 'base.img' initramfs. Feed in the list of filenames + * partly because we conveniently have them, and partly because + * this results in a nice alphabetical ordering in the cpio file. + *) + (*let cmd = sprintf "ls -lR %s" rootdir in + ignore (Sys.command cmd);*) + let cmd = + sprintf "(cd %s && cpio --quiet -o -0 -H newc) > %s" + rootdir (tmpdir // "base.img") in + let chan = open_process_out cmd in + List.iter (fun (path, _, _) -> fprintf chan ".%s\000" path) baseimgfiles; + let stat = close_process_out chan in + (match stat with + | WEXITED 0 -> () + | WEXITED i -> + eprintf "febootstrap: command '%s' failed (returned %d), see earlier error messages\n" cmd i; + exit i + | WSIGNALED i -> + eprintf "febootstrap: command '%s' killed by signal %d" cmd i; + exit 1 + | WSTOPPED i -> + eprintf "febootstrap: command '%s' stopped by signal %d" cmd i; + exit 1 + ); + + (* Undo directory permissions, because rm -rf can't delete files in + * unreadable directories. + *) + List.iter ( + fun (path, { ft_dir = is_dir; ft_mode = mode }, _) -> + if is_dir then chmod (rootdir // path) 0o755 + ) (List.rev baseimgfiles); + + (* Print warnings. *) + if warnings then ( + (match !warn_unreadable with + | [] -> () + | paths -> + eprintf "febootstrap: warning: some host files are unreadable by non-root\nGet your distro to fix these files:\n"; + List.iter + (fun path -> eprintf "\t%s\n" path) + (List.sort compare paths) + ); + ); + + (* Near-atomically copy files to the final output directory. *) + let cmd = + sprintf "mv %s %s" + (Filename.quote (tmpdir // "base.img")) + (Filename.quote (outputdir // "base.img")) in + run_command cmd; + let cmd = + sprintf "mv %s %s" + (Filename.quote (tmpdir // "hostfiles")) + (Filename.quote (outputdir // "hostfiles")) in + run_command cmd diff --git a/febootstrap.pod b/febootstrap.pod index b1e512b..c76b4eb 100644 --- a/febootstrap.pod +++ b/febootstrap.pod @@ -1,259 +1,170 @@ +=encoding utf8 + =head1 NAME -febootstrap - Bootstrap a basic Fedora system (like Debian debootstrap) +febootstrap - Bootstrapping tool for creating supermin appliances =head1 SYNOPSIS - febootstrap [--options] REPO TARGET [MIRROR] - -=head1 EXAMPLES - - febootstrap fedora-10 /tmp/f10 - febootstrap rawhide /tmp/rawhide - febootstrap rawhide /tmp/rawhide http://mymirror/rawhide/x86_64/os - febootstrap --groupinstall="Mail Server" fedora-10 /tmp/mailserver + febootstrap [-o OUTPUTDIR] --names LIST OF PKGS ... + febootstrap [-o OUTPUTDIR] PKG FILE NAMES ... =head1 DESCRIPTION -febootstrap creates a Fedora root filesystem, based on the Fedora -version specified by I under the directory specified by -I. Optionally I can point to a local mirror -(otherwise the public Fedora mirrors are used). I names are -C> (eg. C) or C. - -febootstrap does I need to be run as root. If for some reason -you do run it as root, then it works slightly differently and may have -side effects such as stopping or starting system daemons. - -For more advanced needs, take a look at L, C -and I's C. - -The normal output is a root directory located at I and -a fakeroot logfile at C/fakeroot.log>. +febootstrap is a tool for building supermin appliances. These are +tiny appliances (similar to virtual machines), usually around 100KB in +size, which get fully instantiated on-the-fly in a fraction of a +second when you need to boot one of them. + +Originally "fe" in febootstrap stood for "Fedora", but this tool is +now distro-independent and can build supermin appliances for several +popular Linux distros, and adding support for others is reasonably +easy. + +Note that this manual page documents febootstrap 3.x which is a +complete rewrite and quite different from version 2.x. If you are +looking for the febootstrap 2.x tools, then this is not the right +place. + +=head2 BASIC OPERATION + +There are two modes for using febootstrap. With the I<--names> +parameter, febootstrap takes a list of package names and creates a +supermin appliance containing those packages and all dependencies that +those packages require. In this mode febootstrap usually needs +network access because it may need to consult package repositories in +order to work out dependencies and download packages. + +Without I<--names>, febootstrap takes a list of packages (ie. +filenames of locally available packages). This package set must be +complete and consistent with no dependencies outside the set of +packages you provide. In this mode febootstrap does not require any +network access. It works by looking at the package files themselves. + +By "package" we mean the RPM, DEB, (etc.) package. A package name +might be the fully qualified name (eg. C) +or some abbreviation (eg. C). The precise format of the +name and what abbreviations are allowed depends on the package +manager. + +The supermin appliance that febootstrap writes consists of two files +called C and C (it is common for users to add +more files). By default these are written to the current directory. +If you specify the I<-o OUTPUTDIR> option then these files are written +to the named directory instead (traditionally this directory is named +C but you can call it whatever you want). + +In all cases febootstrap can only build a supermin appliance which is +identical in distro, version and architecture to the host. It does +I do cross-builds. + +=head2 MINIMIZING THE SUPERMIN APPLIANCE + +You may want to "minimize" the supermin appliance in order to save +time and space when it is instantiated. Typically you might want to +remove documentation, info files, man pages and locales. We used to +provide a separate tool called C for this +purpose, but it is no longer provided. Instead you can post-process +C yourself to remove any files or directories that you +don't want (by removing lines from the file). Be careful what you +remove because files may be necessary for correct operation of the +appliance. + +=head2 KERNEL AND KERNEL MODULES + +Usually the kernel and kernel modules are I included in the +supermin appliance. When the appliance is instantiated, the kernel +modules from the host kernel are copied in, and it is booted using the +host kernel. + +=head2 BOOTING AND CACHING THE SUPERMIN APPLIANCE + +To instantiate and boot the supermin appliance you need to use the +separate tool L. For fastest boot +times you should cache the output of that tool. See the libguestfs +source file C for an example of how this is done. + +=head2 ENFORCING AVAILABILITY OF HOSTFILES + +L builds the appliance by copying in +host files as listed in C. For this to work those host +files must be available. We usually enforce this by adding +requirements (eg. RPM C lines) on the package that uses the +supermin appliance, so that package cannot be installed without +pulling in the dependent packages and thus making sure the host files +are available. =head1 OPTIONS =over 4 -=item B<-i package> - -=item B<--install=package> +=item B<--help> -=item B<-g "group"> +Display brief command line usage, and exit. -=item B<--groupinstall="group"> +=item B<--exclude REGEXP> -Specify the package or group to install. To list multiple packages or -groups, you must give multiple C<-i> or C<-g> options. Group names -can contain spaces, so use quotes where necessary. +After doing dependency resolution, exclude packages which match the +regular expression. -These are passed directly to C or C -commands, and thus any dependencies are also resolved by yum. You can -also use shell globs and filenames here, as with ordinary yum. +This option is only used with I<--names>, and it can be given multiple +times on the command line. -If no packages or groups are given, then we install the C group -which is a small working Fedora installation (but by no means -minimal). Use C to list the packages currently in -the C group. +=item B<--names> -=item B<--no-clean> +Provide a list of package names, instead of providing packages +directly. In this mode febootstrap may require network access. See +L above. -Normally febootstrap will clean up the yum repository -(C inside the image). This contains the downloaded -RPMs and metadata. However if you give the C<--no-clean> option, then -the yum repository is left. This is useful if you want to run further -yum commands inside the filesystem by hand. +=item B<--no-warnings> -=item B<-p "proxyurl"> +Don't print warnings about packaging problems. -=item B<--proxy="proxyurl"> +=item B<-o outputdir> -URL to the proxy server that yum should use. +Select the output directory where the two supermin appliance files are +written (C and C). The default directory is the +current directory. Note that if this files exist already in the +output directory then they will be overwritten. -=item B<-u source> +=item B<-v> -=item B<--updates=source> +=item B<--verbose> -Pull in updates from an additional updates repository. The possible -sources are: - -=over 4 +Enable verbose messages. -=item -u C (a URL) +=item B<-V> -Get updates from the specific URL. +=item B<--version> -=item -u C (an updates repository name) - -Get updates from the public mirrors of the named repository -(eg. C). See REPOSITORIES below. - -=item -u C (default) - -Don't add an updates repository. This is the default. - -=back +Print the package name and version number, and exit. =back -=head1 REPOSITORIES - -You can list available repositories by visiting this URL: - -L - -(If necessary replace C with your architecture, but it seems -unlikely that this list will change based on architecture). - -=head1 RUNNING EXTRA COMMANDS IN THE ROOT FILESYSTEM - -If you want to run further commands inside the root filesystem, for -example additional C installs, then use C. See -the L manual page for more details. - -You have to be careful about modifying files in the root filesystem -directly (without using C). It's easy to confuse -fakeroot and end up with the wrong permissions on files (see FAKEROOT -LOGFILE below). - -C runs the command inside the root filesystem, which -means it won't normally have access to files outside the root. You -can use C environment variable (see -L) or copy files into the root first. - -=head2 FAKEROOT LOGFILE - -When febootstrap is run as non-root (the normal case) we use fakeroot -so that yum thinks it is running as root. Fakeroot keeps track of -"real" file permissions in a log file which is saved into the target -directory as C/fakeroot.log>. - -This logfile is indexed by inode number, which makes certain -operations safe and other operations unsafe. -Files should be replaced only by doing: - - echo updated-content > old-file - -(since that preserves the original inode). - -Deleting files and then creating new ones (even with a different name) -is usually unsafe, because the new files might reuse inodes claimed by -the old files, and so appear with peculiar permissions -(eg. unreadable, or as a symbolic link). - -Deleting files is also usually unsafe, although the reasons are more -subtle. If you just use C then the inode number is not deleted -from C which means it can be reused by another file -later on. +=head1 SEE ALSO -In most cases it's usually safest to use C. +L, +L, +L, +L. -You can use the fakeroot logfile in a number of ways: +=head1 AUTHORS =over 4 =item * -Use L to run a command with the faked file -permissions. - -=item * - -Use L to install a file with permissions -in the root filesystem. +Richard W.M. Jones L =item * -Generate an initramfs (compressed cpio) file containing the correct -permissions using the tool C. - -=item * - -Generate a supermin appliance using the tool -C. - -=item * - -Apply the permissions to the target directory using the forthcoming -tool C (requires root). +Matthew Booth L =back -=head1 RUNNING FEBOOTSTRAP AS ROOT - -There is some rudimentary support for running C as root. -However it is not well-tested and generally not recommended. - -=head1 COMPARISON TO DEBOOTSTRAP - -febootstrap cannot do cross-architecture installs (C). The reason is that C<%pre> and C<%post> scripts cannot -run. It may be possible to defer running of scriptlets (which is -basically how debootstrap works), and patches to do this are welcomed. - -febootstrap cannot do 32-on-64 bit installs. The reason is that -fakeroot and fakechroot do not load the correct preload library. This -is really a bug in fakeroot/fakechroot, which we think would be easy -to fix. (debootstrap deals with this case the same as for -C<--foreign> installs - see previous point). - -=head1 OTHER RESTRICTIONS AND BUGS - -The following programs are not run during C<%post> scriptlets (because -they are all statically linked, and fakechroot cannot run statically -linked programs). - -=over 4 - -=item C (from many packages) - -=item C (from C) - -=item C (from C) - -=item C (from C) - -=back - -If you wish, you can run them the first time you boot into the new -machine. - -febootstrap recreates the repository anew each time, and this causes -yum to download all the RPMs every time. This is very wasteful, and -we should provide a way to cache the repository. - -=head1 HOME PAGE - -L - -=head1 SEE ALSO - -L, -L, -L, -L, -L, -L, -L, -L, -L. - -=head1 ALTERNATIVES - -L, -L, -L, -L, -C. - -=head1 AUTHORS - -Richard W.M. Jones - =head1 COPYRIGHT -(C) Copyright 2009 Red Hat Inc., -L. +Copyright (C) 2009-2010 Red Hat Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/febootstrap.sh b/febootstrap.sh deleted file mode 100755 index 2965a7e..0000000 --- a/febootstrap.sh +++ /dev/null @@ -1,245 +0,0 @@ -#!/bin/bash - -# febootstrap -# (C) Copyright 2009 Red Hat Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Written by Richard W.M. Jones - -unset CDPATH - -TEMP=`getopt \ - -o g:i:p:u: \ - --long groupinstall:,group-install:,help,install:,noclean,no-clean,proxy:,updates: \ - -n febootstrap -- "$@"` -if [ $? != 0 ]; then - echo "febootstrap: problem parsing the command line arguments" - exit 1 -fi -eval set -- "$TEMP" - -declare -a packages -packages[0]="@Core" -i=0 - -clean=yes - -usage () -{ - echo "Usage: febootstrap [--options] REPO TARGET [MIRROR]" - echo "Please read febootstrap(8) man page for more information." -} - -while true; do - case "$1" in - -i|--install) - packages[i++]="$2" - shift 2;; - -g|--groupinstall|--group-install) - packages[i++]="@$2" - shift 2;; - -p|--proxy) - proxy="proxy=$2" - shift 2;; - -u|--updates) - updates="$2"; - shift 2;; - --noclean|--no-clean) - clean=no - shift;; - --help) - usage - exit 0;; - --) - shift - break;; - *) - echo "Internal error!" - exit 1;; - esac -done - -if [ $# -lt 2 -o $# -gt 3 ]; then - usage - exit 1 -fi - -repo="$1" -target="$2" -mirror="$3" - -# Architecture is currently always the same as the current arch. We -# cannot do --foreign builds. See discussion in the manpage. -arch=$(uname -m) -case $arch in - i?86) arch=i386 ;; -esac - -# Create a temporary directory, make sure it gets cleaned up at the end. -tmpdir=$(mktemp -d) -remove_tmpdir () -{ - status=$? - rm -rf "$tmpdir" && exit $status -} -trap remove_tmpdir EXIT - -# Create the temporary repository configuration. The name of the -# repository is always 'febootstrap'. -cat > $tmpdir/febootstrap.repo <<__EOF__ -[febootstrap] -name=febootstrap $repo $arch -failovermethod=priority -enabled=1 -gpgcheck=0 -$proxy -__EOF__ - -# "Mirror" parameter is a bit misnamed, but it means a local mirror, -# instead of the public Fedora mirrors. -if [ -n "$mirror" ]; then - echo "baseurl=$mirror" >> "$tmpdir"/febootstrap.repo -else - echo "mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=$repo&arch=$arch" >> "$tmpdir"/febootstrap.repo -fi - -# Add the updates repository if asked. -case "$updates" in - ""|none|no) - ;; - *://*) - cat >> $tmpdir/febootstrap.repo <> $tmpdir/febootstrap.repo < /dev/null; pwd) - -# This is necessary to keep yum happy. It's not clear why yum can't -# just create this file itself. -mkdir -p "$target"/var/cache/yum/febootstrap/packages - -# NB: REQUIRED for useradd/groupadd to run properly. -# -# However this causes 'filesystem' RPM install to give the -# following error. Not sure how serious the error is: -# error: unpacking of archive failed on file /proc: cpio: utime -export FAKECHROOT_EXCLUDE_PATH=/proc - -# Substitute some statically-linked commands. This is only supported -# in fakechroot > 2.9. For previous versions of fakechroot it is -# ignored. -export FAKECHROOT_CMD_SUBST=/sbin/ldconfig=/bin/true:/usr/sbin/glibc_post_upgrade.i686=/bin/true:/usr/sbin/glibc_post_upgrade.x86_64=/bin/true:/usr/sbin/build-locale-archive=/bin/true:/usr/sbin/libgcc_post_upgrade=/bin/true:/sbin/new-kernel-pkg=/bin/true:/usr/sbin/nscd=/bin/true - -# Use the libraries inside the chroot. -export LD_LIBRARY_PATH="$target"/usr/lib64:"$target"/usr/lib:"$target"/lib64:"$target"/usr/lib - -# Make the device nodes inside the fake chroot. -# (Copied from mock/backend.py) Why isn't there a base package which -# creates these? -make_device_nodes () -{ - mkdir "$target"/proc - mkdir "$target"/sys - mkdir "$target"/dev - ( - cd "$target"/dev - mkdir pts - mkdir shm - mkdir mapper - mknod null c 1 3; chmod 0666 null - mknod full c 1 7; chmod 0666 full - mknod zero c 1 5; chmod 0666 zero - mknod random c 1 8; chmod 0666 random - mknod urandom c 1 9; chmod 0444 urandom - mknod tty c 5 0; chmod 0666 tty - mknod console c 5 1; chmod 0600 console - mknod ptmx c 5 2; chmod 0666 ptmx - ln -sf /proc/self/fd/0 stdin - ln -sf /proc/self/fd/1 stdout - ln -sf /proc/self/fd/2 stderr - ) -} -export -f make_device_nodes -export target - -if [ $(id -u) -ne 0 ]; then - fakeroot -s "$target"/fakeroot.log \ - make_device_nodes -else - make_device_nodes -fi - -repos=febootstrap -if [ -n "$addrepo" ]; then - repos="$repos,$addrepo" -fi - -# Run yum. -run_yum () -{ - yum \ - -y -c "$tmpdir"/febootstrap.repo \ - --disablerepo=* --enablerepo=$repos \ - --noplugins --nogpgcheck \ - --installroot="$target" \ - install "$@" -} -export -f run_yum -export tmpdir -export repos - -if [ $(id -u) -ne 0 ]; then - # Bash doesn't support exporting array variables, hence this - # tortuous workaround. - fakeroot -i "$target"/fakeroot.log -s "$target"/fakeroot.log \ - fakechroot -s \ - bash -c 'run_yum "$@"' run_yum "${packages[@]}" -else - run_yum "${packages[@]}" -fi - -# Clean up the yum repository. -if [ "$clean" = "yes" ]; then - febootstrap-run "$target" -- rm -rf /var/cache/yum/febootstrap - febootstrap-run "$target" -- rm -rf /var/cache/yum/febootstrap-updates -fi diff --git a/febootstrap_cmdline.ml b/febootstrap_cmdline.ml new file mode 100644 index 0000000..3ce1029 --- /dev/null +++ b/febootstrap_cmdline.ml @@ -0,0 +1,82 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +open Printf + +let excludes = ref [] +let names_mode = ref false +let outputdir = ref "." +let packages = ref [] +let verbose = ref false +let warnings = ref true + +let print_version () = + printf "%s %s\n" Config.package_name Config.package_version; + exit 0 + +let add_exclude re = + excludes := Str.regexp re :: !excludes + +let argspec = Arg.align [ + "--exclude", Arg.String add_exclude, + "regexp Exclude packages matching regexp"; + "--names", Arg.Set names_mode, + " Specify set of root package names on command line"; + "--no-warnings", Arg.Clear warnings, + " Suppress warnings"; + "-o", Arg.Set_string outputdir, + "outputdir Set output directory (default: \".\")"; + "-v", Arg.Set verbose, + " Enable verbose output"; + "--verbose", Arg.Set verbose, + " Enable verbose output"; + "-V", Arg.Unit print_version, + " Print package name and version, and exit"; + "--version", Arg.Unit print_version, + " Print package name and version, and exit"; +] +let anon_fn str = + packages := str :: !packages + +let usage_msg = + "\ +febootstrap - bootstrapping tool for creating supermin appliances +Copyright (C) 2009-2010 Red Hat Inc. + +Usage: + febootstrap [-o OUTPUTDIR] --names LIST OF PKGS ... + febootstrap [-o OUTPUTDIR] PKG FILE NAMES ... + +For full instructions see the febootstrap(8) man page. + +Options:\n" + +let () = + Arg.parse argspec anon_fn usage_msg; + if !packages = [] then ( + eprintf "febootstrap: no packages listed on the command line\n"; + exit 1 + ) + +let excludes = List.rev !excludes +let names_mode = !names_mode +let outputdir = !outputdir +let packages = List.rev !packages +let warnings = !warnings + +let debug fs = ksprintf (fun str -> if !verbose then print_endline str) fs diff --git a/febootstrap_cmdline.mli b/febootstrap_cmdline.mli new file mode 100644 index 0000000..cbb6b87 --- /dev/null +++ b/febootstrap_cmdline.mli @@ -0,0 +1,39 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +(** Command line parsing. *) + +val debug : ('a, unit, string, unit) format4 -> 'a + (** Print string (like printf), but only if --verbose was given on + the command line. *) + +val excludes : Str.regexp list + (** List of package regexps to exclude. *) + +val names_mode : bool + (** True if [--names] was given on the command line (otherwise + {!packages} is a list of filenames). *) + +val outputdir : string + (** Output directory. *) + +val packages : string list + (** List of packages or package names as supplied on the command line. *) + +val warnings : bool + (** If true, print warnings. [--no-warnings] sets this to false. *) diff --git a/febootstrap_debian.ml b/febootstrap_debian.ml new file mode 100644 index 0000000..c0cfbac --- /dev/null +++ b/febootstrap_debian.ml @@ -0,0 +1,132 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +(* Debian support. *) + +open Unix +open Printf + +open Febootstrap_package_handlers +open Febootstrap_utils +open Febootstrap_cmdline + +(* Create a temporary directory for use by all the functions in this file. *) +let tmpdir = tmpdir () + +let debian_detect () = + file_exists "/etc/debian_version" && + Config.aptitude <> "no" && Config.dpkg <> "no" + +let debian_resolve_dependencies_and_download names = + let cmd = + sprintf "apt-cache depends --recurse -i %s | grep -v '^[<[:space:]]'" + (String.concat " " (List.map Filename.quote names)) in + let pkgs = run_command_get_lines cmd in + + (* Exclude packages matching [--exclude] regexps on the command line. *) + let pkgs = + List.filter ( + fun name -> + not (List.exists (fun re -> Str.string_match re name 0) excludes) + ) pkgs in + + (* Download the packages. *) + let cmd = + sprintf "cd %s && aptitude download %s" + (Filename.quote tmpdir) + (String.concat " " (List.map Filename.quote pkgs)) in + run_command cmd; + + (* Find out what aptitude downloaded. *) + let files = Sys.readdir tmpdir in + + let pkgs = List.map ( + fun pkg -> + (* Look for 'pkg_*.deb' in the list of files. *) + let pre = pkg ^ "_" in + let r = ref "" in + try + for i = 0 to Array.length files - 1 do + if string_prefix pre files.(i) then ( + r := files.(i); + files.(i) <- ""; + raise Exit + ) + done; + eprintf "febootstrap: aptitude: error: no file was downloaded corresponding to package %s\n" pkg; + exit 1 + with + Exit -> !r + ) pkgs in + + List.sort compare pkgs + +let debian_list_files pkg = + debug "unpacking %s ..." pkg; + + (* We actually need to extract the file in order to get the + * information about modes etc. + *) + let pkgdir = tmpdir // pkg ^ ".d" in + mkdir pkgdir 0o755; + let cmd = + sprintf "dpkg-deb --fsys-tarfile %s | (cd %s && tar xf -)" + (tmpdir // pkg) pkgdir in + run_command cmd; + + let cmd = sprintf "cd %s && find ." pkgdir in + let lines = run_command_get_lines cmd in + + let files = List.map ( + fun path -> + assert (path.[0] = '.'); + (* No leading '.' *) + let path = + if path = "." then "/" + else String.sub path 1 (String.length path - 1) in + + (* Find out what it is and get the canonical filename. *) + let statbuf = lstat (pkgdir // path) in + let is_dir = statbuf.st_kind = S_DIR in + + (* No per-file metadata like in RPM, but we can synthesize it + * from the path. + *) + let config = statbuf.st_kind = S_REG && string_prefix path "/etc/" in + + let mode = statbuf.st_perm in + + (path, { ft_dir = is_dir; ft_config = config; ft_mode = mode; + ft_ghost = false }) + ) lines in + + files + +(* Easy because we already unpacked the archive above. *) +let debian_get_file_from_package pkg file = + tmpdir // pkg ^ ".d" // file + +let () = + let ph = { + ph_detect = debian_detect; + ph_resolve_dependencies_and_download = + debian_resolve_dependencies_and_download; + ph_list_files = debian_list_files; + ph_get_file_from_package = debian_get_file_from_package; + } in + register_package_handler "debian" ph diff --git a/febootstrap_package_handlers.ml b/febootstrap_package_handlers.ml new file mode 100644 index 0000000..72bb172 --- /dev/null +++ b/febootstrap_package_handlers.ml @@ -0,0 +1,79 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +open Unix +open Printf + +open Febootstrap_utils +open Febootstrap_cmdline + +type package_handler = { + ph_detect : unit -> bool; + ph_resolve_dependencies_and_download : string list -> string list; + ph_list_files : string -> (string * file_type) list; + ph_get_file_from_package : string -> string -> string +} +and file_type = { + ft_dir : bool; + ft_config : bool; + ft_ghost : bool; + ft_mode : int; +} + +let tmpdir = tmpdir () + +let handlers = ref [] + +let register_package_handler name ph = + debug "registering package handler: %s" name; + handlers := (name, ph) :: !handlers + +let handler = ref None + +let check_system () = + try + handler := Some ( + List.find ( + fun (_, ph) -> + ph.ph_detect () + ) !handlers + ) + with Not_found -> + eprintf "\ +febootstrap: could not detect package manager used by this system or distro. + +If this is a new Linux distro, or not Linux, or a Linux distro that uses +an unusual packaging format then you may need to port febootstrap. If +you are expecting that febootstrap should work on this system or distro +then it may be that the package detection code is not working. +"; + exit 1 + +let rec get_package_handler () = + match !handler with + | Some (_, ph) -> ph + | None -> + check_system (); + get_package_handler () + +let rec get_package_handler_name () = + match !handler with + | Some (name, _) -> name + | None -> + check_system (); + get_package_handler_name () diff --git a/febootstrap_package_handlers.mli b/febootstrap_package_handlers.mli new file mode 100644 index 0000000..673e448 --- /dev/null +++ b/febootstrap_package_handlers.mli @@ -0,0 +1,65 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +(** Generic package handler code. *) + +type package_handler = { + ph_detect : unit -> bool; + (** Detect if the current system uses this package manager. *) + + ph_resolve_dependencies_and_download : string list -> string list; + (** [ph_resolve_dependencies_and_download pkgs] + Take a list of package names, and using the package manager + resolve those to a list of all the packages that are required + including dependencies. Download the full list of packages and + dependencies into a tmpdir. Return the list of full filenames. + + Note this should also process the [excludes] list. *) + + ph_list_files : string -> (string * file_type) list; + (** [ph_list_files pkg] lists the files and file metadata in the + package called [pkg] (a package file). *) + + ph_get_file_from_package : string -> string -> string; + (** [ph_get_file_from_package pkg file] extracts the + single named file [file] from [pkg]. The path of the + extracted file is returned. *) +} + +(* These file types are inspired by the metadata specifically + * stored by RPM. We should look at what other package formats + * can use too. + *) +and file_type = { + ft_dir : bool; (** Is a directory. *) + ft_config : bool; (** Is a configuration file. *) + ft_ghost : bool; (** Is a ghost (created empty) file. *) + ft_mode : int; (** File mode. *) +} + +val register_package_handler : string -> package_handler -> unit + (** Register a package handler. *) + +val check_system : unit -> unit + (** Check which package manager this system uses. *) + +val get_package_handler : unit -> package_handler + (** Get the selected package manager for this system. *) + +val get_package_handler_name : unit -> string + (** Get the name of the selected package manager for this system. *) diff --git a/febootstrap_utils.ml b/febootstrap_utils.ml new file mode 100644 index 0000000..04c91ad --- /dev/null +++ b/febootstrap_utils.ml @@ -0,0 +1,145 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +open Unix +open Printf + +let (//) = Filename.concat + +let file_exists name = + try access name [F_OK]; true + with Unix_error _ -> false + +let dir_exists name = + try (stat name).st_kind = S_DIR + with Unix_error _ -> false + +let rec uniq ?(cmp = Pervasives.compare) = function + | [] -> [] + | [x] -> [x] + | x :: y :: xs when cmp x y = 0 -> + uniq ~cmp (x :: xs) + | x :: y :: xs -> + x :: uniq ~cmp (y :: xs) + +let sort_uniq ?(cmp = Pervasives.compare) xs = + let xs = List.sort cmp xs in + let xs = uniq ~cmp xs in + xs + +let rec input_all_lines chan = + try let line = input_line chan in line :: input_all_lines chan + with End_of_file -> [] + +let run_command_get_lines cmd = + let chan = open_process_in cmd in + let lines = input_all_lines chan in + let stat = close_process_in chan in + (match stat with + | WEXITED 0 -> () + | WEXITED i -> + eprintf "febootstrap: command '%s' failed (returned %d), see earlier error messages\n" cmd i; + exit i + | WSIGNALED i -> + eprintf "febootstrap: command '%s' killed by signal %d" cmd i; + exit 1 + | WSTOPPED i -> + eprintf "febootstrap: command '%s' stopped by signal %d" cmd i; + exit 1 + ); + lines + +let run_command cmd = + if Sys.command cmd <> 0 then ( + eprintf "febootstrap: %s: command failed, see earlier errors\n" cmd; + exit 1 + ) + +let run_python code args = + let cmd = sprintf "python -c %s %s" + (Filename.quote code) + (String.concat " " (List.map Filename.quote args)) in + if Sys.command cmd <> 0 then ( + eprintf "febootstrap: external python program failed, see earlier error messages\n"; + exit 1 + ) + +let tmpdir () = + let chan = open_in "/dev/urandom" in + let data = String.create 16 in + really_input chan data 0 (String.length data); + close_in chan; + let data = Digest.to_hex (Digest.string data) in + (* Note this is secure, because if the name already exists, even as a + * symlink, mkdir(2) will fail. + *) + let tmpdir = Filename.temp_dir_name // sprintf "febootstrap%s.tmp" data in + Unix.mkdir tmpdir 0o700; + at_exit + (fun () -> + let cmd = sprintf "rm -rf %s" (Filename.quote tmpdir) in + ignore (Sys.command cmd)); + tmpdir + +let rec find s sub = + let len = String.length s in + let sublen = String.length sub in + let rec loop i = + if i <= len-sublen then ( + let rec loop2 j = + if j < sublen then ( + if s.[i+j] = sub.[j] then loop2 (j+1) + else -1 + ) else + i (* found *) + in + let r = loop2 0 in + if r = -1 then loop (i+1) else r + ) else + -1 (* not found *) + in + loop 0 + +let rec string_split sep str = + let len = String.length str in + let seplen = String.length sep in + let i = find str sep in + if i = -1 then [str] + else ( + let s' = String.sub str 0 i in + let s'' = String.sub str (i+seplen) (len-i-seplen) in + s' :: string_split sep s'' + ) + +let string_prefix p str = + let len = String.length str in + let plen = String.length p in + len >= plen && String.sub str 0 plen = p + +let path_prefix p path = + let len = String.length path in + let plen = String.length p in + path = p || (len > plen && String.sub path 0 (plen+1) = (p ^ "/")) + +let rec filter_map f = function + | [] -> [] + | x :: xs -> + let x = f x in + match x with + | None -> filter_map f xs + | Some x -> x :: filter_map f xs diff --git a/febootstrap_utils.mli b/febootstrap_utils.mli new file mode 100644 index 0000000..3087ee0 --- /dev/null +++ b/febootstrap_utils.mli @@ -0,0 +1,73 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +(** Utilities. *) + +val file_exists : string -> bool + (** Return [true] iff file exists. *) + +val dir_exists : string -> bool + (** Return [true] iff dir exists. *) + +val uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list + (** Uniquify a list (the list must be sorted first). *) + +val sort_uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list + (** Sort and uniquify a list. *) + +val input_all_lines : in_channel -> string list + (** Input all lines from a channel, returning a list of lines. *) + +val run_command_get_lines : string -> string list + (** Run the command and read the list of lines that it prints to stdout. *) + +val run_command : string -> unit + (** Run a command using {!Sys.command} and exit if it fails. Be careful + when constructing the command to properly quote any arguments + (using {!Filename.quote}). *) + +val run_python : string -> string list -> unit + (** [run_python code args] runs Python [code] with arguments [args]. + This does not return anything, but exits with an error message + if the Python code returns an error. *) + +val tmpdir : unit -> string + (** [tmpdir ()] returns a newly created temporary directory. The + tmp directory is automatically removed when the program exits. + Note that a fresh temporary directory is returned each time you + call this function. *) + +val (//) : string -> string -> string + (** [x // y] concatenates file paths [x] and [y] into a single path. *) + +val find : string -> string -> int +(** [find str sub] searches for [sub] in [str], returning the index + or -1 if not found. *) + +val string_split : string -> string -> string list + (** [string_split sep str] splits [str] at [sep]. *) + +val string_prefix : string -> string -> bool + (** [string_prefix prefix str] returns true iff [str] starts with [prefix]. *) + +val path_prefix : string -> string -> bool + (** [path_prefix prefix path] returns true iff [path] is [prefix] or + [path] starts with [prefix/]. *) + +val filter_map : ('a -> 'b option) -> 'a list -> 'b list + (** map + filter *) diff --git a/febootstrap_yum_rpm.ml b/febootstrap_yum_rpm.ml new file mode 100644 index 0000000..43021cc --- /dev/null +++ b/febootstrap_yum_rpm.ml @@ -0,0 +1,222 @@ +(* febootstrap 3 + * Copyright (C) 2009-2010 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +(* Yum and RPM support. *) + +open Unix +open Printf + +open Febootstrap_package_handlers +open Febootstrap_utils +open Febootstrap_cmdline + +(* Create a temporary directory for use by all the functions in this file. *) +let tmpdir = tmpdir () + +let yum_rpm_detect () = + (file_exists "/etc/redhat-release" || file_exists "/etc/fedora-release") && + Config.yum <> "no" && Config.rpm <> "no" + +let yum_rpm_resolve_dependencies_and_download names = + (* Liberate this data from python. *) + let py = " +import yum +import yum.misc +import sys + +yb = yum.YumBase () +#yum.logginglevels.setDebugLevel(0) -- doesn't work? + +# Look up the base packages from the command line. +deps = dict () +pkgs = yb.pkgSack.returnPackages (patterns=sys.argv[2:]) +for pkg in pkgs: + deps[pkg] = False + +# Recursively find all the dependencies. +stable = False +while not stable: + stable = True + for pkg in deps.keys(): + if deps[pkg] == False: + deps[pkg] = [] + stable = False + for r in pkg.requires: + ps = yb.whatProvides (r[0], r[1], r[2]) + best = yb._bestPackageFromList (ps.returnPackages ()) + if best.name != pkg.name: + deps[pkg].append (best) + if not deps.has_key (best): + deps[best] = False + deps[pkg] = yum.misc.unique (deps[pkg]) + +# Write it to a file because yum spews garbage on stdout. +f = open (sys.argv[1], \"w\") +for pkg in deps.keys (): + f.write (\"%s %s %s %s %s\\n\" % + (pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch)) +f.close () +" in + let tmpfile = tmpdir // "names.tmp" in + run_python py (tmpfile :: names); + let chan = open_in tmpfile in + let lines = input_all_lines chan in + close_in chan; + + (* Get fields. *) + let pkgs = + List.map ( + fun line -> + match string_split " " line with + | [name; epoch; version; release; arch] -> + name, int_of_string epoch, version, release, arch + | _ -> + eprintf "febootstrap: bad output from python script: '%s'" line; + exit 1 + ) lines in + + (* Something of a hack for x86_64: exclude all i[3456]86 packages. *) + let pkgs = + if Config.host_cpu = "x86_64" then ( + List.filter ( + function (_, _, _, _, ("i386"|"i486"|"i586"|"i686")) -> false + | _ -> true + ) pkgs + ) + else pkgs in + + (* Drop the kernel package to save time. *) + let pkgs = + List.filter (function ("kernel",_,_,_,_) -> false | _ -> true) pkgs in + + (* Exclude packages matching [--exclude] regexps on the command line. *) + let pkgs = + List.filter ( + fun (name, _, _, _, _) -> + not (List.exists (fun re -> Str.string_match re name 0) excludes) + ) pkgs in + + (* Sort the list of packages, and remove duplicates (by name). + * XXX This is not quite right: we really want to keep the latest + * package if duplicates are found, but that would require a full + * version compare function. + *) + let pkgs = List.sort (fun a b -> compare b a) pkgs in + let pkgs = + let cmp (name1, _, _, _, _) (name2, _, _, _, _) = compare name1 name2 in + uniq ~cmp pkgs in + let pkgs = List.sort compare pkgs in + + (* Construct package names. *) + let pkgnames = List.map ( + function + | name, 0, version, release, arch -> + sprintf "%s-%s-%s.%s" name version release arch + | name, epoch, version, release, arch -> + sprintf "%d:%s-%s-%s.%s" epoch name version release arch + ) pkgs in + + if pkgnames = [] then ( + eprintf "febootstrap: yum-rpm: error: no packages to download\n"; + exit 1 + ); + + let cmd = sprintf "yumdownloader --destdir %s %s" + (Filename.quote tmpdir) + (String.concat " " (List.map Filename.quote pkgnames)) in + run_command cmd; + + (* Return list of package filenames. *) + List.map ( + (* yumdownloader doesn't include epoch in the filename *) + fun (name, _, version, release, arch) -> + sprintf "%s/%s-%s-%s.%s.rpm" tmpdir name version release arch + ) pkgs + +let rec yum_rpm_list_files pkg = + (* Run rpm -qlp with some extra magic. *) + let cmd = + sprintf "rpm -q --qf '[%%{FILENAMES} %%{FILEFLAGS:fflags} %%{FILEMODES}\\n]' -p %s" + pkg in + let lines = run_command_get_lines cmd in + + let files = + filter_map ( + fun line -> + match string_split " " line with + | [filename; flags; mode] -> + let test_flag = String.contains flags in + let mode = int_of_string mode in + if test_flag 'd' then None (* ignore documentation *) + else + Some (filename, { + ft_dir = mode land 0o40000 <> 0; + ft_ghost = test_flag 'g'; ft_config = test_flag 'c'; + ft_mode = mode; + }) + | _ -> + eprintf "febootstrap: bad output from rpm command: '%s'" line; + exit 1 + ) lines in + + (* I've never understood why the base packages like 'filesystem' don't + * contain any /dev nodes at all. This leaves every program that + * bootstraps RPMs to create a varying set of device nodes themselves. + * This collection was copied from mock/backend.py. + *) + let files = + let b = Filename.basename pkg in + if string_prefix "filesystem-" b then ( + let dirs = [ "/proc"; "/sys"; "/dev"; "/dev/pts"; "/dev/shm"; + "/dev/mapper" ] in + let dirs = + List.map (fun name -> + name, { ft_dir = true; ft_ghost = false; + ft_config = false; ft_mode = 0o40755 }) dirs in + let devs = [ "/dev/null"; "/dev/full"; "/dev/zero"; "/dev/random"; + "/dev/urandom"; "/dev/tty"; "/dev/console"; + "/dev/ptmx"; "/dev/stdin"; "/dev/stdout"; "/dev/stderr" ] in + (* No need to set the mode because these will go into hostfiles. *) + let devs = + List.map (fun name -> + name, { ft_dir = false; ft_ghost = false; + ft_config = false; ft_mode = 0o644 }) devs in + dirs @ devs @ files + ) else files in + + files + +let yum_rpm_get_file_from_package pkg file = + debug "extracting %s from %s ..." file (Filename.basename pkg); + + let outfile = tmpdir // file in + let cmd = + sprintf "rpm2cpio %s | (cd %s && cpio --quiet -id .%s)" + (Filename.quote pkg) (Filename.quote tmpdir) (Filename.quote file) in + run_command cmd; + outfile + +let () = + let ph = { + ph_detect = yum_rpm_detect; + ph_resolve_dependencies_and_download = + yum_rpm_resolve_dependencies_and_download; + ph_list_files = yum_rpm_list_files; + ph_get_file_from_package = yum_rpm_get_file_from_package; + } in + register_package_handler "yum-rpm" ph diff --git a/helper/Makefile.am b/helper/Makefile.am index 804fa49..fb356a4 100644 --- a/helper/Makefile.am +++ b/helper/Makefile.am @@ -63,12 +63,9 @@ febootstrap-supermin-helper.8: febootstrap-supermin-helper.pod --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ $< > $@ -febootstrap-supermin-helper.txt: febootstrap-supermin-helper.pod - pod2text $< > $@ - endif EXTRA_DIST = \ - febootstrap-supermin-helper.8 febootstrap-supermin-helper.txt \ - febootstrap-supermin-helper.pod \ - elf-default-arch + febootstrap-supermin-helper.8 \ + febootstrap-supermin-helper.pod \ + elf-default-arch diff --git a/m4/ocaml.m4 b/m4/ocaml.m4 new file mode 100644 index 0000000..479f3a8 --- /dev/null +++ b/m4/ocaml.m4 @@ -0,0 +1,240 @@ +dnl autoconf macros for OCaml +dnl +dnl Copyright © 2009 Richard W.M. Jones +dnl Copyright © 2009 Stefano Zacchiroli +dnl Copyright © 2000-2005 Olivier Andrieu +dnl Copyright © 2000-2005 Jean-Christophe Filliâtre +dnl Copyright © 2000-2005 Georges Mariano +dnl +dnl For documentation, please read the ocaml.m4 man page. + +AC_DEFUN([AC_PROG_OCAML], +[dnl + # checking for ocamlc + AC_CHECK_TOOL([OCAMLC],[ocamlc],[no]) + + if test "$OCAMLC" != "no"; then + OCAMLVERSION=`$OCAMLC -v | sed -n -e 's|.*version* *\(.*\)$|\1|p'` + AC_MSG_RESULT([OCaml version is $OCAMLVERSION]) + # If OCAMLLIB is set, use it + if test "$OCAMLLIB" = ""; then + OCAMLLIB=`$OCAMLC -where 2>/dev/null || $OCAMLC -v|tail -1|cut -d ' ' -f 4` + else + AC_MSG_RESULT([OCAMLLIB previously set; preserving it.]) + fi + AC_MSG_RESULT([OCaml library path is $OCAMLLIB]) + + AC_SUBST([OCAMLVERSION]) + AC_SUBST([OCAMLLIB]) + + # checking for ocamlopt + AC_CHECK_TOOL([OCAMLOPT],[ocamlopt],[no]) + OCAMLBEST=byte + if test "$OCAMLOPT" = "no"; then + AC_MSG_WARN([Cannot find ocamlopt; bytecode compilation only.]) + else + TMPVERSION=`$OCAMLOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` + if test "$TMPVERSION" != "$OCAMLVERSION" ; then + AC_MSG_RESULT([versions differs from ocamlc; ocamlopt discarded.]) + OCAMLOPT=no + else + OCAMLBEST=opt + fi + fi + + AC_SUBST([OCAMLBEST]) + + # checking for ocamlc.opt + AC_CHECK_TOOL([OCAMLCDOTOPT],[ocamlc.opt],[no]) + if test "$OCAMLCDOTOPT" != "no"; then + TMPVERSION=`$OCAMLCDOTOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` + if test "$TMPVERSION" != "$OCAMLVERSION" ; then + AC_MSG_RESULT([versions differs from ocamlc; ocamlc.opt discarded.]) + else + OCAMLC=$OCAMLCDOTOPT + fi + fi + + # checking for ocamlopt.opt + if test "$OCAMLOPT" != "no" ; then + AC_CHECK_TOOL([OCAMLOPTDOTOPT],[ocamlopt.opt],[no]) + if test "$OCAMLOPTDOTOPT" != "no"; then + TMPVERSION=`$OCAMLOPTDOTOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` + if test "$TMPVERSION" != "$OCAMLVERSION" ; then + AC_MSG_RESULT([version differs from ocamlc; ocamlopt.opt discarded.]) + else + OCAMLOPT=$OCAMLOPTDOTOPT + fi + fi + fi + + AC_SUBST([OCAMLOPT]) + fi + + AC_SUBST([OCAMLC]) + + # checking for ocaml toplevel + AC_CHECK_TOOL([OCAML],[ocaml],[no]) + + # checking for ocamldep + AC_CHECK_TOOL([OCAMLDEP],[ocamldep],[no]) + + # checking for ocamlmktop + AC_CHECK_TOOL([OCAMLMKTOP],[ocamlmktop],[no]) + + # checking for ocamlmklib + AC_CHECK_TOOL([OCAMLMKLIB],[ocamlmklib],[no]) + + # checking for ocamldoc + AC_CHECK_TOOL([OCAMLDOC],[ocamldoc],[no]) + + # checking for ocamlbuild + AC_CHECK_TOOL([OCAMLBUILD],[ocamlbuild],[no]) +]) + + +AC_DEFUN([AC_PROG_OCAMLLEX], +[dnl + # checking for ocamllex + AC_CHECK_TOOL([OCAMLLEX],[ocamllex],[no]) + if test "$OCAMLLEX" != "no"; then + AC_CHECK_TOOL([OCAMLLEXDOTOPT],[ocamllex.opt],[no]) + if test "$OCAMLLEXDOTOPT" != "no"; then + OCAMLLEX=$OCAMLLEXDOTOPT + fi + fi + AC_SUBST([OCAMLLEX]) +]) + +AC_DEFUN([AC_PROG_OCAMLYACC], +[dnl + AC_CHECK_TOOL([OCAMLYACC],[ocamlyacc],[no]) + AC_SUBST([OCAMLYACC]) +]) + + +AC_DEFUN([AC_PROG_CAMLP4], +[dnl + AC_REQUIRE([AC_PROG_OCAML])dnl + + # checking for camlp4 + AC_CHECK_TOOL([CAMLP4],[camlp4],[no]) + if test "$CAMLP4" != "no"; then + TMPVERSION=`$CAMLP4 -v 2>&1| sed -n -e 's|.*version *\(.*\)$|\1|p'` + if test "$TMPVERSION" != "$OCAMLVERSION" ; then + AC_MSG_RESULT([versions differs from ocamlc]) + CAMLP4=no + fi + fi + AC_SUBST([CAMLP4]) + + # checking for companion tools + AC_CHECK_TOOL([CAMLP4BOOT],[camlp4boot],[no]) + AC_CHECK_TOOL([CAMLP4O],[camlp4o],[no]) + AC_CHECK_TOOL([CAMLP4OF],[camlp4of],[no]) + AC_CHECK_TOOL([CAMLP4OOF],[camlp4oof],[no]) + AC_CHECK_TOOL([CAMLP4ORF],[camlp4orf],[no]) + AC_CHECK_TOOL([CAMLP4PROF],[camlp4prof],[no]) + AC_CHECK_TOOL([CAMLP4R],[camlp4r],[no]) + AC_CHECK_TOOL([CAMLP4RF],[camlp4rf],[no]) + AC_SUBST([CAMLP4BOOT]) + AC_SUBST([CAMLP4O]) + AC_SUBST([CAMLP4OF]) + AC_SUBST([CAMLP4OOF]) + AC_SUBST([CAMLP4ORF]) + AC_SUBST([CAMLP4PROF]) + AC_SUBST([CAMLP4R]) + AC_SUBST([CAMLP4RF]) +]) + + +AC_DEFUN([AC_PROG_FINDLIB], +[dnl + AC_REQUIRE([AC_PROG_OCAML])dnl + + # checking for ocamlfind + AC_CHECK_TOOL([OCAMLFIND],[ocamlfind],[no]) + AC_SUBST([OCAMLFIND]) +]) + + +dnl Thanks to Jim Meyering for working this next bit out for us. +dnl XXX We should define AS_TR_SH if it's not defined already +dnl (eg. for old autoconf). +AC_DEFUN([AC_CHECK_OCAML_PKG], +[dnl + AC_REQUIRE([AC_PROG_FINDLIB])dnl + + AC_MSG_CHECKING([for OCaml findlib package $1]) + + unset found + unset pkg + found=no + for pkg in $1 $2 ; do + if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then + AC_MSG_RESULT([found]) + AS_TR_SH([OCAML_PKG_$1])=$pkg + found=yes + break + fi + done + if test "$found" = "no" ; then + AC_MSG_RESULT([not found]) + AS_TR_SH([OCAML_PKG_$1])=no + fi + + AC_SUBST(AS_TR_SH([OCAML_PKG_$1])) +]) + + +AC_DEFUN([AC_CHECK_OCAML_MODULE], +[dnl + AC_MSG_CHECKING([for OCaml module $2]) + + cat > conftest.ml <&5 2>&5 ; then + found=yes + break + fi + done + + if test "$found" ; then + AC_MSG_RESULT([$$1]) + else + AC_MSG_RESULT([not found]) + $1=no + fi + AC_SUBST([$1]) +]) + + +dnl XXX Cross-compiling +AC_DEFUN([AC_CHECK_OCAML_WORD_SIZE], +[dnl + AC_REQUIRE([AC_PROG_OCAML])dnl + AC_MSG_CHECKING([for OCaml compiler word size]) + cat > conftest.ml < conftest.ml <