2013-11-16 19:21:16 +00:00
|
|
|
/*
|
|
|
|
* 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>
|
2013-12-14 22:31:56 +00:00
|
|
|
#include <grub/emu/hostdisk.h>
|
2013-11-16 19:21:16 +00:00
|
|
|
#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)
|
|
|
|
{
|
2013-11-25 06:34:49 +00:00
|
|
|
size_t alloced = 4096;
|
|
|
|
char *ret = xmalloc (alloced);
|
|
|
|
size_t offset = 0;
|
2013-11-16 19:21:16 +00:00
|
|
|
int fd;
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
pid = grub_util_exec_pipe ((const char * []){ "ofpathname", dev, NULL }, &fd);
|
|
|
|
if (!pid)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
FILE *fp = fdopen (fd, "r");
|
|
|
|
if (!fp)
|
|
|
|
goto fail;
|
|
|
|
|
2013-11-25 06:34:49 +00:00
|
|
|
while (!feof (fp))
|
2013-11-16 19:21:16 +00:00
|
|
|
{
|
|
|
|
size_t r;
|
2013-11-25 06:34:49 +00:00
|
|
|
if (alloced == offset)
|
|
|
|
{
|
|
|
|
alloced *= 2;
|
|
|
|
ret = xrealloc (ret, alloced);
|
|
|
|
}
|
|
|
|
r = fread (ret + offset, 1, alloced - offset, fp);
|
|
|
|
offset += r;
|
2013-11-16 19:21:16 +00:00
|
|
|
}
|
|
|
|
|
2013-11-25 06:34:49 +00:00
|
|
|
if (offset > 0 && ret[offset - 1] == '\n')
|
|
|
|
offset--;
|
|
|
|
if (offset > 0 && ret[offset - 1] == '\r')
|
|
|
|
offset--;
|
|
|
|
if (alloced == offset)
|
|
|
|
{
|
|
|
|
alloced++;
|
|
|
|
ret = xrealloc (ret, alloced);
|
|
|
|
}
|
|
|
|
ret[offset] = '\0';
|
|
|
|
|
2013-11-16 19:21:16 +00:00
|
|
|
fclose (fp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
fail:
|
2013-12-21 00:41:16 +00:00
|
|
|
grub_util_error (_("couldn't find IEEE1275 device path for %s.\nYou will have to set `boot-device' variable manually"),
|
2013-11-16 19:21:16 +00:00
|
|
|
dev);
|
|
|
|
}
|
|
|
|
|
2018-01-31 21:49:36 +00:00
|
|
|
static int
|
2013-11-16 19:21:16 +00:00
|
|
|
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;
|
unix/platform: Initialize variable to fix grub-install on UEFI system
On a UEFI system, were no boot entry *grub* is present, currently,
`grub-install` fails with an error.
$ efibootmgr
BootCurrent: 0000
Timeout: 0 seconds
BootOrder: 0001,0006,0003,0004,0005
Boot0001 Diskette Drive
Boot0003* USB Storage Device
Boot0004* CD/DVD/CD-RW Drive
Boot0005 Onboard NIC
Boot0006* WDC WD2500AAKX-75U6AA0
$ sudo grub-install /dev/sda
Installing for x86_64-efi platform.
grub-install: error: efibootmgr failed to register the boot entry: Unknown error 22020.
The error code is always different, and the error message (incorrectly)
points to efibootmgr.
But, the error is in GRUB’s function
`grub_install_remove_efi_entries_by_distributor()`, where the variable
`rc` for the return value, is uninitialized and never set, when no boot
entry for the distributor is found.
The content of that uninitialized variable is then returned as the error
code of efibootmgr.
Set the variable to 0, so that success is returned, when no entry needs
to be deleted.
Tested on Dell OptiPlex 7010 with firmware A28.
$ sudo ./grub-install /dev/sda
Installing for x86_64-efi platform.
Installation finished. No error reported.
[1]: https://github.com/rhboot/efibootmgr/issues/100
Signed-off-by: Paul Menzel <pmenzel@molgen.mpg.de>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
2018-10-23 13:00:13 +00:00
|
|
|
int rc = 0;
|
2013-11-16 19:21:16 +00:00
|
|
|
|
|
|
|
if (!pid)
|
|
|
|
{
|
|
|
|
grub_util_warn (_("Unable to open stream from %s: %s"),
|
|
|
|
"efibootmgr", strerror (errno));
|
2018-01-31 21:49:36 +00:00
|
|
|
return errno;
|
2013-11-16 19:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FILE *fp = fdopen (fd, "r");
|
|
|
|
if (!fp)
|
|
|
|
{
|
|
|
|
grub_util_warn (_("Unable to open stream from %s: %s"),
|
|
|
|
"efibootmgr", strerror (errno));
|
2018-01-31 21:49:36 +00:00
|
|
|
return errno;
|
2013-11-16 19:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2018-01-31 21:49:36 +00:00
|
|
|
rc = grub_util_exec ((const char * []){ "efibootmgr", "-q",
|
2013-11-16 19:21:16 +00:00
|
|
|
"-b", bootnum, "-B", NULL });
|
|
|
|
else
|
2018-01-31 21:49:36 +00:00
|
|
|
rc = grub_util_exec ((const char * []){ "efibootmgr",
|
2013-11-16 19:21:16 +00:00
|
|
|
"-b", bootnum, "-B", NULL });
|
|
|
|
}
|
|
|
|
|
|
|
|
free (line);
|
2018-01-31 21:49:36 +00:00
|
|
|
return rc;
|
2013-11-16 19:21:16 +00:00
|
|
|
}
|
|
|
|
|
2018-01-31 21:49:36 +00:00
|
|
|
int
|
2013-12-14 22:31:56 +00:00
|
|
|
grub_install_register_efi (grub_device_t efidir_grub_dev,
|
2013-11-16 19:21:16 +00:00
|
|
|
const char *efifile_path,
|
|
|
|
const char *efi_distributor)
|
|
|
|
{
|
2013-12-14 22:31:56 +00:00
|
|
|
const char * efidir_disk;
|
|
|
|
int efidir_part;
|
2018-01-31 21:49:36 +00:00
|
|
|
int ret;
|
2013-12-14 22:31:56 +00:00
|
|
|
efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk);
|
|
|
|
efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
|
|
|
|
|
2013-11-16 19:21:16 +00:00
|
|
|
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. */
|
2018-01-31 21:49:36 +00:00
|
|
|
ret = grub_install_remove_efi_entries_by_distributor (efi_distributor);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2013-11-16 19:21:16 +00:00
|
|
|
|
|
|
|
char *efidir_part_str = xasprintf ("%d", efidir_part);
|
|
|
|
|
|
|
|
if (!verbosity)
|
2018-01-31 21:49:36 +00:00
|
|
|
ret = grub_util_exec ((const char * []){ "efibootmgr", "-q",
|
2013-11-16 19:21:16 +00:00
|
|
|
"-c", "-d", efidir_disk,
|
|
|
|
"-p", efidir_part_str, "-w",
|
|
|
|
"-L", efi_distributor, "-l",
|
|
|
|
efifile_path, NULL });
|
|
|
|
else
|
2018-01-31 21:49:36 +00:00
|
|
|
ret = grub_util_exec ((const char * []){ "efibootmgr",
|
2013-11-16 19:21:16 +00:00
|
|
|
"-c", "-d", efidir_disk,
|
|
|
|
"-p", efidir_part_str, "-w",
|
|
|
|
"-L", efi_distributor, "-l",
|
|
|
|
efifile_path, NULL });
|
|
|
|
free (efidir_part_str);
|
2018-01-31 21:49:36 +00:00
|
|
|
return ret;
|
2013-11-16 19:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2013-12-18 05:50:24 +00:00
|
|
|
grub_util_error (_("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n"),
|
2013-11-16 19:21:16 +00:00
|
|
|
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."));
|
|
|
|
}
|