Implement better integration with Mac firmware.

This commit is contained in:
Vladimir Serbinenko 2013-12-17 15:21:02 +01:00
parent 1f032575bb
commit b8765fa082
15 changed files with 835 additions and 39 deletions

View file

@ -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> 2013-12-17 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/loader/multiboot_mbi2.c: Implement special value for * grub-core/loader/multiboot_mbi2.c: Implement special value for

View file

@ -62,6 +62,7 @@ library = {
common_nodist = grub_script.tab.h; common_nodist = grub_script.tab.h;
common = grub-core/commands/blocklist.c; common = grub-core/commands/blocklist.c;
common = grub-core/commands/macbless.c;
common = grub-core/commands/xnu_uuid.c; common = grub-core/commands/xnu_uuid.c;
common = grub-core/commands/testload.c; common = grub-core/commands/testload.c;
common = grub-core/commands/ls.c; common = grub-core/commands/ls.c;
@ -401,6 +402,21 @@ program = {
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; 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 = { data = {
common = util/grub.d/README; common = util/grub.d/README;
installdir = grubconf; installdir = grubconf;
@ -585,6 +601,9 @@ program = {
common = grub-core/osdep/blocklist.c; common = grub-core/osdep/blocklist.c;
common = grub-core/osdep/config.c; common = grub-core/osdep/config.c;
common = util/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; common = util/resolve.c;
enable = noemu; enable = noemu;

View file

@ -0,0 +1,4 @@
[NAME]
grub-macbless \- bless a mac file/directory
[SEE ALSO]
.BR grub-install (1)

View file

@ -1450,6 +1450,11 @@ module = {
common = fs/zfs/zfsinfo.c; common = fs/zfs/zfsinfo.c;
}; };
module = {
name = macbless;
common = commands/macbless.c;
};
module = { module = {
name = pxe; name = pxe;
i386_pc = net/drivers/i386/pc/pxe.c; i386_pc = net/drivers/i386/pc/pxe.c;

View file

@ -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;
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);
}

View file

@ -1229,14 +1229,18 @@ grub_hfs_dir_hook (struct grub_hfs_record *rec, void *hook_arg)
{ {
info.dir = 1; info.dir = 1;
info.mtimeset = 1; info.mtimeset = 1;
info.inodeset = 1;
info.mtime = grub_be_to_cpu32 (drec->mtime) - 2082844800; 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); return ctx->hook (fname, &info, ctx->hook_data);
} }
if (frec->type == GRUB_HFS_FILETYPE_FILE) if (frec->type == GRUB_HFS_FILETYPE_FILE)
{ {
info.dir = 0; info.dir = 0;
info.mtimeset = 1; info.mtimeset = 1;
info.inodeset = 1;
info.mtime = grub_be_to_cpu32 (frec->mtime) - 2082844800; 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); return ctx->hook (fname, &info, ctx->hook_data);
} }

View file

@ -34,11 +34,6 @@
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
#define GRUB_HFSPLUS_MAGIC 0x482B
#define GRUB_HFSPLUSX_MAGIC 0x4858
#define GRUB_HFSPLUS_SBLOCK 2
/* The type of node. */ /* The type of node. */
enum grub_hfsplus_btnode_type 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.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1; info.mtimeset = 1;
info.mtime = node->mtime; info.mtime = node->mtime;
info.inodeset = 1;
info.inode = node->fileid;
info.case_insensitive = !! (filetype & GRUB_FSHELP_CASE_INSENSITIVE); info.case_insensitive = !! (filetype & GRUB_FSHELP_CASE_INSENSITIVE);
grub_free (node); grub_free (node);
return ctx->hook (filename, &info, ctx->hook_data); return ctx->hook (filename, &info, ctx->hook_data);

View file

@ -38,7 +38,9 @@ struct grub_dirhook_info
unsigned dir:1; unsigned dir:1;
unsigned mtimeset:1; unsigned mtimeset:1;
unsigned case_insensitive:1; unsigned case_insensitive:1;
unsigned inodeset:1;
grub_int32_t mtime; grub_int32_t mtime;
grub_uint64_t inode;
}; };
typedef int (*grub_fs_dir_hook_t) (const char *filename, typedef int (*grub_fs_dir_hook_t) (const char *filename,

View file

@ -50,11 +50,20 @@ struct grub_hfs_sblock
/* A pascal style string that holds the volumename. */ /* A pascal style string that holds the volumename. */
grub_uint8_t volname[28]; 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_uint64_t num_serial;
grub_uint16_t embed_sig; grub_uint16_t embed_sig;
struct grub_hfs_extent embed_extent; struct grub_hfs_extent embed_extent;
grub_uint8_t unused6[4]; grub_uint8_t unused7[4];
grub_hfs_datarecord_t extent_recs; grub_hfs_datarecord_t extent_recs;
grub_uint32_t catalog_size; grub_uint32_t catalog_size;
grub_hfs_datarecord_t catalog_recs; grub_hfs_datarecord_t catalog_recs;

View 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/types.h>
#include <grub/disk.h> #include <grub/disk.h>
#define GRUB_HFSPLUS_MAGIC 0x482B
#define GRUB_HFSPLUSX_MAGIC 0x4858
#define GRUB_HFSPLUS_SBLOCK 2
/* A HFS+ extent. */ /* A HFS+ extent. */
struct grub_hfsplus_extent struct grub_hfsplus_extent
{ {
@ -30,7 +51,16 @@ struct grub_hfsplus_volheader
grub_uint32_t utime; grub_uint32_t utime;
grub_uint8_t unused2[16]; grub_uint8_t unused2[16];
grub_uint32_t blksize; 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; grub_uint64_t num_serial;
struct grub_hfsplus_forkdata allocations_file; struct grub_hfsplus_forkdata allocations_file;
struct grub_hfsplus_forkdata extents_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_key_internal *keyb),
struct grub_hfsplus_btnode **matchnode, struct grub_hfsplus_btnode **matchnode,
grub_off_t *keyoffset); 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);

View file

@ -41,6 +41,7 @@
#include <grub/gpt_partition.h> #include <grub/gpt_partition.h>
#include <grub/emu/config.h> #include <grub/emu/config.h>
#include <grub/util/ofpath.h> #include <grub/util/ofpath.h>
#include <grub/hfsplus.h>
#include <string.h> #include <string.h>
@ -60,6 +61,7 @@ static int allow_floppy = 0;
static int force_file_id = 0; static int force_file_id = 0;
static char *disk_module = NULL; static char *disk_module = NULL;
static char *efidir = NULL; static char *efidir = NULL;
static char *macppcdir = NULL;
static int force = 0; static int force = 0;
static int have_abstractions = 0; static int have_abstractions = 0;
static int have_cryptodisk = 0; static int have_cryptodisk = 0;
@ -68,6 +70,10 @@ static int have_load_cfg = 0;
static FILE * load_cfg_f = NULL; static FILE * load_cfg_f = NULL;
static char *load_cfg; static char *load_cfg;
static int install_bootsector = 1; 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; static int add_rs_codes = 1;
enum enum
@ -96,6 +102,11 @@ enum
OPTION_DISK_MODULE, OPTION_DISK_MODULE,
OPTION_NO_BOOTSECTOR, OPTION_NO_BOOTSECTOR,
OPTION_NO_RS_CODES, OPTION_NO_RS_CODES,
OPTION_MACPPC_DIRECTORY,
OPTION_LABEL_FONT,
OPTION_LABEL_COLOR,
OPTION_LABEL_BGCOLOR,
OPTION_PRODUCT_VERSION
}; };
static int fs_probe = 1; static int fs_probe = 1;
@ -119,6 +130,25 @@ argp_parser (int key, char *arg, struct argp_state *state)
install_bootsector = 0; install_bootsector = 0;
return 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. */ /* Accept and ignore for compatibility. */
case OPTION_FONT: case OPTION_FONT:
case OPTION_MKRELPATH: case OPTION_MKRELPATH:
@ -138,6 +168,11 @@ argp_parser (int key, char *arg, struct argp_state *state)
bootdir = xstrdup (arg); bootdir = xstrdup (arg);
return 0; return 0;
case OPTION_MACPPC_DIRECTORY:
free (macppcdir);
macppcdir = xstrdup (arg);
return 0;
case OPTION_EFI_DIRECTORY: case OPTION_EFI_DIRECTORY:
free (efidir); free (efidir);
efidir = xstrdup (arg); efidir = xstrdup (arg);
@ -255,9 +290,15 @@ static struct argp_option options[] = {
N_("the installation device is removable. " N_("the installation device is removable. "
"This option is only available on EFI."), 2}, "This option is only available on EFI."), 2},
{"bootloader-id", OPTION_BOOTLOADER_ID, N_("ID"), 0, {"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, {"efi-directory", OPTION_EFI_DIRECTORY, N_("DIR"), 0,
N_("use DIR as the EFI System Partition root."), 2}, 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} {0, 0, 0, 0, 0, 0}
}; };
@ -697,6 +738,63 @@ is_prep_empty (grub_device_t dev)
return 1; 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 int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
@ -714,8 +812,14 @@ main (int argc, char *argv[])
char **efidir_device_names = NULL; char **efidir_device_names = NULL;
grub_device_t efidir_grub_dev = NULL; grub_device_t efidir_grub_dev = NULL;
char *efidir_grub_devname; char *efidir_grub_devname;
int efidir_is_mac = 0;
int is_prep = 0;
const char *pkgdatadir;
grub_util_host_init (&argc, &argv); 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); argp_parse (&argp, argc, argv, 0, 0, 0);
@ -800,9 +904,12 @@ main (int argc, char *argv[])
if (!install_device) if (!install_device)
grub_util_error ("%s", _("install device isn't specified")); grub_util_error ("%s", _("install device isn't specified"));
break; break;
case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
if (install_device)
is_prep = 1;
break;
case GRUB_INSTALL_PLATFORM_MIPS_ARC: case GRUB_INSTALL_PLATFORM_MIPS_ARC:
case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
break; break;
case GRUB_INSTALL_PLATFORM_I386_EFI: case GRUB_INSTALL_PLATFORM_I386_EFI:
case GRUB_INSTALL_PLATFORM_X86_64_EFI: case GRUB_INSTALL_PLATFORM_X86_64_EFI:
@ -850,6 +957,9 @@ main (int argc, char *argv[])
/* Initialize all modules. */ /* Initialize all modules. */
grub_init_all (); grub_init_all ();
grub_gcry_init_all (); grub_gcry_init_all ();
grub_hostfs_init ();
grub_host_init ();
switch (platform) switch (platform)
{ {
case GRUB_INSTALL_PLATFORM_I386_EFI: case GRUB_INSTALL_PLATFORM_I386_EFI:
@ -927,7 +1037,13 @@ main (int argc, char *argv[])
if (! fs) if (! fs)
grub_util_error ("%s", grub_errmsg); 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); grub_util_error (_("%s doesn't look like an EFI partition.\n"), efidir);
/* The EFI specification requires that an EFI System Partition must /* The EFI specification requires that an EFI System Partition must
@ -1001,6 +1117,76 @@ main (int argc, char *argv[])
grub_install_mkdir_p (efidir); 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, grub_install_copy_files (grub_install_source_directory,
grubdir, platform); grubdir, platform);
@ -1491,8 +1677,59 @@ main (int argc, char *argv[])
} }
case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: 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 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; grub_device_t ins_dev;
ins_dev = grub_device_open (install_drive); ins_dev = grub_device_open (install_drive);
@ -1512,28 +1749,24 @@ main (int argc, char *argv[])
s); s);
} }
grub_device_close (ins_dev); grub_device_close (ins_dev);
if (update_nvram)
grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device),
0, NULL);
break;
} }
/* fallthrough. */ /* fallthrough. */
case GRUB_INSTALL_PLATFORM_I386_IEEE1275: case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
if (update_nvram) if (update_nvram)
{ {
if (platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275 const char *dev;
|| !install_device char *relpath;
|| install_device[0] == '\0') int partno;
{ relpath = grub_make_system_path_relative_to_its_root (imgfile);
const char *dev; partno = grub_dev->disk->partition
char *relpath; ? grub_dev->disk->partition->number + 1 : 0;
int partno; dev = grub_util_get_os_disk (grub_devices[0]);
relpath = grub_make_system_path_relative_to_its_root (imgfile); grub_install_register_ieee1275 (0, dev,
partno = grub_dev->disk->partition partno, relpath);
? 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);
} }
break; break;
case GRUB_INSTALL_PLATFORM_MIPS_ARC: case GRUB_INSTALL_PLATFORM_MIPS_ARC:
@ -1541,14 +1774,59 @@ main (int argc, char *argv[])
break; break;
case GRUB_INSTALL_PLATFORM_I386_EFI: case GRUB_INSTALL_PLATFORM_I386_EFI:
{ if (!efidir_is_mac)
char *dst = grub_util_path_concat (2, efidir, "grub.efi"); {
/* For old macs. Suggested by Peter Jones. */ char *dst = grub_util_path_concat (2, efidir, "grub.efi");
grub_install_copy_file (imgfile, dst, 1); /* For old macs. Suggested by Peter Jones. */
free (dst); grub_install_copy_file (imgfile, dst, 1);
} free (dst);
}
case GRUB_INSTALL_PLATFORM_X86_64_EFI: 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_ARM_EFI:
case GRUB_INSTALL_PLATFORM_ARM64_EFI: case GRUB_INSTALL_PLATFORM_ARM64_EFI:
case GRUB_INSTALL_PLATFORM_IA64_EFI: case GRUB_INSTALL_PLATFORM_IA64_EFI:

199
util/grub-macbless.c Normal file
View file

@ -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;
}

