1.\" 2.\" SPDX-License-Identifier: BSD-2-Clause 3.\" 4.\" Copyright (c) 2017 Kyle Kneitinger 5.\" Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> 6.\" 7.\" Redistribution and use in source and binary forms, with or without 8.\" modification, are permitted provided that the following conditions 9.\" are met: 10.\" 1. Redistributions of source code must retain the above copyright 11.\" notice, this list of conditions and the following disclaimer. 12.\" 2. Redistributions in binary form must reproduce the above copyright 13.\" notice, this list of conditions and the following disclaimer in the 14.\" documentation and/or other materials provided with the distribution. 15.\" 16.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26.\" SUCH DAMAGE. 27.\" 28.Dd December 11, 2025 29.Dt LIBBE 3 30.Os 31.Sh NAME 32.Nm libbe 33.Nd library for creating, destroying and modifying ZFS boot environments 34.Sh LIBRARY 35.Lb libbe 36.Sh SYNOPSIS 37.In be.h 38.Ft "libbe_handle_t *hdl" Ns 39.Fn libbe_init "const char *be_root" 40.Pp 41.Ft void 42.Fn libbe_close "libbe_handle_t *hdl" 43.Pp 44.Ft const char * Ns 45.Fn be_active_name "libbe_handle_t *hdl" 46.Pp 47.Ft const char * Ns 48.Fn be_active_path "libbe_handle_t *hdl" 49.Pp 50.Ft const char * Ns 51.Fn be_nextboot_name "libbe_handle_t *hdl" 52.Pp 53.Ft const char * Ns 54.Fn be_nextboot_path "libbe_handle_t *hdl" 55.Pp 56.Ft const char * Ns 57.Fn be_root_path "libbe_handle_t *hdl" 58.Pp 59.Ft int Ns 60.Fn be_snapshot "libbe_handle_t *hdl" "const char *be_name" "const char *snap_name" "bool recursive" "char *result" 61.Pp 62.Ft bool Ns 63.Fn be_is_auto_snapshot_name "libbe_handle_t *hdl" "const char *snap" 64.Pp 65.Ft int 66.Fn be_create "libbe_handle_t *hdl" "const char *be_name" 67.Pp 68.Ft int 69.Fn be_create_depth "libbe_handle_t *hdl" "const char *be_name" "const char *snap" "int depth" 70.Pp 71.Ft int 72.Fn be_create_from_existing "libbe_handle_t *hdl" "const char *be_name" "const char *be_origin" 73.Pp 74.Ft int 75.Fn be_create_from_existing_snap "libbe_handle_t *hdl" "const char *be_name" "const char *snap" 76.Pp 77.Ft int 78.Fn be_rename "libbe_handle_t *hdl" "const char *be_old" "const char *be_new" 79.Pp 80.Ft int 81.Fn be_activate "libbe_handle_t *hdl" "const char *be_name" "bool temporary" 82.Pp 83.Ft int 84.Fn be_deactivate "libbe_handle_t *hdl" "const char *be_name" "bool temporary" 85.Pp 86.Ft int 87.Fn be_destroy "libbe_handle_t *hdl" "const char *be_name" "int options" 88.Pp 89.Ft void 90.Fn be_nicenum "uint64_t num" "char *buf" "size_t bufsz" 91.Pp 92.\" TODO: Write up of mount options 93.\" typedef enum { 94.\" BE_MNT_FORCE = 1 << 0, 95.\" BE_MNT_DEEP = 1 << 1, 96.\" } be_mount_opt_t 97.Ft int 98.Fn be_mount "libbe_handle_t *hdl" "const char *be_name" "const char *mntpoint" "int flags" "char *result" 99.Pp 100.Ft int 101.Fn be_mounted_at "libbe_handle_t *hdl" "const char *path" "nvlist_t *details" 102.Pp 103.Ft int 104.Fn be_unmount "libbe_handle_t *hdl" "const char *be_name" "int flags" 105.Pp 106.Ft int 107.Fn libbe_errno "libbe_handle_t *hdl" 108.Pp 109.Ft const char * Ns 110.Fn libbe_error_description "libbe_handle_t *hdl" 111.Pp 112.Ft void 113.Fn libbe_print_on_error "libbe_handle_t *hdl" "bool doprint" 114.Pp 115.Ft int 116.Fn be_root_concat "libbe_handle_t *hdl" "const char *be_name" "char *result" 117.Pp 118.Ft int 119.Fn be_validate_name "libbe_handle_t *hdl" "const char *be_name" 120.Pp 121.Ft int 122.Fn be_validate_snap "libbe_handle_t *hdl" "const char *snap" 123.Pp 124.Ft int 125.Fn be_exists "libbe_handle_t *hdl" "const char *be_name" 126.Pp 127.Ft int 128.Fn be_export "libbe_handle_t *hdl" "const char *be_name" "int fd" 129.Pp 130.Ft int 131.Fn be_import "libbe_handle_t *hdl" "const char *be_name" "int fd" 132.Pp 133.Ft int 134.Fn be_prop_list_alloc "nvlist_t **prop_list" 135.Pp 136.Ft int 137.Fn be_get_bootenv_props "libbe_handle_t *hdl" "nvlist_t *be_list" 138.Pp 139.Ft int 140.Fn be_get_dataset_props "libbe_handle_t *hdl" "const char *ds_name" "nvlist_t *props" 141.Pp 142.Ft int 143.Fn be_get_dataset_snapshots "libbe_handle_t *hdl" "const char *ds_name" "nvlist_t *snap_list" 144.Pp 145.Ft void 146.Fn be_prop_list_free "nvlist_t *prop_list" 147.Pp 148.Ft int 149.Fn be_log_history "libbe_handle_t *hdl" "const char *message" 150.Sh DESCRIPTION 151.Nm 152interfaces with libzfs to provide a set of functions for various operations 153regarding ZFS boot environments, including "deep" boot environments in which 154a boot environment has child datasets. 155.Pp 156A context structure is passed to each function, allowing for a small amount 157of state to be retained, such as errors from previous operations. 158.Nm 159may be configured to print the corresponding error message to 160.Dv stderr 161when an error is encountered with 162.Fn libbe_print_on_error . 163.Pp 164All functions returning an 165.Vt int 166return 0 on success, or a 167.Nm 168errno otherwise as described in 169.Sx DIAGNOSTICS . 170.Pp 171The 172.Fn libbe_init 173function takes an optional BE root and initializes 174.Nm , 175returning a 176.Vt "libbe_handle_t *" 177on success, or 178.Dv NULL 179on error. 180If a BE root is supplied, 181.Nm 182will only operate out of that pool and BE root. 183An error may occur if: 184.Bl -bullet 185.It 186.Pa /boot 187and 188.Pa / 189are not on the same filesystem and device, 190.It 191libzfs fails to initialize, 192.It 193The system has not been properly booted with a ZFS boot 194environment, 195.It 196.Nm 197fails to open the zpool the active boot environment resides on, or 198.It 199.Nm 200fails to locate the boot environment that is currently mounted. 201.El 202.Pp 203The 204.Fn libbe_close 205function frees all resources previously acquired in 206.Fn libbe_init , 207invalidating the handle in the process. 208.Pp 209The 210.Fn be_active_name 211function returns the name of the currently booted boot environment. 212This boot environment may not belong to the same BE root as the root libbe 213is operating on! 214.Pp 215The 216.Fn be_active_path 217function returns the full path of the currently booted boot environment. 218This boot environment may not belong to the same BE root as the root libbe 219is operating on! 220.Pp 221The 222.Fn be_nextboot_name 223function returns the name of the boot environment that will be active on reboot. 224.Pp 225The 226.Fn be_nextboot_path 227function returns the full path of the boot environment that will be 228active on reboot. 229.Pp 230The 231.Fn be_root_path 232function returns the boot environment root path. 233.Pp 234The 235.Fn be_snapshot 236function creates a snapshot of 237.Fa be_name 238named 239.Fa snap_name . 240A value of 241.Dv NULL 242may be used, indicating that 243.Fn be_snaphot 244should derive the snapshot name from the current date and time. 245If 246.Fa recursive 247is set, then 248.Fn be_snapshot 249will recursively snapshot the dataset. 250If 251.Fa result 252is not 253.Dv NULL , 254then it will be populated with the final 255.Dq Fa be_name Ns @ Ns Fa snap_name . 256.Pp 257The 258.Fn be_is_auto_snapshot_name 259function is used to determine if the given snapshot name matches the format that 260the 261.Fn be_snapshot 262function will use by default if it is not given a snapshot name to use. 263It returns 264.Dv true 265if the name matches the format, and 266.Dv false 267if it does not. 268.Pp 269The 270.Fn be_create 271function creates a boot environment with the given name. 272The new boot environment will be created from a recursive snapshot of the 273currently booted boot environment. 274.Pp 275The 276.Fn be_create_depth 277function creates a boot environment with the given name from an existing 278snapshot. 279The depth parameter specifies the depth of recursion that will be cloned from 280the existing snapshot. 281A depth of '0' is no recursion and '-1' is unlimited (i.e., a recursive boot 282environment). 283.Pp 284The 285.Fn be_create_from_existing 286function creates a boot environment with the given name from the name of an 287existing boot environment. 288A recursive snapshot will be made of the origin boot environment, and the new 289boot environment will be created from that. 290.Pp 291The 292.Fn be_create_from_existing_snap 293function creates a recursive boot environment with the given name from an 294existing snapshot. 295.Pp 296The 297.Fn be_rename 298function renames a boot environment without unmounting it, as if renamed with 299the 300.Fl u 301argument were passed to 302.Nm zfs 303.Cm rename 304.Pp 305The 306.Fn be_activate 307function makes a boot environment active on the next boot. 308If the 309.Fa temporary 310flag is set, then it will be active for the next boot only, as done by 311.Xr zfsbootcfg 8 . 312.Pp 313The 314.Fn be_deactivate 315function deactivates a boot environment. 316If the 317.Fa temporary 318flag is set, then it will cause removal of boot once configuration, set by 319.Fn be_activate 320function or by 321.Xr zfsbootcfg 8 . 322If the 323.Fa temporary 324flag is not set, 325.Fn be_deactivate 326function will set zfs 327.Dv canmount 328property to 329.Dv noauto . 330.Pp 331The 332.Fn be_destroy 333function will recursively destroy the given boot environment. 334It will not destroy a mounted boot environment unless the 335.Dv BE_DESTROY_FORCE 336option is set in 337.Fa options . 338If the 339.Dv BE_DESTROY_ORIGIN 340option is set in 341.Fa options , 342the 343.Fn be_destroy 344function will destroy the origin snapshot to this boot environment as well. 345.Pp 346The 347.Fn be_nicenum 348function will format 349.Fa name 350in a traditional ZFS humanized format, similar to 351.Xr humanize_number 3 . 352This function effectively proxies 353.Fn zfs_nicenum 354from libzfs. 355.Pp 356The 357.Fn be_mount 358function will mount the given boot environment. 359If 360.Fa mountpoint 361is 362.Dv NULL , 363a mount point will be generated in 364.Ev TMPDIR 365or, if 366.Ev TMPDIR 367is not set, 368.Pa /tmp 369using 370.Xr mkdtemp 3 . 371If 372.Fa result 373is not 374.Dv NULL , 375it should be large enough to accommodate 376.Dv BE_MAXPATHLEN 377including the null terminator. 378the final mount point will be copied into it. 379Setting the 380.Dv BE_MNT_FORCE 381flag will pass 382.Dv MNT_FORCE 383to the underlying 384.Xr mount 2 385call. 386.Pp 387The 388.Fn be_mounted_at 389function will check if there is a boot environment mounted at the given 390.Fa path . 391If 392.Fa details 393is not 394.Dv NULL , 395it will be populated with a list of the mounted dataset's properties. 396This list of properties matches the properties collected by 397.Fn be_get_bootenv_props . 398.Pp 399The 400.Fn be_unmount 401function will unmount the given boot environment. 402If the mount point looks like it was created by 403.Fn be_mount , 404then 405.Fn be_unmount 406will attempt to 407.Xr rmdir 2 408the mountpoint after a successful unmount. 409Setting the 410.Dv BE_MNT_FORCE 411flag will pass 412.Dv MNT_FORCE 413to the underlying 414.Xr mount 2 415call. 416.Pp 417The 418.Fn libbe_errno 419function returns the 420.Nm 421errno. 422.Pp 423The 424.Fn libbe_error_description 425function returns a string description of the currently set 426.Nm 427errno. 428.Pp 429The 430.Fn libbe_print_on_error 431function will change whether or not 432.Nm 433prints the description of any encountered error to 434.Dv stderr , 435based on 436.Fa doprint . 437.Pp 438The 439.Fn be_root_concat 440function will concatenate the boot environment root and the given boot 441environment name into 442.Fa result . 443.Pp 444The 445.Fn be_validate_name 446function will validate the given boot environment name for both length 447restrictions as well as valid character restrictions. 448This function does not set the internal library error state. 449.Pp 450The 451.Fn be_validate_snap 452function will validate the given snapshot name. 453The snapshot must have a valid name, exist, and have a mountpoint of 454.Pa / . 455This function does not set the internal library error state. 456.Pp 457The 458.Fn be_exists 459function will check whether the given boot environment exists and has a 460mountpoint of 461.Pa / . 462This function does not set the internal library error state, but will return 463the appropriate error. 464.Pp 465The 466.Fn be_export 467function will export the given boot environment to the file specified by 468.Fa fd . 469A snapshot will be created of the boot environment prior to export. 470.Pp 471The 472.Fn be_import 473function will import the boot environment in the file specified by 474.Fa fd , 475and give it the name 476.Fa be_name . 477.Pp 478The 479.Fn be_prop_list_alloc 480function allocates a property list suitable for passing to 481.Fn be_get_bootenv_props , 482.Fn be_get_dataset_props , 483or 484.Fn be_get_dataset_snapshots . 485It should be freed later by 486.Fa be_prop_list_free . 487.Pp 488The 489.Fn be_get_bootenv_props 490function will populate 491.Fa be_list 492with 493.Vt nvpair_t 494of boot environment names paired with an 495.Vt nvlist_t 496of their properties. 497The following properties are currently collected as appropriate: 498.Bl -column "Returned name" 499.It Sy Returned name Ta Sy Description 500.It dataset Ta - 501.It name Ta Boot environment name 502.It mounted Ta Current mount point 503.It mountpoint Ta Do mountpoint Dc property 504.It origin Ta Do origin Dc property 505.It creation Ta Do creation Dc property 506.It active Ta Currently booted environment 507.It used Ta Literal Do used Dc property 508.It usedds Ta Literal Do usedds Dc property 509.It usedsnap Ta Literal Do usedrefreserv Dc property 510.It referenced Ta Literal Do referenced Dc property 511.It nextboot Ta Active on next boot 512.El 513.Pp 514Only the 515.Dq dataset , 516.Dq name , 517.Dq active , 518and 519.Dq nextboot 520returned values will always be present. 521All other properties may be omitted if not available. 522.Pp 523The 524.Fn be_get_dataset_props 525function will get properties of the specified dataset. 526.Fa props 527is populated directly with a list of the properties as returned by 528.Fn be_get_bootenv_props . 529.Pp 530The 531.Fn be_get_dataset_snapshots 532function will retrieve all snapshots of the given dataset. 533.Fa snap_list 534will be populated with a list of 535.Vt nvpair_t 536exactly as specified by 537.Fn be_get_bootenv_props . 538.Pp 539The 540.Fn be_prop_list_free 541function will free the property list. 542.Pp 543The 544.Fn be_log_history 545function will log the given 546.Fa message 547to the zpool history, which can be later retrieved using the 548.Xr zpool-history 8 549command. 550.Sh DIAGNOSTICS 551Upon error, one of the following values will be returned: 552.Bl -bullet -offset indent -compact 553.It 554BE_ERR_SUCCESS 555.It 556BE_ERR_INVALIDNAME 557.It 558BE_ERR_EXISTS 559.It 560BE_ERR_NOENT 561.It 562BE_ERR_PERMS 563.It 564BE_ERR_DESTROYACT 565.It 566BE_ERR_DESTROYMNT 567.It 568BE_ERR_BADPATH 569.It 570BE_ERR_PATHBUSY 571.It 572BE_ERR_PATHLEN 573.It 574BE_ERR_BADMOUNT 575.It 576BE_ERR_NOORIGIN 577.It 578BE_ERR_MOUNTED 579.It 580BE_ERR_NOMOUNT 581.It 582BE_ERR_ZFSOPEN 583.It 584BE_ERR_ZFSCLONE 585.It 586BE_ERR_IO 587.It 588BE_ERR_NOPOOL 589.It 590BE_ERR_NOMEM 591.It 592BE_ERR_UNKNOWN 593.It 594BE_ERR_INVORIGIN 595.El 596.Sh SEE ALSO 597.Xr bectl 8 , 598.Xr zpool-history 8 599.Sh HISTORY 600.Xr bectl 8 601and 602.Nm 603were written by 604.An Kyle Kneitinger (kneitinger) Aq Mt kyle@kneit.in 605as a 2017 Google Summer of Code project, with 606.An Allan Jude (allanjude) Aq Mt allanjude@freebsd.org 607as mentor. 608.Sh AUTHORS 609Kyle Kneitinger, mentored as above. 610.Pp 611Post-GSoC changes were written by 612.An Kyle Evans (kevans) Aq Mt kevans@freebsd.org . 613