xref: /illumos-gate/usr/src/lib/pylibbe/common/libbe_py.c (revision b69c34dad3717624ff6b4f32b71014ee05b6a678)
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 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2012 OmniTI Computer Consulting, Inc.  All rights reserved.
25  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
26  */
27 
28 #include <Python.h>
29 #include <sys/varargs.h>
30 #include <stdio.h>
31 #include <libnvpair.h>
32 
33 #include <libbe.h>
34 #include <libbe_priv.h>
35 
36 enum {
37 	BE_PY_SUCCESS = 0,
38 	BE_PY_ERR_APPEND = 6000,
39 	BE_PY_ERR_DICT,
40 	BE_PY_ERR_LIST,
41 	BE_PY_ERR_NVLIST,
42 	BE_PY_ERR_PARSETUPLE,
43 	BE_PY_ERR_PRINT_ERR,
44 	BE_PY_ERR_VAR_CONV,
45 } bePyErr;
46 
47 /*
48  * public libbe functions
49  */
50 
51 PyObject *beCreateSnapshot(PyObject *, PyObject *);
52 PyObject *beCopy(PyObject *, PyObject *);
53 PyObject *beList(PyObject *, PyObject *, PyObject *);
54 PyObject *beActivate(PyObject *, PyObject *);
55 PyObject *beDestroy(PyObject *, PyObject *);
56 PyObject *beDestroySnapshot(PyObject *, PyObject *);
57 PyObject *beRename(PyObject *, PyObject *);
58 PyObject *beMount(PyObject *, PyObject *);
59 PyObject *beUnmount(PyObject *, PyObject *);
60 PyObject *bePrintErrors(PyObject *, PyObject *);
61 PyObject *beGetErrDesc(PyObject *, PyObject *);
62 char *beMapLibbePyErrorToString(int);
63 
64 static boolean_t convertBEInfoToDictionary(be_node_list_t *be,
65     PyObject **listDict);
66 static boolean_t convertDatasetInfoToDictionary(be_dataset_list_t *ds,
67     PyObject **listDict);
68 static boolean_t convertSnapshotInfoToDictionary(be_snapshot_list_t *ss,
69     PyObject **listDict);
70 static boolean_t convertPyArgsToNvlist(nvlist_t **nvList, int numArgs, ...);
71 
72 
73 /* ~~~~~~~~~~~~~~~ */
74 /* Public Funtions */
75 /* ~~~~~~~~~~~~~~~ */
76 
77 /*
78  * Function:    beCreateSnapshot
79  * Description: Convert Python args to nvlist pairs and
80  *              call libbe:be_create_snapshot to create a
81  *              snapshot of all the datasets within a BE
82  * Parameters:
83  *   args -          pointer to a python object containing:
84  *        beName -   The name of the BE to create a snapshot of
85  *        snapName - The name of the snapshot to create (optional)
86  *
87  *        The following public attribute values. defined by libbe.h,
88  *        are used by this function:
89  *
90  * Returns a pointer to a python object and an optional snapshot name:
91  *      0, [snapName] - Success
92  *      1, [snapName] - Failure
93  * Scope:
94  *      Public
95  */
96 /* ARGSUSED */
97 PyObject *
98 beCreateSnapshot(PyObject *self, PyObject *args)
99 {
100 	char	*beName = NULL;
101 	char	*snapName = NULL;
102 	int	ret = BE_PY_SUCCESS;
103 	nvlist_t	*beAttrs = NULL;
104 	PyObject	*retVals = NULL;
105 
106 	if (!PyArg_ParseTuple(args, "z|z", &beName, &snapName)) {
107 		return (Py_BuildValue("[is]", BE_PY_ERR_PARSETUPLE, NULL));
108 	}
109 
110 	if (!convertPyArgsToNvlist(&beAttrs, 4,
111 	    BE_ATTR_ORIG_BE_NAME, beName,
112 	    BE_ATTR_SNAP_NAME, snapName)) {
113 		nvlist_free(beAttrs);
114 		return (Py_BuildValue("[is]", BE_PY_ERR_NVLIST, NULL));
115 	}
116 
117 	if (beAttrs == NULL) {
118 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
119 	}
120 
121 	if ((ret = be_create_snapshot(beAttrs)) != 0) {
122 		nvlist_free(beAttrs);
123 		return (Py_BuildValue("[is]", ret, NULL));
124 	}
125 	if (snapName == NULL) {
126 		if (nvlist_lookup_pairs(beAttrs, NV_FLAG_NOENTOK,
127 		    BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &snapName,
128 		    NULL) != 0) {
129 			nvlist_free(beAttrs);
130 			return (Py_BuildValue("[is]",
131 			    BE_PY_ERR_NVLIST, NULL));
132 		}
133 		retVals = Py_BuildValue("[is]", ret, snapName);
134 		nvlist_free(beAttrs);
135 		return (retVals);
136 	}
137 	nvlist_free(beAttrs);
138 
139 	return (Py_BuildValue("[is]", ret, NULL));
140 }
141 
142 /*
143  * Function:    beCopy
144  * Description: Convert Python args to nvlist pairs and call libbe:be_copy
145  *              to create a Boot Environment
146  * Parameters:
147  *   args -     pointer to a python object containing:
148  *     trgtBeName - The name of the BE to create
149  *     srcBeName - The name of the BE used to create trgtBeName (optional)
150  *     rpool - The pool to create the new BE in (optional)
151  *     srcSnapName - The snapshot name (optional)
152  *     beNameProperties - The properties to use when creating
153  *                        the BE (optional)
154  *
155  * Returns a pointer to a python object. That Python object will consist of
156  * the return code and optional attributes, trgtBeName and snapshotName
157  *      BE_SUCCESS, [trgtBeName], [trgtSnapName] - Success
158  *      1, [trgtBeName], [trgtSnapName] - Failure
159  * Scope:
160  *      Public
161  */
162 /* ARGSUSED */
163 PyObject *
164 beCopy(PyObject *self, PyObject *args)
165 {
166 	char	*trgtBeName = NULL;
167 	char	*srcBeName = NULL;
168 	char	*srcSnapName = NULL;
169 	char	*trgtSnapName = NULL;
170 	char	*rpool = NULL;
171 	char	*beDescription = NULL;
172 	Py_ssize_t	pos = 0;
173 	int		ret = BE_PY_SUCCESS;
174 	nvlist_t	*beAttrs = NULL;
175 	nvlist_t	*beProps = NULL;
176 	PyObject	*beNameProperties = NULL;
177 	PyObject	*pkey = NULL;
178 	PyObject	*pvalue = NULL;
179 	PyObject	*retVals = NULL;
180 
181 	if (!PyArg_ParseTuple(args, "|zzzzOz", &trgtBeName, &srcBeName,
182 	    &srcSnapName, &rpool, &beNameProperties, &beDescription)) {
183 		return (Py_BuildValue("[iss]", BE_PY_ERR_PARSETUPLE,
184 		    NULL, NULL));
185 	}
186 
187 	if (!convertPyArgsToNvlist(&beAttrs, 10,
188 	    BE_ATTR_NEW_BE_NAME, trgtBeName,
189 	    BE_ATTR_ORIG_BE_NAME, srcBeName,
190 	    BE_ATTR_SNAP_NAME, srcSnapName,
191 	    BE_ATTR_NEW_BE_POOL, rpool,
192 	    BE_ATTR_NEW_BE_DESC, beDescription)) {
193 		nvlist_free(beAttrs);
194 		return (Py_BuildValue("[iss]", BE_PY_ERR_NVLIST, NULL, NULL));
195 	}
196 
197 	if (beNameProperties != NULL) {
198 		if (nvlist_alloc(&beProps, NV_UNIQUE_NAME, 0) != 0) {
199 			(void) printf("nvlist_alloc failed.\n");
200 			nvlist_free(beAttrs);
201 			return (Py_BuildValue("[iss]", BE_PY_ERR_NVLIST,
202 			    NULL, NULL));
203 		}
204 		while (PyDict_Next(beNameProperties, &pos, &pkey, &pvalue)) {
205 #if PY_MAJOR_VERSION >= 3
206 			if (!convertPyArgsToNvlist(&beProps, 2,
207 			    PyUnicode_AsUTF8(pkey),
208 			    PyUnicode_AsUTF8(pvalue))) {
209 #else
210 			if (!convertPyArgsToNvlist(&beProps, 2,
211 			    PyString_AsString(pkey),
212 			    PyString_AsString(pvalue))) {
213 #endif
214 				nvlist_free(beProps);
215 				nvlist_free(beAttrs);
216 				return (Py_BuildValue("[iss]", BE_PY_ERR_NVLIST,
217 				    NULL, NULL));
218 			}
219 		}
220 	}
221 
222 	if (beProps != NULL && beAttrs != NULL &&
223 	    nvlist_add_nvlist(beAttrs, BE_ATTR_ZFS_PROPERTIES,
224 	    beProps) != 0) {
225 		nvlist_free(beProps);
226 		nvlist_free(beAttrs);
227 		return (Py_BuildValue("[iss]", BE_PY_ERR_NVLIST,
228 		    NULL, NULL));
229 	}
230 
231 	nvlist_free(beProps);
232 
233 	if (trgtBeName == NULL) {
234 		/*
235 		 * Caller wants to get back the BE_ATTR_NEW_BE_NAME and
236 		 * BE_ATTR_SNAP_NAME
237 		 */
238 		if ((ret = be_copy(beAttrs)) != BE_SUCCESS) {
239 			nvlist_free(beAttrs);
240 			return (Py_BuildValue("[iss]", ret, NULL, NULL));
241 		}
242 
243 		/*
244 		 * When no trgtBeName is passed to be_copy, be_copy
245 		 * returns an auto generated beName and snapshot name.
246 		 */
247 		if (nvlist_lookup_string(beAttrs, BE_ATTR_NEW_BE_NAME,
248 		    &trgtBeName) != 0) {
249 			nvlist_free(beAttrs);
250 			return (Py_BuildValue("[iss]", BE_PY_ERR_NVLIST,
251 			    NULL, NULL));
252 		}
253 		if (nvlist_lookup_string(beAttrs, BE_ATTR_SNAP_NAME,
254 		    &trgtSnapName) != 0) {
255 			nvlist_free(beAttrs);
256 			return (Py_BuildValue("[iss]", BE_PY_ERR_NVLIST,
257 			    NULL, NULL));
258 		}
259 
260 		retVals = Py_BuildValue("[iss]", BE_PY_SUCCESS,
261 		    trgtBeName, trgtSnapName);
262 		nvlist_free(beAttrs);
263 		return (retVals);
264 
265 	} else {
266 		ret = be_copy(beAttrs);
267 		nvlist_free(beAttrs);
268 		return (Py_BuildValue("[iss]", ret, NULL, NULL));
269 	}
270 }
271 
272 /*
273  * Function:    beList
274  * Description: Convert Python args to nvlist pairs and call libbe:be_list
275  *              to gather information about Boot Environments
276  * Parameters:
277  *   args -     pointer to a python object containing:
278  *     bename  - The name of the BE to list (optional)
279  *     nosnaps - boolean indicating whether to exclude snapshots (optional)
280  *
281  * Returns a pointer to a python object. That Python object will consist of
282  * the return code and a list of Dicts or NULL.
283  *      BE_PY_SUCCESS, listOfDicts - Success
284  *      bePyErr or be_errno_t, NULL - Failure
285  * Scope:
286  *      Public
287  */
288 /* ARGSUSED */
289 PyObject *
290 beList(PyObject *self, PyObject *args, PyObject *keywds)
291 {
292 	char	*beName = NULL;
293 	int	noSnaps = 0;
294 	int	ret = BE_PY_SUCCESS;
295 	be_node_list_t *list = NULL;
296 	be_node_list_t *be = NULL;
297 	PyObject *dict = NULL;
298 	PyObject *listOfDicts = NULL;
299 	uint64_t listopts = BE_LIST_SNAPSHOTS;
300 
301 	static char *kwlist[] = {"bename", "nosnaps", NULL};
302 
303 	if ((listOfDicts = PyList_New(0)) == NULL) {
304 		ret = BE_PY_ERR_DICT;
305 		listOfDicts = Py_None;
306 		goto done;
307 	}
308 
309 	if (!PyArg_ParseTupleAndKeywords(args, keywds, "|zi",
310 	    kwlist, &beName, &noSnaps)) {
311 		ret = BE_PY_ERR_PARSETUPLE;
312 		goto done;
313 	}
314 
315 	if (noSnaps)
316 		listopts &= ~BE_LIST_SNAPSHOTS;
317 
318 	if ((ret = be_list(beName, &list, listopts)) != BE_SUCCESS) {
319 		goto done;
320 	}
321 
322 	for (be = list; be != NULL; be = be->be_next_node) {
323 		be_dataset_list_t *ds = be->be_node_datasets;
324 		be_snapshot_list_t *ss = be->be_node_snapshots;
325 
326 		if ((dict = PyDict_New()) == NULL) {
327 			ret = BE_PY_ERR_DICT;
328 			goto done;
329 		}
330 
331 		if (!convertBEInfoToDictionary(be, &dict)) {
332 			/* LINTED */
333 			Py_DECREF(dict);
334 			ret = BE_PY_ERR_VAR_CONV;
335 			goto done;
336 		}
337 
338 		if (PyList_Append(listOfDicts, dict) != 0) {
339 			/* LINTED */
340 			Py_DECREF(dict);
341 			ret = BE_PY_ERR_APPEND;
342 			goto done;
343 		}
344 
345 		/* LINTED */
346 		Py_DECREF(dict);
347 
348 		while (ds != NULL) {
349 			if ((dict = PyDict_New()) == NULL) {
350 				ret = BE_PY_ERR_DICT;
351 				goto done;
352 			}
353 
354 			if (!convertDatasetInfoToDictionary(ds, &dict)) {
355 				/* LINTED */
356 				Py_DECREF(dict);
357 				ret = BE_PY_ERR_VAR_CONV;
358 				goto done;
359 			}
360 
361 			if (PyList_Append(listOfDicts, dict) != 0) {
362 				/* LINTED */
363 				Py_DECREF(dict);
364 				ret = BE_PY_ERR_APPEND;
365 				goto done;
366 			}
367 
368 			ds = ds->be_next_dataset;
369 
370 			/* LINTED */
371 			Py_DECREF(dict);
372 		}
373 
374 
375 		while (ss != NULL) {
376 			if ((dict = PyDict_New()) == NULL) {
377 				/* LINTED */
378 				Py_DECREF(dict);
379 				ret = BE_PY_ERR_DICT;
380 				goto done;
381 			}
382 
383 			if (!convertSnapshotInfoToDictionary(ss, &dict)) {
384 				/* LINTED */
385 				Py_DECREF(dict);
386 				ret = BE_PY_ERR_VAR_CONV;
387 				goto done;
388 			}
389 
390 			if (PyList_Append(listOfDicts, dict) != 0) {
391 				/* LINTED */
392 				Py_DECREF(dict);
393 				ret = BE_PY_ERR_APPEND;
394 				goto done;
395 			}
396 
397 			ss = ss->be_next_snapshot;
398 
399 			/* LINTED */
400 			Py_DECREF(dict);
401 		}
402 	}
403 
404 done:
405 	if (list != NULL)
406 		be_free_list(list);
407 	return (Py_BuildValue("[iO]", ret, listOfDicts));
408 }
409 
410 /*
411  * Function:    beActivate
412  * Description: Convert Python args to nvlist pairs and call libbe:be_activate
413  *              to activate a Boot Environment
414  * Parameters:
415  *   args -     pointer to a python object containing:
416  *     beName - The name of the BE to activate
417  *
418  * Returns a pointer to a python object:
419  *      BE_SUCCESS - Success
420  *      bePyErr or be_errno_t - Failure
421  * Scope:
422  *      Public
423  */
424 /* ARGSUSED */
425 PyObject *
426 beActivate(PyObject *self, PyObject *args)
427 {
428 	char		*beName = NULL;
429 	int		ret = BE_PY_SUCCESS;
430 	nvlist_t	*beAttrs = NULL;
431 
432 	if (!PyArg_ParseTuple(args, "z", &beName)) {
433 		return (Py_BuildValue("i", BE_PY_ERR_PARSETUPLE));
434 	}
435 
436 	if (!convertPyArgsToNvlist(&beAttrs, 2, BE_ATTR_ORIG_BE_NAME, beName)) {
437 		nvlist_free(beAttrs);
438 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
439 	}
440 
441 	if (beAttrs == NULL) {
442 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
443 	}
444 
445 	ret = be_activate(beAttrs);
446 	nvlist_free(beAttrs);
447 	return (Py_BuildValue("i", ret));
448 }
449 
450 /*
451  * Function:    beDestroy
452  * Description: Convert Python args to nvlist pairs and call libbe:be_destroy
453  *              to destroy a Boot Environment
454  * Parameters:
455  *   args -     pointer to a python object containing:
456  *     beName - The name of the BE to destroy
457  *
458  * Returns a pointer to a python object:
459  *      BE_SUCCESS - Success
460  *      bePyErr or be_errno_t - Failure
461  * Scope:
462  *      Public
463  */
464 /* ARGSUSED */
465 PyObject *
466 beDestroy(PyObject *self, PyObject *args)
467 {
468 	char		*beName = NULL;
469 	int		destroy_snaps = 0;
470 	int		force_unmount = 0;
471 	int		destroy_flags = 0;
472 	int		ret = BE_PY_SUCCESS;
473 	nvlist_t	*beAttrs = NULL;
474 
475 	if (!PyArg_ParseTuple(args, "z|ii", &beName, &destroy_snaps,
476 	    &force_unmount)) {
477 		return (Py_BuildValue("i", BE_PY_ERR_PARSETUPLE));
478 	}
479 
480 	if (destroy_snaps == 1)
481 		destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
482 
483 	if (force_unmount == 1)
484 		destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
485 
486 	if (!convertPyArgsToNvlist(&beAttrs, 2, BE_ATTR_ORIG_BE_NAME, beName)) {
487 		nvlist_free(beAttrs);
488 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
489 	}
490 
491 	if (nvlist_add_uint16(beAttrs, BE_ATTR_DESTROY_FLAGS, destroy_flags)
492 	    != 0) {
493 		(void) printf("nvlist_add_uint16 failed for "
494 		    "BE_ATTR_DESTROY_FLAGS (%d).\n", destroy_flags);
495 		nvlist_free(beAttrs);
496 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
497 	}
498 
499 	if (beAttrs == NULL) {
500 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
501 	}
502 
503 	ret = be_destroy(beAttrs);
504 	nvlist_free(beAttrs);
505 	return (Py_BuildValue("i", ret));
506 }
507 
508 /*
509  * Function:    beDestroySnapshot
510  * Description: Convert Python args to nvlist pairs and call libbe:be_destroy
511  *              to destroy a snapshot of a Boot Environment
512  * Parameters:
513  *   args -     pointer to a python object containing:
514  *     beName - The name of the BE to destroy
515  *     snapName - The name of the snapshot to destroy
516  *
517  * Returns a pointer to a python object:
518  *      BE_SUCCESS - Success
519  *      bePyErr or be_errno_t - Failure
520  * Scope:
521  *      Public
522  */
523 /* ARGSUSED */
524 PyObject *
525 beDestroySnapshot(PyObject *self, PyObject *args)
526 {
527 	char		*beName = NULL;
528 	char		*snapName = NULL;
529 	int		ret = BE_PY_SUCCESS;
530 	nvlist_t	*beAttrs = NULL;
531 
532 	if (!PyArg_ParseTuple(args, "zz", &beName, &snapName)) {
533 		return (Py_BuildValue("i", BE_PY_ERR_PARSETUPLE));
534 	}
535 
536 	if (!convertPyArgsToNvlist(&beAttrs, 4,
537 	    BE_ATTR_ORIG_BE_NAME, beName,
538 	    BE_ATTR_SNAP_NAME, snapName)) {
539 		nvlist_free(beAttrs);
540 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
541 	}
542 
543 	if (beAttrs == NULL) {
544 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
545 	}
546 
547 	ret = be_destroy_snapshot(beAttrs);
548 	nvlist_free(beAttrs);
549 	return (Py_BuildValue("i", ret));
550 }
551 
552 /*
553  * Function:    beRename
554  * Description: Convert Python args to nvlist pairs and call libbe:be_rename
555  *              to rename a Boot Environment
556  * Parameters:
557  *   args -     pointer to a python object containing:
558  *     oldBeName - The name of the old Boot Environment
559  *     newBeName - The name of the new Boot Environment
560  *
561  * Returns a pointer to a python object:
562  *      BE_SUCCESS - Success
563  *      bePyErr or be_errno_t - Failure
564  * Scope:
565  *      Public
566  */
567 /* ARGSUSED */
568 PyObject *
569 beRename(PyObject *self, PyObject *args)
570 {
571 	char		*oldBeName = NULL;
572 	char		*newBeName = NULL;
573 	int		ret = BE_PY_SUCCESS;
574 	nvlist_t	*beAttrs = NULL;
575 
576 	if (!PyArg_ParseTuple(args, "zz", &oldBeName, &newBeName)) {
577 		return (Py_BuildValue("i", BE_PY_ERR_PARSETUPLE));
578 	}
579 
580 	if (!convertPyArgsToNvlist(&beAttrs, 4,
581 	    BE_ATTR_ORIG_BE_NAME, oldBeName,
582 	    BE_ATTR_NEW_BE_NAME, newBeName)) {
583 		nvlist_free(beAttrs);
584 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
585 	}
586 
587 	if (beAttrs == NULL) {
588 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
589 	}
590 
591 	ret = be_rename(beAttrs);
592 	nvlist_free(beAttrs);
593 	return (Py_BuildValue("i", ret));
594 }
595 
596 /*
597  * Function:    beMount
598  * Description: Convert Python args to nvlist pairs and call libbe:be_mount
599  *              to mount a Boot Environment
600  * Parameters:
601  *   args -     pointer to a python object containing:
602  *     beName - The name of the Boot Environment to mount
603  *     mountpoint - The path of the mountpoint to mount the
604  *                  Boot Environment on (optional)
605  *
606  * Returns a pointer to a python object:
607  *      BE_SUCCESS - Success
608  *      bePyErr or be_errno_t - Failure
609  * Scope:
610  *      Public
611  */
612 /* ARGSUSED */
613 PyObject *
614 beMount(PyObject *self, PyObject *args)
615 {
616 	char		*beName = NULL;
617 	char		*mountpoint = NULL;
618 	int		ret = BE_PY_SUCCESS;
619 	nvlist_t	*beAttrs = NULL;
620 
621 	if (!PyArg_ParseTuple(args, "zz", &beName, &mountpoint)) {
622 		return (Py_BuildValue("i", BE_PY_ERR_PARSETUPLE));
623 	}
624 
625 	if (!convertPyArgsToNvlist(&beAttrs, 4,
626 	    BE_ATTR_ORIG_BE_NAME, beName,
627 	    BE_ATTR_MOUNTPOINT, mountpoint)) {
628 		nvlist_free(beAttrs);
629 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
630 	}
631 
632 	if (beAttrs == NULL) {
633 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
634 	}
635 
636 	ret = be_mount(beAttrs);
637 	nvlist_free(beAttrs);
638 	return (Py_BuildValue("i", ret));
639 }
640 
641 /*
642  * Function:    beUnmount
643  * Description: Convert Python args to nvlist pairs and call libbe:be_unmount
644  *              to unmount a Boot Environment
645  * Parameters:
646  *   args -     pointer to a python object containing:
647  *     beName - The name of the Boot Environment to unmount
648  *
649  * Returns a pointer to a python object:
650  *      BE_SUCCESS - Success
651  *      bePyErr or be_errno_t - Failure
652  * Scope:
653  *      Public
654  */
655 /* ARGSUSED */
656 PyObject *
657 beUnmount(PyObject *self, PyObject *args)
658 {
659 	char		*beName = NULL;
660 	int		force_unmount = 0;
661 	int		unmount_flags = 0;
662 	int		ret = BE_PY_SUCCESS;
663 	nvlist_t	*beAttrs = NULL;
664 
665 	if (!PyArg_ParseTuple(args, "z|i", &beName, &force_unmount)) {
666 		return (Py_BuildValue("i", BE_PY_ERR_PARSETUPLE));
667 	}
668 
669 	if (force_unmount == 1)
670 		unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
671 
672 	if (!convertPyArgsToNvlist(&beAttrs, 2,
673 	    BE_ATTR_ORIG_BE_NAME, beName)) {
674 		nvlist_free(beAttrs);
675 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
676 	}
677 
678 	if (nvlist_add_uint16(beAttrs, BE_ATTR_UNMOUNT_FLAGS, unmount_flags)
679 	    != 0) {
680 		(void) printf("nvlist_add_uint16 failed for "
681 		    "BE_ATTR_UNMOUNT_FLAGS (%d).\n", unmount_flags);
682 		nvlist_free(beAttrs);
683 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
684 	}
685 
686 	if (beAttrs == NULL) {
687 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
688 	}
689 
690 	ret = be_unmount(beAttrs);
691 	nvlist_free(beAttrs);
692 	return (Py_BuildValue("i", ret));
693 }
694 
695 /*
696  * Function:    beRollback
697  * Description: Convert Python args to nvlist pairs and call libbe:be_rollback
698  *              to rollback a Boot Environment to a previously taken
699  *               snapshot.
700  * Parameters:
701  *   args -     pointer to a python object containing:
702  *     beName - The name of the Boot Environment to unmount
703  *
704  * Returns a pointer to a python object:
705  *      BE_SUCCESS - Success
706  *      bePyErr or be_errno_t - Failure
707  * Scope:
708  *      Public
709  */
710 /* ARGSUSED */
711 PyObject *
712 beRollback(PyObject *self, PyObject *args)
713 {
714 	char		*beName = NULL;
715 	char		*snapName = NULL;
716 	int		ret = BE_PY_SUCCESS;
717 	nvlist_t	*beAttrs = NULL;
718 
719 	if (!PyArg_ParseTuple(args, "zz", &beName, &snapName)) {
720 		return (Py_BuildValue("i", BE_PY_ERR_PARSETUPLE));
721 	}
722 
723 	if (!convertPyArgsToNvlist(&beAttrs, 4,
724 	    BE_ATTR_ORIG_BE_NAME, beName,
725 	    BE_ATTR_SNAP_NAME, snapName)) {
726 		nvlist_free(beAttrs);
727 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
728 	}
729 
730 	if (beAttrs == NULL) {
731 		return (Py_BuildValue("i", BE_PY_ERR_NVLIST));
732 	}
733 
734 	ret = be_rollback(beAttrs);
735 	nvlist_free(beAttrs);
736 	return (Py_BuildValue("i", ret));
737 }
738 
739 /*
740  * Function:    bePrintErrors
741  * Description: Convert Python args to boolean and call libbe_print_errors to
742  *			turn on/off error output for the library.
743  * Parameter:
744  *   args -     pointer to a python object containing:
745  *		print_errors - Boolean that turns library error
746  *			       printing on or off.
747  * Parameters:
748  *   args -     pointer to a python object containing:
749  *     0 - do not print errors - Python boolean "False"
750  *     1 - print errors - Python boolean "True"
751  *
752  * Returns 1 on missing or invalid argument, 0 otherwise
753  * Scope:
754  *      Public
755  */
756 /* ARGSUSED */
757 PyObject *
758 bePrintErrors(PyObject *self, PyObject *args)
759 {
760 	int		print_errors;
761 
762 	if (!PyArg_ParseTuple(args, "i", &print_errors) ||
763 	    (print_errors != 1 && print_errors != 0))
764 		return (Py_BuildValue("i", BE_PY_ERR_PRINT_ERR));
765 	libbe_print_errors(print_errors == 1);
766 	return (Py_BuildValue("i", BE_PY_SUCCESS));
767 }
768 
769 /*
770  * Function:    beGetErrDesc
771  * Description: Convert Python args to an int and call be_err_to_str to
772  *			map an error code to an error string.
773  * Parameter:
774  *   args -     pointer to a python object containing:
775  *		errCode - value to map to an error string.
776  *
777  * Returns: error string or NULL
778  * Scope:
779  *      Public
780  */
781 /* ARGSUSED */
782 PyObject *
783 beGetErrDesc(PyObject *self, PyObject *args)
784 {
785 	int	errCode = 0;
786 	char	*beErrStr = NULL;
787 
788 	if (!PyArg_ParseTuple(args, "i", &errCode)) {
789 		return (Py_BuildValue("s", NULL));
790 	}
791 
792 	/*
793 	 * First check libbe_py errors. If NULL is returned check error codes
794 	 * in libbe.
795 	 */
796 
797 	if ((beErrStr = beMapLibbePyErrorToString(errCode)) == NULL) {
798 		beErrStr = be_err_to_str(errCode);
799 	}
800 
801 	return (Py_BuildValue("s", beErrStr));
802 }
803 
804 /*
805  * Function:    beVerifyBEName
806  * Description: Call be_valid_be_name() to verify the BE name.
807  * Parameter:
808  *   args -     pointer to a python object containing:
809  *		string - value to map to a string.
810  *
811  * Returns:  0 for success or 1 for failure
812  * Scope:
813  *      Public
814  */
815 /* ARGSUSED */
816 PyObject *
817 beVerifyBEName(PyObject *self, PyObject *args)
818 {
819 	char	*string = NULL;
820 
821 	if (!PyArg_ParseTuple(args, "s", &string)) {
822 		return (Py_BuildValue("i", 1));
823 	}
824 
825 	if (be_valid_be_name(string)) {
826 		return (Py_BuildValue("i", 0));
827 	} else {
828 		return (Py_BuildValue("i", 1));
829 	}
830 }
831 
832 /* ~~~~~~~~~~~~~~~~~ */
833 /* Private Functions */
834 /* ~~~~~~~~~~~~~~~~~ */
835 
836 static boolean_t
837 convertBEInfoToDictionary(be_node_list_t *be, PyObject **listDict)
838 {
839 	if (be->be_node_name != NULL) {
840 		if (PyDict_SetItemString(*listDict, BE_ATTR_ORIG_BE_NAME,
841 		    PyUnicode_FromString(be->be_node_name)) != 0) {
842 			return (B_FALSE);
843 		}
844 	}
845 
846 	if (be->be_rpool != NULL) {
847 		if (PyDict_SetItemString(*listDict, BE_ATTR_ORIG_BE_POOL,
848 		    PyUnicode_FromString(be->be_rpool)) != 0) {
849 			return (B_FALSE);
850 		}
851 	}
852 
853 	if (be->be_mntpt != NULL) {
854 		if (PyDict_SetItemString(*listDict, BE_ATTR_MOUNTPOINT,
855 		    PyUnicode_FromString(be->be_mntpt)) != 0) {
856 			return (B_FALSE);
857 		}
858 	}
859 
860 	if (PyDict_SetItemString(*listDict, BE_ATTR_MOUNTED,
861 	    (be->be_mounted ? Py_True : Py_False)) != 0) {
862 		return (B_FALSE);
863 	}
864 
865 	if (PyDict_SetItemString(*listDict, BE_ATTR_ACTIVE,
866 	    (be->be_active ? Py_True : Py_False)) != 0) {
867 		return (B_FALSE);
868 	}
869 
870 	if (PyDict_SetItemString(*listDict, BE_ATTR_ACTIVE_ON_BOOT,
871 	    (be->be_active_on_boot ? Py_True : Py_False)) != 0) {
872 		return (B_FALSE);
873 	}
874 
875 	if (PyDict_SetItemString(*listDict, BE_ATTR_GLOBAL_ACTIVE,
876 	    (be->be_global_active ? Py_True : Py_False)) != 0) {
877 		return (B_FALSE);
878 	}
879 
880 	if (be->be_space_used != 0) {
881 		if (PyDict_SetItemString(*listDict, BE_ATTR_SPACE,
882 		    PyLong_FromUnsignedLongLong(be->be_space_used)) != 0) {
883 			return (B_FALSE);
884 		}
885 	}
886 
887 	if (be->be_root_ds != NULL) {
888 		if (PyDict_SetItemString(*listDict, BE_ATTR_ROOT_DS,
889 		    PyUnicode_FromString(be->be_root_ds)) != 0) {
890 			return (B_FALSE);
891 		}
892 	}
893 
894 	if (be->be_node_creation != 0) {
895 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATE,
896 		    PyLong_FromLong(be->be_node_creation)) != 0) {
897 			return (B_FALSE);
898 		}
899 	}
900 
901 	if (be->be_policy_type != NULL) {
902 		if (PyDict_SetItemString(*listDict, BE_ATTR_POLICY,
903 		    PyUnicode_FromString(be->be_policy_type)) != 0) {
904 			return (B_FALSE);
905 		}
906 	}
907 
908 	if (be->be_uuid_str != NULL) {
909 		if (PyDict_SetItemString(*listDict, BE_ATTR_UUID_STR,
910 		    PyUnicode_FromString(be->be_uuid_str)) != 0) {
911 			return (B_FALSE);
912 		}
913 	}
914 
915 	return (B_TRUE);
916 }
917 
918 static boolean_t
919 convertDatasetInfoToDictionary(be_dataset_list_t *ds, PyObject **listDict)
920 {
921 	if (ds->be_dataset_name != NULL) {
922 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATASET,
923 		    PyUnicode_FromString(ds->be_dataset_name)) != 0) {
924 			return (B_FALSE);
925 		}
926 	}
927 
928 	if (PyDict_SetItemString(*listDict, BE_ATTR_STATUS,
929 	    (ds->be_ds_mounted ? Py_True : Py_False)) != 0) {
930 			return (B_FALSE);
931 	}
932 
933 	if (ds->be_ds_mntpt != NULL) {
934 		if (PyDict_SetItemString(*listDict, BE_ATTR_MOUNTPOINT,
935 		    PyUnicode_FromString(ds->be_ds_mntpt)) != 0) {
936 			return (B_FALSE);
937 		}
938 	}
939 
940 	if (PyDict_SetItemString(*listDict, BE_ATTR_MOUNTED,
941 	    (ds->be_ds_mounted ? Py_True : Py_False)) != 0) {
942 		return (B_FALSE);
943 	}
944 
945 	if (ds->be_ds_space_used != 0) {
946 		if (PyDict_SetItemString(*listDict, BE_ATTR_SPACE,
947 		    PyLong_FromUnsignedLongLong(ds->be_ds_space_used))
948 		    != 0) {
949 			return (B_FALSE);
950 		}
951 	}
952 
953 	if (ds->be_dataset_name != 0) {
954 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATASET,
955 		    PyUnicode_FromString(ds->be_dataset_name)) != 0) {
956 			return (B_FALSE);
957 		}
958 	}
959 
960 	if (ds->be_ds_plcy_type != NULL) {
961 		if (PyDict_SetItemString(*listDict, BE_ATTR_POLICY,
962 		    PyUnicode_FromString(ds->be_ds_plcy_type)) != 0) {
963 			return (B_FALSE);
964 		}
965 	}
966 
967 	if (ds->be_ds_creation != 0) {
968 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATE,
969 		    PyLong_FromLong(ds->be_ds_creation)) != 0) {
970 			return (B_FALSE);
971 		}
972 	}
973 
974 	return (B_TRUE);
975 }
976 
977 static boolean_t
978 convertSnapshotInfoToDictionary(be_snapshot_list_t *ss, PyObject **listDict)
979 {
980 	if (ss->be_snapshot_name != NULL) {
981 		if (PyDict_SetItemString(*listDict, BE_ATTR_SNAP_NAME,
982 		    PyUnicode_FromString(ss->be_snapshot_name)) != 0) {
983 			return (B_FALSE);
984 		}
985 	}
986 
987 	if (ss->be_snapshot_creation != 0) {
988 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATE,
989 		    PyLong_FromLong(ss->be_snapshot_creation)) != 0) {
990 			return (B_FALSE);
991 		}
992 	}
993 
994 	if (ss->be_snapshot_type != NULL) {
995 		if (PyDict_SetItemString(*listDict, BE_ATTR_POLICY,
996 		    PyUnicode_FromString(ss->be_snapshot_type)) != 0) {
997 			return (B_FALSE);
998 		}
999 	}
1000 
1001 	if (ss->be_snapshot_space_used != 0) {
1002 		if (PyDict_SetItemString(*listDict, BE_ATTR_SPACE,
1003 		    PyLong_FromUnsignedLongLong(ss->be_snapshot_space_used))
1004 		    != 0) {
1005 			return (B_FALSE);
1006 		}
1007 	}
1008 
1009 	return (B_TRUE);
1010 }
1011 
1012 /*
1013  * Convert string arguments to nvlist attributes
1014  */
1015 
1016 static boolean_t
1017 convertPyArgsToNvlist(nvlist_t **nvList, int numArgs, ...)
1018 {
1019 	char *pt, *pt2;
1020 	va_list ap;
1021 	int i;
1022 
1023 	if (*nvList == NULL) {
1024 		if (nvlist_alloc(nvList, NV_UNIQUE_NAME, 0) != 0) {
1025 			(void) printf("nvlist_alloc failed.\n");
1026 			return (B_FALSE);
1027 		}
1028 	}
1029 
1030 	va_start(ap, numArgs);
1031 
1032 	for (i = 0; i < numArgs; i += 2) {
1033 		if ((pt = va_arg(ap, char *)) == NULL ||
1034 		    (pt2 = va_arg(ap, char *)) == NULL) {
1035 			continue;
1036 		}
1037 		if (nvlist_add_string(*nvList, pt, pt2) != 0) {
1038 			(void) printf("nvlist_add_string failed for %s (%s).\n",
1039 			    pt, pt2);
1040 			nvlist_free(*nvList);
1041 			return (B_FALSE);
1042 		}
1043 	}
1044 
1045 	va_end(ap);
1046 
1047 	return (B_TRUE);
1048 }
1049 
1050 /*
1051  * Function:    beMapLibbePyErrorToString
1052  * Description: Convert Python args to an int and map an error code to an
1053  *			error string.
1054  * Parameter:
1055  *		errCode - value to map to an error string.
1056  *
1057  * Returns error string or NULL
1058  * Scope:
1059  *      Public
1060  */
1061 
1062 char *
1063 beMapLibbePyErrorToString(int errCode)
1064 {
1065 	switch (errCode) {
1066 	case BE_PY_ERR_APPEND:
1067 		return ("Unable to append a dictionary to a list "
1068 		    "of dictionaries.");
1069 	case BE_PY_ERR_DICT:
1070 		return ("Creation of a Python dictionary failed.");
1071 	case BE_PY_ERR_LIST:
1072 		return ("beList() failed.");
1073 	case BE_PY_ERR_NVLIST:
1074 		return ("An nvlist operation failed.");
1075 	case BE_PY_ERR_PARSETUPLE:
1076 		return ("PyArg_ParseTuple() failed to convert variable to C.");
1077 	case BE_PY_ERR_PRINT_ERR:
1078 		return ("bePrintErrors() failed.");
1079 	case BE_PY_ERR_VAR_CONV:
1080 		return ("Unable to add variables to a Python dictionary.");
1081 	default:
1082 		return (NULL);
1083 	}
1084 }
1085 
1086 /* Private python initialization structure */
1087 
1088 static struct PyMethodDef libbeMethods[] = {
1089 	{"beCopy", beCopy, METH_VARARGS, "Create/Copy a BE."},
1090 	{"beCreateSnapshot", beCreateSnapshot, METH_VARARGS,
1091 	    "Create a snapshot."},
1092 	{"beDestroy", beDestroy, METH_VARARGS, "Destroy a BE."},
1093 	{"beDestroySnapshot", beDestroySnapshot, METH_VARARGS,
1094 	    "Destroy a snapshot."},
1095 	{"beMount", beMount, METH_VARARGS, "Mount a BE."},
1096 	{"beUnmount", beUnmount, METH_VARARGS, "Unmount a BE."},
1097 	{"beList", (PyCFunction)(uintptr_t)beList, METH_VARARGS | METH_KEYWORDS,
1098 	    "List BE info."},
1099 	{"beRename", beRename, METH_VARARGS, "Rename a BE."},
1100 	{"beActivate", beActivate, METH_VARARGS, "Activate a BE."},
1101 	{"beRollback", beRollback, METH_VARARGS, "Rollback a BE."},
1102 	{"bePrintErrors", bePrintErrors, METH_VARARGS,
1103 	    "Enable/disable error printing."},
1104 	{"beGetErrDesc", beGetErrDesc, METH_VARARGS,
1105 	    "Map Error codes to strings."},
1106 	{"beVerifyBEName", beVerifyBEName, METH_VARARGS,
1107 	    "Verify BE name."},
1108 	{NULL, NULL, 0, NULL}
1109 };
1110 
1111 #if PY_MAJOR_VERSION >= 3
1112 static struct PyModuleDef libbe_module = {
1113 	PyModuleDef_HEAD_INIT,
1114 	"libbe_py",
1115 	NULL,
1116 	-1,
1117 	libbeMethods
1118 };
1119 #endif
1120 
1121 static PyObject *
1122 moduleinit()
1123 {
1124 	/* PyMODINIT_FUNC; */
1125 #if PY_MAJOR_VERSION >= 3
1126 	return (PyModule_Create(&libbe_module));
1127 #else
1128 	/*
1129 	 * Python2 module initialisation functions are void and may not return
1130 	 * a value. However, they will set an exception if appropriate.
1131 	 */
1132 	(void) Py_InitModule("libbe_py", libbeMethods);
1133 	return (NULL);
1134 #endif
1135 }
1136 
1137 #if PY_MAJOR_VERSION >= 3
1138 PyMODINIT_FUNC
1139 PyInit_libbe_py(void)
1140 {
1141 	return (moduleinit());
1142 }
1143 #else
1144 PyMODINIT_FUNC
1145 initlibbe_py(void)
1146 {
1147 	(void) moduleinit();
1148 }
1149 #endif
1150