Current File : //sbin/beadm
#!/usr/bin/python2.7 -E

#
# Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
#

"""
beadm - The Boot Environment Administration tool. Use this CLI to
manage boot environments.
"""

import getopt
import gettext
import os
import sys
import shutil
import traceback
import time
import subprocess
import errno

from beadm import _
from beadm.BootEnvironment import *
import solaris.zones as zones
import beadm.messages as msg
import libbe as lb


def usage():
    '''Defines parameters and options of the command beadm.'''
    print >> sys.stderr, _("""
Usage:
    beadm subcommand cmd_options

    subcommands:

    beadm activate beName
    beadm create [-a] [-d description]
        [-e non-activeBeName | beName@snapshot]
        [-o property=value] ... [-p zpool] beName
    beadm create beName@snapshot
    beadm destroy [-fF] beName | beName@snapshot
    beadm destroy [-fF] -O
    beadm list [[-a] | [-d] [-s]] [-H] [beName]
    beadm mount [-b] beName mountpoint
    beadm rename beName newBeName
    beadm set-policy {-n policy [-n -policy2] ...} beName [beName2 ...]
    beadm unmount [-f] beName""")
    sys.exit(1)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Public Command Line functions described in beadm(1)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


def activate(opts):
    """
    Function:    activate

            Description: Activate a Boot Environment.The following is the
                         subcommand, options and args that make up the
                         opts object passed in:

            Parameters:
                opts - A string containing the active subcommand

            Returns:
                0 - Success
                1 - Failure
    """

    if len(opts) != 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    priv_check()

    be = BootEnvironment()

    if lb.beVerifyBEName(opts[0]) != 0:
        msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
        return 1

    rc = lb.beActivate(opts[0])
    if rc == 0:
        return 0

    be.msg_buf["0"] = opts[0]
    if rc == msg.Msgs.BE_ERR_BE_NOENT:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST, opts[0])
    elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
        msg.printMsg(msg.Msgs.BEADM_ERR_ACTIVATE, be.msg_buf, -1)
        return 1
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_ACTIVATE, be.msg_buf, -1)
    return 1


def create(opts):
    """
    Function:    create

            Description: Create a Boot Environment. The following is the
                         subcommand, options and args that make up the
                         opts object passed in:

                         create [-a] [-d description]
                            [-e non-activeBeName | beName@Snapshot]
                            [-o property=value] ... [-p zpool] beName

                         create beName@Snapshot

            Parameters:
                opts - A object containing the create subcommand
                       and all the options and arguments passed in
                       on the command line mentioned above.

            Returns:
                0 - Success
                1 - Failure
    """

    priv_check()

    be = BootEnvironment()

    activate = False

    try:
        opts_args, be.trgt_be_name_or_snapshot = getopt.getopt(opts,
            "ad:e:o:p:")
    except getopt.GetoptError:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    # Counters for detecting multiple options.
    # e.g. beadm create -p rpool -p rpool2 newbe
    num_a_opts = 0
    num_e_opts = 0
    num_p_opts = 0
    num_d_opts = 0

    for opt, arg in opts_args:
        if opt == "-a":
            activate = True
            num_a_opts += 1
        elif opt == "-e":
            be.src_be_name_or_snapshot = arg
            num_e_opts += 1
        elif opt == "-o":
            key, value = arg.split("=")
            be.properties[key] = value
        elif opt == "-p":
            be.trgt_rpool = arg
            num_p_opts += 1
        elif opt == "-d":
            be.description = arg
            num_d_opts += 1

    if num_a_opts > 1 or num_e_opts > 1 or num_p_opts > 1 or num_d_opts > 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    # Check that all info provided from the user is legitimate.
    if (verifyCreateOptionsArgs(be) != 0):
        usage()

    if initBELog("create", be) != 0:
        return 1

    msg.printMsg(msg.Msgs.BEADM_MSG_BE_CREATE_START,
        be.trgt_be_name_or_snapshot[0], be.log_id)

    if '@' in be.trgt_be_name_or_snapshot[0]:
        # Create a snapshot
        rc = createSnapshot(be)
    else:
        if lb.beVerifyBEName(be.trgt_be_name_or_snapshot[0]) != 0:
            msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
            return 1

        # Create a BE based on a snapshot
        if be.src_be_name_or_snapshot is not None and \
            '@' in be.src_be_name_or_snapshot:
            # Create a BE from a snapshot
            rc = createBEFromSnapshot(be)
        else:
            rc = createBE(be)

        # Activate the BE if the user chose to.
        if activate and rc == 0:
            rc = activateBE(be)
    cleanupBELog(be)

    return rc

