osdep/linux: handle autofs entries in /proc/self/mountinfo
authorAndrei Borzenkov <arvidjaar@gmail.com>
Tue, 24 Jan 2017 17:05:19 +0000 (20:05 +0300)
committerAndrei Borzenkov <arvidjaar@gmail.com>
Tue, 24 Jan 2017 17:05:19 +0000 (20:05 +0300)
These entries have placeholder for device name and so are useless for our
purpose. grub failed with something like

grub-install: error: failed to get canonical path of `systemd-1'.

When we see autofs entry, record it (to keep parent-child relationship) but
continue to look for real mount. If it is found, we process it as usual. If
only autofs entry exists, attempt to trigger mount by opening mount point
and retry. Mount point itself is then kept open to avoid timeout.

Recent systemd is by default using automount for /boot/efi so this should
become more popular problem on EFI systems.

Closes: 49942

grub-core/osdep/linux/getroot.c

index 09e7e6e..90d92d3 100644 (file)
@@ -380,24 +380,30 @@ get_btrfs_fs_prefix (const char *mount_path)
 char **
 grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
 {
-  FILE *fp;
+  FILE *fp = NULL;
   char *buf = NULL;
   size_t len = 0;
-  grub_size_t entry_len = 0, entry_max = 4;
+  grub_size_t entry_len, entry_max = 4;
   struct mountinfo_entry *entries;
   struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
   int i;
+  int retry = 0;
+  int dir_fd = -1;
+  char **ret = NULL;
 
   if (! *dir)
     dir = "/";
   if (relroot)
     *relroot = NULL;
 
+  entries = xmalloc (entry_max * sizeof (*entries));
+
+again:
   fp = grub_util_fopen ("/proc/self/mountinfo", "r");
   if (! fp)
-    return NULL; /* fall through to other methods */
+    goto out; /* fall through to other methods */
 
-  entries = xmalloc (entry_max * sizeof (*entries));
+  entry_len = 0;
 
   /* First, build a list of relevant visible mounts.  */
   while (getline (&buf, &len, fp) > 0)
@@ -484,7 +490,6 @@ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
   /* Now scan visible mounts for the ones we're interested in.  */
   for (i = entry_len - 1; i >= 0; i--)
     {
-      char **ret = NULL;
       char *fs_prefix = NULL;
       if (!*entries[i].device)
        continue;
@@ -515,6 +520,23 @@ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
          ret = grub_find_root_devices_from_btrfs (dir);
          fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
        }
+      else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
+       {
+         /* If the best match is automounted, try to trigger mount. We cannot
+            simply return here because stat() on automounted directory does not
+            trigger mount and returns bogus (pseudo)device number instead.
+            We keep mountpoint open until end of scan to prevent timeout. */
+
+         int flags = O_RDONLY|O_DIRECTORY;
+
+         fclose (fp);
+#ifdef O_LARGEFILE
+         flags |= O_LARGEFILE;
+#endif
+         dir_fd = open (entries[i].enc_path, flags);
+         retry = 1;
+         goto again;
+       }
       if (!ret)
        {
          ret = xmalloc (2 * sizeof (ret[0]));
@@ -544,16 +566,17 @@ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
        }
       if (fs_prefix != entries[i].enc_root)
        free (fs_prefix);
-      free (buf);
-      free (entries);
-      fclose (fp);
-      return ret;
+      break;
     }
 
+out:
   free (buf);
   free (entries);
-  fclose (fp);
-  return NULL;
+  if (fp)
+    fclose (fp);
+  if (dir_fd != -1)
+    close (dir_fd);
+  return ret;
 }
 
 static char *