]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Implement better integration with Mac firmware.
authorVladimir Serbinenko <phcoder@gmail.com>
Tue, 17 Dec 2013 14:21:02 +0000 (15:21 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Tue, 17 Dec 2013 14:21:02 +0000 (15:21 +0100)
15 files changed:
ChangeLog
Makefile.util.def
docs/man/grub-macbless.h2m [new file with mode: 0644]
grub-core/Makefile.core.def
grub-core/commands/macbless.c [new file with mode: 0644]
grub-core/fs/hfs.c
grub-core/fs/hfsplus.c
include/grub/fs.h
include/grub/hfs.h
include/grub/hfsplus.h
util/grub-install.c
util/grub-macbless.c [new file with mode: 0644]
util/grub-mkrescue.c
util/grub-render-label.c
util/render-label.c

index 2850c76c75eb1e5f5db2c9eae72b09d657224f5a..c75b86f33af1b775060492620181aebd2787afda 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-12-17  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Implement better integration with Mac firmware.
+
 2013-12-17  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/loader/multiboot_mbi2.c: Implement special value for
index 2720f6bd3c63d5c9f10587e80321c44bc105339b..4ea1c3501d4c79ab139c9090627be84628adebc3 100644 (file)
@@ -62,6 +62,7 @@ library = {
   common_nodist = grub_script.tab.h;
 
   common = grub-core/commands/blocklist.c;
+  common = grub-core/commands/macbless.c;
   common = grub-core/commands/xnu_uuid.c;
   common = grub-core/commands/testload.c;
   common = grub-core/commands/ls.c;
@@ -401,6 +402,21 @@ program = {
   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
 };
 
+program = {
+  name = grub-macbless;
+  installdir = sbin;
+  mansection = 1;
+  common = util/grub-macbless.c;
+  common = grub-core/osdep/init.c;
+  common = grub-core/kern/emu/argp_common.c;
+
+  ldadd = libgrubmods.a;
+  ldadd = libgrubgcry.a;
+  ldadd = libgrubkern.a;
+  ldadd = grub-core/gnulib/libgnu.a;
+  ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+};
+
 data = {
   common = util/grub.d/README;
   installdir = grubconf;
@@ -585,6 +601,9 @@ program = {
   common = grub-core/osdep/blocklist.c;
   common = grub-core/osdep/config.c;
   common = util/config.c;
+  common = util/render-label.c;
+  common = grub-core/kern/emu/hostfs.c;
+  common = grub-core/disk/host.c;
 
   common = util/resolve.c;
   enable = noemu;
diff --git a/docs/man/grub-macbless.h2m b/docs/man/grub-macbless.h2m
new file mode 100644 (file)
index 0000000..0197c00
--- /dev/null
@@ -0,0 +1,4 @@
+[NAME]
+grub-macbless \- bless a mac file/directory
+[SEE ALSO]
+.BR grub-install (1)
index e32e2ca209a99e8a40dbccda3142ceb41bf9d7cd..286ea98a4cc02e432cad955bd52147067410ea8b 100644 (file)
@@ -1450,6 +1450,11 @@ module = {
   common = fs/zfs/zfsinfo.c;
 };
 
+module = {
+  name = macbless;
+  common = commands/macbless.c;
+};
+
 module = {
   name = pxe;
   i386_pc = net/drivers/i386/pc/pxe.c;
diff --git a/grub-core/commands/macbless.c b/grub-core/commands/macbless.c
new file mode 100644 (file)
index 0000000..df53b02
--- /dev/null
@@ -0,0 +1,234 @@
+/* hfspbless.c - set the hfs+ boot directory.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2005,2007,2008,2009,2012,2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/command.h>
+#include <grub/fs.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/hfsplus.h>
+#include <grub/hfs.h>
+#include <grub/partition.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+
+struct find_node_context
+{
+  grub_uint64_t inode_found;
+  char *dirname;
+  enum
+  { NONE, FILE, DIR } found;
+};
+
+static int
+find_inode (const char *filename,
+           const struct grub_dirhook_info *info, void *data)
+{
+  struct find_node_context *ctx = data;
+  if (!info->inodeset)
+    return 0;
+
+  if ((grub_strcmp (ctx->dirname, filename) == 0
+       || (info->case_insensitive
+          && grub_strcasecmp (ctx->dirname, filename) == 0)))
+    {
+      ctx->inode_found = info->inode;
+      ctx->found = info->dir ? DIR : FILE;
+    }
+  return 0;
+}
+
+grub_err_t
+grub_mac_bless_inode (grub_device_t dev, grub_uint64_t inode, int is_dir,
+                     int intel)
+{
+  grub_err_t err;
+  union
+  {
+    struct grub_hfs_sblock hfs;
+    struct grub_hfsplus_volheader hfsplus;
+  } volheader;
+  grub_disk_addr_t embedded_offset;
+
+  if (intel && is_dir)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                      "can't bless a directory for mactel");
+  if (!intel && !is_dir)
+    return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                      "can't bless a file for mac PPC");
+
+  /* Read the bootblock.  */
+  err = grub_disk_read (dev->disk, GRUB_HFSPLUS_SBLOCK, 0, sizeof (volheader),
+                       (char *) &volheader);
+  if (err)
+    return err;
+
+  embedded_offset = 0;
+  if (grub_be_to_cpu16 (volheader.hfs.magic) == GRUB_HFS_MAGIC)
+    {
+      int extent_start;
+      int ablk_size;
+      int ablk_start;
+
+      /* See if there's an embedded HFS+ filesystem.  */
+      if (grub_be_to_cpu16 (volheader.hfs.embed_sig) != GRUB_HFSPLUS_MAGIC)
+       {
+         if (intel)
+           volheader.hfs.intel_bootfile = grub_be_to_cpu32 (inode);
+         else
+           volheader.hfs.ppc_bootdir = grub_be_to_cpu32 (inode);
+         return GRUB_ERR_NONE;
+       }
+
+      /* Calculate the offset needed to translate HFS+ sector numbers.  */
+      extent_start =
+       grub_be_to_cpu16 (volheader.hfs.embed_extent.first_block);
+      ablk_size = grub_be_to_cpu32 (volheader.hfs.blksz);
+      ablk_start = grub_be_to_cpu16 (volheader.hfs.first_block);
+      embedded_offset = (ablk_start
+                        + extent_start
+                        * (ablk_size >> GRUB_DISK_SECTOR_BITS));
+
+      err =
+       grub_disk_read (dev->disk, embedded_offset + GRUB_HFSPLUS_SBLOCK, 0,
+                       sizeof (volheader), (char *) &volheader);
+      if (err)
+       return err;
+    }
+
+  if ((grub_be_to_cpu16 (volheader.hfsplus.magic) != GRUB_HFSPLUS_MAGIC)
+      && (grub_be_to_cpu16 (volheader.hfsplus.magic) != GRUB_HFSPLUSX_MAGIC))
+    return grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem");
+  if (intel)
+    volheader.hfsplus.intel_bootfile = grub_be_to_cpu32 (inode);
+  else
+    volheader.hfsplus.ppc_bootdir = grub_be_to_cpu32 (inode);
+
+  return grub_disk_write (dev->disk, embedded_offset + GRUB_HFSPLUS_SBLOCK, 0,
+                         sizeof (volheader), (char *) &volheader);
+}
+
+grub_err_t
+grub_mac_bless_file (grub_device_t dev, const char *path_in, int intel)
+{
+  grub_fs_t fs;
+
+  char *path, *tail;
+  struct find_node_context ctx;
+
+  fs = grub_fs_probe (dev);
+  if (!fs || (grub_strcmp (fs->name, "hfsplus") != 0
+             && grub_strcmp (fs->name, "hfs") != 0))
+    return grub_error (GRUB_ERR_BAD_FS, "no suitable FS found");
+
+  path = grub_strdup (path_in);
+  if (!path)
+    return grub_errno;
+
+  tail = path + grub_strlen (path) - 1;
+
+  /* Remove trailing '/'. */
+  while (tail != path && *tail == '/')
+    *(tail--) = 0;
+
+  tail = grub_strrchr (path, '/');
+  ctx.found = 0;
+
+  if (tail)
+    {
+      *tail = 0;
+      ctx.dirname = tail + 1;
+
+      (fs->dir) (dev, *path == 0 ? "/" : path, find_inode, &ctx);
+    }
+  else
+    {
+      ctx.dirname = path + 1;
+      (fs->dir) (dev, "/", find_inode, &ctx);
+    }
+  if (!ctx.found)
+    {
+      grub_free (path);
+      return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
+                        path_in);
+    }
+  grub_free (path);
+
+  return grub_mac_bless_inode (dev, ctx.inode_found, (ctx.found == DIR),
+                              intel);
+}
+
+static grub_err_t
+grub_cmd_macbless (grub_command_t cmd, int argc, char **args)
+{
+  char *device_name;
+  char *path = 0;
+  grub_device_t dev;
+  grub_err_t err;
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+  device_name = grub_file_get_device_name (args[0]);
+  dev = grub_device_open (device_name);
+
+  path = grub_strchr (args[0], ')');
+  if (!path)
+    path = args[0];
+  else
+    path = path + 1;
+
+  if (!path || *path == 0 || !device_name)
+    {
+      if (dev)
+       grub_device_close (dev);
+
+      grub_free (device_name);
+      grub_free (path);
+
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
+    }
+
+  err = grub_mac_bless_file (dev, path, cmd->name[3] == 't');
+
+  grub_device_close (dev);
+  grub_free (device_name);
+  return err;
+}
+
+static grub_command_t cmd, cmd_ppc;
+\f
+GRUB_MOD_INIT(macbless)
+{
+  cmd = grub_register_command ("mactelbless", grub_cmd_macbless,
+                              N_("FILE"),
+                              N_
+                              ("Bless FILE of HFS or HFS+ partition for intel macs."));
+  cmd_ppc =
+    grub_register_command ("macppcbless", grub_cmd_macbless, N_("DIR"),
+                          N_
+                          ("Bless DIR of HFS or HFS+ partition for PPC macs."));
+}
+
+GRUB_MOD_FINI(macbless)
+{
+  grub_unregister_command (cmd);
+  grub_unregister_command (cmd_ppc);
+}
index ee6f6f955442db4571cb678de5bc83a9b6e15ea1..1e593059a7419e40ab9bdf0e5e0a28ca71d2fd21 100644 (file)
@@ -1229,14 +1229,18 @@ grub_hfs_dir_hook (struct grub_hfs_record *rec, void *hook_arg)
     {
       info.dir = 1;
       info.mtimeset = 1;
+      info.inodeset = 1;
       info.mtime = grub_be_to_cpu32 (drec->mtime) - 2082844800;
+      info.inode = grub_be_to_cpu32 (drec->dirid);
       return ctx->hook (fname, &info, ctx->hook_data);
     }
   if (frec->type == GRUB_HFS_FILETYPE_FILE)
     {
       info.dir = 0;
       info.mtimeset = 1;
+      info.inodeset = 1;
       info.mtime = grub_be_to_cpu32 (frec->mtime) - 2082844800;
+      info.inode = grub_be_to_cpu32 (frec->fileid);
       return ctx->hook (fname, &info, ctx->hook_data);
     }
 
index a5d7bc8f73bd4f5a55e262c15b894b9022d3198c..950d8a1e1c638fb7e58945db0a7dc2411de036b7 100644 (file)
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
-#define GRUB_HFSPLUS_MAGIC 0x482B
-#define GRUB_HFSPLUSX_MAGIC 0x4858
-#define GRUB_HFSPLUS_SBLOCK 2
-
-
 /* The type of node.  */
 enum grub_hfsplus_btnode_type
   {
@@ -919,6 +914,8 @@ grub_hfsplus_dir_iter (const char *filename,
   info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
   info.mtimeset = 1;
   info.mtime = node->mtime;
+  info.inodeset = 1;
+  info.inode = node->fileid;
   info.case_insensitive = !! (filetype & GRUB_FSHELP_CASE_INSENSITIVE);
   grub_free (node);
   return ctx->hook (filename, &info, ctx->hook_data);
index e4517972b8d2b95e9d02d125a94cf72d6555ed00..5678c60c2d855e0c9650359c66ae82b217e4a512 100644 (file)
@@ -38,7 +38,9 @@ struct grub_dirhook_info
   unsigned dir:1;
   unsigned mtimeset:1;
   unsigned case_insensitive:1;
+  unsigned inodeset:1;
   grub_int32_t mtime;
+  grub_uint64_t inode;
 };
 
 typedef int (*grub_fs_dir_hook_t) (const char *filename,
index bb8ec051782bc82201169013c202a9d861ca1c47..d935f5005c30fce4fe850985d78d5cb41bbef001 100644 (file)
@@ -50,11 +50,20 @@ struct grub_hfs_sblock
   /* A pascal style string that holds the volumename.  */
   grub_uint8_t volname[28];
 
-  grub_uint8_t unused5[52];
+  grub_uint8_t unused5[28];
+
+  grub_uint32_t ppc_bootdir;
+  grub_uint32_t intel_bootfile;
+  /* Folder opened when disk is mounted. Unused by GRUB. */
+  grub_uint32_t showfolder;
+  grub_uint32_t os9folder;
+  grub_uint8_t unused6[4];
+  grub_uint32_t osxfolder;
+
   grub_uint64_t num_serial;
   grub_uint16_t embed_sig;
   struct grub_hfs_extent embed_extent;
-  grub_uint8_t unused6[4];
+  grub_uint8_t unused7[4];
   grub_hfs_datarecord_t extent_recs;
   grub_uint32_t catalog_size;
   grub_hfs_datarecord_t catalog_recs;
index fedf37d3dc7659da6a8b512a4109ee6337025ffc..75c9d18a33974321e65f4a6b6c28bc1e6dec6daa 100644 (file)
@@ -1,7 +1,28 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005,2006,2007,2008,2009,2012,2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <grub/types.h>
 #include <grub/disk.h>
 
+#define GRUB_HFSPLUS_MAGIC 0x482B
+#define GRUB_HFSPLUSX_MAGIC 0x4858
+#define GRUB_HFSPLUS_SBLOCK 2
+
 /* A HFS+ extent.  */
 struct grub_hfsplus_extent
 {
@@ -30,7 +51,16 @@ struct grub_hfsplus_volheader
   grub_uint32_t utime;
   grub_uint8_t unused2[16];
   grub_uint32_t blksize;
-  grub_uint8_t unused3[60];
+  grub_uint8_t unused3[36];
+
+  grub_uint32_t ppc_bootdir;
+  grub_uint32_t intel_bootfile;
+  /* Folder opened when disk is mounted. Unused by GRUB. */
+  grub_uint32_t showfolder;
+  grub_uint32_t os9folder;
+  grub_uint8_t unused4[4];
+  grub_uint32_t osxfolder;
+
   grub_uint64_t num_serial;
   struct grub_hfsplus_forkdata allocations_file;
   struct grub_hfsplus_forkdata extents_file;
@@ -216,3 +246,8 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
                                                struct grub_hfsplus_key_internal *keyb),
                           struct grub_hfsplus_btnode **matchnode, 
                           grub_off_t *keyoffset);
+grub_err_t
+grub_mac_bless_inode (grub_device_t dev, grub_uint64_t inode, int is_dir,
+                     int intel);
+grub_err_t
+grub_mac_bless_file (grub_device_t dev, const char *path_in, int intel);
index 0c584084aa8875cdfb825db11c561326bc15d43b..9bc0b163e47cbc7d2bcddebb55267bc19da68b39 100644 (file)
@@ -41,6 +41,7 @@
 #include <grub/gpt_partition.h>
 #include <grub/emu/config.h>
 #include <grub/util/ofpath.h>
+#include <grub/hfsplus.h>
 
 #include <string.h>
 
@@ -60,6 +61,7 @@ static int allow_floppy = 0;
 static int force_file_id = 0;
 static char *disk_module = NULL;
 static char *efidir = NULL;
+static char *macppcdir = NULL;
 static int force = 0;
 static int have_abstractions = 0;
 static int have_cryptodisk = 0;
@@ -68,6 +70,10 @@ static int have_load_cfg = 0;
 static FILE * load_cfg_f = NULL;
 static char *load_cfg;
 static int install_bootsector = 1;
+static char *label_font;
+static char *label_color;
+static char *label_bgcolor;
+static char *product_version;
 static int add_rs_codes = 1;
 
 enum
@@ -96,6 +102,11 @@ enum
     OPTION_DISK_MODULE,
     OPTION_NO_BOOTSECTOR,
     OPTION_NO_RS_CODES,
+    OPTION_MACPPC_DIRECTORY,
+    OPTION_LABEL_FONT,
+    OPTION_LABEL_COLOR,
+    OPTION_LABEL_BGCOLOR,
+    OPTION_PRODUCT_VERSION
   };
 
 static int fs_probe = 1;
@@ -119,6 +130,25 @@ argp_parser (int key, char *arg, struct argp_state *state)
        install_bootsector = 0;
       return 0;
 
+    case OPTION_PRODUCT_VERSION:
+      free (product_version);
+      product_version = xstrdup (arg);
+      return 0;
+    case OPTION_LABEL_FONT:
+      free (label_font);
+      label_font = xstrdup (arg);
+      return 0;
+
+    case OPTION_LABEL_COLOR:
+      free (label_color);
+      label_color = xstrdup (arg);
+      return 0;
+
+    case OPTION_LABEL_BGCOLOR:
+      free (label_bgcolor);
+      label_bgcolor = xstrdup (arg);
+      return 0;
+
       /* Accept and ignore for compatibility.  */
     case OPTION_FONT:
     case OPTION_MKRELPATH:
@@ -138,6 +168,11 @@ argp_parser (int key, char *arg, struct argp_state *state)
       bootdir = xstrdup (arg);
       return 0;
 
+    case OPTION_MACPPC_DIRECTORY:
+      free (macppcdir);
+      macppcdir = xstrdup (arg);
+      return 0;
+
     case OPTION_EFI_DIRECTORY:
       free (efidir);
       efidir = xstrdup (arg);
@@ -255,9 +290,15 @@ static struct argp_option options[] = {
    N_("the installation device is removable. "
       "This option is only available on EFI."), 2},
   {"bootloader-id", OPTION_BOOTLOADER_ID, N_("ID"), 0,
-   N_("the ID of bootloader. This option is only available on EFI."), 2},
+   N_("the ID of bootloader. This option is only available on EFI and Macs."), 2},
   {"efi-directory", OPTION_EFI_DIRECTORY, N_("DIR"), 0,
    N_("use DIR as the EFI System Partition root."), 2},
+  {"macppc-directory", OPTION_MACPPC_DIRECTORY, N_("DIR"), 0,
+   N_("use DIR for PPC MAC install."), 2},
+  {"label-font", OPTION_LABEL_FONT, N_("FILE"), 0, N_("use FILE as font for label"), 2},
+  {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2},
+  {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2},
+  {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2},
   {0, 0, 0, 0, 0, 0}
 };
 
@@ -697,6 +738,63 @@ is_prep_empty (grub_device_t dev)
   return 1;
 }
 
