appliance: Use supermin >= 5.

This requires the new version of supermin (5.1.0).
This commit is contained in:
Richard W.M. Jones
2014-02-25 16:08:13 +00:00
parent d353b4a3c8
commit b13c22668d
16 changed files with 284 additions and 876 deletions

6
.gitignore vendored
View File

@@ -37,7 +37,10 @@ Makefile.in
/align/stamp-virt-alignment-scan.pod /align/stamp-virt-alignment-scan.pod
/align/virt-alignment-scan /align/virt-alignment-scan
/align/virt-alignment-scan.1 /align/virt-alignment-scan.1
/appliance/excludelist /appliance/daemon.tar.gz
/appliance/excludefiles
/appliance/hostfiles
/appliance/init.tar.gz
/appliance/libguestfs-make-fixed-appliance /appliance/libguestfs-make-fixed-appliance
/appliance/libguestfs-make-fixed-appliance.1 /appliance/libguestfs-make-fixed-appliance.1
/appliance/make.sh /appliance/make.sh
@@ -45,6 +48,7 @@ Makefile.in
/appliance/stamp-libguestfs-make-fixed-appliance.pod /appliance/stamp-libguestfs-make-fixed-appliance.pod
/appliance/stamp-supermin /appliance/stamp-supermin
/appliance/supermin.d /appliance/supermin.d
/appliance/udev-rules.tar.gz
/autom4te.cache /autom4te.cache
/bash/virt-builder /bash/virt-builder
/bash/virt-cat /bash/virt-cat

5
README
View File

@@ -61,12 +61,11 @@ The full requirements are described below.
| | | | - virtio-block | | | | | - virtio-block |
| | | | - virtio-net | | | | | - virtio-net |
+--------------+-------------+---+-----------------------------------------+ +--------------+-------------+---+-----------------------------------------+
| supermin | 4.1.0 | R | This is required on all distros. | | supermin | 5.1.0 | R | This is required on all distros. |
| febootstrap | 3.20 | | 'supermin' is the new name for | | | | | 'supermin' is the new name for |
| | | | 'febootstrap'. | | | | | 'febootstrap'. |
| | | | For alternatives, see: | | | | | For alternatives, see: |
| | | | libguestfs.org/download/binaries/appliance/ | | | | libguestfs.org/download/binaries/appliance/
| | | | febootstrap 2.x WILL NOT WORK |
+--------------+-------------+---+-----------------------------------------+ +--------------+-------------+---+-----------------------------------------+
| glibc | | R | We use various glibc-isms. | | glibc | | R | We use various glibc-isms. |
| | | | Also glibc provides XDR, rpcgen. | | | | | Also glibc provides XDR, rpcgen. |

View File

@@ -1,5 +1,5 @@
# libguestfs # libguestfs
# Copyright (C) 2009 Red Hat Inc. # Copyright (C) 2009-2014 Red Hat Inc.
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@@ -19,8 +19,9 @@ include $(top_srcdir)/subdir-rules.mk
EXTRA_DIST = \ EXTRA_DIST = \
99-guestfs-serial.rules \ 99-guestfs-serial.rules \
excludelist.in \ excludefiles.in \
guestfsd.suppressions \ guestfsd.suppressions \
hostfiles.in \
init \ init \
libguestfs-make-fixed-appliance.in \ libguestfs-make-fixed-appliance.in \
libguestfs-make-fixed-appliance.pod \ libguestfs-make-fixed-appliance.pod \
@@ -32,24 +33,42 @@ superminfsdir = $(libdir)/guestfs/supermin.d
fs_DATA = fs_DATA =
superminfs_DATA = \ superminfs_DATA = \
supermin.d/init.img \ supermin.d/init.tar.gz \
supermin.d/udev-rules.img supermin.d/udev-rules.tar.gz
if SUPERMIN_HELPER_COMPRESSED_CPIO
GZ = .gz
endif
if ENABLE_DAEMON if ENABLE_DAEMON
superminfs_DATA += \ superminfs_DATA += \
supermin.d/daemon.img$(GZ) supermin.d/daemon.tar.gz
endif endif
if ENABLE_APPLIANCE if ENABLE_APPLIANCE
superminfs_DATA += \ superminfs_DATA += \
supermin.d/base.img$(GZ) \ supermin.d/base.tar.gz \
supermin.d/packages \
supermin.d/excludefiles \
supermin.d/hostfiles supermin.d/hostfiles
endif endif
supermin.d/base.tar.gz \
supermin.d/daemon.tar.gz \
supermin.d/excludefiles \
supermin.d/hostfiles \
supermin.d/init.tar.gz \
supermin.d/packages \
supermin.d/udev-rules.tar.gz: stamp-supermin
stamp-supermin: make.sh \
packagelist \
hostfiles \
excludefiles \
daemon.tar.gz \
init.tar.gz \
udev-rules.tar.gz
rm -f $@ supermin.d/base.tar.gz supermin.d/packages
./make.sh
cp -t supermin.d \
daemon.tar.gz excludefiles hostfiles init.tar.gz udev-rules.tar.gz
touch $@
# This used to be a configure-generated file. However config.status # This used to be a configure-generated file. However config.status
# always touches the destination file, which means the appliance got # always touches the destination file, which means the appliance got
# rebuilt too often. # rebuilt too often.
@@ -65,57 +84,47 @@ if VALGRIND_DAEMON
PACKAGELIST_CPP_FLAGS += -DVALGRIND_DAEMON=1 PACKAGELIST_CPP_FLAGS += -DVALGRIND_DAEMON=1
endif endif
excludefiles: excludefiles.in Makefile
m4 $(PACKAGELIST_CPP_FLAGS) $< | \
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
cmp -s $@ $@-t || mv $@-t $@
rm -f $@-t
hostfiles: hostfiles.in Makefile
m4 $(PACKAGELIST_CPP_FLAGS) $< | \
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
cmp -s $@ $@-t || mv $@-t $@
rm -f $@-t
packagelist: packagelist.in Makefile packagelist: packagelist.in Makefile
cpp -undef $(PACKAGELIST_CPP_FLAGS) < $< | \ m4 $(PACKAGELIST_CPP_FLAGS) $< | \
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
cmp -s $@ $@-t || mv $@-t $@ cmp -s $@ $@-t || mv $@-t $@
rm -f $@-t rm -f $@-t
excludelist: excludelist.in Makefile daemon.tar.gz: ../daemon/guestfsd guestfsd.suppressions
cpp -undef $(PACKAGELIST_CPP_FLAGS) < $< | \ rm -f $@ $@-t
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
cmp -s $@ $@-t || mv $@-t $@
rm -f $@-t
supermin.d/base.img$(GZ) supermin.d/hostfiles: stamp-supermin
stamp-supermin: make.sh packagelist excludelist
rm -f $@ supermin.d/base.img$(GZ) supermin.d/hostfiles
./make.sh
if SUPERMIN_HELPER_COMPRESSED_CPIO
gzip -9 supermin.d/base.img
endif
touch $@
supermin.d/daemon.img$(GZ): ../daemon/guestfsd guestfsd.suppressions
rm -f $@ $@-t $@-tt
rm -rf tmp-d rm -rf tmp-d
mkdir -p tmp-d$(DAEMON_SUPERMIN_DIR) tmp-d/etc mkdir -p tmp-d$(DAEMON_SUPERMIN_DIR) tmp-d/etc
ln ../daemon/guestfsd tmp-d$(DAEMON_SUPERMIN_DIR)/guestfsd ln ../daemon/guestfsd tmp-d$(DAEMON_SUPERMIN_DIR)/guestfsd
ln $(srcdir)/guestfsd.suppressions tmp-d/etc/guestfsd.suppressions ln $(srcdir)/guestfsd.suppressions tmp-d/etc/guestfsd.suppressions
( cd tmp-d && find | cpio --quiet -o -H newc ) > $@-t ( cd tmp-d && tar zcf - * ) > $@-t
rm -r tmp-d rm -r tmp-d
if SUPERMIN_HELPER_COMPRESSED_CPIO
gzip -9 -c $@-t > $@-tt
mv $@-tt $@-t
endif
mv $@-t $@ mv $@-t $@
supermin.d/init.img: init init.tar.gz: init
rm -rf init.tmp $@ $@-t rm -f $@ $@-t
mkdir init.tmp tar zcf $@-t init
cp $< init.tmp
(cd init.tmp; echo "init" | cpio --quiet -o -H newc) > $@-t
rm -r init.tmp
mv $@-t $@ mv $@-t $@
# We should put this file in /lib/udev/rules.d, but put it in /etc so # We should put this file in /lib/udev/rules.d, but put it in /etc so
# we don't have to deal with all the UsrMove crap in Fedora. # we don't have to deal with all the UsrMove crap in Fedora.
supermin.d/udev-rules.img: 99-guestfs-serial.rules udev-rules.tar.gz: 99-guestfs-serial.rules
rm -f $@ $@-t rm -f $@ $@-t
rm -rf tmp-u rm -rf tmp-u
mkdir -p tmp-u/etc/udev/rules.d mkdir -p tmp-u/etc/udev/rules.d
for f in $^; do ln $$f tmp-u/etc/udev/rules.d/$$(basename $$f); done for f in $^; do ln $$f tmp-u/etc/udev/rules.d/$$(basename $$f); done
( cd tmp-u && find | cpio --quiet -o -H newc ) > $@-t ( cd tmp-u && tar zcf - etc ) > $@-t
rm -r tmp-u rm -r tmp-u
mv $@-t $@ mv $@-t $@
@@ -144,7 +153,14 @@ stamp-libguestfs-make-fixed-appliance.pod: libguestfs-make-fixed-appliance.pod
# Make clean. # Make clean.
CLEANFILES = packagelist excludelist \ CLEANFILES = \
*~ \
daemon.tar.gz \
excludefiles \
hostfiles \
init.tar.gz \
libguestfs-make-fixed-appliance.1 \ libguestfs-make-fixed-appliance.1 \
packagelist \
stamp-libguestfs-make-fixed-appliance.pod \ stamp-libguestfs-make-fixed-appliance.pod \
supermin.d/* supermin.d/* \
udev-rules.tar.gz

29
appliance/excludefiles.in Normal file
View File

@@ -0,0 +1,29 @@
dnl This is the list of files excluded from the appliance, even if
dnl they appear in packagelist.in (or more likely, as dependencies of
dnl packages in packagelist.in).
dnl
dnl List is a list of wildcards, one per line, prefixed by a '-' character.
dnl
dnl This file is processed by m4 with one of the
dnl following symbols defined (depending on the distro):
dnl
dnl REDHAT=1 For Fedora, RHEL, EPEL and workalikes.
dnl DEBIAN=1 For Debian.
dnl UBUNTU=1 For Ubuntu.
dnl ARCHLINUX=1 For Archlinux.
dnl
dnl Note that any matching file will be dropped from the appliance.
dnl Of course, this may break the appliance, so be careful.
dnl The right kernel modules are added back by supermin.
-/boot/*
-/lib/modules/*
-/usr/lib/locale/*
-/usr/share/locale/*
-/usr/share/man/*
-/usr/share/doc/*
-/usr/share/info/*
-/usr/share/gnome/help/*
-/usr/share/cracklib/*
-/usr/share/i18n/*

View File

@@ -1,57 +0,0 @@
/* This is the list of distro packages which are
* excluded from the appliance, even if they appear in
* packagelist.in (or more likely, as dependencies of
* packages in packagelist.in).
*
* List is a list of basic regular expressions, one per line.
*
* This file is processed by cpp with one of the
* following symbols defined (depending on the distro):
*
* REDHAT=1 For Fedora, RHEL, EPEL and workalikes.
* DEBIAN=1 For Debian.
* UBUNTU=1 For Ubuntu.
* ARCHLINUX=1 For Archlinux.
*
* Note that any file provided by one of these packages will
* be dropped from the appliance. Of course, this may break
* the appliance, so be careful. Other files are also dropped
* from the appliance such as docs and man pages: see 'make.sh.in'
* for the full details.
*/
/* Basically the same with a few minor tweaks. */
#ifdef UBUNTU
#define DEBIAN 1
#endif
/* Don't need any Perl or Python appearing in the appliance. */
^perl
^python
/* Plymouth is a graphical boot thing - not needed. */
^plymouth
/* Linux firmware. */
^linux-firmware
/* Keyboard maps - appliance is not interactive. */
^kbd-misc
#ifdef REDHAT
/* Linux kernel. febootstrap <= 3.18 used to exclude the kernel
* package (only) by default, but since 3.19 it doesn't do this any
* longer.
*/
^kernel
^fedora-logos
^redhat-logos
^dracut
#endif
#ifdef DEBIAN
^file-rc
#endif