def destroy_be(be, be_name, snap_name, be_active, be_active_on_boot,
    is_snapshot, suppress_prompt, force_unmount):

    # If the user is trying to destroy the 'active' BE then quit now.
    if not is_snapshot and be_active == be_name:
        be.msg_buf["0"] = be.msg_buf["1"] = be_active
        msg.printMsg(msg.Msgs.BEADM_ERR_DESTROY_ACTIVE, be.msg_buf, -1)
        return 1

    if not suppress_prompt:
        # Display a destruction question and wait for user response.
        # Quit if negative user response.
        if not displayDestructionQuestion(be):
            return 0

    if is_snapshot:
        # Destroy a snapshot.
        rc = lb.beDestroySnapshot(be_name, snap_name)
    else:
        # Destroy a BE.  Passing in 1 for the second arg destroys
        # any snapshots the BE may have as well.
        rc = lb.beDestroy(be_name, 1, force_unmount)

        # Check if the BE that was just destroyed was the
        # 'active on boot' BE. If it was, display a message letting
        # the user know that the 'active' BE is now also the
        # 'active on boot' BE.
        if be_active_on_boot == be_name and rc == 0:
            msg.printMsg(msg.Msgs.BEADM_MSG_ACTIVE_ON_BOOT,
            be_active, -1)

    if rc == 0:
        try:
            shutil.rmtree("/var/log/beadm/" + \
                          be.trgt_be_name_or_snapshot[0], True)
        except:
            msg.printMsg(msg.Msgs.BEADM_ERR_LOG_RM,
                         "/var/log/beadm/" + be.trgt_be_name_or_snapshot[0],
                         -1)

        return 0

    be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
    if rc == msg.Msgs.BE_ERR_MOUNTED:
        be.msg_buf["1"] = be.msg_buf["2"] = be.trgt_be_name_or_snapshot[0]
        msg.printMsg(msg.Msgs.BEADM_ERR_MOUNTED, be.msg_buf, -1)
        return 1
    elif rc == msg.Msgs.BE_ERR_DESTROY_CURR_BE:
        msg.printMsg(msg.Msgs.BEADM_ERR_DESTROY_ACTIVE, \
        be.msg_buf["0"], -1)
        return 1
    elif rc == msg.Msgs.BE_ERR_ZONES_UNMOUNT:
        be.msg_buf["1"] = be.trgt_be_name_or_snapshot[0]
        msg.printMsg(msg.Msgs.BE_ERR_ZONES_UNMOUNT, be.msg_buf, -1)
        return 1
    elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
        msg.printMsg(msg.Msgs.BEADM_ERR_DESTROY, be.msg_buf, -1)
        return 1
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_DESTROY, be.msg_buf, -1)
    return 1

