From c6ba0c184d297a454baf387663668db77f79c1b5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 6 Sep 2015 23:04:32 +0200 Subject: gpt-auto: try to handle LUKS root partitions better If the root file system is located on an encrypted root disk, we'll not find the GPT partition table for it. Let's fix that by following the slaves/ symlinks in /sys for the device. We only handle devices having exactly one backing device. Also see: #1167 --- src/gpt-auto-generator/gpt-auto-generator.c | 79 ++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) (limited to 'src/gpt-auto-generator') diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 0a34f86be7..2ab7257a24 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -799,6 +799,10 @@ static int get_block_device(const char *path, dev_t *dev) { assert(path); assert(dev); + /* Get's the block device directly backing a file system. If + * the block device is encrypted, returns the device mapper + * block device. */ + if (lstat(path, &st)) return -errno; @@ -816,6 +820,77 @@ static int get_block_device(const char *path, dev_t *dev) { return 0; } +static int get_block_device_harder(const char *path, dev_t *dev) { + _cleanup_closedir_ DIR *d = NULL; + _cleanup_free_ char *p = NULL, *t = NULL; + struct dirent *de, *found = NULL; + const char *q; + unsigned maj, min; + dev_t dt; + int r; + + assert(path); + assert(dev); + + /* Gets the backing block device for a file system, and + * handles LUKS encrypted file systems, looking for its + * immediate parent, if there is one. */ + + r = get_block_device(path, &dt); + if (r <= 0) + return r; + + if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0) + return -ENOMEM; + + d = opendir(p); + if (!d) { + if (errno == ENOENT) + goto fallback; + + return -errno; + } + + FOREACH_DIRENT_ALL(de, d, return -errno) { + + if (STR_IN_SET(de->d_name, ".", "..")) + continue; + + if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN)) + continue; + + if (found) /* Don't try to support multiple backing block devices */ + goto fallback; + + found = de; + break; + } + + if (!found) + goto fallback; + + q = strjoina(p, "/", found->d_name, "/dev"); + + r = read_one_line_file(q, &t); + if (r == -ENOENT) + goto fallback; + if (r < 0) + return r; + + if (sscanf(t, "%u:%u", &maj, &min) != 2) + return -EINVAL; + + if (maj == 0) + goto fallback; + + *dev = makedev(maj, min); + return 1; + +fallback: + *dev = dt; + return 1; +} + static int parse_proc_cmdline_item(const char *key, const char *value) { int r; @@ -883,11 +958,11 @@ static int add_mounts(void) { dev_t devno; int r; - r = get_block_device("/", &devno); + r = get_block_device_harder("/", &devno); if (r < 0) return log_error_errno(r, "Failed to determine block device of root file system: %m"); else if (r == 0) { - r = get_block_device("/usr", &devno); + r = get_block_device_harder("/usr", &devno); if (r < 0) return log_error_errno(r, "Failed to determine block device of /usr file system: %m"); else if (r == 0) { -- cgit v1.2.3-54-g00ecf