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