xref: /titanic_44/usr/src/lib/pyzfs/common/ioctl.c (revision 842727c2f41f01b380de4f5e787d905702870f23)
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 /*
2214843421SMatthew Ahrens  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2314843421SMatthew Ahrens  * Use is subject to license terms.
2414843421SMatthew Ahrens  */
2514843421SMatthew Ahrens 
2614843421SMatthew Ahrens #include <Python.h>
2714843421SMatthew Ahrens #include <sys/zfs_ioctl.h>
2814843421SMatthew Ahrens #include <sys/fs/zfs.h>
2914843421SMatthew Ahrens #include <strings.h>
3014843421SMatthew Ahrens #include <unistd.h>
3114843421SMatthew Ahrens #include <libnvpair.h>
3214843421SMatthew Ahrens #include <idmap.h>
3314843421SMatthew Ahrens #include <zone.h>
3414843421SMatthew Ahrens #include <libintl.h>
3514843421SMatthew Ahrens #include <libzfs.h>
363b12c289SMatthew Ahrens #include <directory.h>
3714843421SMatthew Ahrens #include "zfs_prop.h"
3814843421SMatthew Ahrens 
3914843421SMatthew Ahrens static PyObject *ZFSError;
4014843421SMatthew Ahrens static int zfsdevfd;
4114843421SMatthew Ahrens 
4214843421SMatthew Ahrens #ifdef __lint
4314843421SMatthew Ahrens #define	dgettext(x, y) y
4414843421SMatthew Ahrens #endif
4514843421SMatthew Ahrens 
4614843421SMatthew Ahrens #define	_(s) dgettext(TEXT_DOMAIN, s)
4714843421SMatthew Ahrens 
4814843421SMatthew Ahrens extern int sid_to_id(char *sid, boolean_t user, uid_t *id);
4914843421SMatthew Ahrens 
5014843421SMatthew Ahrens /*PRINTFLIKE1*/
5114843421SMatthew Ahrens static void
5214843421SMatthew Ahrens seterr(char *fmt, ...)
5314843421SMatthew Ahrens {
5414843421SMatthew Ahrens 	char errstr[1024];
5514843421SMatthew Ahrens 	va_list v;
5614843421SMatthew Ahrens 
5714843421SMatthew Ahrens 	va_start(v, fmt);
5814843421SMatthew Ahrens 	(void) vsnprintf(errstr, sizeof (errstr), fmt, v);
5914843421SMatthew Ahrens 	va_end(v);
6014843421SMatthew Ahrens 
6114843421SMatthew Ahrens 	PyErr_SetObject(ZFSError, Py_BuildValue("is", errno, errstr));
6214843421SMatthew Ahrens }
6314843421SMatthew Ahrens 
6414843421SMatthew Ahrens static char cmdstr[HIS_MAX_RECORD_LEN];
6514843421SMatthew Ahrens 
6614843421SMatthew Ahrens static int
6714843421SMatthew Ahrens ioctl_with_cmdstr(int ioc, zfs_cmd_t *zc)
6814843421SMatthew Ahrens {
6914843421SMatthew Ahrens 	int err;
7014843421SMatthew Ahrens 
7114843421SMatthew Ahrens 	if (cmdstr[0])
7214843421SMatthew Ahrens 		zc->zc_history = (uint64_t)(uintptr_t)cmdstr;
7314843421SMatthew Ahrens 	err = ioctl(zfsdevfd, ioc, zc);
7414843421SMatthew Ahrens 	cmdstr[0] = '\0';
7514843421SMatthew Ahrens 	return (err);
7614843421SMatthew Ahrens }
7714843421SMatthew Ahrens 
7814843421SMatthew Ahrens static PyObject *
7914843421SMatthew Ahrens nvl2py(nvlist_t *nvl)
8014843421SMatthew Ahrens {
8114843421SMatthew Ahrens 	PyObject *pyo;
8214843421SMatthew Ahrens 	nvpair_t *nvp;
8314843421SMatthew Ahrens 
8414843421SMatthew Ahrens 	pyo = PyDict_New();
8514843421SMatthew Ahrens 
8614843421SMatthew Ahrens 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp;
8714843421SMatthew Ahrens 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
8814843421SMatthew Ahrens 		PyObject *pyval;
8914843421SMatthew Ahrens 		char *sval;
9014843421SMatthew Ahrens 		uint64_t ival;
9114843421SMatthew Ahrens 		boolean_t bval;
9214843421SMatthew Ahrens 		nvlist_t *nval;
9314843421SMatthew Ahrens 
9414843421SMatthew Ahrens 		switch (nvpair_type(nvp)) {
9514843421SMatthew Ahrens 		case DATA_TYPE_STRING:
9614843421SMatthew Ahrens 			(void) nvpair_value_string(nvp, &sval);
9714843421SMatthew Ahrens 			pyval = Py_BuildValue("s", sval);
9814843421SMatthew Ahrens 			break;
9914843421SMatthew Ahrens 
10014843421SMatthew Ahrens 		case DATA_TYPE_UINT64:
10114843421SMatthew Ahrens 			(void) nvpair_value_uint64(nvp, &ival);
10214843421SMatthew Ahrens 			pyval = Py_BuildValue("K", ival);
10314843421SMatthew Ahrens 			break;
10414843421SMatthew Ahrens 
10514843421SMatthew Ahrens 		case DATA_TYPE_NVLIST:
10614843421SMatthew Ahrens 			(void) nvpair_value_nvlist(nvp, &nval);
10714843421SMatthew Ahrens 			pyval = nvl2py(nval);
10814843421SMatthew Ahrens 			break;
10914843421SMatthew Ahrens 
11014843421SMatthew Ahrens 		case DATA_TYPE_BOOLEAN:
11114843421SMatthew Ahrens 			Py_INCREF(Py_None);
11214843421SMatthew Ahrens 			pyval = Py_None;
11314843421SMatthew Ahrens 			break;
11414843421SMatthew Ahrens 
11514843421SMatthew Ahrens 		case DATA_TYPE_BOOLEAN_VALUE:
11614843421SMatthew Ahrens 			(void) nvpair_value_boolean_value(nvp, &bval);
11714843421SMatthew Ahrens 			pyval = Py_BuildValue("i", bval);
11814843421SMatthew Ahrens 			break;
11914843421SMatthew Ahrens 
12014843421SMatthew Ahrens 		default:
12114843421SMatthew Ahrens 			PyErr_SetNone(PyExc_ValueError);
12214843421SMatthew Ahrens 			Py_DECREF(pyo);
12314843421SMatthew Ahrens 			return (NULL);
12414843421SMatthew Ahrens 		}
12514843421SMatthew Ahrens 
12614843421SMatthew Ahrens 		PyDict_SetItemString(pyo, nvpair_name(nvp), pyval);
12714843421SMatthew Ahrens 		Py_DECREF(pyval);
12814843421SMatthew Ahrens 	}
12914843421SMatthew Ahrens 
13014843421SMatthew Ahrens 	return (pyo);
13114843421SMatthew Ahrens }
13214843421SMatthew Ahrens 
13314843421SMatthew Ahrens static nvlist_t *
13414843421SMatthew Ahrens dict2nvl(PyObject *d)
13514843421SMatthew Ahrens {
13614843421SMatthew Ahrens 	nvlist_t *nvl;
13714843421SMatthew Ahrens 	int err;
13814843421SMatthew Ahrens 	PyObject *key, *value;
13914843421SMatthew Ahrens 	int pos = 0;
14014843421SMatthew Ahrens 
14114843421SMatthew Ahrens 	if (!PyDict_Check(d)) {
14214843421SMatthew Ahrens 		PyErr_SetObject(PyExc_ValueError, d);
14314843421SMatthew Ahrens 		return (NULL);
14414843421SMatthew Ahrens 	}
14514843421SMatthew Ahrens 
14614843421SMatthew Ahrens 	err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
14714843421SMatthew Ahrens 	assert(err == 0);
14814843421SMatthew Ahrens 
14914843421SMatthew Ahrens 	while (PyDict_Next(d, &pos, &key, &value)) {
15014843421SMatthew Ahrens 		char *keystr = PyString_AsString(key);
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);
16314843421SMatthew Ahrens 		} else if (PyString_Check(value)) {
16414843421SMatthew Ahrens 			char *valstr = PyString_AsString(value);
16514843421SMatthew Ahrens 			err = nvlist_add_string(nvl, keystr, valstr);
16614843421SMatthew Ahrens 		} else if (PyInt_Check(value)) {
16714843421SMatthew Ahrens 			uint64_t valint = PyInt_AsUnsignedLongLongMask(value);
16814843421SMatthew Ahrens 			err = nvlist_add_uint64(nvl, keystr, valint);
16914843421SMatthew Ahrens 		} else if (PyBool_Check(value)) {
17014843421SMatthew Ahrens 			boolean_t valbool = value == Py_True ? B_TRUE : B_FALSE;
17114843421SMatthew Ahrens 			err = nvlist_add_boolean_value(nvl, keystr, valbool);
17214843421SMatthew Ahrens 		} else {
17314843421SMatthew Ahrens 			PyErr_SetObject(PyExc_ValueError, value);
17414843421SMatthew Ahrens 			nvlist_free(nvl);
17514843421SMatthew Ahrens 			return (NULL);
17614843421SMatthew Ahrens 		}
17714843421SMatthew Ahrens 		assert(err == 0);
17814843421SMatthew Ahrens 	}
17914843421SMatthew Ahrens 
18014843421SMatthew Ahrens 	return (nvl);
18114843421SMatthew Ahrens }
18214843421SMatthew Ahrens 
18314843421SMatthew Ahrens static PyObject *
18414843421SMatthew Ahrens fakepropval(uint64_t value)
18514843421SMatthew Ahrens {
18614843421SMatthew Ahrens 	PyObject *d = PyDict_New();
18714843421SMatthew Ahrens 	PyDict_SetItemString(d, "value", Py_BuildValue("K", value));
18814843421SMatthew Ahrens 	return (d);
18914843421SMatthew Ahrens }
19014843421SMatthew Ahrens 
19114843421SMatthew Ahrens static void
19214843421SMatthew Ahrens add_ds_props(zfs_cmd_t *zc, PyObject *nvl)
19314843421SMatthew Ahrens {
19414843421SMatthew Ahrens 	dmu_objset_stats_t *s = &zc->zc_objset_stats;
19514843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "numclones",
19614843421SMatthew Ahrens 	    fakepropval(s->dds_num_clones));
19714843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "issnap",
19814843421SMatthew Ahrens 	    fakepropval(s->dds_is_snapshot));
19914843421SMatthew Ahrens 	PyDict_SetItemString(nvl, "inconsistent",
20014843421SMatthew Ahrens 	    fakepropval(s->dds_inconsistent));
20114843421SMatthew Ahrens }
20214843421SMatthew Ahrens 
20314843421SMatthew Ahrens /* On error, returns NULL but does not set python exception. */
20414843421SMatthew Ahrens static PyObject *
20514843421SMatthew Ahrens ioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
20614843421SMatthew Ahrens {
20714843421SMatthew Ahrens 	int nvsz = 2048;
20814843421SMatthew Ahrens 	void *nvbuf;
20914843421SMatthew Ahrens 	PyObject *pynv = NULL;
21014843421SMatthew Ahrens 
21114843421SMatthew Ahrens again:
21214843421SMatthew Ahrens 	nvbuf = malloc(nvsz);
21314843421SMatthew Ahrens 	zc->zc_nvlist_dst_size = nvsz;
21414843421SMatthew Ahrens 	zc->zc_nvlist_dst = (uintptr_t)nvbuf;
21514843421SMatthew Ahrens 
21614843421SMatthew Ahrens 	if (ioctl(zfsdevfd, ioc, zc) == 0) {
21714843421SMatthew Ahrens 		nvlist_t *nvl;
21814843421SMatthew Ahrens 
21914843421SMatthew Ahrens 		errno = nvlist_unpack(nvbuf, zc->zc_nvlist_dst_size, &nvl, 0);
22014843421SMatthew Ahrens 		if (errno == 0) {
22114843421SMatthew Ahrens 			pynv = nvl2py(nvl);
22214843421SMatthew Ahrens 			nvlist_free(nvl);
22314843421SMatthew Ahrens 		}
22414843421SMatthew Ahrens 	} else if (errno == ENOMEM) {
22514843421SMatthew Ahrens 		free(nvbuf);
22614843421SMatthew Ahrens 		nvsz = zc->zc_nvlist_dst_size;
22714843421SMatthew Ahrens 		goto again;
22814843421SMatthew Ahrens 	}
22914843421SMatthew Ahrens 	free(nvbuf);
23014843421SMatthew Ahrens 	return (pynv);
23114843421SMatthew Ahrens }
23214843421SMatthew Ahrens 
23314843421SMatthew Ahrens static PyObject *
23414843421SMatthew Ahrens py_next_dataset(PyObject *self, PyObject *args)
23514843421SMatthew Ahrens {
23614843421SMatthew Ahrens 	int ioc;
23714843421SMatthew Ahrens 	uint64_t cookie;
23814843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
23914843421SMatthew Ahrens 	int snaps;
24014843421SMatthew Ahrens 	char *name;
24114843421SMatthew Ahrens 	PyObject *nvl;
24214843421SMatthew Ahrens 	PyObject *ret = NULL;
24314843421SMatthew Ahrens 
24414843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "siK", &name, &snaps, &cookie))
24514843421SMatthew Ahrens 		return (NULL);
24614843421SMatthew Ahrens 
24714843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
24814843421SMatthew Ahrens 	zc.zc_cookie = cookie;
24914843421SMatthew Ahrens 
25014843421SMatthew Ahrens 	if (snaps)
25114843421SMatthew Ahrens 		ioc = ZFS_IOC_SNAPSHOT_LIST_NEXT;
25214843421SMatthew Ahrens 	else
25314843421SMatthew Ahrens 		ioc = ZFS_IOC_DATASET_LIST_NEXT;
25414843421SMatthew Ahrens 
25514843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ioc, &zc);
25614843421SMatthew Ahrens 	if (nvl) {
25714843421SMatthew Ahrens 		add_ds_props(&zc, nvl);
25814843421SMatthew Ahrens 		ret = Py_BuildValue("sKO", zc.zc_name, zc.zc_cookie, nvl);
25914843421SMatthew Ahrens 		Py_DECREF(nvl);
26014843421SMatthew Ahrens 	} else if (errno == ESRCH) {
26114843421SMatthew Ahrens 		PyErr_SetNone(PyExc_StopIteration);
26214843421SMatthew Ahrens 	} else {
26314843421SMatthew Ahrens 		if (snaps)
26414843421SMatthew Ahrens 			seterr(_("cannot get snapshots of %s"), name);
26514843421SMatthew Ahrens 		else
26614843421SMatthew Ahrens 			seterr(_("cannot get child datasets of %s"), name);
26714843421SMatthew Ahrens 	}
26814843421SMatthew Ahrens 	return (ret);
26914843421SMatthew Ahrens }
27014843421SMatthew Ahrens 
27114843421SMatthew Ahrens static PyObject *
27214843421SMatthew Ahrens py_dataset_props(PyObject *self, PyObject *args)
27314843421SMatthew Ahrens {
27414843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
27514843421SMatthew Ahrens 	int snaps;
27614843421SMatthew Ahrens 	char *name;
27714843421SMatthew Ahrens 	PyObject *nvl;
27814843421SMatthew Ahrens 
27914843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
28014843421SMatthew Ahrens 		return (NULL);
28114843421SMatthew Ahrens 
28214843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
28314843421SMatthew Ahrens 
28414843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ZFS_IOC_OBJSET_STATS, &zc);
28514843421SMatthew Ahrens 	if (nvl) {
28614843421SMatthew Ahrens 		add_ds_props(&zc, nvl);
28714843421SMatthew Ahrens 	} else {
28814843421SMatthew Ahrens 		seterr(_("cannot access dataset %s"), name);
28914843421SMatthew Ahrens 	}
29014843421SMatthew Ahrens 	return (nvl);
29114843421SMatthew Ahrens }
29214843421SMatthew Ahrens 
29314843421SMatthew Ahrens static PyObject *
29414843421SMatthew Ahrens py_get_fsacl(PyObject *self, PyObject *args)
29514843421SMatthew Ahrens {
29614843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
29714843421SMatthew Ahrens 	char *name;
29814843421SMatthew Ahrens 	PyObject *nvl;
29914843421SMatthew Ahrens 
30014843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
30114843421SMatthew Ahrens 		return (NULL);
30214843421SMatthew Ahrens 
30314843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
30414843421SMatthew Ahrens 
30514843421SMatthew Ahrens 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_FSACL, &zc);
30614843421SMatthew Ahrens 	if (nvl == NULL)
30714843421SMatthew Ahrens 		seterr(_("cannot get permissions on %s"), name);
30814843421SMatthew Ahrens 
30914843421SMatthew Ahrens 	return (nvl);
31014843421SMatthew Ahrens }
31114843421SMatthew Ahrens 
31214843421SMatthew Ahrens static PyObject *
31314843421SMatthew Ahrens py_set_fsacl(PyObject *self, PyObject *args)
31414843421SMatthew Ahrens {
31514843421SMatthew Ahrens 	int un;
31614843421SMatthew Ahrens 	size_t nvsz;
31714843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
31814843421SMatthew Ahrens 	char *name, *nvbuf;
31914843421SMatthew Ahrens 	PyObject *dict, *file;
32014843421SMatthew Ahrens 	nvlist_t *nvl;
32114843421SMatthew Ahrens 	int err;
32214843421SMatthew Ahrens 
32314843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "siO!", &name, &un,
32414843421SMatthew Ahrens 	    &PyDict_Type, &dict))
32514843421SMatthew Ahrens 		return (NULL);
32614843421SMatthew Ahrens 
32714843421SMatthew Ahrens 	nvl = dict2nvl(dict);
32814843421SMatthew Ahrens 	if (nvl == NULL)
32914843421SMatthew Ahrens 		return (NULL);
33014843421SMatthew Ahrens 
33114843421SMatthew Ahrens 	err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
33214843421SMatthew Ahrens 	assert(err == 0);
33314843421SMatthew Ahrens 	nvbuf = malloc(nvsz);
33414843421SMatthew Ahrens 	err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
33514843421SMatthew Ahrens 	assert(err == 0);
33614843421SMatthew Ahrens 
33714843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
33814843421SMatthew Ahrens 	zc.zc_nvlist_src_size = nvsz;
33914843421SMatthew Ahrens 	zc.zc_nvlist_src = (uintptr_t)nvbuf;
34014843421SMatthew Ahrens 	zc.zc_perm_action = un;
34114843421SMatthew Ahrens 
34214843421SMatthew Ahrens 	err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
34314843421SMatthew Ahrens 	free(nvbuf);
34414843421SMatthew Ahrens 	if (err) {
34514843421SMatthew Ahrens 		seterr(_("cannot set permissions on %s"), name);
34614843421SMatthew Ahrens 		return (NULL);
34714843421SMatthew Ahrens 	}
34814843421SMatthew Ahrens 
34914843421SMatthew Ahrens 	Py_RETURN_NONE;
35014843421SMatthew Ahrens }
35114843421SMatthew Ahrens 
35214843421SMatthew Ahrens static PyObject *
353*842727c2SChris Kirby py_get_holds(PyObject *self, PyObject *args)
354*842727c2SChris Kirby {
355*842727c2SChris Kirby 	zfs_cmd_t zc = { 0 };
356*842727c2SChris Kirby 	char *name;
357*842727c2SChris Kirby 	PyObject *nvl;
358*842727c2SChris Kirby 
359*842727c2SChris Kirby 	if (!PyArg_ParseTuple(args, "s", &name))
360*842727c2SChris Kirby 		return (NULL);
361*842727c2SChris Kirby 
362*842727c2SChris Kirby 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
363*842727c2SChris Kirby 
364*842727c2SChris Kirby 	nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
365*842727c2SChris Kirby 	if (nvl == NULL)
366*842727c2SChris Kirby 		seterr(_("cannot get holds for %s"), name);
367*842727c2SChris Kirby 
368*842727c2SChris Kirby 	return (nvl);
369*842727c2SChris Kirby }
370*842727c2SChris Kirby 
371*842727c2SChris Kirby static PyObject *
37214843421SMatthew Ahrens py_userspace_many(PyObject *self, PyObject *args)
37314843421SMatthew Ahrens {
37414843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
37514843421SMatthew Ahrens 	zfs_userquota_prop_t type;
37614843421SMatthew Ahrens 	char *name, *propname;
37714843421SMatthew Ahrens 	int bufsz = 1<<20;
37814843421SMatthew Ahrens 	void *buf;
37914843421SMatthew Ahrens 	PyObject *dict, *file;
38014843421SMatthew Ahrens 	int error;
38114843421SMatthew Ahrens 
38214843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "ss", &name, &propname))
38314843421SMatthew Ahrens 		return (NULL);
38414843421SMatthew Ahrens 
38514843421SMatthew Ahrens 	for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++)
38614843421SMatthew Ahrens 		if (strcmp(propname, zfs_userquota_prop_prefixes[type]) == 0)
38714843421SMatthew Ahrens 			break;
38814843421SMatthew Ahrens 	if (type == ZFS_NUM_USERQUOTA_PROPS) {
38914843421SMatthew Ahrens 		PyErr_SetString(PyExc_KeyError, propname);
39014843421SMatthew Ahrens 		return (NULL);
39114843421SMatthew Ahrens 	}
39214843421SMatthew Ahrens 
39314843421SMatthew Ahrens 	dict = PyDict_New();
39414843421SMatthew Ahrens 	buf = malloc(bufsz);
39514843421SMatthew Ahrens 
39614843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
39714843421SMatthew Ahrens 	zc.zc_objset_type = type;
39814843421SMatthew Ahrens 	zc.zc_cookie = 0;
39914843421SMatthew Ahrens 
40014843421SMatthew Ahrens 	while (1) {
40114843421SMatthew Ahrens 		zfs_useracct_t *zua = buf;
40214843421SMatthew Ahrens 
40314843421SMatthew Ahrens 		zc.zc_nvlist_dst = (uintptr_t)buf;
40414843421SMatthew Ahrens 		zc.zc_nvlist_dst_size = bufsz;
40514843421SMatthew Ahrens 
40614843421SMatthew Ahrens 		error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_MANY, &zc);
40714843421SMatthew Ahrens 		if (error || zc.zc_nvlist_dst_size == 0)
40814843421SMatthew Ahrens 			break;
40914843421SMatthew Ahrens 
41014843421SMatthew Ahrens 		while (zc.zc_nvlist_dst_size > 0) {
41114843421SMatthew Ahrens 			PyObject *pykey, *pyval;
41214843421SMatthew Ahrens 
41314843421SMatthew Ahrens 			pykey = Py_BuildValue("sI",
41414843421SMatthew Ahrens 			    zua->zu_domain, zua->zu_rid);
41514843421SMatthew Ahrens 			pyval = Py_BuildValue("K", zua->zu_space);
41614843421SMatthew Ahrens 			PyDict_SetItem(dict, pykey, pyval);
41714843421SMatthew Ahrens 			Py_DECREF(pykey);
41814843421SMatthew Ahrens 			Py_DECREF(pyval);
41914843421SMatthew Ahrens 
42014843421SMatthew Ahrens 			zua++;
42114843421SMatthew Ahrens 			zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
42214843421SMatthew Ahrens 		}
42314843421SMatthew Ahrens 	}
42414843421SMatthew Ahrens 
42514843421SMatthew Ahrens 	free(buf);
42614843421SMatthew Ahrens 
42714843421SMatthew Ahrens 	if (error != 0) {
42814843421SMatthew Ahrens 		Py_DECREF(dict);
42914843421SMatthew Ahrens 		seterr(_("cannot get %s property on %s"), propname, name);
43014843421SMatthew Ahrens 		return (NULL);
43114843421SMatthew Ahrens 	}
43214843421SMatthew Ahrens 
43314843421SMatthew Ahrens 	return (dict);
43414843421SMatthew Ahrens }
43514843421SMatthew Ahrens 
43614843421SMatthew Ahrens static PyObject *
43714843421SMatthew Ahrens py_userspace_upgrade(PyObject *self, PyObject *args)
43814843421SMatthew Ahrens {
43914843421SMatthew Ahrens 	zfs_cmd_t zc = { 0 };
44014843421SMatthew Ahrens 	char *name;
44114843421SMatthew Ahrens 	int error;
44214843421SMatthew Ahrens 
44314843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &name))
44414843421SMatthew Ahrens 		return (NULL);
44514843421SMatthew Ahrens 
44614843421SMatthew Ahrens 	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
44714843421SMatthew Ahrens 	error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_UPGRADE, &zc);
44814843421SMatthew Ahrens 
44914843421SMatthew Ahrens 	if (error != 0) {
45014843421SMatthew Ahrens 		seterr(_("cannot initialize user accounting information on %s"),
45114843421SMatthew Ahrens 		    name);
45214843421SMatthew Ahrens 		return (NULL);
45314843421SMatthew Ahrens 	}
45414843421SMatthew Ahrens 
45514843421SMatthew Ahrens 	Py_RETURN_NONE;
45614843421SMatthew Ahrens }
45714843421SMatthew Ahrens 
45814843421SMatthew Ahrens static PyObject *
45914843421SMatthew Ahrens py_sid_to_id(PyObject *self, PyObject *args)
46014843421SMatthew Ahrens {
46114843421SMatthew Ahrens 	char *sid;
46214843421SMatthew Ahrens 	int err, isuser;
46314843421SMatthew Ahrens 	uid_t id;
46414843421SMatthew Ahrens 
46514843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "si", &sid, &isuser))
46614843421SMatthew Ahrens 		return (NULL);
46714843421SMatthew Ahrens 
46814843421SMatthew Ahrens 	err = sid_to_id(sid, isuser, &id);
46914843421SMatthew Ahrens 	if (err) {
47014843421SMatthew Ahrens 		PyErr_SetString(PyExc_KeyError, sid);
47114843421SMatthew Ahrens 		return (NULL);
47214843421SMatthew Ahrens 	}
47314843421SMatthew Ahrens 
47414843421SMatthew Ahrens 	return (Py_BuildValue("I", id));
47514843421SMatthew Ahrens }
47614843421SMatthew Ahrens 
47714843421SMatthew Ahrens /*
47814843421SMatthew Ahrens  * Translate the sid string ("S-1-...") to the user@domain name, if
4793b12c289SMatthew Ahrens  * possible.
48014843421SMatthew Ahrens  */
48114843421SMatthew Ahrens static PyObject *
48214843421SMatthew Ahrens py_sid_to_name(PyObject *self, PyObject *args)
48314843421SMatthew Ahrens {
4843b12c289SMatthew Ahrens 	int isuser;
4853b12c289SMatthew Ahrens 	char *name, *sid;
4863b12c289SMatthew Ahrens 	directory_error_t e;
4873b12c289SMatthew Ahrens 	uint64_t classes;
4883b12c289SMatthew Ahrens 	PyObject *ret;
48914843421SMatthew Ahrens 
49014843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "si", &sid, &isuser))
49114843421SMatthew Ahrens 		return (NULL);
4923b12c289SMatthew Ahrens 	e = directory_name_from_sid(NULL, sid, &name, &classes);
4933b12c289SMatthew Ahrens 	if (e != NULL) {
4943b12c289SMatthew Ahrens 		directory_error_free(e);
49514843421SMatthew Ahrens 		PyErr_SetString(PyExc_KeyError, sid);
49614843421SMatthew Ahrens 		return (NULL);
49714843421SMatthew Ahrens 	}
4983b12c289SMatthew Ahrens 	if (name == NULL) {
4993b12c289SMatthew Ahrens 		PyErr_SetString(PyExc_KeyError, sid);
5003b12c289SMatthew Ahrens 		return (NULL);
5013b12c289SMatthew Ahrens 	}
50214843421SMatthew Ahrens 	if (isuser) {
5033b12c289SMatthew Ahrens 		if (!(classes & DIRECTORY_CLASS_USER)) {
5043b12c289SMatthew Ahrens 			free(name);
50514843421SMatthew Ahrens 			PyErr_SetString(PyExc_KeyError, sid);
50614843421SMatthew Ahrens 			return (NULL);
50714843421SMatthew Ahrens 		}
5083b12c289SMatthew Ahrens 	} else {
5093b12c289SMatthew Ahrens 		if (!(classes & DIRECTORY_CLASS_GROUP)) {
51014843421SMatthew Ahrens 			free(name);
5113b12c289SMatthew Ahrens 			PyErr_SetString(PyExc_KeyError, sid);
5123b12c289SMatthew Ahrens 			return (NULL);
5133b12c289SMatthew Ahrens 		}
5143b12c289SMatthew Ahrens 	}
51514843421SMatthew Ahrens 
5163b12c289SMatthew Ahrens 	ret = PyString_FromString(name);
5173b12c289SMatthew Ahrens 	free(name);
5183b12c289SMatthew Ahrens 	return (ret);
51914843421SMatthew Ahrens }
52014843421SMatthew Ahrens 
52114843421SMatthew Ahrens static PyObject *
52214843421SMatthew Ahrens py_isglobalzone(PyObject *self, PyObject *args)
52314843421SMatthew Ahrens {
52414843421SMatthew Ahrens 	return (Py_BuildValue("i", getzoneid() == GLOBAL_ZONEID));
52514843421SMatthew Ahrens }
52614843421SMatthew Ahrens 
52714843421SMatthew Ahrens static PyObject *
52814843421SMatthew Ahrens py_set_cmdstr(PyObject *self, PyObject *args)
52914843421SMatthew Ahrens {
53014843421SMatthew Ahrens 	char *str;
53114843421SMatthew Ahrens 
53214843421SMatthew Ahrens 	if (!PyArg_ParseTuple(args, "s", &str))
53314843421SMatthew Ahrens 		return (NULL);
53414843421SMatthew Ahrens 
53514843421SMatthew Ahrens 	(void) strlcpy(cmdstr, str, sizeof (cmdstr));
53614843421SMatthew Ahrens 
53714843421SMatthew Ahrens 	Py_RETURN_NONE;
53814843421SMatthew Ahrens }
53914843421SMatthew Ahrens 
54014843421SMatthew Ahrens static PyObject *
54114843421SMatthew Ahrens py_get_proptable(PyObject *self, PyObject *args)
54214843421SMatthew Ahrens {
54314843421SMatthew Ahrens 	zprop_desc_t *t = zfs_prop_get_table();
54414843421SMatthew Ahrens 	PyObject *d = PyDict_New();
54514843421SMatthew Ahrens 	zfs_prop_t i;
54614843421SMatthew Ahrens 
54714843421SMatthew Ahrens 	for (i = 0; i < ZFS_NUM_PROPS; i++) {
54814843421SMatthew Ahrens 		zprop_desc_t *p = &t[i];
54914843421SMatthew Ahrens 		PyObject *tuple;
55014843421SMatthew Ahrens 		static const char *typetable[] =
55114843421SMatthew Ahrens 		    {"number", "string", "index"};
55214843421SMatthew Ahrens 		static const char *attrtable[] =
55314843421SMatthew Ahrens 		    {"default", "readonly", "inherit", "onetime"};
55414843421SMatthew Ahrens 		PyObject *indextable;
55514843421SMatthew Ahrens 
55614843421SMatthew Ahrens 		if (p->pd_proptype == PROP_TYPE_INDEX) {
55714843421SMatthew Ahrens 			const zprop_index_t *it = p->pd_table;
55814843421SMatthew Ahrens 			indextable = PyDict_New();
55914843421SMatthew Ahrens 			int j;
56014843421SMatthew Ahrens 			for (j = 0; it[j].pi_name; j++) {
56114843421SMatthew Ahrens 				PyDict_SetItemString(indextable,
56214843421SMatthew Ahrens 				    it[j].pi_name,
56314843421SMatthew Ahrens 				    Py_BuildValue("K", it[j].pi_value));
56414843421SMatthew Ahrens 			}
56514843421SMatthew Ahrens 		} else {
56614843421SMatthew Ahrens 			Py_INCREF(Py_None);
56714843421SMatthew Ahrens 			indextable = Py_None;
56814843421SMatthew Ahrens 		}
56914843421SMatthew Ahrens 
57014843421SMatthew Ahrens 		tuple = Py_BuildValue("sissKsissiiO",
57114843421SMatthew Ahrens 		    p->pd_name, p->pd_propnum, typetable[p->pd_proptype],
57214843421SMatthew Ahrens 		    p->pd_strdefault, p->pd_numdefault,
57314843421SMatthew Ahrens 		    attrtable[p->pd_attr], p->pd_types,
57414843421SMatthew Ahrens 		    p->pd_values, p->pd_colname,
57514843421SMatthew Ahrens 		    p->pd_rightalign, p->pd_visible, indextable);
57614843421SMatthew Ahrens 		PyDict_SetItemString(d, p->pd_name, tuple);
57714843421SMatthew Ahrens 		Py_DECREF(tuple);
57814843421SMatthew Ahrens 	}
57914843421SMatthew Ahrens 
58014843421SMatthew Ahrens 	return (d);
58114843421SMatthew Ahrens }
58214843421SMatthew Ahrens 
58314843421SMatthew Ahrens static PyMethodDef zfsmethods[] = {
58414843421SMatthew Ahrens 	{"next_dataset", py_next_dataset, METH_VARARGS,
58514843421SMatthew Ahrens 	    "Get next child dataset or snapshot."},
58614843421SMatthew Ahrens 	{"get_fsacl", py_get_fsacl, METH_VARARGS, "Get allowed permissions."},
58714843421SMatthew Ahrens 	{"set_fsacl", py_set_fsacl, METH_VARARGS, "Set allowed permissions."},
58814843421SMatthew Ahrens 	{"userspace_many", py_userspace_many, METH_VARARGS,
58914843421SMatthew Ahrens 	    "Get user space accounting."},
59014843421SMatthew Ahrens 	{"userspace_upgrade", py_userspace_upgrade, METH_VARARGS,
59114843421SMatthew Ahrens 	    "Upgrade fs to enable user space accounting."},
59214843421SMatthew Ahrens 	{"set_cmdstr", py_set_cmdstr, METH_VARARGS,
59314843421SMatthew Ahrens 	    "Set command string for history logging."},
59414843421SMatthew Ahrens 	{"dataset_props", py_dataset_props, METH_VARARGS,
59514843421SMatthew Ahrens 	    "Get dataset properties."},
59614843421SMatthew Ahrens 	{"get_proptable", py_get_proptable, METH_NOARGS,
59714843421SMatthew Ahrens 	    "Get property table."},
59814843421SMatthew Ahrens 	/* Below are not really zfs-specific: */
59914843421SMatthew Ahrens 	{"sid_to_id", py_sid_to_id, METH_VARARGS, "Map SID to UID/GID."},
60014843421SMatthew Ahrens 	{"sid_to_name", py_sid_to_name, METH_VARARGS,
60114843421SMatthew Ahrens 	    "Map SID to name@domain."},
60214843421SMatthew Ahrens 	{"isglobalzone", py_isglobalzone, METH_NOARGS,
60314843421SMatthew Ahrens 	    "Determine if this is the global zone."},
604*842727c2SChris Kirby 	{"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
60514843421SMatthew Ahrens 	{NULL, NULL, 0, NULL}
60614843421SMatthew Ahrens };
60714843421SMatthew Ahrens 
60814843421SMatthew Ahrens void
60914843421SMatthew Ahrens initioctl(void)
61014843421SMatthew Ahrens {
61114843421SMatthew Ahrens 	PyObject *zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
61214843421SMatthew Ahrens 	PyObject *zfs_util = PyImport_ImportModule("zfs.util");
61314843421SMatthew Ahrens 	PyObject *devfile;
61414843421SMatthew Ahrens 
61514843421SMatthew Ahrens 	if (zfs_util == NULL)
61614843421SMatthew Ahrens 		return;
61714843421SMatthew Ahrens 
61814843421SMatthew Ahrens 	ZFSError = PyObject_GetAttrString(zfs_util, "ZFSError");
61914843421SMatthew Ahrens 	devfile = PyObject_GetAttrString(zfs_util, "dev");
62014843421SMatthew Ahrens 	zfsdevfd = PyObject_AsFileDescriptor(devfile);
62114843421SMatthew Ahrens 
62214843421SMatthew Ahrens 	zfs_prop_init();
62314843421SMatthew Ahrens }
624