def destroy(opts):
    """
    Function:    destroy

            Description: Destroy a Boot Environment. The following is the
                         subcommand, options and args that make up the
                         opts object passed in:

                         destroy [-fF] beName | beName@snapshot
                             destroy the boot environment or boot
                             environment snapshot

                         destroy [-fF] -O
                             destroy all orphan boot environments

            Parameters:
                opts - A object containing the destroy subcommand
                       and all the options and arguments passed in
                       on the command line mentioned above.

            Returns:
                0 - Success
                1 - Failure
    """

    priv_check()

    force_unmount = 0
    suppress_prompt = False
    be_active_on_boot = None
    destroy_orphans = False
    be = BootEnvironment()

    try:
        opts_args, be.trgt_be_name_or_snapshot = getopt.getopt(opts, "fFO")
    except getopt.GetoptError:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    # Counters for detecting multiple options.
    # e.g. beadm destroy -f -f newbe
    num_f_opts = 0
    num_sf_opts = 0
    num_o_opts = 0

    for opt, arg in opts_args:
        if opt == "-f":
            force_unmount = 1
            num_sf_opts += 1
        elif opt == "-F":
            suppress_prompt = True
            num_f_opts += 1
        elif opt == "-O":
            destroy_orphans = True
            num_o_opts += 1

    if num_sf_opts > 1 or num_f_opts > 1 or num_o_opts > 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    # Check if invocation has correct arguments
    if (((not destroy_orphans) and len(be.trgt_be_name_or_snapshot) != 1) or
        (destroy_orphans and len(be.trgt_be_name_or_snapshot) != 0)):
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    is_snapshot = False

    if destroy_orphans:
        # Fail if we are in global zone.
        if zones.getzoneid() == 0:
            msg.printMsg(msg.Msgs.BEADM_ERR_ZONE_NOTSUP, 'global', -1)
            return 1

        # Get list of Boot Environments.
        rc, be_list = lb.beList()
        if rc != 0:
            string = lb.beGetErrDesc(rc)
            if string is None:
                string = msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)
        
            msg.printMsg(msg.Msgs.BEADM_ERR_LIST, string, -1)
            return 1

        # Scroll over list of all boot environments.
        error_seen = 0
        for be_entry in be_list:
            # Check if BE is orphan.
            if 'orphan' in be_entry and be_entry['orphan']:
                is_active = None
                is_be_active_on_boot = None

                # Get BE properties.
                be_name = be_entry.get("orig_be_name")
                if be_entry.get("active"):
                    is_active = be_name
                if be_entry.get("active_boot"):
                    is_be_active_on_boot = be_name

                # Set the target BE name to destroy.
                be.trgt_be_name_or_snapshot = [be_name]

                # If we fail for any BE, set error_seen and continue
                # to destroy other orphan zone BEs.
                if (destroy_be(be, be_name, None, is_active, \
                    is_be_active_on_boot, False, suppress_prompt, \
                    force_unmount) != 0):
                    error_seen = 1

        return error_seen
    
    if "@" in be.trgt_be_name_or_snapshot[0]:
        is_snapshot = True
        try:
            be_name, snap_name = be.trgt_be_name_or_snapshot[0].split("@")
        except ValueError:
            msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
            return 1 
    else:
        be_name = be.trgt_be_name_or_snapshot[0]
        snap_name = None

    if lb.beVerifyBEName(be_name) != 0:
        msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
        return 1

    # Check to see if the BE or BE snapshot the user supplied actually exists.
    rc, be_list = lb.beList(be_name)
    if rc != 0:
        if rc == msg.Msgs.BE_ERR_BE_NOENT:
            if is_snapshot:
                msg.printMsg(msg.Msgs.BEADM_ERR_SNAP_DOES_NOT_EXISTS,
                             be_name, -1)
            else:
                msg.printMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST, be_name, -1)
            return 1
        else:
            string = lb.beGetErrDesc(rc)

            if string is None:
                string = msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

            msg.printMsg(msg.Msgs.BEADM_ERR_LIST, string, -1)
            return 1

    if is_snapshot:
        for be_entry in be_list:
            if be_entry.get("snap_name") == be.trgt_be_name_or_snapshot[0]:
                break
        else:
            msg.printMsg(msg.Msgs.BEADM_ERR_SNAP_DOES_NOT_EXISTS,
                         be.trgt_be_name_or_snapshot[0], -1)
            return 1

    be_active, be_active_on_boot = getActiveBEAndActiveOnBootBE()

    return (destroy_be(be, be_name, snap_name, be_active, be_active_on_boot,
        is_snapshot, suppress_prompt, force_unmount))

