grub/grub-core/osdep/unix/platform.c

214 lines
5.6 KiB
C

/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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 <config.h>
#include <grub/util/install.h>
#include <grub/util/misc.h>
#include <grub/misc.h>
#include <grub/i18n.h>
#include <grub/emu/exec.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
static char *
get_ofpathname (const char *dev)
{
char *ret = xmalloc (2 * PATH_MAX);
char *end = ret + 2 * PATH_MAX - 1;
int fd;
pid_t pid;
char *ptr = ret;
pid = grub_util_exec_pipe ((const char * []){ "ofpathname", dev, NULL }, &fd);
if (!pid)
goto fail;
FILE *fp = fdopen (fd, "r");
if (!fp)
goto fail;
while (!feof (fp) && ptr < end)
{
size_t r;
r = fread (ptr, 1, end - ptr, fp);
ptr += r;
}
fclose (fp);
return ret;
fail:
grub_util_error (_("couldn't find IEEE1275 device tree path for %s.\nYou will have to set `boot-device' variable manually"),
dev);
}
static void
grub_install_remove_efi_entries_by_distributor (const char *efi_distributor)
{
int fd;
pid_t pid = grub_util_exec_pipe ((const char * []){ "efibootmgr", NULL }, &fd);
char *line = NULL;
size_t len = 0;
if (!pid)
{
grub_util_warn (_("Unable to open stream from %s: %s"),
"efibootmgr", strerror (errno));
return;
}
FILE *fp = fdopen (fd, "r");
if (!fp)
{
grub_util_warn (_("Unable to open stream from %s: %s"),
"efibootmgr", strerror (errno));
return;
}
line = xmalloc (80);
len = 80;
while (1)
{
int ret;
char *bootnum;
ret = getline (&line, &len, fp);
if (ret == -1)
break;
if (grub_memcmp (line, "Boot", sizeof ("Boot") - 1) != 0
|| line[sizeof ("Boot") - 1] < '0'
|| line[sizeof ("Boot") - 1] > '9')
continue;
if (!strcasestr (line, efi_distributor))
continue;
bootnum = line + sizeof ("Boot") - 1;
bootnum[4] = '\0';
if (!verbosity)
grub_util_exec ((const char * []){ "efibootmgr", "-q",
"-b", bootnum, "-B", NULL });
else
grub_util_exec ((const char * []){ "efibootmgr",
"-b", bootnum, "-B", NULL });
}
free (line);
}
void
grub_install_register_efi (const char *efidir_disk, int efidir_part,
const char *efifile_path,
const char *efi_distributor)
{
if (grub_util_exec_redirect_null ((const char * []){ "efibootmgr", "--version", NULL }))
{
/* TRANSLATORS: This message is shown when required executable `%s'
isn't found. */
grub_util_error (_("%s: not found"), "efibootmgr");
}
/* On Linux, we need the efivars kernel modules. */
#ifdef __linux__
grub_util_exec ((const char * []){ "modprobe", "-q", "efivars", NULL });
#endif
/* Delete old entries from the same distributor. */
grub_install_remove_efi_entries_by_distributor (efi_distributor);
char *efidir_part_str = xasprintf ("%d", efidir_part);
if (!verbosity)
grub_util_exec ((const char * []){ "efibootmgr", "-q",
"-c", "-d", efidir_disk,
"-p", efidir_part_str, "-w",
"-L", efi_distributor, "-l",
efifile_path, NULL });
else
grub_util_exec ((const char * []){ "efibootmgr",
"-c", "-d", efidir_disk,
"-p", efidir_part_str, "-w",
"-L", efi_distributor, "-l",
efifile_path, NULL });
free (efidir_part_str);
}
void
grub_install_register_ieee1275 (int is_prep, const char *install_device,
int partno, const char *relpath)
{
char *boot_device;
if (grub_util_exec_redirect_null ((const char * []){ "ofpathname", "--version", NULL }))
{
/* TRANSLATORS: This message is shown when required executable `%s'
isn't found. */
grub_util_error (_("%s: not found"), "ofpathname");
}
/* Get the Open Firmware device tree path translation. */
if (!is_prep)
{
char *ptr;
char *ofpath;
const char *iptr;
ofpath = get_ofpathname (install_device);
boot_device = xmalloc (strlen (ofpath) + 1
+ sizeof ("XXXXXXXXXXXXXXXXXXXX")
+ 1 + strlen (relpath) + 1);
ptr = grub_stpcpy (boot_device, ofpath);
*ptr++ = ':';
grub_snprintf (ptr, sizeof ("XXXXXXXXXXXXXXXXXXXX"), "%d",
partno);
ptr += strlen (ptr);
*ptr++ = ',';
for (iptr = relpath; *iptr; iptr++, ptr++)
{
if (*iptr == '/')
*ptr = '\\';
else
*ptr = *iptr;
}
*ptr = '\0';
}
else
boot_device = get_ofpathname (install_device);
if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device",
boot_device, NULL }))
{
char *cmd = xasprintf ("setenv boot-device %s", boot_device);
grub_util_error ("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n",
cmd);
free (cmd);
}
free (boot_device);
}
void
grub_install_sgi_setup (const char *install_device,
const char *imgfile, const char *destname)
{
grub_util_exec ((const char * []){ "dvhtool", "-d",
install_device, "--unix-to-vh",
imgfile, destname, NULL });
grub_util_warn ("%s", _("You will have to set `SystemPartition' and `OSLoader' manually."));
}