* grub-core/kern/emu/hostdisk.c: Disentagle into a series of OS-specific

files rather than one file with loads of #if's.
	* util/getroot.c: Likewise.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2013-09-22 07:36:17 +02:00
parent 287faafe8d
commit 3ff4063dd3
30 changed files with 4039 additions and 2364 deletions

File diff suppressed because it is too large Load diff

102
util/getroot_apple.c Normal file
View file

@ -0,0 +1,102 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/types.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
#include <sys/wait.h>
# include <sys/disk.h>
# include <sys/param.h>
# include <sys/sysctl.h>
# include <sys/mount.h>
char *
grub_util_part_to_disk (const char *os_dev, struct stat *st,
int *is_part)
{
char *path = xstrdup (os_dev);
if (strncmp ("/dev/", path, 5) == 0)
{
char *p;
for (p = path + 5; *p; ++p)
if (grub_isdigit(*p))
{
p = strpbrk (p, "sp");
if (p)
{
*is_part = 1;
*p = '\0';
}
break;
}
}
return path;
}
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
{
return GRUB_DEV_ABSTRACTION_NONE;
}
int
grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
enum grub_dev_abstraction_types ab __attribute__ ((unused)))
{
return 0;
}
char *
grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
grub_disk_addr_t
grub_util_find_partition_start_os (const char *dev __attribute__ ((unused)))
{
return 0;
}

82
util/getroot_basic.c Normal file
View file

@ -0,0 +1,82 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/types.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
char *
grub_util_part_to_disk (const char *os_dev,
struct stat *st __attribute__ ((unused)),
int *is_part)
{
*is_part = 0;
return xstrdup (os_dev);
}
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
{
return GRUB_DEV_ABSTRACTION_NONE;
}
int
grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
enum grub_dev_abstraction_types ab __attribute__ ((unused)))
{
return 0;
}
char *
grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
grub_disk_addr_t
grub_util_find_partition_start_os (const char *dev __attribute__ ((unused)))
{
return 0;
}

199
util/getroot_bsd.c Normal file
View file

@ -0,0 +1,199 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/types.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
#include <sys/wait.h>
# include <sys/ioctl.h>
# include <sys/disklabel.h> /* struct disklabel */
# include <sys/disk.h> /* struct dkwedge_info */
# ifdef HAVE_GETRAWPARTITION
# include <util.h> /* getrawpartition */
# endif /* HAVE_GETRAWPARTITION */
#if defined(__NetBSD__)
# include <sys/fdio.h>
#endif
#if defined(__OpenBSD__)
# include <sys/dkio.h>
#endif
char *
grub_util_part_to_disk (const char *os_dev, struct stat *st,
int *is_part)
{
int rawpart = -1;
# ifdef HAVE_GETRAWPARTITION
rawpart = getrawpartition();
# endif /* HAVE_GETRAWPARTITION */
if (rawpart < 0)
return xstrdup (os_dev);
#if defined(__NetBSD__)
/* NetBSD disk wedges are of the form "/dev/rdk.*". */
if (strncmp ("/dev/rdk", os_dev, sizeof("/dev/rdk") - 1) == 0)
{
struct dkwedge_info dkw;
int fd;
fd = open (os_dev, O_RDONLY);
if (fd == -1)
{
grub_error (GRUB_ERR_BAD_DEVICE,
N_("cannot open `%s': %s"), os_dev,
strerror (errno));
return xstrdup (os_dev);
}
/* We don't call configure_device_driver since this isn't a floppy device name. */
if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == -1)
{
grub_error (GRUB_ERR_BAD_DEVICE,
"cannot get disk wedge info of `%s'", os_dev);
close (fd);
return xstrdup (os_dev);
}
*is_part = (dkw.dkw_offset != 0);
close (fd);
return xasprintf ("/dev/r%s%c", dkw.dkw_parent, 'a' + rawpart);
}
#endif
/* NetBSD (disk label) partitions are of the form "/dev/r[a-z]+[0-9][a-z]". */
if (strncmp ("/dev/r", os_dev, sizeof("/dev/r") - 1) == 0 &&
(os_dev[sizeof("/dev/r") - 1] >= 'a' && os_dev[sizeof("/dev/r") - 1] <= 'z') &&
strncmp ("fd", os_dev + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
{
char *path = xstrdup (os_dev);
char *p;
for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
if (grub_isdigit(*p))
{
p++;
if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
{
if (*p != 'a' + rawpart)
*is_part = 1;
/* path matches the required regular expression and
p points to its last character. */
*p = 'a' + rawpart;
}
}
return path;
}
return xstrdup (os_dev);
}
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
{
return GRUB_DEV_ABSTRACTION_NONE;
}
int
grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
enum grub_dev_abstraction_types ab __attribute__ ((unused)))
{
return 0;
}
char *
grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
grub_disk_addr_t
grub_util_find_partition_start_os (const char *dev)
{
int fd;
# if defined(__NetBSD__)
struct dkwedge_info dkw;
# endif /* defined(__NetBSD__) */
struct disklabel label;
int p_index;
fd = open (dev, O_RDONLY);
if (fd == -1)
{
grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
dev, strerror (errno));
return 0;
}
# if defined(__NetBSD__)
configure_device_driver (fd);
/* First handle the case of disk wedges. */
if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == 0)
{
close (fd);
return (grub_disk_addr_t) dkw.dkw_offset;
}
# endif /* defined(__NetBSD__) */
if (ioctl (fd, DIOCGDINFO, &label) == -1)
{
grub_error (GRUB_ERR_BAD_DEVICE,
"cannot get disk label of `%s'", dev);
close (fd);
return 0;
}
close (fd);
if (dev[0])
p_index = dev[strlen(dev) - 1] - 'a';
else
p_index = -1;
if (p_index >= label.d_npartitions || p_index < 0)
{
grub_error (GRUB_ERR_BAD_DEVICE,
"no disk label entry for `%s'", dev);
return 0;
}
return (grub_disk_addr_t) label.d_partitions[p_index].p_offset;
}

115
util/getroot_cygwin.c Normal file
View file

@ -0,0 +1,115 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/types.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
#include <sys/wait.h>
# include <sys/ioctl.h>
# include <cygwin/fs.h> /* BLKGETSIZE64 */
# include <cygwin/hdreg.h> /* HDIO_GETGEO */
# include <sys/cygwin.h>
char *
grub_util_part_to_disk (const char *os_dev,
struct stat *st __attribute__ ((unused)),
int *is_part)
{
char *path = xstrdup (os_dev);
if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z'
&& path[8])
{
*is_part = 1;
path[8] = 0;
}
return path;
}
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
{
return GRUB_DEV_ABSTRACTION_NONE;
}
int
grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
enum grub_dev_abstraction_types ab __attribute__ ((unused)))
{
return 0;
}
char *
grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
grub_disk_addr_t
grub_util_find_partition_start_os (const char *dev)
{
int fd;
struct hd_geometry hdg;
fd = open (dev, O_RDONLY);
if (fd == -1)
{
grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
dev, strerror (errno));
return 0;
}
if (ioctl (fd, HDIO_GETGEO, &hdg))
{
grub_error (GRUB_ERR_BAD_DEVICE,
"cannot get disk geometry of `%s'", dev);
close (fd);
return 0;
}
close (fd);
return hdg.start;
}

451
util/getroot_devmapper.c Normal file
View file

