The branch main has been updated by kevans:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2a87929671e6e6919c18f2c25d60f2c73c3d18f4

commit 2a87929671e6e6919c18f2c25d60f2c73c3d18f4
Author:     Rob Norris <[email protected]>
AuthorDate: 2025-12-17 17:00:47 +0000
Commit:     Kyle Evans <[email protected]>
CommitDate: 2025-12-17 17:00:47 +0000

    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 <[email protected]>
    Co-authored-by: Kyle Evans <[email protected]>
    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);
 }

Reply via email to