/* deviceiter.c - iterate over system devices */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2011 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <dirent.h>
#if defined (__sun__)
#include <dirent.h>
# if !defined(__GLIBC__) || \
/* Maybe libc doesn't have large file support. */
# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
# ifndef HDIO_GETGEO
/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
defined. */
struct hd_geometry
{
unsigned char heads;
unsigned char sectors;
unsigned short cylinders;
unsigned long start;
};
# endif /* ! HDIO_GETGEO */
# ifndef FLOPPY_MAJOR
# endif /* ! FLOPPY_MAJOR */
# ifndef MAJOR
({ \
})
# endif /* ! MAJOR */
# ifndef MINOR
({ \
})
# endif /* ! MINOR */
# ifndef CDROM_GET_CAPABILITY
# endif /* ! CDROM_GET_CAPABILITY */
# ifndef BLKGETSIZE
# endif /* ! BLKGETSIZE */
#ifdef HAVE_DEVICE_MAPPER
# include <libdevmapper.h>
#endif
#endif /* __linux__ */
/* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
#if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
# define __FreeBSD_kernel__
#endif
#ifdef __FreeBSD_kernel__
/* Obtain version of kFreeBSD headers */
# include <osreldate.h>
# ifndef __FreeBSD_kernel_version
# endif
/* Runtime detection of kernel */
int
get_kfreebsd_version (void)
{
int major;
int minor;
int v[2];
if (major >= 9)
major = 9;
if (major >= 5)
{
}
else
{
}
}
#endif /* __FreeBSD_kernel__ */
# include <sys/disklabel.h>
# if defined(__FreeBSD_kernel__)
# if __FreeBSD_kernel_version >= 500040
# endif
# endif /* __FreeBSD_kernel__ */
#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
#ifdef HAVE_OPENDISK
# include <util.h>
#endif /* HAVE_OPENDISK */
#ifdef __linux__
/* Check if we have devfs support. */
static int
have_devfs (void)
{
}
#endif /* __linux__ */
/* These three functions are quite different among OSes. */
static void
{
#if defined(__sun__)
/* Solaris */
if (have_devfs ())
else
#elif defined(__FreeBSD_kernel__)
/* kFreeBSD */
if (get_kfreebsd_version () >= 400000)
else
#elif defined(__NetBSD__)
/* NetBSD */
/* opendisk() doesn't work for floppies. */
#elif defined(__OpenBSD__)
/* OpenBSD */
#elif defined(__QNXNTO__)
/* QNX RTP */
#elif defined(__CYGWIN__)
/* Cygwin */
#elif defined(__MINGW32__)
(void) unit;
*name = 0;
#else
# warning "BIOS floppy drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
#ifndef __sun__
static void
{
#if defined(__linux__)
#elif defined(__FreeBSD_kernel__)
/* kFreeBSD */
if (get_kfreebsd_version () >= 400000)
else
/* NetBSD */
char shortname[16];
int fd;
16, /* length of NAME */
0 /* char device */
);
#elif defined(__OpenBSD__)
/* OpenBSD */
#elif defined(__QNXNTO__)
/* QNX RTP */
/* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
contain SCSI disks. */
#elif defined(__CYGWIN__)
(void) unit;
*name = 0;
#elif defined(__MINGW32__)
#else
# warning "BIOS IDE drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
static void
{
#if defined(__linux__)
#elif defined(__FreeBSD_kernel__)
/* kFreeBSD */
if (get_kfreebsd_version () >= 400000)
else
/* NetBSD */
char shortname[16];
int fd;
16, /* length of NAME */
0 /* char device */
);
#elif defined(__OpenBSD__)
/* OpenBSD */
#elif defined(__QNXNTO__)
/* QNX RTP */
/* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
disable the detection of SCSI disks here. */
*name = 0;
#elif defined(__CYGWIN__)
#elif defined(__MINGW32__)
(void) unit;
*name = 0;
#else
# warning "BIOS SCSI drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
#endif /* __sun__ */
#ifdef __FreeBSD_kernel__
static void
{
}
static void
{
}
static void
{
}
#endif
#ifdef __linux__
static void
{
#ifdef __sparc__
#else
#endif
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
#endif
static struct seen_device
{
const char *name;
} *seen;
/* Check if DEVICE can be read. Skip any DEVICE that we have already seen.
If an error occurs, return zero, otherwise return non-zero. */
static int
{
#ifdef __sun__
#endif
char *real_device;
/* If DEVICE is empty, just return error. */
if (*device == 0)
return 0;
/* Have we seen this device already? */
if (! real_device)
return 0;
{
goto fail;
}
if (! fp)
{
switch (errno)
{
#ifdef ENOMEDIUM
case ENOMEDIUM:
# if 0
/* At the moment, this finds only CDROMs, which can't be
read anyway, so leave it out. Code should be
reactivated if `removable disks' and CDROMs are
supported. */
/* Accept it, it may be inserted. */
return 1;
# endif
break;
#endif /* ENOMEDIUM */
default:
/* Break case and leave. */
break;
}
/* Error opening the device. */
goto fail;
}
/* Make sure CD-ROMs don't get assigned a BIOS disk number
before SCSI disks! */
#ifdef __linux__
# ifdef CDROM_GET_CAPABILITY
goto fail;
# else /* ! CDROM_GET_CAPABILITY */
/* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
{
goto fail;
/* If it is a block device and isn't a floppy, check if HDIO_GETGEO
succeeds. */
goto fail;
}
# endif /* ! CDROM_GET_CAPABILITY */
#endif /* __linux__ */
# ifdef CDIOCCLRDEBUG
goto fail;
# endif /* CDIOCCLRDEBUG */
#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
#if defined (__sun__)
/* If this is not a disk, skip it. Though not documented,
DKC_DIRECT disks are driven by the cmdk target driver
(used by the pci-ide nexus driver, and DKC_SCSI_CCS
disks are driven by sd (which covers SATA framework-driven,
SCSI, SAS, USB, and removable media (e.g. SD cards)
DKC_MD are for supporting lofi devices */
{
return 0;
}
#endif
/* Attempt to read the first sector. */
{
goto fail;
}
/* Remember that we've seen this device. */
return 1;
fail:
free (real_device);
return 0;
}
static void
clear_seen_devices (void)
{
while (seen)
{
}
}
#if defined (__sun__)
static void
(const char *, int))
{
int namelen;
return;
{
/* XXX revisit for GPT-labeled disks */
/* Pass up only the p0 (full disk) nodes */
continue;
continue;
{
{
return;
}
}
}
/* Also iterate over rlofi devices, if any */
return;
{
continue;
{
{
return;
}
}
}
/* Also iterate over ramdisk devices, if any */
return;
{
continue;
{
{
return;
}
}
}
}
#endif
#ifdef __linux__
# ifdef HAVE_DEVICE_MAPPER
struct dmraid_seen
const char *name;
};
#endif
/* Sort by the kernel name for preference since that most closely matches
older device.map files, but sort by stable by-id names as a fallback.
identifications of devices (e.g. ATA vs. SATA).
check_device_readable_unique will ensure that we only get one for any
given disk, but sort the list so that the choice of which one we get is
stable. */
static int
compare_devices (const void *a, const void *b)
{
{
if (ret)
return ret;
}
}
#endif /* __linux__ */
void
int floppy_disks)
{
int i;
/* Floppies. */
for (i = 0; i < floppy_disks; i++)
{
char name[16];
get_floppy_disk_name (name, i);
break;
/* In floppies, write the map, whether check_device_readable_unique
succeeds or not, because the user just may not insert floppies. */
goto out;
}
#ifdef __sun__
return;
#else
#ifdef __linux__
{
if (dir)
{
/* Dump all the directory entries into names, resizing if
necessary. */
{
/* Skip current and parent directory entries. */
continue;
/* Skip partition entries. */
continue;
/* Skip device-mapper entries; we'll handle the ones we want
later. */
continue;
/* Skip RAID entries; they are handled by upper layers. */
continue;
{
devs_max *= 2;
}
devs_len++;
}
/* Now add all the devices in sorted order. */
for (i = 0; i < devs_len; ++i)
{
{
goto out;
}
}
}
}
if (have_devfs ())
{
i = 0;
while (1)
{
char discn[32];
The way to number disks is the same as GRUB's. */
break;
{
goto out;
}
}
goto out;
}
#endif /* __linux__ */
/* IDE disks. */
for (i = 0; i < 96; i++)
{
char name[16];
get_ide_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
#ifdef __FreeBSD_kernel__
/* IDE disks using ATA Direct Access driver. */
if (get_kfreebsd_version () >= 800000)
for (i = 0; i < 96; i++)
{
char name[16];
get_ada_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
/* ATARAID disks. */
for (i = 0; i < 8; i++)
{
char name[20];
get_ataraid_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
/* LSI MegaRAID SAS. */
for (i = 0; i < 32; i++)
{
char name[20];
get_mfi_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
#endif
#ifdef __linux__
/* Virtio disks. */
for (i = 0; i < 26; i++)
{
char name[16];
get_virtio_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
/* ATARAID disks. */
for (i = 0; i < 8; i++)
{
char name[20];
get_ataraid_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
/* Xen virtual block devices. */
for (i = 0; i < 26; i++)
{
char name[16];
get_xvd_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
#endif /* __linux__ */
/* The rest is SCSI disks. */
for (i = 0; i < 48; i++)
{
char name[16];
get_scsi_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
#ifdef __linux__
/* This is for DAC960 - we have
DAC960 driver currently supports up to 8 controllers, 32 logical
drives, and 7 partitions. */
{
int controller, drive;
{
{
char name[24];
if (check_device_readable_unique (name))
{
goto out;
}
}
}
}
/* This is for Mylex Acceleraid - we have
{
int controller, drive;
{
{
char name[24];
if (check_device_readable_unique (name))
{
goto out;
}
}
}
}
/* This is for CCISS - we have
{
int controller, drive;
{
{
char name[24];
if (check_device_readable_unique (name))
{
goto out;
}
}
}
}
/* This is for Compaq Intelligent Drive Array - we have
{
int controller, drive;
{
{
char name[24];
if (check_device_readable_unique (name))
{
goto out;
}
}
}
}
{
char unit;
{
char name[24];
if (check_device_readable_unique (name))
{
goto out;
}
}
}
/* MultiMediaCard (MMC). */
for (i = 0; i < 10; i++)
{
char name[16];
get_mmc_disk_name (name, i);
if (check_device_readable_unique (name))
{
goto out;
}
}
# ifdef HAVE_DEVICE_MAPPER
# define dmraid_check(cond, ...) \
if (! (cond)) \
{ \
goto dmraid_end; \
}
/* DM-RAID. */
if (grub_device_mapper_supported ())
{
unsigned int next = 0;
void *top_handle, *second_handle;
/* Build DM tree for all devices. */
tree = dm_tree_create ();
do
{
}
while (next);
/* Walk the second-level children of the inverted tree; that is, devices
which are directly composed of non-DM devices such as hard disks.
This class includes all DM-RAID disks and excludes all DM-RAID
partitions. */
top_handle = NULL;
while (top)
{
while (second)
{
char *name;
{
goto dmraid_next_child;
}
if (check_device_readable_unique (name))
{
{
if (task)
if (tree)
dm_tree_free (tree);
goto out;
}
}
}
}
if (task)
if (tree)
dm_tree_free (tree);
}
# endif /* HAVE_DEVICE_MAPPER */
#endif /* __linux__ */
#endif /* __sun__ */
out:
}