grub2/0001-grub-install-bailout-root-device-probing.patch

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: