Esempio n. 1
0
/*
 * 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);
}
Esempio n. 2
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);
}
Esempio n. 3
0
/*
 * 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);
}
Esempio n. 4
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);
}
Esempio n. 5
0
/*
 * 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));
}
Esempio n. 6
0
/*
 * 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);
}
Esempio n. 7
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);
}
Esempio n. 8
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;
}
Esempio n. 9
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);
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
/*
 * 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);
}
Esempio n. 12
0
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);
}
Esempio n. 13
0
/*
 * 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);
}
Esempio n. 14
0
/*
 * 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);
}