grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Remove nested functions from device iterators


From: Colin Watson
Subject: [PATCH] Remove nested functions from device iterators
Date: Wed, 16 Jan 2013 14:07:54 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

Part four of my nested functions patch set.  (I promise that they will
start getting less indigestibly enormous soon, although the filesystems
upheaval is still to come!)  There are lots of little size increases in
modules here due to passing extra hook data arguments through, but as
you can see it still results in smaller uncompressed and compressed
kernel images and smaller typical core images:

  DOWN: obj/amd64-efi/grub-core/kernel.img (96960 > 96824) - change: -136
  DOWN: obj/i386-coreboot/grub-core/kernel.img (27912 > 27864) - change: -48
  DOWN: obj/i386-efi/grub-core/kernel.img (59528 > 59488) - change: -40
  DOWN: obj/i386-ieee1275/grub-core/kernel.img (48404 > 48360) - change: -44
  DOWN: obj/i386-pc/grub-core/kernel.img (28896 > 28848) - change: -48
  UP:   obj/amd64-efi/grub-core/ahci.mod (13352 < 13368) - change: 16
  DOWN: obj/amd64-efi/grub-core/ata.mod (8680 > 8616) - change: -64
  DOWN: obj/amd64-efi/grub-core/btrfs.mod (19224 > 19112) - change: -112
  UP:   obj/amd64-efi/grub-core/cryptodisk.mod (13832 < 13848) - change: 16
  DOWN: obj/amd64-efi/grub-core/diskfilter.mod (13872 > 13816) - change: -56
  DOWN: obj/amd64-efi/grub-core/ldm.mod (8536 > 8504) - change: -32
  UP:   obj/amd64-efi/grub-core/loopback.mod (4720 < 4736) - change: 16
  DOWN: obj/amd64-efi/grub-core/ls.mod (7032 > 7000) - change: -32
  UP:   obj/amd64-efi/grub-core/normal.mod (175880 < 175896) - change: 16
  UP:   obj/amd64-efi/grub-core/part_acorn.mod (2288 < 2304) - change: 16
  UP:   obj/amd64-efi/grub-core/part_amiga.mod (2568 < 2584) - change: 16
  UP:   obj/amd64-efi/grub-core/part_bsd.mod (4160 < 4176) - change: 16
  UP:   obj/amd64-efi/grub-core/part_gpt.mod (3216 < 3232) - change: 16
  UP:   obj/amd64-efi/grub-core/part_msdos.mod (3024 < 3040) - change: 16
  UP:   obj/amd64-efi/grub-core/part_plan.mod (2512 < 2528) - change: 16
  UP:   obj/amd64-efi/grub-core/part_sun.mod (2200 < 2216) - change: 16
  UP:   obj/amd64-efi/grub-core/part_sunpc.mod (2440 < 2456) - change: 16
  DOWN: obj/amd64-efi/grub-core/regexp.mod (79056 > 79008) - change: -48
  DOWN: obj/amd64-efi/grub-core/scsi.mod (7792 > 7760) - change: -32
  DOWN: obj/amd64-efi/grub-core/search_fs_file.mod (5128 > 5064) - change: -64
  DOWN: obj/amd64-efi/grub-core/search_fs_uuid.mod (5072 > 4992) - change: -80
  DOWN: obj/amd64-efi/grub-core/search_label.mod (5008 > 4936) - change: -72
  UP:   obj/amd64-efi/grub-core/usbms.mod (11344 < 11360) - change: 16
  DOWN: obj/amd64-efi/grub-core/zfs.mod (54168 > 54136) - change: -32
  UP:   obj/i386-coreboot/grub-core/ahci.mod (8656 < 8668) - change: 12
  DOWN: obj/i386-coreboot/grub-core/ata.mod (5436 > 5420) - change: -16
  DOWN: obj/i386-coreboot/grub-core/btrfs.mod (14296 > 14168) - change: -128
  UP:   obj/i386-coreboot/grub-core/cryptodisk.mod (8728 < 8732) - change: 4
  DOWN: obj/i386-coreboot/grub-core/diskfilter.mod (9724 > 9700) - change: -24
  DOWN: obj/i386-coreboot/grub-core/ldm.mod (6772 > 6756) - change: -16
  UP:   obj/i386-coreboot/grub-core/loopback.mod (2920 < 2932) - change: 12
  DOWN: obj/i386-coreboot/grub-core/ls.mod (4320 > 4292) - change: -28
  UP:   obj/i386-coreboot/grub-core/normal.mod (111972 < 111980) - change: 8
  UP:   obj/i386-coreboot/grub-core/part_acorn.mod (1632 < 1668) - change: 36
  UP:   obj/i386-coreboot/grub-core/part_amiga.mod (1796 < 1808) - change: 12
  UP:   obj/i386-coreboot/grub-core/part_apple.mod (2064 < 2076) - change: 12
  UP:   obj/i386-coreboot/grub-core/part_dvh.mod (1460 < 1464) - change: 4
  UP:   obj/i386-coreboot/grub-core/part_gpt.mod (2368 < 2376) - change: 8
  UP:   obj/i386-coreboot/grub-core/part_msdos.mod (2352 < 2364) - change: 12
  DOWN: obj/i386-coreboot/grub-core/part_plan.mod (1808 > 1800) - change: -8
  UP:   obj/i386-coreboot/grub-core/part_sun.mod (1500 < 1512) - change: 12
  UP:   obj/i386-coreboot/grub-core/part_sunpc.mod (1608 < 1620) - change: 12
  UP:   obj/i386-coreboot/grub-core/pata.mod (4676 < 4688) - change: 12
  DOWN: obj/i386-coreboot/grub-core/regexp.mod (51592 > 51564) - change: -28
  DOWN: obj/i386-coreboot/grub-core/scsi.mod (5068 > 5060) - change: -8
  DOWN: obj/i386-coreboot/grub-core/search_fs_file.mod (3304 > 3236) - change: 
-68
  DOWN: obj/i386-coreboot/grub-core/search_fs_uuid.mod (3276 > 3208) - change: 
-68
  DOWN: obj/i386-coreboot/grub-core/search_label.mod (3208 > 3140) - change: -68
  UP:   obj/i386-coreboot/grub-core/usbms.mod (7180 < 7192) - change: 12
  DOWN: obj/i386-coreboot/grub-core/zfs.mod (36560 > 36528) - change: -32
  DOWN: obj/i386-efi/grub-core/ata.mod (5576 > 5552) - change: -24
  DOWN: obj/i386-efi/grub-core/btrfs.mod (14640 > 14520) - change: -120
  UP:   obj/i386-efi/grub-core/cryptodisk.mod (8840 < 8844) - change: 4
  DOWN: obj/i386-efi/grub-core/diskfilter.mod (10024 > 10000) - change: -24
  DOWN: obj/i386-efi/grub-core/ldm.mod (6996 > 6964) - change: -32
  DOWN: obj/i386-efi/grub-core/ls.mod (4496 > 4476) - change: -20
  UP:   obj/i386-efi/grub-core/normal.mod (116464 < 116468) - change: 4
  UP:   obj/i386-efi/grub-core/part_apple.mod (2060 < 2064) - change: 4
  UP:   obj/i386-efi/grub-core/part_bsd.mod (2880 < 2896) - change: 16
  UP:   obj/i386-efi/grub-core/part_plan.mod (1824 < 1828) - change: 4
  UP:   obj/i386-efi/grub-core/part_sunpc.mod (1632 < 1636) - change: 4
  DOWN: obj/i386-efi/grub-core/regexp.mod (53464 > 53440) - change: -24
  DOWN: obj/i386-efi/grub-core/scsi.mod (5088 > 5084) - change: -4
  DOWN: obj/i386-efi/grub-core/search_fs_file.mod (3440 > 3384) - change: -56
  DOWN: obj/i386-efi/grub-core/search_fs_uuid.mod (3416 > 3360) - change: -56
  DOWN: obj/i386-efi/grub-core/search_label.mod (3356 > 3300) - change: -56
  DOWN: obj/i386-efi/grub-core/zfs.mod (37712 > 37672) - change: -40
  UP:   obj/i386-ieee1275/grub-core/ahci.mod (8656 < 8668) - change: 12
  DOWN: obj/i386-ieee1275/grub-core/ata.mod (5436 > 5420) - change: -16
  DOWN: obj/i386-ieee1275/grub-core/btrfs.mod (14296 > 14168) - change: -128
  UP:   obj/i386-ieee1275/grub-core/cryptodisk.mod (8720 < 8724) - change: 4
  DOWN: obj/i386-ieee1275/grub-core/diskfilter.mod (9724 > 9700) - change: -24
  DOWN: obj/i386-ieee1275/grub-core/ldm.mod (6772 > 6756) - change: -16
  UP:   obj/i386-ieee1275/grub-core/loopback.mod (2848 < 2860) - change: 12
  DOWN: obj/i386-ieee1275/grub-core/ls.mod (4312 > 4284) - change: -28
  UP:   obj/i386-ieee1275/grub-core/nand.mod (2520 < 2536) - change: 16
  UP:   obj/i386-ieee1275/grub-core/normal.mod (111964 < 111972) - change: 8
  UP:   obj/i386-ieee1275/grub-core/part_acorn.mod (1632 < 1668) - change: 36
  UP:   obj/i386-ieee1275/grub-core/part_amiga.mod (1796 < 1808) - change: 12
  UP:   obj/i386-ieee1275/grub-core/part_apple.mod (2064 < 2076) - change: 12
  UP:   obj/i386-ieee1275/grub-core/part_dvh.mod (1460 < 1464) - change: 4
  UP:   obj/i386-ieee1275/grub-core/part_gpt.mod (2368 < 2376) - change: 8
  UP:   obj/i386-ieee1275/grub-core/part_msdos.mod (2352 < 2364) - change: 12
  DOWN: obj/i386-ieee1275/grub-core/part_plan.mod (1808 > 1800) - change: -8
  UP:   obj/i386-ieee1275/grub-core/part_sun.mod (1500 < 1512) - change: 12
  UP:   obj/i386-ieee1275/grub-core/part_sunpc.mod (1608 < 1620) - change: 12
  UP:   obj/i386-ieee1275/grub-core/pata.mod (4676 < 4688) - change: 12
  DOWN: obj/i386-ieee1275/grub-core/regexp.mod (51584 > 51556) - change: -28
  DOWN: obj/i386-ieee1275/grub-core/scsi.mod (5068 > 5060) - change: -8
  DOWN: obj/i386-ieee1275/grub-core/search_fs_file.mod (3304 > 3236) - change: 
-68
  DOWN: obj/i386-ieee1275/grub-core/search_fs_uuid.mod (3276 > 3208) - change: 
-68
  DOWN: obj/i386-ieee1275/grub-core/search_label.mod (3208 > 3140) - change: -68
  UP:   obj/i386-ieee1275/grub-core/usbms.mod (7180 < 7192) - change: 12
  DOWN: obj/i386-ieee1275/grub-core/zfs.mod (36560 > 36528) - change: -32
  UP:   obj/i386-pc/grub-core/ahci.mod (8656 < 8668) - change: 12
  DOWN: obj/i386-pc/grub-core/ata.mod (5436 > 5420) - change: -16
  UP:   obj/i386-pc/grub-core/biosdisk.mod (4664 < 4684) - change: 20
  DOWN: obj/i386-pc/grub-core/btrfs.mod (14296 > 14168) - change: -128
  UP:   obj/i386-pc/grub-core/cryptodisk.mod (8728 < 8732) - change: 4
  DOWN: obj/i386-pc/grub-core/diskfilter.mod (9724 > 9700) - change: -24
  DOWN: obj/i386-pc/grub-core/ldm.mod (6772 > 6756) - change: -16
  UP:   obj/i386-pc/grub-core/loopback.mod (2920 < 2932) - change: 12
  DOWN: obj/i386-pc/grub-core/ls.mod (4320 > 4292) - change: -28
  UP:   obj/i386-pc/grub-core/normal.mod (111944 < 111952) - change: 8
  UP:   obj/i386-pc/grub-core/part_acorn.mod (1632 < 1668) - change: 36
  UP:   obj/i386-pc/grub-core/part_amiga.mod (1796 < 1808) - change: 12
  UP:   obj/i386-pc/grub-core/part_apple.mod (2064 < 2076) - change: 12
  UP:   obj/i386-pc/grub-core/part_dvh.mod (1460 < 1464) - change: 4
  UP:   obj/i386-pc/grub-core/part_gpt.mod (2368 < 2376) - change: 8
  UP:   obj/i386-pc/grub-core/part_msdos.mod (2352 < 2364) - change: 12
  DOWN: obj/i386-pc/grub-core/part_plan.mod (1808 > 1800) - change: -8
  UP:   obj/i386-pc/grub-core/part_sun.mod (1500 < 1512) - change: 12
  UP:   obj/i386-pc/grub-core/part_sunpc.mod (1608 < 1620) - change: 12
  UP:   obj/i386-pc/grub-core/pata.mod (4676 < 4688) - change: 12
  DOWN: obj/i386-pc/grub-core/plan9.mod (6296 > 6160) - change: -136
  DOWN: obj/i386-pc/grub-core/regexp.mod (51592 > 51564) - change: -28
  DOWN: obj/i386-pc/grub-core/scsi.mod (5068 > 5060) - change: -8
  DOWN: obj/i386-pc/grub-core/search_fs_file.mod (3304 > 3236) - change: -68
  DOWN: obj/i386-pc/grub-core/search_fs_uuid.mod (3276 > 3208) - change: -68
  DOWN: obj/i386-pc/grub-core/search_label.mod (3208 > 3140) - change: -68
  UP:   obj/i386-pc/grub-core/usbms.mod (7180 < 7192) - change: 12
  DOWN: obj/i386-pc/grub-core/zfs.mod (36560 > 36528) - change: -32
  DOWN: i386-pc core image (biosdisk ext2 part_msdos) (26691 > 26670) - change: 
-21
  DOWN: i386-pc core image (biosdisk ext2 part_msdos lvm mdraid1x) (34046 > 
34033) - change: -13

In accordance with Vladimir's latest mail, I didn't document everything
in the ChangeLog, although I do generally feel uncomfortable about
making major internal interface changes without ChangeLog-style
documentation, so I compromised and produced file-by-file descriptions
of just the changes to include/.  Does this look reasonable?  It's
certainly much shorter and clearer than a full old-style ChangeLog entry
would have been.

=== modified file 'ChangeLog'
--- ChangeLog   2013-01-16 12:41:16 +0000
+++ ChangeLog   2013-01-16 14:05:42 +0000
@@ -1,3 +1,29 @@
+2013-01-16  Colin Watson  <address@hidden>
+
+       Remove nested functions from device iteration.
+
+       * include/grub/arc/arc.h (grub_arc_iterate_devs_hook_t): New type.
+       (grub_arc_iterate_devs): Add hook_data argument.
+       * include/grub/ata.h (grub_ata_dev_iterate_hook_t): New type.
+       (struct grub_ata_dev.iterate): Add hook_data argument.
+       * include/grub/device.h (grub_device_iterate_hook_t): New type.
+       (grub_device_iterate): Add hook_data argument.
+       * include/grub/disk.h (grub_disk_dev_iterate_hook_t): New type.
+       (struct grub_disk_dev.iterate): Add hook_data argument.
+       (grub_disk_dev_iterate): Likewise.
+       * include/grub/gpt_partition.h (grub_gpt_partition_map_iterate):
+       Likewise.
+       * include/grub/msdos_partition.h (grub_partition_msdos_iterate):
+       Likewise.
+       * include/grub/partition.h (grub_partition_iterate_hook_t): New
+       type.
+       (struct grub_partition_map.iterate): Add hook_data argument.
+       (grub_partition_iterate): Likewise.
+       * include/grub/scsi.h (grub_scsi_dev_iterate_hook_t): New type.
+       (struct grub_scsi_dev.iterate): Add hook_data argument.
+
+       Update all callers.
+
 2013-01-16  Vladimir Serbinenko  <address@hidden>
 
        Improve bidi handling in entry editor.

=== modified file 'grub-core/commands/arc/lsdev.c'
--- grub-core/commands/arc/lsdev.c      2011-05-13 14:36:05 +0000
+++ grub-core/commands/arc/lsdev.c      2013-01-15 17:00:40 +0000
@@ -24,18 +24,22 @@
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
+/* Helper for grub_cmd_lsdev.  */
+static int
+grub_cmd_lsdev_iter (const char *name,
+                    const struct grub_arc_component *comp __attribute__ 
((unused)),
+                    void *data __attribute__ ((unused)))
+{
+  grub_printf ("%s\n", name);
+  return 0;
+}
+
 static grub_err_t
 grub_cmd_lsdev (grub_command_t cmd __attribute__ ((unused)),
                int argc __attribute__ ((unused)),
                char **args __attribute__ ((unused)))
 {
-  auto int hook (const char *name, const struct grub_arc_component *comp);
-  int hook (const char *name, const struct grub_arc_component *comp 
__attribute__ ((unused)))
-  {
-    grub_printf ("%s\n", name);
-    return 0;
-  }
-  grub_arc_iterate_devs (hook, 0);
+  grub_arc_iterate_devs (grub_cmd_lsdev_iter, 0, 0);
   return 0;
 }
 

=== modified file 'grub-core/commands/ls.c'
--- grub-core/commands/ls.c     2012-06-26 01:45:46 +0000
+++ grub-core/commands/ls.c     2013-01-15 17:18:31 +0000
@@ -45,21 +45,24 @@ static const struct grub_arg_option opti
 
 static const char grub_human_sizes[] = {' ', 'K', 'M', 'G', 'T'};
 
-static grub_err_t
-grub_ls_list_devices (int longlist)
+/* Helper for grub_ls_list_devices.  */
+static int
+grub_ls_print_devices (const char *name, void *data)
 {
-  auto int grub_ls_print_devices (const char *name);
-  int grub_ls_print_devices (const char *name)
-    {
-      if (longlist)
-       grub_normal_print_device_info (name);
-      else
-       grub_printf ("(%s) ", name);
+  int *longlist = data;
+
+  if (longlist)
+    grub_normal_print_device_info (name);
+  else
+    grub_printf ("(%s) ", name);
 
-      return 0;
-    }
+  return 0;
+}
 
