1209962Smm/*
2209962Smm * CDDL HEADER START
3209962Smm *
4209962Smm * The contents of this file are subject to the terms of the
5209962Smm * Common Development and Distribution License (the "License").
6209962Smm * You may not use this file except in compliance with the License.
7209962Smm *
8209962Smm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9209962Smm * or http://www.opensolaris.org/os/licensing.
10209962Smm * See the License for the specific language governing permissions
11209962Smm * and limitations under the License.
12209962Smm *
13209962Smm * When distributing Covered Code, include this CDDL HEADER in each
14209962Smm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15209962Smm * If applicable, add the following below this CDDL HEADER, with the
16209962Smm * fields enclosed by brackets "[]" replaced with your own identifying
17209962Smm * information: Portions Copyright [yyyy] [name of copyright owner]
18209962Smm *
19209962Smm * CDDL HEADER END
20209962Smm */
21209962Smm/*
22219089Spjd * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23209962Smm * Use is subject to license terms.
24209962Smm */
25209962Smm
26209962Smm#include <Python.h>
27209962Smm#include <sys/zfs_ioctl.h>
28209962Smm#include <sys/fs/zfs.h>
29209962Smm#include <strings.h>
30209962Smm#include <unistd.h>
31209962Smm#include <libnvpair.h>
32209962Smm#include <libintl.h>
33209962Smm#include <libzfs.h>
34211970Spjd#include <libzfs_impl.h>
35209962Smm#include "zfs_prop.h"
36209962Smm
37209962Smmstatic PyObject *ZFSError;
38209962Smmstatic int zfsdevfd;
39209962Smm
40209962Smm#ifdef __lint
41209962Smm#define	dgettext(x, y) y
42209962Smm#endif
43209962Smm
44209962Smm#define	_(s) dgettext(TEXT_DOMAIN, s)
45209962Smm
46209962Smm/*PRINTFLIKE1*/
47209962Smmstatic void
48209962Smmseterr(char *fmt, ...)
49209962Smm{
50209962Smm	char errstr[1024];
51209962Smm	va_list v;
52209962Smm
53209962Smm	va_start(v, fmt);
54209962Smm	(void) vsnprintf(errstr, sizeof (errstr), fmt, v);
55209962Smm	va_end(v);
56209962Smm
57209962Smm	PyErr_SetObject(ZFSError, Py_BuildValue("is", errno, errstr));
58209962Smm}
59209962Smm
60209962Smmstatic char cmdstr[HIS_MAX_RECORD_LEN];
61209962Smm
62209962Smmstatic int
63219089Spjdioctl_with_cmdstr(int ioc, zfs_cmd_t *zc)
64209962Smm{
65209962Smm	int err;
66209962Smm
67209962Smm	if (cmdstr[0])
68209962Smm		zc->zc_history = (uint64_t)(uintptr_t)cmdstr;
69209962Smm	err = ioctl(zfsdevfd, ioc, zc);
70209962Smm	cmdstr[0] = '\0';
71209962Smm	return (err);
72209962Smm}
73209962Smm
74209962Smmstatic PyObject *
75209962Smmnvl2py(nvlist_t *nvl)
76209962Smm{
77209962Smm	PyObject *pyo;
78209962Smm	nvpair_t *nvp;
79209962Smm
80209962Smm	pyo = PyDict_New();
81209962Smm
82209962Smm	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp;
83209962Smm	    nvp = nvlist_next_nvpair(nvl, nvp)) {
84209962Smm		PyObject *pyval;
85209962Smm		char *sval;
86209962Smm		uint64_t ival;
87209962Smm		boolean_t bval;
88209962Smm		nvlist_t *nval;
89209962Smm
90209962Smm		switch (nvpair_type(nvp)) {
91209962Smm		case DATA_TYPE_STRING:
92209962Smm			(void) nvpair_value_string(nvp, &sval);
93209962Smm			pyval = Py_BuildValue("s", sval);
94209962Smm			break;
95209962Smm
96209962Smm		case DATA_TYPE_UINT64:
97209962Smm			(void) nvpair_value_uint64(nvp, &ival);
98209962Smm			pyval = Py_BuildValue("K", ival);
99209962Smm			break;
100209962Smm
101209962Smm		case DATA_TYPE_NVLIST:
102209962Smm			(void) nvpair_value_nvlist(nvp, &nval);
103209962Smm			pyval = nvl2py(nval);
104209962Smm			break;
105209962Smm
106209962Smm		case DATA_TYPE_BOOLEAN:
107209962Smm			Py_INCREF(Py_None);
108209962Smm			pyval = Py_None;
109209962Smm			break;
110209962Smm
111209962Smm		case DATA_TYPE_BOOLEAN_VALUE:
112209962Smm			(void) nvpair_value_boolean_value(nvp, &bval);
113209962Smm			pyval = Py_BuildValue("i", bval);
114209962Smm			break;
115209962Smm
116209962Smm		default:
117209962Smm			PyErr_SetNone(PyExc_ValueError);
118209962Smm			Py_DECREF(pyo);
119209962Smm			return (NULL);
120209962Smm		}
121209962Smm
122209962Smm		PyDict_SetItemString(pyo, nvpair_name(nvp), pyval);
123209962Smm		Py_DECREF(pyval);
124209962Smm	}
125209962Smm
126209962Smm	return (pyo);
127209962Smm}
128209962Smm
129209962Smmstatic nvlist_t *
130209962Smmdict2nvl(PyObject *d)
131209962Smm{
132209962Smm	nvlist_t *nvl;
133209962Smm	int err;
134209962Smm	PyObject *key, *value;
135219089Spjd	int pos = 0;
136209962Smm
137209962Smm	if (!PyDict_Check(d)) {
138209962Smm		PyErr_SetObject(PyExc_ValueError, d);
139209962Smm		return (NULL);
140209962Smm	}
141209962Smm
142209962Smm	err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
143209962Smm	assert(err == 0);
144209962Smm
145209962Smm	while (PyDict_Next(d, &pos, &key, &value)) {
146209962Smm		char *keystr = PyString_AsString(key);
147209962Smm		if (keystr == NULL) {
148209962Smm			PyErr_SetObject(PyExc_KeyError, key);
149209962Smm			nvlist_free(nvl);
150209962Smm			return (NULL);
151209962Smm		}
152209962Smm
153209962Smm		if (PyDict_Check(value)) {
154209962Smm			nvlist_t *valnvl = dict2nvl(value);
155209962Smm			err = nvlist_add_nvlist(nvl, keystr, valnvl);
156209962Smm			nvlist_free(valnvl);
157209962Smm		} else if (value == Py_None) {
158209962Smm			err = nvlist_add_boolean(nvl, keystr);
159209962Smm		} else if (PyString_Check(value)) {
160209962Smm			char *valstr = PyString_AsString(value);
161209962Smm			err = nvlist_add_string(nvl, keystr, valstr);
162209962Smm		} else if (PyInt_Check(value)) {
163209962Smm			uint64_t valint = PyInt_AsUnsignedLongLongMask(value);
164209962Smm			err = nvlist_add_uint64(nvl, keystr, valint);
165209962Smm		} else if (PyBool_Check(value)) {
166209962Smm			boolean_t valbool = value == Py_True ? B_TRUE : B_FALSE;
167209962Smm			err = nvlist_add_boolean_value(nvl, keystr, valbool);
168209962Smm		} else {
169209962Smm			PyErr_SetObject(PyExc_ValueError, value);
170209962Smm			nvlist_free(nvl);
171209962Smm			return (NULL);
172209962Smm		}
173209962Smm		assert(err == 0);
174209962Smm	}
175209962Smm
176209962Smm	return (nvl);
177209962Smm}
178209962Smm
179209962Smmstatic PyObject *
180209962Smmfakepropval(uint64_t value)
181209962Smm{
182209962Smm	PyObject *d = PyDict_New();
183209962Smm	PyDict_SetItemString(d, "value", Py_BuildValue("K", value));
184209962Smm	return (d);
185209962Smm}
186209962Smm
187209962Smmstatic void
188209962Smmadd_ds_props(zfs_cmd_t *zc, PyObject *nvl)
189209962Smm{
190209962Smm	dmu_objset_stats_t *s = &zc->zc_objset_stats;
191209962Smm	PyDict_SetItemString(nvl, "numclones",
192209962Smm	    fakepropval(s->dds_num_clones));
193209962Smm	PyDict_SetItemString(nvl, "issnap",
194209962Smm	    fakepropval(s->dds_is_snapshot));
195209962Smm	PyDict_SetItemString(nvl, "inconsistent",
196209962Smm	    fakepropval(s->dds_inconsistent));
197209962Smm}
198209962Smm
199209962Smm/* On error, returns NULL but does not set python exception. */
200209962Smmstatic PyObject *
201219089Spjdioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
202209962Smm{
203209962Smm	int nvsz = 2048;
204209962Smm	void *nvbuf;
205209962Smm	PyObject *pynv = NULL;
206209962Smm
207209962Smmagain:
208209962Smm	nvbuf = malloc(nvsz);
209209962Smm	zc->zc_nvlist_dst_size = nvsz;
210209962Smm	zc->zc_nvlist_dst = (uintptr_t)nvbuf;
211209962Smm
212209962Smm	if (ioctl(zfsdevfd, ioc, zc) == 0) {
213209962Smm		nvlist_t *nvl;
214209962Smm
215209962Smm		errno = nvlist_unpack(nvbuf, zc->zc_nvlist_dst_size, &nvl, 0);
216209962Smm		if (errno == 0) {
217209962Smm			pynv = nvl2py(nvl);
218209962Smm			nvlist_free(nvl);
219209962Smm		}
220209962Smm	} else if (errno == ENOMEM) {
221209962Smm		free(nvbuf);
222209962Smm		nvsz = zc->zc_nvlist_dst_size;
223209962Smm		goto again;
224209962Smm	}
225209962Smm	free(nvbuf);
226209962Smm	return (pynv);
227209962Smm}
228209962Smm
229209962Smmstatic PyObject *
230209962Smmpy_next_dataset(PyObject *self, PyObject *args)
231209962Smm{
232219089Spjd	int ioc;
233209962Smm	uint64_t cookie;
234209962Smm	zfs_cmd_t zc = { 0 };
235209962Smm	int snaps;
236209962Smm	char *name;
237209962Smm	PyObject *nvl;
238209962Smm	PyObject *ret = NULL;
239209962Smm
240209962Smm	if (!PyArg_ParseTuple(args, "siK", &name, &snaps, &cookie))
241209962Smm		return (NULL);
242209962Smm
243209962Smm	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
244209962Smm	zc.zc_cookie = cookie;
245209962Smm
246209962Smm	if (snaps)
247209962Smm		ioc = ZFS_IOC_SNAPSHOT_LIST_NEXT;
248209962Smm	else
249209962Smm		ioc = ZFS_IOC_DATASET_LIST_NEXT;
250209962Smm
251209962Smm	nvl = ioctl_with_dstnv(ioc, &zc);
252209962Smm	if (nvl) {
253209962Smm		add_ds_props(&zc, nvl);
254209962Smm		ret = Py_BuildValue("sKO", zc.zc_name, zc.zc_cookie, nvl);
255209962Smm		Py_DECREF(nvl);
256209962Smm	} else if (errno == ESRCH) {
257209962Smm		PyErr_SetNone(PyExc_StopIteration);
258209962Smm	} else {
259209962Smm		if (snaps)
260209962Smm			seterr(_("cannot get snapshots of %s"), name);
261209962Smm		else
262209962Smm			seterr(_("cannot get child datasets of %s"), name);
263209962Smm	}
264209962Smm	return (ret);
265209962Smm}
266209962Smm
267209962Smmstatic PyObject *
268209962Smmpy_dataset_props(PyObject *self, PyObject *args)
269209962Smm{
270209962Smm	zfs_cmd_t zc = { 0 };
271209962Smm	int snaps;
272209962Smm	char *name;
273209962Smm	PyObject *nvl;
274209962Smm
275209962Smm	if (!PyArg_ParseTuple(args, "s", &name))
276209962Smm		return (NULL);
277209962Smm
278209962Smm	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
279209962Smm
280209962Smm	nvl = ioctl_with_dstnv(ZFS_IOC_OBJSET_STATS, &zc);
281209962Smm	if (nvl) {
282209962Smm		add_ds_props(&zc, nvl);
283209962Smm	} else {
284209962Smm		seterr(_("cannot access dataset %s"), name);
285209962Smm	}
286209962Smm	return (nvl);
287209962Smm}
288209962Smm
289209962Smmstatic PyObject *
290209962Smmpy_get_fsacl(PyObject *self, PyObject *args)
291209962Smm{
292209962Smm	zfs_cmd_t zc = { 0 };
293209962Smm	char *name;
294209962Smm	PyObject *nvl;
295209962Smm
296209962Smm	if (!PyArg_ParseTuple(args, "s", &name))
297209962Smm		return (NULL);
298209962Smm
299209962Smm	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
300209962Smm
301209962Smm	nvl = ioctl_with_dstnv(ZFS_IOC_GET_FSACL, &zc);
302209962Smm	if (nvl == NULL)
303209962Smm		seterr(_("cannot get permissions on %s"), name);
304209962Smm
305209962Smm	return (nvl);
306209962Smm}
307209962Smm
308209962Smmstatic PyObject *
309209962Smmpy_set_fsacl(PyObject *self, PyObject *args)
310209962Smm{
311209962Smm	int un;
312209962Smm	size_t nvsz;
313209962Smm	zfs_cmd_t zc = { 0 };
314209962Smm	char *name, *nvbuf;
315209962Smm	PyObject *dict, *file;
316209962Smm	nvlist_t *nvl;
317209962Smm	int err;
318209962Smm
319209962Smm	if (!PyArg_ParseTuple(args, "siO!", &name, &un,
320209962Smm	    &PyDict_Type, &dict))
321209962Smm		return (NULL);
322209962Smm
323209962Smm	nvl = dict2nvl(dict);
324209962Smm	if (nvl == NULL)
325209962Smm		return (NULL);
326209962Smm
327209962Smm	err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
328209962Smm	assert(err == 0);
329209962Smm	nvbuf = malloc(nvsz);
330209962Smm	err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
331209962Smm	assert(err == 0);
332209962Smm
333209962Smm	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
334209962Smm	zc.zc_nvlist_src_size = nvsz;
335209962Smm	zc.zc_nvlist_src = (uintptr_t)nvbuf;
336209962Smm	zc.zc_perm_action = un;
337209962Smm
338209962Smm	err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
339209962Smm	free(nvbuf);
340209962Smm	if (err) {
341209962Smm		seterr(_("cannot set permissions on %s"), name);
342209962Smm		return (NULL);
343209962Smm	}
344209962Smm
345209962Smm	Py_RETURN_NONE;
346209962Smm}
347209962Smm
348209962Smmstatic PyObject *
349219089Spjdpy_get_holds(PyObject *self, PyObject *args)
350219089Spjd{
351219089Spjd	zfs_cmd_t zc = { 0 };
352219089Spjd	char *name;
353219089Spjd	PyObject *nvl;
354219089Spjd
355219089Spjd	if (!PyArg_ParseTuple(args, "s", &name))
356219089Spjd		return (NULL);
357219089Spjd
358219089Spjd	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
359219089Spjd
360219089Spjd	nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
361219089Spjd	if (nvl == NULL)
362219089Spjd		seterr(_("cannot get holds for %s"), name);
363219089Spjd
364219089Spjd	return (nvl);
365219089Spjd}
366219089Spjd
367219089Spjdstatic PyObject *
368209962Smmpy_userspace_many(PyObject *self, PyObject *args)
369209962Smm{
370209962Smm	zfs_cmd_t zc = { 0 };
371209962Smm	zfs_userquota_prop_t type;
372209962Smm	char *name, *propname;
373209962Smm	int bufsz = 1<<20;
374209962Smm	void *buf;
375209962Smm	PyObject *dict, *file;
376209962Smm	int error;
377209962Smm
378209962Smm	if (!PyArg_ParseTuple(args, "ss", &name, &propname))
379209962Smm		return (NULL);
380209962Smm
381209962Smm	for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++)
382209962Smm		if (strcmp(propname, zfs_userquota_prop_prefixes[type]) == 0)
383209962Smm			break;
384209962Smm	if (type == ZFS_NUM_USERQUOTA_PROPS) {
385209962Smm		PyErr_SetString(PyExc_KeyError, propname);
386209962Smm		return (NULL);
387209962Smm	}
388209962Smm
389209962Smm	dict = PyDict_New();
390209962Smm	buf = malloc(bufsz);
391209962Smm
392209962Smm	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
393209962Smm	zc.zc_objset_type = type;
394209962Smm	zc.zc_cookie = 0;
395209962Smm
396209962Smm	while (1) {
397209962Smm		zfs_useracct_t *zua = buf;
398209962Smm
399209962Smm		zc.zc_nvlist_dst = (uintptr_t)buf;
400209962Smm		zc.zc_nvlist_dst_size = bufsz;
401209962Smm
402209962Smm		error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_MANY, &zc);
403209962Smm		if (error || zc.zc_nvlist_dst_size == 0)
404209962Smm			break;
405209962Smm
406209962Smm		while (zc.zc_nvlist_dst_size > 0) {
407209962Smm			PyObject *pykey, *pyval;
408209962Smm
409209962Smm			pykey = Py_BuildValue("sI",
410209962Smm			    zua->zu_domain, zua->zu_rid);
411209962Smm			pyval = Py_BuildValue("K", zua->zu_space);
412209962Smm			PyDict_SetItem(dict, pykey, pyval);
413209962Smm			Py_DECREF(pykey);
414209962Smm			Py_DECREF(pyval);
415209962Smm
416209962Smm			zua++;
417209962Smm			zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
418209962Smm		}
419209962Smm	}
420209962Smm
421209962Smm	free(buf);
422209962Smm
423209962Smm	if (error != 0) {
424209962Smm		Py_DECREF(dict);
425209962Smm		seterr(_("cannot get %s property on %s"), propname, name);
426209962Smm		return (NULL);
427209962Smm	}
428209962Smm
429209962Smm	return (dict);
430209962Smm}
431209962Smm
432209962Smmstatic PyObject *
433209962Smmpy_userspace_upgrade(PyObject *self, PyObject *args)
434209962Smm{
435209962Smm	zfs_cmd_t zc = { 0 };
436209962Smm	char *name;
437209962Smm	int error;
438209962Smm
439209962Smm	if (!PyArg_ParseTuple(args, "s", &name))
440209962Smm		return (NULL);
441209962Smm
442209962Smm	(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
443209962Smm	error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_UPGRADE, &zc);
444209962Smm
445209962Smm	if (error != 0) {
446209962Smm		seterr(_("cannot initialize user accounting information on %s"),
447209962Smm		    name);
448209962Smm		return (NULL);
449209962Smm	}
450209962Smm
451209962Smm	Py_RETURN_NONE;
452209962Smm}
453209962Smm
454209962Smmstatic PyObject *
455209962Smmpy_set_cmdstr(PyObject *self, PyObject *args)
456209962Smm{
457209962Smm	char *str;
458209962Smm
459209962Smm	if (!PyArg_ParseTuple(args, "s", &str))
460209962Smm		return (NULL);
461209962Smm
462209962Smm	(void) strlcpy(cmdstr, str, sizeof (cmdstr));
463209962Smm
464209962Smm	Py_RETURN_NONE;
465209962Smm}
466209962Smm
467209962Smmstatic PyObject *
468209962Smmpy_get_proptable(PyObject *self, PyObject *args)
469209962Smm{
470209962Smm	zprop_desc_t *t = zfs_prop_get_table();
471209962Smm	PyObject *d = PyDict_New();
472209962Smm	zfs_prop_t i;
473209962Smm
474209962Smm	for (i = 0; i < ZFS_NUM_PROPS; i++) {
475209962Smm		zprop_desc_t *p = &t[i];
476209962Smm		PyObject *tuple;
477209962Smm		static const char *typetable[] =
478209962Smm		    {"number", "string", "index"};
479209962Smm		static const char *attrtable[] =
480209962Smm		    {"default", "readonly", "inherit", "onetime"};
481209962Smm		PyObject *indextable;
482209962Smm
483209962Smm		if (p->pd_proptype == PROP_TYPE_INDEX) {
484209962Smm			const zprop_index_t *it = p->pd_table;
485209962Smm			indextable = PyDict_New();
486209962Smm			int j;
487209962Smm			for (j = 0; it[j].pi_name; j++) {
488209962Smm				PyDict_SetItemString(indextable,
489209962Smm				    it[j].pi_name,
490209962Smm				    Py_BuildValue("K", it[j].pi_value));
491209962Smm			}
492209962Smm		} else {
493209962Smm			Py_INCREF(Py_None);
494209962Smm			indextable = Py_None;
495209962Smm		}
496209962Smm
497209962Smm		tuple = Py_BuildValue("sissKsissiiO",
498209962Smm		    p->pd_name, p->pd_propnum, typetable[p->pd_proptype],
499209962Smm		    p->pd_strdefault, p->pd_numdefault,
500209962Smm		    attrtable[p->pd_attr], p->pd_types,
501209962Smm		    p->pd_values, p->pd_colname,
502209962Smm		    p->pd_rightalign, p->pd_visible, indextable);
503209962Smm		PyDict_SetItemString(d, p->pd_name, tuple);
504209962Smm		Py_DECREF(tuple);
505209962Smm	}
506209962Smm
507209962Smm	return (d);
508209962Smm}
509209962Smm
510209962Smmstatic PyMethodDef zfsmethods[] = {
511209962Smm	{"next_dataset", py_next_dataset, METH_VARARGS,
512209962Smm	    "Get next child dataset or snapshot."},
513209962Smm	{"get_fsacl", py_get_fsacl, METH_VARARGS, "Get allowed permissions."},
514209962Smm	{"set_fsacl", py_set_fsacl, METH_VARARGS, "Set allowed permissions."},
515209962Smm	{"userspace_many", py_userspace_many, METH_VARARGS,
516209962Smm	    "Get user space accounting."},
517209962Smm	{"userspace_upgrade", py_userspace_upgrade, METH_VARARGS,
518209962Smm	    "Upgrade fs to enable user space accounting."},
519209962Smm	{"set_cmdstr", py_set_cmdstr, METH_VARARGS,
520209962Smm	    "Set command string for history logging."},
521209962Smm	{"dataset_props", py_dataset_props, METH_VARARGS,
522209962Smm	    "Get dataset properties."},
523209962Smm	{"get_proptable", py_get_proptable, METH_NOARGS,
524209962Smm	    "Get property table."},
525219089Spjd	{"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
526209962Smm	{NULL, NULL, 0, NULL}
527209962Smm};
528209962Smm
529209962Smmvoid
530209962Smminitioctl(void)
531209962Smm{
532209962Smm	PyObject *zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
533209962Smm	PyObject *zfs_util = PyImport_ImportModule("zfs.util");
534209962Smm	PyObject *devfile;
535209962Smm
536209962Smm	if (zfs_util == NULL)
537209962Smm		return;
538209962Smm
539209962Smm	ZFSError = PyObject_GetAttrString(zfs_util, "ZFSError");
540209962Smm	devfile = PyObject_GetAttrString(zfs_util, "dev");
541209962Smm	zfsdevfd = PyObject_AsFileDescriptor(devfile);
542209962Smm
543209962Smm	zfs_prop_init();
544209962Smm}
545