@ -0,0 +1,451 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <grub/emu/getroot.h>
#include <grub/mm.h>
#ifdef HAVE_DEVICE_MAPPER
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <libdevmapper.h>
#include <grub/types.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
static int
grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
struct dm_tree_node **node)
{
uint32_t maj, min;
struct stat st;
*node = NULL;
*tree = NULL;
if (stat (os_dev, &st) < 0)
return 0;
maj = major (st.st_rdev);
min = minor (st.st_rdev);
if (!dm_is_dm_major (maj))
return 0;
*tree = dm_tree_create ();
if (! *tree)
{
grub_puts_ (N_("Failed to create `device-mapper' tree"));
grub_dprintf ("hostdisk", "dm_tree_create failed\n");
return 0;
}
if (! dm_tree_add_dev (*tree, maj, min))
{
grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
dm_tree_free (*tree);
*tree = NULL;
return 0;
}
*node = dm_tree_find_node (*tree, maj, min);
if (! *node)
{
grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
dm_tree_free (*tree);
*tree = NULL;
return 0;
}
return 1;
}
static char *
get_dm_uuid (const char *os_dev)
{
struct dm_tree *tree;
struct dm_tree_node *node;
const char *node_uuid;
char *ret;
if (!grub_util_open_dm (os_dev, &tree, &node))
return NULL;
node_uuid = dm_tree_node_get_uuid (node);
if (! node_uuid)
{
grub_dprintf ("hostdisk", "%s has no DM uuid\n", os_dev);
dm_tree_free (tree);
return NULL;
}
ret = grub_strdup (node_uuid);
dm_tree_free (tree);
return ret;
}
enum grub_dev_abstraction_types
grub_util_get_dm_abstraction (const char *os_dev)
{
char *uuid;
uuid = get_dm_uuid (os_dev);
if (uuid == NULL)
return GRUB_DEV_ABSTRACTION_NONE;
if (strncmp (uuid, "LVM-", 4) == 0)
{
grub_free (uuid);
return GRUB_DEV_ABSTRACTION_LVM;
}
if (strncmp (uuid, "CRYPT-LUKS1-", 4) == 0)
{
grub_free (uuid);
return GRUB_DEV_ABSTRACTION_LUKS;
}
grub_free (uuid);
return GRUB_DEV_ABSTRACTION_NONE;
}
void
grub_util_pull_devmapper (const char *os_dev)
{
struct dm_tree *tree;
struct dm_tree_node *node;
struct dm_tree_node *child;
void *handle = NULL;
char *lastsubdev = NULL;
char *uuid;
uuid = get_dm_uuid (os_dev);
if (!grub_util_open_dm (os_dev, &tree, &node))
return;
while ((child = dm_tree_next_child (&handle, node, 0)))
{
const struct dm_info *dm = dm_tree_node_get_info (child);
char *subdev;
if (!dm)
continue;
subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor));
if (subdev)
{
lastsubdev = subdev;
grub_util_pull_device (subdev);
}
}
if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
&& lastsubdev)
{
char *grdev = grub_util_get_grub_dev (lastsubdev);
dm_tree_free (tree);
if (grdev)
{
grub_err_t err;
err = grub_cryptodisk_cheat_mount (grdev, os_dev);
if (err)
grub_util_error (_("can't mount encrypted volume `%s': %s"),
lastsubdev, grub_errmsg);
}
grub_free (grdev);
}
else
dm_tree_free (tree);
}
char *
grub_util_devmapper_part_to_disk (struct stat *st,
int *is_part, const char *path)
{
struct dm_tree *tree;
uint32_t maj, min;
struct dm_tree_node *node = NULL, *child;
void *handle;
const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
tree = dm_tree_create ();
if (! tree)
{
grub_util_info ("dm_tree_create failed");
goto devmapper_out;
}
maj = major (st->st_rdev);
min = minor (st->st_rdev);
if (! dm_tree_add_dev (tree, maj, min))
{
grub_util_info ("dm_tree_add_dev failed");
goto devmapper_out;
}
node = dm_tree_find_node (tree, maj, min);
if (! node)
{
grub_util_info ("dm_tree_find_node failed");
goto devmapper_out;
}
reiterate:
node_uuid = dm_tree_node_get_uuid (node);
if (! node_uuid)
{
grub_util_info ("%s has no DM uuid", path);
goto devmapper_out;
}
if (strncmp (node_uuid, "LVM-", 4) == 0)
{
grub_util_info ("%s is an LVM", path);
goto devmapper_out;
}
if (strncmp (node_uuid, "mpath-", 6) == 0)
{
/* Multipath partitions have partN-mpath-* UUIDs, and are
linear mappings so are handled by
grub_util_get_dm_node_linear_info. Multipath disks are not
linear mappings and must be handled specially. */
grub_util_info ("%s is a multipath disk", path);
goto devmapper_out;
}
if (strncmp (node_uuid, "DMRAID-", 7) != 0)
{
int major, minor;
const char *node_name;
grub_util_info ("%s is not DM-RAID", path);
if ((node_name = dm_tree_node_get_name (node))
&& grub_util_get_dm_node_linear_info (node_name,
&major, &minor, 0))
{
*is_part = 1;
if (tree)
dm_tree_free (tree);
char *ret = grub_find_device ("/dev",
(major << 8) | minor);
return ret;
}
goto devmapper_out;
}
handle = NULL;
/* Counter-intuitively, device-mapper refers to the disk-like
device containing a DM-RAID partition device as a "child" of
the partition device. */
child = dm_tree_next_child (&handle, node, 0);
if (! child)
{
grub_util_info ("%s has no DM children", path);
goto devmapper_out;
}
child_uuid = dm_tree_node_get_uuid (child);
if (! child_uuid)
{
grub_util_info ("%s child has no DM uuid", path);
goto devmapper_out;
}
else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
{
grub_util_info ("%s child is not DM-RAID", path);
goto devmapper_out;
}
child_name = dm_tree_node_get_name (child);
if (! child_name)
{
grub_util_info ("%s child has no DM name", path);
goto devmapper_out;
}
mapper_name = child_name;
*is_part = 1;
node = child;
goto reiterate;
devmapper_out:
if (! mapper_name && node)
{
/* This is a DM-RAID disk, not a partition. */
mapper_name = dm_tree_node_get_name (node);
if (! mapper_name)
grub_util_info ("%s has no DM name", path);
}
char *ret;
if (mapper_name)
ret = xasprintf ("/dev/mapper/%s", mapper_name);
else
ret = NULL;
if (tree)
dm_tree_free (tree);
return ret;
}
int
grub_util_device_is_mapped_stat (struct stat *st)
{
if (!grub_device_mapper_supported ())
return 0;
return dm_is_dm_major (major (st->st_rdev));
}
char *
grub_util_get_devmapper_grub_dev (const char *os_dev)
{
char *uuid, *optr;
char *grub_dev;
uuid = get_dm_uuid (os_dev);
if (!uuid)
return NULL;
if (strncmp (uuid, "LVM-", sizeof ("LVM-") - 1) == 0)
{
unsigned i;
int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32, 38, 42, 46, 50, 54, 58};
grub_dev = xmalloc (grub_strlen (uuid) + 40);
optr = grub_stpcpy (grub_dev, "lvmid/");
for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
{
memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
dashes[i+1] - dashes[i]);
optr += dashes[i+1] - dashes[i];
*optr++ = '-';
}
optr = stpcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i]);
*optr = '\0';
grub_dev[sizeof("lvmid/xxxxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxxxx") - 1]
= '/';
free (uuid);
return grub_dev;
}
if (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0)
{
char *dash;
dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-');
if (dash)
*dash = 0;
grub_dev = grub_xasprintf ("cryptouuid/%s",
uuid + sizeof ("CRYPT-LUKS1-") - 1);
grub_free (uuid);
return grub_dev;
}
return NULL;
}
char *
grub_util_get_vg_uuid (const char *os_dev)
{
char *uuid, *vgid;
int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32};
unsigned i;
char *optr;
uuid = get_dm_uuid (os_dev);
if (!uuid)
return NULL;
vgid = xmalloc (grub_strlen (uuid));
optr = vgid;
for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
{
memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
dashes[i+1] - dashes[i]);
optr += dashes[i+1] - dashes[i];
*optr++ = '-';
}
optr--;
*optr = '\0';
return vgid;
}
void
grub_util_devmapper_cleanup (void)
{
dm_lib_release ();
}
#else
void
grub_util_pull_devmapper (const char *os_dev __attribute__ ((unused)))
{
return;
}
int
grub_util_device_is_mapped_stat (struct stat *st __attribute__ ((unused)))
{
return 0;
}
void
grub_util_devmapper_cleanup (void)
{
}
enum grub_dev_abstraction_types
grub_util_get_dm_abstraction (const char *os_dev __attribute__ ((unused)))
{
return GRUB_DEV_ABSTRACTION_NONE;
}
char *
grub_util_get_vg_uuid (const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
char *
grub_util_devmapper_part_to_disk (struct stat *st __attribute__ ((unused)),
int *is_part __attribute__ ((unused)),
const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
char *
grub_util_get_devmapper_grub_dev (const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
#endif

355
util/getroot_freebsd.c Normal file
View file

@ -0,0 +1,355 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/types.h>
# include <sys/param.h>
# include <sys/mount.h>
# include <sys/disk.h> /* DIOCGMEDIASIZE */
# include <sys/param.h>
# include <sys/sysctl.h>
#include <libgeom.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
#include <grub/cryptodisk.h>
#include <sys/wait.h>
#include <libgeom.h>
static const char *
grub_util_get_geom_abstraction (const char *dev)
{
char *whole;
struct gmesh mesh;
struct gclass *class;
const char *name;
int err;
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return 0;
name = dev + sizeof ("/dev/") - 1;
grub_util_follow_gpart_up (name, NULL, &whole);
grub_util_info ("following geom '%s'", name);
err = geom_gettree (&mesh);
if (err != 0)
/* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
Usually left untranslated.
*/
grub_util_error ("%s", _("couldn't open geom"));
LIST_FOREACH (class, &mesh.lg_class, lg_class)
{
struct ggeom *geom;
LIST_FOREACH (geom, &class->lg_geom, lg_geom)
{
struct gprovider *provider;
LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
if (strcmp (provider->lg_name, name) == 0)
return class->lg_name;
}
}
return NULL;
}
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev)
{
const char *abstrac;
abstrac = grub_util_get_geom_abstraction (os_dev);
grub_util_info ("abstraction of %s is %s", os_dev, abstrac);
if (abstrac && grub_strcasecmp (abstrac, "eli") == 0)
return GRUB_DEV_ABSTRACTION_GELI;
/* Check for LVM. */
if (!strncmp (os_dev, LVM_DEV_MAPPER_STRING, sizeof(LVM_DEV_MAPPER_STRING)-1))
return GRUB_DEV_ABSTRACTION_LVM;
return GRUB_DEV_ABSTRACTION_NONE;
}
char *
grub_util_part_to_disk (const char *os_dev, struct stat *st,
int *is_part)
{
char *out, *out2;
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return xstrdup (os_dev);
grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
if (grub_strcmp (os_dev + sizeof ("/dev/") - 1, out) != 0)
*is_part = 1;
out2 = xasprintf ("/dev/%s", out);
free (out);
return out2;
}
int
grub_util_pull_device_os (const char *os_dev,
enum grub_dev_abstraction_types ab)
{
switch (ab)
{
case GRUB_DEV_ABSTRACTION_GELI:
{
char *whole;
struct gmesh mesh;
struct gclass *class;
const char *name;
int err;
char *lastsubdev = NULL;
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return 1;
name = os_dev + sizeof ("/dev/") - 1;
grub_util_follow_gpart_up (name, NULL, &whole);
grub_util_info ("following geom '%s'", name);
err = geom_gettree (&mesh);
if (err != 0)
/* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
Usually left untranslated.
*/
grub_util_error ("%s", _("couldn't open geom"));
LIST_FOREACH (class, &mesh.lg_class, lg_class)
{
struct ggeom *geom;
LIST_FOREACH (geom, &class->lg_geom, lg_geom)
{
struct gprovider *provider;
LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
if (strcmp (provider->lg_name, name) == 0)
{
struct gconsumer *consumer;
char *fname;
LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer)
break;
if (!consumer)
grub_util_error ("%s",
_("couldn't find geli consumer"));
fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name);
grub_util_info ("consumer %s", consumer->lg_provider->lg_name);
lastsubdev = consumer->lg_provider->lg_name;
grub_util_pull_device (fname);
free (fname);
}
}
}
if (ab == GRUB_DEV_ABSTRACTION_GELI && lastsubdev)
{
char *fname = xasprintf ("/dev/%s", lastsubdev);
char *grdev = grub_util_get_grub_dev (fname);
free (fname);
if (grdev)
{
grub_err_t gr_err;
gr_err = grub_cryptodisk_cheat_mount (grdev, os_dev);
if (gr_err)
grub_util_error (_("can't mount encrypted volume `%s': %s"),
lastsubdev, grub_errmsg);
}
grub_free (grdev);
}
}
return 1;
default:
return 0;
}
}
char *
grub_util_get_grub_dev_os (const char *os_dev)
{
char *grub_dev = NULL;
switch (grub_util_get_dev_abstraction (os_dev))
{
/* Fallback for non-devmapper build. In devmapper-builds LVM is handled
in rub_util_get_devmapper_grub_dev and this point isn't reached.
*/
case GRUB_DEV_ABSTRACTION_LVM:
{
unsigned short len;
grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
len = strlen (os_dev) - offset + 1;
grub_dev = xmalloc (len + sizeof ("lvm/"));
grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
}
break;
case GRUB_DEV_ABSTRACTION_GELI:
{
char *whole;
struct gmesh mesh;
struct gclass *class;
const char *name;
int err;
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return 0;
name = os_dev + sizeof ("/dev/") - 1;
grub_util_follow_gpart_up (name, NULL, &whole);
grub_util_info ("following geom '%s'", name);
err = geom_gettree (&mesh);
if (err != 0)
/* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
Usually left untranslated.
*/
grub_util_error ("%s", _("couldn't open geom"));
LIST_FOREACH (class, &mesh.lg_class, lg_class)
{
struct ggeom *geom;
LIST_FOREACH (geom, &class->lg_geom, lg_geom)
{
struct gprovider *provider;
LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
if (strcmp (provider->lg_name, name) == 0)
{
struct gconsumer *consumer;
char *fname;
char *uuid;
LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer)
break;
if (!consumer)
grub_util_error ("%s",
_("couldn't find geli consumer"));
fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name);
uuid = grub_util_get_geli_uuid (fname);
if (!uuid)
grub_util_error ("%s",
_("couldn't retrieve geli UUID"));
grub_dev = xasprintf ("cryptouuid/%s", uuid);
free (fname);
free (uuid);
}
}
}
}
break;
default:
break;
}
return grub_dev;
}
/* FIXME: geom actually gives us the whole container hierarchy.
It can be used more efficiently than this. */
void
grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
{
struct gmesh mesh;
struct gclass *class;
int err;
struct ggeom *geom;
grub_util_info ("following geom '%s'", name);
err = geom_gettree (&mesh);
if (err != 0)
/* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
Usually left untranslated.
*/
grub_util_error ("%s", _("couldn't open geom"));
LIST_FOREACH (class, &mesh.lg_class, lg_class)
if (strcasecmp (class->lg_name, "part") == 0)
break;
if (!class)
/* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
Usually left untranslated. "part" is the identifier of one of its
classes. */
grub_util_error ("%s", _("couldn't find geom `part' class"));
LIST_FOREACH (geom, &class->lg_geom, lg_geom)
{
struct gprovider *provider;
LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
if (strcmp (provider->lg_name, name) == 0)
{
char *name_tmp = xstrdup (geom->lg_name);
grub_disk_addr_t off = 0;
struct gconfig *config;
grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name);
grub_util_follow_gpart_up (name_tmp, &off, name_out);
free (name_tmp);
LIST_FOREACH (config, &provider->lg_config, lg_config)
if (strcasecmp (config->lg_name, "start") == 0)
off += strtoull (config->lg_val, 0, 10);
if (off_out)
*off_out = off;
return;
}
}
grub_util_info ("geom '%s' has no parent", name);
if (name_out)
*name_out = xstrdup (name);
if (off_out)
*off_out = 0;
}
grub_disk_addr_t
grub_util_find_partition_start_os (const char *dev)
{
grub_disk_addr_t out;
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return 0;
grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
return out;
}