def list(opts):
    """
            Description: List the attributes of a Boot Environment.
                         The following is the subcommand, options
                         and args that make up the opts object
                         passed in:

                         list [[-a] | [-d] [-s]] [-H] [beName]

                         -a displays all info
                         -d displays BE info plus dataset info
                         -s displays BE info plus snapshot info
                         -H displays info parsable by a computer

            Parameters:
                opts - A object containing the list subcommand
                       and all the options and arguments passed in
                       on the command line mentioned above.

            Returns:
                0 - Success
                1 - Failure
    """

    be = BootEnvironment()

    list_all_attrs = ""
    list_datasets = ""
    list_snapshots = ""
    dont_display_headers = False
    be_name = None
    be_list = None

    # Counters for detecting multiple options.
    # e.g. beadm list -a -a newbe
    num_a_opts = 0
    num_d_opts = 0
    num_s_opts = 0
    num_h_opts = 0

    try:
        opts_args, be.trgt_be_name_or_snapshot = getopt.getopt(opts, "adHs")
    except getopt.GetoptError:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    for opt, arg in opts_args:
        if opt == "-a":
            list_all_attrs = opt
            num_a_opts += 1
        elif opt == "-d":
            list_datasets = opt
            num_d_opts += 1
        elif opt == "-s":
            list_snapshots = opt
            num_s_opts += 1
        elif opt == "-H":
            dont_display_headers = True
            num_h_opts += 1

    if num_a_opts > 1 or num_d_opts > 1 or num_s_opts > 1 or num_h_opts > 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    if len(be.trgt_be_name_or_snapshot) > 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    if len(be.trgt_be_name_or_snapshot) == 1:
        be_name = be.trgt_be_name_or_snapshot[0]
        if lb.beVerifyBEName(be_name) != 0:
            msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
            return 1

    if (list_all_attrs == "-a" and (list_datasets == "-d" \
        or list_snapshots == "-s")):
        msg.printMsg(msg.Msgs.BEADM_ERR_MUTUALLY_EXCL,
            list_all_attrs + " " + list_datasets + " " +
            list_snapshots, -1)
        usage()

    list_options = ""

    # When zones are implemented add "listZones == "-z" below

    # Coalesce options to pass to display BEs.

    if (list_datasets == "-d" and list_snapshots == "-s" or \
        list_all_attrs == "-a"):
        list_options = "-a"
    elif list_datasets != "" or list_snapshots != "" or list_all_attrs != "":
        list_options = list_datasets + " " + list_snapshots

    rc, be_list = lb.beList()
    if rc != 0:
        if rc == msg.Msgs.BE_ERR_BE_NOENT:
            if be_name == None:
                msg.printMsg(msg.Msgs.BEADM_ERR_NO_BES_EXIST,
                None, -1)
                return 1

            string = \
                msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
                be_name)
        else:
            string = lb.beGetErrDesc(rc)
            if string == None:
                string = \
                    msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

        msg.printMsg(msg.Msgs.BEADM_ERR_LIST, string, -1)
        return 1

    # classify according to command line options
    if list_options.find("-a") != -1 or \
        (list_options.find("-d") != -1 and list_options.find("-s") != -1):
        list_object = CompleteList(dont_display_headers) #all
    elif list_options.find("-d") != -1:
        list_object = DatasetList(dont_display_headers) #dataset
    elif list_options.find("-s") != -1:
        list_object = SnapshotList(dont_display_headers) #snapshot
    else:
        list_object = BEList(dont_display_headers) #only BE

    # use list method for object
    if list_object.list(be_list, dont_display_headers, be_name) != 0:
        msg.printMsg(msg.Msgs.BEADM_ERR_LIST_DATA, None, -1)
        return 1

    return 0


