diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml index 1799961527..06bccad8c3 100644 --- a/man/systemd-repart.xml +++ b/man/systemd-repart.xml @@ -440,6 +440,14 @@ due to missing permissions. + + IMAGE + + Instructs systemd-repart to copy the partitions from the given + image. The partitions from the given image are synthesized into partition definitions that are + parsed before the partition definition files. + + diff --git a/src/partition/repart.c b/src/partition/repart.c index 8c9bc08d20..4fe2c63a46 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -153,6 +153,7 @@ static uint64_t arg_sector_size = 0; static ImagePolicy *arg_image_policy = NULL; static Architecture arg_architecture = _ARCHITECTURE_INVALID; static int arg_offline = -1; +static char *arg_copy_from = NULL; STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); @@ -164,6 +165,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep); STATIC_DESTRUCTOR_REGISTER(arg_filter_partitions, freep); STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); +STATIC_DESTRUCTOR_REGISTER(arg_copy_from, freep); typedef struct FreeArea FreeArea; @@ -228,6 +230,7 @@ typedef struct Partition { bool copy_blocks_auto; const char *copy_blocks_root; int copy_blocks_fd; + uint64_t copy_blocks_offset; uint64_t copy_blocks_size; char *format; @@ -346,6 +349,7 @@ static Partition *partition_new(void) { .partno = UINT64_MAX, .offset = UINT64_MAX, .copy_blocks_fd = -EBADF, + .copy_blocks_offset = UINT64_MAX, .copy_blocks_size = UINT64_MAX, .no_auto = -1, .read_only = -1, @@ -423,24 +427,20 @@ static void partition_foreignize(Partition *p) { p->verity = VERITY_OFF; } -static bool partition_exclude(const Partition *p) { - assert(p); - +static bool partition_type_exclude(GptPartitionType type) { if (arg_filter_partitions_type == FILTER_PARTITIONS_NONE) return false; for (size_t i = 0; i < arg_n_filter_partitions; i++) - if (sd_id128_equal(p->type.uuid, arg_filter_partitions[i].uuid)) + if (sd_id128_equal(type.uuid, arg_filter_partitions[i].uuid)) return arg_filter_partitions_type == FILTER_PARTITIONS_EXCLUDE; return arg_filter_partitions_type == FILTER_PARTITIONS_INCLUDE; } -static bool partition_defer(const Partition *p) { - assert(p); - +static bool partition_type_defer(GptPartitionType type) { for (size_t i = 0; i < arg_n_defer_partitions; i++) - if (sd_id128_equal(p->type.uuid, arg_defer_partitions[i].uuid)) + if (sd_id128_equal(type.uuid, arg_defer_partitions[i].uuid)) return true; return false; @@ -1657,7 +1657,7 @@ static int partition_read_definition(Partition *p, const char *path, const char if (r < 0) return r; - if (partition_exclude(p)) + if (partition_type_exclude(p->type)) return 0; if (p->size_min != UINT64_MAX && p->size_max != UINT64_MAX && p->size_min > p->size_max) @@ -1805,9 +1805,231 @@ static int find_verity_sibling(Context *context, Partition *p, VerityMode mode, return 0; } +static int context_open_and_lock_backing_fd(const char *node, int *backing_fd) { + _cleanup_close_ int fd = -EBADF; + + assert(node); + assert(backing_fd); + + if (*backing_fd >= 0) + return 0; + + fd = open(node, O_RDONLY|O_CLOEXEC); + if (fd < 0) + return log_error_errno(errno, "Failed to open device '%s': %m", node); + + /* Tell udev not to interfere while we are processing the device */ + if (flock(fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0) + return log_error_errno(errno, "Failed to lock device '%s': %m", node); + + log_debug("Device %s opened and locked.", node); + *backing_fd = TAKE_FD(fd); + return 1; +} + +static int determine_current_padding( + struct fdisk_context *c, + struct fdisk_table *t, + struct fdisk_partition *p, + uint64_t secsz, + uint64_t grainsz, + uint64_t *ret) { + + size_t n_partitions; + uint64_t offset, next = UINT64_MAX; + + assert(c); + assert(t); + assert(p); + assert(ret); + + if (!fdisk_partition_has_end(p)) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition has no end!"); + + offset = fdisk_partition_get_end(p); + assert(offset < UINT64_MAX); + offset++; /* The end is one sector before the next partition or padding. */ + assert(offset < UINT64_MAX / secsz); + offset *= secsz; + + n_partitions = fdisk_table_get_nents(t); + for (size_t i = 0; i < n_partitions; i++) { + struct fdisk_partition *q; + uint64_t start; + + q = fdisk_table_get_partition(t, i); + if (!q) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata: %m"); + + if (fdisk_partition_is_used(q) <= 0) + continue; + + if (!fdisk_partition_has_start(q)) + continue; + + start = fdisk_partition_get_start(q); + assert(start < UINT64_MAX / secsz); + start *= secsz; + + if (start >= offset && (next == UINT64_MAX || next > start)) + next = start; + } + + if (next == UINT64_MAX) { + /* No later partition? In that case check the end of the usable area */ + next = fdisk_get_last_lba(c); + assert(next < UINT64_MAX); + next++; /* The last LBA is one sector before the end */ + + assert(next < UINT64_MAX / secsz); + next *= secsz; + + if (offset > next) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition end beyond disk end."); + } + + assert(next >= offset); + offset = round_up_size(offset, grainsz); + next = round_down_size(next, grainsz); + + *ret = LESS_BY(next, offset); /* Saturated subtraction, rounding might have fucked things up */ + return 0; +} + +static int context_copy_from(Context *context) { + _cleanup_close_ int fd = -EBADF; + _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL; + _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL; + Partition *last = NULL; + unsigned long secsz, grainsz; + size_t n_partitions; + int r; + + if (!arg_copy_from) + return 0; + + r = context_open_and_lock_backing_fd(arg_copy_from, &fd); + if (r < 0) + return r; + + r = fd_verify_regular(fd); + if (r < 0) + return log_error_errno(r, "%s is not a file: %m", arg_copy_from); + + r = fdisk_new_context_fd(fd, /* read_only = */ true, /* sector_size = */ UINT32_MAX, &c); + if (r < 0) + return log_error_errno(r, "Failed to create fdisk context: %m"); + + secsz = fdisk_get_sector_size(c); + grainsz = fdisk_get_grain_size(c); + + /* Insist on a power of two, and that it's a multiple of 512, i.e. the traditional sector size. */ + if (secsz < 512 || !ISPOWEROF2(secsz)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size %lu is not a power of two larger than 512? Refusing.", secsz); + + if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT)) + return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), "Cannot copy from disk %s with no GPT disk label.", arg_copy_from); + + r = fdisk_get_partitions(c, &t); + if (r < 0) + return log_error_errno(r, "Failed to acquire partition table: %m"); + + n_partitions = fdisk_table_get_nents(t); + for (size_t i = 0; i < n_partitions; i++) { + _cleanup_(partition_freep) Partition *np = NULL; + _cleanup_free_ char *label_copy = NULL; + struct fdisk_partition *p; + const char *label; + uint64_t sz, start, padding; + sd_id128_t ptid, id; + GptPartitionType type; + + p = fdisk_table_get_partition(t, i); + if (!p) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata: %m"); + + if (fdisk_partition_is_used(p) <= 0) + continue; + + if (fdisk_partition_has_start(p) <= 0 || + fdisk_partition_has_size(p) <= 0 || + fdisk_partition_has_partno(p) <= 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a position, size or number."); + + r = fdisk_partition_get_type_as_id128(p, &ptid); + if (r < 0) + return log_error_errno(r, "Failed to query partition type UUID: %m"); + + type = gpt_partition_type_from_uuid(ptid); + + r = fdisk_partition_get_uuid_as_id128(p, &id); + if (r < 0) + return log_error_errno(r, "Failed to query partition UUID: %m"); + + label = fdisk_partition_get_name(p); + if (!isempty(label)) { + label_copy = strdup(label); + if (!label_copy) + return log_oom(); + } + + sz = fdisk_partition_get_size(p); + assert(sz <= UINT64_MAX/secsz); + sz *= secsz; + + start = fdisk_partition_get_start(p); + assert(start <= UINT64_MAX/secsz); + start *= secsz; + + if (partition_type_exclude(type)) + continue; + + np = partition_new(); + if (!np) + return log_oom(); + + np->type = type; + np->new_uuid = id; + np->new_uuid_is_set = true; + np->size_min = np->size_max = sz; + np->new_label = TAKE_PTR(label_copy); + + np->definition_path = strdup(arg_copy_from); + if (!np->definition_path) + return log_oom(); + + r = determine_current_padding(c, t, p, secsz, grainsz, &padding); + if (r < 0) + return r; + + np->padding_min = np->padding_max = padding; + + np->copy_blocks_path = strdup(arg_copy_from); + if (!np->copy_blocks_path) + return log_oom(); + + np->copy_blocks_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (np->copy_blocks_fd < 0) + return log_error_errno(r, "Failed to duplicate file descriptor of %s: %m", arg_copy_from); + + np->copy_blocks_offset = start; + np->copy_blocks_size = sz; + + r = fdisk_partition_get_attrs_as_uint64(p, &np->gpt_flags); + if (r < 0) + return log_error_errno(r, "Failed to get partition flags: %m"); + + LIST_INSERT_AFTER(partitions, context->partitions, last, np); + last = TAKE_PTR(np); + context->n_partitions++; + } + + return 0; +} + static int context_read_definitions(Context *context) { _cleanup_strv_free_ char **files = NULL; - Partition *last = NULL; + Partition *last = LIST_FIND_TAIL(partitions, context->partitions); const char *const *dirs; int r; @@ -1903,74 +2125,6 @@ static int context_read_definitions(Context *context) { return 0; } -static int determine_current_padding( - struct fdisk_context *c, - struct fdisk_table *t, - struct fdisk_partition *p, - uint64_t secsz, - uint64_t grainsz, - uint64_t *ret) { - - size_t n_partitions; - uint64_t offset, next = UINT64_MAX; - - assert(c); - assert(t); - assert(p); - - if (!fdisk_partition_has_end(p)) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition has no end!"); - - offset = fdisk_partition_get_end(p); - assert(offset < UINT64_MAX); - offset++; /* The end is one sector before the next partition or padding. */ - assert(offset < UINT64_MAX / secsz); - offset *= secsz; - - n_partitions = fdisk_table_get_nents(t); - for (size_t i = 0; i < n_partitions; i++) { - struct fdisk_partition *q; - uint64_t start; - - q = fdisk_table_get_partition(t, i); - if (!q) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata: %m"); - - if (fdisk_partition_is_used(q) <= 0) - continue; - - if (!fdisk_partition_has_start(q)) - continue; - - start = fdisk_partition_get_start(q); - assert(start < UINT64_MAX / secsz); - start *= secsz; - - if (start >= offset && (next == UINT64_MAX || next > start)) - next = start; - } - - if (next == UINT64_MAX) { - /* No later partition? In that case check the end of the usable area */ - next = fdisk_get_last_lba(c); - assert(next < UINT64_MAX); - next++; /* The last LBA is one sector before the end */ - - assert(next < UINT64_MAX / secsz); - next *= secsz; - - if (offset > next) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Partition end beyond disk end."); - } - - assert(next >= offset); - offset = round_up_size(offset, grainsz); - next = round_down_size(next, grainsz); - - *ret = LESS_BY(next, offset); /* Saturated subtraction, rounding might have fucked things up */ - return 0; -} - static int fdisk_ask_cb(struct fdisk_context *c, struct fdisk_ask *ask, void *data) { _cleanup_free_ char *ids = NULL; int r; @@ -2026,28 +2180,6 @@ static int derive_uuid(sd_id128_t base, const char *token, sd_id128_t *ret) { return 0; } -static int context_open_and_lock_backing_fd(Context *context, const char *node) { - _cleanup_close_ int fd = -EBADF; - - assert(context); - assert(node); - - if (context->backing_fd >= 0) - return 0; - - fd = open(node, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return log_error_errno(errno, "Failed to open device '%s': %m", node); - - /* Tell udev not to interfere while we are processing the device */ - if (flock(fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0) - return log_error_errno(errno, "Failed to lock device '%s': %m", node); - - log_debug("Device %s opened and locked.", node); - context->backing_fd = TAKE_FD(fd); - return 1; -} - static int context_load_partition_table(Context *context) { _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL; _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL; @@ -2076,7 +2208,7 @@ static int context_load_partition_table(Context *context) { else { uint32_t ssz; - r = context_open_and_lock_backing_fd(context, context->node); + r = context_open_and_lock_backing_fd(context->node, &context->backing_fd); if (r < 0) return r; @@ -2123,7 +2255,7 @@ static int context_load_partition_table(Context *context) { if (context->backing_fd < 0) { /* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */ - r = context_open_and_lock_backing_fd(context, FORMAT_PROC_FD_PATH(fdisk_get_devfd(c))); + r = context_open_and_lock_backing_fd(FORMAT_PROC_FD_PATH(fdisk_get_devfd(c)), &context->backing_fd); if (r < 0) return r; } @@ -3130,7 +3262,7 @@ static int context_wipe_and_discard(Context *context) { if (!p->allocated_to_area) continue; - if (partition_defer(p)) + if (partition_type_defer(p->type)) continue; r = context_wipe_partition(context, p); @@ -3922,7 +4054,7 @@ static int context_copy_blocks(Context *context) { if (PARTITION_EXISTS(p)) /* Never copy over existing partitions */ continue; - if (partition_defer(p)) + if (partition_type_defer(p->type)) continue; assert(p->new_size != UINT64_MAX); @@ -3944,6 +4076,9 @@ static int context_copy_blocks(Context *context) { log_info("Copying in '%s' (%s) on block level into future partition %" PRIu64 ".", p->copy_blocks_path, FORMAT_BYTES(p->copy_blocks_size), p->partno); + if (p->copy_blocks_offset != UINT64_MAX && lseek(p->copy_blocks_fd, p->copy_blocks_offset, SEEK_SET) < 0) + return log_error_errno(errno, "Failed to seek to copy blocks offset in %s: %m", p->copy_blocks_path); + r = copy_bytes(p->copy_blocks_fd, partition_target_fd(t), p->copy_blocks_size, COPY_REFLINK); if (r < 0) return log_error_errno(r, "Failed to copy in data from '%s': %m", p->copy_blocks_path); @@ -3960,14 +4095,14 @@ static int context_copy_blocks(Context *context) { if (r < 0) return r; - if (p->siblings[VERITY_HASH] && !partition_defer(p->siblings[VERITY_HASH])) { + if (p->siblings[VERITY_HASH] && !partition_type_defer(p->siblings[VERITY_HASH]->type)) { r = partition_format_verity_hash(context, p->siblings[VERITY_HASH], /* node = */ NULL, partition_target_path(t)); if (r < 0) return r; } - if (p->siblings[VERITY_SIG] && !partition_defer(p->siblings[VERITY_SIG])) { + if (p->siblings[VERITY_SIG] && !partition_type_defer(p->siblings[VERITY_SIG]->type)) { r = partition_format_verity_sig(context, p->siblings[VERITY_SIG]); if (r < 0) return r; @@ -4362,7 +4497,7 @@ static int context_mkfs(Context *context) { if (p->copy_blocks_fd >= 0) continue; - if (partition_defer(p)) + if (partition_type_defer(p->type)) continue; assert(p->offset != UINT64_MAX); @@ -4446,14 +4581,14 @@ static int context_mkfs(Context *context) { if (r < 0) return r; - if (p->siblings[VERITY_HASH] && !partition_defer(p->siblings[VERITY_HASH])) { + if (p->siblings[VERITY_HASH] && !partition_type_defer(p->siblings[VERITY_HASH]->type)) { r = partition_format_verity_hash(context, p->siblings[VERITY_HASH], /* node = */ NULL, partition_target_path(t)); if (r < 0) return r; } - if (p->siblings[VERITY_SIG] && !partition_defer(p->siblings[VERITY_SIG])) { + if (p->siblings[VERITY_SIG] && !partition_type_defer(p->siblings[VERITY_SIG]->type)) { r = partition_format_verity_sig(context, p->siblings[VERITY_SIG]); if (r < 0) return r; @@ -4782,7 +4917,7 @@ static int context_mangle_partitions(Context *context) { if (p->dropped) continue; - if (partition_defer(p)) + if (partition_type_defer(p->type)) continue; assert(p->new_size != UINT64_MAX); @@ -5031,7 +5166,7 @@ static int context_split(Context *context) { if (!p->split_path) continue; - if (partition_defer(p)) + if (partition_type_defer(p->type)) continue; fdt = open(p->split_path, O_WRONLY|O_NOCTTY|O_CLOEXEC|O_NOFOLLOW|O_CREAT|O_EXCL, 0666); @@ -6000,6 +6135,7 @@ static int help(void) { " --sector-size=SIZE Set the logical sector size for the image\n" " --architecture=ARCH Set the generic architecture for the image\n" " --offline=BOOL Whether to build the image offline\n" + " --copy-from=IMAGE Copy partitions from the given image\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -6043,6 +6179,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SKIP_PARTITIONS, ARG_ARCHITECTURE, ARG_OFFLINE, + ARG_COPY_FROM, }; static const struct option options[] = { @@ -6077,6 +6214,7 @@ static int parse_argv(int argc, char *argv[]) { { "sector-size", required_argument, NULL, ARG_SECTOR_SIZE }, { "architecture", required_argument, NULL, ARG_ARCHITECTURE }, { "offline", required_argument, NULL, ARG_OFFLINE }, + { "copy-from", required_argument, NULL, ARG_COPY_FROM }, {} }; @@ -6398,6 +6536,12 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_COPY_FROM: + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_copy_from); + if (r < 0) + return r; + break; + case '?': return -EINVAL; @@ -6949,6 +7093,10 @@ static int run(int argc, char *argv[]) { if (!context) return log_oom(); + r = context_copy_from(context); + if (r < 0) + return r; + strv_uniq(arg_definitions); r = context_read_definitions(context); diff --git a/src/shared/fdisk-util.c b/src/shared/fdisk-util.c index e88adb2d43..9a301f38ac 100644 --- a/src/shared/fdisk-util.c +++ b/src/shared/fdisk-util.c @@ -1,8 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "dissect-image.h" +#include "extract-word.h" #include "fd-util.h" #include "fdisk-util.h" +#include "parse-util.h" #if HAVE_LIBFDISK @@ -75,4 +77,79 @@ int fdisk_partition_get_type_as_id128(struct fdisk_partition *p, sd_id128_t *ret return sd_id128_from_string(pts, ret); } +int fdisk_partition_get_attrs_as_uint64(struct fdisk_partition *pa, uint64_t *ret) { + uint64_t flags = 0; + const char *a; + int r; + + assert(pa); + assert(ret); + + /* Retrieve current flags as uint64_t mask */ + + a = fdisk_partition_get_attrs(pa); + if (!a) { + *ret = 0; + return 0; + } + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&a, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + break; + + if (streq(word, "RequiredPartition")) + flags |= SD_GPT_FLAG_REQUIRED_PARTITION; + else if (streq(word, "NoBlockIOProtocol")) + flags |= SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL; + else if (streq(word, "LegacyBIOSBootable")) + flags |= SD_GPT_FLAG_LEGACY_BIOS_BOOTABLE; + else { + const char *e; + unsigned u; + + /* Drop "GUID" prefix if specified */ + e = startswith(word, "GUID:") ?: word; + + if (safe_atou(e, &u) < 0) { + log_debug("Unknown partition flag '%s', ignoring.", word); + continue; + } + + if (u >= sizeof(flags)*8) { /* partition flags on GPT are 64-bit. Let's ignore any further + bits should libfdisk report them */ + log_debug("Partition flag above bit 63 (%s), ignoring.", word); + continue; + } + + flags |= UINT64_C(1) << u; + } + } + + *ret = flags; + return 0; +} + +int fdisk_partition_set_attrs_as_uint64(struct fdisk_partition *pa, uint64_t flags) { + _cleanup_free_ char *attrs = NULL; + int r; + + assert(pa); + + for (unsigned i = 0; i < sizeof(flags) * 8; i++) { + if (!FLAGS_SET(flags, UINT64_C(1) << i)) + continue; + + r = strextendf_with_separator(&attrs, ",", "%u", i); + if (r < 0) + return r; + } + + return fdisk_partition_set_attrs(pa, strempty(attrs)); +} + #endif diff --git a/src/shared/fdisk-util.h b/src/shared/fdisk-util.h index 4845132927..b82ff705d7 100644 --- a/src/shared/fdisk-util.h +++ b/src/shared/fdisk-util.h @@ -19,4 +19,7 @@ int fdisk_new_context_fd(int fd, bool read_only, uint32_t sector_size, struct fd int fdisk_partition_get_uuid_as_id128(struct fdisk_partition *p, sd_id128_t *ret); int fdisk_partition_get_type_as_id128(struct fdisk_partition *p, sd_id128_t *ret); +int fdisk_partition_get_attrs_as_uint64(struct fdisk_partition *pa, uint64_t *ret); +int fdisk_partition_set_attrs_as_uint64(struct fdisk_partition *pa, uint64_t flags); + #endif diff --git a/src/sysupdate/sysupdate-partition.c b/src/sysupdate/sysupdate-partition.c index 8f33469663..587265482b 100644 --- a/src/sysupdate/sysupdate-partition.c +++ b/src/sysupdate/sysupdate-partition.c @@ -18,87 +18,6 @@ void partition_info_destroy(PartitionInfo *p) { p->device = mfree(p->device); } -static int fdisk_partition_get_attrs_as_uint64( - struct fdisk_partition *pa, - uint64_t *ret) { - - uint64_t flags = 0; - const char *a; - int r; - - assert(pa); - assert(ret); - - /* Retrieve current flags as uint64_t mask */ - - a = fdisk_partition_get_attrs(pa); - if (!a) { - *ret = 0; - return 0; - } - - for (;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&a, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS); - if (r < 0) - return r; - if (r == 0) - break; - - if (streq(word, "RequiredPartition")) - flags |= SD_GPT_FLAG_REQUIRED_PARTITION; - else if (streq(word, "NoBlockIOProtocol")) - flags |= SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL; - else if (streq(word, "LegacyBIOSBootable")) - flags |= SD_GPT_FLAG_LEGACY_BIOS_BOOTABLE; - else { - const char *e; - unsigned u; - - /* Drop "GUID" prefix if specified */ - e = startswith(word, "GUID:") ?: word; - - if (safe_atou(e, &u) < 0) { - log_debug("Unknown partition flag '%s', ignoring.", word); - continue; - } - - if (u >= sizeof(flags)*8) { /* partition flags on GPT are 64-bit. Let's ignore any further - bits should libfdisk report them */ - log_debug("Partition flag above bit 63 (%s), ignoring.", word); - continue; - } - - flags |= UINT64_C(1) << u; - } - } - - *ret = flags; - return 0; -} - -static int fdisk_partition_set_attrs_as_uint64( - struct fdisk_partition *pa, - uint64_t flags) { - - _cleanup_free_ char *attrs = NULL; - int r; - - assert(pa); - - for (unsigned i = 0; i < sizeof(flags) * 8; i++) { - if (!FLAGS_SET(flags, UINT64_C(1) << i)) - continue; - - r = strextendf_with_separator(&attrs, ",", "%u", i); - if (r < 0) - return r; - } - - return fdisk_partition_set_attrs(pa, strempty(attrs)); -} - int read_partition_info( struct fdisk_context *c, struct fdisk_table *t, diff --git a/test/units/testsuite-58.sh b/test/units/testsuite-58.sh index 13e40bd82a..118d797f2b 100755 --- a/test/units/testsuite-58.sh +++ b/test/units/testsuite-58.sh @@ -160,6 +160,27 @@ last-lba: 2097118 $imgs/zzz1 : start= 2048, size= 1775576, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\" $imgs/zzz2 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\"" + systemd-repart --offline="$OFFLINE" \ + --empty=create \ + --size=1G \ + --dry-run=no \ + --seed="$seed" \ + --copy-from="$imgs/zzz" \ + "$imgs/copy" + + output=$(sfdisk -d "$imgs/copy" | grep -v -e 'sector-size' -e '^$') + + assert_eq "$output" "label: gpt +label-id: 1D2CE291-7CCE-4F7D-BC83-FDB49AD74EBD +device: $imgs/copy +unit: sectors +first-lba: 2048 +last-lba: 2097118 +$imgs/copy1 : start= 2048, size= 1775576, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\" +$imgs/copy2 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\"" + + rm "$imgs/copy" # Save disk space + systemd-repart --offline="$OFFLINE" \ --definitions="$defs" \ --dry-run=no \