[systemd-commits] 3 commits - src/import src/nspawn

Lennart Poettering lennart at kemper.freedesktop.org
Tue Jan 20 11:40:51 PST 2015


 src/import/import-raw.c  |   45 +++++++++-----
 src/import/import-raw.h  |    3 
 src/import/import-util.c |    8 ++
 src/import/import-util.h |   11 +++
 src/import/import.c      |   26 +++++++-
 src/nspawn/nspawn.c      |  144 ++++++++++++++++++++++++-----------------------
 6 files changed, 147 insertions(+), 90 deletions(-)

New commits:
commit c09ef2e4e8331ddc7ee063d295c322a0939ea851
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 20 20:36:19 2015 +0100

    nspawn: work around kernel bug with partition table probing on loopback devices
    
    When we set up a loopback device with partition probing, the udev
    "change" event about the configured device is first passed on to
    userspace, only the the in-kernel partition prober is started. Since
    partition probing fails with EBUSY when somebody has the device open,
    the probing frequently fails since udev starts probing/opening the
    device as soon as it gets the notification about it, and it might do so
    earlier than the kernel probing.
    
    This patch adds a (hopefully temporary) work-around for this, that
    compares the number of probed partitions of the kernel with those of
    blkid and synchronously asks for reprobing until the numebrs are in
    sync.
    
    This really deserves a proper kernel fix.

diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 588a8ae..d0e4ee7 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2653,63 +2653,6 @@ static int setup_image(char **device_path, int *loop_nr) {
         return r;
 }
 
-static int wait_for_block_device(struct udev *udev, dev_t devnum, struct udev_device **ret) {
-        _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
-        int r;
-
-        assert(udev);
-        assert(ret);
-
-        for (;;) {
-                _cleanup_udev_device_unref_ struct udev_device *d = NULL;
-                struct pollfd pfd = {
-                        .events = POLLIN
-                };
-
-                d = udev_device_new_from_devnum(udev, 'b', devnum);
-                if (!d)
-                        return log_oom();
-
-                r = udev_device_get_is_initialized(d);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to check if device is initialized: %m");
-                if (r > 0) {
-                        *ret = d;
-                        d = NULL;
-                        return 0;
-                }
-                d = udev_device_unref(d);
-
-                if (!monitor) {
-                        monitor = udev_monitor_new_from_netlink(udev, "udev");
-                        if (!monitor)
-                                return log_oom();
-
-                        r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "block", NULL);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to add block match: %m");
-
-                        r = udev_monitor_enable_receiving(monitor);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to turn on monitor: %m");
-
-                        continue;
-                }
-
-                pfd.fd = udev_monitor_get_fd(monitor);
-                if (pfd.fd < 0)
-                        return log_error_errno(r, "Failed to get udev monitor fd: %m");
-
-                r = poll(&pfd, 1, -1);
-                if (r < 0)
-                        return log_error_errno(errno, "Failed to wait for device initialization: %m");
-
-                d = udev_monitor_receive_device(monitor);
-        }
-
-        return 0;
-}
-
 #define PARTITION_TABLE_BLURB \
         "Note that the disk image needs to either contain only a single MBR partition of\n" \
         "type 0x83 that is marked bootable, or a sinlge GPT partition of type" \
