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