PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c

https://github.com/okuoku/freebsd-head
C | 544 lines | 426 code | 92 blank | 26 comment | 75 complexity | b6610786adbaa96feff01465f3f39c4c MD5 | raw file
  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. #include <Python.h>
  26. #include <sys/zfs_ioctl.h>
  27. #include <sys/fs/zfs.h>
  28. #include <strings.h>
  29. #include <unistd.h>
  30. #include <libnvpair.h>
  31. #include <libintl.h>
  32. #include <libzfs.h>
  33. #include <libzfs_impl.h>
  34. #include "zfs_prop.h"
  35. static PyObject *ZFSError;
  36. static int zfsdevfd;
  37. #ifdef __lint
  38. #define dgettext(x, y) y
  39. #endif
  40. #define _(s) dgettext(TEXT_DOMAIN, s)
  41. /*PRINTFLIKE1*/
  42. static void
  43. seterr(char *fmt, ...)
  44. {
  45. char errstr[1024];
  46. va_list v;
  47. va_start(v, fmt);
  48. (void) vsnprintf(errstr, sizeof (errstr), fmt, v);
  49. va_end(v);
  50. PyErr_SetObject(ZFSError, Py_BuildValue("is", errno, errstr));
  51. }
  52. static char cmdstr[HIS_MAX_RECORD_LEN];
  53. static int
  54. ioctl_with_cmdstr(int ioc, zfs_cmd_t *zc)
  55. {
  56. int err;
  57. if (cmdstr[0])
  58. zc->zc_history = (uint64_t)(uintptr_t)cmdstr;
  59. err = ioctl(zfsdevfd, ioc, zc);
  60. cmdstr[0] = '\0';
  61. return (err);
  62. }
  63. static PyObject *
  64. nvl2py(nvlist_t *nvl)
  65. {
  66. PyObject *pyo;
  67. nvpair_t *nvp;
  68. pyo = PyDict_New();
  69. for (nvp = nvlist_next_nvpair(nvl, NULL); nvp;
  70. nvp = nvlist_next_nvpair(nvl, nvp)) {
  71. PyObject *pyval;
  72. char *sval;
  73. uint64_t ival;
  74. boolean_t bval;
  75. nvlist_t *nval;
  76. switch (nvpair_type(nvp)) {
  77. case DATA_TYPE_STRING:
  78. (void) nvpair_value_string(nvp, &sval);
  79. pyval = Py_BuildValue("s", sval);
  80. break;
  81. case DATA_TYPE_UINT64:
  82. (void) nvpair_value_uint64(nvp, &ival);
  83. pyval = Py_BuildValue("K", ival);
  84. break;
  85. case DATA_TYPE_NVLIST:
  86. (void) nvpair_value_nvlist(nvp, &nval);
  87. pyval = nvl2py(nval);
  88. break;
  89. case DATA_TYPE_BOOLEAN:
  90. Py_INCREF(Py_None);
  91. pyval = Py_None;
  92. break;
  93. case DATA_TYPE_BOOLEAN_VALUE:
  94. (void) nvpair_value_boolean_value(nvp, &bval);
  95. pyval = Py_BuildValue("i", bval);
  96. break;
  97. default:
  98. PyErr_SetNone(PyExc_ValueError);
  99. Py_DECREF(pyo);
  100. return (NULL);
  101. }
  102. PyDict_SetItemString(pyo, nvpair_name(nvp), pyval);
  103. Py_DECREF(pyval);
  104. }
  105. return (pyo);
  106. }
  107. static nvlist_t *
  108. dict2nvl(PyObject *d)
  109. {
  110. nvlist_t *nvl;
  111. int err;
  112. PyObject *key, *value;
  113. int pos = 0;
  114. if (!PyDict_Check(d)) {
  115. PyErr_SetObject(PyExc_ValueError, d);
  116. return (NULL);
  117. }
  118. err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
  119. assert(err == 0);
  120. while (PyDict_Next(d, &pos, &key, &value)) {
  121. char *keystr = PyString_AsString(key);
  122. if (keystr == NULL) {
  123. PyErr_SetObject(PyExc_KeyError, key);
  124. nvlist_free(nvl);
  125. return (NULL);
  126. }
  127. if (PyDict_Check(value)) {
  128. nvlist_t *valnvl = dict2nvl(value);
  129. err = nvlist_add_nvlist(nvl, keystr, valnvl);
  130. nvlist_free(valnvl);
  131. } else if (value == Py_None) {
  132. err = nvlist_add_boolean(nvl, keystr);
  133. } else if (PyString_Check(value)) {
  134. char *valstr = PyString_AsString(value);
  135. err = nvlist_add_string(nvl, keystr, valstr);
  136. } else if (PyInt_Check(value)) {
  137. uint64_t valint = PyInt_AsUnsignedLongLongMask(value);
  138. err = nvlist_add_uint64(nvl, keystr, valint);
  139. } else if (PyBool_Check(value)) {
  140. boolean_t valbool = value == Py_True ? B_TRUE : B_FALSE;
  141. err = nvlist_add_boolean_value(nvl, keystr, valbool);
  142. } else {
  143. PyErr_SetObject(PyExc_ValueError, value);
  144. nvlist_free(nvl);
  145. return (NULL);
  146. }
  147. assert(err == 0);
  148. }
  149. return (nvl);
  150. }
  151. static PyObject *
  152. fakepropval(uint64_t value)
  153. {
  154. PyObject *d = PyDict_New();
  155. PyDict_SetItemString(d, "value", Py_BuildValue("K", value));
  156. return (d);
  157. }
  158. static void
  159. add_ds_props(zfs_cmd_t *zc, PyObject *nvl)
  160. {
  161. dmu_objset_stats_t *s = &zc->zc_objset_stats;
  162. PyDict_SetItemString(nvl, "numclones",
  163. fakepropval(s->dds_num_clones));
  164. PyDict_SetItemString(nvl, "issnap",
  165. fakepropval(s->dds_is_snapshot));
  166. PyDict_SetItemString(nvl, "inconsistent",
  167. fakepropval(s->dds_inconsistent));
  168. }
  169. /* On error, returns NULL but does not set python exception. */
  170. static PyObject *
  171. ioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
  172. {
  173. int nvsz = 2048;
  174. void *nvbuf;
  175. PyObject *pynv = NULL;
  176. again:
  177. nvbuf = malloc(nvsz);
  178. zc->zc_nvlist_dst_size = nvsz;
  179. zc->zc_nvlist_dst = (uintptr_t)nvbuf;
  180. if (ioctl(zfsdevfd, ioc, zc) == 0) {
  181. nvlist_t *nvl;
  182. errno = nvlist_unpack(nvbuf, zc->zc_nvlist_dst_size, &nvl, 0);
  183. if (errno == 0) {
  184. pynv = nvl2py(nvl);
  185. nvlist_free(nvl);
  186. }
  187. } else if (errno == ENOMEM) {
  188. free(nvbuf);
  189. nvsz = zc->zc_nvlist_dst_size;
  190. goto again;
  191. }
  192. free(nvbuf);
  193. return (pynv);
  194. }
  195. static PyObject *
  196. py_next_dataset(PyObject *self, PyObject *args)
  197. {
  198. int ioc;
  199. uint64_t cookie;
  200. zfs_cmd_t zc = { 0 };
  201. int snaps;
  202. char *name;
  203. PyObject *nvl;
  204. PyObject *ret = NULL;
  205. if (!PyArg_ParseTuple(args, "siK", &name, &snaps, &cookie))
  206. return (NULL);
  207. (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
  208. zc.zc_cookie = cookie;
  209. if (snaps)
  210. ioc = ZFS_IOC_SNAPSHOT_LIST_NEXT;
  211. else
  212. ioc = ZFS_IOC_DATASET_LIST_NEXT;
  213. nvl = ioctl_with_dstnv(ioc, &zc);
  214. if (nvl) {
  215. add_ds_props(&zc, nvl);
  216. ret = Py_BuildValue("sKO", zc.zc_name, zc.zc_cookie, nvl);
  217. Py_DECREF(nvl);
  218. } else if (errno == ESRCH) {
  219. PyErr_SetNone(PyExc_StopIteration);
  220. } else {
  221. if (snaps)
  222. seterr(_("cannot get snapshots of %s"), name);
  223. else
  224. seterr(_("cannot get child datasets of %s"), name);
  225. }
  226. return (ret);
  227. }
  228. static PyObject *
  229. py_dataset_props(PyObject *self, PyObject *args)
  230. {
  231. zfs_cmd_t zc = { 0 };
  232. int snaps;
  233. char *name;
  234. PyObject *nvl;
  235. if (!PyArg_ParseTuple(args, "s", &name))
  236. return (NULL);
  237. (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
  238. nvl = ioctl_with_dstnv(ZFS_IOC_OBJSET_STATS, &zc);
  239. if (nvl) {
  240. add_ds_props(&zc, nvl);
  241. } else {
  242. seterr(_("cannot access dataset %s"), name);
  243. }
  244. return (nvl);
  245. }
  246. static PyObject *
  247. py_get_fsacl(PyObject *self, PyObject *args)
  248. {
  249. zfs_cmd_t zc = { 0 };
  250. char *name;
  251. PyObject *nvl;
  252. if (!PyArg_ParseTuple(args, "s", &name))
  253. return (NULL);
  254. (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
  255. nvl = ioctl_with_dstnv(ZFS_IOC_GET_FSACL, &zc);
  256. if (nvl == NULL)
  257. seterr(_("cannot get permissions on %s"), name);
  258. return (nvl);
  259. }
  260. static PyObject *
  261. py_set_fsacl(PyObject *self, PyObject *args)
  262. {
  263. int un;
  264. size_t nvsz;
  265. zfs_cmd_t zc = { 0 };
  266. char *name, *nvbuf;
  267. PyObject *dict, *file;
  268. nvlist_t *nvl;
  269. int err;
  270. if (!PyArg_ParseTuple(args, "siO!", &name, &un,
  271. &PyDict_Type, &dict))
  272. return (NULL);
  273. nvl = dict2nvl(dict);
  274. if (nvl == NULL)
  275. return (NULL);
  276. err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
  277. assert(err == 0);
  278. nvbuf = malloc(nvsz);
  279. err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
  280. assert(err == 0);
  281. (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
  282. zc.zc_nvlist_src_size = nvsz;
  283. zc.zc_nvlist_src = (uintptr_t)nvbuf;
  284. zc.zc_perm_action = un;
  285. err = ioctl_with_cmdstr(ZFS_IOC_SET_FSACL, &zc);
  286. free(nvbuf);
  287. if (err) {
  288. seterr(_("cannot set permissions on %s"), name);
  289. return (NULL);
  290. }
  291. Py_RETURN_NONE;
  292. }
  293. static PyObject *
  294. py_get_holds(PyObject *self, PyObject *args)
  295. {
  296. zfs_cmd_t zc = { 0 };
  297. char *name;
  298. PyObject *nvl;
  299. if (!PyArg_ParseTuple(args, "s", &name))
  300. return (NULL);
  301. (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
  302. nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
  303. if (nvl == NULL)
  304. seterr(_("cannot get holds for %s"), name);
  305. return (nvl);
  306. }
  307. static PyObject *
  308. py_userspace_many(PyObject *self, PyObject *args)
  309. {
  310. zfs_cmd_t zc = { 0 };
  311. zfs_userquota_prop_t type;
  312. char *name, *propname;
  313. int bufsz = 1<<20;
  314. void *buf;
  315. PyObject *dict, *file;
  316. int error;
  317. if (!PyArg_ParseTuple(args, "ss", &name, &propname))
  318. return (NULL);
  319. for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++)
  320. if (strcmp(propname, zfs_userquota_prop_prefixes[type]) == 0)
  321. break;
  322. if (type == ZFS_NUM_USERQUOTA_PROPS) {
  323. PyErr_SetString(PyExc_KeyError, propname);
  324. return (NULL);
  325. }
  326. dict = PyDict_New();
  327. buf = malloc(bufsz);
  328. (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
  329. zc.zc_objset_type = type;
  330. zc.zc_cookie = 0;
  331. while (1) {
  332. zfs_useracct_t *zua = buf;
  333. zc.zc_nvlist_dst = (uintptr_t)buf;
  334. zc.zc_nvlist_dst_size = bufsz;
  335. error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_MANY, &zc);
  336. if (error || zc.zc_nvlist_dst_size == 0)
  337. break;
  338. while (zc.zc_nvlist_dst_size > 0) {
  339. PyObject *pykey, *pyval;
  340. pykey = Py_BuildValue("sI",
  341. zua->zu_domain, zua->zu_rid);
  342. pyval = Py_BuildValue("K", zua->zu_space);
  343. PyDict_SetItem(dict, pykey, pyval);
  344. Py_DECREF(pykey);
  345. Py_DECREF(pyval);
  346. zua++;
  347. zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
  348. }
  349. }
  350. free(buf);
  351. if (error != 0) {
  352. Py_DECREF(dict);
  353. seterr(_("cannot get %s property on %s"), propname, name);
  354. return (NULL);
  355. }
  356. return (dict);
  357. }
  358. static PyObject *
  359. py_userspace_upgrade(PyObject *self, PyObject *args)
  360. {
  361. zfs_cmd_t zc = { 0 };
  362. char *name;
  363. int error;
  364. if (!PyArg_ParseTuple(args, "s", &name))
  365. return (NULL);
  366. (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
  367. error = ioctl(zfsdevfd, ZFS_IOC_USERSPACE_UPGRADE, &zc);
  368. if (error != 0) {
  369. seterr(_("cannot initialize user accounting information on %s"),
  370. name);
  371. return (NULL);
  372. }
  373. Py_RETURN_NONE;
  374. }
  375. static PyObject *
  376. py_set_cmdstr(PyObject *self, PyObject *args)
  377. {
  378. char *str;
  379. if (!PyArg_ParseTuple(args, "s", &str))
  380. return (NULL);
  381. (void) strlcpy(cmdstr, str, sizeof (cmdstr));
  382. Py_RETURN_NONE;
  383. }
  384. static PyObject *
  385. py_get_proptable(PyObject *self, PyObject *args)
  386. {
  387. zprop_desc_t *t = zfs_prop_get_table();
  388. PyObject *d = PyDict_New();
  389. zfs_prop_t i;
  390. for (i = 0; i < ZFS_NUM_PROPS; i++) {
  391. zprop_desc_t *p = &t[i];
  392. PyObject *tuple;
  393. static const char *typetable[] =
  394. {"number", "string", "index"};
  395. static const char *attrtable[] =
  396. {"default", "readonly", "inherit", "onetime"};
  397. PyObject *indextable;
  398. if (p->pd_proptype == PROP_TYPE_INDEX) {
  399. const zprop_index_t *it = p->pd_table;
  400. indextable = PyDict_New();
  401. int j;
  402. for (j = 0; it[j].pi_name; j++) {
  403. PyDict_SetItemString(indextable,
  404. it[j].pi_name,
  405. Py_BuildValue("K", it[j].pi_value));
  406. }
  407. } else {
  408. Py_INCREF(Py_None);
  409. indextable = Py_None;
  410. }
  411. tuple = Py_BuildValue("sissKsissiiO",
  412. p->pd_name, p->pd_propnum, typetable[p->pd_proptype],
  413. p->pd_strdefault, p->pd_numdefault,
  414. attrtable[p->pd_attr], p->pd_types,
  415. p->pd_values, p->pd_colname,
  416. p->pd_rightalign, p->pd_visible, indextable);
  417. PyDict_SetItemString(d, p->pd_name, tuple);
  418. Py_DECREF(tuple);
  419. }
  420. return (d);
  421. }
  422. static PyMethodDef zfsmethods[] = {
  423. {"next_dataset", py_next_dataset, METH_VARARGS,
  424. "Get next child dataset or snapshot."},
  425. {"get_fsacl", py_get_fsacl, METH_VARARGS, "Get allowed permissions."},
  426. {"set_fsacl", py_set_fsacl, METH_VARARGS, "Set allowed permissions."},
  427. {"userspace_many", py_userspace_many, METH_VARARGS,
  428. "Get user space accounting."},
  429. {"userspace_upgrade", py_userspace_upgrade, METH_VARARGS,
  430. "Upgrade fs to enable user space accounting."},
  431. {"set_cmdstr", py_set_cmdstr, METH_VARARGS,
  432. "Set command string for history logging."},
  433. {"dataset_props", py_dataset_props, METH_VARARGS,
  434. "Get dataset properties."},
  435. {"get_proptable", py_get_proptable, METH_NOARGS,
  436. "Get property table."},
  437. {"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
  438. {NULL, NULL, 0, NULL}
  439. };
  440. void
  441. initioctl(void)
  442. {
  443. PyObject *zfs_ioctl = Py_InitModule("zfs.ioctl", zfsmethods);
  444. PyObject *zfs_util = PyImport_ImportModule("zfs.util");
  445. PyObject *devfile;
  446. if (zfs_util == NULL)
  447. return;
  448. ZFSError = PyObject_GetAttrString(zfs_util, "ZFSError");
  449. devfile = PyObject_GetAttrString(zfs_util, "dev");
  450. zfsdevfd = PyObject_AsFileDescriptor(devfile);
  451. zfs_prop_init();
  452. }