221
util/getroot_hurd.c Normal file
View file

@ -0,0 +1,221 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/types.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
#include <sys/wait.h>
#include <hurd.h>
#include <hurd/lookup.h>
#include <hurd/fs.h>
#include <sys/mman.h>
char *
grub_util_find_hurd_root_device (const char *path)
{
file_t file;
error_t err;
char *argz = NULL, *name = NULL, *ret;
size_t argz_len = 0;
int i;
file = file_name_lookup (path, 0, 0);
if (file == MACH_PORT_NULL)
/* TRANSLATORS: The first %s is the file being looked at, the second %s is
the error message. */
grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
/* This returns catenated 0-terminated strings. */
err = file_get_fs_options (file, &argz, &argz_len);
if (err)
/* TRANSLATORS: On GNU/Hurd, a "translator" is similar to a filesystem
mount, but handled by a userland daemon, whose invocation command line
is being fetched here. First %s is the file being looked at (for which
we are fetching the "translator" command line), second %s is the error
message.
*/
grub_util_error (_("cannot get translator command line "
"for path `%s': %s"), path, strerror(err));
if (argz_len == 0)
grub_util_error (_("translator command line is empty for path `%s'"), path);
/* Make sure the string is terminated. */
argz[argz_len-1] = 0;
/* Skip first word (translator path) and options. */
for (i = strlen (argz) + 1; i < argz_len; i += strlen (argz + i) + 1)
{
if (argz[i] != '-')
{
/* Non-option. Only accept one, assumed to be the FS path. */
/* XXX: this should be replaced by an RPC to the translator. */
if (name)
/* TRANSLATORS: we expect to get something like
/hurd/foobar --option1 --option2=baz /dev/something
*/
grub_util_error (_("translator `%s' for path `%s' has several "
"non-option words, at least `%s' and `%s'"),
argz, path, name, argz + i);
name = argz + i;
}
}
if (!name)
/* TRANSLATORS: we expect to get something like
/hurd/foobar --option1 --option2=baz /dev/something
*/
grub_util_error (_("translator `%s' for path `%s' is given only options, "
"cannot find device part"), argz, path);
if (strncmp (name, "device:", sizeof ("device:") - 1) == 0)
{
char *dev_name = name + sizeof ("device:") - 1;
size_t size = sizeof ("/dev/") - 1 + strlen (dev_name) + 1;
char *next;
ret = malloc (size);
next = stpncpy (ret, "/dev/", size);
stpncpy (next, dev_name, size - (next - ret));
}
else if (!strncmp (name, "file:", sizeof ("file:") - 1))
ret = strdup (name + sizeof ("file:") - 1);
else
ret = strdup (name);
munmap (argz, argz_len);
return ret;
}
static int
is_fulldisk (const char *child, const char *parent)
{
if (strcmp (parent, child) == 0)
return 1;
if (strncmp (parent, "/dev/", sizeof ("/dev/") - 1) == 0
&& child[0] !=0 && strcmp (parent + sizeof ("/dev/") - 1, child) == 0)
return 1;
if (strncmp (child, "/dev/", sizeof ("/dev/") - 1) == 0
&& parent[0] != 0 && strcmp (child + sizeof ("/dev/") - 1, parent) == 0)
return 1;
return 0;
}
char *
grub_util_part_to_disk (const char *os_dev,
struct stat *st __attribute__ ((unused)),
int *is_part)
{
char *path;
grub_disk_addr_t offset;
char *p;
if (!grub_util_hurd_get_disk_info (os_dev, NULL, &offset, NULL, &path))
return xstrdup (os_dev);
/* Some versions of Hurd use badly glued Linux code to handle partitions
resulting in partitions being promoted to disks. */
if (path && !(offset == 0 && is_fulldisk (path, os_dev)
&& (strncmp ("/dev/sd", os_dev, 7) == 0
|| strncmp ("/dev/hd", os_dev, 7) == 0)))
{
*is_part = !is_fulldisk (path, os_dev);
if (path[0] != '/')
{
char *n = xasprintf ("/dev/%s", path);
free (path);
path = n;
}
return path;
}
free (path);
path = xstrdup (os_dev);
p = strchr (path + 7, 's');
if (p)
{
*is_part = 1;
*p = '\0';
}
return path;
}
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
{
return GRUB_DEV_ABSTRACTION_NONE;
}
int
grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
enum grub_dev_abstraction_types ab __attribute__ ((unused)))
{
return 0;
}
char *
grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
grub_disk_addr_t
grub_util_find_partition_start_os (const char *dev)
{
grub_uint32_t secsize;
grub_disk_addr_t offset;
char *path;
if (!grub_util_hurd_get_disk_info (dev, &secsize, &offset, NULL, &path))
return 0;
if (path && !(offset == 0 && is_fulldisk (path, dev)
&& (strncmp ("/dev/sd", dev, 7) == 0
|| strncmp ("/dev/hd", dev, 7) == 0)))
{
free (path);
return (secsize / 512) * offset;
}
free (path);
return -1;
}

