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 }
|