be_list.c revision de1ab35c09a8c3ae1b531c0a613d2cc1c61cee9d
/*
* 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.
*/
#include <assert.h>
#include <libintl.h>
#include <libnvpair.h>
#include <libzfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>
#include <libbe.h>
#include <libbe_priv.h>
/*
* Callback data used for zfs_iter calls.
*/
typedef struct list_callback_data {
char *zpool_name;
char *be_name;
char current_be[MAXPATHLEN];
/*
* Private function prototypes
*/
static int be_get_list_callback(zpool_handle_t *, void *);
const char *, char *, char *);
static int be_get_zone_node_data(be_node_list_t *, char *);
be_node_list_t *);
be_node_list_t *);
static void be_sort_list(be_node_list_t **);
static int be_qsort_compare_BEs(const void *, const void *);
static int be_qsort_compare_snapshots(const void *x, const void *y);
static int be_qsort_compare_datasets(const void *x, const void *y);
static void *be_list_alloc(int *, size_t);
/*
* Private data.
*/
static char be_container_ds[MAXPATHLEN];
/* ******************************************************************** */
/* Public Functions */
/* ******************************************************************** */
/*
* Function: be_list
* Description: Calls _be_list which finds all the BEs on the system and
* returns the datasets and snapshots belonging to each BE.
* Also data, such as dataset and snapshot properties,
* for each BE and their snapshots and datasets is
* returned. The data returned is as described in the
* be_dataset_list_t, be_snapshot_list_t and be_node_list_t
* structures.
* Parameters:
* be_name - The name of the BE to look up.
* If NULL a list of all BEs will be returned.
* be_nodes - A reference pointer to the list of BEs. The list
* structure will be allocated by _be_list and must
* be freed by a call to be_free_list. If there are no
* BEs found on the system this reference will be
* set to NULL.
* Return:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Public
*/
int
{
int ret = BE_SUCCESS;
/* Initialize libzfs handle */
if (!be_zfs_init())
return (BE_ERR_INIT);
/* Validate be_name if its not NULL */
if (!be_valid_be_name(be_name)) {
"invalid BE name %s\n"), be_name);
return (BE_ERR_INVAL);
}
}
be_zfs_fini();
return (ret);
}
/* ******************************************************************** */
/* Semi-Private Functions */
/* ******************************************************************** */
/*
* Function: _be_list
* Description: This does the actual work described in be_list.
* Parameters:
* be_name - The name of the BE to look up.
* If NULL a list of all BEs will be returned.
* be_nodes - A reference pointer to the list of BEs. The list
* structure will be allocated here and must
* be freed by a call to be_free_list. If there are no
* BEs found on the system this reference will be
* set to NULL.
* Return:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Semi-private (library wide use only)
*/
int
{
list_callback_data_t cb = { 0 };
be_transaction_data_t bt = { 0 };
int ret = BE_SUCCESS;
struct be_defaults be_defaults;
return (BE_ERR_INVAL);
/*
* We were unable to find a currently booted BE which
* probably means that we're not booted in a BE envoronment.
* None of the BE's will be marked as the active BE.
*/
} else {
sizeof (cb.current_be));
}
/*
* If be_name is NULL we'll look for all BE's on the system.
* If not then we will only return data for the specified BE.
*/
"open rpool (%s): %s\n"), rpool,
return (zfs_err_to_be_err(g_zfs));
}
} else {
}
}
}
"exist\n"), be_name);
else
}
return (ret);
}
/*
* Function: be_free_list
* Description: Frees up all the data allocated for the list of BEs,
* datasets and snapshots returned by be_list.
* Parameters:
* be_node - be_nodes_t structure returned from call to be_list.
* Returns:
* none
* Scope:
* Semi-private (library wide use only)
*/
void
{
}
}
}
}
/*
* Function: be_get_zone_be_list
* Description: Finds all the BEs for this zone on the system.
* Parameters:
* zone_be_name - The name of the BE to look up.
* zone_be_container_ds - The dataset for the zone.
* zbe_nodes - A reference pointer to the list of BEs. The list
* structure will be allocated here and must
* be freed by a call to be_free_list. If there are no
* BEs found on the system this reference will be
* set to NULL.
* Return:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Semi-private (library wide use only)
*/
int
/* LINTED */
char *zone_be_name,
char *zone_be_container_ds,
{
list_callback_data_t cb = { 0 };
int ret = BE_SUCCESS;
return (BE_ERR_INVAL);
return (BE_ERR_BE_NOENT);
}
ZFS_TYPE_FILESYSTEM)) == NULL) {
"the zone BE dataset %s: %s\n"), zone_be_container_ds,
goto cleanup;
}
sizeof (be_node_list_t))) == NULL) {
goto cleanup;
}
}
if (ret == 0)
return (ret);
}
/* ******************************************************************** */
/* Private Functions */
/* ******************************************************************** */
/*
* Function: be_get_list_callback
* Description: Callback function used by zfs_iter to look through all
* the pools on the system looking for BEs. If a BE name was
* specified only that BE's information will be collected and
* returned.
* Parameters:
* zlp - handle to the first zfs dataset. (provided by the
* zfs_iter_* call)
* data - pointer to the callback data and where we'll pass
* the BE information back.
* Returns:
* 0 - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
{
char be_ds[MAXPATHLEN];
int ret = 0;
/*
* Generate string for the BE container dataset
*/
sizeof (be_container_ds));
/*
* If a BE name was specified we use it's root dataset in place of
* the container dataset. This is because we only want to collect
* the information for the specified BE.
*/
return (BE_ERR_INVAL);
/*
* Generate string for the BE root dataset
*/
} else {
}
/*
* Check if the dataset exists
*/
/*
* The specified dataset does not exist in this pool or
* there are no valid BE's in this pool. Try the next zpool.
*/
return (0);
}
"the BE dataset %s: %s\n"), open_ds,
return (ret);
}
/*
* If a BE name was specified we iterate through the datasets
* and snapshots for this BE only. Otherwise we will iterate
* through the next level of datasets to find all the BE's
* within the pool
*/
sizeof (be_node_list_t))) == NULL) {
return (ret);
}
}
return (ret);
}
}
if (ret == 0)
return (ret);
}
/*
* Function: be_add_children_callback
* Description: Callback function used by zfs_iter to look through all
* the datasets and snapshots for each BE and add them to
* the lists of information to be passed back.
* Parameters:
* zhp - handle to the first zfs dataset. (provided by the
* zfs_iter_* call)
* data - pointer to the callback data and where we'll pass
* the BE information back.
* Returns:
* 0 - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
{
int ret = 0;
struct be_defaults be_defaults;
/*
* get past the end of the container dataset plus the trailing "/"
*/
/* just skip if invalid */
if (!be_valid_be_name(str))
return (BE_SUCCESS);
}
sizeof (be_node_list_t))) == NULL) {
return (ret);
}
}
return (ret);
}
NULL;
} else {
continue;
/*
* We're at the end of the list add the
* new snapshot.
*/
if ((snapshots->be_next_snapshot =
sizeof (be_snapshot_list_t))) == NULL ||
ret != BE_SUCCESS) {
return (ret);
}
break;
}
}
return (ret);
}
return (ret);
}
}
/*
* If this is a zone root dataset then we only need
* the name of the zone BE at this point. We grab that
* and return.
*/
if (zone_be) {
return (ret);
}
return (ret);
}
return (ret);
}
} else {
continue;
/*
* We're at the end of the list add
* the new dataset.
*/
if ((datasets->be_next_dataset =
sizeof (be_dataset_list_t)))
return (ret);
}
break;
}
}
return (ret);
}
}
if (ret != 0) {
"encountered error: %s\n"),
}
return (ret);
}
/*
* Function: be_sort_list
* Description: Sort BE node list
* Parameters:
* pointer to address of list head
* Returns:
* nothing
* Side effect:
* node list sorted by name
* Scope:
* Private
*/
static void
{
be_node_list_t *p = NULL;
return;
/* build array of linked list BE struct pointers */
}
if (nbe == 0)
return;
/* in-place list quicksort using qsort(3C) */
/* for each BE in list */
/* rewrite list pointer chain, including terminator */
/* sort subordinate snapshots */
be_snapshot_list_t ** const slist =
continue;
/* build array of linked list snapshot struct ptrs */
ns++, p = p->be_next_snapshot) {
}
if (ns < 2)
goto end_snapshot;
/* in-place list quicksort using qsort(3C) */
/* rewrite list pointer chain, including terminator */
for (k = 0; k < ns; k++)
}
/* sort subordinate datasets */
be_dataset_list_t ** const slist =
continue;
/* build array of linked list dataset struct ptrs */
ns++, p = p->be_next_dataset) {
}
goto end_dataset;
/* in-place list quicksort using qsort(3C) */
/* rewrite list pointer chain, including terminator */
for (k = 0; k < ns; k++)
}
}
free:
}
/*
* Function: be_qsort_compare_BEs
* Description: lexical compare of BE names for qsort(3C)
* Parameters:
* x,y - BEs with names to compare
* Returns:
* positive if y>x, negative if x>y, 0 if equal
* Scope:
* Private
*/
static int
be_qsort_compare_BEs(const void *x, const void *y)
{
be_node_list_t *p = *(be_node_list_t **)x;
be_node_list_t *q = *(be_node_list_t **)y;
return (1);
return (-1);
}
/*
* Function: be_qsort_compare_snapshots
* Description: lexical compare of BE names for qsort(3C)
* Parameters:
* x,y - BE snapshots with names to compare
* Returns:
* positive if y>x, negative if x>y, 0 if equal
* Scope:
* Private
*/
static int
be_qsort_compare_snapshots(const void *x, const void *y)
{
be_snapshot_list_t *p = *(be_snapshot_list_t **)x;
be_snapshot_list_t *q = *(be_snapshot_list_t **)y;
return (1);
return (-1);
}
/*
* Function: be_qsort_compare_datasets
* Description: lexical compare of dataset names for qsort(3C)
* Parameters:
* x,y - BE snapshots with names to compare
* Returns:
* positive if y>x, negative if x>y, 0 if equal
* Scope:
* Private
*/
static int
be_qsort_compare_datasets(const void *x, const void *y)
{
be_dataset_list_t *p = *(be_dataset_list_t **)x;
be_dataset_list_t *q = *(be_dataset_list_t **)y;
return (1);
return (-1);
}
/*
* Function: be_get_node_data
* Description: Helper function used to collect all the information to fill
* in the be_node_list structure to be returned by be_list.
* Parameters:
* zhp - Handle to the root dataset for the BE whose information
* we're collecting.
* be_node - a pointer to the node structure we're filling in.
* be_name - The BE name of the node whose information we're
* collecting.
* current_be - the name of the currently active BE.
* be_ds - The dataset name for the BE.
*
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
char *be_name,
const char *rpool,
char *current_be,
char *be_ds)
{
char prop_buf[MAXPATHLEN];
char *grub_default_bootfs = NULL;
int err = 0;
"can not be NULL\n"));
return (BE_ERR_INVAL);
}
errno = 0;
"copy root dataset name\n"));
return (errno_to_be_err(err));
}
"copy BE name\n"));
return (errno_to_be_err(err));
}
else
"copy root pool name\n"));
return (errno_to_be_err(err));
}
return (zfs_err_to_be_err(g_zfs));
}
NULL);
if (be_has_grub() &&
else
else
/*
* If the dataset is mounted use the mount point
* returned from the zfs_is_mounted call. If the
* dataset is not mounted then pull the mount
* point information out of the zfs properties.
*/
if (!be_node->be_mounted) {
else
return (zfs_err_to_be_err(g_zfs));
}
/* Get all user properties used for libbe */
} else {
} else {
&prop_str) == 0);
else
}
&prop_str) == 0) {
}
}
/*
* Increment the dataset counter to include the root dataset
* of the BE.
*/
return (BE_SUCCESS);
}
/*
* Function: be_get_ds_data
* Description: Helper function used by be_add_children_callback to collect
* the dataset related information that will be returned by
* be_list.
* Parameters:
* zhp - Handle to the zfs dataset whose information we're
* collecting.
* name - The name of the dataset we're processing.
* dataset - A pointer to the be_dataset_list structure
* we're filling in.
* node - The node structure that this dataset belongs to.
* Return:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
char *name,
{
char prop_buf[ZFS_MAXPROPLEN];
int err = 0;
"can not be NULL\n"));
return (BE_ERR_INVAL);
}
errno = 0;
"dataset name\n"));
return (errno_to_be_err(err));
}
/*
* If the dataset is mounted use the mount point
* returned from the zfs_is_mounted call. If the
* dataset is not mounted then pull the mount
* point information out of the zfs properties.
*/
&(dataset->be_ds_mntpt)))) {
B_FALSE) == 0)
else
return (zfs_err_to_be_err(g_zfs));
}
/*
* Get the user property used for the libbe
* cleaup policy
*/
} else {
BE_POLICY_PROPERTY, &propval) != 0 ||
} else {
ZPROP_VALUE, &prop_str) == 0);
else
}
}
return (BE_SUCCESS);
}
/*
* Function: be_get_ss_data
* Description: Helper function used by be_add_children_callback to collect
* the dataset related information that will be returned by
* be_list.
* Parameters:
* zhp - Handle to the zfs snapshot whose information we're
* collecting.
* name - The name of the snapshot we're processing.
* shapshot - A pointer to the be_snapshot_list structure
* we're filling in.
* node - The node structure that this snapshot belongs to.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
char *name,
{
int err = 0;
"can not be NULL\n"));
return (BE_ERR_INVAL);
}
errno = 0;
return (errno_to_be_err(err));
}
/*
* Try to get this snapshot's cleanup policy from its
* user properties first. If not there, use default
* cleanup policy.
*/
ZPROP_VALUE, &prop_str) == 0) {
} else {
}
return (BE_SUCCESS);
}
/*
* Function: be_list_alloc
* Description: Helper function used to allocate memory for the various
* sructures that make up a BE node.
* Parameters:
* err - Used to return any errors encountered.
* BE_SUCCESS - Success
* BE_ERR_NOMEM - Allocation failure
* size - The size of memory to allocate.
* Returns:
* Success - A pointer to the allocated memory
* Failure - NULL
* Scope:
* Private
*/
static void*
{
"allocation failed\n"));
*err = BE_ERR_NOMEM;
}
*err = BE_SUCCESS;
return (bep);
}
/*
* Function: be_get_zone_node_data
* Description: Helper function used to collect all the information to
* fill in the be_node_list structure to be returned by
* be_get_zone_list.
* Parameters:
* be_node - a pointer to the node structure we're filling in.
* be_name - The BE name of the node whose information we're
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Private
*
* NOTE: This function currently only collects the zone BE name but when
* in the rest of the information needed for a zone BE.
*/
static int
{
return (BE_SUCCESS);
return (BE_ERR_NOMEM);
}