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