#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 <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <libbe.h>
#include <libbe_priv.h>
#include <libzfsbootenv.h>
typedef struct list_callback_data {
char *zpool_name;
char *be_name;
be_node_list_t *be_nodes_head;
be_node_list_t *be_nodes;
be_dataset_list_t **be_datasets_tail;
be_snapshot_list_t **be_snapshots_tail;
char current_be[MAXPATHLEN];
struct be_defaults be_defaults;
uint64_t flags;
} list_callback_data_t;
static int be_add_children_callback(zfs_handle_t *zhp, void *data);
static int be_get_list_callback(zpool_handle_t *, void *);
static int be_get_node_data(zfs_handle_t *, be_node_list_t *, char *,
const char *, char *, char *);
static int be_get_zone_node_data(be_node_list_t *, char *);
static int be_get_ds_data(zfs_handle_t *, char *, be_dataset_list_t *,
be_node_list_t *);
static int be_get_ss_data(zfs_handle_t *, char *, be_snapshot_list_t *,
be_node_list_t *);
static int be_sort_list(be_node_list_t **,
int (*)(const void *, const void *));
static int be_qsort_compare_BEs_name(const void *, const void *);
static int be_qsort_compare_BEs_name_rev(const void *, const void *);
static int be_qsort_compare_BEs_date(const void *, const void *);
static int be_qsort_compare_BEs_date_rev(const void *, const void *);
static int be_qsort_compare_BEs_space(const void *, const void *);
static int be_qsort_compare_BEs_space_rev(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);
static int be_allocate_callback_nodes(list_callback_data_t *);
static char be_container_ds[MAXPATHLEN];
static boolean_t zone_be = B_FALSE;
int
be_list(char *be_name, be_node_list_t **be_nodes, uint64_t flags)
{
int ret = BE_SUCCESS;
if (!be_zfs_init())
return (BE_ERR_INIT);
if (be_name != NULL) {
if (!be_valid_be_name(be_name)) {
be_print_err(gettext("be_list: "
"invalid BE name %s\n"), be_name);
return (BE_ERR_INVAL);
}
}
ret = _be_list(be_name, be_nodes, flags);
be_zfs_fini();
return (ret);
}
int
be_sort(be_node_list_t **be_nodes, int order)
{
int (*compar)(const void *, const void *) = be_qsort_compare_BEs_date;
if (be_nodes == NULL)
return (BE_ERR_INVAL);
switch (order) {
case BE_SORT_UNSPECIFIED:
case BE_SORT_DATE:
compar = be_qsort_compare_BEs_date;
break;
case BE_SORT_DATE_REV:
compar = be_qsort_compare_BEs_date_rev;
break;
case BE_SORT_NAME:
compar = be_qsort_compare_BEs_name;
break;
case BE_SORT_NAME_REV:
compar = be_qsort_compare_BEs_name_rev;
break;
case BE_SORT_SPACE:
compar = be_qsort_compare_BEs_space;
break;
case BE_SORT_SPACE_REV:
compar = be_qsort_compare_BEs_space_rev;
break;
default:
be_print_err(gettext("be_sort: invalid sort order %d\n"),
order);
return (BE_ERR_INVAL);
}
return (be_sort_list(be_nodes, compar));
}
int
_be_list(char *be_name, be_node_list_t **be_nodes, uint64_t flags)
{
list_callback_data_t cb = { 0 };
be_transaction_data_t bt = { 0 };
int ret = BE_SUCCESS;
int sret;
zpool_handle_t *zphp;
char *rpool = NULL;
if (be_nodes == NULL)
return (BE_ERR_INVAL);
be_get_defaults(&cb.be_defaults);
cb.flags = flags;
if (be_find_current_be(&bt) != BE_SUCCESS) {
(void) strcpy(cb.current_be, "-");
} else {
(void) strncpy(cb.current_be, bt.obe_name,
sizeof (cb.current_be));
rpool = bt.obe_zpool;
}
if (be_name != NULL)
cb.be_name = strdup(be_name);
if (cb.be_defaults.be_deflt_rpool_container && rpool != NULL) {
if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
be_print_err(gettext("be_list: failed to "
"open rpool (%s): %s\n"), rpool,
libzfs_error_description(g_zfs));
free(cb.be_name);
return (zfs_err_to_be_err(g_zfs));
}
ret = be_get_list_callback(zphp, &cb);
} else {
if ((zpool_iter(g_zfs, be_get_list_callback, &cb)) != 0) {
if (cb.be_nodes_head != NULL) {
be_free_list(cb.be_nodes_head);
cb.be_nodes_head = NULL;
cb.be_nodes = NULL;
}
ret = BE_ERR_BE_NOENT;
}
}
if (cb.be_nodes_head == NULL) {
if (be_name != NULL)
be_print_err(gettext("be_list: BE (%s) does not "
"exist\n"), be_name);
else
be_print_err(gettext("be_list: No BE's found\n"));
ret = BE_ERR_BE_NOENT;
}
*be_nodes = cb.be_nodes_head;
free(cb.be_name);
sret = be_sort(be_nodes, BE_SORT_DATE);
return ((ret == BE_SUCCESS) ? sret : ret);
}
void
be_free_list(be_node_list_t *be_nodes)
{
be_node_list_t *temp_node = NULL;
be_node_list_t *list = be_nodes;
while (list != NULL) {
be_dataset_list_t *datasets = list->be_node_datasets;
be_snapshot_list_t *snapshots = list->be_node_snapshots;
while (datasets != NULL) {
be_dataset_list_t *temp_ds = datasets;
datasets = datasets->be_next_dataset;
free(temp_ds->be_dataset_name);
free(temp_ds->be_ds_mntpt);
free(temp_ds->be_ds_plcy_type);
free(temp_ds);
}
while (snapshots != NULL) {
be_snapshot_list_t *temp_ss = snapshots;
snapshots = snapshots->be_next_snapshot;
free(temp_ss->be_snapshot_name);
free(temp_ss->be_snapshot_type);
free(temp_ss);
}
temp_node = list;
list = list->be_next_node;
free(temp_node->be_node_name);
free(temp_node->be_root_ds);
free(temp_node->be_rpool);
free(temp_node->be_mntpt);
free(temp_node->be_policy_type);
free(temp_node->be_uuid_str);
free(temp_node);
}
}
int
be_get_zone_be_list(char *zone_be_name, char *zone_be_container_ds,
be_node_list_t **zbe_nodes)
{
zfs_handle_t *zhp = NULL;
list_callback_data_t cb = { 0 };
int ret = BE_SUCCESS;
if (zbe_nodes == NULL)
return (BE_ERR_INVAL);
if (!zfs_dataset_exists(g_zfs, zone_be_container_ds,
ZFS_TYPE_FILESYSTEM)) {
return (BE_ERR_BE_NOENT);
}
zone_be = B_TRUE;
if ((zhp = zfs_open(g_zfs, zone_be_container_ds,
ZFS_TYPE_FILESYSTEM)) == NULL) {
be_print_err(gettext("be_get_zone_be_list: failed to open "
"the zone BE dataset %s: %s\n"), zone_be_container_ds,
libzfs_error_description(g_zfs));
ret = zfs_err_to_be_err(g_zfs);
goto cleanup;
}
(void) strcpy(be_container_ds, zone_be_container_ds);
if ((ret = be_allocate_callback_nodes(&cb)) != BE_SUCCESS) {
ZFS_CLOSE(zhp);
goto cleanup;
}
if (ret == 0) {
be_get_defaults(&cb.be_defaults);
ret = zfs_iter_filesystems(zhp, be_add_children_callback, &cb);
}
ZFS_CLOSE(zhp);
*zbe_nodes = cb.be_nodes_head;
cleanup:
zone_be = B_FALSE;
return (ret);
}
static int
be_get_list_callback(zpool_handle_t *zlp, void *data)
{
list_callback_data_t *cb = (list_callback_data_t *)data;
char be_ds[MAXPATHLEN];
char *open_ds = NULL;
char *rpool = NULL;
zfs_handle_t *zhp = NULL;
int ret = 0;
cb->zpool_name = rpool = (char *)zpool_get_name(zlp);
if (be_make_container_ds(rpool, be_container_ds,
sizeof (be_container_ds)) != BE_SUCCESS) {
zpool_close(zlp);
return (0);
}
if (cb->be_name != NULL) {
int rv;
if (!be_valid_be_name(cb->be_name))
return (BE_ERR_INVAL);
if ((rv = be_make_root_ds(rpool, cb->be_name, be_ds,
sizeof (be_ds))) != BE_SUCCESS) {
return (rv);
}
open_ds = be_ds;
} else {
open_ds = be_container_ds;
}
if (!zfs_dataset_exists(g_zfs, open_ds,
ZFS_TYPE_FILESYSTEM)) {
zpool_close(zlp);
return (0);
}
if ((zhp = zfs_open(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
be_print_err(gettext("be_get_list_callback: failed to open "
"the BE dataset %s: %s\n"), open_ds,
libzfs_error_description(g_zfs));
ret = zfs_err_to_be_err(g_zfs);
zpool_close(zlp);
return (ret);
}
if (cb->be_name != NULL) {
if ((ret = be_allocate_callback_nodes(cb)) != BE_SUCCESS) {
ZFS_CLOSE(zhp);
zpool_close(zlp);
return (ret);
}
if ((ret = be_get_node_data(zhp, cb->be_nodes, cb->be_name,
rpool, cb->current_be, be_ds)) != BE_SUCCESS) {
ZFS_CLOSE(zhp);
zpool_close(zlp);
return (ret);
}
if (cb->flags & BE_LIST_SNAPSHOTS)
ret = zfs_iter_snapshots(zhp, B_FALSE,
be_add_children_callback, cb);
}
if (ret == 0)
ret = zfs_iter_filesystems(zhp, be_add_children_callback, cb);
ZFS_CLOSE(zhp);
zpool_close(zlp);
return (ret);
}
static int
be_allocate_callback_nodes(list_callback_data_t *cb)
{
int ret = BE_SUCCESS;
if (cb->be_nodes_head != NULL)
return (BE_SUCCESS);
if ((cb->be_nodes_head = be_list_alloc(&ret, sizeof (be_node_list_t)))
== NULL)
return (ret);
cb->be_nodes = cb->be_nodes_head;
cb->be_snapshots_tail = &cb->be_nodes->be_node_snapshots;
cb->be_datasets_tail = &cb->be_nodes->be_node_datasets;
return (BE_SUCCESS);
}
static int
be_add_children_callback(zfs_handle_t *zhp, void *data)
{
list_callback_data_t *cb = (list_callback_data_t *)data;
char *str = NULL, *ds_path = NULL;
int ret = 0;
ds_path = str = strdup(zfs_get_name(zhp));
str = str + (strlen(be_container_ds) + 1);
if (cb->be_defaults.be_deflt_rpool_container) {
if (!be_valid_be_name(str))
return (BE_SUCCESS);
}
if (cb->be_nodes_head == NULL &&
(ret = be_allocate_callback_nodes(cb)) != BE_SUCCESS) {
ZFS_CLOSE(zhp);
return (ret);
}
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && !zone_be) {
be_snapshot_list_t *snapshot;
if ((snapshot = be_list_alloc(&ret,
sizeof (be_snapshot_list_t))) == NULL ||
ret != BE_SUCCESS) {
ZFS_CLOSE(zhp);
return (ret);
}
if ((ret = be_get_ss_data(zhp, str, snapshot,
cb->be_nodes)) != BE_SUCCESS) {
free(snapshot);
ZFS_CLOSE(zhp);
return (ret);
}
snapshot->be_next_snapshot = NULL;
*cb->be_snapshots_tail = snapshot;
cb->be_snapshots_tail = &snapshot->be_next_snapshot;
} else if (strchr(str, '/') == NULL) {
if (cb->be_nodes->be_node_name != NULL) {
if ((cb->be_nodes->be_next_node =
be_list_alloc(&ret, sizeof (be_node_list_t))) ==
NULL || ret != BE_SUCCESS) {
ZFS_CLOSE(zhp);
return (ret);
}
cb->be_nodes = cb->be_nodes->be_next_node;
cb->be_nodes->be_next_node = NULL;
}
if (zone_be) {
ret = be_get_zone_node_data(cb->be_nodes, str);
ZFS_CLOSE(zhp);
return (ret);
}
if ((ret = be_get_node_data(zhp, cb->be_nodes, str,
cb->zpool_name, cb->current_be, ds_path)) != BE_SUCCESS) {
ZFS_CLOSE(zhp);
return (ret);
}
} else if (strchr(str, '/') != NULL && !zone_be) {
be_dataset_list_t *dataset;
if ((dataset = be_list_alloc(&ret,
sizeof (be_dataset_list_t))) == NULL ||
ret != BE_SUCCESS) {
ZFS_CLOSE(zhp);
return (ret);
}
if ((ret = be_get_ds_data(zhp, str,
dataset, cb->be_nodes)) != BE_SUCCESS) {
free(dataset);
ZFS_CLOSE(zhp);
return (ret);
}
dataset->be_next_dataset = NULL;
*cb->be_datasets_tail = dataset;
cb->be_datasets_tail = &dataset->be_next_dataset;
}
if (cb->flags & BE_LIST_SNAPSHOTS)
ret = zfs_iter_children(zhp, be_add_children_callback, cb);
else
ret = zfs_iter_filesystems(zhp, be_add_children_callback, cb);
if (ret != 0) {
be_print_err(gettext("be_add_children_callback: "
"encountered error: %s\n"),
libzfs_error_description(g_zfs));
ret = zfs_err_to_be_err(g_zfs);
}
ZFS_CLOSE(zhp);
return (ret);
}
static int
be_sort_list(be_node_list_t **pstart, int (*compar)(const void *, const void *))
{
int ret = BE_SUCCESS;
size_t ibe, nbe;
be_node_list_t *p = NULL;
be_node_list_t **ptrlist = NULL;
be_node_list_t **ptrtmp;
if (pstart == NULL)
return (BE_SUCCESS);
for (p = *pstart, nbe = 0; p != NULL; nbe++, p = p->be_next_node) {
ptrtmp = realloc(ptrlist,
sizeof (be_node_list_t *) * (nbe + 2));
if (ptrtmp == NULL) {
be_print_err(gettext("be_sort_list: memory "
"allocation failed\n"));
ret = BE_ERR_NOMEM;
goto free;
}
ptrlist = ptrtmp;
ptrlist[nbe] = p;
}
if (nbe == 0)
return (BE_SUCCESS);
if (nbe > 1)
qsort(ptrlist, nbe, sizeof (be_node_list_t *), compar);
ptrlist[nbe] = NULL;
*pstart = ptrlist[0];
for (ibe = 0; ibe < nbe; ibe++) {
size_t k, ns;
ptrlist[ibe]->be_next_node = ptrlist[ibe + 1];
if (ptrlist[ibe]->be_node_num_snapshots > 1) {
const size_t nmax = ptrlist[ibe]->be_node_num_snapshots;
be_snapshot_list_t ** const slist =
malloc(sizeof (be_snapshot_list_t *) * (nmax + 1));
be_snapshot_list_t *p;
if (slist == NULL) {
ret = BE_ERR_NOMEM;
continue;
}
for (ns = 0, p = ptrlist[ibe]->be_node_snapshots;
ns < nmax && p != NULL;
ns++, p = p->be_next_snapshot) {
slist[ns] = p;
}
if (ns < 2)
goto end_snapshot;
slist[ns] = NULL;
qsort(slist, ns, sizeof (be_snapshot_list_t *),
be_qsort_compare_snapshots);
ptrlist[ibe]->be_node_snapshots = slist[0];
for (k = 0; k < ns; k++)
slist[k]->be_next_snapshot = slist[k + 1];
end_snapshot:
free(slist);
}
if (ptrlist[ibe]->be_node_num_datasets > 1) {
const size_t nmax = ptrlist[ibe]->be_node_num_datasets;
be_dataset_list_t ** const slist =
malloc(sizeof (be_dataset_list_t *) * (nmax + 1));
be_dataset_list_t *p;
if (slist == NULL) {
ret = BE_ERR_NOMEM;
continue;
}
for (ns = 0, p = ptrlist[ibe]->be_node_datasets;
ns < nmax && p != NULL;
ns++, p = p->be_next_dataset) {
slist[ns] = p;
}
if (ns < 2)
goto end_dataset;
slist[ns] = NULL;
qsort(slist, ns, sizeof (be_dataset_list_t *),
be_qsort_compare_datasets);
ptrlist[ibe]->be_node_datasets = slist[0];
for (k = 0; k < ns; k++)
slist[k]->be_next_dataset = slist[k + 1];
end_dataset:
free(slist);
}
}
free:
free(ptrlist);
return (ret);
}
static int
be_qsort_compare_BEs_date(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;
assert(p != NULL);
assert(q != NULL);
if (p->be_node_creation > q->be_node_creation)
return (1);
if (p->be_node_creation < q->be_node_creation)
return (-1);
return (0);
}
static int
be_qsort_compare_BEs_date_rev(const void *x, const void *y)
{
return (be_qsort_compare_BEs_date(y, x));
}
static int
be_qsort_compare_BEs_name(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;
assert(p != NULL);
assert(p->be_node_name != NULL);
assert(q != NULL);
assert(q->be_node_name != NULL);
return (strcmp(p->be_node_name, q->be_node_name));
}
static int
be_qsort_compare_BEs_name_rev(const void *x, const void *y)
{
return (be_qsort_compare_BEs_name(y, x));
}
static int
be_qsort_compare_BEs_space(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;
assert(p != NULL);
assert(q != NULL);
if (p->be_space_used > q->be_space_used)
return (1);
if (p->be_space_used < q->be_space_used)
return (-1);
return (0);
}
static int
be_qsort_compare_BEs_space_rev(const void *x, const void *y)
{
return (be_qsort_compare_BEs_space(y, x));
}
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;
if (p == NULL || p->be_snapshot_name == NULL)
return (1);
if (q == NULL || q->be_snapshot_name == NULL)
return (-1);
return (strcmp(p->be_snapshot_name, q->be_snapshot_name));
}
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;
if (p == NULL || p->be_dataset_name == NULL)
return (1);
if (q == NULL || q->be_dataset_name == NULL)
return (-1);
return (strcmp(p->be_dataset_name, q->be_dataset_name));
}
static int
be_get_node_data(zfs_handle_t *zhp, be_node_list_t *be_node, char *be_name,
const char *rpool, char *current_be, char *be_ds)
{
char prop_buf[MAXPATHLEN];
nvlist_t *userprops = NULL;
nvlist_t *propval = NULL;
nvlist_t *zone_propval = NULL;
char *prop_str = NULL;
char *zone_prop_str = NULL;
char *grub_default_bootfs = NULL;
zpool_handle_t *zphp = NULL;
int err = 0;
if (be_node == NULL || be_name == NULL || current_be == NULL ||
be_ds == NULL) {
be_print_err(gettext("be_get_node_data: invalid arguments, "
"can not be NULL\n"));
return (BE_ERR_INVAL);
}
errno = 0;
be_node->be_root_ds = strdup(be_ds);
if ((err = errno) != 0 || be_node->be_root_ds == NULL) {
be_print_err(gettext("be_get_node_data: failed to "
"copy root dataset name\n"));
return (errno_to_be_err(err));
}
be_node->be_node_name = strdup(be_name);
if ((err = errno) != 0 || be_node->be_node_name == NULL) {
be_print_err(gettext("be_get_node_data: failed to "
"copy BE name\n"));
return (errno_to_be_err(err));
}
if (strncmp(be_name, current_be, MAXPATHLEN) == 0)
be_node->be_active = B_TRUE;
else
be_node->be_active = B_FALSE;
be_node->be_rpool = strdup(rpool);
if (be_node->be_rpool == NULL || (err = errno) != 0) {
be_print_err(gettext("be_get_node_data: failed to "
"copy root pool name\n"));
return (errno_to_be_err(err));
}
be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED);
if (getzoneid() == GLOBAL_ZONEID) {
char *nextboot;
if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
be_print_err(gettext("be_get_node_data: failed to open "
"pool (%s): %s\n"), rpool,
libzfs_error_description(g_zfs));
return (zfs_err_to_be_err(g_zfs));
}
be_node->be_active_next = B_FALSE;
if (lzbe_get_boot_device(rpool, &nextboot) == 0) {
if (nextboot != NULL) {
if (strcmp(nextboot, be_ds) == 0)
be_node->be_active_next = B_TRUE;
free(nextboot);
}
}
(void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf,
ZFS_MAXPROPLEN, NULL, B_FALSE);
if (be_has_grub() && (be_default_grub_bootfs(rpool,
&grub_default_bootfs) == BE_SUCCESS) &&
grub_default_bootfs != NULL)
if (strcmp(grub_default_bootfs, be_ds) == 0)
be_node->be_active_on_boot = B_TRUE;
else
be_node->be_active_on_boot = B_FALSE;
else if (strcmp(prop_buf, be_ds) == 0)
be_node->be_active_on_boot = B_TRUE;
else
be_node->be_active_on_boot = B_FALSE;
be_node->be_global_active = B_TRUE;
free(grub_default_bootfs);
zpool_close(zphp);
} else {
if (be_zone_compare_uuids(be_node->be_root_ds))
be_node->be_global_active = B_TRUE;
else
be_node->be_global_active = B_FALSE;
}
be_node->be_mounted = zfs_is_mounted(zhp,
&(be_node->be_mntpt));
if (!be_node->be_mounted) {
if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) == 0)
be_node->be_mntpt = strdup(prop_buf);
else
return (zfs_err_to_be_err(g_zfs));
}
be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp,
ZFS_PROP_CREATION);
if ((userprops = zfs_get_user_props(zhp)) == NULL) {
be_node->be_policy_type = strdup(be_default_policy());
} else {
if (getzoneid() != GLOBAL_ZONEID) {
if (nvlist_lookup_nvlist(userprops,
BE_ZONE_ACTIVE_PROPERTY, &zone_propval) != 0 ||
zone_propval == NULL) {
be_node->be_active_on_boot = B_FALSE;
} else {
verify(nvlist_lookup_string(zone_propval,
ZPROP_VALUE, &zone_prop_str) == 0);
if (strcmp(zone_prop_str, "on") == 0) {
be_node->be_active_on_boot = B_TRUE;
} else {
be_node->be_active_on_boot = B_FALSE;
}
}
}
if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
&propval) != 0 || propval == NULL) {
be_node->be_policy_type =
strdup(be_default_policy());
} else {
verify(nvlist_lookup_string(propval, ZPROP_VALUE,
&prop_str) == 0);
if (prop_str == NULL || strcmp(prop_str, "-") == 0 ||
strcmp(prop_str, "") == 0)
be_node->be_policy_type =
strdup(be_default_policy());
else
be_node->be_policy_type = strdup(prop_str);
}
if (getzoneid() != GLOBAL_ZONEID) {
if (nvlist_lookup_nvlist(userprops,
BE_ZONE_PARENTBE_PROPERTY, &propval) != 0 &&
nvlist_lookup_string(propval, ZPROP_VALUE,
&prop_str) == 0) {
be_node->be_uuid_str = strdup(prop_str);
}
} else {
if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY,
&propval) == 0 && nvlist_lookup_string(propval,
ZPROP_VALUE, &prop_str) == 0) {
be_node->be_uuid_str = strdup(prop_str);
}
}
}
be_node->be_node_num_datasets++;
return (BE_SUCCESS);
}
static int
be_get_ds_data(
zfs_handle_t *zfshp,
char *name,
be_dataset_list_t *dataset,
be_node_list_t *node)
{
char prop_buf[ZFS_MAXPROPLEN];
nvlist_t *propval = NULL;
nvlist_t *userprops = NULL;
char *prop_str = NULL;
int err = 0;
if (zfshp == NULL || name == NULL || dataset == NULL || node == NULL) {
be_print_err(gettext("be_get_ds_data: invalid arguments, "
"can not be NULL\n"));
return (BE_ERR_INVAL);
}
errno = 0;
dataset->be_dataset_name = strdup(name);
if ((err = errno) != 0) {
be_print_err(gettext("be_get_ds_data: failed to copy "
"dataset name\n"));
return (errno_to_be_err(err));
}
dataset->be_ds_space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED);
if (!(dataset->be_ds_mounted = zfs_is_mounted(zfshp,
&(dataset->be_ds_mntpt)))) {
if (zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
B_FALSE) == 0)
dataset->be_ds_mntpt = strdup(prop_buf);
else
return (zfs_err_to_be_err(g_zfs));
}
dataset->be_ds_creation =
(time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION);
if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
dataset->be_ds_plcy_type =
strdup(node->be_policy_type);
} else {
if (nvlist_lookup_nvlist(userprops,
BE_POLICY_PROPERTY, &propval) != 0 ||
propval == NULL) {
dataset->be_ds_plcy_type =
strdup(node->be_policy_type);
} else {
verify(nvlist_lookup_string(propval,
ZPROP_VALUE, &prop_str) == 0);
if (prop_str == NULL ||
strcmp(prop_str, "-") == 0 ||
strcmp(prop_str, "") == 0)
dataset->be_ds_plcy_type
= strdup(node->be_policy_type);
else
dataset->be_ds_plcy_type = strdup(prop_str);
}
}
node->be_node_num_datasets++;
return (BE_SUCCESS);
}
static int
be_get_ss_data(
zfs_handle_t *zfshp,
char *name,
be_snapshot_list_t *snapshot,
be_node_list_t *node)
{
nvlist_t *propval = NULL;
nvlist_t *userprops = NULL;
char *prop_str = NULL;
int err = 0;
if (zfshp == NULL || name == NULL || snapshot == NULL || node == NULL) {
be_print_err(gettext("be_get_ss_data: invalid arguments, "
"can not be NULL\n"));
return (BE_ERR_INVAL);
}
errno = 0;
snapshot->be_snapshot_name = strdup(name);
if ((err = errno) != 0) {
be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
return (errno_to_be_err(err));
}
snapshot->be_snapshot_creation = (time_t)zfs_prop_get_int(zfshp,
ZFS_PROP_CREATION);
if ((userprops = zfs_get_user_props(zfshp)) != NULL &&
nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
&propval) == 0 && nvlist_lookup_string(propval,
ZPROP_VALUE, &prop_str) == 0) {
snapshot->be_snapshot_type =
strdup(prop_str);
} else {
snapshot->be_snapshot_type =
strdup(be_default_policy());
}
snapshot->be_snapshot_space_used = zfs_prop_get_int(zfshp,
ZFS_PROP_USED);
node->be_node_num_snapshots++;
return (BE_SUCCESS);
}
static void*
be_list_alloc(int *err, size_t size)
{
void *bep = NULL;
bep = calloc(1, size);
if (bep == NULL) {
be_print_err(gettext("be_list_alloc: memory "
"allocation failed\n"));
*err = BE_ERR_NOMEM;
}
*err = BE_SUCCESS;
return (bep);
}
static int
be_get_zone_node_data(be_node_list_t *be_node, char *be_name)
{
if ((be_node->be_node_name = strdup(be_name)) != NULL)
return (BE_SUCCESS);
return (BE_ERR_NOMEM);
}