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