repart: add new --copy-source= switch

This specifies a directory to which CopyFiles= is considered relative.
If unset defaults to the --root=/--image= setting, or host / otherwise.

This is very similar to --root= but is much more focussed: it is really
and exclusively about CopyFiles= (and related settings such as
ExcludeFiles=) and does not affect any of the settings, i.e. it doesn't
affect CopyBlocks=, the machine ID/seed handling, or where definitions
are read from.

In fact, --root= and --copy-source= may be combined for example to
use the machine ID and similar from one tree, but the copy the files
from another.
This commit is contained in:
Lennart Poettering 2023-09-29 16:24:48 +02:00
parent 248f0186c1
commit 607343a1ac
3 changed files with 50 additions and 15 deletions

View file

@ -468,10 +468,11 @@
<para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para>
<para>When
<citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry>
is invoked with the <option>--image=</option> or <option>--root=</option> command line switches the
source paths specified are taken relative to the specified root directory or disk image root.
</para>
<citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry> is
invoked with the <option>--copy-source=</option> command line switch the file paths are taken
relative to the specified directory. If <option>--copy-source=</option> is not used, but the
<option>--image=</option> or <option>--root=</option> switches are used, the source paths are taken
relative to the specified root directory or disk image root.</para>
<xi:include href="version-info.xml" xpointer="v247"/></listitem>
</varlistentry>

View file

@ -276,6 +276,9 @@
so that the tool operates on the configuration and machine ID stored in the root file system later
transitioned into itself.</para>
<para>See <option>--copy-source=</option> for a more restricted option that only affects
<varname>CopyFiles=</varname>.</para>
<xi:include href="version-info.xml" xpointer="v245"/></listitem>
</varlistentry>
@ -500,6 +503,19 @@
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--copy-source=</option><replaceable>PATH</replaceable></term>
<term><option>-s</option> <replaceable>PATH</replaceable></term>
<listitem><para>Specifies a source directory all <varname>CopyFiles=</varname> source paths shall be
considered relative to. This is similar to <option>--root=</option>, but exclusively applies to the
<varname>CopyFiles=</varname> setting. If <option>--root=</option> and
<option>--copy-source=</option> are used in combination the former applies as usual, except for
<varname>CopyFiles=</varname> where the latter takes precedence.</para>
<xi:include href="version-info.xml" xpointer="v255"/></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" />

View file

@ -162,6 +162,7 @@ static ImagePolicy *arg_image_policy = NULL;
static Architecture arg_architecture = _ARCHITECTURE_INVALID;
static int arg_offline = -1;
static char **arg_copy_from = NULL;
static char *arg_copy_source = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@ -175,6 +176,7 @@ 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, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_copy_source, freep);
typedef struct FreeArea FreeArea;
@ -4274,11 +4276,11 @@ static int add_exclude_path(const char *path, Hashmap **denylist, DenyType type)
if (!st)
return log_oom();
r = chase_and_stat(path, arg_root, CHASE_PREFIX_ROOT, NULL, st);
r = chase_and_stat(path, arg_copy_source, CHASE_PREFIX_ROOT, NULL, st);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to stat source file '%s/%s': %m", strempty(arg_root), path);
return log_error_errno(r, "Failed to stat source file '%s/%s': %m", strempty(arg_copy_source), path);
r = hashmap_ensure_put(denylist, &inode_hash_ops, st, INT_TO_PTR(type));
if (r == -EEXIST)
@ -4402,11 +4404,11 @@ static int add_subvolume_path(const char *path, Set **subvolumes) {
if (!st)
return log_oom();
r = chase_and_stat(path, arg_root, CHASE_PREFIX_ROOT, NULL, st);
r = chase_and_stat(path, arg_copy_source, CHASE_PREFIX_ROOT, NULL, st);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to stat source file '%s/%s': %m", strempty(arg_root), path);
return log_error_errno(r, "Failed to stat source file '%s/%s': %m", strempty(arg_copy_source), path);
r = set_ensure_consume(subvolumes, &inode_hash_ops, TAKE_PTR(st));
if (r < 0)
@ -4469,9 +4471,9 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
if (rfd < 0)
return rfd;
sfd = chase_and_open(*source, arg_root, CHASE_PREFIX_ROOT, O_PATH|O_DIRECTORY|O_CLOEXEC|O_NOCTTY, NULL);
sfd = chase_and_open(*source, arg_copy_source, CHASE_PREFIX_ROOT, O_PATH|O_DIRECTORY|O_CLOEXEC|O_NOCTTY, NULL);
if (sfd < 0)
return log_error_errno(sfd, "Failed to open source file '%s%s': %m", strempty(arg_root), *source);
return log_error_errno(sfd, "Failed to open source file '%s%s': %m", strempty(arg_copy_source), *source);
(void) copy_xattr(sfd, NULL, rfd, NULL, COPY_ALL_XATTRS);
(void) copy_access(sfd, rfd);
@ -4493,9 +4495,9 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
if (r < 0)
return r;
sfd = chase_and_open(*source, arg_root, CHASE_PREFIX_ROOT, O_CLOEXEC|O_NOCTTY, NULL);
sfd = chase_and_open(*source, arg_copy_source, CHASE_PREFIX_ROOT, O_CLOEXEC|O_NOCTTY, NULL);
if (sfd < 0)
return log_error_errno(sfd, "Failed to open source file '%s%s': %m", strempty(arg_root), *source);
return log_error_errno(sfd, "Failed to open source file '%s%s': %m", strempty(arg_copy_source), *source);
r = fd_verify_regular(sfd);
if (r < 0) {
@ -4541,7 +4543,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
denylist, subvolumes_by_source_inode);
if (r < 0)
return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m",
strempty(arg_root), *source, strempty(root), *target);
strempty(arg_copy_source), *source, strempty(root), *target);
} else {
_cleanup_free_ char *dn = NULL, *fn = NULL;
@ -4572,7 +4574,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_SIGINT|COPY_TRUNCATE);
if (r < 0)
return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_copy_source), *target);
(void) copy_xattr(sfd, NULL, tfd, NULL, COPY_ALL_XATTRS);
(void) copy_access(sfd, tfd);
@ -6372,6 +6374,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"
" -s --copy-source=PATH Specify the primary source tree to copy files from\n"
" --copy-from=IMAGE Copy partitions from the given image(s)\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
@ -6417,6 +6420,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ARCHITECTURE,
ARG_OFFLINE,
ARG_COPY_FROM,
ARG_COPY_SOURCE,
};
static const struct option options[] = {
@ -6452,6 +6456,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "architecture", required_argument, NULL, ARG_ARCHITECTURE },
{ "offline", required_argument, NULL, ARG_OFFLINE },
{ "copy-from", required_argument, NULL, ARG_COPY_FROM },
{ "copy-source", required_argument, NULL, 's' },
{}
};
@ -6460,7 +6465,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
while ((c = getopt_long(argc, argv, "hs:", options, NULL)) >= 0)
switch (c) {
@ -6785,6 +6790,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case 's':
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_copy_source);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
@ -7345,6 +7356,13 @@ static int run(int argc, char *argv[]) {
}
}
if (!arg_copy_source && arg_root) {
/* If no explicit copy source is specified, then use --root=/--image= */
arg_copy_source = strdup(arg_root);
if (!arg_copy_source)
return log_oom();
}
context = context_new(arg_seed);
if (!context)
return log_oom();