Le lun. 21 oct. 2024, 06:49, Michael Chang via Grub-devel <
grub-devel@gnu.org> a écrit :

> On Fri, Oct 18, 2024 at 08:39:01PM GMT, Vladimir 'phcoder' Serbinenko
> wrote:
> > Le lun. 14 oct. 2024, 20:10, Leo Sandoval <lsand...@redhat.com> a écrit
> :
> >
> > > From: Jeff Mahoney <je...@suse.com>
> > >
> > > This patch adds the ability to specify a different root on a btrfs
> > > filesystem too boot from other than the default one.
> > >
> > Does it make available some files that are currentl y unavailable? Do you
> > have an example?
>
> Say, if we want to boot snapshot "foo" via it's grub.cfg, the config can
> be written as:
>
>   menuentry "boot snapshot foo" {
>     saved_subvol=$btrfs_subvol
>     btrfs_subvol=foo
>     configfile /boot/grub/grub.cfg
>     btrfs_subvol=$saved_subvol
>   }
>
> In combination with relative path, the grub.cfg executed from foo
> snapshot is also set to use files from foo snapshots explicitly. rather
> than default or other sources.
>
It's not the question I asked

>
> Thanks,
> Michael
>
> >
> > >
> > > btrfs-list-snapshots <dev> will list the subvolumes available on the
> > > filesystem.
> > >
> > > set btrfs_subvol=<path> and set btrfs_subvolid=<subvolid> will specify
> > > which subvolume to use and any pathnames provided with either of those
> > > variables set will start using that root. If the subvolume or
> subvolume id
> > > doesn't exist, then an error case will result.
> > >
> > > It is possible to boot into a separate GRUB instance by exporting the
> > > variable and loading the config file from the subvolume.
> > >
> > > Signed-off-by: Jeff Mahoney <je...@suse.com>
> > > ---
> > >  grub-core/fs/btrfs.c | 554 +++++++++++++++++++++++++++++++++++++++++--
> > >  include/grub/btrfs.h |   1 +
> > >  2 files changed, 534 insertions(+), 21 deletions(-)
> > >
> > > diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
> > > index ba0c58352..f14fe9c1b 100644
> > > --- a/grub-core/fs/btrfs.c
> > > +++ b/grub-core/fs/btrfs.c
> > > @@ -38,6 +38,9 @@
> > >  #include <zstd.h>
> > >  #include <grub/i18n.h>
> > >  #include <grub/btrfs.h>
> > > +#include <grub/command.h>
> > > +#include <grub/env.h>
> > > +#include <grub/extcmd.h>
> > >  #include <grub/crypto.h>
> > >  #include <grub/diskfilter.h>
> > >  #include <grub/safemath.h>
> > > @@ -79,9 +82,11 @@ struct grub_btrfs_superblock
> > >    grub_uint64_t generation;
> > >    grub_uint64_t root_tree;
> > >    grub_uint64_t chunk_tree;
> > > -  grub_uint8_t dummy2[0x20];
> > > +  grub_uint8_t dummy2[0x18];
> > > +  grub_uint64_t bytes_used;
> > >    grub_uint64_t root_dir_objectid;
> > > -  grub_uint8_t dummy3[0x41];
> > > +  grub_uint64_t num_devices;
> > > +  grub_uint8_t dummy3[0x39];
> > >    struct grub_btrfs_device this_device;
> > >    char label[0x100];
> > >    grub_uint8_t dummy4[0x100];
> > > @@ -121,6 +126,7 @@ struct grub_btrfs_data
> > >    grub_uint64_t exttree;
> > >    grub_size_t extsize;
> > >    struct grub_btrfs_extent_data *extent;
> > > +  grub_uint64_t fs_tree;
> > >  };
> > >
> > >  struct grub_btrfs_chunk_item
> > > @@ -191,6 +197,14 @@ struct grub_btrfs_leaf_descriptor
> > >    } *data;
> > >  };
> > >
> > > +struct grub_btrfs_root_ref
> > > +{
> > > +  grub_uint64_t dirid;
> > > +  grub_uint64_t sequence;
> > > +  grub_uint16_t name_len;
> > > +  const char name[0];
> > > +} __attribute__ ((packed));
> > > +
> > >  struct grub_btrfs_time
> > >  {
> > >    grub_int64_t sec;
> > > @@ -236,6 +250,14 @@ struct grub_btrfs_extent_data
> > >
> > >  #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
> > >
> > > +#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL
> > > +#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL
> > > +#define GRUB_BTRFS_ROOT_REF_KEY     156
> > > +#define GRUB_BTRFS_ROOT_ITEM_KEY     132
> > > +
> > > +static grub_uint64_t btrfs_default_subvolid = 0;
> > > +static char *btrfs_default_subvol = NULL;
> > > +
> > >  static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 *
> 2,
> > >    256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
> > >  };
> > > @@ -1252,6 +1274,62 @@ grub_btrfs_read_logical (struct grub_btrfs_data
> > > *data, grub_disk_addr_t addr,
> > >    return GRUB_ERR_NONE;
> > >  }
> > >
> > > +static grub_err_t
> > > +get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
> > > +            grub_uint64_t objectid, grub_uint64_t offset,
> > > +            grub_uint64_t *fs_root);
> > > +
> > > +static grub_err_t
> > > +lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id)
> > > +{
> > > +  grub_err_t err;
> > > +  grub_uint64_t tree;
> > > +
> > > +  err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree);
> > > +  if (!err)
> > > +    data->fs_tree = tree;
> > > +  return err;
> > > +}
> > > +
> > > +static grub_err_t
> > > +find_path (struct grub_btrfs_data *data,
> > > +          const char *path, struct grub_btrfs_key *key,
> > > +          grub_uint64_t *tree, grub_uint8_t *type);
> > > +
> > > +static grub_err_t
> > > +lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
> > > +{
> > > +  grub_err_t err;
> > > +  grub_uint64_t tree = 0;
> > > +  grub_uint8_t type;
> > > +  struct grub_btrfs_key key;
> > > +
> > > +  err = find_path (data, path, &key, &tree, &type);
> > > +  if (err)
> > > +      return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate
> %s\n",
> > > path);
> > > +
> > > +  if (key.object_id != grub_cpu_to_le64_compile_time
> > > (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
> > > +    return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n",
> > > path);
> > > +
> > > +  data->fs_tree = tree;
> > > +  return GRUB_ERR_NONE;
> > > +}
> > > +
> > > +static grub_err_t
> > > +btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__
> ((unused)))
> > > +{
> > > +  if (btrfs_default_subvol)
> > > +    return lookup_root_by_name(data, btrfs_default_subvol);
> > > +
> > > +  if (btrfs_default_subvolid)
> > > +    return lookup_root_by_id(data, btrfs_default_subvolid);
> > > +
> > > +  data->fs_tree = 0;
> > > +
> > > +  return GRUB_ERR_NONE;
> > > +}
> > > +
> > > +
> > >  static struct grub_btrfs_data *
> > >  grub_btrfs_mount (grub_device_t dev)
> > >  {
> > > @@ -1287,6 +1365,13 @@ grub_btrfs_mount (grub_device_t dev)
> > >    data->devices_attached[0].dev = dev;
> > >    data->devices_attached[0].id = data->sblock.this_device.device_id;
> > >
> > > +  err = btrfs_handle_subvol (data);
> > > +  if (err)
> > > +    {
> > > +      grub_free (data);
> > > +      return NULL;
> > > +    }
> > > +
> > >    return data;
> > >  }
> > >
> > > @@ -1784,6 +1869,91 @@ get_root (struct grub_btrfs_data *data, struct
> > > grub_btrfs_key *key,
> > >    return GRUB_ERR_NONE;
> > >  }
> > >
> > > +static grub_err_t
> > > +find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid,
> > > +              grub_uint64_t fs_root, const char *name, char
> **pathname)
> > > +{
> > > +  grub_err_t err;
> > > +  struct grub_btrfs_key key = {
> > > +    .object_id = objectid,
> > > +    .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF,
> > > +    .offset = 0,
> > > +  };
> > > +  struct grub_btrfs_key key_out;
> > > +  struct grub_btrfs_leaf_descriptor desc;
> > > +  char *p = grub_strdup (name);
> > > +  grub_disk_addr_t elemaddr;
> > > +  grub_size_t elemsize;
> > > +  grub_size_t alloc = grub_strlen(name) + 1;
> > > +
> > > +  err = lower_bound(data, &key, &key_out, fs_root,
> > > +                    &elemaddr, &elemsize, &desc, 0);
> > > +  if (err)
> > > +    return grub_error(err, "lower_bound caught %d\n", err);
> > > +
> > > +  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
> > > +    next(data, &desc, &elemaddr, &elemsize, &key_out);
> > > +
> > > +  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
> > > +    {
> > > +      return grub_error(GRUB_ERR_FILE_NOT_FOUND,
> > > +                        "Can't find inode ref for {%"PRIuGRUB_UINT64_T
> > > +                        ", %u, %"PRIuGRUB_UINT64_T"}
> %"PRIuGRUB_UINT64_T
> > > +                        "/%"PRIuGRUB_SIZE"\n",
> > > +                        key_out.object_id, key_out.type,
> > > +                        key_out.offset, elemaddr, elemsize);
> > > +    }
> > > +
> > > +
> > > +  while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF &&
> > > +         key_out.object_id != key_out.offset) {
> > > +    struct grub_btrfs_inode_ref *inode_ref;
> > > +    char *new;
> > > +
> > > +    inode_ref = grub_malloc(elemsize + 1);
> > > +    if (!inode_ref)
> > > +      return grub_error(GRUB_ERR_OUT_OF_MEMORY,
> > > +                        "couldn't allocate memory for inode_ref
> > > (%"PRIuGRUB_SIZE")\n", elemsize);
> > > +
> > > +    err = grub_btrfs_read_logical(data, elemaddr, inode_ref,
> elemsize, 0);
> > > +    if (err)
> > > +      return grub_error(err, "read_logical caught %d\n", err);
> > > +
> > > +    alloc += grub_le_to_cpu16 (inode_ref->n) + 2;
> > > +    new = grub_malloc(alloc);
> > > +    if (!new)
> > > +      return grub_error(GRUB_ERR_OUT_OF_MEMORY,
> > > +                        "couldn't allocate memory for name
> > > (%"PRIuGRUB_SIZE")\n", alloc);
> > > +
> > > +    grub_memcpy(new, inode_ref->name, grub_le_to_cpu16
> (inode_ref->n));
> > > +    if (p)
> > > +      {
> > > +        new[grub_le_to_cpu16 (inode_ref->n)] = '/';
> > > +        grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p);
> > > +        grub_free(p);
> > > +      }
> > > +    else
> > > +      new[grub_le_to_cpu16 (inode_ref->n)] = 0;
> > > +    grub_free(inode_ref);
> > > +
> > > +    p = new;
> > > +
> > > +    key.object_id = key_out.offset;
> > > +
> > > +    err = lower_bound(data, &key, &key_out, fs_root, &elemaddr,
> > > +                      &elemsize, &desc, 0);
> > > +    if (err)
> > > +      return grub_error(err, "lower_bound caught %d\n", err);
> > > +
> > > +    if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
> > > +      next(data, &desc, &elemaddr, &elemsize, &key_out);
> > > +
> > > +  }
> > > +
> > > +  *pathname = p;
> > > +  return 0;
> > > +}
> > > +
> > >  static grub_err_t
> > >  find_path (struct grub_btrfs_data *data,
> > >            const char *path, struct grub_btrfs_key *key,
> > > @@ -1802,14 +1972,26 @@ find_path (struct grub_btrfs_data *data,
> > >    char *origpath = NULL;
> > >    unsigned symlinks_max = 32;
> > >
> > > -  err = get_root (data, key, tree, type);
> > > -  if (err)
> > > -    return err;
> > > -
> > >    origpath = grub_strdup (path);
> > >    if (!origpath)
> > >      return grub_errno;
> > >
> > > +  if (data->fs_tree)
> > > +    {
> > > +      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
> > > +      *tree = data->fs_tree;
> > > +      /* This is a tree root, so everything starts at objectid 256 */
> > > +      key->object_id = grub_cpu_to_le64_compile_time
> > > (GRUB_BTRFS_OBJECT_ID_CHUNK);
> > > +      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
> > > +      key->offset = 0;
> > > +    }
> > > +  else
> > > +    {
> > > +      err = get_root (data, key, tree, type);
> > > +      if (err)
> > > +       return err;
> > > +    }
> > > +
> > >    while (1)
> > >      {
> > >        while (path[0] == '/')
> > > @@ -1982,13 +2164,25 @@ find_path (struct grub_btrfs_data *data,
> > >           path = path_alloc = tmp;
> > >           if (path[0] == '/')
> > >             {
> > > -             err = get_root (data, key, tree, type);
> > > -             if (err)
> > > +             if (data->fs_tree)
> > > +               {
> > > +                 *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
> > > +                 *tree = data->fs_tree;
> > > +                 /* This is a tree root, so everything starts at
> objectid
> > > 256 */
> > > +                 key->object_id = grub_cpu_to_le64_compile_time
> > > (GRUB_BTRFS_OBJECT_ID_CHUNK);
> > > +                 key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
> > > +                 key->offset = 0;
> > > +               }
> > > +             else
> > >                 {
> > > -                 grub_free (direl);
> > > -                 grub_free (path_alloc);
> > > -                 grub_free (origpath);
> > > -                 return err;
> > > +                 err = get_root (data, key, tree, type);
> > > +                 if (err)
> > > +                    {
> > > +                      grub_free (direl);
> > > +                      grub_free (path_alloc);
> > > +                      grub_free (origpath);
> > > +                      return err;
> > > +                    }
> > >                 }
> > >             }
> > >           continue;
> > > @@ -2256,6 +2450,20 @@ grub_btrfs_read (grub_file_t file, char *buf,
> > > grub_size_t len)
> > >                                  data->tree, file->offset, buf, len);
> > >  }
> > >
> > > +static char *
> > > +btrfs_unparse_uuid(struct grub_btrfs_data *data)
> > > +{
> > > +  return  grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
> > > +                         grub_be_to_cpu16 (data->sblock.uuid[0]),
> > > +                         grub_be_to_cpu16 (data->sblock.uuid[1]),
> > > +                         grub_be_to_cpu16 (data->sblock.uuid[2]),
> > > +                         grub_be_to_cpu16 (data->sblock.uuid[3]),
> > > +                         grub_be_to_cpu16 (data->sblock.uuid[4]),
> > > +                         grub_be_to_cpu16 (data->sblock.uuid[5]),
> > > +                         grub_be_to_cpu16 (data->sblock.uuid[6]),
> > > +                         grub_be_to_cpu16 (data->sblock.uuid[7]));
> > > +}
> > > +
> > >  static grub_err_t
> > >  grub_btrfs_uuid (grub_device_t device, char **uuid)
> > >  {
> > > @@ -2267,15 +2475,7 @@ grub_btrfs_uuid (grub_device_t device, char
> **uuid)
> > >    if (!data)
> > >      return grub_errno;
> > >
> > > -  *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
> > > -                         grub_be_to_cpu16 (data->sblock.uuid[0]),
> > > -                         grub_be_to_cpu16 (data->sblock.uuid[1]),
> > > -                         grub_be_to_cpu16 (data->sblock.uuid[2]),
> > > -                         grub_be_to_cpu16 (data->sblock.uuid[3]),
> > > -                         grub_be_to_cpu16 (data->sblock.uuid[4]),
> > > -                         grub_be_to_cpu16 (data->sblock.uuid[5]),
> > > -                         grub_be_to_cpu16 (data->sblock.uuid[6]),
> > > -                         grub_be_to_cpu16 (data->sblock.uuid[7]));
> > > +  *uuid = btrfs_unparse_uuid(data);
> > >
> > >    grub_btrfs_unmount (data);
> > >
> > > @@ -2396,6 +2596,242 @@ grub_btrfs_embed (grub_device_t device
> > > __attribute__ ((unused)),
> > >  }
> > >  #endif
> > >
> > > +static grub_err_t
> > > +grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int
> > > argc,
> > > +                    char **argv)
> > > +{
> > > +  grub_device_t dev;
> > > +  char *devname;
> > > +  struct grub_btrfs_data *data;
> > > +  char *uuid;
> > > +
> > > +  if (argc < 1)
> > > +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
> > > +
> > > +  devname = grub_file_get_device_name(argv[0]);
> > > +
> > > +  if (!devname)
> > > +    return grub_errno;
> > > +
> > > +  dev = grub_device_open (devname);
> > > +  grub_free (devname);
> > > +  if (!dev)
> > > +    return grub_errno;
> > > +
> > > +  data = grub_btrfs_mount (dev);
> > > +  if (!data)
> > > +    {
> > > +      grub_device_close(dev);
> > > +      return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs");
> > > +    }
> > > +
> > > +  if (data->sblock.label)
> > > +    grub_printf("Label: '%s' ", data->sblock.label);
> > > +  else
> > > +    grub_printf("Label: none ");
> > > +
> > > +  uuid = btrfs_unparse_uuid(data);
> > > +
> > > +  grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T
> > > +              " FS bytes used %" PRIuGRUB_UINT64_T "\n",
> > > +             uuid, grub_cpu_to_le64(data->sblock.num_devices),
> > > +             grub_cpu_to_le64(data->sblock.bytes_used));
> > > +
> > > +  grub_btrfs_unmount (data);
> > > +
> > > +  return 0;
> > > +}
> > > +
> > > +static grub_err_t
> > > +get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
> > > +            grub_uint64_t objectid, grub_uint64_t offset,
> > > +            grub_uint64_t *fs_root)
> > > +{
> > > +  grub_err_t err;
> > > +  struct grub_btrfs_key key_in = {
> > > +    .object_id = objectid,
> > > +    .type = GRUB_BTRFS_ROOT_ITEM_KEY,
> > > +    .offset = offset,
> > > +  }, key_out;
> > > +  struct grub_btrfs_leaf_descriptor desc;
> > > +  grub_disk_addr_t elemaddr;
> > > +  grub_size_t elemsize;
> > > +  struct grub_btrfs_root_item ri;
> > > +
> > > +  err = lower_bound(data, &key_in, &key_out, tree,
> > > +                    &elemaddr, &elemsize, &desc, 0);
> > > +
> > > +  if (err)
> > > +    return err;
> > > +
> > > +  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0)
> > > +    return grub_error(GRUB_ERR_FILE_NOT_FOUND,
> > > +                    N_("can't find fs root for subvol
> > > %"PRIuGRUB_UINT64_T"\n"),
> > > +                    key_in.object_id);
> > > +
> > > +  err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0);
> > > +  if (err)
> > > +    return err;
> > > +
> > > +  *fs_root = ri.tree;
> > > +
> > > +  return GRUB_ERR_NONE;
> > > +}
> > > +
> > > +static const struct grub_arg_option options[] = {
> > > +  {"output", 'o', 0, N_("Output to a variable instead of the
> console."),
> > > +   N_("VARNAME"), ARG_TYPE_STRING},
> > > +  {"path-only", 'p', 0, N_("Show only the path of the subvolume."),
> 0, 0},
> > > +  {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0},
> > > +  {0, 0, 0, 0, 0, 0}
> > > +};
> > > +
> > > +static grub_err_t
> > > +grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt,
> > > +                            int argc, char **argv)
> > > +{
> > > +  struct grub_btrfs_data *data;
> > > +  grub_device_t dev;
> > > +  char *devname;
> > > +  grub_uint64_t tree;
> > > +  struct grub_btrfs_key key_in = {
> > > +    .object_id = grub_cpu_to_le64_compile_time
> > > (GRUB_BTRFS_FS_TREE_OBJECTID),
> > > +    .type = GRUB_BTRFS_ROOT_REF_KEY,
> > > +    .offset = 0,
> > > +  }, key_out;
> > > +  struct grub_btrfs_leaf_descriptor desc;
> > > +  grub_disk_addr_t elemaddr;
> > > +  grub_uint64_t fs_root = 0;
> > > +  grub_size_t elemsize;
> > > +  grub_size_t allocated = 0;
> > > +  int r = 0;
> > > +  grub_err_t err;
> > > +  char *buf = NULL;
> > > +  int print = 1;
> > > +  int path_only = ctxt->state[1].set;
> > > +  int num_only = ctxt->state[2].set;
> > > +  char *varname = NULL;
> > > +  char *output = NULL;
> > > +
> > > +  if (ctxt->state[0].set) {
> > > +    varname = ctxt->state[0].arg;
> > > +    print = 0;
> > > +  }
> > > +
> > > +  if (argc < 1)
> > > +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
> > > +
> > > +  devname = grub_file_get_device_name(argv[0]);
> > > +  if (!devname)
> > > +    return grub_errno;
> > > +
> > > +  dev = grub_device_open (devname);
> > > +  grub_free (devname);
> > > +  if (!dev)
> > > +    return grub_errno;
> > > +
> > > +  data = grub_btrfs_mount(dev);
> > > +  if (!data)
> > > +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open
> device");
> > > +
> > > +  tree = data->sblock.root_tree;
> > > +  err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time
> > > (GRUB_BTRFS_FS_TREE_OBJECTID),
> > > +                    0, &fs_root);
> > > +  if (err)
> > > +    goto out;
> > > +
> > > +  err = lower_bound(data, &key_in, &key_out, tree,
> > > +                    &elemaddr, &elemsize, &desc, 0);
> > > +
> > > +  if (err)
> > > +    {
> > > +      grub_btrfs_unmount(data);
> > > +      return err;
> > > +    }
> > > +
> > > +  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0)
> > > +    {
> > > +      r = next(data, &desc, &elemaddr, &elemsize, &key_out);
> > > +    }
> > > +
> > > +  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) {
> > > +    err = GRUB_ERR_FILE_NOT_FOUND;
> > > +    grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs"));
> > > +    goto out;
> > > +  }
> > > +
> > > +  do
> > > +    {
> > > +      struct grub_btrfs_root_ref *ref;
> > > +      char *p = NULL;
> > > +
> > > +      if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF)
> > > +        {
> > > +          r = 0;
> > > +          break;
> > > +        }
> > > +
> > > +      if (elemsize > allocated)
> > > +        {
> > > +          grub_free(buf);
> > > +          allocated = 2 * elemsize;
> > > +          buf = grub_malloc(allocated + 1);
> > > +          if (!buf)
> > > +            {
> > > +              r = -grub_errno;
> > > +              break;
> > > +            }
> > > +        }
> > > +      ref = (struct grub_btrfs_root_ref *)buf;
> > > +
> > > +      err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0);
> > > +      if (err)
> > > +        {
> > > +          r = -err;
> > > +          break;
> > > +        }
> > > +        buf[elemsize] = 0;
> > > +
> > > +      find_pathname(data, ref->dirid, fs_root, ref->name, &p);
> > > +
> > > +      if (print)
> > > +        {
> > > +          if (num_only)
> > > +            grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset);
> > > +          else if (path_only)
> > > +            grub_printf("%s\n", p);
> > > +          else
> > > +            grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n",
> > > key_out.offset, p);
> > > +        } else {
> > > +          char *old = output;
> > > +          if (num_only)
> > > +            output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n",
> > > +                                    old ?: "", key_out.offset);
> > > +          else if (path_only)
> > > +            output = grub_xasprintf("%s%s\n", old ?: "", p);
> > > +          else
> > > +            output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path
> %s\n",
> > > +                                    old ?: "", key_out.offset, p);
> > > +
> > > +          if (old)
> > > +            grub_free(old);
> > > +        }
> > > +
> > > +      r = next(data, &desc, &elemaddr, &elemsize, &key_out);
> > > +  } while(r > 0);
> > > +
> > > +  if (output)
> > > +    grub_env_set(varname, output);
> > > +
> > > +out:
> > > +  free_iterator(&desc);
> > > +  grub_btrfs_unmount(data);
> > > +
> > > +  grub_device_close (dev);
> > > +
> > > +  return 0;
> > > +}
> > > +
> > >  static struct grub_fs grub_btrfs_fs = {
> > >    .name = "btrfs",
> > >    .fs_dir = grub_btrfs_dir,
> > > @@ -2411,12 +2847,88 @@ static struct grub_fs grub_btrfs_fs = {
> > >  #endif
> > >  };
> > >
> > > +static grub_command_t cmd_info;
> > > +static grub_extcmd_t cmd_list_subvols;
> > > +
> > > +static char *
> > > +subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)),
> > > +                  const char *val)
> > > +{
> > > +  unsigned long long result = 0;
> > > +
> > > +  grub_errno = GRUB_ERR_NONE;
> > > +  if (*val)
> > > +    {
> > > +      result = grub_strtoull(val, NULL, 10);
> > > +      if (grub_errno)
> > > +        return NULL;
> > > +    }
> > > +
> > > +  grub_free (btrfs_default_subvol);
> > > +  btrfs_default_subvol = NULL;
> > > +  btrfs_default_subvolid = result;
> > > +  return grub_strdup(val);
> > > +}
> > > +
> > > +static const char *
> > > +subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)),
> > > +                  const char *val __attribute__ ((unused)))
> > > +{
> > > +  if (btrfs_default_subvol)
> > > +    return grub_xasprintf("subvol:%s", btrfs_default_subvol);
> > > +  else if (btrfs_default_subvolid)
> > > +    return grub_xasprintf("%"PRIuGRUB_UINT64_T,
> btrfs_default_subvolid);
> > > +  else
> > > +    return "";
> > > +}
> > > +
> > > +static char *
> > > +subvol_set_env (struct grub_env_var *var __attribute__ ((unused)),
> > > +                const char *val)
> > > +{
> > > +  grub_free (btrfs_default_subvol);
> > > +  btrfs_default_subvol = grub_strdup (val);
> > > +  btrfs_default_subvolid = 0;
> > > +  return grub_strdup(val);
> > > +}
> > > +
> > > +static const char *
> > > +subvol_get_env (struct grub_env_var *var __attribute__ ((unused)),
> > > +                const char *val __attribute__ ((unused)))
> > > +{
> > > +  if (btrfs_default_subvol)
> > > +    return btrfs_default_subvol;
> > > +  else if (btrfs_default_subvolid)
> > > +    return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T,
> > > +                          btrfs_default_subvolid);
> > > +  else
> > > +    return "";
> > > +}
> > > +
> > >  GRUB_MOD_INIT (btrfs)
> > >  {
> > >    grub_fs_register (&grub_btrfs_fs);
> > > +  cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
> > > +                                  "DEVICE",
> > > +                                  "Print BtrFS info about DEVICE.");
> > > +  cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols",
> > > +                                        grub_cmd_btrfs_list_subvols,
> 0,
> > > +                                        "[-p|-n] [-o var] DEVICE",
> > > +                                        "Print list of BtrFS
> subvolumes
> > > on "
> > > +                                        "DEVICE.", options);
> > > +  grub_register_variable_hook ("btrfs_subvol", subvol_get_env,
> > > +                               subvol_set_env);
> > > +  grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
> > > +                               subvolid_set_env);
> > >  }
> > >
> > >  GRUB_MOD_FINI (btrfs)
> > >  {
> > > +  grub_register_variable_hook ("btrfs_subvol", NULL, NULL);
> > > +  grub_register_variable_hook ("btrfs_subvolid", NULL, NULL);
> > > +  grub_unregister_command (cmd_info);
> > > +  grub_unregister_extcmd (cmd_list_subvols);
> > >    grub_fs_unregister (&grub_btrfs_fs);
> > >  }
> > > +
> > > +// vim: si et sw=2:
> > > diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h
> > > index 9d93fb6c1..234ad9767 100644
> > > --- a/include/grub/btrfs.h
> > > +++ b/include/grub/btrfs.h
> > > @@ -29,6 +29,7 @@ enum
> > >      GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84,
> > >      GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90,
> > >      GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8,
> > > +    GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c,
> > >      GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4
> > >    };
> > >
> > > --
> > > 2.46.2
> > >
> > >
> > > _______________________________________________
> > > Grub-devel mailing list
> > > Grub-devel@gnu.org
> > > https://lists.gnu.org/mailman/listinfo/grub-devel
> > >
>
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > https://lists.gnu.org/mailman/listinfo/grub-devel
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to