mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Unify supermin appliance building using febootstrap 2.7
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -9,16 +9,12 @@ appliance/debian/root/
|
||||
appliance/debian/vmlinuz-*
|
||||
appliance/debian/debirf.conf
|
||||
appliance/initramfs.*.img
|
||||
appliance/initramfs.*.supermin.hostfiles
|
||||
appliance/kmod.whitelist
|
||||
appliance/libguestfs-supermin-helper
|
||||
appliance/libguestfs-supermin-helper.old
|
||||
appliance/make.sh
|
||||
appliance/packagelist
|
||||
appliance/stamp-debirf-modules
|
||||
appliance/supermin.incfiles
|
||||
appliance/supermin-make.sh
|
||||
appliance/supermin-split.sh
|
||||
appliance/stamp-supermin
|
||||
appliance/supermin.d
|
||||
appliance/update.sh
|
||||
appliance/vmlinuz.*
|
||||
autom4te.cache
|
||||
|
||||
2
README
2
README
@@ -40,7 +40,7 @@ Requirements
|
||||
- recent QEMU >= 0.10 with vmchannel support
|
||||
http://lists.gnu.org/archive/html/qemu-devel/2009-02/msg01042.html
|
||||
|
||||
- febootstrap >= 2.3
|
||||
- febootstrap >= 2.7
|
||||
|
||||
- fakeroot
|
||||
|
||||
|
||||
@@ -32,35 +32,24 @@ EXTRA_DIST = \
|
||||
# $(libdir) is best. When we build cross-architecture filesystems we
|
||||
# should probably move them to $(datadir).
|
||||
fsdir = $(libdir)/guestfs
|
||||
fs_DATA = $(APPLIANCE_FILES)
|
||||
superminfsdir = $(libdir)/guestfs/supermin.d
|
||||
|
||||
# These are the resulting output files from the whole process:
|
||||
# VMLINUZ kernel for the full appliance
|
||||
# INITRAMFSIMG initramfs (ie. root fs) for the full appliance
|
||||
# For details of the supermin appliance, read the README file:
|
||||
# SUPERMINIMG initramfs (ie. partial root fs) for the supermin appliance
|
||||
# SUPERMINFILES list of missing files (the ones we will pull out of the
|
||||
# host filesystem at runtime) in the supermin appliance
|
||||
APPLIANCE_FILES = $(INITRAMFSIMG) $(VMLINUZ)
|
||||
# For details of the supermin appliance, read the README file.
|
||||
fs_DATA = $(INITRAMFSIMG) $(VMLINUZ)
|
||||
if SUPERMIN
|
||||
APPLIANCE_FILES += $(SUPERMINIMG) $(SUPERMINFILES) kmod.whitelist
|
||||
bin_PROGRAMS = libguestfs-supermin-helper
|
||||
libguestfs_supermin_helper_SOURCES = \
|
||||
libguestfs-supermin-helper.c ../gnulib/lib/xalloc-die.c
|
||||
libguestfs_supermin_helper_CFLAGS = \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
libguestfs_supermin_helper_LDADD = \
|
||||
../gnulib/lib/libgnu.la
|
||||
fs_DATA += kmod.whitelist
|
||||
superminfs_DATA = \
|
||||
supermin.d/base.img \
|
||||
supermin.d/daemon.img \
|
||||
supermin.d/hostfiles
|
||||
endif
|
||||
|
||||
# Don't change these names - they must be the same as in '*.sh' scripts.
|
||||
INITRAMFSIMG = initramfs.$(REPO).$(host_cpu).img
|
||||
VMLINUZ = vmlinuz.$(REPO).$(host_cpu)
|
||||
if SUPERMIN
|
||||
SUPERMINIMG = initramfs.$(REPO).$(host_cpu).supermin.img
|
||||
SUPERMINFILES = initramfs.$(REPO).$(host_cpu).supermin.hostfiles
|
||||
endif
|
||||
|
||||
# This is for building the normal appliance:
|
||||
$(INITRAMFSIMG) $(VMLINUZ): $(top_builddir)/initramfs/fakeroot.log
|
||||
@@ -97,19 +86,19 @@ packagelist: packagelist.in
|
||||
|
||||
if SUPERMIN
|
||||
|
||||
# First we need to decide which files go in and out of the supermin
|
||||
# appliance. This decision is made by 'supermin-split.sh'.
|
||||
$(SUPERMINFILES): supermin.incfiles
|
||||
supermin.incfiles: $(top_builddir)/initramfs/fakeroot.log $(top_builddir)/daemon/guestfsd supermin-split.sh
|
||||
rm -f supermin.incfiles $(SUPERMINFILES)
|
||||
bash supermin-split.sh
|
||||
|
||||
# Second we need to create a supermin appliance with just the included
|
||||
# files (leaving out the host files, which we'll add back at runtime).
|
||||
$(SUPERMINIMG): supermin.incfiles supermin-make.sh
|
||||
rm -f $@
|
||||
bash supermin-make.sh
|
||||
supermin.d/base.img supermin.d/hostfiles: stamp-supermin
|
||||
stamp-supermin: $(top_builddir)/initramfs/fakeroot.log $(top_builddir)/initramfs/init
|
||||
mkdir -p supermin.d
|
||||
rm -f $@ supermin.d/base.img supermin.d/hostfiles
|
||||
febootstrap-to-supermin $(top_builddir)/initramfs supermin.d/base.img supermin.d/hostfiles
|
||||
touch $@
|
||||
|
||||
supermin.d/daemon.img: $(top_builddir)/initramfs/sbin/guestfsd
|
||||
mkdir -p supermin.d
|
||||
rm -f $@ $@-t
|
||||
(cd $(top_builddir)/initramfs && \
|
||||
echo -e "sbin\nsbin/guestfsd" | cpio --quiet -o -H newc ) > $@-t
|
||||
mv $@-t $@
|
||||
endif
|
||||
|
||||
# Extra symlinks needed by the Debian appliance.
|
||||
@@ -160,7 +149,8 @@ test-boot-realistic: emptydisk
|
||||
|
||||
# Make clean.
|
||||
|
||||
CLEANFILES = $(APPLIANCE_FILES) packagelist kmod.whitelist supermin.incfiles
|
||||
CLEANFILES = packagelist kmod.whitelist
|
||||
|
||||
clean-local:
|
||||
rm -f supermin.d/*
|
||||
rm -rf $(top_builddir)/initramfs
|
||||
|
||||
@@ -5,6 +5,8 @@ echo Starting /init script ...
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
export PATH
|
||||
|
||||
mkdir -p /sysroot
|
||||
|
||||
mount -t proc /proc /proc
|
||||
mount -t sysfs /sys /sys
|
||||
|
||||
|
||||
@@ -1,919 +0,0 @@
|
||||
/* libguestfs-supermin-helper reimplementation in C.
|
||||
* Copyright (C) 2009-2010 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* This script builds the supermin appliance on the fly each
|
||||
* time the appliance runs.
|
||||
*
|
||||
* *NOTE*: This program is designed to be very short-lived, and so we
|
||||
* don't normally bother to free up any memory that we allocate.
|
||||
* That's not completely true - we free up stuff if it's obvious and
|
||||
* easy to free up, and ignore the rest.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "filevercmp.h"
|
||||
#include "fts_.h"
|
||||
#include "full-write.h"
|
||||
#include "hash.h"
|
||||
#include "hash-pjw.h"
|
||||
#include "xalloc.h"
|
||||
#include "xvasprintf.h"
|
||||
|
||||
/* Directory containing candidate kernels. We could make this
|
||||
* configurable at some point.
|
||||
*/
|
||||
#define KERNELDIR "/boot"
|
||||
#define MODULESDIR "/lib/modules"
|
||||
|
||||
/* Buffer size used in copy operations throughout. Large for
|
||||
* greatest efficiency.
|
||||
*/
|
||||
#define BUFFER_SIZE 65536
|
||||
|
||||
static struct timeval start_t;
|
||||
static int verbose = 0;
|
||||
|
||||
static void print_timestamped_message (const char *fs, ...);
|
||||
static const char *create_kernel (const char *hostcpu, const char *kernel);
|
||||
static void create_appliance (const char *sourcedir, const char *hostcpu, const char *repo, const char *modpath, const char *initrd);
|
||||
|
||||
enum { HELP_OPTION = CHAR_MAX + 1 };
|
||||
|
||||
static const char *options = "vV";
|
||||
static const struct option long_options[] = {
|
||||
{ "help", 0, 0, HELP_OPTION },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ "version", 0, 0, 'V' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
usage (const char *progname)
|
||||
{
|
||||
printf ("%s: build the supermin appliance on the fly\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
" %s [-options] sourcedir host_cpu repo kernel initrd\n"
|
||||
" %s --help\n"
|
||||
" %s --version\n"
|
||||
"\n"
|
||||
"This script is used by libguestfs to build the supermin appliance\n"
|
||||
"(kernel and initrd output files). You should NOT need to run this\n"
|
||||
"program directly except if you are debugging tricky supermin\n"
|
||||
"appliance problems.\n"
|
||||
"\n"
|
||||
"NB: The kernel and initrd parameters are OUTPUT parameters. If\n"
|
||||
"those files exist, they are overwritten by the output.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" --help\n"
|
||||
" Display this help text and exit.\n"
|
||||
" --verbose | -v\n"
|
||||
" Enable verbose messages (give multiple times for more verbosity).\n"
|
||||
" --version | -V\n"
|
||||
" Display version number and exit.\n"
|
||||
"\n"
|
||||
"Typical usage when debugging supermin appliance problems:\n"
|
||||
" %s -v /usr/lib*/guestfs x86_64 fedora-12 /tmp/kernel /tmp/initrd\n"
|
||||
"Note: This will OVERWRITE any existing files called /tmp/kernel\n"
|
||||
"and /tmp/initrd.\n",
|
||||
progname, progname, progname, progname, progname);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
/* First thing: start the clock. */
|
||||
gettimeofday (&start_t, NULL);
|
||||
|
||||
/* Command line arguments. */
|
||||
for (;;) {
|
||||
int c = getopt_long (argc, argv, options, long_options, NULL);
|
||||
if (c == -1) break;
|
||||
|
||||
switch (c) {
|
||||
case HELP_OPTION:
|
||||
usage (argv[0]);
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
printf (PACKAGE_NAME " " PACKAGE_VERSION "\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
default:
|
||||
usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind != 5) {
|
||||
usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char *sourcedir = argv[optind];
|
||||
|
||||
/* Host CPU and repo constants passed from the library (see:
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=558593).
|
||||
*/
|
||||
const char *hostcpu = argv[optind+1];
|
||||
const char *repo = argv[optind+2];
|
||||
|
||||
/* Output files. */
|
||||
const char *kernel = argv[optind+3];
|
||||
const char *initrd = argv[optind+4];
|
||||
|
||||
if (verbose)
|
||||
print_timestamped_message ("sourcedir = %s, "
|
||||
"host_cpu = %s, "
|
||||
"repo = %s, "
|
||||
"kernel = %s, "
|
||||
"initrd = %s",
|
||||
sourcedir, hostcpu, repo, kernel, initrd);
|
||||
|
||||
/* Remove the output files if they exist. */
|
||||
unlink (kernel);
|
||||
unlink (initrd);
|
||||
|
||||
/* Create kernel output file. */
|
||||
const char *modpath;
|
||||
modpath = create_kernel (hostcpu, kernel);
|
||||
|
||||
if (verbose)
|
||||
print_timestamped_message ("finished creating kernel");
|
||||
|
||||
/* Create the appliance. */
|
||||
create_appliance (sourcedir, hostcpu, repo, modpath, initrd);
|
||||
|
||||
if (verbose)
|
||||
print_timestamped_message ("finished creating appliance");
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Compute Y - X and return the result in milliseconds.
|
||||
* Approximately the same as this code:
|
||||
* http://www.mpp.mpg.de/~huber/util/timevaldiff.c
|
||||
*/
|
||||
static int64_t
|
||||
timeval_diff (const struct timeval *x, const struct timeval *y)
|
||||
{
|
||||
int64_t msec;
|
||||
|
||||
msec = (y->tv_sec - x->tv_sec) * 1000;
|
||||
msec += (y->tv_usec - x->tv_usec) / 1000;
|
||||
return msec;
|
||||
}
|
||||
|
||||
static void
|
||||
print_timestamped_message (const char *fs, ...)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday (&tv, NULL);
|
||||
|
||||
va_list args;
|
||||
char *msg;
|
||||
int err;
|
||||
|
||||
va_start (args, fs);
|
||||
err = vasprintf (&msg, fs, args);
|
||||
va_end (args);
|
||||
|
||||
if (err < 0) return;
|
||||
|
||||
fprintf (stderr, "supermin helper [%05" PRIi64 "ms] %s\n",
|
||||
timeval_diff (&start_t, &tv), msg);
|
||||
|
||||
free (msg);
|
||||
}
|
||||
|
||||
static char **read_dir (const char *dir);
|
||||
static char **filter_fnmatch (char **strings, const char *patt, int flags);
|
||||
static char **filter_notmatching_substring (char **strings, const char *sub);
|
||||
static void sort (char **strings, int (*compare) (const void *, const void *));
|
||||
static int isdir (const char *path);
|
||||
|
||||
static int
|
||||
reverse_filevercmp (const void *p1, const void *p2)
|
||||
{
|
||||
const char *s1 = * (char * const *) p1;
|
||||
const char *s2 = * (char * const *) p2;
|
||||
|
||||
/* Note, arguments are reversed to achieve a reverse sort. */
|
||||
return filevercmp (s2, s1);
|
||||
}
|
||||
|
||||
/* Create the kernel. This chooses an appropriate kernel and makes a
|
||||
* symlink to it.
|
||||
*
|
||||
* Look for the most recent kernel named vmlinuz-*.<arch>* which has a
|
||||
* corresponding directory in /lib/modules/. If the architecture is
|
||||
* x86, look for any x86 kernel.
|
||||
*
|
||||
* RHEL 5 didn't append the arch to the kernel name, so look for
|
||||
* kernels without arch second.
|
||||
*
|
||||
* If no suitable kernel can be found, exit with an error.
|
||||
*
|
||||
* This function returns the module path (ie. /lib/modules/<version>).
|
||||
*/
|
||||
static const char *
|
||||
create_kernel (const char *hostcpu, const char *kernel)
|
||||
{
|
||||
char **all_files = read_dir (KERNELDIR);
|
||||
|
||||
/* In original: ls -1dvr /boot/vmlinuz-*.$arch* 2>/dev/null | grep -v xen */
|
||||
const char *patt;
|
||||
if (hostcpu[0] == 'i' && hostcpu[2] == '8' && hostcpu[3] == '6' &&
|
||||
hostcpu[4] == '\0')
|
||||
patt = "vmlinuz-*.i?86*";
|
||||
else
|
||||
patt = xasprintf ("vmlinuz-*.%s*", hostcpu);
|
||||
|
||||
char **candidates;
|
||||
candidates = filter_fnmatch (all_files, patt, FNM_NOESCAPE);
|
||||
candidates = filter_notmatching_substring (candidates, "xen");
|
||||
|
||||
if (candidates[0] == NULL) {
|
||||
/* In original: ls -1dvr /boot/vmlinuz-* 2>/dev/null | grep -v xen */
|
||||
patt = "vmlinuz-*";
|
||||
candidates = filter_fnmatch (all_files, patt, FNM_NOESCAPE);
|
||||
candidates = filter_notmatching_substring (candidates, "xen");
|
||||
|
||||
if (candidates[0] == NULL)
|
||||
goto no_kernels;
|
||||
}
|
||||
|
||||
sort (candidates, reverse_filevercmp);
|
||||
|
||||
/* Choose the first candidate which has a corresponding /lib/modules
|
||||
* directory.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; candidates[i] != NULL; ++i) {
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "candidate kernel: " KERNELDIR "/%s\n", candidates[i]);
|
||||
|
||||
/* Ignore "vmlinuz-" at the beginning of the kernel name. */
|
||||
const char *version = &candidates[i][8];
|
||||
|
||||
/* /lib/modules/<version> */
|
||||
char *modpath = xasprintf (MODULESDIR "/%s", version);
|
||||
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "checking modpath %s is a directory\n", modpath);
|
||||
|
||||
if (isdir (modpath)) {
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "picked %s because modpath %s exists\n",
|
||||
candidates[i], modpath);
|
||||
|
||||
char *tmp = xasprintf (KERNELDIR "/%s", candidates[i]);
|
||||
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "creating symlink %s -> %s\n", kernel, tmp);
|
||||
|
||||
if (symlink (tmp, kernel) == -1)
|
||||
error (EXIT_FAILURE, errno, "symlink kernel");
|
||||
|
||||
free (tmp);
|
||||
|
||||
return modpath;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print more diagnostics here than the old script did. */
|
||||
no_kernels:
|
||||
fprintf (stderr,
|
||||
"libguestfs-supermin-helper: failed to find a suitable kernel.\n"
|
||||
"I looked for kernels in " KERNELDIR " and modules in " MODULESDIR
|
||||
".\n"
|
||||
"If this is a Xen guest, and you only have Xen domU kernels\n"
|
||||
"installed, try installing a fullvirt kernel (only for\n"
|
||||
"libguestfs use, you shouldn't boot the Xen guest with it).\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void write_kernel_modules (const char *sourcedir, const char *modpath);
|
||||
static void write_hostfiles (const char *sourcedir, const char *hostcpu, const char *repo);
|
||||
static void write_to_fd (const void *buffer, size_t len);
|
||||
static void write_file_to_fd (const char *filename);
|
||||
static void write_file_len_to_fd (const char *filename, size_t len);
|
||||
static void write_padding (size_t len);
|
||||
static char **load_file (const char *filename);
|
||||
static void cpio_append_fts_entry (FTSENT *entry);
|
||||
static void cpio_append_stat (const char *filename, struct stat *);
|
||||
static void cpio_append (const char *filename);
|
||||
static void cpio_append_trailer (void);
|
||||
|
||||
static int out_fd = -1;
|
||||
static off_t out_offset = 0;
|
||||
|
||||
/* Create the appliance.
|
||||
*
|
||||
* The initrd consists of these components concatenated together:
|
||||
*
|
||||
* (1) The base skeleton appliance that we constructed at build time.
|
||||
* name = initramfs.$repo.$host_cpu.supermin.img
|
||||
* format = plain cpio
|
||||
* (2) The modules from modpath which are on the module whitelist.
|
||||
* format = plain cpio
|
||||
* (3) The host files which match wildcards in *.supermin.hostfiles.
|
||||
* format = plain cpio
|
||||
*
|
||||
* The original shell scripted used the external cpio program to
|
||||
* create parts (2) and (3), but we have decided it's going to be
|
||||
* faster if we just write out the data outselves. The reasons are
|
||||
* that external cpio is slow (particularly when used with SELinux
|
||||
* because it does 512 byte reads), and the format that we're writing
|
||||
* is narrow and well understood, because we only care that the Linux
|
||||
* kernel can read it.
|
||||
*/
|
||||
static void
|
||||
create_appliance (const char *sourcedir,
|
||||
const char *hostcpu, const char *repo,
|
||||
const char *modpath,
|
||||
const char *initrd)
|
||||
{
|
||||
out_fd = open (initrd, O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY, 0644);
|
||||
if (out_fd == -1)
|
||||
error (EXIT_FAILURE, errno, "open: %s", initrd);
|
||||
out_offset = 0;
|
||||
|
||||
/* Copy the base skeleton appliance (1). */
|
||||
char *tmp = xasprintf ("%s/initramfs.%s.%s.supermin.img",
|
||||
sourcedir, repo, hostcpu);
|
||||
write_file_to_fd (tmp);
|
||||
free (tmp);
|
||||
|
||||
/* Kernel modules (2). */
|
||||
write_kernel_modules (sourcedir, modpath);
|
||||
|
||||
/* Copy hostfiles (3). */
|
||||
write_hostfiles (sourcedir, hostcpu, repo);
|
||||
|
||||
cpio_append_trailer ();
|
||||
|
||||
/* Finish off and close output file. */
|
||||
if (close (out_fd) == -1)
|
||||
error (EXIT_FAILURE, errno, "close: %s", initrd);
|
||||
}
|
||||
|
||||
/* Copy kernel modules.
|
||||
*
|
||||
* Find every file under modpath.
|
||||
*
|
||||
* Exclude all *.ko files, *except* ones which match names in
|
||||
* the whitelist (which may contain wildcards). Include all
|
||||
* other files.
|
||||
*
|
||||
* Add chosen files to the output.
|
||||
*/
|
||||
static void
|
||||
write_kernel_modules (const char *sourcedir, const char *modpath)
|
||||
{
|
||||
char *tmp = xasprintf ("%s/kmod.whitelist", sourcedir);
|
||||
char **whitelist = load_file (tmp);
|
||||
free (tmp);
|
||||
|
||||
char *paths[2] = { (char *) modpath, NULL };
|
||||
FTS *fts = fts_open (paths, FTS_COMFOLLOW|FTS_PHYSICAL, NULL);
|
||||
if (fts == NULL)
|
||||
error (EXIT_FAILURE, errno, "write_kernel_modules: fts_open: %s", modpath);
|
||||
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
FTSENT *entry = fts_read (fts);
|
||||
if (entry == NULL && errno != 0)
|
||||
error (EXIT_FAILURE, errno, "write_kernel_modules: fts_read: %s", modpath);
|
||||
if (entry == NULL)
|
||||
break;
|
||||
|
||||
/* Ignore directories being visited in post-order. */
|
||||
if (entry->fts_info & FTS_DP)
|
||||
continue;
|
||||
|
||||
/* Is it a *.ko file? */
|
||||
if (entry->fts_namelen >= 3 &&
|
||||
entry->fts_name[entry->fts_namelen-3] == '.' &&
|
||||
entry->fts_name[entry->fts_namelen-2] == 'k' &&
|
||||
entry->fts_name[entry->fts_namelen-1] == 'o') {
|
||||
/* Is it a *.ko file which is on the whitelist? */
|
||||
size_t j;
|
||||
for (j = 0; whitelist[j] != NULL; ++j) {
|
||||
int r;
|
||||
r = fnmatch (whitelist[j], entry->fts_name, 0);
|
||||
if (r == 0) {
|
||||
/* It's on the whitelist, so include it. */
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "including kernel module %s (matches whitelist entry %s)\n",
|
||||
entry->fts_name, whitelist[j]);
|
||||
cpio_append_fts_entry (entry);
|
||||
break;
|
||||
} else if (r != FNM_NOMATCH)
|
||||
error (EXIT_FAILURE, 0, "internal error: fnmatch ('%s', '%s', %d) returned unexpected non-zero value %d\n",
|
||||
whitelist[j], entry->fts_name, 0, r);
|
||||
} /* for (j) */
|
||||
} else
|
||||
/* It's some other sort of file, or a directory, always include. */
|
||||
cpio_append_fts_entry (entry);
|
||||
}
|
||||
|
||||
if (fts_close (fts) == -1)
|
||||
error (EXIT_FAILURE, errno, "write_kernel_modules: fts_close: %s", modpath);
|
||||
}
|
||||
|
||||
/* Copy the host files.
|
||||
*
|
||||
* Read the list of entries in *.supermin.hostfiles (which may contain
|
||||
* wildcards). Look them up in the filesystem, and add those files
|
||||
* that exist. Ignore any files that don't exist or are not readable.
|
||||
*/
|
||||
static void
|
||||
write_hostfiles (const char *sourcedir, const char *hostcpu, const char *repo)
|
||||
{
|
||||
char *tmp = xasprintf ("%s/initramfs.%s.%s.supermin.hostfiles",
|
||||
sourcedir, repo, hostcpu);
|
||||
char **hostfiles = load_file (tmp);
|
||||
free (tmp);
|
||||
|
||||
/* Hostfiles list can contain "." before each path - ignore it.
|
||||
* It also contains each directory name before we enter it. But
|
||||
* we don't read that until we see a wildcard for that directory.
|
||||
*/
|
||||
size_t i, j;
|
||||
for (i = 0; hostfiles[i] != NULL; ++i) {
|
||||
char *hostfile = hostfiles[i];
|
||||
if (hostfile[0] == '.')
|
||||
hostfile++;
|
||||
|
||||
struct stat statbuf;
|
||||
|
||||
/* Is it a wildcard? */
|
||||
if (strchr (hostfile, '*') || strchr (hostfile, '?')) {
|
||||
char *dirname = xstrdup (hostfile);
|
||||
char *patt = strrchr (dirname, '/');
|
||||
assert (patt);
|
||||
*patt++ = '\0';
|
||||
|
||||
char **files = read_dir (dirname);
|
||||
files = filter_fnmatch (files, patt, FNM_NOESCAPE);
|
||||
|
||||
/* Add matching files. */
|
||||
for (j = 0; files[j] != NULL; ++j) {
|
||||
tmp = xasprintf ("%s/%s", dirname, files[j]);
|
||||
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "including host file %s (matches %s)\n", tmp, patt);
|
||||
|
||||
cpio_append (tmp);
|
||||
|
||||
free (tmp);
|
||||
}
|
||||
}
|
||||
/* Else does this file/directory/whatever exist? */
|
||||
else if (lstat (hostfile, &statbuf) == 0) {
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "including host file %s (directly referenced)\n",
|
||||
hostfile);
|
||||
|
||||
cpio_append_stat (hostfile, &statbuf);
|
||||
} /* Ignore files that don't exist. */
|
||||
}
|
||||
}
|
||||
|
||||
/*----------*/
|
||||
/* Helper functions. */
|
||||
|
||||
static void
|
||||
add_string (char ***argv, size_t *n_used, size_t *n_alloc, const char *str)
|
||||
{
|
||||
char **new_argv;
|
||||
char *new_str;
|
||||
|
||||
if (*n_used >= *n_alloc)
|
||||
*argv = x2nrealloc (*argv, n_alloc, sizeof (char *));
|
||||
|
||||
if (str)
|
||||
new_str = xstrdup (str);
|
||||
else
|
||||
new_str = NULL;
|
||||
|
||||
(*argv)[*n_used] = new_str;
|
||||
|
||||
(*n_used)++;
|
||||
}
|
||||
|
||||
static size_t
|
||||
count_strings (char *const *argv)
|
||||
{
|
||||
size_t argc;
|
||||
|
||||
for (argc = 0; argv[argc] != NULL; ++argc)
|
||||
;
|
||||
return argc;
|
||||
}
|
||||
|
||||
struct dir_cache {
|
||||
char *path;
|
||||
char **files;
|
||||
};
|
||||
|
||||
static size_t
|
||||
dir_cache_hash (void const *x, size_t table_size)
|
||||
{
|
||||
struct dir_cache const *p = x;
|
||||
return hash_pjw (p->path, table_size);
|
||||
}
|
||||
|
||||
static bool
|
||||
dir_cache_compare (void const *x, void const *y)
|
||||
{
|
||||
struct dir_cache const *p = x;
|
||||
struct dir_cache const *q = y;
|
||||
return strcmp (p->path, q->path) == 0;
|
||||
}
|
||||
|
||||
/* Read a directory into a list of strings.
|
||||
*
|
||||
* Previously looked up directories are cached and returned quickly,
|
||||
* saving some considerable amount of time compared to reading the
|
||||
* directory over again. However this means you really must not
|
||||
* alter the array of strings that are returned.
|
||||
*
|
||||
* Returns an empty list if the directory cannot be opened.
|
||||
*/
|
||||
static char **
|
||||
read_dir (const char *name)
|
||||
{
|
||||
static Hash_table *ht = NULL;
|
||||
|
||||
if (!ht)
|
||||
ht = hash_initialize (1024, NULL, dir_cache_hash, dir_cache_compare, NULL);
|
||||
|
||||
struct dir_cache key = { .path = (char *) name };
|
||||
struct dir_cache *p = hash_lookup (ht, &key);
|
||||
if (p)
|
||||
return p->files;
|
||||
|
||||
char **files = NULL;
|
||||
size_t n_used = 0, n_alloc = 0;
|
||||
|
||||
DIR *dir = opendir (name);
|
||||
if (!dir) {
|
||||
/* If it fails to open, that's OK, skip to the end. */
|
||||
/*perror (name);*/
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
struct dirent *d = readdir (dir);
|
||||
if (d == NULL) {
|
||||
if (errno != 0)
|
||||
/* But if it fails here, after opening and potentially reading
|
||||
* part of the directory, that's a proper failure - inform the
|
||||
* user and exit.
|
||||
*/
|
||||
error (EXIT_FAILURE, errno, "%s", name);
|
||||
break;
|
||||
}
|
||||
|
||||
add_string (&files, &n_used, &n_alloc, d->d_name);
|
||||
}
|
||||
|
||||
if (closedir (dir) == -1)
|
||||
error (EXIT_FAILURE, errno, "closedir: %s", name);
|
||||
|
||||
done:
|
||||
/* NULL-terminate the array. */
|
||||
add_string (&files, &n_used, &n_alloc, NULL);
|
||||
|
||||
/* Add it to the hash for next time. */
|
||||
p = xmalloc (sizeof *p);
|
||||
p->path = (char *) name;
|
||||
p->files = files;
|
||||
p = hash_insert (ht, p);
|
||||
assert (p != NULL);
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/* Filter a list of strings and return only those matching the wildcard. */
|
||||
static char **
|
||||
filter_fnmatch (char **strings, const char *patt, int flags)
|
||||
{
|
||||
char **out = NULL;
|
||||
size_t n_used = 0, n_alloc = 0;
|
||||
|
||||
int i, r;
|
||||
for (i = 0; strings[i] != NULL; ++i) {
|
||||
r = fnmatch (patt, strings[i], flags);
|
||||
if (r == 0)
|
||||
add_string (&out, &n_used, &n_alloc, strings[i]);
|
||||
else if (r != FNM_NOMATCH)
|
||||
error (EXIT_FAILURE, 0, "internal error: fnmatch ('%s', '%s', %d) returned unexpected non-zero value %d\n",
|
||||
patt, strings[i], flags, r);
|
||||
}
|
||||
|
||||
add_string (&out, &n_used, &n_alloc, NULL);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Filter a list of strings and return only those which DON'T contain sub. */
|
||||
static char **
|
||||
filter_notmatching_substring (char **strings, const char *sub)
|
||||
{
|
||||
char **out = NULL;
|
||||
size_t n_used = 0, n_alloc = 0;
|
||||
|
||||
int i;
|
||||
for (i = 0; strings[i] != NULL; ++i) {
|
||||
if (strstr (strings[i], sub) == NULL)
|
||||
add_string (&out, &n_used, &n_alloc, strings[i]);
|
||||
}
|
||||
|
||||
add_string (&out, &n_used, &n_alloc, NULL);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Sort a list of strings, in place, with the comparison function supplied. */
|
||||
static void
|
||||
sort (char **strings, int (*compare) (const void *, const void *))
|
||||
{
|
||||
qsort (strings, count_strings (strings), sizeof (char *), compare);
|
||||
}
|
||||
|
||||
/* Return true iff path exists and is a directory. This version
|
||||
* follows symlinks.
|
||||
*/
|
||||
static int
|
||||
isdir (const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat (path, &statbuf) == -1)
|
||||
return 0;
|
||||
|
||||
return S_ISDIR (statbuf.st_mode);
|
||||
}
|
||||
|
||||
/* Copy contents of buffer to out_fd and keep out_offset correct. */
|
||||
static void
|
||||
write_to_fd (const void *buffer, size_t len)
|
||||
{
|
||||
if (full_write (out_fd, buffer, len) != len)
|
||||
error (EXIT_FAILURE, errno, "write");
|
||||
out_offset += len;
|
||||
}
|
||||
|
||||
/* Copy contents of file to out_fd. */
|
||||
static void
|
||||
write_file_to_fd (const char *filename)
|
||||
{
|
||||
char buffer[BUFFER_SIZE];
|
||||
int fd2;
|
||||
ssize_t r;
|
||||
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "write_file_to_fd %s -> %d\n", filename, out_fd);
|
||||
|
||||
fd2 = open (filename, O_RDONLY);
|
||||
if (fd2 == -1)
|
||||
error (EXIT_FAILURE, errno, "open: %s", filename);
|
||||
for (;;) {
|
||||
r = read (fd2, buffer, sizeof buffer);
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
||||
continue;
|
||||
error (EXIT_FAILURE, errno, "read: %s", filename);
|
||||
}
|
||||
write_to_fd (buffer, r);
|
||||
}
|
||||
|
||||
if (close (fd2) == -1)
|
||||
error (EXIT_FAILURE, errno, "close: %s", filename);
|
||||
}
|
||||
|
||||
/* Copy file of given length to output, and fail if the file has
|
||||
* changed size.
|
||||
*/
|
||||
static void
|
||||
write_file_len_to_fd (const char *filename, size_t len)
|
||||
{
|
||||
char buffer[BUFFER_SIZE];
|
||||
size_t count = 0;
|
||||
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "write_file_to_fd %s -> %d\n", filename, out_fd);
|
||||
|
||||
int fd2 = open (filename, O_RDONLY);
|
||||
if (fd2 == -1)
|
||||
error (EXIT_FAILURE, errno, "open: %s", filename);
|
||||
for (;;) {
|
||||
ssize_t r = read (fd2, buffer, sizeof buffer);
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
||||
continue;
|
||||
error (EXIT_FAILURE, errno, "read: %s", filename);
|
||||
}
|
||||
write_to_fd (buffer, r);
|
||||
count += r;
|
||||
if (count > len)
|
||||
error (EXIT_FAILURE, 0, "write_file_len_to_fd: %s: file has increased in size\n", filename);
|
||||
}
|
||||
|
||||
if (close (fd2) == -1)
|
||||
error (EXIT_FAILURE, errno, "close: %s", filename);
|
||||
|
||||
if (count != len)
|
||||
error (EXIT_FAILURE, 0, "libguestfs-supermin-helper: write_file_len_to_fd: %s: file has changed size\n", filename);
|
||||
}
|
||||
|
||||
/* Load in a file, returning a list of lines. */
|
||||
static char **
|
||||
load_file (const char *filename)
|
||||
{
|
||||
char **lines = 0;
|
||||
size_t n_used = 0, n_alloc = 0;
|
||||
|
||||
FILE *fp;
|
||||
fp = fopen (filename, "r");
|
||||
if (fp == NULL)
|
||||
error (EXIT_FAILURE, errno, "fopen: %s", filename);
|
||||
|
||||
char line[4096];
|
||||
while (fgets (line, sizeof line, fp)) {
|
||||
size_t len = strlen (line);
|
||||
if (len > 0 && line[len-1] == '\n')
|
||||
line[len-1] = '\0';
|
||||
add_string (&lines, &n_used, &n_alloc, line);
|
||||
}
|
||||
|
||||
add_string (&lines, &n_used, &n_alloc, NULL);
|
||||
return lines;
|
||||
}
|
||||
|
||||
/* Append the file pointed to by FTSENT to the cpio output. */
|
||||
static void
|
||||
cpio_append_fts_entry (FTSENT *entry)
|
||||
{
|
||||
if (entry->fts_info & FTS_NS || entry->fts_info & FTS_NSOK)
|
||||
cpio_append (entry->fts_path);
|
||||
else
|
||||
cpio_append_stat (entry->fts_path, entry->fts_statp);
|
||||
}
|
||||
|
||||
/* Append the file named 'filename' to the cpio output. */
|
||||
static void
|
||||
cpio_append (const char *filename)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (lstat (filename, &statbuf) == -1)
|
||||
error (EXIT_FAILURE, errno, "lstat: %s", filename);
|
||||
cpio_append_stat (filename, &statbuf);
|
||||
}
|
||||
|
||||
/* Append the file to the cpio output. */
|
||||
#define PADDING(len) ((((len) + 3) & ~3) - (len))
|
||||
|
||||
#define CPIO_HEADER_LEN (6 + 13*8)
|
||||
|
||||
static void
|
||||
cpio_append_stat (const char *filename, struct stat *statbuf)
|
||||
{
|
||||
const char *orig_filename = filename;
|
||||
|
||||
if (*filename == '/')
|
||||
filename++;
|
||||
if (*filename == '\0')
|
||||
filename = ".";
|
||||
|
||||
if (verbose >= 2)
|
||||
fprintf (stderr, "cpio_append_stat %s 0%o -> %d\n",
|
||||
orig_filename, statbuf->st_mode, out_fd);
|
||||
|
||||
/* Regular files and symlinks are the only ones that have a "body"
|
||||
* in this cpio entry.
|
||||
*/
|
||||
int has_body = S_ISREG (statbuf->st_mode) || S_ISLNK (statbuf->st_mode);
|
||||
|
||||
size_t len = strlen (filename) + 1;
|
||||
|
||||
char header[CPIO_HEADER_LEN + 1];
|
||||
snprintf (header, sizeof header,
|
||||
"070701" /* magic */
|
||||
"%08X" /* inode */
|
||||
"%08X" /* mode */
|
||||
"%08X" "%08X" /* uid, gid */
|
||||
"%08X" /* nlink */
|
||||
"%08X" /* mtime */
|
||||
"%08X" /* file length */
|
||||
"%08X" "%08X" /* device holding file major, minor */
|
||||
"%08X" "%08X" /* for specials, device major, minor */
|
||||
"%08X" /* name length (including \0 byte) */
|
||||
"%08X", /* checksum (not used by the kernel) */
|
||||
(unsigned) statbuf->st_ino, statbuf->st_mode,
|
||||
statbuf->st_uid, statbuf->st_gid,
|
||||
(unsigned) statbuf->st_nlink, (unsigned) statbuf->st_mtime,
|
||||
has_body ? (unsigned) statbuf->st_size : 0,
|
||||
major (statbuf->st_dev), minor (statbuf->st_dev),
|
||||
major (statbuf->st_rdev), minor (statbuf->st_rdev),
|
||||
(unsigned) len, 0);
|
||||
|
||||
/* Write the header. */
|
||||
write_to_fd (header, CPIO_HEADER_LEN);
|
||||
|
||||
/* Follow with the filename, and pad it. */
|
||||
write_to_fd (filename, len);
|
||||
size_t padding_len = PADDING (CPIO_HEADER_LEN + len);
|
||||
write_padding (padding_len);
|
||||
|
||||
/* Follow with the file or symlink content, and pad it. */
|
||||
if (has_body) {
|
||||
if (S_ISREG (statbuf->st_mode))
|
||||
write_file_len_to_fd (orig_filename, statbuf->st_size);
|
||||
else if (S_ISLNK (statbuf->st_mode)) {
|
||||
char tmp[PATH_MAX];
|
||||
if (readlink (orig_filename, tmp, sizeof tmp) == -1)
|
||||
error (EXIT_FAILURE, errno, "readlink: %s", orig_filename);
|
||||
write_to_fd (tmp, statbuf->st_size);
|
||||
}
|
||||
|
||||
padding_len = PADDING (statbuf->st_size);
|
||||
write_padding (padding_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* CPIO voodoo. */
|
||||
static void
|
||||
cpio_append_trailer (void)
|
||||
{
|
||||
struct stat statbuf;
|
||||
memset (&statbuf, 0, sizeof statbuf);
|
||||
statbuf.st_nlink = 1;
|
||||
cpio_append_stat ("TRAILER!!!", &statbuf);
|
||||
|
||||
/* CPIO seems to pad up to the next block boundary, ie. up to
|
||||
* the next 512 bytes.
|
||||
*/
|
||||
write_padding (((out_offset + 511) & ~511) - out_offset);
|
||||
assert ((out_offset & 511) == 0);
|
||||
}
|
||||
|
||||
/* Write 'len' bytes of zeroes out. */
|
||||
static void
|
||||
write_padding (size_t len)
|
||||
{
|
||||
static const char buffer[512] = { 0 };
|
||||
|
||||
while (len > 0) {
|
||||
size_t n = len < sizeof buffer ? len : sizeof buffer;
|
||||
write_to_fd (buffer, n);
|
||||
len -= n;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# @configure_input@
|
||||
# Copyright (C) 2009 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# Build the supermin appliance.
|
||||
# Read the README file!
|
||||
|
||||
unset CDPATH
|
||||
|
||||
set -e
|
||||
|
||||
cd @top_builddir@
|
||||
|
||||
output=appliance/initramfs.@REPO@.@host_cpu@.supermin.img
|
||||
|
||||
# Generate final image.
|
||||
@FEBOOTSTRAP_TO_INITRAMFS@ \
|
||||
--nocompress \
|
||||
--files=$(pwd)/appliance/supermin.incfiles \
|
||||
initramfs > $output-t
|
||||
mv $output-t $output
|
||||
ls -lh $output
|
||||
@@ -1,133 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# @configure_input@
|
||||
# Copyright (C) 2009 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# Decide which files will stay in the supermin appliance and which
|
||||
# files will be pulled out of the host at runtime.
|
||||
#
|
||||
# Read the README file!
|
||||
#
|
||||
# The basic idea is that we create two output files, one containing
|
||||
# the files that will stay, and the other listing the files that
|
||||
# will be pulled from the host (ie. not go into the appliance now).
|
||||
#
|
||||
# The list of files that stay ('supermin.incfiles') is just a straight
|
||||
# list of files and directories.
|
||||
#
|
||||
# The list of files that come from the host ('*.supermin.hostfiles')
|
||||
# can include wildcards, to allow libraries to be upgraded on the
|
||||
# host.
|
||||
|
||||
unset CDPATH
|
||||
|
||||
set -e
|
||||
|
||||
cd @top_builddir@/initramfs
|
||||
|
||||
incfiles=../appliance/supermin.incfiles
|
||||
hostfiles=../appliance/initramfs.@REPO@.@host_cpu@.supermin.hostfiles
|
||||
|
||||
exec 5>$incfiles
|
||||
exec 6>$hostfiles
|
||||
|
||||
# Note currently the initramfs contains ~2500 files, and none have
|
||||
# "funny characters" in the names. So this is reasonable just to
|
||||
# simplify the script.
|
||||
for path in $(find -not -name fakeroot.log); do
|
||||
dir=$(dirname "$path")
|
||||
file=$(basename "$path")
|
||||
|
||||
# For quoting problems with the bash =~ operator, see bash FAQ
|
||||
# question E14 here http://tiswww.case.edu/php/chet/bash/FAQ and
|
||||
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=487387#25
|
||||
# (RHBZ#566511).
|
||||
p_etc='^\./etc'
|
||||
p_dev='^\./dev'
|
||||
p_var='^\./var'
|
||||
p_lib_modules='^\./lib/modules/'
|
||||
p_builddir='^\./builddir'
|
||||
p_ld_so='^ld-[.0-9]+\.so$'
|
||||
p_libbfd='^libbfd-.*\.so$'
|
||||
p_libgcc='^libgcc_s-.*\.so\.([0-9]+)$'
|
||||
p_libntfs3g='^libntfs-3g\.so\..*$'
|
||||
p_lib123so='^lib(.*)-[-.0-9]+\.so$'
|
||||
p_lib123so123='^lib(.*)-[-.0-9]+\.so\.([0-9]+)\.'
|
||||
p_libso123='^lib(.*)\.so\.([0-9]+)\.'
|
||||
|
||||
# All we're going to keep are the special files /init, the daemon,
|
||||
# configuration files (/etc), devices and modifiable stuff (/var).
|
||||
if [ "$path" = "./init" -o "$file" = "guestfsd" ]; then
|
||||
echo "$path" >&5
|
||||
|
||||
# Get timezone configuration from local system.
|
||||
elif [ "$path" = "./etc/localtime" ]; then
|
||||
echo "$path" >&6
|
||||
|
||||
elif [[ "$path" =~ $p_etc || "$path" =~ $p_dev || "$path" =~ $p_var ]]
|
||||
then
|
||||
echo "$path" >&5
|
||||
|
||||
# Kernel modules are always copied in from the host, including all
|
||||
# the dependency files.
|
||||
elif [[ "$path" =~ $p_lib_modules ]]; then
|
||||
:
|
||||
|
||||
# On mock/Koji, exclude bogus /builddir directory which for some
|
||||
# reason contains some yum temporary files (RHBZ#566512).
|
||||
elif [[ "$path" =~ $p_builddir ]]; then
|
||||
:
|
||||
|
||||
elif [ -d "$path" ]; then
|
||||
# Always write directory names to both output files.
|
||||
echo "$path" >&5
|
||||
echo "$path" >&6
|
||||
|
||||
# Some libraries need fixed version numbers replaced by wildcards.
|
||||
|
||||
elif [[ "$file" =~ $p_ld_so ]]; then
|
||||
echo "$dir/ld-*.so" >&6
|
||||
|
||||
# Special case for libbfd
|
||||
elif [[ "$file" =~ $p_libbfd ]]; then
|
||||
echo "$dir/libbfd-*.so" >&6
|
||||
|
||||
# Special case for libgcc_s-<gccversion>-<date>.so.N
|
||||
elif [[ "$file" =~ $p_libgcc ]]; then
|
||||
echo "$dir/libgcc_s-*.so.${BASH_REMATCH[1]}" >&6
|
||||
|
||||
# Special case for libntfs-3g.so.*
|
||||
elif [[ "$file" =~ $p_libntfs3g ]]; then
|
||||
[ -n "$libntfs3g_once" ] || echo "$dir/libntfs-3g.so.*" >&6
|
||||
libntfs3g_once=1
|
||||
|
||||
# libfoo-1.2.3.so
|
||||
elif [[ "$file" =~ $p_lib123so ]]; then
|
||||
echo "$dir/lib${BASH_REMATCH[1]}-*.so" >&6
|
||||
|
||||
# libfoo-1.2.3.so.1.2.3 (but NOT '*.so.N')
|
||||
elif [[ "$file" =~ $p_lib123so123 ]]; then
|
||||
echo "$dir/lib${BASH_REMATCH[1]}-*.so.${BASH_REMATCH[2]}.*" >&6
|
||||
|
||||
# libfoo.so.1.2.3 (but NOT '*.so.N')
|
||||
elif [[ "$file" =~ $p_libso123 ]]; then
|
||||
echo "$dir/lib${BASH_REMATCH[1]}.so.${BASH_REMATCH[2]}.*" >&6
|
||||
|
||||
else
|
||||
# Anything else comes from the host directly.
|
||||
echo "$path" >&6
|
||||
fi
|
||||
done
|
||||
42
configure.ac
42
configure.ac
@@ -305,6 +305,10 @@ if test "x$enable_appliance" = "xyes"; then
|
||||
[febootstrap-to-initramfs],[febootstrap-to-initramfs],[no])
|
||||
test "x$FEBOOTSTRAP_TO_INITRAMFS" = "xno" && \
|
||||
AC_MSG_ERROR([febootstrap-to-initramfs must be installed])
|
||||
AC_CHECK_PROG([FEBOOTSTRAP_TO_SUPERMIN],
|
||||
[febootstrap-to-supermin],[febootstrap-to-supermin],[no])
|
||||
test "x$FEBOOTSTRAP_TO_SUPERMIN" = "xno" && \
|
||||
AC_MSG_ERROR([febootstrap-to-supermin must be installed])
|
||||
|
||||
dnl Check we have fakechroot >= 2.9 (it's an indirect requirement
|
||||
dnl of febootstrap, but old versions will fail with yum).
|
||||
@@ -391,40 +395,6 @@ AC_ARG_ENABLE([supermin],
|
||||
[enable_supermin=no])
|
||||
AM_CONDITIONAL([SUPERMIN],[test "x$enable_supermin" = "xyes"])
|
||||
|
||||
if test "x$enable_supermin" = "xyes"; then
|
||||
dnl Check febootstrap-to-initramfs accepts the --files option
|
||||
dnl (febootstrap >= 2.2).
|
||||
AC_MSG_CHECKING([for --files support in $FEBOOTSTRAP_TO_INITRAMFS])
|
||||
out=`$FEBOOTSTRAP_TO_INITRAMFS 2>&1 ||:`
|
||||
echo "febootstrap_to_initramfs test command output: $out" >&AS_MESSAGE_LOG_FD
|
||||
if ! echo "$out" | grep -sq -e --files ; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE(
|
||||
[febootstrap-to-initramfs does not support the --files option.
|
||||
|
||||
To build the supermin appliance, you need to upgrade to the latest
|
||||
version of febootstrap.
|
||||
])
|
||||
fi
|
||||
AC_MSG_RESULT([yes])
|
||||
|
||||
dnl Check febootstrap-to-initramfs accepts the --nocompress option
|
||||
dnl (febootstrap >= 2.3).
|
||||
AC_MSG_CHECKING([for --nocompress support in $FEBOOTSTRAP_TO_INITRAMFS])
|
||||
out=`$FEBOOTSTRAP_TO_INITRAMFS 2>&1 ||:`
|
||||
echo "febootstrap_to_initramfs test command output: $out" >&AS_MESSAGE_LOG_FD
|
||||
if ! echo "$out" | grep -sq -e --nocompress ; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE(
|
||||
[febootstrap-to-initramfs does not support the --nocompress option.
|
||||
|
||||
To build the supermin appliance, you need to upgrade to the latest
|
||||
version of febootstrap.
|
||||
])
|
||||
fi
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
dnl Enable packet dumps when in verbose mode. This generates lots
|
||||
dnl of debug info, only useful for people debugging the RPC mechanism.
|
||||
AC_ARG_ENABLE([packet-dump],
|
||||
@@ -761,10 +731,6 @@ AC_CONFIG_HEADERS([config.h])
|
||||
dnl http://www.mail-archive.com/automake@gnu.org/msg10204.html
|
||||
AC_CONFIG_FILES([appliance/update.sh],
|
||||
[chmod +x appliance/update.sh])
|
||||
AC_CONFIG_FILES([appliance/supermin-split.sh],
|
||||
[chmod +x appliance/supermin-split.sh])
|
||||
AC_CONFIG_FILES([appliance/supermin-make.sh],
|
||||
[chmod +x appliance/supermin-make.sh])
|
||||
AC_CONFIG_FILES([Makefile
|
||||
src/Makefile fish/Makefile po/Makefile.in examples/Makefile
|
||||
appliance/Makefile
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
appliance/libguestfs-supermin-helper.c
|
||||
daemon/augeas.c
|
||||
daemon/available.c
|
||||
daemon/base64.c
|
||||
|
||||
@@ -928,10 +928,6 @@ static void print_cmdline (guestfs_h *g);
|
||||
|
||||
static const char *kernel_name = "vmlinuz." REPO "." host_cpu;
|
||||
static const char *initrd_name = "initramfs." REPO "." host_cpu ".img";
|
||||
static const char *supermin_name =
|
||||
"initramfs." REPO "." host_cpu ".supermin.img";
|
||||
static const char *supermin_hostfiles_name =
|
||||
"initramfs." REPO "." host_cpu ".supermin.hostfiles";
|
||||
|
||||
int
|
||||
guestfs__launch (guestfs_h *g)
|
||||
@@ -998,8 +994,7 @@ guestfs__launch (guestfs_h *g)
|
||||
fprintf (stderr,
|
||||
"looking for supermin appliance in current directory\n");
|
||||
if (dir_contains_files (".",
|
||||
supermin_name, supermin_hostfiles_name,
|
||||
"kmod.whitelist", NULL)) {
|
||||
"supermin.d", "kmod.whitelist", NULL)) {
|
||||
if (build_supermin_appliance (g, ".", &kernel, &initrd) == -1)
|
||||
return -1;
|
||||
break;
|
||||
@@ -1011,8 +1006,7 @@ guestfs__launch (guestfs_h *g)
|
||||
fprintf (stderr, "looking for supermin appliance in %s\n", pelem);
|
||||
|
||||
if (dir_contains_files (pelem,
|
||||
supermin_name, supermin_hostfiles_name,
|
||||
"kmod.whitelist", NULL)) {
|
||||
"supermin.d", "kmod.whitelist", NULL)) {
|
||||
if (build_supermin_appliance (g, pelem, &kernel, &initrd) == -1)
|
||||
return -1;
|
||||
break;
|
||||
@@ -1591,11 +1585,15 @@ build_supermin_appliance (guestfs_h *g, const char *path,
|
||||
snprintf (*initrd, len+8, "%s/initrd", g->tmpdir);
|
||||
|
||||
snprintf (cmd, sizeof cmd,
|
||||
"PATH='%s':$PATH "
|
||||
"libguestfs-supermin-helper%s '%s' " host_cpu " " REPO " %s %s",
|
||||
path,
|
||||
"febootstrap-supermin-helper%s "
|
||||
"-k '%s/kmod.whitelist' "
|
||||
"'%s/supermin.d' "
|
||||
host_cpu " "
|
||||
"%s %s",
|
||||
g->verbose ? " --verbose" : "",
|
||||
path, *kernel, *initrd);
|
||||
path,
|
||||
path,
|
||||
*kernel, *initrd);
|
||||
if (g->verbose)
|
||||
print_timestamped_message (g, "%s", cmd);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user