]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Add grub-probe support for NetBSD.
authorGrégoire Sutre <gregoire.sutre@gmail.com>
Sat, 10 Apr 2010 15:07:33 +0000 (17:07 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 10 Apr 2010 15:07:33 +0000 (17:07 +0200)
* util/getroot.c (find_root_device): Convert block device to
character device on NetBSD.
* util/probe.c (probe): Require character device on NetBSD.
* util/hostdisk.c: NetBSD specific headers.
(configure_device_driver): new function to tune device driver
parameters (currently only for NetBSD floppy driver).
(grub_util_biosdisk_open): NetBSD specific code (get disk size
via disklabel ioctl).
(open_device): call configure_device_driver on NetBSD.
(convert_system_partition_to_system_disk): NetBSD specific code.
(device_is_wholedisk): Likewise.
(grub_util_biosdisk_get_grub_dev): Likewise.
(make_device_name): Fixed a typo in bsd_part_str.
* configure.ac: check for opendisk() and getrawpartition() on
NetBSD and set LIBUTIL.
* Makefile.in: add LIBUTIL to LIBS.

ChangeLog
Makefile.in
configure.ac
util/getroot.c
util/hostdisk.c

index 38171b1f019bf8f35293c3e73601ddeb7f6725ad..f71c37ad006b42bb6560bec2e540d2c9b984d69d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2010-04-10  Grégoire Sutre  <gregoire.sutre@gmail.com>
+
+       Add grub-probe support for NetBSD.
+
+       * util/getroot.c (find_root_device): Convert block device to
+       character device on NetBSD.
+       * util/probe.c (probe): Require character device on NetBSD.
+       * util/hostdisk.c: NetBSD specific headers.
+       (configure_device_driver): new function to tune device driver
+       parameters (currently only for NetBSD floppy driver).
+       (grub_util_biosdisk_open): NetBSD specific code (get disk size
+       via disklabel ioctl).
+       (open_device): call configure_device_driver on NetBSD.
+       (convert_system_partition_to_system_disk): NetBSD specific code.
+       (device_is_wholedisk): Likewise.
+       (grub_util_biosdisk_get_grub_dev): Likewise.
+       (make_device_name): Fixed a typo in bsd_part_str.
+       * configure.ac: check for opendisk() and getrawpartition() on
+       NetBSD and set LIBUTIL.
+       * Makefile.in: add LIBUTIL to LIBS.
+
 2010-04-10  BVK Chaitanya  <bvk.groups@gmail.com>
 
        Documentation fix.
index 898e6b92ac03fd4d5ff5ca9a49d4b772a98afc6f..08c25971fecdc4f88834c881bae474a2c6fb90cb 100644 (file)
@@ -45,6 +45,9 @@ pkglibdir =  $(libdir)/`echo @PACKAGE_TARNAME@/$(target_cpu)-$(platform) | sed '
 LIBINTL = @LIBINTL@
 TARGET_NO_MODULES = @TARGET_NO_MODULES@
 
+# Util library.
+LIBUTIL = @LIBUTIL@
+
 XGETTEXT = @XGETTEXT@
 MSGMERGE = @MSGMERGE@
 MSGFMT = @MSGFMT@
@@ -76,7 +79,7 @@ MKDIR_P = @MKDIR_P@
 
 mkinstalldirs = $(srcdir)/mkinstalldirs
 
-LIBS = @LIBS@ $(LIBINTL)
+LIBS = @LIBS@ $(LIBINTL) $(LIBUTIL)
 
 CC = @CC@
 CFLAGS = @CFLAGS@
index cabae08e38826327495e7bb1b48419b646309755..afdb7b32d7127f2425d40b6999d7a2a1eaf7cdab 100644 (file)
@@ -130,6 +130,7 @@ case "$host_os" in
   gnu*)                                host_kernel=hurd ;;
   linux*)                      host_kernel=linux ;;
   freebsd* | kfreebsd*-gnu)    host_kernel=kfreebsd ;;
+  netbsd*)                     host_kernel=netbsd ;;
   cygwin)                      host_kernel=windows ;;
 esac
 
@@ -242,6 +243,20 @@ AC_CHECK_FUNCS(memmove sbrk strdup lstat getuid getgid)
 AC_CHECK_HEADERS(sys/mkdev.h sys/sysmacros.h malloc.h termios.h sys/types.h)
 AC_CHECK_HEADERS(unistd.h string.h strings.h sys/stat.h sys/fcntl.h limits.h)
 
+# For opendisk() and getrawpartition() on NetBSD.
+# Used in util/deviceiter.c and in util/hostdisk.c.
+AC_CHECK_HEADER([util.h], [
+  AC_CHECK_LIB([util], [opendisk], [
+    LIBUTIL="-lutil"
+    AC_DEFINE(HAVE_OPENDISK, 1, [Define if opendisk() in -lutil can be used])
+  ])
+  AC_CHECK_LIB([util], [getrawpartition], [
+    LIBUTIL="-lutil"
+    AC_DEFINE(HAVE_GETRAWPARTITION, 1, [Define if getrawpartition() in -lutil can be used])
+  ])
+])
+AC_SUBST([LIBUTIL])
+
 #
 # Check for target programs.
 #
index 82393635cd33bbfcbb24da19af49a32af8dbc4be..94eadc5e113f85b77fbb185332c838b4884e0ecb 100644 (file)
@@ -264,10 +264,17 @@ find_root_device (const char *dir, dev_t dev)
          /* Found!  */
          char *res;
          char *cwd;
+#if defined(__NetBSD__)
+         /* Convert this block device to its character (raw) device.  */
+         const char *template = "%s/r%s";
+#else
+         /* Keep the device name as it is.  */
+         const char *template = "%s/%s";
+#endif
 
          cwd = xgetcwd ();
-         res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 2);
-         sprintf (res, "%s/%s", cwd, ent->d_name);
+         res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3);
+         sprintf (res, template, cwd, ent->d_name);
          strip_extra_slashes (res);
          free (cwd);
 
index 3ecc953916b10b606802bd5324fa33045c67088e..8a412da5537f45d50f58f2c6e77a2da1ca4a250b 100644 (file)
@@ -98,6 +98,18 @@ struct hd_geometry
 # include <sys/disk.h>
 #endif
 
+#if defined(__NetBSD__)
+# include <sys/ioctl.h>
+# include <sys/disklabel.h>    /* struct disklabel */
+# ifdef HAVE_GETRAWPARTITION
+#  include <util.h>    /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+# include <sys/fdio.h>
+# ifndef RAW_FLOPPY_MAJOR
+#  define RAW_FLOPPY_MAJOR     9
+# endif /* ! RAW_FLOPPY_MAJOR */
+#endif /* defined(__NetBSD__) */
+
 struct
 {
   char *drive;
@@ -129,6 +141,31 @@ have_devfs (void)
 }
 #endif /* __linux__ */
 
+#if defined(__NetBSD__)
+/* Adjust device driver parameters.  This function should be called just
+   after successfully opening the device.  For now, it simply prevents the
+   floppy driver from retrying operations on failure, as otherwise the
+   driver takes a while to abort when there is no floppy in the drive.  */
+static void
+configure_device_driver (int fd)
+{
+  struct stat st;
+
+  if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
+    return;
+  if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
+    {
+      int floppy_opts;
+
+      if (ioctl (fd, FDIOCGETOPTS, &floppy_opts) == -1)
+       return;
+      floppy_opts |= FDOPT_NORETRY;
+      if (ioctl (fd, FDIOCSETOPTS, &floppy_opts) == -1)
+       return;
+    }
+}
+#endif /* defined(__NetBSD__) */
+
 static int
 find_grub_drive (const char *name)
 {
@@ -204,16 +241,20 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
     return GRUB_ERR_NONE;
   }
 #elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
-      defined(__FreeBSD_kernel__) || defined(__APPLE__)
+      defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
   {
+# 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);
 
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
+# 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))
@@ -227,6 +268,9 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
     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
@@ -237,14 +281,16 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
 
     close (fd);
 
-#if defined (__APPLE__)
+# if defined (__APPLE__)
     disk->total_sectors = nr;
-#else
+# 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
+# endif
 
     grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
 
@@ -483,6 +529,10 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
     }
 #endif /* ! __linux__ */
 
+#if defined(__NetBSD__)
+  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.  */
@@ -811,7 +861,7 @@ make_device_name (int drive, int dos_part, int bsd_part)
     dos_part_str = xasprintf (",%d", dos_part + 1);
 
   if (bsd_part >= 0)
-    bsd_part_str = xasprintf (",%c", dos_part + 'a');
+    bsd_part_str = xasprintf (",%c", bsd_part + 'a');
 
   ret = xasprintf ("%s%s%s", map[drive].drive,
                    dos_part_str ? : "",
@@ -981,6 +1031,27 @@ convert_system_partition_to_system_disk (const char *os_dev)
     }
   return path;
 
+#elif defined(__NetBSD__)
+  /* NetBSD uses "/dev/r[wsc]d[0-9]+[a-z]".  */
+  char *path = xstrdup (os_dev);
+  if (strncmp ("/dev/rwd", path, 8) == 0 ||
+      strncmp ("/dev/rsd", path, 8) == 0 ||
+      strncmp ("/dev/rcd", path, 8) == 0)
+    {
+      char *q;
+      q = path + strlen(path) - 1;    /* last character */
+      if (grub_isalpha(*q) && grub_isdigit(*(q-1)))
+        {
+          int rawpart = -1;
+# ifdef HAVE_GETRAWPARTITION
+          rawpart = getrawpartition();
+# endif /* HAVE_GETRAWPARTITION */
+          if (rawpart >= 0)
+            *q = 'a' + rawpart;
+        }
+    }
+  return path;
+
 #else
 # warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
   return xstrdup (os_dev);
@@ -999,6 +1070,26 @@ device_is_wholedisk (const char *os_dev)
 }
 #endif
 
+#if defined(__NetBSD__)
+/* Try to determine whether a given device name corresponds to a whole disk.
+   This function should give in most cases a definite answer, but it may
+   actually give an approximate one in the following sense: if the return
+   value is 0 then the device name does not correspond to a whole disk.  */
+static int
+device_is_wholedisk (const char *os_dev)
+{
+  int len = strlen (os_dev);
+  int rawpart = -1;
+
+# ifdef HAVE_GETRAWPARTITION
+  rawpart = getrawpartition();
+# endif /* HAVE_GETRAWPARTITION */
+  if (rawpart < 0)
+    return 1;
+  return (os_dev[len - 1] == ('a' + rawpart));
+}
+#endif /* defined(__NetBSD__) */
+
 static int
 find_system_device (const char *os_dev)
 {
@@ -1051,14 +1142,14 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
       == 0)
     return make_device_name (drive, -1, -1);
 
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
   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__)
+#if defined(__linux__) || defined(__CYGWIN__) || defined(__NetBSD__)
   /* Linux counts partitions uniformly, whether a BSD partition or a DOS
      partition, so mapping them to GRUB devices is not trivial.
      Here, get the start sector of a partition by HDIO_GETGEO, and
@@ -1066,12 +1157,24 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
 
      Cygwin /dev/sdXN emulation uses Windows partition mapping. It
      does not count the extended partition and missing primary
-     partitions.  Use same method as on Linux here.  */
+     partitions.  Use same method as on Linux here.
+
+     For NetBSD, proceed as for Linux, except that the start sector is
+     obtained from the disk label.  */
   {
     char *name;
     grub_disk_t disk;
     int fd;
+# if !defined(__NetBSD__)
+    const char *disk_info_msg = "geometry";
     struct hd_geometry hdg;
+    typeof (hdg.start) p_offset;
+# else /* defined(__NetBSD__) */
+    const char *disk_info_msg = "label";
+    struct disklabel label;
+    int index;
+    u_int32_t p_offset;
+# endif /* !defined(__NetBSD__) */
     int dos_part = -1;
     int bsd_part = -1;
     auto int find_partition (grub_disk_t dsk,
@@ -1086,7 +1189,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
 
        part_start = grub_partition_get_start (partition);
 
-       if (hdg.start == part_start)
+       if (p_offset == part_start)
          {
            if (partition->parent)
              {
@@ -1107,21 +1210,33 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
 
     name = make_device_name (drive, -1, -1);
 
+# if !defined(__NetBSD__)
     if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
       return name;
+# else /* defined(__NetBSD__) */
+    /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
+     * different, we know that os_dev is of the form /dev/r[wsc]d[0-9]+[a-z]
+     * and in particular it cannot be a floppy device.  */
+    index = os_dev[strlen(os_dev) - 1] - 'a';
+# endif /* !defined(__NetBSD__) */
 
     fd = open (os_dev, O_RDONLY);
     if (fd == -1)
       {
-       grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", os_dev);
+       grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk %s", os_dev, disk_info_msg);
        free (name);
        return 0;
       }
 
+# if !defined(__NetBSD__)
     if (ioctl (fd, HDIO_GETGEO, &hdg))
+# else /* defined(__NetBSD__) */
+    configure_device_driver (fd);
+    if (ioctl (fd, DIOCGDINFO, &label) == -1)
+# endif /* !defined(__NetBSD__) */
       {
        grub_error (GRUB_ERR_BAD_DEVICE,
-                   "cannot get geometry of `%s'", os_dev);
+                   "cannot get disk %s of `%s'", disk_info_msg, os_dev);
        close (fd);
        free (name);
        return 0;
@@ -1129,9 +1244,22 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
 
     close (fd);
 
-    grub_util_info ("%s starts from %lu", os_dev, hdg.start);
+# if !defined(__NetBSD__)
+    p_offset = hdg.start;
+# else /* defined(__NetBSD__) */
+    if (index >= label.d_npartitions)
+      {
+       grub_error (GRUB_ERR_BAD_DEVICE,
+                   "no disk label entry for `%s'", os_dev);
+       free (name);
+       return 0;
+      }
+    p_offset = label.d_partitions[index].p_offset;
+# endif /* !defined(__NetBSD__) */
+
+    grub_util_info ("%s starts from %lu", os_dev, p_offset);
 
-    if (hdg.start == 0 && device_is_wholedisk (os_dev))
+    if (p_offset == 0 && device_is_wholedisk (os_dev))
       return name;
 
     grub_util_info ("opening the device %s", name);