2
* GRUB -- GRand Unified Bootloader
3
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
5
* GRUB is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
10
* GRUB is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19
#include <config-util.h>
23
#include <sys/types.h>
38
#include <grub/types.h>
39
#include <sys/ioctl.h> /* ioctl */
40
#include <sys/mount.h>
42
#include <grub/util/misc.h>
45
#include <grub/misc.h>
46
#include <grub/emu/misc.h>
47
#include <grub/emu/hostdisk.h>
48
#include <grub/emu/getroot.h>
52
#include <linux/types.h>
53
#include <linux/major.h>
54
#include <linux/raid/md_p.h>
55
#include <linux/raid/md_u.h>
56
#include <grub/i18n.h>
57
#include <grub/emu/exec.h>
58
#include <grub/btrfs.h>
60
#define LVM_DEV_MAPPER_STRING "/dev/mapper/"
62
/* Defines taken from btrfs/ioctl.h. */
64
struct btrfs_ioctl_dev_info_args
67
grub_uint8_t uuid[16];
68
grub_uint64_t bytes_used;
69
grub_uint64_t total_bytes;
70
grub_uint64_t unused[379];
71
grub_uint8_t path[1024];
74
struct btrfs_ioctl_fs_info_args
77
grub_uint64_t num_devices;
78
grub_uint8_t fsid[16];
79
grub_uint64_t reserved[124];
82
struct btrfs_ioctl_ino_lookup_args
85
grub_uint64_t objectid;
89
struct btrfs_ioctl_search_key
91
grub_uint64_t tree_id;
92
grub_uint64_t min_objectid;
93
grub_uint64_t max_objectid;
94
grub_uint64_t min_offset;
95
grub_uint64_t max_offset;
96
grub_uint64_t min_transid;
97
grub_uint64_t max_transid;
98
grub_uint32_t min_type;
99
grub_uint32_t max_type;
100
grub_uint32_t nr_items;
101
grub_uint32_t unused[9];
104
struct btrfs_ioctl_search_args {
105
struct btrfs_ioctl_search_key key;
106
grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key))
107
/ sizeof (grub_uint64_t)];
110
#define BTRFS_IOC_TREE_SEARCH _IOWR(0x94, 17, \
111
struct btrfs_ioctl_search_args)
112
#define BTRFS_IOC_INO_LOOKUP _IOWR(0x94, 18, \
113
struct btrfs_ioctl_ino_lookup_args)
114
#define BTRFS_IOC_DEV_INFO _IOWR(0x94, 30, \
115
struct btrfs_ioctl_dev_info_args)
116
#define BTRFS_IOC_FS_INFO _IOR(0x94, 31, \
117
struct btrfs_ioctl_fs_info_args)
120
grub_util_is_imsm (const char *os_dev);
123
#define ESCAPED_PATH_MAX (4 * PATH_MAX)
124
struct mountinfo_entry
128
char enc_root[ESCAPED_PATH_MAX + 1], enc_path[ESCAPED_PATH_MAX + 1];
129
char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1];
133
grub_util_raid_getmembers (const char *name, int bootable)
137
mdu_version_t version;
138
mdu_array_info_t info;
139
mdu_disk_info_t disk;
141
fd = open (name, O_RDONLY);
144
grub_util_error (_("cannot open `%s': %s"), name, strerror (errno));
146
ret = ioctl (fd, RAID_VERSION, &version);
148
grub_util_error (_("ioctl RAID_VERSION error: %s"), strerror (errno));
150
if ((version.major != 0 || version.minor != 90)
151
&& (version.major != 1 || version.minor != 0)
152
&& (version.major != 1 || version.minor != 1)
153
&& (version.major != 1 || version.minor != 2))
154
grub_util_error (_("unsupported RAID version: %d.%d"),
155
version.major, version.minor);
157
if (bootable && (version.major != 0 || version.minor != 90))
158
grub_util_error (_("unsupported RAID version: %d.%d"),
159
version.major, version.minor);
161
ret = ioctl (fd, GET_ARRAY_INFO, &info);
163
grub_util_error (_("ioctl GET_ARRAY_INFO error: %s"), strerror (errno));
165
devicelist = xmalloc ((info.nr_disks + 1) * sizeof (char *));
167
for (i = 0, j = 0; j < info.nr_disks; i++)
170
ret = ioctl (fd, GET_DISK_INFO, &disk);
172
grub_util_error (_("ioctl GET_DISK_INFO error: %s"), strerror (errno));
174
if (disk.state & (1 << MD_DISK_REMOVED))
177
if (disk.state & (1 << MD_DISK_ACTIVE))
178
devicelist[j] = grub_find_device (NULL,
179
makedev (disk.major, disk.minor));
181
devicelist[j] = NULL;
185
devicelist[j] = NULL;
192
/* Statting something on a btrfs filesystem always returns a virtual device
193
major/minor pair rather than the real underlying device, because btrfs
194
can span multiple underlying devices (and even if it's currently only
195
using a single device it can be dynamically extended onto another). We
196
can't deal with the multiple-device case yet, but in the meantime, we can
197
at least cope with the single-device case by scanning
198
/proc/self/mountinfo. */
204
for (iptr = optr = str; *iptr; optr++)
206
if (iptr[0] == '\\' && iptr[1] >= '0' && iptr[1] < '8'
207
&& iptr[2] >= '0' && iptr[2] < '8'
208
&& iptr[3] >= '0' && iptr[3] < '8')
210
*optr = (((iptr[1] - '0') << 6) | ((iptr[2] - '0') << 3)
221
grub_find_root_devices_from_btrfs (const char *dir)
224
struct btrfs_ioctl_fs_info_args fsi;
232
if (ioctl (fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
238
ret = xmalloc ((fsi.num_devices + 1) * sizeof (ret[0]));
240
for (i = 1; i <= fsi.max_id && j < fsi.num_devices; i++)
242
struct btrfs_ioctl_dev_info_args devi;
243
memset (&devi, 0, sizeof (devi));
245
if (ioctl (fd, BTRFS_IOC_DEV_INFO, &devi) < 0)
251
ret[j++] = xstrdup ((char *) devi.path);
252
if (j >= fsi.num_devices)
261
get_btrfs_fs_prefix (const char *mount_path)
263
struct btrfs_ioctl_ino_lookup_args args;
266
grub_uint64_t tree_id, inode_id;
269
fd = open (mount_path, O_RDONLY);
273
memset (&args, 0, sizeof(args));
274
args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID;
276
if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
278
tree_id = args.treeid;
280
if (fstat (fd, &st) < 0)
282
inode_id = st.st_ino;
284
while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID
285
|| inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID)
289
struct btrfs_ioctl_search_args sargs;
292
memset (&sargs, 0, sizeof(sargs));
294
if (inode_id == GRUB_BTRFS_TREE_ROOT_OBJECTID)
296
struct grub_btrfs_root_backref *br;
298
sargs.key.tree_id = 1;
299
sargs.key.min_objectid = tree_id;
300
sargs.key.max_objectid = tree_id;
302
sargs.key.min_offset = 0;
303
sargs.key.max_offset = ~0ULL;
304
sargs.key.min_transid = 0;
305
sargs.key.max_transid = ~0ULL;
306
sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
307
sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
309
sargs.key.nr_items = 1;
311
if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
314
if (sargs.key.nr_items == 0)
317
tree_id = sargs.buf[2];
318
br = (struct grub_btrfs_root_backref *) (sargs.buf + 4);
319
inode_id = br->inode_id;
325
struct grub_btrfs_inode_ref *ir;
327
sargs.key.tree_id = tree_id;
328
sargs.key.min_objectid = inode_id;
329
sargs.key.max_objectid = inode_id;
331
sargs.key.min_offset = 0;
332
sargs.key.max_offset = ~0ULL;
333
sargs.key.min_transid = 0;
334
sargs.key.max_transid = ~0ULL;
335
sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_INODE_REF;
336
sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_INODE_REF;
338
if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
341
if (sargs.key.nr_items == 0)
344
inode_id = sargs.buf[2];
346
ir = (struct grub_btrfs_inode_ref *) (sargs.buf + 4);
351
ret = xmalloc (namelen + (old ? strlen (old) : 0) + 2);
353
memcpy (ret + 1, name, namelen);
356
strcpy (ret + 1 + namelen, old);
360
ret[1+namelen] = '\0';
363
return xstrdup ("/");
369
grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
374
grub_size_t entry_len = 0, entry_max = 4;
375
struct mountinfo_entry *entries;
376
struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
384
fp = grub_util_fopen ("/proc/self/mountinfo", "r");
386
return NULL; /* fall through to other methods */
388
entries = xmalloc (entry_max * sizeof (*entries));
390
/* First, build a list of relevant visible mounts. */
391
while (getline (&buf, &len, fp) > 0)
393
struct mountinfo_entry entry;
398
if (sscanf (buf, "%d %d %u:%u %s %s%n",
399
&entry.id, &parent_entry.id, &entry.major, &entry.minor,
400
entry.enc_root, entry.enc_path, &count) < 6)
403
unescape (entry.enc_root);
404
unescape (entry.enc_path);
406
enc_path_len = strlen (entry.enc_path);
407
/* Check that enc_path is a prefix of dir. The prefix must either be
408
the entire string, or end with a slash, or be immediately followed
410
if (strncmp (dir, entry.enc_path, enc_path_len) != 0 ||
411
(enc_path_len && dir[enc_path_len - 1] != '/' &&
412
dir[enc_path_len] && dir[enc_path_len] != '/'))
415
sep = strstr (buf + count, " - ");
419
sep += sizeof (" - ") - 1;
420
if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2)
423
unescape (entry.device);
425
/* Using the mount IDs, find out where this fits in the list of
426
visible mount entries we've seen so far. There are three
427
interesting cases. Firstly, it may be inserted at the end: this is
428
the usual case of /foo/bar being mounted after /foo. Secondly, it
429
may be inserted at the start: for example, this can happen for
430
filesystems that are mounted before / and later moved under it.
431
Thirdly, it may occlude part or all of the existing filesystem
432
tree, in which case the end of the list needs to be pruned and this
433
new entry will be inserted at the end. */
434
if (entry_len >= entry_max)
437
entries = xrealloc (entries, entry_max * sizeof (*entries));
442
/* Initialise list. */
444
entries[0] = parent_entry;
449
for (i = entry_len - 1; i >= 0; i--)
451
if (entries[i].id == parent_entry.id)
453
/* Insert at end, pruning anything previously above this. */
455
entries[i + 1] = entry;
458
else if (i == 0 && entries[i].id == entry.id)
460
/* Insert at start. */
462
memmove (entries + 1, entries,
463
(entry_len - 1) * sizeof (*entries));
464
entries[0] = parent_entry;
472
/* Now scan visible mounts for the ones we're interested in. */
473
for (i = entry_len - 1; i >= 0; i--)
476
char *fs_prefix = NULL;
477
if (!*entries[i].device)
480
if (grub_strcmp (entries[i].fstype, "fuse.zfs") == 0
481
|| grub_strcmp (entries[i].fstype, "zfs") == 0)
484
slash = strchr (entries[i].device, '/');
487
ret = grub_util_find_root_devices_from_poolname (entries[i].device);
493
fs_prefix = xasprintf ("/@%s", entries[i].enc_root);
494
else if (strchr (slash + 1, '@'))
495
fs_prefix = xasprintf ("/%s%s", slash + 1, entries[i].enc_root);
497
fs_prefix = xasprintf ("/%s@%s", slash + 1,
498
entries[i].enc_root);
501
else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
503
ret = grub_find_root_devices_from_btrfs (dir);
504
fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
508
ret = xmalloc (2 * sizeof (ret[0]));
509
ret[0] = strdup (entries[i].device);
513
fs_prefix = entries[i].enc_root;
517
grub_size_t enc_root_len = strlen (fs_prefix);
518
grub_size_t enc_path_len = strlen (entries[i].enc_path);
519
grub_size_t dir_strlen = strlen (dir);
520
*relroot = xmalloc (enc_root_len +
522
ptr = grub_stpcpy (*relroot, fs_prefix);
523
if (dir_strlen > enc_path_len)
525
while (ptr > *relroot && *(ptr - 1) == '/')
527
if (dir[enc_path_len] != '/')
529
ptr = grub_stpcpy (ptr, dir + enc_path_len);
533
if (fs_prefix != entries[i].enc_root)
548
get_mdadm_uuid (const char *os_dev)
559
argv[1] = "--detail";
560
argv[2] = "--export";
564
pid = grub_util_exec_pipe (argv, &fd);
569
/* Parent. Read mdadm's output. */
570
mdadm = fdopen (fd, "r");
573
grub_util_warn (_("Unable to open stream from %s: %s"),
574
"mdadm", strerror (errno));
578
while (getline (&buf, &len, mdadm) > 0)
580
if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
582
char *name_start, *ptri, *ptro;
585
name_start = buf + sizeof ("MD_UUID=") - 1;
586
ptro = name = xmalloc (strlen (name_start) + 1);
587
for (ptri = name_start; *ptri && *ptri != '\n' && *ptri != '\r';
589
if ((*ptri >= '0' && *ptri <= '9')
590
|| (*ptri >= 'a' && *ptri <= 'f')
591
|| (*ptri >= 'A' && *ptri <= 'F'))
599
waitpid (pid, NULL, 0);
606
grub_util_is_imsm (const char *os_dev)
610
int container_seen = 0;
611
const char *dev = os_dev;
622
retry = 0; /* We'll do one more pass if device is part of container */
625
argv[1] = "--detail";
626
argv[2] = "--export";
630
pid = grub_util_exec_pipe (argv, &fd);
639
/* Parent. Read mdadm's output. */
640
mdadm = fdopen (fd, "r");
643
grub_util_warn (_("Unable to open stream from %s: %s"),
644
"mdadm", strerror (errno));
646
waitpid (pid, NULL, 0);
652
while (getline (&buf, &len, mdadm) > 0)
654
if (strncmp (buf, "MD_CONTAINER=", sizeof ("MD_CONTAINER=") - 1) == 0
658
newdev = xstrdup (buf + sizeof ("MD_CONTAINER=") - 1);
659
ptr = newdev + strlen (newdev) - 1;
660
for (; ptr >= newdev && (*ptr == '\n' || *ptr == '\r'); ptr--);
662
grub_util_info ("Container of %s is %s", dev, newdev);
664
container_seen = retry = 1;
667
if (strncmp (buf, "MD_METADATA=imsm",
668
sizeof ("MD_METADATA=imsm") - 1) == 0)
671
grub_util_info ("%s is imsm", dev);
678
waitpid (pid, NULL, 0);
688
grub_util_part_to_disk (const char *os_dev, struct stat *st,
691
char *path = xmalloc (PATH_MAX);
693
if (! S_ISBLK (st->st_mode))
696
return xstrdup (os_dev);
699
if (! realpath (os_dev, path))
702
if (strncmp ("/dev/", path, 5) == 0)
706
/* If this is an IDE disk. */
707
if (strncmp ("ide/", p, 4) == 0)
709
p = strstr (p, "part");
719
/* If this is a SCSI disk. */
720
if (strncmp ("scsi/", p, 5) == 0)
722
p = strstr (p, "part");
732
/* If this is a DAC960 disk. */
733
if (strncmp ("rd/c", p, 4) == 0)
735
/* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
746
/* If this is a Mylex AcceleRAID Array. */
747
if (strncmp ("rs/c", p, 4) == 0)
749
/* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
759
/* If this is a CCISS disk. */
760
if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
762
/* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
773
/* If this is an AOE disk. */
774
if (strncmp ("etherd/e", p, sizeof ("etherd/e") - 1) == 0)
776
/* /dev/etherd/e[0-9]+\.[0-9]+(p[0-9]+)? */
787
/* If this is a Compaq Intelligent Drive Array. */
788
if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
790
/* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
801
/* If this is an I2O disk. */
802
if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
804
/* /dev/i2o/hd[a-z]([0-9]+)? */
805
if (p[sizeof ("i2o/hda") - 1])
807
p[sizeof ("i2o/hda") - 1] = '\0';
811
/* If this is a MultiMediaCard (MMC). */
812
if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
814
/* /dev/mmcblk[0-9]+(p[0-9]+)? */
825
if (strncmp ("md", p, 2) == 0
826
&& p[2] >= '0' && p[2] <= '9')
829
while (*ptr >= '0' && *ptr <= '9')
837
if (strncmp ("nbd", p, 3) == 0
838
&& p[3] >= '0' && p[3] <= '9')
841
while (*ptr >= '0' && *ptr <= '9')
849
/* If this is an IDE, SCSI or Virtio disk. */
850
if (strncmp ("vdisk", p, 5) == 0
851
&& p[5] >= 'a' && p[5] <= 'z')
853
/* /dev/vdisk[a-z][0-9]* */
859
if ((strncmp ("hd", p, 2) == 0
860
|| strncmp ("vd", p, 2) == 0
861
|| strncmp ("sd", p, 2) == 0)
862
&& p[2] >= 'a' && p[2] <= 'z')
865
while (*pp >= 'a' && *pp <= 'z')
869
/* /dev/[hsv]d[a-z]+[0-9]* */
874
/* If this is a Xen virtual block device. */
875
if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
878
while (*pp >= 'a' && *pp <= 'z')
882
/* /dev/xvd[a-z]+[0-9]* */
887
/* If this is a FusionIO disk. */
888
if ((strncmp ("fio", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
891
while (*pp >= 'a' && *pp <= 'z')
895
/* /dev/fio[a-z]+[0-9]* */
905
grub_util_get_raid_grub_dev (const char *os_dev)
907
char *grub_dev = NULL;
908
if (os_dev[7] == '_' && os_dev[8] == 'd')
910
/* This a partitionable RAID device of the form /dev/md_dNNpMM. */
914
p = strdup (os_dev + sizeof ("/dev/md_d") - 1);
920
grub_dev = xasprintf ("md%s", p);
923
else if (os_dev[7] == '/' && os_dev[8] == 'd')
925
/* This a partitionable RAID device of the form /dev/md/dNNpMM. */
929
p = strdup (os_dev + sizeof ("/dev/md/d") - 1);
935
grub_dev = xasprintf ("md%s", p);
938
else if (os_dev[7] >= '0' && os_dev[7] <= '9')
942
p = strdup (os_dev + sizeof ("/dev/md") - 1);
948
grub_dev = xasprintf ("md%s", p);
951
else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9')
955
p = strdup (os_dev + sizeof ("/dev/md/") - 1);
961
grub_dev = xasprintf ("md%s", p);
964
else if (os_dev[7] == '/')
966
/* mdraid 1.x with a free name. */
969
p = strdup (os_dev + sizeof ("/dev/md/") - 1);
975
grub_dev = xasprintf ("md/%s", p);
979
grub_util_error (_("unknown kind of RAID device `%s'"), os_dev);
982
char *mdadm_name = get_mdadm_uuid (os_dev);
988
for (q = os_dev + strlen (os_dev) - 1; q >= os_dev
989
&& grub_isdigit (*q); q--);
991
if (q >= os_dev && *q == 'p')
994
grub_dev = xasprintf ("mduuid/%s,%s", mdadm_name, q + 1);
998
grub_dev = xasprintf ("mduuid/%s", mdadm_name);
1007
enum grub_dev_abstraction_types
1008
grub_util_get_dev_abstraction_os (const char *os_dev)
1010
#ifndef HAVE_DEVICE_MAPPER
1011
if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
1012
return GRUB_DEV_ABSTRACTION_LVM;
1015
/* Check for RAID. */
1016
if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev)
1017
&& !grub_util_is_imsm (os_dev))
1018
return GRUB_DEV_ABSTRACTION_RAID;
1019
return GRUB_DEV_ABSTRACTION_NONE;
1023
grub_util_pull_device_os (const char *os_dev,
1024
enum grub_dev_abstraction_types ab)
1028
case GRUB_DEV_ABSTRACTION_RAID:
1030
char **devicelist = grub_util_raid_getmembers (os_dev, 0);
1032
for (i = 0; devicelist[i];i++)
1034
grub_util_pull_device (devicelist[i]);
1035
free (devicelist[i]);
1046
grub_util_get_grub_dev_os (const char *os_dev)
1048
char *grub_dev = NULL;
1050
switch (grub_util_get_dev_abstraction (os_dev))
1052
/* Fallback for non-devmapper build. In devmapper-builds LVM is handled
1053
in rub_util_get_devmapper_grub_dev and this point isn't reached.
1055
case GRUB_DEV_ABSTRACTION_LVM:
1058
grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
1060
len = strlen (os_dev) - offset + 1;
1061
grub_dev = xmalloc (len + sizeof ("lvm/"));
1063
grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
1064
grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
1068
case GRUB_DEV_ABSTRACTION_RAID:
1069
grub_dev = grub_util_get_raid_grub_dev (os_dev);
1072
default: /* GRUB_DEV_ABSTRACTION_NONE */
1080
grub_make_system_path_relative_to_its_root_os (const char *path)
1084
grub_free (grub_find_root_devices_from_mountinfo (path, &bind));
1085
if (bind && bind[0])
1087
len = strlen (bind);
1088
while (len > 0 && bind[len - 1] == '/')
1090
bind[len - 1] = '\0';