1 /* grub-mkdevicemap.c - make a device map file automatically */
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/>.
26 #include <sys/types.h>
32 #include <grub/util/misc.h>
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 */
45 # define HDIO_GETGEO 0x0301 /* get device geometry */
46 /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
51 unsigned char sectors
;
52 unsigned short cylinders
;
55 # endif /* ! HDIO_GETGEO */
57 # define FLOPPY_MAJOR 2 /* the major number for floppy */
58 # endif /* ! FLOPPY_MAJOR */
62 unsigned long long __dev = (dev); \
63 (unsigned) ((__dev >> 8) & 0xfff) \
64 | ((unsigned int) (__dev >> 32) & ~0xfff); \
67 # ifndef CDROM_GET_CAPABILITY
68 # define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
69 # endif /* ! CDROM_GET_CAPABILITY */
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__
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
87 /* Runtime detection of kernel */
88 # include <sys/utsname.h>
90 get_kfreebsd_version (void)
98 sscanf (uts
.release
, "%d.%d", &major
, &minor
);
104 v
[0] = minor
/10; v
[1] = minor
%10;
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>
123 # endif /* __FreeBSD_kernel__ */
124 #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
128 #endif /* HAVE_OPENDISK */
131 /* Check if we have devfs support. */
136 return stat ("/dev/.devfsd", &st
) == 0;
138 #endif /* __linux__ */
140 /* These three functions are quite different among OSes. */
142 get_floppy_disk_name (char *name
, int unit
)
144 #if defined(__linux__)
147 sprintf (name
, "/dev/floppy/%d", unit
);
149 sprintf (name
, "/dev/fd%d", unit
);
150 #elif defined(__GNU__)
152 sprintf (name
, "/dev/fd%d", unit
);
153 #elif defined(__FreeBSD_kernel__)
155 if (get_kfreebsd_version () >= 400000)
156 sprintf (name
, "/dev/fd%d", unit
);
158 sprintf (name
, "/dev/rfd%d", unit
);
159 #elif defined(__NetBSD__)
161 /* opendisk() doesn't work for floppies. */
162 sprintf (name
, "/dev/rfd%da", unit
);
163 #elif defined(__OpenBSD__)
165 sprintf (name
, "/dev/rfd%dc", unit
);
166 #elif defined(__QNXNTO__)
168 sprintf (name
, "/dev/fd%d", unit
);
170 # warning "BIOS floppy drives cannot be guessed in your operating system."
171 /* Set NAME to a bogus string. */
177 get_ide_disk_name (char *name
, int unit
)
179 #if defined(__linux__)
181 sprintf (name
, "/dev/hd%c", unit
+ 'a');
182 #elif defined(__GNU__)
184 sprintf (name
, "/dev/hd%d", unit
);
185 #elif defined(__FreeBSD_kernel__)
187 if (get_kfreebsd_version () >= 400000)
188 sprintf (name
, "/dev/ad%d", unit
);
190 sprintf (name
, "/dev/rwd%d", unit
);
191 #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
196 sprintf (shortname
, "wd%d", unit
);
197 fd
= opendisk (shortname
, O_RDONLY
, name
,
198 16, /* length of NAME */
202 #elif defined(__OpenBSD__)
204 sprintf (name
, "/dev/rwd%dc", unit
);
205 #elif defined(__QNXNTO__)
207 /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
208 contain SCSI disks. */
209 sprintf (name
, "/dev/hd%d", unit
);
211 # warning "BIOS IDE drives cannot be guessed in your operating system."
212 /* Set NAME to a bogus string. */
218 get_scsi_disk_name (char *name
, int unit
)
220 #if defined(__linux__)
222 sprintf (name
, "/dev/sd%c", unit
+ 'a');
223 #elif defined(__GNU__)
225 sprintf (name
, "/dev/sd%d", unit
);
226 #elif defined(__FreeBSD_kernel__)
228 if (get_kfreebsd_version () >= 400000)
229 sprintf (name
, "/dev/da%d", unit
);
231 sprintf (name
, "/dev/rda%d", unit
);
232 #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
237 sprintf (shortname
, "sd%d", unit
);
238 fd
= opendisk (shortname
, O_RDONLY
, name
,
239 16, /* length of NAME */
243 #elif defined(__OpenBSD__)
245 sprintf (name
, "/dev/rsd%dc", unit
);
246 #elif defined(__QNXNTO__)
248 /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
249 disable the detection of SCSI disks here. */
252 # warning "BIOS SCSI drives cannot be guessed in your operating system."
253 /* Set NAME to a bogus string. */
260 get_dac960_disk_name (char *name
, int controller
, int drive
)
262 sprintf (name
, "/dev/rd/c%dd%d", controller
, drive
);
266 get_ataraid_disk_name (char *name
, int unit
)
268 sprintf (name
, "/dev/ataraid/d%c", unit
+ '0');
272 get_i2o_disk_name (char *name
, char unit
)
274 sprintf (name
, "/dev/i2o/hd%c", unit
);
278 /* Check if DEVICE can be read. If an error occurs, return zero,
279 otherwise return non-zero. */
281 check_device (const char *device
)
286 /* If DEVICE is empty, just return 1. */
290 fp
= fopen (device
, "r");
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
302 /* Accept it, it may be inserted. */
306 #endif /* ENOMEDIUM */
308 /* Break case and leave. */
311 /* Error opening the device. */
315 /* Make sure CD-ROMs don't get assigned a BIOS disk number
316 before SCSI disks! */
318 # ifdef CDROM_GET_CAPABILITY
319 if (ioctl (fileno (fp
), CDROM_GET_CAPABILITY
, 0) >= 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
;
327 if (fstat (fileno (fp
), &st
))
330 /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
332 if (S_ISBLK (st
.st_mode
)
333 && MAJOR (st
.st_rdev
) != FLOPPY_MAJOR
334 && ioctl (fileno (fp
), HDIO_GETGEO
, &hdg
))
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)
344 # endif /* CDIOCCLRDEBUG */
345 #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
347 /* Attempt to read the first sector. */
348 if (fread (buf
, 1, 512, fp
) != 512)
359 make_device_map (const char *device_map
, int floppy_disks
)
365 if (strcmp (device_map
, "-") == 0)
368 fp
= fopen (device_map
, "w");
371 grub_util_error ("cannot open %s", device_map
);
374 for (i
= 0; i
< floppy_disks
; i
++)
379 get_floppy_disk_name (name
, i
);
380 if (stat (name
, &st
) < 0)
382 /* In floppies, write the map, whether check_device succeeds
383 or not, because the user just may not insert floppies. */
385 fprintf (fp
, "(fd%d)\t%s\n", i
, name
);
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)
403 if (realpath (discn
, name
))
406 strcat (name
, "/disc");
407 p
= grub_util_get_disk_name (num_hd
, name
);
408 fprintf (fp
, "(%s)\t%s\n", p
, name
);
417 #endif /* __linux__ */
420 for (i
= 0; i
< 20; i
++)
424 get_ide_disk_name (name
, i
);
425 if (check_device (name
))
428 p
= grub_util_get_disk_name (num_hd
, name
);
429 fprintf (fp
, "(%s)\t%s\n", p
, name
);
437 for (i
= 0; i
< 8; i
++)
441 get_ataraid_disk_name (name
, i
);
442 if (check_device (name
))
445 p
= grub_util_get_disk_name (num_hd
, name
);
446 fprintf (fp
, "(%s)\t%s\n", p
, name
);
451 #endif /* __linux__ */
453 /* The rest is SCSI disks. */
454 for (i
= 0; i
< 16; i
++)
458 get_scsi_disk_name (name
, i
);
459 if (check_device (name
))
462 p
= grub_util_get_disk_name (num_hd
, name
);
463 fprintf (fp
, "(%s)\t%s\n", p
, name
);
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
++)
484 get_dac960_disk_name (name
, controller
, drive
);
485 if (check_device (name
))
488 p
= grub_util_get_disk_name (num_hd
, name
);
489 fprintf (fp
, "(%s)\t%s\n", p
, name
);
497 /* This is for I2O - we have /dev/i2o/hd<logical drive><partition> */
501 for (unit
= 'a'; unit
< 'f'; unit
++)
505 get_i2o_disk_name (name
, unit
);
506 if (check_device (name
))
509 p
= grub_util_get_disk_name (num_hd
, name
);
510 fprintf (fp
, "(%s)\t%s\n", p
, name
);
516 #endif /* __linux__ */
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'},
539 "Try ``grub-mkdevicemap --help'' for more information.\n");
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
);
561 main (int argc
, char *argv
[])
564 int floppy_disks
= 1;
566 progname
= "grub-mkdevicemap";
568 /* Check for options. */
571 int c
= getopt_long (argc
, argv
, "snm:r:hVv", options
, 0);
582 dev_map
= xstrdup (optarg
);
598 printf ("%s (%s) %s\n", progname
, PACKAGE_NAME
, PACKAGE_VERSION
);
611 make_device_map (dev_map
? : DEFAULT_DEVICE_MAP
, floppy_disks
);