index | | raw e-mail
bectl: log modifying functions to zpool history
Modeled directly after the method used by the zfs/zpool commands: flag
commands with a "please log me" flag, and when there, reconstruct the
command line. On success, call the library function to add it to the
log.
(Majority of the change by Rob; minor edits by kevans@)
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Co-authored-by: Kyle Evans <kevans@FreeBSD.org>
Sponsored by: Modirum MDPay
Sponsored by: Klara, Inc.
---
lib/libbe/be.c | 12 +++++++++
lib/libbe/be.h | 2 ++
lib/libbe/libbe.3 | 16 ++++++++++--
sbin/bectl/bectl.c | 73 ++++++++++++++++++++++++++++++++++++++++++------------
4 files changed, 85 insertions(+), 18 deletions(-)
diff --git a/lib/libbe/be.c b/lib/libbe/be.c
index 613235d5e908..4a7c2e43b2c1 100644
--- a/lib/libbe/be.c
+++ b/lib/libbe/be.c
@@ -1343,3 +1343,15 @@ be_activate(libbe_handle_t *lbh, const char *bootenv, bool temporary)
return (BE_ERR_SUCCESS);
}
+
+int
+be_log_history(libbe_handle_t *lbh, const char *message)
+{
+ int err;
+
+ err = zpool_log_history(lbh->lzh, message);
+ if (err)
+ return (set_error(lbh, BE_ERR_UNKNOWN));
+
+ return (BE_ERR_SUCCESS);
+}
diff --git a/lib/libbe/be.h b/lib/libbe/be.h
index 01ee94fd03ca..d3f47c0604fe 100644
--- a/lib/libbe/be.h
+++ b/lib/libbe/be.h
@@ -107,6 +107,8 @@ int be_exists(libbe_handle_t *, const char *);
int be_export(libbe_handle_t *, const char *, int fd);
int be_import(libbe_handle_t *, const char *, int fd);
+int be_log_history(libbe_handle_t *, const char *);
+
#if SOON
int be_add_child(libbe_handle_t *, const char *, bool);
#endif
diff --git a/lib/libbe/libbe.3 b/lib/libbe/libbe.3
index 3b10711dd0f9..4331713e9227 100644
--- a/lib/libbe/libbe.3
+++ b/lib/libbe/libbe.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 20, 2025
+.Dd December 11, 2025
.Dt LIBBE 3
.Os
.Sh NAME
@@ -144,6 +144,9 @@
.Pp
.Ft void
.Fn be_prop_list_free "nvlist_t *prop_list"
+.Pp
+.Ft int
+.Fn be_log_history "libbe_handle_t *hdl" "const char *message"
.Sh DESCRIPTION
.Nm
interfaces with libzfs to provide a set of functions for various operations
@@ -536,6 +539,14 @@ exactly as specified by
The
.Fn be_prop_list_free
function will free the property list.
+.Pp
+The
+.Fn be_log_history
+function will log the given
+.Fa message
+to the zpool history, which can be later retrieved using the
+.Xr zpool-history 8
+command.
.Sh DIAGNOSTICS
Upon error, one of the following values will be returned:
.Bl -bullet -offset indent -compact
@@ -583,7 +594,8 @@ BE_ERR_UNKNOWN
BE_ERR_INVORIGIN
.El
.Sh SEE ALSO
-.Xr bectl 8
+.Xr bectl 8 ,
+.Xr zpool-history 8
.Sh HISTORY
.Xr bectl 8
and
diff --git a/sbin/bectl/bectl.c b/sbin/bectl/bectl.c
index 95715b34336b..28483dae17b2 100644
--- a/sbin/bectl/bectl.c
+++ b/sbin/bectl/bectl.c
@@ -6,6 +6,7 @@
#include <sys/param.h>
#include <sys/mount.h>
+#include <err.h>
#include <errno.h>
#include <libutil.h>
#include <stdbool.h>
@@ -76,27 +77,28 @@ struct command_map_entry {
int (*fn)(int argc, char *argv[]);
/* True if libbe_print_on_error should be disabled */
bool silent;
+ bool save_history;
};
static struct command_map_entry command_map[] =
{
- { "activate", bectl_cmd_activate,false },
- { "create", bectl_cmd_create, false },
- { "destroy", bectl_cmd_destroy, false },
- { "export", bectl_cmd_export, false },
- { "import", bectl_cmd_import, false },
+ { "activate", bectl_cmd_activate,false, true },
+ { "create", bectl_cmd_create, false, true },
+ { "destroy", bectl_cmd_destroy, false, true },
+ { "export", bectl_cmd_export, false, true },
+ { "import", bectl_cmd_import, false, true },
#if SOON
- { "add", bectl_cmd_add, false },
+ { "add", bectl_cmd_add, false, true },
#endif
- { "jail", bectl_cmd_jail, false },
- { "list", bectl_cmd_list, false },
- { "mount", bectl_cmd_mount, false },
- { "rename", bectl_cmd_rename, false },
- { "unjail", bectl_cmd_unjail, false },
- { "ujail", bectl_cmd_unjail, false },
- { "unmount", bectl_cmd_unmount, false },
- { "umount", bectl_cmd_unmount, false },
- { "check", bectl_cmd_check, true },
+ { "jail", bectl_cmd_jail, false, false },
+ { "list", bectl_cmd_list, false, false },
+ { "mount", bectl_cmd_mount, false, false },
+ { "rename", bectl_cmd_rename, false, true },
+ { "unjail", bectl_cmd_unjail, false, false },
+ { "ujail", bectl_cmd_unjail, false, false },
+ { "unmount", bectl_cmd_unmount, false, false },
+ { "umount", bectl_cmd_unmount, false, false },
+ { "check", bectl_cmd_check, true, false },
};
static struct command_map_entry *
@@ -523,12 +525,42 @@ bectl_cmd_check(int argc, char *argv[] __unused)
return (0);
}
+static char *
+save_cmdline(int argc, char *argv[])
+{
+ char *cmdline, *basename, *p;
+ int len, n, i;
+
+ len = MAXPATHLEN * 2 + 1; /* HIS_MAX_RECORD_LEN from zfs.h */
+ cmdline = p = malloc(len);
+ if (cmdline == NULL)
+ err(2, "malloc");
+
+ basename = strrchr(argv[0], '/');
+ if (basename == NULL)
+ basename = argv[0];
+ else
+ basename++;
+
+ n = strlcpy(p, basename, len);
+ for (i = 1; i < argc; i++) {
+ if (n >= len)
+ break;
+ p += n;
+ *p++ = ' ';
+ len -= (n + 1);
+ n = strlcpy(p, argv[i], len);
+ }
+
+ return (cmdline);
+}
+
int
main(int argc, char *argv[])
{
struct command_map_entry *cmd;
const char *command;
- char *root = NULL;
+ char *root = NULL, *cmdline = NULL;
int opt, rc;
while ((opt = getopt(argc, argv, "hr:")) != -1) {
@@ -565,10 +597,19 @@ main(int argc, char *argv[])
return (-1);
}
+ if (cmd->save_history)
+ cmdline = save_cmdline(argc+optind, argv-optind);
+
libbe_print_on_error(be, !cmd->silent);
rc = cmd->fn(argc, argv);
+ if (cmd->save_history) {
+ if (rc == 0)
+ be_log_history(be, cmdline);
+ free(cmdline);
+ }
+
libbe_close(be);
return (rc);
}
help