View file

@ -24,6 +24,7 @@
#include <grub/util/misc.h> #include <grub/util/misc.h>
#include <grub/emu/exec.h> #include <grub/emu/exec.h>
#include <grub/emu/config.h> #include <grub/emu/config.h>
#include <grub/emu/hostdisk.h>
#include <argp.h> #include <argp.h>
#include <sys/types.h> #include <sys/types.h>
@ -378,6 +379,10 @@ main (int argc, char *argv[])
if (!output_image) if (!output_image)
grub_util_error ("%s", _("output file must be specified")); grub_util_error ("%s", _("output file must be specified"));
grub_init_all ();
grub_hostfs_init ();
grub_host_init ();
xorriso_push (xorriso); xorriso_push (xorriso);
xorriso_push ("-as"); xorriso_push ("-as");
xorriso_push ("mkisofs"); xorriso_push ("mkisofs");

View file

@ -26,6 +26,7 @@
#include <grub/gfxmenu_view.h> #include <grub/gfxmenu_view.h>
#include <grub/color.h> #include <grub/color.h>
#include <grub/util/install.h> #include <grub/util/install.h>
#include <grub/emu/hostdisk.h>
#define _GNU_SOURCE 1 #define _GNU_SOURCE 1
@ -166,6 +167,10 @@ main (int argc, char *argv[])
fclose (in); fclose (in);
} }
grub_init_all ();
grub_hostfs_init ();
grub_host_init ();
grub_util_render_label (arguments.font, grub_util_render_label (arguments.font,
arguments.bgcolor, arguments.bgcolor,
arguments.fgcolor, arguments.fgcolor,

View file

@ -167,10 +167,6 @@ grub_util_render_label (const char *label_font,
fontfull = xasprintf ("(host)/%s", t); fontfull = xasprintf ("(host)/%s", t);
free (t); free (t);
grub_init_all ();
grub_hostfs_init ();
grub_host_init ();
grub_font_loader_init (); grub_font_loader_init ();
font = grub_font_load (fontfull); font = grub_font_load (fontfull);
if (!font) if (!font)