845
util/getroot_linux.c Normal file
View file

@ -0,0 +1,845 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/types.h>
#include <sys/ioctl.h> /* ioctl */
#include <sys/mount.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
#include <sys/wait.h>
/* Defines taken from btrfs/ioctl.h. */
struct btrfs_ioctl_dev_info_args
{
grub_uint64_t devid;
grub_uint8_t uuid[16];
grub_uint64_t bytes_used;
grub_uint64_t total_bytes;
grub_uint64_t unused[379];
grub_uint8_t path[1024];
};
struct btrfs_ioctl_fs_info_args
{
grub_uint64_t max_id;
grub_uint64_t num_devices;
grub_uint8_t fsid[16];
grub_uint64_t reserved[124];
};
#define BTRFS_IOC_DEV_INFO _IOWR(0x94, 30, \
struct btrfs_ioctl_dev_info_args)
#define BTRFS_IOC_FS_INFO _IOR(0x94, 31, \
struct btrfs_ioctl_fs_info_args)
static int
grub_util_is_imsm (const char *os_dev);
#define ESCAPED_PATH_MAX (4 * PATH_MAX)
struct mountinfo_entry
{
int id;
int major, minor;
char enc_root[ESCAPED_PATH_MAX + 1], enc_path[ESCAPED_PATH_MAX + 1];
char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1];
};
/* Statting something on a btrfs filesystem always returns a virtual device
major/minor pair rather than the real underlying device, because btrfs
can span multiple underlying devices (and even if it's currently only
using a single device it can be dynamically extended onto another). We
can't deal with the multiple-device case yet, but in the meantime, we can
at least cope with the single-device case by scanning
/proc/self/mountinfo. */
static void
unescape (char *str)
{
char *optr;
const char *iptr;
for (iptr = optr = str; *iptr; optr++)
{
if (iptr[0] == '\\' && iptr[1] >= '0' && iptr[1] < '8'
&& iptr[2] >= '0' && iptr[2] < '8'
&& iptr[3] >= '0' && iptr[3] < '8')
{
*optr = (((iptr[1] - '0') << 6) | ((iptr[2] - '0') << 3)
| (iptr[3] - '0'));
iptr += 4;
}
else
*optr = *iptr++;
}
*optr = 0;
}
static char **
grub_find_root_devices_from_btrfs (const char *dir)
{
int fd;
struct btrfs_ioctl_fs_info_args fsi;
int i, j = 0;
char **ret;
fd = open (dir, 0);
if (!fd)
return NULL;
if (ioctl (fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
{
close (fd);
return NULL;
}
ret = xmalloc ((fsi.num_devices + 1) * sizeof (ret[0]));
for (i = 1; i <= fsi.max_id && j < fsi.num_devices; i++)
{
struct btrfs_ioctl_dev_info_args devi;
memset (&devi, 0, sizeof (devi));
devi.devid = i;
if (ioctl (fd, BTRFS_IOC_DEV_INFO, &devi) < 0)
{
close (fd);
free (ret);
return NULL;
}
ret[j++] = xstrdup ((char *) devi.path);
if (j >= fsi.num_devices)
break;
}
close (fd);
ret[j] = 0;
return ret;
}
char **
grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
{
FILE *fp;
char *buf = NULL;
size_t len = 0;
grub_size_t entry_len = 0, entry_max = 4;
struct mountinfo_entry *entries;
struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
int i;
if (! *dir)
dir = "/";
if (relroot)
*relroot = NULL;
fp = fopen ("/proc/self/mountinfo", "r");
if (! fp)
return NULL; /* fall through to other methods */
entries = xmalloc (entry_max * sizeof (*entries));
/* First, build a list of relevant visible mounts. */
while (getline (&buf, &len, fp) > 0)
{
struct mountinfo_entry entry;
int count;
size_t enc_path_len;
const char *sep;
if (sscanf (buf, "%d %d %u:%u %s %s%n",
&entry.id, &parent_entry.id, &entry.major, &entry.minor,
entry.enc_root, entry.enc_path, &count) < 6)
continue;
unescape (entry.enc_root);
unescape (entry.enc_path);
enc_path_len = strlen (entry.enc_path);
/* Check that enc_path is a prefix of dir. The prefix must either be
the entire string, or end with a slash, or be immediately followed
by a slash. */
if (strncmp (dir, entry.enc_path, enc_path_len) != 0 ||
(enc_path_len && dir[enc_path_len - 1] != '/' &&
dir[enc_path_len] && dir[enc_path_len] != '/'))
continue;
sep = strstr (buf + count, " - ");
if (!sep)
continue;
sep += sizeof (" - ") - 1;
if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2)
continue;
unescape (entry.device);
/* Using the mount IDs, find out where this fits in the list of
visible mount entries we've seen so far. There are three
interesting cases. Firstly, it may be inserted at the end: this is
the usual case of /foo/bar being mounted after /foo. Secondly, it
may be inserted at the start: for example, this can happen for
filesystems that are mounted before / and later moved under it.
Thirdly, it may occlude part or all of the existing filesystem
tree, in which case the end of the list needs to be pruned and this
new entry will be inserted at the end. */
if (entry_len >= entry_max)
{
entry_max <<= 1;
entries = xrealloc (entries, entry_max * sizeof (*entries));
}
if (!entry_len)
{
/* Initialise list. */
entry_len = 2;
entries[0] = parent_entry;
entries[1] = entry;
}
else
{
for (i = entry_len - 1; i >= 0; i--)
{
if (entries[i].id == parent_entry.id)
{
/* Insert at end, pruning anything previously above this. */
entry_len = i + 2;
entries[i + 1] = entry;
break;
}
else if (i == 0 && entries[i].id == entry.id)
{
/* Insert at start. */
entry_len++;
memmove (entries + 1, entries,
(entry_len - 1) * sizeof (*entries));
entries[0] = parent_entry;
entries[1] = entry;
break;
}
}
}
}
/* Now scan visible mounts for the ones we're interested in. */
for (i = entry_len - 1; i >= 0; i--)
{
char **ret = NULL;
if (!*entries[i].device)
continue;
if (grub_strcmp (entries[i].fstype, "fuse.zfs") == 0
|| grub_strcmp (entries[i].fstype, "zfs") == 0)
{
char *slash;
slash = strchr (entries[i].device, '/');
if (slash)
*slash = 0;
ret = grub_util_find_root_devices_from_poolname (entries[i].device);
if (slash)
*slash = '/';
if (relroot)
{
if (!slash)
*relroot = xasprintf ("/@%s", entries[i].enc_root);
else if (strchr (slash + 1, '@'))
*relroot = xasprintf ("/%s%s", slash + 1, entries[i].enc_root);
else
*relroot = xasprintf ("/%s@%s", slash + 1, entries[i].enc_root);
}
}
else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
{
ret = grub_find_root_devices_from_btrfs (dir);
if (relroot)
{
char *ptr;
*relroot = xmalloc (strlen (entries[i].enc_root) +
2 + strlen (dir));
ptr = grub_stpcpy (*relroot, entries[i].enc_root);
if (strlen (dir) > strlen (entries[i].enc_path))
{
while (ptr > *relroot && *(ptr - 1) == '/')
ptr--;
if (dir[strlen (entries[i].enc_path)] != '/')
*ptr++ = '/';
ptr = grub_stpcpy (ptr, dir + strlen (entries[i].enc_path));
}
*ptr = 0;
}
}
if (!ret)
{
ret = xmalloc (2 * sizeof (ret[0]));
ret[0] = strdup (entries[i].device);
ret[1] = 0;
if (relroot)
*relroot = strdup (entries[i].enc_root);
}
free (buf);
free (entries);
fclose (fp);
return ret;
}
free (buf);
free (entries);
fclose (fp);
return NULL;
}
static char *
get_mdadm_uuid (const char *os_dev)
{
char *argv[5];
int fd;
pid_t pid;
FILE *mdadm;
char *buf = NULL;
size_t len = 0;
char *name = NULL;
/* execvp has inconvenient types, hence the casts. None of these
strings will actually be modified. */
argv[0] = (char *) "mdadm";
argv[1] = (char *) "--detail";
argv[2] = (char *) "--export";
argv[3] = (char *) os_dev;
argv[4] = NULL;
pid = grub_util_exec_pipe (argv, &fd);
if (!pid)
return NULL;
/* Parent. Read mdadm's output. */
mdadm = fdopen (fd, "r");
if (! mdadm)
{
grub_util_warn (_("Unable to open stream from %s: %s"),
"mdadm", strerror (errno));
goto out;
}
while (getline (&buf, &len, mdadm) > 0)
{
if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
{
char *name_start, *ptri, *ptro;
free (name);
name_start = buf + sizeof ("MD_UUID=") - 1;
ptro = name = xmalloc (strlen (name_start) + 1);
for (ptri = name_start; *ptri && *ptri != '\n' && *ptri != '\r';
ptri++)
if ((*ptri >= '0' && *ptri <= '9')
|| (*ptri >= 'a' && *ptri <= 'f')
|| (*ptri >= 'A' && *ptri <= 'F'))
*ptro++ = *ptri;
*ptro = 0;
}
}
out:
close (fd);
waitpid (pid, NULL, 0);
free (buf);
return name;
}
static int
grub_util_is_imsm (const char *os_dev)
{
int retry;
int is_imsm = 0;
int container_seen = 0;
const char *dev = os_dev;
do
{
char *argv[5];
int fd;
pid_t pid;
FILE *mdadm;
char *buf = NULL;
size_t len = 0;
retry = 0; /* We'll do one more pass if device is part of container */
/* execvp has inconvenient types, hence the casts. None of these
strings will actually be modified. */
argv[0] = (char *) "mdadm";
argv[1] = (char *) "--detail";
argv[2] = (char *) "--export";
argv[3] = (char *) dev;
argv[4] = NULL;
pid = grub_util_exec_pipe (argv, &fd);
if (!pid)
{
if (dev != os_dev)
free ((void *) dev);
return 0;
}
/* Parent. Read mdadm's output. */
mdadm = fdopen (fd, "r");
if (! mdadm)
{
grub_util_warn (_("Unable to open stream from %s: %s"),
"mdadm", strerror (errno));
close (fd);
waitpid (pid, NULL, 0);
if (dev != os_dev)
free ((void *) dev);
return 0;
}
while (getline (&buf, &len, mdadm) > 0)
{
if (strncmp (buf, "MD_CONTAINER=", sizeof ("MD_CONTAINER=") - 1) == 0
&& !container_seen)
{
char *newdev, *ptr;
newdev = xstrdup (buf + sizeof ("MD_CONTAINER=") - 1);
ptr = newdev + strlen (newdev) - 1;
for (; ptr >= newdev && (*ptr == '\n' || *ptr == '\r'); ptr--);
ptr[1] = 0;
grub_util_info ("Container of %s is %s", dev, newdev);
dev = newdev;
container_seen = retry = 1;
break;
}
if (strncmp (buf, "MD_METADATA=imsm",
sizeof ("MD_METADATA=imsm") - 1) == 0)
{
is_imsm = 1;
grub_util_info ("%s is imsm", dev);
break;
}
}
free (buf);
close (fd);
waitpid (pid, NULL, 0);
}
while (retry);
if (dev != os_dev)
free ((void *) dev);
return is_imsm;
}
char *
grub_util_part_to_disk (const char *os_dev, struct stat *st,
int *is_part)
{
char *path = xmalloc (PATH_MAX);
if (! realpath (os_dev, path))
return NULL;
if (strncmp ("/dev/", path, 5) == 0)
{
char *p = path + 5;
/* If this is an IDE disk. */
if (strncmp ("ide/", p, 4) == 0)
{
p = strstr (p, "part");
if (p)
{
*is_part = 1;
strcpy (p, "disc");
}
return path;
}
/* If this is a SCSI disk. */
if (strncmp ("scsi/", p, 5) == 0)
{
p = strstr (p, "part");
if (p)
{
*is_part = 1;
strcpy (p, "disc");
}
return path;
}
/* If this is a DAC960 disk. */
if (strncmp ("rd/c", p, 4) == 0)
{
/* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
p = strchr (p, 'p');
if (p)
{
*is_part = 1;
*p = '\0';
}
return path;
}
/* If this is a Mylex AcceleRAID Array. */
if (strncmp ("rs/c", p, 4) == 0)
{
/* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
p = strchr (p, 'p');
if (p)
{
*is_part = 1;
*p = '\0';
}
return path;
}
/* If this is a CCISS disk. */
if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
{
/* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
p = strchr (p, 'p');
if (p)
{
*is_part = 1;
*p = '\0';
}
return path;
}
/* If this is an AOE disk. */
if (strncmp ("etherd/e", p, sizeof ("etherd/e") - 1) == 0)
{
/* /dev/etherd/e[0-9]+\.[0-9]+(p[0-9]+)? */
p = strchr (p, 'p');
if (p)
{
*is_part = 1;
*p = '\0';
}
return path;
}
/* If this is a Compaq Intelligent Drive Array. */
if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
{
/* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
p = strchr (p, 'p');
if (p)
{
*is_part = 1;
*p = '\0';
}
return path;
}
/* If this is an I2O disk. */
if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
{
/* /dev/i2o/hd[a-z]([0-9]+)? */
if (p[sizeof ("i2o/hda") - 1])
*is_part = 1;
p[sizeof ("i2o/hda") - 1] = '\0';
return path;
}
/* If this is a MultiMediaCard (MMC). */
if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
{
/* /dev/mmcblk[0-9]+(p[0-9]+)? */
p = strchr (p, 'p');
if (p)
{
*is_part = 1;
*p = '\0';
}
return path;
}
if (strncmp ("md", p, 2) == 0
&& p[2] >= '0' && p[2] <= '9')
{
char *ptr = p + 2;
while (*ptr >= '0' && *ptr <= '9')
ptr++;
if (*ptr)
*is_part = 1;
*ptr = 0;
return path;
}
if (strncmp ("nbd", p, 3) == 0
&& p[3] >= '0' && p[3] <= '9')
{
char *ptr = p + 3;
while (*ptr >= '0' && *ptr <= '9')
ptr++;
if (*ptr)
*is_part = 1;
*ptr = 0;
return path;
}
/* If this is an IDE, SCSI or Virtio disk. */
if (strncmp ("vdisk", p, 5) == 0
&& p[5] >= 'a' && p[5] <= 'z')
{
/* /dev/vdisk[a-z][0-9]* */
if (p[6])
*is_part = 1;
p[6] = '\0';
return path;
}
if ((strncmp ("hd", p, 2) == 0
|| strncmp ("vd", p, 2) == 0
|| strncmp ("sd", p, 2) == 0)
&& p[2] >= 'a' && p[2] <= 'z')
{
char *pp = p + 2;
while (*pp >= 'a' && *pp <= 'z')
pp++;
if (*pp)
*is_part = 1;
/* /dev/[hsv]d[a-z]+[0-9]* */
*pp = '\0';
return path;
}
/* If this is a Xen virtual block device. */
if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
{
char *pp = p + 3;
while (*pp >= 'a' && *pp <= 'z')
pp++;
if (*pp)
*is_part = 1;
/* /dev/xvd[a-z]+[0-9]* */
*pp = '\0';
return path;
}
}
return path;
}
char *
grub_util_get_raid_grub_dev (const char *os_dev)
{
char *grub_dev = NULL;
if (os_dev[7] == '_' && os_dev[8] == 'd')
{
/* This a partitionable RAID device of the form /dev/md_dNNpMM. */
char *p, *q;
p = strdup (os_dev + sizeof ("/dev/md_d") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/' && os_dev[8] == 'd')
{
/* This a partitionable RAID device of the form /dev/md/dNNpMM. */
char *p, *q;
p = strdup (os_dev + sizeof ("/dev/md/d") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] >= '0' && os_dev[7] <= '9')
{
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9')
{
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md/") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/')
{
/* mdraid 1.x with a free name. */
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md/") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md/%s", p);
free (p);
}
else
grub_util_error (_("unknown kind of RAID device `%s'"), os_dev);
{
char *mdadm_name = get_mdadm_uuid (os_dev);
if (mdadm_name)
{
const char *q;
for (q = os_dev + strlen (os_dev) - 1; q >= os_dev
&& grub_isdigit (*q); q--);
if (q >= os_dev && *q == 'p')
{
free (grub_dev);
grub_dev = xasprintf ("mduuid/%s,%s", mdadm_name, q + 1);
goto done;
}
free (grub_dev);
grub_dev = xasprintf ("mduuid/%s", mdadm_name);
done:
free (mdadm_name);
}
}
return grub_dev;
}
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev)
{
#ifndef HAVE_DEVICE_MAPPER
if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
return GRUB_DEV_ABSTRACTION_LVM;
#endif
/* Check for RAID. */
if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev)
&& !grub_util_is_imsm (os_dev))
return GRUB_DEV_ABSTRACTION_RAID;
return GRUB_DEV_ABSTRACTION_NONE;
}
int
grub_util_pull_device_os (const char *os_dev,
enum grub_dev_abstraction_types ab)
{
switch (ab)
{
case GRUB_DEV_ABSTRACTION_RAID:
{
char **devicelist = grub_util_raid_getmembers (os_dev, 0);
int i;
for (i = 0; devicelist[i];i++)
{
grub_util_pull_device (devicelist[i]);
free (devicelist[i]);
}
free (devicelist);
}
return 1;
default:
return 0;
}
}
char *
grub_util_get_grub_dev_os (const char *os_dev)
{
char *grub_dev = NULL;
switch (grub_util_get_dev_abstraction (os_dev))
{
/* Fallback for non-devmapper build. In devmapper-builds LVM is handled
in rub_util_get_devmapper_grub_dev and this point isn't reached.
*/
case GRUB_DEV_ABSTRACTION_LVM:
{
unsigned short len;
grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
len = strlen (os_dev) - offset + 1;
grub_dev = xmalloc (len + sizeof ("lvm/"));
grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
}
break;
case GRUB_DEV_ABSTRACTION_RAID:
grub_dev = grub_util_get_raid_grub_dev (os_dev);
break;
default: /* GRUB_DEV_ABSTRACTION_NONE */
break;
}
return grub_dev;
}

18
util/getroot_os.c Normal file
View file

@ -0,0 +1,18 @@
#ifdef __linux__
#include "getroot_linux.c"
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include "getroot_freebsd.c"
#elif defined(__NetBSD__) || defined(__OpenBSD__)
#include "getroot_bsd.c"
#elif defined(__APPLE__)
#include "getroot_apple.c"
#elif defined(__sun__)
#include "getroot_sun.c"
#elif defined(__GNU__)
#include "getroot_hurd.c"
#elif defined(__CYGWIN__)
#include "getroot_cygwin.c"
#else
# warning "No getroot OS-specific functions is available for your system. Device detection may not work properly."
#include "getroot_basic.c"
#endif

119
util/getroot_sun.c Normal file
View file

@ -0,0 +1,119 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,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 <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/types.h>
#include <grub/util/misc.h>
#include <grub/util/lvm.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
#include <sys/wait.h>
# include <sys/types.h>
# include <sys/mkdev.h>
# include <sys/dkio.h>
char *
grub_util_part_to_disk (const char *os_dev,
struct stat *st __attribute__ ((unused)),
int *is_part)
{
char *colon = grub_strrchr (os_dev, ':');
if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
&& colon)
{
char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
if (grub_strcmp (colon, ":q,raw") != 0)
*is_part = 1;
grub_memcpy (ret, os_dev, colon - os_dev);
grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
return ret;
}
else
return xstrdup (os_dev);
}
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
{
return GRUB_DEV_ABSTRACTION_NONE;
}
int
grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
enum grub_dev_abstraction_types ab __attribute__ ((unused)))
{
return 0;
}
char *
grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
{
return NULL;
}
grub_disk_addr_t
grub_util_find_partition_start_os (const char *dev)
{
int fd;
struct extpart_info pinfo;
fd = open (dev, O_RDONLY);
if (fd == -1)
{
grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
dev, strerror (errno));
return 0;
}
if (ioctl (fd, DKIOCEXTPARTINFO, &pinfo))
{
grub_error (GRUB_ERR_BAD_DEVICE,
"cannot get disk geometry of `%s'", dev);
close (fd);
return 0;
}
close (fd);
return pinfo.p_start;
}