/* * 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 */ 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); }
/* * 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 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; struct be_defaults be_defaults; be_get_defaults(&be_defaults); ds_path = str = strdup(zfs_get_name(zhp)); /* * get past the end of the container dataset plus the trailing "/" */ str = str + (strlen(be_container_ds) + 1); if (be_defaults.be_deflt_rpool_container) { /* just skip if invalid */ if (!be_valid_be_name(str)) return (BE_SUCCESS); } if (cb->be_nodes_head == NULL) { if ((cb->be_nodes_head = be_list_alloc(&ret, sizeof (be_node_list_t))) == NULL) { ZFS_CLOSE(zhp); return (ret); } cb->be_nodes = cb->be_nodes_head; } if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && !zone_be) { be_snapshot_list_t *snapshots = NULL; if (cb->be_nodes->be_node_snapshots == NULL) { if ((cb->be_nodes->be_node_snapshots = be_list_alloc(&ret, sizeof (be_snapshot_list_t))) == NULL || ret != BE_SUCCESS) { ZFS_CLOSE(zhp); return (ret); } cb->be_nodes->be_node_snapshots->be_next_snapshot = NULL; snapshots = cb->be_nodes->be_node_snapshots; } else { for (snapshots = cb->be_nodes->be_node_snapshots; snapshots != NULL; snapshots = snapshots->be_next_snapshot) { if (snapshots->be_next_snapshot != NULL) continue; /* * We're at the end of the list add the * new snapshot. */ if ((snapshots->be_next_snapshot = be_list_alloc(&ret, sizeof (be_snapshot_list_t))) == NULL || ret != BE_SUCCESS) { ZFS_CLOSE(zhp); return (ret); } snapshots = snapshots->be_next_snapshot; snapshots->be_next_snapshot = NULL; break; } } if ((ret = be_get_ss_data(zhp, str, snapshots, cb->be_nodes)) != BE_SUCCESS) { ZFS_CLOSE(zhp); return (ret); } } 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 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) { 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 *datasets = NULL; if (cb->be_nodes->be_node_datasets == NULL) { if ((cb->be_nodes->be_node_datasets = be_list_alloc(&ret, sizeof (be_dataset_list_t))) == NULL || ret != BE_SUCCESS) { ZFS_CLOSE(zhp); return (ret); } cb->be_nodes->be_node_datasets->be_next_dataset = NULL; datasets = cb->be_nodes->be_node_datasets; } else { for (datasets = cb->be_nodes->be_node_datasets; datasets != NULL; datasets = datasets->be_next_dataset) { if (datasets->be_next_dataset != NULL) continue; /* * We're at the end of the list add * the new dataset. */ if ((datasets->be_next_dataset = be_list_alloc(&ret, sizeof (be_dataset_list_t))) == NULL || ret != BE_SUCCESS) { ZFS_CLOSE(zhp); return (ret); } datasets = datasets->be_next_dataset; datasets->be_next_dataset = NULL; break; } } if ((ret = be_get_ds_data(zhp, str, datasets, cb->be_nodes)) != BE_SUCCESS) { ZFS_CLOSE(zhp); return (ret); } } ret = zfs_iter_children(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); }
/* * 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 _be_list(char *be_name, be_node_list_t **be_nodes) { list_callback_data_t cb = { 0 }; be_transaction_data_t bt = { 0 }; int ret = BE_SUCCESS; zpool_handle_t *zphp; char *rpool = NULL; struct be_defaults be_defaults; if (be_nodes == NULL) return (BE_ERR_INVAL); be_get_defaults(&be_defaults); if (be_find_current_be(&bt) != BE_SUCCESS) { /* * 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. */ (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 is NULL we'll look for all BE's on the system. * If not then we will only return data for the specified BE. */ if (be_name != NULL) cb.be_name = strdup(be_name); if (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); be_sort_list(be_nodes); return (ret); }