Mercurial > illumos > illumos-gate
changeset 13260:b7552a888d42
418 replace beadm by tbeadm with gettext support
Reviewed by: roland.mainz@nrubsig.org
Reviewed by: gordon.w.ross@gmail.com
Reviewed by: trisk@opensolaris.org
Approved by: garrett@nexenta.com
author | Alexander Stetsenko <ams@nexenta.com> |
---|---|
date | Mon, 27 Dec 2010 21:47:11 +0300 |
parents | 8dc1138162bb |
children | 12b93a567f6f |
files | usr/src/cmd/beadm/BootEnvironment.py usr/src/cmd/beadm/Makefile usr/src/cmd/beadm/__init__.py usr/src/cmd/beadm/beadm.c usr/src/cmd/beadm/beadm.py usr/src/cmd/beadm/messages.py usr/src/lib/libbe/Makefile usr/src/lib/libbe/tbeadm/Makefile usr/src/lib/libbe/tbeadm/tbeadm.c usr/src/pkg/manifests/install-beadm.mf |
diffstat | 10 files changed, 1702 insertions(+), 2757 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/beadm/BootEnvironment.py Thu Dec 16 09:43:44 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,444 +0,0 @@ -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. -# - -"""Boot Environment classes used by beadm.""" - -import datetime - -class BootEnvironment: - """Boot Environment object that is used by beadm to manage command line - options, arguments and the log.""" - - def __init__(self): - self.trgt_rpool = None - self.trgt_be_name_or_snapshot = None - self.src_be_name_or_snapshot = None - self.properties = {} - self.log_id = None - self.log = None - self.msg_buf = {} - self.description = None - -class listBootEnvironment: - """Base class for beadm list - Determine the BE's to display. Prints command output according to option: - -d - dataset - -s - snapshot - -a - all (both dataset and snapshot) - <none> - only BE information - The -H option produces condensed, parseable output - The ';' delimits each field in the output. BEs with multiple - datasets will have multiple lines in the output. - """ - - def list(self, be_list, ddh, be_name): - """ print all output for beadm list command - be_list - list of all BEs - ddh - if True, Do not Display Headers - just parseable data - be_name - user-specified BE, if any - - returns 0 for success - side effect: beadm list output printed to stdout - """ - - #If we're listing Headers, initialize the array holding the - #column widths with the header widths themselves. Later on, - #the data in this array will get adjusted as we process actual - #row data and find that a piece of data is wider than its - #column header. - bemaxout = [0 for i in range(len(self.hdr[0]))] - if not ddh: - #iterate all header rows since their fields may not - #be of equal length. - for header in self.hdr: - icol = 0 - for hc in header: - if len(hc) + 1 > bemaxout[icol]: - bemaxout[icol] = len(hc) + 1 - icol += 1 - - #collect BEs - beout = {} #matrix of output text [row][attribute] - beoutname = {} #list of BE names [row] - be_space = {} #space used totals for BE [BE name]['space_used','ibei'] - ibe = 0 #BE index - spacecol = -1 #to contain column where space used is displayed - for be in be_list: - if 'orig_be_name' in be: - cur_be = be['orig_be_name'] - cur_be_obj = be - - #if BE name specified, collect matching BEs - if be_name is not None and not self.beMatch(be, be_name): - continue - attrs = () - #identify BE|dataset|snapshot attributes - att = '' - for att in ('orig_be_name', 'dataset', 'snap_name'): - if att in be and att in self.lattrs: - attrs = self.lattrs[att] - if att == 'orig_be_name': - be_space[cur_be] = {} - be_space[cur_be]['space_used'] = 0 - be_space[cur_be]['ibe'] = ibe - if not ddh and len(cur_be) + 1 > bemaxout[0]: - bemaxout[0] = len(cur_be) + 1 - break - beout[ibe] = {} - beoutname[ibe] = cur_be - - icol = 0 #first column - for at in attrs: - #for option -s, withhold subordinate datasets - if self.__class__.__name__ == 'SnapshotList' and \ - att == 'snap_name' and 'snap_name' in be and \ - '/' in be[att]: - break - #convert output to readable format and save - save = self.getAttr(at, be, ddh, cur_be_obj) - beout[ibe][at] = save - #maintain maximum column widths - if not ddh and len(save) + 1 > bemaxout[icol]: - bemaxout[icol] = len(save) + 1 - #sum all snapshots for BE - if at == 'space_used' and 'space_used' in be: - spacecol = icol - icol += 1 #next column - ibe += 1 - if 'space_used' in be: - #sum all snapshots and datasets for BE in 'beadm list' - if isinstance(self, BEList): - be_space[cur_be]['space_used'] += be.get('space_used') - elif cur_be in be_space and \ - ('space_used' not in be_space[cur_be] or - be_space[cur_be]['space_used'] == 0): - #list space used separately for other options - be_space[cur_be]['space_used'] = be.get('space_used') - - #output format total lengths for each BE with any snapshots - for cur_be in be_space: - save = self.getSpaceValue(be_space[cur_be]['space_used'], ddh) - ibe = be_space[cur_be]['ibe'] - beout[ibe]['space_used'] = save - #expand column if widest column entry - if (spacecol != -1) and \ - (not ddh and len(save) + 1 > bemaxout[spacecol]): - bemaxout[spacecol] = len(save) + 1 - - #print headers in columns - if not ddh: - for header in self.hdr: - outstr = '' - for icol in range(len(header)): - outstr += header[icol].ljust(bemaxout[icol]) - if outstr != '': - print outstr - - #print collected output in columns - outstr = '' - prev_be = None - cur_be = None - for ibe in beout: #index output matrix - if beoutname[ibe] != None: - cur_be = beoutname[ibe] - #find attributes for BE type - curtype = None - for att in ('orig_be_name', 'dataset', 'snap_name'): - if att in beout[ibe]: - attrs = self.lattrs[att] - curtype = att - break - - if curtype == None: #default to BE - curtype = 'orig_be_name' - if 'orig_be_name' in self.lattrs: - attrs = self.lattrs['orig_be_name'] - else: attrs = () - - if not ddh: - if prev_be != cur_be and cur_be != None: - #for -d,-s,-a, print BE alone on line - if self.__class__.__name__ != 'BEList': - print cur_be - prev_be = cur_be - - #print for one BE/snapshot/dataset - icol = 0 #first column - - #if this is a 'dataset' or 'snap_name', start line with BE - #name token - if ddh and curtype != 'orig_be_name': - outstr = cur_be - - for at in attrs: #for each attribute specified in table - if ddh: #add separators for parsing - if outstr != '': - outstr += ';' #attribute separator - if at in beout[ibe] and beout[ibe][at] != '-' and \ - beout[ibe][at] != '': - outstr += beout[ibe][at] - else: #append text justified in column - if at in beout[ibe]: - outstr += beout[ibe][at].ljust(bemaxout[icol]) - icol += 1 #next column - - if outstr != '': - print outstr - outstr = '' - - return 0 - - def beMatch(self, be, be_name): - """find match on user-specified BE.""" - - if 'orig_be_name' in be: - return be.get('orig_be_name') == be_name - if 'dataset' in be: - if be.get('dataset') == be_name: - return True - out = be.get('dataset').split("/") - return out[0] == be_name - if 'snap_name' in be: - if be.get('snap_name') == be_name: - return True - out = be.get('snap_name').split('@') - if out[0] == be_name: - return True - out = be.get('snap_name').split('/') - return out[0] == be_name - return False - - def getAttr(self, at, be, ddh, beobj): - """ - Extract information by attribute and format for printing - returns '?' if normally present attribute not found - error. - """ - if at == 'blank': - return ' ' - if at == 'dash': - return '-' - if at == 'orig_be_name': - if at not in be: - return '-' - ret = be[at] - if ddh or self.__class__.__name__ == 'BEList': - return ret - return ' ' + ret #indent - if at == 'snap_name': - if at not in be: - return '-' - if self.__class__.__name__ == 'CompleteList': - ret = self.prependRootDS(be[at], beobj) - else: - ret = be[at] - if ddh: - return ret - return ' ' + ret #indent - if at == 'dataset': - if at not in be: - return '-' - if self.__class__.__name__ == 'DatasetList' or \ - self.__class__.__name__ == 'CompleteList': - ret = self.prependRootDS(be[at], beobj) - else: - ret = be[at] - if ddh: - return ret - return ' ' + ret #indent - if at == 'active': - if at not in be: - return '-' - ret = '' - if 'active' in be and be['active']: - ret += 'N' - if 'active_boot' in be and be['active_boot']: - ret += 'R' - if ret == '': - return '-' - return ret - if at == 'mountpoint': - if at not in be: - return '-' - if 'mounted' not in be or not be['mounted']: - return '-' - return be[at] - if at == 'space_used': - if at not in be: - return '0' - return self.getSpaceValue(be[at], ddh) - if at == 'mounted': - if at not in be: - return '-' - return be[at] - if at == 'date': - if at not in be: - return '?' - if ddh: - return str(be[at]) #timestamp in seconds - sec = str(datetime.datetime.fromtimestamp(be[at])) - return sec[0:len(sec)-3] #trim seconds - if at == 'policy': - if at not in be: - return '?' - return be[at] - if at == 'root_ds': - if at not in be: - return '?' - if ddh or self.__class__.__name__ == 'BEList': - return be[at] - return ' ' + be[at] - if at == 'uuid_str': - if at not in be: - return '-' - return be[at] - #default case - no match on attribute - return be[at] - - def getSpaceValue(self, num, ddh): - """Readable formatting for disk space size.""" - - if ddh: - return str(num) #return size in bytes as string - - kilo = 1024.0 - mega = 1048576.0 - giga = 1073741824.0 - tera = 1099511627776.0 - - if num == None: - return '0' - if num < kilo: - return str(num) + 'B' - if num < mega: - return str('%.1f' % (num / kilo)) + 'K' - if num < giga: - return str('%.2f' % (num / mega)) + 'M' - if num < tera: - return str('%.2f' % (num / giga)) + 'G' - return str('%.2f' % (num / tera)) + 'T' - - def prependRootDS(self, val, beobj): - """Prepend root dataset name with BE name stripped.""" - - root_ds = beobj.get('root_ds') - return root_ds[0:root_ds.rfind('/')+1] + val - - -"""Top level "beadm list" derived classes defined here. - Only table definition is done here - all methods are in the base class. - Tables driving list: - hdr - list of text to output for each column - lattrs - dictionary of attributes - Each entry specifies either BE, dataset, snapshot with - an attribute key: - orig_be_name - for BEs - dataset - for datasets - snap_name - for snapshots - Each list item in entry indicates specific datum for - column - Number of hdr columns must equal number of lattrs entries - unless ddh (dontDisplayHeaders) is true. -""" -class BEList(listBootEnvironment): - """specify header and attribute information for BE-only output""" - - def __init__(self, ddh): - """Init function for the class.""" - self.hdr = \ - ('BE','Active','Mountpoint','Space','Policy','Created'), \ - ('--','------','----------','-----','------','-------') - if ddh: - self.lattrs = {'orig_be_name':('orig_be_name', 'uuid_str', - 'active', 'mountpoint', 'space_used', 'policy', - 'date')} - else: - self.lattrs = {'orig_be_name':('orig_be_name', 'active', - 'mountpoint', 'space_used', 'policy', 'date')} - -class DatasetList(listBootEnvironment): - """ - specify header and attribute information for dataset output, - -d option - """ - def __init__(self, ddh): - """Init function for the class.""" - - self.hdr = \ - ('BE/Dataset','Active','Mountpoint','Space','Policy','Created'), \ - ('----------','------','----------','-----','------','-------') - if ddh: - self.lattrs = { \ - 'orig_be_name':('orig_be_name', 'root_ds', 'active', - 'mountpoint', 'space_used', 'policy', 'date'), \ - 'dataset':('dataset', 'dash', 'mountpoint', 'space_used', - 'policy', 'date')} - else: - self.lattrs = { \ - 'orig_be_name':('root_ds', 'active', 'mountpoint', - 'space_used', 'policy', 'date'), \ - 'dataset':('dataset', 'dash', 'mountpoint', 'space_used', - 'policy', 'date')} - -class SnapshotList(listBootEnvironment): - """ - specify header and attribute information for snapshot output, - -s option - """ - def __init__(self, ddh): - """Init function for the class.""" - - self.hdr = \ - ('BE/Snapshot','Space','Policy','Created'), \ - ('-----------','-----','------','-------') - self.lattrs = {'snap_name':('snap_name', 'space_used', 'policy', - 'date')} - -class CompleteList(listBootEnvironment): - """ - specify header and attribute information for BE and/or dataset and/or - snapshot output, - -a or -ds options - """ - def __init__(self, ddh): - """Init function for the class.""" - - self.hdr = \ - ('BE/Dataset/Snapshot','Active','Mountpoint','Space','Policy','Created'), \ - ('-------------------','------','----------','-----','------','-------') - if ddh: - self.lattrs = { \ - 'orig_be_name':('orig_be_name', 'root_ds', 'active', - 'mountpoint', 'space_used', 'policy', 'date'), - 'dataset':('dataset', 'dash', 'mountpoint', 'space_used', - 'policy', 'date'), - 'snap_name':('snap_name', 'dash', 'dash', 'space_used', - 'policy', 'date')} - else: - self.lattrs = { \ - 'orig_be_name':('root_ds', 'active', 'mountpoint', - 'space_used', 'policy', 'date'), \ - 'dataset':('dataset', 'dash', 'mountpoint', 'space_used', - 'policy', 'date'), - 'snap_name':('snap_name', 'dash', 'dash', 'space_used', - 'policy', 'date')}
--- a/usr/src/cmd/beadm/Makefile Thu Dec 16 09:43:44 2010 -0800 +++ b/usr/src/cmd/beadm/Makefile Mon Dec 27 21:47:11 2010 +0300 @@ -18,60 +18,45 @@ # # CDDL HEADER END # - -# # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # +# Copyright 2010 Nexenta Systems, Inc. All rights reserved. +# + +PROG= beadm +OBJS= beadm.o +SRCS= $(OBJS:%.o=%.c) +POFILE= beadm.po include ../Makefile.cmd -FILEMODE=0444 - -PYTHON= $(PYTHON_26) -ROOTPYDIR= $(ROOT)/usr/lib/python2.6/vendor-packages -ROOTMODDIR= $(ROOTPYDIR)/beadm - -PYCMD= beadm.py -PYCMDFILE= $(PYCMD:%.py=%) +LDLIBS += -lnvpair -lbe -PYMODULES= __init__.py BootEnvironment.py messages.py -PYMODOBJS= $(PYMODULES:%.py=%.pyc) -PYMODFILES= $(PYMODULES) $(PYMODOBJS) +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG -ROOTCMDFILE= $(PYCMDFILE:%=$(ROOTSBIN)/%) -$(ROOTCMDFILE) := FILEMODE = 0555 -ROOTMODFILES= $(PYMODFILES:%=$(ROOTMODDIR)/%) -ROOTUSRSBINLINKS= $(PYCMDFILE:%=$(ROOTUSRSBIN)/%) - -POFILE = beadm.po -MSGFILES = beadm.py messages.py -XGETTEXT = $(GNUXGETTEXT) -XGETFLAGS = $(GNUXGETFLAGS) +ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%) .KEEP_STATE: -all: $(PYCMDFILE) $(PYMODOBJS) +.PARALLEL: + +all: $(PROG) -install: all $(ROOTCMDFILE) $(ROOTMODFILES) $(ROOTUSRSBINLINKS) +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +install: all $(ROOTSBINPROG) $(ROOTUSRSBINLINKS) clean: - $(RM) $(PYCMDFILE) $(PYMODOBJS) - -clobber: clean + $(RM) $(OBJS) -$(ROOTCMDDIR)/%: % - $(INS.pyfile) - -$(ROOTMODDIR)/%: % - $(INS.pyfile) +lint: lint_SRCS +# Links from /usr/sbin to /sbin $(ROOTUSRSBINLINKS): - -$(RM) $@; $(SYMLINK) ../../sbin/$(@F) $@ + -$(RM) $@; $(SYMLINK) ../../sbin/$(PROG) $@ -$(POFILE): $(MSGFILES) - $(BUILDPO.msgfiles) +FRC: -_msg: $(MSGDOMAINPOFILE) - -include $(SRC)/Makefile.msg.targ include ../Makefile.targ
--- a/usr/src/cmd/beadm/__init__.py Thu Dec 16 09:43:44 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. -# - -import gettext - -_ = gettext.translation("beadm", "/usr/lib/locale", - fallback=True).gettext - -__all__ = ["messages", "BootEnvironment"] -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/beadm/beadm.c Mon Dec 27 21:47:11 2010 +0300 @@ -0,0 +1,1677 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* + * Copyright 2010 Nexenta Systems, Inc. All rights reserved. + */ + +/* + * System includes + */ + +#include <assert.h> +#include <stdio.h> +#include <strings.h> +#include <libzfs.h> +#include <locale.h> +#include <langinfo.h> +#include <stdlib.h> +#include <wchar.h> +#include <sys/types.h> + +#include "libbe.h" + +#ifndef lint +#define _(x) gettext(x) +#else +#define _(x) (x) +#endif + +#ifndef TEXT_DOMAIN +#define TEXT_DOMAIN "SYS_TEST" +#endif + +#define DT_BUF_LEN (128) +#define NUM_COLS (6) + +static int be_do_activate(int argc, char **argv); +static int be_do_create(int argc, char **argv); +static int be_do_create_snapshot(int argc, char **argv); +static int be_do_destroy(int argc, char **argv); +static int be_do_destroy_snapshot(int argc, char **argv); +static int be_do_list(int argc, char **argv); +static int be_do_mount(int argc, char **argv); +static int be_do_unmount(int argc, char **argv); +static int be_do_rename(int argc, char **argv); +static int be_do_rollback(int argc, char **argv); +static void usage(void); + +/* + * single column name/width output format description + */ +struct col_info { + const char *col_name; + size_t width; +}; + +/* + * all columns output format + */ +struct hdr_info { + struct col_info cols[NUM_COLS]; +}; + +/* + * type of possible output formats + */ +enum be_fmt { + BE_FMT_DEFAULT, + BE_FMT_DATASET, + BE_FMT_SNAPSHOT, + BE_FMT_ALL, + BE_NUM_FMTS +}; + +/* + * command id + */ +enum be_cmd { + BE_CMD_ACTIVATE, + BE_CMD_CREATE, + BE_CMD_CREATE_SNAP, + BE_CMD_DESTROY, + BE_CMD_DESTROY_SNAP, + BE_CMD_LIST, + BE_CMD_MOUNT, + BE_CMD_UNMOUNT, + BE_CMD_RENAME, + BE_CMD_ROLLBACK, + + BE_NUM_COMMANDS +}; + +/* + * command handler description + */ +typedef struct be_command { + const char *name; + int (*func)(int argc, char **argv); +} be_command_t; + +/* + * sorted list of be commands + */ +static const be_command_t be_command_tbl[BE_NUM_COMMANDS] = { + { "activate", be_do_activate }, + { "create", be_do_create }, + { "create_snap", be_do_create_snapshot }, + { "destroy", be_do_destroy }, + { "destroy_snap", be_do_destroy_snapshot }, + { "list", be_do_list }, + { "mount", be_do_mount }, + { "unmount", be_do_unmount }, + { "rename", be_do_rename }, + { "rollback", be_do_rollback }, +}; + +static struct hdr_info hdrs[BE_NUM_FMTS] = { 0 }; + +static void +usage(void) +{ + (void) fprintf(stderr, _("usage:\n" + "\tbeadm subcommand cmd_options\n" + "\n" + "\tsubcommands:\n" + "\n" + "\tbeadm create [-d BE_desc]\n" + "\t\t[-o property=value] ... [-p zpool] \n" + "\t\t[-e nonActiveBe | beName@snapshot] beName\n" + "\tbeadm create [-d BE_desc]\n" + "\t\t[-o property=value] ... [-p zpool] beName@snapshot\n" + "\tbeadm create_snap [-p policy] beName [snapshot]\n" + "\tbeadm destroy [-Ffs] beName \n" + "\tbeadm destroy [-F] beName@snapshot \n" + "\tbeadm destroy_snap beName snapshot\n" + "\tbeadm list [[-a] | [-d] [-s]] [-H] [beName]\n" + "\tbeadm mount [-s ro|rw] beName [mountpoint]\n" + "\tbeadm unmount [-f] beName\n" + "\tbeadm rename origBeName newBeName\n" + "\tbeadm rollback beName snapshot\n" + "\tbeadm rollback beName@snapshot\n")); +} + +static int +run_be_cmd(const char *cmdname, int argc, char **argv) +{ + int cmd; + for (cmd = 0; cmd < BE_NUM_COMMANDS; cmd++) { + const be_command_t *command = &be_command_tbl[cmd]; + if (strcmp(command->name, cmdname) == 0) + return (command->func(argc, argv)); + } + + (void) fprintf(stderr, _("Invalid command: %s\n"), cmdname); + usage(); + return (1); +} + +int +main(int argc, char **argv) +{ + const char *cmdname; + + (void) setlocale(LC_ALL, ""); + (void) textdomain(TEXT_DOMAIN); + + if (argc < 2) { + usage(); + return (1); + } + + cmdname = argv[1]; + + /* Turn error printing off */ + libbe_print_errors(B_FALSE); + + return (run_be_cmd(cmdname, --argc, ++argv)); +} + +static void +print_hdr(struct hdr_info *hdr_info) +{ + boolean_t first = B_TRUE; + size_t i; + for (i = 0; i < NUM_COLS; i++) { + struct col_info *col_info = &hdr_info->cols[i]; + const char *name = col_info->col_name; + size_t width = col_info->width; + if (name == NULL) + continue; + + if (first) { + (void) printf("%-*s", width, name); + first = B_FALSE; + } else + (void) printf(" %-*s", width, name); + } + (void) putchar('\n'); +} + +static void +init_hdr_cols(enum be_fmt be_fmt, struct hdr_info *hdr) +{ + struct col_info *col = hdr->cols; + size_t i; + + col[1].col_name = _("Active"); + col[2].col_name = _("Mountpoint"); + col[3].col_name = _("Space"); + col[4].col_name = _("Policy"); + col[5].col_name = _("Created"); + col[6].col_name = NULL; + + switch (be_fmt) { + case BE_FMT_ALL: + col[0].col_name = _("BE/Dataset/Snapshot"); + break; + case BE_FMT_DATASET: + col[0].col_name = _("BE/Dataset"); + break; + case BE_FMT_SNAPSHOT: + col[0].col_name = _("BE/Snapshot"); + col[1].col_name = NULL; + col[2].col_name = NULL; + break; + case BE_FMT_DEFAULT: + default: + col[0].col_name = _("BE"); + } + + for (i = 0; i < NUM_COLS; i++) { + const char *name = col[i].col_name; + col[i].width = 0; + + if (name != NULL) { + wchar_t wname[128]; + size_t sz = mbstowcs(wname, name, sizeof (wname) / + sizeof (wchar_t)); + if (sz > 0) + col[i].width = wcswidth(wname, sz); + } + } +} + +static void +nicenum(uint64_t num, char *buf, size_t buflen) +{ + uint64_t n = num; + int index = 0; + char u; + + while (n >= 1024) { + n /= 1024; + index++; + } + + u = " KMGTPE"[index]; + + if (index == 0) { + (void) snprintf(buf, buflen, "%llu", n); + } else { + int i; + for (i = 2; i >= 0; i--) { + if (snprintf(buf, buflen, "%.*f%c", i, + (double)num / (1ULL << 10 * index), u) <= 5) + break; + } + } +} + +static void +count_widths(enum be_fmt be_fmt, struct hdr_info *hdr, be_node_list_t *be_nodes) +{ + size_t len[NUM_COLS]; + char buf[DT_BUF_LEN]; + int i; + be_node_list_t *cur_be; + + for (i = 0; i < NUM_COLS; i++) + len[i] = hdr->cols[i].width; + + for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { + char name[ZFS_MAXNAMELEN+1]; + const char *be_name = cur_be->be_node_name; + const char *root_ds = cur_be->be_root_ds; + char *pos; + size_t node_name_len = strlen(cur_be->be_node_name); + size_t root_ds_len = strlen(cur_be->be_root_ds); + size_t mntpt_len = strlen(cur_be->be_mntpt); + size_t policy_len = strlen(cur_be->be_policy_type); + size_t used_len; + + uint64_t used = cur_be->be_space_used; + be_snapshot_list_t *snap = NULL; + + (void) strncpy(name, root_ds, sizeof (name)); + pos = strstr(name, be_name); + + if (be_fmt == BE_FMT_DEFAULT) { + if (node_name_len > len[0]) + len[0] = node_name_len; + } else { + if (root_ds_len + 3 > len[0]) + len[0] = root_ds_len + 3; + } + + if (mntpt_len > len[2]) + len[2] = mntpt_len; + if (policy_len > len[4]) + len[4] = policy_len; + + for (snap = cur_be->be_node_snapshots; snap != NULL; + snap = snap->be_next_snapshot) { + uint64_t snap_used = snap->be_snapshot_space_used; + const char *snap_name = snap->be_snapshot_name; + (void) strcpy(pos, snap_name); + + if (be_fmt == BE_FMT_DEFAULT) + used += snap_used; + else if (be_fmt & BE_FMT_SNAPSHOT) { + int snap_len = strlen(name) + 3; + if (be_fmt == BE_FMT_SNAPSHOT) + snap_len -= pos - name; + if (snap_len > len[0]) + len[0] = snap_len; + nicenum(snap_used, buf, sizeof (buf)); + used_len = strlen(buf); + if (used_len > len[3]) + len[3] = used_len; + } + } + + if (be_fmt == BE_FMT_DEFAULT) { + int used_len; + nicenum(used, buf, sizeof (buf)); + used_len = strlen(buf); + if (used_len > len[3]) + len[3] = used_len; + } + + nicenum(used, buf, sizeof (buf)); + } + + for (i = 0; i < NUM_COLS; i++) + hdr->cols[i].width = len[i]; +} + +static void +print_be_nodes(const char *be_name, boolean_t parsable, be_node_list_t *nodes) +{ + char buf[64]; + char datetime[DT_BUF_LEN]; + struct hdr_info *hdr = NULL; + enum be_fmt be_fmt = BE_FMT_DEFAULT; + be_node_list_t *cur_be; + + if (!parsable) { + hdr = hdrs; + init_hdr_cols(be_fmt, hdr); + count_widths(be_fmt, hdr, nodes); + print_hdr(hdr); + } + + for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { + char active[3] = "-\0"; + int ai = 0; + const char *datetime_fmt = "%F %R"; + const char *name = cur_be->be_node_name; + const char *mntpt = cur_be->be_mntpt; + be_snapshot_list_t *snap = NULL; + uint64_t used = cur_be->be_space_used; + time_t creation = cur_be->be_node_creation; + struct tm *tm; + + if (be_name != NULL && strcmp(be_name, name) != 0) + continue; + + if (parsable) + active[0] = '\0'; + + tm = localtime(&creation); + (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); + + for (snap = cur_be->be_node_snapshots; snap != NULL; + snap = snap->be_next_snapshot) + used += snap->be_snapshot_space_used; + + if (cur_be->be_active) + active[ai++] = 'N'; + if (cur_be->be_active_on_boot) + active[ai] = 'R'; + + nicenum(used, buf, sizeof (buf)); + if (parsable) + (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", + name, + cur_be->be_uuid_str, + active, + (cur_be->be_mounted ? mntpt: ""), + used, + cur_be->be_policy_type, + creation); + else + (void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n", + hdr->cols[0].width, name, + hdr->cols[1].width, active, + hdr->cols[2].width, (cur_be->be_mounted ? mntpt: + "-"), + hdr->cols[3].width, buf, + hdr->cols[4].width, cur_be->be_policy_type, + hdr->cols[5].width, datetime); + } +} + +static void +print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable) +{ + char buf[64]; + char datetime[DT_BUF_LEN]; + be_snapshot_list_t *snap = NULL; + + for (snap = be->be_node_snapshots; snap != NULL; + snap = snap->be_next_snapshot) { + char name[ZFS_MAXNAMELEN+1]; + const char *datetime_fmt = "%F %R"; + const char *be_name = be->be_node_name; + const char *root_ds = be->be_root_ds; + const char *snap_name = snap->be_snapshot_name; + char *pos; + uint64_t used = snap->be_snapshot_space_used; + time_t creation = snap->be_snapshot_creation; + struct tm *tm = localtime(&creation); + + (void) strncpy(name, root_ds, sizeof (name)); + pos = strstr(name, be_name); + (void) strcpy(pos, snap_name); + + (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); + nicenum(used, buf, sizeof (buf)); + + if (parsable) + if (hdr->cols[1].width != 0) + (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", + be_name, + snap_name, + "", + "", + used, + be->be_policy_type, + creation); + else + (void) printf("%s;%s;%llu;%s;%ld\n", + be_name, + snap_name, + used, + be->be_policy_type, + creation); + else + if (hdr->cols[1].width != 0) + (void) printf(" %-*s %-*s %-*s %-*s %-*s " + "%-*s\n", + hdr->cols[0].width-3, name, + hdr->cols[1].width, "-", + hdr->cols[2].width, "-", + hdr->cols[3].width, buf, + hdr->cols[4].width, be->be_policy_type, + hdr->cols[5].width, datetime); + else + (void) printf(" %-*s %-*s %-*s %-*s\n", + hdr->cols[0].width-3, snap_name, + hdr->cols[3].width, buf, + hdr->cols[4].width, be->be_policy_type, + hdr->cols[5].width, datetime); + } +} + +static void +print_fmt_nodes(const char *be_name, enum be_fmt be_fmt, boolean_t parsable, + be_node_list_t *nodes) +{ + char buf[64]; + char datetime[DT_BUF_LEN]; + struct hdr_info *hdr = NULL; + be_node_list_t *cur_be; + + if (!parsable) { + hdr = hdrs + be_fmt; + init_hdr_cols(be_fmt, hdr); + count_widths(be_fmt, hdr, nodes); + print_hdr(hdr); + } + + for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { + char active[3] = "-\0"; + int ai = 0; + const char *datetime_fmt = "%F %R"; + const char *name = cur_be->be_node_name; + const char *mntpt = cur_be->be_mntpt; + uint64_t used = cur_be->be_space_used; + time_t creation = cur_be->be_node_creation; + struct tm *tm; + + if (be_name != NULL && strcmp(be_name, name) != 0) + continue; + + if (!parsable) + (void) printf("%-s\n", name); + else + active[0] = '\0'; + + tm = localtime(&creation); + (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm); + + if (cur_be->be_active) + active[ai++] = 'N'; + if (cur_be->be_active_on_boot) + active[ai] = 'R'; + + nicenum(used, buf, sizeof (buf)); + if (be_fmt & BE_FMT_DATASET) + if (parsable) + (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n", + cur_be->be_node_name, + cur_be->be_root_ds, + active, + (cur_be->be_mounted ? mntpt: ""), + used, + cur_be->be_policy_type, + creation); + else + (void) printf(" %-*s %-*s %-*s %-*s %-*s " + "%-*s\n", + hdr->cols[0].width-3, cur_be->be_root_ds, + hdr->cols[1].width, active, + hdr->cols[2].width, (cur_be->be_mounted ? + mntpt: "-"), + hdr->cols[3].width, buf, + hdr->cols[4].width, cur_be->be_policy_type, + hdr->cols[5].width, datetime); + + if (be_fmt & BE_FMT_SNAPSHOT) + print_be_snapshots(cur_be, hdr, parsable); + } +} + +static void +print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps, + boolean_t parsable, be_node_list_t *be_nodes) +{ + enum be_fmt be_fmt = BE_FMT_DEFAULT; + + if (dsets) + be_fmt |= BE_FMT_DATASET; + if (snaps) + be_fmt |= BE_FMT_SNAPSHOT; + + if (be_fmt == BE_FMT_DEFAULT) + print_be_nodes(be_name, parsable, be_nodes); + else + print_fmt_nodes(be_name, be_fmt, parsable, be_nodes); +} + +static boolean_t +confirm_destroy(const char *name) +{ + boolean_t res = B_FALSE; + const char *yesre = nl_langinfo(YESEXPR); + const char *nore = nl_langinfo(NOEXPR); + regex_t yes_re; + regex_t no_re; + char buf[128]; + char *answer; + int cflags = REG_EXTENDED; + + if (regcomp(&yes_re, yesre, cflags) != 0) { + /* should not happen */ + (void) fprintf(stderr, _("Failed to compile 'yes' regexp\n")); + return (res); + } + if (regcomp(&no_re, nore, cflags) != 0) { + /* should not happen */ + (void) fprintf(stderr, _("Failed to compile 'no' regexp\n")); + regfree(&yes_re); + return (res); + } + + (void) printf(_("Are you sure you want to destroy %s?\n" + "This action cannot be undone (y/[n]): "), name); + + answer = fgets(buf, sizeof (buf), stdin); + if (answer == NULL || *answer == '\0' || *answer == 10) + goto out; + + if (regexec(&yes_re, answer, 0, NULL, 0) == 0) { + res = B_TRUE; + } else if (regexec(&no_re, answer, 0, NULL, 0) != 0) { + (void) fprintf(stderr, _("Invalid response. " + "Please enter 'y' or 'n'.\n")); + } + +out: + regfree(&yes_re); + regfree(&no_re); + return (res); +} + +static int +be_nvl_alloc(nvlist_t **nvlp) +{ + assert(nvlp != NULL); + + if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) { + (void) perror(_("nvlist_alloc failed.\n")); + return (1); + } + + return (0); +} + +static int +be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val) +{ + assert(nvl != NULL); + + if (nvlist_add_string(nvl, name, val) != 0) { + (void) fprintf(stderr, _("nvlist_add_string failed for " + "%s (%s).\n"), name, val); + return (1); + } + + return (0); +} + +static int +be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) +{ + assert(nvl != NULL); + + if (nvlist_add_nvlist(nvl, name, val) != 0) { + (void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"), + name); + return (1); + } + + return (0); +} + +static int +be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val) +{ + assert(nvl != NULL); + + if (nvlist_add_uint16(nvl, name, val) != 0) { + (void) fprintf(stderr, _("nvlist_add_uint16 failed for " + "%s (%hu).\n"), name, val); + return (1); + } + + return (0); +} + +static int +be_do_activate(int argc, char **argv) +{ + nvlist_t *be_attrs; + int err = 1; + char *obe_name; + + argc -= optind; + argv += optind; + + if (argc != 1) { + usage(); + return (1); + } + + obe_name = argv[0]; + + if (be_nvl_alloc(&be_attrs) != 0) + return (1); + + if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) + goto out; + + err = be_activate(be_attrs); + + switch (err) { + case BE_SUCCESS: + (void) printf(_("Activated successfully\n")); + break; + case BE_ERR_BE_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid BE.\nPlease check that the name of " + "the BE provided is correct.\n"), obe_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + case BE_ERR_ACTIVATE_CURR: + default: + (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + nvlist_free(be_attrs); + return (err); +} + +static int +be_do_create(int argc, char **argv) +{ + nvlist_t *be_attrs; + nvlist_t *zfs_props = NULL; + boolean_t activate = B_FALSE; + boolean_t is_snap = B_FALSE; + int c; + int err = 1; + char *obe_name = NULL; + char *snap_name = NULL; + char *nbe_zpool = NULL; + char *nbe_name = NULL; + char *nbe_desc = NULL; + char *propname = NULL; + char *propval = NULL; + char *strval = NULL; + + while ((c = getopt(argc, argv, "ad:e:io:p:")) != -1) { + switch (c) { + case 'a': + activate = B_TRUE; + break; + case 'd': + nbe_desc = optarg; + break; + case 'e': + obe_name = optarg; + break; + case 'o': + if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0) + return (1); + + propname = optarg; + if ((propval = strchr(propname, '=')) == NULL) { + (void) fprintf(stderr, _("missing " + "'=' for -o option\n")); + goto out2; + } + *propval = '\0'; + propval++; + if (nvlist_lookup_string(zfs_props, propname, + &strval) == 0) { + (void) fprintf(stderr, _("property '%s' " + "specified multiple times\n"), propname); + goto out2; + + } + if (be_nvl_add_string(zfs_props, propname, propval) + != 0) + goto out2; + + break; + case 'p': + nbe_zpool = optarg; + break; + default: + usage(); + goto out2; + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + usage(); + goto out2; + } + + nbe_name = argv[0]; + + if ((snap_name = strrchr(nbe_name, '@')) != NULL) { + if (snap_name[1] == '\0') { + usage(); + goto out2; + } + + snap_name[0] = '\0'; + snap_name++; + is_snap = B_TRUE; + } + + if (obe_name) { + if (is_snap) { + usage(); + goto out2; + } + + /* + * Check if obe_name is really a snapshot name. + * If so, split it out. + */ + if ((snap_name = strrchr(obe_name, '@')) != NULL) { + if (snap_name[1] == '\0') { + usage(); + goto out2; + } + + snap_name[0] = '\0'; + snap_name++; + } + } else if (is_snap) { + obe_name = nbe_name; + nbe_name = NULL; + } + + if (be_nvl_alloc(&be_attrs) != 0) + goto out2; + + + if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs, + BE_ATTR_ORIG_BE_NAME, zfs_props) != 0) + goto out; + + if (obe_name != NULL && be_nvl_add_string(be_attrs, + BE_ATTR_ORIG_BE_NAME, obe_name) != 0) + goto out; + + if (snap_name != NULL && be_nvl_add_string(be_attrs, + BE_ATTR_SNAP_NAME, snap_name) != 0) + goto out; + + if (nbe_zpool != NULL && be_nvl_add_string(be_attrs, + BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0) + goto out; + + if (nbe_name != NULL && be_nvl_add_string(be_attrs, + BE_ATTR_NEW_BE_NAME, nbe_name) != 0) + goto out; + + if (nbe_desc != NULL && be_nvl_add_string(be_attrs, + BE_ATTR_NEW_BE_DESC, nbe_desc) != 0) + goto out; + + if (is_snap) + err = be_create_snapshot(be_attrs); + else + err = be_copy(be_attrs); + + switch (err) { + case BE_SUCCESS: + if (!is_snap && !nbe_name) { + /* + * We requested an auto named BE; find out the + * name of the BE that was created for us and + * the auto snapshot created from the original BE. + */ + if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, + &nbe_name) != 0) { + (void) fprintf(stderr, _("failed to get %s " + "attribute\n"), BE_ATTR_NEW_BE_NAME); + break; + } else + (void) printf(_("Auto named BE: %s\n"), + nbe_name); + + if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, + &snap_name) != 0) { + (void) fprintf(stderr, _("failed to get %s " + "attribute\n"), BE_ATTR_SNAP_NAME); + break; + } else + (void) printf(_("Auto named snapshot: %s\n"), + snap_name); + } + + if (!is_snap && activate) { + char *args[] = { "activate", "", NULL }; + args[1] = nbe_name; + optind = 1; + + err = be_do_activate(2, args); + goto out; + } + + (void) printf(_("Created successfully\n")); + break; + case BE_ERR_BE_EXISTS: + (void) fprintf(stderr, _("BE %s already exists\n." + "Please choose a different BE name.\n"), nbe_name); + break; + case BE_ERR_SS_EXISTS: + (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n" + "Please choose a different snapshot name.\n"), obe_name, + snap_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + if (is_snap) + (void) fprintf(stderr, _("Unable to create snapshot " + "%s.\n"), snap_name); + else + (void) fprintf(stderr, _("Unable to create %s.\n"), + nbe_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + default: + if (is_snap) + (void) fprintf(stderr, _("Unable to create snapshot " + "%s.\n"), snap_name); + else + (void) fprintf(stderr, _("Unable to create %s.\n"), + nbe_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + nvlist_free(be_attrs); +out2: + if (zfs_props != NULL) + nvlist_free(zfs_props); + + return (err); +} + +static int +be_do_create_snapshot(int argc, char **argv) +{ + nvlist_t *be_attrs; + int err = 1; + int c; + char *obe_name = NULL; + char *snap_name = NULL; + char *policy = NULL; + + while ((c = getopt(argc, argv, "p:")) != -1) { + switch (c) { + case 'p': + policy = optarg; + break; + default: + usage(); + return (1); + } + } + + argc -= optind; + argv += optind; + + if (argc < 1 || argc > 2) { + usage(); + return (1); + } + + obe_name = argv[0]; + + if (argc > 1) { + /* Snapshot name provided */ + snap_name = argv[1]; + } + + if (be_nvl_alloc(&be_attrs) != 0) + return (1); + + + if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) + goto out; + + if (policy != NULL && be_nvl_add_string(be_attrs, + BE_ATTR_POLICY, policy) != 0) + goto out; + + if (snap_name != NULL && be_nvl_add_string(be_attrs, + BE_ATTR_SNAP_NAME, snap_name) != 0) + goto out; + + err = be_create_snapshot(be_attrs); + + switch (err) { + case BE_SUCCESS: + if (!snap_name) { + /* + * We requested an auto named snapshot; find out + * the snapshot name that was created for us. + */ + if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, + &snap_name) != 0) { + (void) fprintf(stderr, _("failed to get %s " + "attribute\n"), BE_ATTR_SNAP_NAME); + err = 1; + break; + } + + (void) printf(_("Auto named snapshot: %s\n"), + snap_name); + } + (void) printf(_("Created successfully\n")); + break; + case BE_ERR_BE_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid BE.\nPlease check that the name of " + "the BE provided is correct.\n"), obe_name); + break; + case BE_ERR_SS_EXISTS: + (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n" + "Please choose a different snapshot name.\n"), obe_name, + snap_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + (void) fprintf(stderr, _("Unable to create snapshot %s.\n"), + snap_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + default: + (void) fprintf(stderr, _("Unable to create snapshot %s.\n"), + snap_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + nvlist_free(be_attrs); + return (err); +} + +static int +be_do_destroy(int argc, char **argv) +{ + nvlist_t *be_attrs; + boolean_t is_snap = B_FALSE; + boolean_t suppress_prompt = B_FALSE; + int err = 1; + int c; + int destroy_flags = 0; + char *snap_name; + char *be_name; + + while ((c = getopt(argc, argv, "fFs")) != -1) { + switch (c) { + case 'f': + destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT; + break; + case 's': + destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS; + break; + case 'F': + suppress_prompt = B_TRUE; + break; + default: + usage(); + return (1); + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + usage(); + return (1); + } + + be_name = argv[0]; + if (!suppress_prompt && !confirm_destroy(be_name)) { + (void) printf(_("%s has not been destroyed.\n"), be_name); + return (0); + } + + if ((snap_name = strrchr(be_name, '@')) != NULL) { + if (snap_name[1] == '\0') { + usage(); + return (1); + } + + is_snap = B_TRUE; + *snap_name = '\0'; + snap_name++; + } + + if (be_nvl_alloc(&be_attrs) != 0) + return (1); + + + if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0) + goto out; + + if (is_snap) { + if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, + snap_name) != 0) + goto out; + + err = be_destroy_snapshot(be_attrs); + } else { + if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS, + destroy_flags) != 0) + goto out; + + err = be_destroy(be_attrs); + } + + switch (err) { + case BE_SUCCESS: + (void) printf(_("Destroyed successfully\n")); + break; + case BE_ERR_MOUNTED: + (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); + (void) fprintf(stderr, _("It is currently mounted and must be " + "unmounted before it can be destroyed.\n" "Use 'beadm " + "unmount %s' to unmount the BE before destroying\nit or " + "'beadm destroy -f %s'.\n"), be_name, be_name); + break; + case BE_ERR_DESTROY_CURR_BE: + (void) fprintf(stderr, _("%s is the currently active BE and " + "cannot be destroyed.\nYou must boot from another BE in " + "order to destroy %s.\n"), be_name, be_name); + break; + case BE_ERR_ZONES_UNMOUNT: + (void) fprintf(stderr, _("Unable to destroy one of " "%s's " + "zone BE's.\nUse 'beadm destroy -f %s' or " + "'zfs -f destroy <dataset>'.\n"), be_name, be_name); + break; + case BE_ERR_SS_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid snapshot.\nPlease check that the name of " + "the snapshot provided is correct.\n"), snap_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + default: + (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + nvlist_free(be_attrs); + return (err); +} + +static int +be_do_destroy_snapshot(int argc, char **argv) +{ + nvlist_t *be_attrs; + boolean_t suppress_prompt = B_FALSE; + int err = 1; + char c; + char *obe_name; + char *snap_name; + char *sn; + int sz; + + while ((c = getopt(argc, argv, "F")) != -1) { + switch (c) { + case 'F': + suppress_prompt = B_TRUE; + break; + default: + usage(); + return (1); + } + } + + argc -= optind; + argv += optind; + + if (argc != 2) { + usage(); + return (1); + } + + obe_name = argv[0]; + snap_name = argv[1]; + + sz = asprintf(&sn, "%s@%s", obe_name, snap_name); + if (sz < 0) { + (void) fprintf(stderr, _("internal error: " + "out of memory\n")); + return (1); + } + + if (!suppress_prompt && !confirm_destroy(sn)) { + (void) printf(_("%s has not been destroyed.\n"), sn); + free(sn); + return (0); + } + + free(sn); + + + if (be_nvl_alloc(&be_attrs) != 0) + return (1); + + + if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) + goto out; + + if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0) + goto out; + + err = be_destroy_snapshot(be_attrs); + + switch (err) { + case BE_SUCCESS: + (void) printf(_("Destroyed successfully\n")); + break; + case BE_ERR_BE_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid BE.\nPlease check that the name of " + "the BE provided is correct.\n"), obe_name); + break; + case BE_ERR_SS_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid snapshot.\nPlease check that the name of " + "the snapshot provided is correct.\n"), snap_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + (void) fprintf(stderr, _("Unable to destroy snapshot %s.\n"), + snap_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + default: + (void) fprintf(stderr, _("Unable to destroy snapshot %s.\n"), + snap_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + nvlist_free(be_attrs); + return (err); +} + +static int +be_do_list(int argc, char **argv) +{ + be_node_list_t *be_nodes = NULL; + boolean_t all = B_FALSE; + boolean_t dsets = B_FALSE; + boolean_t snaps = B_FALSE; + boolean_t parsable = B_FALSE; + int err = 1; + int c = 0; + char *be_name = NULL; + + while ((c = getopt(argc, argv, "nadsH")) != -1) { + switch (c) { + case 'a': + all = B_TRUE; + break; + case 'd': + dsets = B_TRUE; + break; + case 's': + snaps = B_TRUE; + break; + case 'H': + parsable = B_TRUE; + break; + default: + usage(); + return (1); + } + } + + if (all) { + if (dsets) { + (void) fprintf(stderr, _("Invalid options: -a and %s " + "are mutually exclusive.\n"), "-d"); + usage(); + return (1); + } + if (snaps) { + (void) fprintf(stderr, _("Invalid options: -a and %s " + "are mutually exclusive.\n"), "-s"); + usage(); + return (1); + } + + dsets = B_TRUE; + snaps = B_TRUE; + } + + argc -= optind; + argv += optind; + + + if (argc == 1) + be_name = argv[0]; + + err = be_list(be_name, &be_nodes); + + switch (err) { + case BE_SUCCESS: + print_nodes(be_name, dsets, snaps, parsable, be_nodes); + break; + case BE_ERR_BE_NOENT: + if (be_name == NULL) + (void) fprintf(stderr, _("No boot environments found " + "on this system.\n")); + else { + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid BE.\nPlease check that the name of " + "the BE provided is correct.\n"), be_name); + } + break; + default: + (void) fprintf(stderr, _("Unable to display Boot " + "Environment\n")); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + + if (be_nodes != NULL) + be_free_list(be_nodes); + return (err); +} + +static int +be_do_mount(int argc, char **argv) +{ + nvlist_t *be_attrs; + boolean_t shared_fs = B_FALSE; + int err = 1; + int c; + int mount_flags = 0; + char *obe_name; + char *mountpoint; + char *tmp_mp = NULL; + + while ((c = getopt(argc, argv, "s:")) != -1) { + switch (c) { + case 's': + shared_fs = B_TRUE; + + mount_flags |= BE_MOUNT_FLAG_SHARED_FS; + + if (strcmp(optarg, "rw") == 0) { + mount_flags |= BE_MOUNT_FLAG_SHARED_RW; + } else if (strcmp(optarg, "ro") != 0) { + (void) fprintf(stderr, _("The -s flag " + "requires an argument [ rw | ro ]\n")); + usage(); + return (1); + } + + break; + default: + usage(); + return (1); + } + } + + argc -= optind; + argv += optind; + + if (argc < 1 || argc > 2) { + usage(); + return (1); + } + + obe_name = argv[0]; + + if (argc == 2) { + mountpoint = argv[1]; + if (mountpoint[0] != '/') { + (void) fprintf(stderr, _("Invalid mount point %s. " + "Mount point must start with a /.\n"), mountpoint); + return (1); + } + } else { + const char *tmpdir = getenv("TMPDIR"); + const char *tmpname = "tmp.XXXXXX"; + int sz; + + if (tmpdir == NULL) + tmpdir = "/tmp"; + + sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname); + if (sz < 0) { + (void) fprintf(stderr, _("internal error: " + "out of memory\n")); + return (1); + } + + mountpoint = mkdtemp(tmp_mp); + } + + if (be_nvl_alloc(&be_attrs) != 0) + return (1); + + if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) + goto out; + + if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0) + goto out; + + if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS, + mount_flags) != 0) + goto out; + + err = be_mount(be_attrs); + + switch (err) { + case BE_SUCCESS: + (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint); + break; + case BE_ERR_BE_NOENT: + err = 1; + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid BE.\nPlease check that the name of " + "the BE provided is correct.\n"), obe_name); + break; + case BE_ERR_MOUNTED: + (void) fprintf(stderr, _("%s is already mounted.\n" + "Please unmount the BE before mounting it again.\n"), + obe_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + err = 1; + (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + default: + err = 1; + (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + if (tmp_mp != NULL) + free(tmp_mp); + nvlist_free(be_attrs); + return (err); +} + +static int +be_do_unmount(int argc, char **argv) +{ + nvlist_t *be_attrs; + char *obe_name; + int err = 1; + int c; + int unmount_flags = 0; + + while ((c = getopt(argc, argv, "f")) != -1) { + switch (c) { + case 'f': + unmount_flags |= BE_UNMOUNT_FLAG_FORCE; + break; + default: + usage(); + return (1); + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + usage(); + return (1); + } + + obe_name = argv[0]; + + if (be_nvl_alloc(&be_attrs) != 0) + return (1); + + + if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) + goto out; + + if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS, + unmount_flags) != 0) + goto out; + + err = be_unmount(be_attrs); + + switch (err) { + case BE_SUCCESS: + (void) printf(_("Unmounted successfully\n")); + break; + case BE_ERR_BE_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid BE.\nPlease check that the name of " + "the BE provided is correct.\n"), obe_name); + break; + case BE_ERR_UMOUNT_CURR_BE: + (void) fprintf(stderr, _("%s is the currently active BE.\n" + "It cannot be unmounted unless another BE is the " + "currently active BE.\n"), obe_name); + break; + case BE_ERR_UMOUNT_SHARED: + (void) fprintf(stderr, _("%s is a shared file system and it " + "cannot be unmounted.\n"), obe_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + default: + (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + nvlist_free(be_attrs); + return (err); +} + +static int +be_do_rename(int argc, char **argv) +{ + nvlist_t *be_attrs; + char *obe_name; + char *nbe_name; + int err = 1; + + argc -= optind; + argv += optind; + + if (argc != 2) { + usage(); + return (1); + } + + obe_name = argv[0]; + nbe_name = argv[1]; + + if (be_nvl_alloc(&be_attrs) != 0) + return (1); + + if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) + goto out; + + if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0) + goto out; + + err = be_rename(be_attrs); + + switch (err) { + case BE_SUCCESS: + (void) printf(_("Renamed successfully\n")); + break; + case BE_ERR_BE_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid BE.\nPlease check that the name of " + "the BE provided is correct.\n"), obe_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + (void) fprintf(stderr, _("Rename of BE %s failed.\n"), + obe_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + default: + (void) fprintf(stderr, _("Rename of BE %s failed.\n"), + obe_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + nvlist_free(be_attrs); + return (err); +} + +static int +be_do_rollback(int argc, char **argv) +{ + nvlist_t *be_attrs; + char *obe_name; + char *snap_name; + int err = 1; + + argc -= optind; + argv += optind; + + if (argc < 1 || argc > 2) { + usage(); + return (1); + } + + obe_name = argv[0]; + if (argc == 2) + snap_name = argv[1]; + else { /* argc == 1 */ + if ((snap_name = strrchr(obe_name, '@')) != NULL) { + if (snap_name[1] == '\0') { + usage(); + return (1); + } + + snap_name[0] = '\0'; + snap_name++; + } else { + usage(); + return (1); + } + } + + if (be_nvl_alloc(&be_attrs) != 0) + return (1); + + if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0) + goto out; + + if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0) + goto out; + + err = be_rollback(be_attrs); + + switch (err) { + case BE_SUCCESS: + (void) printf(_("Rolled back successfully\n")); + break; + case BE_ERR_BE_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid BE.\nPlease check that the name of " + "the BE provided is correct.\n"), obe_name); + break; + case BE_ERR_SS_NOENT: + (void) fprintf(stderr, _("%s does not exist or appear " + "to be a valid snapshot.\nPlease check that the name of " + "the snapshot provided is correct.\n"), snap_name); + break; + case BE_ERR_PERM: + case BE_ERR_ACCESS: + (void) fprintf(stderr, _("Rollback of BE %s snapshot %s " + "failed.\n"), obe_name, snap_name); + (void) fprintf(stderr, _("You have insufficient privileges to " + "execute this command.\n")); + break; + default: + (void) fprintf(stderr, _("Rollback of BE %s snapshot %s " + "failed.\n"), obe_name, snap_name); + (void) fprintf(stderr, "%s\n", be_err_to_str(err)); + } + +out: + nvlist_free(be_attrs); + return (err); +}
--- a/usr/src/cmd/beadm/beadm.py Thu Dec 16 09:43:44 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1058 +0,0 @@ -#!/usr/bin/python2.6 -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright (c) 2008, 2010, 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 - -from beadm import _ -from beadm.BootEnvironment import * -import beadm.messages as msg -import libbe_py 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 list [[-a] | [-d] [-s]] [-H] [beName] - beadm mount beName mountpoint - beadm rename beName newBeName - 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() - - 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 - """ - - 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(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 - - 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 - """ - - force_unmount = 0 - suppress_prompt = False - be_active_on_boot = None - be = BootEnvironment() - - try: - opts_args, be.trgt_be_name_or_snapshot = getopt.getopt(opts, "fF") - 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 - - 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 - - if num_sf_opts > 1 or num_f_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() - - is_snapshot = False - - if "@" in be.trgt_be_name_or_snapshot[0]: - is_snapshot = True - be_name, snap_name = be.trgt_be_name_or_snapshot[0].split("@") - if lb.beVerifyBEName(be_name) != 0: - msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1) - return 1 - else: - if lb.beVerifyBEName(be.trgt_be_name_or_snapshot[0]) != 0: - msg.printMsg(msg.Msgs.BEADM_ERR_BENAME, None, -1) - return 1 - - # Get the 'active' BE and the 'active on boot' BE. - be_active, be_active_on_boot = getActiveBEAndActiveOnBootBE() - - # If the user is trying to destroy the 'active' BE then quit now. - if not is_snapshot and be_active == be.trgt_be_name_or_snapshot[0]: - 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.trgt_be_name_or_snapshot[0], 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.trgt_be_name_or_snapshot[0] 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 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 - - # Coelesce options to pass to displayBEs - - 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 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 - """ - - be = BootEnvironment() - - mountpoint = None - - try: - be_name_mnt_point = getopt.getopt(opts, "")[1] - 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) - 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 - """ - - 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 - """ - - 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 - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# End of CLI public functions -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# 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 == "upgrade": - rc = upgrade(opts_args) - elif subcommand == "unmount" or \ - subcommand == "umount": #aliased for convenience - rc = unmount(opts_args) - elif subcommand == "verify": - rc = verify() - else: - msg.printMsg(msg.Msgs.BEADM_ERR_ILL_SUBCOMMAND, - subcommand, -1) - usage() - - return(rc) - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -def main(): - """main function.""" - - gettext.install("beadm", "/usr/lib/locale") - - if not isBeadmSupported(): - return(1) - - 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), 0644) - except OSError: - 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: - 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.""" - - be_name, snap_name = be.trgt_be_name_or_snapshot[0].split("@") - - 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.""" - - be_name, snap_name = be.src_be_name_or_snapshot.split("@") - - 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, opts[0]) - 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 isBeadmSupported(): - """ - Currently the only environment that beadm is supported in is - a global zone. Check that beadm is executing in a - global zone and not in a non-global zone. - """ - - try: - proc = subprocess.Popen("/sbin/zonename", - stdout = subprocess.PIPE, - stderr = subprocess.STDOUT) - # Grab stdout. - zonename = proc.communicate()[0].rstrip('\n') - except OSError, (errno, strerror): - msg.printMsg(msg.Msgs.BEADM_ERR_OS, strerror, -1) - # Ignore a failed attempt to retreive the zonename. - return True - - if zonename != "global": - msg.printMsg(msg.Msgs.BEADM_ERR_NOT_SUPPORTED_NGZ, None, -1) - return False - - return True - - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -if __name__ == "__main__": - try: - RC = main() - except SystemExit, e: - raise e - except: - traceback.print_exc() - sys.exit(99) - sys.exit(RC)
--- a/usr/src/cmd/beadm/messages.py Thu Dec 16 09:43:44 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. -# - -""" -beadm - The Boot Environment Administration tool. - -A module containing all of the messages output by beadm. -""" - -import sys -from beadm import _ - -class Msgs: - """Indices corresponding to message numbers for beadm.""" - - (BEADM_ERR_ACTIVATE, - BEADM_ERR_BE_EXISTS, - BEADM_ERR_SNAP_EXISTS, - BEADM_ERR_CREATE, - BEADM_ERR_DESTROY, - BEADM_ERR_DESTROY_ACTIVE, - BEADM_ERR_BE_DOES_NOT_EXIST, - BEADM_ERR_NO_BES_EXIST, - BEADM_ERR_MSG_SUB, - BEADM_ERR_ILL_SUBCOMMAND, - BEADM_ERR_INVALID_RESPONSE, - BEADM_ERR_LIST, - BEADM_ERR_LIST_DATA, - BEADM_ERR_LOG_CREATE, - BEADM_ERR_LOG_RM, - BEADM_ERR_MOUNT, - BEADM_ERR_MOUNT_EXISTS, - BEADM_ERR_MOUNTED, - BEADM_ERR_MOUNTPOINT, - BEADM_ERR_MUTUALLY_EXCL, - BEADM_ERR_NO_MSG, - BEADM_ERR_NO_ZPOOL, - BEADM_ERR_NOT_SUPPORTED_NGZ, - BEADM_ERR_OPT_ARGS, - BEADM_ERR_OS, - BEADM_ERR_PERMISSIONS, - BEADM_ERR_RENAME, - BEADM_ERR_SHARED_FS, - BEADM_ERR_SNAP_DOES_NOT_EXISTS, - BEADM_ERR_UNMOUNT, - BEADM_ERR_UNMOUNT_ACTIVE, - BEADM_ERR_BENAME, - BEADM_MSG_ACTIVE_ON_BOOT, - BEADM_MSG_DESTROY, - BEADM_MSG_DESTROY_NO, - BEADM_MSG_BE_CREATE_START, - BEADM_MSG_BE_CREATE_SUCCESS, - BEADM_MSG_FREE_FORMAT, - ) = range(38) - - # Indices corresponding to message numbers for libbe that we are - # interested in expanding messages. - (BE_ERR_ACCESS, - BE_ERR_ACTIVATE_CURR, - BE_ERR_AUTONAME, - BE_ERR_BE_NOENT, - BE_ERR_BUSY, - BE_ERR_CANCELED, - BE_ERR_CLONE, - BE_ERR_COPY, - BE_ERR_CREATDS, - BE_ERR_CURR_BE_NOT_FOUND, - BE_ERR_DESTROY, - BE_ERR_DEMOTE, - BE_ERR_DSTYPE, - BE_ERR_BE_EXISTS, - BE_ERR_INIT, - BE_ERR_INTR, - BE_ERR_INVAL, - BE_ERR_INVALPROP, - BE_ERR_INVALMOUNTPOINT, - BE_ERR_MOUNT, - BE_ERR_MOUNTED, - BE_ERR_NAMETOOLONG, - BE_ERR_NOENT, - BE_ERR_POOL_NOENT, - BE_ERR_NODEV, - BE_ERR_NOTMOUNTED, - BE_ERR_NOMEM, - BE_ERR_NONINHERIT, - BE_ERR_NXIO, - BE_ERR_NOSPC, - BE_ERR_NOTSUP, - BE_ERR_OPEN, - BE_ERR_PERM, - BE_ERR_UNAVAIL, - BE_ERR_PROMOTE, - BE_ERR_ROFS, - BE_ERR_READONLYDS, - BE_ERR_READONLYPROP, - BE_ERR_SS_EXISTS, - BE_ERR_SS_NOENT, - BE_ERR_UMOUNT, - BE_ERR_UMOUNT_CURR_BE, - BE_ERR_UMOUNT_SHARED, - BE_ERR_UNKNOWN, - BE_ERR_ZFS, - BE_ERR_DESTROY_CURR_BE, - BE_ERR_GEN_UUID, - BE_ERR_PARSE_UUID, - BE_ERR_NO_UUID, - BE_ERR_ZONE_NO_PARENTBE, - BE_ERR_ZONE_MULTIPLE_ACTIVE, - BE_ERR_ZONE_NO_ACTIVE_ROOT, - BE_ERR_ZONE_ROOT_NOT_LEGACY, - BE_ERR_NO_MOUNTED_ZONE, - BE_ERR_MOUNT_ZONEROOT, - BE_ERR_UMOUNT_ZONEROOT, - BE_ERR_ZONES_UNMOUNT, - BE_ERR_FAULT, - BE_ERR_RENAME_ACTIVE, - BE_ERR_NO_MENU, - BE_ERR_DEV_BUSY, - BE_ERR_BAD_MENU_PATH, - BE_ERR_ZONE_SS_EXISTS - ) = range(4000, 4063) - - # Error message dictionaries. - mBeadmErr = {} - mBeadmOut = {} - mBeadmLog = {} - - # Errors from beadm (to stderr). - mBeadmErr[BEADM_ERR_ACTIVATE] = _("Unable to activate %(0)s.\n%(1)s") - mBeadmErr[BEADM_ERR_BE_EXISTS] = _("BE %s already exists. Please choose a different BE name.") - mBeadmErr[BEADM_ERR_BE_DOES_NOT_EXIST] = _("%s does not exist or appear to be a valid BE.\nPlease check that the name of the BE provided is correct.") - mBeadmErr[BEADM_ERR_NO_BES_EXIST] = _("No boot environments found on this system.") - mBeadmErr[BEADM_ERR_CREATE] = _("Unable to create %(0)s.\n%(1)s") - mBeadmErr[BEADM_ERR_DESTROY] = _("Unable to destroy %(0)s.\n%(1)s") - mBeadmErr[BEADM_ERR_DESTROY_ACTIVE] = _("%(0)s is the currently active BE and cannot be destroyed.\nYou must boot from another BE in order to destroy %(1)s.") - mBeadmErr[BEADM_ERR_MSG_SUB] = _("Fatal error. No message associated with index %d") - mBeadmErr[BEADM_ERR_ILL_SUBCOMMAND] = _("Illegal subcommand %s") - mBeadmErr[BEADM_ERR_INVALID_RESPONSE] = _("Invalid response. Please enter 'y' or 'n'.") - mBeadmErr[BEADM_ERR_LIST] = _("Unable to display Boot Environment: %s") - mBeadmErr[BEADM_ERR_LIST_DATA] = _("Unable to process list data.") - mBeadmErr[BEADM_ERR_LOG_CREATE] = _("Unable to create log file.") - mBeadmErr[BEADM_ERR_LOG_RM] = _("Unable to remove %s") - mBeadmErr[BEADM_ERR_MOUNT] = _("Unable to mount %(0)s.\n%(1)s") - mBeadmErr[BEADM_ERR_MOUNT_EXISTS] = _("%s is already mounted.\nPlease unmount the BE before mounting it again.") - mBeadmErr[BEADM_ERR_MOUNTED] = _("Unable to destroy %(0)s.\nIt is currently mounted and must be unmounted before it can be destroyed.\nUse 'beadm unmount %(1)s' to unmount the BE before destroying\nit or 'beadm destroy -fF %(2)s'.") - mBeadmErr[BEADM_ERR_MOUNTPOINT] = _("Invalid mount point %s. Mount point must start with a /.") - mBeadmErr[BEADM_ERR_MUTUALLY_EXCL] = _("Invalid options: %s are mutually exclusive.") - mBeadmErr[BEADM_ERR_NO_MSG] = _("Unable to find message for error code: %d") - mBeadmErr[BEADM_ERR_NO_ZPOOL] = _("BE: %s was not found in any pool.\n The pool may not exist or the name of the BE is not correct.") - mBeadmErr[BEADM_ERR_NOT_SUPPORTED_NGZ] = _("beadm is not supported in a non-global zone.") - mBeadmErr[BEADM_ERR_OPT_ARGS] = _("Invalid options and arguments:") - mBeadmErr[BEADM_ERR_OS] = _("System error: %s") - mBeadmErr[BEADM_ERR_RENAME] = _("Rename of BE %(0)s failed.\n%(1)s") - mBeadmErr[BEADM_ERR_SHARED_FS] = _("%s is a shared file system and it cannot be unmounted.") - mBeadmErr[BEADM_ERR_SNAP_DOES_NOT_EXISTS] = _("%s does not exist or appear to be a valid snapshot.\nPlease check that the name of the snapshot provided is correct.") - mBeadmErr[BEADM_ERR_SNAP_EXISTS] = _("Snapshot %s already exists.\n Please choose a different snapshot name.") - mBeadmErr[BEADM_ERR_UNMOUNT] = _("Unable to unmount %(0)s.\n%(1)s") - mBeadmErr[BEADM_ERR_UNMOUNT_ACTIVE] = _("%s is the currently active BE.\nIt cannot be unmounted unless another BE is the currently active BE.") - mBeadmErr[BE_ERR_ZONES_UNMOUNT] = _("Unable to destroy one of %(0)s's zone BE's.\nUse 'beadm destroy -fF %(1)s' or 'zfs -f destroy <dataset>'.") - mBeadmErr[BEADM_ERR_PERMISSIONS] = _("You have insufficient privileges to execute this command.\nEither use 'pfexec' to execute the command or become superuser.") - mBeadmErr[BEADM_ERR_BENAME] = _("The BE name provided is invalid.\n Please check it and try again.") - - # Catchall - mBeadmErr[BEADM_MSG_FREE_FORMAT] = "%s" - - # Messages from beadm (to stdout). - mBeadmOut[BEADM_MSG_ACTIVE_ON_BOOT] = _("The BE that was just destroyed was the 'active on boot' BE.\n%s is now the 'active on boot' BE. Use 'beadm activate' to change it.\n") - mBeadmOut[BEADM_MSG_DESTROY] = _("Are you sure you want to destroy %s? This action cannot be undone(y/[n]):") - mBeadmOut[BEADM_MSG_DESTROY_NO] = _("%s has not been destroyed.\n") - - # Messages from beadm (to log only). - mBeadmLog[BEADM_MSG_BE_CREATE_START] = "Attempting to create %s" - mBeadmLog[BEADM_MSG_BE_CREATE_SUCCESS] = "%s was created successfully" - -msgLog, msgOut, msgErr = range(3) - -def printLog(string, log_fd): - """Print log.""" - - sendMsg(string, msgLog, log_fd) - -def printStdout(string, log_fd): - """Print standard output.""" - - sendMsg(string, msgOut, log_fd) - -def printStderr(string, log_fd): - """Print standard error.""" - - sendMsg(string, msgErr, log_fd) - -def composeMsg(string, txt=None): - """ - Compose the message to be dispayed. - txt can be either a list or string object. - Return the newly composed string. - """ - - try: - msg = string % txt - except TypeError: - msg = string - - return (msg) - -def sendMsg(string, mode, log_fd=-1): - """Send message.""" - - if mode == msgOut: - print >> sys.stdout, string, - if mode == msgErr: - print >> sys.stderr, string - if log_fd != -1 or mode == msgLog: - log_fd.write(string + "\n") - -def printMsg(msg_idx=-1, txt="", log_fd=-1): - """Print the message based on the message index.""" - - if msg_idx in Msgs.mBeadmErr: - printStderr(composeMsg(Msgs.mBeadmErr[msg_idx], txt), - log_fd) - elif msg_idx in Msgs.mBeadmOut: - printStdout(composeMsg(Msgs.mBeadmOut[msg_idx], txt), - log_fd) - elif msg_idx in Msgs.mBeadmLog: - printLog(composeMsg(Msgs.mBeadmLog[msg_idx], txt), log_fd) - else: - printStderr(composeMsg(Msgs.mLibbe[BEADM_ERR_MSG_SUB], - msg_idx), -1) - sys.exit(1) - -def getMsg(msg_idx=-1, txt=""): - """Print the message based on the message index.""" - - if msg_idx in Msgs.mBeadmErr: - return(composeMsg(Msgs.mBeadmErr[msg_idx], txt)) - elif msg_idx in Msgs.mBeadmOut: - return(composeMsg(Msgs.mBeadmOut[msg_idx], txt)) - elif msg_idx in Msgs.mBeadmLog: - return(composeMsg(Msgs.mBeadmLog[msg_idx], txt)) - else: - return(composeMsg(Msgs.mLibbe[BEADM_ERR_MSG_SUB])) - sys.exit(1)
--- a/usr/src/lib/libbe/Makefile Thu Dec 16 09:43:44 2010 -0800 +++ b/usr/src/lib/libbe/Makefile Mon Dec 27 21:47:11 2010 +0300 @@ -31,14 +31,12 @@ HDRDIR= common SUBDIRS= $(MACH) -TESTDIR= tbeadm all := TARGET= all clean := TARGET= clean clobber := TARGET= clobber install := TARGET= install lint := TARGET= lint -test := TARGET= test POFILE = libbe.po MSGFILES = `$(GREP) -l gettext $(HDRDIR)/*.[ch]` @@ -47,7 +45,7 @@ all install lint: install_h $(SUBDIRS) -clean clobber: $(SUBDIRS) $(TESTDIR) +clean clobber: $(SUBDIRS) $(POFILE): pofile_MSGFILES @@ -57,12 +55,6 @@ _msg: $(MSGDOMAINPOFILE) -test: - cd tbeadm; pwd; $(MAKE) install - -$(TESTDIR): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET)
--- a/usr/src/lib/libbe/tbeadm/Makefile Thu Dec 16 09:43:44 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -# - -ARCH = $(TARGET_ARCH:-%=%) - -PROG = tbeadm - - -OBJS = tbeadm.o -SRCS = $(OBJS:%.o=../%.c) - -include ../../Makefile.lib - -#LIBS= $(DYNLIB) - -INCLUDE = -I../common - -STATICDEPLIBS = ../$(ARCH)/libbe.a -STATICLDLIBS += -linstzones -L/lib -L../$(ARCH) -lzfs -lnvpair \ - -luuid -lgen -Bstatic -lbe -Bdynamic - -DEPLIBS = ../$(ARCH)/libbe.so.1 -LDLIBS += -L/lib -L../pics/$(ARCH) -lzfs -lnvpair -lbe - -CPPFLAGS += -D_LARGEFILE64_SOURCE=1 -D_REENTRANT ${INCLUDE} -CFLAGS += -g -DDEBUG - - -$(PROG): $(OBJS) $(STATICDEPLIBS) - $(LINK.c) -o $@ $@.c $(OBJS) $(STATICLDLIBS) - $(POST_PROCESS) - -all: $(PROG) - -install_h: - -install: all - -lint: - $(LINT.c) $(SRCS) $(LDLIBS) - -clobber: clean - $(RM) tbeadm.o - -clean: - $(RM) tbeadm -
--- a/usr/src/lib/libbe/tbeadm/tbeadm.c Thu Dec 16 09:43:44 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,837 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - */ - -/* - * System includes - */ - -#include <stdio.h> -#include <strings.h> -#include <libzfs.h> - -#include "libbe.h" - -static int be_do_create(int argc, char **argv); -static int be_do_destroy(int argc, char **argv); -static int be_do_list(int argc, char **argv); -static int be_do_mount(int argc, char **argv); -static int be_do_unmount(int argc, char **argv); -static int be_do_rename(int argc, char **argv); -static int be_do_activate(int argc, char **argv); -static int be_do_create_snapshot(int argc, char **argv); -static int be_do_destroy_snapshot(int argc, char **argv); -static int be_do_rollback(int argc, char **argv); -static void usage(void); - -typedef struct be_command { - const char *name; - int (*func)(int argc, char **argv); -} be_command_t; - -static be_command_t command_table[] = { - { "create", be_do_create }, - { "destroy", be_do_destroy }, - { "list", be_do_list }, - { "mount", be_do_mount }, - { "unmount", be_do_unmount }, - { "rename", be_do_rename }, - { "activate", be_do_activate }, - { "create_snap", be_do_create_snapshot }, - { "destroy_snap", be_do_destroy_snapshot }, -}; - -static int fs_num = 2; -static int shared_fs_num = 2; -static char *fs_names[2] = {"/", "/opt"}; -static char *shared_fs_names[4] = {"/export", "/export/home"}; - -static void -usage(void) -{ - (void) printf("usage:\n" - "\ttbeadm\n" - "\ttbeadm create [-d BE_desc] [-e nonActiveBe | -i] \n" - "\t\t[-o property=value] ... [-p zpool] [beName]\n" - "\ttbeadm destroy [-fs] beName\n" - "\ttbeadm create_snap [-p policy] beName [snapshot]\n" - "\ttbeadm destroy_snap beName snapshot\n" - "\ttbeadm list [-s] [beName]\n" - "\ttbeadm mount [-s ro|rw] beName mountpoint\n" - "\ttbeadm unmount [-f] beName\n" - "\ttbeadm rename origBeName newBeName\n" - "\ttbeadm activate beName\n" - "\ttbeadm rollback beName snapshot\n"); -} - -int -main(int argc, char **argv) { - - if (argc < 2) { - usage(); - return (1); - } - - /* Turn error printing on */ - libbe_print_errors(B_TRUE); - - if (strcmp(argv[1], "create") == 0) { - return (be_do_create(argc - 1, argv + 1)); - } else if (strcmp(argv[1], "destroy") == 0) { - return (be_do_destroy(argc - 1, argv + 1)); - } else if (strcmp(argv[1], "list") == 0) { - return (be_do_list(argc - 1, argv + 1)); - } else if (strcmp(argv[1], "mount") == 0) { - return (be_do_mount(argc - 1, argv + 1)); - } else if (strcmp(argv[1], "unmount") == 0) { - return (be_do_unmount(argc - 1, argv + 1)); - } else if (strcmp(argv[1], "rename") == 0) { - return (be_do_rename(argc - 2, argv + 2)); - } else if (strcmp(argv[1], "activate") == 0) { - return (be_do_activate(argc - 2, argv + 2)); - } else if (strcmp(argv[1], "create_snap") == 0) { - return (be_do_create_snapshot(argc - 1, argv + 1)); - } else if (strcmp(argv[1], "destroy_snap") == 0) { - return (be_do_destroy_snapshot(argc - 2, argv + 2)); - } else if (strcmp(argv[1], "rollback") == 0) { - return (be_do_rollback(argc - 2, argv + 2)); - } else { - usage(); - return (1); - } - - /* NOTREACHED */ -} - -static int -be_do_create(int argc, char **argv) -{ - nvlist_t *be_attrs; - char *obe_name = NULL; - char *snap_name = NULL; - char *nbe_zpool = NULL; - char *nbe_name = NULL; - char *nbe_desc = NULL; - nvlist_t *zfs_props = NULL; - char *propname = NULL; - char *propval = NULL; - char *strval = NULL; - boolean_t init = B_FALSE; - int c; - int ret = BE_SUCCESS; - - if (nvlist_alloc(&zfs_props, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - while ((c = getopt(argc, argv, "d:e:io:p:")) != -1) { - switch (c) { - case 'd': - nbe_desc = optarg; - break; - case 'e': - obe_name = optarg; - break; - case 'i': - /* Special option to test be_init() function */ - init = B_TRUE; - break; - case 'o': - if (zfs_props == NULL) { - if (nvlist_alloc(&zfs_props, NV_UNIQUE_NAME, - 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - } - - propname = optarg; - if ((propval = strchr(propname, '=')) == NULL) { - (void) fprintf(stderr, "missing " - "'=' for -o option\n"); - return (1); - } - *propval = '\0'; - propval++; - if (nvlist_lookup_string(zfs_props, propname, - &strval) == 0) { - (void) fprintf(stderr, "property '%s' " - "specified multiple times\n", propname); - return (1); - } - if (nvlist_add_string(zfs_props, propname, propval) - != 0) { - (void) fprintf(stderr, "internal " - "error: out of memory\n"); - return (1); - } - break; - case 'p': - nbe_zpool = optarg; - break; - default: - usage(); - return (1); - } - } - - if (init && obe_name) { - printf("ERROR: -e and -i are exclusive options\n"); - usage(); - return (1); - } - - argc -= optind; - argv += optind; - - if (argc == 1) { - nbe_name = argv[0]; - } else if (argc > 1) { - usage(); - return (1); - } - - if (obe_name) { - /* - * Check if obe_name is really a snapshot name. - * If so, split it out. - */ - char *cp = NULL; - - cp = strrchr(obe_name, '@'); - if (cp != NULL) { - cp[0] = '\0'; - if (cp[1] != NULL && cp[1] != '\0') { - snap_name = cp+1; - } - } - } - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (zfs_props) { - if (nvlist_add_nvlist(be_attrs, BE_ATTR_ZFS_PROPERTIES, - zfs_props) != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ZFS_PROPERTES (%s).\n", zfs_props); - return (1); - } - } - - if (obe_name != NULL) { - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name); - return (1); - } - } - - if (snap_name != NULL) { - if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_SNAP_NANE (%s).\n", snap_name); - return (1); - } - } - - if (nbe_zpool != NULL) { - if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_POOL, nbe_zpool) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_NEW_BE_POOL (%s).\n", nbe_zpool); - return (1); - } - } - - if (nbe_name) { - if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_NEW_BE_NAME (%s).\n", nbe_name); - return (1); - } - } - - if (nbe_desc) { - if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_DESC, nbe_desc) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_NEW_BE_DESC (%s)\n", nbe_desc); - return (1); - } - } - - if (init) { - /* - * Add the default file system test values to test - * creating an initial BE. - */ - if (nvlist_add_uint16(be_attrs, BE_ATTR_FS_NUM, fs_num) != 0) { - printf("nvlist_add_uint16 failed for BE_ATTR_FS_NUM " - "(%d).\n", fs_num); - return (1); - } - - if (nvlist_add_string_array(be_attrs, BE_ATTR_FS_NAMES, - fs_names, fs_num) != 0) { - printf("nvlist_add_string_array failed for " - "BE_ATTR_FS_NAMES\n"); - return (1); - } - - if (nvlist_add_uint16(be_attrs, BE_ATTR_SHARED_FS_NUM, - shared_fs_num) != 0) { - printf("nvlist_add_uint16 failed for " - "BE_ATTR_SHARED_FS_NUM (%d).\n", shared_fs_num); - return (1); - } - - if (nvlist_add_string_array(be_attrs, BE_ATTR_SHARED_FS_NAMES, - shared_fs_names, shared_fs_num) != 0) { - printf("nvlist_add_string_array failed for " - "BE_ATTR_SHARED_FS_NAMES\n"); - return (1); - } - - return (be_init(be_attrs)); - } - - ret = be_copy(be_attrs); - - if (!nbe_name & ret == BE_SUCCESS) { - /* - * We requested an auto named BE; find out the - * name of the BE that was created for us and - * the auto snapshot created from the original BE. - */ - if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, - &nbe_name) != 0) { - printf("failed to get BE_ATTR_NEW_BE_NAME attribute\n"); - ret = 1; - } else { - printf("Auto named BE: %s\n", nbe_name); - } - - if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, - &snap_name) != 0) { - printf("failed to get BE_ATTR_SNAP_NAME attribute\n"); - ret = 1; - } else { - printf("Auto named snapshot: %s\n", snap_name); - } - } - - return (ret); -} - -static int -be_do_destroy(int argc, char **argv) -{ - nvlist_t *be_attrs; - int c; - int destroy_flags = 0; - char *be_name; - - while ((c = getopt(argc, argv, "fs")) != -1) { - switch (c) { - case 'f': - destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT; - break; - case 's': - destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS; - break; - default: - usage(); - return (1); - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) { - usage(); - return (1); - } - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, argv[0]) != 0) { - printf("nvlist_add_string failed for BE_ATTR_NEW_BE_NAME " - "(%s).\n", argv[0]); - return (1); - } - - if (nvlist_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS, destroy_flags) - != 0) { - printf("nvlist_add_uint16 failed for " - "BE_ATTR_DESTROY_FLAGS.\n"); - return (1); - } - - return (be_destroy(be_attrs)); -} - -static int -be_do_list(int argc, char **argv) -{ - int err = BE_SUCCESS; - be_node_list_t *be_nodes; - be_node_list_t *cur_be; - boolean_t snaps = B_FALSE; - int c = 0; - - while ((c = getopt(argc, argv, "s")) != -1) { - switch (c) { - case 's': - snaps = B_TRUE; - break; - default: - usage(); - return (1); - } - } - - argc -= optind; - argv += optind; - - - if (argc == 1) { - err = be_list(argv[0], &be_nodes); - } else { - err = be_list(NULL, &be_nodes); - } - - if (err == BE_SUCCESS) { - - printf( - "BE name\t\tActive\tActive \tDataset\t\t\tPolicy\tUUID\n"); - printf( - " \t\t \ton boot\t \t\t\t \t \n"); - printf( - "-------\t\t------\t-------\t-------\t\t\t------\t----\n"); - - for (cur_be = be_nodes; cur_be != NULL; - cur_be = cur_be->be_next_node) { - - int name_len = strlen(cur_be->be_node_name); - int ds_len = strlen(cur_be->be_root_ds); - - printf("%s%s%s\t%s\t%s%s%s\t%s\n", - cur_be->be_node_name, - name_len < 8 ? "\t\t" : "\t", - cur_be->be_active ? "yes" : "no", - cur_be->be_active_on_boot ? "yes" : "no", - cur_be->be_root_ds, - ds_len < 8 ? "\t\t\t" : - (ds_len < 16 ? "\t\t" : "\t"), - cur_be->be_policy_type, - cur_be->be_uuid_str ? cur_be->be_uuid_str : "-"); - if (snaps) { - be_snapshot_list_t *snapshots = NULL; - printf("Snapshot Name\n"); - printf("--------------\n"); - for (snapshots = cur_be->be_node_snapshots; - snapshots != NULL; snapshots = - snapshots->be_next_snapshot) { - printf("%s\n", - snapshots->be_snapshot_name); - } - } - } - } - - be_free_list(be_nodes); - return (err); -} - -static int -be_do_rename(int argc, char **argv) -{ - nvlist_t *be_attrs; - char *obe_name; - char *nbe_name; - - if (argc < 1 || argc > 2) { - usage(); - return (1); - } - - obe_name = argv[0]; - nbe_name = argv[1]; - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_NEW_BE_NAME (%s).\n", nbe_name); - return (1); - } - - return (be_rename(be_attrs)); - -} - -static int -be_do_create_snapshot(int argc, char **argv) -{ - nvlist_t *be_attrs; - char *obe_name = NULL; - char *snap_name = NULL; - char *policy = NULL; - int c; - int ret = BE_SUCCESS; - - while ((c = getopt(argc, argv, "p:")) != -1) { - switch (c) { - case 'p': - policy = optarg; - break; - default: - usage(); - return (1); - } - } - - argc -= optind; - argv += optind; - - if (argc < 1 || argc > 2) { - usage(); - return (1); - } - - obe_name = argv[0]; - - if (argc > 1) { - /* Snapshot name provided */ - snap_name = argv[1]; - } - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name); - return (1); - } - - if (policy) { - if (nvlist_add_string(be_attrs, BE_ATTR_POLICY, policy) != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_POLICY (%s).\n", policy); - return (1); - } - } - - if (snap_name) { - if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_SNAP_NAME (%s).\n", snap_name); - return (1); - } - } - - ret = be_create_snapshot(be_attrs); - - if (!snap_name && ret == BE_SUCCESS) { - /* - * We requested an auto named snapshot; find out - * the snapshot name that was created for us. - */ - if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, - &snap_name) != 0) { - printf("failed to get BE_ATTR_SNAP_NAME attribute\n"); - ret = 1; - } else { - printf("Auto named snapshot: %s\n", snap_name); - } - } - - return (ret); -} - -static int -be_do_destroy_snapshot(int argc, char **argv) -{ - nvlist_t *be_attrs; - char *obe_name; - char *snap_name; - - if (argc != 2) { - usage(); - return (1); - } - - obe_name = argv[0]; - snap_name = argv[1]; - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_SNAP_NAME (%s).\n", snap_name); - return (1); - } - - return (be_destroy_snapshot(be_attrs)); -} - -static int -be_do_rollback(int argc, char **argv) -{ - nvlist_t *be_attrs; - char *obe_name; - char *snap_name; - - if (argc < 1 || argc > 2) { - usage(); - return (1); - } - - obe_name = argv[0]; - snap_name = argv[1]; - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_SNAP_NAME (%s).\n", snap_name); - return (1); - } - - return (be_rollback(be_attrs)); -} - -static int -be_do_activate(int argc, char **argv) -{ - nvlist_t *be_attrs; - char *obe_name; - - if (argc < 1 || argc > 2) { - usage(); - return (1); - } - - obe_name = argv[0]; - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name); - return (1); - } - - return (be_activate(be_attrs)); -} - -static int -be_do_mount(int argc, char **argv) -{ - nvlist_t *be_attrs; - int c; - boolean_t shared_fs = B_FALSE; - int mount_flags = 0; - char *obe_name; - char *mountpoint; - - while ((c = getopt(argc, argv, "s:")) != -1) { - switch (c) { - case 's': - shared_fs = B_TRUE; - - mount_flags |= BE_MOUNT_FLAG_SHARED_FS; - - if (strcmp(optarg, "rw") == 0) { - mount_flags |= BE_MOUNT_FLAG_SHARED_RW; - } else if (strcmp(optarg, "ro") != 0) { - printf("The -s flag requires an argument " - "[ rw | ro ]\n"); - usage(); - return (1); - } - - break; - default: - usage(); - return (1); - } - } - - argc -= optind; - argv += optind; - - if (argc < 1 || argc > 2) { - usage(); - return (1); - } - - obe_name = argv[0]; - - if (argc == 2) { - mountpoint = argv[1]; - } else { - /* - * XXX - Need to generate a random mountpoint here; - * right now we're just exitting if one isn't supplied. - */ - usage(); - return (1); - } - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_MOUNTPOINT (%s).\n", mountpoint); - return (1); - } - - if (shared_fs) { - if (nvlist_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS, - mount_flags) != 0) { - printf("nvlist_add_uint16 failed for " - "BE_ATTR_MOUNT_FLAGS (%d).\n", mount_flags); - return (1); - } - } - - return (be_mount(be_attrs)); -} - - -static int -be_do_unmount(int argc, char **argv) -{ - nvlist_t *be_attrs; - int c; - int unmount_flags = 0; - char *obe_name; - - while ((c = getopt(argc, argv, "f")) != -1) { - switch (c) { - case 'f': - unmount_flags |= BE_UNMOUNT_FLAG_FORCE; - break; - default: - usage(); - return (1); - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) { - usage(); - return (1); - } - - obe_name = argv[0]; - - if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) { - printf("nvlist_alloc failed.\n"); - return (1); - } - - if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) - != 0) { - printf("nvlist_add_string failed for " - "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name); - return (1); - } - - if (nvlist_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS, unmount_flags) - != 0) { - printf("nvlist_add_uint16 failed for " - "BE_ATTR_UNMOUNT_FLAGS\n"); - return (1); - } - - return (be_unmount(be_attrs)); -}
--- a/usr/src/pkg/manifests/install-beadm.mf Thu Dec 16 09:43:44 2010 -0800 +++ b/usr/src/pkg/manifests/install-beadm.mf Mon Dec 27 21:47:11 2010 +0300 @@ -20,6 +20,7 @@ # # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2010 Nexenta Systems, Inc. All rights reserved. # set name=pkg.fmri value=pkg:/install/beadm@$(PKGVERS) @@ -41,13 +42,6 @@ file path=usr/lib/libbe.so.1 file path=usr/lib/llib-lbe file path=usr/lib/llib-lbe.ln -file path=usr/lib/python2.6/vendor-packages/beadm/BootEnvironment.py mode=0444 -file path=usr/lib/python2.6/vendor-packages/beadm/BootEnvironment.pyc \ - mode=0444 -file path=usr/lib/python2.6/vendor-packages/beadm/__init__.py mode=0444 -file path=usr/lib/python2.6/vendor-packages/beadm/__init__.pyc mode=0444 -file path=usr/lib/python2.6/vendor-packages/beadm/messages.py mode=0444 -file path=usr/lib/python2.6/vendor-packages/beadm/messages.pyc mode=0444 file path=usr/lib/python2.6/vendor-packages/libbe_py.so license cr_Sun license=cr_Sun license lic_CDDL license=lic_CDDL