xref: /illumos-gate/usr/src/lib/pylibbe/common/libbe_py.c (revision 621be8d08fd45483b5ca1cb8e2e88239f1502b4d)
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 	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 (PyDict_SetItemString(*listDict, BE_ATTR_GLOBAL_ACTIVE,
861 	    (be->be_global_active ? Py_True : Py_False)) != 0) {
862 		return (B_FALSE);
863 	}
864 
865 	if (be->be_space_used != 0) {
866 		if (PyDict_SetItemString(*listDict, BE_ATTR_SPACE,
867 		    PyLong_FromUnsignedLongLong(be->be_space_used)) != 0) {
868 			return (B_FALSE);
869 		}
870 	}
871 
872 	if (be->be_root_ds != NULL) {
873 		if (PyDict_SetItemString(*listDict, BE_ATTR_ROOT_DS,
874 		    PyString_FromString(be->be_root_ds)) != 0) {
875 			return (B_FALSE);
876 		}
877 	}
878 
879 	if (be->be_node_creation != NULL) {
880 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATE,
881 		    PyLong_FromLong(be->be_node_creation)) != 0) {
882 			return (B_FALSE);
883 		}
884 	}
885 
886 	if (be->be_policy_type != NULL) {
887 		if (PyDict_SetItemString(*listDict, BE_ATTR_POLICY,
888 		    PyString_FromString(be->be_policy_type)) != 0) {
889 			return (B_FALSE);
890 		}
891 	}
892 
893 	if (be->be_uuid_str != NULL) {
894 		if (PyDict_SetItemString(*listDict, BE_ATTR_UUID_STR,
895 		    PyString_FromString(be->be_uuid_str)) != 0) {
896 			return (B_FALSE);
897 		}
898 	}
899 
900 	return (B_TRUE);
901 }
902 
903 static boolean_t
904 convertDatasetInfoToDictionary(be_dataset_list_t *ds, PyObject **listDict)
905 {
906 	if (ds->be_dataset_name != NULL) {
907 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATASET,
908 		    PyString_FromString(ds->be_dataset_name)) != 0) {
909 			return (B_FALSE);
910 		}
911 	}
912 
913 	if (PyDict_SetItemString(*listDict, BE_ATTR_STATUS,
914 	    (ds->be_ds_mounted ? Py_True : Py_False)) != 0) {
915 			return (B_FALSE);
916 	}
917 
918 	if (ds->be_ds_mntpt != NULL) {
919 		if (PyDict_SetItemString(*listDict, BE_ATTR_MOUNTPOINT,
920 		    PyString_FromString(ds->be_ds_mntpt)) != 0) {
921 			return (B_FALSE);
922 		}
923 	}
924 
925 	if (PyDict_SetItemString(*listDict, BE_ATTR_MOUNTED,
926 	    (ds->be_ds_mounted ? Py_True : Py_False)) != 0) {
927 		return (B_FALSE);
928 	}
929 
930 	if (ds->be_ds_space_used != 0) {
931 		if (PyDict_SetItemString(*listDict, BE_ATTR_SPACE,
932 		    PyLong_FromUnsignedLongLong(ds->be_ds_space_used))
933 		    != 0) {
934 			return (B_FALSE);
935 		}
936 	}
937 
938 	if (ds->be_dataset_name != 0) {
939 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATASET,
940 		    PyString_FromString(ds->be_dataset_name)) != 0) {
941 			return (B_FALSE);
942 		}
943 	}
944 
945 	if (ds->be_ds_plcy_type != NULL) {
946 		if (PyDict_SetItemString(*listDict, BE_ATTR_POLICY,
947 		    PyString_FromString(ds->be_ds_plcy_type)) != 0) {
948 			return (B_FALSE);
949 		}
950 	}
951 
952 	if (ds->be_ds_creation != NULL) {
953 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATE,
954 		    PyLong_FromLong(ds->be_ds_creation)) != 0) {
955 			return (B_FALSE);
956 		}
957 	}
958 
959 	return (B_TRUE);
960 }
961 
962 static boolean_t
963 convertSnapshotInfoToDictionary(be_snapshot_list_t *ss, PyObject **listDict)
964 {
965 	if (ss->be_snapshot_name != NULL) {
966 		if (PyDict_SetItemString(*listDict, BE_ATTR_SNAP_NAME,
967 		    PyString_FromString(ss->be_snapshot_name)) != 0) {
968 			return (B_FALSE);
969 		}
970 	}
971 
972 	if (ss->be_snapshot_creation != NULL) {
973 		if (PyDict_SetItemString(*listDict, BE_ATTR_DATE,
974 		    PyLong_FromLong(ss->be_snapshot_creation)) != 0) {
975 			return (B_FALSE);
976 		}
977 	}
978 
979 	if (ss->be_snapshot_type != NULL) {
980 		if (PyDict_SetItemString(*listDict, BE_ATTR_POLICY,
981 		    PyString_FromString(ss->be_snapshot_type)) != 0) {
982 			return (B_FALSE);
983 		}
984 	}
985 
986 	if (ss->be_snapshot_space_used != 0) {
987 		if (PyDict_SetItemString(*listDict, BE_ATTR_SPACE,
988 		    PyLong_FromUnsignedLongLong(ss->be_snapshot_space_used))
989 		    != 0) {
990 			return (B_FALSE);
991 		}
992 	}
993 
994 	return (B_TRUE);
995 }
996 
997 /*
998  * Convert string arguments to nvlist attributes
999  */
1000 
1001 static boolean_t
1002 convertPyArgsToNvlist(nvlist_t **nvList, int numArgs, ...)
1003 {
1004 	char *pt, *pt2;
1005 	va_list ap;
1006 	int i;
1007 
1008 	if (*nvList == NULL) {
1009 		if (nvlist_alloc(nvList, NV_UNIQUE_NAME, 0) != 0) {
1010 			(void) printf("nvlist_alloc failed.\n");
1011 			return (B_FALSE);
1012 		}
1013 	}
1014 
1015 	va_start(ap, numArgs);
1016 
1017 	for (i = 0; i < numArgs; i += 2) {
1018 		if ((pt = va_arg(ap, char *)) == NULL ||
1019 		    (pt2 = va_arg(ap, char *)) == NULL) {
1020 			continue;
1021 		}
1022 		if (nvlist_add_string(*nvList, pt, pt2) != 0) {
1023 			(void) printf("nvlist_add_string failed for %s (%s).\n",
1024 			    pt, pt2);
1025 			nvlist_free(*nvList);
1026 			return (B_FALSE);
1027 		}
1028 	}
1029 
1030 	va_end(ap);
1031 
1032 	return (B_TRUE);
1033 }
1034 
1035 /*
1036  * Function:    beMapLibbePyErrorToString
1037  * Description: Convert Python args to an int and map an error code to an
1038  *			error string.
1039  * Parameter:
1040  *		errCode - value to map to an error string.
1041  *
1042  * Returns error string or NULL
1043  * Scope:
1044  *      Public
1045  */
1046 
1047 char *
1048 beMapLibbePyErrorToString(int errCode)
1049 {
1050 	switch (errCode) {
1051 	case BE_PY_ERR_APPEND:
1052 		return ("Unable to append a dictionary to a list "
1053 		    "of dictinaries.");
1054 	case BE_PY_ERR_DICT:
1055 		return ("Creation of a Python dictionary failed.");
1056 	case BE_PY_ERR_LIST:
1057 		return ("beList() failed.");
1058 	case BE_PY_ERR_NVLIST:
1059 		return ("An nvlist operation failed.");
1060 	case BE_PY_ERR_PARSETUPLE:
1061 		return ("PyArg_ParseTuple() failed to convert variable to C.");
1062 	case BE_PY_ERR_PRINT_ERR:
1063 		return ("bePrintErrors() failed.");
1064 	case BE_PY_ERR_VAR_CONV:
1065 		return ("Unable to add variables to a Python dictionary.");
1066 	default:
1067 		return (NULL);
1068 	}
1069 }
1070 
1071 /* Private python initialization structure */
1072 
1073 static struct PyMethodDef libbeMethods[] = {
1074 	{"beCopy", (PyCFunction)beCopy, METH_VARARGS, "Create/Copy a BE."},
1075 	{"beCreateSnapshot", (PyCFunction)beCreateSnapshot, METH_VARARGS,
1076 	    "Create a snapshot."},
1077 	{"beDestroy", (PyCFunction)beDestroy, METH_VARARGS, "Destroy a BE."},
1078 	{"beDestroySnapshot", (PyCFunction)beDestroySnapshot, METH_VARARGS,
1079 	    "Destroy a snapshot."},
1080 	{"beMount", (PyCFunction)beMount, METH_VARARGS, "Mount a BE."},
1081 	{"beUnmount", (PyCFunction)beUnmount, METH_VARARGS, "Unmount a BE."},
1082 	{"beList", (PyCFunction)beList, METH_VARARGS, "List BE info."},
1083 	{"beRename", (PyCFunction)beRename, METH_VARARGS, "Rename a BE."},
1084 	{"beActivate", (PyCFunction)beActivate, METH_VARARGS, "Activate a BE."},
1085 	{"beRollback", (PyCFunction)beRollback, METH_VARARGS, "Rollback a BE."},
1086 	{"bePrintErrors", (PyCFunction)bePrintErrors, METH_VARARGS,
1087 	    "Enable/disable error printing."},
1088 	{"beGetErrDesc", (PyCFunction)beGetErrDesc, METH_VARARGS,
1089 	    "Map Error codes to strings."},
1090 	{"beVerifyBEName", (PyCFunction)beVerifyBEName, METH_VARARGS,
1091 	    "Verify BE name."},
1092 	{NULL, NULL, 0, NULL}
1093 };
1094 
1095 void
1096 initlibbe_py()
1097 {
1098 	/* PyMODINIT_FUNC; */
1099 	(void) Py_InitModule("libbe_py", libbeMethods);
1100 }
1101