mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
appliance: Use supermin >= 5.
This requires the new version of supermin (5.1.0).
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -37,7 +37,10 @@ Makefile.in
|
||||
/align/stamp-virt-alignment-scan.pod
|
||||
/align/virt-alignment-scan
|
||||
/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.1
|
||||
/appliance/make.sh
|
||||
@@ -45,6 +48,7 @@ Makefile.in
|
||||
/appliance/stamp-libguestfs-make-fixed-appliance.pod
|
||||
/appliance/stamp-supermin
|
||||
/appliance/supermin.d
|
||||
/appliance/udev-rules.tar.gz
|
||||
/autom4te.cache
|
||||
/bash/virt-builder
|
||||
/bash/virt-cat
|
||||
|
||||
5
README
5
README
@@ -61,12 +61,11 @@ The full requirements are described below.
|
||||
| | | | - virtio-block |
|
||||
| | | | - virtio-net |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| supermin | 4.1.0 | R | This is required on all distros. |
|
||||
| febootstrap | 3.20 | | 'supermin' is the new name for |
|
||||
| supermin | 5.1.0 | R | This is required on all distros. |
|
||||
| | | | 'supermin' is the new name for |
|
||||
| | | | 'febootstrap'. |
|
||||
| | | | For alternatives, see: |
|
||||
| | | | libguestfs.org/download/binaries/appliance/
|
||||
| | | | febootstrap 2.x WILL NOT WORK |
|
||||
+--------------+-------------+---+-----------------------------------------+
|
||||
| glibc | | R | We use various glibc-isms. |
|
||||
| | | | Also glibc provides XDR, rpcgen. |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 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
|
||||
# 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 = \
|
||||
99-guestfs-serial.rules \
|
||||
excludelist.in \
|
||||
excludefiles.in \
|
||||
guestfsd.suppressions \
|
||||
hostfiles.in \
|
||||
init \
|
||||
libguestfs-make-fixed-appliance.in \
|
||||
libguestfs-make-fixed-appliance.pod \
|
||||
@@ -32,24 +33,42 @@ superminfsdir = $(libdir)/guestfs/supermin.d
|
||||
|
||||
fs_DATA =
|
||||
superminfs_DATA = \
|
||||
supermin.d/init.img \
|
||||
supermin.d/udev-rules.img
|
||||
|
||||
if SUPERMIN_HELPER_COMPRESSED_CPIO
|
||||
GZ = .gz
|
||||
endif
|
||||
supermin.d/init.tar.gz \
|
||||
supermin.d/udev-rules.tar.gz
|
||||
|
||||
if ENABLE_DAEMON
|
||||
superminfs_DATA += \
|
||||
supermin.d/daemon.img$(GZ)
|
||||
supermin.d/daemon.tar.gz
|
||||
endif
|
||||
|
||||
if ENABLE_APPLIANCE
|
||||
superminfs_DATA += \
|
||||
supermin.d/base.img$(GZ) \
|
||||
supermin.d/base.tar.gz \
|
||||
supermin.d/packages \
|
||||
supermin.d/excludefiles \
|
||||
supermin.d/hostfiles
|
||||
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
|
||||
# always touches the destination file, which means the appliance got
|
||||
# rebuilt too often.
|
||||
@@ -65,57 +84,47 @@ if VALGRIND_DAEMON
|
||||
PACKAGELIST_CPP_FLAGS += -DVALGRIND_DAEMON=1
|
||||
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
|
||||
cpp -undef $(PACKAGELIST_CPP_FLAGS) < $< | \
|
||||
m4 $(PACKAGELIST_CPP_FLAGS) $< | \
|
||||
grep -v '^[[:space:]]*$$' | grep -v '^#' > $@-t
|
||||
cmp -s $@ $@-t || mv $@-t $@
|
||||
rm -f $@-t
|
||||
|
||||
excludelist: excludelist.in Makefile
|
||||
cpp -undef $(PACKAGELIST_CPP_FLAGS) < $< | \
|
||||
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
|
||||
daemon.tar.gz: ../daemon/guestfsd guestfsd.suppressions
|
||||
rm -f $@ $@-t
|
||||
rm -rf tmp-d
|
||||
mkdir -p tmp-d$(DAEMON_SUPERMIN_DIR) tmp-d/etc
|
||||
ln ../daemon/guestfsd tmp-d$(DAEMON_SUPERMIN_DIR)/guestfsd
|
||||
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
|
||||
if SUPERMIN_HELPER_COMPRESSED_CPIO
|
||||
gzip -9 -c $@-t > $@-tt
|
||||
mv $@-tt $@-t
|
||||
endif
|
||||
mv $@-t $@
|
||||
|
||||
supermin.d/init.img: init
|
||||
rm -rf init.tmp $@ $@-t
|
||||
mkdir init.tmp
|
||||
cp $< init.tmp
|
||||
(cd init.tmp; echo "init" | cpio --quiet -o -H newc) > $@-t
|
||||
rm -r init.tmp
|
||||
init.tar.gz: init
|
||||
rm -f $@ $@-t
|
||||
tar zcf $@-t init
|
||||
mv $@-t $@
|
||||
|
||||
# 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.
|
||||
supermin.d/udev-rules.img: 99-guestfs-serial.rules
|
||||
udev-rules.tar.gz: 99-guestfs-serial.rules
|
||||
rm -f $@ $@-t
|
||||
rm -rf tmp-u
|
||||
mkdir -p tmp-u/etc/udev/rules.d
|
||||
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
|
||||
mv $@-t $@
|
||||
|
||||
@@ -144,7 +153,14 @@ stamp-libguestfs-make-fixed-appliance.pod: libguestfs-make-fixed-appliance.pod
|
||||
|
||||
# Make clean.
|
||||
|
||||
CLEANFILES = packagelist excludelist \
|
||||
CLEANFILES = \
|
||||
*~ \
|
||||
daemon.tar.gz \
|
||||
excludefiles \
|
||||
hostfiles \
|
||||
init.tar.gz \
|
||||
libguestfs-make-fixed-appliance.1 \
|
||||
packagelist \
|
||||
stamp-libguestfs-make-fixed-appliance.pod \
|
||||
supermin.d/*
|
||||
supermin.d/* \
|
||||
udev-rules.tar.gz
|
||||
|
||||
29
appliance/excludefiles.in
Normal file
29
appliance/excludefiles.in
Normal 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/*
|
||||
@@ -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
13
appliance/hostfiles.in
Normal 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
|
||||
@@ -105,7 +105,7 @@ guestfish -a /dev/null run
|
||||
# Find the location of the appliance.
|
||||
cachedir="$(guestfish get-cachedir)"
|
||||
euid="$(id -u)"
|
||||
appliancedir="$cachedir/.guestfs-$euid"
|
||||
appliancedir="$cachedir/.guestfs-$euid/appliance.d"
|
||||
|
||||
cp "$appliancedir/kernel" "$outputdir/kernel"
|
||||
cp "$appliancedir/initrd" "$outputdir/initrd"
|
||||
|
||||
@@ -130,7 +130,7 @@ be set using the C<LIBGUESTFS_PATH> environment variable.
|
||||
|
||||
Normally a supermin appliance is located on this path (see
|
||||
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
|
||||
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<supermin(1)>,
|
||||
L<supermin-helper(1)>,
|
||||
L<xz(1)>,
|
||||
L<http://libguestfs.org/>,
|
||||
L<http://qemu.org/>.
|
||||
|
||||
@@ -20,42 +20,14 @@ unset CDPATH
|
||||
|
||||
set -e
|
||||
|
||||
# Turn excludelist file into command line arguments.
|
||||
exec 5<excludelist
|
||||
while read regexp <&5; do
|
||||
excludes="$excludes --exclude $regexp"
|
||||
done
|
||||
exec 5<&-
|
||||
# Run supermin.
|
||||
|
||||
# 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
|
||||
extra="--yum-config @SUPERMIN_PACKAGER_CONFIG@"
|
||||
extra="--packager-config @SUPERMIN_PACKAGER_CONFIG@"
|
||||
fi
|
||||
if [ "x@SUPERMIN_EXTRA_OPTIONS@" != "xno" ]; then
|
||||
extra="$extra @SUPERMIN_EXTRA_OPTIONS@"
|
||||
fi
|
||||
|
||||
echo @SUPERMIN@ -v -o supermin.d --names $(< packagelist ) $excludes $extra
|
||||
@SUPERMIN@ -v -o supermin.d --names $(< packagelist ) $excludes $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
|
||||
echo @SUPERMIN@ --prepare -v -o supermin.d $(< packagelist ) $extra
|
||||
@SUPERMIN@ --prepare -v -o supermin.d $(< packagelist ) $extra
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
/* This is the list of distro packages which are
|
||||
* installed on the appliance.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* There is also a list of packages which are excluded if they appear
|
||||
* as dependencies of the packages below. See: excludelist.in
|
||||
*
|
||||
* To add arbitrary extra packages, use:
|
||||
*
|
||||
* ./configure --with-extra-packages="gdb valgrind [etc]"
|
||||
*/
|
||||
dnl This is the list of distro packages which are
|
||||
dnl installed on the appliance.
|
||||
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 There is also a list of packages which are excluded if they appear
|
||||
dnl as dependencies of the packages below. See: excludelist.in
|
||||
dnl
|
||||
dnl To add arbitrary extra packages, use:
|
||||
dnl
|
||||
dnl ./configure --with-extra-packages="gdb valgrind [etc]"
|
||||
|
||||
/* Basically the same with a few minor tweaks. */
|
||||
#ifdef UBUNTU
|
||||
#define DEBIAN 1
|
||||
#endif
|
||||
dnl Basically the same with a few minor tweaks.
|
||||
ifelse(UBUNTU,1,define(DEBIAN,1))
|
||||
|
||||
#ifdef REDHAT
|
||||
ifelse(REDHAT,1,
|
||||
augeas-libs
|
||||
btrfs-progs
|
||||
cryptsetup
|
||||
cryptsetup-luks /* old name used before Fedora 17 */
|
||||
cryptsetup-luks dnl old name used before Fedora 17
|
||||
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
|
||||
genisoimage
|
||||
gfs-utils
|
||||
@@ -40,7 +37,7 @@
|
||||
iputils
|
||||
kernel
|
||||
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
|
||||
ntfsprogs
|
||||
ntfs-3g
|
||||
@@ -49,14 +46,14 @@
|
||||
reiserfs-utils
|
||||
libselinux
|
||||
syslinux-extlinux
|
||||
systemd /* for /sbin/reboot and udevd */
|
||||
systemd dnl for /sbin/reboot and udevd
|
||||
vim-minimal
|
||||
xz
|
||||
yajl
|
||||
zfs-fuse
|
||||
#endif /* REDHAT */
|
||||
)
|
||||
|
||||
#ifdef DEBIAN
|
||||
ifelse(DEBIAN,1,
|
||||
bsdmainutils
|
||||
btrfs-tools
|
||||
cryptsetup
|
||||
@@ -74,21 +71,21 @@
|
||||
libpcre3
|
||||
libyajl2
|
||||
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
|
||||
nilfs-tools
|
||||
ntfs-3g
|
||||
ntfsprogs
|
||||
openssh-client
|
||||
reiserfsprogs
|
||||
sysvinit /* for /sbin/reboot */
|
||||
sysvinit dnl for /sbin/reboot
|
||||
ufsutils
|
||||
vim-tiny
|
||||
xz-utils
|
||||
zfs-fuse
|
||||
#endif /* DEBIAN */
|
||||
)
|
||||
|
||||
#ifdef ARCHLINUX
|
||||
ifelse(ARCHLINUX,1,
|
||||
augeas
|
||||
btrfs-progs
|
||||
cdrkit
|
||||
@@ -111,9 +108,9 @@
|
||||
xz
|
||||
yajl
|
||||
zfs-fuse
|
||||
#endif /* ARCHLINUX */
|
||||
)
|
||||
|
||||
#ifdef FRUGALWARE
|
||||
ifelse(FRUGALWARE,1,
|
||||
augeas
|
||||
btrfs-progs
|
||||
cryptsetup-luks
|
||||
@@ -169,7 +166,7 @@
|
||||
tar
|
||||
util-linux
|
||||
xfsprogs
|
||||
#endif /* FRUGALWARE */
|
||||
)
|
||||
|
||||
acl
|
||||
attr
|
||||
@@ -196,11 +193,9 @@ lvm2
|
||||
lzop
|
||||
mdadm
|
||||
module-init-tools
|
||||
/*
|
||||
Enabling this pulls out 140 extra packages
|
||||
into the appliance:
|
||||
ocfs2-tools
|
||||
*/
|
||||
dnl Enabling this pulls out 140 extra packages
|
||||
dnl into the appliance:
|
||||
dnl ocfs2-tools
|
||||
parted
|
||||
procps
|
||||
procps-ng
|
||||
@@ -214,17 +209,10 @@ tar
|
||||
udev
|
||||
util-linux
|
||||
util-linux-ng
|
||||
#ifndef UBUNTU
|
||||
/* on Ubuntu contains a file in /lib64 which conflicts with libc6 that has
|
||||
* /lib64 as a symbolic link
|
||||
*/
|
||||
xfsprogs
|
||||
#endif
|
||||
zerofree
|
||||
|
||||
#ifdef VALGRIND_DAEMON
|
||||
valgrind
|
||||
#endif
|
||||
ifelse(VALGRIND_DAEMON,1,valgrind)
|
||||
|
||||
/* Define this by doing: ./configure --with-extra-packages="..." */
|
||||
dnl Define this by doing: ./configure --with-extra-packages="..."
|
||||
EXTRA_PACKAGES
|
||||
|
||||
79
configure.ac
79
configure.ac
@@ -447,45 +447,10 @@ AM_CONDITIONAL([ENABLE_APPLIANCE],[test "x$ENABLE_APPLIANCE" = "xyes"])
|
||||
AC_MSG_RESULT([$ENABLE_APPLIANCE])
|
||||
AC_SUBST([ENABLE_APPLIANCE])
|
||||
|
||||
dnl Check for supermin >= 4.1.0 or febootstrap >= 3.20.
|
||||
AC_CHECK_PROGS([SUPERMIN],
|
||||
[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 Check for supermin >= 5.1.0.
|
||||
AC_CHECK_PROGS([SUPERMIN],[supermin],[no])
|
||||
|
||||
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
|
||||
|
||||
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([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])
|
||||
|
||||
dnl Pass additional supermin options.
|
||||
@@ -528,21 +477,35 @@ AC_ARG_WITH([supermin-extra-options],
|
||||
AC_SUBST([SUPERMIN_EXTRA_OPTIONS])
|
||||
|
||||
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" &&
|
||||
AC_MSG_ERROR([supermin (formerly called febootstrap) must be installed])
|
||||
dnl febootstrap 2.x did not support the --version parameter
|
||||
AC_MSG_ERROR([supermin >= $supermin_min must be installed])
|
||||
|
||||
AC_MSG_CHECKING([supermin is new enough])
|
||||
$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
|
||||
|
||||
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
|
||||
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 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])
|
||||
DISTRO=REDHAT
|
||||
if test -f /etc/debian_version; then
|
||||
|
||||
@@ -153,7 +153,7 @@ L<libguestfs-make-fixed-appliance(1)>).
|
||||
|
||||
In our testing we did not find that using a fixed appliance gave any
|
||||
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:
|
||||
|
||||
=over 4
|
||||
@@ -166,14 +166,6 @@ times.
|
||||
|
||||
=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:
|
||||
|
||||
time guestfish -a /dev/null run
|
||||
@@ -567,7 +559,6 @@ bit.
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<supermin(1)>,
|
||||
L<supermin-helper(1)>,
|
||||
L<guestfish(1)>,
|
||||
L<guestfs(3)>,
|
||||
L<guestfs-examples(3)>,
|
||||
|
||||
@@ -1525,10 +1525,10 @@ the path of qemu/KVM.
|
||||
=item SUPERMIN_MODULES
|
||||
|
||||
These two environment variables allow the kernel that libguestfs uses
|
||||
in the appliance to be selected. If C<$SUPERMIN_KERNEL> is not
|
||||
set, then the most recent host kernel is chosen. For more information
|
||||
about kernel selection, see L<supermin-helper(1)>. This
|
||||
feature is only available in supermin / febootstrap E<ge> 3.8.
|
||||
in the appliance to be selected. If C<$SUPERMIN_KERNEL> is not set,
|
||||
then the most recent host kernel is chosen. For more information
|
||||
about kernel selection, see L<supermin(1)>. This feature is only
|
||||
available in supermin / febootstrap E<ge> 3.8.
|
||||
|
||||
=item TMPDIR
|
||||
|
||||
@@ -1629,7 +1629,7 @@ L<virt-win-reg(1)>,
|
||||
L<libguestfs-tools.conf(5)>,
|
||||
L<display(1)>,
|
||||
L<hexedit(1)>,
|
||||
L<supermin-helper(1)>.
|
||||
L<supermin(1)>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
|
||||
693
src/appliance.c
693
src/appliance.c
@@ -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_fixed_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 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 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);
|
||||
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 run_supermin_build (guestfs_h *g, const char *lockfile, const char *appliancedir, const char *supermin_path);
|
||||
|
||||
/* 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
|
||||
* 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
|
||||
* 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.
|
||||
* (3) Check each element of g->path, looking for a fixed appliance.
|
||||
* 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.
|
||||
*
|
||||
* The supermin appliance cache directory lives in
|
||||
* $TMPDIR/.guestfs-$UID/ and consists of up to five files:
|
||||
*
|
||||
* $TMPDIR/.guestfs-$UID/checksum - the checksum
|
||||
* $TMPDIR/.guestfs-$UID/kernel - the kernel
|
||||
* $TMPDIR/.guestfs-$UID/dtb - the device tree (on ARM)
|
||||
* $TMPDIR/.guestfs-$UID/initrd - the supermin initrd
|
||||
* $TMPDIR/.guestfs-$UID/root - the appliance
|
||||
* $TMPDIR/.guestfs-$UID/lock - the supermin lock file
|
||||
* $TMPDIR/.guestfs-$UID/appliance.d/kernel - the kernel
|
||||
* $TMPDIR/.guestfs-$UID/appliance.d/dtb - the device tree (on ARM)
|
||||
* $TMPDIR/.guestfs-$UID/appliance.d/initrd - the supermin initrd
|
||||
* $TMPDIR/.guestfs-$UID/appliance.d/root - the appliance
|
||||
*
|
||||
* Since multiple instances of libguestfs with the same UID may be
|
||||
* racing to create an appliance, we need to be careful when building
|
||||
* and using the appliance.
|
||||
*
|
||||
* 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.
|
||||
* Multiple instances of libguestfs with the same UID may be racing to
|
||||
* create an appliance. However (since supermin >= 5) supermin
|
||||
* provides a --lock flag and atomic update of the appliance.d
|
||||
* subdirectory.
|
||||
*/
|
||||
int
|
||||
guestfs___build_appliance (guestfs_h *g,
|
||||
@@ -145,14 +106,9 @@ guestfs___build_appliance (guestfs_h *g,
|
||||
char **initrd_rtn,
|
||||
char **appliance_rtn)
|
||||
{
|
||||
int r;
|
||||
char *kernel, *dtb, *initrd, *appliance;
|
||||
|
||||
gl_lock_lock (building_lock);
|
||||
r = build_appliance (g, &kernel, &dtb, &initrd, &appliance);
|
||||
gl_lock_unlock (building_lock);
|
||||
|
||||
if (r == -1)
|
||||
if (build_appliance (g, &kernel, &dtb, &initrd, &appliance) == -1)
|
||||
return -1;
|
||||
|
||||
/* 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)
|
||||
return -1;
|
||||
|
||||
if (r == 1) {
|
||||
/* Step (2): calculate checksum. */
|
||||
CLEANUP_FREE char *checksum =
|
||||
calculate_supermin_checksum (g, supermin_path);
|
||||
if (checksum) {
|
||||
/* Step (3): cached appliance exists? */
|
||||
r = check_for_cached_appliance (g, supermin_path, checksum, uid,
|
||||
if (r == 1)
|
||||
/* Step (2): build supermin appliance. */
|
||||
return build_supermin_appliance (g, supermin_path, uid,
|
||||
kernel, dtb, initrd, appliance);
|
||||
if (r != 0)
|
||||
return r == 1 ? 0 : -1;
|
||||
|
||||
/* Step (4): build supermin appliance. */
|
||||
return build_supermin_appliance (g, supermin_path, checksum, uid,
|
||||
kernel, dtb, initrd, appliance);
|
||||
}
|
||||
}
|
||||
|
||||
/* Step (5). */
|
||||
/* Step (3). */
|
||||
r = find_path (g, contains_fixed_appliance, NULL, &path);
|
||||
if (r == -1)
|
||||
return -1;
|
||||
@@ -223,7 +167,7 @@ build_appliance (guestfs_h *g,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Step (6). */
|
||||
/* Step (4). */
|
||||
r = find_path (g, contains_old_style_appliance, NULL, &path);
|
||||
if (r == -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);
|
||||
}
|
||||
|
||||
#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.
|
||||
*
|
||||
* Returns:
|
||||
@@ -446,222 +216,87 @@ check_for_cached_appliance (guestfs_h *g,
|
||||
*/
|
||||
static int
|
||||
build_supermin_appliance (guestfs_h *g,
|
||||
const char *supermin_path, const char *checksum,
|
||||
const char *supermin_path,
|
||||
uid_t uid,
|
||||
char **kernel, char **dtb,
|
||||
char **initrd, char **appliance)
|
||||
{
|
||||
CLEANUP_FREE char *tmpdir = guestfs_get_cachedir (g);
|
||||
struct stat statbuf;
|
||||
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
|
||||
* generate in this function.
|
||||
*/
|
||||
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. */
|
||||
char tmpcd[len];
|
||||
snprintf (tmpcd, len, "%s/guestfs.XXXXXX", tmpdir);
|
||||
ignore_value (mkdir (cachedir, 0755));
|
||||
ignore_value (chmod (cachedir, 0755)); /* RHBZ#921292 */
|
||||
|
||||
if (mkdtemp (tmpcd) == NULL) {
|
||||
perrorf (g, "mkdtemp");
|
||||
/* See if the cache directory exists and passes some simple checks
|
||||
* 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;
|
||||
}
|
||||
|
||||
(void) utimes (cachedir, NULL);
|
||||
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);
|
||||
if (r == -1) {
|
||||
guestfs___recursive_remove_dir (g, tmpcd);
|
||||
/* Build the appliance if it needs to be built. */
|
||||
if (g->verbose)
|
||||
guestfs___print_timestamped_message (g, "run supermin");
|
||||
|
||||
if (run_supermin_build (g, lockfile, appliancedir, supermin_path) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g->verbose)
|
||||
guestfs___print_timestamped_message (g, "finished building supermin appliance");
|
||||
|
||||
char cachedir[len];
|
||||
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;
|
||||
|
||||
/* Return the appliance filenames. */
|
||||
*kernel = safe_malloc (g, len);
|
||||
#ifdef DTB_WILDCARD
|
||||
*dtb = safe_malloc (g, len);
|
||||
#else
|
||||
*dtb = NULL;
|
||||
#endif
|
||||
*initrd = safe_malloc (g, len);
|
||||
*appliance = safe_malloc (g, len);
|
||||
snprintf (*kernel, len, "%s/kernel.%d", cachedir, pid);
|
||||
snprintf (*dtb, len, "%s/dtb.%d", cachedir, pid);
|
||||
snprintf (*initrd, len, "%s/initrd.%d", cachedir, pid);
|
||||
snprintf (*appliance, len, "%s/root.%d", cachedir, pid);
|
||||
snprintf (*kernel, len, "%s/kernel", appliancedir);
|
||||
#ifdef DTB_WILDCARD
|
||||
snprintf (*dtb, len, "%s/dtb", appliancedir);
|
||||
#endif
|
||||
snprintf (*initrd, len, "%s/initrd", appliancedir);
|
||||
snprintf (*appliance, len, "%s/root", appliancedir);
|
||||
|
||||
char filename[len];
|
||||
snprintf (filename, len, "%s/kernel", cachedir);
|
||||
(void) unlink (*kernel);
|
||||
if (link (filename, *kernel) == -1) {
|
||||
perrorf (g, "link: %s %s", filename, *kernel);
|
||||
goto error;
|
||||
}
|
||||
(void) utimes (filename, NULL);
|
||||
/* Touch the files so they don't get deleted (as they are in /var/tmp). */
|
||||
(void) utimes (*kernel, NULL);
|
||||
#ifdef DTB_WILDCARD
|
||||
(void) utimes (*dtb, NULL);
|
||||
#endif
|
||||
(void) utimes (*initrd, 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
|
||||
* 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
|
||||
@@ -675,211 +310,69 @@ hard_link_to_cached_appliance (guestfs_h *g,
|
||||
* XXX
|
||||
*/
|
||||
if (STRNEQ (g->backend, "uml"))
|
||||
(void) utime (filename, NULL);
|
||||
(void) utimes (*appliance, NULL);
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#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
|
||||
run_supermin_helper (guestfs_h *g, const char *supermin_path,
|
||||
const char *cachedir)
|
||||
run_supermin_build (guestfs_h *g,
|
||||
const char *lockfile,
|
||||
const char *appliancedir,
|
||||
const char *supermin_path)
|
||||
{
|
||||
CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g);
|
||||
int r;
|
||||
#if 0 /* not supported in supermin 5 yet XXX */
|
||||
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;
|
||||
#endif
|
||||
|
||||
guestfs___cmd_add_arg (cmd, SUPERMIN_HELPER);
|
||||
guestfs___cmd_add_arg (cmd, SUPERMIN);
|
||||
guestfs___cmd_add_arg (cmd, "--build");
|
||||
if (g->verbose)
|
||||
guestfs___cmd_add_arg (cmd, "--verbose");
|
||||
#if 0
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
guestfs___cmd_add_arg (cmd, "--copy-kernel");
|
||||
guestfs___cmd_add_arg (cmd, "-f");
|
||||
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, "--if-newer");
|
||||
guestfs___cmd_add_arg (cmd, "--lock");
|
||||
guestfs___cmd_add_arg (cmd, lockfile);
|
||||
#ifdef DTB_WILDCARD
|
||||
guestfs___cmd_add_arg (cmd, "--dtb");
|
||||
guestfs___cmd_add_arg (cmd, DTB_WILDCARD);
|
||||
#endif
|
||||
guestfs___cmd_add_arg_format (cmd, "%s/supermin.d", supermin_path);
|
||||
guestfs___cmd_add_arg (cmd, "--output-kernel");
|
||||
guestfs___cmd_add_arg_format (cmd, "%s/kernel", cachedir);
|
||||
#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);
|
||||
guestfs___cmd_add_arg (cmd, "-o");
|
||||
guestfs___cmd_add_arg (cmd, appliancedir);
|
||||
|
||||
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);
|
||||
guestfs___external_command_failed (g, r, SUPERMIN, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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
|
||||
* matches the predicate function 'pred'.
|
||||
*
|
||||
|
||||
@@ -3477,15 +3477,14 @@ debugging (set the environment variable C<LIBGUESTFS_DEBUG=1>).
|
||||
|
||||
=item Create the appliance
|
||||
|
||||
C<supermin-helper> is invoked to create the kernel, a
|
||||
small initrd and the appliance.
|
||||
C<supermin --build> is invoked to create the kernel, a small initrd
|
||||
and the appliance.
|
||||
|
||||
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).
|
||||
|
||||
For a complete description of how the appliance is created and cached,
|
||||
read the L<supermin(1)> and L<supermin-helper(1)> man
|
||||
pages.
|
||||
read the L<supermin(1)> man page.
|
||||
|
||||
=item Start qemu and boot the kernel
|
||||
|
||||
@@ -3493,12 +3492,12 @@ qemu is invoked to boot the kernel.
|
||||
|
||||
=item Run the initrd
|
||||
|
||||
C<supermin-helper> builds a small initrd. The initrd is
|
||||
not the appliance. The purpose of the initrd is to load enough kernel
|
||||
modules in order that the appliance itself can be mounted and started.
|
||||
C<supermin --build> builds a small initrd. The initrd is not the
|
||||
appliance. The purpose of the initrd is to load enough kernel modules
|
||||
in order that the appliance itself can be mounted and started.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
in the appliance to be selected. If C<$SUPERMIN_KERNEL> is not
|
||||
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.
|
||||
|
||||
=item TMPDIR
|
||||
@@ -4758,7 +4758,6 @@ L<guestfs-testing(1)>,
|
||||
L<libguestfs-test-tool(1)>,
|
||||
L<libguestfs-make-fixed-appliance(1)>,
|
||||
L<supermin(1)>,
|
||||
L<supermin-helper(1)>,
|
||||
L<qemu(1)>,
|
||||
L<hivex(3)>,
|
||||
L<stap(1)>,
|
||||
|
||||
@@ -87,8 +87,7 @@ variables C<SUPERMIN_KERNEL> and/or C<SUPERMIN_MODULES>
|
||||
(C<FEBOOTSTRAP_KERNEL> and C<FEBOOTSTRAP_MODULES> if still using the
|
||||
old febootstrap 3.21 program).
|
||||
|
||||
Refer to L<supermin-helper(1)/ENVIRONMENT VARIABLES>
|
||||
for further information.
|
||||
Refer to L<supermin(1)/ENVIRONMENT VARIABLES> for further information.
|
||||
|
||||
=head1 TRYING OUT A DIFFERENT VERSION OF LIBVIRT
|
||||
|
||||
|
||||
Reference in New Issue
Block a user