gpt-auto-discovery: port to dissect-image.c dissector

Change the gpt auto discovery generator to use the same dissector as
nspawn and the rest of the tools. This removes the separate dissector
code that the generator previously had and unifies the relevant code.
This commit is contained in:
Lennart Poettering 2016-12-15 18:18:29 +01:00
parent 47f9472950
commit 72e18a98ba

View file

@ -29,6 +29,7 @@
#include "blkid-util.h"
#include "btrfs-util.h"
#include "dirent-util.h"
#include "dissect-image.h"
#include "efivars.h"
#include "fd-util.h"
#include "fileio.h"
@ -273,61 +274,28 @@ static bool path_is_busy(const char *where) {
return false;
}
static int probe_and_add_mount(
static int add_partition_mount(
DissectedPartition *p,
const char *id,
const char *what,
const char *where,
bool rw,
const char *description,
const char *post) {
const char *description) {
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
const char *fstype = NULL;
int r;
assert(id);
assert(what);
assert(where);
assert(description);
assert(p);
if (path_is_busy(where)) {
log_debug("%s already populated, ignoring.", where);
return 0;
}
/* Let's check the partition type here, so that we know
* whether to do LUKS magic. */
errno = 0;
b = blkid_new_probe_from_filename(what);
if (!b) {
if (errno == 0)
return log_oom();
return log_error_errno(errno, "Failed to allocate prober: %m");
}
blkid_probe_enable_superblocks(b, 1);
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
errno = 0;
r = blkid_do_safeprobe(b);
if (r == -2 || r == 1) /* no result or uncertain */
return 0;
else if (r != 0)
return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
/* add_mount is OK with fstype being NULL. */
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
return add_mount(
id,
what,
p->node,
where,
fstype,
rw,
p->fstype,
p->rw,
NULL,
description,
post);
SPECIAL_LOCAL_FS_TARGET);
}
static int add_swap(const char *path) {
@ -452,11 +420,11 @@ static int add_automount(
return 0;
}
static int add_esp(const char *what) {
static int add_esp(DissectedPartition *p) {
const char *esp;
int r;
assert(what);
assert(p);
if (in_initrd()) {
log_debug("In initrd, ignoring the ESP.");
@ -478,9 +446,7 @@ static int add_esp(const char *what) {
}
if (is_efi_boot()) {
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
const char *fstype = NULL, *uuid_string = NULL;
sd_id128_t loader_uuid, part_uuid;
sd_id128_t loader_uuid;
/* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
@ -492,43 +458,7 @@ static int add_esp(const char *what) {
if (r < 0)
return log_error_errno(r, "Failed to read ESP partition UUID: %m");
errno = 0;
b = blkid_new_probe_from_filename(what);
if (!b) {
if (errno == 0)
return log_oom();
return log_error_errno(errno, "Failed to allocate prober: %m");
}
blkid_probe_enable_partitions(b, 1);
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0;
r = blkid_do_safeprobe(b);
if (r == -2 || r == 1) /* no result or uncertain */
return 0;
else if (r != 0)
return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
if (!streq_ptr(fstype, "vfat")) {
log_debug("Partition for %s is not a FAT filesystem, ignoring.", esp);
return 0;
}
errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid_string, NULL);
if (r != 0) {
log_debug_errno(errno, "Partition for %s does not have a UUID, ignoring.", esp);
return 0;
}
if (sd_id128_from_string(uuid_string, &part_uuid) < 0) {
log_debug("Partition for %s does not have a valid UUID, ignoring.", esp);
return 0;
}
if (!sd_id128_equal(part_uuid, loader_uuid)) {
if (!sd_id128_equal(p->uuid, loader_uuid)) {
log_debug("Partition for %s does not appear to be the partition we are booted from.", esp);
return 0;
}
@ -536,13 +466,13 @@ static int add_esp(const char *what) {
log_debug("Not an EFI boot, skipping ESP check.");
return add_automount("boot",
what,
esp,
"vfat",
true,
"umask=0077",
"EFI System Partition Automount",
120 * USEC_PER_SEC);
p->node,
esp,
p->fstype,
true,
"umask=0077",
"EFI System Partition Automount",
120 * USEC_PER_SEC);
}
#else
static int add_esp(const char *what) {
@ -550,21 +480,15 @@ static int add_esp(const char *what) {
}
#endif
static int enumerate_partitions(dev_t devnum) {
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
static int open_parent(dev_t devnum, int *ret) {
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
_cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL;
struct udev_list_entry *first, *item;
struct udev_device *parent = NULL;
const char *name, *node, *pttype, *devtype;
int boot_nr = -1, home_nr = -1, srv_nr = -1;
bool home_rw = true, srv_rw = true;
blkid_partlist pl;
int r, k;
const char *name, *devtype, *node;
struct udev_device *parent;
dev_t pn;
int fd;
assert(ret);
udev = udev_new();
if (!udev)
@ -578,228 +502,94 @@ static int enumerate_partitions(dev_t devnum) {
if (!name)
name = udev_device_get_syspath(d);
if (!name) {
log_debug("Device %u:%u does not have a name, ignoring.",
major(devnum), minor(devnum));
return 0;
log_debug("Device %u:%u does not have a name, ignoring.", major(devnum), minor(devnum));
goto not_found;
}
parent = udev_device_get_parent(d);
if (!parent) {
log_debug("%s: not a partitioned device, ignoring.", name);
return 0;
goto not_found;
}
/* Does it have a devtype? */
devtype = udev_device_get_devtype(parent);
if (!devtype) {
log_debug("%s: parent doesn't have a device type, ignoring.", name);
return 0;
goto not_found;
}
/* Is this a disk or a partition? We only care for disks... */
if (!streq(devtype, "disk")) {
log_debug("%s: parent isn't a raw disk, ignoring.", name);
return 0;
goto not_found;
}
/* Does it have a device node? */
node = udev_device_get_devnode(parent);
if (!node) {
log_debug("%s: parent device does not have device node, ignoring.", name);
return 0;
goto not_found;
}
log_debug("%s: root device %s.", name, node);
pn = udev_device_get_devnum(parent);
if (major(pn) == 0)
return 0;
errno = 0;
b = blkid_new_probe_from_filename(node);
if (!b) {
if (errno == 0)
return log_oom();
return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
if (major(pn) == 0) {
log_debug("%s: parent device is not a proper block device, ignoring.", name);
goto not_found;
}
blkid_probe_enable_partitions(b, 1);
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
fd = open(node, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", node);
errno = 0;
r = blkid_do_safeprobe(b);
if (r == 1)
return 0; /* no results */
else if (r == -2) {
log_warning("%s: probe gave ambiguous results, ignoring.", node);
return 0;
} else if (r != 0)
return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
*ret = fd;
return 1;
errno = 0;
r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
if (r != 0) {
if (errno == 0)
return 0; /* No partition table found. */
not_found:
*ret = -1;
return 0;
}
return log_error_errno(errno, "%s: failed to determine partition table type: %m", node);
}
static int enumerate_partitions(dev_t devnum) {
/* We only do this all for GPT... */
if (!streq_ptr(pttype, "gpt")) {
log_debug("%s: not a GPT partition table, ignoring.", node);
_cleanup_close_ int fd = -1;
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
int r, k;
r = open_parent(devnum, &fd);
if (r <= 0)
return r;
r = dissect_image(fd, NULL, 0, DISSECT_IMAGE_GPT_ONLY, &m);
if (r == -ENOPKG) {
log_debug_errno(r, "No suitable partition table found, ignoring.");
return 0;
}
errno = 0;
pl = blkid_probe_get_partitions(b);
if (!pl) {
if (errno == 0)
return log_oom();
return log_error_errno(errno, "%s: failed to list partitions: %m", node);
}
e = udev_enumerate_new(udev);
if (!e)
return log_oom();
r = udev_enumerate_add_match_parent(e, parent);
if (r < 0)
return log_oom();
return log_error_errno(r, "Failed to dissect: %m");
r = udev_enumerate_add_match_subsystem(e, "block");
if (r < 0)
return log_oom();
r = udev_enumerate_scan_devices(e);
if (r < 0)
return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
_cleanup_udev_device_unref_ struct udev_device *q;
unsigned long long flags;
const char *stype, *subnode;
sd_id128_t type_id;
blkid_partition pp;
dev_t qn;
int nr;
q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
if (!q)
continue;
qn = udev_device_get_devnum(q);
if (major(qn) == 0)
continue;
if (qn == devnum)
continue;
if (qn == pn)
continue;
subnode = udev_device_get_devnode(q);
if (!subnode)
continue;
pp = blkid_partlist_devno_to_partition(pl, qn);
if (!pp)
continue;
nr = blkid_partition_get_partno(pp);
if (nr < 0)
continue;
stype = blkid_partition_get_type_string(pp);
if (!stype)
continue;
if (sd_id128_from_string(stype, &type_id) < 0)
continue;
flags = blkid_partition_get_flags(pp);
if (sd_id128_equal(type_id, GPT_SWAP)) {
if (flags & GPT_FLAG_NO_AUTO)
continue;
if (flags & GPT_FLAG_READ_ONLY) {
log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
continue;
}
k = add_swap(subnode);
if (k < 0)
r = k;
} else if (sd_id128_equal(type_id, GPT_ESP)) {
/* We only care for the first /boot partition */
if (boot && nr >= boot_nr)
continue;
/* Note that we do not honour the "no-auto"
* flag for the ESP, as it is often unset, to
* hide it from Windows. */
boot_nr = nr;
r = free_and_strdup(&boot, subnode);
if (r < 0)
return log_oom();
} else if (sd_id128_equal(type_id, GPT_HOME)) {
if (flags & GPT_FLAG_NO_AUTO)
continue;
/* We only care for the first /home partition */
if (home && nr >= home_nr)
continue;
home_nr = nr;
home_rw = !(flags & GPT_FLAG_READ_ONLY),
r = free_and_strdup(&home, subnode);
if (r < 0)
return log_oom();
} else if (sd_id128_equal(type_id, GPT_SRV)) {
if (flags & GPT_FLAG_NO_AUTO)
continue;
/* We only care for the first /srv partition */
if (srv && nr >= srv_nr)
continue;
srv_nr = nr;
srv_rw = !(flags & GPT_FLAG_READ_ONLY),
r = free_and_strdup(&srv, subnode);
if (r < 0)
return log_oom();
}
}
if (boot) {
k = add_esp(boot);
if (m->partitions[PARTITION_SWAP].found) {
k = add_swap(m->partitions[PARTITION_SWAP].node);
if (k < 0)
r = k;
}
if (home) {
k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
if (m->partitions[PARTITION_ESP].found) {
k = add_esp(m->partitions + PARTITION_ESP);
if (k < 0)
r = k;
}
if (srv) {
k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
if (m->partitions[PARTITION_HOME].found) {
k = add_partition_mount(m->partitions + PARTITION_HOME, "home", "/home", "Home Partition");
if (k < 0)
r = k;
}
if (m->partitions[PARTITION_SRV].found) {
k = add_partition_mount(m->partitions + PARTITION_SRV, "srv", "/srv", "Server Data Partition");
if (k < 0)
r = k;
}