X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fnspawn%2Fnspawn.c;h=9fe040c81b6342005e89d72ef98eabdf0edc8c8c;hp=3fce3ad77f0c72cd4081dbe74c9e2faf705ebd08;hb=ada4799ac5ad2e6c0fe11dc5c096faca8a85876b;hpb=ab5e3a1bccaf79d65c93fc15ddeaa7595ffe0b86 diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3fce3ad77..9fe040c81 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1655,7 +1655,7 @@ static int watch_rtnl(sd_event *event, int recv_fd, union in_addr_union *exposed cmsg = CMSG_FIRSTHDR(&mh); assert(cmsg->cmsg_level == SOL_SOCKET); assert(cmsg->cmsg_type == SCM_RIGHTS); - assert(cmsg->cmsg_len = CMSG_LEN(sizeof(int))); + assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int))); memcpy(&fd, CMSG_DATA(cmsg), sizeof(int)); r = sd_rtnl_open_fd(&rtnl, fd, 1, RTNLGRP_IPV4_IFADDR); @@ -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 (is_gpt) { + sd_id128_t type_id; + const char *stype; - if (sd_id128_from_string(stype, &type_id) < 0) - continue; - - 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 - if (secondary_root && nr >= secondary_root_nr) + } else if (is_mbr) { + int type; + + 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; } @@ -3337,6 +3385,7 @@ int main(int argc, char *argv[]) { pid_t pid = 0; int ret = EXIT_SUCCESS; union in_addr_union exposed = {}; + _cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT; log_parse_environment(); log_open(); @@ -3382,20 +3431,8 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_template) { - r = btrfs_subvol_snapshot(arg_template, arg_directory, arg_read_only, true); - if (r == -EEXIST) { - if (!arg_quiet) - log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template); - } else if (r < 0) { - log_error_errno(r, "Couldn't create snapshort %s from %s: %m", arg_directory, arg_template); - goto finish; - } else { - if (!arg_quiet) - log_info("Populated %s from template %s.", arg_directory, arg_template); - } - - } else if (arg_ephemeral) { + if (arg_ephemeral) { + _cleanup_release_lock_file_ LockFile original_lock = LOCK_FILE_INIT; char *np; /* If the specified path is a mount point we @@ -3418,6 +3455,12 @@ int main(int argc, char *argv[]) { goto finish; } + r = image_path_lock(np, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock); + if (r < 0) { + log_error_errno(r, "Failed to lock %s: %m", np); + goto finish; + } + r = btrfs_subvol_snapshot(arg_directory, np, arg_read_only, true); if (r < 0) { free(np); @@ -3429,6 +3472,31 @@ int main(int argc, char *argv[]) { arg_directory = np; remove_subvol = true; + + } else { + r = image_path_lock(arg_directory, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock); + if (r == -EBUSY) { + log_error_errno(r, "Directory tree %s is currently busy.", arg_directory); + goto finish; + } + if (r < 0) { + log_error_errno(r, "Failed to lock %s: %m", arg_directory); + return r; + } + + if (arg_template) { + r = btrfs_subvol_snapshot(arg_template, arg_directory, arg_read_only, true); + if (r == -EEXIST) { + if (!arg_quiet) + log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template); + } else if (r < 0) { + log_error_errno(r, "Couldn't create snapshort %s from %s: %m", arg_directory, arg_template); + goto finish; + } else { + if (!arg_quiet) + log_info("Populated %s from template %s.", arg_directory, arg_template); + } + } } if (arg_boot) { @@ -3455,6 +3523,16 @@ int main(int argc, char *argv[]) { assert(arg_image); assert(!arg_template); + r = image_path_lock(arg_image, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock); + if (r == -EBUSY) { + r = log_error_errno(r, "Disk image %s is currently busy.", arg_image); + goto finish; + } + if (r < 0) { + r = log_error_errno(r, "Failed to create image lock: %m"); + goto finish; + } + if (!mkdtemp(template)) { log_error_errno(errno, "Failed to create temporary directory: %m"); r = -errno; @@ -3917,9 +3995,10 @@ int main(int argc, char *argv[]) { _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; char last_char = 0; - sd_notify(false, - "READY=1\n" - "STATUS=Container running."); + sd_notifyf(false, + "READY=1\n" + "STATUS=Container running.\n" + "X_NSPAWN_LEADER_PID=" PID_FMT, pid); r = sd_event_new(&event); if (r < 0) { @@ -4034,7 +4113,7 @@ finish: if (arg_machine) { const char *p; - p = strappenda("/run/systemd/nspawn/propagate", arg_machine); + p = strappenda("/run/systemd/nspawn/propagate/", arg_machine); (void) rm_rf(p, false, true, false); }