source: grub-pc/trunk/fuentes/.pc/probe_nvme.patch/grub-core/osdep/linux/getroot.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 24.4 KB
Line 
1/*
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.
4 *
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.
9 *
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.
14 *
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/>.
17 */
18
19#include <config-util.h>
20#include <config.h>
21
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <assert.h>
25#include <fcntl.h>
26#include <unistd.h>
27#include <string.h>
28#include <dirent.h>
29#include <errno.h>
30#include <error.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <stdint.h>
34#ifdef HAVE_LIMITS_H
35#include <limits.h>
36#endif
37
38#include <grub/types.h>
39#include <sys/ioctl.h>         /* ioctl */
40#include <sys/mount.h>
41
42#include <grub/util/misc.h>
43
44#include <grub/mm.h>
45#include <grub/misc.h>
46#include <grub/emu/misc.h>
47#include <grub/emu/hostdisk.h>
48#include <grub/emu/getroot.h>
49
50#include <sys/wait.h>
51
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>
59
60#define LVM_DEV_MAPPER_STRING "/dev/mapper/"
61
62/* Defines taken from btrfs/ioctl.h.  */
63
64struct btrfs_ioctl_dev_info_args
65{
66  grub_uint64_t devid;
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];
72};
73
74struct btrfs_ioctl_fs_info_args
75{
76  grub_uint64_t max_id;
77  grub_uint64_t num_devices;
78  grub_uint8_t fsid[16];
79  grub_uint64_t reserved[124];
80};
81
82struct btrfs_ioctl_ino_lookup_args
83{
84  grub_uint64_t treeid;
85  grub_uint64_t objectid;
86  char name[4080];
87};
88
89struct btrfs_ioctl_search_key
90{
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];
102};
103
104struct 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)];
108};
109
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)
118
119static int
120grub_util_is_imsm (const char *os_dev);
121
122
123#define ESCAPED_PATH_MAX (4 * PATH_MAX)
124struct mountinfo_entry
125{
126  int id;
127  int major, minor;
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];
130};
131
132static char **
133grub_util_raid_getmembers (const char *name, int bootable)
134{
135  int fd, ret, i, j;
136  char **devicelist;
137  mdu_version_t version;
138  mdu_array_info_t info;
139  mdu_disk_info_t disk;
140
141  fd = open (name, O_RDONLY);
142
143  if (fd == -1)
144    grub_util_error (_("cannot open `%s': %s"), name, strerror (errno));
145
146  ret = ioctl (fd, RAID_VERSION, &version);
147  if (ret != 0)
148    grub_util_error (_("ioctl RAID_VERSION error: %s"), strerror (errno));
149
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);
156
157  if (bootable && (version.major != 0 || version.minor != 90))
158    grub_util_error (_("unsupported RAID version: %d.%d"),
159                     version.major, version.minor);
160
161  ret = ioctl (fd, GET_ARRAY_INFO, &info);
162  if (ret != 0)
163    grub_util_error (_("ioctl GET_ARRAY_INFO error: %s"), strerror (errno));
164
165  devicelist = xmalloc ((info.nr_disks + 1) * sizeof (char *));
166
167  for (i = 0, j = 0; j < info.nr_disks; i++)
168    {
169      disk.number = i;
170      ret = ioctl (fd, GET_DISK_INFO, &disk);
171      if (ret != 0)
172        grub_util_error (_("ioctl GET_DISK_INFO error: %s"), strerror (errno));
173     
174      if (disk.state & (1 << MD_DISK_REMOVED))
175        continue;
176
177      if (disk.state & (1 << MD_DISK_ACTIVE))
178        devicelist[j] = grub_find_device (NULL,
179                                          makedev (disk.major, disk.minor));
180      else
181        devicelist[j] = NULL;
182      j++;
183    }
184
185  devicelist[j] = NULL;
186
187  close (fd);
188
189  return devicelist;
190}
191
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.  */
199static void
200unescape (char *str)
201{
202  char *optr;
203  const char *iptr;
204  for (iptr = optr = str; *iptr; optr++)
205    {
206      if (iptr[0] == '\\' && iptr[1] >= '0' && iptr[1] < '8'
207          && iptr[2] >= '0' && iptr[2] < '8'
208          && iptr[3] >= '0' && iptr[3] < '8')
209        {
210          *optr = (((iptr[1] - '0') << 6) | ((iptr[2] - '0') << 3)
211                   | (iptr[3] - '0'));
212          iptr += 4;
213        }
214      else
215        *optr = *iptr++;
216    }
217  *optr = 0;
218}
219
220static char **
221grub_find_root_devices_from_btrfs (const char *dir)
222{
223  int fd;
224  struct btrfs_ioctl_fs_info_args fsi;
225  int i, j = 0;
226  char **ret;
227
228  fd = open (dir, 0);
229  if (!fd)
230    return NULL;
231
232  if (ioctl (fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
233    {
234      close (fd);
235      return NULL;
236    }
237
238  ret = xmalloc ((fsi.num_devices + 1) * sizeof (ret[0]));
239
240  for (i = 1; i <= fsi.max_id && j < fsi.num_devices; i++)
241    {
242      struct btrfs_ioctl_dev_info_args devi;
243      memset (&devi, 0, sizeof (devi));
244      devi.devid = i;
245      if (ioctl (fd, BTRFS_IOC_DEV_INFO, &devi) < 0)
246        {
247          close (fd);
248          free (ret);
249          return NULL;
250        }
251      ret[j++] = xstrdup ((char *) devi.path);
252      if (j >= fsi.num_devices)
253        break;
254    }
255  close (fd);
256  ret[j] = 0;
257  return ret;
258}
259
260static char *
261get_btrfs_fs_prefix (const char *mount_path)
262{
263  struct btrfs_ioctl_ino_lookup_args args;
264  struct stat st;
265  int fd;
266  grub_uint64_t tree_id, inode_id;
267  char *ret = NULL;
268
269  fd = open (mount_path, O_RDONLY);
270         
271  if (fd < 0)
272    return NULL;
273  memset (&args, 0, sizeof(args));
274  args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID;
275 
276  if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
277    return NULL;
278  tree_id = args.treeid;
279
280  if (fstat (fd, &st) < 0)
281    return NULL;
282  inode_id = st.st_ino;
283
284  while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID
285         || inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID)
286    {
287      const char *name;
288      size_t namelen;
289      struct btrfs_ioctl_search_args sargs;
290      char *old;
291
292      memset (&sargs, 0, sizeof(sargs));
293
294      if (inode_id == GRUB_BTRFS_TREE_ROOT_OBJECTID)
295        {
296          struct grub_btrfs_root_backref *br;
297
298          sargs.key.tree_id = 1;
299          sargs.key.min_objectid = tree_id;
300          sargs.key.max_objectid = tree_id;
301
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;
308
309          sargs.key.nr_items = 1;
310
311          if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
312            return NULL;
313
314          if (sargs.key.nr_items == 0)
315            return NULL;
316     
317          tree_id = sargs.buf[2];
318          br = (struct grub_btrfs_root_backref *) (sargs.buf + 4);
319          inode_id = br->inode_id;
320          name = br->name;
321          namelen = br->n;
322        }
323      else
324        {
325          struct grub_btrfs_inode_ref *ir;
326
327          sargs.key.tree_id = tree_id;
328          sargs.key.min_objectid = inode_id;
329          sargs.key.max_objectid = inode_id;
330
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;
337
338          if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
339            return NULL;
340
341          if (sargs.key.nr_items == 0)
342            return NULL;
343
344          inode_id = sargs.buf[2];
345
346          ir = (struct grub_btrfs_inode_ref *) (sargs.buf + 4);
347          name = ir->name;
348          namelen = ir->n;
349        }
350      old = ret;
351      ret = xmalloc (namelen + (old ? strlen (old) : 0) + 2);
352      ret[0] = '/';
353      memcpy (ret + 1, name, namelen);
354      if (old)
355        {
356          strcpy (ret + 1 + namelen, old);
357          free (old);
358        }
359      else
360        ret[1+namelen] = '\0';
361    }
362  if (!ret)
363    return xstrdup ("/");
364  return ret;
365}
366
367
368char **
369grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
370{
371  FILE *fp;
372  char *buf = NULL;
373  size_t len = 0;
374  grub_size_t entry_len = 0, entry_max = 4;
375  struct mountinfo_entry *entries;
376  struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
377  int i;
378
379  if (! *dir)
380    dir = "/";
381  if (relroot)
382    *relroot = NULL;
383
384  fp = grub_util_fopen ("/proc/self/mountinfo", "r");
385  if (! fp)
386    return NULL; /* fall through to other methods */
387
388  entries = xmalloc (entry_max * sizeof (*entries));
389
390  /* First, build a list of relevant visible mounts.  */
391  while (getline (&buf, &len, fp) > 0)
392    {
393      struct mountinfo_entry entry;
394      int count;
395      size_t enc_path_len;
396      const char *sep;
397
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)
401        continue;
402
403      unescape (entry.enc_root);
404      unescape (entry.enc_path);
405
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
409         by a slash.  */
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] != '/'))
413        continue;
414
415      sep = strstr (buf + count, " - ");
416      if (!sep)
417        continue;
418
419      sep += sizeof (" - ") - 1;
420      if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2)
421        continue;
422
423      unescape (entry.device);
424
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)
435        {
436          entry_max <<= 1;
437          entries = xrealloc (entries, entry_max * sizeof (*entries));
438        }
439
440      if (!entry_len)
441        {
442          /* Initialise list.  */
443          entry_len = 2;
444          entries[0] = parent_entry;
445          entries[1] = entry;
446        }
447      else
448        {
449          for (i = entry_len - 1; i >= 0; i--)
450            {
451              if (entries[i].id == parent_entry.id)
452                {
453                  /* Insert at end, pruning anything previously above this.  */
454                  entry_len = i + 2;
455                  entries[i + 1] = entry;
456                  break;
457                }
458              else if (i == 0 && entries[i].id == entry.id)
459                {
460                  /* Insert at start.  */
461                  entry_len++;
462                  memmove (entries + 1, entries,
463                           (entry_len - 1) * sizeof (*entries));
464                  entries[0] = parent_entry;
465                  entries[1] = entry;
466                  break;
467                }
468            }
469        }
470    }
471
472  /* Now scan visible mounts for the ones we're interested in.  */
473  for (i = entry_len - 1; i >= 0; i--)
474    {
475      char **ret = NULL;
476      char *fs_prefix = NULL;
477      if (!*entries[i].device)
478        continue;
479
480      if (grub_strcmp (entries[i].fstype, "fuse.zfs") == 0
481          || grub_strcmp (entries[i].fstype, "zfs") == 0)
482        {
483          char *slash;
484          slash = strchr (entries[i].device, '/');
485          if (slash)
486            *slash = 0;
487          ret = grub_util_find_root_devices_from_poolname (entries[i].device);
488          if (slash)
489            *slash = '/';
490          if (relroot)
491            {
492              if (!slash)
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);
496              else
497                fs_prefix = xasprintf ("/%s@%s", slash + 1,
498                                       entries[i].enc_root);
499            }
500        }
501      else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
502        {
503          ret = grub_find_root_devices_from_btrfs (dir);
504          fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
505        }
506      if (!ret)
507        {
508          ret = xmalloc (2 * sizeof (ret[0]));
509          ret[0] = strdup (entries[i].device);
510          ret[1] = 0;
511        }
512      if (!fs_prefix)
513        fs_prefix = entries[i].enc_root;
514      if (relroot)
515        {
516          char *ptr;
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 +
521                              2 + dir_strlen);
522          ptr = grub_stpcpy (*relroot, fs_prefix);
523          if (dir_strlen > enc_path_len)
524            {
525              while (ptr > *relroot && *(ptr - 1) == '/')
526                ptr--;
527              if (dir[enc_path_len] != '/')
528                *ptr++ = '/';
529              ptr = grub_stpcpy (ptr, dir + enc_path_len);
530            }
531          *ptr = 0;
532        }
533      if (fs_prefix != entries[i].enc_root)
534        free (fs_prefix);
535      free (buf);
536      free (entries);
537      fclose (fp);
538      return ret;
539    }
540
541  free (buf);
542  free (entries);
543  fclose (fp);
544  return NULL;
545}
546
547static char *
548get_mdadm_uuid (const char *os_dev)
549{
550  const char *argv[5];
551  int fd;
552  pid_t pid;
553  FILE *mdadm;
554  char *buf = NULL;
555  size_t len = 0;
556  char *name = NULL;
557
558  argv[0] = "mdadm";
559  argv[1] = "--detail";
560  argv[2] = "--export";
561  argv[3] = os_dev;
562  argv[4] = NULL;
563
564  pid = grub_util_exec_pipe (argv, &fd);
565
566  if (!pid)
567    return NULL;
568
569  /* Parent.  Read mdadm's output.  */
570  mdadm = fdopen (fd, "r");
571  if (! mdadm)
572    {
573      grub_util_warn (_("Unable to open stream from %s: %s"),
574                      "mdadm", strerror (errno));
575      goto out;
576    }
577
578  while (getline (&buf, &len, mdadm) > 0)
579    {
580      if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
581        {
582          char *name_start, *ptri, *ptro;
583         
584          free (name);
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';
588               ptri++)
589            if ((*ptri >= '0' && *ptri <= '9')
590                || (*ptri >= 'a' && *ptri <= 'f')
591                || (*ptri >= 'A' && *ptri <= 'F'))
592              *ptro++ = *ptri;
593          *ptro = 0;
594        }
595    }
596
597out:
598  close (fd);
599  waitpid (pid, NULL, 0);
600  free (buf);
601
602  return name;
603}
604
605static int
606grub_util_is_imsm (const char *os_dev)
607{
608  int retry;
609  int is_imsm = 0;
610  int container_seen = 0;
611  const char *dev = os_dev;
612
613  do
614    {
615      const char *argv[5];
616      int fd;
617      pid_t pid;
618      FILE *mdadm;
619      char *buf = NULL;
620      size_t len = 0;
621
622      retry = 0; /* We'll do one more pass if device is part of container */
623
624      argv[0] = "mdadm";
625      argv[1] = "--detail";
626      argv[2] = "--export";
627      argv[3] = dev;
628      argv[4] = NULL;
629
630      pid = grub_util_exec_pipe (argv, &fd);
631
632      if (!pid)
633        {
634          if (dev != os_dev)
635            free ((void *) dev);
636          return 0;
637        }
638
639      /* Parent.  Read mdadm's output.  */
640      mdadm = fdopen (fd, "r");
641      if (! mdadm)
642        {
643          grub_util_warn (_("Unable to open stream from %s: %s"),
644                          "mdadm", strerror (errno));
645          close (fd);
646          waitpid (pid, NULL, 0);
647          if (dev != os_dev)
648            free ((void *) dev);
649          return 0;
650        }
651
652      while (getline (&buf, &len, mdadm) > 0)
653        {
654          if (strncmp (buf, "MD_CONTAINER=", sizeof ("MD_CONTAINER=") - 1) == 0
655              && !container_seen)
656            {
657              char *newdev, *ptr;
658              newdev = xstrdup (buf + sizeof ("MD_CONTAINER=") - 1);
659              ptr = newdev + strlen (newdev) - 1;
660              for (; ptr >= newdev && (*ptr == '\n' || *ptr == '\r'); ptr--);
661              ptr[1] = 0;
662              grub_util_info ("Container of %s is %s", dev, newdev);
663              dev = newdev;
664              container_seen = retry = 1;
665              break;
666            }
667          if (strncmp (buf, "MD_METADATA=imsm",
668                       sizeof ("MD_METADATA=imsm") - 1) == 0)
669            {
670              is_imsm = 1;
671              grub_util_info ("%s is imsm", dev);             
672              break;
673            }
674        }
675
676      free (buf);
677      close (fd);
678      waitpid (pid, NULL, 0);
679    }
680  while (retry);
681
682  if (dev != os_dev)
683    free ((void *) dev);
684  return is_imsm;
685}
686
687char *
688grub_util_part_to_disk (const char *os_dev, struct stat *st,
689                        int *is_part)
690{
691  char *path = xmalloc (PATH_MAX);
692
693  if (! S_ISBLK (st->st_mode))
694    {
695      *is_part = 0;
696      return xstrdup (os_dev);
697    }
698
699  if (! realpath (os_dev, path))
700    return NULL;
701
702  if (strncmp ("/dev/", path, 5) == 0)
703    {
704      char *p = path + 5;
705
706      /* If this is an IDE disk.  */
707      if (strncmp ("ide/", p, 4) == 0)
708        {
709          p = strstr (p, "part");
710          if (p)
711            {
712              *is_part = 1;
713              strcpy (p, "disc");
714            }
715
716          return path;
717        }
718
719      /* If this is a SCSI disk.  */
720      if (strncmp ("scsi/", p, 5) == 0)
721        {
722          p = strstr (p, "part");
723          if (p)
724            {
725              *is_part = 1;
726              strcpy (p, "disc");
727            }
728
729          return path;
730        }
731
732      /* If this is a DAC960 disk.  */
733      if (strncmp ("rd/c", p, 4) == 0)
734        {
735          /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
736          p = strchr (p, 'p');
737          if (p)
738            {
739              *is_part = 1;
740              *p = '\0';
741            }
742
743          return path;
744        }
745
746      /* If this is a Mylex AcceleRAID Array.  */
747      if (strncmp ("rs/c", p, 4) == 0)
748        {
749          /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
750          p = strchr (p, 'p');
751          if (p)
752            {
753              *is_part = 1;
754              *p = '\0';
755            }
756
757          return path;
758        }
759      /* If this is a CCISS disk.  */
760      if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
761        {
762          /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
763          p = strchr (p, 'p');
764          if (p)
765            {
766              *is_part = 1;
767              *p = '\0';
768            }
769
770          return path;
771        }
772
773      /* If this is an AOE disk.  */
774      if (strncmp ("etherd/e", p, sizeof ("etherd/e") - 1) == 0)
775        {
776          /* /dev/etherd/e[0-9]+\.[0-9]+(p[0-9]+)? */
777          p = strchr (p, 'p');
778          if (p)
779            {
780              *is_part = 1;
781              *p = '\0';
782            }
783
784          return path;
785        }
786
787      /* If this is a Compaq Intelligent Drive Array.  */
788      if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
789        {
790          /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
791          p = strchr (p, 'p');
792          if (p)
793            {
794              *is_part = 1;
795              *p = '\0';
796            }
797
798          return path;
799        }
800
801      /* If this is an I2O disk.  */
802      if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
803        {
804          /* /dev/i2o/hd[a-z]([0-9]+)? */
805          if (p[sizeof ("i2o/hda") - 1])
806            *is_part = 1;
807          p[sizeof ("i2o/hda") - 1] = '\0';
808          return path;
809        }
810
811      /* If this is a MultiMediaCard (MMC).  */
812      if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
813        {
814          /* /dev/mmcblk[0-9]+(p[0-9]+)? */
815          p = strchr (p, 'p');
816          if (p)
817            {
818              *is_part = 1;
819              *p = '\0';
820            }
821
822          return path;
823        }
824
825      if (strncmp ("md", p, 2) == 0
826          && p[2] >= '0' && p[2] <= '9')
827        {
828          char *ptr = p + 2;
829          while (*ptr >= '0' && *ptr <= '9')
830            ptr++;
831          if (*ptr)
832            *is_part = 1;
833          *ptr = 0;
834          return path;
835        }
836
837      if (strncmp ("nbd", p, 3) == 0
838          && p[3] >= '0' && p[3] <= '9')
839        {
840          char *ptr = p + 3;
841          while (*ptr >= '0' && *ptr <= '9')
842            ptr++;
843          if (*ptr)
844            *is_part = 1;
845          *ptr = 0;
846          return path;
847        }
848
849      /* If this is an IDE, SCSI or Virtio disk.  */
850      if (strncmp ("vdisk", p, 5) == 0
851          && p[5] >= 'a' && p[5] <= 'z')
852        {
853          /* /dev/vdisk[a-z][0-9]* */
854          if (p[6])
855            *is_part = 1;
856          p[6] = '\0';
857          return path;
858        }
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')
863        {
864          char *pp = p + 2;
865          while (*pp >= 'a' && *pp <= 'z')
866            pp++;
867          if (*pp)
868            *is_part = 1;
869          /* /dev/[hsv]d[a-z]+[0-9]* */
870          *pp = '\0';
871          return path;
872        }
873
874      /* If this is a Xen virtual block device.  */
875      if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
876        {
877          char *pp = p + 3;
878          while (*pp >= 'a' && *pp <= 'z')
879            pp++;
880          if (*pp)
881            *is_part = 1;
882          /* /dev/xvd[a-z]+[0-9]* */
883          *pp = '\0';
884          return path;
885        }
886
887      /* If this is a FusionIO disk.  */
888      if ((strncmp ("fio", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
889        {
890          char *pp = p + 3;
891          while (*pp >= 'a' && *pp <= 'z')
892            pp++;
893          if (*pp)
894            *is_part = 1;
895          /* /dev/fio[a-z]+[0-9]* */
896          *pp = '\0';
897          return path;
898        }
899    }
900
901  return path;
902}
903
904static char *
905grub_util_get_raid_grub_dev (const char *os_dev)
906{
907  char *grub_dev = NULL;
908  if (os_dev[7] == '_' && os_dev[8] == 'd')
909    {
910      /* This a partitionable RAID device of the form /dev/md_dNNpMM. */
911
912      char *p, *q;
913
914      p = strdup (os_dev + sizeof ("/dev/md_d") - 1);
915
916      q = strchr (p, 'p');
917      if (q)
918        *q = ',';
919
920      grub_dev = xasprintf ("md%s", p);
921      free (p);
922    }
923  else if (os_dev[7] == '/' && os_dev[8] == 'd')
924    {
925      /* This a partitionable RAID device of the form /dev/md/dNNpMM. */
926
927      char *p, *q;
928
929      p = strdup (os_dev + sizeof ("/dev/md/d") - 1);
930
931      q = strchr (p, 'p');
932      if (q)
933        *q = ',';
934
935      grub_dev = xasprintf ("md%s", p);
936      free (p);
937    }
938  else if (os_dev[7] >= '0' && os_dev[7] <= '9')
939    {
940      char *p , *q;
941
942      p = strdup (os_dev + sizeof ("/dev/md") - 1);
943
944      q = strchr (p, 'p');
945      if (q)
946        *q = ',';
947
948      grub_dev = xasprintf ("md%s", p);
949      free (p);
950    }
951  else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9')
952    {
953      char *p , *q;
954
955      p = strdup (os_dev + sizeof ("/dev/md/") - 1);
956
957      q = strchr (p, 'p');
958      if (q)
959        *q = ',';
960
961      grub_dev = xasprintf ("md%s", p);
962      free (p);
963    }
964  else if (os_dev[7] == '/')
965    {
966      /* mdraid 1.x with a free name.  */
967      char *p , *q;
968
969      p = strdup (os_dev + sizeof ("/dev/md/") - 1);
970
971      q = strchr (p, 'p');
972      if (q)
973        *q = ',';
974
975      grub_dev = xasprintf ("md/%s", p);
976      free (p);
977    }
978  else
979    grub_util_error (_("unknown kind of RAID device `%s'"), os_dev);
980
981  {
982    char *mdadm_name = get_mdadm_uuid (os_dev);
983
984    if (mdadm_name)
985      {
986        const char *q;
987
988        for (q = os_dev + strlen (os_dev) - 1; q >= os_dev
989               && grub_isdigit (*q); q--);
990
991        if (q >= os_dev && *q == 'p')
992          {
993            free (grub_dev);
994            grub_dev = xasprintf ("mduuid/%s,%s", mdadm_name, q + 1);
995            goto done;
996          }
997        free (grub_dev);
998        grub_dev = xasprintf ("mduuid/%s", mdadm_name);
999
1000      done:
1001        free (mdadm_name);
1002      }
1003  }
1004  return grub_dev;
1005}
1006
1007enum grub_dev_abstraction_types
1008grub_util_get_dev_abstraction_os (const char *os_dev)
1009{
1010#ifndef HAVE_DEVICE_MAPPER
1011  if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
1012    return GRUB_DEV_ABSTRACTION_LVM;
1013#endif
1014
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;
1020}
1021
1022int
1023grub_util_pull_device_os (const char *os_dev,
1024                          enum grub_dev_abstraction_types ab)
1025{
1026  switch (ab)
1027    {
1028    case GRUB_DEV_ABSTRACTION_RAID:
1029      {
1030        char **devicelist = grub_util_raid_getmembers (os_dev, 0);
1031        int i;
1032        for (i = 0; devicelist[i];i++)
1033          {
1034            grub_util_pull_device (devicelist[i]);
1035            free (devicelist[i]);
1036          }
1037        free (devicelist);
1038      }
1039      return 1;
1040    default:
1041      return 0;
1042    }
1043}
1044
1045char *
1046grub_util_get_grub_dev_os (const char *os_dev)
1047{
1048  char *grub_dev = NULL;
1049
1050  switch (grub_util_get_dev_abstraction (os_dev))
1051    {
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.
1054       */
1055    case GRUB_DEV_ABSTRACTION_LVM:
1056      {
1057        unsigned short len;
1058        grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
1059
1060        len = strlen (os_dev) - offset + 1;
1061        grub_dev = xmalloc (len + sizeof ("lvm/"));
1062
1063        grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
1064        grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
1065      }
1066      break;
1067
1068    case GRUB_DEV_ABSTRACTION_RAID:
1069      grub_dev = grub_util_get_raid_grub_dev (os_dev);
1070      break;
1071
1072    default:  /* GRUB_DEV_ABSTRACTION_NONE */
1073      break;
1074    }
1075
1076  return grub_dev;
1077}
1078
1079char *
1080grub_make_system_path_relative_to_its_root_os (const char *path)
1081{
1082  char *bind = NULL;
1083  grub_size_t len;
1084  grub_free (grub_find_root_devices_from_mountinfo (path, &bind));
1085  if (bind && bind[0])
1086    {
1087      len = strlen (bind);
1088      while (len > 0 && bind[len - 1] == '/')
1089        {
1090          bind[len - 1] = '\0';
1091          len--;
1092        }
1093      return bind;
1094    }
1095  grub_free (bind);
1096  return NULL;
1097}
Note: See TracBrowser for help on using the repository browser.