+static void
+bless (grub_device_t dev, const char *path, int x86)
+{
+  struct stat st;
+  grub_err_t err;
+
+  grub_util_info ("blessing %s", path);
+
+  if (stat (path, &st) < 0)
+    grub_util_error (N_("cannot stat `%s': %s"),
+                    path, strerror (errno));
+
+  err = grub_mac_bless_inode (dev, st.st_ino, S_ISDIR (st.st_mode), x86);
+  if (err)
+    grub_util_error ("%s", grub_errmsg);
+  grub_util_info ("blessed\n");
+}
+
+static void
+fill_core_services (const char *core_services)
+{
+  char *label;
+  FILE *f;
+  char *label_text;
+  char *label_string = xasprintf ("%s %s", bootloader_id, product_version);
+  char *sysv_plist;
+
+  label = grub_util_path_concat (2, core_services, ".disk_label");
+  grub_util_info ("rendering label %s", label_string);
+  grub_util_render_label (label_font, label_bgcolor ? : "white",
+                         label_color ? : "black", label_string, label);
+  grub_util_info ("label rendered");
+  free (label);
+  label_text = grub_util_path_concat (2, core_services, ".disk_label.contentDetails");
+  f = grub_util_fopen (label_text, "wb");
+  fprintf (f, "%s\n", label_string);
+  fclose (f);
+  free (label_string);
+  free (label_text);
+
+  sysv_plist = grub_util_path_concat (2, core_services, "SystemVersion.plist");
+  f = grub_util_fopen (sysv_plist, "wb");
+  fprintf (f,
+          "<plist version=\"1.0\">\n"
+          "<dict>\n"
+          "        <key>ProductBuildVersion</key>\n"
+          "        <string></string>\n"
+          "        <key>ProductName</key>\n"
+          "        <string>%s</string>\n"
+          "        <key>ProductVersion</key>\n"
+          "        <string>%s</string>\n"
+          "</dict>\n"
+          "</plist>\n", bootloader_id, product_version);
+  fclose (f);
+  free (sysv_plist);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -714,8 +812,14 @@ main (int argc, char *argv[])
   char **efidir_device_names = NULL;
   grub_device_t efidir_grub_dev = NULL;
   char *efidir_grub_devname;
+  int efidir_is_mac = 0;
+  int is_prep = 0;
+  const char *pkgdatadir;
 
   grub_util_host_init (&argc, &argv);
+  product_version = xstrdup (PACKAGE_VERSION);
+  pkgdatadir = grub_util_get_pkgdatadir ();
+  label_font = grub_util_path_concat (2, pkgdatadir, "unicode.pf2");
 
   argp_parse (&argp, argc, argv, 0, 0, 0);
 
@@ -800,9 +904,12 @@ main (int argc, char *argv[])
       if (!install_device)
        grub_util_error ("%s", _("install device isn't specified"));
       break;
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      if (install_device)
+       is_prep = 1;
+      break;
     case GRUB_INSTALL_PLATFORM_MIPS_ARC:
     case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
-    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
       break;
     case GRUB_INSTALL_PLATFORM_I386_EFI:
     case GRUB_INSTALL_PLATFORM_X86_64_EFI:
@@ -850,6 +957,9 @@ main (int argc, char *argv[])
   /* Initialize all modules. */
   grub_init_all ();
   grub_gcry_init_all ();
+  grub_hostfs_init ();
+  grub_host_init ();
+
   switch (platform)
     {
     case GRUB_INSTALL_PLATFORM_I386_EFI:
@@ -927,7 +1037,13 @@ main (int argc, char *argv[])
       if (! fs)
        grub_util_error ("%s", grub_errmsg);
 
-      if (grub_strcmp (fs->name, "fat") != 0)
+      efidir_is_mac = 0;
+
+      if (grub_strcmp (fs->name, "hfs") == 0
+         || grub_strcmp (fs->name, "hfsplus") == 0)
+       efidir_is_mac = 1;
+
+      if (!efidir_is_mac && grub_strcmp (fs->name, "fat") != 0)
        grub_util_error (_("%s doesn't look like an EFI partition.\n"), efidir);
 
       /* The EFI specification requires that an EFI System Partition must
@@ -1001,6 +1117,76 @@ main (int argc, char *argv[])
       grub_install_mkdir_p (efidir);
     }
 
+  if (platform == GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
+    {
+      int is_guess = 0;
+      if (!macppcdir)
+       {
+         char *d;
+
+         is_guess = 1;
+         d = grub_util_path_concat (2, bootdir, "macppc");
+         if (!grub_util_is_directory (d))
+           {
+             free (d);
+             d = grub_util_path_concat (2, bootdir, "efi");
+           }
+         /* Find the Mac HFS(+) System Partition.  */
+         if (!grub_util_is_directory (d))
+           {
+             free (d);
+             d = grub_util_path_concat (2, bootdir, "EFI");
+           }
+         if (!grub_util_is_directory (d))
+           {
+             free (d);
+             d = 0;
+           }
+         if (d)
+           macppcdir = d;
+       }
+      if (macppcdir)
+       {
+         char **macppcdir_device_names = NULL;
+         grub_device_t macppcdir_grub_dev = NULL;
+         char *macppcdir_grub_devname;
+         grub_fs_t fs;
+
+         macppcdir_device_names = grub_guess_root_devices (macppcdir);
+         if (!macppcdir_device_names || !macppcdir_device_names[0])
+           grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
+                            macppcdir);
+
+         for (curdev = macppcdir_device_names; *curdev; curdev++)
+           grub_util_pull_device (*curdev);
+      
+         macppcdir_grub_devname = grub_util_get_grub_dev (macppcdir_device_names[0]);
+         if (!macppcdir_grub_devname)
+           grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+                            macppcdir_device_names[0]);
+         
+         macppcdir_grub_dev = grub_device_open (macppcdir_grub_devname);
+         if (! macppcdir_grub_dev)
+           grub_util_error ("%s", grub_errmsg);
+
+         fs = grub_fs_probe (macppcdir_grub_dev);
+         if (! fs)
+           grub_util_error ("%s", grub_errmsg);
+
+         if (grub_strcmp (fs->name, "hfs") != 0
+             && grub_strcmp (fs->name, "hfsplus") != 0
+             && !is_guess)
+           grub_util_error (_("%s is neither hfs nor hfsplue"),
+                            macppcdir);
+         if (grub_strcmp (fs->name, "hfs") == 0
+             || grub_strcmp (fs->name, "hfsplus") == 0)
+           {
+             install_device = macppcdir_device_names[0];
+             is_prep = 0;
+           }
+       }
+    }
+
   grub_install_copy_files (grub_install_source_directory,
                           grubdir, platform);
 
