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