grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 4/4] Update grub editenv to support modifying envblk


From: Daniel Kiper
Subject: Re: [PATCH 4/4] Update grub editenv to support modifying envblk
Date: Tue, 3 Mar 2020 17:09:37 +0100
User-agent: NeoMutt/20170113 (1.7.2)

On Tue, Feb 25, 2020 at 11:26:47AM -0800, Paul Dagnelie wrote:
> This patch adds the capability for the editenv utility to modify the
> envblk, and adds ZFS-specific handlers that will be built if GRUB is
> built with libzfs support. It also adds logic that editenv uses to
> detect GRUB's (root) filesystem.
>
> One question I have related to this patch is if there is some existing
> requirement on the minimum version of ZFS being used to build GRUB; if

I do not know about any of such requirements.

> not, this code probably needs some additional checks to verify that
> the attached version of libzfs has the zpool_set_bootenv and
> zpool_get_bootenv functions.

This check should happen when configure runs.

> commit 98f854215f7e0488cbe2a639b8dde76015c26e55
> Author:     Paul Dagnelie <address@hidden>
> AuthorDate: Mon Feb 24 14:29:47 2020 -0800
> Commit:     Paul Dagnelie <address@hidden>
> CommitDate: Tue Feb 25 10:08:08 2020 -0800
>
>     Update editenv to support editing zfs envblock
> ---
>  include/grub/util/libzfs.h |   7 ++
>  util/grub-editenv.c        | 279 
> +++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 277 insertions(+), 9 deletions(-)
>
> diff --git a/include/grub/util/libzfs.h b/include/grub/util/libzfs.h
> index a02caa335..9990e8120 100644
> --- a/include/grub/util/libzfs.h
> +++ b/include/grub/util/libzfs.h
> @@ -40,6 +40,13 @@ extern int zpool_get_physpath (zpool_handle_t *,
> const char *);
>
>  extern nvlist_t *zpool_get_config (zpool_handle_t *, nvlist_t **);
>
> +extern libzfs_handle_t *zpool_get_handle(zpool_handle_t *);
> +
> +extern int zpool_set_bootenv(zpool_handle_t *, const char *);
> +extern int zpool_get_bootenv(zpool_handle_t *, char *, size_t, off_t);
> +
> +extern int libzfs_errno(libzfs_handle_t *);

Formatting is not correct for this function prototypes. Please take a
look a bit above...

>  #endif /* ! HAVE_LIBZFS_H */
>
>  libzfs_handle_t *grub_get_libzfs_handle (void);
> diff --git a/util/grub-editenv.c b/util/grub-editenv.c
> index f3662c95b..b636ed1b8 100644
> --- a/util/grub-editenv.c
> +++ b/util/grub-editenv.c
> @@ -24,7 +24,12 @@
>  #include <grub/lib/envblk.h>
>  #include <grub/i18n.h>
>  #include <grub/emu/hostfile.h>
> +#include <grub/emu/hostdisk.h>
>  #include <grub/util/install.h>
> +#include <grub/util/libzfs.h>
> +#include <grub/emu/getroot.h>
> +#include <grub/fs.h>
> +#include <grub/crypto.h>
>
>  #include <stdio.h>
>  #include <unistd.h>
> @@ -36,7 +41,6 @@
>  #pragma GCC diagnostic error "-Wmissing-prototypes"
>  #pragma GCC diagnostic error "-Wmissing-declarations"
>
> -

OK but please mention in the commit message that you are doing some
cleanups too.

