summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-01-15 00:47:10 +0100
committerLennart Poettering <lennart@poettering.net>2015-01-15 00:47:10 +0100
commitada4799ac5ad2e6c0fe11dc5c096faca8a85876b (patch)
tree42532e2fab672f0aef39ae768c73eb596e859a69
parent733d15ac7a23c80f2e447f6c2fca0406bc9960db (diff)
nspawn: add support for limited dissecting of MBR disk images with nspawn
With this change nspawn's -i switch now can now make sense of MBR disk images too - however only if there's only a single, bootable partition of type 0x83 on the image. For all other cases we cannot really make sense from the partition table alone. The big benefit of this change is that upstream Fedora Cloud Images can now be booted unmodified with systemd-nspawn: # wget http://download.fedoraproject.org/pub/fedora/linux/releases/21/Cloud/Images/x86_64/Fedora-Cloud-Base-20141203-21.x86_64.raw.xz # unxz Fedora-Cloud-Base-20141203-21.x86_64.raw.xz # systemd-nspawn -i Fedora-Cloud-Base-20141203-21.x86_64.raw -b Next stop: teach the import logic to automatically download these images, uncompress and verify them.
-rw-r--r--src/nspawn/nspawn.c152
1 files changed, 100 insertions, 52 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 2bda27edf0..9fe040c81b 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2557,6 +2557,12 @@ static int setup_image(char **device_path, int *loop_nr) {
return r;
}
+#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 follow\n" \
+ " http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" \
+ "to be bootable with systemd-nspawn."
+
static int dissect_image(
int fd,
char **root_device, bool *root_device_rw,
@@ -2584,6 +2590,7 @@ static int dissect_image(
blkid_partlist pl;
struct stat st;
int r;
+ bool is_gpt, is_mbr;
assert(fd >= 0);
assert(root_device);
@@ -2612,8 +2619,9 @@ static int dissect_image(
errno = 0;
r = blkid_do_safeprobe(b);
if (r == -2 || r == 1) {
- log_error("Failed to identify any partition table on %s.\n"
- "Note that the disk image needs to follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/ to be supported by systemd-nspawn.", arg_image);
+ log_error("Failed to identify any partition table on\n"
+ " %s\n"
+ PARTITION_TABLE_BLURB, arg_image);
return -EINVAL;
} else if (r != 0) {
if (errno == 0)
@@ -2623,9 +2631,14 @@ static int dissect_image(
}
blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
- if (!streq_ptr(pttype, "gpt")) {
- log_error("Image %s does not carry a GUID Partition Table.\n"
- "Note that the disk image needs to follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/ to be supported by systemd-nspawn.", arg_image);
+
+ is_gpt = streq_ptr(pttype, "gpt");
+ is_mbr = streq_ptr(pttype, "dos");
+
+ if (!is_gpt && !is_mbr) {
+ log_error("No GPT or MBR partition table discovered on\n"
+ " %s\n"
+ PARTITION_TABLE_BLURB, arg_image);
return -EINVAL;
}
@@ -2665,9 +2678,8 @@ static int dissect_image(
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
_cleanup_udev_device_unref_ struct udev_device *q;
- const char *stype, *node;
+ const char *node;
unsigned long long flags;
- sd_id128_t type_id;
blkid_partition pp;
dev_t qn;
int nr;
@@ -2698,81 +2710,117 @@ static int dissect_image(
continue;
flags = blkid_partition_get_flags(pp);
- if (flags & GPT_FLAG_NO_AUTO)
+ if (is_gpt && (flags & GPT_FLAG_NO_AUTO))
+ continue;
+ if (is_mbr && (flags != 0x80)) /* Bootable flag */
continue;
nr = blkid_partition_get_partno(pp);
if (nr < 0)
continue;
- stype = blkid_partition_get_type_string(pp);
- if (!stype)
- continue;
-
- if (sd_id128_from_string(stype, &type_id) < 0)
- continue;
+ if (is_gpt) {
+ sd_id128_t type_id;
+ const char *stype;
- if (sd_id128_equal(type_id, GPT_HOME)) {
+ stype = blkid_partition_get_type_string(pp);
+ if (!stype)
+ continue;
- if (home && nr >= home_nr)
+ if (sd_id128_from_string(stype, &type_id) < 0)
continue;
- home_nr = nr;
- home_rw = !(flags & GPT_FLAG_READ_ONLY);
+ if (sd_id128_equal(type_id, GPT_HOME)) {
- free(home);
- home = strdup(node);
- if (!home)
- return log_oom();
- } else if (sd_id128_equal(type_id, GPT_SRV)) {
+ if (home && nr >= home_nr)
+ continue;
- if (srv && nr >= srv_nr)
- continue;
+ home_nr = nr;
+ home_rw = !(flags & GPT_FLAG_READ_ONLY);
- srv_nr = nr;
- srv_rw = !(flags & GPT_FLAG_READ_ONLY);
+ r = free_and_strdup(&home, node);
+ if (r < 0)
+ return log_oom();
- free(srv);
- srv = strdup(node);
- if (!srv)
- return log_oom();
- }
+ } else if (sd_id128_equal(type_id, GPT_SRV)) {
+
+ if (srv && nr >= srv_nr)
+ continue;
+
+ srv_nr = nr;
+ srv_rw = !(flags & GPT_FLAG_READ_ONLY);
+
+ r = free_and_strdup(&srv, node);
+ if (r < 0)
+ return log_oom();
+ }
#ifdef GPT_ROOT_NATIVE
- else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
+ else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
- if (root && nr >= root_nr)
- continue;
+ if (root && nr >= root_nr)
+ continue;
- root_nr = nr;
- root_rw = !(flags & GPT_FLAG_READ_ONLY);
+ root_nr = nr;
+ root_rw = !(flags & GPT_FLAG_READ_ONLY);
- free(root);
- root = strdup(node);
- if (!root)
- return log_oom();
- }
+ r = free_and_strdup(&root, node);
+ if (r < 0)
+ return log_oom();
+ }
#endif
#ifdef GPT_ROOT_SECONDARY
- else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) {
+ else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) {
+
+ if (secondary_root && nr >= secondary_root_nr)
+ continue;
+
+ secondary_root_nr = nr;
+ secondary_root_rw = !(flags & GPT_FLAG_READ_ONLY);
+
+ r = free_and_strdup(&secondary_root, node);
+ if (r < 0)
+ return log_oom();
+ }
+#endif
+
+ } else if (is_mbr) {
+ int type;
- if (secondary_root && nr >= secondary_root_nr)
+ type = blkid_partition_get_type(pp);
+ if (type != 0x83) /* Linux partition */
continue;
- secondary_root_nr = nr;
- secondary_root_rw = !(flags & GPT_FLAG_READ_ONLY);
+ /* Note that there's a certain, intended
+ * asymmetry here: while for GPT we simply
+ * take the first valid partition and ignore
+ * all others of the same type, for MBR we
+ * fail if there are multiple suitable
+ * partitions. This is because the GPT
+ * partition types are defined by us, and
+ * hence we can define their lookup semantics,
+ * while for the MBR logic we reuse existing
+ * definitions, and simply don't want to make
+ * out the situation. */
+
+ if (root) {
+ log_error("Identified multiple bootable Linux 0x83 partitions on\n"
+ " %s\n"
+ PARTITION_TABLE_BLURB, arg_image);
+ return -EINVAL;
+ }
+ root_nr = nr;
- free(secondary_root);
- secondary_root = strdup(node);
- if (!secondary_root)
+ r = free_and_strdup(&root, node);
+ if (r < 0)
return log_oom();
}
-#endif
}
if (!root && !secondary_root) {
- log_error("Failed to identify root partition in disk image %s.\n"
- "Note that the disk image needs to follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/ to be supported by systemd-nspawn.", arg_image);
+ log_error("Failed to identify root partition in disk image\n"
+ " %s\n"
+ PARTITION_TABLE_BLURB, arg_image);
return -EINVAL;
}