def mount(opts):
    """
            Description: Mount a Boot Environment on a directory.
                         The following is the subcommand, options
                         and args that make up the opts object
                         passed in:

                         mount [-b] beName [mountpoint]

            Parameters:
                opts - A object containing the mount subcommand
                       and all the options and arguments passed in
                       on the command line mentioned above.

            Returns:
                0 - Success
                1 - Failure
    """

    priv_check()

    be = BootEnvironment()

    mountpoint = None
    b_flag = False

    try:
        optlist, be_name_mnt_point = getopt.getopt(opts, "b")
        for opt, arg in optlist:
            if opt == "-b":
                b_flag = True
    except getopt.GetoptError:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    mnt_point_len = len(be_name_mnt_point)

    if mnt_point_len != 2:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()
    else:
        # Check for leading / in mount point
        mountpoint = be_name_mnt_point[1]
        if not mountpoint.startswith('/'):
            msg.printMsg(msg.Msgs.BEADM_ERR_MOUNTPOINT,
                mountpoint, -1)
            return 1

    if lb.beVerifyBEName(be_name_mnt_point[0]) != 0:
        msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
        return 1

    rc = lb.beMount(be_name_mnt_point[0], mountpoint, b_flag)
    if rc == 0:
        return 0

    be.msg_buf["0"] = be_name_mnt_point[0]
    if rc == msg.Msgs.BE_ERR_MOUNTED:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_MOUNT_EXISTS,
            be_name_mnt_point[0])
    elif rc == msg.Msgs.BE_ERR_BE_NOENT:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
            be_name_mnt_point[0])
    elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
        msg.printMsg(msg.Msgs.BEADM_ERR_MOUNT, be.msg_buf, -1)
        return 1
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_MOUNT, be.msg_buf, -1)
    return 1


def unmount(opts):
    """
            Description: Unmount a Boot Environment.
                         The following is the subcommand, options
                         and args that make up the opts object
                         passed in:

                         unmount [-f] beName

            Parameters:
                opts - A object containing the unmount subcommand
                       and all the options and arguments passed in
                       on the command line mentioned above.

            Returns:
                0 - Success
                1 - Failure
    """

    priv_check()

    be = BootEnvironment()

    force_unmount = 0

    # Counter for detecting multiple options.
    # e.g. beadm unmount -f -f newbe
    num_f_opts = 0

    try:
        optlist, args = getopt.getopt(opts, "f")
    except getopt.GetoptError:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    for opt, arg in optlist:
        if opt == "-f":
            force_unmount = 1
            num_f_opts += 1

    if num_f_opts > 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    if len(args) != 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    if lb.beVerifyBEName(args[0]) != 0:
        msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
        return 1

    rc = lb.beUnmount(args[0], force_unmount)
    if rc == 0:
        return 0

    be.msg_buf["0"] = args[0]
    if rc == msg.Msgs.BE_ERR_UMOUNT_CURR_BE:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_UNMOUNT_ACTIVE,
            args[0])
    elif rc == msg.Msgs.BE_ERR_UMOUNT_SHARED:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_SHARED_FS, args[0])
    elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
        msg.printMsg(msg.Msgs.BEADM_ERR_UNMOUNT, be.msg_buf, -1)
        return 1
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_UNMOUNT, be.msg_buf, -1)
    return 1


def rename(opts):
    """
            Description: Rename the name of a Boot Environment.
                         The following is the subcommand, options
                         and args that make up the opts object
                         passed in:

                         rename beName newBeName

            Parameters:
                opts - A object containing the mount subcommand
                       and all the options and arguments passed in
                       on the command line mentioned above.

            Returns:
                0 - Success
                1 - Failure
    """

    priv_check()

    be = BootEnvironment()

    try:
        be_names = getopt.getopt(opts, "")[1]
    except getopt.GetoptError:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    if len(be_names) != 2:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    if lb.beVerifyBEName(be_names[0]) != 0:
        msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
        return 1

    if lb.beVerifyBEName(be_names[1]) != 0:
        msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
        return 1

    rc = lb.beRename(be_names[0], be_names[1])

    if rc == 0:
        return 0

    be.msg_buf["0"] = be_names[0]
    if rc == msg.Msgs.BE_ERR_BE_NOENT:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
            be_names[0])
    elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
        msg.printMsg(msg.Msgs.BEADM_ERR_RENAME, be.msg_buf, -1)
        return 1
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_RENAME, be.msg_buf, -1)
    return 1


