1.\" This file and its contents are supplied under the terms of the 2.\" Common Development and Distribution License ("CDDL"), version 1.0. 3.\" You may only use this file in accordance with the terms of version 4.\" 1.0 of the CDDL. 5.\" 6.\" A full copy of the text of the CDDL should have accompanied this 7.\" source. A copy of the CDDL is also available via the Internet at 8.\" http://www.illumos.org/license/CDDL. 9.\" 10.\" 11.\" Copyright (c) 2016, 2019 by Delphix. All Rights Reserved. 12.\" Copyright (c) 2019, 2020 by Christian Schwarz. All Rights Reserved. 13.\" Copyright 2020 Joyent, Inc. 14.\" 15.Dd January 26, 2021 16.Dt ZFS-PROGRAM 8 17.Os 18.Sh NAME 19.Nm zfs-program 20.Nd executes ZFS channel programs 21.Sh SYNOPSIS 22.Nm zfs 23.Cm program 24.Op Fl jn 25.Op Fl t Ar instruction-limit 26.Op Fl m Ar memory-limit 27.Ar pool 28.Ar script 29.\".Op Ar optional arguments to channel program 30.Sh DESCRIPTION 31The ZFS channel program interface allows ZFS administrative operations to be 32run programmatically as a Lua script. 33The entire script is executed atomically, with no other administrative 34operations taking effect concurrently. 35A library of ZFS calls is made available to channel program scripts. 36Channel programs may only be run with root privileges. 37.Pp 38A modified version of the Lua 5.2 interpreter is used to run channel program 39scripts. 40The Lua 5.2 manual can be found at: 41.Bd -centered -offset indent 42.Lk http://www.lua.org/manual/5.2/ 43.Ed 44.Pp 45The channel program given by 46.Ar script 47will be run on 48.Ar pool , 49and any attempts to access or modify other pools will cause an error. 50.Sh OPTIONS 51.Bl -tag -width "-t" 52.It Fl j 53Display channel program output in JSON format. When this flag is specified and 54standard output is empty - channel program encountered an error. The details of 55such an error will be printed to standard error in plain text. 56.It Fl n 57Executes a read-only channel program, which runs faster. 58The program cannot change on-disk state by calling functions from the 59zfs.sync submodule. 60The program can be used to gather information such as properties and 61determining if changes would succeed (zfs.check.*). 62Without this flag, all pending changes must be synced to disk before a 63channel program can complete. 64.It Fl t Ar instruction-limit 65Limit the number of Lua instructions to execute. 66If a channel program executes more than the specified number of instructions, 67it will be stopped and an error will be returned. 68The default limit is 10 million instructions, and it can be set to a maximum of 69100 million instructions. 70.It Fl m Ar memory-limit 71Memory limit, in bytes. 72If a channel program attempts to allocate more memory than the given limit, it 73will be stopped and an error returned. 74The default memory limit is 10 MB, and can be set to a maximum of 100 MB. 75.El 76.Pp 77All remaining argument strings will be passed directly to the Lua script as 78described in the 79.Sx LUA INTERFACE 80section below. 81.Sh LUA INTERFACE 82A channel program can be invoked either from the command line, or via a library 83call to 84.Fn lzc_channel_program . 85.Ss Arguments 86Arguments passed to the channel program are converted to a Lua table. 87If invoked from the command line, extra arguments to the Lua script will be 88accessible as an array stored in the argument table with the key 'argv': 89.Bd -literal -offset indent 90args = ... 91argv = args["argv"] 92-- argv == {1="arg1", 2="arg2", ...} 93.Ed 94.Pp 95If invoked from the libZFS interface, an arbitrary argument list can be 96passed to the channel program, which is accessible via the same 97"..." syntax in Lua: 98.Bd -literal -offset indent 99args = ... 100-- args == {"foo"="bar", "baz"={...}, ...} 101.Ed 102.Pp 103Note that because Lua arrays are 1-indexed, arrays passed to Lua from the 104libZFS interface will have their indices incremented by 1. 105That is, the element 106in 107.Va arr[0] 108in a C array passed to a channel program will be stored in 109.Va arr[1] 110when accessed from Lua. 111.Ss Return Values 112Lua return statements take the form: 113.Bd -literal -offset indent 114return ret0, ret1, ret2, ... 115.Ed 116.Pp 117Return statements returning multiple values are permitted internally in a 118channel program script, but attempting to return more than one value from the 119top level of the channel program is not permitted and will throw an error. 120However, tables containing multiple values can still be returned. 121If invoked from the command line, a return statement: 122.Bd -literal -offset indent 123a = {foo="bar", baz=2} 124return a 125.Ed 126.Pp 127Will be output formatted as: 128.Bd -literal -offset indent 129Channel program fully executed with return value: 130 return: 131 baz: 2 132 foo: 'bar' 133.Ed 134.Ss Fatal Errors 135If the channel program encounters a fatal error while running, a non-zero exit 136status will be returned. 137If more information about the error is available, a singleton list will be 138returned detailing the error: 139.Bd -literal -offset indent 140error: "error string, including Lua stack trace" 141.Ed 142.Pp 143If a fatal error is returned, the channel program may have not executed at all, 144may have partially executed, or may have fully executed but failed to pass a 145return value back to userland. 146.Pp 147If the channel program exhausts an instruction or memory limit, a fatal error 148will be generated and the program will be stopped, leaving the program partially 149executed. 150No attempt is made to reverse or undo any operations already performed. 151Note that because both the instruction count and amount of memory used by a 152channel program are deterministic when run against the same inputs and 153filesystem state, as long as a channel program has run successfully once, you 154can guarantee that it will finish successfully against a similar size system. 155.Pp 156If a channel program attempts to return too large a value, the program will 157fully execute but exit with a nonzero status code and no return value. 158.Pp 159.Em Note : 160ZFS API functions do not generate Fatal Errors when correctly invoked, they 161return an error code and the channel program continues executing. 162See the 163.Sx ZFS API 164section below for function-specific details on error return codes. 165.Ss Lua to C Value Conversion 166When invoking a channel program via the libZFS interface, it is necessary to 167translate arguments and return values from Lua values to their C equivalents, 168and vice-versa. 169.Pp 170There is a correspondence between nvlist values in C and Lua tables. 171A Lua table which is returned from the channel program will be recursively 172converted to an nvlist, with table values converted to their natural 173equivalents: 174.Bd -literal -offset indent 175string -> string 176number -> int64 177boolean -> boolean_value 178nil -> boolean (no value) 179table -> nvlist 180.Ed 181.Pp 182Likewise, table keys are replaced by string equivalents as follows: 183.Bd -literal -offset indent 184string -> no change 185number -> signed decimal string ("%lld") 186boolean -> "true" | "false" 187.Ed 188.Pp 189Any collision of table key strings (for example, the string "true" and a 190true boolean value) will cause a fatal error. 191.Pp 192Lua numbers are represented internally as signed 64-bit integers. 193.Sh LUA STANDARD LIBRARY 194The following Lua built-in base library functions are available: 195.Bd -literal -offset indent 196assert rawlen 197collectgarbage rawget 198error rawset 199getmetatable select 200ipairs setmetatable 201next tonumber 202pairs tostring 203rawequal type 204.Ed 205.Pp 206All functions in the 207.Em coroutine , 208.Em string , 209and 210.Em table 211built-in submodules are also available. 212A complete list and documentation of these modules is available in the Lua 213manual. 214.Pp 215The following functions base library functions have been disabled and are 216not available for use in channel programs: 217.Bd -literal -offset indent 218dofile 219loadfile 220load 221pcall 222print 223xpcall 224.Ed 225.Sh ZFS API 226.Ss Function Arguments 227Each API function takes a fixed set of required positional arguments and 228optional keyword arguments. 229For example, the destroy function takes a single positional string argument 230(the name of the dataset to destroy) and an optional "defer" keyword boolean 231argument. 232When using parentheses to specify the arguments to a Lua function, only 233positional arguments can be used: 234.Bd -literal -offset indent 235zfs.sync.destroy("rpool@snap") 236.Ed 237.Pp 238To use keyword arguments, functions must be called with a single argument that 239is a Lua table containing entries mapping integers to positional arguments and 240strings to keyword arguments: 241.Bd -literal -offset indent 242zfs.sync.destroy({1="rpool@snap", defer=true}) 243.Ed 244.Pp 245The Lua language allows curly braces to be used in place of parenthesis as 246syntactic sugar for this calling convention: 247.Bd -literal -offset indent 248zfs.sync.snapshot{"rpool@snap", defer=true} 249.Ed 250.Ss Function Return Values 251If an API function succeeds, it returns 0. 252If it fails, it returns an error code and the channel program continues 253executing. 254API functions do not generate Fatal Errors except in the case of an 255unrecoverable internal file system error. 256.Pp 257In addition to returning an error code, some functions also return extra 258details describing what caused the error. 259This extra description is given as a second return value, and will always be a 260Lua table, or Nil if no error details were returned. 261Different keys will exist in the error details table depending on the function 262and error case. 263Any such function may be called expecting a single return value: 264.Bd -literal -offset indent 265errno = zfs.sync.promote(dataset) 266.Ed 267.Pp 268Or, the error details can be retrieved: 269.Bd -literal -offset indent 270errno, details = zfs.sync.promote(dataset) 271if (errno == EEXIST) then 272 assert(details ~= Nil) 273 list_of_conflicting_snapshots = details 274end 275.Ed 276.Pp 277The following global aliases for API function error return codes are defined 278for use in channel programs: 279.Bd -literal -offset indent 280EPERM ECHILD ENODEV ENOSPC 281ENOENT EAGAIN ENOTDIR ESPIPE 282ESRCH ENOMEM EISDIR EROFS 283EINTR EACCES EINVAL EMLINK 284EIO EFAULT ENFILE EPIPE 285ENXIO ENOTBLK EMFILE EDOM 286E2BIG EBUSY ENOTTY ERANGE 287ENOEXEC EEXIST ETXTBSY EDQUOT 288EBADF EXDEV EFBIG 289.Ed 290.Ss API Functions 291For detailed descriptions of the exact behavior of any zfs administrative 292operations, see the main 293.Xr zfs 8 294manual page. 295.Bl -tag -width "xx" 296.It Em zfs.debug(msg) 297Record a debug message in the zfs_dbgmsg log. 298A log of these messages can be printed via mdb's "::zfs_dbgmsg" command, or 299can be monitored live by running: 300.Bd -literal -offset indent 301 dtrace -n 'zfs-dbgmsg{trace(stringof(arg0))}' 302.Ed 303.Pp 304msg (string) 305.Bd -ragged -compact -offset "xxxx" 306Debug message to be printed. 307.Ed 308.It Em zfs.exists(dataset) 309Returns true if the given dataset exists, or false if it doesn't. 310A fatal error will be thrown if the dataset is not in the target pool. 311That is, in a channel program running on rpool, 312zfs.exists("rpool/nonexistent_fs") returns false, but 313zfs.exists("somepool/fs_that_may_exist") will error. 314.Pp 315dataset (string) 316.Bd -ragged -compact -offset "xxxx" 317Dataset to check for existence. 318Must be in the target pool. 319.Ed 320.It Em zfs.get_prop(dataset, property) 321Returns two values. 322First, a string, number or table containing the property value for the given 323dataset. 324Second, a string containing the source of the property (i.e. the name of the 325dataset in which it was set or nil if it is readonly). 326Throws a Lua error if the dataset is invalid or the property doesn't exist. 327Note that Lua only supports int64 number types whereas ZFS number properties 328are uint64. 329This means very large values (like guid) may wrap around and appear negative. 330.Pp 331dataset (string) 332.Bd -ragged -compact -offset "xxxx" 333Filesystem or snapshot path to retrieve properties from. 334.Ed 335.Pp 336property (string) 337.Bd -ragged -compact -offset "xxxx" 338Name of property to retrieve. 339All filesystem, snapshot and volume properties are supported except 340for 'mounted' and 'iscsioptions.' 341Also supports the 'written@snap' and 'written#bookmark' properties and 342the '<user|group><quota|used>@id' properties, though the id must be in numeric 343form. 344.Ed 345.El 346.Bl -tag -width "xx" 347.It Sy zfs.sync submodule 348The sync submodule contains functions that modify the on-disk state. 349They are executed in "syncing context". 350.Pp 351The available sync submodule functions are as follows: 352.Bl -tag -width "xx" 353.It Em zfs.sync.destroy(dataset, [defer=true|false]) 354Destroy the given dataset. 355Returns 0 on successful destroy, or a nonzero error code if the dataset could 356not be destroyed (for example, if the dataset has any active children or 357clones). 358.Pp 359dataset (string) 360.Bd -ragged -compact -offset "xxxx" 361Filesystem or snapshot to be destroyed. 362.Ed 363.Pp 364[optional] defer (boolean) 365.Bd -ragged -compact -offset "xxxx" 366Valid only for destroying snapshots. 367If set to true, and the snapshot has holds or clones, allows the snapshot to be 368marked for deferred deletion rather than failing. 369.Ed 370.It Em zfs.sync.inherit(dataset, property) 371Clears the specified property in the given dataset, causing it to be inherited 372from an ancestor, or restored to the default if no ancestor property is set. 373The 374.Ql zfs inherit -S 375option has not been implemented. 376Returns 0 on success, or a nonzero error code if the property could not be 377cleared. 378.Pp 379dataset (string) 380.Bd -ragged -compact -offset "xxxx" 381Filesystem or snapshot containing the property to clear. 382.Ed 383.Pp 384property (string) 385.Bd -ragged -compact -offset "xxxx" 386The property to clear. 387Allowed properties are the same as those for the 388.Nm zfs Cm inherit 389command. 390.Ed 391.It Em zfs.sync.promote(dataset) 392Promote the given clone to a filesystem. 393Returns 0 on successful promotion, or a nonzero error code otherwise. 394If EEXIST is returned, the second return value will be an array of the clone's 395snapshots whose names collide with snapshots of the parent filesystem. 396.Pp 397dataset (string) 398.Bd -ragged -compact -offset "xxxx" 399Clone to be promoted. 400.Ed 401.It Em zfs.sync.rollback(filesystem) 402Rollback to the previous snapshot for a dataset. 403Returns 0 on successful rollback, or a nonzero error code otherwise. 404Rollbacks can be performed on filesystems or zvols, but not on snapshots 405or mounted datasets. 406EBUSY is returned in the case where the filesystem is mounted. 407.Pp 408filesystem (string) 409.Bd -ragged -compact -offset "xxxx" 410Filesystem to rollback. 411.Ed 412.It Em zfs.sync.set_prop(dataset, property, value) 413Sets the given property on a dataset. 414Currently only user properties are supported. 415Returns 0 if the property was set, or a nonzero error code otherwise. 416.Pp 417dataset (string) 418.Bd -ragged -compact -offset "xxxx" 419The dataset where the property will be set. 420.Ed 421.Pp 422property (string) 423.Bd -ragged -compact -offset "xxxx" 424The property to set. 425Only user properties are supported. 426.Ed 427.Pp 428value (string) 429.Bd -ragged -compact -offset "xxxx" 430The value of the property to be set. 431.Ed 432.It Em zfs.sync.snapshot(dataset) 433Create a snapshot of a filesystem. 434Returns 0 if the snapshot was successfully created, 435and a nonzero error code otherwise. 436.Pp 437Note: Taking a snapshot will fail on any pool older than legacy version 27. 438To enable taking snapshots from ZCP scripts, the pool must be upgraded. 439.Pp 440dataset (string) 441.Bd -ragged -compact -offset "xxxx" 442Name of snapshot to create. 443.Ed 444.It Em zfs.sync.bookmark(source, newbookmark) 445Create a bookmark of an existing source snapshot or bookmark. 446Returns 0 if the new bookmark was successfully created, 447and a nonzero error code otherwise. 448.Pp 449Note: Bookmarking requires the corresponding pool feature to be enabled. 450.Pp 451source (string) 452.Bd -ragged -compact -offset "xxxx" 453Full name of the existing snapshot or bookmark. 454.Ed 455.Pp 456newbookmark (string) 457.Bd -ragged -compact -offset "xxxx" 458Full name of the new bookmark. 459.El 460.It Sy zfs.check submodule 461For each function in the zfs.sync submodule, there is a corresponding zfs.check 462function which performs a "dry run" of the same operation. 463Each takes the same arguments as its zfs.sync counterpart and returns 0 if the 464operation would succeed, or a non-zero error code if it would fail, along with 465any other error details. 466That is, each has the same behavior as the corresponding sync function except 467for actually executing the requested change. 468For example, 469.Em zfs.check.destroy("fs") 470returns 0 if 471.Em zfs.sync.destroy("fs") 472would successfully destroy the dataset. 473.Pp 474The available zfs.check functions are: 475.Bl -tag -width "xx" 476.It Em zfs.check.destroy(dataset, [defer=true|false]) 477.It Em zfs.check.promote(dataset) 478.It Em zfs.check.rollback(filesystem) 479.It Em zfs.check.set_property(dataset, property, value) 480.It Em zfs.check.snapshot(dataset) 481.El 482.It Sy zfs.list submodule 483The zfs.list submodule provides functions for iterating over datasets and 484properties. 485Rather than returning tables, these functions act as Lua iterators, and are 486generally used as follows: 487.Bd -literal -offset indent 488for child in zfs.list.children("rpool") do 489 ... 490end 491.Ed 492.Pp 493The available zfs.list functions are: 494.Bl -tag -width "xx" 495.It Em zfs.list.clones(snapshot) 496Iterate through all clones of the given snapshot. 497.Pp 498snapshot (string) 499.Bd -ragged -compact -offset "xxxx" 500Must be a valid snapshot path in the current pool. 501.Ed 502.It Em zfs.list.snapshots(dataset) 503Iterate through all snapshots of the given dataset. 504Each snapshot is returned as a string containing the full dataset name, e.g. 505"pool/fs@snap". 506.Pp 507dataset (string) 508.Bd -ragged -compact -offset "xxxx" 509Must be a valid filesystem or volume. 510.Ed 511.It Em zfs.list.children(dataset) 512Iterate through all direct children of the given dataset. 513Each child is returned as a string containing the full dataset name, e.g. 514"pool/fs/child". 515.Pp 516dataset (string) 517.Bd -ragged -compact -offset "xxxx" 518Must be a valid filesystem or volume. 519.Ed 520.It Em zfs.list.bookmarks(dataset) 521Iterate through all bookmarks of the given dataset. Each bookmark is returned 522as a string containing the full dataset name, e.g. "pool/fs#bookmark". 523.Pp 524dataset (string) 525.Bd -ragged -compact -offset "xxxx" 526Must be a valid filesystem or volume. 527.Ed 528.It Em zfs.list.holds(snapshot) 529Iterate through all user holds on the given snapshot. Each hold is returned 530as a pair of the hold's tag and the timestamp (in seconds since the epoch) at 531which it was created. 532.Pp 533snapshot (string) 534.Bd -ragged -compact -offset "xxxx" 535Must be a valid snapshot. 536.Ed 537.It Em zfs.list.properties(dataset) 538An alias for zfs.list.user_properties (see relevant entry). 539.Pp 540dataset (string) 541.Bd -ragged -compact -offset "xxxx" 542Must be a valid filesystem, snapshot, or volume. 543.Ed 544.It Em zfs.list.user_properties(dataset) 545Iterate through all user properties for the given dataset. For each 546step of the iteration, output the property name, its value, and its source. 547Throws a Lua error if the dataset is invalid. 548.Pp 549dataset (string) 550.Bd -ragged -compact -offset "xxxx" 551Must be a valid filesystem, snapshot, or volume. 552.Ed 553.It Em zfs.list.system_properties(dataset) 554Returns an array of strings, the names of the valid system (non-user defined) 555properties for the given dataset. 556Throws a Lua error if the dataset is invalid. 557.Pp 558dataset (string) 559.Bd -ragged -compact -offset "xxxx" 560Must be a valid filesystem, snapshot or volume. 561.Ed 562.El 563.El 564.Sh EXAMPLES 565.Ss Example 1 566The following channel program recursively destroys a filesystem and all its 567snapshots and children in a naive manner. 568Note that this does not involve any error handling or reporting. 569.Bd -literal -offset indent 570function destroy_recursive(root) 571 for child in zfs.list.children(root) do 572 destroy_recursive(child) 573 end 574 for snap in zfs.list.snapshots(root) do 575 zfs.sync.destroy(snap) 576 end 577 zfs.sync.destroy(root) 578end 579destroy_recursive("pool/somefs") 580.Ed 581.Ss Example 2 582A more verbose and robust version of the same channel program, which 583properly detects and reports errors, and also takes the dataset to destroy 584as a command line argument, would be as follows: 585.Bd -literal -offset indent 586succeeded = {} 587failed = {} 588 589function destroy_recursive(root) 590 for child in zfs.list.children(root) do 591 destroy_recursive(child) 592 end 593 for snap in zfs.list.snapshots(root) do 594 err = zfs.sync.destroy(snap) 595 if (err ~= 0) then 596 failed[snap] = err 597 else 598 succeeded[snap] = err 599 end 600 end 601 err = zfs.sync.destroy(root) 602 if (err ~= 0) then 603 failed[root] = err 604 else 605 succeeded[root] = err 606 end 607end 608 609args = ... 610argv = args["argv"] 611 612destroy_recursive(argv[1]) 613 614results = {} 615results["succeeded"] = succeeded 616results["failed"] = failed 617return results 618.Ed 619.Ss Example 3 620The following function performs a forced promote operation by attempting to 621promote the given clone and destroying any conflicting snapshots. 622.Bd -literal -offset indent 623function force_promote(ds) 624 errno, details = zfs.check.promote(ds) 625 if (errno == EEXIST) then 626 assert(details ~= Nil) 627 for i, snap in ipairs(details) do 628 zfs.sync.destroy(ds .. "@" .. snap) 629 end 630 elseif (errno ~= 0) then 631 return errno 632 end 633 return zfs.sync.promote(ds) 634end 635.Ed 636