#include <sys/prctl.h>
#include <sys/wait.h>
+#include "sd-id128.h"
+
#include "architecture.h"
#include "ask-password-api.h"
#include "blkid-util.h"
+#include "blockdev-util.h"
#include "copy.h"
#include "crypt-util.h"
#include "def.h"
#include "hostname-util.h"
#include "id128-util.h"
#include "linux-3.13/dm-ioctl.h"
+#include "missing.h"
#include "mount-util.h"
#include "path-util.h"
#include "process-util.h"
#endif
}
-int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret) {
+/* Detect RPMB and Boot partitions, which are not listed by blkid.
+ * See https://github.com/systemd/systemd/issues/5806. */
+static bool device_is_mmc_special_partition(struct udev_device *d) {
+ const char *sysname = udev_device_get_sysname(d);
+ return (sysname && startswith(sysname, "mmcblk") &&
+ (endswith(sysname, "rpmb") || endswith(sysname, "boot0") || endswith(sysname, "boot1")));
+}
+
+int dissect_image(
+ int fd,
+ const void *root_hash,
+ size_t root_hash_size,
+ DissectImageFlags flags,
+ DissectedImage **ret) {
#if HAVE_BLKID
sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
.rw = true,
.partno = -1,
.architecture = _ARCHITECTURE_INVALID,
- .fstype = t,
- .node = n,
+ .fstype = TAKE_PTR(t),
+ .node = TAKE_PTR(n),
};
- t = n = NULL;
-
m->encrypted = streq(fstype, "crypto_LUKS");
- *ret = m;
- m = NULL;
+ *ret = TAKE_PTR(m);
return 0;
}
/* Count the partitions enumerated by the kernel */
n = 0;
first = udev_enumerate_get_list_entry(e);
- udev_list_entry_foreach(item, first)
+ udev_list_entry_foreach(item, first) {
+ _cleanup_udev_device_unref_ struct udev_device *q;
+
+ q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
+ if (!q)
+ return -errno;
+
+ if (device_is_mmc_special_partition(q))
+ continue;
n++;
+ }
/* Count the partitions enumerated by blkid */
z = blkid_partlist_numof_partitions(pl);
_cleanup_udev_device_unref_ struct udev_device *q;
unsigned long long pflags;
blkid_partition pp;
- const char *node, *sysname;
+ const char *node;
dev_t qn;
int nr;
if (st.st_rdev == qn)
continue;
- /* Filter out weird MMC RPMB partitions, which cannot reasonably be read, see
- * https://github.com/systemd/systemd/issues/5806 */
- sysname = udev_device_get_sysname(q);
- if (sysname && startswith(sysname, "mmcblk") && endswith(sysname, "rpmb"))
+ if (device_is_mmc_special_partition(q))
continue;
node = udev_device_get_devnode(q);
.partno = nr,
.rw = rw,
.architecture = architecture,
- .node = n,
- .fstype = t,
+ .node = TAKE_PTR(n),
+ .fstype = TAKE_PTR(t),
.uuid = id,
};
-
- n = t = NULL;
}
} else if (is_mbr) {
.rw = generic_rw,
.partno = generic_nr,
.architecture = _ARCHITECTURE_INVALID,
- .node = generic_node,
+ .node = TAKE_PTR(generic_node),
.uuid = generic_uuid,
};
-
- generic_node = NULL;
}
}
p->rw = false;
}
- *ret = m;
- m = NULL;
+ *ret = TAKE_PTR(m);
return 0;
#else
if (!node)
return -ENOMEM;
- *ret_name = name;
- *ret_node = node;
+ *ret_name = TAKE_PTR(name);
+ *ret_node = TAKE_PTR(node);
- name = node = NULL;
return 0;
}
return r == -EPERM ? -EKEYREJECTED : r;
}
- d->decrypted[d->n_decrypted].name = name;
- name = NULL;
-
- d->decrypted[d->n_decrypted].device = cd;
- cd = NULL;
+ d->decrypted[d->n_decrypted].name = TAKE_PTR(name);
+ d->decrypted[d->n_decrypted].device = TAKE_PTR(cd);
d->n_decrypted++;
- m->decrypted_node = node;
- node = NULL;
+ m->decrypted_node = TAKE_PTR(node);
return 0;
}
if (r < 0)
return r;
- d->decrypted[d->n_decrypted].name = name;
- name = NULL;
-
- d->decrypted[d->n_decrypted].device = cd;
- cd = NULL;
+ d->decrypted[d->n_decrypted].name = TAKE_PTR(name);
+ d->decrypted[d->n_decrypted].device = TAKE_PTR(cd);
d->n_decrypted++;
- m->decrypted_node = node;
- node = NULL;
+ m->decrypted_node = TAKE_PTR(node);
return 0;
}
}
}
- *ret = d;
- d = NULL;
+ *ret = TAKE_PTR(d);
return 1;
#else
if (l < sizeof(sd_id128_t))
return -EINVAL;
- *ret = k;
+ *ret = TAKE_PTR(k);
*ret_size = l;
- k = NULL;
-
return 1;
}
_cleanup_free_ char *hostname = NULL;
unsigned n_meta_initialized = 0, k;
int fds[2 * _META_MAX], r;
- siginfo_t si;
BLOCK_SIGNALS(SIGCHLD);
if (r < 0)
goto finish;
- child = raw_clone(SIGCHLD|CLONE_NEWNS);
- if (child < 0) {
- r = -errno;
+ r = safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_NEW_MOUNTNS, &child);
+ if (r < 0)
goto finish;
- }
-
- if (child == 0) {
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
+ if (r == 0) {
/* Make sure we never propagate to the host */
if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
_exit(EXIT_FAILURE);
fds[2*k] = safe_close(fds[2*k]);
NULSTR_FOREACH(p, paths[k]) {
- _cleanup_free_ char *q = NULL;
-
- r = chase_symlinks(p, t, CHASE_PREFIX_ROOT, &q);
- if (r < 0)
- continue;
-
- fd = open(q, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ fd = chase_symlinks_and_open(p, t, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
if (fd >= 0)
break;
}
- if (fd < 0)
+ if (fd < 0) {
+ log_debug_errno(fd, "Failed to read %s file of image, ignoring: %m", paths[k]);
continue;
+ }
r = copy_bytes(fd, fds[2*k+1], (uint64_t) -1, 0);
if (r < 0)
}
}
- r = wait_for_terminate(child, &si);
- if (r < 0)
- goto finish;
+ r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
child = 0;
-
- if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) {
- r = -EPROTO;
+ if (r < 0)
goto finish;
- }
+ if (r != EXIT_SUCCESS)
+ return -EPROTO;
free_and_replace(m->hostname, hostname);
m->machine_id = machine_id;
return r;
}
+int dissect_image_and_warn(
+ int fd,
+ const char *name,
+ const void *root_hash,
+ size_t root_hash_size,
+ DissectImageFlags flags,
+ DissectedImage **ret) {
+
+ _cleanup_free_ char *buffer = NULL;
+ int r;
+
+ if (!name) {
+ r = fd_get_path(fd, &buffer);
+ if (r < 0)
+ return r;
+
+ name = buffer;
+ }
+
+ r = dissect_image(fd, root_hash, root_hash_size, flags, ret);
+
+ switch (r) {
+
+ case -EOPNOTSUPP:
+ return log_error_errno(r, "Dissecting images is not supported, compiled without blkid support.");
+
+ case -ENOPKG:
+ return log_error_errno(r, "Couldn't identify a suitable partition table or file system in '%s'.", name);
+
+ case -EADDRNOTAVAIL:
+ return log_error_errno(r, "No root partition for specified root hash found in '%s'.", name);
+
+ case -ENOTUNIQ:
+ return log_error_errno(r, "Multiple suitable root partitions found in image '%s'.", name);
+
+ case -ENXIO:
+ return log_error_errno(r, "No suitable root partition found in image '%s'.", name);
+
+ case -EPROTONOSUPPORT:
+ return log_error_errno(r, "Device '%s' is loopback block device with partition scanning turned off, please turn it on.", name);
+
+ default:
+ if (r < 0)
+ return log_error_errno(r, "Failed to dissect image '%s': %m", name);
+
+ return r;
+ }
+}
+
static const char *const partition_designator_table[] = {
[PARTITION_ROOT] = "root",
[PARTITION_ROOT_SECONDARY] = "root-secondary",