/* * Count the number of ZFS properties and user/group quotas */ int zfs_get_prop_counts(zfs_handle_t *zhp) { int count = 0; nvlist_t *uprops; nvpair_t *elp; if (zhp == NULL) return (0); (void) zprop_iter(zfs_count_prop_cb, &count, TRUE, TRUE, ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET); (void) zfs_userspace(zhp, ZFS_PROP_USERQUOTA, zfs_count_quota_cb, &count); (void) zfs_userspace(zhp, ZFS_PROP_GROUPQUOTA, zfs_count_quota_cb, &count); uprops = zfs_get_user_props(zhp); elp = nvlist_next_nvpair(uprops, NULL); for (; elp != NULL; elp = nvlist_next_nvpair(uprops, elp)) count++; return (count); }
/* * 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 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); /* * Try to get this snapshot's cleanup policy from its * user properties first. If not there, use default * cleanup policy. */ 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 int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, char *val) { nvlist_t *propval; char *propstr; int ret; ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval); if (ret) return ret; ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr); if (ret) return ret; (void) strcpy(val, propstr); return ret; }
static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, __u32 *val) { nvlist_t *propval; char *propstr; int ret; ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval); if (ret) return ret; ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr); if (ret) return ret; errno = 0; *val = strtoul(propstr, NULL, 10); if (errno) return errno; return ret; }
/* * Sort datasets by specified columns. * * o Numeric types sort in ascending order. * o String types sort in alphabetical order. * o Types inappropriate for a row sort that row to the literal * bottom, regardless of the specified ordering. * * If no sort columns are specified, or two datasets compare equally * across all specified columns, they are sorted alphabetically by name * with snapshots grouped under their parents. */ static int zfs_sort(const void *larg, const void *rarg, void *data) { zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; zfs_sort_column_t *sc = (zfs_sort_column_t *)data; zfs_sort_column_t *psc; for (psc = sc; psc != NULL; psc = psc->sc_next) { char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN]; char *lstr, *rstr; uint64_t lnum, rnum; boolean_t lvalid, rvalid; int ret = 0; /* * We group the checks below the generic code. If 'lstr' and * 'rstr' are non-NULL, then we do a string based comparison. * Otherwise, we compare 'lnum' and 'rnum'. */ lstr = rstr = NULL; if (psc->sc_prop == ZPROP_INVAL) { nvlist_t *luser, *ruser; nvlist_t *lval, *rval; luser = zfs_get_user_props(l); ruser = zfs_get_user_props(r); lvalid = (nvlist_lookup_nvlist(luser, psc->sc_user_prop, &lval) == 0); rvalid = (nvlist_lookup_nvlist(ruser, psc->sc_user_prop, &rval) == 0); if (lvalid) verify(nvlist_lookup_string(lval, ZPROP_VALUE, &lstr) == 0); if (rvalid) verify(nvlist_lookup_string(rval, ZPROP_VALUE, &rstr) == 0); } else if (psc->sc_prop == ZFS_PROP_NAME) { lvalid = rvalid = B_TRUE; (void) strlcpy(lbuf, zfs_get_name(l), sizeof(lbuf)); (void) strlcpy(rbuf, zfs_get_name(r), sizeof(rbuf)); lstr = lbuf; rstr = rbuf; } else if (zfs_prop_is_string(psc->sc_prop)) { lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf, sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0); rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf, sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0); lstr = lbuf; rstr = rbuf; } else { lvalid = zfs_prop_valid_for_type(psc->sc_prop, zfs_get_type(l)); rvalid = zfs_prop_valid_for_type(psc->sc_prop, zfs_get_type(r)); if (lvalid) (void) zfs_prop_get_numeric(l, psc->sc_prop, &lnum, NULL, NULL, 0); if (rvalid) (void) zfs_prop_get_numeric(r, psc->sc_prop, &rnum, NULL, NULL, 0); } if (!lvalid && !rvalid) continue; else if (!lvalid) return (1); else if (!rvalid) return (-1); if (lstr) ret = strcmp(lstr, rstr); else if (lnum < rnum) ret = -1; else if (lnum > rnum) ret = 1; if (ret != 0) { if (psc->sc_reverse == B_TRUE) ret = (ret < 0) ? 1 : -1; return (ret); } } return (zfs_compare(larg, rarg, NULL)); }
/* * 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 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 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 (!(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); /* * Get the user property used for the libbe * cleaup policy */ 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); }
/* * 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 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) { 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)); } (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 (prop_buf != NULL && 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; } /* * 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. */ 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); /* Get all user properties used for libbe */ 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); } } } /* * Increment the dataset counter to include the root dataset * of the BE. */ be_node->be_node_num_datasets++; return (BE_SUCCESS); }
/* * Notifies ndmpd that the metadata associated with the given ZFS dataset * should be backed up. */ int ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset) { tlm_commands_t *cmds; ndmp_metadata_handle_t mhd; ndmp_metadata_header_ext_t *mhp; ndmp_metadata_property_ext_t *mpp; zfs_handle_t *zhp; tlm_cmd_t *lcmd; long actual_size; nvlist_t *uprops, *ulist; const char *pname; nvpair_t *elp; char *sval, *ssrc; char *wbuf, *pp, *tp; long size, lsize, sz; int align = RECORDSIZE - 1; int pcount; if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL) return (-1); if ((lcmd = cmds->tcs_command) == NULL || lcmd->tc_buffers == NULL) return (-1); (void) mutex_lock(&zlib_mtx); if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) { (void) mutex_unlock(&zlib_mtx); return (-1); } pcount = zfs_get_prop_counts(zhp); size = sizeof (ndmp_metadata_header_ext_t) + pcount * sizeof (ndmp_metadata_property_ext_t); size += align; size &= ~align; if ((mhp = malloc(size)) == NULL) { zfs_close(zhp); (void) mutex_unlock(&zlib_mtx); return (-1); } (void) memset(mhp, 0, size); mhd.ml_handle = zhp; mhd.ml_xhdr = mhp; mhp->nh_total_bytes = size; mhp->nh_major = META_HDR_MAJOR_VERSION; mhp->nh_minor = META_HDR_MINOR_VERSION; mhp->nh_plversion = nctx->nc_plversion; (void) strlcpy(mhp->nh_plname, nctx->nc_plname, sizeof (mhp->nh_plname)); (void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT, sizeof (mhp->nh_magic)); (void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset)); /* Get all the ZFS properties */ (void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE, ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET); /* Get user properties */ uprops = zfs_get_user_props(mhd.ml_handle); elp = nvlist_next_nvpair(uprops, NULL); while (elp != NULL) { mpp = &mhp->nh_property[mhp->nh_count]; if (nvpair_value_nvlist(elp, &ulist) != 0 || nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 || nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) { zfs_close(mhd.ml_handle); (void) mutex_unlock(&zlib_mtx); free(mhp); return (-1); } if ((pname = nvpair_name(elp)) != NULL) (void) strlcpy(mpp->mp_name, pname, ZFS_MAXNAMELEN); (void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN); (void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN); mhp->nh_count++; elp = nvlist_next_nvpair(uprops, elp); } mhd.ml_quota_prop = ZFS_PROP_USERQUOTA; (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA, zfs_put_quota_cb, &mhd); mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA; (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA, zfs_put_quota_cb, &mhd); mhp->nh_count = pcount; zfs_close(mhd.ml_handle); (void) mutex_unlock(&zlib_mtx); if ((wbuf = get_write_buffer(size, &actual_size, TRUE, lcmd)) != NULL) { pp = (char *)mhp; (void) memcpy(wbuf, pp, (actual_size < size) ? actual_size : size); pp += (actual_size < size) ? actual_size : size; sz = actual_size; while (sz < size && ((tp = get_write_buffer(size - sz, &lsize, TRUE, lcmd))) != NULL) { (void) memcpy(tp, pp, lsize); sz += lsize; pp += lsize; } if (sz > size) { tlm_unget_write_buffer(lcmd->tc_buffers, sz - size); } } free(mhp); return (0); }