@@ -2739,11 +2682,12 @@ static int dissect_image(
         _cleanup_udev_unref_ struct udev *udev = NULL;
         struct udev_list_entry *first, *item;
         bool home_rw = true, root_rw = true, secondary_root_rw = true, srv_rw = true, generic_rw = true;
+        bool is_gpt, is_mbr, multiple_generic = false;
         const char *pttype = NULL;
         blkid_partlist pl;
         struct stat st;
+        unsigned i;
         int r;
-        bool is_gpt, is_mbr, multiple_generic = false;
 
         assert(fd >= 0);
         assert(root_device);
@@ -2812,21 +2756,81 @@ static int dissect_image(
         if (fstat(fd, &st) < 0)
                 return log_error_errno(errno, "Failed to stat block device: %m");
 
-        r = wait_for_block_device(udev, st.st_rdev, &d);
-        if (r < 0)
-                return r;
-
-        e = udev_enumerate_new(udev);
-        if (!e)
+        d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
+        if (!d)
                 return log_oom();
 
-        r = udev_enumerate_add_match_parent(e, d);
-        if (r < 0)
-                return log_oom();
+        for (i = 0;; i++) {
+                int n, m;
 
-        r = udev_enumerate_scan_devices(e);
-        if (r < 0)
-                return log_error_errno(r, "Failed to scan for partition devices of %s: %m", arg_image);
+                if (i >= 10) {
+                        log_error("Kernel partitions never appeared.");
+                        return -ENXIO;
+                }
+
+                e = udev_enumerate_new(udev);
+                if (!e)
+                        return log_oom();
+
+                r = udev_enumerate_add_match_parent(e, d);
+                if (r < 0)
+                        return log_oom();
+
+                r = udev_enumerate_scan_devices(e);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to scan for partition devices of %s: %m", arg_image);
+
+                /* Count the partitions enumerated by the kernel */
+                n = 0;
+                first = udev_enumerate_get_list_entry(e);
+                udev_list_entry_foreach(item, first)
+                        n++;
+
+                /* Count the partitions enumerated by blkid */
+                m = blkid_partlist_numof_partitions(pl);
+                if (n == m + 1)
+                        break;
+                if (n > m + 1) {
+                        log_error("blkid and kernel partition list do not match.");
+                        return -EIO;
+                }
+                if (n < m + 1) {
+                        unsigned j;
+
+                        /* The kernel has probed fewer partitions than
+                         * blkid? Maybe the kernel prober is still
+                         * running or it got EBUSY because udev
+                         * already opened the device. Let's reprobe
+                         * the device, which is a synchronous call
+                         * that waits until probing is complete. */
+
+                        for (j = 0; j < 20; j++) {
+
+                                r = ioctl(fd, BLKRRPART, 0);
+                                if (r < 0)
+                                        r = -errno;
+                                if (r >= 0 || r != -EBUSY)
+                                        break;
+
+                                /* If something else has the device
+                                 * open, such as an udev rule, the
+                                 * ioctl will return EBUSY. Since
+                                 * there's no way to wait until it
+                                 * isn't busy anymore, let's just wait
+                                 * a bit, and try again.
+                                 *
+                                 * This is really something they
+                                 * should fix in the kernel! */
+
+                                usleep(50 * USEC_PER_MSEC);
+                        }
+
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to reread partition table: %m");
+                }
+
+                e = udev_enumerate_unref(e);
+        }
 
         first = udev_enumerate_get_list_entry(e);
         udev_list_entry_foreach(item, first) {

commit c660bb094288d89762cdbedd08661127988e5548
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 20 16:37:27 2015 +0100

    import: add a couple of additional suffixes to remove from raw images

diff --git a/src/import/import.c b/src/import/import.c
index f44d47d..62e3118 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -165,9 +165,11 @@ static void on_raw_finished(RawImport *import, int error, void *userdata) {
 static int strip_raw_suffixes(const char *p, char **ret) {
         static const char suffixes[] =
                 ".xz\0"
+                ".gz\0"
                 ".raw\0"
                 ".qcow2\0"
-                ".img\0";
+                ".img\0"
+                ".bin\0";
 
         _cleanup_free_ char *q = NULL;
 

commit 8f6950587ab7b4d6fe1b51241759cc3a4682b96d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 20 16:36:40 2015 +0100

    import: make image verification optional

diff --git a/src/import/import-raw.c b/src/import/import-raw.c
index 8ca1091..6fb0882 100644
--- a/src/import/import-raw.c
+++ b/src/import/import-raw.c
@@ -56,6 +56,8 @@ struct RawImport {
 
         char *temp_path;
         char *final_path;
+
+        ImportVerify verify;
 };
 
 RawImport* raw_import_unref(RawImport *i) {
@@ -251,6 +253,7 @@ static int raw_import_verify_sha256sum(RawImport *i) {
         int r;
 
         assert(i);
+        assert(i->verify != IMPORT_VERIFY_NO);
 
         assert(i->raw_job);
         assert(i->raw_job->sha256);
@@ -291,10 +294,12 @@ static int raw_import_finalize(RawImport *i) {
         assert(i);
 
         if (!IMPORT_JOB_STATE_IS_COMPLETE(i->raw_job) ||
-            !IMPORT_JOB_STATE_IS_COMPLETE(i->sha256sums_job))
+            (i->verify != IMPORT_VERIFY_NO && !IMPORT_JOB_STATE_IS_COMPLETE(i->sha256sums_job)))
                 return 0;
 
-        if (!i->raw_job->etag_exists) {
+        if (i->verify != IMPORT_VERIFY_NO &&
+            i->raw_job->etag_exists) {
+
                 assert(i->temp_path);
                 assert(i->final_path);
                 assert(i->raw_job->disk_fd >= 0);
@@ -379,7 +384,10 @@ static void raw_import_sha256sums_job_on_finished(ImportJob *j) {
         assert(j->userdata);
 
         i = j->userdata;
+        assert(i->verify != IMPORT_VERIFY_NO);
+
         if (j->error != 0) {
+                log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify.");
                 r = j->error;
                 goto finish;
         }
@@ -425,11 +433,13 @@ static int raw_import_raw_job_on_open_disk(ImportJob *j) {
         return 0;
 }
 
-int raw_import_pull(RawImport *i, const char *url, const char *local, bool force_local) {
+int raw_import_pull(RawImport *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
         _cleanup_free_ char *sha256sums_url = NULL;
         int r;
 
         assert(i);
+        assert(verify < _IMPORT_VERIFY_MAX);
+        assert(verify >= 0);
 
         if (i->raw_job)
                 return -EBUSY;
@@ -444,6 +454,7 @@ int raw_import_pull(RawImport *i, const char *url, const char *local, bool force
         if (r < 0)
                 return r;
         i->force_local = force_local;
+        i->verify = verify;
 
         /* Queue job for the image itself */
         r = import_job_new(&i->raw_job, url, i->glue, i);
@@ -458,23 +469,25 @@ int raw_import_pull(RawImport *i, const char *url, const char *local, bool force
         if (r < 0)
                 return r;
 
-        /* Queue job for the SHA256SUMS file for the image */
-        r = import_url_change_last_component(url, "SHA256SUMS", &sha256sums_url);
-        if (r < 0)
-                return r;
+        if (verify != IMPORT_VERIFY_NO) {
+                /* Queue job for the SHA256SUMS file for the image */
+                r = import_url_change_last_component(url, "SHA256SUMS", &sha256sums_url);
+                if (r < 0)
+                        return r;
 
-        r = import_job_new(&i->sha256sums_job, sha256sums_url, i->glue, i);
-        if (r < 0)
-                return r;
+                r = import_job_new(&i->sha256sums_job, sha256sums_url, i->glue, i);
+                if (r < 0)
+                        return r;
 
-        i->sha256sums_job->on_finished = raw_import_sha256sums_job_on_finished;
-        i->sha256sums_job->uncompressed_max = i->sha256sums_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
+                i->sha256sums_job->on_finished = raw_import_sha256sums_job_on_finished;
+                i->sha256sums_job->uncompressed_max = i->sha256sums_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
 
-        r = import_job_begin(i->raw_job);
-        if (r < 0)
-                return r;
+                r = import_job_begin(i->sha256sums_job);
+                if (r < 0)
+                        return r;
+        }
 
-        r = import_job_begin(i->sha256sums_job);
+        r = import_job_begin(i->raw_job);
         if (r < 0)
                 return r;
 
diff --git a/src/import/import-raw.h b/src/import/import-raw.h
index 9e23142..ae2c299 100644
--- a/src/import/import-raw.h
+++ b/src/import/import-raw.h
@@ -23,6 +23,7 @@
 
 #include "sd-event.h"
 #include "macro.h"
+#include "import-util.h"
 
 typedef struct RawImport RawImport;
 
@@ -33,4 +34,4 @@ RawImport* raw_import_unref(RawImport *import);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(RawImport*, raw_import_unref);
 
-int raw_import_pull(RawImport *import, const char *url, const char *local, bool force_local);
+int raw_import_pull(RawImport *import, const char *url, const char *local, bool force_local, ImportVerify verify);
diff --git a/src/import/import-util.c b/src/import/import-util.c
index 1212025..79c60b3 100644
--- a/src/import/import-util.c
+++ b/src/import/import-util.c
@@ -270,3 +270,11 @@ int import_url_change_last_component(const char *url, const char *suffix, char *
         *ret = s;
         return 0;
 }
+
+static const char* const import_verify_table[_IMPORT_VERIFY_MAX] = {
+        [IMPORT_VERIFY_NO] = "no",
+        [IMPORT_VERIFY_SUM] = "sum",
+        [IMPORT_VERIFY_SIGNATURE] = "signature",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(import_verify, ImportVerify);
diff --git a/src/import/import-util.h b/src/import/import-util.h
index a8a5ca5..811f3fa 100644
--- a/src/import/import-util.h
+++ b/src/import/import-util.h
@@ -23,6 +23,14 @@
 
 #include <stdbool.h>
 
+typedef enum ImportVerify {
+        IMPORT_VERIFY_NO,
+        IMPORT_VERIFY_SUM,
+        IMPORT_VERIFY_SIGNATURE,
+        _IMPORT_VERIFY_MAX,
+        _IMPORT_VERIFY_INVALID = -1,
+} ImportVerify;
+
 bool http_etag_is_valid(const char *etag);
 
 int import_make_local_copy(const char *final, const char *root, const char *local, bool force_local);
@@ -36,3 +44,6 @@ int import_make_path(const char *url, const char *etag, const char *image_root,
 
 int import_url_last_component(const char *url, char **ret);
 int import_url_change_last_component(const char *url, const char *suffix, char **ret);
+
+const char* import_verify_to_string(ImportVerify v) _const_;
+ImportVerify import_verify_from_string(const char *s) _pure_;
diff --git a/src/import/import.c b/src/import/import.c
index 3362f4a..f44d47d 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -33,7 +33,7 @@
 
 static bool arg_force = false;
 static const char *arg_image_root = "/var/lib/machines";
-
+static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
 static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL;
 
 static void on_tar_finished(TarImport *import, int error, void *userdata) {
@@ -263,7 +263,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate importer: %m");
 
-        r = raw_import_pull(import, url, local, arg_force);
+        r = raw_import_pull(import, url, local, arg_force, arg_verify);
         if (r < 0)
                 return log_error_errno(r, "Failed to pull image: %m");
 
@@ -299,6 +299,11 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
                 return -EINVAL;
         }
 
+        if (arg_verify != IMPORT_VERIFY_NO) {
+                log_error("Imports from dkr do not support image verification, please pass --verify=no.");
+                return -EINVAL;
+        }
+
         tag = strchr(argv[1], ':');
         if (tag) {
                 name = strndupa(argv[1], tag - argv[1]);
@@ -384,6 +389,8 @@ static int help(int argc, char *argv[], void *userdata) {
                "  -h --help                   Show this help\n"
                "     --version                Show package version\n"
                "     --force                  Force creation of image\n"
+               "     --verify=                Verify downloaded image, one of: 'no', 'sum'\n"
+               "                              'signature'.\n"
                "     --image-root=            Image root directory\n"
                "     --dkr-index-url=URL      Specify index URL to use for downloads\n\n"
                "Commands:\n"
@@ -402,6 +409,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_FORCE,
                 ARG_DKR_INDEX_URL,
                 ARG_IMAGE_ROOT,
+                ARG_VERIFY,
         };
 
         static const struct option options[] = {
@@ -410,6 +418,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "force",           no_argument,       NULL, ARG_FORCE           },
                 { "dkr-index-url",   required_argument, NULL, ARG_DKR_INDEX_URL   },
                 { "image-root",      required_argument, NULL, ARG_IMAGE_ROOT      },
+                { "verify",          required_argument, NULL, ARG_VERIFY          },
                 {}
         };
 
@@ -447,6 +456,15 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_image_root = optarg;
                         break;
 
+                case ARG_VERIFY:
+                        arg_verify = import_verify_from_string(optarg);
+                        if (arg_verify < 0) {
+                                log_error("Invalid verification setting '%s'", optarg);
+                                return -EINVAL;
+                        }
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 



More information about the systemd-commits mailing list