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