282 lines
6.9 KiB
Diff
282 lines
6.9 KiB
Diff
From db67bd0800c69f94fa3696351e7387515464d30c Mon Sep 17 00:00:00 2001
|
|
From: Michael Chang <mchang@suse.com>
|
|
Date: Thu, 10 Feb 2022 22:16:58 +0800
|
|
Subject: [PATCH] grub-install: bailout root device probing
|
|
|
|
The root device is probed to test if the filesystem is btrfs in order to setup
|
|
boot configs for snapshot booting. However when the root device is a lvm thin
|
|
volume, due to lack in grub support, the probing will be errored out and entire
|
|
installation process aborts.
|
|
|
|
Here we call out stat to bailout the situation whenever grub fails to probe
|
|
filesystem in it's own right.
|
|
|
|
stat -f -c %T /
|
|
|
|
The command is also used by grub-mkconfig for the same purpose.
|
|
|
|
v2:
|
|
|
|
Test the root device first before probing to avoid encountering
|
|
unexpected errors. If this test fails, the device is considered
|
|
irrelevant and of no interest, as it is not useful.
|
|
|
|
v2.1:
|
|
Besides verifying that the target's canonical path can be resolved,
|
|
ensure that the target is a block device file.
|
|
|
|
Signed-off-by: Michael Chang <mchang@suse.com>
|
|
---
|
|
grub-core/osdep/basic/no_platform.c | 5 +++
|
|
grub-core/osdep/unix/getroot.c | 67 +++++++++++++++++++++++++++++
|
|
grub-core/osdep/unix/platform.c | 34 +++++++++++++++
|
|
grub-core/osdep/windows/platform.c | 6 +++
|
|
include/grub/emu/getroot.h | 3 ++
|
|
include/grub/util/install.h | 3 ++
|
|
util/grub-install.c | 45 +++++++++++++++----
|
|
7 files changed, 154 insertions(+), 9 deletions(-)
|
|
|
|
--- a/grub-core/osdep/basic/no_platform.c
|
|
+++ b/grub-core/osdep/basic/no_platform.c
|
|
@@ -51,3 +51,8 @@
|
|
grub_util_error ("%s", _("no zIPL routines are available for your platform"));
|
|
}
|
|
|
|
+char *
|
|
+grub_install_get_filesystem (const char *path)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
--- a/grub-core/osdep/unix/getroot.c
|
|
+++ b/grub-core/osdep/unix/getroot.c
|
|
@@ -489,6 +489,73 @@
|
|
return 0;
|
|
}
|
|
|
|
+#ifdef __linux__
|
|
+int
|
|
+grub_can_guess_from_mountinfo (const char *dir_in)
|
|
+{
|
|
+ char **cur;
|
|
+ char **os_dev = NULL;
|
|
+ char *dir = grub_canonicalize_file_name (dir_in);
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!dir)
|
|
+ return 0;
|
|
+
|
|
+ os_dev = grub_find_root_devices_from_mountinfo (dir, NULL);
|
|
+
|
|
+ if (!os_dev)
|
|
+ os_dev = find_root_devices_from_libzfs (dir);
|
|
+
|
|
+ if (!os_dev)
|
|
+ {
|
|
+ free (dir);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ for (cur = os_dev; *cur; cur++)
|
|
+ {
|
|
+ if (strcmp (*cur, "/dev/root") == 0
|
|
+ || strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0)
|
|
+ /* Assume known and good names */
|
|
+ continue;
|
|
+ else
|
|
+ {
|
|
+ struct stat st;
|
|
+
|
|
+ char *tmp = grub_canonicalize_file_name (*cur);
|
|
+ if (tmp == NULL)
|
|
+ break;
|
|
+
|
|
+ if (strncmp (tmp, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0)
|
|
+ continue;
|
|
+
|
|
+ if (lstat (tmp, &st) < 0)
|
|
+ {
|
|
+ free (tmp);
|
|
+ break;
|
|
+ }
|
|
+ free (tmp);
|
|
+ if (! S_ISBLK (st.st_mode))
|
|
+ /* only block device allowed */
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (*cur == NULL)
|
|
+ /* no bogus device left, good */
|
|
+ ret = 1;
|
|
+ else
|
|
+ grub_util_info ("`%s' is not os device", *cur);
|
|
+
|
|
+ for (cur = os_dev; *cur; cur++)
|
|
+ free (*cur);
|
|
+ free (os_dev);
|
|
+ free (dir);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+#endif /* __linux__ */
|
|
+
|
|
char **
|
|
grub_guess_root_devices (const char *dir_in)
|
|
{
|
|
--- a/grub-core/osdep/unix/platform.c
|
|
+++ b/grub-core/osdep/unix/platform.c
|
|
@@ -250,3 +250,37 @@
|
|
"-z", dest, NULL }))
|
|
grub_util_error (_("`%s' failed.\n"), PACKAGE"-zipl-setup");
|
|
}
|
|
+
|
|
+char *
|
|
+grub_install_get_filesystem (const char *path)
|
|
+{
|
|
+ int fd;
|
|
+ pid_t pid;
|
|
+ FILE *fp;
|
|
+ ssize_t len;
|
|
+ char *buf = NULL;
|
|
+ size_t bufsz = 0;
|
|
+
|
|
+ pid = grub_util_exec_pipe ((const char * []){ "stat", "-f", "-c", "%T", path, NULL }, &fd);
|
|
+ if (!pid)
|
|
+ return NULL;
|
|
+
|
|
+ fp = fdopen (fd, "r");
|
|
+ if (!fp)
|
|
+ return NULL;
|
|
+
|
|
+ len = getline (&buf, &bufsz, fp);
|
|
+ if (len == -1)
|
|
+ {
|
|
+ free (buf);
|
|
+ fclose (fp);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ fclose (fp);
|
|
+
|
|
+ if (len > 0 && buf[len - 1] == '\n')
|
|
+ buf[len - 1] = '\0';
|
|
+
|
|
+ return buf;
|
|
+}
|
|
--- a/grub-core/osdep/windows/platform.c
|
|
+++ b/grub-core/osdep/windows/platform.c
|
|
@@ -440,3 +440,9 @@
|
|
{
|
|
grub_util_error ("%s", _("no zIPL routines are available for your platform"));
|
|
}
|
|
+
|
|
+char *
|
|
+grub_install_get_filesystem (const char *path)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
--- a/include/grub/emu/getroot.h
|
|
+++ b/include/grub/emu/getroot.h
|
|
@@ -35,6 +35,9 @@
|
|
|
|
char *grub_find_device (const char *dir, dev_t dev);
|
|
void grub_util_pull_device (const char *osname);
|
|
+#ifdef __linux__
|
|
+int grub_can_guess_from_mountinfo (const char *dir);
|
|
+#endif
|
|
char **grub_guess_root_devices (const char *dir);
|
|
int grub_util_get_dev_abstraction (const char *os_dev);
|
|
char *grub_make_system_path_relative_to_its_root (const char *path);
|
|
--- a/include/grub/util/install.h
|
|
+++ b/include/grub/util/install.h
|
|
@@ -251,6 +251,9 @@
|
|
void
|
|
grub_install_zipl (const char *d, int i, int f);
|
|
|
|
+char *
|
|
+grub_install_get_filesystem (const char *path);
|
|
+
|
|
int
|
|
grub_install_compress_gzip (const char *src, const char *dest);
|
|
int
|
|
--- a/util/grub-install.c
|
|
+++ b/util/grub-install.c
|
|
@@ -922,7 +922,6 @@
|
|
const char *efi_file = NULL;
|
|
char **grub_devices;
|
|
grub_fs_t grub_fs;
|
|
- grub_fs_t root_fs;
|
|
grub_device_t grub_dev = NULL;
|
|
enum grub_install_plat platform;
|
|
char *grubdir, *device_map;
|
|
@@ -1102,10 +1101,22 @@
|
|
grub_host_init ();
|
|
|
|
{
|
|
- char *rootdir_grub_devname;
|
|
- grub_device_t rootdir_grub_dev;
|
|
+ grub_device_t rootdir_grub_dev = NULL;
|
|
+ char *rootdir_grub_devname = NULL;
|
|
+ char *root_fs_name = NULL;
|
|
+
|
|
char *t = grub_util_path_concat (2, "/", rootdir);
|
|
|
|
+#ifdef __linux__
|
|
+ if (!grub_can_guess_from_mountinfo (t))
|
|
+ {
|
|
+ free(t);
|
|
+ /* We can safely ignore the root probe here; whichever cannot be
|
|
+ * reliably detected is irrelevant and of no interest */
|
|
+ goto skip_root_probe;
|
|
+ }
|
|
+#endif
|
|
+
|
|
rootdir_path = grub_canonicalize_file_name (t);
|
|
if (!rootdir_path)
|
|
grub_util_error (_("failed to get canonical path of `%s'"), t);
|
|
@@ -1124,22 +1135,38 @@
|
|
rootdir_devices[0]);
|
|
|
|
rootdir_grub_dev = grub_device_open (rootdir_grub_devname);
|
|
- if (! rootdir_grub_dev)
|
|
- grub_util_error ("%s", grub_errmsg);
|
|
+ if (!rootdir_grub_dev)
|
|
+ {
|
|
+ root_fs_name = grub_install_get_filesystem (t);
|
|
+ if (root_fs_name)
|
|
+ grub_errno = 0;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ grub_fs_t root_fs = grub_fs_probe (rootdir_grub_dev);
|
|
+ if (root_fs)
|
|
+ root_fs_name = grub_strdup (root_fs->name);
|
|
+ }
|
|
|
|
- root_fs = grub_fs_probe (rootdir_grub_dev);
|
|
- if (!root_fs)
|
|
+ if (!root_fs_name)
|
|
grub_util_error ("%s", grub_errmsg);
|
|
|
|
if (config.is_suse_btrfs_snapshot_enabled
|
|
- && grub_strncmp(root_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0)
|
|
+ && root_fs_name
|
|
+ && grub_strncmp(root_fs_name, "btrfs", sizeof ("btrfs") - 1) == 0)
|
|
use_relative_path_on_btrfs = 1;
|
|
|
|
+ free (root_fs_name);
|
|
free (t);
|
|
free (rootdir_grub_devname);
|
|
- grub_device_close (rootdir_grub_dev);
|
|
+ if (rootdir_grub_dev)
|
|
+ grub_device_close (rootdir_grub_dev);
|
|
}
|
|
|
|
+#ifdef __linux__
|
|
+ skip_root_probe:
|
|
+#endif
|
|
+
|
|
switch (platform)
|
|
{
|
|
case GRUB_INSTALL_PLATFORM_I386_EFI:
|