mirror of
https://github.com/systemd/systemd.git
synced 2025-02-03 17:47:28 +03:00
Merge pull request #28632 from DaanDeMeyer/repart-synthesize
repart: Add --copy-from option
This commit is contained in:
commit
1f1efbbf55
@ -440,6 +440,14 @@
|
||||
due to missing permissions.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--copy-from=</option><arg>IMAGE</arg></term>
|
||||
|
||||
<listitem><para>Instructs <command>systemd-repart</command> 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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 \
|
||||
|
Loading…
x
Reference in New Issue
Block a user