xref: /titanic_51/usr/src/lib/pyzfs/common/ioctl.c (revision 019853a6d596efa0894944beb070ff383745494a)
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.
24d561bb99SAndy 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;
135d561bb99SAndy 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)) {
146*019853a6SAndy Fiddaman 		const char *keystr;
147d561bb99SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
148*019853a6SAndy Fiddaman 		keystr = PyUnicode_AsUTF8(key);
149d561bb99SAndy Fiddaman #else
150*019853a6SAndy Fiddaman 		keystr = PyString_AsString(key);
151d561bb99SAndy Fiddaman #endif
15214843421SMatthew Ahrens 		if (keystr == NULL) {
15314843421SMatthew Ahrens 			PyErr_SetObject(PyExc_KeyError, key);
15414843421SMatthew Ahrens 			nvlist_free(nvl);
15514843421SMatthew Ahrens 			return (NULL);
15614843421SMatthew Ahrens 		}
15714843421SMatthew Ahrens 
15814843421SMatthew Ahrens 		if (PyDict_Check(value)) {
15914843421SMatthew Ahrens 			nvlist_t *valnvl = dict2nvl(value);
16014843421SMatthew Ahrens 			err = nvlist_add_nvlist(nvl, keystr, valnvl);
16114843421SMatthew Ahrens 			nvlist_free(valnvl);
16214843421SMatthew Ahrens 		} else if (value == Py_None) {
16314843421SMatthew Ahrens 			err = nvlist_add_boolean(nvl, keystr);
164d561bb99SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
165d2b4b850SAlexander Pyhalov 		} else if (PyUnicode_Check(value)) {
166d561bb99SAndy Fiddaman #else
16714843421SMatthew Ahrens 		} else if (PyString_Check(value)) {
168d561bb99SAndy Fiddaman #endif
169*019853a6SAndy Fiddaman 			const char *valstr;
170d561bb99SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
171*019853a6SAndy Fiddaman 			valstr = PyUnicode_AsUTF8(value);
172d561bb99SAndy Fiddaman #else
173*019853a6SAndy Fiddaman 			valstr = PyString_AsString(value);
174d561bb99SAndy Fiddaman #endif
17514843421SMatthew Ahrens 			err = nvlist_add_string(nvl, keystr, valstr);
176d561bb99SAndy Fiddaman 		} else if (PyLong_Check(value)) {
177d561bb99SAndy Fiddaman 			uint64_t valint = PyLong_AsUnsignedLongLongMask(value);
17814843421SMatthew Ahrens 			err = nvlist_add_uint64(nvl, keystr, valint);
17914843421SMatthew Ahrens 		} else if (PyBool_Check(value)) {
18014843421SMatthew Ahrens 			boolean_t valbool = value == Py_True ? B_TRUE : B_FALSE;
18114843421SMatthew Ahrens 			err = nvlist_add_boolean_value(nvl, keystr, valbool);
18214843421SMatthew Ahrens 		} else {
18314843421SMatthew Ahrens 			PyErr_SetObject(PyExc_ValueError, value);
18414843421SMatthew Ahrens 			nvlist_free(nvl);
18514843421SMatthew Ahrens 			return (NULL);
18614843421SMatthew Ahrens 		}
18714843421SMatthew Ahrens 		assert(err == 0);
18814843421SMatthew Ahrens 	}
18914843421SMatthew Ahrens 
19014843421SMatthew Ahrens 	return (nvl);
19114843421SMatthew Ahrens }
19214843421SMatthew Ahrens 
19314843421SMatthew Ahrens static PyObject *
19414843421SMatthew Ahrens fakepropval(uint64_t value)
19514843421SMatthew Ahrens {
19614843421SMatthew Ahrens 	PyObject *d = PyDict_New();
19714843421SMatthew Ahrens 	PyDict_SetItemString(d, "value", Py_BuildValue("K", value));
19814843421SMatthew Ahrens 	return (d);
19914843421SMatthew Ahrens }
20014843421SMatthew Ahrens 
20114843421SMatthew Ahrens static void
20214843421SMatthew Ahrens add_ds_props(zfs_cmd_t *zc, PyObject *nvl)
20314843421SMatthew Ahrens {
20414843421SMatthew Ahrens 	dmu_objset_stats_t *s = &zc->zc_objset_stats;
20514843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "numclones",
20614843421SMatthew Ahrens 	    fakepropval(s->dds_num_clones));
20714843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "issnap",
20814843421SMatthew Ahrens 	    fakepropval(s->dds_is_snapshot));
20914843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "inconsistent",
21014843421SMatthew Ahrens 	    fakepropval(s->dds_inconsistent));
21114843421SMatthew Ahrens }
21214843421SMatthew Ahrens 
21314843421SMatthew Ahrens /* On error, returns NULL but does not set python exception. */
21414843421SMatthew Ahrens static PyObject *
21514843421SMatthew Ahrens ioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
21614843421SMatthew Ahrens {
21714843421SMatthew Ahrens 	int nvsz = 2048;
21814843421SMatthew Ahrens 	void *nvbuf;
21914843421SMatthew Ahrens 	PyObject *pynv = NULL;
22014843421SMatthew Ahrens 
22114843421SMatthew Ahrens again:
22214843421SMatthew Ahrens 	nvbuf = malloc(nvsz);
22314843421SMatthew Ahrens 	zc->zc_nvlist_dst_size = nvsz;
22414843421SMatthew Ahrens 	zc->zc_nvlist_dst = (uintptr_t)nvbuf;
22514843421SMatthew Ahrens 
22614843421SMatthew Ahrens 	if (ioctl(zfsdevfd, ioc, zc) == 0) {
22714843421SMatthew Ahrens 		nvlist_t *nvl;
22814843421SMatthew Ahrens 
22914843421SMatthew Ahrens 		errno = nvlist_unpack(nvbuf, zc->zc_nvlist_dst_size, &nvl, 0);
23014843421SMatthew Ahrens 		if (errno == 0) {
23114843421SMatthew Ahrens 			pynv = nvl2py(nvl);
23214843421SMatthew Ahrens 			nvlist_free(nvl);
23314843421SMatthew Ahrens 		}
23414843421SMatthew Ahrens 	} else if (errno == ENOMEM) {
23514843421SMatthew Ahrens 		free(nvbuf);
23614843421SMatthew Ahrens 		nvsz = zc->zc_nvlist_dst_size;
23714843421SMatthew Ahrens 		goto again;
23814843421SMatthew Ahrens 	}
23914843421SMatthew Ahrens 	free(nvbuf);
24014843421SMatthew Ahrens 	return (pynv);
24114843421SMatthew Ahrens }
24214843421SMatthew Ahrens 
24314843421SMatthew Ahrens static PyObject *
24414843421SMatthew Ahrens py_next_dataset(PyObject *self, PyObject *args)
24514843421SMatthew Ahrens {
24614843421SMatthew Ahrens 	int ioc;
24714843421SMatthew Ahrens 	uint64_t cookie;
24814843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
24914843421SMatthew Ahrens 	int snaps;
25014843421SMatthew Ahrens 	char *name;
25114843421SMatthew Ahrens 	PyObject *nvl;
25214843421SMatthew Ahrens 	PyObject *ret = NULL;
25314843421SMatthew Ahrens 
25414843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "siK", &name, &snaps, &cookie))
25514843421SMatthew Ahrens 		return (NULL);
25614843421SMatthew Ahrens 
25714843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
25814843421SMatthew Ahrens 	zc.zc_cookie = cookie;
25914843421SMatthew Ahrens 
26014843421SMatthew Ahrens 	if (snaps)
26114843421SMatthew Ahrens 		ioc = ZFS_IOC_SNAPSHOT_LIST_NEXT;
26214843421SMatthew Ahrens 	else
26314843421SMatthew Ahrens 		ioc = ZFS_IOC_DATASET_LIST_NEXT;
26414843421SMatthew Ahrens 
26514843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ioc, &zc);
26614843421SMatthew Ahrens 	if (nvl) {
26714843421SMatthew Ahrens 		add_ds_props(&zc, nvl);
26814843421SMatthew Ahrens 		ret = Py_BuildValue("sKO", zc.zc_name, zc.zc_cookie, nvl);
26914843421SMatthew Ahrens 		Py_DECREF(nvl);
27014843421SMatthew Ahrens 	} else if (errno == ESRCH) {
27114843421SMatthew Ahrens 		PyErr_SetNone(PyExc_StopIteration);
27214843421SMatthew Ahrens 	} else {
27314843421SMatthew Ahrens 		if (snaps)
27414843421SMatthew Ahrens 			seterr(_("cannot get snapshots of %s"), name);
27514843421SMatthew Ahrens 		else
27614843421SMatthew Ahrens 			seterr(_("cannot get child datasets of %s"), name);
27714843421SMatthew Ahrens 	}
27814843421SMatthew Ahrens 	return (ret);
27914843421SMatthew Ahrens }
28014843421SMatthew Ahrens 
28114843421SMatthew Ahrens static PyObject *
28214843421SMatthew Ahrens py_dataset_props(PyObject *self, PyObject *args)
28314843421SMatthew Ahrens {
28414843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
28514843421SMatthew Ahrens 	int snaps;
28614843421SMatthew Ahrens 	char *name;
28714843421SMatthew Ahrens 	PyObject *nvl;
28814843421SMatthew Ahrens 
28914843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
29014843421SMatthew Ahrens 		return (NULL);
29114843421SMatthew Ahrens 
29214843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
29314843421SMatthew Ahrens 
29414843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ZFS_IOC_OBJSET_STATS, &zc);
29514843421SMatthew Ahrens 	if (nvl) {
29614843421SMatthew Ahrens 		add_ds_props(&zc, nvl);
29714843421SMatthew Ahrens 	} else {
29814843421SMatthew Ahrens 		seterr(_("cannot access dataset %s"), name);
29914843421SMatthew Ahrens 	}
30014843421SMatthew Ahrens 	return (nvl);
30114843421SMatthew Ahrens }
30214843421SMatthew Ahrens 
30314843421SMatthew Ahrens static PyObject *
30414843421SMatthew Ahrens py_get_fsacl(PyObject *self, PyObject *args)
30514843421SMatthew Ahrens {
30614843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
30714843421SMatthew Ahrens 	char *name;
30814843421SMatthew Ahrens 	PyObject *nvl;
30914843421SMatthew Ahrens 
31014843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
31114843421SMatthew Ahrens 		return (NULL);
31214843421SMatthew Ahrens 
31314843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
31414843421SMatthew Ahrens 
31514843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_FSACL, &zc);
31614843421SMatthew Ahrens 	if (nvl == NULL)
31714843421SMatthew Ahrens 		seterr(_("cannot get permissions on %s"), name);
31814843421SMatthew Ahrens 
31914843421SMatthew Ahrens 	return (nvl);
32014843421SMatthew Ahrens }
32114843421SMatthew Ahrens 
32214843421SMatthew Ahrens static PyObject *
32314843421SMatthew Ahrens py_set_fsacl(PyObject *self, PyObject *args)
32414843421SMatthew Ahrens {
32514843421SMatthew Ahrens 	int un;
32614843421SMatthew Ahrens 	size_t nvsz;
32714843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
32814843421SMatthew Ahrens 	char *name, *nvbuf;
32914843421SMatthew Ahrens 	PyObject *dict, *file;
33014843421SMatthew Ahrens 	nvlist_t *nvl;
33114843421SMatthew Ahrens 	int err;
33214843421SMatthew Ahrens 
33314843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "siO!", &name, &un,
33414843421SMatthew Ahrens 	    &PyDict_Type, &dict))
33514843421SMatthew Ahrens 		return (NULL);
33614843421SMatthew Ahrens 
33714843421SMatthew Ahrens 	nvl = dict2nvl(dict);
33814843421SMatthew Ahrens 	if (nvl == NULL)
33914843421SMatthew Ahrens 		return (NULL);
34014843421SMatthew Ahrens 
34114843421SMatthew Ahrens 	err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
34214843421SMatthew Ahrens 	assert(err == 0);
34314843421SMatthew Ahrens 	nvbuf = malloc(nvsz);
34414843421SMatthew Ahrens 	err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
34514843421SMatthew Ahrens 	assert(err == 0);
34614843421SMatthew Ahrens 
34714843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
34814843421SMatthew Ahrens 	zc.zc_nvlist_src_size = nvsz;
34914843421SMatthew Ahrens 	zc.zc_nvlist_src = (uintptr_t)nvbuf;
35014843421SMatthew Ahrens 	zc.zc_perm_action = un;
35114843421SMatthew Ahrens 
35214843421SMatthew Ahrens 	err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
35314843421SMatthew Ahrens 	free(nvbuf);
35414843421SMatthew Ahrens 	if (err) {
35514843421SMatthew Ahrens 		seterr(_("cannot set permissions on %s"), name);
35614843421SMatthew Ahrens 		return (NULL);
35714843421SMatthew Ahrens 	}
35814843421SMatthew Ahrens 
35914843421SMatthew Ahrens 	Py_RETURN_NONE;
36014843421SMatthew Ahrens }
36114843421SMatthew Ahrens 
36214843421SMatthew Ahrens static PyObject *
363842727c2SChris Kirby py_get_holds(PyObject *self, PyObject *args)
364842727c2SChris Kirby {
365842727c2SChris Kirby 	zfs_cmd_t zc = { 0 };
366842727c2SChris Kirby 	char *name;
367842727c2SChris Kirby 	PyObject *nvl;
368842727c2SChris Kirby 
369842727c2SChris Kirby 	if (!PyArg_ParseTuple(args, "s", &name))
370842727c2SChris Kirby 		return (NULL);
371842727c2SChris Kirby 
372842727c2SChris Kirby 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
373842727c2SChris Kirby 
374842727c2SChris Kirby 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
375842727c2SChris Kirby 	if (nvl == NULL)
376842727c2SChris Kirby 		seterr(_("cannot get holds for %s"), name);
377842727c2SChris Kirby 
378842727c2SChris Kirby 	return (nvl);
379842727c2SChris Kirby }
380842727c2SChris Kirby 
381842727c2SChris Kirby static PyObject *
38214843421SMatthew Ahrens py_userspace_many(PyObject *self, PyObject *args)
38314843421SMatthew Ahrens {
38414843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
38514843421SMatthew Ahrens 	zfs_userquota_prop_t type;
38614843421SMatthew Ahrens 	char *name, *propname;
38714843421SMatthew Ahrens 	int bufsz = 1<<20;
38814843421SMatthew Ahrens 	void *buf;
38914843421SMatthew Ahrens 	PyObject *dict, *file;
39014843421SMatthew Ahrens 	int error;
39114843421SMatthew Ahrens 
39214843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "ss", &name, &propname))
39314843421SMatthew Ahrens 		return (NULL);
39414843421SMatthew Ahrens 
39514843421SMatthew Ahrens 	for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++)
39614843421SMatthew Ahrens 		if (strcmp(propname, zfs_userquota_prop_prefixes[type]) == 0)
39714843421SMatthew Ahrens 			break;
39814843421SMatthew Ahrens 	if (type == ZFS_NUM_USERQUOTA_PROPS) {
39914843421SMatthew Ahrens 		PyErr_SetString(PyExc_KeyError, propname);
40014843421SMatthew Ahrens 		return (NULL);
40114843421SMatthew Ahrens 	}
40214843421SMatthew Ahrens 
40314843421SMatthew Ahrens 	dict = PyDict_New();
40414843421SMatthew Ahrens 	buf = malloc(bufsz);
40514843421SMatthew Ahrens 
40614843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
40714843421SMatthew Ahrens 	zc.zc_objset_type = type;
40814843421SMatthew Ahrens 	zc.zc_cookie = 0;
40914843421SMatthew Ahrens 
41014843421SMatthew Ahrens 	while (1) {
41114843421SMatthew Ahrens 		zfs_useracct_t *zua = buf;
41214843421SMatthew Ahrens 
41314843421SMatthew Ahrens 		zc.zc_nvlist_dst = (uintptr_t)buf;
41414843421SMatthew Ahrens 		zc.zc_nvlist_dst_size = bufsz;
41514843421SMatthew Ahrens 
41614843421SMatthew Ahrens 		error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_MANY, &zc);
41714843421SMatthew Ahrens 		if (error || zc.zc_nvlist_dst_size == 0)
41814843421SMatthew Ahrens 			break;
41914843421SMatthew Ahrens 
42014843421SMatthew Ahrens 		while (zc.zc_nvlist_dst_size > 0) {
42114843421SMatthew Ahrens 			PyObject *pykey, *pyval;
42214843421SMatthew Ahrens 
42314843421SMatthew Ahrens 			pykey = Py_BuildValue("sI",
42414843421SMatthew Ahrens 			    zua->zu_domain, zua->zu_rid);
42514843421SMatthew Ahrens 			pyval = Py_BuildValue("K", zua->zu_space);
42614843421SMatthew Ahrens 			PyDict_SetItem(dict, pykey, pyval);
42714843421SMatthew Ahrens 			Py_DECREF(pykey);
42814843421SMatthew Ahrens 			Py_DECREF(pyval);
42914843421SMatthew Ahrens 
43014843421SMatthew Ahrens 			zua++;
43114843421SMatthew Ahrens 			zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
43214843421SMatthew Ahrens 		}
43314843421SMatthew Ahrens 	}
43414843421SMatthew Ahrens 
43514843421SMatthew Ahrens 	free(buf);
43614843421SMatthew Ahrens 
43714843421SMatthew Ahrens 	if (error != 0) {
43814843421SMatthew Ahrens 		Py_DECREF(dict);
43914843421SMatthew Ahrens 		seterr(_("cannot get %s property on %s"), propname, name);
44014843421SMatthew Ahrens 		return (NULL);
44114843421SMatthew Ahrens 	}
44214843421SMatthew Ahrens 
44314843421SMatthew Ahrens 	return (dict);
44414843421SMatthew Ahrens }
44514843421SMatthew Ahrens 
44614843421SMatthew Ahrens static PyObject *
44714843421SMatthew Ahrens py_userspace_upgrade(PyObject *self, PyObject *args)
44814843421SMatthew Ahrens {
44914843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
45014843421SMatthew Ahrens 	char *name;
45114843421SMatthew Ahrens 	int error;
45214843421SMatthew Ahrens 
45314843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
45414843421SMatthew Ahrens 		return (NULL);
45514843421SMatthew Ahrens 
45614843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
45714843421SMatthew Ahrens 	error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_UPGRADE, &zc);
45814843421SMatthew Ahrens 
45914843421SMatthew Ahrens 	if (error != 0) {
46014843421SMatthew Ahrens 		seterr(_("cannot initialize user accounting information on %s"),
46114843421SMatthew Ahrens 		    name);
46214843421SMatthew Ahrens 		return (NULL);
46314843421SMatthew Ahrens 	}
46414843421SMatthew Ahrens 
46514843421SMatthew Ahrens 	Py_RETURN_NONE;
46614843421SMatthew Ahrens }
46714843421SMatthew Ahrens 
46814843421SMatthew Ahrens static PyObject *
46914843421SMatthew Ahrens py_set_cmdstr(PyObject *self, PyObject *args)
47014843421SMatthew Ahrens {
47114843421SMatthew Ahrens 	char *str;
47214843421SMatthew Ahrens 
47314843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &str))
47414843421SMatthew Ahrens 		return (NULL);
47514843421SMatthew Ahrens 
47614843421SMatthew Ahrens 	(void) strlcpy(cmdstr, str, sizeof (cmdstr));
47714843421SMatthew Ahrens 
47814843421SMatthew Ahrens 	Py_RETURN_NONE;
47914843421SMatthew Ahrens }
48014843421SMatthew Ahrens 
48114843421SMatthew Ahrens static PyObject *
48214843421SMatthew Ahrens py_get_proptable(PyObject *self, PyObject *args)
48314843421SMatthew Ahrens {
48414843421SMatthew Ahrens 	zprop_desc_t *t = zfs_prop_get_table();
48514843421SMatthew Ahrens 	PyObject *d = PyDict_New();
48614843421SMatthew Ahrens 	zfs_prop_t i;
48714843421SMatthew Ahrens 
48814843421SMatthew Ahrens 	for (i = 0; i < ZFS_NUM_PROPS; i++) {
48914843421SMatthew Ahrens 		zprop_desc_t *p = &t[i];
49014843421SMatthew Ahrens 		PyObject *tuple;
49114843421SMatthew Ahrens 		static const char *typetable[] =
49214843421SMatthew Ahrens 		    {"number", "string", "index"};
49314843421SMatthew Ahrens 		static const char *attrtable[] =
49414843421SMatthew Ahrens 		    {"default", "readonly", "inherit", "onetime"};
49514843421SMatthew Ahrens 		PyObject *indextable;
49614843421SMatthew Ahrens 
49714843421SMatthew Ahrens 		if (p->pd_proptype == PROP_TYPE_INDEX) {
49814843421SMatthew Ahrens 			const zprop_index_t *it = p->pd_table;
49914843421SMatthew Ahrens 			indextable = PyDict_New();
50014843421SMatthew Ahrens 			int j;
50114843421SMatthew Ahrens 			for (j = 0; it[j].pi_name; j++) {
50214843421SMatthew Ahrens 				PyDict_SetItemString(indextable,
50314843421SMatthew Ahrens 				    it[j].pi_name,
50414843421SMatthew Ahrens 				    Py_BuildValue("K", it[j].pi_value));
50514843421SMatthew Ahrens 			}
50614843421SMatthew Ahrens 		} else {
50714843421SMatthew Ahrens 			Py_INCREF(Py_None);
50814843421SMatthew Ahrens 			indextable = Py_None;
50914843421SMatthew Ahrens 		}
51014843421SMatthew Ahrens 
51114843421SMatthew Ahrens 		tuple = Py_BuildValue("sissKsissiiO",
51214843421SMatthew Ahrens 		    p->pd_name, p->pd_propnum, typetable[p->pd_proptype],
51314843421SMatthew Ahrens 		    p->pd_strdefault, p->pd_numdefault,
51414843421SMatthew Ahrens 		    attrtable[p->pd_attr], p->pd_types,
51514843421SMatthew Ahrens 		    p->pd_values, p->pd_colname,
51614843421SMatthew Ahrens 		    p->pd_rightalign, p->pd_visible, indextable);
51714843421SMatthew Ahrens 		PyDict_SetItemString(d, p->pd_name, tuple);
51814843421SMatthew Ahrens 		Py_DECREF(tuple);
51914843421SMatthew Ahrens 	}
52014843421SMatthew Ahrens 
52114843421SMatthew Ahrens 	return (d);
52214843421SMatthew Ahrens }
52314843421SMatthew Ahrens 
52414843421SMatthew Ahrens static PyMethodDef zfsmethods[] = {
52514843421SMatthew Ahrens 	{"next_dataset", py_next_dataset, METH_VARARGS,
52614843421SMatthew Ahrens 	    "Get next child dataset or snapshot."},
52714843421SMatthew Ahrens 	{"get_fsacl", py_get_fsacl, METH_VARARGS, "Get allowed permissions."},
52814843421SMatthew Ahrens 	{"set_fsacl", py_set_fsacl, METH_VARARGS, "Set allowed permissions."},
52914843421SMatthew Ahrens 	{"userspace_many", py_userspace_many, METH_VARARGS,
53014843421SMatthew Ahrens 	    "Get user space accounting."},
53114843421SMatthew Ahrens 	{"userspace_upgrade", py_userspace_upgrade, METH_VARARGS,
53214843421SMatthew Ahrens 	    "Upgrade fs to enable user space accounting."},
53314843421SMatthew Ahrens 	{"set_cmdstr", py_set_cmdstr, METH_VARARGS,
53414843421SMatthew Ahrens 	    "Set command string for history logging."},
53514843421SMatthew Ahrens 	{"dataset_props", py_dataset_props, METH_VARARGS,
53614843421SMatthew Ahrens 	    "Get dataset properties."},
53714843421SMatthew Ahrens 	{"get_proptable", py_get_proptable, METH_NOARGS,
53814843421SMatthew Ahrens 	    "Get property table."},
539842727c2SChris Kirby 	{"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
54014843421SMatthew Ahrens 	{NULL, NULL, 0, NULL}
54114843421SMatthew Ahrens };
54214843421SMatthew Ahrens 
543d561bb99SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
544d561bb99SAndy Fiddaman static struct PyModuleDef zfs_module = {
545d561bb99SAndy Fiddaman 	PyModuleDef_HEAD_INIT,
546d561bb99SAndy Fiddaman 	"zfs.ioctl",
547d561bb99SAndy Fiddaman 	NULL,
548d561bb99SAndy Fiddaman 	-1,
549d561bb99SAndy Fiddaman 	zfsmethods
550d561bb99SAndy Fiddaman };
551d561bb99SAndy Fiddaman #endif
552d561bb99SAndy Fiddaman 
553d561bb99SAndy Fiddaman static PyObject *
554d561bb99SAndy Fiddaman moduleinit()
55514843421SMatthew Ahrens {
556d561bb99SAndy Fiddaman 	PyObject *zfs_ioctl, *zfs_util, *devfile;
557d561bb99SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
558d561bb99SAndy Fiddaman 	zfs_ioctl = PyModule_Create(&zfs_module);
559d561bb99SAndy Fiddaman #else
560d561bb99SAndy Fiddaman 	zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
561d561bb99SAndy Fiddaman #endif
562d561bb99SAndy Fiddaman 	zfs_util = PyImport_ImportModule("zfs.util");
56314843421SMatthew Ahrens 
56414843421SMatthew Ahrens 	if (zfs_util == NULL)
565d561bb99SAndy Fiddaman 		return (NULL);
56614843421SMatthew Ahrens 
56714843421SMatthew Ahrens 	ZFSError = PyObject_GetAttrString(zfs_util, "ZFSError");
56814843421SMatthew Ahrens 	devfile = PyObject_GetAttrString(zfs_util, "dev");
56914843421SMatthew Ahrens 	zfsdevfd = PyObject_AsFileDescriptor(devfile);
57014843421SMatthew Ahrens 
57114843421SMatthew Ahrens 	zfs_prop_init();
572d561bb99SAndy Fiddaman 
573d561bb99SAndy Fiddaman 	return (zfs_ioctl);
57414843421SMatthew Ahrens }
575d561bb99SAndy Fiddaman 
576d561bb99SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
577d561bb99SAndy Fiddaman PyMODINIT_FUNC
578d561bb99SAndy Fiddaman PyInit_ioctl(void)
579d561bb99SAndy Fiddaman {
580d561bb99SAndy Fiddaman 	return (moduleinit());
581d561bb99SAndy Fiddaman }
582d561bb99SAndy Fiddaman #else
583d561bb99SAndy Fiddaman PyMODINIT_FUNC
584d561bb99SAndy Fiddaman initioctl(void)
585d561bb99SAndy Fiddaman {
586d561bb99SAndy Fiddaman 	(void) moduleinit();
587d561bb99SAndy Fiddaman }
588d561bb99SAndy Fiddaman #endif
589