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