xref: /illumos-gate/usr/src/lib/pyzfs/common/ioctl.c (revision b0858fdc)
114843421SMatthew Ahrens /*
214843421SMatthew Ahrens  * CDDL HEADER START
314843421SMatthew Ahrens  *
414843421SMatthew Ahrens  * The contents of this file are subject to the terms of the
514843421SMatthew Ahrens  * Common Development and Distribution License (the "License").
614843421SMatthew Ahrens  * You may not use this file except in compliance with the License.
714843421SMatthew Ahrens  *
814843421SMatthew Ahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
914843421SMatthew Ahrens  * or http://www.opensolaris.org/os/licensing.
1014843421SMatthew Ahrens  * See the License for the specific language governing permissions
1114843421SMatthew Ahrens  * and limitations under the License.
1214843421SMatthew Ahrens  *
1314843421SMatthew Ahrens  * When distributing Covered Code, include this CDDL HEADER in each
1414843421SMatthew Ahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1514843421SMatthew Ahrens  * If applicable, add the following below this CDDL HEADER, with the
1614843421SMatthew Ahrens  * fields enclosed by brackets "[]" replaced with your own identifying
1714843421SMatthew Ahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
1814843421SMatthew Ahrens  *
1914843421SMatthew Ahrens  * CDDL HEADER END
2014843421SMatthew Ahrens  */
2114843421SMatthew Ahrens /*
22e4d060fbSSam Falkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2314843421SMatthew Ahrens  * Use is subject to license terms.
24e8921a52SAndy Fiddaman  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
2514843421SMatthew Ahrens  */
2614843421SMatthew Ahrens 
2714843421SMatthew Ahrens #include <Python.h>
2814843421SMatthew Ahrens #include <sys/zfs_ioctl.h>
2914843421SMatthew Ahrens #include <sys/fs/zfs.h>
3014843421SMatthew Ahrens #include <strings.h>
3114843421SMatthew Ahrens #include <unistd.h>
3214843421SMatthew Ahrens #include <libnvpair.h>
3314843421SMatthew Ahrens #include <libintl.h>
3414843421SMatthew Ahrens #include <libzfs.h>
3514843421SMatthew Ahrens #include "zfs_prop.h"
3614843421SMatthew Ahrens 
3714843421SMatthew Ahrens static PyObject *ZFSError;
3814843421SMatthew Ahrens static int zfsdevfd;
3914843421SMatthew Ahrens 
4014843421SMatthew Ahrens #ifdef __lint
4114843421SMatthew Ahrens #define	dgettext(x, y) y
4214843421SMatthew Ahrens #endif
4314843421SMatthew Ahrens 
4414843421SMatthew Ahrens #define	_(s) dgettext(TEXT_DOMAIN, s)
4514843421SMatthew Ahrens 
4614843421SMatthew Ahrens /*PRINTFLIKE1*/
4714843421SMatthew Ahrens static void
4814843421SMatthew Ahrens seterr(char *fmt, ...)
4914843421SMatthew Ahrens {
5014843421SMatthew Ahrens 	char errstr[1024];
5114843421SMatthew Ahrens 	va_list v;
5214843421SMatthew Ahrens 
5314843421SMatthew Ahrens 	va_start(v, fmt);
5414843421SMatthew Ahrens 	(void) vsnprintf(errstr, sizeof (errstr), fmt, v);
5514843421SMatthew Ahrens 	va_end(v);
5614843421SMatthew Ahrens 
5714843421SMatthew Ahrens 	PyErr_SetObject(ZFSError, Py_BuildValue("is", errno, errstr));
5814843421SMatthew Ahrens }
5914843421SMatthew Ahrens 
6014843421SMatthew Ahrens static char cmdstr[HIS_MAX_RECORD_LEN];
6114843421SMatthew Ahrens 
6214843421SMatthew Ahrens static int
6314843421SMatthew Ahrens ioctl_with_cmdstr(int ioc, zfs_cmd_t *zc)
6414843421SMatthew Ahrens {
6514843421SMatthew Ahrens 	int err;
6614843421SMatthew Ahrens 
6714843421SMatthew Ahrens 	if (cmdstr[0])
6814843421SMatthew Ahrens 		zc->zc_history = (uint64_t)(uintptr_t)cmdstr;
6914843421SMatthew Ahrens 	err = ioctl(zfsdevfd, ioc, zc);
7014843421SMatthew Ahrens 	cmdstr[0] = '\0';
7114843421SMatthew Ahrens 	return (err);
7214843421SMatthew Ahrens }
7314843421SMatthew Ahrens 
7414843421SMatthew Ahrens static PyObject *
7514843421SMatthew Ahrens nvl2py(nvlist_t *nvl)
7614843421SMatthew Ahrens {
7714843421SMatthew Ahrens 	PyObject *pyo;
7814843421SMatthew Ahrens 	nvpair_t *nvp;
7914843421SMatthew Ahrens 
8014843421SMatthew Ahrens 	pyo = PyDict_New();
8114843421SMatthew Ahrens 
8214843421SMatthew Ahrens 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp;
8314843421SMatthew Ahrens 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
8414843421SMatthew Ahrens 		PyObject *pyval;
8514843421SMatthew Ahrens 		char *sval;
8614843421SMatthew Ahrens 		uint64_t ival;
8714843421SMatthew Ahrens 		boolean_t bval;
8814843421SMatthew Ahrens 		nvlist_t *nval;
8914843421SMatthew Ahrens 
9014843421SMatthew Ahrens 		switch (nvpair_type(nvp)) {
9114843421SMatthew Ahrens 		case DATA_TYPE_STRING:
9214843421SMatthew Ahrens 			(void) nvpair_value_string(nvp, &sval);
9314843421SMatthew Ahrens 			pyval = Py_BuildValue("s", sval);
9414843421SMatthew Ahrens 			break;
9514843421SMatthew Ahrens 
9614843421SMatthew Ahrens 		case DATA_TYPE_UINT64:
9714843421SMatthew Ahrens 			(void) nvpair_value_uint64(nvp, &ival);
9814843421SMatthew Ahrens 			pyval = Py_BuildValue("K", ival);
9914843421SMatthew Ahrens 			break;
10014843421SMatthew Ahrens 
10114843421SMatthew Ahrens 		case DATA_TYPE_NVLIST:
10214843421SMatthew Ahrens 			(void) nvpair_value_nvlist(nvp, &nval);
10314843421SMatthew Ahrens 			pyval = nvl2py(nval);
10414843421SMatthew Ahrens 			break;
10514843421SMatthew Ahrens 
10614843421SMatthew Ahrens 		case DATA_TYPE_BOOLEAN:
10714843421SMatthew Ahrens 			Py_INCREF(Py_None);
10814843421SMatthew Ahrens 			pyval = Py_None;
10914843421SMatthew Ahrens 			break;
11014843421SMatthew Ahrens 
11114843421SMatthew Ahrens 		case DATA_TYPE_BOOLEAN_VALUE:
11214843421SMatthew Ahrens 			(void) nvpair_value_boolean_value(nvp, &bval);
11314843421SMatthew Ahrens 			pyval = Py_BuildValue("i", bval);
11414843421SMatthew Ahrens 			break;
11514843421SMatthew Ahrens 
11614843421SMatthew Ahrens 		default:
11714843421SMatthew Ahrens 			PyErr_SetNone(PyExc_ValueError);
11814843421SMatthew Ahrens 			Py_DECREF(pyo);
11914843421SMatthew Ahrens 			return (NULL);
12014843421SMatthew Ahrens 		}
12114843421SMatthew Ahrens 
12214843421SMatthew Ahrens 		PyDict_SetItemString(pyo, nvpair_name(nvp), pyval);
12314843421SMatthew Ahrens 		Py_DECREF(pyval);
12414843421SMatthew Ahrens 	}
12514843421SMatthew Ahrens 
12614843421SMatthew Ahrens 	return (pyo);
12714843421SMatthew Ahrens }
12814843421SMatthew Ahrens 
12914843421SMatthew Ahrens static nvlist_t *
13014843421SMatthew Ahrens dict2nvl(PyObject *d)
13114843421SMatthew Ahrens {
13214843421SMatthew Ahrens 	nvlist_t *nvl;
13314843421SMatthew Ahrens 	int err;
13414843421SMatthew Ahrens 	PyObject *key, *value;
135e8921a52SAndy Fiddaman 	Py_ssize_t pos = 0;
13614843421SMatthew Ahrens 
13714843421SMatthew Ahrens 	if (!PyDict_Check(d)) {
13814843421SMatthew Ahrens 		PyErr_SetObject(PyExc_ValueError, d);
13914843421SMatthew Ahrens 		return (NULL);
14014843421SMatthew Ahrens 	}
14114843421SMatthew Ahrens 
14214843421SMatthew Ahrens 	err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
14314843421SMatthew Ahrens 	assert(err == 0);
14414843421SMatthew Ahrens 
14514843421SMatthew Ahrens 	while (PyDict_Next(d, &pos, &key, &value)) {
146e8921a52SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
147*b0858fdcSAlexander Pyhalov 		char *keystr = PyUnicode_AsUTF8(key);
148e8921a52SAndy Fiddaman #else
14914843421SMatthew Ahrens 		char *keystr = PyString_AsString(key);
150e8921a52SAndy Fiddaman #endif
15114843421SMatthew Ahrens 		if (keystr == NULL) {
15214843421SMatthew Ahrens 			PyErr_SetObject(PyExc_KeyError, key);
15314843421SMatthew Ahrens 			nvlist_free(nvl);
15414843421SMatthew Ahrens 			return (NULL);
15514843421SMatthew Ahrens 		}
15614843421SMatthew Ahrens 
15714843421SMatthew Ahrens 		if (PyDict_Check(value)) {
15814843421SMatthew Ahrens 			nvlist_t *valnvl = dict2nvl(value);
15914843421SMatthew Ahrens 			err = nvlist_add_nvlist(nvl, keystr, valnvl);
16014843421SMatthew Ahrens 			nvlist_free(valnvl);
16114843421SMatthew Ahrens 		} else if (value == Py_None) {
16214843421SMatthew Ahrens 			err = nvlist_add_boolean(nvl, keystr);
163e8921a52SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
164*b0858fdcSAlexander Pyhalov 		} else if (PyUnicode_Check(value)) {
165e8921a52SAndy Fiddaman #else
16614843421SMatthew Ahrens 		} else if (PyString_Check(value)) {
167e8921a52SAndy Fiddaman #endif
168e8921a52SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
169*b0858fdcSAlexander Pyhalov 			char *valstr = PyUnicode_AsUTF8(value);
170e8921a52SAndy Fiddaman #else
17114843421SMatthew Ahrens 			char *valstr = PyString_AsString(value);
172e8921a52SAndy Fiddaman #endif
17314843421SMatthew Ahrens 			err = nvlist_add_string(nvl, keystr, valstr);
174e8921a52SAndy Fiddaman 		} else if (PyLong_Check(value)) {
175e8921a52SAndy Fiddaman 			uint64_t valint = PyLong_AsUnsignedLongLongMask(value);
17614843421SMatthew Ahrens 			err = nvlist_add_uint64(nvl, keystr, valint);
17714843421SMatthew Ahrens 		} else if (PyBool_Check(value)) {
17814843421SMatthew Ahrens 			boolean_t valbool = value == Py_True ? B_TRUE : B_FALSE;
17914843421SMatthew Ahrens 			err = nvlist_add_boolean_value(nvl, keystr, valbool);
18014843421SMatthew Ahrens 		} else {
18114843421SMatthew Ahrens 			PyErr_SetObject(PyExc_ValueError, value);
18214843421SMatthew Ahrens 			nvlist_free(nvl);
18314843421SMatthew Ahrens 			return (NULL);
18414843421SMatthew Ahrens 		}
18514843421SMatthew Ahrens 		assert(err == 0);
18614843421SMatthew Ahrens 	}
18714843421SMatthew Ahrens 
18814843421SMatthew Ahrens 	return (nvl);
18914843421SMatthew Ahrens }
19014843421SMatthew Ahrens 
19114843421SMatthew Ahrens static PyObject *
19214843421SMatthew Ahrens fakepropval(uint64_t value)
19314843421SMatthew Ahrens {
19414843421SMatthew Ahrens 	PyObject *d = PyDict_New();
19514843421SMatthew Ahrens 	PyDict_SetItemString(d, "value", Py_BuildValue("K", value));
19614843421SMatthew Ahrens 	return (d);
19714843421SMatthew Ahrens }
19814843421SMatthew Ahrens 
19914843421SMatthew Ahrens static void
20014843421SMatthew Ahrens add_ds_props(zfs_cmd_t *zc, PyObject *nvl)
20114843421SMatthew Ahrens {
20214843421SMatthew Ahrens 	dmu_objset_stats_t *s = &zc->zc_objset_stats;
20314843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "numclones",
20414843421SMatthew Ahrens 	    fakepropval(s->dds_num_clones));
20514843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "issnap",
20614843421SMatthew Ahrens 	    fakepropval(s->dds_is_snapshot));
20714843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "inconsistent",
20814843421SMatthew Ahrens 	    fakepropval(s->dds_inconsistent));
20914843421SMatthew Ahrens }
21014843421SMatthew Ahrens 
21114843421SMatthew Ahrens /* On error, returns NULL but does not set python exception. */
21214843421SMatthew Ahrens static PyObject *
21314843421SMatthew Ahrens ioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
21414843421SMatthew Ahrens {
21514843421SMatthew Ahrens 	int nvsz = 2048;
21614843421SMatthew Ahrens 	void *nvbuf;
21714843421SMatthew Ahrens 	PyObject *pynv = NULL;
21814843421SMatthew Ahrens 
21914843421SMatthew Ahrens again:
22014843421SMatthew Ahrens 	nvbuf = malloc(nvsz);
22114843421SMatthew Ahrens 	zc->zc_nvlist_dst_size = nvsz;
22214843421SMatthew Ahrens 	zc->zc_nvlist_dst = (uintptr_t)nvbuf;
22314843421SMatthew Ahrens 
22414843421SMatthew Ahrens 	if (ioctl(zfsdevfd, ioc, zc) == 0) {
22514843421SMatthew Ahrens 		nvlist_t *nvl;
22614843421SMatthew Ahrens 
22714843421SMatthew Ahrens 		errno = nvlist_unpack(nvbuf, zc->zc_nvlist_dst_size, &nvl, 0);
22814843421SMatthew Ahrens 		if (errno == 0) {
22914843421SMatthew Ahrens 			pynv = nvl2py(nvl);
23014843421SMatthew Ahrens 			nvlist_free(nvl);
23114843421SMatthew Ahrens 		}
23214843421SMatthew Ahrens 	} else if (errno == ENOMEM) {
23314843421SMatthew Ahrens 		free(nvbuf);
23414843421SMatthew Ahrens 		nvsz = zc->zc_nvlist_dst_size;
23514843421SMatthew Ahrens 		goto again;
23614843421SMatthew Ahrens 	}
23714843421SMatthew Ahrens 	free(nvbuf);
23814843421SMatthew Ahrens 	return (pynv);
23914843421SMatthew Ahrens }
24014843421SMatthew Ahrens 
24114843421SMatthew Ahrens static PyObject *
24214843421SMatthew Ahrens py_next_dataset(PyObject *self, PyObject *args)
24314843421SMatthew Ahrens {
24414843421SMatthew Ahrens 	int ioc;
24514843421SMatthew Ahrens 	uint64_t cookie;
24614843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
24714843421SMatthew Ahrens 	int snaps;
24814843421SMatthew Ahrens 	char *name;
24914843421SMatthew Ahrens 	PyObject *nvl;
25014843421SMatthew Ahrens 	PyObject *ret = NULL;
25114843421SMatthew Ahrens 
25214843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "siK", &name, &snaps, &cookie))
25314843421SMatthew Ahrens 		return (NULL);
25414843421SMatthew Ahrens 
25514843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
25614843421SMatthew Ahrens 	zc.zc_cookie = cookie;
25714843421SMatthew Ahrens 
25814843421SMatthew Ahrens 	if (snaps)
25914843421SMatthew Ahrens 		ioc = ZFS_IOC_SNAPSHOT_LIST_NEXT;
26014843421SMatthew Ahrens 	else
26114843421SMatthew Ahrens 		ioc = ZFS_IOC_DATASET_LIST_NEXT;
26214843421SMatthew Ahrens 
26314843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ioc, &zc);
26414843421SMatthew Ahrens 	if (nvl) {
26514843421SMatthew Ahrens 		add_ds_props(&zc, nvl);
26614843421SMatthew Ahrens 		ret = Py_BuildValue("sKO", zc.zc_name, zc.zc_cookie, nvl);
26714843421SMatthew Ahrens 		Py_DECREF(nvl);
26814843421SMatthew Ahrens 	} else if (errno == ESRCH) {
26914843421SMatthew Ahrens 		PyErr_SetNone(PyExc_StopIteration);
27014843421SMatthew Ahrens 	} else {
27114843421SMatthew Ahrens 		if (snaps)
27214843421SMatthew Ahrens 			seterr(_("cannot get snapshots of %s"), name);
27314843421SMatthew Ahrens 		else
27414843421SMatthew Ahrens 			seterr(_("cannot get child datasets of %s"), name);
27514843421SMatthew Ahrens 	}
27614843421SMatthew Ahrens 	return (ret);
27714843421SMatthew Ahrens }
27814843421SMatthew Ahrens 
27914843421SMatthew Ahrens static PyObject *
28014843421SMatthew Ahrens py_dataset_props(PyObject *self, PyObject *args)
28114843421SMatthew Ahrens {
28214843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
28314843421SMatthew Ahrens 	int snaps;
28414843421SMatthew Ahrens 	char *name;
28514843421SMatthew Ahrens 	PyObject *nvl;
28614843421SMatthew Ahrens 
28714843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
28814843421SMatthew Ahrens 		return (NULL);
28914843421SMatthew Ahrens 
29014843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
29114843421SMatthew Ahrens 
29214843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ZFS_IOC_OBJSET_STATS, &zc);
29314843421SMatthew Ahrens 	if (nvl) {
29414843421SMatthew Ahrens 		add_ds_props(&zc, nvl);
29514843421SMatthew Ahrens 	} else {
29614843421SMatthew Ahrens 		seterr(_("cannot access dataset %s"), name);
29714843421SMatthew Ahrens 	}
29814843421SMatthew Ahrens 	return (nvl);
29914843421SMatthew Ahrens }
30014843421SMatthew Ahrens 
30114843421SMatthew Ahrens static PyObject *
30214843421SMatthew Ahrens py_get_fsacl(PyObject *self, PyObject *args)
30314843421SMatthew Ahrens {
30414843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
30514843421SMatthew Ahrens 	char *name;
30614843421SMatthew Ahrens 	PyObject *nvl;
30714843421SMatthew Ahrens 
30814843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
30914843421SMatthew Ahrens 		return (NULL);
31014843421SMatthew Ahrens 
31114843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
31214843421SMatthew Ahrens 
31314843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_FSACL, &zc);
31414843421SMatthew Ahrens 	if (nvl == NULL)
31514843421SMatthew Ahrens 		seterr(_("cannot get permissions on %s"), name);
31614843421SMatthew Ahrens 
31714843421SMatthew Ahrens 	return (nvl);
31814843421SMatthew Ahrens }
31914843421SMatthew Ahrens 
32014843421SMatthew Ahrens static PyObject *
32114843421SMatthew Ahrens py_set_fsacl(PyObject *self, PyObject *args)
32214843421SMatthew Ahrens {
32314843421SMatthew Ahrens 	int un;
32414843421SMatthew Ahrens 	size_t nvsz;
32514843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
32614843421SMatthew Ahrens 	char *name, *nvbuf;
32714843421SMatthew Ahrens 	PyObject *dict, *file;
32814843421SMatthew Ahrens 	nvlist_t *nvl;
32914843421SMatthew Ahrens 	int err;
33014843421SMatthew Ahrens 
33114843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "siO!", &name, &un,
33214843421SMatthew Ahrens 	    &PyDict_Type, &dict))
33314843421SMatthew Ahrens 		return (NULL);
33414843421SMatthew Ahrens 
33514843421SMatthew Ahrens 	nvl = dict2nvl(dict);
33614843421SMatthew Ahrens 	if (nvl == NULL)
33714843421SMatthew Ahrens 		return (NULL);
33814843421SMatthew Ahrens 
33914843421SMatthew Ahrens 	err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
34014843421SMatthew Ahrens 	assert(err == 0);
34114843421SMatthew Ahrens 	nvbuf = malloc(nvsz);
34214843421SMatthew Ahrens 	err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
34314843421SMatthew Ahrens 	assert(err == 0);
34414843421SMatthew Ahrens 
34514843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
34614843421SMatthew Ahrens 	zc.zc_nvlist_src_size = nvsz;
34714843421SMatthew Ahrens 	zc.zc_nvlist_src = (uintptr_t)nvbuf;
34814843421SMatthew Ahrens 	zc.zc_perm_action = un;
34914843421SMatthew Ahrens 
35014843421SMatthew Ahrens 	err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
35114843421SMatthew Ahrens 	free(nvbuf);
35214843421SMatthew Ahrens 	if (err) {
35314843421SMatthew Ahrens 		seterr(_("cannot set permissions on %s"), name);
35414843421SMatthew Ahrens 		return (NULL);
35514843421SMatthew Ahrens 	}
35614843421SMatthew Ahrens 
35714843421SMatthew Ahrens 	Py_RETURN_NONE;
35814843421SMatthew Ahrens }
35914843421SMatthew Ahrens 
360842727c2SChris Kirby static PyObject *
361842727c2SChris Kirby py_get_holds(PyObject *self, PyObject *args)
362842727c2SChris Kirby {
363842727c2SChris Kirby 	zfs_cmd_t zc = { 0 };
364842727c2SChris Kirby 	char *name;
365842727c2SChris Kirby 	PyObject *nvl;
366842727c2SChris Kirby 
367842727c2SChris Kirby 	if (!PyArg_ParseTuple(args, "s", &name))
368842727c2SChris Kirby 		return (NULL);
369842727c2SChris Kirby 
370842727c2SChris Kirby 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
371842727c2SChris Kirby 
372842727c2SChris Kirby 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
373842727c2SChris Kirby 	if (nvl == NULL)
374842727c2SChris Kirby 		seterr(_("cannot get holds for %s"), name);
375842727c2SChris Kirby 
376842727c2SChris Kirby 	return (nvl);
377842727c2SChris Kirby }
378842727c2SChris Kirby 
37914843421SMatthew Ahrens static PyObject *
38014843421SMatthew Ahrens py_userspace_many(PyObject *self, PyObject *args)
38114843421SMatthew Ahrens {
38214843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
38314843421SMatthew Ahrens 	zfs_userquota_prop_t type;
38414843421SMatthew Ahrens 	char *name, *propname;
38514843421SMatthew Ahrens 	int bufsz = 1<<20;
38614843421SMatthew Ahrens 	void *buf;
38714843421SMatthew Ahrens 	PyObject *dict, *file;
38814843421SMatthew Ahrens 	int error;
38914843421SMatthew Ahrens 
39014843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "ss", &name, &propname))
39114843421SMatthew Ahrens 		return (NULL);
39214843421SMatthew Ahrens 
39314843421SMatthew Ahrens 	for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++)
39414843421SMatthew Ahrens 		if (strcmp(propname, zfs_userquota_prop_prefixes[type]) == 0)
39514843421SMatthew Ahrens 			break;
39614843421SMatthew Ahrens 	if (type == ZFS_NUM_USERQUOTA_PROPS) {
39714843421SMatthew Ahrens 		PyErr_SetString(PyExc_KeyError, propname);
39814843421SMatthew Ahrens 		return (NULL);
39914843421SMatthew Ahrens 	}
40014843421SMatthew Ahrens 
40114843421SMatthew Ahrens 	dict = PyDict_New();
40214843421SMatthew Ahrens 	buf = malloc(bufsz);
40314843421SMatthew Ahrens 
40414843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
40514843421SMatthew Ahrens 	zc.zc_objset_type = type;
40614843421SMatthew Ahrens 	zc.zc_cookie = 0;
40714843421SMatthew Ahrens 
40814843421SMatthew Ahrens 	while (1) {
40914843421SMatthew Ahrens 		zfs_useracct_t *zua = buf;
41014843421SMatthew Ahrens 
41114843421SMatthew Ahrens 		zc.zc_nvlist_dst = (uintptr_t)buf;
41214843421SMatthew Ahrens 		zc.zc_nvlist_dst_size = bufsz;
41314843421SMatthew Ahrens 
41414843421SMatthew Ahrens 		error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_MANY, &zc);
41514843421SMatthew Ahrens 		if (error || zc.zc_nvlist_dst_size == 0)
41614843421SMatthew Ahrens 			break;
41714843421SMatthew Ahrens 
41814843421SMatthew Ahrens 		while (zc.zc_nvlist_dst_size > 0) {
41914843421SMatthew Ahrens 			PyObject *pykey, *pyval;
42014843421SMatthew Ahrens 
42114843421SMatthew Ahrens 			pykey = Py_BuildValue("sI",
42214843421SMatthew Ahrens 			    zua->zu_domain, zua->zu_rid);
42314843421SMatthew Ahrens 			pyval = Py_BuildValue("K", zua->zu_space);
42414843421SMatthew Ahrens 			PyDict_SetItem(dict, pykey, pyval);
42514843421SMatthew Ahrens 			Py_DECREF(pykey);
42614843421SMatthew Ahrens 			Py_DECREF(pyval);
42714843421SMatthew Ahrens 
42814843421SMatthew Ahrens 			zua++;
42914843421SMatthew Ahrens 			zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
43014843421SMatthew Ahrens 		}
43114843421SMatthew Ahrens 	}
43214843421SMatthew Ahrens 
43314843421SMatthew Ahrens 	free(buf);
43414843421SMatthew Ahrens 
43514843421SMatthew Ahrens 	if (error != 0) {
43614843421SMatthew Ahrens 		Py_DECREF(dict);
43714843421SMatthew Ahrens 		seterr(_("cannot get %s property on %s"), propname, name);
43814843421SMatthew Ahrens 		return (NULL);
43914843421SMatthew Ahrens 	}
44014843421SMatthew Ahrens 
44114843421SMatthew Ahrens 	return (dict);
44214843421SMatthew Ahrens }
44314843421SMatthew Ahrens 
44414843421SMatthew Ahrens static PyObject *
44514843421SMatthew Ahrens py_userspace_upgrade(PyObject *self, PyObject *args)
44614843421SMatthew Ahrens {
44714843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
44814843421SMatthew Ahrens 	char *name;
44914843421SMatthew Ahrens 	int error;
45014843421SMatthew Ahrens 
45114843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
45214843421SMatthew Ahrens 		return (NULL);
45314843421SMatthew Ahrens 
45414843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
45514843421SMatthew Ahrens 	error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_UPGRADE, &zc);
45614843421SMatthew Ahrens 
45714843421SMatthew Ahrens 	if (error != 0) {
45814843421SMatthew Ahrens 		seterr(_("cannot initialize user accounting information on %s"),
45914843421SMatthew Ahrens 		    name);
46014843421SMatthew Ahrens 		return (NULL);
46114843421SMatthew Ahrens 	}
46214843421SMatthew Ahrens 
46314843421SMatthew Ahrens 	Py_RETURN_NONE;
46414843421SMatthew Ahrens }
46514843421SMatthew Ahrens 
46614843421SMatthew Ahrens static PyObject *
46714843421SMatthew Ahrens py_set_cmdstr(PyObject *self, PyObject *args)
46814843421SMatthew Ahrens {
46914843421SMatthew Ahrens 	char *str;
47014843421SMatthew Ahrens 
47114843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &str))
47214843421SMatthew Ahrens 		return (NULL);
47314843421SMatthew Ahrens 
47414843421SMatthew Ahrens 	(void) strlcpy(cmdstr, str, sizeof (cmdstr));
47514843421SMatthew Ahrens 
47614843421SMatthew Ahrens 	Py_RETURN_NONE;
47714843421SMatthew Ahrens }
47814843421SMatthew Ahrens 
47914843421SMatthew Ahrens static PyObject *
48014843421SMatthew Ahrens py_get_proptable(PyObject *self, PyObject *args)
48114843421SMatthew Ahrens {
48214843421SMatthew Ahrens 	zprop_desc_t *t = zfs_prop_get_table();
48314843421SMatthew Ahrens 	PyObject *d = PyDict_New();
48414843421SMatthew Ahrens 	zfs_prop_t i;
48514843421SMatthew Ahrens 
48614843421SMatthew Ahrens 	for (i = 0; i < ZFS_NUM_PROPS; i++) {
48714843421SMatthew Ahrens 		zprop_desc_t *p = &t[i];
48814843421SMatthew Ahrens 		PyObject *tuple;
48914843421SMatthew Ahrens 		static const char *typetable[] =
49014843421SMatthew Ahrens 		    {"number", "string", "index"};
49114843421SMatthew Ahrens 		static const char *attrtable[] =
49214843421SMatthew Ahrens 		    {"default", "readonly", "inherit", "onetime"};
49314843421SMatthew Ahrens 		PyObject *indextable;
49414843421SMatthew Ahrens 
49514843421SMatthew Ahrens 		if (p->pd_proptype == PROP_TYPE_INDEX) {
49614843421SMatthew Ahrens 			const zprop_index_t *it = p->pd_table;
49714843421SMatthew Ahrens 			indextable = PyDict_New();
49814843421SMatthew Ahrens 			int j;
49914843421SMatthew Ahrens 			for (j = 0; it[j].pi_name; j++) {
50014843421SMatthew Ahrens 				PyDict_SetItemString(indextable,
50114843421SMatthew Ahrens 				    it[j].pi_name,
50214843421SMatthew Ahrens 				    Py_BuildValue("K", it[j].pi_value));
50314843421SMatthew Ahrens 			}
50414843421SMatthew Ahrens 		} else {
50514843421SMatthew Ahrens 			Py_INCREF(Py_None);
50614843421SMatthew Ahrens 			indextable = Py_None;
50714843421SMatthew Ahrens 		}
50814843421SMatthew Ahrens 
50914843421SMatthew Ahrens 		tuple = Py_BuildValue("sissKsissiiO",
51014843421SMatthew Ahrens 		    p->pd_name, p->pd_propnum, typetable[p->pd_proptype],
51114843421SMatthew Ahrens 		    p->pd_strdefault, p->pd_numdefault,
51214843421SMatthew Ahrens 		    attrtable[p->pd_attr], p->pd_types,
51314843421SMatthew Ahrens 		    p->pd_values, p->pd_colname,
51414843421SMatthew Ahrens 		    p->pd_rightalign, p->pd_visible, indextable);
51514843421SMatthew Ahrens 		PyDict_SetItemString(d, p->pd_name, tuple);
51614843421SMatthew Ahrens 		Py_DECREF(tuple);
51714843421SMatthew Ahrens 	}
51814843421SMatthew Ahrens 
51914843421SMatthew Ahrens 	return (d);
52014843421SMatthew Ahrens }
52114843421SMatthew Ahrens 
52214843421SMatthew Ahrens static PyMethodDef zfsmethods[] = {
52314843421SMatthew Ahrens 	{"next_dataset", py_next_dataset, METH_VARARGS,
52414843421SMatthew Ahrens 	    "Get next child dataset or snapshot."},
52514843421SMatthew Ahrens 	{"get_fsacl", py_get_fsacl, METH_VARARGS, "Get allowed permissions."},
52614843421SMatthew Ahrens 	{"set_fsacl", py_set_fsacl, METH_VARARGS, "Set allowed permissions."},
52714843421SMatthew Ahrens 	{"userspace_many", py_userspace_many, METH_VARARGS,
52814843421SMatthew Ahrens 	    "Get user space accounting."},
52914843421SMatthew Ahrens 	{"userspace_upgrade", py_userspace_upgrade, METH_VARARGS,
53014843421SMatthew Ahrens 	    "Upgrade fs to enable user space accounting."},
53114843421SMatthew Ahrens 	{"set_cmdstr", py_set_cmdstr, METH_VARARGS,
53214843421SMatthew Ahrens 	    "Set command string for history logging."},
53314843421SMatthew Ahrens 	{"dataset_props", py_dataset_props, METH_VARARGS,
53414843421SMatthew Ahrens 	    "Get dataset properties."},
53514843421SMatthew Ahrens 	{"get_proptable", py_get_proptable, METH_NOARGS,
53614843421SMatthew Ahrens 	    "Get property table."},
537842727c2SChris Kirby 	{"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
53814843421SMatthew Ahrens 	{NULL, NULL, 0, NULL}
53914843421SMatthew Ahrens };
54014843421SMatthew Ahrens 
541e8921a52SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
542e8921a52SAndy Fiddaman static struct PyModuleDef zfs_module = {
543e8921a52SAndy Fiddaman 	PyModuleDef_HEAD_INIT,
544e8921a52SAndy Fiddaman 	"zfs.ioctl",
545e8921a52SAndy Fiddaman 	NULL,
546e8921a52SAndy Fiddaman 	-1,
547e8921a52SAndy Fiddaman 	zfsmethods
548e8921a52SAndy Fiddaman };
549e8921a52SAndy Fiddaman #endif
550e8921a52SAndy Fiddaman 
551e8921a52SAndy Fiddaman static PyObject *
552e8921a52SAndy Fiddaman moduleinit()
55314843421SMatthew Ahrens {
554e8921a52SAndy Fiddaman 	PyObject *zfs_ioctl, *zfs_util, *devfile;
555e8921a52SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
556e8921a52SAndy Fiddaman 	zfs_ioctl = PyModule_Create(&zfs_module);
557e8921a52SAndy Fiddaman #else
558e8921a52SAndy Fiddaman 	zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
559e8921a52SAndy Fiddaman #endif
560e8921a52SAndy Fiddaman 	zfs_util = PyImport_ImportModule("zfs.util");
56114843421SMatthew Ahrens 
56214843421SMatthew Ahrens 	if (zfs_util == NULL)
563e8921a52SAndy Fiddaman 		return (NULL);
56414843421SMatthew Ahrens 
56514843421SMatthew Ahrens 	ZFSError = PyObject_GetAttrString(zfs_util, "ZFSError");
56614843421SMatthew Ahrens 	devfile = PyObject_GetAttrString(zfs_util, "dev");
56714843421SMatthew Ahrens 	zfsdevfd = PyObject_AsFileDescriptor(devfile);
56814843421SMatthew Ahrens 
56914843421SMatthew Ahrens 	zfs_prop_init();
570e8921a52SAndy Fiddaman 
571e8921a52SAndy Fiddaman 	return (zfs_ioctl);
572e8921a52SAndy Fiddaman }
573e8921a52SAndy Fiddaman 
574e8921a52SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
575e8921a52SAndy Fiddaman PyMODINIT_FUNC
576e8921a52SAndy Fiddaman PyInit_ioctl(void)
577e8921a52SAndy Fiddaman {
578e8921a52SAndy Fiddaman 	return (moduleinit());
57914843421SMatthew Ahrens }
580e8921a52SAndy Fiddaman #else
581e8921a52SAndy Fiddaman PyMODINIT_FUNC
582e8921a52SAndy Fiddaman initioctl(void)
583e8921a52SAndy Fiddaman {
584e8921a52SAndy Fiddaman 	(void) moduleinit();
585e8921a52SAndy Fiddaman }
586e8921a52SAndy Fiddaman #endif
587