def set_policy(opts):
    """
            Description: Sets the given Boot Environments' policy properties
                         to the specified value(s).
                         The following is the subcommand, options
                         and args that make up the opts object
                         passed in:

                         set-policy -n policy [-n -policy2] beName [beName2 ...]

            Parameters:
                opts - A object containing the set-policy subcommand
                       and all the options and arguments passed in
                       on the command line mentioned above.

            Returns:
                0 - Success
                1 - Failure
    """

    priv_check()

    be = BootEnvironment()


    try:
        optlist, be_names = getopt.getopt(opts, "n:")
    except getopt.GetoptError:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        usage()

    policy = set()

    for opt, arg in optlist:
        if opt == "-n":
            policy = policy.union(arg.split(','))

    try:
        errors = lb.beSetPolicy(be_names, policy)
        if not errors:
            return 0

        for be_name, err_str in errors:
            be.msg_buf["0"] = be_name
            be.msg_buf["1"] = err_str
            msg_code = msg.Msgs.BEADM_ERR_SET_POLICY
            msg.printMsg(msg_code, be.msg_buf, -1)
        return 1
    except lb.LibbeBadPolicyError as lbpe:
        be.msg_buf["0"] = lbpe.badpolicy
        msg_code = msg.Msgs.BEADM_ERR_BAD_POLICY
    except lb.LibbePolicyConflictError as lpce:
        be.msg_buf["0"] = "' and '".join(lpce.conflicts)
        msg_code = msg.Msgs.BEADM_ERR_POLICY_CONFLICT
    except lb.LibbeBEDoesNotExistError as lbdnee:
        be.msg_buf["0"] = lbdnee.be_name
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
            lbdnee.be_name)
        msg_code = msg.Msgs.BEADM_ERR_SET_POLICY
    except lb.LibbeUnsupportedOperationError as luoe:
        be.msg_buf["0"] = luoe.error_str
        msg_code = msg.Msgs.BEADM_ERR_SET_POLICY_UNSUP
    except lb.LibbeInvalidPolicyError as lipe:
        be.msg_buf["0"] = lipe.error_str
        msg_code = msg.Msgs.BEADM_ERR_SET_POLICY_INVALID
    except lb.LibbeOperationError as lpoe:
        be.msg_buf["0"] = lpoe.be_name
        be.msg_buf["1"] = lpoe.error_str
        msg_code = msg.Msgs.BEADM_ERR_SET_POLICY

    msg.printMsg(msg_code, be.msg_buf, -1)
    return 1



#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# End of CLI public functions
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


def priv_check():
    '''Checks to make sure that beadm is run with superuser privs'''
    if not os.geteuid() == 0:
        print >> sys.stderr, _("Must be root to execute this command")
        sys.exit(1)
    if not os.access("/", os.W_OK):
        print >> sys.stderr, _("Current system is read-only")
        sys.exit(1);


# Verify the options and arguments for the beadm create subcommand

def verifyCreateOptionsArgs(be):
    """Check valid BE names."""

    len_be_args = len(be.trgt_be_name_or_snapshot)
    if len_be_args < 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        return 1
    if len_be_args > 1:
        msg.printMsg(msg.Msgs.BEADM_ERR_OPT_ARGS, None, -1)
        idx = 0
        while len_be_args > idx:
            msg.printMsg(msg.Msgs.BEADM_MSG_FREE_FORMAT,
                be.trgt_be_name_or_snapshot[idx], -1)
            idx += 1
        return 1

    return 0


def parseCLI(cli_opts_args):
    """Parse command line interface arguments."""

    gettext.install("beadm", "/usr/lib/locale")

    if len(cli_opts_args) == 0:
        usage()

    subcommand = cli_opts_args[0]
    opts_args = cli_opts_args[1:]

    if subcommand == "activate":
        rc = activate(opts_args)
    elif subcommand == "create":
        rc = create(opts_args)
    elif subcommand == "destroy":
        rc = destroy(opts_args)
    elif subcommand == "list":
        rc = list(opts_args)
    elif subcommand == "mount":
        rc = mount(opts_args)
    elif subcommand == "rename":
        rc = rename(opts_args)
    elif subcommand == "set-policy":
        rc = set_policy(opts_args)
    elif subcommand == "unmount" or \
        subcommand == "umount": #aliased for convenience
        rc = unmount(opts_args)
    else:
        msg.printMsg(msg.Msgs.BEADM_ERR_ILL_SUBCOMMAND,
            subcommand, -1)
        usage()

    return(rc)


def main():
    """main function."""

    gettext.install("beadm", "/usr/lib/locale")

    # Set BE_PRINT_ERR=true to enable more verbose error messaging
    # when failures occur.
    os.environ["BE_PRINT_ERR"] = "true"

    return(parseCLI(sys.argv[1:]))


