xref: /onnv-gate/usr/src/lib/pyzfs/common/ioctl.c (revision 11821:25c34ce7b825)
19396SMatthew.Ahrens@Sun.COM /*
29396SMatthew.Ahrens@Sun.COM  * CDDL HEADER START
39396SMatthew.Ahrens@Sun.COM  *
49396SMatthew.Ahrens@Sun.COM  * The contents of this file are subject to the terms of the
59396SMatthew.Ahrens@Sun.COM  * Common Development and Distribution License (the "License").
69396SMatthew.Ahrens@Sun.COM  * You may not use this file except in compliance with the License.
79396SMatthew.Ahrens@Sun.COM  *
89396SMatthew.Ahrens@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99396SMatthew.Ahrens@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109396SMatthew.Ahrens@Sun.COM  * See the License for the specific language governing permissions
119396SMatthew.Ahrens@Sun.COM  * and limitations under the License.
129396SMatthew.Ahrens@Sun.COM  *
139396SMatthew.Ahrens@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149396SMatthew.Ahrens@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159396SMatthew.Ahrens@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169396SMatthew.Ahrens@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179396SMatthew.Ahrens@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189396SMatthew.Ahrens@Sun.COM  *
199396SMatthew.Ahrens@Sun.COM  * CDDL HEADER END
209396SMatthew.Ahrens@Sun.COM  */
219396SMatthew.Ahrens@Sun.COM /*
22*11821SSam.Falkner@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
239396SMatthew.Ahrens@Sun.COM  * Use is subject to license terms.
249396SMatthew.Ahrens@Sun.COM  */
259396SMatthew.Ahrens@Sun.COM 
269396SMatthew.Ahrens@Sun.COM #include <Python.h>
279396SMatthew.Ahrens@Sun.COM #include <sys/zfs_ioctl.h>
289396SMatthew.Ahrens@Sun.COM #include <sys/fs/zfs.h>
299396SMatthew.Ahrens@Sun.COM #include <strings.h>
309396SMatthew.Ahrens@Sun.COM #include <unistd.h>
319396SMatthew.Ahrens@Sun.COM #include <libnvpair.h>
329396SMatthew.Ahrens@Sun.COM #include <libintl.h>
339396SMatthew.Ahrens@Sun.COM #include <libzfs.h>
349396SMatthew.Ahrens@Sun.COM #include "zfs_prop.h"
359396SMatthew.Ahrens@Sun.COM 
369396SMatthew.Ahrens@Sun.COM static PyObject *ZFSError;
379396SMatthew.Ahrens@Sun.COM static int zfsdevfd;
389396SMatthew.Ahrens@Sun.COM 
399396SMatthew.Ahrens@Sun.COM #ifdef __lint
409396SMatthew.Ahrens@Sun.COM #define	dgettext(x, y) y
419396SMatthew.Ahrens@Sun.COM #endif
429396SMatthew.Ahrens@Sun.COM 
439396SMatthew.Ahrens@Sun.COM #define	_(s) dgettext(TEXT_DOMAIN, s)
449396SMatthew.Ahrens@Sun.COM 
459396SMatthew.Ahrens@Sun.COM /*PRINTFLIKE1*/
469396SMatthew.Ahrens@Sun.COM static void
seterr(char * fmt,...)479396SMatthew.Ahrens@Sun.COM seterr(char *fmt, ...)
489396SMatthew.Ahrens@Sun.COM {
499396SMatthew.Ahrens@Sun.COM 	char errstr[1024];
509396SMatthew.Ahrens@Sun.COM 	va_list v;
519396SMatthew.Ahrens@Sun.COM 
529396SMatthew.Ahrens@Sun.COM 	va_start(v, fmt);
539396SMatthew.Ahrens@Sun.COM 	(void) vsnprintf(errstr, sizeof (errstr), fmt, v);
549396SMatthew.Ahrens@Sun.COM 	va_end(v);
559396SMatthew.Ahrens@Sun.COM 
569396SMatthew.Ahrens@Sun.COM 	PyErr_SetObject(ZFSError, Py_BuildValue("is", errno, errstr));
579396SMatthew.Ahrens@Sun.COM }
589396SMatthew.Ahrens@Sun.COM 
599396SMatthew.Ahrens@Sun.COM static char cmdstr[HIS_MAX_RECORD_LEN];
609396SMatthew.Ahrens@Sun.COM 
619396SMatthew.Ahrens@Sun.COM static int
ioctl_with_cmdstr(int ioc,zfs_cmd_t * zc)629396SMatthew.Ahrens@Sun.COM ioctl_with_cmdstr(int ioc, zfs_cmd_t *zc)
639396SMatthew.Ahrens@Sun.COM {
649396SMatthew.Ahrens@Sun.COM 	int err;
659396SMatthew.Ahrens@Sun.COM 
669396SMatthew.Ahrens@Sun.COM 	if (cmdstr[0])
679396SMatthew.Ahrens@Sun.COM 		zc->zc_history = (uint64_t)(uintptr_t)cmdstr;
689396SMatthew.Ahrens@Sun.COM 	err = ioctl(zfsdevfd, ioc, zc);
699396SMatthew.Ahrens@Sun.COM 	cmdstr[0] = '\0';
709396SMatthew.Ahrens@Sun.COM 	return (err);
719396SMatthew.Ahrens@Sun.COM }
729396SMatthew.Ahrens@Sun.COM 
739396SMatthew.Ahrens@Sun.COM static PyObject *
nvl2py(nvlist_t * nvl)749396SMatthew.Ahrens@Sun.COM nvl2py(nvlist_t *nvl)
759396SMatthew.Ahrens@Sun.COM {
769396SMatthew.Ahrens@Sun.COM 	PyObject *pyo;
779396SMatthew.Ahrens@Sun.COM 	nvpair_t *nvp;
789396SMatthew.Ahrens@Sun.COM 
799396SMatthew.Ahrens@Sun.COM 	pyo = PyDict_New();
809396SMatthew.Ahrens@Sun.COM 
819396SMatthew.Ahrens@Sun.COM 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp;
829396SMatthew.Ahrens@Sun.COM 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
839396SMatthew.Ahrens@Sun.COM 		PyObject *pyval;
849396SMatthew.Ahrens@Sun.COM 		char *sval;
859396SMatthew.Ahrens@Sun.COM 		uint64_t ival;
869396SMatthew.Ahrens@Sun.COM 		boolean_t bval;
879396SMatthew.Ahrens@Sun.COM 		nvlist_t *nval;
889396SMatthew.Ahrens@Sun.COM 
899396SMatthew.Ahrens@Sun.COM 		switch (nvpair_type(nvp)) {
909396SMatthew.Ahrens@Sun.COM 		case DATA_TYPE_STRING:
919396SMatthew.Ahrens@Sun.COM 			(void) nvpair_value_string(nvp, &sval);
929396SMatthew.Ahrens@Sun.COM 			pyval = Py_BuildValue("s", sval);
939396SMatthew.Ahrens@Sun.COM 			break;
949396SMatthew.Ahrens@Sun.COM 
959396SMatthew.Ahrens@Sun.COM 		case DATA_TYPE_UINT64:
969396SMatthew.Ahrens@Sun.COM 			(void) nvpair_value_uint64(nvp, &ival);
979396SMatthew.Ahrens@Sun.COM 			pyval = Py_BuildValue("K", ival);
989396SMatthew.Ahrens@Sun.COM 			break;
999396SMatthew.Ahrens@Sun.COM 
1009396SMatthew.Ahrens@Sun.COM 		case DATA_TYPE_NVLIST:
1019396SMatthew.Ahrens@Sun.COM 			(void) nvpair_value_nvlist(nvp, &nval);
1029396SMatthew.Ahrens@Sun.COM 			pyval = nvl2py(nval);
1039396SMatthew.Ahrens@Sun.COM 			break;
1049396SMatthew.Ahrens@Sun.COM 
1059396SMatthew.Ahrens@Sun.COM 		case DATA_TYPE_BOOLEAN:
1069396SMatthew.Ahrens@Sun.COM 			Py_INCREF(Py_None);
1079396SMatthew.Ahrens@Sun.COM 			pyval = Py_None;
1089396SMatthew.Ahrens@Sun.COM 			break;
1099396SMatthew.Ahrens@Sun.COM 
1109396SMatthew.Ahrens@Sun.COM 		case DATA_TYPE_BOOLEAN_VALUE:
1119396SMatthew.Ahrens@Sun.COM 			(void) nvpair_value_boolean_value(nvp, &bval);
1129396SMatthew.Ahrens@Sun.COM 			pyval = Py_BuildValue("i", bval);
1139396SMatthew.Ahrens@Sun.COM 			break;
1149396SMatthew.Ahrens@Sun.COM 
1159396SMatthew.Ahrens@Sun.COM 		default:
1169396SMatthew.Ahrens@Sun.COM 			PyErr_SetNone(PyExc_ValueError);
1179396SMatthew.Ahrens@Sun.COM 			Py_DECREF(pyo);
1189396SMatthew.Ahrens@Sun.COM 			return (NULL);
1199396SMatthew.Ahrens@Sun.COM 		}
1209396SMatthew.Ahrens@Sun.COM 
1219396SMatthew.Ahrens@Sun.COM 		PyDict_SetItemString(pyo, nvpair_name(nvp), pyval);
1229396SMatthew.Ahrens@Sun.COM 		Py_DECREF(pyval);
1239396SMatthew.Ahrens@Sun.COM 	}
1249396SMatthew.Ahrens@Sun.COM 
1259396SMatthew.Ahrens@Sun.COM 	return (pyo);
1269396SMatthew.Ahrens@Sun.COM }
1279396SMatthew.Ahrens@Sun.COM 
1289396SMatthew.Ahrens@Sun.COM static nvlist_t *
dict2nvl(PyObject * d)1299396SMatthew.Ahrens@Sun.COM dict2nvl(PyObject *d)
1309396SMatthew.Ahrens@Sun.COM {
1319396SMatthew.Ahrens@Sun.COM 	nvlist_t *nvl;
1329396SMatthew.Ahrens@Sun.COM 	int err;
1339396SMatthew.Ahrens@Sun.COM 	PyObject *key, *value;
1349396SMatthew.Ahrens@Sun.COM 	int pos = 0;
1359396SMatthew.Ahrens@Sun.COM 
1369396SMatthew.Ahrens@Sun.COM 	if (!PyDict_Check(d)) {
1379396SMatthew.Ahrens@Sun.COM 		PyErr_SetObject(PyExc_ValueError, d);
1389396SMatthew.Ahrens@Sun.COM 		return (NULL);
1399396SMatthew.Ahrens@Sun.COM 	}
1409396SMatthew.Ahrens@Sun.COM 
1419396SMatthew.Ahrens@Sun.COM 	err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
1429396SMatthew.Ahrens@Sun.COM 	assert(err == 0);
1439396SMatthew.Ahrens@Sun.COM 
1449396SMatthew.Ahrens@Sun.COM 	while (PyDict_Next(d, &pos, &key, &value)) {
1459396SMatthew.Ahrens@Sun.COM 		char *keystr = PyString_AsString(key);
1469396SMatthew.Ahrens@Sun.COM 		if (keystr == NULL) {
1479396SMatthew.Ahrens@Sun.COM 			PyErr_SetObject(PyExc_KeyError, key);
1489396SMatthew.Ahrens@Sun.COM 			nvlist_free(nvl);
1499396SMatthew.Ahrens@Sun.COM 			return (NULL);
1509396SMatthew.Ahrens@Sun.COM 		}
1519396SMatthew.Ahrens@Sun.COM 
1529396SMatthew.Ahrens@Sun.COM 		if (PyDict_Check(value)) {
1539396SMatthew.Ahrens@Sun.COM 			nvlist_t *valnvl = dict2nvl(value);
1549396SMatthew.Ahrens@Sun.COM 			err = nvlist_add_nvlist(nvl, keystr, valnvl);
1559396SMatthew.Ahrens@Sun.COM 			nvlist_free(valnvl);
1569396SMatthew.Ahrens@Sun.COM 		} else if (value == Py_None) {
1579396SMatthew.Ahrens@Sun.COM 			err = nvlist_add_boolean(nvl, keystr);
1589396SMatthew.Ahrens@Sun.COM 		} else if (PyString_Check(value)) {
1599396SMatthew.Ahrens@Sun.COM 			char *valstr = PyString_AsString(value);
1609396SMatthew.Ahrens@Sun.COM 			err = nvlist_add_string(nvl, keystr, valstr);
1619396SMatthew.Ahrens@Sun.COM 		} else if (PyInt_Check(value)) {
1629396SMatthew.Ahrens@Sun.COM 			uint64_t valint = PyInt_AsUnsignedLongLongMask(value);
1639396SMatthew.Ahrens@Sun.COM 			err = nvlist_add_uint64(nvl, keystr, valint);
1649396SMatthew.Ahrens@Sun.COM 		} else if (PyBool_Check(value)) {
1659396SMatthew.Ahrens@Sun.COM 			boolean_t valbool = value == Py_True ? B_TRUE : B_FALSE;
1669396SMatthew.Ahrens@Sun.COM 			err = nvlist_add_boolean_value(nvl, keystr, valbool);
1679396SMatthew.Ahrens@Sun.COM 		} else {
1689396SMatthew.Ahrens@Sun.COM 			PyErr_SetObject(PyExc_ValueError, value);
1699396SMatthew.Ahrens@Sun.COM 			nvlist_free(nvl);
1709396SMatthew.Ahrens@Sun.COM 			return (NULL);
1719396SMatthew.Ahrens@Sun.COM 		}
1729396SMatthew.Ahrens@Sun.COM 		assert(err == 0);
1739396SMatthew.Ahrens@Sun.COM 	}
1749396SMatthew.Ahrens@Sun.COM 
1759396SMatthew.Ahrens@Sun.COM 	return (nvl);
1769396SMatthew.Ahrens@Sun.COM }
1779396SMatthew.Ahrens@Sun.COM 
1789396SMatthew.Ahrens@Sun.COM static PyObject *
fakepropval(uint64_t value)1799396SMatthew.Ahrens@Sun.COM fakepropval(uint64_t value)
1809396SMatthew.Ahrens@Sun.COM {
1819396SMatthew.Ahrens@Sun.COM 	PyObject *d = PyDict_New();
1829396SMatthew.Ahrens@Sun.COM 	PyDict_SetItemString(d, "value", Py_BuildValue("K", value));
1839396SMatthew.Ahrens@Sun.COM 	return (d);
1849396SMatthew.Ahrens@Sun.COM }
1859396SMatthew.Ahrens@Sun.COM 
1869396SMatthew.Ahrens@Sun.COM static void
add_ds_props(zfs_cmd_t * zc,PyObject * nvl)1879396SMatthew.Ahrens@Sun.COM add_ds_props(zfs_cmd_t *zc, PyObject *nvl)
1889396SMatthew.Ahrens@Sun.COM {
1899396SMatthew.Ahrens@Sun.COM 	dmu_objset_stats_t *s = &zc->zc_objset_stats;
1909396SMatthew.Ahrens@Sun.COM 	PyDict_SetItemString(nvl, "numclones",
1919396SMatthew.Ahrens@Sun.COM 	    fakepropval(s->dds_num_clones));
1929396SMatthew.Ahrens@Sun.COM 	PyDict_SetItemString(nvl, "issnap",
1939396SMatthew.Ahrens@Sun.COM 	    fakepropval(s->dds_is_snapshot));
1949396SMatthew.Ahrens@Sun.COM 	PyDict_SetItemString(nvl, "inconsistent",
1959396SMatthew.Ahrens@Sun.COM 	    fakepropval(s->dds_inconsistent));
1969396SMatthew.Ahrens@Sun.COM }
1979396SMatthew.Ahrens@Sun.COM 
1989396SMatthew.Ahrens@Sun.COM /* On error, returns NULL but does not set python exception. */
1999396SMatthew.Ahrens@Sun.COM static PyObject *
ioctl_with_dstnv(int ioc,zfs_cmd_t * zc)2009396SMatthew.Ahrens@Sun.COM ioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
2019396SMatthew.Ahrens@Sun.COM {
2029396SMatthew.Ahrens@Sun.COM 	int nvsz = 2048;
2039396SMatthew.Ahrens@Sun.COM 	void *nvbuf;
2049396SMatthew.Ahrens@Sun.COM 	PyObject *pynv = NULL;
2059396SMatthew.Ahrens@Sun.COM 
2069396SMatthew.Ahrens@Sun.COM again:
2079396SMatthew.Ahrens@Sun.COM 	nvbuf = malloc(nvsz);
2089396SMatthew.Ahrens@Sun.COM 	zc->zc_nvlist_dst_size = nvsz;
2099396SMatthew.Ahrens@Sun.COM 	zc->zc_nvlist_dst = (uintptr_t)nvbuf;
2109396SMatthew.Ahrens@Sun.COM 
2119396SMatthew.Ahrens@Sun.COM 	if (ioctl(zfsdevfd, ioc, zc) == 0) {
2129396SMatthew.Ahrens@Sun.COM 		nvlist_t *nvl;
2139396SMatthew.Ahrens@Sun.COM 
2149396SMatthew.Ahrens@Sun.COM 		errno = nvlist_unpack(nvbuf, zc->zc_nvlist_dst_size, &nvl, 0);
2159396SMatthew.Ahrens@Sun.COM 		if (errno == 0) {
2169396SMatthew.Ahrens@Sun.COM 			pynv = nvl2py(nvl);
2179396SMatthew.Ahrens@Sun.COM 			nvlist_free(nvl);
2189396SMatthew.Ahrens@Sun.COM 		}
2199396SMatthew.Ahrens@Sun.COM 	} else if (errno == ENOMEM) {
2209396SMatthew.Ahrens@Sun.COM 		free(nvbuf);
2219396SMatthew.Ahrens@Sun.COM 		nvsz = zc->zc_nvlist_dst_size;
2229396SMatthew.Ahrens@Sun.COM 		goto again;
2239396SMatthew.Ahrens@Sun.COM 	}
2249396SMatthew.Ahrens@Sun.COM 	free(nvbuf);
2259396SMatthew.Ahrens@Sun.COM 	return (pynv);
2269396SMatthew.Ahrens@Sun.COM }
2279396SMatthew.Ahrens@Sun.COM 
2289396SMatthew.Ahrens@Sun.COM static PyObject *
py_next_dataset(PyObject * self,PyObject * args)2299396SMatthew.Ahrens@Sun.COM py_next_dataset(PyObject *self, PyObject *args)
2309396SMatthew.Ahrens@Sun.COM {
2319396SMatthew.Ahrens@Sun.COM 	int ioc;
2329396SMatthew.Ahrens@Sun.COM 	uint64_t cookie;
2339396SMatthew.Ahrens@Sun.COM 	zfs_cmd_t zc = { 0 };
2349396SMatthew.Ahrens@Sun.COM 	int snaps;
2359396SMatthew.Ahrens@Sun.COM 	char *name;
2369396SMatthew.Ahrens@Sun.COM 	PyObject *nvl;
2379396SMatthew.Ahrens@Sun.COM 	PyObject *ret = NULL;
2389396SMatthew.Ahrens@Sun.COM 
2399396SMatthew.Ahrens@Sun.COM 	if (!PyArg_ParseTuple(args, "siK", &name, &snaps, &cookie))
2409396SMatthew.Ahrens@Sun.COM 		return (NULL);
2419396SMatthew.Ahrens@Sun.COM 
2429396SMatthew.Ahrens@Sun.COM 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
2439396SMatthew.Ahrens@Sun.COM 	zc.zc_cookie = cookie;
2449396SMatthew.Ahrens@Sun.COM 
2459396SMatthew.Ahrens@Sun.COM 	if (snaps)
2469396SMatthew.Ahrens@Sun.COM 		ioc = ZFS_IOC_SNAPSHOT_LIST_NEXT;
2479396SMatthew.Ahrens@Sun.COM 	else
2489396SMatthew.Ahrens@Sun.COM 		ioc = ZFS_IOC_DATASET_LIST_NEXT;
2499396SMatthew.Ahrens@Sun.COM 
2509396SMatthew.Ahrens@Sun.COM 	nvl = ioctl_with_dstnv(ioc, &zc);
2519396SMatthew.Ahrens@Sun.COM 	if (nvl) {
2529396SMatthew.Ahrens@Sun.COM 		add_ds_props(&zc, nvl);
2539396SMatthew.Ahrens@Sun.COM 		ret = Py_BuildValue("sKO", zc.zc_name, zc.zc_cookie, nvl);
2549396SMatthew.Ahrens@Sun.COM 		Py_DECREF(nvl);
2559396SMatthew.Ahrens@Sun.COM 	} else if (errno == ESRCH) {
2569396SMatthew.Ahrens@Sun.COM 		PyErr_SetNone(PyExc_StopIteration);
2579396SMatthew.Ahrens@Sun.COM 	} else {
2589396SMatthew.Ahrens@Sun.COM 		if (snaps)
2599396SMatthew.Ahrens@Sun.COM 			seterr(_("cannot get snapshots of %s"), name);
2609396SMatthew.Ahrens@Sun.COM 		else
2619396SMatthew.Ahrens@Sun.COM 			seterr(_("cannot get child datasets of %s"), name);
2629396SMatthew.Ahrens@Sun.COM 	}
2639396SMatthew.Ahrens@Sun.COM 	return (ret);
2649396SMatthew.Ahrens@Sun.COM }
2659396SMatthew.Ahrens@Sun.COM 
2669396SMatthew.Ahrens@Sun.COM static PyObject *
py_dataset_props(PyObject * self,PyObject * args)2679396SMatthew.Ahrens@Sun.COM py_dataset_props(PyObject *self, PyObject *args)
2689396SMatthew.Ahrens@Sun.COM {
2699396SMatthew.Ahrens@Sun.COM 	zfs_cmd_t zc = { 0 };
2709396SMatthew.Ahrens@Sun.COM 	int snaps;
2719396SMatthew.Ahrens@Sun.COM 	char *name;
2729396SMatthew.Ahrens@Sun.COM 	PyObject *nvl;
2739396SMatthew.Ahrens@Sun.COM 
2749396SMatthew.Ahrens@Sun.COM 	if (!PyArg_ParseTuple(args, "s", &name))
2759396SMatthew.Ahrens@Sun.COM 		return (NULL);
2769396SMatthew.Ahrens@Sun.COM 
2779396SMatthew.Ahrens@Sun.COM 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
2789396SMatthew.Ahrens@Sun.COM 
2799396SMatthew.Ahrens@Sun.COM 	nvl = ioctl_with_dstnv(ZFS_IOC_OBJSET_STATS, &zc);
2809396SMatthew.Ahrens@Sun.COM 	if (nvl) {
2819396SMatthew.Ahrens@Sun.COM 		add_ds_props(&zc, nvl);
2829396SMatthew.Ahrens@Sun.COM 	} else {
2839396SMatthew.Ahrens@Sun.COM 		seterr(_("cannot access dataset %s"), name);
2849396SMatthew.Ahrens@Sun.COM 	}
2859396SMatthew.Ahrens@Sun.COM 	return (nvl);
2869396SMatthew.Ahrens@Sun.COM }
2879396SMatthew.Ahrens@Sun.COM 
2889396SMatthew.Ahrens@Sun.COM static PyObject *
py_get_fsacl(PyObject * self,PyObject * args)2899396SMatthew.Ahrens@Sun.COM py_get_fsacl(PyObject *self, PyObject *args)
2909396SMatthew.Ahrens@Sun.COM {
2919396SMatthew.Ahrens@Sun.COM 	zfs_cmd_t zc = { 0 };
2929396SMatthew.Ahrens@Sun.COM 	char *name;
2939396SMatthew.Ahrens@Sun.COM 	PyObject *nvl;
2949396SMatthew.Ahrens@Sun.COM 
2959396SMatthew.Ahrens@Sun.COM 	if (!PyArg_ParseTuple(args, "s", &name))
2969396SMatthew.Ahrens@Sun.COM 		return (NULL);
2979396SMatthew.Ahrens@Sun.COM 
2989396SMatthew.Ahrens@Sun.COM 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
2999396SMatthew.Ahrens@Sun.COM 
3009396SMatthew.Ahrens@Sun.COM 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_FSACL, &zc);
3019396SMatthew.Ahrens@Sun.COM 	if (nvl == NULL)
3029396SMatthew.Ahrens@Sun.COM 		seterr(_("cannot get permissions on %s"), name);
3039396SMatthew.Ahrens@Sun.COM 
3049396SMatthew.Ahrens@Sun.COM 	return (nvl);
3059396SMatthew.Ahrens@Sun.COM }
3069396SMatthew.Ahrens@Sun.COM 
3079396SMatthew.Ahrens@Sun.COM static PyObject *
py_set_fsacl(PyObject * self,PyObject * args)3089396SMatthew.Ahrens@Sun.COM py_set_fsacl(PyObject *self, PyObject *args)
3099396SMatthew.Ahrens@Sun.COM {
3109396SMatthew.Ahrens@Sun.COM 	int un;
3119396SMatthew.Ahrens@Sun.COM 	size_t nvsz;
3129396SMatthew.Ahrens@Sun.COM 	zfs_cmd_t zc = { 0 };
3139396SMatthew.Ahrens@Sun.COM 	char *name, *nvbuf;
3149396SMatthew.Ahrens@Sun.COM 	PyObject *dict, *file;
3159396SMatthew.Ahrens@Sun.COM 	nvlist_t *nvl;
3169396SMatthew.Ahrens@Sun.COM 	int err;
3179396SMatthew.Ahrens@Sun.COM 
3189396SMatthew.Ahrens@Sun.COM 	if (!PyArg_ParseTuple(args, "siO!", &name, &un,
3199396SMatthew.Ahrens@Sun.COM 	    &PyDict_Type, &dict))
3209396SMatthew.Ahrens@Sun.COM 		return (NULL);
3219396SMatthew.Ahrens@Sun.COM 
3229396SMatthew.Ahrens@Sun.COM 	nvl = dict2nvl(dict);
3239396SMatthew.Ahrens@Sun.COM 	if (nvl == NULL)
3249396SMatthew.Ahrens@Sun.COM 		return (NULL);
3259396SMatthew.Ahrens@Sun.COM 
3269396SMatthew.Ahrens@Sun.COM 	err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
3279396SMatthew.Ahrens@Sun.COM 	assert(err == 0);
3289396SMatthew.Ahrens@Sun.COM 	nvbuf = malloc(nvsz);
3299396SMatthew.Ahrens@Sun.COM 	err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
3309396SMatthew.Ahrens@Sun.COM 	assert(err == 0);
3319396SMatthew.Ahrens@Sun.COM 
3329396SMatthew.Ahrens@Sun.COM 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
3339396SMatthew.Ahrens@Sun.COM 	zc.zc_nvlist_src_size = nvsz;
3349396SMatthew.Ahrens@Sun.COM 	zc.zc_nvlist_src = (uintptr_t)nvbuf;
3359396SMatthew.Ahrens@Sun.COM 	zc.zc_perm_action = un;
3369396SMatthew.Ahrens@Sun.COM 
3379396SMatthew.Ahrens@Sun.COM 	err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
3389396SMatthew.Ahrens@Sun.COM 	free(nvbuf);
3399396SMatthew.Ahrens@Sun.COM 	if (err) {
3409396SMatthew.Ahrens@Sun.COM 		seterr(_("cannot set permissions on %s"), name);
3419396SMatthew.Ahrens@Sun.COM 		return (NULL);
3429396SMatthew.Ahrens@Sun.COM 	}
3439396SMatthew.Ahrens@Sun.COM 
3449396SMatthew.Ahrens@Sun.COM 	Py_RETURN_NONE;
3459396SMatthew.Ahrens@Sun.COM }
3469396SMatthew.Ahrens@Sun.COM 
3479396SMatthew.Ahrens@Sun.COM static PyObject *
py_get_holds(PyObject * self,PyObject * args)34810242Schris.kirby@sun.com py_get_holds(PyObject *self, PyObject *args)
34910242Schris.kirby@sun.com {
35010242Schris.kirby@sun.com 	zfs_cmd_t zc = { 0 };
35110242Schris.kirby@sun.com 	char *name;
35210242Schris.kirby@sun.com 	PyObject *nvl;
35310242Schris.kirby@sun.com 
35410242Schris.kirby@sun.com 	if (!PyArg_ParseTuple(args, "s", &name))
35510242Schris.kirby@sun.com 		return (NULL);
35610242Schris.kirby@sun.com 
35710242Schris.kirby@sun.com 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
35810242Schris.kirby@sun.com 
35910242Schris.kirby@sun.com 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
36010242Schris.kirby@sun.com 	if (nvl == NULL)
36110242Schris.kirby@sun.com 		seterr(_("cannot get holds for %s"), name);
36210242Schris.kirby@sun.com 
36310242Schris.kirby@sun.com 	return (nvl);
36410242Schris.kirby@sun.com }
36510242Schris.kirby@sun.com 
36610242Schris.kirby@sun.com static PyObject *
py_userspace_many(PyObject * self,PyObject * args)3679396SMatthew.Ahrens@Sun.COM py_userspace_many(PyObject *self, PyObject *args)
3689396SMatthew.Ahrens@Sun.COM {
3699396SMatthew.Ahrens@Sun.COM 	zfs_cmd_t zc = { 0 };
3709396SMatthew.Ahrens@Sun.COM 	zfs_userquota_prop_t type;
3719396SMatthew.Ahrens@Sun.COM 	char *name, *propname;
3729396SMatthew.Ahrens@Sun.COM 	int bufsz = 1<<20;
3739396SMatthew.Ahrens@Sun.COM 	void *buf;
3749396SMatthew.Ahrens@Sun.COM 	PyObject *dict, *file;
3759396SMatthew.Ahrens@Sun.COM 	int error;
3769396SMatthew.Ahrens@Sun.COM 
3779396SMatthew.Ahrens@Sun.COM 	if (!PyArg_ParseTuple(args, "ss", &name, &propname))
3789396SMatthew.Ahrens@Sun.COM 		return (NULL);
3799396SMatthew.Ahrens@Sun.COM 
3809396SMatthew.Ahrens@Sun.COM 	for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++)
3819396SMatthew.Ahrens@Sun.COM 		if (strcmp(propname, zfs_userquota_prop_prefixes[type]) == 0)
3829396SMatthew.Ahrens@Sun.COM 			break;
3839396SMatthew.Ahrens@Sun.COM 	if (type == ZFS_NUM_USERQUOTA_PROPS) {
3849396SMatthew.Ahrens@Sun.COM 		PyErr_SetString(PyExc_KeyError, propname);
3859396SMatthew.Ahrens@Sun.COM 		return (NULL);
3869396SMatthew.Ahrens@Sun.COM 	}
3879396SMatthew.Ahrens@Sun.COM 
3889396SMatthew.Ahrens@Sun.COM 	dict = PyDict_New();
3899396SMatthew.Ahrens@Sun.COM 	buf = malloc(bufsz);
3909396SMatthew.Ahrens@Sun.COM 
3919396SMatthew.Ahrens@Sun.COM 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
3929396SMatthew.Ahrens@Sun.COM 	zc.zc_objset_type = type;
3939396SMatthew.Ahrens@Sun.COM 	zc.zc_cookie = 0;
3949396SMatthew.Ahrens@Sun.COM 
3959396SMatthew.Ahrens@Sun.COM 	while (1) {
3969396SMatthew.Ahrens@Sun.COM 		zfs_useracct_t *zua = buf;
3979396SMatthew.Ahrens@Sun.COM 
3989396SMatthew.Ahrens@Sun.COM 		zc.zc_nvlist_dst = (uintptr_t)buf;
3999396SMatthew.Ahrens@Sun.COM 		zc.zc_nvlist_dst_size = bufsz;
4009396SMatthew.Ahrens@Sun.COM 
4019396SMatthew.Ahrens@Sun.COM 		error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_MANY, &zc);
4029396SMatthew.Ahrens@Sun.COM 		if (error || zc.zc_nvlist_dst_size == 0)
4039396SMatthew.Ahrens@Sun.COM 			break;
4049396SMatthew.Ahrens@Sun.COM 
4059396SMatthew.Ahrens@Sun.COM 		while (zc.zc_nvlist_dst_size > 0) {
4069396SMatthew.Ahrens@Sun.COM 			PyObject *pykey, *pyval;
4079396SMatthew.Ahrens@Sun.COM 
4089396SMatthew.Ahrens@Sun.COM 			pykey = Py_BuildValue("sI",
4099396SMatthew.Ahrens@Sun.COM 			    zua->zu_domain, zua->zu_rid);
4109396SMatthew.Ahrens@Sun.COM 			pyval = Py_BuildValue("K", zua->zu_space);
4119396SMatthew.Ahrens@Sun.COM 			PyDict_SetItem(dict, pykey, pyval);
4129396SMatthew.Ahrens@Sun.COM 			Py_DECREF(pykey);
4139396SMatthew.Ahrens@Sun.COM 			Py_DECREF(pyval);
4149396SMatthew.Ahrens@Sun.COM 
4159396SMatthew.Ahrens@Sun.COM 			zua++;
4169396SMatthew.Ahrens@Sun.COM 			zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4179396SMatthew.Ahrens@Sun.COM 		}
4189396SMatthew.Ahrens@Sun.COM 	}
4199396SMatthew.Ahrens@Sun.COM 
4209396SMatthew.Ahrens@Sun.COM 	free(buf);
4219396SMatthew.Ahrens@Sun.COM 
4229396SMatthew.Ahrens@Sun.COM 	if (error != 0) {
4239396SMatthew.Ahrens@Sun.COM 		Py_DECREF(dict);
4249396SMatthew.Ahrens@Sun.COM 		seterr(_("cannot get %s property on %s"), propname, name);
4259396SMatthew.Ahrens@Sun.COM 		return (NULL);
4269396SMatthew.Ahrens@Sun.COM 	}
4279396SMatthew.Ahrens@Sun.COM 
4289396SMatthew.Ahrens@Sun.COM 	return (dict);
4299396SMatthew.Ahrens@Sun.COM }
4309396SMatthew.Ahrens@Sun.COM 
4319396SMatthew.Ahrens@Sun.COM static PyObject *
py_userspace_upgrade(PyObject * self,PyObject * args)4329396SMatthew.Ahrens@Sun.COM py_userspace_upgrade(PyObject *self, PyObject *args)
4339396SMatthew.Ahrens@Sun.COM {
4349396SMatthew.Ahrens@Sun.COM 	zfs_cmd_t zc = { 0 };
4359396SMatthew.Ahrens@Sun.COM 	char *name;
4369396SMatthew.Ahrens@Sun.COM 	int error;
4379396SMatthew.Ahrens@Sun.COM 
4389396SMatthew.Ahrens@Sun.COM 	if (!PyArg_ParseTuple(args, "s", &name))
4399396SMatthew.Ahrens@Sun.COM 		return (NULL);
4409396SMatthew.Ahrens@Sun.COM 
4419396SMatthew.Ahrens@Sun.COM 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
4429396SMatthew.Ahrens@Sun.COM 	error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_UPGRADE, &zc);
4439396SMatthew.Ahrens@Sun.COM 
4449396SMatthew.Ahrens@Sun.COM 	if (error != 0) {
4459396SMatthew.Ahrens@Sun.COM 		seterr(_("cannot initialize user accounting information on %s"),
4469396SMatthew.Ahrens@Sun.COM 		    name);
4479396SMatthew.Ahrens@Sun.COM 		return (NULL);
4489396SMatthew.Ahrens@Sun.COM 	}
4499396SMatthew.Ahrens@Sun.COM 
4509396SMatthew.Ahrens@Sun.COM 	Py_RETURN_NONE;
4519396SMatthew.Ahrens@Sun.COM }
4529396SMatthew.Ahrens@Sun.COM 
4539396SMatthew.Ahrens@Sun.COM static PyObject *
py_set_cmdstr(PyObject * self,PyObject * args)4549396SMatthew.Ahrens@Sun.COM py_set_cmdstr(PyObject *self, PyObject *args)
4559396SMatthew.Ahrens@Sun.COM {
4569396SMatthew.Ahrens@Sun.COM 	char *str;
4579396SMatthew.Ahrens@Sun.COM 
4589396SMatthew.Ahrens@Sun.COM 	if (!PyArg_ParseTuple(args, "s", &str))
4599396SMatthew.Ahrens@Sun.COM 		return (NULL);
4609396SMatthew.Ahrens@Sun.COM 
4619396SMatthew.Ahrens@Sun.COM 	(void) strlcpy(cmdstr, str, sizeof (cmdstr));
4629396SMatthew.Ahrens@Sun.COM 
4639396SMatthew.Ahrens@Sun.COM 	Py_RETURN_NONE;
4649396SMatthew.Ahrens@Sun.COM }
4659396SMatthew.Ahrens@Sun.COM 
4669396SMatthew.Ahrens@Sun.COM static PyObject *
py_get_proptable(PyObject * self,PyObject * args)4679396SMatthew.Ahrens@Sun.COM py_get_proptable(PyObject *self, PyObject *args)
4689396SMatthew.Ahrens@Sun.COM {
4699396SMatthew.Ahrens@Sun.COM 	zprop_desc_t *t = zfs_prop_get_table();
4709396SMatthew.Ahrens@Sun.COM 	PyObject *d = PyDict_New();
4719396SMatthew.Ahrens@Sun.COM 	zfs_prop_t i;
4729396SMatthew.Ahrens@Sun.COM 
4739396SMatthew.Ahrens@Sun.COM 	for (i = 0; i < ZFS_NUM_PROPS; i++) {
4749396SMatthew.Ahrens@Sun.COM 		zprop_desc_t *p = &t[i];
4759396SMatthew.Ahrens@Sun.COM 		PyObject *tuple;
4769396SMatthew.Ahrens@Sun.COM 		static const char *typetable[] =
4779396SMatthew.Ahrens@Sun.COM 		    {"number", "string", "index"};
4789396SMatthew.Ahrens@Sun.COM 		static const char *attrtable[] =
4799396SMatthew.Ahrens@Sun.COM 		    {"default", "readonly", "inherit", "onetime"};
4809396SMatthew.Ahrens@Sun.COM 		PyObject *indextable;
4819396SMatthew.Ahrens@Sun.COM 
4829396SMatthew.Ahrens@Sun.COM 		if (p->pd_proptype == PROP_TYPE_INDEX) {
4839396SMatthew.Ahrens@Sun.COM 			const zprop_index_t *it = p->pd_table;
4849396SMatthew.Ahrens@Sun.COM 			indextable = PyDict_New();
4859396SMatthew.Ahrens@Sun.COM 			int j;
4869396SMatthew.Ahrens@Sun.COM 			for (j = 0; it[j].pi_name; j++) {
4879396SMatthew.Ahrens@Sun.COM 				PyDict_SetItemString(indextable,
4889396SMatthew.Ahrens@Sun.COM 				    it[j].pi_name,
4899396SMatthew.Ahrens@Sun.COM 				    Py_BuildValue("K", it[j].pi_value));
4909396SMatthew.Ahrens@Sun.COM 			}
4919396SMatthew.Ahrens@Sun.COM 		} else {
4929396SMatthew.Ahrens@Sun.COM 			Py_INCREF(Py_None);
4939396SMatthew.Ahrens@Sun.COM 			indextable = Py_None;
4949396SMatthew.Ahrens@Sun.COM 		}
4959396SMatthew.Ahrens@Sun.COM 
4969396SMatthew.Ahrens@Sun.COM 		tuple = Py_BuildValue("sissKsissiiO",
4979396SMatthew.Ahrens@Sun.COM 		    p->pd_name, p->pd_propnum, typetable[p->pd_proptype],
4989396SMatthew.Ahrens@Sun.COM 		    p->pd_strdefault, p->pd_numdefault,
4999396SMatthew.Ahrens@Sun.COM 		    attrtable[p->pd_attr], p->pd_types,
5009396SMatthew.Ahrens@Sun.COM 		    p->pd_values, p->pd_colname,
5019396SMatthew.Ahrens@Sun.COM 		    p->pd_rightalign, p->pd_visible, indextable);
5029396SMatthew.Ahrens@Sun.COM 		PyDict_SetItemString(d, p->pd_name, tuple);
5039396SMatthew.Ahrens@Sun.COM 		Py_DECREF(tuple);
5049396SMatthew.Ahrens@Sun.COM 	}
5059396SMatthew.Ahrens@Sun.COM 
5069396SMatthew.Ahrens@Sun.COM 	return (d);
5079396SMatthew.Ahrens@Sun.COM }
5089396SMatthew.Ahrens@Sun.COM 
5099396SMatthew.Ahrens@Sun.COM static PyMethodDef zfsmethods[] = {
5109396SMatthew.Ahrens@Sun.COM 	{"next_dataset", py_next_dataset, METH_VARARGS,
5119396SMatthew.Ahrens@Sun.COM 	    "Get next child dataset or snapshot."},
5129396SMatthew.Ahrens@Sun.COM 	{"get_fsacl", py_get_fsacl, METH_VARARGS, "Get allowed permissions."},
5139396SMatthew.Ahrens@Sun.COM 	{"set_fsacl", py_set_fsacl, METH_VARARGS, "Set allowed permissions."},
5149396SMatthew.Ahrens@Sun.COM 	{"userspace_many", py_userspace_many, METH_VARARGS,
5159396SMatthew.Ahrens@Sun.COM 	    "Get user space accounting."},
5169396SMatthew.Ahrens@Sun.COM 	{"userspace_upgrade", py_userspace_upgrade, METH_VARARGS,
5179396SMatthew.Ahrens@Sun.COM 	    "Upgrade fs to enable user space accounting."},
5189396SMatthew.Ahrens@Sun.COM 	{"set_cmdstr", py_set_cmdstr, METH_VARARGS,
5199396SMatthew.Ahrens@Sun.COM 	    "Set command string for history logging."},
5209396SMatthew.Ahrens@Sun.COM 	{"dataset_props", py_dataset_props, METH_VARARGS,
5219396SMatthew.Ahrens@Sun.COM 	    "Get dataset properties."},
5229396SMatthew.Ahrens@Sun.COM 	{"get_proptable", py_get_proptable, METH_NOARGS,
5239396SMatthew.Ahrens@Sun.COM 	    "Get property table."},
52410242Schris.kirby@sun.com 	{"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
5259396SMatthew.Ahrens@Sun.COM 	{NULL, NULL, 0, NULL}
5269396SMatthew.Ahrens@Sun.COM };
5279396SMatthew.Ahrens@Sun.COM 
5289396SMatthew.Ahrens@Sun.COM void
initioctl(void)5299396SMatthew.Ahrens@Sun.COM initioctl(void)
5309396SMatthew.Ahrens@Sun.COM {
5319396SMatthew.Ahrens@Sun.COM 	PyObject *zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
5329396SMatthew.Ahrens@Sun.COM 	PyObject *zfs_util = PyImport_ImportModule("zfs.util");
5339396SMatthew.Ahrens@Sun.COM 	PyObject *devfile;
5349396SMatthew.Ahrens@Sun.COM 
5359396SMatthew.Ahrens@Sun.COM 	if (zfs_util == NULL)
5369396SMatthew.Ahrens@Sun.COM 		return;
5379396SMatthew.Ahrens@Sun.COM 
5389396SMatthew.Ahrens@Sun.COM 	ZFSError = PyObject_GetAttrString(zfs_util, "ZFSError");
5399396SMatthew.Ahrens@Sun.COM 	devfile = PyObject_GetAttrString(zfs_util, "dev");
5409396SMatthew.Ahrens@Sun.COM 	zfsdevfd = PyObject_AsFileDescriptor(devfile);
5419396SMatthew.Ahrens@Sun.COM 
5429396SMatthew.Ahrens@Sun.COM 	zfs_prop_init();
5439396SMatthew.Ahrens@Sun.COM }
544