xref: /illumos-gate/usr/src/uts/common/fs/zfs/zcp_iter.c (revision dd328bf6)
1dfc11533SChris Williamson /*
2dfc11533SChris Williamson  * CDDL HEADER START
3dfc11533SChris Williamson  *
4dfc11533SChris Williamson  * This file and its contents are supplied under the terms of the
5dfc11533SChris Williamson  * Common Development and Distribution License ("CDDL"), version 1.0.
6dfc11533SChris Williamson  * You may only use this file in accordance with the terms of version
7dfc11533SChris Williamson  * 1.0 of the CDDL.
8dfc11533SChris Williamson  *
9dfc11533SChris Williamson  * A full copy of the text of the CDDL should have accompanied this
10dfc11533SChris Williamson  * source.  A copy of the CDDL is also available via the Internet at
11dfc11533SChris Williamson  * http://www.illumos.org/license/CDDL.
12dfc11533SChris Williamson  *
13dfc11533SChris Williamson  * CDDL HEADER END
14dfc11533SChris Williamson  */
15dfc11533SChris Williamson 
16dfc11533SChris Williamson /*
17dfc11533SChris Williamson  * Copyright (c) 2016 by Delphix. All rights reserved.
18dfc11533SChris Williamson  */
19dfc11533SChris Williamson 
20dfc11533SChris Williamson #include "lua.h"
21dfc11533SChris Williamson #include "lauxlib.h"
22dfc11533SChris Williamson 
23dfc11533SChris Williamson #include <sys/dmu.h>
24dfc11533SChris Williamson #include <sys/dsl_prop.h>
25dfc11533SChris Williamson #include <sys/dsl_synctask.h>
26dfc11533SChris Williamson #include <sys/dsl_dataset.h>
27dfc11533SChris Williamson #include <sys/dsl_pool.h>
28dfc11533SChris Williamson #include <sys/dmu_tx.h>
29dfc11533SChris Williamson #include <sys/dmu_objset.h>
30dfc11533SChris Williamson #include <sys/zap.h>
31dfc11533SChris Williamson #include <sys/dsl_dir.h>
32dfc11533SChris Williamson #include <sys/zcp_prop.h>
33dfc11533SChris Williamson 
34dfc11533SChris Williamson #include <sys/zcp.h>
35dfc11533SChris Williamson 
36dfc11533SChris Williamson typedef int (zcp_list_func_t)(lua_State *);
37dfc11533SChris Williamson typedef struct zcp_list_info {
38dfc11533SChris Williamson 	const char *name;
39dfc11533SChris Williamson 	zcp_list_func_t *func;
40dfc11533SChris Williamson 	zcp_list_func_t *gc;
41dfc11533SChris Williamson 	const zcp_arg_t pargs[4];
42dfc11533SChris Williamson 	const zcp_arg_t kwargs[2];
43dfc11533SChris Williamson } zcp_list_info_t;
44dfc11533SChris Williamson 
45dfc11533SChris Williamson static int
zcp_clones_iter(lua_State * state)46dfc11533SChris Williamson zcp_clones_iter(lua_State *state)
47dfc11533SChris Williamson {
48dfc11533SChris Williamson 	int err;
49dfc11533SChris Williamson 	char clonename[ZFS_MAX_DATASET_NAME_LEN];
50dfc11533SChris Williamson 	uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
51dfc11533SChris Williamson 	uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
52dfc11533SChris Williamson 	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
53dfc11533SChris Williamson 	dsl_dataset_t *ds, *clone;
54dfc11533SChris Williamson 	zap_attribute_t za;
55dfc11533SChris Williamson 	zap_cursor_t zc;
56dfc11533SChris Williamson 
57dfc11533SChris Williamson 	err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
58dfc11533SChris Williamson 	if (err == ENOENT) {
59dfc11533SChris Williamson 		return (0);
60dfc11533SChris Williamson 	} else if (err != 0) {
61dfc11533SChris Williamson 		return (luaL_error(state,
62dfc11533SChris Williamson 		    "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
63dfc11533SChris Williamson 		    err));
64dfc11533SChris Williamson 	}
65dfc11533SChris Williamson 
66dfc11533SChris Williamson 	if (dsl_dataset_phys(ds)->ds_next_clones_obj == 0) {
67dfc11533SChris Williamson 		dsl_dataset_rele(ds, FTAG);
68dfc11533SChris Williamson 		return (0);
69dfc11533SChris Williamson 	}
70dfc11533SChris Williamson 
71dfc11533SChris Williamson 	zap_cursor_init_serialized(&zc, dp->dp_meta_objset,
72dfc11533SChris Williamson 	    dsl_dataset_phys(ds)->ds_next_clones_obj, cursor);
73dfc11533SChris Williamson 	dsl_dataset_rele(ds, FTAG);
74dfc11533SChris Williamson 
75dfc11533SChris Williamson 	err = zap_cursor_retrieve(&zc, &za);
76dfc11533SChris Williamson 	if (err != 0) {
77dfc11533SChris Williamson 		zap_cursor_fini(&zc);
78dfc11533SChris Williamson 		if (err != ENOENT) {
79dfc11533SChris Williamson 			return (luaL_error(state,
80dfc11533SChris Williamson 			    "unexpected error %d from zap_cursor_retrieve()",
81dfc11533SChris Williamson 			    err));
82dfc11533SChris Williamson 		}
83dfc11533SChris Williamson 		return (0);
84dfc11533SChris Williamson 	}
85dfc11533SChris Williamson 	zap_cursor_advance(&zc);
86dfc11533SChris Williamson 	cursor = zap_cursor_serialize(&zc);
87dfc11533SChris Williamson 	zap_cursor_fini(&zc);
88dfc11533SChris Williamson 
89dfc11533SChris Williamson 	err = dsl_dataset_hold_obj(dp, za.za_first_integer, FTAG, &clone);
90dfc11533SChris Williamson 	if (err != 0) {
91dfc11533SChris Williamson 		return (luaL_error(state,
92dfc11533SChris Williamson 		    "unexpected error %d from "
93dfc11533SChris Williamson 		    "dsl_dataset_hold_obj(za_first_integer)", err));
94dfc11533SChris Williamson 	}
95dfc11533SChris Williamson 
96dfc11533SChris Williamson 	dsl_dir_name(clone->ds_dir, clonename);
97dfc11533SChris Williamson 	dsl_dataset_rele(clone, FTAG);
98dfc11533SChris Williamson 
99dfc11533SChris Williamson 	lua_pushnumber(state, cursor);
100dfc11533SChris Williamson 	lua_replace(state, lua_upvalueindex(2));
101dfc11533SChris Williamson 
102dfc11533SChris Williamson 	(void) lua_pushstring(state, clonename);
103dfc11533SChris Williamson 	return (1);
104dfc11533SChris Williamson }
105dfc11533SChris Williamson 
106dfc11533SChris Williamson static int zcp_clones_list(lua_State *);
107dfc11533SChris Williamson static zcp_list_info_t zcp_clones_list_info = {
108dfc11533SChris Williamson 	.name = "clones",
109dfc11533SChris Williamson 	.func = zcp_clones_list,
110dfc11533SChris Williamson 	.gc = NULL,
111dfc11533SChris Williamson 	.pargs = {
112dfc11533SChris Williamson 	    { .za_name = "snapshot", .za_lua_type = LUA_TSTRING},
113*dd328bf6SToomas Soome 	    {NULL, 0}
114dfc11533SChris Williamson 	},
115dfc11533SChris Williamson 	.kwargs = {
116*dd328bf6SToomas Soome 	    {NULL, 0}
117dfc11533SChris Williamson 	}
118dfc11533SChris Williamson };
119dfc11533SChris Williamson 
120dfc11533SChris Williamson static int
zcp_clones_list(lua_State * state)121dfc11533SChris Williamson zcp_clones_list(lua_State *state)
122dfc11533SChris Williamson {
123dfc11533SChris Williamson 	const char *snapname = lua_tostring(state, 1);
124dfc11533SChris Williamson 	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
125dfc11533SChris Williamson 	boolean_t issnap;
126dfc11533SChris Williamson 	uint64_t dsobj, cursor;
127dfc11533SChris Williamson 
128dfc11533SChris Williamson 	/*
129dfc11533SChris Williamson 	 * zcp_dataset_hold will either successfully return the requested
130dfc11533SChris Williamson 	 * dataset or throw a lua error and longjmp out of the zfs.list.clones
131dfc11533SChris Williamson 	 * call without returning.
132dfc11533SChris Williamson 	 */
133dfc11533SChris Williamson 	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, snapname, FTAG);
134dfc11533SChris Williamson 	if (ds == NULL)
135dfc11533SChris Williamson 		return (1); /* not reached; zcp_dataset_hold() longjmp'd */
136dfc11533SChris Williamson 	cursor = 0;
137dfc11533SChris Williamson 	issnap = ds->ds_is_snapshot;
138dfc11533SChris Williamson 	dsobj = ds->ds_object;
139dfc11533SChris Williamson 	dsl_dataset_rele(ds, FTAG);
140dfc11533SChris Williamson 
141dfc11533SChris Williamson 	if (!issnap) {
142dfc11533SChris Williamson 		return (zcp_argerror(state, 1, "%s is not a snapshot",
143dfc11533SChris Williamson 		    snapname));
144dfc11533SChris Williamson 	}
145dfc11533SChris Williamson 
146dfc11533SChris Williamson 	lua_pushnumber(state, dsobj);
147dfc11533SChris Williamson 	lua_pushnumber(state, cursor);
148dfc11533SChris Williamson 	lua_pushcclosure(state, &zcp_clones_iter, 2);
149dfc11533SChris Williamson 	return (1);
150dfc11533SChris Williamson }
151dfc11533SChris Williamson 
152dfc11533SChris Williamson static int
zcp_snapshots_iter(lua_State * state)153dfc11533SChris Williamson zcp_snapshots_iter(lua_State *state)
154dfc11533SChris Williamson {
155dfc11533SChris Williamson 	int err;
156dfc11533SChris Williamson 	char snapname[ZFS_MAX_DATASET_NAME_LEN];
157dfc11533SChris Williamson 	uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
158dfc11533SChris Williamson 	uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
159dfc11533SChris Williamson 	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
160dfc11533SChris Williamson 	dsl_dataset_t *ds;
161dfc11533SChris Williamson 	objset_t *os;
162dfc11533SChris Williamson 	char *p;
163dfc11533SChris Williamson 
164dfc11533SChris Williamson 	err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
165dfc11533SChris Williamson 	if (err != 0) {
166dfc11533SChris Williamson 		return (luaL_error(state,
167dfc11533SChris Williamson 		    "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
168dfc11533SChris Williamson 		    err));
169dfc11533SChris Williamson 	}
170dfc11533SChris Williamson 
171dfc11533SChris Williamson 	dsl_dataset_name(ds, snapname);
172dfc11533SChris Williamson 	VERIFY3U(sizeof (snapname), >,
173dfc11533SChris Williamson 	    strlcat(snapname, "@", sizeof (snapname)));
174dfc11533SChris Williamson 
175dfc11533SChris Williamson 	p = strchr(snapname, '\0');
176dfc11533SChris Williamson 	VERIFY0(dmu_objset_from_ds(ds, &os));
177dfc11533SChris Williamson 	err = dmu_snapshot_list_next(os,
178dfc11533SChris Williamson 	    sizeof (snapname) - (p - snapname), p, NULL, &cursor, NULL);
179dfc11533SChris Williamson 	dsl_dataset_rele(ds, FTAG);
180dfc11533SChris Williamson 
181dfc11533SChris Williamson 	if (err == ENOENT) {
182dfc11533SChris Williamson 		return (0);
183dfc11533SChris Williamson 	} else if (err != 0) {
184dfc11533SChris Williamson 		return (luaL_error(state,
185dfc11533SChris Williamson 		    "unexpected error %d from dmu_snapshot_list_next()", err));
186dfc11533SChris Williamson 	}
187dfc11533SChris Williamson 
188dfc11533SChris Williamson 	lua_pushnumber(state, cursor);
189dfc11533SChris Williamson 	lua_replace(state, lua_upvalueindex(2));
190dfc11533SChris Williamson 
191dfc11533SChris Williamson 	(void) lua_pushstring(state, snapname);
192dfc11533SChris Williamson 	return (1);
193dfc11533SChris Williamson }
194dfc11533SChris Williamson 
195dfc11533SChris Williamson static int zcp_snapshots_list(lua_State *);
196dfc11533SChris Williamson static zcp_list_info_t zcp_snapshots_list_info = {
197dfc11533SChris Williamson 	.name = "snapshots",
198dfc11533SChris Williamson 	.func = zcp_snapshots_list,
199dfc11533SChris Williamson 	.gc = NULL,
200dfc11533SChris Williamson 	.pargs = {
201dfc11533SChris Williamson 	    { .za_name = "filesystem | volume", .za_lua_type = LUA_TSTRING},
202*dd328bf6SToomas Soome 	    {NULL, 0}
203dfc11533SChris Williamson 	},
204dfc11533SChris Williamson 	.kwargs = {
205*dd328bf6SToomas Soome 	    {NULL, 0}
206dfc11533SChris Williamson 	}
207dfc11533SChris Williamson };
208dfc11533SChris Williamson 
209dfc11533SChris Williamson static int
zcp_snapshots_list(lua_State * state)210dfc11533SChris Williamson zcp_snapshots_list(lua_State *state)
211dfc11533SChris Williamson {
212dfc11533SChris Williamson 	const char *fsname = lua_tostring(state, 1);
213dfc11533SChris Williamson 	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
214dfc11533SChris Williamson 	boolean_t issnap;
215dfc11533SChris Williamson 	uint64_t dsobj;
216dfc11533SChris Williamson 
217dfc11533SChris Williamson 	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, fsname, FTAG);
218dfc11533SChris Williamson 	if (ds == NULL)
219dfc11533SChris Williamson 		return (1); /* not reached; zcp_dataset_hold() longjmp'd */
220dfc11533SChris Williamson 	issnap = ds->ds_is_snapshot;
221dfc11533SChris Williamson 	dsobj = ds->ds_object;
222dfc11533SChris Williamson 	dsl_dataset_rele(ds, FTAG);
223dfc11533SChris Williamson 
224dfc11533SChris Williamson 	if (issnap) {
225dfc11533SChris Williamson 		return (zcp_argerror(state, 1,
226dfc11533SChris Williamson 		    "argument %s cannot be a snapshot", fsname));
227dfc11533SChris Williamson 	}
228dfc11533SChris Williamson 
229dfc11533SChris Williamson 	lua_pushnumber(state, dsobj);
230dfc11533SChris Williamson 	lua_pushnumber(state, 0);
231dfc11533SChris Williamson 	lua_pushcclosure(state, &zcp_snapshots_iter, 2);
232dfc11533SChris Williamson 	return (1);
233dfc11533SChris Williamson }
234dfc11533SChris Williamson 
235dfc11533SChris Williamson /*
236dfc11533SChris Williamson  * Note: channel programs only run in the global zone, so all datasets
237dfc11533SChris Williamson  * are visible to this zone.
238dfc11533SChris Williamson  */
239dfc11533SChris Williamson static boolean_t
dataset_name_hidden(const char * name)240dfc11533SChris Williamson dataset_name_hidden(const char *name)
241dfc11533SChris Williamson {
242dfc11533SChris Williamson 	if (strchr(name, '$') != NULL)
243dfc11533SChris Williamson 		return (B_TRUE);
244dfc11533SChris Williamson 	if (strchr(name, '%') != NULL)
245dfc11533SChris Williamson 		return (B_TRUE);
246dfc11533SChris Williamson 	return (B_FALSE);
247dfc11533SChris Williamson }
248dfc11533SChris Williamson 
249dfc11533SChris Williamson static int
zcp_children_iter(lua_State * state)250dfc11533SChris Williamson zcp_children_iter(lua_State *state)
251dfc11533SChris Williamson {
252dfc11533SChris Williamson 	int err;
253dfc11533SChris Williamson 	char childname[ZFS_MAX_DATASET_NAME_LEN];
254dfc11533SChris Williamson 	uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
255dfc11533SChris Williamson 	uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
256dfc11533SChris Williamson 	zcp_run_info_t *ri = zcp_run_info(state);
257dfc11533SChris Williamson 	dsl_pool_t *dp = ri->zri_pool;
258dfc11533SChris Williamson 	dsl_dataset_t *ds;
259dfc11533SChris Williamson 	objset_t *os;
260dfc11533SChris Williamson 	char *p;
261dfc11533SChris Williamson 
262dfc11533SChris Williamson 	err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
263dfc11533SChris Williamson 	if (err != 0) {
264dfc11533SChris Williamson 		return (luaL_error(state,
265dfc11533SChris Williamson 		    "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
266dfc11533SChris Williamson 		    err));
267dfc11533SChris Williamson 	}
268dfc11533SChris Williamson 
269dfc11533SChris Williamson 	dsl_dataset_name(ds, childname);
270dfc11533SChris Williamson 	VERIFY3U(sizeof (childname), >,
271dfc11533SChris Williamson 	    strlcat(childname, "/", sizeof (childname)));
272dfc11533SChris Williamson 	p = strchr(childname, '\0');
273dfc11533SChris Williamson 
274dfc11533SChris Williamson 	VERIFY0(dmu_objset_from_ds(ds, &os));
275dfc11533SChris Williamson 	do {
276dfc11533SChris Williamson 		err = dmu_dir_list_next(os,
277dfc11533SChris Williamson 		    sizeof (childname) - (p - childname), p, NULL, &cursor);
278dfc11533SChris Williamson 	} while (err == 0 && dataset_name_hidden(childname));
279dfc11533SChris Williamson 	dsl_dataset_rele(ds, FTAG);
280dfc11533SChris Williamson 
281dfc11533SChris Williamson 	if (err == ENOENT) {
282dfc11533SChris Williamson 		return (0);
283dfc11533SChris Williamson 	} else if (err != 0) {
284dfc11533SChris Williamson 		return (luaL_error(state,
285dfc11533SChris Williamson 		    "unexpected error %d from dmu_dir_list_next()",
286dfc11533SChris Williamson 		    err));
287dfc11533SChris Williamson 	}
288dfc11533SChris Williamson 
289dfc11533SChris Williamson 	lua_pushnumber(state, cursor);
290dfc11533SChris Williamson 	lua_replace(state, lua_upvalueindex(2));
291dfc11533SChris Williamson 
292dfc11533SChris Williamson 	(void) lua_pushstring(state, childname);
293dfc11533SChris Williamson 	return (1);
294dfc11533SChris Williamson }
295dfc11533SChris Williamson 
296dfc11533SChris Williamson static int zcp_children_list(lua_State *);
297dfc11533SChris Williamson static zcp_list_info_t zcp_children_list_info = {
298dfc11533SChris Williamson 	.name = "children",
299dfc11533SChris Williamson 	.func = zcp_children_list,
300dfc11533SChris Williamson 	.gc = NULL,
301dfc11533SChris Williamson 	.pargs = {
302dfc11533SChris Williamson 	    { .za_name = "filesystem | volume", .za_lua_type = LUA_TSTRING},
303*dd328bf6SToomas Soome 	    {NULL, 0}
304dfc11533SChris Williamson 	},
305dfc11533SChris Williamson 	.kwargs = {
306*dd328bf6SToomas Soome 	    {NULL, 0}
307dfc11533SChris Williamson 	}
308dfc11533SChris Williamson };
309dfc11533SChris Williamson 
310dfc11533SChris Williamson static int
zcp_children_list(lua_State * state)311dfc11533SChris Williamson zcp_children_list(lua_State *state)
312dfc11533SChris Williamson {
313dfc11533SChris Williamson 	const char *fsname = lua_tostring(state, 1);
314dfc11533SChris Williamson 	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
315dfc11533SChris Williamson 	boolean_t issnap;
316dfc11533SChris Williamson 	uint64_t dsobj;
317dfc11533SChris Williamson 
318dfc11533SChris Williamson 	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, fsname, FTAG);
319dfc11533SChris Williamson 	if (ds == NULL)
320dfc11533SChris Williamson 		return (1); /* not reached; zcp_dataset_hold() longjmp'd */
321dfc11533SChris Williamson 
322dfc11533SChris Williamson 	issnap = ds->ds_is_snapshot;
323dfc11533SChris Williamson 	dsobj = ds->ds_object;
324dfc11533SChris Williamson 	dsl_dataset_rele(ds, FTAG);
325dfc11533SChris Williamson 
326dfc11533SChris Williamson 	if (issnap) {
327dfc11533SChris Williamson 		return (zcp_argerror(state, 1,
328dfc11533SChris Williamson 		    "argument %s cannot be a snapshot", fsname));
329dfc11533SChris Williamson 	}
330dfc11533SChris Williamson 
331dfc11533SChris Williamson 	lua_pushnumber(state, dsobj);
332dfc11533SChris Williamson 	lua_pushnumber(state, 0);
333dfc11533SChris Williamson 	lua_pushcclosure(state, &zcp_children_iter, 2);
334dfc11533SChris Williamson 	return (1);
335dfc11533SChris Williamson }
336dfc11533SChris Williamson 
337dfc11533SChris Williamson static int
zcp_props_list_gc(lua_State * state)338dfc11533SChris Williamson zcp_props_list_gc(lua_State *state)
339dfc11533SChris Williamson {
340dfc11533SChris Williamson 	nvlist_t **props = lua_touserdata(state, 1);
341dfc11533SChris Williamson 	if (*props != NULL)
342dfc11533SChris Williamson 		fnvlist_free(*props);
343dfc11533SChris Williamson 	return (0);
344dfc11533SChris Williamson }
345dfc11533SChris Williamson 
346dfc11533SChris Williamson static int
zcp_props_iter(lua_State * state)347dfc11533SChris Williamson zcp_props_iter(lua_State *state)
348dfc11533SChris Williamson {
349dfc11533SChris Williamson 	char *source, *val;
350dfc11533SChris Williamson 	nvlist_t *nvprop;
351dfc11533SChris Williamson 	nvlist_t **props = lua_touserdata(state, lua_upvalueindex(1));
352dfc11533SChris Williamson 	nvpair_t *pair = lua_touserdata(state, lua_upvalueindex(2));
353dfc11533SChris Williamson 
354dfc11533SChris Williamson 	do {
355dfc11533SChris Williamson 		pair = nvlist_next_nvpair(*props, pair);
356dfc11533SChris Williamson 		if (pair == NULL) {
357dfc11533SChris Williamson 			fnvlist_free(*props);
358dfc11533SChris Williamson 			*props = NULL;
359dfc11533SChris Williamson 			return (0);
360dfc11533SChris Williamson 		}
361dfc11533SChris Williamson 	} while (!zfs_prop_user(nvpair_name(pair)));
362dfc11533SChris Williamson 
363dfc11533SChris Williamson 	lua_pushlightuserdata(state, pair);
364dfc11533SChris Williamson 	lua_replace(state, lua_upvalueindex(2));
365dfc11533SChris Williamson 
366dfc11533SChris Williamson 	nvprop = fnvpair_value_nvlist(pair);
367dfc11533SChris Williamson 	val = fnvlist_lookup_string(nvprop, ZPROP_VALUE);
368dfc11533SChris Williamson 	source = fnvlist_lookup_string(nvprop, ZPROP_SOURCE);
369dfc11533SChris Williamson 
370dfc11533SChris Williamson 	(void) lua_pushstring(state, nvpair_name(pair));
371dfc11533SChris Williamson 	(void) lua_pushstring(state, val);
372dfc11533SChris Williamson 	(void) lua_pushstring(state, source);
373dfc11533SChris Williamson 	return (3);
374dfc11533SChris Williamson }
375dfc11533SChris Williamson 
376dfc11533SChris Williamson static int zcp_props_list(lua_State *);
377dfc11533SChris Williamson static zcp_list_info_t zcp_props_list_info = {
378dfc11533SChris Williamson 	.name = "properties",
379dfc11533SChris Williamson 	.func = zcp_props_list,
380dfc11533SChris Williamson 	.gc = zcp_props_list_gc,
381dfc11533SChris Williamson 	.pargs = {
382dfc11533SChris Williamson 	    { .za_name = "filesystem | snapshot | volume",
383dfc11533SChris Williamson 	    .za_lua_type = LUA_TSTRING},
384*dd328bf6SToomas Soome 	    {NULL, 0}
385dfc11533SChris Williamson 	},
386dfc11533SChris Williamson 	.kwargs = {
387*dd328bf6SToomas Soome 	    {NULL, 0}
388dfc11533SChris Williamson 	}
389dfc11533SChris Williamson };
390dfc11533SChris Williamson 
391dfc11533SChris Williamson static int
zcp_props_list(lua_State * state)392dfc11533SChris Williamson zcp_props_list(lua_State *state)
393dfc11533SChris Williamson {
394dfc11533SChris Williamson 	const char *dsname = lua_tostring(state, 1);
395dfc11533SChris Williamson 	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
396dfc11533SChris Williamson 	objset_t *os;
397dfc11533SChris Williamson 	nvlist_t **props = lua_newuserdata(state, sizeof (nvlist_t *));
398dfc11533SChris Williamson 
399dfc11533SChris Williamson 	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dsname, FTAG);
400dfc11533SChris Williamson 	if (ds == NULL)
401dfc11533SChris Williamson 		return (1); /* not reached; zcp_dataset_hold() longjmp'd */
402dfc11533SChris Williamson 	VERIFY0(dmu_objset_from_ds(ds, &os));
403dfc11533SChris Williamson 	VERIFY0(dsl_prop_get_all(os, props));
404dfc11533SChris Williamson 	dsl_dataset_rele(ds, FTAG);
405dfc11533SChris Williamson 
406dfc11533SChris Williamson 	/*
407dfc11533SChris Williamson 	 * Set the metatable for the properties list to free it on completion.
408dfc11533SChris Williamson 	 */
409dfc11533SChris Williamson 	luaL_getmetatable(state, zcp_props_list_info.name);
410dfc11533SChris Williamson 	(void) lua_setmetatable(state, -2);
411dfc11533SChris Williamson 
412dfc11533SChris Williamson 	lua_pushlightuserdata(state, NULL);
413dfc11533SChris Williamson 	lua_pushcclosure(state, &zcp_props_iter, 2);
414dfc11533SChris Williamson 	return (1);
415dfc11533SChris Williamson }
416dfc11533SChris Williamson 
417dfc11533SChris Williamson 
418dfc11533SChris Williamson /*
419dfc11533SChris Williamson  * Populate nv with all valid properties and their values for the given
420dfc11533SChris Williamson  * dataset.
421dfc11533SChris Williamson  */
422dfc11533SChris Williamson static void
zcp_dataset_props(dsl_dataset_t * ds,nvlist_t * nv)423dfc11533SChris Williamson zcp_dataset_props(dsl_dataset_t *ds, nvlist_t *nv)
424dfc11533SChris Williamson {
425dfc11533SChris Williamson 	for (int prop = ZFS_PROP_TYPE; prop < ZFS_NUM_PROPS; prop++) {
426dfc11533SChris Williamson 		/* Do not display hidden props */
427dfc11533SChris Williamson 		if (!zfs_prop_visible(prop))
428dfc11533SChris Williamson 			continue;
429dfc11533SChris Williamson 		/* Do not display props not valid for this dataset */
430dfc11533SChris Williamson 		if (!prop_valid_for_ds(ds, prop))
431dfc11533SChris Williamson 			continue;
432dfc11533SChris Williamson 		fnvlist_add_boolean(nv, zfs_prop_to_name(prop));
433dfc11533SChris Williamson 	}
434dfc11533SChris Williamson }
435dfc11533SChris Williamson 
436dfc11533SChris Williamson static int zcp_system_props_list(lua_State *);
437dfc11533SChris Williamson static zcp_list_info_t zcp_system_props_list_info = {
438dfc11533SChris Williamson 	.name = "system_properties",
439dfc11533SChris Williamson 	.func = zcp_system_props_list,
440dfc11533SChris Williamson 	.pargs = {
441dfc11533SChris Williamson 	    { .za_name = "dataset", .za_lua_type = LUA_TSTRING},
442*dd328bf6SToomas Soome 	    {NULL, 0}
443dfc11533SChris Williamson 	},
444dfc11533SChris Williamson 	.kwargs = {
445*dd328bf6SToomas Soome 	    {NULL, 0}
446dfc11533SChris Williamson 	}
447dfc11533SChris Williamson };
448dfc11533SChris Williamson 
449dfc11533SChris Williamson /*
450dfc11533SChris Williamson  * Get a list of all visble properties and their values for a given dataset.
451dfc11533SChris Williamson  * Returned on the stack as a Lua table.
452dfc11533SChris Williamson  */
453dfc11533SChris Williamson static int
zcp_system_props_list(lua_State * state)454dfc11533SChris Williamson zcp_system_props_list(lua_State *state)
455dfc11533SChris Williamson {
456dfc11533SChris Williamson 	int error;
457dfc11533SChris Williamson 	char errbuf[128];
458dfc11533SChris Williamson 	const char *dataset_name;
459dfc11533SChris Williamson 	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
460dfc11533SChris Williamson 	zcp_list_info_t *libinfo = &zcp_system_props_list_info;
461dfc11533SChris Williamson 	zcp_parse_args(state, libinfo->name, libinfo->pargs, libinfo->kwargs);
462dfc11533SChris Williamson 	dataset_name = lua_tostring(state, 1);
463dfc11533SChris Williamson 	nvlist_t *nv = fnvlist_alloc();
464dfc11533SChris Williamson 
465dfc11533SChris Williamson 	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dataset_name, FTAG);
466dfc11533SChris Williamson 	if (ds == NULL)
467dfc11533SChris Williamson 		return (1); /* not reached; zcp_dataset_hold() longjmp'd */
468dfc11533SChris Williamson 
469dfc11533SChris Williamson 	/* Get the names of all valid properties for this dataset */
470dfc11533SChris Williamson 	zcp_dataset_props(ds, nv);
471dfc11533SChris Williamson 	dsl_dataset_rele(ds, FTAG);
472dfc11533SChris Williamson 
473dfc11533SChris Williamson 	/* push list as lua table */
474dfc11533SChris Williamson 	error = zcp_nvlist_to_lua(state, nv, errbuf, sizeof (errbuf));
475dfc11533SChris Williamson 	nvlist_free(nv);
476dfc11533SChris Williamson 	if (error != 0) {
477dfc11533SChris Williamson 		return (luaL_error(state,
478dfc11533SChris Williamson 		    "Error returning nvlist: %s", errbuf));
479dfc11533SChris Williamson 	}
480dfc11533SChris Williamson 	return (1);
481dfc11533SChris Williamson }
482dfc11533SChris Williamson 
483dfc11533SChris Williamson static int
zcp_list_func(lua_State * state)484dfc11533SChris Williamson zcp_list_func(lua_State *state)
485dfc11533SChris Williamson {
486dfc11533SChris Williamson 	zcp_list_info_t *info = lua_touserdata(state, lua_upvalueindex(1));
487dfc11533SChris Williamson 
488dfc11533SChris Williamson 	zcp_parse_args(state, info->name, info->pargs, info->kwargs);
489dfc11533SChris Williamson 
490dfc11533SChris Williamson 	return (info->func(state));
491dfc11533SChris Williamson }
492dfc11533SChris Williamson 
493dfc11533SChris Williamson int
zcp_load_list_lib(lua_State * state)494dfc11533SChris Williamson zcp_load_list_lib(lua_State *state)
495dfc11533SChris Williamson {
496dfc11533SChris Williamson 	int i;
497dfc11533SChris Williamson 	zcp_list_info_t *zcp_list_funcs[] = {
498dfc11533SChris Williamson 		&zcp_children_list_info,
499dfc11533SChris Williamson 		&zcp_snapshots_list_info,
500dfc11533SChris Williamson 		&zcp_props_list_info,
501dfc11533SChris Williamson 		&zcp_clones_list_info,
502dfc11533SChris Williamson 		&zcp_system_props_list_info,
503dfc11533SChris Williamson 		NULL
504dfc11533SChris Williamson 	};
505dfc11533SChris Williamson 
506dfc11533SChris Williamson 	lua_newtable(state);
507dfc11533SChris Williamson 
508dfc11533SChris Williamson 	for (i = 0; zcp_list_funcs[i] != NULL; i++) {
509dfc11533SChris Williamson 		zcp_list_info_t *info = zcp_list_funcs[i];
510dfc11533SChris Williamson 
511dfc11533SChris Williamson 		if (info->gc != NULL) {
512dfc11533SChris Williamson 			/*
513dfc11533SChris Williamson 			 * If the function requires garbage collection, create
514dfc11533SChris Williamson 			 * a metatable with its name and register the __gc
515dfc11533SChris Williamson 			 * function.
516dfc11533SChris Williamson 			 */
517dfc11533SChris Williamson 			(void) luaL_newmetatable(state, info->name);
518dfc11533SChris Williamson 			(void) lua_pushstring(state, "__gc");
519dfc11533SChris Williamson 			lua_pushcfunction(state, info->gc);
520dfc11533SChris Williamson 			lua_settable(state, -3);
521dfc11533SChris Williamson 			lua_pop(state, 1);
522dfc11533SChris Williamson 		}
523dfc11533SChris Williamson 
524dfc11533SChris Williamson 		lua_pushlightuserdata(state, info);
525dfc11533SChris Williamson 		lua_pushcclosure(state, &zcp_list_func, 1);
526dfc11533SChris Williamson 		lua_setfield(state, -2, info->name);
527dfc11533SChris Williamson 		info++;
528dfc11533SChris Williamson 	}
529dfc11533SChris Williamson 
530dfc11533SChris Williamson 	return (1);
531dfc11533SChris Williamson }
532