From 0480665b9de31aefc7f1d95448efdf8349997fe9 Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Thu, 5 Dec 2013 13:51:52 +0000 Subject: [PATCH] On Linux, read partition start offsets from sysfs if possible This lets us cope with block device drivers that don't implement HDIO_GETGEO. Fixes Ubuntu bug #1237519. * grub-core/osdep/linux/hostdisk.c (sysfs_partition_path): New function. (sysfs_partition_start): Likewise. (grub_util_find_partition_start_os): Try sysfs_partition_start before HDIO_GETGEO. --- ChangeLog | 12 +++++ grub-core/osdep/linux/hostdisk.c | 89 ++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/ChangeLog b/ChangeLog index 840a40405..d8e3563d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2013-12-05 Colin Watson + + On Linux, read partition start offsets from sysfs if possible, to + cope with block device drivers that don't implement HDIO_GETGEO. + Fixes Ubuntu bug #1237519. + + * grub-core/osdep/linux/hostdisk.c (sysfs_partition_path): New + function. + (sysfs_partition_start): Likewise. + (grub_util_find_partition_start_os): Try sysfs_partition_start + before HDIO_GETGEO. + 2013-12-05 Leif Lindholm * grub-core/kern/fdt.c: Update struct size when adding node. diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c index a2c80f39d..74d87a43c 100644 --- a/grub-core/osdep/linux/hostdisk.c +++ b/grub-core/osdep/linux/hostdisk.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -93,12 +95,99 @@ grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_sec return nr; } +static char * +sysfs_partition_path (const char *dev, const char *entry) +{ + const char *argv[7]; + int fd; + pid_t pid; + FILE *udevadm; + char *buf = NULL; + size_t len = 0; + char *path = NULL; + + argv[0] = "udevadm"; + argv[1] = "info"; + argv[2] = "--query"; + argv[3] = "path"; + argv[4] = "--name"; + argv[5] = dev; + argv[6] = NULL; + + pid = grub_util_exec_pipe (argv, &fd); + + if (!pid) + return NULL; + + /* Parent. Read udevadm's output. */ + udevadm = fdopen (fd, "r"); + if (!udevadm) + { + grub_util_warn (_("Unable to open stream from %s: %s"), + "udevadm", strerror (errno)); + close (fd); + goto out; + } + + if (getline (&buf, &len, udevadm) > 0) + { + char *newline; + + newline = strchr (buf, '\n'); + if (newline) + *newline = '\0'; + path = xasprintf ("/sys%s/%s", buf, entry); + } + +out: + if (udevadm) + fclose (udevadm); + waitpid (pid, NULL, 0); + free (buf); + + return path; +} + +static int +sysfs_partition_start (const char *dev, grub_disk_addr_t *start) +{ + char *path; + FILE *fp; + unsigned long long val; + int ret = 0; + + path = sysfs_partition_path (dev, "start"); + if (!path) + return 0; + + fp = grub_util_fopen (path, "r"); + if (!fp) + goto out; + + if (fscanf (fp, "%llu", &val) == 1) + { + *start = (grub_disk_addr_t) val; + ret = 1; + } + +out: + free (path); + if (fp) + fclose (fp); + + return ret; +} + grub_disk_addr_t grub_util_find_partition_start_os (const char *dev) { + grub_disk_addr_t start; grub_util_fd_t fd; struct hd_geometry hdg; + if (sysfs_partition_start (dev, &start)) + return start; + fd = open (dev, O_RDONLY); if (fd == -1) {