[libvirt] [sandbox v2 05/11] Copy all needed init programs and all its deps to config subdir

Cédric Bosdonnat cbosdonnat at suse.com
Mon Jun 29 16:44:13 UTC 2015


In order to be able to mount a custom host-image as / we need to be able
to access libvirt-sandbox-init-common and all its needed dependencies.
In the container case we also need to copy libvirt-sandbox-init-lxc.

They are now copied into SANDBOXCONFIGDIR /.libs. Hard linking is not
possible since we may be working on separate partitions, and symlinks
wouldn't help to work with apparmor. Copying makes apparmor happy and
solves our problem.
---
 configure.ac                                       |   7 +
 .../libvirt-sandbox-builder-container.c            |  15 +-
 libvirt-sandbox/libvirt-sandbox-builder.c          | 159 ++++++++++++++++++++-
 libvirt-sandbox/libvirt-sandbox-builder.h          |   2 +
 libvirt-sandbox/libvirt-sandbox-init-lxc.c         |   8 +-
 libvirt-sandbox/libvirt-sandbox-init-qemu.c        |   9 +-
 6 files changed, 196 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index 99d22d7..608f56b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,6 +109,13 @@ LIBVIRT_SANDBOX_SELINUX
 
 LIBVIRT_SANDBOX_STATIC_LIBC
 
+dnl search for LDD path
+AC_PATH_PROG([LDD_PATH], [ldd])
+if test -z "$LDD_PATH"; then
+    AC_MSG_ERROR([Failed to find ldd.])
+fi
+AC_DEFINE_UNQUOTED([LDD_PATH], "$LDD_PATH", [path to ldd binary])
+
 GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_REQUIRED])
 
 dnl Should be in m4/virt-gettext.m4 but intltoolize is too
diff --git a/libvirt-sandbox/libvirt-sandbox-builder-container.c b/libvirt-sandbox/libvirt-sandbox-builder-container.c
index c23b82b..d226d35 100644
--- a/libvirt-sandbox/libvirt-sandbox-builder-container.c
+++ b/libvirt-sandbox/libvirt-sandbox-builder-container.c
@@ -184,7 +184,7 @@ static gboolean gvir_sandbox_builder_container_construct_os(GVirSandboxBuilder *
     gvir_config_domain_os_set_arch(os,
                                    gvir_sandbox_config_get_arch(config));
     gvir_config_domain_os_set_init(os,
-                                   LIBEXECDIR "/libvirt-sandbox-init-lxc");
+                                   SANDBOXCONFIGDIR "/.libs/libvirt-sandbox-init-lxc");
     gvir_config_domain_os_set_cmdline(os, cmdline);
     gvir_config_domain_set_os(domain, os);
 
@@ -444,6 +444,18 @@ static const gchar *gvir_sandbox_builder_container_get_disk_prefix(GVirSandboxBu
     return "sd";
 }
 
+
+static GList *gvir_sandbox_builder_container_get_files_to_copy(GVirSandboxBuilder *builder,
+                                                               GVirSandboxConfig *config G_GNUC_UNUSED)
+{
+    GList * tocopy = GVIR_SANDBOX_BUILDER_CLASS(gvir_sandbox_builder_container_parent_class)->
+                     get_files_to_copy(builder, config);
+    gchar *file = g_strdup_printf("%s/libvirt-sandbox-init-lxc", LIBEXECDIR);
+
+    return g_list_append(tocopy, file);
+}
+
+
 static void gvir_sandbox_builder_container_class_init(GVirSandboxBuilderContainerClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS(klass);
@@ -458,6 +470,7 @@ static void gvir_sandbox_builder_container_class_init(GVirSandboxBuilderContaine
     builder_class->construct_features = gvir_sandbox_builder_container_construct_features;
     builder_class->construct_devices = gvir_sandbox_builder_container_construct_devices;
     builder_class->get_disk_prefix = gvir_sandbox_builder_container_get_disk_prefix;
+    builder_class->get_files_to_copy = gvir_sandbox_builder_container_get_files_to_copy;
 
     g_type_class_add_private(klass, sizeof(GVirSandboxBuilderContainerPrivate));
 }
diff --git a/libvirt-sandbox/libvirt-sandbox-builder.c b/libvirt-sandbox/libvirt-sandbox-builder.c
index aa932db..2726868 100644
--- a/libvirt-sandbox/libvirt-sandbox-builder.c
+++ b/libvirt-sandbox/libvirt-sandbox-builder.c
@@ -107,6 +107,8 @@ static gboolean gvir_sandbox_builder_clean_post_stop_default(GVirSandboxBuilder
                                                              GVirSandboxConfig *config,
                                                              const gchar *statedir,
                                                              GError **error);
+static GList *gvir_sandbox_builder_get_files_to_copy(GVirSandboxBuilder *builder,
+                                                     GVirSandboxConfig *config);
 
 static void gvir_sandbox_builder_get_property(GObject *object,
                                               guint prop_id,
@@ -176,6 +178,7 @@ static void gvir_sandbox_builder_class_init(GVirSandboxBuilderClass *klass)
     klass->construct_security = gvir_sandbox_builder_construct_security;
     klass->clean_post_start = gvir_sandbox_builder_clean_post_start_default;
     klass->clean_post_stop = gvir_sandbox_builder_clean_post_stop_default;
+    klass->get_files_to_copy = gvir_sandbox_builder_get_files_to_copy;
 
     g_object_class_install_property(object_class,
                                     PROP_CONNECTION,
@@ -247,6 +250,108 @@ GVirConnection *gvir_sandbox_builder_get_connection(GVirSandboxBuilder *builder)
 }
 
 
+static gboolean gvir_sandbox_builder_copy_file(const char *path,
+                                               const char *libsdir,
+                                               GError **error)
+{
+    gchar *name = g_path_get_basename(path);
+    gchar *target = g_build_filename(libsdir, name, NULL);
+    GFile *srcFile = g_file_new_for_path(path);
+    GFile *tgtFile = g_file_new_for_path(target);
+    gboolean result = FALSE;
+
+
+    if (!g_file_query_exists(tgtFile, NULL) &&
+        !g_file_copy(srcFile, tgtFile, 0, NULL, NULL, NULL, error))
+        goto cleanup;
+
+    result = TRUE;
+
+ cleanup:
+    g_object_unref(tgtFile);
+    g_object_unref(srcFile);
+    g_free(target);
+    g_free(name);
+
+    return result;
+}
+
+static gboolean gvir_sandbox_builder_copy_program(const char *program,
+                                                  const char *dest,
+                                                  GError **error)
+{
+    gchar *out = NULL;
+    gchar *line, *tmp;
+    const gchar *argv[] = {LDD_PATH, program, NULL};
+    gboolean result = FALSE;
+
+    if (!gvir_sandbox_builder_copy_file(program, dest, error))
+        goto cleanup;
+
+
+    /* Get all the dependencies to be hard linked */
+    if (!g_spawn_sync(NULL, (gchar **)argv, NULL, 0,
+                      NULL, NULL, &out, NULL, NULL, error))
+        goto cleanup;
+
+    /* Loop over the output lines to get the path to the libraries to copy */
+    line = out;
+    while ((tmp = strchr(line, '\n'))) {
+        gchar *start, *end;
+        *tmp = '\0';
+
+        /* Search the line for the library path */
+        start = strstr(line, " => ");
+        end = strstr(line, " (");
+
+        if (start && end) {
+            start = start + 4;
+            *end = '\0';
+
+            if (!gvir_sandbox_builder_copy_file(start, dest, error))
+                goto cleanup;
+        }
+
+        line = tmp + 1;
+    }
+    result = TRUE;
+
+ cleanup:
+    g_free(out);
+
+    return result;
+}
+
+static gboolean gvir_sandbox_builder_copy_init(GVirSandboxBuilder *builder,
+                                               GVirSandboxConfig *config,
+                                               const gchar *statedir,
+                                               GError **error)
+{
+    gchar *libsdir;
+    GVirSandboxBuilderClass *klass = GVIR_SANDBOX_BUILDER_GET_CLASS(builder);
+    GList *tocopy = NULL, *tmp = NULL;
+    gboolean result = FALSE;
+
+    libsdir = g_build_filename(statedir, "config", ".libs", NULL);
+    g_mkdir_with_parents(libsdir, 0755);
+
+    tmp = tocopy = klass->get_files_to_copy(builder, config);
+    while (tmp) {
+        if (!gvir_sandbox_builder_copy_program(tmp->data, libsdir, error))
+            goto cleanup;
+
+        tmp = tmp->next;
+    }
+    result = TRUE;
+
+ cleanup:
+    g_free(libsdir);
+    g_list_free_full(tocopy, g_free);
+
+    return result;
+}
+
+
 static gboolean gvir_sandbox_builder_construct_domain(GVirSandboxBuilder *builder,
                                                       GVirSandboxConfig *config,
                                                       const gchar *statedir,
@@ -255,6 +360,9 @@ static gboolean gvir_sandbox_builder_construct_domain(GVirSandboxBuilder *builde
 {
     GVirSandboxBuilderClass *klass = GVIR_SANDBOX_BUILDER_GET_CLASS(builder);
 
+    if (!gvir_sandbox_builder_copy_init(builder, config, statedir, error))
+        return FALSE;
+
     if (!(klass->construct_basic(builder, config, statedir, domain, error)))
         return FALSE;
 
@@ -511,6 +619,15 @@ static gboolean gvir_sandbox_builder_clean_post_stop_default(GVirSandboxBuilder
     return TRUE;
 }
 
+static GList *gvir_sandbox_builder_get_files_to_copy(GVirSandboxBuilder *builder,
+                                                     GVirSandboxConfig *config G_GNUC_UNUSED)
+{
+    GList *tocopy = NULL;
+    gchar *file = g_strdup_printf("%s/libvirt-sandbox-init-common", LIBEXECDIR);
+    return g_list_append(tocopy, file);
+}
+
+
 /**
  * gvir_sandbox_builder_construct:
  * @builder: (transfer none): the sandbox builder
@@ -577,8 +694,48 @@ gboolean gvir_sandbox_builder_clean_post_stop(GVirSandboxBuilder *builder,
                                               GError **error)
 {
     GVirSandboxBuilderClass *klass = GVIR_SANDBOX_BUILDER_GET_CLASS(builder);
+    gchar *libsdir = g_build_filename(statedir, "config", ".libs", NULL);
+    GFile *libsFile = g_file_new_for_path(libsdir);
+    GFileEnumerator *enumerator = NULL;
+    GFileInfo *info = NULL;
+    GFile *child = NULL;
+    gboolean ret = TRUE;
+
+    ret = klass->clean_post_stop(builder, config, statedir, error);
+
+    if (!(enumerator = g_file_enumerate_children(libsFile, "*", G_FILE_QUERY_INFO_NONE,
+                                                 NULL, error)) &&
+        (*error)->code != G_IO_ERROR_NOT_FOUND) {
+        ret = FALSE;
+        goto cleanup;
+    }
+
+    while ((info = g_file_enumerator_next_file(enumerator, NULL, error))) {
+        child = g_file_enumerator_get_child(enumerator, info);
+        if (!g_file_delete(child, NULL, error))
+            ret = FALSE;
+        g_object_unref(child);
+        child = NULL;
+        g_object_unref(info);
+        info = NULL;
+    }
+
+    if (!g_file_enumerator_close(enumerator, NULL, error))
+        ret = FALSE;
 
-    return klass->clean_post_stop(builder, config, statedir, error);
+    if (!g_file_delete(libsFile, NULL, error) &&
+        (*error)->code != G_IO_ERROR_NOT_FOUND)
+        ret = FALSE;
+
+ cleanup:
+    if (child)
+        g_object_unref(child);
+    if (info)
+        g_object_unref(info);
+    g_object_unref(enumerator);
+    g_object_unref(libsFile);
+    g_free(libsdir);
+    return ret;
 }
 
 
diff --git a/libvirt-sandbox/libvirt-sandbox-builder.h b/libvirt-sandbox/libvirt-sandbox-builder.h
index 81df92a..2d22f1a 100644
--- a/libvirt-sandbox/libvirt-sandbox-builder.h
+++ b/libvirt-sandbox/libvirt-sandbox-builder.h
@@ -97,6 +97,8 @@ struct _GVirSandboxBuilderClass
     const gchar *(*get_disk_prefix)(GVirSandboxBuilder *builder,
                                     GVirSandboxConfig *config,
                                     GVirSandboxConfigDisk *disk);
+    GList *(*get_files_to_copy)(GVirSandboxBuilder *builder,
+                                GVirSandboxConfig *config);
 
     gpointer padding[LIBVIRT_SANDBOX_CLASS_PADDING];
 };
diff --git a/libvirt-sandbox/libvirt-sandbox-init-lxc.c b/libvirt-sandbox/libvirt-sandbox-init-lxc.c
index 798af37..e2fe7f0 100644
--- a/libvirt-sandbox/libvirt-sandbox-init-lxc.c
+++ b/libvirt-sandbox/libvirt-sandbox-init-lxc.c
@@ -77,10 +77,16 @@ main(int argc, char **argv)
         args[narg++] = "1000";
     }
 
-    args[narg++] = LIBEXECDIR "/libvirt-sandbox-init-common";
+    args[narg++] = SANDBOXCONFIGDIR "/.libs/libvirt-sandbox-init-common";
     if (debug)
         args[narg++] = "-d";
 
+    if (setenv("LD_LIBRARY_PATH", SANDBOXCONFIGDIR "/.libs", 1) != 0) {
+        fprintf(stderr, "libvirt-sandbox-init-lxc: %s: cannot set LD_LIBRARY_PATH: %s\n",
+                __func__, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
     if (debug)
         fprintf(stderr, "Running interactive\n");
     execv(args[0], (char**)args);
diff --git a/libvirt-sandbox/libvirt-sandbox-init-qemu.c b/libvirt-sandbox/libvirt-sandbox-init-qemu.c
index 44305fd..62e8e40 100644
--- a/libvirt-sandbox/libvirt-sandbox-init-qemu.c
+++ b/libvirt-sandbox/libvirt-sandbox-init-qemu.c
@@ -338,10 +338,17 @@ main(int argc ATTR_UNUSED, char **argv ATTR_UNUSED)
         args[narg++] = "1000";
     }
 
-    args[narg++] = LIBEXECDIR "/libvirt-sandbox-init-common";
+    args[narg++] = SANDBOXCONFIGDIR "/.libs/libvirt-sandbox-init-common";
     if (debug)
         args[narg++] = "-d";
 
+    if (setenv("LD_LIBRARY_PATH", SANDBOXCONFIGDIR "/.libs", 1) < 0) {
+        fprintf(stderr, "libvirt-sandbox-init-qemu: %s: cannot set LD_LIBRARY_PATH: %s\n",
+                __func__, strerror(errno));
+        exit_poweroff();
+    }
+
+
     if (debug)
         fprintf(stderr, "libvirt-sandbox-init-qemu: Running common init %s\n", args[0]);
     execv(args[0], (char**)args);
-- 
2.1.4




More information about the libvir-list mailing list