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