>  #include "progname.h"
>
>  #define DEFAULT_ENVBLK_PATH DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG
> @@ -120,6 +124,80 @@ block, use `rm %s'."),
>    NULL, help_filter, NULL
>  };
>
> +struct fs_envblk_spec {
> +  const char *fs_name;
> +  int (*fs_read) (void *, char *, size_t, off_t);
> +  int (*fs_write) (void *, const char *);
> +  void *(*fs_init) (grub_device_t);
> +  void (*fs_fini) (void *);
> +};
> +
> +struct fs_envblk {
> +  struct fs_envblk_spec *spec;
> +  grub_fs_t fs;
> +  void *data;
> +};
> +
> +typedef struct fs_envblk_spec fs_envblk_spec_t;
> +typedef struct fs_envblk fs_envblk_t;

Both typedefs should go immediately behind relevant struct
definitions. Good example is include/grub/menu.h:grub_menu_t.

> +fs_envblk_t *fs_envblk = NULL;
> +
> +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
> +static void *
> +grub_zfs_init (grub_device_t dev)
> +{
> +  libzfs_handle_t *g_zfs = libzfs_init();
> +  int err;
> +  char *name;
> +  zpool_handle_t *zhp;
> +
> +  if (g_zfs == NULL)
> +    return NULL;
> +
> +  err = fs_envblk->fs->fs_label(dev, &name);
> +  if (err != GRUB_ERR_NONE) {
> +    libzfs_fini(g_zfs);
> +    return NULL;
> +  }
> +  zhp = zpool_open(g_zfs, name);
> +  if (zhp == NULL)
> +    {
> +      libzfs_fini(g_zfs);
> +      return NULL;
> +    }
> +  return zhp;
> +}
> +
> +static void
> +grub_zfs_fini (void *arg)
> +{
> +  zpool_handle_t *zhp = arg;
> +  libzfs_handle_t *g_zfs = zpool_get_handle(zhp);
> +  zpool_close(zhp);
> +  libzfs_fini(g_zfs);
> +}
> +
> +/* We need to convert ZFS's error returning pattern to the one we expect */
> +static int
> +grub_zfs_get_bootenv (void *arg, char *buf, size_t size, off_t offset)
> +{
> +  zpool_handle_t *zhp = arg;
> +  int error = zpool_get_bootenv (zhp, buf, size, offset);
> +  if (error != -1)
> +    return error;
> +  error = libzfs_errno(zpool_get_handle(zhp));
> +  return error;
> +}
> +#endif
> +
> +fs_envblk_spec_t fs_envblk_table[] = {
> +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
> +  { "zfs", grub_zfs_get_bootenv, zpool_set_bootenv, grub_zfs_init,
> grub_zfs_fini},
> +#endif
> +  { NULL, NULL, NULL, NULL, NULL }
> +};
> +
>  static grub_envblk_t
>  open_envblk_file (const char *name)
>  {
> @@ -164,6 +242,51 @@ open_envblk_file (const char *name)
>    return envblk;
>  }
>
> +static grub_envblk_t
> +open_envblk (const char *name)
> +{
> +  char *buf = NULL;
> +  off_t off = 0;
> +  size_t size = 1024;

Could you use a constant here?

> +  grub_envblk_t envblk;
> +
> +  if (fs_envblk == NULL)
> +    return open_envblk_file(name);
> +
> +  while (1)
> +    {
> +      int res;

s/res/rc/

...and empty line here...

> +      buf = xrealloc(buf, size);
> +      res = fs_envblk->spec->fs_read(fs_envblk->data, buf + off, size, off);
> +      if (res < 0)
> +    {
> +      grub_util_error (_("cannot read envblock: %s"), strerror (errno));
> +      free(buf);
> +      return NULL;
> +    }
> +      if (res < size)
> +    {
> +      envblk = grub_envblk_open (buf, res + off);
> +      if (! envblk)
> +        grub_util_error ("%s", _("invalid environment block"));
> +      return envblk;
> +    }
> +      off += size;
> +      size *= 2;

What is happening here?

> +    }
> +}
> +
> +static void
> +close_envblk (grub_envblk_t envblk)
> +{
> +  grub_envblk_close (envblk);
> +  if (fs_envblk != NULL)
> +    {
> +      fs_envblk->spec->fs_fini (fs_envblk->data);
> +      fs_envblk->data = NULL;
> +    }
> +}

Yeah, here is good/proper close!

> +
>  static int
>  print_var (const char *varname, const char *value,
>             void *hook_data __attribute__ ((unused)))
> @@ -177,13 +300,13 @@ list_variables (const char *name)
>  {
>    grub_envblk_t envblk;
>
> -  envblk = open_envblk_file (name);
> +  envblk = open_envblk (name);
>    grub_envblk_iterate (envblk, NULL, print_var);
> -  grub_envblk_close (envblk);
> +  close_envblk (envblk);
>  }
>
>  static void
> -write_envblk (const char *name, grub_envblk_t envblk)
> +write_envblk_file (const char *name, grub_envblk_t envblk)
>  {
>    FILE *fp;
>
> @@ -202,12 +325,37 @@ write_envblk (const char *name, grub_envblk_t envblk)
>    fclose (fp);
>  }
>
> +static void
> +write_envblk (const char *name, grub_envblk_t envblk)
> +{
> +  if (fs_envblk == NULL)
> +    return write_envblk_file(name, envblk);
> +
> +  if (fs_envblk->spec->fs_write (fs_envblk->data, grub_envblk_buffer
> (envblk)) != 0)
> +    grub_util_error (_("cannot write to envblock: %s"), strerror (errno));
> +}
> +
> +static void
> +create_envblk (const char *name)
> +{
> +  char *buf;
> +  grub_envblk_t envblk;

Empty line here...

> +  if (fs_envblk == NULL)
> +    grub_util_create_envblk_file (name);
> +  buf = xmalloc (1024);
> +  grub_util_create_envblk_buffer(buf, 1024);
> +
> +  envblk = grub_envblk_open (buf, 1024);

Please use constants instead of plain numbers.

> +  write_envblk (name, envblk);
> +  close_envblk (envblk);
> +}
> +
>  static void
>  set_variables (const char *name, int argc, char *argv[])
>  {
>    grub_envblk_t envblk;
>
> -  envblk = open_envblk_file (name);
> +  envblk = open_envblk (name);
>    while (argc)
>      {
>        char *p;
> @@ -226,7 +374,7 @@ set_variables (const char *name, int argc, char *argv[])
>      }
>
>    write_envblk (name, envblk);
> -  grub_envblk_close (envblk);
> +  close_envblk (envblk);
>  }
>
>  static void
> @@ -234,7 +382,7 @@ unset_variables (const char *name, int argc, char *argv[])
>  {
>    grub_envblk_t envblk;
>
> -  envblk = open_envblk_file (name);
> +  envblk = open_envblk (name);
>    while (argc)
>      {
>        grub_envblk_delete (envblk, argv[0]);
> @@ -244,7 +392,117 @@ unset_variables (const char *name, int argc, char 
> *argv[])
>      }
>
>    write_envblk (name, envblk);
> -  grub_envblk_close (envblk);
> +  close_envblk (envblk);
> +}
> +
> +int have_abstraction = 0;
> +static void
> +probe_abstraction (grub_disk_t disk)
> +{
> +  if (disk->partition == NULL)
> +    grub_util_info ("no partition map found for %s", disk->name);
> +
> +  if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID ||
> +      disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
> +    {
> +      have_abstraction = 1;

Could not this function return info about abstraction instead of setting
the global value?

> +    }

Curly braces are not needed here.

> + }
> +
> +static fs_envblk_t *
> +probe_fs_envblk (fs_envblk_spec_t *spec)
> +{
> +  char **grub_devices;
> +  char **curdev, **curdrive;
> +  size_t ndev = 0;
> +  char **grub_drives;
> +  grub_device_t grub_dev = NULL;
> +  grub_fs_t grub_fs;
> +  const char *fs_envblk_device;
> +
> +#ifdef __s390x__
> +  return NULL;
> +#endif

This is not nice. I think that you should use #else here too.

> +
> +  grub_util_biosdisk_init (DEFAULT_DEVICE_MAP);
> +  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 ();
> +
> +  grub_devices = grub_guess_root_devices (DEFAULT_DIRECTORY);
> +
> +  if (!grub_devices || !grub_devices[0])
> +    grub_util_error (_("cannot find a device for %s (is /dev
> mounted?)"), DEFAULT_DIRECTORY);
> +
> +  fs_envblk_device = grub_devices[0];
> +
> +  for (curdev = grub_devices; *curdev; curdev++)
> +    {
> +      grub_util_pull_device (*curdev);
> +      ndev++;
> +    }
> +
> +  grub_drives = xmalloc (sizeof (grub_drives[0]) * (ndev + 1));
> +
> +  for (curdev = grub_devices, curdrive = grub_drives; *curdev; curdev++,
> +       curdrive++)
> +    {
> +      *curdrive = grub_util_get_grub_dev (*curdev);
> +      if (! *curdrive)
> +    grub_util_error (_("cannot find a GRUB drive for %s.  Check your
> device.map"),
> +             *curdev);
> +    }
> +  *curdrive = 0;

s/0/NULL/

> +  grub_dev = grub_device_open (grub_drives[0]);
> +
> +  grub_fs = grub_fs_probe (grub_dev);
> +
> +  if (grub_dev->disk)
> +    {
> +     probe_abstraction (grub_dev->disk);
> +    }

Please drop curly braces here.

> +  for (curdrive = grub_drives + 1; *curdrive; curdrive++)
> +    {
> +      grub_device_t dev = grub_device_open (*curdrive);
> +      if (!dev)
> +    continue;
> +      if (dev->disk)
> +    probe_abstraction (dev->disk);
> +      grub_device_close (dev);
> +    }
> +
> +  free (grub_drives);
> +  grub_gcry_fini_all ();
> +  grub_fini_all ();
> +  grub_util_biosdisk_fini ();
> +
> +  fs_envblk_spec_t *p;

Please move this to the beginning of the function.

Daniel



reply via email to

[Prev in Thread] Current Thread [Next in Thread]