1 /* getroot.c - Get root device */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <config-util.h>
24 #include <sys/types.h>
38 #include <grub/util/misc.h>
39 #include <grub/util/lvm.h>
40 #include <grub/cryptodisk.h>
41 #include <grub/i18n.h>
43 #ifdef HAVE_DEVICE_MAPPER
44 # include <libdevmapper.h>
49 #include <hurd/lookup.h>
54 #include <sys/types.h>
56 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
57 # include <sys/param.h>
58 # include <sys/mount.h>
61 #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
62 # include <grub/util/libzfs.h>
63 # include <grub/util/libnvpair.h>
67 # include <sys/types.h>
68 # include <sys/mkdev.h>
72 #include <grub/misc.h>
73 #include <grub/emu/misc.h>
74 #include <grub/emu/hostdisk.h>
75 #include <grub/emu/getroot.h>
78 # include <sys/ioctl.h> /* ioctl */
79 # include <sys/mount.h>
83 # endif /* ! MINORBITS */
84 # define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
87 # define FLOPPY_MAJOR 2
88 # endif /* ! FLOPPY_MAJOR */
92 # include <sys/ioctl.h>
93 # include <cygwin/fs.h> /* BLKGETSIZE64 */
94 # include <cygwin/hdreg.h> /* HDIO_GETGEO */
95 # include <sys/cygwin.h>
97 # define MAJOR(dev) ((unsigned) ((dev) >> 16))
98 # define FLOPPY_MAJOR 2
101 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
102 # include <sys/disk.h> /* DIOCGMEDIASIZE */
103 # include <sys/param.h>
104 # include <sys/sysctl.h>
105 # include <sys/mount.h>
107 # define MAJOR(dev) major(dev)
108 # define FLOPPY_MAJOR 2
111 #if defined (__sun__)
112 # include <sys/dkio.h>
115 #if defined(__APPLE__)
116 # include <sys/disk.h>
117 # include <sys/param.h>
118 # include <sys/sysctl.h>
119 # include <sys/mount.h>
122 #ifdef HAVE_DEVICE_MAPPER
123 # include <libdevmapper.h>
126 #if defined(__NetBSD__) || defined(__OpenBSD__)
127 # define HAVE_DIOCGDINFO
128 # include <sys/ioctl.h>
129 # include <sys/disklabel.h> /* struct disklabel */
130 # include <sys/disk.h> /* struct dkwedge_info */
131 #else /* !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */
132 # undef HAVE_DIOCGDINFO
133 #endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
135 #if defined(__NetBSD__) || defined(__OpenBSD__)
136 # ifdef HAVE_GETRAWPARTITION
137 # include <util.h> /* getrawpartition */
138 # endif /* HAVE_GETRAWPARTITION */
139 #if defined(__NetBSD__)
140 # include <sys/fdio.h>
142 # ifndef FLOPPY_MAJOR
143 # define FLOPPY_MAJOR 2
144 # endif /* ! FLOPPY_MAJOR */
145 # ifndef RAW_FLOPPY_MAJOR
146 # define RAW_FLOPPY_MAJOR 9
147 # endif /* ! RAW_FLOPPY_MAJOR */
148 #endif /* defined(__NetBSD__) */
151 /* Defines taken from btrfs/ioctl.h. */
153 struct btrfs_ioctl_dev_info_args
156 grub_uint8_t uuid
[16];
157 grub_uint64_t bytes_used
;
158 grub_uint64_t total_bytes
;
159 grub_uint64_t unused
[379];
160 grub_uint8_t path
[1024];
163 struct btrfs_ioctl_fs_info_args
165 grub_uint64_t max_id
;
166 grub_uint64_t num_devices
;
167 grub_uint8_t fsid
[16];
168 grub_uint64_t reserved
[124];
171 #define BTRFS_IOC_DEV_INFO _IOWR(0x94, 30, \
172 struct btrfs_ioctl_dev_info_args)
173 #define BTRFS_IOC_FS_INFO _IOR(0x94, 31, \
174 struct btrfs_ioctl_fs_info_args)
179 grub_util_is_imsm (const char *os_dev
);
182 #if ! defined(__CYGWIN__) && !defined(__GNU__)
185 strip_extra_slashes (char *dir
)
189 while ((p
= strchr (p
, '/')) != 0)
193 memmove (p
, p
+ 1, strlen (p
));
196 else if (p
[1] == '\0')
213 path
= xmalloc (size
);
214 while (! getcwd (path
, size
))
217 path
= xrealloc (path
, size
);
225 #if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
227 #include <sys/types.h>
228 #include <sys/wait.h>
231 exec_pipe (char **argv
, int *fd
)
238 if (pipe (mdadm_pipe
) < 0)
240 grub_util_warn (_("Unable to create pipe: %s"),
246 grub_util_error (_("Unable to fork: %s"), strerror (errno
));
247 else if (mdadm_pid
== 0)
252 #ifdef HAVE_DEVICE_MAPPER
255 grub_diskfilter_fini ();
257 /* Ensure child is not localised. */
258 setenv ("LC_ALL", "C", 1);
260 close (mdadm_pipe
[0]);
261 dup2 (mdadm_pipe
[1], STDOUT_FILENO
);
262 close (mdadm_pipe
[1]);
264 execvp (argv
[0], argv
);
269 close (mdadm_pipe
[1]);
276 find_root_devices_from_poolname (char *poolname
)
280 size_t devices_allocated
= 0;
282 #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
283 zpool_handle_t
*zpool
;
284 libzfs_handle_t
*libzfs
;
285 nvlist_t
*config
, *vdev_tree
;
287 unsigned int nvlist_count
;
291 libzfs
= grub_get_libzfs_handle ();
295 zpool
= zpool_open (libzfs
, poolname
);
296 config
= zpool_get_config (zpool
, NULL
);
298 if (nvlist_lookup_nvlist (config
, "vdev_tree", &vdev_tree
) != 0)
299 error (1, errno
, "nvlist_lookup_nvlist (\"vdev_tree\")");
301 if (nvlist_lookup_nvlist_array (vdev_tree
, "children", &children
, &nvlist_count
) != 0)
302 error (1, errno
, "nvlist_lookup_nvlist_array (\"children\")");
303 assert (nvlist_count
> 0);
305 while (nvlist_lookup_nvlist_array (children
[0], "children",
306 &children
, &nvlist_count
) == 0)
307 assert (nvlist_count
> 0);
309 for (i
= 0; i
< nvlist_count
; i
++)
311 if (nvlist_lookup_string (children
[i
], "path", &device
) != 0)
312 error (1, errno
, "nvlist_lookup_string (\"path\")");
315 if (stat (device
, &st
) == 0)
318 if (grub_memcmp (device
, "/dev/dsk/", sizeof ("/dev/dsk/") - 1)
320 device
= xasprintf ("/dev/rdsk/%s",
321 device
+ sizeof ("/dev/dsk/") - 1);
322 else if (grub_memcmp (device
, "/devices", sizeof ("/devices") - 1)
324 && grub_memcmp (device
+ strlen (device
) - 4,
326 device
= xasprintf ("%s,raw", device
);
329 device
= xstrdup (device
);
330 if (ndevices
>= devices_allocated
)
332 devices_allocated
= 2 * (devices_allocated
+ 8);
333 devices
= xrealloc (devices
, sizeof (devices
[0])
334 * devices_allocated
);
336 devices
[ndevices
++] = device
;
350 char name
[PATH_MAX
+ 1], state
[257], readlen
[257], writelen
[257];
351 char cksum
[257], notes
[257];
357 /* execvp has inconvenient types, hence the casts. None of these
358 strings will actually be modified. */
359 argv
[0] = (char *) "zpool";
360 argv
[1] = (char *) "status";
361 argv
[2] = (char *) poolname
;
364 pid
= exec_pipe (argv
, &fd
);
368 fp
= fdopen (fd
, "r");
371 grub_util_warn (_("Unable to open stream from %s: %s"),
372 "zpool", strerror (errno
));
380 ret
= getline (&line
, &len
, fp
);
384 if (sscanf (line
, " %s %256s %256s %256s %256s %256s",
385 name
, state
, readlen
, writelen
, cksum
, notes
) >= 5)
389 if (!strcmp (name
, "NAME")
390 && !strcmp (state
, "STATE")
391 && !strcmp (readlen
, "READ")
392 && !strcmp (writelen
, "WRITE")
393 && !strcmp (cksum
, "CKSUM"))
401 if (strncmp (ptr
, poolname
, strlen (poolname
)) == 0
402 && grub_isspace(ptr
[strlen (poolname
)]))
404 if (!grub_isspace (*ptr
))
411 if (strcmp (name
, "mirror") && !sscanf (name
, "mirror-%u", &dummy
)
412 && !sscanf (name
, "raidz%u", &dummy
)
413 && !sscanf (name
, "raidz1%u", &dummy
)
414 && !sscanf (name
, "raidz2%u", &dummy
)
415 && !sscanf (name
, "raidz3%u", &dummy
)
416 && !strcmp (state
, "ONLINE"))
418 if (ndevices
>= devices_allocated
)
420 devices_allocated
= 2 * (devices_allocated
+ 8);
421 devices
= xrealloc (devices
, sizeof (devices
[0])
422 * devices_allocated
);
425 devices
[ndevices
++] = xstrdup (name
);
427 devices
[ndevices
++] = xasprintf ("/dev/%s", name
);
437 waitpid (pid
, NULL
, 0);
441 if (ndevices
>= devices_allocated
)
443 devices_allocated
= 2 * (devices_allocated
+ 8);
444 devices
= xrealloc (devices
, sizeof (devices
[0])
445 * devices_allocated
);
447 devices
[ndevices
++] = 0;
456 #define ESCAPED_PATH_MAX (4 * PATH_MAX)
457 struct mountinfo_entry
461 char enc_root
[ESCAPED_PATH_MAX
+ 1], enc_path
[ESCAPED_PATH_MAX
+ 1];
462 char fstype
[ESCAPED_PATH_MAX
+ 1], device
[ESCAPED_PATH_MAX
+ 1];
465 /* Statting something on a btrfs filesystem always returns a virtual device
466 major/minor pair rather than the real underlying device, because btrfs
467 can span multiple underlying devices (and even if it's currently only
468 using a single device it can be dynamically extended onto another). We
469 can't deal with the multiple-device case yet, but in the meantime, we can
470 at least cope with the single-device case by scanning
471 /proc/self/mountinfo. */
477 for (iptr
= optr
= str
; *iptr
; optr
++)
479 if (iptr
[0] == '\\' && iptr
[1] >= '0' && iptr
[1] < '8'
480 && iptr
[2] >= '0' && iptr
[2] < '8'
481 && iptr
[3] >= '0' && iptr
[3] < '8')
483 *optr
= (((iptr
[1] - '0') << 6) | ((iptr
[2] - '0') << 3)
494 grub_find_root_devices_from_btrfs (const char *dir
)
497 struct btrfs_ioctl_fs_info_args fsi
;
505 if (ioctl (fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
511 ret
= xmalloc ((fsi
.num_devices
+ 1) * sizeof (ret
[0]));
513 for (i
= 1; i
<= fsi
.max_id
&& j
< fsi
.num_devices
; i
++)
515 struct btrfs_ioctl_dev_info_args devi
;
516 memset (&devi
, 0, sizeof (devi
));
518 if (ioctl (fd
, BTRFS_IOC_DEV_INFO
, &devi
) < 0)
524 ret
[j
++] = xstrdup ((char *) devi
.path
);
525 if (j
>= fsi
.num_devices
)
534 grub_find_root_devices_from_mountinfo (const char *dir
, char **relroot
)
539 grub_size_t entry_len
= 0, entry_max
= 4;
540 struct mountinfo_entry
*entries
;
541 struct mountinfo_entry parent_entry
= { 0, 0, 0, "", "", "", "" };
549 fp
= fopen ("/proc/self/mountinfo", "r");
551 return NULL
; /* fall through to other methods */
553 entries
= xmalloc (entry_max
* sizeof (*entries
));
555 /* First, build a list of relevant visible mounts. */
556 while (getline (&buf
, &len
, fp
) > 0)
558 struct mountinfo_entry entry
;
563 if (sscanf (buf
, "%d %d %u:%u %s %s%n",
564 &entry
.id
, &parent_entry
.id
, &entry
.major
, &entry
.minor
,
565 entry
.enc_root
, entry
.enc_path
, &count
) < 6)
568 unescape (entry
.enc_root
);
569 unescape (entry
.enc_path
);
571 enc_path_len
= strlen (entry
.enc_path
);
572 /* Check that enc_path is a prefix of dir. The prefix must either be
573 the entire string, or end with a slash, or be immediately followed
575 if (strncmp (dir
, entry
.enc_path
, enc_path_len
) != 0 ||
576 (enc_path_len
&& dir
[enc_path_len
- 1] != '/' &&
577 dir
[enc_path_len
] && dir
[enc_path_len
] != '/'))
580 sep
= strstr (buf
+ count
, " - ");
584 sep
+= sizeof (" - ") - 1;
585 if (sscanf (sep
, "%s %s", entry
.fstype
, entry
.device
) != 2)
588 unescape (entry
.device
);
590 /* Using the mount IDs, find out where this fits in the list of
591 visible mount entries we've seen so far. There are three
592 interesting cases. Firstly, it may be inserted at the end: this is
593 the usual case of /foo/bar being mounted after /foo. Secondly, it
594 may be inserted at the start: for example, this can happen for
595 filesystems that are mounted before / and later moved under it.
596 Thirdly, it may occlude part or all of the existing filesystem
597 tree, in which case the end of the list needs to be pruned and this
598 new entry will be inserted at the end. */
599 if (entry_len
>= entry_max
)
602 entries
= xrealloc (entries
, entry_max
* sizeof (*entries
));
607 /* Initialise list. */
609 entries
[0] = parent_entry
;
614 for (i
= entry_len
- 1; i
>= 0; i
--)
616 if (entries
[i
].id
== parent_entry
.id
)
618 /* Insert at end, pruning anything previously above this. */
620 entries
[i
+ 1] = entry
;
623 else if (i
== 0 && entries
[i
].id
== entry
.id
)
625 /* Insert at start. */
627 memmove (entries
+ 1, entries
,
628 (entry_len
- 1) * sizeof (*entries
));
629 entries
[0] = parent_entry
;
637 /* Now scan visible mounts for the ones we're interested in. */
638 for (i
= entry_len
- 1; i
>= 0; i
--)
641 if (!*entries
[i
].device
)
644 if (grub_strcmp (entries
[i
].fstype
, "fuse.zfs") == 0
645 || grub_strcmp (entries
[i
].fstype
, "zfs") == 0)
648 slash
= strchr (entries
[i
].device
, '/');
651 ret
= find_root_devices_from_poolname (entries
[i
].device
);
657 *relroot
= xasprintf ("/@%s", entries
[i
].enc_root
);
658 else if (strchr (slash
+ 1, '@'))
659 *relroot
= xasprintf ("/%s%s", slash
+ 1, entries
[i
].enc_root
);
661 *relroot
= xasprintf ("/%s@%s", slash
+ 1, entries
[i
].enc_root
);
664 else if (grub_strcmp (entries
[i
].fstype
, "btrfs") == 0)
666 ret
= grub_find_root_devices_from_btrfs (dir
);
670 *relroot
= xmalloc (strlen (entries
[i
].enc_root
) +
672 ptr
= grub_stpcpy (*relroot
, entries
[i
].enc_root
);
673 if (strlen (dir
) > strlen (entries
[i
].enc_path
))
675 while (ptr
> *relroot
&& *(ptr
- 1) == '/')
677 if (dir
[strlen (entries
[i
].enc_path
)] != '/')
679 ptr
= grub_stpcpy (ptr
, dir
+ strlen (entries
[i
].enc_path
));
686 ret
= xmalloc (2 * sizeof (ret
[0]));
687 ret
[0] = strdup (entries
[i
].device
);
690 *relroot
= strdup (entries
[i
].enc_root
);
704 #endif /* __linux__ */
706 #if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
709 find_root_devices_from_libzfs (const char *dir
)
711 char **devices
= NULL
;
715 grub_find_zpool_from_dir (dir
, &poolname
, &poolfs
);
719 devices
= find_root_devices_from_poolname (poolname
);
733 grub_find_device (const char *dir
__attribute__ ((unused
)),
734 dev_t dev
__attribute__ ((unused
)))
739 #elif defined (__GNU__)
742 find_hurd_root_device (const char *path
)
746 char *argz
= NULL
, *name
= NULL
, *ret
;
750 file
= file_name_lookup (path
, 0, 0);
751 if (file
== MACH_PORT_NULL
)
752 /* TRANSLATORS: The first %s is the file being looked at, the second %s is
753 the error message. */
754 grub_util_error (_("cannot open `%s': %s"), path
, strerror (errno
));
756 /* This returns catenated 0-terminated strings. */
757 err
= file_get_fs_options (file
, &argz
, &argz_len
);
759 /* TRANSLATORS: On GNU/Hurd, a "translator" is similar to a filesystem
760 mount, but handled by a userland daemon, whose invocation command line
761 is being fetched here. First %s is the file being looked at (for which
762 we are fetching the "translator" command line), second %s is the error
765 grub_util_error (_("cannot get translator command line "
766 "for path `%s': %s"), path
, strerror(err
));
768 grub_util_error (_("translator command line is empty for path `%s'"), path
);
770 /* Make sure the string is terminated. */
771 argz
[argz_len
-1] = 0;
773 /* Skip first word (translator path) and options. */
774 for (i
= strlen (argz
) + 1; i
< argz_len
; i
+= strlen (argz
+ i
) + 1)
778 /* Non-option. Only accept one, assumed to be the FS path. */
779 /* XXX: this should be replaced by an RPC to the translator. */
781 /* TRANSLATORS: we expect to get something like
782 /hurd/foobar --option1 --option2=baz /dev/something
784 grub_util_error (_("translator `%s' for path `%s' has several "
785 "non-option words, at least `%s' and `%s'"),
786 argz
, path
, name
, argz
+ i
);
792 /* TRANSLATORS: we expect to get something like
793 /hurd/foobar --option1 --option2=baz /dev/something
795 grub_util_error (_("translator `%s' for path `%s' is given only options, "
796 "cannot find device part"), argz
, path
);
798 if (strncmp (name
, "device:", sizeof ("device:") - 1) == 0)
800 char *dev_name
= name
+ sizeof ("device:") - 1;
801 size_t size
= sizeof ("/dev/") - 1 + strlen (dev_name
) + 1;
804 next
= stpncpy (ret
, "/dev/", size
);
805 stpncpy (next
, dev_name
, size
- (next
- ret
));
807 else if (!strncmp (name
, "file:", sizeof ("file:") - 1))
808 ret
= strdup (name
+ sizeof ("file:") - 1);
812 munmap (argz
, argz_len
);
816 #elif ! defined(__CYGWIN__)
819 grub_find_device (const char *dir
, dev_t dev
)
838 saved_cwd
= xgetcwd ();
840 grub_util_info ("changing current directory to %s", dir
);
848 while ((ent
= readdir (dp
)) != 0)
853 - dotfiles (like "/dev/.tmp.md0") since they could be duplicates.
854 - dotdirs (like "/dev/.static") since they could contain duplicates. */
855 if (ent
->d_name
[0] == '.')
858 if (lstat (ent
->d_name
, &st
) < 0)
859 /* Ignore any error. */
862 if (S_ISLNK (st
.st_mode
)) {
864 if (strcmp (dir
, "mapper") == 0 || strcmp (dir
, "/dev/mapper") == 0) {
865 /* Follow symbolic links under /dev/mapper/; the canonical name
866 may be something like /dev/dm-0, but the names under
867 /dev/mapper/ are more human-readable and so we prefer them if
869 if (stat (ent
->d_name
, &st
) < 0)
872 #endif /* __linux__ */
873 /* Don't follow other symbolic links. */
877 if (S_ISDIR (st
.st_mode
))
879 /* Find it recursively. */
882 res
= grub_find_device (ent
->d_name
, dev
);
886 if (chdir (saved_cwd
) < 0)
887 grub_util_error ("%s",
888 _("cannot restore the original directory"));
896 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
897 if (S_ISCHR (st
.st_mode
) && st
.st_rdev
== dev
)
899 if (S_ISBLK (st
.st_mode
) && st
.st_rdev
== dev
)
903 /* Skip device names like /dev/dm-0, which are short-hand aliases
904 to more descriptive device names, e.g. those under /dev/mapper */
905 if (ent
->d_name
[0] == 'd' &&
906 ent
->d_name
[1] == 'm' &&
907 ent
->d_name
[2] == '-' &&
908 ent
->d_name
[3] >= '0' &&
909 ent
->d_name
[3] <= '9')
916 #if defined(__NetBSD__)
917 /* Convert this block device to its character (raw) device. */
918 const char *template = "%s/r%s";
920 /* Keep the device name as it is. */
921 const char *template = "%s/%s";
925 res
= xmalloc (strlen (cwd
) + strlen (ent
->d_name
) + 3);
926 sprintf (res
, template, cwd
, ent
->d_name
);
927 strip_extra_slashes (res
);
930 /* /dev/root is not a real block device keep looking, takes care
931 of situation where root filesystem is on the same partition as
934 if (strcmp(res
, "/dev/root") == 0)
940 if (chdir (saved_cwd
) < 0)
941 grub_util_error ("%s", _("cannot restore the original directory"));
949 if (chdir (saved_cwd
) < 0)
950 grub_util_error ("%s", _("cannot restore the original directory"));
957 #else /* __CYGWIN__ */
959 /* Read drive/partition serial number from mbr/boot sector,
960 return 0 on read error, ~0 on unknown serial. */
962 get_bootsec_serial (const char *os_dev
, int mbr
)
964 /* Read boot sector. */
965 int fd
= open (os_dev
, O_RDONLY
);
968 unsigned char buf
[0x200];
969 int n
= read (fd
, buf
, sizeof (buf
));
971 if (n
!= sizeof(buf
))
974 /* Check signature. */
975 if (!(buf
[0x1fe] == 0x55 && buf
[0x1ff] == 0xaa))
978 /* Serial number offset depends on boot sector type. */
981 else if (memcmp (buf
+ 0x03, "NTFS", 4) == 0)
983 else if (memcmp (buf
+ 0x52, "FAT32", 5) == 0)
985 else if (memcmp (buf
+ 0x36, "FAT", 3) == 0)
990 unsigned serial
= *(unsigned *)(buf
+ n
);
996 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
999 grub_find_device (const char *path
, dev_t dev
)
1001 /* No root device for /cygdrive. */
1002 if (dev
== (DEV_CYGDRIVE_MAJOR
<< 16))
1005 /* Convert to full POSIX and Win32 path. */
1006 char fullpath
[PATH_MAX
], winpath
[PATH_MAX
];
1008 cygwin_conv_path (CCP_WIN_A_TO_POSIX
, path
, fullpath
, sizeof (fullpath
));
1009 cygwin_conv_path (CCP_POSIX_TO_WIN_A
, fullpath
, winpath
, sizeof (winpath
));
1011 /* If identical, this is no real filesystem path. */
1012 if (strcmp (fullpath
, winpath
) == 0)
1015 /* Check for floppy drive letter. */
1016 if (winpath
[0] && winpath
[1] == ':' && strchr ("AaBb", winpath
[0]))
1017 return xstrdup (strchr ("Aa", winpath
[0]) ? "/dev/fd0" : "/dev/fd1");
1019 /* Cygwin returns the partition serial number in stat.st_dev.
1020 This is never identical to the device number of the emulated
1021 /dev/sdXN device, so above grub_find_device () does not work.
1022 Search the partition with the same serial in boot sector instead. */
1023 char devpath
[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */
1025 for (d
= 'a'; d
<= 'z'; d
++)
1027 sprintf (devpath
, "/dev/sd%c", d
);
1028 if (get_bootsec_serial (devpath
, 1) == 0)
1031 for (p
= 1; p
<= 15; p
++)
1033 sprintf (devpath
, "/dev/sd%c%d", d
, p
);
1034 unsigned ser
= get_bootsec_serial (devpath
, 0);
1037 if (ser
!= (unsigned)~0 && dev
== (dev_t
)ser
)
1038 return xstrdup (devpath
);
1044 #endif /* __CYGWIN__ */
1047 grub_guess_root_devices (const char *dir
)
1049 char **os_dev
= NULL
;
1056 os_dev
= grub_find_root_devices_from_mountinfo (dir
, NULL
);
1057 #endif /* __linux__ */
1059 #if !defined (__MINGW32__) && !defined (__CYGWIN__)
1061 os_dev
= find_root_devices_from_libzfs (dir
);
1067 for (cur
= os_dev
; *cur
; cur
++)
1071 if (strcmp (*cur
, "/dev/root") == 0
1072 || strncmp (*cur
, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0)
1076 *cur
= canonicalize_file_name (tmp
);
1078 grub_util_error (_("failed to get canonical path of `%s'"), tmp
);
1081 root
= (strcmp (*cur
, "/dev/root") == 0);
1082 dm
= (strncmp (*cur
, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0);
1085 if (stat (*cur
, &st
) < 0)
1089 *cur
= grub_find_device (dm
? "/dev/mapper" : "/dev", dev
);
1093 for (cur
= os_dev
; *cur
; cur
++)
1099 if (stat (dir
, &st
) < 0)
1100 grub_util_error (_("cannot stat `%s': %s"), dir
, strerror (errno
));
1103 #endif /* !__GNU__ */
1105 os_dev
= xmalloc (2 * sizeof (os_dev
[0]));
1108 /* Cygwin specific function. */
1109 os_dev
[0] = grub_find_device (dir
, dev
);
1111 #elif defined __GNU__
1112 /* GNU/Hurd specific function. */
1113 os_dev
[0] = find_hurd_root_device (dir
);
1117 /* This might be truly slow, but is there any better way? */
1118 os_dev
[0] = grub_find_device ("/dev", dev
);
1131 #ifdef HAVE_DEVICE_MAPPER
1134 grub_util_open_dm (const char *os_dev
, struct dm_tree
**tree
,
1135 struct dm_tree_node
**node
)
1143 if (stat (os_dev
, &st
) < 0)
1146 maj
= major (st
.st_rdev
);
1147 min
= minor (st
.st_rdev
);
1149 if (!dm_is_dm_major (maj
))
1152 *tree
= dm_tree_create ();
1155 grub_puts_ (N_("Failed to create `device-mapper' tree"));
1156 grub_dprintf ("hostdisk", "dm_tree_create failed\n");
1160 if (! dm_tree_add_dev (*tree
, maj
, min
))
1162 grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
1163 dm_tree_free (*tree
);
1168 *node
= dm_tree_find_node (*tree
, maj
, min
);
1171 grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
1172 dm_tree_free (*tree
);
1181 #ifdef HAVE_DEVICE_MAPPER
1183 get_dm_uuid (const char *os_dev
)
1185 struct dm_tree
*tree
;
1186 struct dm_tree_node
*node
;
1187 const char *node_uuid
;
1190 if (!grub_util_open_dm (os_dev
, &tree
, &node
))
1193 node_uuid
= dm_tree_node_get_uuid (node
);
1196 grub_dprintf ("hostdisk", "%s has no DM uuid\n", os_dev
);
1197 dm_tree_free (tree
);
1201 ret
= grub_strdup (node_uuid
);
1203 dm_tree_free (tree
);
1211 static enum grub_dev_abstraction_types
1212 grub_util_get_dm_abstraction (const char *os_dev
)
1214 #ifdef HAVE_DEVICE_MAPPER
1217 uuid
= get_dm_uuid (os_dev
);
1220 return GRUB_DEV_ABSTRACTION_NONE
;
1222 if (strncmp (uuid
, "LVM-", 4) == 0)
1225 return GRUB_DEV_ABSTRACTION_LVM
;
1227 if (strncmp (uuid
, "CRYPT-LUKS1-", 4) == 0)
1230 return GRUB_DEV_ABSTRACTION_LUKS
;
1234 return GRUB_DEV_ABSTRACTION_NONE
;
1236 if ((strncmp ("/dev/mapper/", os_dev
, 12) != 0))
1237 return GRUB_DEV_ABSTRACTION_NONE
;
1238 return GRUB_DEV_ABSTRACTION_LVM
;
1244 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1245 #include <libgeom.h>
1248 grub_util_get_geom_abstraction (const char *dev
)
1252 struct gclass
*class;
1256 if (strncmp (dev
, "/dev/", sizeof ("/dev/") - 1) != 0)
1258 name
= dev
+ sizeof ("/dev/") - 1;
1259 grub_util_follow_gpart_up (name
, NULL
, &whole
);
1261 grub_util_info ("following geom '%s'", name
);
1263 err
= geom_gettree (&mesh
);
1265 /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
1266 Usually left untranslated.
1268 grub_util_error ("%s", _("couldn't open geom"));
1270 LIST_FOREACH (class, &mesh
.lg_class
, lg_class
)
1273 LIST_FOREACH (geom
, &class->lg_geom
, lg_geom
)
1275 struct gprovider
*provider
;
1276 LIST_FOREACH (provider
, &geom
->lg_provider
, lg_provider
)
1277 if (strcmp (provider
->lg_name
, name
) == 0)
1278 return class->lg_name
;
1286 grub_util_get_dev_abstraction (const char *os_dev
)
1288 #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1289 /* User explicitly claims that this drive is visible by BIOS. */
1290 if (grub_util_biosdisk_is_present (os_dev
))
1291 return GRUB_DEV_ABSTRACTION_NONE
;
1295 enum grub_dev_abstraction_types ret
;
1297 /* Check for LVM and LUKS. */
1298 ret
= grub_util_get_dm_abstraction (os_dev
);
1300 if (ret
!= GRUB_DEV_ABSTRACTION_NONE
)
1303 /* Check for RAID. */
1304 if (!strncmp (os_dev
, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev
)
1305 && !grub_util_is_imsm (os_dev
))
1306 return GRUB_DEV_ABSTRACTION_RAID
;
1309 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1310 const char *abstrac
;
1311 abstrac
= grub_util_get_geom_abstraction (os_dev
);
1312 grub_util_info ("abstraction of %s is %s", os_dev
, abstrac
);
1313 if (abstrac
&& grub_strcasecmp (abstrac
, "eli") == 0)
1314 return GRUB_DEV_ABSTRACTION_GELI
;
1316 /* Check for LVM. */
1317 if (!strncmp (os_dev
, LVM_DEV_MAPPER_STRING
, sizeof(LVM_DEV_MAPPER_STRING
)-1))
1318 return GRUB_DEV_ABSTRACTION_LVM
;
1321 /* No abstraction found. */
1322 return GRUB_DEV_ABSTRACTION_NONE
;
1325 #if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
1328 pull_lvm_by_command (const char *os_dev
)
1340 if (strncmp (os_dev
, "/dev/mapper/", sizeof ("/dev/mapper/") - 1)
1344 vgname
= xmalloc (strlen (os_dev
+ sizeof ("/dev/mapper/") - 1) + 1);
1345 for (iptr
= os_dev
+ sizeof ("/dev/mapper/") - 1, optr
= vgname
; *iptr
; )
1348 else if (iptr
[0] == '-' && iptr
[1] == '-')
1357 /* execvp has inconvenient types, hence the casts. None of these
1358 strings will actually be modified. */
1359 /* by default PV name is left aligned in 10 character field, meaning that
1360 we do not know where name ends. Using dummy --separator disables
1361 alignment. We have a single field, so separator itself is not output */
1362 argv
[0] = (char *) "vgs";
1363 argv
[1] = (char *) "--options";
1364 argv
[2] = (char *) "pv_name";
1365 argv
[3] = (char *) "--noheadings";
1366 argv
[4] = (char *) "--separator";
1367 argv
[5] = (char *) ":";
1371 pid
= exec_pipe (argv
, &fd
);
1377 /* Parent. Read mdadm's output. */
1378 mdadm
= fdopen (fd
, "r");
1381 grub_util_warn (_("Unable to open stream from %s: %s"),
1382 "vgs", strerror (errno
));
1386 while (getline (&buf
, &len
, mdadm
) > 0)
1389 /* LVM adds two spaces as standard prefix */
1390 for (ptr
= buf
; ptr
< buf
+ 2 && *ptr
== ' '; ptr
++);
1393 *(ptr
+ strlen (ptr
) - 1) = '\0';
1394 grub_util_pull_device (ptr
);
1399 waitpid (pid
, NULL
, 0);
1407 get_mdadm_uuid (const char *os_dev
)
1417 /* execvp has inconvenient types, hence the casts. None of these
1418 strings will actually be modified. */
1419 argv
[0] = (char *) "mdadm";
1420 argv
[1] = (char *) "--detail";
1421 argv
[2] = (char *) "--export";
1422 argv
[3] = (char *) os_dev
;
1425 pid
= exec_pipe (argv
, &fd
);
1430 /* Parent. Read mdadm's output. */
1431 mdadm
= fdopen (fd
, "r");
1434 grub_util_warn (_("Unable to open stream from %s: %s"),
1435 "mdadm", strerror (errno
));
1439 while (getline (&buf
, &len
, mdadm
) > 0)
1441 if (strncmp (buf
, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
1443 char *name_start
, *ptri
, *ptro
;
1446 name_start
= buf
+ sizeof ("MD_UUID=") - 1;
1447 ptro
= name
= xmalloc (strlen (name_start
) + 1);
1448 for (ptri
= name_start
; *ptri
&& *ptri
!= '\n' && *ptri
!= '\r';
1450 if ((*ptri
>= '0' && *ptri
<= '9')
1451 || (*ptri
>= 'a' && *ptri
<= 'f')
1452 || (*ptri
>= 'A' && *ptri
<= 'F'))
1460 waitpid (pid
, NULL
, 0);
1467 grub_util_is_imsm (const char *os_dev
)
1471 int container_seen
= 0;
1472 const char *dev
= os_dev
;
1483 retry
= 0; /* We'll do one more pass if device is part of container */
1485 /* execvp has inconvenient types, hence the casts. None of these
1486 strings will actually be modified. */
1487 argv
[0] = (char *) "mdadm";
1488 argv
[1] = (char *) "--detail";
1489 argv
[2] = (char *) "--export";
1490 argv
[3] = (char *) dev
;
1493 pid
= exec_pipe (argv
, &fd
);
1498 free ((void *) dev
);
1502 /* Parent. Read mdadm's output. */
1503 mdadm
= fdopen (fd
, "r");
1506 grub_util_warn (_("Unable to open stream from %s: %s"),
1507 "mdadm", strerror (errno
));
1509 waitpid (pid
, NULL
, 0);
1511 free ((void *) dev
);
1515 while (getline (&buf
, &len
, mdadm
) > 0)
1517 if (strncmp (buf
, "MD_CONTAINER=", sizeof ("MD_CONTAINER=") - 1) == 0
1521 newdev
= xstrdup (buf
+ sizeof ("MD_CONTAINER=") - 1);
1522 ptr
= newdev
+ strlen (newdev
) - 1;
1523 for (; ptr
>= newdev
&& (*ptr
== '\n' || *ptr
== '\r'); ptr
--);
1525 grub_util_info ("Container of %s is %s", dev
, newdev
);
1527 container_seen
= retry
= 1;
1530 if (strncmp (buf
, "MD_METADATA=imsm",
1531 sizeof ("MD_METADATA=imsm") - 1) == 0)
1534 grub_util_info ("%s is imsm", dev
);
1541 waitpid (pid
, NULL
, 0);
1546 free ((void *) dev
);
1549 #endif /* __linux__ */
1552 grub_util_pull_device (const char *os_dev
)
1555 ab
= grub_util_get_dev_abstraction (os_dev
);
1558 case GRUB_DEV_ABSTRACTION_GELI
:
1559 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1563 struct gclass
*class;
1566 char *lastsubdev
= NULL
;
1568 if (strncmp (os_dev
, "/dev/", sizeof ("/dev/") - 1) != 0)
1570 name
= os_dev
+ sizeof ("/dev/") - 1;
1571 grub_util_follow_gpart_up (name
, NULL
, &whole
);
1573 grub_util_info ("following geom '%s'", name
);
1575 err
= geom_gettree (&mesh
);
1577 /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
1578 Usually left untranslated.
1580 grub_util_error ("%s", _("couldn't open geom"));
1582 LIST_FOREACH (class, &mesh
.lg_class
, lg_class
)
1585 LIST_FOREACH (geom
, &class->lg_geom
, lg_geom
)
1587 struct gprovider
*provider
;
1588 LIST_FOREACH (provider
, &geom
->lg_provider
, lg_provider
)
1589 if (strcmp (provider
->lg_name
, name
) == 0)
1591 struct gconsumer
*consumer
;
1594 LIST_FOREACH (consumer
, &geom
->lg_consumer
, lg_consumer
)
1597 grub_util_error ("%s",
1598 _("couldn't find geli consumer"));
1599 fname
= xasprintf ("/dev/%s", consumer
->lg_provider
->lg_name
);
1600 grub_util_info ("consumer %s", consumer
->lg_provider
->lg_name
);
1601 lastsubdev
= consumer
->lg_provider
->lg_name
;
1602 grub_util_pull_device (fname
);
1607 if (ab
== GRUB_DEV_ABSTRACTION_GELI
&& lastsubdev
)
1609 char *fname
= xasprintf ("/dev/%s", lastsubdev
);
1610 char *grdev
= grub_util_get_grub_dev (fname
);
1616 gr_err
= grub_cryptodisk_cheat_mount (grdev
, os_dev
);
1618 grub_util_error (_("can't mount encrypted volume `%s': %s"),
1619 lastsubdev
, grub_errmsg
);
1628 case GRUB_DEV_ABSTRACTION_LVM
:
1629 #if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__GNU__)
1630 pull_lvm_by_command (os_dev
);
1632 /* Fallthrough in case that lvm-tools are unavailable. */
1633 case GRUB_DEV_ABSTRACTION_LUKS
:
1634 #ifdef HAVE_DEVICE_MAPPER
1636 struct dm_tree
*tree
;
1637 struct dm_tree_node
*node
;
1638 struct dm_tree_node
*child
;
1639 void *handle
= NULL
;
1640 char *lastsubdev
= NULL
;
1642 if (!grub_util_open_dm (os_dev
, &tree
, &node
))
1645 while ((child
= dm_tree_next_child (&handle
, node
, 0)))
1647 const struct dm_info
*dm
= dm_tree_node_get_info (child
);
1651 subdev
= grub_find_device ("/dev", makedev (dm
->major
, dm
->minor
));
1654 lastsubdev
= subdev
;
1655 grub_util_pull_device (subdev
);
1658 if (ab
== GRUB_DEV_ABSTRACTION_LUKS
&& lastsubdev
)
1660 char *grdev
= grub_util_get_grub_dev (lastsubdev
);
1661 dm_tree_free (tree
);
1665 err
= grub_cryptodisk_cheat_mount (grdev
, os_dev
);
1667 grub_util_error (_("can't mount encrypted volume `%s': %s"),
1668 lastsubdev
, grub_errmsg
);
1673 dm_tree_free (tree
);
1677 case GRUB_DEV_ABSTRACTION_RAID
:
1680 char **devicelist
= grub_util_raid_getmembers (os_dev
, 0);
1682 for (i
= 0; devicelist
[i
];i
++)
1684 grub_util_pull_device (devicelist
[i
]);
1685 free (devicelist
[i
]);
1692 default: /* GRUB_DEV_ABSTRACTION_NONE */
1693 free (grub_util_biosdisk_get_grub_dev (os_dev
));
1699 grub_util_biosdisk_is_floppy (grub_disk_t disk
)
1705 dname
= grub_util_biosdisk_get_osdev (disk
);
1710 fd
= open (dname
, O_RDONLY
);
1711 /* Shouldn't happen. */
1715 /* Shouldn't happen either. */
1716 if (fstat (fd
, &st
) < 0)
1724 #if defined(__NetBSD__)
1725 if (major(st
.st_rdev
) == RAW_FLOPPY_MAJOR
)
1729 #if defined(FLOPPY_MAJOR)
1730 if (major(st
.st_rdev
) == FLOPPY_MAJOR
)
1732 /* Some kernels (e.g. kFreeBSD) don't have a static major number
1733 for floppies, but they still use a "fd[0-9]" pathname. */
1745 convert_system_partition_to_system_disk (const char *os_dev
, struct stat
*st
,
1750 #if defined(__linux__)
1751 char *path
= xmalloc (PATH_MAX
);
1753 if (! realpath (os_dev
, path
))
1756 if (strncmp ("/dev/", path
, 5) == 0)
1760 /* If this is an IDE disk. */
1761 if (strncmp ("ide/", p
, 4) == 0)
1763 p
= strstr (p
, "part");
1773 /* If this is a SCSI disk. */
1774 if (strncmp ("scsi/", p
, 5) == 0)
1776 p
= strstr (p
, "part");
1786 /* If this is a DAC960 disk. */
1787 if (strncmp ("rd/c", p
, 4) == 0)
1789 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
1790 p
= strchr (p
, 'p');
1800 /* If this is a Mylex AcceleRAID Array. */
1801 if (strncmp ("rs/c", p
, 4) == 0)
1803 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
1804 p
= strchr (p
, 'p');
1813 /* If this is a CCISS disk. */
1814 if (strncmp ("cciss/c", p
, sizeof ("cciss/c") - 1) == 0)
1816 /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
1817 p
= strchr (p
, 'p');
1827 /* If this is an AOE disk. */
1828 if (strncmp ("etherd/e", p
, sizeof ("etherd/e") - 1) == 0)
1830 /* /dev/etherd/e[0-9]+\.[0-9]+(p[0-9]+)? */
1831 p
= strchr (p
, 'p');
1841 /* If this is a Compaq Intelligent Drive Array. */
1842 if (strncmp ("ida/c", p
, sizeof ("ida/c") - 1) == 0)
1844 /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
1845 p
= strchr (p
, 'p');
1855 /* If this is an I2O disk. */
1856 if (strncmp ("i2o/hd", p
, sizeof ("i2o/hd") - 1) == 0)
1858 /* /dev/i2o/hd[a-z]([0-9]+)? */
1859 if (p
[sizeof ("i2o/hda") - 1])
1861 p
[sizeof ("i2o/hda") - 1] = '\0';
1865 /* If this is a MultiMediaCard (MMC). */
1866 if (strncmp ("mmcblk", p
, sizeof ("mmcblk") - 1) == 0)
1868 /* /dev/mmcblk[0-9]+(p[0-9]+)? */
1869 p
= strchr (p
, 'p');
1879 if (strncmp ("md", p
, 2) == 0
1880 && p
[2] >= '0' && p
[2] <= '9')
1883 while (*ptr
>= '0' && *ptr
<= '9')
1891 if (strncmp ("nbd", p
, 3) == 0
1892 && p
[3] >= '0' && p
[3] <= '9')
1895 while (*ptr
>= '0' && *ptr
<= '9')
1903 /* If this is an IDE, SCSI or Virtio disk. */
1904 if (strncmp ("vdisk", p
, 5) == 0
1905 && p
[5] >= 'a' && p
[5] <= 'z')
1907 /* /dev/vdisk[a-z][0-9]* */
1913 if ((strncmp ("hd", p
, 2) == 0
1914 || strncmp ("vd", p
, 2) == 0
1915 || strncmp ("sd", p
, 2) == 0)
1916 && p
[2] >= 'a' && p
[2] <= 'z')
1919 while (*pp
>= 'a' && *pp
<= 'z')
1923 /* /dev/[hsv]d[a-z]+[0-9]* */
1928 /* If this is a Xen virtual block device. */
1929 if ((strncmp ("xvd", p
, 3) == 0) && p
[3] >= 'a' && p
[3] <= 'z')
1932 while (*pp
>= 'a' && *pp
<= 'z')
1936 /* /dev/xvd[a-z]+[0-9]* */
1941 #ifdef HAVE_DEVICE_MAPPER
1942 if (dm_is_dm_major (major (st
->st_rdev
)))
1944 struct dm_tree
*tree
;
1946 struct dm_tree_node
*node
= NULL
, *child
;
1948 const char *node_uuid
, *mapper_name
= NULL
, *child_uuid
, *child_name
;
1950 tree
= dm_tree_create ();
1953 grub_util_info ("dm_tree_create failed");
1957 maj
= major (st
->st_rdev
);
1958 min
= minor (st
->st_rdev
);
1959 if (! dm_tree_add_dev (tree
, maj
, min
))
1961 grub_util_info ("dm_tree_add_dev failed");
1965 node
= dm_tree_find_node (tree
, maj
, min
);
1968 grub_util_info ("dm_tree_find_node failed");
1972 node_uuid
= dm_tree_node_get_uuid (node
);
1975 grub_util_info ("%s has no DM uuid", path
);
1978 if (strncmp (node_uuid
, "LVM-", 4) == 0)
1980 grub_util_info ("%s is an LVM", path
);
1983 if (strncmp (node_uuid
, "mpath-", 6) == 0)
1985 /* Multipath partitions have partN-mpath-* UUIDs, and are
1986 linear mappings so are handled by
1987 grub_util_get_dm_node_linear_info. Multipath disks are not
1988 linear mappings and must be handled specially. */
1989 grub_util_info ("%s is a multipath disk", path
);
1992 if (strncmp (node_uuid
, "DMRAID-", 7) != 0)
1995 const char *node_name
;
1996 grub_util_info ("%s is not DM-RAID", path
);
1998 if ((node_name
= dm_tree_node_get_name (node
))
1999 && grub_util_get_dm_node_linear_info (node_name
,
2004 dm_tree_free (tree
);
2006 char *ret
= grub_find_device ("/dev",
2007 (major
<< 8) | minor
);
2015 /* Counter-intuitively, device-mapper refers to the disk-like
2016 device containing a DM-RAID partition device as a "child" of
2017 the partition device. */
2018 child
= dm_tree_next_child (&handle
, node
, 0);
2021 grub_util_info ("%s has no DM children", path
);
2024 child_uuid
= dm_tree_node_get_uuid (child
);
2027 grub_util_info ("%s child has no DM uuid", path
);
2030 else if (strncmp (child_uuid
, "DMRAID-", 7) != 0)
2032 grub_util_info ("%s child is not DM-RAID", path
);
2035 child_name
= dm_tree_node_get_name (child
);
2038 grub_util_info ("%s child has no DM name", path
);
2041 mapper_name
= child_name
;
2047 if (! mapper_name
&& node
)
2049 /* This is a DM-RAID disk, not a partition. */
2050 mapper_name
= dm_tree_node_get_name (node
);
2052 grub_util_info ("%s has no DM name", path
);
2056 ret
= xasprintf ("/dev/mapper/%s", mapper_name
);
2061 dm_tree_free (tree
);
2065 #endif /* HAVE_DEVICE_MAPPER */
2070 #elif defined(__GNU__)
2071 char *path
= xstrdup (os_dev
);
2072 if (strncmp ("/dev/sd", path
, 7) == 0 || strncmp ("/dev/hd", path
, 7) == 0)
2074 char *p
= strchr (path
+ 7, 's');
2083 #elif defined(__CYGWIN__)
2084 char *path
= xstrdup (os_dev
);
2085 if (strncmp ("/dev/sd", path
, 7) == 0 && 'a' <= path
[7] && path
[7] <= 'z'
2093 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
2095 if (strncmp (os_dev
, "/dev/", sizeof ("/dev/") - 1) != 0)
2096 return xstrdup (os_dev
);
2097 grub_util_follow_gpart_up (os_dev
+ sizeof ("/dev/") - 1, NULL
, &out
);
2099 if (grub_strcmp (os_dev
+ sizeof ("/dev/") - 1, out
) != 0)
2101 out2
= xasprintf ("/dev/%s", out
);
2105 #elif defined(__APPLE__)
2106 char *path
= xstrdup (os_dev
);
2107 if (strncmp ("/dev/", path
, 5) == 0)
2110 for (p
= path
+ 5; *p
; ++p
)
2111 if (grub_isdigit(*p
))
2113 p
= strpbrk (p
, "sp");
2124 #elif defined(__NetBSD__) || defined(__OpenBSD__)
2126 # ifdef HAVE_GETRAWPARTITION
2127 rawpart
= getrawpartition();
2128 # endif /* HAVE_GETRAWPARTITION */
2130 return xstrdup (os_dev
);
2132 #if defined(__NetBSD__)
2133 /* NetBSD disk wedges are of the form "/dev/rdk.*". */
2134 if (strncmp ("/dev/rdk", os_dev
, sizeof("/dev/rdk") - 1) == 0)
2136 struct dkwedge_info dkw
;
2139 fd
= open (os_dev
, O_RDONLY
);
2142 grub_error (GRUB_ERR_BAD_DEVICE
,
2143 N_("cannot open `%s': %s"), os_dev
,
2145 return xstrdup (os_dev
);
2147 /* We don't call configure_device_driver since this isn't a floppy device name. */
2148 if (ioctl (fd
, DIOCGWEDGEINFO
, &dkw
) == -1)
2150 grub_error (GRUB_ERR_BAD_DEVICE
,
2151 "cannot get disk wedge info of `%s'", os_dev
);
2153 return xstrdup (os_dev
);
2155 *is_part
= (dkw
.dkw_offset
!= 0);
2157 return xasprintf ("/dev/r%s%c", dkw
.dkw_parent
, 'a' + rawpart
);
2161 /* NetBSD (disk label) partitions are of the form "/dev/r[a-z]+[0-9][a-z]". */
2162 if (strncmp ("/dev/r", os_dev
, sizeof("/dev/r") - 1) == 0 &&
2163 (os_dev
[sizeof("/dev/r") - 1] >= 'a' && os_dev
[sizeof("/dev/r") - 1] <= 'z') &&
2164 strncmp ("fd", os_dev
+ sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
2166 char *path
= xstrdup (os_dev
);
2168 for (p
= path
+ sizeof("/dev/r"); *p
>= 'a' && *p
<= 'z'; p
++);
2169 if (grub_isdigit(*p
))
2172 if ((*p
>= 'a' && *p
<= 'z') && (*(p
+1) == '\0'))
2174 if (*p
!= 'a' + rawpart
)
2176 /* path matches the required regular expression and
2177 p points to its last character. */
2184 return xstrdup (os_dev
);
2186 #elif defined (__sun__)
2187 char *colon
= grub_strrchr (os_dev
, ':');
2188 if (grub_memcmp (os_dev
, "/devices", sizeof ("/devices") - 1) == 0
2191 char *ret
= xmalloc (colon
- os_dev
+ sizeof (":q,raw"));
2192 if (grub_strcmp (colon
, ":q,raw") != 0)
2194 grub_memcpy (ret
, os_dev
, colon
- os_dev
);
2195 grub_memcpy (ret
+ (colon
- os_dev
), ":q,raw", sizeof (":q,raw"));
2199 return xstrdup (os_dev
);
2200 #elif defined (__APPLE__)
2202 char *ret
= xstrdup (os_dev
);
2203 int disk
= grub_memcmp (ret
, "/dev/disk", sizeof ("/dev/disk") - 1) == 0;
2204 int rdisk
= grub_memcmp (ret
, "/dev/rdisk", sizeof ("/dev/rdisk") - 1) == 0;
2205 if (!disk
&& !rdisk
)
2207 ptr
= ret
+ sizeof ("/dev/disk") + rdisk
- 1;
2208 while (*ptr
>= '0' && *ptr
<= '9')
2217 # warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
2218 return xstrdup (os_dev
);
2223 find_system_device (const char *os_dev
, struct stat
*st
, int convert
, int add
)
2230 os_disk
= convert_system_partition_to_system_disk (os_dev
, st
, &is_part
);
2232 os_disk
= xstrdup (os_dev
);
2236 drive
= grub_hostdisk_os_dev_to_grub_drive (os_disk
, add
);
2242 * Note: we do not use the new partition naming scheme as dos_part does not
2243 * necessarily correspond to an msdos partition.
2246 make_device_name (const char *drive
, int dos_part
, int bsd_part
)
2248 char *ret
, *ptr
, *end
;
2251 ret
= xmalloc (strlen (drive
) * 2
2252 + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
2253 ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
2254 end
= (ret
+ strlen (drive
) * 2
2255 + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
2256 ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
2258 for (iptr
= drive
; *iptr
; iptr
++)
2266 snprintf (ptr
, end
- ptr
, ",%d", dos_part
+ 1);
2267 ptr
+= strlen (ptr
);
2269 snprintf (ptr
, end
- ptr
, ",%d", bsd_part
+ 1);
2275 grub_util_get_os_disk (const char *os_dev
)
2280 grub_util_info ("Looking for %s", os_dev
);
2282 if (stat (os_dev
, &st
) < 0)
2284 const char *errstr
= strerror (errno
);
2285 grub_error (GRUB_ERR_BAD_DEVICE
, N_("cannot stat `%s': %s"),
2287 grub_util_info (_("cannot stat `%s': %s"), os_dev
, errstr
);
2291 return convert_system_partition_to_system_disk (os_dev
, &st
, &is_part
);
2294 #if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
2295 /* Context for grub_util_biosdisk_get_grub_dev. */
2296 struct grub_util_biosdisk_get_grub_dev_ctx
2299 grub_disk_addr_t start
;
2302 /* Helper for grub_util_biosdisk_get_grub_dev. */
2304 find_partition (grub_disk_t dsk
__attribute__ ((unused
)),
2305 const grub_partition_t partition
, void *data
)
2307 struct grub_util_biosdisk_get_grub_dev_ctx
*ctx
= data
;
2308 grub_disk_addr_t part_start
= 0;
2309 grub_util_info ("Partition %d starts from %" PRIuGRUB_UINT64_T
,
2310 partition
->number
, partition
->start
);
2312 part_start
= grub_partition_get_start (partition
);
2314 if (ctx
->start
== part_start
)
2316 ctx
->partname
= grub_partition_get_name (partition
);
2325 grub_util_biosdisk_get_grub_dev (const char *os_dev
)
2332 grub_util_info ("Looking for %s", os_dev
);
2334 if (stat (os_dev
, &st
) < 0)
2336 const char *errstr
= strerror (errno
);
2337 grub_error (GRUB_ERR_BAD_DEVICE
, N_("cannot stat `%s': %s"), os_dev
,
2339 grub_util_info (_("cannot stat `%s': %s"), os_dev
, errstr
);
2343 drive
= find_system_device (os_dev
, &st
, 1, 1);
2344 sys_disk
= convert_system_partition_to_system_disk (os_dev
, &st
, &is_part
);
2347 grub_util_info ("%s is a parent of %s", sys_disk
, os_dev
);
2351 return make_device_name (drive
, -1, -1);
2355 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
2356 if (! S_ISCHR (st
.st_mode
))
2358 if (! S_ISBLK (st
.st_mode
))
2360 return make_device_name (drive
, -1, -1);
2362 #if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__) || defined(__OpenBSD__)
2364 /* Linux counts partitions uniformly, whether a BSD partition or a DOS
2365 partition, so mapping them to GRUB devices is not trivial.
2366 Here, get the start sector of a partition by HDIO_GETGEO, and
2367 compare it with each partition GRUB recognizes.
2369 Cygwin /dev/sdXN emulation uses Windows partition mapping. It
2370 does not count the extended partition and missing primary
2371 partitions. Use same method as on Linux here.
2373 For NetBSD and FreeBSD, proceed as for Linux, except that the start
2374 sector is obtained from the disk label. */
2378 struct grub_util_biosdisk_get_grub_dev_ctx ctx
;
2380 name
= make_device_name (drive
, -1, -1);
2382 # if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
2383 if (MAJOR (st
.st_rdev
) == FLOPPY_MAJOR
)
2385 # else /* defined(HAVE_DIOCGDINFO) */
2386 /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
2387 * different, we know that os_dev cannot be a floppy device. */
2388 # endif /* !defined(HAVE_DIOCGDINFO) */
2390 ctx
.start
= grub_hostdisk_find_partition_start (os_dev
);
2391 if (grub_errno
!= GRUB_ERR_NONE
)
2397 grub_util_info ("%s starts from %" PRIuGRUB_UINT64_T
, os_dev
, ctx
.start
);
2399 if (ctx
.start
== 0 && !is_part
)
2402 grub_util_info ("opening the device %s", name
);
2403 disk
= grub_disk_open (name
);
2408 /* We already know that the partition exists. Given that we already
2409 checked the device map above, we can only get
2410 GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist.
2411 This can happen on Xen, where disk images in the host can be
2412 assigned to devices that have partition-like names in the guest
2413 but are really more like disks. */
2414 if (grub_errno
== GRUB_ERR_UNKNOWN_DEVICE
)
2418 (_("disk does not exist, so falling back to partition device %s"),
2420 grub_errno
= GRUB_ERR_NONE
;
2422 canon
= canonicalize_file_name (os_dev
);
2423 drive
= find_system_device (canon
? : os_dev
, &st
, 0, 1);
2426 return make_device_name (drive
, -1, -1);
2432 name
= grub_util_get_ldm (disk
, ctx
.start
);
2436 ctx
.partname
= NULL
;
2438 grub_partition_iterate (disk
, find_partition
, &ctx
);
2439 if (grub_errno
!= GRUB_ERR_NONE
)
2441 grub_disk_close (disk
);
2445 if (ctx
.partname
== NULL
)
2447 grub_disk_close (disk
);
2448 grub_util_info ("cannot find the partition of `%s'", os_dev
);
2449 grub_error (GRUB_ERR_BAD_DEVICE
,
2450 "cannot find the partition of `%s'", os_dev
);
2454 name
= grub_xasprintf ("%s,%s", disk
->name
, ctx
.partname
);
2455 free (ctx
.partname
);
2456 grub_disk_close (disk
);
2460 #elif defined(__GNU__)
2461 /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
2467 p
= strrchr (os_dev
, 's');
2474 n
= strtol (p
, &q
, 10);
2475 if (p
!= q
&& n
!= GRUB_LONG_MIN
&& n
!= GRUB_LONG_MAX
)
2477 dos_part
= (int) n
- 1;
2479 if (*q
>= 'a' && *q
<= 'g')
2480 bsd_part
= *q
- 'a';
2484 return make_device_name (drive
, dos_part
, bsd_part
);
2487 #elif defined(__APPLE__)
2488 /* Apple uses "/dev/r?disk[0-9]+(s[0-9]+)?". */
2491 int disk
= (grub_memcmp (os_dev
, "/dev/disk", sizeof ("/dev/disk") - 1)
2493 int rdisk
= (grub_memcmp (os_dev
, "/dev/rdisk", sizeof ("/dev/rdisk") - 1)
2496 if (!disk
&& !rdisk
)
2497 return make_device_name (drive
, -1, -1);
2499 p
= os_dev
+ sizeof ("/dev/disk") + rdisk
- 1;
2500 while (*p
>= '0' && *p
<= '9')
2503 return make_device_name (drive
, -1, -1);
2506 return make_device_name (drive
, strtol (p
, NULL
, 10) - 1, -1);
2509 # warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
2510 return make_device_name (drive
, -1, -1);
2515 grub_util_biosdisk_is_present (const char *os_dev
)
2519 if (stat (os_dev
, &st
) < 0)
2522 int ret
= (find_system_device (os_dev
, &st
, 1, 0) != NULL
);
2523 grub_util_info ((ret
? "%s is present" : "%s is not present"),
2529 grub_util_get_grub_dev (const char *os_dev
)
2531 char *grub_dev
= NULL
;
2533 grub_util_pull_device (os_dev
);
2535 switch (grub_util_get_dev_abstraction (os_dev
))
2537 #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
2538 case GRUB_DEV_ABSTRACTION_LVM
:
2542 grub_size_t offset
= sizeof (LVM_DEV_MAPPER_STRING
) - 1;
2544 len
= strlen (os_dev
) - offset
+ 1;
2545 grub_dev
= xmalloc (len
+ sizeof ("lvm/"));
2547 grub_memcpy (grub_dev
, "lvm/", sizeof ("lvm/") - 1);
2548 grub_memcpy (grub_dev
+ sizeof ("lvm/") - 1, os_dev
+ offset
, len
);
2554 case GRUB_DEV_ABSTRACTION_LUKS
:
2555 #ifdef HAVE_DEVICE_MAPPER
2558 uuid
= get_dm_uuid (os_dev
);
2561 dash
= grub_strchr (uuid
+ sizeof ("CRYPT-LUKS1-") - 1, '-');
2564 grub_dev
= grub_xasprintf ("cryptouuid/%s",
2565 uuid
+ sizeof ("CRYPT-LUKS1-") - 1);
2571 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
2572 case GRUB_DEV_ABSTRACTION_GELI
:
2576 struct gclass
*class;
2580 if (strncmp (os_dev
, "/dev/", sizeof ("/dev/") - 1) != 0)
2582 name
= os_dev
+ sizeof ("/dev/") - 1;
2583 grub_util_follow_gpart_up (name
, NULL
, &whole
);
2585 grub_util_info ("following geom '%s'", name
);
2587 err
= geom_gettree (&mesh
);
2589 /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
2590 Usually left untranslated.
2592 grub_util_error ("%s", _("couldn't open geom"));
2594 LIST_FOREACH (class, &mesh
.lg_class
, lg_class
)
2597 LIST_FOREACH (geom
, &class->lg_geom
, lg_geom
)
2599 struct gprovider
*provider
;
2600 LIST_FOREACH (provider
, &geom
->lg_provider
, lg_provider
)
2601 if (strcmp (provider
->lg_name
, name
) == 0)
2603 struct gconsumer
*consumer
;
2607 LIST_FOREACH (consumer
, &geom
->lg_consumer
, lg_consumer
)
2610 grub_util_error ("%s",
2611 _("couldn't find geli consumer"));
2612 fname
= xasprintf ("/dev/%s", consumer
->lg_provider
->lg_name
);
2613 uuid
= grub_util_get_geli_uuid (fname
);
2615 grub_util_error ("%s",
2616 _("couldn't retrieve geli UUID"));
2617 grub_dev
= xasprintf ("cryptouuid/%s", uuid
);
2628 case GRUB_DEV_ABSTRACTION_RAID
:
2630 if (os_dev
[7] == '_' && os_dev
[8] == 'd')
2632 /* This a partitionable RAID device of the form /dev/md_dNNpMM. */
2636 p
= strdup (os_dev
+ sizeof ("/dev/md_d") - 1);
2638 q
= strchr (p
, 'p');
2642 grub_dev
= xasprintf ("md%s", p
);
2645 else if (os_dev
[7] == '/' && os_dev
[8] == 'd')
2647 /* This a partitionable RAID device of the form /dev/md/dNNpMM. */
2651 p
= strdup (os_dev
+ sizeof ("/dev/md/d") - 1);
2653 q
= strchr (p
, 'p');
2657 grub_dev
= xasprintf ("md%s", p
);
2660 else if (os_dev
[7] >= '0' && os_dev
[7] <= '9')
2664 p
= strdup (os_dev
+ sizeof ("/dev/md") - 1);
2666 q
= strchr (p
, 'p');
2670 grub_dev
= xasprintf ("md%s", p
);
2673 else if (os_dev
[7] == '/' && os_dev
[8] >= '0' && os_dev
[8] <= '9')
2677 p
= strdup (os_dev
+ sizeof ("/dev/md/") - 1);
2679 q
= strchr (p
, 'p');
2683 grub_dev
= xasprintf ("md%s", p
);
2686 else if (os_dev
[7] == '/')
2688 /* mdraid 1.x with a free name. */
2691 p
= strdup (os_dev
+ sizeof ("/dev/md/") - 1);
2693 q
= strchr (p
, 'p');
2697 grub_dev
= xasprintf ("md/%s", p
);
2701 grub_util_error (_("unknown kind of RAID device `%s'"), os_dev
);
2704 char *mdadm_name
= get_mdadm_uuid (os_dev
);
2710 for (q
= os_dev
+ strlen (os_dev
) - 1; q
>= os_dev
2711 && grub_isdigit (*q
); q
--);
2713 if (q
>= os_dev
&& *q
== 'p')
2716 grub_dev
= xasprintf ("mduuid/%s,%s", mdadm_name
, q
+ 1);
2720 grub_dev
= xasprintf ("mduuid/%s", mdadm_name
);
2727 #endif /* __linux__ */
2729 default: /* GRUB_DEV_ABSTRACTION_NONE */
2730 grub_dev
= grub_util_biosdisk_get_grub_dev (os_dev
);
2737 grub_util_check_block_device (const char *blk_dev
)
2741 if (stat (blk_dev
, &st
) < 0)
2742 grub_util_error (_("cannot stat `%s': %s"), blk_dev
,
2745 if (S_ISBLK (st
.st_mode
))
2752 grub_util_check_char_device (const char *blk_dev
)
2756 if (stat (blk_dev
, &st
) < 0)
2757 grub_util_error (_("cannot stat `%s': %s"), blk_dev
, strerror (errno
));
2759 if (S_ISCHR (st
.st_mode
))
2766 /* Convert POSIX path to Win32 path,
2767 remove drive letter, replace backslashes. */
2769 get_win32_path (const char *path
)
2771 char winpath
[PATH_MAX
];
2772 if (cygwin_conv_path (CCP_POSIX_TO_WIN_A
, path
, winpath
, sizeof(winpath
)))
2773 grub_util_error ("%s", _("cygwin_conv_path() failed"));
2775 int len
= strlen (winpath
);
2776 int offs
= (len
> 2 && winpath
[1] == ':' ? 2 : 0);
2779 for (i
= offs
; i
< len
; i
++)
2780 if (winpath
[i
] == '\\')
2782 return xstrdup (winpath
+ offs
);
2787 static libzfs_handle_t
*__libzfs_handle
;
2792 libzfs_fini (__libzfs_handle
);
2796 grub_get_libzfs_handle (void)
2798 if (! __libzfs_handle
)
2800 __libzfs_handle
= libzfs_init ();
2802 if (__libzfs_handle
)
2803 atexit (fini_libzfs
);
2806 return __libzfs_handle
;
2808 #endif /* HAVE_LIBZFS */
2810 #if !defined (__MINGW32__) && !defined (__CYGWIN__)
2811 /* ZFS has similar problems to those of btrfs (see above). */
2813 grub_find_zpool_from_dir (const char *dir
, char **poolname
, char **poolfs
)
2817 *poolname
= *poolfs
= NULL
;
2819 #if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
2820 /* FreeBSD and GNU/kFreeBSD. */
2824 if (statfs (dir
, &mnt
) != 0)
2827 if (strcmp (mnt
.f_fstypename
, "zfs") != 0)
2830 *poolname
= xstrdup (mnt
.f_mntfromname
);
2832 #elif defined(HAVE_GETEXTMNTENT)
2836 struct extmnttab mnt
;
2838 if (stat (dir
, &st
) != 0)
2841 FILE *mnttab
= fopen ("/etc/mnttab", "r");
2845 while (getextmntent (mnttab
, &mnt
, sizeof (mnt
)) == 0)
2847 if (makedev (mnt
.mnt_major
, mnt
.mnt_minor
) == st
.st_dev
2848 && !strcmp (mnt
.mnt_fstype
, "zfs"))
2850 *poolname
= xstrdup (mnt
.mnt_special
);
2862 slash
= strchr (*poolname
, '/');
2866 *poolfs
= xstrdup (slash
+ 1);
2869 *poolfs
= xstrdup ("");
2873 /* This function never prints trailing slashes (so that its output
2874 can be appended a slash unconditionally). */
2876 grub_make_system_path_relative_to_its_root (const char *path
)
2879 char *p
, *buf
, *buf2
, *buf3
, *ret
;
2880 uintptr_t offset
= 0;
2883 char *poolfs
= NULL
;
2886 p
= canonicalize_file_name (path
);
2888 grub_util_error (_("failed to get canonical path of `%s'"), path
);
2890 /* For ZFS sub-pool filesystems, could be extended to others (btrfs?). */
2891 #if !defined (__MINGW32__) && !defined (__CYGWIN__)
2894 grub_find_zpool_from_dir (p
, &dummy
, &poolfs
);
2898 len
= strlen (p
) + 1;
2902 if (stat (buf
, &st
) < 0)
2903 grub_util_error (_("cannot stat `%s': %s"), buf
, strerror (errno
));
2905 buf2
= xstrdup (buf
);
2908 /* This loop sets offset to the number of chars of the root
2909 directory we're inspecting. */
2912 p
= strrchr (buf
, '/');
2914 /* This should never happen. */
2915 grub_util_error ("%s",
2916 /* TRANSLATORS: canonical pathname is the
2917 complete one e.g. /etc/fstab. It has
2918 to contain `/' normally, if it doesn't
2919 we're in trouble and throw this error. */
2920 _("no `/' in canonical filename"));
2926 if (stat (buf
, &st
) < 0)
2927 grub_util_error (_("cannot stat `%s': %s"), buf
, strerror (errno
));
2929 /* buf is another filesystem; we found it. */
2930 if (st
.st_dev
!= num
)
2932 /* offset == 0 means path given is the mount point.
2933 This works around special-casing of "/" in Un*x. This function never
2934 prints trailing slashes (so that its output can be appended a slash
2935 unconditionally). Each slash in is considered a preceding slash, and
2936 therefore the root directory is an empty string. */
2943 grub_free (grub_find_root_devices_from_mountinfo (buf2
, &bind
));
2944 if (bind
&& bind
[0] && bind
[1])
2954 return xasprintf ("/%s/@", poolfs
);
2955 return xstrdup ("");
2962 /* offset == 1 means root directory. */
2965 /* Include leading slash. */
2971 buf3
= xstrdup (buf2
+ offset
);
2976 grub_free (grub_find_root_devices_from_mountinfo (buf2
, &bind
));
2977 if (bind
&& bind
[0] && bind
[1])
2980 buf3
= grub_xasprintf ("%s%s%s", bind
, buf3
[0] == '/' ?"":"/", buf3
);
2990 if (st
.st_dev
!= (DEV_CYGDRIVE_MAJOR
<< 16))
2992 /* Reached some mount point not below /cygdrive.
2993 GRUB does not know Cygwin's emulated mounts,
2994 convert to Win32 path. */
2995 grub_util_info ("Cygwin path = %s\n", buf3
);
2996 char * temp
= get_win32_path (buf3
);
3005 /* Remove trailing slashes, return empty string if root directory. */
3006 len
= strlen (buf3
);
3007 while (len
> 0 && buf3
[len
- 1] == '/')
3009 buf3
[len
- 1] = '\0';
3015 ret
= xasprintf ("/%s/@%s", poolfs
, buf3
);