GRUB-1.98 changes
[grub2/jjazz.git] / util / deviceiter.c
blobb0a9e1388721f832295124f919d413bd9949fa70
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 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.h>
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>
32 #include <grub/util/misc.h>
33 #include <grub/util/deviceiter.h>
35 #ifdef __linux__
36 # if !defined(__GLIBC__) || \
37 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
38 /* Maybe libc doesn't have large file support. */
39 # include <linux/unistd.h> /* _llseek */
40 # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
41 # include <sys/ioctl.h> /* ioctl */
42 # ifndef HDIO_GETGEO
43 # define HDIO_GETGEO 0x0301 /* get device geometry */
44 /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
45 defined. */
46 struct hd_geometry
48 unsigned char heads;
49 unsigned char sectors;
50 unsigned short cylinders;
51 unsigned long start;
53 # endif /* ! HDIO_GETGEO */
54 # ifndef FLOPPY_MAJOR
55 # define FLOPPY_MAJOR 2 /* the major number for floppy */
56 # endif /* ! FLOPPY_MAJOR */
57 # ifndef MAJOR
58 # define MAJOR(dev) \
59 ({ \
60 unsigned long long __dev = (dev); \
61 (unsigned) ((__dev >> 8) & 0xfff) \
62 | ((unsigned int) (__dev >> 32) & ~0xfff); \
64 # endif /* ! MAJOR */
65 # ifndef CDROM_GET_CAPABILITY
66 # define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
67 # endif /* ! CDROM_GET_CAPABILITY */
68 # ifndef BLKGETSIZE
69 # define BLKGETSIZE _IO(0x12,96) /* return device size */
70 # endif /* ! BLKGETSIZE */
71 #endif /* __linux__ */
73 /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
74 kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
75 #if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
76 # define __FreeBSD_kernel__
77 #endif
78 #ifdef __FreeBSD_kernel__
79 /* Obtain version of kFreeBSD headers */
80 # include <osreldate.h>
81 # ifndef __FreeBSD_kernel_version
82 # define __FreeBSD_kernel_version __FreeBSD_version
83 # endif
85 /* Runtime detection of kernel */
86 # include <sys/utsname.h>
87 int
88 get_kfreebsd_version (void)
90 struct utsname uts;
91 int major;
92 int minor;
93 int v[2];
95 uname (&uts);
96 sscanf (uts.release, "%d.%d", &major, &minor);
98 if (major >= 9)
99 major = 9;
100 if (major >= 5)
102 v[0] = minor/10; v[1] = minor%10;
104 else
106 v[0] = minor%10; v[1] = minor/10;
108 return major*100000+v[0]*10000+v[1]*1000;
110 #endif /* __FreeBSD_kernel__ */
112 #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
113 # include <sys/ioctl.h> /* ioctl */
114 # include <sys/disklabel.h>
115 # include <sys/cdio.h> /* CDIOCCLRDEBUG */
116 # if defined(__FreeBSD_kernel__)
117 # include <sys/param.h>
118 # if __FreeBSD_kernel_version >= 500040
119 # include <sys/disk.h>
120 # endif
121 # endif /* __FreeBSD_kernel__ */
122 #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
124 #ifdef HAVE_OPENDISK
125 # include <util.h>
126 #endif /* HAVE_OPENDISK */
128 #ifdef __linux__
129 /* Check if we have devfs support. */
130 static int
131 have_devfs (void)
133 struct stat st;
134 return stat ("/dev/.devfsd", &st) == 0;
136 #endif /* __linux__ */
138 /* These three functions are quite different among OSes. */
139 static void
140 get_floppy_disk_name (char *name, int unit)
142 #if defined(__linux__)
143 /* GNU/Linux */
144 if (have_devfs ())
145 sprintf (name, "/dev/floppy/%d", unit);
146 else
147 sprintf (name, "/dev/fd%d", unit);
148 #elif defined(__GNU__)
149 /* GNU/Hurd */
150 sprintf (name, "/dev/fd%d", unit);
151 #elif defined(__FreeBSD_kernel__)
152 /* kFreeBSD */
153 if (get_kfreebsd_version () >= 400000)
154 sprintf (name, "/dev/fd%d", unit);
155 else
156 sprintf (name, "/dev/rfd%d", unit);
157 #elif defined(__NetBSD__)
158 /* NetBSD */
159 /* opendisk() doesn't work for floppies. */
160 sprintf (name, "/dev/rfd%da", unit);
161 #elif defined(__OpenBSD__)
162 /* OpenBSD */
163 sprintf (name, "/dev/rfd%dc", unit);
164 #elif defined(__QNXNTO__)
165 /* QNX RTP */
166 sprintf (name, "/dev/fd%d", unit);
167 #elif defined(__CYGWIN__)
168 /* Cygwin */
169 sprintf (name, "/dev/fd%d", unit);
170 #elif defined(__MINGW32__)
171 (void) unit;
172 *name = 0;
173 #else
174 # warning "BIOS floppy drives cannot be guessed in your operating system."
175 /* Set NAME to a bogus string. */
176 *name = 0;
177 #endif
180 static void
181 get_ide_disk_name (char *name, int unit)
183 #if defined(__linux__)
184 /* GNU/Linux */
185 sprintf (name, "/dev/hd%c", unit + 'a');
186 #elif defined(__GNU__)
187 /* GNU/Hurd */
188 sprintf (name, "/dev/hd%d", unit);
189 #elif defined(__FreeBSD_kernel__)
190 /* kFreeBSD */
191 if (get_kfreebsd_version () >= 400000)
192 sprintf (name, "/dev/ad%d", unit);
193 else
194 sprintf (name, "/dev/rwd%d", unit);
195 #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
196 /* NetBSD */
197 char shortname[16];
198 int fd;
200 sprintf (shortname, "wd%d", unit);
201 fd = opendisk (shortname, O_RDONLY, name,
202 16, /* length of NAME */
203 0 /* char device */
205 close (fd);
206 #elif defined(__OpenBSD__)
207 /* OpenBSD */
208 sprintf (name, "/dev/rwd%dc", unit);
209 #elif defined(__QNXNTO__)
210 /* QNX RTP */
211 /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
212 contain SCSI disks. */
213 sprintf (name, "/dev/hd%d", unit);
214 #elif defined(__CYGWIN__)
215 /* Cygwin emulates all disks as /dev/sdX. */
216 (void) unit;
217 *name = 0;
218 #elif defined(__MINGW32__)
219 sprintf (name, "//./PHYSICALDRIVE%d", unit);
220 #else
221 # warning "BIOS IDE drives cannot be guessed in your operating system."
222 /* Set NAME to a bogus string. */
223 *name = 0;
224 #endif
227 static void
228 get_scsi_disk_name (char *name, int unit)
230 #if defined(__linux__)
231 /* GNU/Linux */
232 sprintf (name, "/dev/sd%c", unit + 'a');
233 #elif defined(__GNU__)
234 /* GNU/Hurd */
235 sprintf (name, "/dev/sd%d", unit);
236 #elif defined(__FreeBSD_kernel__)
237 /* kFreeBSD */
238 if (get_kfreebsd_version () >= 400000)
239 sprintf (name, "/dev/da%d", unit);
240 else
241 sprintf (name, "/dev/rda%d", unit);
242 #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
243 /* NetBSD */
244 char shortname[16];
245 int fd;
247 sprintf (shortname, "sd%d", unit);
248 fd = opendisk (shortname, O_RDONLY, name,
249 16, /* length of NAME */
250 0 /* char device */
252 close (fd);
253 #elif defined(__OpenBSD__)
254 /* OpenBSD */
255 sprintf (name, "/dev/rsd%dc", unit);
256 #elif defined(__QNXNTO__)
257 /* QNX RTP */
258 /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
259 disable the detection of SCSI disks here. */
260 *name = 0;
261 #elif defined(__CYGWIN__)
262 /* Cygwin emulates all disks as /dev/sdX. */
263 sprintf (name, "/dev/sd%c", unit + 'a');
264 #elif defined(__MINGW32__)
265 (void) unit;
266 *name = 0;
267 #else
268 # warning "BIOS SCSI drives cannot be guessed in your operating system."
269 /* Set NAME to a bogus string. */
270 *name = 0;
271 #endif
274 #ifdef __linux__
275 static void
276 get_virtio_disk_name (char *name, int unit)
278 #ifdef __sparc__
279 sprintf (name, "/dev/vdisk%c", unit + 'a');
280 #else
281 sprintf (name, "/dev/vd%c", unit + 'a');
282 #endif
285 static void
286 get_dac960_disk_name (char *name, int controller, int drive)
288 sprintf (name, "/dev/rd/c%dd%d", controller, drive);
291 static void
292 get_acceleraid_disk_name (char *name, int controller, int drive)
294 sprintf (name, "/dev/rs/c%dd%d", controller, drive);
297 static void
298 get_ataraid_disk_name (char *name, int unit)
300 sprintf (name, "/dev/ataraid/d%c", unit + '0');
303 static void
304 get_i2o_disk_name (char *name, char unit)
306 sprintf (name, "/dev/i2o/hd%c", unit);
309 static void
310 get_cciss_disk_name (char *name, int controller, int drive)
312 sprintf (name, "/dev/cciss/c%dd%d", controller, drive);
315 static void
316 get_ida_disk_name (char *name, int controller, int drive)
318 sprintf (name, "/dev/ida/c%dd%d", controller, drive);
321 static void
322 get_mmc_disk_name (char *name, int unit)
324 sprintf (name, "/dev/mmcblk%d", unit);
327 static void
328 get_xvd_disk_name (char *name, int unit)
330 sprintf (name, "/dev/xvd%c", unit + 'a');
332 #endif
334 /* Check if DEVICE can be read. If an error occurs, return zero,
335 otherwise return non-zero. */
336 static int
337 check_device (const char *device)
339 char buf[512];
340 FILE *fp;
342 /* If DEVICE is empty, just return error. */
343 if (*device == 0)
344 return 0;
346 fp = fopen (device, "r");
347 if (! fp)
349 switch (errno)
351 #ifdef ENOMEDIUM
352 case ENOMEDIUM:
353 # if 0
354 /* At the moment, this finds only CDROMs, which can't be
355 read anyway, so leave it out. Code should be
356 reactivated if `removable disks' and CDROMs are
357 supported. */
358 /* Accept it, it may be inserted. */
359 return 1;
360 # endif
361 break;
362 #endif /* ENOMEDIUM */
363 default:
364 /* Break case and leave. */
365 break;
367 /* Error opening the device. */
368 return 0;
371 /* Make sure CD-ROMs don't get assigned a BIOS disk number
372 before SCSI disks! */
373 #ifdef __linux__
374 # ifdef CDROM_GET_CAPABILITY
375 if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
376 return 0;
377 # else /* ! CDROM_GET_CAPABILITY */
378 /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
380 struct hd_geometry hdg;
381 struct stat st;
383 if (fstat (fileno (fp), &st))
384 return 0;
386 /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
387 succeeds. */
388 if (S_ISBLK (st.st_mode)
389 && MAJOR (st.st_rdev) != FLOPPY_MAJOR
390 && ioctl (fileno (fp), HDIO_GETGEO, &hdg))
391 return 0;
393 # endif /* ! CDROM_GET_CAPABILITY */
394 #endif /* __linux__ */
396 #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
397 # ifdef CDIOCCLRDEBUG
398 if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
399 return 0;
400 # endif /* CDIOCCLRDEBUG */
401 #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
403 /* Attempt to read the first sector. */
404 if (fread (buf, 1, 512, fp) != 512)
406 fclose (fp);
407 return 0;
410 fclose (fp);
411 return 1;
414 void
415 grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int),
416 int floppy_disks)
418 int i;
420 /* Floppies. */
421 for (i = 0; i < floppy_disks; i++)
423 char name[16];
424 struct stat st;
426 get_floppy_disk_name (name, i);
427 if (stat (name, &st) < 0)
428 break;
429 /* In floppies, write the map, whether check_device succeeds
430 or not, because the user just may not insert floppies. */
431 if (hook (name, 1))
432 return;
435 #ifdef __linux__
436 if (have_devfs ())
438 i = 0;
439 while (1)
441 char discn[32];
442 char name[PATH_MAX];
443 struct stat st;
445 /* Linux creates symlinks "/dev/discs/discN" for convenience.
446 The way to number disks is the same as GRUB's. */
447 sprintf (discn, "/dev/discs/disc%d", i++);
448 if (stat (discn, &st) < 0)
449 break;
451 if (realpath (discn, name))
453 strcat (name, "/disc");
454 if (hook (name, 0))
455 return;
458 return;
460 #endif /* __linux__ */
462 /* IDE disks. */
463 for (i = 0; i < 26; i++)
465 char name[16];
467 get_ide_disk_name (name, i);
468 if (check_device (name))
470 if (hook (name, 0))
471 return;
475 #ifdef __linux__
476 /* Virtio disks. */
477 for (i = 0; i < 26; i++)
479 char name[16];
481 get_virtio_disk_name (name, i);
482 if (check_device (name))
484 if (hook (name, 0))
485 return;
489 /* ATARAID disks. */
490 for (i = 0; i < 8; i++)
492 char name[20];
494 get_ataraid_disk_name (name, i);
495 if (check_device (name))
497 if (hook (name, 0))
498 return;
502 /* Xen virtual block devices. */
503 for (i = 0; i < 26; i++)
505 char name[16];
507 get_xvd_disk_name (name, i);
508 if (check_device (name))
510 if (hook (name, 0))
511 return;
514 #endif /* __linux__ */
516 /* The rest is SCSI disks. */
517 for (i = 0; i < 26; i++)
519 char name[16];
521 get_scsi_disk_name (name, i);
522 if (check_device (name))
524 if (hook (name, 0))
525 return;
529 #ifdef __linux__
530 /* This is for DAC960 - we have
531 /dev/rd/c<controller>d<logical drive>p<partition>.
533 DAC960 driver currently supports up to 8 controllers, 32 logical
534 drives, and 7 partitions. */
536 int controller, drive;
538 for (controller = 0; controller < 8; controller++)
540 for (drive = 0; drive < 15; drive++)
542 char name[24];
544 get_dac960_disk_name (name, controller, drive);
545 if (check_device (name))
547 if (hook (name, 0))
548 return;
554 /* This is for Mylex Acceleraid - we have
555 /dev/rd/c<controller>d<logical drive>p<partition>. */
557 int controller, drive;
559 for (controller = 0; controller < 8; controller++)
561 for (drive = 0; drive < 15; drive++)
563 char name[24];
565 get_acceleraid_disk_name (name, controller, drive);
566 if (check_device (name))
568 if (hook (name, 0))
569 return;
575 /* This is for CCISS - we have
576 /dev/cciss/c<controller>d<logical drive>p<partition>. */
578 int controller, drive;
580 for (controller = 0; controller < 3; controller++)
582 for (drive = 0; drive < 16; drive++)
584 char name[24];
586 get_cciss_disk_name (name, controller, drive);
587 if (check_device (name))
589 if (hook (name, 0))
590 return;
596 /* This is for Compaq Intelligent Drive Array - we have
597 /dev/ida/c<controller>d<logical drive>p<partition>. */
599 int controller, drive;
601 for (controller = 0; controller < 3; controller++)
603 for (drive = 0; drive < 16; drive++)
605 char name[24];
607 get_ida_disk_name (name, controller, drive);
608 if (check_device (name))
610 if (hook (name, 0))
611 return;
617 /* This is for I2O - we have /dev/i2o/hd<logical drive><partition> */
619 char unit;
621 for (unit = 'a'; unit < 'f'; unit++)
623 char name[24];
625 get_i2o_disk_name (name, unit);
626 if (check_device (name))
628 if (hook (name, 0))
629 return;
634 /* MultiMediaCard (MMC). */
635 for (i = 0; i < 10; i++)
637 char name[16];
639 get_mmc_disk_name (name, i);
640 if (check_device (name))
642 if (hook (name, 0))
643 return;
646 #endif /* __linux__ */