Print this page
2882 implement libzfs_core
2883 changing "canmount" property to "on" should not always remount dataset
2900 "zfs snapshot" should be able to create multiple, arbitrary snapshots at once
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Chris Siden <christopher.siden@delphix.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Bill Pijewski <wdp@joyent.com>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>


  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 #include <strings.h>
  42 #include <unistd.h>
  43 #include <fcntl.h>
  44 #include <zone.h>
  45 #include <grp.h>
  46 #include <pwd.h>
  47 #include <signal.h>
  48 #include <sys/list.h>
  49 #include <sys/mkdev.h>
  50 #include <sys/mntent.h>
  51 #include <sys/mnttab.h>
  52 #include <sys/mount.h>
  53 #include <sys/stat.h>
  54 #include <sys/fs/zfs.h>
  55 #include <sys/types.h>
  56 #include <time.h>
  57 
  58 #include <libzfs.h>

  59 #include <zfs_prop.h>
  60 #include <zfs_deleg.h>
  61 #include <libuutil.h>
  62 #include <aclutils.h>
  63 #include <directory.h>
  64 
  65 #include "zfs_iter.h"
  66 #include "zfs_util.h"
  67 #include "zfs_comutil.h"
  68 
  69 libzfs_handle_t *g_zfs;
  70 
  71 static FILE *mnttab_file;
  72 static char history_str[HIS_MAX_RECORD_LEN];

  73 
  74 static int zfs_do_clone(int argc, char **argv);
  75 static int zfs_do_create(int argc, char **argv);
  76 static int zfs_do_destroy(int argc, char **argv);
  77 static int zfs_do_get(int argc, char **argv);
  78 static int zfs_do_inherit(int argc, char **argv);
  79 static int zfs_do_list(int argc, char **argv);
  80 static int zfs_do_mount(int argc, char **argv);
  81 static int zfs_do_rename(int argc, char **argv);
  82 static int zfs_do_rollback(int argc, char **argv);
  83 static int zfs_do_set(int argc, char **argv);
  84 static int zfs_do_upgrade(int argc, char **argv);
  85 static int zfs_do_snapshot(int argc, char **argv);
  86 static int zfs_do_unmount(int argc, char **argv);
  87 static int zfs_do_share(int argc, char **argv);
  88 static int zfs_do_unshare(int argc, char **argv);
  89 static int zfs_do_send(int argc, char **argv);
  90 static int zfs_do_receive(int argc, char **argv);
  91 static int zfs_do_promote(int argc, char **argv);
  92 static int zfs_do_userspace(int argc, char **argv);


 242                 return (gettext("\treceive [-vnFu] <filesystem|volume|"
 243                 "snapshot>\n"
 244                 "\treceive [-vnFu] [-d | -e] <filesystem>\n"));
 245         case HELP_RENAME:
 246                 return (gettext("\trename [-f] <filesystem|volume|snapshot> "
 247                     "<filesystem|volume|snapshot>\n"
 248                     "\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
 249                     "\trename -r <snapshot> <snapshot>"));
 250         case HELP_ROLLBACK:
 251                 return (gettext("\trollback [-rRf] <snapshot>\n"));
 252         case HELP_SEND:
 253                 return (gettext("\tsend [-DnPpRrv] [-[iI] snapshot] "
 254                     "<snapshot>\n"));
 255         case HELP_SET:
 256                 return (gettext("\tset <property=value> "
 257                     "<filesystem|volume|snapshot> ...\n"));
 258         case HELP_SHARE:
 259                 return (gettext("\tshare <-a | filesystem>\n"));
 260         case HELP_SNAPSHOT:
 261                 return (gettext("\tsnapshot [-r] [-o property=value] ... "
 262                     "<filesystem@snapname|volume@snapname>\n"));
 263         case HELP_UNMOUNT:
 264                 return (gettext("\tunmount [-f] "
 265                     "<-a | filesystem|mountpoint>\n"));
 266         case HELP_UNSHARE:
 267                 return (gettext("\tunshare "
 268                     "<-a | filesystem|mountpoint>\n"));
 269         case HELP_ALLOW:
 270                 return (gettext("\tallow <filesystem|volume>\n"
 271                     "\tallow [-ldug] "
 272                     "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
 273                     "\t    <filesystem|volume>\n"
 274                     "\tallow [-ld] -e <perm|@setname>[,...] "
 275                     "<filesystem|volume>\n"
 276                     "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n"
 277                     "\tallow -s @setname <perm|@setname>[,...] "
 278                     "<filesystem|volume>\n"));
 279         case HELP_UNALLOW:
 280                 return (gettext("\tunallow [-rldug] "
 281                     "<\"everyone\"|user|group>[,...]\n"
 282                     "\t    [<perm|@setname>[,...]] <filesystem|volume>\n"


 871  *      -d      If we can't destroy now, mark for deferred destruction
 872  *
 873  * Destroys the given dataset.  By default, it will unmount any filesystems,
 874  * and refuse to destroy a dataset that has any dependents.  A dependent can
 875  * either be a child, or a clone of a child.
 876  */
 877 typedef struct destroy_cbdata {
 878         boolean_t       cb_first;
 879         boolean_t       cb_force;
 880         boolean_t       cb_recurse;
 881         boolean_t       cb_error;
 882         boolean_t       cb_doclones;
 883         zfs_handle_t    *cb_target;
 884         boolean_t       cb_defer_destroy;
 885         boolean_t       cb_verbose;
 886         boolean_t       cb_parsable;
 887         boolean_t       cb_dryrun;
 888         nvlist_t        *cb_nvl;
 889 
 890         /* first snap in contiguous run */
 891         zfs_handle_t    *cb_firstsnap;
 892         /* previous snap in contiguous run */
 893         zfs_handle_t    *cb_prevsnap;
 894         int64_t         cb_snapused;
 895         char            *cb_snapspec;
 896 } destroy_cbdata_t;
 897 
 898 /*
 899  * Check for any dependents based on the '-r' or '-R' flags.
 900  */
 901 static int
 902 destroy_check_dependent(zfs_handle_t *zhp, void *data)
 903 {
 904         destroy_cbdata_t *cbp = data;
 905         const char *tname = zfs_get_name(cbp->cb_target);
 906         const char *name = zfs_get_name(zhp);
 907 
 908         if (strncmp(tname, name, strlen(tname)) == 0 &&
 909             (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
 910                 /*
 911                  * This is a direct descendant, not a clone somewhere else in
 912                  * the hierarchy.
 913                  */


 987                 if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
 988                     zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
 989                         zfs_close(zhp);
 990                         return (-1);
 991                 }
 992         }
 993 
 994         zfs_close(zhp);
 995         return (0);
 996 }
 997 
 998 static int
 999 destroy_print_cb(zfs_handle_t *zhp, void *arg)
1000 {
1001         destroy_cbdata_t *cb = arg;
1002         const char *name = zfs_get_name(zhp);
1003         int err = 0;
1004 
1005         if (nvlist_exists(cb->cb_nvl, name)) {
1006                 if (cb->cb_firstsnap == NULL)
1007                         cb->cb_firstsnap = zfs_handle_dup(zhp);
1008                 if (cb->cb_prevsnap != NULL)
1009                         zfs_close(cb->cb_prevsnap);
1010                 /* this snap continues the current range */
1011                 cb->cb_prevsnap = zfs_handle_dup(zhp);


1012                 if (cb->cb_verbose) {
1013                         if (cb->cb_parsable) {
1014                                 (void) printf("destroy\t%s\n", name);
1015                         } else if (cb->cb_dryrun) {
1016                                 (void) printf(gettext("would destroy %s\n"),
1017                                     name);
1018                         } else {
1019                                 (void) printf(gettext("will destroy %s\n"),
1020                                     name);
1021                         }
1022                 }
1023         } else if (cb->cb_firstsnap != NULL) {
1024                 /* end of this range */
1025                 uint64_t used = 0;
1026                 err = zfs_get_snapused_int(cb->cb_firstsnap,
1027                     cb->cb_prevsnap, &used);
1028                 cb->cb_snapused += used;
1029                 zfs_close(cb->cb_firstsnap);
1030                 cb->cb_firstsnap = NULL;
1031                 zfs_close(cb->cb_prevsnap);
1032                 cb->cb_prevsnap = NULL;
1033         }
1034         zfs_close(zhp);
1035         return (err);
1036 }
1037 
1038 static int
1039 destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
1040 {
1041         int err = 0;
1042         assert(cb->cb_firstsnap == NULL);
1043         assert(cb->cb_prevsnap == NULL);
1044         err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
1045         if (cb->cb_firstsnap != NULL) {
1046                 uint64_t used = 0;
1047                 if (err == 0) {
1048                         err = zfs_get_snapused_int(cb->cb_firstsnap,
1049                             cb->cb_prevsnap, &used);
1050                 }
1051                 cb->cb_snapused += used;
1052                 zfs_close(cb->cb_firstsnap);
1053                 cb->cb_firstsnap = NULL;
1054                 zfs_close(cb->cb_prevsnap);
1055                 cb->cb_prevsnap = NULL;
1056         }
1057         return (err);
1058 }
1059 
1060 static int
1061 snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
1062 {
1063         destroy_cbdata_t *cb = arg;
1064         int err = 0;
1065 
1066         /* Check for clones. */
1067         if (!cb->cb_doclones) {
1068                 cb->cb_target = zhp;
1069                 cb->cb_first = B_TRUE;
1070                 err = zfs_iter_dependents(zhp, B_TRUE,
1071                     destroy_check_dependent, cb);
1072         }
1073 
1074         if (err == 0) {


1887 
1888         if (spa_version < needed_spa_version) {
1889                 /* can't upgrade */
1890                 (void) printf(gettext("%s: can not be "
1891                     "upgraded; the pool version needs to first "
1892                     "be upgraded\nto version %d\n\n"),
1893                     zfs_get_name(zhp), needed_spa_version);
1894                 cb->cb_numfailed++;
1895                 return (0);
1896         }
1897 
1898         /* upgrade */
1899         if (version < cb->cb_version) {
1900                 char verstr[16];
1901                 (void) snprintf(verstr, sizeof (verstr),
1902                     "%llu", cb->cb_version);
1903                 if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
1904                         /*
1905                          * If they did "zfs upgrade -a", then we could
1906                          * be doing ioctls to different pools.  We need
1907                          * to log this history once to each pool.

1908                          */
1909                         verify(zpool_stage_history(g_zfs, history_str) == 0);

1910                 }
1911                 if (zfs_prop_set(zhp, "version", verstr) == 0)
1912                         cb->cb_numupgraded++;
1913                 else
1914                         cb->cb_numfailed++;
1915                 (void) strcpy(cb->cb_lastfs, zfs_get_name(zhp));
1916         } else if (version > cb->cb_version) {
1917                 /* can't downgrade */
1918                 (void) printf(gettext("%s: can not be downgraded; "
1919                     "it is already at version %u\n"),
1920                     zfs_get_name(zhp), version);
1921                 cb->cb_numfailed++;
1922         } else {
1923                 cb->cb_numsamegraded++;
1924         }
1925         return (0);
1926 }
1927 
1928 /*
1929  * zfs upgrade


3407                 (void) fprintf(stderr, gettext("missing value in "
3408                     "property=value argument\n"));
3409                 usage(B_FALSE);
3410         }
3411 
3412         *cb.cb_value = '\0';
3413         cb.cb_value++;
3414 
3415         if (*cb.cb_propname == '\0') {
3416                 (void) fprintf(stderr,
3417                     gettext("missing property in property=value argument\n"));
3418                 usage(B_FALSE);
3419         }
3420 
3421         ret = zfs_for_each(argc - 2, argv + 2, NULL,
3422             ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
3423 
3424         return (ret);
3425 }
3426 


























3427 /*
3428  * zfs snapshot [-r] [-o prop=value] ... <fs@snap>
3429  *
3430  * Creates a snapshot with the given name.  While functionally equivalent to
3431  * 'zfs create', it is a separate command to differentiate intent.
3432  */
3433 static int
3434 zfs_do_snapshot(int argc, char **argv)
3435 {
3436         boolean_t recursive = B_FALSE;
3437         int ret = 0;
3438         char c;
3439         nvlist_t *props;


3440 
3441         if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
3442                 nomem();


3443 
3444         /* check options */
3445         while ((c = getopt(argc, argv, "ro:")) != -1) {
3446                 switch (c) {
3447                 case 'o':
3448                         if (parseprop(props))
3449                                 return (1);
3450                         break;
3451                 case 'r':
3452                         recursive = B_TRUE;

3453                         break;
3454                 case '?':
3455                         (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3456                             optopt);
3457                         goto usage;
3458                 }
3459         }
3460 
3461         argc -= optind;
3462         argv += optind;
3463 
3464         /* check number of arguments */
3465         if (argc < 1) {
3466                 (void) fprintf(stderr, gettext("missing snapshot argument\n"));
3467                 goto usage;
3468         }
3469         if (argc > 1) {
3470                 (void) fprintf(stderr, gettext("too many arguments\n"));















3471                 goto usage;
3472         }
3473 
3474         ret = zfs_snapshot(g_zfs, argv[0], recursive, props);

3475         nvlist_free(props);
3476         if (ret && recursive)
3477                 (void) fprintf(stderr, gettext("no snapshots were created\n"));
3478         return (ret != 0);
3479 
3480 usage:

3481         nvlist_free(props);
3482         usage(B_FALSE);
3483         return (-1);
3484 }
3485 
3486 /*
3487  * Send a backup stream to stdout.
3488  */
3489 static int
3490 zfs_do_send(int argc, char **argv)
3491 {
3492         char *fromname = NULL;
3493         char *toname = NULL;
3494         char *cp;
3495         zfs_handle_t *zhp;
3496         sendflags_t flags = { 0 };
3497         int c, err;
3498         nvlist_t *dbgnv = NULL;
3499         boolean_t extraverbose = B_FALSE;
3500 


6462 
6463 int
6464 main(int argc, char **argv)
6465 {
6466         int ret = 0;
6467         int i;
6468         char *progname;
6469         char *cmdname;
6470 
6471         (void) setlocale(LC_ALL, "");
6472         (void) textdomain(TEXT_DOMAIN);
6473 
6474         opterr = 0;
6475 
6476         if ((g_zfs = libzfs_init()) == NULL) {
6477                 (void) fprintf(stderr, gettext("internal error: failed to "
6478                     "initialize ZFS library\n"));
6479                 return (1);
6480         }
6481 
6482         zpool_set_history_str("zfs", argc, argv, history_str);
6483         verify(zpool_stage_history(g_zfs, history_str) == 0);
6484 
6485         libzfs_print_on_error(g_zfs, B_TRUE);
6486 
6487         if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) {
6488                 (void) fprintf(stderr, gettext("internal error: unable to "
6489                     "open %s\n"), MNTTAB);
6490                 return (1);
6491         }
6492 
6493         /*
6494          * This command also doubles as the /etc/fs mount and unmount program.
6495          * Determine if we should take this behavior based on argv[0].
6496          */
6497         progname = basename(argv[0]);
6498         if (strcmp(progname, "mount") == 0) {
6499                 ret = manual_mount(argc, argv);
6500         } else if (strcmp(progname, "umount") == 0) {
6501                 ret = manual_unmount(argc, argv);
6502         } else {
6503                 /*


6532                  * Run the appropriate command.
6533                  */
6534                 libzfs_mnttab_cache(g_zfs, B_TRUE);
6535                 if (find_command_idx(cmdname, &i) == 0) {
6536                         current_command = &command_table[i];
6537                         ret = command_table[i].func(argc - 1, argv + 1);
6538                 } else if (strchr(cmdname, '=') != NULL) {
6539                         verify(find_command_idx("set", &i) == 0);
6540                         current_command = &command_table[i];
6541                         ret = command_table[i].func(argc, argv);
6542                 } else {
6543                         (void) fprintf(stderr, gettext("unrecognized "
6544                             "command '%s'\n"), cmdname);
6545                         usage(B_FALSE);
6546                 }
6547                 libzfs_mnttab_cache(g_zfs, B_FALSE);
6548         }
6549 
6550         (void) fclose(mnttab_file);
6551 



6552         libzfs_fini(g_zfs);
6553 
6554         /*
6555          * The 'ZFS_ABORT' environment variable causes us to dump core on exit
6556          * for the purposes of running ::findleaks.
6557          */
6558         if (getenv("ZFS_ABORT") != NULL) {
6559                 (void) printf("dumping core by request\n");
6560                 abort();
6561         }
6562 
6563         return (ret);
6564 }


  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 #include <strings.h>
  42 #include <unistd.h>
  43 #include <fcntl.h>
  44 #include <zone.h>
  45 #include <grp.h>
  46 #include <pwd.h>
  47 #include <signal.h>
  48 #include <sys/list.h>
  49 #include <sys/mkdev.h>
  50 #include <sys/mntent.h>
  51 #include <sys/mnttab.h>
  52 #include <sys/mount.h>
  53 #include <sys/stat.h>
  54 #include <sys/fs/zfs.h>
  55 #include <sys/types.h>
  56 #include <time.h>
  57 
  58 #include <libzfs.h>
  59 #include <libzfs_core.h>
  60 #include <zfs_prop.h>
  61 #include <zfs_deleg.h>
  62 #include <libuutil.h>
  63 #include <aclutils.h>
  64 #include <directory.h>
  65 
  66 #include "zfs_iter.h"
  67 #include "zfs_util.h"
  68 #include "zfs_comutil.h"
  69 
  70 libzfs_handle_t *g_zfs;
  71 
  72 static FILE *mnttab_file;
  73 static char history_str[HIS_MAX_RECORD_LEN];
  74 static boolean_t log_history = B_TRUE;
  75 
  76 static int zfs_do_clone(int argc, char **argv);
  77 static int zfs_do_create(int argc, char **argv);
  78 static int zfs_do_destroy(int argc, char **argv);
  79 static int zfs_do_get(int argc, char **argv);
  80 static int zfs_do_inherit(int argc, char **argv);
  81 static int zfs_do_list(int argc, char **argv);
  82 static int zfs_do_mount(int argc, char **argv);
  83 static int zfs_do_rename(int argc, char **argv);
  84 static int zfs_do_rollback(int argc, char **argv);
  85 static int zfs_do_set(int argc, char **argv);
  86 static int zfs_do_upgrade(int argc, char **argv);
  87 static int zfs_do_snapshot(int argc, char **argv);
  88 static int zfs_do_unmount(int argc, char **argv);
  89 static int zfs_do_share(int argc, char **argv);
  90 static int zfs_do_unshare(int argc, char **argv);
  91 static int zfs_do_send(int argc, char **argv);
  92 static int zfs_do_receive(int argc, char **argv);
  93 static int zfs_do_promote(int argc, char **argv);
  94 static int zfs_do_userspace(int argc, char **argv);


 244                 return (gettext("\treceive [-vnFu] <filesystem|volume|"
 245                 "snapshot>\n"
 246                 "\treceive [-vnFu] [-d | -e] <filesystem>\n"));
 247         case HELP_RENAME:
 248                 return (gettext("\trename [-f] <filesystem|volume|snapshot> "
 249                     "<filesystem|volume|snapshot>\n"
 250                     "\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
 251                     "\trename -r <snapshot> <snapshot>"));
 252         case HELP_ROLLBACK:
 253                 return (gettext("\trollback [-rRf] <snapshot>\n"));
 254         case HELP_SEND:
 255                 return (gettext("\tsend [-DnPpRrv] [-[iI] snapshot] "
 256                     "<snapshot>\n"));
 257         case HELP_SET:
 258                 return (gettext("\tset <property=value> "
 259                     "<filesystem|volume|snapshot> ...\n"));
 260         case HELP_SHARE:
 261                 return (gettext("\tshare <-a | filesystem>\n"));
 262         case HELP_SNAPSHOT:
 263                 return (gettext("\tsnapshot [-r] [-o property=value] ... "
 264                     "<filesystem@snapname|volume@snapname> ...\n"));
 265         case HELP_UNMOUNT:
 266                 return (gettext("\tunmount [-f] "
 267                     "<-a | filesystem|mountpoint>\n"));
 268         case HELP_UNSHARE:
 269                 return (gettext("\tunshare "
 270                     "<-a | filesystem|mountpoint>\n"));
 271         case HELP_ALLOW:
 272                 return (gettext("\tallow <filesystem|volume>\n"
 273                     "\tallow [-ldug] "
 274                     "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
 275                     "\t    <filesystem|volume>\n"
 276                     "\tallow [-ld] -e <perm|@setname>[,...] "
 277                     "<filesystem|volume>\n"
 278                     "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n"
 279                     "\tallow -s @setname <perm|@setname>[,...] "
 280                     "<filesystem|volume>\n"));
 281         case HELP_UNALLOW:
 282                 return (gettext("\tunallow [-rldug] "
 283                     "<\"everyone\"|user|group>[,...]\n"
 284                     "\t    [<perm|@setname>[,...]] <filesystem|volume>\n"


 873  *      -d      If we can't destroy now, mark for deferred destruction
 874  *
 875  * Destroys the given dataset.  By default, it will unmount any filesystems,
 876  * and refuse to destroy a dataset that has any dependents.  A dependent can
 877  * either be a child, or a clone of a child.
 878  */
 879 typedef struct destroy_cbdata {
 880         boolean_t       cb_first;
 881         boolean_t       cb_force;
 882         boolean_t       cb_recurse;
 883         boolean_t       cb_error;
 884         boolean_t       cb_doclones;
 885         zfs_handle_t    *cb_target;
 886         boolean_t       cb_defer_destroy;
 887         boolean_t       cb_verbose;
 888         boolean_t       cb_parsable;
 889         boolean_t       cb_dryrun;
 890         nvlist_t        *cb_nvl;
 891 
 892         /* first snap in contiguous run */
 893         char            *cb_firstsnap;
 894         /* previous snap in contiguous run */
 895         char            *cb_prevsnap;
 896         int64_t         cb_snapused;
 897         char            *cb_snapspec;
 898 } destroy_cbdata_t;
 899 
 900 /*
 901  * Check for any dependents based on the '-r' or '-R' flags.
 902  */
 903 static int
 904 destroy_check_dependent(zfs_handle_t *zhp, void *data)
 905 {
 906         destroy_cbdata_t *cbp = data;
 907         const char *tname = zfs_get_name(cbp->cb_target);
 908         const char *name = zfs_get_name(zhp);
 909 
 910         if (strncmp(tname, name, strlen(tname)) == 0 &&
 911             (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
 912                 /*
 913                  * This is a direct descendant, not a clone somewhere else in
 914                  * the hierarchy.
 915                  */


 989                 if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
 990                     zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
 991                         zfs_close(zhp);
 992                         return (-1);
 993                 }
 994         }
 995 
 996         zfs_close(zhp);
 997         return (0);
 998 }
 999 
1000 static int
1001 destroy_print_cb(zfs_handle_t *zhp, void *arg)
1002 {
1003         destroy_cbdata_t *cb = arg;
1004         const char *name = zfs_get_name(zhp);
1005         int err = 0;
1006 
1007         if (nvlist_exists(cb->cb_nvl, name)) {
1008                 if (cb->cb_firstsnap == NULL)
1009                         cb->cb_firstsnap = strdup(name);
1010                 if (cb->cb_prevsnap != NULL)
1011                         free(cb->cb_prevsnap);
1012                 /* this snap continues the current range */
1013                 cb->cb_prevsnap = strdup(name);
1014                 if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
1015                         nomem();
1016                 if (cb->cb_verbose) {
1017                         if (cb->cb_parsable) {
1018                                 (void) printf("destroy\t%s\n", name);
1019                         } else if (cb->cb_dryrun) {
1020                                 (void) printf(gettext("would destroy %s\n"),
1021                                     name);
1022                         } else {
1023                                 (void) printf(gettext("will destroy %s\n"),
1024                                     name);
1025                         }
1026                 }
1027         } else if (cb->cb_firstsnap != NULL) {
1028                 /* end of this range */
1029                 uint64_t used = 0;
1030                 err = lzc_snaprange_space(cb->cb_firstsnap,
1031                     cb->cb_prevsnap, &used);
1032                 cb->cb_snapused += used;
1033                 free(cb->cb_firstsnap);
1034                 cb->cb_firstsnap = NULL;
1035                 free(cb->cb_prevsnap);
1036                 cb->cb_prevsnap = NULL;
1037         }
1038         zfs_close(zhp);
1039         return (err);
1040 }
1041 
1042 static int
1043 destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
1044 {
1045         int err = 0;
1046         assert(cb->cb_firstsnap == NULL);
1047         assert(cb->cb_prevsnap == NULL);
1048         err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
1049         if (cb->cb_firstsnap != NULL) {
1050                 uint64_t used = 0;
1051                 if (err == 0) {
1052                         err = lzc_snaprange_space(cb->cb_firstsnap,
1053                             cb->cb_prevsnap, &used);
1054                 }
1055                 cb->cb_snapused += used;
1056                 free(cb->cb_firstsnap);
1057                 cb->cb_firstsnap = NULL;
1058                 free(cb->cb_prevsnap);
1059                 cb->cb_prevsnap = NULL;
1060         }
1061         return (err);
1062 }
1063 
1064 static int
1065 snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
1066 {
1067         destroy_cbdata_t *cb = arg;
1068         int err = 0;
1069 
1070         /* Check for clones. */
1071         if (!cb->cb_doclones) {
1072                 cb->cb_target = zhp;
1073                 cb->cb_first = B_TRUE;
1074                 err = zfs_iter_dependents(zhp, B_TRUE,
1075                     destroy_check_dependent, cb);
1076         }
1077 
1078         if (err == 0) {


1891 
1892         if (spa_version < needed_spa_version) {
1893                 /* can't upgrade */
1894                 (void) printf(gettext("%s: can not be "
1895                     "upgraded; the pool version needs to first "
1896                     "be upgraded\nto version %d\n\n"),
1897                     zfs_get_name(zhp), needed_spa_version);
1898                 cb->cb_numfailed++;
1899                 return (0);
1900         }
1901 
1902         /* upgrade */
1903         if (version < cb->cb_version) {
1904                 char verstr[16];
1905                 (void) snprintf(verstr, sizeof (verstr),
1906                     "%llu", cb->cb_version);
1907                 if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
1908                         /*
1909                          * If they did "zfs upgrade -a", then we could
1910                          * be doing ioctls to different pools.  We need
1911                          * to log this history once to each pool, and bypass
1912                          * the normal history logging that happens in main().
1913                          */
1914                         (void) zpool_log_history(g_zfs, history_str);
1915                         log_history = B_FALSE;
1916                 }
1917                 if (zfs_prop_set(zhp, "version", verstr) == 0)
1918                         cb->cb_numupgraded++;
1919                 else
1920                         cb->cb_numfailed++;
1921                 (void) strcpy(cb->cb_lastfs, zfs_get_name(zhp));
1922         } else if (version > cb->cb_version) {
1923                 /* can't downgrade */
1924                 (void) printf(gettext("%s: can not be downgraded; "
1925                     "it is already at version %u\n"),
1926                     zfs_get_name(zhp), version);
1927                 cb->cb_numfailed++;
1928         } else {
1929                 cb->cb_numsamegraded++;
1930         }
1931         return (0);
1932 }
1933 
1934 /*
1935  * zfs upgrade


3413                 (void) fprintf(stderr, gettext("missing value in "
3414                     "property=value argument\n"));
3415                 usage(B_FALSE);
3416         }
3417 
3418         *cb.cb_value = '\0';
3419         cb.cb_value++;
3420 
3421         if (*cb.cb_propname == '\0') {
3422                 (void) fprintf(stderr,
3423                     gettext("missing property in property=value argument\n"));
3424                 usage(B_FALSE);
3425         }
3426 
3427         ret = zfs_for_each(argc - 2, argv + 2, NULL,
3428             ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
3429 
3430         return (ret);
3431 }
3432 
3433 typedef struct snap_cbdata {
3434         nvlist_t *sd_nvl;
3435         boolean_t sd_recursive;
3436         const char *sd_snapname;
3437 } snap_cbdata_t;
3438 
3439 static int
3440 zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
3441 {
3442         snap_cbdata_t *sd = arg;
3443         char *name;
3444         int rv = 0;
3445         int error;
3446 
3447         error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
3448         if (error == -1)
3449                 nomem();
3450         fnvlist_add_boolean(sd->sd_nvl, name);
3451         free(name);
3452 
3453         if (sd->sd_recursive)
3454                 rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
3455         zfs_close(zhp);
3456         return (rv);
3457 }
3458 
3459 /*
3460  * zfs snapshot [-r] [-o prop=value] ... <fs@snap>
3461  *
3462  * Creates a snapshot with the given name.  While functionally equivalent to
3463  * 'zfs create', it is a separate command to differentiate intent.
3464  */
3465 static int
3466 zfs_do_snapshot(int argc, char **argv)
3467 {

3468         int ret = 0;
3469         char c;
3470         nvlist_t *props;
3471         snap_cbdata_t sd = { 0 };
3472         boolean_t multiple_snaps = B_FALSE;
3473 
3474         if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
3475                 nomem();
3476         if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
3477                 nomem();
3478 
3479         /* check options */
3480         while ((c = getopt(argc, argv, "ro:")) != -1) {
3481                 switch (c) {
3482                 case 'o':
3483                         if (parseprop(props))
3484                                 return (1);
3485                         break;
3486                 case 'r':
3487                         sd.sd_recursive = B_TRUE;
3488                         multiple_snaps = B_TRUE;
3489                         break;
3490                 case '?':
3491                         (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3492                             optopt);
3493                         goto usage;
3494                 }
3495         }
3496 
3497         argc -= optind;
3498         argv += optind;
3499 
3500         /* check number of arguments */
3501         if (argc < 1) {
3502                 (void) fprintf(stderr, gettext("missing snapshot argument\n"));
3503                 goto usage;
3504         }
3505 
3506         if (argc > 1)
3507                 multiple_snaps = B_TRUE;
3508         for (; argc > 0; argc--, argv++) {
3509                 char *atp;
3510                 zfs_handle_t *zhp;
3511 
3512                 atp = strchr(argv[0], '@');
3513                 if (atp == NULL)
3514                         goto usage;
3515                 *atp = '\0';
3516                 sd.sd_snapname = atp + 1;
3517                 zhp = zfs_open(g_zfs, argv[0],
3518                     ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
3519                 if (zhp == NULL)
3520                         goto usage;
3521                 if (zfs_snapshot_cb(zhp, &sd) != 0)
3522                         goto usage;
3523         }
3524 
3525         ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
3526         nvlist_free(sd.sd_nvl);
3527         nvlist_free(props);
3528         if (ret != 0 && multiple_snaps)
3529                 (void) fprintf(stderr, gettext("no snapshots were created\n"));
3530         return (ret != 0);
3531 
3532 usage:
3533         nvlist_free(sd.sd_nvl);
3534         nvlist_free(props);
3535         usage(B_FALSE);
3536         return (-1);
3537 }
3538 
3539 /*
3540  * Send a backup stream to stdout.
3541  */
3542 static int
3543 zfs_do_send(int argc, char **argv)
3544 {
3545         char *fromname = NULL;
3546         char *toname = NULL;
3547         char *cp;
3548         zfs_handle_t *zhp;
3549         sendflags_t flags = { 0 };
3550         int c, err;
3551         nvlist_t *dbgnv = NULL;
3552         boolean_t extraverbose = B_FALSE;
3553 


6515 
6516 int
6517 main(int argc, char **argv)
6518 {
6519         int ret = 0;
6520         int i;
6521         char *progname;
6522         char *cmdname;
6523 
6524         (void) setlocale(LC_ALL, "");
6525         (void) textdomain(TEXT_DOMAIN);
6526 
6527         opterr = 0;
6528 
6529         if ((g_zfs = libzfs_init()) == NULL) {
6530                 (void) fprintf(stderr, gettext("internal error: failed to "
6531                     "initialize ZFS library\n"));
6532                 return (1);
6533         }
6534 
6535         zfs_save_arguments(argc, argv, history_str, sizeof (history_str));

6536 
6537         libzfs_print_on_error(g_zfs, B_TRUE);
6538 
6539         if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) {
6540                 (void) fprintf(stderr, gettext("internal error: unable to "
6541                     "open %s\n"), MNTTAB);
6542                 return (1);
6543         }
6544 
6545         /*
6546          * This command also doubles as the /etc/fs mount and unmount program.
6547          * Determine if we should take this behavior based on argv[0].
6548          */
6549         progname = basename(argv[0]);
6550         if (strcmp(progname, "mount") == 0) {
6551                 ret = manual_mount(argc, argv);
6552         } else if (strcmp(progname, "umount") == 0) {
6553                 ret = manual_unmount(argc, argv);
6554         } else {
6555                 /*


6584                  * Run the appropriate command.
6585                  */
6586                 libzfs_mnttab_cache(g_zfs, B_TRUE);
6587                 if (find_command_idx(cmdname, &i) == 0) {
6588                         current_command = &command_table[i];
6589                         ret = command_table[i].func(argc - 1, argv + 1);
6590                 } else if (strchr(cmdname, '=') != NULL) {
6591                         verify(find_command_idx("set", &i) == 0);
6592                         current_command = &command_table[i];
6593                         ret = command_table[i].func(argc, argv);
6594                 } else {
6595                         (void) fprintf(stderr, gettext("unrecognized "
6596                             "command '%s'\n"), cmdname);
6597                         usage(B_FALSE);
6598                 }
6599                 libzfs_mnttab_cache(g_zfs, B_FALSE);
6600         }
6601 
6602         (void) fclose(mnttab_file);
6603 
6604         if (ret == 0 && log_history)
6605                 (void) zpool_log_history(g_zfs, history_str);
6606 
6607         libzfs_fini(g_zfs);
6608 
6609         /*
6610          * The 'ZFS_ABORT' environment variable causes us to dump core on exit
6611          * for the purposes of running ::findleaks.
6612          */
6613         if (getenv("ZFS_ABORT") != NULL) {
6614                 (void) printf("dumping core by request\n");
6615                 abort();
6616         }
6617 
6618         return (ret);
6619 }