]> git.proxmox.com Git - grub2.git/blame - util/deviceiter.c
Probe FusionIO devices
[grub2.git] / util / deviceiter.c
CommitLineData
06ea8f32
CW
1/* deviceiter.c - iterate over system devices */
2/*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2011 Free Software Foundation, Inc.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20#include <config.h>
21
22#include <stdio.h>
23#include <unistd.h>
24#include <string.h>
25#include <stdlib.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <limits.h>
31#include <dirent.h>
32
33#include <grub/util/misc.h>
34#include <grub/util/deviceiter.h>
35#include <grub/list.h>
36#include <grub/misc.h>
37#include <grub/emu/misc.h>
38
39#ifdef __linux__
40# if !defined(__GLIBC__) || \
41 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
42/* Maybe libc doesn't have large file support. */
43# include <linux/unistd.h> /* _llseek */
44# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
45# include <sys/ioctl.h> /* ioctl */
46# ifndef HDIO_GETGEO
47# define HDIO_GETGEO 0x0301 /* get device geometry */
48/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
49 defined. */
50struct hd_geometry
51{
52 unsigned char heads;
53 unsigned char sectors;
54 unsigned short cylinders;
55 unsigned long start;
56};
57# endif /* ! HDIO_GETGEO */
58# ifndef FLOPPY_MAJOR
59# define FLOPPY_MAJOR 2 /* the major number for floppy */
60# endif /* ! FLOPPY_MAJOR */
61# ifndef MAJOR
62# define MAJOR(dev) \
63 ({ \
64 unsigned long long __dev = (dev); \
65 (unsigned) ((__dev >> 8) & 0xfff) \
66 | ((unsigned int) (__dev >> 32) & ~0xfff); \
67 })
68# endif /* ! MAJOR */
69# ifndef MINOR
70# define MINOR(dev) \
71 ({ \
72 unsigned long long __dev = (dev); \
73 (unsigned) (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff); \
74 })
75# endif /* ! MINOR */
76# ifndef CDROM_GET_CAPABILITY
77# define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
78# endif /* ! CDROM_GET_CAPABILITY */
79# ifndef BLKGETSIZE
80# define BLKGETSIZE _IO(0x12,96) /* return device size */
81# endif /* ! BLKGETSIZE */
82
83#ifdef HAVE_DEVICE_MAPPER
84# include <libdevmapper.h>
85# pragma GCC diagnostic ignored "-Wcast-align"
86#endif
87#endif /* __linux__ */
88
89/* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
90 kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
91#if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
92# define __FreeBSD_kernel__
93#endif
94#ifdef __FreeBSD_kernel__
95 /* Obtain version of kFreeBSD headers */
96# include <osreldate.h>
97# ifndef __FreeBSD_kernel_version
98# define __FreeBSD_kernel_version __FreeBSD_version
99# endif
100
101 /* Runtime detection of kernel */
102# include <sys/utsname.h>
103static int
104get_kfreebsd_version (void)
105{
106 struct utsname uts;
107 int major;
108 int minor;
109 int v[2];
110
111 uname (&uts);
112 sscanf (uts.release, "%d.%d", &major, &minor);
113
114 if (major >= 9)
115 major = 9;
116 if (major >= 5)
117 {
118 v[0] = minor/10; v[1] = minor%10;
119 }
120 else
121 {
122 v[0] = minor%10; v[1] = minor/10;
123 }
124 return major*100000+v[0]*10000+v[1]*1000;
125}
126#endif /* __FreeBSD_kernel__ */
127
128#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
129# include <sys/ioctl.h> /* ioctl */
130# include <sys/disklabel.h>
131# include <sys/cdio.h> /* CDIOCCLRDEBUG */
132# if defined(__FreeBSD_kernel__)
133# include <sys/param.h>
134# if __FreeBSD_kernel_version >= 500040
135# include <sys/disk.h>
136# endif
137# endif /* __FreeBSD_kernel__ */
138#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
139
140#ifdef HAVE_OPENDISK
141# include <util.h>
142#endif /* HAVE_OPENDISK */
143
144#ifdef __linux__
145/* Check if we have devfs support. */
146static int
147have_devfs (void)
148{
149 struct stat st;
150 return stat ("/dev/.devfsd", &st) == 0;
151}
152#endif /* __linux__ */
153
154/* These three functions are quite different among OSes. */
155static void
156get_floppy_disk_name (char *name, int unit)
157{
158#if defined(__linux__)
159 /* GNU/Linux */
160 if (have_devfs ())
161 sprintf (name, "/dev/floppy/%d", unit);
162 else
163 sprintf (name, "/dev/fd%d", unit);
164#elif defined(__GNU__)
165 /* GNU/Hurd */
166 sprintf (name, "/dev/fd%d", unit);
167#elif defined(__FreeBSD_kernel__)
168 /* kFreeBSD */
169 if (get_kfreebsd_version () >= 400000)
170 sprintf (name, "/dev/fd%d", unit);
171 else
172 sprintf (name, "/dev/rfd%d", unit);
173#elif defined(__NetBSD__)
174 /* NetBSD */
175 /* opendisk() doesn't work for floppies. */
176 sprintf (name, "/dev/rfd%da", unit);
177#elif defined(__OpenBSD__)
178 /* OpenBSD */
179 sprintf (name, "/dev/rfd%dc", unit);
180#elif defined(__QNXNTO__)
181 /* QNX RTP */
182 sprintf (name, "/dev/fd%d", unit);
183#elif defined(__CYGWIN__)
184 /* Cygwin */
185 sprintf (name, "/dev/fd%d", unit);
186#elif defined(__MINGW32__)
187 (void) unit;
188 *name = 0;
189#else
190# warning "BIOS floppy drives cannot be guessed in your operating system."
191 /* Set NAME to a bogus string. */
192 *name = 0;
193#endif
194}
195
196static void
197get_ide_disk_name (char *name, int unit)
198{
199#if defined(__linux__)
200 /* GNU/Linux */
201 sprintf (name, "/dev/hd%c", unit + 'a');
202#elif defined(__GNU__)
203 /* GNU/Hurd */
204 sprintf (name, "/dev/hd%d", unit);
205#elif defined(__FreeBSD_kernel__)
206 /* kFreeBSD */
207 if (get_kfreebsd_version () >= 400000)
208 sprintf (name, "/dev/ad%d", unit);
209 else
210 sprintf (name, "/dev/rwd%d", unit);
211#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
212 /* NetBSD */
213 char shortname[16];
214 int fd;
215
216 sprintf (shortname, "wd%d", unit);
217 fd = opendisk (shortname, O_RDONLY, name,
218 16, /* length of NAME */
219 0 /* char device */
220 );
221 close (fd);
222#elif defined(__OpenBSD__)
223 /* OpenBSD */
224 sprintf (name, "/dev/rwd%dc", unit);
225#elif defined(__QNXNTO__)
226 /* QNX RTP */
227 /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
228 contain SCSI disks. */
229 sprintf (name, "/dev/hd%d", unit);
230#elif defined(__CYGWIN__)
231 /* Cygwin emulates all disks as /dev/sdX. */
232 (void) unit;
233 *name = 0;
234#elif defined(__MINGW32__)
235 sprintf (name, "//./PHYSICALDRIVE%d", unit);
236#else
237# warning "BIOS IDE drives cannot be guessed in your operating system."
238 /* Set NAME to a bogus string. */
239 *name = 0;
240#endif
241}
242
243static void
244get_scsi_disk_name (char *name, int unit)
245{
246#if defined(__linux__)
247 /* GNU/Linux */
248 sprintf (name, "/dev/sd%c", unit + 'a');
249#elif defined(__GNU__)
250 /* GNU/Hurd */
251 sprintf (name, "/dev/sd%d", unit);
252#elif defined(__FreeBSD_kernel__)
253 /* kFreeBSD */
254 if (get_kfreebsd_version () >= 400000)
255 sprintf (name, "/dev/da%d", unit);
256 else
257 sprintf (name, "/dev/rda%d", unit);
258#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
259 /* NetBSD */
260 char shortname[16];
261 int fd;
262
263 sprintf (shortname, "sd%d", unit);
264 fd = opendisk (shortname, O_RDONLY, name,
265 16, /* length of NAME */
266 0 /* char device */
267 );
268 close (fd);
269#elif defined(__OpenBSD__)
270 /* OpenBSD */
271 sprintf (name, "/dev/rsd%dc", unit);
272#elif defined(__QNXNTO__)
273 /* QNX RTP */
274 /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
275 disable the detection of SCSI disks here. */
276 *name = 0;
277#elif defined(__CYGWIN__)
278 /* Cygwin emulates all disks as /dev/sdX. */
279 sprintf (name, "/dev/sd%c", unit + 'a');
280#elif defined(__MINGW32__)
281 (void) unit;
282 *name = 0;
283#else
284# warning "BIOS SCSI drives cannot be guessed in your operating system."
285 /* Set NAME to a bogus string. */
286 *name = 0;
287#endif
288}
289
290#ifdef __FreeBSD_kernel__
291static void
292get_ada_disk_name (char *name, int unit)
293{
294 sprintf (name, "/dev/ada%d", unit);
295}
296
297static void
298get_ataraid_disk_name (char *name, int unit)
299{
300 sprintf (name, "/dev/ar%d", unit);
301}
302
303static void
304get_mfi_disk_name (char *name, int unit)
305{
306 sprintf (name, "/dev/mfid%d", unit);
307}
308
309static void
310get_virtio_disk_name (char *name, int unit)
311{
312 sprintf (name, "/dev/vtbd%d", unit);
313}
314
315static void
316get_xvd_disk_name (char *name, int unit)
317{
318 sprintf (name, "/dev/xbd%d", unit);
319}
320#endif
321
322#ifdef __linux__
323static void
324get_virtio_disk_name (char *name, int unit)
325{
326#ifdef __sparc__
327 sprintf (name, "/dev/vdisk%c", unit + 'a');
328#else
329 sprintf (name, "/dev/vd%c", unit + 'a');
330#endif
331}
332
333static void
334get_dac960_disk_name (char *name, int controller, int drive)
335{
336 sprintf (name, "/dev/rd/c%dd%d", controller, drive);
337}
338
339static void
340get_acceleraid_disk_name (char *name, int controller, int drive)
341{
342 sprintf (name, "/dev/rs/c%dd%d", controller, drive);
343}
344
345static void
346get_ataraid_disk_name (char *name, int unit)
347{
348 sprintf (name, "/dev/ataraid/d%c", unit + '0');
349}
350
351static void
352get_i2o_disk_name (char *name, char unit)
353{
354 sprintf (name, "/dev/i2o/hd%c", unit);
355}
356
357static void
358get_cciss_disk_name (char *name, int controller, int drive)
359{
360 sprintf (name, "/dev/cciss/c%dd%d", controller, drive);
361}
362
363static void
364get_ida_disk_name (char *name, int controller, int drive)
365{
366 sprintf (name, "/dev/ida/c%dd%d", controller, drive);
367}
368
369static void
370get_mmc_disk_name (char *name, int unit)
371{
372 sprintf (name, "/dev/mmcblk%d", unit);
373}
374
375static void
376get_xvd_disk_name (char *name, int unit)
377{
378 sprintf (name, "/dev/xvd%c", unit + 'a');
379}
380
381static void
382get_nvme_disk_name (char *name, int controller, int namespace)
383{
384 sprintf (name, "/dev/nvme%dn%d", controller, namespace);
385}
f5c06b7f
CW
386
387static void
388get_fio_disk_name (char *name, int unit)
389{
390 sprintf (name, "/dev/fio%c", unit + 'a');
391}
06ea8f32
CW
392#endif
393
394static struct seen_device
395{
396 struct seen_device *next;
397 struct seen_device **prev;
398 const char *name;
399} *seen;
400
401/* Check if DEVICE can be read. Skip any DEVICE that we have already seen.
402 If an error occurs, return zero, otherwise return non-zero. */
403static int
404check_device_readable_unique (const char *device)
405{
406 char *real_device;
407 char buf[512];
408 FILE *fp;
409 struct seen_device *seen_elt;
410
411 /* If DEVICE is empty, just return error. */
412 if (*device == 0)
413 return 0;
414
415 /* Have we seen this device already? */
416 real_device = canonicalize_file_name (device);
417 if (! real_device)
418 return 0;
419 if (grub_named_list_find (GRUB_AS_NAMED_LIST (seen), real_device))
420 {
421 grub_dprintf ("deviceiter", "Already seen %s (%s)\n",
422 device, real_device);
423 goto fail;
424 }
425
426 fp = fopen (device, "r");
427 if (! fp)
428 {
429 switch (errno)
430 {
431#ifdef ENOMEDIUM
432 case ENOMEDIUM:
433# if 0
434 /* At the moment, this finds only CDROMs, which can't be
435 read anyway, so leave it out. Code should be
436 reactivated if `removable disks' and CDROMs are
437 supported. */
438 /* Accept it, it may be inserted. */
439 return 1;
440# endif
441 break;
442#endif /* ENOMEDIUM */
443 default:
444 /* Break case and leave. */
445 break;
446 }
447 /* Error opening the device. */
448 goto fail;
449 }
450
451 /* Make sure CD-ROMs don't get assigned a BIOS disk number
452 before SCSI disks! */
453#ifdef __linux__
454# ifdef CDROM_GET_CAPABILITY
455 if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
456 goto fail;
457# else /* ! CDROM_GET_CAPABILITY */
458 /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
459 {
460 struct hd_geometry hdg;
461 struct stat st;
462
463 if (fstat (fileno (fp), &st))
464 goto fail;
465
466 /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
467 succeeds. */
468 if (S_ISBLK (st.st_mode)
469 && MAJOR (st.st_rdev) != FLOPPY_MAJOR
470 && ioctl (fileno (fp), HDIO_GETGEO, &hdg))
471 goto fail;
472 }
473# endif /* ! CDROM_GET_CAPABILITY */
474#endif /* __linux__ */
475
476#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
477# ifdef CDIOCCLRDEBUG
478 if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
479 goto fail;
480# endif /* CDIOCCLRDEBUG */
481#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
482
483 /* Attempt to read the first sector. */
484 if (fread (buf, 1, 512, fp) != 512)
485 {
486 fclose (fp);
487 goto fail;
488 }
489
490 /* Remember that we've seen this device. */
491 seen_elt = xmalloc (sizeof (*seen_elt));
492 seen_elt->name = real_device; /* steal memory */
493 grub_list_push (GRUB_AS_LIST_P (&seen), GRUB_AS_LIST (seen_elt));
494
495 fclose (fp);
496 return 1;
497
498fail:
499 free (real_device);
500 return 0;
501}
502
503static void
504clear_seen_devices (void)
505{
506 while (seen)
507 {
508 struct seen_device *seen_elt = seen;
509 seen = seen->next;
510 free (seen_elt);
511 }
512 seen = NULL;
513}
514
515#ifdef __linux__
516struct device
517{
518 char *stable;
519 char *kernel;
520};
521
522/* Sort by the kernel name for preference since that most closely matches
523 older device.map files, but sort by stable by-id names as a fallback.
524 This is because /dev/disk/by-id/ usually has a few alternative
525 identifications of devices (e.g. ATA vs. SATA).
526 check_device_readable_unique will ensure that we only get one for any
527 given disk, but sort the list so that the choice of which one we get is
528 stable. */
529static int
530compare_devices (const void *a, const void *b)
531{
532 const struct device *left = (const struct device *) a;
533 const struct device *right = (const struct device *) b;
534
535 if (left->kernel && right->kernel)
536 {
537 int ret = strcmp (left->kernel, right->kernel);
538 if (ret)
539 return ret;
540 }
541
542 return strcmp (left->stable, right->stable);
543}
544#endif /* __linux__ */
545
546void
547grub_util_iterate_devices (int (*hook) (const char *, int, void *), void *hook_data,
548 int floppy_disks)
549{
550 int i;
551
552 clear_seen_devices ();
553
554 /* Floppies. */
555 for (i = 0; i < floppy_disks; i++)
556 {
557 char name[32];
558 struct stat st;
559
560 get_floppy_disk_name (name, i);
561 if (stat (name, &st) < 0)
562 break;
563 /* In floppies, write the map, whether check_device_readable_unique
564 succeeds or not, because the user just may not insert floppies. */
565 if (hook (name, 1, hook_data))
566 goto out;
567 }
568
569#ifdef __linux__
570 {
571 DIR *dir = opendir ("/dev/disk/by-id");
572
573 if (dir)
574 {
575 struct dirent *entry;
576 struct device *devs;
577 size_t devs_len = 0, devs_max = 1024, dev;
578
579 devs = xmalloc (devs_max * sizeof (*devs));
580
581 /* Dump all the directory entries into names, resizing if
582 necessary. */
583 for (entry = readdir (dir); entry; entry = readdir (dir))
584 {
585 /* Skip current and parent directory entries. */
586 if (strcmp (entry->d_name, ".") == 0 ||
587 strcmp (entry->d_name, "..") == 0)
588 continue;
589 /* Skip partition entries. */
590 if (strstr (entry->d_name, "-part"))
591 continue;
592 /* Skip device-mapper entries; we'll handle the ones we want
593 later. */
594 if (strncmp (entry->d_name, "dm-", sizeof ("dm-") - 1) == 0)
595 continue;
596 /* Skip RAID entries; they are handled by upper layers. */
597 if (strncmp (entry->d_name, "md-", sizeof ("md-") - 1) == 0)
598 continue;
599 if (devs_len >= devs_max)
600 {
601 devs_max *= 2;
602 devs = xrealloc (devs, devs_max * sizeof (*devs));
603 }
604 devs[devs_len].stable =
605 xasprintf ("/dev/disk/by-id/%s", entry->d_name);
606 devs[devs_len].kernel =
607 canonicalize_file_name (devs[devs_len].stable);
608 devs_len++;
609 }
610
611 qsort (devs, devs_len, sizeof (*devs), &compare_devices);
612
613 closedir (dir);
614
615 /* Now add all the devices in sorted order. */
616 for (dev = 0; dev < devs_len; ++dev)
617 {
618 if (check_device_readable_unique (devs[dev].stable))
619 {
620 if (hook (devs[dev].stable, 0, hook_data))
621 goto out;
622 }
623 free (devs[dev].stable);
624 free (devs[dev].kernel);
625 }
626 free (devs);
627 }
628 }
629
630 if (have_devfs ())
631 {
632 i = 0;
633 while (1)
634 {
635 char discn[32];
636 char name[PATH_MAX];
637 struct stat st;
638
639 /* Linux creates symlinks "/dev/discs/discN" for convenience.
640 The way to number disks is the same as GRUB's. */
641 sprintf (discn, "/dev/discs/disc%d", i++);
642 if (stat (discn, &st) < 0)
643 break;
644
645 if (realpath (discn, name))
646 {
647 strcat (name, "/disc");
648 if (hook (name, 0, hook_data))
649 goto out;
650 }
651 }
652 goto out;
653 }
654#endif /* __linux__ */
655
656 /* IDE disks. */
657 for (i = 0; i < 96; i++)
658 {
659 char name[16];
660
661 get_ide_disk_name (name, i);
662 if (check_device_readable_unique (name))
663 {
664 if (hook (name, 0, hook_data))
665 goto out;
666 }
667 }
668
669#ifdef __FreeBSD_kernel__
670 /* IDE disks using ATA Direct Access driver. */
671 if (get_kfreebsd_version () >= 800000)
672 for (i = 0; i < 96; i++)
673 {
674 char name[16];
675
676 get_ada_disk_name (name, i);
677 if (check_device_readable_unique (name))
678 {
679 if (hook (name, 0, hook_data))
680 goto out;
681 }
682 }
683
684 /* ATARAID disks. */
685 for (i = 0; i < 8; i++)
686 {
687 char name[20];
688
689 get_ataraid_disk_name (name, i);
690 if (check_device_readable_unique (name))
691 {
692 if (hook (name, 0, hook_data))
693 goto out;
694 }
695 }
696
697 /* LSI MegaRAID SAS. */
698 for (i = 0; i < 32; i++)
699 {
700 char name[20];
701
702 get_mfi_disk_name (name, i);
703 if (check_device_readable_unique (name))
704 {
705 if (hook (name, 0, hook_data))
706 goto out;
707 }
708 }
709
710 /* Virtio disks. */
711 for (i = 0; i < 96; i++)
712 {
713 char name[16];
714
715 get_virtio_disk_name (name, i);
716 if (check_device_readable_unique (name))
717 {
718 if (hook (name, 0, hook_data))
719 goto out;
720 }
721 }
722
723 /* Xen virtual block devices. */
724 for (i = 0; i < 96; i++)
725 {
726 char name[16];
727
728 get_xvd_disk_name (name, i);
729 if (check_device_readable_unique (name))
730 {
731 if (hook (name, 0, hook_data))
732 goto out;
733 }
734 }
735#endif
736
737#ifdef __linux__
738 /* Virtio disks. */
739 for (i = 0; i < 26; i++)
740 {
741 char name[16];
742
743 get_virtio_disk_name (name, i);
744 if (check_device_readable_unique (name))
745 {
746 if (hook (name, 0, hook_data))
747 goto out;
748 }
749 }
750
751 /* ATARAID disks. */
752 for (i = 0; i < 8; i++)
753 {
754 char name[20];
755
756 get_ataraid_disk_name (name, i);
757 if (check_device_readable_unique (name))
758 {
759 if (hook (name, 0, hook_data))
760 goto out;
761 }
762 }
763
764 /* Xen virtual block devices. */
765 for (i = 0; i < 26; i++)
766 {
767 char name[16];
768
769 get_xvd_disk_name (name, i);
770 if (check_device_readable_unique (name))
771 {
772 if (hook (name, 0, hook_data))
773 goto out;
774 }
775 }
776#endif /* __linux__ */
777
778 /* The rest is SCSI disks. */
779 for (i = 0; i < 48; i++)
780 {
781 char name[16];
782
783 get_scsi_disk_name (name, i);
784 if (check_device_readable_unique (name))
785 {
786 if (hook (name, 0, hook_data))
787 goto out;
788 }
789 }
790
791#ifdef __linux__
792 /* This is for DAC960 - we have
793 /dev/rd/c<controller>d<logical drive>p<partition>.
794
795 DAC960 driver currently supports up to 8 controllers, 32 logical
796 drives, and 7 partitions. */
797 {
798 int controller, drive;
799
800 for (controller = 0; controller < 8; controller++)
801 {
802 for (drive = 0; drive < 15; drive++)
803 {
804 char name[24];
805
806 get_dac960_disk_name (name, controller, drive);
807 if (check_device_readable_unique (name))
808 {
809 if (hook (name, 0, hook_data))
810 goto out;
811 }
812 }
813 }
814 }
815
816 /* This is for Mylex Acceleraid - we have
817 /dev/rd/c<controller>d<logical drive>p<partition>. */
818 {
819 int controller, drive;
820
821 for (controller = 0; controller < 8; controller++)
822 {
823 for (drive = 0; drive < 15; drive++)
824 {
825 char name[24];
826
827 get_acceleraid_disk_name (name, controller, drive);
828 if (check_device_readable_unique (name))
829 {
830 if (hook (name, 0, hook_data))
831 goto out;
832 }
833 }
834 }
835 }
836
837 /* This is for CCISS - we have
838 /dev/cciss/c<controller>d<logical drive>p<partition>. */
839 {
840 int controller, drive;
841
842 for (controller = 0; controller < 3; controller++)
843 {
844 for (drive = 0; drive < 16; drive++)
845 {
846 char name[24];
847
848 get_cciss_disk_name (name, controller, drive);
849 if (check_device_readable_unique (name))
850 {
851 if (hook (name, 0, hook_data))
852 goto out;
853 }
854 }
855 }
856 }
857
858 /* This is for Compaq Intelligent Drive Array - we have
859 /dev/ida/c<controller>d<logical drive>p<partition>. */
860 {
861 int controller, drive;
862
863 for (controller = 0; controller < 3; controller++)
864 {
865 for (drive = 0; drive < 16; drive++)
866 {
867 char name[24];
868
869 get_ida_disk_name (name, controller, drive);
870 if (check_device_readable_unique (name))
871 {
872 if (hook (name, 0, hook_data))
873 goto out;
874 }
875 }
876 }
877 }
878
879 /* This is for I2O - we have /dev/i2o/hd<logical drive><partition> */
880 {
881 char unit;
882
883 for (unit = 'a'; unit < 'f'; unit++)
884 {
885 char name[24];
886
887 get_i2o_disk_name (name, unit);
888 if (check_device_readable_unique (name))
889 {
890 if (hook (name, 0, hook_data))
891 goto out;
892 }
893 }
894 }
895
896 /* MultiMediaCard (MMC). */
897 for (i = 0; i < 10; i++)
898 {
899 char name[16];
900
901 get_mmc_disk_name (name, i);
902 if (check_device_readable_unique (name))
903 {
904 if (hook (name, 0, hook_data))
905 goto out;
906 }
907 }
908
909 /* This is for standard NVMe controllers
910 /dev/nvme<controller>n<namespace>p<partition>. No idea about
911 actual limits of how many controllers a system can have and/or
912 how many namespace that would be, 10 for now. */
913 {
914 int controller, namespace;
915
916 for (controller = 0; controller < 10; controller++)
917 {
918 for (namespace = 0; namespace < 10; namespace++)
919 {
920 char name[16];
921
922 get_nvme_disk_name (name, controller, namespace);
923 if (check_device_readable_unique (name))
924 {
925 if (hook (name, 0, hook_data))
926 goto out;
927 }
928 }
929 }
930 }
931
f5c06b7f
CW
932 /* FusionIO. */
933 for (i = 0; i < 26; i++)
934 {
935 char name[16];
936
937 get_fio_disk_name (name, i);
938 if (check_device_readable_unique (name))
939 {
940 if (hook (name, 0, hook_data))
941 goto out;
942 }
943 }
944
06ea8f32
CW
945# ifdef HAVE_DEVICE_MAPPER
946# define dmraid_check(cond, ...) \
947 if (! (cond)) \
948 { \
949 grub_dprintf ("deviceiter", __VA_ARGS__); \
950 goto dmraid_end; \
951 }
952
953 /* DM-RAID. */
954 if (grub_device_mapper_supported ())
955 {
956 struct dm_tree *tree = NULL;
957 struct dm_task *task = NULL;
958 struct dm_names *names = NULL;
959 unsigned int next = 0;
960 void *top_handle, *second_handle;
961 struct dm_tree_node *root, *top, *second;
962
963 /* Build DM tree for all devices. */
964 tree = dm_tree_create ();
965 dmraid_check (tree, "dm_tree_create failed\n");
966 task = dm_task_create (DM_DEVICE_LIST);
967 dmraid_check (task, "dm_task_create failed\n");
968 dmraid_check (dm_task_run (task), "dm_task_run failed\n");
969 names = dm_task_get_names (task);
970 dmraid_check (names, "dm_task_get_names failed\n");
971 dmraid_check (names->dev, "No DM devices found\n");
972 do
973 {
974 names = (struct dm_names *) ((char *) names + next);
975 dmraid_check (dm_tree_add_dev (tree, MAJOR (names->dev),
976 MINOR (names->dev)),
977 "dm_tree_add_dev (%s) failed\n", names->name);
978 next = names->next;
979 }
980 while (next);
981
982 /* Walk the second-level children of the inverted tree; that is, devices
983 which are directly composed of non-DM devices such as hard disks.
984 This class includes all DM-RAID disks and excludes all DM-RAID
985 partitions. */
986 root = dm_tree_find_node (tree, 0, 0);
987 top_handle = NULL;
988 top = dm_tree_next_child (&top_handle, root, 1);
989 while (top)
990 {
991 second_handle = NULL;
992 second = dm_tree_next_child (&second_handle, top, 1);
993 while (second)
994 {
995 const char *node_name, *node_uuid;
996 char *name;
997
998 node_name = dm_tree_node_get_name (second);
999 dmraid_check (node_name, "dm_tree_node_get_name failed\n");
1000 node_uuid = dm_tree_node_get_uuid (second);
1001 dmraid_check (node_uuid, "dm_tree_node_get_uuid failed\n");
1002 if (strstr (node_uuid, "DMRAID-") == 0)
1003 {
1004 grub_dprintf ("deviceiter", "%s is not DM-RAID\n", node_name);
1005 goto dmraid_next_child;
1006 }
1007
1008 name = xasprintf ("/dev/mapper/%s", node_name);
1009 if (check_device_readable_unique (name))
1010 {
1011 if (hook (name, 0, hook_data))
1012 {
1013 free (name);
1014 if (task)
1015 dm_task_destroy (task);
1016 if (tree)
1017 dm_tree_free (tree);
1018 goto out;
1019 }
1020 }
1021 free (name);
1022
1023dmraid_next_child:
1024 second = dm_tree_next_child (&second_handle, top, 1);
1025 }
1026 top = dm_tree_next_child (&top_handle, root, 1);
1027 }
1028
1029dmraid_end:
1030 if (task)
1031 dm_task_destroy (task);
1032 if (tree)
1033 dm_tree_free (tree);
1034 }
1035# endif /* HAVE_DEVICE_MAPPER */
1036#endif /* __linux__ */
1037
1038out:
1039 clear_seen_devices ();
1040}