@@ -1491,8 +1677,59 @@ main (int argc, char *argv[])
       }
 
     case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      if (macppcdir)
+       {
+         char *core_services = grub_util_path_concat (4, macppcdir,
+                                                      "System", "Library",
+                                                      "CoreServices");
+         char *mach_kernel = grub_util_path_concat (2, macppcdir,
+                                                    "mach_kernel");
+         char *grub_elf, *bootx;
+         FILE *f;
+         grub_device_t ins_dev;
+         char *grub_chrp = grub_util_path_concat (2,
+                                                  grub_install_source_directory,
+                                                  "grub.chrp");
+
+         grub_install_mkdir_p (core_services);
+
+         bootx = grub_util_path_concat (2, core_services, "BootX");
+         grub_install_copy_file (grub_chrp, bootx, 1);
+
+         grub_elf = grub_util_path_concat (2, core_services, "grub.elf");
+         grub_install_copy_file (imgfile, grub_elf, 1);
+
+         f = grub_util_fopen (mach_kernel, "r+");
+         if (!f)
+           grub_util_error ("Can't create file: %s", strerror (errno));
+         fclose (f);
+
+         fill_core_services (core_services);
+
+         ins_dev = grub_device_open (install_drive);
+
+         bless (ins_dev, core_services, 0);
+
+         if (update_nvram)
+           {
+             const char *dev;
+             int partno;
+
+             partno = ins_dev->disk->partition
+               ? ins_dev->disk->partition->number + 1 : 0;
+             dev = grub_util_get_os_disk (install_device);
+             grub_install_register_ieee1275 (0, dev, partno,
+                                             "\\\\BootX");
+           }
+         grub_device_close (ins_dev);
+         free (grub_elf);
+         free (bootx);
+         free (mach_kernel);
+         free (grub_chrp);
+         break;
+       }
       /* If a install device is defined, copy the core.elf to PReP partition.  */
