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.
248cfa78e6SAndy 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
seterr(char * fmt,...)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
ioctl_with_cmdstr(int ioc,zfs_cmd_t * zc)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 *
nvl2py(nvlist_t * nvl)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 *
dict2nvl(PyObject * d)13014843421SMatthew Ahrens dict2nvl(PyObject *d)
13114843421SMatthew Ahrens {
13214843421SMatthew Ahrens nvlist_t *nvl;
13314843421SMatthew Ahrens int err;
13414843421SMatthew Ahrens PyObject *key, *value;
1358cfa78e6SAndy 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*7abd0689SAndy Fiddaman const char *keystr;
1478cfa78e6SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
148*7abd0689SAndy Fiddaman keystr = PyUnicode_AsUTF8(key);
1498cfa78e6SAndy Fiddaman #else
150*7abd0689SAndy Fiddaman keystr = PyString_AsString(key);
1518cfa78e6SAndy 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);
1648cfa78e6SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
16583d13c2eSAlexander Pyhalov } else if (PyUnicode_Check(value)) {
1668cfa78e6SAndy Fiddaman #else
16714843421SMatthew Ahrens } else if (PyString_Check(value)) {
1688cfa78e6SAndy Fiddaman #endif
169*7abd0689SAndy Fiddaman const char *valstr;
1708cfa78e6SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
171*7abd0689SAndy Fiddaman valstr = PyUnicode_AsUTF8(value);
1728cfa78e6SAndy Fiddaman #else
173*7abd0689SAndy Fiddaman valstr = PyString_AsString(value);
1748cfa78e6SAndy Fiddaman #endif
17514843421SMatthew Ahrens err = nvlist_add_string(nvl, keystr, valstr);
1768cfa78e6SAndy Fiddaman } else if (PyLong_Check(value)) {
1778cfa78e6SAndy 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 *
fakepropval(uint64_t value)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
add_ds_props(zfs_cmd_t * zc,PyObject * nvl)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 *
ioctl_with_dstnv(int ioc,zfs_cmd_t * zc)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 *
py_next_dataset(PyObject * self,PyObject * args)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 *
py_dataset_props(PyObject * self,PyObject * args)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 *
py_get_fsacl(PyObject * self,PyObject * args)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 *
py_set_fsacl(PyObject * self,PyObject * args)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 *
py_get_holds(PyObject * self,PyObject * args)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 *
py_userspace_many(PyObject * self,PyObject * args)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 *
py_userspace_upgrade(PyObject * self,PyObject * args)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 *
py_set_cmdstr(PyObject * self,PyObject * args)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 *
py_get_proptable(PyObject * self,PyObject * args)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
5438cfa78e6SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
5448cfa78e6SAndy Fiddaman static struct PyModuleDef zfs_module = {
5458cfa78e6SAndy Fiddaman PyModuleDef_HEAD_INIT,
5468cfa78e6SAndy Fiddaman "zfs.ioctl",
5478cfa78e6SAndy Fiddaman NULL,
5488cfa78e6SAndy Fiddaman -1,
5498cfa78e6SAndy Fiddaman zfsmethods
5508cfa78e6SAndy Fiddaman };
5518cfa78e6SAndy Fiddaman #endif
5528cfa78e6SAndy Fiddaman
5538cfa78e6SAndy Fiddaman static PyObject *
moduleinit()5548cfa78e6SAndy Fiddaman moduleinit()
55514843421SMatthew Ahrens {
5568cfa78e6SAndy Fiddaman PyObject *zfs_ioctl, *zfs_util, *devfile;
5578cfa78e6SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
5588cfa78e6SAndy Fiddaman zfs_ioctl = PyModule_Create(&zfs_module);
5598cfa78e6SAndy Fiddaman #else
5608cfa78e6SAndy Fiddaman zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
5618cfa78e6SAndy Fiddaman #endif
5628cfa78e6SAndy Fiddaman zfs_util = PyImport_ImportModule("zfs.util");
56314843421SMatthew Ahrens
56414843421SMatthew Ahrens if (zfs_util == NULL)
5658cfa78e6SAndy 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();
5728cfa78e6SAndy Fiddaman
5738cfa78e6SAndy Fiddaman return (zfs_ioctl);
57414843421SMatthew Ahrens }
5758cfa78e6SAndy Fiddaman
5768cfa78e6SAndy Fiddaman #if PY_MAJOR_VERSION >= 3
5778cfa78e6SAndy Fiddaman PyMODINIT_FUNC
PyInit_ioctl(void)5788cfa78e6SAndy Fiddaman PyInit_ioctl(void)
5798cfa78e6SAndy Fiddaman {
5808cfa78e6SAndy Fiddaman return (moduleinit());
5818cfa78e6SAndy Fiddaman }
5828cfa78e6SAndy Fiddaman #else
5838cfa78e6SAndy Fiddaman PyMODINIT_FUNC
initioctl(void)5848cfa78e6SAndy Fiddaman initioctl(void)
5858cfa78e6SAndy Fiddaman {
5868cfa78e6SAndy Fiddaman (void) moduleinit();
5878cfa78e6SAndy Fiddaman }
5888cfa78e6SAndy Fiddaman #endif
589