diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:29:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:29:51 +0000 |
commit | 6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e (patch) | |
tree | 32451fa3cdd9321fb2591fada9891b2cb70a9cd1 /grub-core/osdep/freebsd | |
parent | Initial commit. (diff) | |
download | grub2-6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e.tar.xz grub2-6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e.zip |
Adding upstream version 2.06.upstream/2.06upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'grub-core/osdep/freebsd')
-rw-r--r-- | grub-core/osdep/freebsd/getroot.c | 364 | ||||
-rw-r--r-- | grub-core/osdep/freebsd/hostdisk.c | 128 |
2 files changed, 492 insertions, 0 deletions
diff --git a/grub-core/osdep/freebsd/getroot.c b/grub-core/osdep/freebsd/getroot.c new file mode 100644 index 0000000..b1e8244 --- /dev/null +++ b/grub-core/osdep/freebsd/getroot.c @@ -0,0 +1,364 @@ +/* + * 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/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> + +#define LVM_DEV_MAPPER_STRING "/dev/linux_lvm/" + +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 (! S_ISCHR (st->st_mode)) + { + *is_part = 0; + return xstrdup (os_dev); + } + + 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, "offset") == 0) + off += strtoull (config->lg_val, 0, 10) / provider->lg_sectorsize; + 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; +} diff --git a/grub-core/osdep/freebsd/hostdisk.c b/grub-core/osdep/freebsd/hostdisk.c new file mode 100644 index 0000000..6145d07 --- /dev/null +++ b/grub-core/osdep/freebsd/hostdisk.c @@ -0,0 +1,128 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,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 <grub/disk.h> +#include <grub/partition.h> +#include <grub/msdos_partition.h> +#include <grub/types.h> +#include <grub/err.h> +#include <grub/emu/misc.h> +#include <grub/emu/hostdisk.h> +#include <grub/emu/getroot.h> +#include <grub/misc.h> +#include <grub/i18n.h> +#include <grub/list.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <limits.h> + +# include <sys/disk.h> /* DIOCGMEDIASIZE */ +# include <sys/param.h> +# include <sys/sysctl.h> +# include <sys/mount.h> +# include <libgeom.h> + +grub_int64_t +grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize) +{ + unsigned long long nr; + unsigned sector_size, log_sector_size; + + if (ioctl (fd, DIOCGMEDIASIZE, &nr)) + return -1; + + if (ioctl (fd, DIOCGSECTORSIZE, §or_size)) + return -1; + if (sector_size & (sector_size - 1) || !sector_size) + return -1; + for (log_sector_size = 0; + (1 << log_sector_size) < sector_size; + log_sector_size++); + + if (log_secsize) + *log_secsize = log_sector_size; + + if (nr & (sector_size - 1)) + grub_util_error ("%s", _("unaligned device size")); + + return nr; +} + +void +grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused))) +{ +} + +grub_util_fd_t +grub_util_fd_open (const char *os_dev, int flags) +{ + grub_util_fd_t ret; + int sysctl_flags, sysctl_oldflags; + size_t sysctl_size = sizeof (sysctl_flags); + +#ifdef O_LARGEFILE + flags |= O_LARGEFILE; +#endif +#ifdef O_BINARY + flags |= O_BINARY; +#endif + + if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags, &sysctl_size, NULL, 0)) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current flags of sysctl kern.geom.debugflags"); + return GRUB_UTIL_FD_INVALID; + } + sysctl_flags = sysctl_oldflags | 0x10; + if (! (sysctl_oldflags & 0x10) + && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_flags, sysctl_size)) + { + if (errno == EPERM) + /* Running as an unprivileged user; don't worry about restoring + flags, although if we try to write to anything interesting such + as the MBR then we may fail later. */ + sysctl_oldflags = 0x10; + else + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags of sysctl kern.geom.debugflags"); + return GRUB_UTIL_FD_INVALID; + } + } + + ret = open (os_dev, flags, S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR); + + if (! (sysctl_oldflags & 0x10) + && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_oldflags, sysctl_size)) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags back to the old value for sysctl kern.geom.debugflags"); + close (ret); + return GRUB_UTIL_FD_INVALID; + } + + return ret; +} |