beadm.c revision 5ee7c79303f6cc727e2df5f1c7332c0f4c9832a3
/*
* 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
* 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 2011 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 "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 void usage(void);
/*
*/
struct col_info {
const char *col_name;
};
/*
* all columns output format
*/
struct hdr_info {
};
/*
* type of possible output formats
*/
enum be_fmt {
};
/*
* command handler description
*/
typedef struct be_command {
const char *name;
} be_command_t;
/*
* sorted list of be commands
*/
static const be_command_t be_command_tbl[] = {
{ "activate", be_do_activate },
{ "create", be_do_create },
{ "destroy", be_do_destroy },
{ "list", be_do_list },
{ "mount", be_do_mount },
{ "unmount", be_do_unmount },
{ "rename", be_do_rename },
{ "rollback", be_do_rollback },
};
static void
usage(void)
{
"\tbeadm subcommand cmd_options\n"
"\n"
"\tsubcommands:\n"
"\n"
"\tbeadm activate beName\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 destroy [-Ffs] beName \n"
"\tbeadm destroy [-F] 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 umount [-f] beName\n"
"\tbeadm rename origBeName newBeName\n"
"\tbeadm rollback beName snapshot\n"
"\tbeadm rollback beName@snapshot\n"));
}
static int
{
const be_command_t *command;
usage();
return (1);
}
int
{
const char *cmdname;
(void) textdomain(TEXT_DOMAIN);
if (argc < 2) {
usage();
return (1);
}
/* Turn error printing off */
}
static void
{
size_t i;
for (i = 0; i < NUM_COLS; i++) {
continue;
if (first) {
} else
}
(void) putchar('\n');
}
static void
{
size_t i;
switch (be_fmt) {
case BE_FMT_ALL:
break;
case BE_FMT_DATASET:
break;
case BE_FMT_SNAPSHOT:
break;
case BE_FMT_DEFAULT:
default:
}
for (i = 0; i < NUM_COLS; i++) {
sizeof (wchar_t));
if (sz > 0) {
if (wcsw > 0)
else
} else {
}
}
}
}
static void
{
int index = 0;
char u;
while (n >= 1024) {
n /= 1024;
index++;
}
u = " KMGTPE"[index];
if (index == 0) {
} else {
int i;
for (i = 2; i >= 0; i--) {
break;
}
}
}
static void
{
char buf[DT_BUF_LEN];
int i;
for (i = 0; i < NUM_COLS; i++)
char *pos;
size_t policy_len = 0;
if (be_fmt == BE_FMT_DEFAULT) {
if (node_name_len > len[0])
len[0] = node_name_len;
} else {
}
if (be_fmt == BE_FMT_DEFAULT)
else if (be_fmt & BE_FMT_SNAPSHOT) {
if (be_fmt == BE_FMT_SNAPSHOT)
}
}
if (be_fmt == BE_FMT_DEFAULT) {
int used_len;
}
}
for (i = 0; i < NUM_COLS; i++)
}
static void
{
char buf[64];
char datetime[DT_BUF_LEN];
if (!parsable) {
}
int ai = 0;
const char *datetime_fmt = "%F %R";
continue;
if (parsable)
active[0] = '\0';
if (cur_be->be_active_on_boot)
if (parsable)
(void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
name,
used,
creation);
else
(void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n",
"-"),
}
}
static void
{
char buf[64];
char datetime[DT_BUF_LEN];
const char *datetime_fmt = "%F %R";
char *pos;
if (parsable)
(void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
"",
"",
used,
creation);
else
(void) printf("%s;%s;%llu;%s;%ld\n",
used,
creation);
else
(void) printf(" %-*s %-*s %-*s %-*s %-*s "
"%-*s\n",
else
(void) printf(" %-*s %-*s %-*s %-*s\n",
}
}
static void
{
char buf[64];
char datetime[DT_BUF_LEN];
if (!parsable)
int ai = 0;
const char *datetime_fmt = "%F %R";
continue;
if (!parsable)
else
active[0] = '\0';
if (cur_be->be_active_on_boot)
if (be_fmt & BE_FMT_DATASET)
if (parsable)
(void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
used,
creation);
else
(void) printf(" %-*s %-*s %-*s %-*s %-*s "
"%-*s\n",
mntpt: "-"),
if (be_fmt & BE_FMT_SNAPSHOT)
}
}
static void
{
if (dsets)
be_fmt |= BE_FMT_DATASET;
if (snaps)
if (be_fmt == BE_FMT_DEFAULT)
else
}
static boolean_t
confirm_destroy(const char *name)
{
char buf[128];
char *answer;
int cflags = REG_EXTENDED;
/* should not happen */
return (res);
}
/* should not happen */
return (res);
}
(void) printf(_("Are you sure you want to destroy %s?\n"
"This action cannot be undone (y/[n]): "), name);
goto out;
"Please enter 'y' or 'n'.\n"));
}
out:
return (res);
}
static int
{
(void) perror(_("nvlist_alloc failed.\n"));
return (1);
}
return (0);
}
static int
{
return (1);
}
return (0);
}
static int
{
name);
return (1);
}
return (0);
}
static int
{
return (1);
}
return (0);
}
static int
{
int err = 1;
char *obe_name;
if (argc != 1) {
usage();
return (1);
}
if (be_nvl_alloc(&be_attrs) != 0)
return (1);
goto out;
switch (err) {
case BE_SUCCESS:
(void) printf(_("Activated successfully\n"));
break;
case BE_ERR_BE_NOENT:
"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:
"execute this command.\n"));
break;
case BE_ERR_ACTIVATE_CURR:
default:
}
out:
return (err);
}
static int
{
int c;
int err = 1;
switch (c) {
case 'a':
break;
case 'd':
break;
case 'e':
break;
case 'o':
return (1);
"'=' for -o option\n"));
goto out2;
}
*propval = '\0';
propval++;
&strval) == 0) {
"specified multiple times\n"), propname);
goto out2;
}
!= 0)
goto out2;
break;
case 'p':
break;
default:
usage();
goto out2;
}
}
if (argc != 1) {
usage();
goto out2;
}
usage();
goto out2;
}
snap_name[0] = '\0';
snap_name++;
}
if (obe_name) {
if (is_snap) {
usage();
goto out2;
}
/*
* Check if obe_name is really a snapshot name.
* If so, split it out.
*/
usage();
goto out2;
}
snap_name[0] = '\0';
snap_name++;
}
} else if (is_snap) {
}
if (be_nvl_alloc(&be_attrs) != 0)
goto out2;
BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
goto out;
BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
goto out;
BE_ATTR_SNAP_NAME, snap_name) != 0)
goto out;
BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
goto out;
BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
goto out;
BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
goto out;
if (is_snap)
else
switch (err) {
case 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.
*/
&nbe_name) != 0) {
"attribute\n"), BE_ATTR_NEW_BE_NAME);
break;
} else
(void) printf(_("Auto named BE: %s\n"),
nbe_name);
&snap_name) != 0) {
"attribute\n"), BE_ATTR_SNAP_NAME);
break;
} else
(void) printf(_("Auto named snapshot: %s\n"),
}
optind = 1;
goto out;
}
(void) printf(_("Created successfully\n"));
break;
case BE_ERR_BE_EXISTS:
"Please choose a different BE name.\n"), nbe_name);
break;
case BE_ERR_SS_EXISTS:
"Please choose a different snapshot name.\n"), obe_name,
break;
case BE_ERR_PERM:
case BE_ERR_ACCESS:
if (is_snap)
"%s.\n"), snap_name);
else
nbe_name);
"execute this command.\n"));
break;
default:
if (is_snap)
"%s.\n"), snap_name);
else
nbe_name);
}
out:
out2:
return (err);
}
static int
{
int err = 1;
int c;
int destroy_flags = 0;
char *snap_name;
char *be_name;
switch (c) {
case 'f':
break;
case 's':
break;
case 'F':
break;
default:
usage();
return (1);
}
}
if (argc != 1) {
usage();
return (1);
}
return (0);
}
usage();
return (1);
}
*snap_name = '\0';
snap_name++;
}
if (be_nvl_alloc(&be_attrs) != 0)
return (1);
goto out;
if (is_snap) {
snap_name) != 0)
goto out;
} else {
destroy_flags) != 0)
goto out;
}
switch (err) {
case BE_SUCCESS:
(void) printf(_("Destroyed successfully\n"));
break;
case BE_ERR_MOUNTED:
"unmounted before it can be destroyed.\n" "Use 'beadm "
"unmount %s' to unmount the BE before destroying\nit or "
break;
case BE_ERR_DESTROY_CURR_BE:
"cannot be destroyed.\nYou must boot from another BE in "
break;
case BE_ERR_ZONES_UNMOUNT:
"zone BE's.\nUse 'beadm destroy -f %s' or "
break;
case BE_ERR_SS_NOENT:
"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:
"execute this command.\n"));
break;
case BE_ERR_SS_EXISTS:
"BE has snapshots.\nUse 'beadm destroy -s %s' or "
break;
default:
}
out:
return (err);
}
static int
{
int err = 1;
int c = 0;
switch (c) {
case 'a':
break;
case 'd':
break;
case 's':
break;
case 'H':
break;
default:
usage();
return (1);
}
}
if (all) {
if (dsets) {
"are mutually exclusive.\n"), "-d");
usage();
return (1);
}
if (snaps) {
"are mutually exclusive.\n"), "-s");
usage();
return (1);
}
}
if (argc == 1)
switch (err) {
case BE_SUCCESS:
break;
case BE_ERR_BE_NOENT:
"on this system.\n"));
else {
"to be a valid BE.\nPlease check that the name of "
"the BE provided is correct.\n"), be_name);
}
break;
default:
"Environment\n"));
}
return (err);
}
static int
{
int err = 1;
int c;
int mount_flags = 0;
char *obe_name;
char *mountpoint;
switch (c) {
case 's':
"requires an argument [ rw | ro ]\n"));
usage();
return (1);
}
break;
default:
usage();
return (1);
}
}
usage();
return (1);
}
if (argc == 2) {
if (mountpoint[0] != '/') {
"Mount point must start with a /.\n"), mountpoint);
return (1);
}
} else {
const char *tmpname = "tmp.XXXXXX";
int sz;
tmpdir = "/tmp";
if (sz < 0) {
"out of memory\n"));
return (1);
}
}
if (be_nvl_alloc(&be_attrs) != 0)
return (1);
goto out;
goto out;
mount_flags) != 0)
goto out;
switch (err) {
case BE_SUCCESS:
break;
case BE_ERR_BE_NOENT:
err = 1;
"to be a valid BE.\nPlease check that the name of "
"the BE provided is correct.\n"), obe_name);
break;
case BE_ERR_MOUNTED:
"Please unmount the BE before mounting it again.\n"),
obe_name);
break;
case BE_ERR_PERM:
case BE_ERR_ACCESS:
err = 1;
"execute this command.\n"));
break;
default:
err = 1;
}
out:
return (err);
}
static int
{
char *obe_name;
int err = 1;
int c;
int unmount_flags = 0;
switch (c) {
case 'f':
break;
default:
usage();
return (1);
}
}
if (argc != 1) {
usage();
return (1);
}
if (be_nvl_alloc(&be_attrs) != 0)
return (1);
goto out;
unmount_flags) != 0)
goto out;
switch (err) {
case BE_SUCCESS:
(void) printf(_("Unmounted successfully\n"));
break;
case BE_ERR_BE_NOENT:
"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:
"It cannot be unmounted unless another BE is the "
"currently active BE.\n"), obe_name);
break;
case BE_ERR_UMOUNT_SHARED:
"cannot be unmounted.\n"), obe_name);
break;
case BE_ERR_PERM:
case BE_ERR_ACCESS:
"execute this command.\n"));
break;
default:
}
out:
return (err);
}
static int
{
char *obe_name;
char *nbe_name;
int err = 1;
if (argc != 2) {
usage();
return (1);
}
if (be_nvl_alloc(&be_attrs) != 0)
return (1);
goto out;
goto out;
switch (err) {
case BE_SUCCESS:
(void) printf(_("Renamed successfully\n"));
break;
case BE_ERR_BE_NOENT:
"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:
obe_name);
"execute this command.\n"));
break;
default:
obe_name);
}
out:
return (err);
}
static int
{
char *obe_name;
char *snap_name;
int err = 1;
usage();
return (1);
}
if (argc == 2)
else { /* argc == 1 */
usage();
return (1);
}
snap_name[0] = '\0';
snap_name++;
} else {
usage();
return (1);
}
}
if (be_nvl_alloc(&be_attrs) != 0)
return (1);
goto out;
goto out;
switch (err) {
case BE_SUCCESS:
(void) printf(_("Rolled back successfully\n"));
break;
case BE_ERR_BE_NOENT:
"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:
"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:
"execute this command.\n"));
break;
default:
}
out:
return (err);
}