summaryrefslogtreecommitdiff
path: root/src/gpt-auto-generator
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-09-06 23:04:32 +0200
committerLennart Poettering <lennart@poettering.net>2015-09-07 00:11:51 +0200
commitc6ba0c184d297a454baf387663668db77f79c1b5 (patch)
treef4ac5844d5435dcd576cddb49b9bafdb69593d2b /src/gpt-auto-generator
parent5e8d4254f916eb7115ae14de42e7eccf6bc83786 (diff)
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
Diffstat (limited to 'src/gpt-auto-generator')
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c79
1 files changed, 77 insertions, 2 deletions
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) {