On 8 Sep 2008, at 20:55, Darren Reed <Darren.Reed at Sun.COM> wrote:

> In the current design of zfs(1m), nearly all of the operations are  
> limited
> to working on a single filesystem at a time. This places some  
> limitations
> on the usability of zfs(1m) when using it with scripts. For example,  
> you
> cannot do:
>
> # zfs list -H -o origin | egrep -v '^\-$' | xargs zfs destroy

That's why 'xargs -l' exists. :-)


However, I see nothing wrong with what you're suggesting.








>
>
> Instead, you need to do this:
>
> # zfs list -H -o origin | egrep -v '^\-$' | sh -c 'while read i; do  
> zfs destroy "$i"; done'
>
> (because not everyone uses sh as their shell...)
>
> As an experiment, I modified zfs_main.c to allow destroy to work in
> a manner that is conducive to being used with xargs - patches  
> attached.
>
> It's a relatively simple change but there are important questions,  
> such
> as does it fail on the first error or continue on, etc.
>
> But I'm sure there was a reason why it was designed and implemented
> the way it is rather than with what my patch suggests?
>
> Darren
>
>
> diff -r 340e8fdced81 usr/src/cmd/zfs/zfs_main.c
> --- a/usr/src/cmd/zfs/zfs_main.c    Thu Sep 04 14:02:34 2008 -0700
> +++ b/usr/src/cmd/zfs/zfs_main.c    Mon Sep 08 17:45:36 2008 -0700
> @@ -77,6 +77,20 @@
> static int zfs_do_promote(int argc, char **argv);
> static int zfs_do_allow(int argc, char **argv);
> static int zfs_do_unallow(int argc, char **argv);
> +
> +typedef struct destroy_cbdata {
> +    boolean_t    cb_first;
> +    int        cb_force;
> +    int        cb_recurse;
> +    int        cb_error;
> +    int        cb_needforce;
> +    int        cb_doclones;
> +    boolean_t    cb_closezhp;
> +    zfs_handle_t    *cb_target;
> +    char        *cb_snapname;
> +} destroy_cbdata_t;
> +
> +static int zfs_destroy_filesystem(destroy_cbdata_t *cbp, char  
> *fsname);
>
> /*
>  * Enable a reasonable set of defaults for libumem debugging on  
> DEBUG builds.
> @@ -746,17 +760,6 @@
>  * and refuse to destroy a dataset that has any dependents.  A  
> dependent can
>  * either be a child, or a clone of a child.
>  */
> -typedef struct destroy_cbdata {
> -    boolean_t    cb_first;
> -    int        cb_force;
> -    int        cb_recurse;
> -    int        cb_error;
> -    int        cb_needforce;
> -    int        cb_doclones;
> -    boolean_t    cb_closezhp;
> -    zfs_handle_t    *cb_target;
> -    char        *cb_snapname;
> -} destroy_cbdata_t;
>
> /*
>  * Check for any dependents based on the '-r' or '-R' flags.
> @@ -886,8 +889,7 @@
> {
>    destroy_cbdata_t cb = { 0 };
>    int c;
> -    zfs_handle_t *zhp;
> -    char *cp;
> +    int idx;
>
>    /* check options */
>    while ((c = getopt(argc, argv, "frR")) != -1) {
> @@ -918,27 +920,36 @@
>        (void) fprintf(stderr, gettext("missing path argument\n"));
>        usage(B_FALSE);
>    }
> -    if (argc > 1) {
> -        (void) fprintf(stderr, gettext("too many arguments\n"));
> -        usage(B_FALSE);
> -    }
>
>    /*
>     * If we are doing recursive destroy of a snapshot, then the
>     * named snapshot may not exist.  Go straight to libzfs.
>     */
> -    if (cb.cb_recurse && (cp = strchr(argv[0], '@'))) {
> +    for (idx = 0; idx < argc; idx++)
> +        if (zfs_destroy_filesystem(&cb, argv[idx]))
> +            return (1);
> +
> +    return (0);
> +}
> +
> +static int
> +zfs_destroy_filesystem(destroy_cbdata_t *cbp, char *fsname)
> +{
> +    char *cp;
> +    zfs_handle_t *zhp;
> +
> +    if (cbp->cb_recurse && (cp = strchr(fsname, '@'))) {
>        int ret;
>
>        *cp = '\0';
> -        if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) ==  
> NULL)
> +        if ((zhp = zfs_open(g_zfs, fsname, ZFS_TYPE_DATASET)) ==  
> NULL)
>            return (1);
>        *cp = '@';
>        cp++;
>
> -        if (cb.cb_doclones) {
> -            cb.cb_snapname = cp;
> -            if (destroy_snap_clones(zhp, &cb) != 0) {
> +        if (cbp->cb_doclones) {
> +            cbp->cb_snapname = cp;
> +            if (destroy_snap_clones(zhp, cbp) != 0) {
>                zfs_close(zhp);
>                return (1);
>            }
> @@ -955,15 +966,15 @@
>
>
>    /* Open the given dataset */
> -    if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
> -        return (1);
> -
> -    cb.cb_target = zhp;
> +    if ((zhp = zfs_open(g_zfs, fsname, ZFS_TYPE_DATASET)) == NULL)
> +        return (1);
> +
> +    cbp->cb_target = zhp;
>
>    /*
>     * Perform an explicit check for pools before going any further.
>     */
> -    if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
> +    if (!cbp->cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
>        zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
>        (void) fprintf(stderr, gettext("cannot destroy '%s': "
>            "operation does not apply to pools\n"),
> @@ -980,16 +991,16 @@
>    /*
>     * Check for any dependents and/or clones.
>     */
> -    cb.cb_first = B_TRUE;
> -    if (!cb.cb_doclones &&
> +    cbp->cb_first = B_TRUE;
> +    if (!cbp->cb_doclones &&
>        zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
> -        &cb) != 0) {
> -        zfs_close(zhp);
> -        return (1);
> -    }
> -
> -    if (cb.cb_error ||
> -        zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) !=  
> 0) {
> +        cbp) != 0) {
> +        zfs_close(zhp);
> +        return (1);
> +    }
> +
> +    if (cbp->cb_error ||
> +        zfs_iter_dependents(zhp, B_FALSE, destroy_callback, cbp) !=  
> 0) {
>        zfs_close(zhp);
>        return (1);
>    }
> @@ -999,9 +1010,8 @@
>     * whether it succeeds or not.
>     */
>
> -    if (destroy_callback(zhp, &cb) != 0)
> -        return (1);
> -
> +    if (destroy_callback(zhp, cbp) != 0)
> +        return (1);
>
>    return (0);
> }
> _______________________________________________
> zfs-code mailing list
> zfs-code at opensolaris.org
> http://mail.opensolaris.org/mailman/listinfo/zfs-code

Reply via email to