-      if (install_device && install_device[0])
+      if (is_prep && install_device && install_device[0])
        {
          grub_device_t ins_dev;
          ins_dev = grub_device_open (install_drive);
@@ -1512,28 +1749,24 @@ main (int argc, char *argv[])
                               s);
            }
          grub_device_close (ins_dev);
+         if (update_nvram)
+           grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device),
+                                           0, NULL);
+         break;
       }
       /* fallthrough.  */
     case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
       if (update_nvram)
        {
-         if (platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275
-             || !install_device
-             || install_device[0] == '\0')
-           {
-             const char *dev;
-             char *relpath;
-             int partno;
-             relpath = grub_make_system_path_relative_to_its_root (imgfile);
-             partno = grub_dev->disk->partition
-               ? grub_dev->disk->partition->number + 1 : 0;
-             dev = grub_util_get_os_disk (grub_devices[0]);
-             grub_install_register_ieee1275 (0, dev,
-                                             partno, relpath);
-           }
-         else
-           grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device),
-                                           0, NULL);
+         const char *dev;
+         char *relpath;
+         int partno;
+         relpath = grub_make_system_path_relative_to_its_root (imgfile);
+         partno = grub_dev->disk->partition
+           ? grub_dev->disk->partition->number + 1 : 0;
+         dev = grub_util_get_os_disk (grub_devices[0]);
+         grub_install_register_ieee1275 (0, dev,
+                                         partno, relpath);
        }
       break;
     case GRUB_INSTALL_PLATFORM_MIPS_ARC:
