bectl(3)/libbe(3): Allow BE root to be specified
Add an undocumented -r option preceding the bectl subcommand to specify a BE root to operate out of. This will remain undocumented for now, as some caveats apply: - BEs cannot be activated in the pool that doesn't contain the rootfs - bectl create cannot work out of the box without the -e option right now, since it defaults to the rootfs and cross-pool cloning doesn't work like that (IIRC) Plumb the BE root through to libbe(3) so that some things -can- be done to it, e.g. bectl -r tank/ROOT create -e default upgrade bectl -r tank/ROOT mount upgrade /mnt this aides in some upgrade setups where rootfs is not necessarily ZFS, and also makes it easier/possible to regression-test bectl when combined with a file-backed zpool. MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D18029
This commit is contained in:
parent
59c7844347
commit
259052139d
@ -74,7 +74,7 @@ be_locate_rootfs(libbe_handle_t *lbh)
|
||||
* dataset, for example, zroot/ROOT.
|
||||
*/
|
||||
libbe_handle_t *
|
||||
libbe_init(void)
|
||||
libbe_init(const char *root)
|
||||
{
|
||||
libbe_handle_t *lbh;
|
||||
char *poolname, *pos;
|
||||
@ -89,16 +89,21 @@ libbe_init(void)
|
||||
if ((lbh->lzh = libzfs_init()) == NULL)
|
||||
goto err;
|
||||
|
||||
/* Grab rootfs, we'll work backwards from there */
|
||||
/*
|
||||
* Grab rootfs, we'll work backwards from there if an optional BE root
|
||||
* has not been passed in.
|
||||
*/
|
||||
if (be_locate_rootfs(lbh) != 0)
|
||||
goto err;
|
||||
|
||||
/* Strip off the final slash from the rootfs to get the be root */
|
||||
strlcpy(lbh->root, lbh->rootfs, sizeof(lbh->root));
|
||||
pos = strrchr(lbh->root, '/');
|
||||
if (pos == NULL)
|
||||
goto err;
|
||||
*pos = '\0';
|
||||
if (root == NULL) {
|
||||
/* Strip off the final slash from rootfs to get the be root */
|
||||
strlcpy(lbh->root, lbh->rootfs, sizeof(lbh->root));
|
||||
pos = strrchr(lbh->root, '/');
|
||||
if (pos == NULL)
|
||||
goto err;
|
||||
*pos = '\0';
|
||||
} else
|
||||
strlcpy(lbh->root, root, sizeof(lbh->root));
|
||||
|
||||
if ((pos = strchr(lbh->root, '/')) == NULL)
|
||||
goto err;
|
||||
|
@ -63,7 +63,7 @@ typedef enum be_error {
|
||||
|
||||
|
||||
/* Library handling functions: be.c */
|
||||
libbe_handle_t *libbe_init(void);
|
||||
libbe_handle_t *libbe_init(const char *root);
|
||||
void libbe_close(libbe_handle_t *);
|
||||
|
||||
/* Bootenv information functions: be_info.c */
|
||||
|
@ -42,7 +42,10 @@ const char *
|
||||
be_active_name(libbe_handle_t *lbh)
|
||||
{
|
||||
|
||||
return (strrchr(lbh->rootfs, '/') + sizeof(char));
|
||||
if (*lbh->rootfs != '\0')
|
||||
return (strrchr(lbh->rootfs, '/') + sizeof(char));
|
||||
else
|
||||
return (lbh->rootfs);
|
||||
}
|
||||
|
||||
|
||||
@ -63,7 +66,10 @@ const char *
|
||||
be_nextboot_name(libbe_handle_t *lbh)
|
||||
{
|
||||
|
||||
return (strrchr(lbh->bootfs, '/') + sizeof(char));
|
||||
if (*lbh->bootfs != '\0')
|
||||
return (strrchr(lbh->bootfs, '/') + sizeof(char));
|
||||
else
|
||||
return (lbh->bootfs);
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 31, 2018
|
||||
.Dd November 17, 2018
|
||||
.Dt LIBBE 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -39,7 +39,7 @@
|
||||
.Sh SYNOPSIS
|
||||
.In be.h
|
||||
.Ft "libbe_handle_t *hdl" Ns
|
||||
.Fn libbe_init void
|
||||
.Fn libbe_init "const char *be_root"
|
||||
.Pp
|
||||
.Ft void
|
||||
.Fn libbe_close "libbe_handle_t *hdl"
|
||||
@ -157,13 +157,16 @@ errno otherwise as described in
|
||||
.Pp
|
||||
The
|
||||
.Fn libbe_init
|
||||
function initializes
|
||||
function takes an optional BE root and initializes
|
||||
.Nm ,
|
||||
returning a
|
||||
.Vt "libbe_handle_t *"
|
||||
on success, or
|
||||
.Dv NULL
|
||||
on error.
|
||||
If a BE root is supplied,
|
||||
.Nm
|
||||
will only operate out of that pool and BE root.
|
||||
An error may occur if:
|
||||
.Bl -column
|
||||
.It /boot and / are not on the same filesystem and device,
|
||||
@ -184,11 +187,15 @@ invalidating the handle in the process.
|
||||
.Pp
|
||||
The
|
||||
.Fn be_active_name
|
||||
function returns the name of the currently booted boot environment,
|
||||
function returns the name of the currently booted boot environment.
|
||||
This boot environment may not belong to the same BE root as the root libbe
|
||||
is operating on!
|
||||
.Pp
|
||||
The
|
||||
.Fn be_active_path
|
||||
function returns the full path of the currently booted boot environment.
|
||||
This boot environment may not belong to the same BE root as the root libbe
|
||||
is operating on!
|
||||
.Pp
|
||||
The
|
||||
.Fn be_nextboot_name
|
||||
|
@ -489,12 +489,25 @@ int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *command;
|
||||
char *root;
|
||||
int command_index, rc;
|
||||
|
||||
root = NULL;
|
||||
if (argc < 2)
|
||||
return (usage(false));
|
||||
|
||||
command = argv[1];
|
||||
if (strcmp(argv[1], "-r") == 0) {
|
||||
if (argc < 4)
|
||||
return (usage(false));
|
||||
root = strdup(argv[2]);
|
||||
command = argv[3];
|
||||
argc -= 3;
|
||||
argv += 3;
|
||||
} else {
|
||||
command = argv[1];
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
}
|
||||
|
||||
/* Handle command aliases */
|
||||
if (strcmp(command, "umount") == 0)
|
||||
@ -512,13 +525,12 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
if ((be = libbe_init()) == NULL)
|
||||
if ((be = libbe_init(root)) == NULL)
|
||||
return (-1);
|
||||
|
||||
libbe_print_on_error(be, true);
|
||||
|
||||
/* XXX TODO: can be simplified if offset by 2 instead of one */
|
||||
rc = command_map[command_index].fn(argc-1, argv+1);
|
||||
rc = command_map[command_index].fn(argc, argv);
|
||||
|
||||
libbe_close(be);
|
||||
return (rc);
|
||||
|
Loading…
Reference in New Issue
Block a user