static uid_t arg_uid_base = UID_INVALID;
static bool arg_quiet = false;
static ImageFilter *arg_image_filter = NULL;
+static int arg_copy_ownership = -1;
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
" --loop-ref=NAME Set reference string for loopback device\n"
" --loop-ref-auto Derive reference string from image file name\n"
" --mtree-hash=BOOL Whether to include SHA256 hash in the mtree output\n"
+ " --copy-ownership=BOOL\n"
+ " Whether to copy ownership when copying files\n"
" --user Discover user images\n"
" --system Discover system images\n"
" --all Show hidden images too\n"
ARG_USER,
ARG_ALL,
ARG_IMAGE_FILTER,
+ ARG_COPY_OWNERSHIP,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
- { "mount", no_argument, NULL, 'm' },
- { "umount", no_argument, NULL, 'u' },
- { "attach", no_argument, NULL, ARG_ATTACH },
- { "detach", no_argument, NULL, ARG_DETACH },
- { "with", no_argument, NULL, ARG_WITH },
- { "read-only", no_argument, NULL, 'r' },
- { "discard", required_argument, NULL, ARG_DISCARD },
- { "fsck", required_argument, NULL, ARG_FSCK },
- { "growfs", required_argument, NULL, ARG_GROWFS },
- { "root-hash", required_argument, NULL, ARG_ROOT_HASH },
- { "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
- { "usr-hash", required_argument, NULL, ARG_USR_HASH },
- { "usr-hash-sig", required_argument, NULL, ARG_USR_HASH_SIG },
- { "verity-data", required_argument, NULL, ARG_VERITY_DATA },
- { "mkdir", no_argument, NULL, ARG_MKDIR },
- { "rmdir", no_argument, NULL, ARG_RMDIR },
- { "in-memory", no_argument, NULL, ARG_IN_MEMORY },
- { "list", no_argument, NULL, 'l' },
- { "mtree", no_argument, NULL, ARG_MTREE },
- { "copy-from", no_argument, NULL, 'x' },
- { "copy-to", no_argument, NULL, 'a' },
- { "json", required_argument, NULL, ARG_JSON },
- { "discover", no_argument, NULL, ARG_DISCOVER },
- { "loop-ref", required_argument, NULL, ARG_LOOP_REF },
- { "loop-ref-auto", no_argument, NULL, ARG_LOOP_REF_AUTO },
- { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
- { "validate", no_argument, NULL, ARG_VALIDATE },
- { "mtree-hash", required_argument, NULL, ARG_MTREE_HASH },
- { "make-archive", no_argument, NULL, ARG_MAKE_ARCHIVE },
- { "shift", no_argument, NULL, ARG_SHIFT },
- { "system", no_argument, NULL, ARG_SYSTEM },
- { "user", no_argument, NULL, ARG_USER },
- { "all", no_argument, NULL, ARG_ALL },
- { "quiet", no_argument, NULL, 'q' },
- { "image-filter", required_argument, NULL, ARG_IMAGE_FILTER },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
+ { "mount", no_argument, NULL, 'm' },
+ { "umount", no_argument, NULL, 'u' },
+ { "attach", no_argument, NULL, ARG_ATTACH },
+ { "detach", no_argument, NULL, ARG_DETACH },
+ { "with", no_argument, NULL, ARG_WITH },
+ { "read-only", no_argument, NULL, 'r' },
+ { "discard", required_argument, NULL, ARG_DISCARD },
+ { "fsck", required_argument, NULL, ARG_FSCK },
+ { "growfs", required_argument, NULL, ARG_GROWFS },
+ { "root-hash", required_argument, NULL, ARG_ROOT_HASH },
+ { "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
+ { "usr-hash", required_argument, NULL, ARG_USR_HASH },
+ { "usr-hash-sig", required_argument, NULL, ARG_USR_HASH_SIG },
+ { "verity-data", required_argument, NULL, ARG_VERITY_DATA },
+ { "mkdir", no_argument, NULL, ARG_MKDIR },
+ { "rmdir", no_argument, NULL, ARG_RMDIR },
+ { "in-memory", no_argument, NULL, ARG_IN_MEMORY },
+ { "list", no_argument, NULL, 'l' },
+ { "mtree", no_argument, NULL, ARG_MTREE },
+ { "copy-from", no_argument, NULL, 'x' },
+ { "copy-to", no_argument, NULL, 'a' },
+ { "json", required_argument, NULL, ARG_JSON },
+ { "discover", no_argument, NULL, ARG_DISCOVER },
+ { "loop-ref", required_argument, NULL, ARG_LOOP_REF },
+ { "loop-ref-auto", no_argument, NULL, ARG_LOOP_REF_AUTO },
+ { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
+ { "validate", no_argument, NULL, ARG_VALIDATE },
+ { "mtree-hash", required_argument, NULL, ARG_MTREE_HASH },
+ { "make-archive", no_argument, NULL, ARG_MAKE_ARCHIVE },
+ { "shift", no_argument, NULL, ARG_SHIFT },
+ { "system", no_argument, NULL, ARG_SYSTEM },
+ { "user", no_argument, NULL, ARG_USER },
+ { "all", no_argument, NULL, ARG_ALL },
+ { "quiet", no_argument, NULL, 'q' },
+ { "image-filter", required_argument, NULL, ARG_IMAGE_FILTER },
+ { "copy-ownership", required_argument, NULL, ARG_COPY_OWNERSHIP },
{}
};
break;
}
+ case ARG_COPY_OWNERSHIP:
+ r = parse_tristate_argument("--copy-ownership=", optarg, &arg_copy_ownership);
+ if (r < 0)
+ return r;
+ break;
+
case '?':
return -EINVAL;
assert(IN_SET(arg_action, ACTION_LIST, ACTION_MTREE, ACTION_COPY_FROM, ACTION_COPY_TO, ACTION_MAKE_ARCHIVE, ACTION_SHIFT));
+ /* Determine whether to copy ownership:
+ * --copy-ownership=yes: always try to preserve ownership
+ * --copy-ownership=no: never preserve ownership, use current user
+ * --copy-ownership=auto (default): preserve ownership for directory trees,
+ * but not for regular files (since DDI password tables are typically
+ * distinct from the host ones, individual file ownership is less meaningful) */
+
if (arg_image) {
assert(m);
}
/* Try to copy as directory? */
- r = copy_directory_at(source_fd, NULL, AT_FDCWD, arg_target, COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
+ r = copy_directory_at(
+ source_fd, /* from= */ NULL,
+ AT_FDCWD, arg_target,
+ arg_copy_ownership == 0 ? getuid() : UID_INVALID,
+ arg_copy_ownership == 0 ? getgid() : GID_INVALID,
+ COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
if (r >= 0)
return 0;
if (r != -ENOTDIR)
(void) copy_xattr(source_fd, NULL, target_fd, NULL, 0);
(void) copy_access(source_fd, target_fd);
+ if (arg_copy_ownership > 0)
+ (void) copy_owner(source_fd, target_fd);
(void) copy_times(source_fd, target_fd, 0);
- /* When this is a regular file we don't copy ownership! */
return 0;
}
if (errno != ENOENT)
return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target);
- r = copy_tree_at(source_fd, ".", dfd, bn, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL, NULL);
+ r = copy_tree_at(
+ source_fd, ".",
+ dfd, bn,
+ arg_copy_ownership == 0 ? getuid() : UID_INVALID,
+ arg_copy_ownership == 0 ? getgid() : GID_INVALID,
+ COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS,
+ /* denylist= */ NULL,
+ /* subvolumes= */ NULL);
} else
- r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL, NULL);
+ r = copy_tree_at(
+ source_fd, ".",
+ target_fd, ".",
+ arg_copy_ownership == 0 ? getuid() : UID_INVALID,
+ arg_copy_ownership == 0 ? getgid() : GID_INVALID,
+ COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS,
+ /* denylist= */ NULL,
+ /* subvolumes= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);
(void) copy_xattr(source_fd, NULL, target_fd, NULL, 0);
(void) copy_access(source_fd, target_fd);
+ if (arg_copy_ownership > 0)
+ (void) copy_owner(source_fd, target_fd);
(void) copy_times(source_fd, target_fd, 0);
- /* When this is a regular file we don't copy ownership! */
return 0;
}