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.
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 typedef int (zcp_list_func_t)(lua_State *);
37 typedef struct zcp_list_info {
39 zcp_list_func_t *func;
41 const zcp_arg_t pargs[4];
42 const zcp_arg_t kwargs[2];
46 zcp_clones_iter(lua_State *state)
49 char clonename[ZFS_MAX_DATASET_NAME_LEN];
50 uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
51 uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
52 dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
53 dsl_dataset_t *ds, *clone;
57 err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
60 } else if (err != 0) {
61 return (luaL_error(state,
62 "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
66 if (dsl_dataset_phys(ds)->ds_next_clones_obj == 0) {
67 dsl_dataset_rele(ds, FTAG);
71 zap_cursor_init_serialized(&zc, dp->dp_meta_objset,
72 dsl_dataset_phys(ds)->ds_next_clones_obj, cursor);
73 dsl_dataset_rele(ds, FTAG);
75 err = zap_cursor_retrieve(&zc, &za);
79 return (luaL_error(state,
80 "unexpected error %d from zap_cursor_retrieve()",
85 zap_cursor_advance(&zc);
86 cursor = zap_cursor_serialize(&zc);
89 err = dsl_dataset_hold_obj(dp, za.za_first_integer, FTAG, &clone);
91 return (luaL_error(state,
92 "unexpected error %d from "
93 "dsl_dataset_hold_obj(za_first_integer)", err));
96 dsl_dir_name(clone->ds_dir, clonename);
97 dsl_dataset_rele(clone, FTAG);
99 lua_pushnumber(state, cursor);
100 lua_replace(state, lua_upvalueindex(2));
102 (void) lua_pushstring(state, clonename);
106 static int zcp_clones_list(lua_State *);
107 static zcp_list_info_t zcp_clones_list_info = {
109 .func = zcp_clones_list,
112 { .za_name = "snapshot", .za_lua_type = LUA_TSTRING},
121 zcp_clones_list(lua_State *state)
123 const char *snapname = lua_tostring(state, 1);
124 dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
126 uint64_t dsobj, cursor;
129 * zcp_dataset_hold will either successfully return the requested
130 * dataset or throw a lua error and longjmp out of the zfs.list.clones
131 * call without returning.
133 dsl_dataset_t *ds = zcp_dataset_hold(state, dp, snapname, FTAG);
135 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
137 issnap = ds->ds_is_snapshot;
138 dsobj = ds->ds_object;
139 dsl_dataset_rele(ds, FTAG);
142 return (zcp_argerror(state, 1, "%s is not a snapshot",
146 lua_pushnumber(state, dsobj);
147 lua_pushnumber(state, cursor);
148 lua_pushcclosure(state, &zcp_clones_iter, 2);
153 zcp_snapshots_iter(lua_State *state)
156 char snapname[ZFS_MAX_DATASET_NAME_LEN];
157 uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
158 uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
159 dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
164 err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
166 return (luaL_error(state,
167 "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
171 dsl_dataset_name(ds, snapname);
172 VERIFY3U(sizeof (snapname), >,
173 strlcat(snapname, "@", sizeof (snapname)));
175 p = strchr(snapname, '\0');
176 VERIFY0(dmu_objset_from_ds(ds, &os));
177 err = dmu_snapshot_list_next(os,
178 sizeof (snapname) - (p - snapname), p, NULL, &cursor, NULL);
179 dsl_dataset_rele(ds, FTAG);
183 } else if (err != 0) {
184 return (luaL_error(state,
185 "unexpected error %d from dmu_snapshot_list_next()", err));
188 lua_pushnumber(state, cursor);
189 lua_replace(state, lua_upvalueindex(2));
191 (void) lua_pushstring(state, snapname);
195 static int zcp_snapshots_list(lua_State *);
196 static zcp_list_info_t zcp_snapshots_list_info = {
198 .func = zcp_snapshots_list,
201 { .za_name = "filesystem | volume", .za_lua_type = LUA_TSTRING},
210 zcp_snapshots_list(lua_State *state)
212 const char *fsname = lua_tostring(state, 1);
213 dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
217 dsl_dataset_t *ds = zcp_dataset_hold(state, dp, fsname, FTAG);
219 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
220 issnap = ds->ds_is_snapshot;
221 dsobj = ds->ds_object;
222 dsl_dataset_rele(ds, FTAG);
225 return (zcp_argerror(state, 1,
226 "argument %s cannot be a snapshot", fsname));
229 lua_pushnumber(state, dsobj);
230 lua_pushnumber(state, 0);
231 lua_pushcclosure(state, &zcp_snapshots_iter, 2);
236 * Note: channel programs only run in the global zone, so all datasets
237 * are visible to this zone.
240 dataset_name_hidden(const char *name)
242 if (strchr(name, '$') != NULL)
244 if (strchr(name, '%') != NULL)
250 zcp_children_iter(lua_State *state)
253 char childname[ZFS_MAX_DATASET_NAME_LEN];
254 uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
255 uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
256 zcp_run_info_t *ri = zcp_run_info(state);
257 dsl_pool_t *dp = ri->zri_pool;
262 err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
264 return (luaL_error(state,
265 "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
269 dsl_dataset_name(ds, childname);
270 VERIFY3U(sizeof (childname), >,
271 strlcat(childname, "/", sizeof (childname)));
272 p = strchr(childname, '\0');
274 VERIFY0(dmu_objset_from_ds(ds, &os));
276 err = dmu_dir_list_next(os,
277 sizeof (childname) - (p - childname), p, NULL, &cursor);
278 } while (err == 0 && dataset_name_hidden(childname));
279 dsl_dataset_rele(ds, FTAG);
283 } else if (err != 0) {
284 return (luaL_error(state,
285 "unexpected error %d from dmu_dir_list_next()",
289 lua_pushnumber(state, cursor);
290 lua_replace(state, lua_upvalueindex(2));
292 (void) lua_pushstring(state, childname);
296 static int zcp_children_list(lua_State *);
297 static zcp_list_info_t zcp_children_list_info = {
299 .func = zcp_children_list,
302 { .za_name = "filesystem | volume", .za_lua_type = LUA_TSTRING},
311 zcp_children_list(lua_State *state)
313 const char *fsname = lua_tostring(state, 1);
314 dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
318 dsl_dataset_t *ds = zcp_dataset_hold(state, dp, fsname, FTAG);
320 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
322 issnap = ds->ds_is_snapshot;
323 dsobj = ds->ds_object;
324 dsl_dataset_rele(ds, FTAG);
327 return (zcp_argerror(state, 1,
328 "argument %s cannot be a snapshot", fsname));
331 lua_pushnumber(state, dsobj);
332 lua_pushnumber(state, 0);
333 lua_pushcclosure(state, &zcp_children_iter, 2);
338 zcp_props_list_gc(lua_State *state)
340 nvlist_t **props = lua_touserdata(state, 1);
342 fnvlist_free(*props);
347 zcp_props_iter(lua_State *state)
351 nvlist_t **props = lua_touserdata(state, lua_upvalueindex(1));
352 nvpair_t *pair = lua_touserdata(state, lua_upvalueindex(2));
355 pair = nvlist_next_nvpair(*props, pair);
357 fnvlist_free(*props);
361 } while (!zfs_prop_user(nvpair_name(pair)));
363 lua_pushlightuserdata(state, pair);
364 lua_replace(state, lua_upvalueindex(2));
366 nvprop = fnvpair_value_nvlist(pair);
367 val = fnvlist_lookup_string(nvprop, ZPROP_VALUE);
368 source = fnvlist_lookup_string(nvprop, ZPROP_SOURCE);
370 (void) lua_pushstring(state, nvpair_name(pair));
371 (void) lua_pushstring(state, val);
372 (void) lua_pushstring(state, source);
376 static int zcp_props_list(lua_State *);
377 static zcp_list_info_t zcp_props_list_info = {
378 .name = "properties",
379 .func = zcp_props_list,
380 .gc = zcp_props_list_gc,
382 { .za_name = "filesystem | snapshot | volume",
383 .za_lua_type = LUA_TSTRING},
392 zcp_props_list(lua_State *state)
394 const char *dsname = lua_tostring(state, 1);
395 dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
397 nvlist_t **props = lua_newuserdata(state, sizeof (nvlist_t *));
399 dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dsname, FTAG);
401 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
402 VERIFY0(dmu_objset_from_ds(ds, &os));
403 VERIFY0(dsl_prop_get_all(os, props));
404 dsl_dataset_rele(ds, FTAG);
407 * Set the metatable for the properties list to free it on completion.
409 luaL_getmetatable(state, zcp_props_list_info.name);
410 (void) lua_setmetatable(state, -2);
412 lua_pushlightuserdata(state, NULL);
413 lua_pushcclosure(state, &zcp_props_iter, 2);
419 * Populate nv with all valid properties and their values for the given
423 zcp_dataset_props(dsl_dataset_t *ds, nvlist_t *nv)
425 for (int prop = ZFS_PROP_TYPE; prop < ZFS_NUM_PROPS; prop++) {
426 /* Do not display hidden props */
427 if (!zfs_prop_visible(prop))
429 /* Do not display props not valid for this dataset */
430 if (!prop_valid_for_ds(ds, prop))
432 fnvlist_add_boolean(nv, zfs_prop_to_name(prop));
436 static int zcp_system_props_list(lua_State *);
437 static zcp_list_info_t zcp_system_props_list_info = {
438 .name = "system_properties",
439 .func = zcp_system_props_list,
441 { .za_name = "dataset", .za_lua_type = LUA_TSTRING},
450 * Get a list of all visble properties and their values for a given dataset.
451 * Returned on the stack as a Lua table.
454 zcp_system_props_list(lua_State *state)
458 const char *dataset_name;
459 dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
460 zcp_list_info_t *libinfo = &zcp_system_props_list_info;
461 zcp_parse_args(state, libinfo->name, libinfo->pargs, libinfo->kwargs);
462 dataset_name = lua_tostring(state, 1);
463 nvlist_t *nv = fnvlist_alloc();
465 dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dataset_name, FTAG);
467 return (1); /* not reached; zcp_dataset_hold() longjmp'd */
469 /* Get the names of all valid properties for this dataset */
470 zcp_dataset_props(ds, nv);
471 dsl_dataset_rele(ds, FTAG);
473 /* push list as lua table */
474 error = zcp_nvlist_to_lua(state, nv, errbuf, sizeof (errbuf));
477 return (luaL_error(state,
478 "Error returning nvlist: %s", errbuf));
484 zcp_list_func(lua_State *state)
486 zcp_list_info_t *info = lua_touserdata(state, lua_upvalueindex(1));
488 zcp_parse_args(state, info->name, info->pargs, info->kwargs);
490 return (info->func(state));
494 zcp_load_list_lib(lua_State *state)
497 zcp_list_info_t *zcp_list_funcs[] = {
498 &zcp_children_list_info,
499 &zcp_snapshots_list_info,
500 &zcp_props_list_info,
501 &zcp_clones_list_info,
502 &zcp_system_props_list_info,
508 for (i = 0; zcp_list_funcs[i] != NULL; i++) {
509 zcp_list_info_t *info = zcp_list_funcs[i];
511 if (info->gc != NULL) {
513 * If the function requires garbage collection, create
514 * a metatable with its name and register the __gc
517 (void) luaL_newmetatable(state, info->name);
518 (void) lua_pushstring(state, "__gc");
519 lua_pushcfunction(state, info->gc);
520 lua_settable(state, -3);
524 lua_pushlightuserdata(state, info);
525 lua_pushcclosure(state, &zcp_list_func, 1);
526 lua_setfield(state, -2, info->name);