/* * path - path of the dataset * count - return value of the number of snapshots for the dataset */ int smbd_vss_get_count(const char *path, uint32_t *count) { char dataset[MAXPATHLEN]; libzfs_handle_t *libhd; zfs_handle_t *zfshd; smbd_vss_count_t vss_count; bzero(&vss_count, sizeof (smbd_vss_count_t)); *count = 0; if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) return (-1); if ((libhd = libzfs_init()) == NULL) return (-1); if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { libzfs_fini(libhd); return (-1); } (void) zfs_iter_snapshots(zfshd, smbd_vss_iterate_count, (void *)&vss_count); if (vss_count.vc_count > SMBD_VSS_SNAPSHOT_MAX) vss_count.vc_count = SMBD_VSS_SNAPSHOT_MAX; *count = vss_count.vc_count; zfs_close(zfshd); libzfs_fini(libhd); return (0); }
/* * This is a ZFS snapshot iterator call-back function which returns the * highest number of SUNWzone snapshots that have been taken. */ static int get_snap_max(zfs_handle_t *zhp, void *data) { int res; zfs_snapshot_data_t *cbp; if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) { zfs_close(zhp); return (0); } cbp = (zfs_snapshot_data_t *)data; if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) { char *nump; int num; cbp->num++; nump = (char *)(zfs_get_name(zhp) + cbp->len); num = atoi(nump); if (num > cbp->max) cbp->max = num; } res = zfs_iter_snapshots(zhp, B_FALSE, get_snap_max, data); zfs_close(zhp); return (res); }
/* * Called for each dataset. If the object is of an appropriate type, * add it to the avl tree and recurse over any children as necessary. */ static int zfs_callback(zfs_handle_t *zhp, void *data) { callback_data_t *cb = data; int dontclose = 0; int include_snaps = zfs_include_snapshots(zhp, cb); if ((zfs_get_type(zhp) & cb->cb_types) || ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) { uu_avl_index_t idx; zfs_node_t *node = safe_malloc(sizeof (zfs_node_t)); node->zn_handle = zhp; uu_avl_node_init(node, &node->zn_avlnode, avl_pool); if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol, &idx) == NULL) { if (cb->cb_proplist) { if ((*cb->cb_proplist) && !(*cb->cb_proplist)->pl_all) zfs_prune_proplist(zhp, cb->cb_props_table); if (zfs_expand_proplist(zhp, cb->cb_proplist, (cb->cb_flags & ZFS_ITER_RECVD_PROPS), (cb->cb_flags & ZFS_ITER_LITERAL_PROPS)) != 0) { free(node); return (-1); } } uu_avl_insert(cb->cb_avl, node, idx); dontclose = 1; } else { free(node); } } /* * Recurse if necessary. */ if (cb->cb_flags & ZFS_ITER_RECURSE && ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 || cb->cb_depth < cb->cb_depth_limit)) { cb->cb_depth++; if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) (void) zfs_iter_filesystems(zhp, zfs_callback, data); if ((zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) && include_snaps) { (void) zfs_iter_snapshots(zhp, (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback, data); } cb->cb_depth--; } if (!dontclose) zfs_close(zhp); return (0); }
static int iter_dependents_cb(zfs_handle_t *zhp, void *arg) { iter_dependents_arg_t *ida = arg; int err = 0; boolean_t first = ida->first; ida->first = B_FALSE; if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { err = zfs_iter_clones(zhp, iter_dependents_cb, ida); } else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) { iter_stack_frame_t isf; iter_stack_frame_t *f; /* * check if there is a cycle by seeing if this fs is already * on the stack. */ for (f = ida->stack; f != NULL; f = f->next) { if (f->zhp->zfs_dmustats.dds_guid == zhp->zfs_dmustats.dds_guid) { if (ida->allowrecursion) { zfs_close(zhp); return (0); } else { zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "recursive dependency at '%s'"), zfs_get_name(zhp)); err = zfs_error(zhp->zfs_hdl, EZFS_RECURSIVE, dgettext(TEXT_DOMAIN, "cannot determine dependent " "datasets")); zfs_close(zhp); return (err); } } } isf.zhp = zhp; isf.next = ida->stack; ida->stack = &isf; err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida); if (err == 0) { err = zfs_iter_snapshots(zhp, B_FALSE, iter_dependents_cb, ida); } ida->stack = isf.next; } if (!first && err == 0) err = ida->func(zhp, ida->data); else zfs_close(zhp); return (err); }
/* * Iterate over all children, snapshots and filesystems */ int zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) { int ret; if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) return (ret); return (zfs_iter_snapshots(zhp, B_FALSE, func, data)); }
/* * path - path of the dataset for the operation * gmttoken - the @GMT token to be looked up * toktime - time_t used if gmttoken == NULL * snapname - the snapshot name to be returned [MAXPATHLEN] * * Here we are going to get the snapshot name from the @GMT token * The snapname returned by ZFS is : <dataset name>@<snapshot name> * So we are going to make sure there is the @ symbol in * the right place and then just return the snapshot name */ int smbd_vss_map_gmttoken(const char *path, char *gmttoken, time_t toktime, char *snapname) { char dataset[MAXPATHLEN]; libzfs_handle_t *libhd; zfs_handle_t *zfshd; smbd_vss_map_gmttoken_t vss_map_gmttoken; char *zsnap; const char *lsnap; struct tm tm; if (gmttoken != NULL && *gmttoken == '@' && strptime(gmttoken, smbd_vss_gmttoken_fmt, &tm) != NULL) { toktime = timegm(&tm); } vss_map_gmttoken.mg_snaptime = toktime; vss_map_gmttoken.mg_snapname = snapname; *snapname = '\0'; if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) return (-1); if ((libhd = libzfs_init()) == NULL) return (-1); if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { libzfs_fini(libhd); return (-1); } (void) zfs_iter_snapshots(zfshd, smbd_vss_iterate_map_gmttoken, (void *)&vss_map_gmttoken); /* compare the zfs snapshot name and the local snap name */ zsnap = snapname; lsnap = dataset; while ((*lsnap != '\0') && (*zsnap != '\0') && (*lsnap == *zsnap)) { zsnap++; lsnap++; } /* Now we should be passed the dataset name */ if ((*zsnap == '@') && (*lsnap == '\0')) { zsnap++; (void) strlcpy(snapname, zsnap, MAXPATHLEN); } else { *snapname = '\0'; } zfs_close(zfshd); libzfs_fini(libhd); return (0); }
/* * Called for each dataset. If the object the object is of an appropriate type, * add it to the avl tree and recurse over any children as necessary. */ static int zfs_callback(zfs_handle_t *zhp, void *data) { callback_data_t *cb = data; int dontclose = 0; /* * If this object is of the appropriate type, add it to the AVL tree. */ if (zfs_get_type(zhp) & cb->cb_types) { uu_avl_index_t idx; zfs_node_t *node = safe_malloc(sizeof (zfs_node_t)); node->zn_handle = zhp; uu_avl_node_init(node, &node->zn_avlnode, avl_pool); if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol, &idx) == NULL) { if (cb->cb_proplist && zfs_expand_proplist(zhp, cb->cb_proplist) != 0) { free(node); return (-1); } uu_avl_insert(cb->cb_avl, node, idx); dontclose = 1; } else { free(node); } } /* * Recurse if necessary. */ if (cb->cb_recurse) { if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) (void) zfs_iter_filesystems(zhp, zfs_callback, data); if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT && (cb->cb_types & ZFS_TYPE_SNAPSHOT)) (void) zfs_iter_snapshots(zhp, zfs_callback, data); } if (!dontclose) zfs_close(zhp); return (0); }
int Destroy::iter_dataset(zfs_handle_t *hzfs, void *ptr) { Destroy *self = (Destroy*)ptr; if (zfs_get_type(hzfs) == ZFS_TYPE_SNAPSHOT) { Dataset ds(hzfs); if (self->check_tag(ds) && self->check_age(ds)) { self->m_datasets.push_back(ds); } } if (self->m_recursive) { zfs_iter_filesystems(hzfs, iter_dataset, self); zfs_iter_snapshots(hzfs, B_FALSE, iter_dataset, self); } return 0; }
void Destroy::find(const std::string &root) { zfs_handle_t *hzfs = zfs_open(m_hlib, root.c_str(), ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); if (!hzfs) { std::cerr << root << ": " << libzfs_error_description(m_hlib) << std::endl; return; } zfs_iter_snapshots(hzfs, B_FALSE, iter_dataset, this); if (m_recursive) { zfs_iter_filesystems(hzfs, iter_dataset, this); } zfs_close(hzfs); }
int zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data) { int ret = 0; zfs_node_t *node; avl_tree_t avl; void *cookie = NULL; avl_create(&avl, zfs_snapshot_compare, sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode)); ret = zfs_iter_snapshots(zhp, B_FALSE, zfs_sort_snaps, &avl); for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node)) ret |= callback(node->zn_handle, data); while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL) free(node); avl_destroy(&avl); return (ret); }
/* * ndmp_has_backup_snapshot * * Returns TRUE if the volume has an active backup snapshot, otherwise, * returns FALSE. * * Parameters: * volname (input) - name of the volume * * Returns: * 0: on success * -1: otherwise */ static int ndmp_has_backup_snapshot(char *volname, char *jobname) { zfs_handle_t *zhp; snap_param_t snp; char chname[ZFS_MAXNAMELEN]; (void) mutex_lock(&zlib_mtx); if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { NDMP_LOG(LOG_ERR, "Cannot open snapshot %s.", volname); (void) mutex_unlock(&zlib_mtx); return (-1); } snp.snp_found = 0; (void) snprintf(chname, ZFS_MAXNAMELEN, "@%s", jobname); snp.snp_name = chname; (void) zfs_iter_snapshots(zhp, B_FALSE, ndmp_has_backup, &snp); zfs_close(zhp); (void) mutex_unlock(&zlib_mtx); return (snp.snp_found); }
void smbd_vss_get_snapshots(const char *path, uint32_t count, uint32_t *return_count, uint32_t *num_gmttokens, char **gmttokenp) { char dataset[MAXPATHLEN]; libzfs_handle_t *libhd; zfs_handle_t *zfshd; smbd_vss_get_uint64_date_t vss_uint64_date; int i; uint64_t *timep; *return_count = 0; *num_gmttokens = 0; if (count == 0) return; if (count > SMBD_VSS_SNAPSHOT_MAX) count = SMBD_VSS_SNAPSHOT_MAX; vss_uint64_date.gd_count = count; vss_uint64_date.gd_return_count = 0; vss_uint64_date.gd_gmt_array = malloc(count * sizeof (uint64_t)); if (vss_uint64_date.gd_gmt_array == NULL) return; if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) { free(vss_uint64_date.gd_gmt_array); return; } if ((libhd = libzfs_init()) == NULL) { free(vss_uint64_date.gd_gmt_array); return; } if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { free(vss_uint64_date.gd_gmt_array); libzfs_fini(libhd); return; } (void) zfs_iter_snapshots(zfshd, smbd_vss_iterate_get_uint64_date, (void *)&vss_uint64_date); *num_gmttokens = vss_uint64_date.gd_return_count; *return_count = vss_uint64_date.gd_return_count; /* * Sort the list since neither zfs nor the client sorts it. */ qsort((char *)vss_uint64_date.gd_gmt_array, vss_uint64_date.gd_return_count, sizeof (uint64_t), smbd_vss_cmp_time); timep = vss_uint64_date.gd_gmt_array; for (i = 0; i < vss_uint64_date.gd_return_count; i++) { *gmttokenp = malloc(SMB_VSS_GMT_SIZE); if (*gmttokenp) smbd_vss_time2gmttoken(*timep, *gmttokenp); else vss_uint64_date.gd_return_count = 0; timep++; gmttokenp++; } free(vss_uint64_date.gd_gmt_array); zfs_close(zfshd); libzfs_fini(libhd); }
/* * 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 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); /* * Generate string for the BE container dataset */ be_make_container_ds(rpool, be_container_ds, 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. */ if (cb->be_name != NULL) { if (!be_valid_be_name(cb->be_name)) return (BE_ERR_INVAL); /* * Generate string for the BE root dataset */ be_make_root_ds(rpool, cb->be_name, be_ds, sizeof (be_ds)); open_ds = be_ds; } else { open_ds = be_container_ds; } /* * Check if the dataset exists */ if (!zfs_dataset_exists(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) { /* * The specified dataset does not exist in this pool or * there are no valid BE's in this pool. Try the next zpool. */ 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 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 */ if (cb->be_name != NULL) { if (cb->be_nodes_head == NULL) { if ((cb->be_nodes_head = be_list_alloc(&ret, sizeof (be_node_list_t))) == NULL) { ZFS_CLOSE(zhp); zpool_close(zlp); return (ret); } cb->be_nodes = cb->be_nodes_head; } 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); } ret = zfs_iter_snapshots(zhp, 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); }
/* * Called for each dataset. If the object is of an appropriate type, * add it to the avl tree and recurse over any children as necessary. */ static int zfs_callback(zfs_handle_t *zhp, void *data) { callback_data_t *cb = data; boolean_t should_close = B_TRUE; boolean_t include_snaps = zfs_include_snapshots(zhp, cb); boolean_t include_bmarks = (cb->cb_types & ZFS_TYPE_BOOKMARK); if ((zfs_get_type(zhp) & cb->cb_types) || ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) { uu_avl_index_t idx; zfs_node_t *node = safe_malloc(sizeof (zfs_node_t)); node->zn_handle = zhp; uu_avl_node_init(node, &node->zn_avlnode, avl_pool); if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol, &idx) == NULL) { if (cb->cb_proplist) { if ((*cb->cb_proplist) && !(*cb->cb_proplist)->pl_all) zfs_prune_proplist(zhp, cb->cb_props_table); if (zfs_expand_proplist(zhp, cb->cb_proplist, (cb->cb_flags & ZFS_ITER_RECVD_PROPS), (cb->cb_flags & ZFS_ITER_LITERAL_PROPS)) != 0) { free(node); return (-1); } } uu_avl_insert(cb->cb_avl, node, idx); should_close = B_FALSE; } else { free(node); } } /* * Recurse if necessary. */ if (cb->cb_flags & ZFS_ITER_RECURSE && ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 || cb->cb_depth < cb->cb_depth_limit)) { cb->cb_depth++; /* * If we are not looking for filesystems, we don't need to * recurse into filesystems when we are at our depth limit. */ if ((cb->cb_depth < cb->cb_depth_limit || (cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 || (cb->cb_types & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) && zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { (void) zfs_iter_filesystems(zhp, zfs_callback, data); } if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) == 0) && include_snaps) { (void) zfs_iter_snapshots(zhp, (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback, data, 0, 0); } if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks) { (void) zfs_iter_bookmarks(zhp, zfs_callback, data); } cb->cb_depth--; } if (should_close) zfs_close(zhp); return (0); }