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