def initBELog(log_id, be):
    """
    Initiate the BE log

    Format of the log
    yyyymmdd_hhmmss - 20071130_140558
    yy - year;   2007
    mm - month;  11
    dd - day;    30
    hh - hour;   14
    mm - minute; 05
    ss - second; 58
    """

    # /var/log/beadm/<beName>/<logId>.log.<yyyymmdd_hhmmss>

    date = time.strftime("%Y%m%d_%H%M%S", time.localtime())

    be.log = "/var/log/beadm/" + be.trgt_be_name_or_snapshot[0] + \
        "/" + log_id + ".log" + "." + date

    if not os.path.isfile(be.log) and not os.path.islink(be.log):
        if not os.path.isdir(os.path.dirname(be.log)):
            try:
                os.makedirs(os.path.dirname(be.log), 0755)
            except OSError as err:
                #
                # if we get an OSError due to EROFS we are in a read-only
                # environment
                #
                if err.errno == errno.EROFS:
                    be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
                    be.msg_buf["1"] = \
                        msg.getMsg(msg.Msgs.BEADM_ERR_ROFS,
                        0)
                    msg.printMsg(msg.Msgs.BEADM_ERR_CREATE,
                        be.msg_buf, -1)
                    return 1
                else:
                    be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
                    be.msg_buf["1"] = \
                        msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS,
                        0)
                    msg.printMsg(msg.Msgs.BEADM_ERR_CREATE,
                        be.msg_buf, -1)
                    return 1
        try:
            be.log_id = open(be.log, "a")
        except (IOError, OSError) as err:
            if err.errno == errno.EROFS:
                msg.printMsg(msg.Msgs.BEADM_ERR_ROFS, None, -1)
                return 1
            else:
                msg.printMsg(msg.Msgs.BEADM_ERR_LOG_CREATE,
                    None, -1)
                return 1
    else:
        # Should never happen due to new time stamp each call
        msg.printMsg(msg.Msgs.BEADM_ERR_LOG_CREATE, None, -1)
        return 1

    return 0


def cleanupBELog(be):
    """Clean up BE log."""

    be.log_id.close()


def displayDestructionQuestion(be):
    """Display a destruction question and wait for user response."""

    msg.printMsg(msg.Msgs.BEADM_MSG_DESTROY, be.trgt_be_name_or_snapshot[0],
                -1)
    while True:
        try:
            value = raw_input().strip().upper()
        except KeyboardInterrupt:
            return False
        if (value == 'Y' or value == 'YES'):
            return True
        elif len(value) == 0 or value == 'N' or value == 'NO':
            msg.printMsg(msg.Msgs.BEADM_MSG_DESTROY_NO,
                be.trgt_be_name_or_snapshot[0], -1)
            return False
        else:
            msg.printMsg(msg.Msgs.BEADM_ERR_INVALID_RESPONSE,
                -1)


def setMaxColumnWidths(be_max_w, ds_max_w, ss_max_w, be_list):
    """Figure out max column widths for BE's, Datasets and Snapshots."""

    for be_item in be_list:
        if be_item.get("orig_be_name") is not None:
            determineMaxBEColWidth(be_item, be_max_w)
        if be_item.get("dataset") is not None:
            determineMaxDSColWidth(be_item, ds_max_w)
        if be_item.get("snap_name") is not None:
            determineMaxSSColWidth(be_item, ss_max_w)


def getActiveBEAndActiveOnBootBE():
    """Return the 'active on boot' BE, the 'active' BE or None."""

    active_be = None
    active_be_on_boot = None

    rc, be_list = lb.beList()

    if rc != 0:
        if rc == msg.Msgs.BE_ERR_BE_NOENT:
            string = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_BES_EXIST)
        else:
            string = lb.beGetErrDesc(rc)
            if string == None:
                string = \
                    msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

        msg.printMsg(msg.Msgs.BEADM_ERR_LIST, string, -1)
        return None

    for be_vals in be_list:
        srcBeName = be_vals.get("orig_be_name")
        if be_vals.get("active"):
            active_be = srcBeName
        if be_vals.get("active_boot"):
            active_be_on_boot = srcBeName
        if active_be is not None and active_be_on_boot is not None:
            break

    return active_be, active_be_on_boot