13
appliance/hostfiles.in Normal file
View File

@@ -0,0 +1,13 @@
dnl This is the list of extra files added to appliance.
dnl
dnl List is a list of wildcards, one per line.
dnl
dnl This file is processed by m4 with one of the
dnl following symbols defined (depending on the distro):
dnl
dnl REDHAT=1 For Fedora, RHEL, EPEL and workalikes.
dnl DEBIAN=1 For Debian.
dnl UBUNTU=1 For Ubuntu.
dnl ARCHLINUX=1 For Archlinux.
/usr/share/augeas/lenses/*.aug

View File

@@ -105,7 +105,7 @@ guestfish -a /dev/null run
# Find the location of the appliance. # Find the location of the appliance.
cachedir="$(guestfish get-cachedir)" cachedir="$(guestfish get-cachedir)"
euid="$(id -u)" euid="$(id -u)"
appliancedir="$cachedir/.guestfs-$euid" appliancedir="$cachedir/.guestfs-$euid/appliance.d"
cp "$appliancedir/kernel" "$outputdir/kernel" cp "$appliancedir/kernel" "$outputdir/kernel"
cp "$appliancedir/initrd" "$outputdir/initrd" cp "$appliancedir/initrd" "$outputdir/initrd"

View File

@@ -130,7 +130,7 @@ be set using the C<LIBGUESTFS_PATH> environment variable.
Normally a supermin appliance is located on this path (see Normally a supermin appliance is located on this path (see
L<supermin(1)/SUPERMIN APPLIANCE>). libguestfs reconstructs this L<supermin(1)/SUPERMIN APPLIANCE>). libguestfs reconstructs this
into a full appliance by running L<supermin-helper(1)>. into a full appliance by running C<supermin --build>.
However, a simpler "fixed appliance" can also be used. libguestfs However, a simpler "fixed appliance" can also be used. libguestfs
detects this by looking for a directory on the path containing four detects this by looking for a directory on the path containing four
@@ -167,7 +167,6 @@ libguestfs, please see the L<guestfs(3)> manual page.
L<guestfs(3)>, L<guestfs(3)>,
L<supermin(1)>, L<supermin(1)>,
L<supermin-helper(1)>,
L<xz(1)>, L<xz(1)>,
L<http://libguestfs.org/>, L<http://libguestfs.org/>,
L<http://qemu.org/>. L<http://qemu.org/>.

View File

@@ -20,42 +20,14 @@ unset CDPATH
set -e set -e
# Turn excludelist file into command line arguments. # Run supermin.
exec 5<excludelist
while read regexp <&5; do
excludes="$excludes --exclude $regexp"
done
exec 5<&-
# Run supermin on the package list.
# NB: Keep using --yum-config (deprecated alias) here since both old
# and new supermin still support it.
if [ "x@SUPERMIN_PACKAGER_CONFIG@" != "xno" ]; then if [ "x@SUPERMIN_PACKAGER_CONFIG@" != "xno" ]; then
extra="--yum-config @SUPERMIN_PACKAGER_CONFIG@" extra="--packager-config @SUPERMIN_PACKAGER_CONFIG@"
fi fi
if [ "x@SUPERMIN_EXTRA_OPTIONS@" != "xno" ]; then if [ "x@SUPERMIN_EXTRA_OPTIONS@" != "xno" ]; then
extra="$extra @SUPERMIN_EXTRA_OPTIONS@" extra="$extra @SUPERMIN_EXTRA_OPTIONS@"
fi fi
echo @SUPERMIN@ -v -o supermin.d --names $(< packagelist ) $excludes $extra echo @SUPERMIN@ --prepare -v -o supermin.d $(< packagelist ) $extra
@SUPERMIN@ -v -o supermin.d --names $(< packagelist ) $excludes $extra @SUPERMIN@ --prepare -v -o supermin.d $(< packagelist ) $extra
# Remove some things that we don't want in the appliance. This is
# copied from the old febootstrap-minimize. However minimization is
# not so important now that we are caching the appliance.
< supermin.d/hostfiles \
grep -v '^/usr/lib/locale' |
grep -v '^/usr/share/locale' |
grep -v '^/usr/share/man/' |
grep -v '^/usr/share/doc/' |
grep -v '^/usr/share/info/' |
grep -v '^/usr/share/gnome/help/' |
grep -v '^/usr/share/cracklib/' |
grep -v '^/usr/share/i18n/' > supermin.d/hostfiles-t
# Include any Augeas lenses from the host.
if grep -q /usr/share/augeas/lenses supermin.d/hostfiles-t; then
echo "/usr/share/augeas/lenses/*.aug" >> supermin.d/hostfiles-t
fi
mv supermin.d/hostfiles-t supermin.d/hostfiles

View File

@@ -1,34 +1,31 @@
/* This is the list of distro packages which are dnl This is the list of distro packages which are
* installed on the appliance. dnl installed on the appliance.
* dnl
* This file is processed by cpp with one of the dnl This file is processed by m4 with one of the
* following symbols defined (depending on the distro): dnl following symbols defined (depending on the distro):
* dnl
* REDHAT=1 For Fedora, RHEL, EPEL and workalikes. dnl REDHAT=1 For Fedora, RHEL, EPEL and workalikes.
* DEBIAN=1 For Debian. dnl DEBIAN=1 For Debian.
* UBUNTU=1 For Ubuntu. dnl UBUNTU=1 For Ubuntu.
* ARCHLINUX=1 For Archlinux. dnl ARCHLINUX=1 For Archlinux.
* dnl
* There is also a list of packages which are excluded if they appear dnl There is also a list of packages which are excluded if they appear
* as dependencies of the packages below. See: excludelist.in dnl as dependencies of the packages below. See: excludelist.in
* dnl
* To add arbitrary extra packages, use: dnl To add arbitrary extra packages, use:
* dnl
* ./configure --with-extra-packages="gdb valgrind [etc]" dnl ./configure --with-extra-packages="gdb valgrind [etc]"
*/
/* Basically the same with a few minor tweaks. */ dnl Basically the same with a few minor tweaks.
#ifdef UBUNTU ifelse(UBUNTU,1,define(DEBIAN,1))
#define DEBIAN 1
#endif
#ifdef REDHAT ifelse(REDHAT,1,
augeas-libs augeas-libs
btrfs-progs btrfs-progs
cryptsetup cryptsetup
cryptsetup-luks /* old name used before Fedora 17 */ cryptsetup-luks dnl old name used before Fedora 17
e2fsprogs e2fsprogs
/* e4fsprogs only exists on RHEL 5, will be ignored everywhere else. */ dnl e4fsprogs only exists on RHEL 5, will be ignored everywhere else.
e4fsprogs e4fsprogs
genisoimage genisoimage
gfs-utils gfs-utils
@@ -40,7 +37,7 @@
iputils iputils
kernel kernel
libcap libcap
libldm /* only Fedora has this for now, but we should add it to others later*/ libldm dnl only Fedora for now, others later
nilfs-utils nilfs-utils
ntfsprogs ntfsprogs
ntfs-3g ntfs-3g
@@ -49,14 +46,14 @@
reiserfs-utils reiserfs-utils
libselinux libselinux
syslinux-extlinux syslinux-extlinux
systemd /* for /sbin/reboot and udevd */ systemd dnl for /sbin/reboot and udevd
vim-minimal vim-minimal
xz xz
yajl yajl
zfs-fuse zfs-fuse
#endif /* REDHAT */ )
#ifdef DEBIAN ifelse(DEBIAN,1,
bsdmainutils bsdmainutils
btrfs-tools btrfs-tools
cryptsetup cryptsetup
@@ -74,21 +71,21 @@
libpcre3 libpcre3
libyajl2 libyajl2
linux-image linux-image
/* syslinux 'suggests' mtools, but in reality it's a hard dependency: */ dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
mtools mtools
nilfs-tools nilfs-tools
ntfs-3g ntfs-3g
ntfsprogs ntfsprogs
openssh-client openssh-client
reiserfsprogs reiserfsprogs
sysvinit /* for /sbin/reboot */ sysvinit dnl for /sbin/reboot
ufsutils ufsutils
vim-tiny vim-tiny
xz-utils xz-utils
zfs-fuse zfs-fuse
#endif /* DEBIAN */ )
#ifdef ARCHLINUX ifelse(ARCHLINUX,1,
augeas augeas
btrfs-progs btrfs-progs
cdrkit cdrkit
@@ -111,9 +108,9 @@
xz xz
yajl yajl
zfs-fuse zfs-fuse
#endif /* ARCHLINUX */ )
#ifdef FRUGALWARE ifelse(FRUGALWARE,1,
augeas augeas
btrfs-progs btrfs-progs
cryptsetup-luks cryptsetup-luks
@@ -169,7 +166,7 @@
tar tar
util-linux util-linux
xfsprogs xfsprogs
#endif /* FRUGALWARE */ )
acl acl
attr attr
@@ -196,11 +193,9 @@ lvm2
lzop lzop
mdadm mdadm
module-init-tools module-init-tools
/* dnl Enabling this pulls out 140 extra packages
Enabling this pulls out 140 extra packages dnl into the appliance:
into the appliance: dnl ocfs2-tools
ocfs2-tools
*/
parted parted
procps procps
procps-ng procps-ng
@@ -214,17 +209,10 @@ tar
udev udev
util-linux util-linux
util-linux-ng util-linux-ng
#ifndef UBUNTU
/* on Ubuntu contains a file in /lib64 which conflicts with libc6 that has
* /lib64 as a symbolic link
*/
xfsprogs xfsprogs
#endif
zerofree zerofree
#ifdef VALGRIND_DAEMON ifelse(VALGRIND_DAEMON,1,valgrind)
valgrind
#endif
/* Define this by doing: ./configure --with-extra-packages="..." */ dnl Define this by doing: ./configure --with-extra-packages="..."
EXTRA_PACKAGES EXTRA_PACKAGES

