Provided by: zfsutils-linux_2.1.5-1ubuntu6~22.04.4_amd64 bug

NAME

     zfs-program — execute ZFS channel programs

SYNOPSIS

     zfs program [-jn] [-t instruction-limit] [-m memory-limit] pool script [script arguments]

DESCRIPTION

     The ZFS channel program interface allows ZFS administrative operations to be run
     programmatically as a Lua script.  The entire script is executed atomically, with no other
     administrative operations taking effect concurrently.  A library of ZFS calls is made
     available to channel program scripts.  Channel programs may only be run with root
     privileges.

     A modified version of the Lua 5.2 interpreter is used to run channel program scripts.  The
     Lua 5.2 manual can be found at http://www.lua.org/manual/5.2/

     The channel program given by script will be run on pool, and any attempts to access or
     modify other pools will cause an error.

OPTIONS

     -j  Display channel program output in JSON format.  When this flag is specified and standard
         output is empty - channel program encountered an error.  The details of such an error
         will be printed to standard error in plain text.

     -n  Executes a read-only channel program, which runs faster.  The program cannot change on-
         disk state by calling functions from the zfs.sync submodule.  The program can be used to
         gather information such as properties and determining if changes would succeed
         (zfs.check.*).  Without this flag, all pending changes must be synced to disk before a
         channel program can complete.

     -t instruction-limit
         Limit the number of Lua instructions to execute.  If a channel program executes more
         than the specified number of instructions, it will be stopped and an error will be
         returned.  The default limit is 10 million instructions, and it can be set to a maximum
         of 100 million instructions.

     -m memory-limit
         Memory limit, in bytes.  If a channel program attempts to allocate more memory than the
         given limit, it will be stopped and an error returned.  The default memory limit is 10
         MB, and can be set to a maximum of 100 MB.

     All remaining argument strings will be passed directly to the Lua script as described in the
     LUA INTERFACE section below.

LUA INTERFACE

     A channel program can be invoked either from the command line, or via a library call to
     lzc_channel_program().

   Arguments
     Arguments passed to the channel program are converted to a Lua table.  If invoked from the
     command line, extra arguments to the Lua script will be accessible as an array stored in the
     argument table with the key 'argv':
           args = ...
           argv = args["argv"]
           -- argv == {1="arg1", 2="arg2", ...}

     If invoked from the libZFS interface, an arbitrary argument list can be passed to the
     channel program, which is accessible via the same "..." syntax in Lua:
           args = ...
           -- args == {"foo"="bar", "baz"={...}, ...}

     Note that because Lua arrays are 1-indexed, arrays passed to Lua from the libZFS interface
     will have their indices incremented by 1.  That is, the element in arr[0] in a C array
     passed to a channel program will be stored in arr[1] when accessed from Lua.

   Return Values
     Lua return statements take the form:
           return ret0, ret1, ret2, ...

     Return statements returning multiple values are permitted internally in a channel program
     script, but attempting to return more than one value from the top level of the channel
     program is not permitted and will throw an error.  However, tables containing multiple
     values can still be returned.  If invoked from the command line, a return statement:
           a = {foo="bar", baz=2}
           return a

     Will be output formatted as:
           Channel program fully executed with return value:
               return:
                   baz: 2
                   foo: 'bar'

   Fatal Errors
     If the channel program encounters a fatal error while running, a non-zero exit status will
     be returned.  If more information about the error is available, a singleton list will be
     returned detailing the error:
           error: "error string, including Lua stack trace"

     If a fatal error is returned, the channel program may have not executed at all, may have
     partially executed, or may have fully executed but failed to pass a return value back to
     userland.

     If the channel program exhausts an instruction or memory limit, a fatal error will be
     generated and the program will be stopped, leaving the program partially executed.  No
     attempt is made to reverse or undo any operations already performed.  Note that because both
     the instruction count and amount of memory used by a channel program are deterministic when
     run against the same inputs and filesystem state, as long as a channel program has run
     successfully once, you can guarantee that it will finish successfully against a similar size
     system.

     If a channel program attempts to return too large a value, the program will fully execute
     but exit with a nonzero status code and no return value.

     Note: ZFS API functions do not generate Fatal Errors when correctly invoked, they return an
     error code and the channel program continues executing.  See the ZFS API section below for
     function-specific details on error return codes.

   Lua to C Value Conversion
     When invoking a channel program via the libZFS interface, it is necessary to translate
     arguments and return values from Lua values to their C equivalents, and vice-versa.

     There is a correspondence between nvlist values in C and Lua tables.  A Lua table which is
     returned from the channel program will be recursively converted to an nvlist, with table
     values converted to their natural equivalents:
           string    ->   string
           number    ->   int64
           boolean   ->   boolean_value
           nil       ->   boolean (no value)
           table     ->   nvlist

     Likewise, table keys are replaced by string equivalents as follows:
           string    ->   no change
           number    ->   signed decimal string ("%lld")
           boolean   ->   "true" | "false"

     Any collision of table key strings (for example, the string "true" and a true boolean value)
     will cause a fatal error.

     Lua numbers are represented internally as signed 64-bit integers.

LUA STANDARD LIBRARY

     The following Lua built-in base library functions are available:
           assert   rawlen         collectgarbage   rawget
           error    rawset         getmetatable     select
           ipairs   setmetatable   next             tonumber
           pairs    tostring       rawequal         type

     All functions in the coroutine, string, and table built-in submodules are also available.  A
     complete list and documentation of these modules is available in the Lua manual.

     The following functions base library functions have been disabled and are not available for
     use in channel programs:
           dofile   loadfile   load   pcall   print   xpcall

ZFS API

   Function Arguments
     Each API function takes a fixed set of required positional arguments and optional keyword
     arguments.  For example, the destroy function takes a single positional string argument (the
     name of the dataset to destroy) and an optional "defer" keyword boolean argument.  When
     using parentheses to specify the arguments to a Lua function, only positional arguments can
     be used:
           zfs.sync.destroy("rpool@snap")

     To use keyword arguments, functions must be called with a single argument that is a Lua
     table containing entries mapping integers to positional arguments and strings to keyword
     arguments:
           zfs.sync.destroy({1="rpool@snap", defer=true})

     The Lua language allows curly braces to be used in place of parenthesis as syntactic sugar
     for this calling convention:
           zfs.sync.snapshot{"rpool@snap", defer=true}

   Function Return Values
     If an API function succeeds, it returns 0.  If it fails, it returns an error code and the
     channel program continues executing.  API functions do not generate Fatal Errors except in
     the case of an unrecoverable internal file system error.

     In addition to returning an error code, some functions also return extra details describing
     what caused the error.  This extra description is given as a second return value, and will
     always be a Lua table, or Nil if no error details were returned.  Different keys will exist
     in the error details table depending on the function and error case.  Any such function may
     be called expecting a single return value:
           errno = zfs.sync.promote(dataset)

     Or, the error details can be retrieved:
           errno, details = zfs.sync.promote(dataset)
           if (errno == EEXIST) then
               assert(details ~= Nil)
               list_of_conflicting_snapshots = details
           end

     The following global aliases for API function error return codes are defined for use in
     channel programs:
           EPERM     ECHILD   ENODEV    ENOSPC   ENOENT   EAGAIN   ENOTDIR
           ESPIPE    ESRCH    ENOMEM    EISDIR   EROFS    EINTR    EACCES
           EINVAL    EMLINK   EIO       EFAULT   ENFILE   EPIPE    ENXIO
           ENOTBLK   EMFILE   EDOM      E2BIG    EBUSY    ENOTTY   ERANGE
           ENOEXEC   EEXIST   ETXTBSY   EDQUOT   EBADF    EXDEV    EFBIG

   API Functions
     For detailed descriptions of the exact behavior of any ZFS administrative operations, see
     the main zfs(8) manual page.

     zfs.debug(msg)
         Record a debug message in the zfs_dbgmsg log.  A log of these messages can be printed
         via mdb's "::zfs_dbgmsg" command, or can be monitored live by running
               dtrace -n 'zfs-dbgmsg{trace(stringof(arg0))}'

         msg (string)       Debug message to be printed.

     zfs.exists(dataset)
         Returns true if the given dataset exists, or false if it doesn't.  A fatal error will be
         thrown if the dataset is not in the target pool.  That is, in a channel program running
         on rpool, zfs.exists("rpool/nonexistent_fs") returns false, but
         zfs.exists("somepool/fs_that_may_exist") will error.

         dataset (string)   Dataset to check for existence.  Must be in the target pool.

     zfs.get_prop(dataset, property)
         Returns two values.  First, a string, number or table containing the property value for
         the given dataset.  Second, a string containing the source of the property (i.e. the
         name of the dataset in which it was set or nil if it is readonly).  Throws a Lua error
         if the dataset is invalid or the property doesn't exist.  Note that Lua only supports
         int64 number types whereas ZFS number properties are uint64.  This means very large
         values (like GUIDs) may wrap around and appear negative.

         dataset (string)   Filesystem or snapshot path to retrieve properties from.
         property (string)  Name of property to retrieve.  All filesystem, snapshot and volume
                            properties are supported except for mounted and iscsioptions.  Also
                            supports the written@snap and written#bookmark properties and the
                            ⟨user|group⟩⟨quota|used@id properties, though the id must be in
                            numeric form.

     zfs.sync submodule
         The sync submodule contains functions that modify the on-disk state.  They are executed
         in "syncing context".

         The available sync submodule functions are as follows:

         zfs.sync.destroy(dataset, [defer=true|false])
             Destroy the given dataset.  Returns 0 on successful destroy, or a nonzero error code
             if the dataset could not be destroyed (for example, if the dataset has any active
             children or clones).

             dataset (string)      Filesystem or snapshot to be destroyed.
             [defer (boolean)]     Valid only for destroying snapshots.  If set to true, and the
                                   snapshot has holds or clones, allows the snapshot to be marked
                                   for deferred deletion rather than failing.

         zfs.sync.inherit(dataset, property)
             Clears the specified property in the given dataset, causing it to be inherited from
             an ancestor, or restored to the default if no ancestor property is set.  The zfs
             inherit -S option has not been implemented.  Returns 0 on success, or a nonzero
             error code if the property could not be cleared.

             dataset (string)      Filesystem or snapshot containing the property to clear.
             property (string)     The property to clear.  Allowed properties are the same as
                                   those for the zfs inherit command.

         zfs.sync.promote(dataset)
             Promote the given clone to a filesystem.  Returns 0 on successful promotion, or a
             nonzero error code otherwise.  If EEXIST is returned, the second return value will
             be an array of the clone's snapshots whose names collide with snapshots of the
             parent filesystem.

             dataset (string)      Clone to be promoted.

         zfs.sync.rollback(filesystem)
             Rollback to the previous snapshot for a dataset.  Returns 0 on successful rollback,
             or a nonzero error code otherwise.  Rollbacks can be performed on filesystems or
             zvols, but not on snapshots or mounted datasets.  EBUSY is returned in the case
             where the filesystem is mounted.

             filesystem (string)   Filesystem to rollback.

         zfs.sync.set_prop(dataset, property, value)
             Sets the given property on a dataset.  Currently only user properties are supported.
             Returns 0 if the property was set, or a nonzero error code otherwise.

             dataset (string)      The dataset where the property will be set.
             property (string)     The property to set.
             value (string)        The value of the property to be set.

         zfs.sync.snapshot(dataset)
             Create a snapshot of a filesystem.  Returns 0 if the snapshot was successfully
             created, and a nonzero error code otherwise.

             Note: Taking a snapshot will fail on any pool older than legacy version 27.  To
             enable taking snapshots from ZCP scripts, the pool must be upgraded.

             dataset (string)      Name of snapshot to create.

         zfs.sync.bookmark(source, newbookmark)
             Create a bookmark of an existing source snapshot or bookmark.  Returns 0 if the new
             bookmark was successfully created, and a nonzero error code otherwise.

             Note: Bookmarking requires the corresponding pool feature to be enabled.

             source (string)       Full name of the existing snapshot or bookmark.
             newbookmark (string)  Full name of the new bookmark.

     zfs.check submodule
         For each function in the zfs.sync submodule, there is a corresponding zfs.check function
         which performs a "dry run" of the same operation.  Each takes the same arguments as its
         zfs.sync counterpart and returns 0 if the operation would succeed, or a non-zero error
         code if it would fail, along with any other error details.  That is, each has the same
         behavior as the corresponding sync function except for actually executing the requested
         change.  For example, zfs.check.destroy("fs") returns 0 if zfs.sync.destroy("fs") would
         successfully destroy the dataset.

         The available zfs.check functions are:
         zfs.check.destroy(dataset, [defer=true|false])
         zfs.check.promote(dataset)
         zfs.check.rollback(filesystem)
         zfs.check.set_property(dataset, property, value)
         zfs.check.snapshot(dataset)

     zfs.list submodule
         The zfs.list submodule provides functions for iterating over datasets and properties.
         Rather than returning tables, these functions act as Lua iterators, and are generally
         used as follows:
               for child in zfs.list.children("rpool") do
                   ...
               end

         The available zfs.list functions are:

         zfs.list.clones(snapshot)
             Iterate through all clones of the given snapshot.

             snapshot (string)  Must be a valid snapshot path in the current pool.

         zfs.list.snapshots(dataset)
             Iterate through all snapshots of the given dataset.  Each snapshot is returned as a
             string containing the full dataset name, e.g. "pool/fs@snap".

             dataset (string)   Must be a valid filesystem or volume.

         zfs.list.children(dataset)
             Iterate through all direct children of the given dataset.  Each child is returned as
             a string containing the full dataset name, e.g. "pool/fs/child".

             dataset (string)   Must be a valid filesystem or volume.

         zfs.list.bookmarks(dataset)
             Iterate through all bookmarks of the given dataset.  Each bookmark is returned as a
             string containing the full dataset name, e.g. "pool/fs#bookmark".

             dataset (string)   Must be a valid filesystem or volume.

         zfs.list.holds(snapshot)
             Iterate through all user holds on the given snapshot.  Each hold is returned as a
             pair of the hold's tag and the timestamp (in seconds since the epoch) at which it
             was created.

             snapshot (string)  Must be a valid snapshot.

         zfs.list.properties(dataset)
             An alias for zfs.list.user_properties (see relevant entry).

             dataset (string)   Must be a valid filesystem, snapshot, or volume.

         zfs.list.user_properties(dataset)
             Iterate through all user properties for the given dataset.  For each step of the
             iteration, output the property name, its value, and its source.  Throws a Lua error
             if the dataset is invalid.

             dataset (string)   Must be a valid filesystem, snapshot, or volume.

         zfs.list.system_properties(dataset)
             Returns an array of strings, the names of the valid system (non-user defined)
             properties for the given dataset.  Throws a Lua error if the dataset is invalid.

             dataset (string)   Must be a valid filesystem, snapshot or volume.

EXAMPLES

   Example 1
     The following channel program recursively destroys a filesystem and all its snapshots and
     children in a naive manner.  Note that this does not involve any error handling or
     reporting.

           function destroy_recursive(root)
               for child in zfs.list.children(root) do
                   destroy_recursive(child)
               end
               for snap in zfs.list.snapshots(root) do
                   zfs.sync.destroy(snap)
               end
               zfs.sync.destroy(root)
           end
           destroy_recursive("pool/somefs")

   Example 2
     A more verbose and robust version of the same channel program, which properly detects and
     reports errors, and also takes the dataset to destroy as a command line argument, would be
     as follows:

           succeeded = {}
           failed = {}

           function destroy_recursive(root)
               for child in zfs.list.children(root) do
                   destroy_recursive(child)
               end
               for snap in zfs.list.snapshots(root) do
                   err = zfs.sync.destroy(snap)
                   if (err ~= 0) then
                       failed[snap] = err
                   else
                       succeeded[snap] = err
                   end
               end
               err = zfs.sync.destroy(root)
               if (err ~= 0) then
                   failed[root] = err
               else
                   succeeded[root] = err
               end
           end

           args = ...
           argv = args["argv"]

           destroy_recursive(argv[1])

           results = {}
           results["succeeded"] = succeeded
           results["failed"] = failed
           return results

   Example 3
     The following function performs a forced promote operation by attempting to promote the
     given clone and destroying any conflicting snapshots.

           function force_promote(ds)
              errno, details = zfs.check.promote(ds)
              if (errno == EEXIST) then
                  assert(details ~= Nil)
                  for i, snap in ipairs(details) do
                      zfs.sync.destroy(ds .. "@" .. snap)
                  end
              elseif (errno ~= 0) then
                  return errno
              end
              return zfs.sync.promote(ds)
           end