#ifdef __linux__
# include <sys/ioctl.h> /* ioctl */
+# include <sys/mount.h>
# if !defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
/* Maybe libc doesn't have large file support. */
# include <sys/disk.h> /* DIOCGMEDIASIZE */
# include <sys/param.h>
# include <sys/sysctl.h>
+# include <sys/mount.h>
+#include <libgeom.h>
# define MAJOR(dev) major(dev)
# define FLOPPY_MAJOR 2
#endif
+#if defined (__sun__)
+# include <sys/dkio.h>
+#endif
+
#if defined(__APPLE__)
# include <sys/disk.h>
#endif
# include <libdevmapper.h>
#endif
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <libgeom.h>
-#elif defined(__NetBSD__)
+#if defined(__NetBSD__)
# define HAVE_DIOCGDINFO
# include <sys/ioctl.h>
# include <sys/disklabel.h> /* struct disklabel */
}
#endif /* defined(__NetBSD__) */
+static int
+unescape_cmp (const char *a, const char *b_escaped)
+{
+ while (*a || *b_escaped)
+ {
+ if (*b_escaped == '\\' && b_escaped[1] != 0)
+ b_escaped++;
+ if (*a < *b_escaped)
+ return -1;
+ if (*a > *b_escaped)
+ return +1;
+ a++;
+ b_escaped++;
+ }
+ if (*a)
+ return +1;
+ if (*b_escaped)
+ return -1;
+ return 0;
+}
+
static int
find_grub_drive (const char *name)
{
if (name)
{
for (i = 0; i < ARRAY_SIZE (map); i++)
- if (map[i].drive && ! strcmp (map[i].drive, name))
+ if (map[i].drive && unescape_cmp (map[i].drive, name) == 0)
return i;
}
}
static int
-grub_util_biosdisk_iterate (int (*hook) (const char *name))
+grub_util_biosdisk_iterate (int (*hook) (const char *name),
+ grub_disk_pull_t pull)
{
unsigned i;
+ if (pull != GRUB_DISK_PULL_NONE)
+ return 0;
+
for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
if (map[i].drive && hook (map[i].drive))
return 1;
return 0;
}
+#if !defined(__MINGW32__)
+grub_uint64_t
+grub_util_get_fd_sectors (int fd, unsigned *log_secsize)
+{
+# if defined(__NetBSD__)
+ struct disklabel label;
+# elif defined (__sun__)
+ struct dk_minfo minfo;
+#else
+ unsigned long long nr;
+# endif
+ unsigned sector_size, log_sector_size;
+ struct stat st;
+
+ if (fstat (fd, &st) < 0)
+ grub_util_error (_("fstat failed"));
+
+#if defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) \
+ || defined (__sun__)
+
+# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
+ if (! S_ISCHR (st.st_mode))
+# else
+ if (! S_ISBLK (st.st_mode))
+# endif
+ goto fail;
+
+# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ if (ioctl (fd, DIOCGMEDIASIZE, &nr))
+# elif defined(__APPLE__)
+ if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr))
+# elif defined(__NetBSD__)
+ configure_device_driver (fd);
+ if (ioctl (fd, DIOCGDINFO, &label) == -1)
+# elif defined (__sun__)
+ if (!ioctl (fd, DKIOCGMEDIAINFO, &minfo))
+# else
+ if (ioctl (fd, BLKGETSIZE64, &nr))
+# endif
+ goto fail;
+
+# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ if (ioctl (fd, DIOCGSECTORSIZE, §or_size))
+ goto fail;
+# elif defined(__sun__)
+ sector_size = minfo.dki_lbsize;
+# elif defined(__NetBSD__)
+ sector_size = label.d_secsize;
+# else
+ if (ioctl (fd, BLKSSZGET, §or_size))
+ goto fail;
+# endif
+ if (sector_size & (sector_size - 1) || !sector_size)
+ goto fail;
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < sector_size;
+ log_sector_size++);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+# if defined (__APPLE__)
+ return nr;
+# elif defined(__NetBSD__)
+ return label.d_secperunit;
+# elif defined (__sun__)
+ return minfo.dki_capacity;
+# else
+ if (nr & ((1 << log_sector_size) - 1))
+ grub_util_error (_("unaligned device size"));
+
+ return (nr >> log_sector_size);
+# endif
+
+ fail:
+
+ /* In GNU/Hurd, stat() will return the right size. */
+#elif !defined (__GNU__)
+# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
+#endif
+
+ sector_size = 512;
+ log_sector_size = 9;
+
+ if (log_secsize)
+ *log_secsize = 9;
+
+ return st.st_size >> 9;
+}
+#endif
+
static grub_err_t
grub_util_biosdisk_open (const char *name, grub_disk_t disk)
{
size = grub_util_get_disk_size (map[drive].device);
if (size % 512)
- grub_util_error ("unaligned device size");
+ grub_util_error (_("unaligned device size"));
disk->total_sectors = size >> 9;
return GRUB_ERR_NONE;
}
-#elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
+#else
{
-# if defined(__NetBSD__)
- struct disklabel label;
-# else
- unsigned long long nr;
-# endif
int fd;
fd = open (map[drive].device, O_RDONLY);
if (fd == -1)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device);
+ disk->total_sectors = grub_util_get_fd_sectors (fd, &disk->log_sector_size);
+
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
# else
if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
# endif
- {
- close (fd);
- goto fail;
- }
- data->is_disk = 1;
-
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- if (ioctl (fd, DIOCGMEDIASIZE, &nr))
-# elif defined(__APPLE__)
- if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr))
-# elif defined(__NetBSD__)
- configure_device_driver (fd);
- if (ioctl (fd, DIOCGDINFO, &label) == -1)
-# else
- if (ioctl (fd, BLKGETSIZE64, &nr))
-# endif
- {
- close (fd);
- goto fail;
- }
+ data->is_disk = 1;
close (fd);
-# if defined (__APPLE__)
- disk->total_sectors = nr;
-# elif defined(__NetBSD__)
- disk->total_sectors = label.d_secperunit;
-# else
- disk->total_sectors = nr / 512;
-
- if (nr % 512)
- grub_util_error ("unaligned device size");
-# endif
-
grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
return GRUB_ERR_NONE;
}
-
- fail:
- /* In GNU/Hurd, stat() will return the right size. */
-#elif !defined (__GNU__)
-# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
#endif
- if (stat (map[drive].device, &st) < 0)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device);
-
- disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS;
-
- grub_util_info ("the size of %s is %lu", name, disk->total_sectors);
-
- return GRUB_ERR_NONE;
}
int
#endif /* HAVE_DEVICE_MAPPER */
}
+
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
+
/* FIXME: geom actually gives us the whole container hierarchy.
It can be used more efficiently than this. */
-static void
-follow_geom_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
+void
+grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
{
struct gmesh mesh;
struct gclass *class;
error = geom_gettree (&mesh);
if (error != 0)
- grub_util_error ("couldn't open geom");
+ grub_util_error (_("couldn't open geom"));
LIST_FOREACH (class, &mesh.lg_class, lg_class)
if (strcasecmp (class->lg_name, "part") == 0)
break;
if (!class)
- grub_util_error ("couldn't open geom part");
+ grub_util_error (_("couldn't open geom part"));
LIST_FOREACH (geom, &class->lg_geom, lg_geom)
{
struct gconfig *config;
grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name);
- follow_geom_up (name_tmp, &off, name_out);
+ grub_util_follow_gpart_up (name_tmp, &off, name_out);
free (name_tmp);
LIST_FOREACH (config, &provider->lg_config, lg_config)
if (strcasecmp (config->lg_name, "start") == 0)
grub_disk_addr_t out;
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return 0;
- follow_geom_up (dev + sizeof ("/dev/") - 1, &out, NULL);
+ grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
return out;
}
-#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO)
+
+#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__)
static grub_disk_addr_t
find_partition_start (const char *dev)
{
int fd;
-# if !defined(HAVE_DIOCGDINFO)
+#ifdef __sun__
+ struct extpart_info pinfo;
+# elif !defined(HAVE_DIOCGDINFO)
struct hd_geometry hdg;
# else /* defined(HAVE_DIOCGDINFO) */
struct disklabel label;
return 0;
}
-# if !defined(HAVE_DIOCGDINFO)
+#if defined(__sun__)
+ if (ioctl (fd, DKIOCEXTPARTINFO, &pinfo))
+# elif !defined(HAVE_DIOCGDINFO)
if (ioctl (fd, HDIO_GETGEO, &hdg))
# else /* defined(HAVE_DIOCGDINFO) */
# if defined(__NetBSD__)
close (fd);
-# if !defined(HAVE_DIOCGDINFO)
+#ifdef __sun__
+ return pinfo.p_start;
+# elif !defined(HAVE_DIOCGDINFO)
return hdg.start;
# else /* defined(HAVE_DIOCGDINFO) */
if (dev[0])
int i;
char real_dev[PATH_MAX];
struct linux_partition_cache *cache;
+ int missing = 0;
strcpy(real_dev, dev);
p = real_dev + len - 4;
format = "part%d";
}
+ else if (strncmp (real_dev, "/dev/disk/by-id/",
+ sizeof ("/dev/disk/by-id/") - 1) == 0)
+ {
+ p = real_dev + len;
+ format = "-part%d";
+ }
else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
{
p = real_dev + len;
fd = open (real_dev, O_RDONLY);
if (fd == -1)
- continue;
+ {
+ if (missing++ < 10)
+ continue;
+ else
+ return 0;
+ }
+ missing = 0;
close (fd);
start = find_partition_start (real_dev);
}
#endif /* __linux__ */
+#if defined(__linux__) && (!defined(__GLIBC__) || \
+ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
+ /* Maybe libc doesn't have large file support. */
+grub_err_t
+grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
+{
+ loff_t offset, result;
+ static int _llseek (uint filedes, ulong hi, ulong lo,
+ loff_t *res, uint wh);
+ _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
+ loff_t *, res, uint, wh);
+
+ offset = (loff_t) off;
+ if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
+ {
+ return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name);
+ }
+ return GRUB_ERR_NONE;
+}
+#else
+grub_err_t
+grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
+{
+ off_t offset = (off_t) off;
+
+ if (lseek (fd, offset, SEEK_SET) != offset)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name);
+ return 0;
+}
+#endif
+
static int
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
{
configure_device_driver (fd);
#endif /* defined(__NetBSD__) */
-#if defined(__linux__) && (!defined(__GLIBC__) || \
- ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
- /* Maybe libc doesn't have large file support. */
- {
- loff_t offset, result;
- static int _llseek (uint filedes, ulong hi, ulong lo,
- loff_t *res, uint wh);
- _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
- loff_t *, res, uint, wh);
-
- offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
- if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
- {
- grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
- close (fd);
- return -1;
- }
- }
-#else
- {
- off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
-
- if (lseek (fd, offset, SEEK_SET) != offset)
- {
- grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
- close (fd);
- return -1;
- }
- }
-#endif
+ if (grub_util_fd_seek (fd, map[disk->id].device,
+ sector << disk->log_sector_size))
+ {
+ close (fd);
+ return -1;
+ }
return fd;
}
/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
error occurs, otherwise return LEN. */
-static ssize_t
-nread (int fd, char *buf, size_t len)
+ssize_t
+grub_util_fd_read (int fd, char *buf, size_t len)
{
ssize_t size = len;
sectors that are read together with the MBR in one read. It
should only remap the MBR, so we split the read in two
parts. -jochen */
- if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE)
+ if (grub_util_fd_read (fd, buf, (1 << disk->log_sector_size))
+ != (1 << disk->log_sector_size))
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
return grub_errno;
}
- buf += GRUB_DISK_SECTOR_SIZE;
+ buf += (1 << disk->log_sector_size);
size--;
}
#endif /* __linux__ */
- if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS)
- != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+ if (grub_util_fd_read (fd, buf, size << disk->log_sector_size)
+ != (ssize_t) (size << disk->log_sector_size))
grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
return grub_errno;
if (fd < 0)
return grub_errno;
- if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS)
- != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+ if (nwrite (fd, buf, size << disk->log_sector_size)
+ != (ssize_t) (size << disk->log_sector_size))
grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
return grub_errno;
continue;
if (*p != '(')
- show_error ("No open parenthesis found");
+ show_error (_("No open parenthesis found"));
p++;
/* Find a free slot. */
drive = find_free_slot ();
if (drive < 0)
- show_error ("Map table size exceeded");
+ show_error (_("Map table size exceeded"));
e = p;
p = strchr (p, ')');
if (! p)
- show_error ("No close parenthesis found");
+ show_error (_("No close parenthesis found"));
map[drive].drive = xmalloc (p - e + sizeof ('\0'));
strncpy (map[drive].drive, e, p - e + sizeof ('\0'));
p++;
if (*p == '\0')
- show_error ("No filename found");
+ show_error (_("No filename found"));
/* NUL-terminate the filename. */
e = p;
{
map[drive].device = xmalloc (PATH_MAX);
if (! realpath (p, map[drive].device))
- grub_util_error ("cannot get the real path of `%s'", p);
+ grub_util_error (_("cannot get the real path of `%s'"), p);
}
else
#endif
static char *
make_device_name (int drive, int dos_part, int bsd_part)
{
- char *ret;
- char *dos_part_str = NULL;
- char *bsd_part_str = NULL;
-
+ char *ret, *ptr, *end;
+ const char *iptr;
+
+ ret = xmalloc (strlen (map[drive].drive) * 2
+ + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
+ ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
+ end = (ret + strlen (map[drive].drive) * 2
+ + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
+ ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
+ ptr = ret;
+ for (iptr = map[drive].drive; *iptr; iptr++)
+ {
+ if (*iptr == ',')
+ *ptr++ = '\\';
+ *ptr++ = *iptr;
+ }
+ *ptr = 0;
if (dos_part >= 0)
- dos_part_str = xasprintf (",%d", dos_part + 1);
-
+ snprintf (ptr, end - ptr, ",%d", dos_part + 1);
+ ptr += strlen (ptr);
if (bsd_part >= 0)
- bsd_part_str = xasprintf (",%d", bsd_part + 1);
-
- ret = xasprintf ("%s%s%s", map[drive].drive,
- dos_part_str ? : "",
- bsd_part_str ? : "");
-
- if (dos_part_str)
- free (dos_part_str);
-
- if (bsd_part_str)
- free (bsd_part_str);
+ snprintf (ptr, end - ptr, ",%d", bsd_part + 1);
return ret;
}
if (tree)
dm_tree_free (tree);
free (path);
- char *ret = grub_find_device (NULL, (major << 8) | minor);
+ char *ret = grub_find_device ("/dev",
+ (major << 8) | minor);
return ret;
}
char *out, *out2;
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return xstrdup (os_dev);
- follow_geom_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
+ grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
out2 = xasprintf ("/dev/%s", out);
free (out);
}
return path;
+#elif defined (__sun__)
+ char *colon = grub_strrchr (os_dev, ':');
+ if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
+ && colon)
+ {
+ char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
+ grub_memcpy (ret, os_dev, colon - os_dev);
+ grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
+ return ret;
+ }
+ else
+ return xstrdup (os_dev);
#else
# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
return xstrdup (os_dev);
#endif
}
+#if defined(__sun__)
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0)
+ return 1;
+ if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1),
+ ":q,raw", (sizeof (":q,raw") - 1)) == 0)
+ return 1;
+ return 0;
+}
+#endif
+
#if defined(__linux__) || defined(__CYGWIN__)
static int
device_is_wholedisk (const char *os_dev)
}
if (!add)
- return -1;
+ {
+ free (os_disk);
+ return -1;
+ }
if (i == ARRAY_SIZE (map))
grub_util_error (_("device count exceeds limit"));
{
struct stat st;
int drive;
+ char *sys_disk;
+
+ grub_util_info ("Looking for %s", os_dev);
if (stat (os_dev, &st) < 0)
{
return 0;
}
- if (grub_strcmp (os_dev,
- convert_system_partition_to_system_disk (os_dev, &st)) == 0)
- return make_device_name (drive, -1, -1);
+ sys_disk = convert_system_partition_to_system_disk (os_dev, &st);
+ if (grub_strcmp (os_dev, sys_disk) == 0)
+ {
+ free (sys_disk);
+ return make_device_name (drive, -1, -1);
+ }
+ free (sys_disk);
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
if (! S_ISCHR (st.st_mode))
#else
if (! S_ISBLK (st.st_mode))
#endif
return make_device_name (drive, -1, -1);
-#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
partition, so mapping them to GRUB devices is not trivial.
name = make_device_name (drive, -1, -1);
-# if !defined(HAVE_DIOCGDINFO)
+# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
return name;
# else /* defined(HAVE_DIOCGDINFO) */
if (partname == NULL)
{
grub_disk_close (disk);
+ grub_util_info ("cannot find the partition of `%s'", os_dev);
grub_error (GRUB_ERR_BAD_DEVICE,
"cannot find the partition of `%s'", os_dev);
return 0;
struct stat st;
int fd;
+ if (disk->dev != &grub_util_biosdisk_dev)
+ return 0;
+
fd = open (map[disk->id].device, O_RDONLY);
/* Shouldn't happen. */
if (fd == -1)
/* Shouldn't happen either. */
if (fstat (fd, &st) < 0)
- return 0;
+ {
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
#if defined(__NetBSD__)
if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)