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