logo

oasis-root

Compiled tree of Oasis Linux based on own branch at <https://hacktivis.me/git/oasis/> git clone https://anongit.hacktivis.me/git/oasis-root.git

zfs-program.8 (21299B)


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