@@ -1541,14 +1774,59 @@ main (int argc, char *argv[])
       break;
 
     case GRUB_INSTALL_PLATFORM_I386_EFI:
-      {
-       char *dst = grub_util_path_concat (2, efidir, "grub.efi");
-       /* For old macs. Suggested by Peter Jones.  */
-       grub_install_copy_file (imgfile, dst, 1);
-       free (dst);
-      }
+      if (!efidir_is_mac)
+       {
+         char *dst = grub_util_path_concat (2, efidir, "grub.efi");
+         /* For old macs. Suggested by Peter Jones.  */
+         grub_install_copy_file (imgfile, dst, 1);
+         free (dst);
+       }
 
     case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+      if (efidir_is_mac)
+       {
+         char *boot_efi;
+         char *core_services = grub_util_path_concat (4, efidir,
+                                                      "System", "Library",
+                                                      "CoreServices");
+         char *mach_kernel = grub_util_path_concat (2, efidir,
+                                                    "mach_kernel");
+         FILE *f;
+         grub_device_t ins_dev;
+
+         grub_install_mkdir_p (core_services);
+
+         boot_efi = grub_util_path_concat (2, core_services, "boot.efi");
+         grub_install_copy_file (imgfile, boot_efi, 1);
+
+         f = grub_util_fopen (mach_kernel, "r+");
+         if (!f)
+           grub_util_error ("Can't create file: %s", strerror (errno));
+         fclose (f);
+
+         fill_core_services(core_services);
+
+         ins_dev = grub_device_open (install_drive);
+
+         bless (ins_dev, boot_efi, 1);
+         if (!removable && update_nvram)
+           {
+             char * efidir_disk;
+             int efidir_part;
+
+             /* Try to make this image bootable using the EFI Boot Manager, if available.  */
+             efidir_disk = grub_util_get_os_disk (efidir_device_names[0]);
+             efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
+             grub_install_register_efi (efidir_disk, efidir_part,
+                                        "\\System\\Library\\CoreServices",
+                                        efi_distributor);
+           }
+
+         grub_device_close (ins_dev);
+         free (boot_efi);
+         free (mach_kernel);
+         break;
+       }
     case GRUB_INSTALL_PLATFORM_ARM_EFI:
     case GRUB_INSTALL_PLATFORM_ARM64_EFI:
     case GRUB_INSTALL_PLATFORM_IA64_EFI:
