log_debug("Unexpected partition flag %llu set on %s!", bit, node);
}
}
+
+static int ioctl_partition_remove(int fd, const char *name, int nr) {
+ assert(fd >= 0);
+ assert(name);
+ assert(nr > 0);
+
+ struct blkpg_partition bp = {
+ .pno = nr,
+ };
+
+ struct blkpg_ioctl_arg ba = {
+ .op = BLKPG_DEL_PARTITION,
+ .data = &bp,
+ .datalen = sizeof(bp),
+ };
+
+ if (strlen(name) >= sizeof(bp.devname))
+ return -EINVAL;
+
+ strcpy(bp.devname, name);
+
+ return RET_NERRNO(ioctl(fd, BLKPG, &ba));
+}
#endif
-static void dissected_partition_done(DissectedPartition *p) {
+static void dissected_partition_done(int fd, DissectedPartition *p) {
+ assert(fd >= 0);
assert(p);
+#if HAVE_BLKID
+ if (p->node && p->partno > 0 && !p->relinquished) {
+ int r;
+
+ r = ioctl_partition_remove(fd, p->node, p->partno);
+ if (r < 0)
+ log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
+ }
+#endif
+
free(p->fstype);
free(p->node);
free(p->label);
return -ENOMEM;
*m = (DissectedImage) {
+ .fd = -1,
.has_init_system = -1,
};
+ m->fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (m->fd < 0)
+ return -errno;
+
r = sd_device_get_sysname(d, &sysname);
if (r < 0)
return log_debug_errno(r, "Failed to get device sysname: %m");
* scheme in OS images. */
if (!PARTITION_DESIGNATOR_VERSIONED(designator) ||
- strverscmp_improved(m->partitions[designator].label, label) >= 0)
+ strverscmp_improved(m->partitions[designator].label, label) >= 0) {
+ r = ioctl_partition_remove(fd, node, nr);
+ if (r < 0)
+ log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
continue;
+ }
- dissected_partition_done(m->partitions + designator);
+ dissected_partition_done(fd, m->partitions + designator);
}
if (fstype) {
const char *sid, *options = NULL;
/* First one wins */
- if (m->partitions[PARTITION_XBOOTLDR].found)
+ if (m->partitions[PARTITION_XBOOTLDR].found) {
+ r = ioctl_partition_remove(fd, node, nr);
+ if (r < 0)
+ log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
continue;
+ }
sid = blkid_partition_get_uuid(pp);
if (sid)
return NULL;
for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++)
- dissected_partition_done(m->partitions + i);
+ dissected_partition_done(m->fd, m->partitions + i);
+ safe_close(m->fd);
free(m->image_name);
free(m->hostname);
strv_free(m->machine_info);
return mfree(m);
}
+void dissected_image_relinquish(DissectedImage *m) {
+ assert(m);
+
+ /* Partitions are automatically removed when the underlying loop device is closed. We just need to
+ * make sure we don't try to remove the partitions early. */
+
+ for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++)
+ m->partitions[i].relinquished = true;
+}
+
static int is_loop_device(const char *path) {
char s[SYS_BLOCK_PATH_MAX("/../loop/")];
struct stat st;
return log_error_errno(r, "Failed to relinquish DM devices: %m");
}
+ dissected_image_relinquish(dissected_image);
loop_device_relinquish(d);
*ret_directory = TAKE_PTR(created_dir);
return log_debug_errno(r, "Failed to relinquish decrypted image: %m");
}
+ dissected_image_relinquish(dissected_image);
loop_device_relinquish(loop_device);
return 0;
char *mount_options;
uint64_t size;
uint64_t offset;
+ bool relinquished;
};
typedef enum PartitionDesignator {
} DissectImageFlags;
struct DissectedImage {
+ int fd; /* Backing fd */
+
bool encrypted:1;
bool has_verity:1; /* verity available in image, but not necessarily used */
bool has_verity_sig:1; /* pkcs#7 signature embedded in image */
DissectedImage* dissected_image_unref(DissectedImage *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
+void dissected_image_relinquish(DissectedImage *m);
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret);
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret);