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