View File

@@ -447,45 +447,10 @@ AM_CONDITIONAL([ENABLE_APPLIANCE],[test "x$ENABLE_APPLIANCE" = "xyes"])
AC_MSG_RESULT([$ENABLE_APPLIANCE]) AC_MSG_RESULT([$ENABLE_APPLIANCE])
AC_SUBST([ENABLE_APPLIANCE]) AC_SUBST([ENABLE_APPLIANCE])
dnl Check for supermin >= 4.1.0 or febootstrap >= 3.20. dnl Check for supermin >= 5.1.0.
AC_CHECK_PROGS([SUPERMIN], AC_CHECK_PROGS([SUPERMIN],[supermin],[no])
[supermin febootstrap],[no])
AC_PATH_PROGS([SUPERMIN_HELPER],
[supermin-helper febootstrap-supermin-helper],[no])
dnl supermin >= 4.1.4 supports compressed cpio images.
AC_MSG_CHECKING([for supermin-helper version])
supermin_helper_version=`$SUPERMIN_HELPER --version | awk '{print $2}'`
AC_MSG_RESULT([$supermin_helper_version])
AC_MSG_CHECKING([if supermin-helper supports compressed cpio images])
supermin_helper_version_int=`echo "$supermin_helper_version" | awk -F. '{print $1 * 1000000 + $2 * 1000 + $3}'`
echo supermin_helper_version_int=$supermin_helper_version_int >&AS_MESSAGE_LOG_FD
if test $supermin_helper_version_int -ge 4001004; then
supermin_helper_compressed_cpio=yes
else
supermin_helper_compressed_cpio=no
fi
AC_MSG_RESULT([$supermin_helper_compressed_cpio])
AM_CONDITIONAL([SUPERMIN_HELPER_COMPRESSED_CPIO],
[test "x$supermin_helper_compressed_cpio" = "xyes"])
dnl supermin >= 4.1.5 supports device trees and uses a new style command
dnl syntax.
AC_MSG_CHECKING([if supermin-helper supports device trees and new style command syntax])
if test $supermin_helper_version_int -ge 4001005; then
supermin_helper_new_style_syntax=yes
AC_DEFINE([SUPERMIN_HELPER_NEW_STYLE_SYNTAX],[1],
[Define to 1 if you have supermin-helper >= 4.1.5.])
else
supermin_helper_new_style_syntax=no
fi
AC_MSG_RESULT([$supermin_helper_new_style_syntax])
dnl Pass supermin --packager-config option. dnl Pass supermin --packager-config option.
dnl
dnl Note that in febootstrap >= 3.21 / supermin >= 4.1.0, this option
dnl is now called --packager-config, although --yum-config can still
dnl be used as a deprecated alias.
SUPERMIN_PACKAGER_CONFIG=no SUPERMIN_PACKAGER_CONFIG=no
AC_MSG_CHECKING([for --with-supermin-packager-config option]) AC_MSG_CHECKING([for --with-supermin-packager-config option])
@@ -496,22 +461,6 @@ AC_ARG_WITH([supermin-packager-config],
AC_MSG_RESULT([$SUPERMIN_PACKAGER_CONFIG"])], AC_MSG_RESULT([$SUPERMIN_PACKAGER_CONFIG"])],
[AC_MSG_RESULT([not set])]) [AC_MSG_RESULT([not set])])
AC_MSG_CHECKING([for --with-febootstrap-yum-config option (deprecated)])
AC_ARG_WITH([febootstrap-yum-config],
[AS_HELP_STRING([--with-febootstrap-yum-config=FILE],
[pass supermin --packager-config option @<:@default=no@:>@])],
[SUPERMIN_PACKAGER_CONFIG="$withval"
AC_MSG_RESULT([$SUPERMIN_PACKAGER_CONFIG"])],
[AC_MSG_RESULT([not set])])
AC_MSG_CHECKING([for --with-febootstrap-packager-config option (deprecated)])
AC_ARG_WITH([febootstrap-packager-config],
[AS_HELP_STRING([--with-febootstrap-packager-config=FILE],
[pass supermin --packager-config option @<:@default=no@:>@])],
[SUPERMIN_PACKAGER_CONFIG="$withval"
AC_MSG_RESULT([$SUPERMIN_PACKAGER_CONFIG"])],
[AC_MSG_RESULT([not set])])
AC_SUBST([SUPERMIN_PACKAGER_CONFIG]) AC_SUBST([SUPERMIN_PACKAGER_CONFIG])
dnl Pass additional supermin options. dnl Pass additional supermin options.
@@ -528,21 +477,35 @@ AC_ARG_WITH([supermin-extra-options],
AC_SUBST([SUPERMIN_EXTRA_OPTIONS]) AC_SUBST([SUPERMIN_EXTRA_OPTIONS])
if test "x$ENABLE_APPLIANCE" = "xyes"; then if test "x$ENABLE_APPLIANCE" = "xyes"; then
supermin_major_min=5
supermin_minor_min=1
supermin_min=$supermin_major_min.$supermin_minor_min
test "x$SUPERMIN" = "xno" && test "x$SUPERMIN" = "xno" &&
AC_MSG_ERROR([supermin (formerly called febootstrap) must be installed]) AC_MSG_ERROR([supermin >= $supermin_min must be installed])
dnl febootstrap 2.x did not support the --version parameter
AC_MSG_CHECKING([supermin is new enough])
$SUPERMIN --version >&AS_MESSAGE_LOG_FD 2>&1 || $SUPERMIN --version >&AS_MESSAGE_LOG_FD 2>&1 ||
AC_MSG_ERROR([supermin (formerly called febootstrap) >= 3.20 must be installed, your version is too old]) AC_MSG_ERROR([supermin >= $supermin_min must be installed, your version is too old])
supermin_major="`$SUPERMIN --version | awk '{print $2}' | awk -F. '{print $1}'`"
supermin_minor="`$SUPERMIN --version | awk '{print $2}' | awk -F. '{print $2}'`"
AC_MSG_RESULT([$supermin_major.$supermin_minor])
if test "$supermin_major" -lt "$supermin_major_min" || \
( test "$supermin_major" -eq "$supermin_major_min" && test "$supermin_minor" -lt "$supermin_minor_min" ); then
AC_MSG_ERROR([supermin >= $supermin_min must be installed, your version is too old])
fi
fi fi
AC_DEFINE_UNQUOTED([SUPERMIN_HELPER],["$SUPERMIN_HELPER"],[Name of supermin-helper program.]) AC_DEFINE_UNQUOTED([SUPERMIN],["$SUPERMIN"],[Name of supermin program])
dnl Which distro? dnl Which distro?
dnl dnl
dnl This used to be Very Important but is now just used to select dnl This used to be Very Important but is now just used to select
dnl which packages to install in the appliance, since the package dnl which packages to install in the appliance, since the package
dnl names vary slightly across distros. (See dnl names vary slightly across distros. (See
dnl appliance/packagelist.in and appliance/excludelist.in) dnl appliance/packagelist.in, appliance/excludefiles.in,
dnl appliance/hostfiles.in)
AC_MSG_CHECKING([which Linux distro for package names]) AC_MSG_CHECKING([which Linux distro for package names])
DISTRO=REDHAT DISTRO=REDHAT
if test -f /etc/debian_version; then if test -f /etc/debian_version; then

View File

@@ -153,7 +153,7 @@ L<libguestfs-make-fixed-appliance(1)>).
In our testing we did not find that using a fixed appliance gave any In our testing we did not find that using a fixed appliance gave any
measurable performance benefit, even when the appliance was located in measurable performance benefit, even when the appliance was located in
memory (ie. on C</dev/shm>). However there are three points to memory (ie. on C</dev/shm>). However there are two points to
consider: consider:
=over 4 =over 4
@@ -166,14 +166,6 @@ times.
=item 2. =item 2.
By default libguestfs (or rather, L<supermin-helper(1)>)
searches over the root filesystem to find out if any host files have
changed and if it needs to rebuild the appliance. If these files are
not cached and the root filesystem is on an HDD, then this generates
lots of seeks. Using a fixed appliance avoids this.
=item 3.
The appliance is loaded on demand. A simple test such as: The appliance is loaded on demand. A simple test such as:
time guestfish -a /dev/null run time guestfish -a /dev/null run
@@ -567,7 +559,6 @@ bit.
=head1 SEE ALSO =head1 SEE ALSO
L<supermin(1)>, L<supermin(1)>,
L<supermin-helper(1)>,
L<guestfish(1)>, L<guestfish(1)>,
L<guestfs(3)>, L<guestfs(3)>,
L<guestfs-examples(3)>, L<guestfs-examples(3)>,

View File

@@ -1525,10 +1525,10 @@ the path of qemu/KVM.
=item SUPERMIN_MODULES =item SUPERMIN_MODULES
These two environment variables allow the kernel that libguestfs uses These two environment variables allow the kernel that libguestfs uses
in the appliance to be selected. If C<$SUPERMIN_KERNEL> is not in the appliance to be selected. If C<$SUPERMIN_KERNEL> is not set,
set, then the most recent host kernel is chosen. For more information then the most recent host kernel is chosen. For more information
about kernel selection, see L<supermin-helper(1)>. This about kernel selection, see L<supermin(1)>. This feature is only
feature is only available in supermin / febootstrap E<ge> 3.8. available in supermin / febootstrap E<ge> 3.8.
=item TMPDIR =item TMPDIR
@@ -1629,7 +1629,7 @@ L<virt-win-reg(1)>,
L<libguestfs-tools.conf(5)>, L<libguestfs-tools.conf(5)>,
L<display(1)>, L<display(1)>,
L<hexedit(1)>, L<hexedit(1)>,
L<supermin-helper(1)>. L<supermin(1)>.
=head1 AUTHORS =head1 AUTHORS

View File

@@ -52,18 +52,8 @@ static int dir_contains_files (const char *dir, ...);
static int contains_old_style_appliance (guestfs_h *g, const char *path, void *data); static int contains_old_style_appliance (guestfs_h *g, const char *path, void *data);
static int contains_fixed_appliance (guestfs_h *g, const char *path, void *data); static int contains_fixed_appliance (guestfs_h *g, const char *path, void *data);
static int contains_supermin_appliance (guestfs_h *g, const char *path, void *data); static int contains_supermin_appliance (guestfs_h *g, const char *path, void *data);
static char *calculate_supermin_checksum (guestfs_h *g, const char *supermin_path); static int build_supermin_appliance (guestfs_h *g, const char *supermin_path, uid_t uid, char **kernel, char **dtb, char **initrd, char **appliance);
static int check_for_cached_appliance (guestfs_h *g, const char *supermin_path, const char *checksum, uid_t uid, char **kernel, char **dtb, char **initrd, char **appliance); static int run_supermin_build (guestfs_h *g, const char *lockfile, const char *appliancedir, const char *supermin_path);
static int build_supermin_appliance (guestfs_h *g, const char *supermin_path, const char *checksum, uid_t uid, char **kernel, char **dtb, char **initrd, char **appliance);
static int hard_link_to_cached_appliance (guestfs_h *g, const char *cachedir, char **kernel, char **dtb, char **initrd, char **appliance);
static int run_supermin_helper (guestfs_h *g, const char *supermin_path, const char *cachedir);
/* RHBZ#790721: It makes no sense to have multiple threads racing to
* build the appliance from within a single process, and the code
* isn't safe for that anyway. Therefore put a thread lock around
* appliance building.
*/
gl_lock_define_initialized (static, building_lock);
/* Locate or build the appliance. /* Locate or build the appliance.
* *
@@ -83,60 +73,31 @@ gl_lock_define_initialized (static, building_lock);
* *
* (1) Look for the first element of g->path which contains a * (1) Look for the first element of g->path which contains a
* supermin appliance skeleton. If no element has this, skip * supermin appliance skeleton. If no element has this, skip
* straight to step (5). * straight to step (3).
* *
* (2) Calculate the checksum of this supermin appliance. * (2) Call 'supermin --build' to build the full appliance (if it
* needs to be rebuilt). If this is successful, return the full
* appliance.
* *
* (3) Check whether a cached appliance with the checksum calculated * (3) Check each element of g->path, looking for a fixed appliance.
* in (2) exists and passes basic security checks. If so, return
* this appliance.
*
* (4) Try to build the supermin appliance. If this is successful,
* return it.
*
* (5) Check each element of g->path, looking for a fixed appliance.
* If one is found, return it. * If one is found, return it.
* *
* (6) Check each element of g->path, looking for an old-style appliance. * (4) Check each element of g->path, looking for an old-style appliance.
* If one is found, return it. * If one is found, return it.
* *
* The supermin appliance cache directory lives in * The supermin appliance cache directory lives in
* $TMPDIR/.guestfs-$UID/ and consists of up to five files: * $TMPDIR/.guestfs-$UID/ and consists of up to five files:
* *
* $TMPDIR/.guestfs-$UID/checksum - the checksum * $TMPDIR/.guestfs-$UID/lock - the supermin lock file
* $TMPDIR/.guestfs-$UID/kernel - the kernel * $TMPDIR/.guestfs-$UID/appliance.d/kernel - the kernel
* $TMPDIR/.guestfs-$UID/dtb - the device tree (on ARM) * $TMPDIR/.guestfs-$UID/appliance.d/dtb - the device tree (on ARM)
* $TMPDIR/.guestfs-$UID/initrd - the supermin initrd * $TMPDIR/.guestfs-$UID/appliance.d/initrd - the supermin initrd
* $TMPDIR/.guestfs-$UID/root - the appliance * $TMPDIR/.guestfs-$UID/appliance.d/root - the appliance
* *
* Since multiple instances of libguestfs with the same UID may be * Multiple instances of libguestfs with the same UID may be racing to
* racing to create an appliance, we need to be careful when building * create an appliance. However (since supermin >= 5) supermin
* and using the appliance. * provides a --lock flag and atomic update of the appliance.d
* * subdirectory.
* If a cached appliance with checksum exists (step (2) above) then we
* make a hard link to it with our current PID, so that we have a copy
* even if the appliance is replaced by another process building an
* appliance afterwards:
*
* $TMPDIR/.guestfs-$UID/kernel.$PID
* $TMPDIR/.guestfs-$UID/dtb.$PID
* $TMPDIR/.guestfs-$UID/initrd.$PID
* $TMPDIR/.guestfs-$UID/root.$PID
*
* A lock is taken on "checksum" while we perform the link.
*
* Linked files are deleted by a garbage collection sweep which can be
* initiated by any libguestfs process with the same UID when the
* corresponding PID no longer exists. (This is safe: the parent is
* always around in guestfs_launch() while qemu is starting up, and
* after that qemu will either have finished with the files or be
* holding them open, so we can unlink them).
*
* When building a new appliance (step (3)), it is built into randomly
* named temporary files in the $TMPDIR. Then a lock is acquired on
* $TMPDIR/.guestfs-$UID/checksum (this file being created if
* necessary), the files are renamed into their final location, and
* the lock is released.
*/ */
int int
guestfs___build_appliance (guestfs_h *g, guestfs___build_appliance (guestfs_h *g,
@@ -145,14 +106,9 @@ guestfs___build_appliance (guestfs_h *g,
char **initrd_rtn, char **initrd_rtn,
char **appliance_rtn) char **appliance_rtn)
{ {
int r;
char *kernel, *dtb, *initrd, *appliance; char *kernel, *dtb, *initrd, *appliance;
gl_lock_lock (building_lock); if (build_appliance (g, &kernel, &dtb, &initrd, &appliance) == -1)
r = build_appliance (g, &kernel, &dtb, &initrd, &appliance);
gl_lock_unlock (building_lock);
if (r == -1)
return -1; return -1;
/* Don't assign these until we know we're going to succeed, to avoid /* Don't assign these until we know we're going to succeed, to avoid
@@ -182,24 +138,12 @@ build_appliance (guestfs_h *g,
if (r == -1) if (r == -1)
return -1; return -1;
if (r == 1) { if (r == 1)
/* Step (2): calculate checksum. */ /* Step (2): build supermin appliance. */
CLEANUP_FREE char *checksum = return build_supermin_appliance (g, supermin_path, uid,
calculate_supermin_checksum (g, supermin_path); kernel, dtb, initrd, appliance);
if (checksum) {
/* Step (3): cached appliance exists? */
r = check_for_cached_appliance (g, supermin_path, checksum, uid,
kernel, dtb, initrd, appliance);
if (r != 0)
return r == 1 ? 0 : -1;
/* Step (4): build supermin appliance. */ /* Step (3). */
return build_supermin_appliance (g, supermin_path, checksum, uid,
kernel, dtb, initrd, appliance);
}
}
/* Step (5). */
r = find_path (g, contains_fixed_appliance, NULL, &path); r = find_path (g, contains_fixed_appliance, NULL, &path);
if (r == -1) if (r == -1)
return -1; return -1;
@@ -223,7 +167,7 @@ build_appliance (guestfs_h *g,
return 0; return 0;
} }
/* Step (6). */ /* Step (4). */
r = find_path (g, contains_old_style_appliance, NULL, &path); r = find_path (g, contains_old_style_appliance, NULL, &path);
if (r == -1) if (r == -1)
return -1; return -1;
@@ -264,180 +208,6 @@ contains_supermin_appliance (guestfs_h *g, const char *path, void *data)
return dir_contains_files (path, "supermin.d", NULL); return dir_contains_files (path, "supermin.d", NULL);
} }
#define MAX_CHECKSUM_LEN 256
static void
read_checksum (guestfs_h *g, void *checksumv, const char *line, size_t len)
{
char *checksum = checksumv;
if (len > MAX_CHECKSUM_LEN)
return;
strcpy (checksum, line);
}
static int
process_exists (int pid)
{
if (kill (pid, 0) == 0)
return 1;
if (errno == ESRCH)
return 0;
return -1;
}
/* Garbage collect appliance hard links. Files that match
* (kernel|dtb|initrd|root).$PID where the corresponding PID doesn't
* exist are deleted. Note that errors in this function don't matter.
* There may also be other libguestfs processes racing to do the same
* thing here.
*/
static void
garbage_collect_appliances (const char *cachedir)
{
DIR *dir;
struct dirent *d;
int pid;
dir = opendir (cachedir);
if (dir == NULL)
return;
while ((d = readdir (dir)) != NULL) {
if (sscanf (d->d_name, "kernel.%d", &pid) == 1 &&
process_exists (pid) == 0)
unlinkat (dirfd (dir), d->d_name, 0);
else if (sscanf (d->d_name, "dtb.%d", &pid) == 1 &&
process_exists (pid) == 0)
unlinkat (dirfd (dir), d->d_name, 0);
else if (sscanf (d->d_name, "initrd.%d", &pid) == 1 &&
process_exists (pid) == 0)
unlinkat (dirfd (dir), d->d_name, 0);
else if (sscanf (d->d_name, "root.%d", &pid) == 1 &&
process_exists (pid) == 0)
unlinkat (dirfd (dir), d->d_name, 0);
}
closedir (dir);
}
static int
check_for_cached_appliance (guestfs_h *g,
const char *supermin_path, const char *checksum,
uid_t uid,
char **kernel, char **dtb,
char **initrd, char **appliance)
{
CLEANUP_FREE char *tmpdir = guestfs_get_cachedir (g);
/* len must be longer than the length of any pathname we can
* generate in this function.
*/
size_t len = strlen (tmpdir) + 128;
char cachedir[len];
snprintf (cachedir, len, "%s/.guestfs-%d", tmpdir, uid);
char filename[len];
snprintf (filename, len, "%s/checksum", cachedir);
ignore_value (mkdir (cachedir, 0755));
ignore_value (chmod (cachedir, 0755)); /* RHBZ#921292 */
/* See if the cache directory exists and passes some simple checks
* to make sure it has not been tampered with.
*/
struct stat statbuf;
if (lstat (cachedir, &statbuf) == -1)
return 0;
if (statbuf.st_uid != uid) {
error (g, _("security: cached appliance %s is not owned by UID %d"),
filename, uid);
return -1;
}
if (!S_ISDIR (statbuf.st_mode)) {
error (g, _("security: cached appliance %s is not a directory (mode %o)"),
filename, statbuf.st_mode);
return -1;
}
if ((statbuf.st_mode & 0022) != 0) {
error (g, _("security: cached appliance %s is writable by group or other (mode %o)"),
cachedir, statbuf.st_mode);
return -1;
}
(void) utime (cachedir, NULL);
garbage_collect_appliances (cachedir);
/* Try to open and acquire a lock on the checksum file. */
int fd = open (filename, O_RDONLY|O_CLOEXEC);
if (fd == -1)
return 0;
#ifdef HAVE_FUTIMENS
(void) futimens (fd, NULL);
#else
(void) futimes (fd, NULL);
#endif
struct flock fl;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
again:
if (fcntl (fd, F_SETLKW, &fl) == -1) {
if (errno == EINTR)
goto again;
perrorf (g, "fcntl: F_SETLKW: %s", filename);
close (fd);
return -1;
}
/* Read the checksum file. */
size_t clen = strlen (checksum);
char checksum_on_disk[clen];
ssize_t rr = read (fd, checksum_on_disk, clen);
if (rr == -1) {
perrorf (g, "read: %s", filename);
close (fd);
return -1;
}
if ((size_t) rr != clen) {
close (fd);
return 0;
}
if (memcmp (checksum, checksum_on_disk, clen) != 0) {
close (fd);
return 0;
}
/* At this point, cachedir exists, and checksum matches, and we have
* a read lock on the checksum file. Make hard links to the files.
*/
if (hard_link_to_cached_appliance (g, cachedir,
kernel, dtb, initrd, appliance) == -1) {
close (fd);
return -1;
}
/* Releases the lock on checksum. */
if (close (fd) == -1) {
perrorf (g, "close");
/* Allocated in hard_link_to_cached_appliance above, must be
* freed along this error path.
*/
free (*kernel);
free (*dtb);
free (*initrd);
free (*appliance);
return -1;
}
/* Exists! */
return 1;
}
/* Build supermin appliance from supermin_path to $TMPDIR/.guestfs-$UID. /* Build supermin appliance from supermin_path to $TMPDIR/.guestfs-$UID.
* *
* Returns: * Returns:
@@ -446,222 +216,87 @@ check_for_cached_appliance (guestfs_h *g,
*/ */
static int static int
build_supermin_appliance (guestfs_h *g, build_supermin_appliance (guestfs_h *g,
const char *supermin_path, const char *checksum, const char *supermin_path,
uid_t uid, uid_t uid,
char **kernel, char **dtb, char **kernel, char **dtb,
char **initrd, char **appliance) char **initrd, char **appliance)
{ {
CLEANUP_FREE char *tmpdir = guestfs_get_cachedir (g); CLEANUP_FREE char *tmpdir = guestfs_get_cachedir (g);
struct stat statbuf;
size_t len; size_t len;
if (g->verbose)
guestfs___print_timestamped_message (g, "begin building supermin appliance");
/* len must be longer than the length of any pathname we can /* len must be longer than the length of any pathname we can
* generate in this function. * generate in this function.
*/ */
len = strlen (tmpdir) + 128; len = strlen (tmpdir) + 128;
char cachedir[len];
snprintf (cachedir, len, "%s/.guestfs-%d", tmpdir, uid);
char lockfile[len];
snprintf (lockfile, len, "%s/lock", cachedir);
char appliancedir[len];
snprintf (appliancedir, len, "%s/appliance.d", cachedir);
/* Build the appliance into a temporary directory. */ ignore_value (mkdir (cachedir, 0755));
char tmpcd[len]; ignore_value (chmod (cachedir, 0755)); /* RHBZ#921292 */
snprintf (tmpcd, len, "%s/guestfs.XXXXXX", tmpdir);
if (mkdtemp (tmpcd) == NULL) { /* See if the cache directory exists and passes some simple checks
perrorf (g, "mkdtemp"); * to make sure it has not been tampered with.
*/
if (lstat (cachedir, &statbuf) == -1)
return 0;
if (statbuf.st_uid != uid) {
error (g, _("security: cached appliance %s is not owned by UID %d"),
cachedir, uid);
return -1;
}
if (!S_ISDIR (statbuf.st_mode)) {
error (g, _("security: cached appliance %s is not a directory (mode %o)"),
cachedir, statbuf.st_mode);
return -1;
}
if ((statbuf.st_mode & 0022) != 0) {
error (g, _("security: cached appliance %s is writable by group or other (mode %o)"),
cachedir, statbuf.st_mode);
return -1; return -1;
} }
(void) utimes (cachedir, NULL);
if (g->verbose) if (g->verbose)
guestfs___print_timestamped_message (g, "run supermin-helper"); guestfs___print_timestamped_message (g, "begin building supermin appliance");
int r = run_supermin_helper (g, supermin_path, tmpcd); /* Build the appliance if it needs to be built. */
if (r == -1) { if (g->verbose)
guestfs___recursive_remove_dir (g, tmpcd); guestfs___print_timestamped_message (g, "run supermin");
if (run_supermin_build (g, lockfile, appliancedir, supermin_path) == -1)
return -1; return -1;
}
if (g->verbose) if (g->verbose)
guestfs___print_timestamped_message (g, "finished building supermin appliance"); guestfs___print_timestamped_message (g, "finished building supermin appliance");
char cachedir[len]; /* Return the appliance filenames. */
snprintf (cachedir, len, "%s/.guestfs-%d", tmpdir, uid);
char filename[len];
char filename2[len];
snprintf (filename, len, "%s/checksum", cachedir);
/* Open and acquire write lock on checksum file. The file might
* not exist, in which case we want to create it.
*/
int fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
if (fd == -1) {
perrorf (g, "open: %s", filename);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
again:
if (fcntl (fd, F_SETLKW, &fl) == -1) {
if (errno == EINTR)
goto again;
perrorf (g, "fcntl: F_SETLKW: %s", filename);
close (fd);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
/* At this point we have acquired a write lock on the checksum
* file so we go ahead and replace it with the new checksum, and
* rename in appliance files into this directory.
*/
size_t clen = strlen (checksum);
if (ftruncate (fd, clen) == -1) {
perrorf (g, "ftruncate: %s", filename);
close (fd);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
ssize_t rr = write (fd, checksum, clen);
if (rr == -1) {
perrorf (g, "write: %s", filename);
close (fd);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
if ((size_t) rr != clen) {
error (g, "partial write: %s", filename);
close (fd);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
snprintf (filename, len, "%s/kernel", tmpcd);
snprintf (filename2, len, "%s/kernel", cachedir);
unlink (filename2);
if (rename (filename, filename2) == -1) {
perrorf (g, "rename: %s %s", filename, filename2);
close (fd);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
#ifdef DTB_WILDCARD
snprintf (filename, len, "%s/dtb", tmpcd);
snprintf (filename2, len, "%s/dtb", cachedir);
unlink (filename2);
if (rename (filename, filename2) == -1) {
perrorf (g, "rename: %s %s", filename, filename2);
close (fd);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
#endif
snprintf (filename, len, "%s/initrd", tmpcd);
snprintf (filename2, len, "%s/initrd", cachedir);
unlink (filename2);
if (rename (filename, filename2) == -1) {
perrorf (g, "rename: %s %s", filename, filename2);
close (fd);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
snprintf (filename, len, "%s/root", tmpcd);
snprintf (filename2, len, "%s/root", cachedir);
unlink (filename2);
if (rename (filename, filename2) == -1) {
perrorf (g, "rename: %s %s", filename, filename2);
close (fd);
guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
guestfs___recursive_remove_dir (g, tmpcd);
/* Now finish off by linking to the cached appliance and returning it. */
if (hard_link_to_cached_appliance (g, cachedir,
kernel, dtb, initrd, appliance) == -1) {
close (fd);
return -1;
}
/* Releases the lock on checksum. */
if (close (fd) == -1) {
perrorf (g, "close");
/* Allocated in hard_link_to_cached_appliance above, must be
* freed along this error path.
*/
free (*kernel);
free (*dtb);
free (*initrd);
free (*appliance);
return -1;
}
return 0;
}
/* NB: lock on checksum file must be held when this is called. */
static int
hard_link_to_cached_appliance (guestfs_h *g,
const char *cachedir,
char **kernel, char **dtb,
char **initrd, char **appliance)
{
pid_t pid = getpid ();
size_t len = strlen (cachedir) + 32;
*kernel = safe_malloc (g, len); *kernel = safe_malloc (g, len);
#ifdef DTB_WILDCARD
*dtb = safe_malloc (g, len); *dtb = safe_malloc (g, len);
#else
*dtb = NULL;
#endif
*initrd = safe_malloc (g, len); *initrd = safe_malloc (g, len);
*appliance = safe_malloc (g, len); *appliance = safe_malloc (g, len);
snprintf (*kernel, len, "%s/kernel.%d", cachedir, pid); snprintf (*kernel, len, "%s/kernel", appliancedir);
snprintf (*dtb, len, "%s/dtb.%d", cachedir, pid); #ifdef DTB_WILDCARD
snprintf (*initrd, len, "%s/initrd.%d", cachedir, pid); snprintf (*dtb, len, "%s/dtb", appliancedir);
snprintf (*appliance, len, "%s/root.%d", cachedir, pid); #endif
snprintf (*initrd, len, "%s/initrd", appliancedir);
snprintf (*appliance, len, "%s/root", appliancedir);
char filename[len]; /* Touch the files so they don't get deleted (as they are in /var/tmp). */
snprintf (filename, len, "%s/kernel", cachedir); (void) utimes (*kernel, NULL);
(void) unlink (*kernel); #ifdef DTB_WILDCARD
if (link (filename, *kernel) == -1) { (void) utimes (*dtb, NULL);
perrorf (g, "link: %s %s", filename, *kernel); #endif
goto error; (void) utimes (*initrd, NULL);
}
(void) utimes (filename, NULL);
snprintf (filename, len, "%s/dtb", cachedir);
(void) unlink (*dtb);
if (link (filename, *dtb) == -1) {
if (errno == ENOENT) {
/* dtb doesn't exist -- this is OK */
free (*dtb);
*dtb = NULL;
} else {
perrorf (g, "link: %s %s", filename, *kernel);
goto error;
}
}
(void) utimes (filename, NULL);
snprintf (filename, len, "%s/initrd", cachedir);
(void) unlink (*initrd);
if (link (filename, *initrd) == -1) {
perrorf (g, "link: %s %s", filename, *initrd);
goto error;
}
(void) utime (filename, NULL);
snprintf (filename, len, "%s/root", cachedir);
(void) unlink (*appliance);
if (link (filename, *appliance) == -1) {
perrorf (g, "link: %s %s", filename, *appliance);
goto error;
}
/* Checking backend != "uml" is a big hack. UML encodes the mtime /* Checking backend != "uml" is a big hack. UML encodes the mtime
* of the original backing file (in this case, the appliance) in the * of the original backing file (in this case, the appliance) in the
* COW file, and checks it when adding it to the VM. If there are * COW file, and checks it when adding it to the VM. If there are
@@ -675,211 +310,69 @@ hard_link_to_cached_appliance (guestfs_h *g,
* XXX * XXX
*/ */
if (STRNEQ (g->backend, "uml")) if (STRNEQ (g->backend, "uml"))
(void) utime (filename, NULL); (void) utimes (*appliance, NULL);
return 0; return 0;
error:
free (*kernel);
free (*dtb);
free (*initrd);
free (*appliance);
return -1;
} }
/* Run supermin-helper and tell it to generate the /* Run supermin --build and tell it to generate the
* appliance. * appliance.
*/ */
#ifdef SUPERMIN_HELPER_NEW_STYLE_SYNTAX
/* supermin_path is a path which is known to contain a supermin
* appliance. Using supermin-helper -f checksum calculate
* the checksum so we can see if it is cached.
*/
static char *
calculate_supermin_checksum (guestfs_h *g, const char *supermin_path)
{
size_t len;
CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g);
int pass_u_g_args = getuid () != geteuid () || getgid () != getegid ();
char checksum[MAX_CHECKSUM_LEN + 1] = { 0 };
guestfs___cmd_add_arg (cmd, SUPERMIN_HELPER);
if (g->verbose)
guestfs___cmd_add_arg (cmd, "--verbose");
if (pass_u_g_args) {
guestfs___cmd_add_arg (cmd, "-u");
guestfs___cmd_add_arg_format (cmd, "%d", geteuid ());
guestfs___cmd_add_arg (cmd, "-g");
guestfs___cmd_add_arg_format (cmd, "%d", getegid ());
}
guestfs___cmd_add_arg (cmd, "-f");
guestfs___cmd_add_arg (cmd, "checksum");
guestfs___cmd_add_arg (cmd, "--host-cpu");
guestfs___cmd_add_arg (cmd, host_cpu);
guestfs___cmd_add_arg_format (cmd, "%s/supermin.d", supermin_path);
guestfs___cmd_set_stdout_callback (cmd, read_checksum, checksum, 0);
/* Errors here are non-fatal, so we don't need to call error(). */
if (guestfs___cmd_run (cmd) == -1)
return NULL;
debug (g, "checksum of existing appliance: %s", checksum);
len = strlen (checksum);
if (len < 16) { /* sanity check */
warning (g, "supermin-helper -f checksum returned a short string");
return NULL;
}
return safe_strndup (g, checksum, len);
}
static int static int
run_supermin_helper (guestfs_h *g, const char *supermin_path, run_supermin_build (guestfs_h *g,
const char *cachedir) const char *lockfile,
const char *appliancedir,
const char *supermin_path)
{ {
CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g); CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g);
int r; int r;
#if 0 /* not supported in supermin 5 yet XXX */
uid_t uid = getuid (); uid_t uid = getuid ();
uid_t euid = geteuid (); uid_t euid = geteuid ();
gid_t gid = getgid (); gid_t gid = getgid ();
gid_t egid = getegid (); gid_t egid = getegid ();
int pass_u_g_args = uid != euid || gid != egid; int pass_u_g_args = uid != euid || gid != egid;
#endif
guestfs___cmd_add_arg (cmd, SUPERMIN_HELPER); guestfs___cmd_add_arg (cmd, SUPERMIN);
guestfs___cmd_add_arg (cmd, "--build");
if (g->verbose) if (g->verbose)
guestfs___cmd_add_arg (cmd, "--verbose"); guestfs___cmd_add_arg (cmd, "--verbose");
#if 0
if (pass_u_g_args) { if (pass_u_g_args) {
guestfs___cmd_add_arg (cmd, "-u"); guestfs___cmd_add_arg (cmd, "-u");
guestfs___cmd_add_arg_format (cmd, "%d", euid); guestfs___cmd_add_arg_format (cmd, "%d", euid);
guestfs___cmd_add_arg (cmd, "-g"); guestfs___cmd_add_arg (cmd, "-g");
guestfs___cmd_add_arg_format (cmd, "%d", egid); guestfs___cmd_add_arg_format (cmd, "%d", egid);
} }
#endif
guestfs___cmd_add_arg (cmd, "--copy-kernel"); guestfs___cmd_add_arg (cmd, "--copy-kernel");
guestfs___cmd_add_arg (cmd, "-f"); guestfs___cmd_add_arg (cmd, "-f");
guestfs___cmd_add_arg (cmd, "ext2"); guestfs___cmd_add_arg (cmd, "ext2");
guestfs___cmd_add_arg (cmd, "--host-cpu"); guestfs___cmd_add_arg (cmd, "--host-cpu");
guestfs___cmd_add_arg (cmd, host_cpu); guestfs___cmd_add_arg (cmd, host_cpu);
guestfs___cmd_add_arg (cmd, "--if-newer");
guestfs___cmd_add_arg (cmd, "--lock");
guestfs___cmd_add_arg (cmd, lockfile);
#ifdef DTB_WILDCARD #ifdef DTB_WILDCARD
guestfs___cmd_add_arg (cmd, "--dtb"); guestfs___cmd_add_arg (cmd, "--dtb");
guestfs___cmd_add_arg (cmd, DTB_WILDCARD); guestfs___cmd_add_arg (cmd, DTB_WILDCARD);
#endif #endif
guestfs___cmd_add_arg_format (cmd, "%s/supermin.d", supermin_path); guestfs___cmd_add_arg_format (cmd, "%s/supermin.d", supermin_path);
guestfs___cmd_add_arg (cmd, "--output-kernel"); guestfs___cmd_add_arg (cmd, "-o");
guestfs___cmd_add_arg_format (cmd, "%s/kernel", cachedir); guestfs___cmd_add_arg (cmd, appliancedir);
#ifdef DTB_WILDCARD
guestfs___cmd_add_arg (cmd, "--output-dtb");
guestfs___cmd_add_arg_format (cmd, "%s/dtb", cachedir);
#endif
guestfs___cmd_add_arg (cmd, "--output-initrd");
guestfs___cmd_add_arg_format (cmd, "%s/initrd", cachedir);
guestfs___cmd_add_arg (cmd, "--output-appliance");
guestfs___cmd_add_arg_format (cmd, "%s/root", cachedir);
r = guestfs___cmd_run (cmd); r = guestfs___cmd_run (cmd);
if (r == -1) if (r == -1)
return -1; return -1;
if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
guestfs___external_command_failed (g, r, SUPERMIN_HELPER, NULL); guestfs___external_command_failed (g, r, SUPERMIN, NULL);
return -1; return -1;
} }
return 0; return 0;
} }
#else /* ! SUPERMIN_HELPER_NEW_STYLE_SYNTAX */
#ifdef DTB_WILDCARD
#error "This architecture has device trees, so requires supermin-helper >= 4.1.5"
#endif
/* supermin_path is a path which is known to contain a supermin
* appliance. Using supermin-helper -f checksum calculate
* the checksum so we can see if it is cached.
*/
static char *
calculate_supermin_checksum (guestfs_h *g, const char *supermin_path)
{
size_t len;
CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g);
int pass_u_g_args = getuid () != geteuid () || getgid () != getegid ();
char checksum[MAX_CHECKSUM_LEN + 1] = { 0 };
guestfs___cmd_add_arg (cmd, SUPERMIN_HELPER);
if (g->verbose)
guestfs___cmd_add_arg (cmd, "--verbose");
if (pass_u_g_args) {
guestfs___cmd_add_arg (cmd, "-u");
guestfs___cmd_add_arg_format (cmd, "%d", geteuid ());
guestfs___cmd_add_arg (cmd, "-g");
guestfs___cmd_add_arg_format (cmd, "%d", getegid ());
}
guestfs___cmd_add_arg (cmd, "-f");
guestfs___cmd_add_arg (cmd, "checksum");
guestfs___cmd_add_arg_format (cmd, "%s/supermin.d", supermin_path);
guestfs___cmd_add_arg (cmd, host_cpu);
guestfs___cmd_set_stdout_callback (cmd, read_checksum, checksum, 0);
/* Errors here are non-fatal, so we don't need to call error(). */
if (guestfs___cmd_run (cmd) == -1)
return NULL;
debug (g, "checksum of existing appliance: %s", checksum);
len = strlen (checksum);
if (len < 16) { /* sanity check */
warning (g, "supermin-helper -f checksum returned a short string");
return NULL;
}
return safe_strndup (g, checksum, len);
}
static int
run_supermin_helper (guestfs_h *g, const char *supermin_path,
const char *cachedir)
{
CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g);
int r;
uid_t uid = getuid ();
uid_t euid = geteuid ();
gid_t gid = getgid ();
gid_t egid = getegid ();
int pass_u_g_args = uid != euid || gid != egid;
guestfs___cmd_add_arg (cmd, SUPERMIN_HELPER);
if (g->verbose)
guestfs___cmd_add_arg (cmd, "--verbose");
if (pass_u_g_args) {
guestfs___cmd_add_arg (cmd, "-u");
guestfs___cmd_add_arg_format (cmd, "%d", euid);
guestfs___cmd_add_arg (cmd, "-g");
guestfs___cmd_add_arg_format (cmd, "%d", egid);
}
guestfs___cmd_add_arg (cmd, "--copy-kernel");
guestfs___cmd_add_arg (cmd, "-f");
guestfs___cmd_add_arg (cmd, "ext2");
guestfs___cmd_add_arg_format (cmd, "%s/supermin.d", supermin_path);
guestfs___cmd_add_arg (cmd, host_cpu);
guestfs___cmd_add_arg_format (cmd, "%s/kernel", cachedir);
guestfs___cmd_add_arg_format (cmd, "%s/initrd", cachedir);
guestfs___cmd_add_arg_format (cmd, "%s/root", cachedir);
r = guestfs___cmd_run (cmd);
if (r == -1)
return -1;
if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
guestfs___external_command_failed (g, r, SUPERMIN_HELPER, NULL);
return -1;
}
return 0;
}
#endif /* ! SUPERMIN_HELPER_NEW_STYLE_SYNTAX */
/* Search elements of g->path, returning the first path element which /* Search elements of g->path, returning the first path element which
* matches the predicate function 'pred'. * matches the predicate function 'pred'.
* *

View File

@@ -3477,15 +3477,14 @@ debugging (set the environment variable C<LIBGUESTFS_DEBUG=1>).
=item Create the appliance =item Create the appliance
C<supermin-helper> is invoked to create the kernel, a C<supermin --build> is invoked to create the kernel, a small initrd
small initrd and the appliance. and the appliance.
The appliance is cached in C</var/tmp/.guestfs-E<lt>UIDE<gt>> (or in The appliance is cached in C</var/tmp/.guestfs-E<lt>UIDE<gt>> (or in
another directory if C<LIBGUESTFS_CACHEDIR> or C<TMPDIR> are set). another directory if C<LIBGUESTFS_CACHEDIR> or C<TMPDIR> are set).
For a complete description of how the appliance is created and cached, For a complete description of how the appliance is created and cached,
read the L<supermin(1)> and L<supermin-helper(1)> man read the L<supermin(1)> man page.
pages.
=item Start qemu and boot the kernel =item Start qemu and boot the kernel
@@ -3493,12 +3492,12 @@ qemu is invoked to boot the kernel.
=item Run the initrd =item Run the initrd
C<supermin-helper> builds a small initrd. The initrd is C<supermin --build> builds a small initrd. The initrd is not the
not the appliance. The purpose of the initrd is to load enough kernel appliance. The purpose of the initrd is to load enough kernel modules
modules in order that the appliance itself can be mounted and started. in order that the appliance itself can be mounted and started.
The initrd is a cpio archive called The initrd is a cpio archive called
C</var/tmp/.guestfs-E<lt>UIDE<gt>/initrd>. C</var/tmp/.guestfs-E<lt>UIDE<gt>/appliance.d/initrd>.
When the initrd has started you will see messages showing that kernel When the initrd has started you will see messages showing that kernel
modules are being loaded, similar to this: modules are being loaded, similar to this:
@@ -3512,7 +3511,8 @@ modules are being loaded, similar to this:
The appliance is a sparse file containing an ext2 filesystem which The appliance is a sparse file containing an ext2 filesystem which
contains a familiar (although reduced in size) Linux operating system. contains a familiar (although reduced in size) Linux operating system.
It would normally be called C</var/tmp/.guestfs-E<lt>UIDE<gt>/root>. It would normally be called
C</var/tmp/.guestfs-E<lt>UIDE<gt>/appliance.d/root>.
The regular disks being inspected by libguestfs are the first The regular disks being inspected by libguestfs are the first
devices exposed by qemu (eg. as C</dev/vda>). devices exposed by qemu (eg. as C</dev/vda>).
@@ -4706,7 +4706,7 @@ environment which tends to break everything.
These two environment variables allow the kernel that libguestfs uses These two environment variables allow the kernel that libguestfs uses
in the appliance to be selected. If C<$SUPERMIN_KERNEL> is not in the appliance to be selected. If C<$SUPERMIN_KERNEL> is not
set, then the most recent host kernel is chosen. For more information set, then the most recent host kernel is chosen. For more information
about kernel selection, see L<supermin-helper(1)>. This about kernel selection, see L<supermin(1)>. This
feature is only available in supermin / febootstrap E<ge> 3.8. feature is only available in supermin / febootstrap E<ge> 3.8.
=item TMPDIR =item TMPDIR
@@ -4758,7 +4758,6 @@ L<guestfs-testing(1)>,
L<libguestfs-test-tool(1)>, L<libguestfs-test-tool(1)>,
L<libguestfs-make-fixed-appliance(1)>, L<libguestfs-make-fixed-appliance(1)>,
L<supermin(1)>, L<supermin(1)>,
L<supermin-helper(1)>,
L<qemu(1)>, L<qemu(1)>,
L<hivex(3)>, L<hivex(3)>,
L<stap(1)>, L<stap(1)>,

View File

@@ -87,8 +87,7 @@ variables C<SUPERMIN_KERNEL> and/or C<SUPERMIN_MODULES>
(C<FEBOOTSTRAP_KERNEL> and C<FEBOOTSTRAP_MODULES> if still using the (C<FEBOOTSTRAP_KERNEL> and C<FEBOOTSTRAP_MODULES> if still using the
old febootstrap 3.21 program). old febootstrap 3.21 program).
Refer to L<supermin-helper(1)/ENVIRONMENT VARIABLES> Refer to L<supermin(1)/ENVIRONMENT VARIABLES> for further information.
for further information.
=head1 TRYING OUT A DIFFERENT VERSION OF LIBVIRT =head1 TRYING OUT A DIFFERENT VERSION OF LIBVIRT