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