diff --git a/util/grub-macbless.c b/util/grub-macbless.c
new file mode 100644 (file)
index 0000000..9869d0b
--- /dev/null
@@ -0,0 +1,199 @@
+/* grub-probe.c - probe device information for a given path */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005,2006,2007,2008,2009,2010  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/fs.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/term.h>
+#include <grub/env.h>
+#include <grub/diskfilter.h>
+#include <grub/i18n.h>
+#include <grub/crypto.h>
+#include <grub/cryptodisk.h>
+#include <grub/hfsplus.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#define _GNU_SOURCE    1
+#include <argp.h>
+
+#include "progname.h"
+
+static void
+bless (const char *path, int x86)
+{
+  char *drive_name = NULL;
+  char **devices;
+  char *grub_path = NULL;
+  char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL;
+  grub_device_t dev = NULL;
+  grub_err_t err;
+  struct stat st;
+
+  grub_path = canonicalize_file_name (path);
+
+  if (stat (grub_path, &st) < 0)
+    grub_util_error (N_("cannot stat `%s': %s"),
+                    grub_path, strerror (errno));
+
+  devices = grub_guess_root_devices (grub_path);
+
+  if (! devices || !devices[0])
+    grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path);
+
+  drive_name = grub_util_get_grub_dev (devices[0]);
+  if (! drive_name)
+    grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+                    devices[0]);
+
+  grub_util_info ("opening %s", drive_name);
+  dev = grub_device_open (drive_name);
+  if (! dev)
+    grub_util_error ("%s", grub_errmsg);
+
+  err = grub_mac_bless_inode (dev, st.st_ino, S_ISDIR (st.st_mode), x86);
+  if (err)
+    grub_util_error ("%s", grub_errmsg);
+  free (grub_path);
+  free (filebuf_via_grub);
+  free (filebuf_via_sys);
+  free (drive_name);
+}
+
+static struct argp_option options[] = {
+  {"x86",  'x', 0, 0,
+   N_("bless for x86-based macs"), 0},
+  {"ppc",  'p', 0, 0,
+   N_("bless for ppc-based macs"), 0},
+  {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
+  { 0, 0, 0, 0, 0, 0 }
+};
+
+struct arguments
+{
+  char *arg;
+  int ppc;
+};
+
+static error_t
+argp_parser (int key, char *arg, struct argp_state *state)
+{
+  /* Get the input argument from argp_parse, which we
+     know is a pointer to our arguments structure. */
+  struct arguments *arguments = state->input;
+
+  switch (key)
+    {
+    case 'v':
+      verbosity++;
+      break;
+
+    case 'x':
+      arguments->ppc = 0;
+      break;
+
+    case 'p':
+      arguments->ppc = 1;
+      break;
+
+    case ARGP_KEY_NO_ARGS:
+      fprintf (stderr, "%s", _("No path or device is specified.\n"));
+      argp_usage (state);
+      break;
+
+    case ARGP_KEY_ARG:
+      if (arguments->arg)
+       {
+         fprintf (stderr, _("Unknown extra argument `%s'."), arg);
+         fprintf (stderr, "\n");
+         return ARGP_ERR_UNKNOWN;
+       }
+      arguments->arg = xstrdup (arg);
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+static struct argp argp = {
+  options, argp_parser, N_("--ppc PATH|--x86 FILE"),
+  N_("Mac-style bless on HFS or HFS+"),
+  NULL, NULL, NULL
+};
+
+int
+main (int argc, char *argv[])
+{
+  struct arguments arguments;
+
+  grub_util_host_init (&argc, &argv);
+
+  /* Check for options.  */
+  memset (&arguments, 0, sizeof (struct arguments));
+  if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
+    {
+      fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
+      exit(1);
+    }
+
+  if (verbosity > 1)
+    grub_env_set ("debug", "all");
+
+  /* Initialize the emulated biosdisk driver.  */
+  grub_util_biosdisk_init (NULL);
+
+  /* Initialize all modules. */
+  grub_init_all ();
+  grub_gcry_init_all ();
+
+  grub_lvm_fini ();
+  grub_mdraid09_fini ();
+  grub_mdraid1x_fini ();
+  grub_diskfilter_fini ();
+  grub_diskfilter_init ();
+  grub_mdraid09_init ();
+  grub_mdraid1x_init ();
+  grub_lvm_init ();
+
+  /* Do it.  */
+  bless (arguments.arg, !arguments.ppc);
+
+  /* Free resources.  */
+  grub_gcry_fini_all ();
+  grub_fini_all ();
+  grub_util_biosdisk_fini ();
+
+  return 0;
+}
index b4ee8f598888f868ca359b5a9eeb2f5e9694c6a2..cfe538bd454687e1b2cfc39c5679d9b26513b50f 100644 (file)
@@ -24,6 +24,7 @@
 #include <grub/util/misc.h>
 #include <grub/emu/exec.h>
 #include <grub/emu/config.h>
+#include <grub/emu/hostdisk.h>
 #include <argp.h>
 
 #include <sys/types.h>
@@ -378,6 +379,10 @@ main (int argc, char *argv[])
   if (!output_image)
     grub_util_error ("%s", _("output file must be specified"));
 
+  grub_init_all ();
+  grub_hostfs_init ();
+  grub_host_init ();
+
   xorriso_push (xorriso);
   xorriso_push ("-as");
   xorriso_push ("mkisofs");
index e2ca34980a4166de80394fb2ef7e7f304c28637b..9a8eedbc122c801221d7b6d3454ef5fb7b2d99d8 100644 (file)
@@ -26,6 +26,7 @@
 #include <grub/gfxmenu_view.h>
 #include <grub/color.h>
 #include <grub/util/install.h>
+#include <grub/emu/hostdisk.h>
 
 #define _GNU_SOURCE    1
 
@@ -166,6 +167,10 @@ main (int argc, char *argv[])
       fclose (in);
     }
 
+  grub_init_all ();
+  grub_hostfs_init ();
+  grub_host_init ();
+
   grub_util_render_label (arguments.font,
                          arguments.bgcolor,
                          arguments.fgcolor,
index 73f877442004c03741077456928ca99c5d677a19..9702ed953ce8457e768baccb999b2e9f2f86432e 100644 (file)
@@ -167,10 +167,6 @@ grub_util_render_label (const char *label_font,
   fontfull = xasprintf ("(host)/%s", t);
   free (t);
 
-  grub_init_all ();
-  grub_hostfs_init ();
-  grub_host_init ();
-
   grub_font_loader_init ();
   font = grub_font_load (fontfull);
   if (!font)