osdep/linux: handle autofs entries in /proc/self/mountinfo

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
This commit is contained in:
Andrei Borzenkov 2017-01-24 20:05:19 +03:00
parent 972765fe82
commit a2932fbe8a

View 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);
if (fp)
fclose (fp);
return NULL;
if (dir_fd != -1)
close (dir_fd);
return ret;
}
static char *