From 228cfb40bf9f6fa70cdb6c8aa7304efe9f558870 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 2 Dec 2010 14:26:46 +0100 Subject: [PATCH] support bind and subvolume mount --- grub-core/kern/emu/getroot.c | 23 ++++++++--------------- grub-core/kern/emu/misc.c | 28 ++++++++++++++++++++++++++++ include/grub/emu/misc.h | 2 ++ 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/grub-core/kern/emu/getroot.c b/grub-core/kern/emu/getroot.c index f51dcd770..373834127 100644 --- a/grub-core/kern/emu/getroot.c +++ b/grub-core/kern/emu/getroot.c @@ -103,8 +103,8 @@ xgetcwd (void) can't deal with the multiple-device case yet, but in the meantime, we can at least cope with the single-device case by scanning /proc/self/mountinfo. */ -static char * -find_root_device_from_mountinfo (const char *dir) +char * +grub_find_root_device_from_mountinfo (const char *dir, char **relroot) { FILE *fp; char *buf = NULL; @@ -115,6 +115,9 @@ find_root_device_from_mountinfo (const char *dir) if (! fp) return NULL; /* fall through to other methods */ + if (relroot) + *relroot = NULL; + while (getline (&buf, &len, fp) > 0) { int mnt_id, parent_mnt_id; @@ -131,9 +134,6 @@ find_root_device_from_mountinfo (const char *dir) &count) < 6) continue; - if (strcmp (enc_root, "/") != 0) - continue; /* only a subtree is mounted */ - enc_path_len = strlen (enc_path); if (strncmp (dir, enc_path, enc_path_len) != 0 || (dir[enc_path_len] && dir[enc_path_len] != '/')) @@ -147,9 +147,6 @@ find_root_device_from_mountinfo (const char *dir) free (ret); ret = NULL; - if (major != 0) - continue; /* not a virtual device */ - sep = strstr (buf + count, " - "); if (!sep) continue; @@ -158,13 +155,9 @@ find_root_device_from_mountinfo (const char *dir) if (sscanf (sep, "%s %s", fstype, device) != 2) continue; - if (stat (device, &st) < 0) - continue; - - if (!S_ISBLK (st.st_mode)) - continue; /* not a block device */ - ret = strdup (device); + if (relroot) + *relroot = strdup (enc_root); } free (buf); @@ -531,7 +524,7 @@ grub_guess_root_device (const char *dir) struct stat st; #ifdef __linux__ - os_dev = find_root_device_from_mountinfo (dir); + os_dev = grub_find_root_device_from_mountinfo (dir, NULL); if (os_dev) return os_dev; #endif /* __linux__ */ diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c index c8b95443b..44c40b010 100644 --- a/grub-core/kern/emu/misc.c +++ b/grub-core/kern/emu/misc.c @@ -415,6 +415,18 @@ grub_make_system_path_relative_to_its_root (const char *path) if (offset == 0) { free (buf); +#ifdef __linux__ + { + char *bind; + grub_free (grub_find_root_device_from_mountinfo (buf2, &bind)); + if (bind && bind[0] && bind[1]) + { + buf3 = bind; + goto parsedir; + } + grub_free (bind); + } +#endif free (buf2); #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) if (poolfs) @@ -437,6 +449,21 @@ grub_make_system_path_relative_to_its_root (const char *path) } free (buf); buf3 = xstrdup (buf2 + offset); + buf2[offset] = 0; +#ifdef __linux__ + { + char *bind; + grub_free (grub_find_root_device_from_mountinfo (buf2, &bind)); + if (bind && bind[0] && bind[1]) + { + char *temp = buf3; + buf3 = grub_xasprintf ("%s%s%s", bind, buf3[0] == '/' ?"":"/", buf3); + grub_free (temp); + } + grub_free (bind); + } +#endif + free (buf2); #ifdef __CYGWIN__ @@ -452,6 +479,7 @@ grub_make_system_path_relative_to_its_root (const char *path) } #endif + parsedir: /* Remove trailing slashes, return empty string if root directory. */ len = strlen (buf3); while (len > 0 && buf3[len - 1] == '/') diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h index ef0d18300..d4ebcb0d1 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -78,4 +78,6 @@ extern char * canonicalize_file_name (const char *path); int grub_device_mapper_supported (void); #endif +char *grub_find_root_device_from_mountinfo (const char *dir, char **relroot); + #endif /* GRUB_EMU_MISC_H */