]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect: immediately close pipes when we determined we have no data for them
authorLennart Poettering <lennart@poettering.net>
Wed, 29 Jul 2020 13:17:22 +0000 (15:17 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 11 Aug 2020 20:26:48 +0000 (22:26 +0200)
This effectively makes little difference because we exit soon later
anyway, which will close the fds, too. However, it's still useful since
it means the parent will get EOF events on them in the order we process
things and isn't delayed to process the data from the pipes until the
child dies.

src/dissect/dissect.c
src/shared/dissect-image.c

index c9f16d7a64b3d743a279b8d05699fc56689a14a5..b2ef84c0e97d88dac2bfd9bfbf13054018462e4c 100644 (file)
@@ -315,365 +315,391 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
-static int run(int argc, char *argv[]) {
-        _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
-        _cleanup_(decrypted_image_unrefp) DecryptedImage *di = NULL;
-        _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
+static int action_dissect(DissectedImage *m, LoopDevice *d) {
+        _cleanup_(table_unrefp) Table *t = NULL;
+        uint64_t size;
         int r;
 
-        log_parse_environment();
-        log_open();
-
-        r = parse_argv(argc, argv);
-        if (r <= 0)
-                return r;
-
-        r = verity_metadata_load(
-                        arg_image, NULL,
-                        arg_root_hash ? NULL : &arg_root_hash,
-                        &arg_root_hash_size,
-                        arg_verity_data ? NULL : &arg_verity_data,
-                        arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path);
-        if (r < 0)
-                return log_error_errno(r, "Failed to read verity artifacts for %s: %m", arg_image);
+        assert(m);
+        assert(d);
 
-        r = loop_device_make_by_path(
-                        arg_image,
-                        (arg_flags & DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : O_RDWR,
-                        arg_verity_data ? 0 : LO_FLAGS_PARTSCAN,
-                        &d);
+        r = dissected_image_acquire_metadata(m);
+        if (r == -EMEDIUMTYPE)
+                return log_error_errno(r, "Not a valid OS image, no os-release file included.");
+        if (r == -ENXIO)
+                return log_error_errno(r, "No root partition discovered.");
         if (r < 0)
-                return log_error_errno(r, "Failed to set up loopback device: %m");
+                return log_error_errno(r, "Failed to acquire image metadata: %m");
 
-        if (arg_verity_data)
-                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 */
-        r = dissect_image_and_warn(
-                        d->fd,
-                        arg_image,
-                        arg_root_hash,
-                        arg_root_hash_size,
-                        arg_verity_data,
-                        NULL,
-                        arg_flags,
-                        &m);
-        if (r < 0)
-                return r;
+        printf("      Name: %s\n", basename(arg_image));
 
-        switch (arg_action) {
+        if (ioctl(d->fd, BLKGETSIZE64, &size) < 0)
+                log_debug_errno(errno, "Failed to query size of loopback device: %m");
+        else {
+                char s[FORMAT_BYTES_MAX];
+                printf("      Size: %s\n", format_bytes(s, sizeof(s), size));
+        }
 
-        case ACTION_DISSECT: {
-                _cleanup_(table_unrefp) Table *t = NULL;
-                uint64_t size;
+        if (m->hostname)
+                printf("  Hostname: %s\n", m->hostname);
 
-                r = dissected_image_acquire_metadata(m);
-                if (r == -EMEDIUMTYPE)
-                        return log_error_errno(r, "Not a valid OS image, no os-release file included.");
-                if (r == -ENXIO)
-                        return log_error_errno(r, "No root partition discovered.");
-                if (r < 0)
-                        return log_error_errno(r, "Failed to acquire image metadata: %m");
+        if (!sd_id128_is_null(m->machine_id))
+                printf("Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->machine_id));
 
-                printf("      Name: %s\n", basename(arg_image));
+        if (!strv_isempty(m->machine_info)) {
+                char **p, **q;
 
-                if (ioctl(d->fd, BLKGETSIZE64, &size) < 0)
-                        log_debug_errno(errno, "Failed to query size of loopback device: %m");
-                else {
-                        char s[FORMAT_BYTES_MAX];
-                        printf("      Size: %s\n", format_bytes(s, sizeof(s), size));
-                }
+                STRV_FOREACH_PAIR(p, q, m->machine_info)
+                        printf("%s %s=%s\n",
+                               p == m->machine_info ? "Mach. Info:" : "           ",
+                               *p, *q);
+        }
 
-                if (m->hostname)
-                        printf("  Hostname: %s\n", m->hostname);
+        if (!strv_isempty(m->os_release)) {
+                char **p, **q;
 
-                if (!sd_id128_is_null(m->machine_id))
-                        printf("Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->machine_id));
+                STRV_FOREACH_PAIR(p, q, m->os_release)
+                        printf("%s %s=%s\n",
+                               p == m->os_release ? "OS Release:" : "           ",
+                               *p, *q);
+        }
 
-                if (!strv_isempty(m->machine_info)) {
-                        char **p, **q;
+        putc('\n', stdout);
 
-                        STRV_FOREACH_PAIR(p, q, m->machine_info)
-                                printf("%s %s=%s\n",
-                                       p == m->machine_info ? "Mach. Info:" : "           ",
-                                       *p, *q);
-                }
-
-                if (!strv_isempty(m->os_release)) {
-                        char **p, **q;
+        t = table_new("rw", "designator", "partition uuid", "fstype", "architecture", "verity", "node", "partno");
+        if (!t)
+                return log_oom();
 
-                        STRV_FOREACH_PAIR(p, q, m->os_release)
-                                printf("%s %s=%s\n",
-                                       p == m->os_release ? "OS Release:" : "           ",
-                                       *p, *q);
-                }
+        (void) table_set_empty_string(t, "-");
+        (void) table_set_align_percent(t, table_get_cell(t, 0, 7), 100);
 
-                putc('\n', stdout);
+        for (unsigned i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
+                DissectedPartition *p = m->partitions + i;
 
-                t = table_new("rw", "designator", "partition uuid", "fstype", "architecture", "verity", "node", "partno");
-                if (!t)
-                        return log_oom();
+                if (!p->found)
+                        continue;
 
-                (void) table_set_empty_string(t, "-");
-                (void) table_set_align_percent(t, table_get_cell(t, 0, 7), 100);
+                r = table_add_many(
+                                t,
+                                TABLE_STRING, p->rw ? "rw" : "ro",
+                                TABLE_STRING, partition_designator_to_string(i));
+                if (r < 0)
+                        return table_log_add_error(r);
 
-                for (unsigned i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
-                        DissectedPartition *p = m->partitions + i;
+                if (sd_id128_is_null(p->uuid))
+                        r = table_add_cell(t, NULL, TABLE_EMPTY, NULL);
+                else
+                        r = table_add_cell(t, NULL, TABLE_UUID, &p->uuid);
+                if (r < 0)
+                        return table_log_add_error(r);
 
-                        if (!p->found)
-                                continue;
+                r = table_add_many(
+                                t,
+                                TABLE_STRING, p->fstype,
+                                TABLE_STRING, architecture_to_string(p->architecture));
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                if (arg_verity_data)
+                        r = table_add_cell(t, NULL, TABLE_STRING, "external");
+                else if (dissected_image_can_do_verity(m, i))
+                        r = table_add_cell(t, NULL, TABLE_STRING, yes_no(dissected_image_has_verity(m, i)));
+                else
+                        r = table_add_cell(t, NULL, TABLE_EMPTY, NULL);
+                if (r < 0)
+                        return table_log_add_error(r);
 
-                        r = table_add_many(
-                                        t,
-                                        TABLE_STRING, p->rw ? "rw" : "ro",
-                                        TABLE_STRING, partition_designator_to_string(i));
+                if (p->partno < 0) /* no partition table, naked file system */ {
+                        r = table_add_cell(t, NULL, TABLE_STRING, arg_image);
                         if (r < 0)
                                 return table_log_add_error(r);
 
-                        if (sd_id128_is_null(p->uuid))
-                                r = table_add_cell(t, NULL, TABLE_EMPTY, NULL);
-                        else
-                                r = table_add_cell(t, NULL, TABLE_UUID, &p->uuid);
+                        r = table_add_cell(t, NULL, TABLE_EMPTY, NULL);
+                } else {
+                        r = table_add_cell(t, NULL, TABLE_STRING, p->node);
                         if (r < 0)
                                 return table_log_add_error(r);
 
-                        r = table_add_many(
-                                        t,
-                                        TABLE_STRING, p->fstype,
-                                        TABLE_STRING, architecture_to_string(p->architecture));
-                        if (r < 0)
-                                return table_log_add_error(r);
+                        r = table_add_cell(t, NULL, TABLE_INT, &p->partno);
+                }
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
 
-                        if (arg_verity_data)
-                                r = table_add_cell(t, NULL, TABLE_STRING, "external");
-                        else if (dissected_image_can_do_verity(m, i))
-                                r = table_add_cell(t, NULL, TABLE_STRING, yes_no(dissected_image_has_verity(m, i)));
-                        else
-                                r = table_add_cell(t, NULL, TABLE_EMPTY, NULL);
-                        if (r < 0)
-                                return table_log_add_error(r);
+        r = table_print(t, stdout);
+        if (r < 0)
+                return log_error_errno(r, "Failed to dump table: %m");
 
+        return 0;
+}
 
-                        if (p->partno < 0) /* no partition table, naked file system */ {
-                                r = table_add_cell(t, NULL, TABLE_STRING, arg_image);
-                                if (r < 0)
-                                        return table_log_add_error(r);
+static int action_mount(DissectedImage *m, LoopDevice *d) {
+        _cleanup_(decrypted_image_unrefp) DecryptedImage *di = NULL;
+        int r;
 
-                                r = table_add_cell(t, NULL, TABLE_EMPTY, NULL);
-                        } else {
-                                r = table_add_cell(t, NULL, TABLE_STRING, p->node);
-                                if (r < 0)
-                                        return table_log_add_error(r);
+        assert(m);
+        assert(d);
 
-                                r = table_add_cell(t, NULL, TABLE_INT, &p->partno);
-                        }
-                        if (r < 0)
-                                return table_log_add_error(r);
-                }
+        r = dissected_image_decrypt_interactively(
+                        m, NULL,
+                        arg_root_hash, arg_root_hash_size,
+                        arg_verity_data,
+                        arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size,
+                        arg_flags,
+                        &di);
+        if (r < 0)
+                return r;
 
-                r = table_print(t, stdout);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to dump table: %m");
+        r = dissected_image_mount(m, arg_path, UID_INVALID, arg_flags);
+        if (r == -EUCLEAN)
+                return log_error_errno(r, "File system check on image failed: %m");
+        if (r < 0)
+                return log_error_errno(r, "Failed to mount image: %m");
 
-                break;
+        if (di) {
+                r = decrypted_image_relinquish(di);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to relinquish DM devices: %m");
         }
 
-        case ACTION_MOUNT:
-                r = dissected_image_decrypt_interactively(
-                                m, NULL,
-                                arg_root_hash, arg_root_hash_size,
-                                arg_verity_data,
-                                arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size,
-                                arg_flags,
-                                &di);
-                if (r < 0)
-                        return r;
+        loop_device_relinquish(d);
+        return 0;
+}
 
-                r = dissected_image_mount(m, arg_path, UID_INVALID, arg_flags);
-                if (r == -EUCLEAN)
-                        return log_error_errno(r, "File system check on image failed: %m");
-                if (r < 0)
-                        return log_error_errno(r, "Failed to mount image: %m");
+static int action_copy(DissectedImage *m, LoopDevice *d) {
+        _cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
+        _cleanup_(decrypted_image_unrefp) DecryptedImage *di = NULL;
+        _cleanup_(rmdir_and_freep) char *created_dir = NULL;
+        _cleanup_free_ char *temp = NULL;
+        int r;
 
-                if (di) {
-                        r = decrypted_image_relinquish(di);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to relinquish DM devices: %m");
-                }
+        assert(m);
+        assert(d);
 
-                loop_device_relinquish(d);
-                break;
+        r = dissected_image_decrypt_interactively(
+                        m, NULL,
+                        arg_root_hash, arg_root_hash_size,
+                        arg_verity_data,
+                        arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size,
+                        arg_flags,
+                        &di);
+        if (r < 0)
+                return r;
 
-        case ACTION_COPY_FROM:
-        case ACTION_COPY_TO: {
-                _cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
-                _cleanup_(rmdir_and_freep) char *created_dir = NULL;
-                _cleanup_free_ char *temp = NULL;
-
-                r = dissected_image_decrypt_interactively(
-                                m, NULL,
-                                arg_root_hash, arg_root_hash_size,
-                                arg_verity_data,
-                                arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size,
-                                arg_flags,
-                                &di);
-                if (r < 0)
-                        return r;
+        r = detach_mount_namespace();
+        if (r < 0)
+                return log_error_errno(r, "Failed to detach mount namespace: %m");
 
-                r = detach_mount_namespace();
-                if (r < 0)
-                        return log_error_errno(r, "Failed to detach mount namespace: %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");
 
-                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 = mkdir_p(temp, 0700);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create mount point: %m");
 
-                r = mkdir_p(temp, 0700);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to create mount point: %m");
+        created_dir = TAKE_PTR(temp);
+
+        r = dissected_image_mount(m, created_dir, UID_INVALID, arg_flags);
+        if (r == -EUCLEAN)
+                return log_error_errno(r, "File system check on image failed: %m");
+        if (r < 0)
+                return log_error_errno(r, "Failed to mount image: %m");
 
-                created_dir = TAKE_PTR(temp);
+        mounted_dir = TAKE_PTR(created_dir);
 
-                r = dissected_image_mount(m, created_dir, UID_INVALID, arg_flags);
-                if (r == -EUCLEAN)
-                        return log_error_errno(r, "File system check on image failed: %m");
+        if (di) {
+                r = decrypted_image_relinquish(di);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to mount image: %m");
+                        return log_error_errno(r, "Failed to relinquish DM devices: %m");
+        }
+
+        loop_device_relinquish(d);
 
-                mounted_dir = TAKE_PTR(created_dir);
+        if (arg_action == ACTION_COPY_FROM) {
+                _cleanup_close_ int source_fd = -1, target_fd = -1;
 
-                if (di) {
-                        r = decrypted_image_relinquish(di);
+                source_fd = chase_symlinks_and_open(arg_source, mounted_dir, 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);
+
+                /* Copying to stdout? */
+                if (streq(arg_target, "-")) {
+                        r = copy_bytes(source_fd, STDOUT_FILENO, (uint64_t) -1, COPY_REFLINK);
                         if (r < 0)
-                                return log_error_errno(r, "Failed to relinquish DM devices: %m");
+                                return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to stdout: %m", arg_source, arg_image);
+
+                        /* When we copy to stdou we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */
+                        return 0;
                 }
 
-                loop_device_relinquish(d);
+                /* Try to copy as directory? */
+                r = copy_directory_fd(source_fd, arg_target, COPY_REFLINK|COPY_MERGE_EMPTY|COPY_SIGINT);
+                if (r >= 0)
+                        return 0;
+                if (r != -ENOTDIR)
+                        return log_error_errno(r, "Failed to copy %s in image '%s' to '%s': %m", arg_source, arg_image, arg_target);
+
+                r = fd_verify_regular(source_fd);
+                if (r == -EISDIR)
+                        return log_error_errno(r, "Target '%s' exists already and is not a directory.", arg_target);
+                if (r < 0)
+                        return log_error_errno(r, "Source path %s in image '%s' is neither regular file nor directory, refusing: %m", arg_source, arg_image);
 
-                if (arg_action == ACTION_COPY_FROM) {
-                        _cleanup_close_ int source_fd = -1, target_fd = -1;
+                /* Nah, it's a plain file! */
+                target_fd = open(arg_target, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
+                if (target_fd < 0)
+                        return log_error_errno(errno, "Failed to create regular file at target path '%s': %m", arg_target);
 
-                        source_fd = chase_symlinks_and_open(arg_source, mounted_dir, 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);
+                r = copy_bytes(source_fd, target_fd, (uint64_t) -1, COPY_REFLINK);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to '%s': %m", arg_source, arg_image, arg_target);
 
-                        /* Copying to stdout? */
-                        if (streq(arg_target, "-")) {
-                                r = copy_bytes(source_fd, STDOUT_FILENO, (uint64_t) -1, COPY_REFLINK);
-                                if (r < 0)
-                                        return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to stdout: %m", arg_source, arg_image);
+                (void) copy_xattr(source_fd, target_fd);
+                (void) copy_access(source_fd, target_fd);
+                (void) copy_times(source_fd, target_fd, 0);
 
-                                /* When we copy to stdou we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */
-                                break;
-                        }
+                /* When this is a regular file we don't copy ownership! */
 
-                        /* Try to copy as directory? */
-                        r = copy_directory_fd(source_fd, arg_target, COPY_REFLINK|COPY_MERGE_EMPTY|COPY_SIGINT);
-                        if (r >= 0)
-                                break;
-                        if (r != -ENOTDIR)
-                                return log_error_errno(r, "Failed to copy %s in image '%s' to '%s': %m", arg_source, arg_image, arg_target);
+        } else {
+                _cleanup_close_ int source_fd = -1, target_fd = -1;
+                _cleanup_close_ int dfd = -1;
+                _cleanup_free_ char *dn = NULL;
 
-                        r = fd_verify_regular(source_fd);
-                        if (r == -EISDIR)
-                                return log_error_errno(r, "Target '%s' exists already and is not a directory.", arg_target);
-                        if (r < 0)
-                                return log_error_errno(r, "Source path %s in image '%s' is neither regular file nor directory, refusing: %m", arg_source, arg_image);
+                assert(arg_action == ACTION_COPY_TO);
+
+                dn = dirname_malloc(arg_target);
+                if (!dn)
+                        return log_oom();
+
+                r = chase_symlinks(dn, mounted_dir, CHASE_PREFIX_ROOT|CHASE_WARN, NULL, &dfd);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to open '%s': %m", dn);
 
-                        /* Nah, it's a plain file! */
-                        target_fd = open(arg_target, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
+                /* Are we reading from stdin? */
+                if (streq(arg_source, "-")) {
+                        target_fd = openat(dfd, basename(arg_target), O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_EXCL, 0644);
                         if (target_fd < 0)
-                                return log_error_errno(errno, "Failed to create regular file at target path '%s': %m", arg_target);
+                                return log_error_errno(errno, "Failed to open target file '%s': %m", arg_target);
 
-                        r = copy_bytes(source_fd, target_fd, (uint64_t) -1, COPY_REFLINK);
+                        r = copy_bytes(STDIN_FILENO, target_fd, (uint64_t) -1, COPY_REFLINK);
                         if (r < 0)
-                                return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to '%s': %m", arg_source, arg_image, arg_target);
+                                return log_error_errno(r, "Failed to copy bytes from stdin to '%s' in image '%s': %m", arg_target, arg_image);
 
-                        (void) copy_xattr(source_fd, target_fd);
-                        (void) copy_access(source_fd, target_fd);
-                        (void) copy_times(source_fd, target_fd, 0);
+                        /* When we copy from stdin we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */
+                        return 0;
+                }
 
-                        /* When this is a regular file we don't copy ownership! */
+                source_fd = open(arg_source, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (source_fd < 0)
+                        return log_error_errno(source_fd, "Failed to open source path '%s': %m", arg_source);
 
-                } else {
-                        _cleanup_close_ int source_fd = -1, target_fd = -1;
-                        _cleanup_close_ int dfd = -1;
-                        _cleanup_free_ char *dn = NULL;
+                r = fd_verify_regular(source_fd);
+                if (r < 0) {
+                        if (r != -EISDIR)
+                                return log_error_errno(r, "Source '%s' is neither regular file nor directory: %m", arg_source);
 
-                        assert(arg_action == ACTION_COPY_TO);
+                        /* We are looking at a directory. */
 
-                        dn = dirname_malloc(arg_target);
-                        if (!dn)
-                                return log_oom();
+                        target_fd = openat(dfd, basename(arg_target), O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+                        if (target_fd < 0) {
+                                if (errno != ENOENT)
+                                        return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target);
 
-                        r = chase_symlinks(dn, mounted_dir, CHASE_PREFIX_ROOT|CHASE_WARN, NULL, &dfd);
+                                r = copy_tree_at(source_fd, ".", dfd, basename(arg_target), UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT);
+                        } else
+                                r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT);
                         if (r < 0)
-                                return log_error_errno(r, "Failed to open '%s': %m", dn);
+                                return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);
 
-                        /* Are we reading from stdin? */
-                        if (streq(arg_source, "-")) {
-                                target_fd = openat(dfd, basename(arg_target), O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_EXCL, 0644);
-                                if (target_fd < 0)
-                                        return log_error_errno(errno, "Failed to open target file '%s': %m", arg_target);
+                        return 0;
+                }
 
-                                r = copy_bytes(STDIN_FILENO, target_fd, (uint64_t) -1, COPY_REFLINK);
-                                if (r < 0)
-                                        return log_error_errno(r, "Failed to copy bytes from stdin to '%s' in image '%s': %m", arg_target, arg_image);
+                /* We area looking at a regular file */
+                target_fd = openat(dfd, basename(arg_target), O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_EXCL, 0600);
+                if (target_fd < 0)
+                        return log_error_errno(errno, "Failed to open target file '%s': %m", arg_target);
 
-                                /* When we copy from stdin we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */
-                                break;
-                        }
+                r = copy_bytes(source_fd, target_fd, (uint64_t) -1, COPY_REFLINK);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to copy bytes from '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);
 
-                        source_fd = open(arg_source, O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                        if (source_fd < 0)
-                                return log_error_errno(source_fd, "Failed to open source path '%s': %m", arg_source);
+                (void) copy_xattr(source_fd, target_fd);
+                (void) copy_access(source_fd, target_fd);
+                (void) copy_times(source_fd, target_fd, 0);
 
-                        r = fd_verify_regular(source_fd);
-                        if (r < 0) {
-                                if (r != -EISDIR)
-                                        return log_error_errno(r, "Source '%s' is neither regular file nor directory: %m", arg_source);
+                /* When this is a regular file we don't copy ownership! */
+        }
 
-                                /* We are looking at a directory. */
+        return 0;
+}
 
-                                target_fd = openat(dfd, basename(arg_target), O_RDONLY|O_DIRECTORY|O_CLOEXEC);
-                                if (target_fd < 0) {
-                                        if (errno != ENOENT)
-                                                return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target);
+static int run(int argc, char *argv[]) {
+        _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
+        _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
+        int r;
 
-                                        r = copy_tree_at(source_fd, ".", dfd, basename(arg_target), UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT);
-                                } else
-                                        r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT);
-                                if (r < 0)
-                                        return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);
+        log_parse_environment();
+        log_open();
 
-                                break;
-                        }
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                return r;
 
-                        /* We area looking at a regular file */
-                        target_fd = openat(dfd, basename(arg_target), O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_EXCL, 0600);
-                        if (target_fd < 0)
-                                return log_error_errno(errno, "Failed to open target file '%s': %m", arg_target);
+        r = verity_metadata_load(
+                        arg_image, NULL,
+                        arg_root_hash ? NULL : &arg_root_hash,
+                        &arg_root_hash_size,
+                        arg_verity_data ? NULL : &arg_verity_data,
+                        arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read verity artifacts for %s: %m", arg_image);
 
-                        r = copy_bytes(source_fd, target_fd, (uint64_t) -1, COPY_REFLINK);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to copy bytes from '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);
+        r = loop_device_make_by_path(
+                        arg_image,
+                        (arg_flags & DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : O_RDWR,
+                        arg_verity_data ? 0 : LO_FLAGS_PARTSCAN,
+                        &d);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set up loopback device: %m");
 
-                        (void) copy_xattr(source_fd, target_fd);
-                        (void) copy_access(source_fd, target_fd);
-                        (void) copy_times(source_fd, target_fd, 0);
+        if (arg_verity_data)
+                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 */
+        r = dissect_image_and_warn(
+                        d->fd,
+                        arg_image,
+                        arg_root_hash,
+                        arg_root_hash_size,
+                        arg_verity_data,
+                        NULL,
+                        arg_flags,
+                        &m);
+        if (r < 0)
+                return r;
 
-                        /* When this is a regular file we don't copy ownership! */
-                }
+        switch (arg_action) {
 
+        case ACTION_DISSECT:
+                r = action_dissect(m, d);
+                break;
+
+        case ACTION_MOUNT:
+                r = action_mount(m, d);
+                break;
+
+        case ACTION_COPY_FROM:
+        case ACTION_COPY_TO:
+                r = action_copy(m, d);
                 break;
-        }
 
         default:
                 assert_not_reached("Unknown action.");
         }
 
-        return 0;
+        return r;
 }
 
 DEFINE_MAIN_FUNCTION(run);
index c42c4569b2ee3dbf4f22289db003827057219242..953598f2ff89e62f364ccfed09f3138a770d556c 100644 (file)
@@ -1776,7 +1776,7 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
                 }
 
                 for (k = 0; k < _META_MAX; k++) {
-                        _cleanup_close_ int fd = -1;
+                        _cleanup_close_ int fd = -ENOENT;
                         const char *p;
 
                         fds[2*k] = safe_close(fds[2*k]);
@@ -1788,6 +1788,7 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
                         }
                         if (fd < 0) {
                                 log_debug_errno(fd, "Failed to read %s file of image, ignoring: %m", paths[k]);
+                                fds[2*k+1] = safe_close(fds[2*k+1]);
                                 continue;
                         }