view usr/src/lib/libbe/tbeadm/tbeadm.c @ 13025:3c7681e3e323

PSARC 2010/059 SNAP BE Management 6964804 SNAP BE management into ON 6971379 libbe should capture and give useful error when installgrub or ict.py fails. 6971390 beadm does not support labeled brand zones 6971394 BEADM_ERR_BE_DOES_NOT_EXIST has an extra space 6971397 libbe error messages need internationalization 6971402 Remove be_get_last_zone_be_callback 6971409 be_create_menu returns errors from both be_errno_t and errno sets
author Glenn Lagasse <glenn.lagasse@oracle.com>
date Wed, 04 Aug 2010 12:28:19 -0700
parents
children
line wrap: on
line source

/*
 * 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));
}