summaryrefslogtreecommitdiffstats
path: root/src/dissect
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2023-07-06 10:58:44 +0200
committerDaan De Meyer <daan.j.demeyer@gmail.com>2023-07-06 12:11:42 +0200
commit2292fa1e311d4c81d11d9de88cf9a9a6bef0befd (patch)
tree83d5f4a890c707dd38288fea2a120ee5290e3494 /src/dissect
parentMerge pull request #27713 from ddstreet/tpm2_replace_make_primary (diff)
downloadsystemd-2292fa1e311d4c81d11d9de88cf9a9a6bef0befd.tar.xz
systemd-2292fa1e311d4c81d11d9de88cf9a9a6bef0befd.zip
dissect: Allow a few verbs to operate on directories as well as image files
--copy-to, --copy-from, --list and --mtree are useful for image directories as well as image files, so for those verbs, let's check if we were passed a directory and skip all the image file setup if that's the case.
Diffstat (limited to 'src/dissect')
-rw-r--r--src/dissect/dissect.c206
1 files changed, 120 insertions, 86 deletions
diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c
index d2a95eaf68..9db8f862e8 100644
--- a/src/dissect/dissect.c
+++ b/src/dissect/dissect.c
@@ -64,6 +64,7 @@ static enum {
ACTION_VALIDATE,
} arg_action = ACTION_DISSECT;
static char *arg_image = NULL;
+static char *arg_root = NULL;
static char *arg_path = NULL;
static const char *arg_source = NULL;
static const char *arg_target = NULL;
@@ -87,6 +88,7 @@ static char *arg_loop_ref = NULL;
static ImagePolicy* arg_image_policy = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_verity_settings, verity_settings_done);
STATIC_DESTRUCTOR_REGISTER(arg_argv, strv_freep);
@@ -206,6 +208,31 @@ static int patch_argv(int *argc, char ***argv, char ***buf) {
return 1;
}
+static int parse_image_path_argument(const char *path, char **ret_root, char **ret_image) {
+ _cleanup_free_ char *p = NULL;
+ struct stat st;
+ int r;
+
+ assert(ret_image);
+
+ r = parse_path_argument(path, /* suppress_root= */ false, &p);
+ if (r < 0)
+ return r;
+
+ if (stat(p, &st) < 0)
+ return log_error_errno(errno, "Failed to stat %s: %m", p);
+
+ if (S_ISDIR(st.st_mode)) {
+ if (!ret_root)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not an image file.", p);
+
+ *ret_root = TAKE_PTR(p);
+ } else
+ *ret_image = TAKE_PTR(p);
+
+ return 0;
+}
+
static int parse_argv(int argc, char *argv[]) {
enum {
@@ -493,7 +520,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image file path as only argument.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], NULL, &arg_image);
if (r < 0)
return r;
@@ -506,7 +533,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image file path and mount point path as only arguments.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], NULL, &arg_image);
if (r < 0)
return r;
@@ -532,7 +559,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image file path as only argument.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], NULL, &arg_image);
if (r < 0)
return r;
break;
@@ -542,7 +569,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image file path or loopback device as only argument.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], NULL, &arg_image);
if (r < 0)
return r;
break;
@@ -551,9 +578,9 @@ static int parse_argv(int argc, char *argv[]) {
case ACTION_MTREE:
if (optind + 1 != argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Expected an image file path as only argument.");
+ "Expected an image file or directory path as only argument.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], &arg_root, &arg_image);
if (r < 0)
return r;
@@ -563,9 +590,9 @@ static int parse_argv(int argc, char *argv[]) {
case ACTION_COPY_FROM:
if (argc < optind + 2 || argc > optind + 3)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Expected an image file path, a source path and an optional destination path as only arguments.");
+ "Expected an image file or directory path, a source path and an optional destination path as only arguments.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], &arg_root, &arg_image);
if (r < 0)
return r;
arg_source = argv[optind + 1];
@@ -577,9 +604,9 @@ static int parse_argv(int argc, char *argv[]) {
case ACTION_COPY_TO:
if (argc < optind + 2 || argc > optind + 3)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Expected an image file path, an optional source path and a destination path as only arguments.");
+ "Expected an image file or directory path, an optional source path and a destination path as only arguments.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], &arg_root, &arg_image);
if (r < 0)
return r;
@@ -599,7 +626,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image file path and an optional command line.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], NULL, &arg_image);
if (r < 0)
return r;
@@ -622,7 +649,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image file path as only argument.");
- r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image);
+ r = parse_image_path_argument(argv[optind], NULL, &arg_image);
if (r < 0)
return r;
@@ -1232,46 +1259,52 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
_cleanup_(rmdir_and_freep) char *created_dir = NULL;
_cleanup_free_ char *temp = NULL;
+ const char *root;
int r;
- assert(m);
- assert(d);
assert(IN_SET(arg_action, ACTION_LIST, ACTION_MTREE, ACTION_COPY_FROM, ACTION_COPY_TO));
- r = detach_mount_namespace();
- if (r < 0)
- return log_error_errno(r, "Failed to detach mount namespace: %m");
+ if (arg_image) {
+ assert(m);
+ assert(d);
- r = tempfn_random_child(NULL, program_invocation_short_name, &temp);
- if (r < 0)
- return log_error_errno(r, "Failed to generate temporary mount directory: %m");
+ r = detach_mount_namespace();
+ if (r < 0)
+ return log_error_errno(r, "Failed to detach mount namespace: %m");
- r = mkdir_p(temp, 0700);
- if (r < 0)
- return log_error_errno(r, "Failed to create mount point: %m");
+ r = tempfn_random_child(NULL, program_invocation_short_name, &temp);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate temporary mount directory: %m");
- created_dir = TAKE_PTR(temp);
+ r = mkdir_p(temp, 0700);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create mount point: %m");
- r = dissected_image_mount_and_warn(m, created_dir, UID_INVALID, UID_INVALID, arg_flags);
- if (r < 0)
- return r;
+ created_dir = TAKE_PTR(temp);
- mounted_dir = TAKE_PTR(created_dir);
+ r = dissected_image_mount_and_warn(m, created_dir, UID_INVALID, UID_INVALID, arg_flags);
+ if (r < 0)
+ return r;
- r = loop_device_flock(d, LOCK_UN);
- if (r < 0)
- return log_error_errno(r, "Failed to unlock loopback block device: %m");
+ mounted_dir = TAKE_PTR(created_dir);
- r = dissected_image_relinquish(m);
- if (r < 0)
- return log_error_errno(r, "Failed to relinquish DM and loopback block devices: %m");
+ r = loop_device_flock(d, LOCK_UN);
+ if (r < 0)
+ return log_error_errno(r, "Failed to unlock loopback block device: %m");
+
+ r = dissected_image_relinquish(m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to relinquish DM and loopback block devices: %m");
+ }
+
+ root = mounted_dir ?: arg_root;
switch (arg_action) {
case ACTION_COPY_FROM: {
_cleanup_close_ int source_fd = -EBADF, target_fd = -EBADF;
- source_fd = chase_and_open(arg_source, mounted_dir, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
+ source_fd = chase_and_open(arg_source, root, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
if (source_fd < 0)
return log_error_errno(source_fd, "Failed to open source path '%s' in image '%s': %m", arg_source, arg_image);
@@ -1328,7 +1361,7 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
return log_error_errno(r, "Failed to extract filename from target path '%s': %m", arg_target);
is_dir = r == O_DIRECTORY;
- r = chase(dn, mounted_dir, CHASE_PREFIX_ROOT|CHASE_WARN, NULL, &dfd);
+ r = chase(dn, root, CHASE_PREFIX_ROOT|CHASE_WARN, NULL, &dfd);
if (r < 0)
return log_error_errno(r, "Failed to open '%s': %m", dn);
@@ -1398,7 +1431,7 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
case ACTION_MTREE: {
_cleanup_close_ int dfd = -EBADF;
- dfd = open(mounted_dir, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
+ dfd = open(root, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
if (dfd < 0)
return log_error_errno(errno, "Failed to open mount directory: %m");
@@ -1778,64 +1811,65 @@ static int run(int argc, char *argv[]) {
break;
}
- r = verity_settings_load(
+ if (arg_image) {
+ r = verity_settings_load(
&arg_verity_settings,
arg_image, NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to read verity artifacts for %s: %m", arg_image);
-
- if (arg_verity_settings.data_path)
- arg_flags |= DISSECT_IMAGE_NO_PARTITION_TABLE; /* We only support Verity per file system,
- * hence if there's external Verity data
- * available we turn off partition table
- * support */
-
- if (arg_action == ACTION_VALIDATE)
- return action_validate();
-
- open_flags = FLAGS_SET(arg_flags, DISSECT_IMAGE_DEVICE_READ_ONLY) ? O_RDONLY : O_RDWR;
- loop_flags = FLAGS_SET(arg_flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN;
-
- if (arg_in_memory)
- r = loop_device_make_by_path_memory(arg_image, open_flags, /* sector_size= */ UINT32_MAX, loop_flags, LOCK_SH, &d);
- else
- r = loop_device_make_by_path(arg_image, open_flags, /* sector_size= */ UINT32_MAX, loop_flags, LOCK_SH, &d);
- if (r < 0)
- return log_error_errno(r, "Failed to set up loopback device for %s: %m", arg_image);
-
- if (arg_loop_ref) {
- r = loop_device_set_filename(d, arg_loop_ref);
if (r < 0)
- log_warning_errno(r, "Failed to set loop reference string to '%s', ignoring: %m", arg_loop_ref);
- }
-
- r = dissect_loop_device_and_warn(
- d,
- &arg_verity_settings,
- /* mount_options= */ NULL,
- arg_image_policy,
- arg_flags,
- &m);
- if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to read verity artifacts for %s: %m", arg_image);
- if (arg_action == ACTION_ATTACH)
- return action_attach(m, d);
+ if (arg_verity_settings.data_path)
+ arg_flags |= DISSECT_IMAGE_NO_PARTITION_TABLE; /* We only support Verity per file system,
+ * hence if there's external Verity data
+ * available we turn off partition table
+ * support */
+
+ if (arg_action == ACTION_VALIDATE)
+ return action_validate();
+
+ open_flags = FLAGS_SET(arg_flags, DISSECT_IMAGE_DEVICE_READ_ONLY) ? O_RDONLY : O_RDWR;
+ loop_flags = FLAGS_SET(arg_flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN;
+ if (arg_in_memory)
+ r = loop_device_make_by_path_memory(arg_image, open_flags, /* sector_size= */ UINT32_MAX, loop_flags, LOCK_SH, &d);
+ else
+ r = loop_device_make_by_path(arg_image, open_flags, /* sector_size= */ UINT32_MAX, loop_flags, LOCK_SH, &d);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set up loopback device for %s: %m", arg_image);
- r = dissected_image_load_verity_sig_partition(
- m,
- d->fd,
- &arg_verity_settings);
- if (r < 0)
- return log_error_errno(r, "Failed to load verity signature partition: %m");
+ if (arg_loop_ref) {
+ r = loop_device_set_filename(d, arg_loop_ref);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set loop reference string to '%s', ignoring: %m", arg_loop_ref);
+ }
- if (arg_action != ACTION_DISSECT) {
- r = dissected_image_decrypt_interactively(
- m, NULL,
+ r = dissect_loop_device_and_warn(
+ d,
&arg_verity_settings,
- arg_flags);
+ /* mount_options= */ NULL,
+ arg_image_policy,
+ arg_flags,
+ &m);
if (r < 0)
return r;
+
+ if (arg_action == ACTION_ATTACH)
+ return action_attach(m, d);
+
+ r = dissected_image_load_verity_sig_partition(
+ m,
+ d->fd,
+ &arg_verity_settings);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load verity signature partition: %m");
+
+ if (arg_action != ACTION_DISSECT) {
+ r = dissected_image_decrypt_interactively(
+ m, NULL,
+ &arg_verity_settings,
+ arg_flags);
+ if (r < 0)
+ return r;
+ }
}
switch (arg_action) {