make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / boot / grub2 / util / grub-mkdevicemap.c
blobc071dab0d25408c82e78fc0dd5d3aa690d933d2c
1 /* grub-mkdevicemap.c - make a device map file automatically */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007 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>
34 #define _GNU_SOURCE 1
35 #include <getopt.h>
37 #ifdef __linux__
38 # if !defined(__GLIBC__) || \
39 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
40 /* Maybe libc doesn't have large file support. */
41 # include <linux/unistd.h> /* _llseek */
42 # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
43 # include <sys/ioctl.h> /* ioctl */
44 # ifndef HDIO_GETGEO
45 # define HDIO_GETGEO 0x0301 /* get device geometry */
46 /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
47 defined. */
48 struct hd_geometry
50 unsigned char heads;
51 unsigned char sectors;
52 unsigned short cylinders;
53 unsigned long start;
55 # endif /* ! HDIO_GETGEO */
56 # ifndef FLOPPY_MAJOR
57 # define FLOPPY_MAJOR 2 /* the major number for floppy */
58 # endif /* ! FLOPPY_MAJOR */
59 # ifndef MAJOR
60 # define MAJOR(dev) \
61 ({ \
62 unsigned long long __dev = (dev); \
63 (unsigned) ((__dev >> 8) & 0xfff) \
64 | ((unsigned int) (__dev >> 32) & ~0xfff); \
66 # endif /* ! MAJOR */
67 # ifndef CDROM_GET_CAPABILITY
68 # define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
69 # endif /* ! CDROM_GET_CAPABILITY */
70 # ifndef BLKGETSIZE
71 # define BLKGETSIZE _IO(0x12,96) /* return device size */
72 # endif /* ! BLKGETSIZE */
73 #endif /* __linux__ */
75 /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
76 kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
77 #if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
78 # define __FreeBSD_kernel__
79 #endif
80 #ifdef __FreeBSD_kernel__
81 /* Obtain version of kFreeBSD headers */
82 # include <osreldate.h>
83 # ifndef __FreeBSD_kernel_version
84 # define __FreeBSD_kernel_version __FreeBSD_version
85 # endif
87 /* Runtime detection of kernel */
88 # include <sys/utsname.h>
89 int
90 get_kfreebsd_version (void)
92 struct utsname uts;
93 int major;
94 int minor;
95 int v[2];
97 uname (&uts);
98 sscanf (uts.release, "%d.%d", &major, &minor);
100 if (major >= 9)
101 major = 9;
102 if (major >= 5)
104 v[0] = minor/10; v[1] = minor%10;
106 else
108 v[0] = minor%10; v[1] = minor/10;
110 return major*100000+v[0]*10000+v[1]*1000;
112 #endif /* __FreeBSD_kernel__ */
114 #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
115 # include <sys/ioctl.h> /* ioctl */
116 # include <sys/disklabel.h>
117 # include <sys/cdio.h> /* CDIOCCLRDEBUG */
118 # if defined(__FreeBSD_kernel__)
119 # include <sys/param.h>
120 # if __FreeBSD_kernel_version >= 500040
121 # include <sys/disk.h>
122 # endif
123 # endif /* __FreeBSD_kernel__ */
124 #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
126 #ifdef HAVE_OPENDISK
127 # include <util.h>
128 #endif /* HAVE_OPENDISK */
130 #ifdef __linux__
131 /* Check if we have devfs support. */
132 static int
133 have_devfs (void)
135 struct stat st;
136 return stat ("/dev/.devfsd", &st) == 0;
138 #endif /* __linux__ */
140 /* These three functions are quite different among OSes. */
141 static void
142 get_floppy_disk_name (char *name, int unit)
144 #if defined(__linux__)
145 /* GNU/Linux */
146 if (have_devfs ())
147 sprintf (name, "/dev/floppy/%d", unit);
148 else
149 sprintf (name, "/dev/fd%d", unit);
150 #elif defined(__GNU__)
151 /* GNU/Hurd */
152 sprintf (name, "/dev/fd%d", unit);
153 #elif defined(__FreeBSD_kernel__)
154 /* kFreeBSD */
155 if (get_kfreebsd_version () >= 400000)
156 sprintf (name, "/dev/fd%d", unit);
157 else
158 sprintf (name, "/dev/rfd%d", unit);
159 #elif defined(__NetBSD__)
160 /* NetBSD */
161 /* opendisk() doesn't work for floppies. */
162 sprintf (name, "/dev/rfd%da", unit);
163 #elif defined(__OpenBSD__)
164 /* OpenBSD */
165 sprintf (name, "/dev/rfd%dc", unit);
166 #elif defined(__QNXNTO__)
167 /* QNX RTP */
168 sprintf (name, "/dev/fd%d", unit);
169 #else
170 # warning "BIOS floppy drives cannot be guessed in your operating system."
171 /* Set NAME to a bogus string. */
172 *name = 0;
173 #endif
176 static void
177 get_ide_disk_name (char *name, int unit)
179 #if defined(__linux__)
180 /* GNU/Linux */
181 sprintf (name, "/dev/hd%c", unit + 'a');
182 #elif defined(__GNU__)
183 /* GNU/Hurd */
184 sprintf (name, "/dev/hd%d", unit);
185 #elif defined(__FreeBSD_kernel__)
186 /* kFreeBSD */
187 if (get_kfreebsd_version () >= 400000)
188 sprintf (name, "/dev/ad%d", unit);
189 else
190 sprintf (name, "/dev/rwd%d", unit);
191 #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
192 /* NetBSD */
193 char shortname[16];
194 int fd;
196 sprintf (shortname, "wd%d", unit);
197 fd = opendisk (shortname, O_RDONLY, name,
198 16, /* length of NAME */
199 0 /* char device */
201 close (fd);
202 #elif defined(__OpenBSD__)
203 /* OpenBSD */
204 sprintf (name, "/dev/rwd%dc", unit);
205 #elif defined(__QNXNTO__)
206 /* QNX RTP */
207 /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
208 contain SCSI disks. */
209 sprintf (name, "/dev/hd%d", unit);
210 #else
211 # warning "BIOS IDE drives cannot be guessed in your operating system."
212 /* Set NAME to a bogus string. */
213 *name = 0;
214 #endif
217 static void
218 get_scsi_disk_name (char *name, int unit)
220 #if defined(__linux__)
221 /* GNU/Linux */
222 sprintf (name, "/dev/sd%c", unit + 'a');
223 #elif defined(__GNU__)
224 /* GNU/Hurd */
225 sprintf (name, "/dev/sd%d", unit);
226 #elif defined(__FreeBSD_kernel__)
227 /* kFreeBSD */
228 if (get_kfreebsd_version () >= 400000)
229 sprintf (name, "/dev/da%d", unit);
230 else
231 sprintf (name, "/dev/rda%d", unit);
232 #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
233 /* NetBSD */
234 char shortname[16];
235 int fd;
237 sprintf (shortname, "sd%d", unit);
238 fd = opendisk (shortname, O_RDONLY, name,
239 16, /* length of NAME */
240 0 /* char device */
242 close (fd);
243 #elif defined(__OpenBSD__)
244 /* OpenBSD */
245 sprintf (name, "/dev/rsd%dc", unit);
246 #elif defined(__QNXNTO__)
247 /* QNX RTP */
248 /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
249 disable the detection of SCSI disks here. */
250 *name = 0;
251 #else
252 # warning "BIOS SCSI drives cannot be guessed in your operating system."
253 /* Set NAME to a bogus string. */
254 *name = 0;
255 #endif
258 #ifdef __linux__
259 static void
260 get_dac960_disk_name (char *name, int controller, int drive)
262 sprintf (name, "/dev/rd/c%dd%d", controller, drive);
265 static void
266 get_ataraid_disk_name (char *name, int unit)
268 sprintf (name, "/dev/ataraid/d%c", unit + '0');
271 static void
272 get_i2o_disk_name (char *name, char unit)
274 sprintf (name, "/dev/i2o/hd%c", unit);
276 #endif
278 /* Check if DEVICE can be read. If an error occurs, return zero,
279 otherwise return non-zero. */
281 check_device (const char *device)
283 char buf[512];
284 FILE *fp;
286 /* If DEVICE is empty, just return 1. */
287 if (*device == 0)
288 return 1;
290 fp = fopen (device, "r");
291 if (! fp)
293 switch (errno)
295 #ifdef ENOMEDIUM
296 case ENOMEDIUM:
297 # if 0
298 /* At the moment, this finds only CDROMs, which can't be
299 read anyway, so leave it out. Code should be
300 reactivated if `removable disks' and CDROMs are
301 supported. */
302 /* Accept it, it may be inserted. */
303 return 1;
304 # endif
305 break;
306 #endif /* ENOMEDIUM */
307 default:
308 /* Break case and leave. */
309 break;
311 /* Error opening the device. */
312 return 0;
315 /* Make sure CD-ROMs don't get assigned a BIOS disk number
316 before SCSI disks! */
317 #ifdef __linux__
318 # ifdef CDROM_GET_CAPABILITY
319 if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
320 return 0;
321 # else /* ! CDROM_GET_CAPABILITY */
322 /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
324 struct hd_geometry hdg;
325 struct stat st;
327 if (fstat (fileno (fp), &st))
328 return 0;
330 /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
331 succeeds. */
332 if (S_ISBLK (st.st_mode)
333 && MAJOR (st.st_rdev) != FLOPPY_MAJOR
334 && ioctl (fileno (fp), HDIO_GETGEO, &hdg))
335 return 0;
337 # endif /* ! CDROM_GET_CAPABILITY */
338 #endif /* __linux__ */
340 #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
341 # ifdef CDIOCCLRDEBUG
342 if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
343 return 0;
344 # endif /* CDIOCCLRDEBUG */
345 #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
347 /* Attempt to read the first sector. */
348 if (fread (buf, 1, 512, fp) != 512)
350 fclose (fp);
351 return 0;
354 fclose (fp);
355 return 1;
358 static void
359 make_device_map (const char *device_map, int floppy_disks)
361 FILE *fp;
362 int num_hd = 0;
363 int i;
365 if (strcmp (device_map, "-") == 0)
366 fp = stdout;
367 else
368 fp = fopen (device_map, "w");
370 if (! fp)
371 grub_util_error ("cannot open %s", device_map);
373 /* Floppies. */
374 for (i = 0; i < floppy_disks; i++)
376 char name[16];
377 struct stat st;
379 get_floppy_disk_name (name, i);
380 if (stat (name, &st) < 0)
381 break;
382 /* In floppies, write the map, whether check_device succeeds
383 or not, because the user just may not insert floppies. */
384 if (fp)
385 fprintf (fp, "(fd%d)\t%s\n", i, name);
388 #ifdef __linux__
389 if (have_devfs ())
391 while (1)
393 char discn[32];
394 char name[PATH_MAX];
395 struct stat st;
397 /* Linux creates symlinks "/dev/discs/discN" for convenience.
398 The way to number disks is the same as GRUB's. */
399 sprintf (discn, "/dev/discs/disc%d", num_hd);
400 if (stat (discn, &st) < 0)
401 break;
403 if (realpath (discn, name))
405 char *p;
406 strcat (name, "/disc");
407 p = grub_util_get_disk_name (num_hd, name);
408 fprintf (fp, "(%s)\t%s\n", p, name);
409 free (p);
412 num_hd++;
415 goto finish;
417 #endif /* __linux__ */
419 /* IDE disks. */
420 for (i = 0; i < 20; i++)
422 char name[16];
424 get_ide_disk_name (name, i);
425 if (check_device (name))
427 char *p;
428 p = grub_util_get_disk_name (num_hd, name);
429 fprintf (fp, "(%s)\t%s\n", p, name);
430 free (p);
431 num_hd++;
435 #ifdef __linux__
436 /* ATARAID disks. */
437 for (i = 0; i < 8; i++)
439 char name[20];
441 get_ataraid_disk_name (name, i);
442 if (check_device (name))
444 char *p;
445 p = grub_util_get_disk_name (num_hd, name);
446 fprintf (fp, "(%s)\t%s\n", p, name);
447 free (p);
448 num_hd++;
451 #endif /* __linux__ */
453 /* The rest is SCSI disks. */
454 for (i = 0; i < 16; i++)
456 char name[16];
458 get_scsi_disk_name (name, i);
459 if (check_device (name))
461 char *p;
462 p = grub_util_get_disk_name (num_hd, name);
463 fprintf (fp, "(%s)\t%s\n", p, name);
464 free (p);
465 num_hd++;
469 #ifdef __linux__
470 /* This is for DAC960 - we have
471 /dev/rd/c<controller>d<logical drive>p<partition>.
473 DAC960 driver currently supports up to 8 controllers, 32 logical
474 drives, and 7 partitions. */
476 int controller, drive;
478 for (controller = 0; controller < 8; controller++)
480 for (drive = 0; drive < 15; drive++)
482 char name[24];
484 get_dac960_disk_name (name, controller, drive);
485 if (check_device (name))
487 char *p;
488 p = grub_util_get_disk_name (num_hd, name);
489 fprintf (fp, "(%s)\t%s\n", p, name);
490 free (p);
491 num_hd++;
497 /* This is for I2O - we have /dev/i2o/hd<logical drive><partition> */
499 char unit;
501 for (unit = 'a'; unit < 'f'; unit++)
503 char name[24];
505 get_i2o_disk_name (name, unit);
506 if (check_device (name))
508 char *p;
509 p = grub_util_get_disk_name (num_hd, name);
510 fprintf (fp, "(%s)\t%s\n", p, name);
511 free (p);
512 num_hd++;
516 #endif /* __linux__ */
518 finish:
519 if (fp != stdout)
520 fclose (fp);
523 static struct option options[] =
525 {"device-map", required_argument, 0, 'm'},
526 {"probe-second-floppy", no_argument, 0, 's'},
527 {"no-floppy", no_argument, 0, 'n'},
528 {"help", no_argument, 0, 'h'},
529 {"version", no_argument, 0, 'V'},
530 {"verbose", no_argument, 0, 'v'},
531 {0, 0, 0, 0}
534 static void
535 usage (int status)
537 if (status)
538 fprintf (stderr,
539 "Try ``grub-mkdevicemap --help'' for more information.\n");
540 else
541 printf ("\
542 Usage: grub-mkdevicemap [OPTION]...\n\
544 Generate a device map file automatically.\n\
546 -n, --no-floppy do not probe any floppy drive\n\
547 -s, --probe-second-floppy probe the second floppy drive\n\
548 -m, --device-map=FILE use FILE as the device map [default=%s]\n\
549 -h, --help display this message and exit\n\
550 -V, --version print version information and exit\n\
551 -v, --verbose print verbose messages\n\
553 Report bugs to <%s>.\n\
555 DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT);
557 exit (status);
561 main (int argc, char *argv[])
563 char *dev_map = 0;
564 int floppy_disks = 1;
566 progname = "grub-mkdevicemap";
568 /* Check for options. */
569 while (1)
571 int c = getopt_long (argc, argv, "snm:r:hVv", options, 0);
573 if (c == -1)
574 break;
575 else
576 switch (c)
578 case 'm':
579 if (dev_map)
580 free (dev_map);
582 dev_map = xstrdup (optarg);
583 break;
585 case 'n':
586 floppy_disks = 0;
587 break;
589 case 's':
590 floppy_disks = 2;
591 break;
593 case 'h':
594 usage (0);
595 break;
597 case 'V':
598 printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
599 return 0;
601 case 'v':
602 verbosity++;
603 break;
605 default:
606 usage (1);
607 break;
611 make_device_map (dev_map ? : DEFAULT_DEVICE_MAP, floppy_disks);
613 free (dev_map);
615 return 0;