4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
17 * Copyright (c) 2016 by Delphix. All rights reserved.
20 #include <sys/lua/lua.h>
21 #include <sys/lua/lauxlib.h>
24 #include <sys/dsl_prop.h>
25 #include <sys/dsl_synctask.h>
26 #include <sys/dsl_dataset.h>
27 #include <sys/dsl_pool.h>
28 #include <sys/dmu_tx.h>
29 #include <sys/dmu_objset.h>
31 #include <sys/dsl_dir.h>
32 #include <sys/zcp_prop.h>
36 #include "zfs_comutil.h"
38 typedef int (zcp_list_func_t
)(lua_State
*);
39 typedef struct zcp_list_info
{
41 zcp_list_func_t
*func
;
43 const zcp_arg_t pargs
[4];
44 const zcp_arg_t kwargs
[2];
48 zcp_clones_iter(lua_State
*state
)
51 char clonename
[ZFS_MAX_DATASET_NAME_LEN
];
52 uint64_t dsobj
= lua_tonumber(state
, lua_upvalueindex(1));
53 uint64_t cursor
= lua_tonumber(state
, lua_upvalueindex(2));
54 dsl_pool_t
*dp
= zcp_run_info(state
)->zri_pool
;
55 dsl_dataset_t
*ds
, *clone
;
59 err
= dsl_dataset_hold_obj(dp
, dsobj
, FTAG
, &ds
);
62 } else if (err
!= 0) {
63 return (luaL_error(state
,
64 "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
68 if (dsl_dataset_phys(ds
)->ds_next_clones_obj
== 0) {
69 dsl_dataset_rele(ds
, FTAG
);
73 zap_cursor_init_serialized(&zc
, dp
->dp_meta_objset
,
74 dsl_dataset_phys(ds
)->ds_next_clones_obj
, cursor
);
75 dsl_dataset_rele(ds
, FTAG
);
77 err
= zap_cursor_retrieve(&zc
, &za
);
81 return (luaL_error(state
,
82 "unexpected error %d from zap_cursor_retrieve()",
87 zap_cursor_advance(&zc
);
88 cursor
= zap_cursor_serialize(&zc
);
91 err
= dsl_dataset_hold_obj(dp
, za
.za_first_integer
, FTAG
, &clone
);
93 return (luaL_error(state
,
94 "unexpected error %d from "
95 "dsl_dataset_hold_obj(za_first_integer)", err
));
98 dsl_dir_name(clone
->ds_dir
, clonename
);
99 dsl_dataset_rele(clone
, FTAG
);
101 lua_pushnumber(state
, cursor
);
102 lua_replace(state
, lua_upvalueindex(2));
104 (void) lua_pushstring(state
, clonename
);
108 static int zcp_clones_list(lua_State
*);
109 static zcp_list_info_t zcp_clones_list_info
= {
111 .func
= zcp_clones_list
,
114 { .za_name
= "snapshot", .za_lua_type
= LUA_TSTRING
},
123 zcp_clones_list(lua_State
*state
)
125 const char *snapname
= lua_tostring(state
, 1);
126 dsl_pool_t
*dp
= zcp_run_info(state
)->zri_pool
;
128 uint64_t dsobj
, cursor
;
131 * zcp_dataset_hold will either successfully return the requested
132 * dataset or throw a lua error and longjmp out of the zfs.list.clones
133 * call without returning.
135 dsl_dataset_t
*ds
= zcp_dataset_hold(state
, dp
, snapname
, FTAG
);
137 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
139 issnap
= ds
->ds_is_snapshot
;
140 dsobj
= ds
->ds_object
;
141 dsl_dataset_rele(ds
, FTAG
);
144 return (zcp_argerror(state
, 1, "%s is not a snapshot",
148 lua_pushnumber(state
, dsobj
);
149 lua_pushnumber(state
, cursor
);
150 lua_pushcclosure(state
, &zcp_clones_iter
, 2);
155 zcp_snapshots_iter(lua_State
*state
)
158 char snapname
[ZFS_MAX_DATASET_NAME_LEN
];
159 uint64_t dsobj
= lua_tonumber(state
, lua_upvalueindex(1));
160 uint64_t cursor
= lua_tonumber(state
, lua_upvalueindex(2));
161 dsl_pool_t
*dp
= zcp_run_info(state
)->zri_pool
;
166 err
= dsl_dataset_hold_obj(dp
, dsobj
, FTAG
, &ds
);
168 return (luaL_error(state
,
169 "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
173 dsl_dataset_name(ds
, snapname
);
174 VERIFY3U(sizeof (snapname
), >,
175 strlcat(snapname
, "@", sizeof (snapname
)));
177 p
= strchr(snapname
, '\0');
178 VERIFY0(dmu_objset_from_ds(ds
, &os
));
179 err
= dmu_snapshot_list_next(os
,
180 sizeof (snapname
) - (p
- snapname
), p
, NULL
, &cursor
, NULL
);
181 dsl_dataset_rele(ds
, FTAG
);
185 } else if (err
!= 0) {
186 return (luaL_error(state
,
187 "unexpected error %d from dmu_snapshot_list_next()", err
));
190 lua_pushnumber(state
, cursor
);
191 lua_replace(state
, lua_upvalueindex(2));
193 (void) lua_pushstring(state
, snapname
);
197 static int zcp_snapshots_list(lua_State
*);
198 static zcp_list_info_t zcp_snapshots_list_info
= {
200 .func
= zcp_snapshots_list
,
203 { .za_name
= "filesystem | volume", .za_lua_type
= LUA_TSTRING
},
212 zcp_snapshots_list(lua_State
*state
)
214 const char *fsname
= lua_tostring(state
, 1);
215 dsl_pool_t
*dp
= zcp_run_info(state
)->zri_pool
;
219 dsl_dataset_t
*ds
= zcp_dataset_hold(state
, dp
, fsname
, FTAG
);
221 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
222 issnap
= ds
->ds_is_snapshot
;
223 dsobj
= ds
->ds_object
;
224 dsl_dataset_rele(ds
, FTAG
);
227 return (zcp_argerror(state
, 1,
228 "argument %s cannot be a snapshot", fsname
));
231 lua_pushnumber(state
, dsobj
);
232 lua_pushnumber(state
, 0);
233 lua_pushcclosure(state
, &zcp_snapshots_iter
, 2);
238 zcp_children_iter(lua_State
*state
)
241 char childname
[ZFS_MAX_DATASET_NAME_LEN
];
242 uint64_t dsobj
= lua_tonumber(state
, lua_upvalueindex(1));
243 uint64_t cursor
= lua_tonumber(state
, lua_upvalueindex(2));
244 zcp_run_info_t
*ri
= zcp_run_info(state
);
245 dsl_pool_t
*dp
= ri
->zri_pool
;
250 err
= dsl_dataset_hold_obj(dp
, dsobj
, FTAG
, &ds
);
252 return (luaL_error(state
,
253 "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
257 dsl_dataset_name(ds
, childname
);
258 VERIFY3U(sizeof (childname
), >,
259 strlcat(childname
, "/", sizeof (childname
)));
260 p
= strchr(childname
, '\0');
262 VERIFY0(dmu_objset_from_ds(ds
, &os
));
264 err
= dmu_dir_list_next(os
,
265 sizeof (childname
) - (p
- childname
), p
, NULL
, &cursor
);
266 } while (err
== 0 && zfs_dataset_name_hidden(childname
));
267 dsl_dataset_rele(ds
, FTAG
);
271 } else if (err
!= 0) {
272 return (luaL_error(state
,
273 "unexpected error %d from dmu_dir_list_next()",
277 lua_pushnumber(state
, cursor
);
278 lua_replace(state
, lua_upvalueindex(2));
280 (void) lua_pushstring(state
, childname
);
284 static int zcp_children_list(lua_State
*);
285 static zcp_list_info_t zcp_children_list_info
= {
287 .func
= zcp_children_list
,
290 { .za_name
= "filesystem | volume", .za_lua_type
= LUA_TSTRING
},
299 zcp_children_list(lua_State
*state
)
301 const char *fsname
= lua_tostring(state
, 1);
302 dsl_pool_t
*dp
= zcp_run_info(state
)->zri_pool
;
306 dsl_dataset_t
*ds
= zcp_dataset_hold(state
, dp
, fsname
, FTAG
);
308 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
310 issnap
= ds
->ds_is_snapshot
;
311 dsobj
= ds
->ds_object
;
312 dsl_dataset_rele(ds
, FTAG
);
315 return (zcp_argerror(state
, 1,
316 "argument %s cannot be a snapshot", fsname
));
319 lua_pushnumber(state
, dsobj
);
320 lua_pushnumber(state
, 0);
321 lua_pushcclosure(state
, &zcp_children_iter
, 2);
326 zcp_props_list_gc(lua_State
*state
)
328 nvlist_t
**props
= lua_touserdata(state
, 1);
330 fnvlist_free(*props
);
335 zcp_props_iter(lua_State
*state
)
339 nvlist_t
**props
= lua_touserdata(state
, lua_upvalueindex(1));
340 nvpair_t
*pair
= lua_touserdata(state
, lua_upvalueindex(2));
343 pair
= nvlist_next_nvpair(*props
, pair
);
345 fnvlist_free(*props
);
349 } while (!zfs_prop_user(nvpair_name(pair
)));
351 lua_pushlightuserdata(state
, pair
);
352 lua_replace(state
, lua_upvalueindex(2));
354 nvprop
= fnvpair_value_nvlist(pair
);
355 val
= fnvlist_lookup_string(nvprop
, ZPROP_VALUE
);
356 source
= fnvlist_lookup_string(nvprop
, ZPROP_SOURCE
);
358 (void) lua_pushstring(state
, nvpair_name(pair
));
359 (void) lua_pushstring(state
, val
);
360 (void) lua_pushstring(state
, source
);
364 static int zcp_props_list(lua_State
*);
365 static zcp_list_info_t zcp_props_list_info
= {
366 .name
= "properties",
367 .func
= zcp_props_list
,
368 .gc
= zcp_props_list_gc
,
370 { .za_name
= "filesystem | snapshot | volume",
371 .za_lua_type
= LUA_TSTRING
},
380 zcp_props_list(lua_State
*state
)
382 const char *dsname
= lua_tostring(state
, 1);
383 dsl_pool_t
*dp
= zcp_run_info(state
)->zri_pool
;
385 nvlist_t
**props
= lua_newuserdata(state
, sizeof (nvlist_t
*));
387 dsl_dataset_t
*ds
= zcp_dataset_hold(state
, dp
, dsname
, FTAG
);
389 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
390 VERIFY0(dmu_objset_from_ds(ds
, &os
));
391 VERIFY0(dsl_prop_get_all(os
, props
));
392 dsl_dataset_rele(ds
, FTAG
);
395 * Set the metatable for the properties list to free it on completion.
397 luaL_getmetatable(state
, zcp_props_list_info
.name
);
398 (void) lua_setmetatable(state
, -2);
400 lua_pushlightuserdata(state
, NULL
);
401 lua_pushcclosure(state
, &zcp_props_iter
, 2);
407 * Populate nv with all valid properties and their values for the given
411 zcp_dataset_props(dsl_dataset_t
*ds
, nvlist_t
*nv
)
413 for (int prop
= ZFS_PROP_TYPE
; prop
< ZFS_NUM_PROPS
; prop
++) {
414 /* Do not display hidden props */
415 if (!zfs_prop_visible(prop
))
417 /* Do not display props not valid for this dataset */
418 if (!prop_valid_for_ds(ds
, prop
))
420 fnvlist_add_boolean(nv
, zfs_prop_to_name(prop
));
424 static int zcp_system_props_list(lua_State
*);
425 static zcp_list_info_t zcp_system_props_list_info
= {
426 .name
= "system_properties",
427 .func
= zcp_system_props_list
,
429 { .za_name
= "dataset", .za_lua_type
= LUA_TSTRING
},
438 * Get a list of all visble properties and their values for a given dataset.
439 * Returned on the stack as a Lua table.
442 zcp_system_props_list(lua_State
*state
)
446 const char *dataset_name
;
447 dsl_pool_t
*dp
= zcp_run_info(state
)->zri_pool
;
448 zcp_list_info_t
*libinfo
= &zcp_system_props_list_info
;
449 zcp_parse_args(state
, libinfo
->name
, libinfo
->pargs
, libinfo
->kwargs
);
450 dataset_name
= lua_tostring(state
, 1);
451 nvlist_t
*nv
= fnvlist_alloc();
453 dsl_dataset_t
*ds
= zcp_dataset_hold(state
, dp
, dataset_name
, FTAG
);
455 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
457 /* Get the names of all valid properties for this dataset */
458 zcp_dataset_props(ds
, nv
);
459 dsl_dataset_rele(ds
, FTAG
);
461 /* push list as lua table */
462 error
= zcp_nvlist_to_lua(state
, nv
, errbuf
, sizeof (errbuf
));
465 return (luaL_error(state
,
466 "Error returning nvlist: %s", errbuf
));
472 zcp_list_func(lua_State
*state
)
474 zcp_list_info_t
*info
= lua_touserdata(state
, lua_upvalueindex(1));
476 zcp_parse_args(state
, info
->name
, info
->pargs
, info
->kwargs
);
478 return (info
->func(state
));
482 zcp_load_list_lib(lua_State
*state
)
485 zcp_list_info_t
*zcp_list_funcs
[] = {
486 &zcp_children_list_info
,
487 &zcp_snapshots_list_info
,
488 &zcp_props_list_info
,
489 &zcp_clones_list_info
,
490 &zcp_system_props_list_info
,
496 for (i
= 0; zcp_list_funcs
[i
] != NULL
; i
++) {
497 zcp_list_info_t
*info
= zcp_list_funcs
[i
];
499 if (info
->gc
!= NULL
) {
501 * If the function requires garbage collection, create
502 * a metatable with its name and register the __gc
505 (void) luaL_newmetatable(state
, info
->name
);
506 (void) lua_pushstring(state
, "__gc");
507 lua_pushcfunction(state
, info
->gc
);
508 lua_settable(state
, -3);
512 lua_pushlightuserdata(state
, info
);
513 lua_pushcclosure(state
, &zcp_list_func
, 1);
514 lua_setfield(state
, -2, info
->name
);