-  grub_device_iterate (grub_ls_print_devices);
+static grub_err_t
+grub_ls_list_devices (int longlist)
+{
+  grub_device_iterate (grub_ls_print_devices, &longlist);
   grub_xputs ("\n");
 
 #if 0

=== modified file 'grub-core/commands/search.c'
--- grub-core/commands/search.c 2012-02-08 18:26:01 +0000
+++ grub-core/commands/search.c 2013-01-15 17:19:25 +0000
@@ -42,23 +42,29 @@ struct cache_entry
 
 static struct cache_entry *cache;
 
-void
-FUNC_NAME (const char *key, const char *var, int no_floppy,
-          char **hints, unsigned nhints)
+/* Context for FUNC_NAME.  */
+struct search_ctx
 {
-  int count = 0;
-  int is_cache = 0;
-  grub_fs_autoload_hook_t saved_autoload;
+  const char *key;
+  const char *var;
+  int no_floppy;
+  char **hints;
+  unsigned nhints;
+  int count;
+  int is_cache;
+};
+
+/* Helper for FUNC_NAME.  */
+static int
+iterate_device (const char *name, void *data)
+{
+  struct search_ctx *ctx = data;
+  int found = 0;
 
-  auto int iterate_device (const char *name);
-  int iterate_device (const char *name)
-  {
-    int found = 0;
-
-    /* Skip floppy drives when requested.  */
-    if (no_floppy &&
-       name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
-      return 0;
+  /* Skip floppy drives when requested.  */
+  if (ctx->no_floppy &&
+      name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
+    return 0;
 
 #ifdef DO_SEARCH_FS_UUID
 #define compare_fn grub_strcasecmp
@@ -67,34 +73,34 @@ FUNC_NAME (const char *key, const char *
 #endif
 
 #ifdef DO_SEARCH_FILE
-      {
-       char *buf;
-       grub_file_t file;
-
-       buf = grub_xasprintf ("(%s)%s", name, key);
-       if (! buf)
-         return 1;
-
-       grub_file_filter_disable_compression ();
-       file = grub_file_open (buf);
-       if (file)
-         {
-           found = 1;
-           grub_file_close (file);
-         }
-       grub_free (buf);
-      }
+    {
+      char *buf;
+      grub_file_t file;
+
+      buf = grub_xasprintf ("(%s)%s", name, ctx->key);
+      if (! buf)
+       return 1;
+
+      grub_file_filter_disable_compression ();
+      file = grub_file_open (buf);
+      if (file)
+       {
+         found = 1;
+         grub_file_close (file);
+       }
+      grub_free (buf);
+    }
 #else
-      {
-       /* SEARCH_FS_UUID or SEARCH_LABEL */
-       grub_device_t dev;
-       grub_fs_t fs;
-       char *quid;
-
-       dev = grub_device_open (name);
-       if (dev)
-         {
-           fs = grub_fs_probe (dev);
+    {
+      /* SEARCH_FS_UUID or SEARCH_LABEL */
+      grub_device_t dev;
+      grub_fs_t fs;
+      char *quid;
+
+      dev = grub_device_open (name);
+      if (dev)
+       {
+         fs = grub_fs_probe (dev);
 
 #ifdef DO_SEARCH_FS_UUID
 #define read_fn uuid
@@ -102,173 +108,191 @@ FUNC_NAME (const char *key, const char *
 #define read_fn label
 #endif
 
-           if (fs && fs->read_fn)
-             {
-               fs->read_fn (dev, &quid);
-
-               if (grub_errno == GRUB_ERR_NONE && quid)
-                 {
-                   if (compare_fn (quid, key) == 0)
-                     found = 1;
-
-                   grub_free (quid);
-                 }
-             }
-
-           grub_device_close (dev);
-         }
-      }
+         if (fs && fs->read_fn)
+           {
+             fs->read_fn (dev, &quid);
+
+             if (grub_errno == GRUB_ERR_NONE && quid)
+               {
+                 if (compare_fn (quid, ctx->key) == 0)
+                   found = 1;
+
+                 grub_free (quid);
+               }
+           }
+
+         grub_device_close (dev);
+       }
+    }
 #endif
 
-    if (!is_cache && found && count == 0)
-      {
-       struct cache_entry *cache_ent;
-       cache_ent = grub_malloc (sizeof (*cache_ent));
-       if (cache_ent)
-         {
-           cache_ent->key = grub_strdup (key);
-           cache_ent->value = grub_strdup (name);
-           if (cache_ent->value && cache_ent->key)
-             {
-               cache_ent->next = cache;
-               cache = cache_ent;
-             }
-           else
-             {
-               grub_free (cache_ent->value);
-               grub_free (cache_ent->key);
-               grub_free (cache_ent);
-               grub_errno = GRUB_ERR_NONE;
-             }
-         }
-       else
-         grub_errno = GRUB_ERR_NONE;
-      }
-
-    if (found)
-      {
-       count++;
-       if (var)
-         grub_env_set (var, name);
-       else
-         grub_printf (" %s", name);
-      }
-
-    grub_errno = GRUB_ERR_NONE;
-    return (found && var);
-  }
-
-  auto int part_hook (grub_disk_t disk, const grub_partition_t partition);
-  int part_hook (grub_disk_t disk, const grub_partition_t partition)
-  {
-    char *partition_name, *devname;
-    int ret;
-
-    partition_name = grub_partition_get_name (partition);
-    if (! partition_name)
-      return 1;
-
-    devname = grub_xasprintf ("%s,%s", disk->name, partition_name);
-    grub_free (partition_name);
-    if (!devname)
-      return 1;
-    ret = iterate_device (devname);
-    grub_free (devname);    
-
-    return ret;
-  }
-
-  auto void try (void);
-  void try (void)    
-  {
-    unsigned i;
-    struct cache_entry **prev;
-    struct cache_entry *cache_ent;
-
-    for (prev = &cache, cache_ent = *prev; cache_ent;
-        prev = &cache_ent->next, cache_ent = *prev)
-      if (compare_fn (cache_ent->key, key) == 0)
-       break;
-    if (cache_ent)
-      {
-       is_cache = 1;
-       if (iterate_device (cache_ent->value))
-         {
-           is_cache = 0;
-           return;
-         }
-       is_cache = 0;
-       /* Cache entry was outdated. Remove it.  */
-       if (!count)
-         {
-           grub_free (cache_ent->key);
-           grub_free (cache_ent->value);
-           grub_free (cache_ent);
-           *prev = cache_ent->next;
-         }
-      }
-
-    for (i = 0; i < nhints; i++)
-      {
-       char *end;
-       if (!hints[i][0])
-         continue;
-       end = hints[i] + grub_strlen (hints[i]) - 1;
-       if (*end == ',')
-         *end = 0;
-       if (iterate_device (hints[i]))
-         {
-           if (!*end)
-             *end = ',';
+  if (!ctx->is_cache && found && ctx->count == 0)
+    {
+      struct cache_entry *cache_ent;
+      cache_ent = grub_malloc (sizeof (*cache_ent));
+      if (cache_ent)
+       {
+         cache_ent->key = grub_strdup (ctx->key);
+         cache_ent->value = grub_strdup (name);
+         if (cache_ent->value && cache_ent->key)
+           {
+             cache_ent->next = cache;
+             cache = cache_ent;
+           }
+         else
+           {
+             grub_free (cache_ent->value);
+             grub_free (cache_ent->key);
+             grub_free (cache_ent);
+             grub_errno = GRUB_ERR_NONE;
+           }
+       }
+      else
+       grub_errno = GRUB_ERR_NONE;
+    }
+
+  if (found)
+    {
+      ctx->count++;
+      if (ctx->var)
+       grub_env_set (ctx->var, name);
+      else
+       grub_printf (" %s", name);
+    }
+
+  grub_errno = GRUB_ERR_NONE;
+  return (found && ctx->var);
+}
+
+/* Helper for FUNC_NAME.  */
+static int
+part_hook (grub_disk_t disk, const grub_partition_t partition, void *data)
+{
+  struct search_ctx *ctx = data;
+  char *partition_name, *devname;
+  int ret;
+
+  partition_name = grub_partition_get_name (partition);
+  if (! partition_name)
+    return 1;
+
+  devname = grub_xasprintf ("%s,%s", disk->name, partition_name);
+  grub_free (partition_name);
+  if (!devname)
+    return 1;
+  ret = iterate_device (devname, ctx);
+  grub_free (devname);    
+
+  return ret;
+}
+
+/* Helper for FUNC_NAME.  */
+static void
+try (struct search_ctx *ctx)    
+{
+  unsigned i;
+  struct cache_entry **prev;
+  struct cache_entry *cache_ent;
+
+  for (prev = &cache, cache_ent = *prev; cache_ent;
+       prev = &cache_ent->next, cache_ent = *prev)
+    if (compare_fn (cache_ent->key, ctx->key) == 0)
+      break;
+  if (cache_ent)
+    {
+      ctx->is_cache = 1;
+      if (iterate_device (cache_ent->value, ctx))
+       {
+         ctx->is_cache = 0;
+         return;
+       }
+      ctx->is_cache = 0;
+      /* Cache entry was outdated. Remove it.  */
+      if (!ctx->count)
+       {
+         grub_free (cache_ent->key);
+         grub_free (cache_ent->value);
+         grub_free (cache_ent);
+         *prev = cache_ent->next;
+       }
+    }
+
+  for (i = 0; i < ctx->nhints; i++)
+    {
+      char *end;
+      if (!ctx->hints[i][0])
+       continue;
+      end = ctx->hints[i] + grub_strlen (ctx->hints[i]) - 1;
+      if (*end == ',')
+       *end = 0;
+      if (iterate_device (ctx->hints[i], ctx))
+       {
+         if (!*end)
+           *end = ',';
+         return;
+       }
+      if (!*end)
+       {
+         grub_device_t dev;
+         int ret;
+         dev = grub_device_open (ctx->hints[i]);
+         if (!dev)
+           {
+             if (!*end)
+               *end = ',';
+             continue;
+           }
+         if (!dev->disk)
+           {
+             grub_device_close (dev);
+             if (!*end)
+               *end = ',';
+             continue;
+           }
+         ret = grub_partition_iterate (dev->disk, part_hook, ctx);
+         if (!*end)
+           *end = ',';
+         grub_device_close (dev);
+         if (ret)
            return;
-         }
-       if (!*end)
-         {
-           grub_device_t dev;
-           int ret;
-           dev = grub_device_open (hints[i]);
-           if (!dev)
-             {
-               if (!*end)
-                 *end = ',';
-               continue;
-             }
-           if (!dev->disk)
-             {
-               grub_device_close (dev);
-               if (!*end)
-                 *end = ',';
-               continue;
-             }
-           ret = grub_partition_iterate (dev->disk, part_hook);
-           if (!*end)
-             *end = ',';
-           grub_device_close (dev);
-           if (ret)
-             return;
-         }
-      }
-    grub_device_iterate (iterate_device);
-  }
+       }
+    }
+  grub_device_iterate (iterate_device, ctx);
+}
+
+void
+FUNC_NAME (const char *key, const char *var, int no_floppy,
+          char **hints, unsigned nhints)
+{
+  struct search_ctx ctx = {
+    .key = key,
+    .var = var,
+    .no_floppy = no_floppy,
+    .hints = hints,
+    .nhints = nhints,
+    .count = 0,
+    .is_cache = 0
+  };
+  grub_fs_autoload_hook_t saved_autoload;
 
   /* First try without autoloading if we're setting variable. */
   if (var)
     {
       saved_autoload = grub_fs_autoload_hook;
       grub_fs_autoload_hook = 0;
-      try ();
+      try (&ctx);
 
       /* Restore autoload hook.  */
       grub_fs_autoload_hook = saved_autoload;
 
       /* Retry with autoload if nothing found.  */
-      if (grub_errno == GRUB_ERR_NONE && count == 0)
-       try ();
+      if (grub_errno == GRUB_ERR_NONE && ctx.count == 0)
+       try (&ctx);
     }
   else
-    try ();
+    try (&ctx);
 
-  if (grub_errno == GRUB_ERR_NONE && count == 0)
+  if (grub_errno == GRUB_ERR_NONE && ctx.count == 0)
     grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key);
 }
 

=== modified file 'grub-core/commands/wildcard.c'
--- grub-core/commands/wildcard.c       2012-06-27 19:13:06 +0000
+++ grub-core/commands/wildcard.c       2013-01-15 17:19:44 +0000
@@ -210,59 +210,71 @@ split_path (const char *str, const char
     *noregexop = split;
 }
 
-static char **
-match_devices (const regex_t *regexp, int noparts)
+/* Context for match_devices.  */
+struct match_devices_ctx
 {
-  int i;
+  const regex_t *regexp;
+  int noparts;
   int ndev;
   char **devs;
+};
 
-  auto int match (const char *name);
-  int match (const char *name)
-  {
-    char **t;
-    char *buffer;
+/* Helper for match_devices.  */
+static int
+match_devices_iter (const char *name, void *data)
+{
+  struct match_devices_ctx *ctx = data;
+  char **t;
+  char *buffer;
 
-    /* skip partitions if asked to. */
-    if (noparts && grub_strchr(name, ','))
+  /* skip partitions if asked to. */
+  if (ctx->noparts && grub_strchr (name, ','))
+    return 0;
+
+  buffer = grub_xasprintf ("(%s)", name);
+  if (! buffer)
+    return 1;
+
+  grub_dprintf ("expand", "matching: %s\n", buffer);
+  if (regexec (ctx->regexp, buffer, 0, 0, 0))
+    {
+      grub_dprintf ("expand", "not matched\n");
+      grub_free (buffer);
       return 0;
+    }
 
-    buffer = grub_xasprintf ("(%s)", name);
-    if (! buffer)
-      return 1;
-
-    grub_dprintf ("expand", "matching: %s\n", buffer);
-    if (regexec (regexp, buffer, 0, 0, 0))
-      {
-       grub_dprintf ("expand", "not matched\n");
-       grub_free (buffer);
-       return 0;
-      }
-
-    t = grub_realloc (devs, sizeof (char*) * (ndev + 2));
-    if (! t)
-      return 1;
-
-    devs = t;
-    devs[ndev++] = buffer;
-    devs[ndev] = 0;
-    return 0;
-  }
+  t = grub_realloc (ctx->devs, sizeof (char*) * (ctx->ndev + 2));
+  if (! t)
+    return 1;
+
+  ctx->devs = t;
+  ctx->devs[ctx->ndev++] = buffer;
+  ctx->devs[ctx->ndev] = 0;
+  return 0;
+}
 
-  ndev = 0;
-  devs = 0;
+static char **
+match_devices (const regex_t *regexp, int noparts)
+{
+  struct match_devices_ctx ctx = {
+    .regexp = regexp,
+    .noparts = noparts,
+    .ndev = 0,
+    .devs = 0
+  };
+  int i;
 
-  if (grub_device_iterate (match))
+  if (grub_device_iterate (match_devices_iter, &ctx))
     goto fail;
 
-  return devs;
+  return ctx.devs;
 
  fail:
 
-  for (i = 0; devs && devs[i]; i++)
-    grub_free (devs[i]);
+  for (i = 0; ctx.devs && ctx.devs[i]; i++)
+    grub_free (ctx.devs[i]);
 
-  grub_free (devs);
+  grub_free (ctx.devs);
 
   return 0;
 }

=== modified file 'grub-core/disk/ahci.c'
--- grub-core/disk/ahci.c       2013-01-13 01:10:41 +0000
+++ grub-core/disk/ahci.c       2013-01-15 16:30:27 +0000
@@ -455,8 +455,8 @@ grub_ahci_restore_hw (void)
 
 
 static int
-grub_ahci_iterate (int (*hook) (int id, int bus),
-                 grub_disk_pull_t pull)
+grub_ahci_iterate (grub_ata_dev_iterate_hook_t hook, void *hook_data,
+                  grub_disk_pull_t pull)
 {
   struct grub_ahci_device *dev;
 
@@ -464,7 +464,7 @@ grub_ahci_iterate (int (*hook) (int id,
     return 0;
 
   FOR_LIST_ELEMENTS(dev, grub_ahci_devices)
-    if (hook (GRUB_SCSI_SUBSYSTEM_AHCI, dev->num))
+    if (hook (GRUB_SCSI_SUBSYSTEM_AHCI, dev->num, hook_data))
       return 1;
 
   return 0;

=== modified file 'grub-core/disk/arc/arcdisk.c'
--- grub-core/disk/arc/arcdisk.c        2012-02-12 14:25:25 +0000
+++ grub-core/disk/arc/arcdisk.c        2013-01-15 17:20:02 +0000
@@ -80,23 +80,37 @@ arcdisk_hash_add (char *devpath)
 }
 
 
+/* Context for grub_arcdisk_iterate.  */
+struct grub_arcdisk_iterate_ctx
+{
+  grub_disk_dev_iterate_hook_t hook;
+  void *hook_data;
+};
+
+/* Helper for grub_arcdisk_iterate.  */
+static int
+grub_arcdisk_iterate_iter (const char *name,
+                          const struct grub_arc_component *comp, void *data)
+{
+  struct grub_arcdisk_iterate_ctx *ctx = data;
+
+  if (!(comp->type == GRUB_ARC_COMPONENT_TYPE_DISK
+       || comp->type == GRUB_ARC_COMPONENT_TYPE_DISK
+       || comp->type == GRUB_ARC_COMPONENT_TYPE_TAPE))
+    return 0;
+  return ctx->hook (name, ctx->hook_data);
+}
+
 static int
 grub_arcdisk_iterate (int (*hook_in) (const char *name),
                      grub_disk_pull_t pull)
 {
-  auto int hook (const char *name, const struct grub_arc_component *comp);
-  int hook (const char *name, const struct grub_arc_component *comp)
-  {
-    if (!(comp->type == GRUB_ARC_COMPONENT_TYPE_DISK
-         || comp->type == GRUB_ARC_COMPONENT_TYPE_DISK
-         || comp->type == GRUB_ARC_COMPONENT_TYPE_TAPE))
-      return 0;
-    return hook_in (name);
-  }
+  struct grub_arcdisk_iterate_ctx ctx = { hook, hook_data };
+
   if (pull != GRUB_DISK_PULL_NONE)
     return 0;
 
-  return grub_arc_iterate_devs (hook, 1);
+  return grub_arc_iterate_devs (grub_arcdisk_iterate_iter, &ctx, 1);
 }
 
 #define RAW_SUFFIX "partition(10)"

=== modified file 'grub-core/disk/ata.c'
--- grub-core/disk/ata.c        2012-06-06 10:22:32 +0000
+++ grub-core/disk/ata.c        2013-01-15 17:20:29 +0000
@@ -392,40 +392,50 @@ grub_ata_real_open (int id, int bus)
   return NULL;
 }
 
+/* Context for grub_ata_iterate.  */
+struct grub_ata_iterate_ctx
+{
+  grub_disk_dev_iterate_hook_t hook;
+  void *hook_data;
+};
+
+/* Helper for grub_ata_iterate.  */
 static int
-grub_ata_iterate (int (*hook_in) (const char *name),
-                 grub_disk_pull_t pull)
+grub_ata_iterate_iter (int id, int bus, void *data)
 {
-  auto int hook (int id, int bus);
-  int hook (int id, int bus)
-  {
-    struct grub_ata *ata;
-    int ret;
-    char devname[40];
-
-    ata = grub_ata_real_open (id, bus);
-
-    if (!ata)
-      {
-       grub_errno = GRUB_ERR_NONE;
-       return 0;
-      }
-    if (ata->atapi)
-      {
-       grub_ata_real_close (ata);
-       return 0;
-      }
-    grub_snprintf (devname, sizeof (devname), 
-                  "%s%d", grub_scsi_names[id], bus);
-    ret = hook_in (devname);
-    grub_ata_real_close (ata);
-    return ret;
-  }
+  struct grub_ata_iterate_ctx *ctx = data;
+  struct grub_ata *ata;
+  int ret;
+  char devname[40];
+
+  ata = grub_ata_real_open (id, bus);
 
+  if (!ata)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return 0;
+    }
+  if (ata->atapi)
+    {
+      grub_ata_real_close (ata);
+      return 0;
+    }
+  grub_snprintf (devname, sizeof (devname), 
+                "%s%d", grub_scsi_names[id], bus);
+  ret = ctx->hook (devname, ctx->hook_data);
+  grub_ata_real_close (ata);
+  return ret;
+}
+
+static int
+grub_ata_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+                 grub_disk_pull_t pull)
+{
+  struct grub_ata_iterate_ctx ctx = { hook, hook_data };
   grub_ata_dev_t p;
   
   for (p = grub_ata_dev_list; p; p = p->next)
-    if (p->iterate && p->iterate (hook, pull))
+    if (p->iterate && p->iterate (grub_ata_iterate_iter, &ctx, pull))
       return 1;
   return 0;
 }
@@ -561,37 +571,47 @@ grub_atapi_open (int id, int bus, struct
   return GRUB_ERR_NONE;
 }
 
+/* Context for grub_atapi_iterate.  */
+struct grub_atapi_iterate_ctx
+{
+  grub_scsi_dev_iterate_hook_t hook;
+  void *hook_data;
+};
+
+/* Helper for grub_atapi_iterate.  */
 static int
-grub_atapi_iterate (int NESTED_FUNC_ATTR (*hook_in) (int id, int bus, int 
luns),
-                   grub_disk_pull_t pull)
+grub_atapi_iterate_iter (int id, int bus, void *data)
 {
-  auto int hook (int id, int bus);
-  int hook (int id, int bus)
-  {
-    struct grub_ata *ata;
-    int ret;
+  struct grub_atapi_iterate_ctx *ctx = data;
+  struct grub_ata *ata;
+  int ret;
 
-    ata = grub_ata_real_open (id, bus);
+  ata = grub_ata_real_open (id, bus);
 
-    if (!ata)
-      {
-       grub_errno = GRUB_ERR_NONE;
-       return 0;
-      }
-    if (!ata->atapi)
-      {
-       grub_ata_real_close (ata);
-       return 0;
-      }
-    ret = hook_in (id, bus, 1);
-    grub_ata_real_close (ata);
-    return ret;
-  }
+  if (!ata)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return 0;
+    }
+  if (!ata->atapi)
+    {
+      grub_ata_real_close (ata);
+      return 0;
+    }
+  ret = ctx->hook (id, bus, 1, ctx->hook_data);
+  grub_ata_real_close (ata);
+  return ret;
+}
 
+static int
+grub_atapi_iterate (grub_scsi_dev_iterate_hook_t hook, void *hook_data,
+                   grub_disk_pull_t pull)
+{
+  struct grub_atapi_iterate_ctx ctx = { hook, hook_data };
   grub_ata_dev_t p;
   
   for (p = grub_ata_dev_list; p; p = p->next)
-    if (p->iterate && p->iterate (hook, pull))
+    if (p->iterate && p->iterate (grub_atapi_iterate_iter, &ctx, pull))
       return 1;
   return 0;
 }

=== modified file 'grub-core/disk/cryptodisk.c'
--- grub-core/disk/cryptodisk.c 2012-12-10 18:15:51 +0000
+++ grub-core/disk/cryptodisk.c 2013-01-15 16:49:26 +0000
@@ -448,8 +448,8 @@ grub_cryptodisk_setkey (grub_cryptodisk_
 }
 
 static int
-grub_cryptodisk_iterate (int (*hook) (const char *name),
-                  grub_disk_pull_t pull)
+grub_cryptodisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+                        grub_disk_pull_t pull)
 {
   grub_cryptodisk_t i;
 
@@ -460,7 +460,7 @@ grub_cryptodisk_iterate (int (*hook) (co
     {
       char buf[30];
       grub_snprintf (buf, sizeof (buf), "crypto%lu", i->id);
-      if (hook (buf))
+      if (hook (buf, hook_data))
        return 1;
     }
 
@@ -866,7 +866,8 @@ grub_cryptodisk_cheat_mount (const char
 #endif
 
 static int
-grub_cryptodisk_scan_device (const char *name)
+grub_cryptodisk_scan_device (const char *name,
+                            void *data __attribute__ ((unused)))
 {
   grub_err_t err;
   grub_disk_t source;
@@ -908,7 +909,7 @@ grub_cmd_cryptomount (grub_extcmd_contex
 
       check_boot = state[2].set;
       search_uuid = args[0];
-      grub_device_iterate (&grub_cryptodisk_scan_device);
+      grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
       search_uuid = NULL;
 
       if (!have_it)
@@ -919,7 +920,7 @@ grub_cmd_cryptomount (grub_extcmd_contex
     {
       search_uuid = NULL;
       check_boot = state[2].set;
-      grub_device_iterate (&grub_cryptodisk_scan_device);
+      grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
       search_uuid = NULL;
       return GRUB_ERR_NONE;
     }

=== modified file 'grub-core/disk/diskfilter.c'
--- grub-core/disk/diskfilter.c 2013-01-05 14:10:46 +0000
+++ grub-core/disk/diskfilter.c 2013-01-15 17:20:51 +0000
@@ -120,65 +120,68 @@ is_valid_diskfilter_name (const char *na
          || grub_memcmp (name, "ldm/", sizeof ("ldm/") - 1) == 0);
 }
 
+/* Helper for scan_disk.  */
 static int
-scan_disk (const char *name, int accept_diskfilter)
+scan_disk_partition_iter (grub_disk_t disk, grub_partition_t p, void *data)
 {
-  auto int hook (grub_disk_t disk, grub_partition_t p);
-  int hook (grub_disk_t disk, grub_partition_t p)
-    {
-      struct grub_diskfilter_vg *arr;
-      grub_disk_addr_t start_sector;
-      struct grub_diskfilter_pv_id id;
-      grub_diskfilter_t diskfilter;
+  const char *name = data;
+  struct grub_diskfilter_vg *arr;
+  grub_disk_addr_t start_sector;
+  struct grub_diskfilter_pv_id id;
+  grub_diskfilter_t diskfilter;
 
-      grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk 
%s\n",
-                   name);
+  grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk %s\n",
+               name);
 #ifdef GRUB_UTIL
-      grub_util_info ("Scanning for DISKFILTER devices on disk %s", name);
+  grub_util_info ("Scanning for DISKFILTER devices on disk %s", name);
 #endif
 
-      disk->partition = p;
-      
-      for (arr = array_list; arr != NULL; arr = arr->next)
-       {
-         struct grub_diskfilter_pv *m;
-         for (m = arr->pvs; m; m = m->next)
-           if (m->disk && m->disk->id == disk->id
-               && m->disk->dev->id == disk->dev->id
-               && m->part_start == grub_partition_get_start (disk->partition)
-               && m->part_size == grub_disk_get_size (disk))
-             return 0;
-       }
+  disk->partition = p;
+  
+  for (arr = array_list; arr != NULL; arr = arr->next)
+    {
+      struct grub_diskfilter_pv *m;
+      for (m = arr->pvs; m; m = m->next)
+       if (m->disk && m->disk->id == disk->id
+           && m->disk->dev->id == disk->dev->id
+           && m->part_start == grub_partition_get_start (disk->partition)
+           && m->part_size == grub_disk_get_size (disk))
+         return 0;
+    }
 
-      for (diskfilter = grub_diskfilter_list; diskfilter; diskfilter = 
diskfilter->next)
-       {
+  for (diskfilter = grub_diskfilter_list; diskfilter; diskfilter = 
diskfilter->next)
+    {
 #ifdef GRUB_UTIL
-         grub_util_info ("Scanning for %s devices on disk %s", 
-                         diskfilter->name, name);
+      grub_util_info ("Scanning for %s devices on disk %s", 
+                     diskfilter->name, name);
 #endif
-         id.uuid = 0;
-         id.uuidlen = 0;
-         arr = diskfilter->detect (disk, &id, &start_sector);
-         if (arr &&
-             (! insert_array (disk, &id, arr, start_sector, diskfilter)))
-           {
-             if (id.uuidlen)
-               grub_free (id.uuid);
-             return 0;
-           }
-         if (arr && id.uuidlen)
+      id.uuid = 0;
+      id.uuidlen = 0;
+      arr = diskfilter->detect (disk, &id, &start_sector);
+      if (arr &&
+         (! insert_array (disk, &id, arr, start_sector, diskfilter)))
+       {
+         if (id.uuidlen)
            grub_free (id.uuid);
-
-         /* This error usually means it's not diskfilter, no need to display
-            it.  */
-         if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
-           grub_print_error ();
-
-         grub_errno = GRUB_ERR_NONE;
+         return 0;
        }
+      if (arr && id.uuidlen)
+       grub_free (id.uuid);
 
-      return 0;
+      /* This error usually means it's not diskfilter, no need to display
+        it.  */
+      if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
+       grub_print_error ();
+
+      grub_errno = GRUB_ERR_NONE;
     }
+
+  return 0;
+}
+
+static int
+scan_disk (const char *name, int accept_diskfilter)
+{
   grub_disk_t disk;
   static int scan_depth = 0;
 
@@ -196,12 +199,12 @@ scan_disk (const char *name, int accept_
       scan_depth--;
       return 0;
     }
-  if (hook (disk, 0))
+  if (scan_disk_partition_iter (disk, 0, (void *) name))
     {
       scan_depth--;
       return 1;
     }
-  if (grub_partition_iterate (disk, hook))
+  if (grub_partition_iterate (disk, scan_disk_partition_iter, (void *) name))
     {
       scan_depth--;
       return 1;
@@ -212,7 +215,7 @@ scan_disk (const char *name, int accept_
 }
 
 static int
-scan_disk_hook (const char *name)
+scan_disk_hook (const char *name, void *data __attribute__ ((unused)))
 {
   return scan_disk (name, 0);
 }
@@ -230,7 +233,7 @@ scan_devices (const char *arname)
       if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID
          && p->iterate)
        {
-         if ((p->iterate) (scan_disk_hook, pull))
+         if ((p->iterate) (scan_disk_hook, NULL, pull))
            return;
          if (arname && is_lv_readable (find_lv (arname), 1))
            return;
@@ -249,8 +252,8 @@ scan_devices (const char *arname)
 }
 
 static int
-grub_diskfilter_iterate (int (*hook) (const char *name),
-                  grub_disk_pull_t pull)
+grub_diskfilter_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+                        grub_disk_pull_t pull)
 {
   struct grub_diskfilter_vg *array;
   int islcnt = 0;
@@ -271,7 +274,7 @@ grub_diskfilter_iterate (int (*hook) (co
        for (lv = array->lvs; lv; lv = lv->next)
          if (lv->visible && lv->fullname && lv->became_readable_at >= islcnt)
            {
-             if (hook (lv->fullname))
+             if (hook (lv->fullname, hook_data))
                return 1;
            }
     }
@@ -303,7 +306,7 @@ grub_diskfilter_memberlist (grub_disk_t
       if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID
          && p->iterate)
        {
-         (p->iterate) (scan_disk_hook, pull);
+         (p->iterate) (scan_disk_hook, NULL, pull);
          while (pv && pv->disk)
            pv = pv->next;
        }

=== modified file 'grub-core/disk/efi/efidisk.c'
--- grub-core/disk/efi/efidisk.c        2012-06-09 08:43:24 +0000
+++ grub-core/disk/efi/efidisk.c        2013-01-15 17:22:30 +0000
@@ -404,7 +404,7 @@ enumerate_disks (void)
 }
 
 static int
-grub_efidisk_iterate (int (*hook) (const char *name),
+grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
                      grub_disk_pull_t pull)
 {
   struct grub_efidisk_data *d;
@@ -418,7 +418,7 @@ grub_efidisk_iterate (int (*hook) (const
        {
          grub_snprintf (buf, sizeof (buf), "hd%d", count);
          grub_dprintf ("efidisk", "iterating %s\n", buf);
-         if (hook (buf))
+         if (hook (buf, hook_data))
            return 1;
        }
       break;
@@ -427,7 +427,7 @@ grub_efidisk_iterate (int (*hook) (const
        {
          grub_snprintf (buf, sizeof (buf), "fd%d", count);
          grub_dprintf ("efidisk", "iterating %s\n", buf);
-         if (hook (buf))
+         if (hook (buf, hook_data))
            return 1;
        }
 
@@ -435,7 +435,7 @@ grub_efidisk_iterate (int (*hook) (const
        {
          grub_snprintf (buf, sizeof (buf), "cd%d", count);
          grub_dprintf ("efidisk", "iterating %s\n", buf);
-         if (hook (buf))
+         if (hook (buf, hook_data))
            return 1;
        }
       break;
@@ -736,6 +736,31 @@ get_diskname_from_path (const grub_efi_d
   return 0;
 }
 
+/* Context for grub_efidisk_get_device_name.  */
+struct grub_efidisk_get_device_name_ctx
+{
+  char *partition_name;
+  grub_efi_hard_drive_device_path_t hd;
+};
+
+/* Helper for grub_efidisk_get_device_name.
+   Find the identical partition.  */
+static int
+grub_efidisk_get_device_name_iter (grub_disk_t disk __attribute__ ((unused)),
+                                  const grub_partition_t part, void *data)
+{
+  struct grub_efidisk_get_device_name_ctx *ctx = data;
+
+  if (grub_partition_get_start (part) == ctx->hd.partition_start
+      && grub_partition_get_len (part) == ctx->hd.partition_size)
+    {
+      ctx->partition_name = grub_partition_get_name (part);
+      return 1;
+    }
+
+  return 0;
+}
+
 char *
 grub_efidisk_get_device_name (grub_efi_handle_t *handle)
 {
@@ -754,28 +779,11 @@ grub_efidisk_get_device_name (grub_efi_h
       && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
          == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
     {
-      char *partition_name = NULL;
+      struct grub_efidisk_get_device_name_ctx ctx;
       char *dev_name;
       grub_efi_device_path_t *dup_dp, *dup_ldp;
-      grub_efi_hard_drive_device_path_t hd;
       grub_disk_t parent = 0;
 
-      auto int find_partition (grub_disk_t disk, const grub_partition_t part);
-
-      /* Find the identical partition.  */
-      int find_partition (grub_disk_t disk __attribute__ ((unused)),
-                         const grub_partition_t part)
-       {
-         if (grub_partition_get_start (part) == hd.partition_start
-             && grub_partition_get_len (part) == hd.partition_size)
-           {
-             partition_name = grub_partition_get_name (part);
-             return 1;
-           }
-
-         return 0;
-       }
-
       /* It is necessary to duplicate the device path so that GRUB
         can overwrite it.  */
       dup_dp = duplicate_device_path (dp);
@@ -797,24 +805,27 @@ grub_efidisk_get_device_name (grub_efi_h
        return 0;
 
       /* Find a partition which matches the hard drive device path.  */
-      grub_memcpy (&hd, ldp, sizeof (hd));
-      if (hd.partition_start == 0
-         && hd.partition_size == grub_disk_get_size (parent))
+      ctx.partition_name = NULL;
+      grub_memcpy (&ctx.hd, ldp, sizeof (ctx.hd));
+      if (ctx.hd.partition_start == 0
+         && ctx.hd.partition_size == grub_disk_get_size (parent))
        {
          dev_name = grub_strdup (parent->name);
        }
       else
        {
-         grub_partition_iterate (parent, find_partition);
+         grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
+                                 &ctx);
 
-         if (! partition_name)
+         if (! ctx.partition_name)
            {
              grub_disk_close (parent);
              return 0;
            }
 
-         dev_name = grub_xasprintf ("%s,%s", parent->name, partition_name);
-         grub_free (partition_name);
+         dev_name = grub_xasprintf ("%s,%s", parent->name,
+                                    ctx.partition_name);
+         grub_free (ctx.partition_name);
        }
       grub_disk_close (parent);
 

=== modified file 'grub-core/disk/host.c'
--- grub-core/disk/host.c       2011-07-07 19:46:25 +0000
+++ grub-core/disk/host.c       2013-01-15 16:51:13 +0000
@@ -27,13 +27,13 @@
 int grub_disk_host_i_want_a_reference;
 
 static int
-grub_host_iterate (int (*hook) (const char *name),
+grub_host_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
                   grub_disk_pull_t pull)
 {
   if (pull != GRUB_DISK_PULL_NONE)
     return 0;
 
-  if (hook ("host"))
+  if (hook ("host", hook_data))
     return 1;
   return 0;
 }

=== modified file 'grub-core/disk/i386/pc/biosdisk.c'
--- grub-core/disk/i386/pc/biosdisk.c   2012-02-26 16:28:05 +0000
+++ grub-core/disk/i386/pc/biosdisk.c   2013-01-16 13:43:58 +0000
@@ -272,20 +272,21 @@ grub_biosdisk_get_drive (const char *nam
 }
 
 static int
-grub_biosdisk_call_hook (int (*hook) (const char *name), int drive)
+grub_biosdisk_call_hook (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+                        int drive)
 {
   char name[10];
 
   if (cd_drive && drive == cd_drive)
-    return hook ("cd");
+    return hook ("cd", hook_data);
 
   grub_snprintf (name, sizeof (name),
                 (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));
-  return hook (name);
+  return hook (name, hook_data);
 }
 
 static int
-grub_biosdisk_iterate (int (*hook) (const char *name),
+grub_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
                       grub_disk_pull_t pull __attribute__ ((unused)))
 {
   int num_floppies;
@@ -304,7 +305,7 @@ grub_biosdisk_iterate (int (*hook) (cons
              break;
            }
 
-         if (grub_biosdisk_call_hook (hook, drive))
+         if (grub_biosdisk_call_hook (hook, hook_data, drive))
            return 1;
        }
       return 0;
@@ -312,14 +313,14 @@ grub_biosdisk_iterate (int (*hook) (cons
     case GRUB_DISK_PULL_REMOVABLE:
       if (cd_drive)
        {
-         if (grub_biosdisk_call_hook (hook, cd_drive))
+         if (grub_biosdisk_call_hook (hook, hook_data, cd_drive))
            return 1;
        }
 
       /* For floppy disks, we can get the number safely.  */
       num_floppies = grub_biosdisk_get_num_floppies ();
       for (drive = 0; drive < num_floppies; drive++)
-       if (grub_biosdisk_call_hook (hook, drive))
+       if (grub_biosdisk_call_hook (hook, hook_data, drive))
          return 1;
       return 0;
     default:

=== modified file 'grub-core/disk/ieee1275/nand.c'
--- grub-core/disk/ieee1275/nand.c      2013-01-05 14:10:46 +0000
+++ grub-core/disk/ieee1275/nand.c      2013-01-15 16:48:33 +0000
@@ -33,7 +33,7 @@ struct grub_nand_data
 };
 
 static int
-grub_nand_iterate (int (*hook) (const char *name),
+grub_nand_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
                   grub_disk_pull_t pull)
 {
   auto int dev_iterate (struct grub_ieee1275_devalias *alias);
@@ -41,7 +41,7 @@ grub_nand_iterate (int (*hook) (const ch
   {
     if (grub_strcmp (alias->name, "nand") == 0)
       {
-       hook (alias->name);
+       hook (alias->name, hook_data);
        return 1;
       }
     

=== modified file 'grub-core/disk/ieee1275/ofdisk.c'
--- grub-core/disk/ieee1275/ofdisk.c    2012-09-05 06:56:08 +0000
+++ grub-core/disk/ieee1275/ofdisk.c    2013-01-15 16:52:22 +0000
@@ -218,7 +218,7 @@ scan (void)
 }
 
 static int
-grub_ofdisk_iterate (int (*hook) (const char *name),
+grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
                     grub_disk_pull_t pull)
 {
   unsigned i;
@@ -276,7 +276,7 @@ grub_ofdisk_iterate (int (*hook) (const
                *optr++ = *iptr++;
              }
            *optr = 0;
-           if (hook (buffer))
+           if (hook (buffer, hook_data))
              return 1;
          }
        }

=== modified file 'grub-core/disk/ldm.c'
--- grub-core/disk/ldm.c        2012-04-18 21:11:33 +0000
+++ grub-core/disk/ldm.c        2013-01-15 17:22:50 +0000
@@ -105,35 +105,39 @@ read_int (grub_uint8_t *in, grub_size_t
 
 static const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
 
+/* Helper for gpt_ldm_sector.  */
+static int
+gpt_ldm_sector_iter (grub_disk_t disk, const grub_partition_t p, void *data)
+{
+  grub_disk_addr_t *sector = data;
+  struct grub_gpt_partentry gptdata;
+  grub_partition_t p2;
+
+  p2 = disk->partition;
+  disk->partition = p->parent;
+  if (grub_disk_read (disk, p->offset, p->index,
+                     sizeof (gptdata), &gptdata))
+    {
+      disk->partition = p2;
+      return 0;
+    }
+  disk->partition = p2;
+
+  if (! grub_memcmp (&gptdata.type, &ldm_type, 16))
+    {
+      *sector = p->start + p->len - 1;
+      return 1;
+    }
+  return 0;
+}
+
 static grub_disk_addr_t
 gpt_ldm_sector (grub_disk_t dsk)
 {
   grub_disk_addr_t sector = 0;
   grub_err_t err;
-  auto int hook (grub_disk_t disk, const grub_partition_t p);
-  int hook (grub_disk_t disk, const grub_partition_t p)
-  {
-    struct grub_gpt_partentry gptdata;
-    grub_partition_t p2;
-
-    p2 = disk->partition;
-    disk->partition = p->parent;
-    if (grub_disk_read (disk, p->offset, p->index,
-                       sizeof (gptdata), &gptdata))
-      {
-       disk->partition = p2;
-       return 0;
-      }
-    disk->partition = p2;
-
-    if (! grub_memcmp (&gptdata.type, &ldm_type, 16))
-      {
-       sector = p->start + p->len - 1;
-       return 1;
-      }
-    return 0;
-  }
-  err = grub_gpt_partition_map_iterate (dsk, hook);
+
+  err = grub_gpt_partition_map_iterate (dsk, gpt_ldm_sector_iter, &sector);
   if (err)
     {
       grub_errno = GRUB_ERR_NONE;

=== modified file 'grub-core/disk/loopback.c'
--- grub-core/disk/loopback.c   2013-01-05 14:10:46 +0000
+++ grub-core/disk/loopback.c   2013-01-15 16:52:42 +0000
@@ -135,15 +135,15 @@ fail:
 
 
 static int
-grub_loopback_iterate (int (*hook) (const char *name),
-                   grub_disk_pull_t pull)
+grub_loopback_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+                      grub_disk_pull_t pull)
 {
   struct grub_loopback *d;
   if (pull != GRUB_DISK_PULL_NONE)
     return 0;
   for (d = loopback_list; d; d = d->next)
     {
-      if (hook (d->devname))
+      if (hook (d->devname, hook_data))
        return 1;
     }
   return 0;

=== modified file 'grub-core/disk/memdisk.c'
--- grub-core/disk/memdisk.c    2011-10-16 13:23:29 +0000
+++ grub-core/disk/memdisk.c    2013-01-15 16:52:57 +0000
@@ -30,13 +30,13 @@ static char *memdisk_addr;
 static grub_off_t memdisk_size = 0;
 
 static int
-grub_memdisk_iterate (int (*hook) (const char *name),
+grub_memdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
                      grub_disk_pull_t pull)
 {
   if (pull != GRUB_DISK_PULL_NONE)
     return 0;
 
-  return hook ("memdisk");
+  return hook ("memdisk", hook_data);
 }
 
 static grub_err_t

=== modified file 'grub-core/disk/pata.c'
--- grub-core/disk/pata.c       2013-01-13 01:10:41 +0000
+++ grub-core/disk/pata.c       2013-01-15 16:30:27 +0000
@@ -501,7 +501,7 @@ grub_pata_open (int id, int devnum, stru
 }
 
 static int
-grub_pata_iterate (int (*hook) (int id, int bus),
+grub_pata_iterate (grub_ata_dev_iterate_hook_t hook, void *hook_data,
                   grub_disk_pull_t pull)
 {
   struct grub_pata_device *dev;
@@ -510,7 +510,8 @@ grub_pata_iterate (int (*hook) (int id,
     return 0;
 
   for (dev = grub_pata_devices; dev; dev = dev->next)
-    if (hook (GRUB_SCSI_SUBSYSTEM_PATA, dev->port * 2 + dev->device))
+    if (hook (GRUB_SCSI_SUBSYSTEM_PATA, dev->port * 2 + dev->device,
+             hook_data))
       return 1;
 
   return 0;

=== modified file 'grub-core/disk/scsi.c'
--- grub-core/disk/scsi.c       2012-02-26 16:28:05 +0000
+++ grub-core/disk/scsi.c       2013-01-15 17:23:15 +0000
@@ -423,50 +423,59 @@ grub_scsi_write16 (grub_disk_t disk, gru
 
 
 
-static int
-grub_scsi_iterate (int (*hook) (const char *name),
-                  grub_disk_pull_t pull)
+/* Context for grub_scsi_iterate.  */
+struct grub_scsi_iterate_ctx
 {
-  grub_scsi_dev_t p;
+  grub_disk_dev_iterate_hook_t hook;
+  void *hook_data;
+};
 
-  auto int NESTED_FUNC_ATTR scsi_iterate (int id, int bus, int luns);
+/* Helper for grub_scsi_iterate.  */
+static int
+scsi_iterate (int id, int bus, int luns, void *data)
+{
+  struct grub_scsi_iterate_ctx *ctx = data;
+  int i;
 
-  int NESTED_FUNC_ATTR scsi_iterate (int id, int bus, int luns)
+  /* In case of a single LUN, just return `usbX'.  */
+  if (luns == 1)
     {
-      int i;
+      char *sname;
+      int ret;
+      sname = grub_xasprintf ("%s%d", grub_scsi_names[id], bus);
+      if (!sname)
+       return 1;
+      ret = ctx->hook (sname, ctx->hook_data);
+      grub_free (sname);
+      return ret;
+    }
 
-      /* In case of a single LUN, just return `usbX'.  */
-      if (luns == 1)
-       {
-         char *sname;
-         int ret;
-         sname = grub_xasprintf ("%s%d", grub_scsi_names[id], bus);
-         if (!sname)
-           return 1;
-         ret = hook (sname);
-         grub_free (sname);
-         return ret;
-       }
-
-      /* In case of multiple LUNs, every LUN will get a prefix to
-        distinguish it.  */
-      for (i = 0; i < luns; i++)
-       {
-         char *sname;
-         int ret;
-         sname = grub_xasprintf ("%s%d%c", grub_scsi_names[id], bus, 'a' + i);
-         if (!sname)
-           return 1;
-         ret = hook (sname);
-         grub_free (sname);
-         if (ret)
-           return 1;
-       }
-      return 0;
+  /* In case of multiple LUNs, every LUN will get a prefix to
+     distinguish it.  */
+  for (i = 0; i < luns; i++)
+    {
+      char *sname;
+      int ret;
+      sname = grub_xasprintf ("%s%d%c", grub_scsi_names[id], bus, 'a' + i);
+      if (!sname)
+       return 1;
+      ret = ctx->hook (sname, ctx->hook_data);
+      grub_free (sname);
+      if (ret)
+       return 1;
     }
+  return 0;
+}
+
+static int
+grub_scsi_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+                  grub_disk_pull_t pull)
+{
+  struct grub_scsi_iterate_ctx ctx = { hook, hook_data };
+  grub_scsi_dev_t p;
 
   for (p = grub_scsi_dev_list; p; p = p->next)
-    if (p->iterate && (p->iterate) (scsi_iterate, pull))
+    if (p->iterate && (p->iterate) (scsi_iterate, &ctx, pull))
       return 1;
 
   return 0;

=== modified file 'grub-core/disk/usbms.c'
--- grub-core/disk/usbms.c      2012-02-01 13:30:40 +0000
+++ grub-core/disk/usbms.c      2013-01-15 16:30:28 +0000
@@ -265,7 +265,7 @@ grub_usbms_attach (grub_usb_device_t usb
 
 
 static int
-grub_usbms_iterate (int NESTED_FUNC_ATTR (*hook) (int id, int bus, int luns),
+grub_usbms_iterate (grub_scsi_dev_iterate_hook_t hook, void *hook_data,
                    grub_disk_pull_t pull)
 {
   unsigned i;
@@ -278,7 +278,8 @@ grub_usbms_iterate (int NESTED_FUNC_ATTR
   for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
     if (grub_usbms_devices[i])
       {
-       if (hook (GRUB_SCSI_SUBSYSTEM_USBMS, i, grub_usbms_devices[i]->luns))
+       if (hook (GRUB_SCSI_SUBSYSTEM_USBMS, i, grub_usbms_devices[i]->luns,
+                 hook_data))
          return 1;
       }
 

=== modified file 'grub-core/fs/btrfs.c'
--- grub-core/fs/btrfs.c        2012-05-26 22:47:37 +0000
+++ grub-core/fs/btrfs.c        2013-01-15 17:23:38 +0000
@@ -538,56 +538,71 @@ lower_bound (struct grub_btrfs_data *dat
     }
 }
 
-static grub_device_t
-find_device (struct grub_btrfs_data *data, grub_uint64_t id, int do_rescan)
+/* Context for find_device.  */
+struct find_device_ctx
+{
+  struct grub_btrfs_data *data;
+  grub_uint64_t id;
+  grub_device_t dev_found;
+};
+
+/* Helper for find_device.  */
+static int
+find_device_iter (const char *name, void *data)
 {
-  grub_device_t dev_found = NULL;
-  auto int hook (const char *name);
-  int hook (const char *name)
-  {
-    grub_device_t dev;
-    grub_err_t err;
-    struct grub_btrfs_superblock sb;
-    dev = grub_device_open (name);
-    if (!dev)
+  struct find_device_ctx *ctx = data;
+  grub_device_t dev;
+  grub_err_t err;
+  struct grub_btrfs_superblock sb;
+
+  dev = grub_device_open (name);
+  if (!dev)
+    return 0;
+  if (!dev->disk)
+    {
+      grub_device_close (dev);
       return 0;
-    if (!dev->disk)
-      {
-       grub_device_close (dev);
-       return 0;
-      }
-    err = read_sblock (dev->disk, &sb);
-    if (err == GRUB_ERR_BAD_FS)
-      {
-       grub_device_close (dev);
-       grub_errno = GRUB_ERR_NONE;
-       return 0;
-      }
-    if (err)
-      {
-       grub_device_close (dev);
-       grub_print_error ();
-       return 0;
-      }
-    if (grub_memcmp (data->sblock.uuid, sb.uuid, sizeof (sb.uuid)) != 0
-       || sb.this_device.device_id != id)
-      {
-       grub_device_close (dev);
-       return 0;
-      }
-
-    dev_found = dev;
-    return 1;
-  }
+    }
+  err = read_sblock (dev->disk, &sb);
+  if (err == GRUB_ERR_BAD_FS)
+    {
+      grub_device_close (dev);
+      grub_errno = GRUB_ERR_NONE;
+      return 0;
+    }
+  if (err)
+    {
+      grub_device_close (dev);
+      grub_print_error ();
+      return 0;
+    }
+  if (grub_memcmp (ctx->data->sblock.uuid, sb.uuid, sizeof (sb.uuid)) != 0
+      || sb.this_device.device_id != ctx->id)
+    {
+      grub_device_close (dev);
+      return 0;
+    }
 
+  ctx->dev_found = dev;
+  return 1;
+}
+
+static grub_device_t
+find_device (struct grub_btrfs_data *data, grub_uint64_t id, int do_rescan)
+{
+  struct find_device_ctx ctx = {
+    .data = data,
+    .id = id,
+    .dev_found = NULL
+  };
   unsigned i;
 
   for (i = 0; i < data->n_devices_attached; i++)
     if (id == data->devices_attached[i].id)
       return data->devices_attached[i].dev;
   if (do_rescan)
-    grub_device_iterate (hook);
-  if (!dev_found)
+    grub_device_iterate (find_device_iter, &ctx);
+  if (!ctx.dev_found)
     {
       grub_error (GRUB_ERR_BAD_FS,
                  N_("couldn't find a necessary member device "
@@ -605,14 +620,14 @@ find_device (struct grub_btrfs_data *dat
                        * sizeof (data->devices_attached[0]));
       if (!data->devices_attached)
        {
-         grub_device_close (dev_found);
+         grub_device_close (ctx.dev_found);
          data->devices_attached = tmp;
          return NULL;
        }
     }
   data->devices_attached[data->n_devices_attached - 1].id = id;
-  data->devices_attached[data->n_devices_attached - 1].dev = dev_found;
-  return dev_found;
+  data->devices_attached[data->n_devices_attached - 1].dev = ctx.dev_found;
+  return ctx.dev_found;
 }
 
 static grub_err_t

=== modified file 'grub-core/fs/zfs/zfs.c'
--- grub-core/fs/zfs/zfs.c      2012-05-03 07:09:30 +0000
+++ grub-core/fs/zfs/zfs.c      2013-01-15 17:23:52 +0000
@@ -988,43 +988,47 @@ scan_disk (grub_device_t dev, struct gru
   return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label");
 }
 
-static grub_err_t
-scan_devices (struct grub_zfs_data *data)
+/* Helper for scan_devices.  */
+static int
+scan_devices_iter (const char *name, void *hook_data)
 {
-  auto int hook (const char *name);
-  int hook (const char *name)
-  {
-    grub_device_t dev;
-    grub_err_t err;
-    int inserted;
-    dev = grub_device_open (name);
-    if (!dev)
-      return 0;
-    if (!dev->disk)
-      {
-       grub_device_close (dev);
-       return 0;
-      }
-    err = scan_disk (dev, data, 0, &inserted);
-    if (err == GRUB_ERR_BAD_FS)
-      {
-       grub_device_close (dev);
-       grub_errno = GRUB_ERR_NONE;
-       return 0;
-      }
-    if (err)
-      {
-       grub_device_close (dev);
-       grub_print_error ();
-       return 0;
-      }
+  struct grub_zfs_data *data = hook_data;
+  grub_device_t dev;
+  grub_err_t err;
+  int inserted;
 
-    if (!inserted)
-      grub_device_close (dev);
-    
+  dev = grub_device_open (name);
+  if (!dev)
     return 0;
-  }
-  grub_device_iterate (hook);
+  if (!dev->disk)
+    {
+      grub_device_close (dev);
+      return 0;
+    }
+  err = scan_disk (dev, data, 0, &inserted);
+  if (err == GRUB_ERR_BAD_FS)
+    {
+      grub_device_close (dev);
+      grub_errno = GRUB_ERR_NONE;
+      return 0;
+    }
+  if (err)
+    {
+      grub_device_close (dev);
+      grub_print_error ();
+      return 0;
+    }
+
+  if (!inserted)
+    grub_device_close (dev);
+  
+  return 0;
+}
+
+static grub_err_t
+scan_devices (struct grub_zfs_data *data)
+{
+  grub_device_iterate (scan_devices_iter, data);
   return GRUB_ERR_NONE;
 }
 

=== modified file 'grub-core/kern/corecmd.c'
--- grub-core/kern/corecmd.c    2012-12-31 17:31:38 +0000
+++ grub-core/kern/corecmd.c    2013-01-15 16:30:28 +0000
@@ -96,7 +96,7 @@ grub_core_cmd_insmod (struct grub_comman
 }
 
 static int
-grub_mini_print_devices (const char *name)
+grub_mini_print_devices (const char *name, void *data __attribute__ ((unused)))
 {
   grub_printf ("(%s) ", name);
 
@@ -119,7 +119,7 @@ grub_core_cmd_ls (struct grub_command *c
 {
   if (argc < 1)
     {
-      grub_device_iterate (grub_mini_print_devices);
+      grub_device_iterate (grub_mini_print_devices, NULL);
       grub_xputs ("\n");
       grub_refresh ();
     }

=== modified file 'grub-core/kern/device.c'
--- grub-core/kern/device.c     2012-06-19 09:20:34 +0000
+++ grub-core/kern/device.c     2013-01-15 17:24:32 +0000
@@ -85,94 +85,107 @@ grub_device_close (grub_device_t device)
   return grub_errno;
 }
 
-int
-grub_device_iterate (int (*hook) (const char *name))
+struct part_ent
+{
+  struct part_ent *next;
+  char *name;
+};
+
+/* Context for grub_device_iterate.  */
+struct grub_device_iterate_ctx
+{
+  grub_device_iterate_hook_t hook;
+  void *hook_data;
+  struct part_ent *ents;
+};
+
+/* Helper for grub_device_iterate.  */
+static int
+iterate_partition (grub_disk_t disk, const grub_partition_t partition,
+                  void *data)
 {
-  auto int iterate_disk (const char *disk_name);
-  auto int iterate_partition (grub_disk_t disk,
-                             const grub_partition_t partition);
-
-  struct part_ent
-  {
-    struct part_ent *next;
-    char *name;
-  } *ents;
+  struct grub_device_iterate_ctx *ctx = data;
+  struct part_ent *p;
+  char *part_name;
 
-  int iterate_disk (const char *disk_name)
+  p = grub_malloc (sizeof (*p));
+  if (!p)
     {
-      grub_device_t dev;
+      return 1;
+    }
 
-      if (hook (disk_name))
-       return 1;
+  part_name = grub_partition_get_name (partition);
+  if (!part_name)
+    {
+      grub_free (p);
+      return 1;
+    }
+  p->name = grub_xasprintf ("%s,%s", disk->name, part_name);
+  grub_free (part_name);
+  if (!p->name)
+    {
+      grub_free (p);
+      return 1;
+    }
 
-      dev = grub_device_open (disk_name);
-      if (! dev)
-       {
-         grub_errno = GRUB_ERR_NONE;
-         return 0;
-       }
+  p->next = ctx->ents;
+  ctx->ents = p;
 
-      if (dev->disk)
-       {
-         struct part_ent *p;
-         int ret = 0;
+  return 0;
+}
 
-         ents = NULL;
-         (void) grub_partition_iterate (dev->disk, iterate_partition);
-         grub_device_close (dev);
-
-         grub_errno = GRUB_ERR_NONE;
-
-         p = ents;
-         while (p != NULL)
-           {
-             struct part_ent *next = p->next;
-
-             if (!ret)
-               ret = hook (p->name);
-             grub_free (p->name);
-             grub_free (p);
-             p = next;
-           }
+/* Helper for grub_device_iterate.  */
+static int
+iterate_disk (const char *disk_name, void *data)
+{
+  struct grub_device_iterate_ctx *ctx = data;
+  grub_device_t dev;
 
-         return ret;
-       }
+  if (ctx->hook (disk_name, ctx->hook_data))
+    return 1;
 
-      grub_device_close (dev);
+  dev = grub_device_open (disk_name);
+  if (! dev)
+    {
+      grub_errno = GRUB_ERR_NONE;
       return 0;
     }
 
-  int iterate_partition (grub_disk_t disk, const grub_partition_t partition)
+  if (dev->disk)
     {
       struct part_ent *p;
-      char *part_name;
+      int ret = 0;
 
-      p = grub_malloc (sizeof (*p));
-      if (!p)
-       {
-         return 1;
-       }
+      ctx->ents = NULL;
+      (void) grub_partition_iterate (dev->disk, iterate_partition, ctx);
+      grub_device_close (dev);
 
-      part_name = grub_partition_get_name (partition);
-      if (!part_name)
-       {
-         grub_free (p);
-         return 1;
-       }
-      p->name = grub_xasprintf ("%s,%s", disk->name, part_name);
-      grub_free (part_name);
-      if (!p->name)
+      grub_errno = GRUB_ERR_NONE;
+
+      p = ctx->ents;
+      while (p != NULL)
        {
+         struct part_ent *next = p->next;
+
+         if (!ret)
+           ret = ctx->hook (p->name, ctx->hook_data);
+         grub_free (p->name);
          grub_free (p);
-         return 1;
+         p = next;
        }
 
-      p->next = ents;
-      ents = p;
-
-      return 0;
+      return ret;
     }
 
+  grub_device_close (dev);
+  return 0;
+}
+
+int
+grub_device_iterate (grub_device_iterate_hook_t hook, void *hook_data)
+{
+  struct grub_device_iterate_ctx ctx = { hook, hook_data, NULL };
+
   /* Only disk devices are supported at the moment.  */
-  return grub_disk_dev_iterate (iterate_disk);
+  return grub_disk_dev_iterate (iterate_disk, &ctx);
 }

=== modified file 'grub-core/kern/emu/hostdisk.c'
--- grub-core/kern/emu/hostdisk.c       2013-01-13 21:45:16 +0000
+++ grub-core/kern/emu/hostdisk.c       2013-01-15 16:53:37 +0000
@@ -223,7 +223,7 @@ find_free_slot (void)
 }
 
 static int
-grub_util_biosdisk_iterate (int (*hook) (const char *name),
+grub_util_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
                            grub_disk_pull_t pull)
 {
   unsigned i;
@@ -232,7 +232,7 @@ grub_util_biosdisk_iterate (int (*hook)
     return 0;
 
   for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
-    if (map[i].drive && hook (map[i].drive))
+    if (map[i].drive && hook (map[i].drive, hook_data))
       return 1;
 
   return 0;

=== modified file 'grub-core/kern/mips/arc/init.c'
--- grub-core/kern/mips/arc/init.c      2013-01-15 12:02:35 +0000
+++ grub-core/kern/mips/arc/init.c      2013-01-15 16:59:30 +0000
@@ -48,8 +48,7 @@ const char *type_names[] = {
 
 static int
 iterate_rec (const char *prefix, const struct grub_arc_component *parent,
-            int (*hook) (const char *name,
-                         const struct grub_arc_component *comp),
+            grub_arc_iterate_devs_hook_t hook, void *hook_data,
             int alt_names)
 {
   const struct grub_arc_component *comp;
@@ -67,12 +66,13 @@ iterate_rec (const char *prefix, const s
        name = grub_xasprintf ("%s%s(%lu)", prefix, cname, comp->key);
       if (!name)
        return 1;
-      if (hook (name, comp))
+      if (hook (name, comp, hook_data))
        {
          grub_free (name);
          return 1;
        }
-      if (iterate_rec ((parent ? name : prefix), comp, hook, alt_names))
+      if (iterate_rec ((parent ? name : prefix), comp, hook, hook_data,
+                      alt_names))
        {
          grub_free (name);
          return 1;
@@ -83,11 +83,11 @@ iterate_rec (const char *prefix, const s
 }
 
 int
-grub_arc_iterate_devs (int (*hook) (const char *name,
-                                   const struct grub_arc_component *comp),
+grub_arc_iterate_devs (grub_arc_iterate_devs_hook_t hook, void *hook_data,
                       int alt_names)
 {
-  return iterate_rec ((alt_names ? "arc" : ""), NULL, hook, alt_names);
+  return iterate_rec ((alt_names ? "arc" : ""), NULL, hook, hook_data,
+                     alt_names);
 }
 
 grub_err_t

=== modified file 'grub-core/kern/partition.c'
--- grub-core/kern/partition.c  2012-02-08 19:19:44 +0000
+++ grub-core/kern/partition.c  2013-01-15 17:25:49 +0000
@@ -59,39 +59,50 @@ grub_partition_check_containment (const
   return 1;
 }
 
-static grub_partition_t
-grub_partition_map_probe (const grub_partition_map_t partmap,
-                         grub_disk_t disk, int partnum)
+/* Context for grub_partition_map_probe.  */
+struct grub_partition_map_probe_ctx
 {
-  grub_partition_t p = 0;
+  int partnum;
+  grub_partition_t p;
+};
+
+/* Helper for grub_partition_map_probe.  */
+static int
+probe_iter (grub_disk_t dsk, const grub_partition_t partition, void *data)
+{
+  struct grub_partition_map_probe_ctx *ctx = data;
 
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
+  if (ctx->partnum != partition->number)
+    return 0;
 
-  int find_func (grub_disk_t dsk,
-                const grub_partition_t partition)
-    {
-      if (partnum != partition->number)
-       return 0;
+  if (!(grub_partition_check_containment (dsk, partition)))
+    return 0;
 
-      if (!(grub_partition_check_containment (dsk, partition)))
-       return 0;
+  ctx->p = (grub_partition_t) grub_malloc (sizeof (*ctx->p));
+  if (! ctx->p)
+    return 1;
 
-      p = (grub_partition_t) grub_malloc (sizeof (*p));
-      if (! p)
-       return 1;
+  grub_memcpy (ctx->p, partition, sizeof (*ctx->p));
+  return 1;
+}
 
-      grub_memcpy (p, partition, sizeof (*p));
-      return 1;
-    }
+static grub_partition_t
+grub_partition_map_probe (const grub_partition_map_t partmap,
+                         grub_disk_t disk, int partnum)
+{
+  struct grub_partition_map_probe_ctx ctx = {
+    .partnum = partnum,
+    .p = 0
+  };
 
-  partmap->iterate (disk, find_func);
+  partmap->iterate (disk, probe_iter, &ctx);
   if (grub_errno)
     goto fail;
 
-  return p;
+  return ctx.p;
 
  fail:
-  grub_free (p);
+  grub_free (ctx.p);
   return 0;
 }
 
@@ -162,62 +173,71 @@ grub_partition_probe (struct grub_disk *
   return part;
 }
 
-int
-grub_partition_iterate (struct grub_disk *disk,
-                       int (*hook) (grub_disk_t disk,
-                                    const grub_partition_t partition))
+/* Context for grub_partition_iterate.  */
+struct grub_partition_iterate_ctx
 {
-  int ret = 0;
+  int ret;
+  grub_partition_iterate_hook_t hook;
+  void *hook_data;
+};
+
+/* Helper for grub_partition_iterate.  */
+static int
+part_iterate (grub_disk_t dsk, const grub_partition_t partition, void *data)
+{
+  struct grub_partition_iterate_ctx *ctx = data;
+  struct grub_partition p = *partition;
 
-  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
+  if (!(grub_partition_check_containment (dsk, partition)))
+    return 0;
 
-  int part_iterate (grub_disk_t dsk,
-                   const grub_partition_t partition)
+  p.parent = dsk->partition;
+  dsk->partition = 0;
+  if (ctx->hook (dsk, &p, ctx->hook_data))
     {
-      struct grub_partition p = *partition;
-
-      if (!(grub_partition_check_containment (dsk, partition)))
-       return 0;
-
-      p.parent = dsk->partition;
-      dsk->partition = 0;
-      if (hook (dsk, &p))
-       {
-         ret = 1;
-         return 1;
-       }
-      if (p.start != 0)
-       {
-         const struct grub_partition_map *partmap;
-         dsk->partition = &p;
-         FOR_PARTITION_MAPS(partmap)
-         {
-           grub_err_t err;
-           err = partmap->iterate (dsk, part_iterate);
-           if (err)
-             grub_errno = GRUB_ERR_NONE;
-           if (ret)
-             break;
-         }
-       }
-      dsk->partition = p.parent;
-      return ret;
+      ctx->ret = 1;
+      return 1;
     }
-
-  {
-    const struct grub_partition_map *partmap;
-    FOR_PARTITION_MAPS(partmap)
+  if (p.start != 0)
     {
-      grub_err_t err;
-      err = partmap->iterate (disk, part_iterate);
-      if (err)
-       grub_errno = GRUB_ERR_NONE;
-      if (ret)
-       break;
+      const struct grub_partition_map *partmap;
+      dsk->partition = &p;
+      FOR_PARTITION_MAPS(partmap)
+      {
+       grub_err_t err;
+       err = partmap->iterate (dsk, part_iterate, ctx);
+       if (err)
+         grub_errno = GRUB_ERR_NONE;
+       if (ctx->ret)
+         break;
+      }
     }
+  dsk->partition = p.parent;
+  return ctx->ret;
+}
+
+int
+grub_partition_iterate (struct grub_disk *disk,
+                       grub_partition_iterate_hook_t hook, void *hook_data)
+{
+  struct grub_partition_iterate_ctx ctx = {
+    .ret = 0,
+    .hook = hook,
+    .hook_data = hook_data
+  };
+  const struct grub_partition_map *partmap;
+
+  FOR_PARTITION_MAPS(partmap)
+  {
+    grub_err_t err;
+    err = partmap->iterate (disk, part_iterate, &ctx);
+    if (err)
+      grub_errno = GRUB_ERR_NONE;
+    if (ctx.ret)
+      break;
   }
 
-  return ret;
+  return ctx.ret;
 }
 
 char *

=== modified file 'grub-core/loader/i386/pc/plan9.c'
--- grub-core/loader/i386/pc/plan9.c    2012-03-03 19:06:41 +0000
+++ grub-core/loader/i386/pc/plan9.c    2013-01-15 17:26:54 +0000
@@ -102,248 +102,281 @@ grub_plan9_unload (void)
   return GRUB_ERR_NONE;
 }
 
-static grub_err_t
-grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[])
+/* Context for grub_cmd_plan9.  */
+struct grub_cmd_plan9_ctx
 {
-  grub_file_t file = 0;
-  void *mem;
-  grub_size_t memsize, padsize;
-  struct grub_plan9_header hdr;
-  char *config, *configptr;
-  grub_size_t configsize;
-  char *pmap = NULL;
-  grub_size_t pmapalloc = 256;
-  grub_size_t pmapptr = 0;
-  int noslash = 1;
-  char prefixes[5][10] = {"dos", "plan9", "ntfs", "linux", "linuxswap"};
+  grub_extcmd_context_t ctxt;
+  grub_file_t file;
+  char *pmap;
+  grub_size_t pmapalloc;
+  grub_size_t pmapptr;
+  int noslash;
   int prefixescnt[5];
-  char *bootdisk = NULL, *bootpart = NULL, *bootpath = NULL;
+  char *bootdisk, *bootpart;
+};
 
-  auto int fill_partition (grub_disk_t disk,
-                          const grub_partition_t partition);
-  int fill_partition (grub_disk_t disk,
-                     const grub_partition_t partition)
-  {
-    int file_disk = 0;
-    int pstart, pend;
-    if (!noslash)
-      {
-       if (grub_extend_alloc (pmapptr + 1, &pmapalloc, (void **) &pmap))
-         return 1;
-       pmap[pmapptr++] = '/';
-      }
-    noslash = 0;
+static const char prefixes[5][10] = {
+  "dos", "plan9", "ntfs", "linux", "linuxswap"
+};
+
+/* Helper for grub_cmd_plan9.  */
+static int
+fill_partition (grub_disk_t disk, const grub_partition_t partition, void *data)
+{
+  struct grub_cmd_plan9_ctx *fill_ctx = data;
+  int file_disk = 0;
+  int pstart, pend;
 
-    file_disk = file->device->disk && disk->id == file->device->disk->id
-      && disk->dev->id == file->device->disk->dev->id;
+  if (!fill_ctx->noslash)
+    {
+      if (grub_extend_alloc (fill_ctx->pmapptr + 1, &fill_ctx->pmapalloc,
+                            (void **) &fill_ctx->pmap))
+       return 1;
+      fill_ctx->pmap[fill_ctx->pmapptr++] = '/';
+    }
+  fill_ctx->noslash = 0;
 
-    pstart = pmapptr;
-    if (grub_strcmp (partition->partmap->name, "plan") == 0)
-      {
-       unsigned ptr = partition->index + sizeof ("part ") - 1;
-       grub_err_t err;
-       disk->partition = partition->parent;
-       do
-         {
-           if (grub_extend_alloc (pmapptr + 1, &pmapalloc, (void **) &pmap))
-             return 1;
-           err = grub_disk_read (disk, 1, ptr, 1, pmap + pmapptr);
-           if (err)
-             {
-               disk->partition = 0;
-               return err;
-             }
-           ptr++;
-           pmapptr++;
-         }
-       while (grub_isalpha (pmap[pmapptr - 1])
-              || grub_isdigit (pmap[pmapptr - 1]));
-       pmapptr--;
-      }
-    else
-      {
-       char name[50];
-       int c = 0;
-       if (grub_strcmp (partition->partmap->name, "msdos") == 0)
-         {
-           switch (partition->msdostype)
-             {
-             case GRUB_PC_PARTITION_TYPE_PLAN9:
-               c = 1;
-               break;
-             case GRUB_PC_PARTITION_TYPE_NTFS:
-               c = 2;
-               break;
-             case GRUB_PC_PARTITION_TYPE_MINIX:
-             case GRUB_PC_PARTITION_TYPE_LINUX_MINIX:
-             case GRUB_PC_PARTITION_TYPE_EXT2FS:
-               c = 3;
-               break;
-             case GRUB_PC_PARTITION_TYPE_LINUX_SWAP:
-               c = 4;
-               break;
-             }
-         }
+  file_disk = fill_ctx->file->device->disk
+    && disk->id == fill_ctx->file->device->disk->id
+    && disk->dev->id == fill_ctx->file->device->disk->dev->id;
 
-       if (prefixescnt[c] == 0)
-         grub_strcpy (name, prefixes[c]);
-       else
-         grub_snprintf (name, sizeof (name), "%s.%d", prefixes[c],
-                        prefixescnt[c]);
-       prefixescnt[c]++;
-       if (grub_extend_alloc (pmapptr + grub_strlen (name) + 1,
-                              &pmapalloc, (void **) &pmap))
-         return 1;
-       grub_strcpy (pmap + pmapptr, name);
-       pmapptr += grub_strlen (name);
-      }
-    pend = pmapptr;
-    if (grub_extend_alloc (pmapptr + 2 + 25 + 5 + 25, &pmapalloc,
-                          (void **) &pmap))
-      return 1;
-    pmap[pmapptr++] = ' ';
-    grub_snprintf (pmap + pmapptr, 25 + 5 + 25,
-                  "%" PRIuGRUB_UINT64_T " %" PRIuGRUB_UINT64_T,
-                  grub_partition_get_start (partition),
-                  grub_partition_get_start (partition)
-                  + grub_partition_get_len (partition));
-    if (file_disk && grub_partition_get_start (partition)
-       == grub_partition_get_start (file->device->disk->partition)
-       && grub_partition_get_len (partition)
-       == grub_partition_get_len (file->device->disk->partition))
-      {
-       grub_free (bootpart);
-       bootpart = grub_strndup (pmap + pstart, pend - pstart);
-      }
+  pstart = fill_ctx->pmapptr;
+  if (grub_strcmp (partition->partmap->name, "plan") == 0)
+    {
+      unsigned ptr = partition->index + sizeof ("part ") - 1;
+      grub_err_t err;
+      disk->partition = partition->parent;
+      do
+       {
+         if (grub_extend_alloc (fill_ctx->pmapptr + 1, &fill_ctx->pmapalloc,
+                                (void **) &fill_ctx->pmap))
+           return 1;
+         err = grub_disk_read (disk, 1, ptr, 1,
+                               fill_ctx->pmap + fill_ctx->pmapptr);
+         if (err)
+           {
+             disk->partition = 0;
+             return err;
+           }
+         ptr++;
+         fill_ctx->pmapptr++;
+       }
+      while (grub_isalpha (fill_ctx->pmap[fill_ctx->pmapptr - 1])
+            || grub_isdigit (fill_ctx->pmap[fill_ctx->pmapptr - 1]));
+      fill_ctx->pmapptr--;
+    }
+  else
+    {
+      char name[50];
+      int c = 0;
+      if (grub_strcmp (partition->partmap->name, "msdos") == 0)
+       {
+         switch (partition->msdostype)
+           {
+           case GRUB_PC_PARTITION_TYPE_PLAN9:
+             c = 1;
+             break;
+           case GRUB_PC_PARTITION_TYPE_NTFS:
+             c = 2;
+             break;
+           case GRUB_PC_PARTITION_TYPE_MINIX:
+           case GRUB_PC_PARTITION_TYPE_LINUX_MINIX:
+           case GRUB_PC_PARTITION_TYPE_EXT2FS:
+             c = 3;
+             break;
+           case GRUB_PC_PARTITION_TYPE_LINUX_SWAP:
+             c = 4;
+             break;
+           }
+       }
 
-    pmapptr += grub_strlen (pmap + pmapptr);
-    return 0;
-  }
+      if (fill_ctx->prefixescnt[c] == 0)
+       grub_strcpy (name, prefixes[c]);
+      else
+       grub_snprintf (name, sizeof (name), "%s.%d", prefixes[c],
+                      fill_ctx->prefixescnt[c]);
+      fill_ctx->prefixescnt[c]++;
+      if (grub_extend_alloc (fill_ctx->pmapptr + grub_strlen (name) + 1,
+                            &fill_ctx->pmapalloc, (void **) &fill_ctx->pmap))
+       return 1;
+      grub_strcpy (fill_ctx->pmap + fill_ctx->pmapptr, name);
+      fill_ctx->pmapptr += grub_strlen (name);
+    }
+  pend = fill_ctx->pmapptr;
+  if (grub_extend_alloc (fill_ctx->pmapptr + 2 + 25 + 5 + 25,
+                        &fill_ctx->pmapalloc, (void **) &fill_ctx->pmap))
+    return 1;
+  fill_ctx->pmap[fill_ctx->pmapptr++] = ' ';
+  grub_snprintf (fill_ctx->pmap + fill_ctx->pmapptr, 25 + 5 + 25,
+                "%" PRIuGRUB_UINT64_T " %" PRIuGRUB_UINT64_T,
+                grub_partition_get_start (partition),
+                grub_partition_get_start (partition)
+                + grub_partition_get_len (partition));
+  if (file_disk && grub_partition_get_start (partition)
+      == grub_partition_get_start (fill_ctx->file->device->disk->partition)
+      && grub_partition_get_len (partition)
+      == grub_partition_get_len (fill_ctx->file->device->disk->partition))
+    {
+      grub_free (fill_ctx->bootpart);
+      fill_ctx->bootpart = grub_strndup (fill_ctx->pmap + pstart,
+                                        pend - pstart);
+    }
 
-  auto int fill_disk (const char *name);
-  int fill_disk (const char *name)
-  {
-    grub_device_t dev;
-    char *plan9name = NULL;
-    unsigned i;
-    int file_disk = 0;
+  fill_ctx->pmapptr += grub_strlen (fill_ctx->pmap + fill_ctx->pmapptr);
+  return 0;
+}
 
-    dev = grub_device_open (name);
-    if (!dev)
-      {
-       grub_print_error ();
-       return 0;
-      }
-    if (!dev->disk)
-      {
-       grub_device_close (dev);
-       return 0;
-      }
-    file_disk = file->device->disk && dev->disk->id == file->device->disk->id
-      && dev->disk->dev->id == file->device->disk->dev->id;
-    for (i = 0; ctxt->state[0].args && ctxt->state[0].args[i]; i++)
-      if (grub_strncmp (name, ctxt->state[0].args[i], grub_strlen (name)) == 0
-         && ctxt->state[0].args[i][grub_strlen (name)] == '=')
+/* Helper for grub_cmd_plan9.  */
+static int
+fill_disk (const char *name, void *data)
+{
+  struct grub_cmd_plan9_ctx *fill_ctx = data;
+  grub_device_t dev;
+  char *plan9name = NULL;
+  unsigned i;
+  int file_disk = 0;
+
+  dev = grub_device_open (name);
+  if (!dev)
+    {
+      grub_print_error ();
+      return 0;
+    }
+  if (!dev->disk)
+    {
+      grub_device_close (dev);
+      return 0;
+    }
+  file_disk = fill_ctx->file->device->disk
+    && dev->disk->id == fill_ctx->file->device->disk->id
+    && dev->disk->dev->id == fill_ctx->file->device->disk->dev->id;
+  for (i = 0;
+       fill_ctx->ctxt->state[0].args && fill_ctx->ctxt->state[0].args[i]; i++)
+    if (grub_strncmp (name, fill_ctx->ctxt->state[0].args[i],
+                     grub_strlen (name)) == 0
+       && fill_ctx->ctxt->state[0].args[i][grub_strlen (name)] == '=')
+      break;
+  if (fill_ctx->ctxt->state[0].args && fill_ctx->ctxt->state[0].args[i])
+    plan9name = grub_strdup (fill_ctx->ctxt->state[0].args[i]
+                            + grub_strlen (name) + 1);
+  else
+    switch (dev->disk->dev->id)
+      {
+      case GRUB_DISK_DEVICE_BIOSDISK_ID:
+       if (dev->disk->id & 0x80)
+         plan9name = grub_xasprintf ("sdB%u",
+                                     (unsigned) (dev->disk->id & 0x7f));
+       else
+         plan9name = grub_xasprintf ("fd%u",
+                                     (unsigned) (dev->disk->id & 0x7f));
        break;
-    if (ctxt->state[0].args && ctxt->state[0].args[i])
-      plan9name = grub_strdup (ctxt->state[0].args[i] + grub_strlen (name) + 
1);
-    else
-      switch (dev->disk->dev->id)
+       /* Shouldn't happen as Plan9 doesn't work on these platforms.  */
+      case GRUB_DISK_DEVICE_OFDISK_ID:
+      case GRUB_DISK_DEVICE_EFIDISK_ID:
+
+       /* Plan9 doesn't see those.  */
+      default:
+
+       /* Not sure how to handle those. */
+      case GRUB_DISK_DEVICE_NAND_ID:
+       if (!file_disk)
+         {
+           grub_device_close (dev);
+           return 0;
+         }
+       
+       /* if it's the disk the kernel is loaded from we need to name
+          it nevertheless.  */
+       plan9name = grub_strdup ("sdZ0");
+       break;
+
+      case GRUB_DISK_DEVICE_ATA_ID:
        {
-       case GRUB_DISK_DEVICE_BIOSDISK_ID:
-         if (dev->disk->id & 0x80)
-           plan9name = grub_xasprintf ("sdB%u",
-                                       (unsigned) (dev->disk->id & 0x7f));
+         int unit;
+         if (grub_strlen (dev->disk->name) < sizeof ("ata0") - 1)
+           unit = 0;
          else
-           plan9name = grub_xasprintf ("fd%u",
-                                       (unsigned) (dev->disk->id & 0x7f));
-         break;
-         /* Shouldn't happen as Plan9 doesn't work on these platforms.  */
-       case GRUB_DISK_DEVICE_OFDISK_ID:
-       case GRUB_DISK_DEVICE_EFIDISK_ID:
-
-         /* Plan9 doesn't see those.  */
-       default:
-
-         /* Not sure how to handle those. */
-       case GRUB_DISK_DEVICE_NAND_ID:
-         if (!file_disk)
-           {
-             grub_device_close (dev);
-             return 0;
-           }
-         
-         /* if it's the disk the kernel is loaded from we need to name
-            it nevertheless.  */
-         plan9name = grub_strdup ("sdZ0");
-         break;
-
-       case GRUB_DISK_DEVICE_ATA_ID:
+           unit = grub_strtoul (dev->disk->name + sizeof ("ata0") - 1, 0, 0);
+         plan9name = grub_xasprintf ("sd%c%d", 'C' + unit / 2, unit % 2);
+       }
+       break;
+      case GRUB_DISK_DEVICE_SCSI_ID:
+       if (((dev->disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xff)
+           == GRUB_SCSI_SUBSYSTEM_PATA)
          {
            int unit;
            if (grub_strlen (dev->disk->name) < sizeof ("ata0") - 1)
              unit = 0;
            else
-             unit = grub_strtoul (dev->disk->name + sizeof ("ata0") - 1, 0, 0);
+             unit = grub_strtoul (dev->disk->name + sizeof ("ata0") - 1,
+                                  0, 0);
            plan9name = grub_xasprintf ("sd%c%d", 'C' + unit / 2, unit % 2);
+           break;
          }
-         break;
-       case GRUB_DISK_DEVICE_SCSI_ID:
-         if (((dev->disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xff)
-             == GRUB_SCSI_SUBSYSTEM_PATA)
-           {
-             int unit;
-             if (grub_strlen (dev->disk->name) < sizeof ("ata0") - 1)
-               unit = 0;
-             else
-               unit = grub_strtoul (dev->disk->name + sizeof ("ata0") - 1,
-                                    0, 0);
-             plan9name = grub_xasprintf ("sd%c%d", 'C' + unit / 2, unit % 2);
-             break;
-           }
-         
-         /* FIXME: how does Plan9 number controllers?
-            We probably need save the SCSI devices and sort them  */
-         plan9name
-           = grub_xasprintf ("sd0%u", (unsigned)
-                             ((dev->disk->id >> GRUB_SCSI_ID_BUS_SHIFT)
-                              & 0xf));
-         break;
-       }
-    if (!plan9name)
-      {
-       grub_print_error ();
-       return 0;
-      }
-    if (grub_extend_alloc (pmapptr + grub_strlen (plan9name)
-                          + sizeof ("part="), &pmapalloc,
-                          (void **) &pmap))
-      {
-       grub_free (plan9name);
-       return 1;
+       
+       /* FIXME: how does Plan9 number controllers?
+          We probably need save the SCSI devices and sort them  */
+       plan9name
+         = grub_xasprintf ("sd0%u", (unsigned)
+                           ((dev->disk->id >> GRUB_SCSI_ID_BUS_SHIFT)
+                            & 0xf));
+       break;
       }
-    grub_strcpy (pmap + pmapptr, plan9name);
-    pmapptr += grub_strlen (plan9name);
-    if (!file_disk)
+  if (!plan9name)
+    {
+      grub_print_error ();
+      return 0;
+    }
+  if (grub_extend_alloc (fill_ctx->pmapptr + grub_strlen (plan9name)
+                        + sizeof ("part="), &fill_ctx->pmapalloc,
+                        (void **) &fill_ctx->pmap))
+    {
       grub_free (plan9name);
-    else
-      {
-       grub_free (bootdisk);
-       bootdisk = plan9name;
-      }
-    grub_strcpy (pmap + pmapptr, "part=");
-    pmapptr += sizeof ("part=") - 1;
-
-    noslash = 1;
-    grub_memset (prefixescnt, 0, sizeof (prefixescnt));
-    if (grub_partition_iterate (dev->disk, fill_partition))
-      return 1;
-    if (grub_extend_alloc (pmapptr + 1, &pmapalloc, (void **) &pmap))
       return 1;
-    pmap[pmapptr++] = '\n';
+    }
+  grub_strcpy (fill_ctx->pmap + fill_ctx->pmapptr, plan9name);
+  fill_ctx->pmapptr += grub_strlen (plan9name);
+  if (!file_disk)
+    grub_free (plan9name);
+  else
+    {
+      grub_free (fill_ctx->bootdisk);
+      fill_ctx->bootdisk = plan9name;
+    }
+  grub_strcpy (fill_ctx->pmap + fill_ctx->pmapptr, "part=");
+  fill_ctx->pmapptr += sizeof ("part=") - 1;
 
-    return 0;
-  }
+  fill_ctx->noslash = 1;
+  grub_memset (fill_ctx->prefixescnt, 0, sizeof (fill_ctx->prefixescnt));
+  if (grub_partition_iterate (dev->disk, fill_partition, fill_ctx))
+    return 1;
+  if (grub_extend_alloc (fill_ctx->pmapptr + 1, &fill_ctx->pmapalloc,
+                        (void **) &fill_ctx->pmap))
+    return 1;
+  fill_ctx->pmap[fill_ctx->pmapptr++] = '\n';
+
+  return 0;
+}
+
+static grub_err_t
+grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[])
+{
+  struct grub_cmd_plan9_ctx fill_ctx = {
+    .ctxt = ctxt,
+    .file = 0,
+    .pmap = NULL,
+    .pmapalloc = 256,
+    .pmapptr = 0,
+    .noslash = 1,
+    .bootdisk = NULL,
+    .bootpart = NULL
+  };
+  void *mem;
+  grub_size_t memsize, padsize;
+  struct grub_plan9_header hdr;
+  char *config, *configptr;
+  grub_size_t configsize;
+  char *bootpath = NULL;
 
   if (argc == 0)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@@ -354,21 +387,21 @@ grub_cmd_plan9 (grub_extcmd_context_t ct
   if (!rel)
     goto fail;
 
-  file = grub_file_open (argv[0]);
-  if (! file)
+  fill_ctx.file = grub_file_open (argv[0]);
+  if (! fill_ctx.file)
     goto fail;
 
-  pmap = grub_malloc (pmapalloc);
-  if (!pmap)
+  fill_ctx.pmap = grub_malloc (fill_ctx.pmapalloc);
+  if (!fill_ctx.pmap)
     goto fail;
 
-  if (grub_disk_dev_iterate (fill_disk))
+  if (grub_disk_dev_iterate (fill_disk, &fill_ctx))
     goto fail;
 
-  if (grub_extend_alloc (pmapptr + 1, &pmapalloc,
-                        (void **) &pmap))
+  if (grub_extend_alloc (fill_ctx.pmapptr + 1, &fill_ctx.pmapalloc,
+                        (void **) &fill_ctx.pmap))
     goto fail;
-  pmap[pmapptr] = 0;
+  fill_ctx.pmap[fill_ctx.pmapptr] = 0;
 
   {
     char *file_name = grub_strchr (argv[0], ')');
@@ -379,17 +412,19 @@ grub_cmd_plan9 (grub_extcmd_context_t ct
     if (*file_name)
       file_name++;
 
-    if (bootpart)
-      bootpath = grub_xasprintf ("%s!%s!%s", bootdisk, bootpart, file_name);
+    if (fill_ctx.bootpart)
+      bootpath = grub_xasprintf ("%s!%s!%s", fill_ctx.bootdisk,
+                                fill_ctx.bootpart, file_name);
     else
-      bootpath = grub_xasprintf ("%s!%s", bootdisk, file_name);
-    grub_free (bootdisk);
-    grub_free (bootpart);
+      bootpath = grub_xasprintf ("%s!%s", fill_ctx.bootdisk, file_name);
+    grub_free (fill_ctx.bootdisk);
+    grub_free (fill_ctx.bootpart);
   }
   if (!bootpath)
     goto fail;
 
-  if (grub_file_read (file, &hdr, sizeof (hdr)) != (grub_ssize_t) sizeof (hdr))
+  if (grub_file_read (fill_ctx.file, &hdr,
+                     sizeof (hdr)) != (grub_ssize_t) sizeof (hdr))
     {
       if (!grub_errno)
        grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
@@ -420,7 +455,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ct
       configsize += grub_strlen (argv[i]) + 1;
   }
   configsize += (sizeof ("bootfile=") - 1) + grub_strlen (bootpath) + 1;
-  configsize += pmapptr;
+  configsize += fill_ctx.pmapptr;
   /* Terminating \0.  */
   configsize++;
 
@@ -452,7 +487,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ct
        *configptr++ = '\n';
       }
   }
-  configptr = grub_stpcpy (configptr, pmap);
+  configptr = grub_stpcpy (configptr, fill_ctx.pmap);
 
   {
     grub_relocator_chunk_t ch;
@@ -471,7 +506,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ct
     grub_memcpy (ptr, &hdr, sizeof (hdr));
     ptr += sizeof (hdr);
 
-    if (grub_file_read (file, ptr, grub_be_to_cpu32 (hdr.text_size))
+    if (grub_file_read (fill_ctx.file, ptr, grub_be_to_cpu32 (hdr.text_size))
        != (grub_ssize_t) grub_be_to_cpu32 (hdr.text_size))
       {
        if (!grub_errno)
@@ -487,7 +522,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ct
     grub_memset (ptr, 0, padsize);
     ptr += padsize;
 
-    if (grub_file_read (file, ptr, grub_be_to_cpu32 (hdr.data_size))
+    if (grub_file_read (fill_ctx.file, ptr, grub_be_to_cpu32 (hdr.data_size))
        != (grub_ssize_t) grub_be_to_cpu32 (hdr.data_size))
       {
        if (!grub_errno)
@@ -508,10 +543,10 @@ grub_cmd_plan9 (grub_extcmd_context_t ct
   return GRUB_ERR_NONE;
 
  fail:
-  grub_free (pmap);
+  grub_free (fill_ctx.pmap);
 
-  if (file)
-    grub_file_close (file);
+  if (fill_ctx.file)
+    grub_file_close (fill_ctx.file);
 
   grub_plan9_unload ();
 

=== modified file 'grub-core/normal/completion.c'
--- grub-core/normal/completion.c       2013-01-15 12:03:25 +0000
+++ grub-core/normal/completion.c       2013-01-15 16:30:28 +0000
@@ -99,7 +99,8 @@ add_completion (const char *completion,
 }
 
 static int
-iterate_partition (grub_disk_t disk, const grub_partition_t p)
+iterate_partition (grub_disk_t disk, const grub_partition_t p,
+                  void *data __attribute__ ((unused)))
 {
   const char *disk_name = disk->name;
   char *name;
@@ -154,7 +155,7 @@ iterate_dir (const char *filename, const
 }
 
 static int
-iterate_dev (const char *devname)
+iterate_dev (const char *devname, void *data __attribute__ ((unused)))
 {
   grub_device_t dev;
 
@@ -180,7 +181,7 @@ iterate_dev (const char *devname)
          }
 
        if (dev->disk)
-         if (grub_partition_iterate (dev->disk, iterate_partition))
+         if (grub_partition_iterate (dev->disk, iterate_partition, NULL))
            {
              grub_device_close (dev);
              return 1;
@@ -213,7 +214,7 @@ complete_device (void)
   if (! p)
     {
       /* Complete the disk part.  */
-      if (grub_disk_dev_iterate (iterate_dev))
+      if (grub_disk_dev_iterate (iterate_dev, NULL))
        return 1;
     }
   else
@@ -228,7 +229,7 @@ complete_device (void)
        {
          if (dev->disk)
            {
-             if (grub_partition_iterate (dev->disk, iterate_partition))
+             if (grub_partition_iterate (dev->disk, iterate_partition, NULL))
                {
                  grub_device_close (dev);
                  return 1;

=== modified file 'grub-core/partmap/acorn.c'
--- grub-core/partmap/acorn.c   2011-06-23 18:05:39 +0000
+++ grub-core/partmap/acorn.c   2013-01-15 16:37:21 +0000
@@ -101,8 +101,8 @@ fail:
 
 static grub_err_t
 acorn_partition_map_iterate (grub_disk_t disk,
-                            int (*hook) (grub_disk_t disk,
-                                         const grub_partition_t partition))
+                            grub_partition_iterate_hook_t hook,
+                            void *hook_data)
 {
   struct grub_partition part;
   struct linux_part map[LINUX_MAP_ENTRIES];
@@ -127,7 +127,7 @@ acorn_partition_map_iterate (grub_disk_t
       part.offset = 6;
       part.number = part.index = i;
 
-      if (hook (disk, &part))
+      if (hook (disk, &part, hook_data))
        return grub_errno;
     }
 

=== modified file 'grub-core/partmap/amiga.c'
--- grub-core/partmap/amiga.c   2011-05-15 10:23:54 +0000
+++ grub-core/partmap/amiga.c   2013-01-15 16:37:17 +0000
@@ -87,8 +87,8 @@ amiga_partition_map_checksum (void *buf,
 
 static grub_err_t
 amiga_partition_map_iterate (grub_disk_t disk,
-                            int (*hook) (grub_disk_t disk,
-                                         const grub_partition_t partition))
+                            grub_partition_iterate_hook_t hook,
+                            void *hook_data)
 {
   struct grub_partition part;
   struct grub_amiga_rdsk rdsk;
@@ -145,7 +145,7 @@ amiga_partition_map_iterate (grub_disk_t
       part.index = 0;
       part.partmap = &grub_amiga_partition_map;
 
-      if (hook (disk, &part))
+      if (hook (disk, &part, hook_data))
        return grub_errno;
 
       next = grub_be_to_cpu32 (apart.next);

=== modified file 'grub-core/partmap/apple.c'
--- grub-core/partmap/apple.c   2011-04-11 21:01:51 +0000
+++ grub-core/partmap/apple.c   2013-01-15 16:37:28 +0000
@@ -101,8 +101,8 @@ static struct grub_partition_map grub_ap
 
 static grub_err_t
 apple_partition_map_iterate (grub_disk_t disk,
-                            int (*hook) (grub_disk_t disk,
-                                         const grub_partition_t partition))
+                            grub_partition_iterate_hook_t hook,
+                            void *hook_data)
 {
   struct grub_partition part;
   struct grub_apple_header aheader;
@@ -163,7 +163,7 @@ apple_partition_map_iterate (grub_disk_t
                    grub_be_to_cpu32 (apart.first_phys_block),
                    grub_be_to_cpu32 (apart.blockcnt));
 
-      if (hook (disk, &part))
+      if (hook (disk, &part, hook_data))
        return grub_errno;
 
       pos += grub_be_to_cpu16 (aheader.blocksize);

=== modified file 'grub-core/partmap/bsdlabel.c'
--- grub-core/partmap/bsdlabel.c        2012-02-10 11:43:11 +0000
+++ grub-core/partmap/bsdlabel.c        2013-01-15 16:37:06 +0000
@@ -41,8 +41,7 @@ static struct grub_partition_map grub_op
 static grub_err_t
 iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd,
              struct grub_partition_map *pmap,
-             int (*hook) (grub_disk_t disk,
-                          const grub_partition_t partition))
+             grub_partition_iterate_hook_t hook, void *hook_data)
 {
   struct grub_partition_bsd_disk_label label;
   struct grub_partition p;
@@ -116,7 +115,7 @@ iterate_real (grub_disk_t disk, grub_dis
 
       p.start -= delta;
 
-      if (hook (disk, &p))
+      if (hook (disk, &p, hook_data))
        return grub_errno;
     }
   return GRUB_ERR_NONE;
@@ -124,14 +123,14 @@ iterate_real (grub_disk_t disk, grub_dis
 
 static grub_err_t
 bsdlabel_partition_map_iterate (grub_disk_t disk,
-                               int (*hook) (grub_disk_t disk,
-                                            const grub_partition_t partition))
+                               grub_partition_iterate_hook_t hook,
+                               void *hook_data)
 {
 
   if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos")
       == 0 && disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_FREEBSD)
     return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 1,
-                        &grub_bsdlabel_partition_map, hook);
+                        &grub_bsdlabel_partition_map, hook, hook_data);
 
   if (disk->partition 
       && (grub_strcmp (disk->partition->partmap->name, "msdos") == 0
@@ -141,7 +140,44 @@ bsdlabel_partition_map_iterate (grub_dis
       return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
 
   return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, 
-                      &grub_bsdlabel_partition_map, hook);
+                      &grub_bsdlabel_partition_map, hook, hook_data);
+}
+
+/* Context for netopenbsdlabel_partition_map_iterate.  */
+struct netopenbsdlabel_ctx
+{
+  grub_uint8_t type;
+  struct grub_partition_map *pmap;
+  grub_partition_iterate_hook_t hook;
+  void *hook_data;
+  int count;
+};
+
+/* Helper for netopenbsdlabel_partition_map_iterate.  */
+static int
+check_msdos (grub_disk_t dsk, const grub_partition_t partition, void *data)
+{
+  struct netopenbsdlabel_ctx *ctx = data;
+  grub_err_t err;
+
+  if (partition->msdostype != ctx->type)
+    return 0;
+
+  err = iterate_real (dsk, partition->start
+                     + GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, ctx->pmap,
+                     ctx->hook, ctx->hook_data);
+  if (err == GRUB_ERR_NONE)
+    {
+      ctx->count++;
+      return 1;
+    }
+  if (err == GRUB_ERR_BAD_PART_TABLE)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return 0;
+    }
+  grub_print_error ();
+  return 0;
 }
 
 /* This is a total breakage. Even when net-/openbsd label is inside partition
@@ -150,45 +186,26 @@ bsdlabel_partition_map_iterate (grub_dis
 static grub_err_t
 netopenbsdlabel_partition_map_iterate (grub_disk_t disk, grub_uint8_t type,
                                       struct grub_partition_map *pmap,
-                                      int (*hook) (grub_disk_t disk,
-                                                   const grub_partition_t 
partition))
+                                      grub_partition_iterate_hook_t hook,
+                                      void *hook_data)
 {
   int count = 0;
 
-  auto int check_msdos (grub_disk_t dsk,
-                       const grub_partition_t partition);
-
-  int check_msdos (grub_disk_t dsk,
-                  const grub_partition_t partition)
-  {
-    grub_err_t err;
-
-    if (partition->msdostype != type)
-      return 0;
-
-    err = iterate_real (dsk, partition->start
-                       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, pmap, hook);
-    if (err == GRUB_ERR_NONE)
-      {
-       count++;
-       return 1;
-      }
-    if (err == GRUB_ERR_BAD_PART_TABLE)
-      {
-       grub_errno = GRUB_ERR_NONE;
-       return 0;
-      }
-    grub_print_error ();
-    return 0;
-  }
-
   if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos")
       == 0)
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
 
   {
+    struct netopenbsdlabel_ctx ctx = {
+      .type = type,
+      .pmap = pmap,
+      .hook = hook,
+      .hook_data = hook_data,
+      .count = count
+    };
     grub_err_t err;
-    err = grub_partition_msdos_iterate (disk, check_msdos);
+
+    err = grub_partition_msdos_iterate (disk, check_msdos, &ctx);
 
     if (err)
       return err;
@@ -200,24 +217,24 @@ netopenbsdlabel_partition_map_iterate (g
 
 static grub_err_t
 netbsdlabel_partition_map_iterate (grub_disk_t disk,
-                                  int (*hook) (grub_disk_t disk,
-                                               const grub_partition_t 
partition))
+                                  grub_partition_iterate_hook_t hook,
+                                  void *hook_data)
 {
   return netopenbsdlabel_partition_map_iterate (disk,
                                                GRUB_PC_PARTITION_TYPE_NETBSD,
                                                &grub_netbsdlabel_partition_map,
-                                               hook);
+                                               hook, hook_data);
 }
 
 static grub_err_t
 openbsdlabel_partition_map_iterate (grub_disk_t disk,
-                                  int (*hook) (grub_disk_t disk,
-                                               const grub_partition_t 
partition))
+                                   grub_partition_iterate_hook_t hook,
+                                   void *hook_data)
 {
   return netopenbsdlabel_partition_map_iterate (disk,
                                                GRUB_PC_PARTITION_TYPE_OPENBSD,
                                                
&grub_openbsdlabel_partition_map,
-                                               hook);
+                                               hook, hook_data);
 }
 
 

=== modified file 'grub-core/partmap/dvh.c'
--- grub-core/partmap/dvh.c     2012-09-05 06:47:39 +0000
+++ grub-core/partmap/dvh.c     2013-01-15 16:37:11 +0000
@@ -64,8 +64,7 @@ grub_dvh_is_valid (grub_uint32_t *label)
 
 static grub_err_t
 dvh_partition_map_iterate (grub_disk_t disk,
-                           int (*hook) (grub_disk_t disk,
-                                       const grub_partition_t partition))
+                          grub_partition_iterate_hook_t hook, void *hook_data)
 {
   struct grub_partition p;
   union
@@ -101,7 +100,7 @@ dvh_partition_map_iterate (grub_disk_t d
       p.start = grub_be_to_cpu32 (block.dvh.parts[partnum].start);
       p.len = grub_be_to_cpu32 (block.dvh.parts[partnum].length);
       p.number = p.index = partnum;
-      if (hook (disk, &p))
+      if (hook (disk, &p, hook_data))
        break;
     }
 

=== modified file 'grub-core/partmap/gpt.c'
--- grub-core/partmap/gpt.c     2012-05-22 07:09:00 +0000
+++ grub-core/partmap/gpt.c     2013-01-15 16:37:32 +0000
@@ -48,8 +48,8 @@ static struct grub_partition_map grub_gp
 
 grub_err_t
 grub_gpt_partition_map_iterate (grub_disk_t disk,
-                               int (*hook) (grub_disk_t disk,
-                                            const grub_partition_t partition))
+                               grub_partition_iterate_hook_t hook,
+                               void *hook_data)
 {
   struct grub_partition part;
   struct grub_gpt_header gpt;
@@ -113,7 +113,7 @@ grub_gpt_partition_map_iterate (grub_dis
                        (unsigned long long) part.start,
                        (unsigned long long) part.len);
 
-         if (hook (disk, &part))
+         if (hook (disk, &part, hook_data))
            return grub_errno;
        }
 
@@ -129,71 +129,81 @@ grub_gpt_partition_map_iterate (grub_dis
 }
 
 #ifdef GRUB_UTIL
+/* Context for gpt_partition_map_embed.  */
+struct gpt_partition_map_embed_ctx
+{
+  grub_disk_addr_t start, len;
+};
+
+/* Helper for gpt_partition_map_embed.  */
+static int
+find_usable_region (grub_disk_t disk __attribute__ ((unused)),
+                   const grub_partition_t p, void *data)
+{
+  struct gpt_partition_map_embed_ctx *ctx = data;
+  struct grub_gpt_partentry gptdata;
+  grub_partition_t p2;
+
+  p2 = disk->partition;
+  disk->partition = p->parent;
+  if (grub_disk_read (disk, p->offset, p->index,
+                     sizeof (gptdata), &gptdata))
+    {
+      disk->partition = p2;
+      return 0;
+    }
+  disk->partition = p2;
+
+  /* If there's an embed region, it is in a dedicated partition.  */
+  if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16))
+    {
+      ctx->start = p->start;
+      ctx->len = p->len;
+      return 1;
+    }
+
+  return 0;
+}
+
 static grub_err_t
-gpt_partition_map_embed (struct grub_disk *disk_, unsigned int *nsectors,
+gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
                         unsigned int max_nsectors,
                         grub_embed_type_t embed_type,
                         grub_disk_addr_t **sectors)
 {
-  grub_disk_addr_t start = 0, len = 0;
+  struct gpt_partition_map_embed_ctx ctx = {
+    .start = 0,
+    .len = 0
+  };
   unsigned i;
   grub_err_t err;
 
-  auto int NESTED_FUNC_ATTR find_usable_region (grub_disk_t disk,
-                                               const grub_partition_t p);
-  int NESTED_FUNC_ATTR find_usable_region (grub_disk_t disk __attribute__ 
((unused)),
-                                          const grub_partition_t p)
-  {
-    struct grub_gpt_partentry gptdata;
-    grub_partition_t p2;
-
-    p2 = disk->partition;
-    disk->partition = p->parent;
-    if (grub_disk_read (disk, p->offset, p->index,
-                       sizeof (gptdata), &gptdata))
-      {
-       disk->partition = p2;
-       return 0;
-      }
-    disk->partition = p2;
-
-    /* If there's an embed region, it is in a dedicated partition.  */
-    if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16))
-      {
-       start = p->start;
-       len = p->len;
-       return 1;
-      }
-
-      return 0;
-    }
-
   if (embed_type != GRUB_EMBED_PCBIOS)
     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
                       "GPT currently supports only PC-BIOS embedding");
 
-  err = grub_gpt_partition_map_iterate (disk_, find_usable_region);
+  err = grub_gpt_partition_map_iterate (disk, find_usable_region, &ctx);
   if (err)
     return err;
 
-  if (len == 0)
+  if (ctx.len == 0)
     return grub_error (GRUB_ERR_FILE_NOT_FOUND,
                       N_("this GPT partition label contains no BIOS Boot 
Partition;"
                          " embedding won't be possible"));
 
-  if (len < *nsectors)
+  if (ctx.len < *nsectors)
     return grub_error (GRUB_ERR_OUT_OF_RANGE,
                       N_("your BIOS Boot Partition is too small;"
                          " embedding won't be possible"));
 
-  *nsectors = len;
+  *nsectors = ctx.len;
   if (*nsectors > max_nsectors)
     *nsectors = max_nsectors;
   *sectors = grub_malloc (*nsectors * sizeof (**sectors));
   if (!*sectors)
     return grub_errno;
   for (i = 0; i < *nsectors; i++)
-    (*sectors)[i] = start + i;
+    (*sectors)[i] = ctx.start + i;
 
   return GRUB_ERR_NONE;
 }

=== modified file 'grub-core/partmap/msdos.c'
--- grub-core/partmap/msdos.c   2012-09-19 01:44:54 +0000
+++ grub-core/partmap/msdos.c   2013-01-15 16:36:45 +0000
@@ -100,8 +100,8 @@ struct embed_signature embed_signatures[
 
 grub_err_t
 grub_partition_msdos_iterate (grub_disk_t disk,
-                             int (*hook) (grub_disk_t disk,
-                                          const grub_partition_t partition))
+                             grub_partition_iterate_hook_t hook,
+                             void *hook_data)
 {
   struct grub_partition p;
   struct grub_msdos_partition_mbr mbr;
@@ -186,7 +186,7 @@ grub_partition_msdos_iterate (grub_disk_
            {
              p.number++;
 
-             if (hook (disk, &p))
+             if (hook (disk, &p, hook_data))
                return grub_errno;
            }
          else if (p.number < 4)

=== modified file 'grub-core/partmap/plan.c'
--- grub-core/partmap/plan.c    2011-11-14 13:25:09 +0000
+++ grub-core/partmap/plan.c    2013-01-15 16:37:14 +0000
@@ -31,8 +31,8 @@ static struct grub_partition_map grub_pl
 
 static grub_err_t
 plan_partition_map_iterate (grub_disk_t disk,
-                           int (*hook) (grub_disk_t disk,
-                                        const grub_partition_t partition))
+                           grub_partition_iterate_hook_t hook,
+                           void *hook_data)
 {
   struct grub_partition p;
   int ptr = 0;
@@ -92,7 +92,7 @@ plan_partition_map_iterate (grub_disk_t
       if (c != '\n')
        break;
       p.len -= p.start;
-      if (hook (disk, &p))
+      if (hook (disk, &p, hook_data))
        return grub_errno;
     }
   if (p.number == 0)

=== modified file 'grub-core/partmap/sun.c'
--- grub-core/partmap/sun.c     2011-12-13 13:40:41 +0000
+++ grub-core/partmap/sun.c     2013-01-15 16:36:41 +0000
@@ -86,8 +86,7 @@ grub_sun_is_valid (grub_uint16_t *label)
 
 static grub_err_t
 sun_partition_map_iterate (grub_disk_t disk,
-                           int (*hook) (grub_disk_t disk,
-                                       const grub_partition_t partition))
+                          grub_partition_iterate_hook_t hook, void *hook_data)
 {
   struct grub_partition p;
   union
@@ -128,7 +127,7 @@ sun_partition_map_iterate (grub_disk_t d
       p.number = p.index = partnum;
       if (p.len)
        {
-         if (hook (disk, &p))
+         if (hook (disk, &p, hook_data))
            partnum = GRUB_PARTMAP_SUN_MAX_PARTS;
        }
     }

=== modified file 'grub-core/partmap/sunpc.c'
--- grub-core/partmap/sunpc.c   2011-12-13 13:42:41 +0000
+++ grub-core/partmap/sunpc.c   2013-01-15 16:37:25 +0000
@@ -68,8 +68,8 @@ grub_sun_is_valid (grub_uint16_t *label)
 
 static grub_err_t
 sun_pc_partition_map_iterate (grub_disk_t disk,
-                             int (*hook) (grub_disk_t disk,
-                                          const grub_partition_t partition))
+                             grub_partition_iterate_hook_t hook,
+                             void *hook_data)
 {
   grub_partition_t p;
   union
@@ -122,7 +122,7 @@ sun_pc_partition_map_iterate (grub_disk_
       p->number = partnum;
       if (p->len)
        {
-         if (hook (disk, p))
+         if (hook (disk, p, hook_data))
            partnum = GRUB_PARTMAP_SUN_PC_MAX_PARTS;
        }
     }

=== modified file 'include/grub/arc/arc.h'
--- include/grub/arc/arc.h      2012-01-25 15:13:34 +0000
+++ include/grub/arc/arc.h      2013-01-15 16:58:24 +0000
@@ -255,7 +255,12 @@ struct grub_arc_system_parameter_block
 #define GRUB_ARC_STDIN 0
 #define GRUB_ARC_STDOUT 1
 
-int EXPORT_FUNC (grub_arc_iterate_devs) (int (*hook) (const char *name, const 
struct grub_arc_component *comp), int alt_names);
+typedef int (*grub_arc_iterate_devs_hook_t)
+  (const char *name, const struct grub_arc_component *comp, void *data);
+
+int EXPORT_FUNC (grub_arc_iterate_devs) (grub_arc_iterate_devs_hook_t hook,
+                                        void *hook_data,
+                                        int alt_names);
 
 #define FOR_ARC_CHILDREN(comp, parent) for (comp = 
GRUB_ARC_FIRMWARE_VECTOR->getchild (parent); comp; comp = 
GRUB_ARC_FIRMWARE_VECTOR->getpeer (comp))
 

=== modified file 'include/grub/ata.h'
--- include/grub/ata.h  2012-01-29 18:00:30 +0000
+++ include/grub/ata.h  2013-01-15 16:30:28 +0000
@@ -193,10 +193,12 @@ struct grub_ata
 
 typedef struct grub_ata *grub_ata_t;
 
+typedef int (*grub_ata_dev_iterate_hook_t) (int id, int bus, void *data);
+
 struct grub_ata_dev
 {
   /* Call HOOK with each device name, until HOOK returns non-zero.  */
-  int (*iterate) (int (*hook) (int id, int bus),
+  int (*iterate) (grub_ata_dev_iterate_hook_t hook, void *hook_data,
                  grub_disk_pull_t pull);
 
   /* Open the device named NAME, and set up SCSI.  */

=== modified file 'include/grub/device.h'
--- include/grub/device.h       2010-09-16 19:57:31 +0000
+++ include/grub/device.h       2013-01-15 16:30:28 +0000
@@ -33,8 +33,11 @@ struct grub_device
 };
 typedef struct grub_device *grub_device_t;
 
+typedef int (*grub_device_iterate_hook_t) (const char *name, void *data);
+
 grub_device_t EXPORT_FUNC(grub_device_open) (const char *name);
 grub_err_t EXPORT_FUNC(grub_device_close) (grub_device_t device);
-int EXPORT_FUNC(grub_device_iterate) (int (*hook) (const char *name));
+int EXPORT_FUNC(grub_device_iterate) (grub_device_iterate_hook_t hook,
+                                     void *hook_data);
 
 #endif /* ! GRUB_DEVICE_HEADER */

=== modified file 'include/grub/disk.h'
--- include/grub/disk.h 2012-02-09 22:15:27 +0000
+++ include/grub/disk.h 2013-01-15 16:30:28 +0000
@@ -56,6 +56,8 @@ typedef enum
     GRUB_DISK_PULL_MAX
   } grub_disk_pull_t;
 
+typedef int (*grub_disk_dev_iterate_hook_t) (const char *name, void *data);
+
 /* Disk device.  */
 struct grub_disk_dev
 {
@@ -66,7 +68,7 @@ struct grub_disk_dev
   enum grub_disk_dev_id id;
 
   /* Call HOOK with each device name, until HOOK returns non-zero.  */
-  int (*iterate) (int (*hook) (const char *name),
+  int (*iterate) (grub_disk_dev_iterate_hook_t hook, void *hook_data,
                  grub_disk_pull_t pull);
 
   /* Open the device named NAME, and set up DISK.  */
@@ -158,14 +160,14 @@ void grub_disk_cache_invalidate_all (voi
 void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev);
 void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev);
 static inline int
-grub_disk_dev_iterate (int (*hook) (const char *name))
+grub_disk_dev_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data)
 {
   grub_disk_dev_t p;
   grub_disk_pull_t pull;
 
   for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
     for (p = grub_disk_dev_list; p; p = p->next)
-      if (p->iterate && (p->iterate) (hook, pull))
+      if (p->iterate && (p->iterate) (hook, hook_data, pull))
        return 1;
 
   return 0;

=== modified file 'include/grub/gpt_partition.h'
--- include/grub/gpt_partition.h        2012-01-29 13:28:01 +0000
+++ include/grub/gpt_partition.h        2013-01-15 16:36:36 +0000
@@ -80,8 +80,8 @@ struct grub_gpt_partentry
 
 grub_err_t
 grub_gpt_partition_map_iterate (grub_disk_t disk,
-                               int (*hook) (grub_disk_t disk,
-                                            const grub_partition_t partition));
+                               grub_partition_iterate_hook_t hook,
+                               void *hook_data);
 
 
 #endif /* ! GRUB_GPT_PARTITION_HEADER */

=== modified file 'include/grub/msdos_partition.h'
--- include/grub/msdos_partition.h      2010-12-20 23:04:31 +0000
+++ include/grub/msdos_partition.h      2013-01-15 16:36:13 +0000
@@ -120,7 +120,7 @@ grub_msdos_partition_is_extended (int ty
 
 grub_err_t
 grub_partition_msdos_iterate (grub_disk_t disk,
-                             int (*hook) (grub_disk_t disk,
-                                          const grub_partition_t partition));
+                             grub_partition_iterate_hook_t hook,
+                             void *hook_data);
 
 #endif /* ! GRUB_PC_PARTITION_HEADER */

=== modified file 'include/grub/partition.h'
--- include/grub/partition.h    2012-02-27 21:25:39 +0000
+++ include/grub/partition.h    2013-01-15 16:36:32 +0000
@@ -33,6 +33,10 @@ typedef enum
 } grub_embed_type_t;
 #endif
 
+typedef int (*grub_partition_iterate_hook_t) (struct grub_disk *disk,
+                                             const grub_partition_t partition,
+                                             void *data);
+
 /* Partition map type.  */
 struct grub_partition_map
 {
@@ -45,8 +49,7 @@ struct grub_partition_map
 
   /* Call HOOK with each partition, until HOOK returns non-zero.  */
   grub_err_t (*iterate) (struct grub_disk *disk,
-                        int (*hook) (struct grub_disk *disk,
-                                     const grub_partition_t partition));
+                        grub_partition_iterate_hook_t hook, void *hook_data);
 #ifdef GRUB_UTIL
   /* Determine sectors available for embedding.  */
   grub_err_t (*embed) (struct grub_disk *disk, unsigned int *nsectors,
@@ -89,8 +92,8 @@ struct grub_partition
 grub_partition_t EXPORT_FUNC(grub_partition_probe) (struct grub_disk *disk,
                                                    const char *str);
 int EXPORT_FUNC(grub_partition_iterate) (struct grub_disk *disk,
-                                        int (*hook) (struct grub_disk *disk,
-                                                     const grub_partition_t 
partition));
+                                        grub_partition_iterate_hook_t hook,
+                                        void *hook_data);
 char *EXPORT_FUNC(grub_partition_get_name) (const grub_partition_t partition);
 
 

=== modified file 'include/grub/scsi.h'
--- include/grub/scsi.h 2012-01-30 17:33:11 +0000
+++ include/grub/scsi.h 2013-01-15 16:30:28 +0000
@@ -49,10 +49,13 @@ grub_make_scsi_id (int subsystem, int bu
     | (bus << GRUB_SCSI_ID_BUS_SHIFT) | (lun << GRUB_SCSI_ID_LUN_SHIFT);
 }
 
+typedef int (*grub_scsi_dev_iterate_hook_t) (int id, int bus, int luns,
+                                            void *data);
+
 struct grub_scsi_dev
 {
   /* Call HOOK with each device name, until HOOK returns non-zero.  */
-  int (*iterate) (int NESTED_FUNC_ATTR (*hook) (int id, int bus, int luns),
+  int (*iterate) (grub_scsi_dev_iterate_hook_t hook, void *hook_data,
                  grub_disk_pull_t pull);
 
   /* Open the device named NAME, and set up SCSI.  */

=== modified file 'util/getroot.c'
--- util/getroot.c      2013-01-13 21:45:16 +0000
+++ util/getroot.c      2013-01-15 17:33:16 +0000
@@ -2198,6 +2198,36 @@ grub_util_get_os_disk (const char *os_de
   return convert_system_partition_to_system_disk (os_dev, &st, &is_part);
 }
 
+#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || 
defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
+/* Context for grub_util_biosdisk_get_grub_dev.  */
+struct grub_util_biosdisk_get_grub_dev_ctx
+{
+  char *partname;
+  grub_disk_addr_t start;
+};
+
+/* Helper for grub_util_biosdisk_get_grub_dev.  */
+static int
+find_partition (grub_disk_t dsk __attribute__ ((unused)),
+               const grub_partition_t partition, void *data)
+{
+  struct grub_util_biosdisk_get_grub_dev_ctx *ctx = data;
+  grub_disk_addr_t part_start = 0;
+  grub_util_info ("Partition %d starts from %" PRIuGRUB_UINT64_T,
+                 partition->number, partition->start);
+
+  part_start = grub_partition_get_start (partition);
+
+  if (ctx->start == part_start)
+    {
+      ctx->partname = grub_partition_get_name (partition);
+      return 1;
+    }
+
+  return 0;
+}
+#endif
+
 char *
 grub_util_biosdisk_get_grub_dev (const char *os_dev)
 {
@@ -2250,29 +2280,9 @@ grub_util_biosdisk_get_grub_dev (const c
      For NetBSD and FreeBSD, proceed as for Linux, except that the start
      sector is obtained from the disk label.  */
   {
-    char *name, *partname;
+    char *name;
     grub_disk_t disk;
-    grub_disk_addr_t start;
-    auto int find_partition (grub_disk_t dsk,
-                            const grub_partition_t partition);
-
-    int find_partition (grub_disk_t dsk __attribute__ ((unused)),
-                       const grub_partition_t partition)
-      {
-       grub_disk_addr_t part_start = 0;
-       grub_util_info ("Partition %d starts from %" PRIuGRUB_UINT64_T,
-                       partition->number, partition->start);
-
-       part_start = grub_partition_get_start (partition);
-
-       if (start == part_start)
-         {
-           partname = grub_partition_get_name (partition);
-           return 1;
-         }
-
-       return 0;
-      }
+    struct grub_util_biosdisk_get_grub_dev_ctx ctx;
 
     name = make_device_name (drive, -1, -1);
 
@@ -2284,16 +2294,16 @@ grub_util_biosdisk_get_grub_dev (const c
      * different, we know that os_dev cannot be a floppy device.  */
 # endif /* !defined(HAVE_DIOCGDINFO) */
 
-    start = grub_hostdisk_find_partition_start (os_dev);
+    ctx.start = grub_hostdisk_find_partition_start (os_dev);
     if (grub_errno != GRUB_ERR_NONE)
       {
        free (name);
        return 0;
       }
 
-    grub_util_info ("%s starts from %" PRIuGRUB_UINT64_T, os_dev, start);
+    grub_util_info ("%s starts from %" PRIuGRUB_UINT64_T, os_dev, ctx.start);
 
-    if (start == 0 && !is_part)
+    if (ctx.start == 0 && !is_part)
       return name;
 
     grub_util_info ("opening the device %s", name);
@@ -2325,20 +2335,20 @@ grub_util_biosdisk_get_grub_dev (const c
          return 0;
       }
 
-    name = grub_util_get_ldm (disk, start);
+    name = grub_util_get_ldm (disk, ctx.start);
     if (name)
       return name;
 
-    partname = NULL;
+    ctx.partname = NULL;
 
-    grub_partition_iterate (disk, find_partition);
+    grub_partition_iterate (disk, find_partition, &ctx);
     if (grub_errno != GRUB_ERR_NONE)
       {
        grub_disk_close (disk);
        return 0;
       }
 
-    if (partname == NULL)
+    if (ctx.partname == NULL)
       {
        grub_disk_close (disk);
        grub_util_info ("cannot find the partition of `%s'", os_dev);
@@ -2347,8 +2357,8 @@ grub_util_biosdisk_get_grub_dev (const c
        return 0;
       }
 
-    name = grub_xasprintf ("%s,%s", disk->name, partname);
-    free (partname);
+    name = grub_xasprintf ("%s,%s", disk->name, ctx.partname);
+    free (ctx.partname);
     grub_disk_close (disk);
     return name;
   }

=== modified file 'util/grub-setup.c'
--- util/grub-setup.c   2012-09-19 01:41:51 +0000
+++ util/grub-setup.c   2013-01-15 17:34:46 +0000
@@ -138,6 +138,44 @@ write_rootdev (grub_device_t root_dev,
 #define BOOT_SECTOR 0
 #endif
 
+#ifdef GRUB_SETUP_BIOS
+/* Context for setup/identify_partmap.  */
+struct identify_partmap_ctx
+{
+  grub_partition_map_t dest_partmap;
+  grub_partition_t container;
+  int multiple_partmaps;
+};
+
+/* Helper for setup/identify_partmap.
+   Unlike root_dev, with dest_dev we're interested in the partition map even
+   if dest_dev itself is a whole disk.  */
+static int
+identify_partmap (grub_disk_t disk __attribute__ ((unused)),
+                 const grub_partition_t p, void *data)
+{
+  struct identify_partmap_ctx *ctx = data;
+
+  if (p->parent != ctx->container)
+    return 0;
+  /* NetBSD and OpenBSD subpartitions have metadata inside a partition,
+     so they are safe to ignore.
+   */
+  if (grub_strcmp (p->partmap->name, "netbsd") == 0
+      || grub_strcmp (p->partmap->name, "openbsd") == 0)
+    return 0;
+  if (ctx->dest_partmap == NULL)
+    {
+      ctx->dest_partmap = p->partmap;
+      return 0;
+    }
+  if (ctx->dest_partmap == p->partmap)
+    return 0;
+  ctx->multiple_partmaps = 1;
+  return 1;
+}
+#endif
+
 static void
 setup (const char *dir,
        const char *boot_file, const char *core_file,
@@ -337,9 +375,11 @@ setup (const char *dir,
 
 #ifdef GRUB_SETUP_BIOS
   {
-    grub_partition_map_t dest_partmap = NULL;
-    grub_partition_t container = dest_dev->disk->partition;
-    int multiple_partmaps = 0;
+    struct identify_partmap_ctx ctx = {
+      .dest_partmap = NULL,
+      .container = dest_dev->disk->partition,
+      .multiple_partmaps = 0
+    };
     int is_ldm;
     grub_err_t err;
     grub_disk_addr_t *sectors;
@@ -347,38 +387,13 @@ setup (const char *dir,
     grub_fs_t fs;
     unsigned int nsec, maxsec;
 
-    /* Unlike root_dev, with dest_dev we're interested in the partition map 
even
-       if dest_dev itself is a whole disk.  */
-    auto int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk,
-                                               const grub_partition_t p);
-    int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ 
((unused)),
-                                          const grub_partition_t p)
-    {
-      if (p->parent != container)
-       return 0;
-      /* NetBSD and OpenBSD subpartitions have metadata inside a partition,
-        so they are safe to ignore.
-       */
-      if (grub_strcmp (p->partmap->name, "netbsd") == 0
-         || grub_strcmp (p->partmap->name, "openbsd") == 0)
-       return 0;
-      if (dest_partmap == NULL)
-       {
-         dest_partmap = p->partmap;
-         return 0;
-       }
-      if (dest_partmap == p->partmap)
-       return 0;
-      multiple_partmaps = 1;
-      return 1;
-    }
-
-    grub_partition_iterate (dest_dev->disk, identify_partmap);
+    grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx);
 
-    if (container && grub_strcmp (container->partmap->name, "msdos") == 0
-       && dest_partmap
-       && (container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD
-           || container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD))
+    if (ctx.container
+       && grub_strcmp (ctx.container->partmap->name, "msdos") == 0
+       && ctx.dest_partmap
+       && (ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD
+           || ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD))
       {
        grub_util_warn ("%s", _("Attempting to install GRUB to a disk with 
multiple partition labels or both partition label and filesystem.  This is not 
supported yet."));
        goto unable_to_embed;
@@ -392,7 +407,7 @@ setup (const char *dir,
 
     if (fs_probe)
       {
-       if (!fs && !dest_partmap)
+       if (!fs && !ctx.dest_partmap)
          grub_util_error (_("unable to identify a filesystem in %s; safety 
check can't be performed"),
                           dest_dev->disk->name);
        if (fs && !fs->reserved_first_sector)
@@ -403,20 +418,20 @@ setup (const char *dir,
                             "by grub-setup (--skip-fs-probe disables this "
                             "check, use at your own risk)"), 
dest_dev->disk->name, fs->name);
 
-       if (dest_partmap && strcmp (dest_partmap->name, "msdos") != 0
-           && strcmp (dest_partmap->name, "gpt") != 0
-           && strcmp (dest_partmap->name, "bsd") != 0
-           && strcmp (dest_partmap->name, "netbsd") != 0
-           && strcmp (dest_partmap->name, "openbsd") != 0
-           && strcmp (dest_partmap->name, "sunpc") != 0)
+       if (ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
+           && strcmp (ctx.dest_partmap->name, "gpt") != 0
+           && strcmp (ctx.dest_partmap->name, "bsd") != 0
+           && strcmp (ctx.dest_partmap->name, "netbsd") != 0
+           && strcmp (ctx.dest_partmap->name, "openbsd") != 0
+           && strcmp (ctx.dest_partmap->name, "sunpc") != 0)
          /* TRANSLATORS: Partition map may reserve the space just GRUB isn't 
sure about it.  */
          grub_util_error (_("%s appears to contain a %s partition map which 
isn't known to "
                             "reserve space for DOS-style boot.  Installing 
GRUB there could "
                             "result in FILESYSTEM DESTRUCTION if valuable data 
is overwritten "
                             "by grub-setup (--skip-fs-probe disables this "
-                            "check, use at your own risk)"), 
dest_dev->disk->name, dest_partmap->name);
-       if (is_ldm && dest_partmap && strcmp (dest_partmap->name, "msdos") != 0
-           && strcmp (dest_partmap->name, "gpt") != 0)
+                            "check, use at your own risk)"), 
dest_dev->disk->name, ctx.dest_partmap->name);
+       if (is_ldm && ctx.dest_partmap && strcmp (ctx.dest_partmap->name, 
"msdos") != 0
+           && strcmp (ctx.dest_partmap->name, "gpt") != 0)
          grub_util_error (_("%s appears to contain a %s partition map and "
                             "LDM which isn't known to be a safe combination."
                             "  Installing GRUB there could "
@@ -424,12 +439,12 @@ setup (const char *dir,
                             " is overwritten "
                             "by grub-setup (--skip-fs-probe disables this "
                             "check, use at your own risk)"),
-                          dest_dev->disk->name, dest_partmap->name);
+                          dest_dev->disk->name, ctx.dest_partmap->name);
 
       }
 
     /* Copy the partition table.  */
-    if (dest_partmap ||
+    if (ctx.dest_partmap ||
         (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)))
       memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
              tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
@@ -437,21 +452,21 @@ setup (const char *dir,
 
     free (tmp_img);
     
-    if (! dest_partmap && ! fs && !is_ldm)
+    if (! ctx.dest_partmap && ! fs && !is_ldm)
       {
        grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless 
disk or to a partition.  This is a BAD idea."));
        goto unable_to_embed;
       }
-    if (multiple_partmaps || (dest_partmap && fs) || (is_ldm && fs))
+    if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs))
       {
        grub_util_warn ("%s", _("Attempting to install GRUB to a disk with 
multiple partition labels.  This is not supported yet."));
        goto unable_to_embed;
       }
 
-    if (dest_partmap && !dest_partmap->embed)
+    if (ctx.dest_partmap && !ctx.dest_partmap->embed)
       {
        grub_util_warn (_("Partition style `%s' doesn't support embedding"),
-                       dest_partmap->name);
+                       ctx.dest_partmap->name);
        goto unable_to_embed;
       }
 
@@ -473,9 +488,9 @@ setup (const char *dir,
     if (is_ldm)
       err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
                                 GRUB_EMBED_PCBIOS, &sectors);
-    else if (dest_partmap)
-      err = dest_partmap->embed (dest_dev->disk, &nsec, maxsec,
-                                GRUB_EMBED_PCBIOS, &sectors);
+    else if (ctx.dest_partmap)
+      err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec,
+                                    GRUB_EMBED_PCBIOS, &sectors);
     else
       err = fs->embed (dest_dev, &nsec, maxsec,
                       GRUB_EMBED_PCBIOS, &sectors);
@@ -507,12 +522,12 @@ setup (const char *dir,
          grub_util_error ("%s", _("no terminator in the core image"));
       }
 
-    save_first_sector (sectors[0] + grub_partition_get_start (container),
+    save_first_sector (sectors[0] + grub_partition_get_start (ctx.container),
                       0, GRUB_DISK_SECTOR_SIZE);
 
     block = first_block;
     for (i = 1; i < nsec; i++)
-      save_blocklists (sectors[i] + grub_partition_get_start (container),
+      save_blocklists (sectors[i] + grub_partition_get_start (ctx.container),
                       0, GRUB_DISK_SECTOR_SIZE);
 
     /* Make sure that the last blocklist is a terminator.  */

Thanks,

-- 
Colin Watson                                       address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]