]> git.proxmox.com Git - mirror_zfs.git/blobdiff - cmd/zfs/zfs_main.c
Don't modify argv[] in user tools
[mirror_zfs.git] / cmd / zfs / zfs_main.c
index 45d9a661b0d5c125dd8e8cc19201042692d9baf9..cf2d8f2d515e974442ad31dad90bfd101e31668d 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
  * Copyright 2012 Milan Jurik. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013 Steven Hartland.  All rights reserved.
@@ -353,7 +353,7 @@ get_usage(zfs_help_t idx)
        case HELP_HOLD:
                return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
        case HELP_HOLDS:
-               return (gettext("\tholds [-r] <snapshot> ...\n"));
+               return (gettext("\tholds [-rH] <snapshot> ...\n"));
        case HELP_RELEASE:
                return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
        case HELP_DIFF:
@@ -1189,6 +1189,15 @@ destroy_callback(zfs_handle_t *zhp, void *data)
                    zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
                    zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
                        zfs_close(zhp);
+                       /*
+                        * When performing a recursive destroy we ignore errors
+                        * so that the recursive destroy could continue
+                        * destroying past problem datasets
+                        */
+                       if (cb->cb_recurse) {
+                               cb->cb_error = B_TRUE;
+                               return (0);
+                       }
                        return (-1);
                }
        }
@@ -1558,7 +1567,7 @@ zfs_do_destroy(int argc, char **argv)
                        err = zfs_destroy_snaps_nvl(g_zfs,
                            cb.cb_batchedsnaps, cb.cb_defer_destroy);
                }
-               if (err != 0)
+               if (err != 0 || cb.cb_error == B_TRUE)
                        rv = 1;
        }
 
@@ -5952,9 +5961,10 @@ holds_callback(zfs_handle_t *zhp, void *data)
 }
 
 /*
- * zfs holds [-r] <snap> ...
+ * zfs holds [-rH] <snap> ...
  *
- *     -r      Recursively hold
+ *     -r      Lists holds that are set on the named snapshots recursively.
+ *     -H      Scripted mode; elide headers and separate columns by tabs.
  */
 static int
 zfs_do_holds(int argc, char **argv)
@@ -7108,11 +7118,29 @@ zfs_do_diff(int argc, char **argv)
        return (err != 0);
 }
 
+
+/*
+ * zfs remap <filesystem | volume>
+ *
+ * Remap the indirect blocks in the given fileystem or volume.
+ */
 static int
 zfs_do_remap(int argc, char **argv)
 {
        const char *fsname;
        int err = 0;
+       int c;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "")) != -1) {
+               switch (c) {
+               case '?':
+                       (void) fprintf(stderr,
+                           gettext("invalid option '%c'\n"), optopt);
+                       usage(B_FALSE);
+               }
+       }
+
        if (argc != 2) {
                (void) fprintf(stderr, gettext("wrong number of arguments\n"));
                usage(B_FALSE);
@@ -7281,24 +7309,10 @@ zfs_do_channel_program(int argc, char **argv)
                        }
 
                        if (c == 't') {
-                               if (arg > ZCP_MAX_INSTRLIMIT || arg == 0) {
-                                       (void) fprintf(stderr, gettext(
-                                           "Invalid instruction limit: "
-                                           "%s\n"), optarg);
-                                       return (1);
-                               } else {
-                                       instrlimit = arg;
-                               }
+                               instrlimit = arg;
                        } else {
                                ASSERT3U(c, ==, 'm');
-                               if (arg > ZCP_MAX_MEMLIMIT || arg == 0) {
-                                       (void) fprintf(stderr, gettext(
-                                           "Invalid memory limit: "
-                                           "%s\n"), optarg);
-                                       return (1);
-                               } else {
-                                       memlimit = arg;
-                               }
+                               memlimit = arg;
                        }
                        break;
                }
@@ -7896,6 +7910,7 @@ main(int argc, char **argv)
        int ret = 0;
        int i = 0;
        char *cmdname;
+       char **newargv;
 
        (void) setlocale(LC_ALL, "");
        (void) textdomain(TEXT_DOMAIN);
@@ -7948,17 +7963,26 @@ main(int argc, char **argv)
 
        libzfs_print_on_error(g_zfs, B_TRUE);
 
+       /*
+        * Many commands modify input strings for string parsing reasons.
+        * We create a copy to protect the original argv.
+        */
+       newargv = malloc((argc + 1) * sizeof (newargv[0]));
+       for (i = 0; i < argc; i++)
+               newargv[i] = strdup(argv[i]);
+       newargv[argc] = NULL;
+
        /*
         * Run the appropriate command.
         */
        libzfs_mnttab_cache(g_zfs, B_TRUE);
        if (find_command_idx(cmdname, &i) == 0) {
                current_command = &command_table[i];
-               ret = command_table[i].func(argc - 1, argv + 1);
+               ret = command_table[i].func(argc - 1, newargv + 1);
        } else if (strchr(cmdname, '=') != NULL) {
                verify(find_command_idx("set", &i) == 0);
                current_command = &command_table[i];
-               ret = command_table[i].func(argc, argv);
+               ret = command_table[i].func(argc, newargv);
        } else {
                (void) fprintf(stderr, gettext("unrecognized "
                    "command '%s'\n"), cmdname);
@@ -7966,6 +7990,10 @@ main(int argc, char **argv)
                ret = 1;
        }
 
+       for (i = 0; i < argc; i++)
+               free(newargv[i]);
+       free(newargv);
+
        if (ret == 0 && log_history)
                (void) zpool_log_history(g_zfs, history_str);