xref: /netbsd-src/external/cddl/osnet/dist/lib/pyzfs/common/ioctl.c (revision 3227e6cf668bd374971740bd6660f43cee4417ac)
1*3227e6cfSchs /*
2*3227e6cfSchs  * CDDL HEADER START
3*3227e6cfSchs  *
4*3227e6cfSchs  * The contents of this file are subject to the terms of the
5*3227e6cfSchs  * Common Development and Distribution License (the "License").
6*3227e6cfSchs  * You may not use this file except in compliance with the License.
7*3227e6cfSchs  *
8*3227e6cfSchs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3227e6cfSchs  * or http://www.opensolaris.org/os/licensing.
10*3227e6cfSchs  * See the License for the specific language governing permissions
11*3227e6cfSchs  * and limitations under the License.
12*3227e6cfSchs  *
13*3227e6cfSchs  * When distributing Covered Code, include this CDDL HEADER in each
14*3227e6cfSchs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3227e6cfSchs  * If applicable, add the following below this CDDL HEADER, with the
16*3227e6cfSchs  * fields enclosed by brackets "[]" replaced with your own identifying
17*3227e6cfSchs  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3227e6cfSchs  *
19*3227e6cfSchs  * CDDL HEADER END
20*3227e6cfSchs  */
21*3227e6cfSchs /*
22*3227e6cfSchs  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23*3227e6cfSchs  * Use is subject to license terms.
24*3227e6cfSchs  */
25*3227e6cfSchs 
26*3227e6cfSchs #include <Python.h>
27*3227e6cfSchs #include <sys/zfs_ioctl.h>
28*3227e6cfSchs #include <sys/fs/zfs.h>
29*3227e6cfSchs #include <strings.h>
30*3227e6cfSchs #include <unistd.h>
31*3227e6cfSchs #include <libnvpair.h>
32*3227e6cfSchs #include <libintl.h>
33*3227e6cfSchs #include <libzfs.h>
34*3227e6cfSchs #include <libzfs_impl.h>
35*3227e6cfSchs #include "zfs_prop.h"
36*3227e6cfSchs 
37*3227e6cfSchs static PyObject *ZFSError;
38*3227e6cfSchs static int zfsdevfd;
39*3227e6cfSchs 
40*3227e6cfSchs #ifdef __lint
41*3227e6cfSchs #define	dgettext(x, y) y
42*3227e6cfSchs #endif
43*3227e6cfSchs 
44*3227e6cfSchs #define	_(s) dgettext(TEXT_DOMAIN, s)
45*3227e6cfSchs 
46*3227e6cfSchs /*PRINTFLIKE1*/
47*3227e6cfSchs static void
seterr(char * fmt,...)48*3227e6cfSchs seterr(char *fmt, ...)
49*3227e6cfSchs {
50*3227e6cfSchs 	char errstr[1024];
51*3227e6cfSchs 	va_list v;
52*3227e6cfSchs 
53*3227e6cfSchs 	va_start(v, fmt);
54*3227e6cfSchs 	(void) vsnprintf(errstr, sizeof (errstr), fmt, v);
55*3227e6cfSchs 	va_end(v);
56*3227e6cfSchs 
57*3227e6cfSchs 	PyErr_SetObject(ZFSError, Py_BuildValue("is", errno, errstr));
58*3227e6cfSchs }
59*3227e6cfSchs 
60*3227e6cfSchs static char cmdstr[HIS_MAX_RECORD_LEN];
61*3227e6cfSchs 
62*3227e6cfSchs static int
ioctl_with_cmdstr(int ioc,zfs_cmd_t * zc)63*3227e6cfSchs ioctl_with_cmdstr(int ioc, zfs_cmd_t *zc)
64*3227e6cfSchs {
65*3227e6cfSchs 	int err;
66*3227e6cfSchs 
67*3227e6cfSchs 	if (cmdstr[0])
68*3227e6cfSchs 		zc->zc_history = (uint64_t)(uintptr_t)cmdstr;
69*3227e6cfSchs 	err = ioctl(zfsdevfd, ioc, zc);
70*3227e6cfSchs 	cmdstr[0] = '\0';
71*3227e6cfSchs 	return (err);
72*3227e6cfSchs }
73*3227e6cfSchs 
74*3227e6cfSchs static PyObject *
nvl2py(nvlist_t * nvl)75*3227e6cfSchs nvl2py(nvlist_t *nvl)
76*3227e6cfSchs {
77*3227e6cfSchs 	PyObject *pyo;
78*3227e6cfSchs 	nvpair_t *nvp;
79*3227e6cfSchs 
80*3227e6cfSchs 	pyo = PyDict_New();
81*3227e6cfSchs 
82*3227e6cfSchs 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp;
83*3227e6cfSchs 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
84*3227e6cfSchs 		PyObject *pyval;
85*3227e6cfSchs 		char *sval;
86*3227e6cfSchs 		uint64_t ival;
87*3227e6cfSchs 		boolean_t bval;
88*3227e6cfSchs 		nvlist_t *nval;
89*3227e6cfSchs 
90*3227e6cfSchs 		switch (nvpair_type(nvp)) {
91*3227e6cfSchs 		case DATA_TYPE_STRING:
92*3227e6cfSchs 			(void) nvpair_value_string(nvp, &sval);
93*3227e6cfSchs 			pyval = Py_BuildValue("s", sval);
94*3227e6cfSchs 			break;
95*3227e6cfSchs 
96*3227e6cfSchs 		case DATA_TYPE_UINT64:
97*3227e6cfSchs 			(void) nvpair_value_uint64(nvp, &ival);
98*3227e6cfSchs 			pyval = Py_BuildValue("K", ival);
99*3227e6cfSchs 			break;
100*3227e6cfSchs 
101*3227e6cfSchs 		case DATA_TYPE_NVLIST:
102*3227e6cfSchs 			(void) nvpair_value_nvlist(nvp, &nval);
103*3227e6cfSchs 			pyval = nvl2py(nval);
104*3227e6cfSchs 			break;
105*3227e6cfSchs 
106*3227e6cfSchs 		case DATA_TYPE_BOOLEAN:
107*3227e6cfSchs 			Py_INCREF(Py_None);
108*3227e6cfSchs 			pyval = Py_None;
109*3227e6cfSchs 			break;
110*3227e6cfSchs 
111*3227e6cfSchs 		case DATA_TYPE_BOOLEAN_VALUE:
112*3227e6cfSchs 			(void) nvpair_value_boolean_value(nvp, &bval);
113*3227e6cfSchs 			pyval = Py_BuildValue("i", bval);
114*3227e6cfSchs 			break;
115*3227e6cfSchs 
116*3227e6cfSchs 		default:
117*3227e6cfSchs 			PyErr_SetNone(PyExc_ValueError);
118*3227e6cfSchs 			Py_DECREF(pyo);
119*3227e6cfSchs 			return (NULL);
120*3227e6cfSchs 		}
121*3227e6cfSchs 
122*3227e6cfSchs 		PyDict_SetItemString(pyo, nvpair_name(nvp), pyval);
123*3227e6cfSchs 		Py_DECREF(pyval);
124*3227e6cfSchs 	}
125*3227e6cfSchs 
126*3227e6cfSchs 	return (pyo);
127*3227e6cfSchs }
128*3227e6cfSchs 
129*3227e6cfSchs static nvlist_t *
dict2nvl(PyObject * d)130*3227e6cfSchs dict2nvl(PyObject *d)
131*3227e6cfSchs {
132*3227e6cfSchs 	nvlist_t *nvl;
133*3227e6cfSchs 	int err;
134*3227e6cfSchs 	PyObject *key, *value;
135*3227e6cfSchs 	int pos = 0;
136*3227e6cfSchs 
137*3227e6cfSchs 	if (!PyDict_Check(d)) {
138*3227e6cfSchs 		PyErr_SetObject(PyExc_ValueError, d);
139*3227e6cfSchs 		return (NULL);
140*3227e6cfSchs 	}
141*3227e6cfSchs 
142*3227e6cfSchs 	err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
143*3227e6cfSchs 	assert(err == 0);
144*3227e6cfSchs 
145*3227e6cfSchs 	while (PyDict_Next(d, &pos, &key, &value)) {
146*3227e6cfSchs 		char *keystr = PyString_AsString(key);
147*3227e6cfSchs 		if (keystr == NULL) {
148*3227e6cfSchs 			PyErr_SetObject(PyExc_KeyError, key);
149*3227e6cfSchs 			nvlist_free(nvl);
150*3227e6cfSchs 			return (NULL);
151*3227e6cfSchs 		}
152*3227e6cfSchs 
153*3227e6cfSchs 		if (PyDict_Check(value)) {
154*3227e6cfSchs 			nvlist_t *valnvl = dict2nvl(value);
155*3227e6cfSchs 			err = nvlist_add_nvlist(nvl, keystr, valnvl);
156*3227e6cfSchs 			nvlist_free(valnvl);
157*3227e6cfSchs 		} else if (value == Py_None) {
158*3227e6cfSchs 			err = nvlist_add_boolean(nvl, keystr);
159*3227e6cfSchs 		} else if (PyString_Check(value)) {
160*3227e6cfSchs 			char *valstr = PyString_AsString(value);
161*3227e6cfSchs 			err = nvlist_add_string(nvl, keystr, valstr);
162*3227e6cfSchs 		} else if (PyInt_Check(value)) {
163*3227e6cfSchs 			uint64_t valint = PyInt_AsUnsignedLongLongMask(value);
164*3227e6cfSchs 			err = nvlist_add_uint64(nvl, keystr, valint);
165*3227e6cfSchs 		} else if (PyBool_Check(value)) {
166*3227e6cfSchs 			boolean_t valbool = value == Py_True ? B_TRUE : B_FALSE;
167*3227e6cfSchs 			err = nvlist_add_boolean_value(nvl, keystr, valbool);
168*3227e6cfSchs 		} else {
169*3227e6cfSchs 			PyErr_SetObject(PyExc_ValueError, value);
170*3227e6cfSchs 			nvlist_free(nvl);
171*3227e6cfSchs 			return (NULL);
172*3227e6cfSchs 		}
173*3227e6cfSchs 		assert(err == 0);
174*3227e6cfSchs 	}
175*3227e6cfSchs 
176*3227e6cfSchs 	return (nvl);
177*3227e6cfSchs }
178*3227e6cfSchs 
179*3227e6cfSchs static PyObject *
fakepropval(uint64_t value)180*3227e6cfSchs fakepropval(uint64_t value)
181*3227e6cfSchs {
182*3227e6cfSchs 	PyObject *d = PyDict_New();
183*3227e6cfSchs 	PyDict_SetItemString(d, "value", Py_BuildValue("K", value));
184*3227e6cfSchs 	return (d);
185*3227e6cfSchs }
186*3227e6cfSchs 
187*3227e6cfSchs static void
add_ds_props(zfs_cmd_t * zc,PyObject * nvl)188*3227e6cfSchs add_ds_props(zfs_cmd_t *zc, PyObject *nvl)
189*3227e6cfSchs {
190*3227e6cfSchs 	dmu_objset_stats_t *s = &zc->zc_objset_stats;
191*3227e6cfSchs 	PyDict_SetItemString(nvl, "numclones",
192*3227e6cfSchs 	    fakepropval(s->dds_num_clones));
193*3227e6cfSchs 	PyDict_SetItemString(nvl, "issnap",
194*3227e6cfSchs 	    fakepropval(s->dds_is_snapshot));
195*3227e6cfSchs 	PyDict_SetItemString(nvl, "inconsistent",
196*3227e6cfSchs 	    fakepropval(s->dds_inconsistent));
197*3227e6cfSchs }
198*3227e6cfSchs 
199*3227e6cfSchs /* On error, returns NULL but does not set python exception. */
200*3227e6cfSchs static PyObject *
ioctl_with_dstnv(int ioc,zfs_cmd_t * zc)201*3227e6cfSchs ioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
202*3227e6cfSchs {
203*3227e6cfSchs 	int nvsz = 2048;
204*3227e6cfSchs 	void *nvbuf;
205*3227e6cfSchs 	PyObject *pynv = NULL;
206*3227e6cfSchs 
207*3227e6cfSchs again:
208*3227e6cfSchs 	nvbuf = malloc(nvsz);
209*3227e6cfSchs 	zc->zc_nvlist_dst_size = nvsz;
210*3227e6cfSchs 	zc->zc_nvlist_dst = (uintptr_t)nvbuf;
211*3227e6cfSchs 
212*3227e6cfSchs 	if (ioctl(zfsdevfd, ioc, zc) == 0) {
213*3227e6cfSchs 		nvlist_t *nvl;
214*3227e6cfSchs 
215*3227e6cfSchs 		errno = nvlist_unpack(nvbuf, zc->zc_nvlist_dst_size, &nvl, 0);
216*3227e6cfSchs 		if (errno == 0) {
217*3227e6cfSchs 			pynv = nvl2py(nvl);
218*3227e6cfSchs 			nvlist_free(nvl);
219*3227e6cfSchs 		}
220*3227e6cfSchs 	} else if (errno == ENOMEM) {
221*3227e6cfSchs 		free(nvbuf);
222*3227e6cfSchs 		nvsz = zc->zc_nvlist_dst_size;
223*3227e6cfSchs 		goto again;
224*3227e6cfSchs 	}
225*3227e6cfSchs 	free(nvbuf);
226*3227e6cfSchs 	return (pynv);
227*3227e6cfSchs }
228*3227e6cfSchs 
229*3227e6cfSchs static PyObject *
py_next_dataset(PyObject * self,PyObject * args)230*3227e6cfSchs py_next_dataset(PyObject *self, PyObject *args)
231*3227e6cfSchs {
232*3227e6cfSchs 	int ioc;
233*3227e6cfSchs 	uint64_t cookie;
234*3227e6cfSchs 	zfs_cmd_t zc = { 0 };
235*3227e6cfSchs 	int snaps;
236*3227e6cfSchs 	char *name;
237*3227e6cfSchs 	PyObject *nvl;
238*3227e6cfSchs 	PyObject *ret = NULL;
239*3227e6cfSchs 
240*3227e6cfSchs 	if (!PyArg_ParseTuple(args, "siK", &name, &snaps, &cookie))
241*3227e6cfSchs 		return (NULL);
242*3227e6cfSchs 
243*3227e6cfSchs 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
244*3227e6cfSchs 	zc.zc_cookie = cookie;
245*3227e6cfSchs 
246*3227e6cfSchs 	if (snaps)
247*3227e6cfSchs 		ioc = ZFS_IOC_SNAPSHOT_LIST_NEXT;
248*3227e6cfSchs 	else
249*3227e6cfSchs 		ioc = ZFS_IOC_DATASET_LIST_NEXT;
250*3227e6cfSchs 
251*3227e6cfSchs 	nvl = ioctl_with_dstnv(ioc, &zc);
252*3227e6cfSchs 	if (nvl) {
253*3227e6cfSchs 		add_ds_props(&zc, nvl);
254*3227e6cfSchs 		ret = Py_BuildValue("sKO", zc.zc_name, zc.zc_cookie, nvl);
255*3227e6cfSchs 		Py_DECREF(nvl);
256*3227e6cfSchs 	} else if (errno == ESRCH) {
257*3227e6cfSchs 		PyErr_SetNone(PyExc_StopIteration);
258*3227e6cfSchs 	} else {
259*3227e6cfSchs 		if (snaps)
260*3227e6cfSchs 			seterr(_("cannot get snapshots of %s"), name);
261*3227e6cfSchs 		else
262*3227e6cfSchs 			seterr(_("cannot get child datasets of %s"), name);
263*3227e6cfSchs 	}
264*3227e6cfSchs 	return (ret);
265*3227e6cfSchs }
266*3227e6cfSchs 
267*3227e6cfSchs static PyObject *
py_dataset_props(PyObject * self,PyObject * args)268*3227e6cfSchs py_dataset_props(PyObject *self, PyObject *args)
269*3227e6cfSchs {
270*3227e6cfSchs 	zfs_cmd_t zc = { 0 };
271*3227e6cfSchs 	int snaps;
272*3227e6cfSchs 	char *name;
273*3227e6cfSchs 	PyObject *nvl;
274*3227e6cfSchs 
275*3227e6cfSchs 	if (!PyArg_ParseTuple(args, "s", &name))
276*3227e6cfSchs 		return (NULL);
277*3227e6cfSchs 
278*3227e6cfSchs 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
279*3227e6cfSchs 
280*3227e6cfSchs 	nvl = ioctl_with_dstnv(ZFS_IOC_OBJSET_STATS, &zc);
281*3227e6cfSchs 	if (nvl) {
282*3227e6cfSchs 		add_ds_props(&zc, nvl);
283*3227e6cfSchs 	} else {
284*3227e6cfSchs 		seterr(_("cannot access dataset %s"), name);
285*3227e6cfSchs 	}
286*3227e6cfSchs 	return (nvl);
287*3227e6cfSchs }
288*3227e6cfSchs 
289*3227e6cfSchs static PyObject *
py_get_fsacl(PyObject * self,PyObject * args)290*3227e6cfSchs py_get_fsacl(PyObject *self, PyObject *args)
291*3227e6cfSchs {
292*3227e6cfSchs 	zfs_cmd_t zc = { 0 };
293*3227e6cfSchs 	char *name;
294*3227e6cfSchs 	PyObject *nvl;
295*3227e6cfSchs 
296*3227e6cfSchs 	if (!PyArg_ParseTuple(args, "s", &name))
297*3227e6cfSchs 		return (NULL);
298*3227e6cfSchs 
299*3227e6cfSchs 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
300*3227e6cfSchs 
301*3227e6cfSchs 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_FSACL, &zc);
302*3227e6cfSchs 	if (nvl == NULL)
303*3227e6cfSchs 		seterr(_("cannot get permissions on %s"), name);
304*3227e6cfSchs 
305*3227e6cfSchs 	return (nvl);
306*3227e6cfSchs }
307*3227e6cfSchs 
308*3227e6cfSchs static PyObject *
py_set_fsacl(PyObject * self,PyObject * args)309*3227e6cfSchs py_set_fsacl(PyObject *self, PyObject *args)
310*3227e6cfSchs {
311*3227e6cfSchs 	int un;
312*3227e6cfSchs 	size_t nvsz;
313*3227e6cfSchs 	zfs_cmd_t zc = { 0 };
314*3227e6cfSchs 	char *name, *nvbuf;
315*3227e6cfSchs 	PyObject *dict, *file;
316*3227e6cfSchs 	nvlist_t *nvl;
317*3227e6cfSchs 	int err;
318*3227e6cfSchs 
319*3227e6cfSchs 	if (!PyArg_ParseTuple(args, "siO!", &name, &un,
320*3227e6cfSchs 	    &PyDict_Type, &dict))
321*3227e6cfSchs 		return (NULL);
322*3227e6cfSchs 
323*3227e6cfSchs 	nvl = dict2nvl(dict);
324*3227e6cfSchs 	if (nvl == NULL)
325*3227e6cfSchs 		return (NULL);
326*3227e6cfSchs 
327*3227e6cfSchs 	err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
328*3227e6cfSchs 	assert(err == 0);
329*3227e6cfSchs 	nvbuf = malloc(nvsz);
330*3227e6cfSchs 	err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
331*3227e6cfSchs 	assert(err == 0);
332*3227e6cfSchs 
333*3227e6cfSchs 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
334*3227e6cfSchs 	zc.zc_nvlist_src_size = nvsz;
335*3227e6cfSchs 	zc.zc_nvlist_src = (uintptr_t)nvbuf;
336*3227e6cfSchs 	zc.zc_perm_action = un;
337*3227e6cfSchs 
338*3227e6cfSchs 	err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
339*3227e6cfSchs 	free(nvbuf);
340*3227e6cfSchs 	if (err) {
341*3227e6cfSchs 		seterr(_("cannot set permissions on %s"), name);
342*3227e6cfSchs 		return (NULL);
343*3227e6cfSchs 	}
344*3227e6cfSchs 
345*3227e6cfSchs 	Py_RETURN_NONE;
346*3227e6cfSchs }
347*3227e6cfSchs 
348*3227e6cfSchs static PyObject *
py_get_holds(PyObject * self,PyObject * args)349*3227e6cfSchs py_get_holds(PyObject *self, PyObject *args)
350*3227e6cfSchs {
351*3227e6cfSchs 	zfs_cmd_t zc = { 0 };
352*3227e6cfSchs 	char *name;
353*3227e6cfSchs 	PyObject *nvl;
354*3227e6cfSchs 
355*3227e6cfSchs 	if (!PyArg_ParseTuple(args, "s", &name))
356*3227e6cfSchs 		return (NULL);
357*3227e6cfSchs 
358*3227e6cfSchs 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
359*3227e6cfSchs 
360*3227e6cfSchs 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
361*3227e6cfSchs 	if (nvl == NULL)
362*3227e6cfSchs 		seterr(_("cannot get holds for %s"), name);
363*3227e6cfSchs 
364*3227e6cfSchs 	return (nvl);
365*3227e6cfSchs }
366*3227e6cfSchs 
367*3227e6cfSchs static PyObject *
py_userspace_many(PyObject * self,PyObject * args)368*3227e6cfSchs py_userspace_many(PyObject *self, PyObject *args)
369*3227e6cfSchs {
370*3227e6cfSchs 	zfs_cmd_t zc = { 0 };
371*3227e6cfSchs 	zfs_userquota_prop_t type;
372*3227e6cfSchs 	char *name, *propname;
373*3227e6cfSchs 	int bufsz = 1<<20;
374*3227e6cfSchs 	void *buf;
375*3227e6cfSchs 	PyObject *dict, *file;
376*3227e6cfSchs 	int error;
377*3227e6cfSchs 
378*3227e6cfSchs 	if (!PyArg_ParseTuple(args, "ss", &name, &propname))
379*3227e6cfSchs 		return (NULL);
380*3227e6cfSchs 
381*3227e6cfSchs 	for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++)
382*3227e6cfSchs 		if (strcmp(propname, zfs_userquota_prop_prefixes[type]) == 0)
383*3227e6cfSchs 			break;
384*3227e6cfSchs 	if (type == ZFS_NUM_USERQUOTA_PROPS) {
385*3227e6cfSchs 		PyErr_SetString(PyExc_KeyError, propname);
386*3227e6cfSchs 		return (NULL);
387*3227e6cfSchs 	}
388*3227e6cfSchs 
389*3227e6cfSchs 	dict = PyDict_New();
390*3227e6cfSchs 	buf = malloc(bufsz);
391*3227e6cfSchs 
392*3227e6cfSchs 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
393*3227e6cfSchs 	zc.zc_objset_type = type;
394*3227e6cfSchs 	zc.zc_cookie = 0;
395*3227e6cfSchs 
396*3227e6cfSchs 	while (1) {
397*3227e6cfSchs 		zfs_useracct_t *zua = buf;
398*3227e6cfSchs 
399*3227e6cfSchs 		zc.zc_nvlist_dst = (uintptr_t)buf;
400*3227e6cfSchs 		zc.zc_nvlist_dst_size = bufsz;
401*3227e6cfSchs 
402*3227e6cfSchs 		error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_MANY, &zc);
403*3227e6cfSchs 		if (error || zc.zc_nvlist_dst_size == 0)
404*3227e6cfSchs 			break;
405*3227e6cfSchs 
406*3227e6cfSchs 		while (zc.zc_nvlist_dst_size > 0) {
407*3227e6cfSchs 			PyObject *pykey, *pyval;
408*3227e6cfSchs 
409*3227e6cfSchs 			pykey = Py_BuildValue("sI",
410*3227e6cfSchs 			    zua->zu_domain, zua->zu_rid);
411*3227e6cfSchs 			pyval = Py_BuildValue("K", zua->zu_space);
412*3227e6cfSchs 			PyDict_SetItem(dict, pykey, pyval);
413*3227e6cfSchs 			Py_DECREF(pykey);
414*3227e6cfSchs 			Py_DECREF(pyval);
415*3227e6cfSchs 
416*3227e6cfSchs 			zua++;
417*3227e6cfSchs 			zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
418*3227e6cfSchs 		}
419*3227e6cfSchs 	}
420*3227e6cfSchs 
421*3227e6cfSchs 	free(buf);
422*3227e6cfSchs 
423*3227e6cfSchs 	if (error != 0) {
424*3227e6cfSchs 		Py_DECREF(dict);
425*3227e6cfSchs 		seterr(_("cannot get %s property on %s"), propname, name);
426*3227e6cfSchs 		return (NULL);
427*3227e6cfSchs 	}
428*3227e6cfSchs 
429*3227e6cfSchs 	return (dict);
430*3227e6cfSchs }
431*3227e6cfSchs 
432*3227e6cfSchs static PyObject *
py_userspace_upgrade(PyObject * self,PyObject * args)433*3227e6cfSchs py_userspace_upgrade(PyObject *self, PyObject *args)
434*3227e6cfSchs {
435*3227e6cfSchs 	zfs_cmd_t zc = { 0 };
436*3227e6cfSchs 	char *name;
437*3227e6cfSchs 	int error;
438*3227e6cfSchs 
439*3227e6cfSchs 	if (!PyArg_ParseTuple(args, "s", &name))
440*3227e6cfSchs 		return (NULL);
441*3227e6cfSchs 
442*3227e6cfSchs 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
443*3227e6cfSchs 	error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_UPGRADE, &zc);
444*3227e6cfSchs 
445*3227e6cfSchs 	if (error != 0) {
446*3227e6cfSchs 		seterr(_("cannot initialize user accounting information on %s"),
447*3227e6cfSchs 		    name);
448*3227e6cfSchs 		return (NULL);
449*3227e6cfSchs 	}
450*3227e6cfSchs 
451*3227e6cfSchs 	Py_RETURN_NONE;
452*3227e6cfSchs }
453*3227e6cfSchs 
454*3227e6cfSchs static PyObject *
py_set_cmdstr(PyObject * self,PyObject * args)455*3227e6cfSchs py_set_cmdstr(PyObject *self, PyObject *args)
456*3227e6cfSchs {
457*3227e6cfSchs 	char *str;
458*3227e6cfSchs 
459*3227e6cfSchs 	if (!PyArg_ParseTuple(args, "s", &str))
460*3227e6cfSchs 		return (NULL);
461*3227e6cfSchs 
462*3227e6cfSchs 	(void) strlcpy(cmdstr, str, sizeof (cmdstr));
463*3227e6cfSchs 
464*3227e6cfSchs 	Py_RETURN_NONE;
465*3227e6cfSchs }
466*3227e6cfSchs 
467*3227e6cfSchs static PyObject *
py_get_proptable(PyObject * self,PyObject * args)468*3227e6cfSchs py_get_proptable(PyObject *self, PyObject *args)
469*3227e6cfSchs {
470*3227e6cfSchs 	zprop_desc_t *t = zfs_prop_get_table();
471*3227e6cfSchs 	PyObject *d = PyDict_New();
472*3227e6cfSchs 	zfs_prop_t i;
473*3227e6cfSchs 
474*3227e6cfSchs 	for (i = 0; i < ZFS_NUM_PROPS; i++) {
475*3227e6cfSchs 		zprop_desc_t *p = &t[i];
476*3227e6cfSchs 		PyObject *tuple;
477*3227e6cfSchs 		static const char *typetable[] =
478*3227e6cfSchs 		    {"number", "string", "index"};
479*3227e6cfSchs 		static const char *attrtable[] =
480*3227e6cfSchs 		    {"default", "readonly", "inherit", "onetime"};
481*3227e6cfSchs 		PyObject *indextable;
482*3227e6cfSchs 
483*3227e6cfSchs 		if (p->pd_proptype == PROP_TYPE_INDEX) {
484*3227e6cfSchs 			const zprop_index_t *it = p->pd_table;
485*3227e6cfSchs 			indextable = PyDict_New();
486*3227e6cfSchs 			int j;
487*3227e6cfSchs 			for (j = 0; it[j].pi_name; j++) {
488*3227e6cfSchs 				PyDict_SetItemString(indextable,
489*3227e6cfSchs 				    it[j].pi_name,
490*3227e6cfSchs 				    Py_BuildValue("K", it[j].pi_value));
491*3227e6cfSchs 			}
492*3227e6cfSchs 		} else {
493*3227e6cfSchs 			Py_INCREF(Py_None);
494*3227e6cfSchs 			indextable = Py_None;
495*3227e6cfSchs 		}
496*3227e6cfSchs 
497*3227e6cfSchs 		tuple = Py_BuildValue("sissKsissiiO",
498*3227e6cfSchs 		    p->pd_name, p->pd_propnum, typetable[p->pd_proptype],
499*3227e6cfSchs 		    p->pd_strdefault, p->pd_numdefault,
500*3227e6cfSchs 		    attrtable[p->pd_attr], p->pd_types,
501*3227e6cfSchs 		    p->pd_values, p->pd_colname,
502*3227e6cfSchs 		    p->pd_rightalign, p->pd_visible, indextable);
503*3227e6cfSchs 		PyDict_SetItemString(d, p->pd_name, tuple);
504*3227e6cfSchs 		Py_DECREF(tuple);
505*3227e6cfSchs 	}
506*3227e6cfSchs 
507*3227e6cfSchs 	return (d);
508*3227e6cfSchs }
509*3227e6cfSchs 
510*3227e6cfSchs static PyMethodDef zfsmethods[] = {
511*3227e6cfSchs 	{"next_dataset", py_next_dataset, METH_VARARGS,
512*3227e6cfSchs 	    "Get next child dataset or snapshot."},
513*3227e6cfSchs 	{"get_fsacl", py_get_fsacl, METH_VARARGS, "Get allowed permissions."},
514*3227e6cfSchs 	{"set_fsacl", py_set_fsacl, METH_VARARGS, "Set allowed permissions."},
515*3227e6cfSchs 	{"userspace_many", py_userspace_many, METH_VARARGS,
516*3227e6cfSchs 	    "Get user space accounting."},
517*3227e6cfSchs 	{"userspace_upgrade", py_userspace_upgrade, METH_VARARGS,
518*3227e6cfSchs 	    "Upgrade fs to enable user space accounting."},
519*3227e6cfSchs 	{"set_cmdstr", py_set_cmdstr, METH_VARARGS,
520*3227e6cfSchs 	    "Set command string for history logging."},
521*3227e6cfSchs 	{"dataset_props", py_dataset_props, METH_VARARGS,
522*3227e6cfSchs 	    "Get dataset properties."},
523*3227e6cfSchs 	{"get_proptable", py_get_proptable, METH_NOARGS,
524*3227e6cfSchs 	    "Get property table."},
525*3227e6cfSchs 	{"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
526*3227e6cfSchs 	{NULL, NULL, 0, NULL}
527*3227e6cfSchs };
528*3227e6cfSchs 
529*3227e6cfSchs void
initioctl(void)530*3227e6cfSchs initioctl(void)
531*3227e6cfSchs {
532*3227e6cfSchs 	PyObject *zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
533*3227e6cfSchs 	PyObject *zfs_util = PyImport_ImportModule("zfs.util");
534*3227e6cfSchs 	PyObject *devfile;
535*3227e6cfSchs 
536*3227e6cfSchs 	if (zfs_util == NULL)
537*3227e6cfSchs 		return;
538*3227e6cfSchs 
539*3227e6cfSchs 	ZFSError = PyObject_GetAttrString(zfs_util, "ZFSError");
540*3227e6cfSchs 	devfile = PyObject_GetAttrString(zfs_util, "dev");
541*3227e6cfSchs 	zfsdevfd = PyObject_AsFileDescriptor(devfile);
542*3227e6cfSchs 
543*3227e6cfSchs 	zfs_prop_init();
544*3227e6cfSchs }
545