def createSnapshot(be):
    """Create a snapshot."""

    try:
        be_name, snap_name = be.trgt_be_name_or_snapshot[0].split("@")
    except ValueError:
        msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
        return 1

    rc = lb.beCreateSnapshot(be_name, snap_name)[0]

    if rc == 0:
        return 0

    be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
    if rc == msg.Msgs.BE_ERR_BE_NOENT:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
            be_name)
    elif rc == msg.Msgs.BE_ERR_SS_EXISTS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_SNAP_EXISTS,
            be.trgt_be_name_or_snapshot[0])
    elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
        msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, -1)
        return 1
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, -1)

    return 1


def createBE(be):
    """Create a Boot Environment."""

    rc = lb.beCopy(be.trgt_be_name_or_snapshot[0], be.src_be_name_or_snapshot,
            None, be.trgt_rpool, be.properties, be.description)[0]

    if rc == 0:
        msg.printMsg(msg.Msgs.BEADM_MSG_BE_CREATE_SUCCESS,
            be.trgt_be_name_or_snapshot[0], be.log_id)
        return 0

    be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
    if rc == msg.Msgs.BE_ERR_BE_NOENT:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
            be.src_be_name_or_snapshot)
    elif rc == msg.Msgs.BE_ERR_BE_EXISTS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_BE_EXISTS,
            be.trgt_be_name_or_snapshot[0])
    elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
        msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, -1)
        return 1
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, be.log_id)

    return 1


def createBEFromSnapshot(be):
    """Create a BE based off a snapshot."""

    try:
        be_name, snap_name = be.src_be_name_or_snapshot.split("@")
    except ValueError:
        msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1)
        return 1

    rc = lb.beCopy(be.trgt_be_name_or_snapshot[0], be_name, snap_name,
        be.trgt_rpool, be.properties, be.description)[0]

    if rc == 0:
        msg.printMsg(msg.Msgs.BEADM_MSG_BE_CREATE_SUCCESS,
            be.trgt_be_name_or_snapshot[0], be.log_id)
        return 0

    be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
    if rc == msg.Msgs.BE_ERR_SS_NOENT:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_SNAP_DOES_NOT_EXISTS,
            be.src_be_name_or_snapshot)
    elif rc == msg.Msgs.BE_ERR_BE_EXISTS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_BE_EXISTS, \
            be.trgt_be_name_or_snapshot[0])
    elif rc == msg.Msgs.BE_ERR_BE_NOENT:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST, \
            be_name)
    elif rc == msg.Msgs.BE_ERR_PERM or rc == msg.Msgs.BE_ERR_ACCESS:
        be.msg_buf["1"] = msg.getMsg(msg.Msgs.BEADM_ERR_PERMISSIONS, rc)
        msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, -1)
        return 1
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_CREATE, be.msg_buf, be.log_id)

    return 1


def activateBE(be):
    """
    Activate a BE. Called from create() when -a is provided as CLI
    Option.
    """

    rc = lb.beActivate(be.trgt_be_name_or_snapshot[0])
    if rc == 0:
        return 0

    be.msg_buf["0"] = be.trgt_be_name_or_snapshot[0]
    if rc == msg.Msgs.BE_ERR_BE_NOENT:
        be.msg_buf["1"] = \
            msg.getMsg(msg.Msgs.BEADM_ERR_BE_DOES_NOT_EXIST,
                be.trgt_be_name_or_snapshot)
    else:
        be.msg_buf["1"] = lb.beGetErrDesc(rc)
        if be.msg_buf["1"] == None:
            be.msg_buf["1"] = \
                msg.getMsg(msg.Msgs.BEADM_ERR_NO_MSG, rc)

    msg.printMsg(msg.Msgs.BEADM_ERR_ACTIVATE, be.msg_buf, -1)

    return 1


if __name__ == "__main__":
    try:
        RC = main()
    except SystemExit, e:
        raise e
    except:
        traceback.print_exc()
        sys.exit(99)
    sys.exit(RC)