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>


 168         { NULL },
 169         { "attach",     zpool_do_attach,        HELP_ATTACH             },
 170         { "detach",     zpool_do_detach,        HELP_DETACH             },
 171         { "replace",    zpool_do_replace,       HELP_REPLACE            },
 172         { "split",      zpool_do_split,         HELP_SPLIT              },
 173         { NULL },
 174         { "scrub",      zpool_do_scrub,         HELP_SCRUB              },
 175         { NULL },
 176         { "import",     zpool_do_import,        HELP_IMPORT             },
 177         { "export",     zpool_do_export,        HELP_EXPORT             },
 178         { "upgrade",    zpool_do_upgrade,       HELP_UPGRADE            },
 179         { "reguid",     zpool_do_reguid,        HELP_REGUID             },
 180         { NULL },
 181         { "history",    zpool_do_history,       HELP_HISTORY            },
 182         { "get",        zpool_do_get,           HELP_GET                },
 183         { "set",        zpool_do_set,           HELP_SET                },
 184 };
 185 
 186 #define NCOMMAND        (sizeof (command_table) / sizeof (command_table[0]))
 187 
 188 zpool_command_t *current_command;
 189 static char history_str[HIS_MAX_RECORD_LEN];
 190 
 191 static uint_t timestamp_fmt = NODATE;
 192 
 193 static const char *
 194 get_usage(zpool_help_t idx) {
 195         switch (idx) {
 196         case HELP_ADD:
 197                 return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
 198         case HELP_ATTACH:
 199                 return (gettext("\tattach [-f] <pool> <device> "
 200                     "<new-device>\n"));
 201         case HELP_CLEAR:
 202                 return (gettext("\tclear [-nF] <pool> [device]\n"));
 203         case HELP_CREATE:
 204                 return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
 205                     "\t    [-O file-system-property=value] ... \n"
 206                     "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
 207         case HELP_DESTROY:
 208                 return (gettext("\tdestroy [-f] <pool>\n"));
 209         case HELP_DETACH:
 210                 return (gettext("\tdetach <pool> <device>\n"));


 918 
 919         pool = argv[0];
 920 
 921         if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
 922                 /*
 923                  * As a special case, check for use of '/' in the name, and
 924                  * direct the user to use 'zfs destroy' instead.
 925                  */
 926                 if (strchr(pool, '/') != NULL)
 927                         (void) fprintf(stderr, gettext("use 'zfs destroy' to "
 928                             "destroy a dataset\n"));
 929                 return (1);
 930         }
 931 
 932         if (zpool_disable_datasets(zhp, force) != 0) {
 933                 (void) fprintf(stderr, gettext("could not destroy '%s': "
 934                     "could not unmount datasets\n"), zpool_get_name(zhp));
 935                 return (1);
 936         }
 937 
 938         ret = (zpool_destroy(zhp) != 0);



 939 
 940         zpool_close(zhp);
 941 
 942         return (ret);
 943 }
 944 
 945 /*
 946  * zpool export [-f] <pool> ...
 947  *
 948  *      -f      Forcefully unmount datasets
 949  *
 950  * Export the given pools.  By default, the command will attempt to cleanly
 951  * unmount any active datasets within the pool.  If the '-f' flag is specified,
 952  * then the datasets will be forcefully unmounted.
 953  */
 954 int
 955 zpool_do_export(int argc, char **argv)
 956 {
 957         boolean_t force = B_FALSE;
 958         boolean_t hardforce = B_FALSE;


 982 
 983         /* check arguments */
 984         if (argc < 1) {
 985                 (void) fprintf(stderr, gettext("missing pool argument\n"));
 986                 usage(B_FALSE);
 987         }
 988 
 989         ret = 0;
 990         for (i = 0; i < argc; i++) {
 991                 if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
 992                         ret = 1;
 993                         continue;
 994                 }
 995 
 996                 if (zpool_disable_datasets(zhp, force) != 0) {
 997                         ret = 1;
 998                         zpool_close(zhp);
 999                         continue;
1000                 }
1001 



1002                 if (hardforce) {
1003                         if (zpool_export_force(zhp) != 0)
1004                                 ret = 1;
1005                 } else if (zpool_export(zhp, force) != 0) {
1006                         ret = 1;
1007                 }
1008 
1009                 zpool_close(zhp);
1010         }
1011 
1012         return (ret);
1013 }
1014 
1015 /*
1016  * Given a vdev configuration, determine the maximum width needed for the device
1017  * name column.
1018  */
1019 static int
1020 max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1021 {
1022         char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1023         nvlist_t **child;
1024         uint_t c, children;
1025         int ret;


4252                         if (cbp->cb_first) {
4253                                 (void) printf(gettext("The following pools are "
4254                                     "out of date, and can be upgraded.  After "
4255                                     "being\nupgraded, these pools will no "
4256                                     "longer be accessible by older software "
4257                                     "versions.\n\n"));
4258                                 (void) printf(gettext("VER  POOL\n"));
4259                                 (void) printf(gettext("---  ------------\n"));
4260                                 cbp->cb_first = B_FALSE;
4261                         }
4262 
4263                         (void) printf("%2llu   %s\n", (u_longlong_t)version,
4264                             zpool_get_name(zhp));
4265                 } else {
4266                         cbp->cb_first = B_FALSE;
4267                         ret = zpool_upgrade(zhp, cbp->cb_version);
4268                         if (!ret) {
4269                                 (void) printf(gettext("Successfully upgraded "
4270                                     "'%s'\n\n"), zpool_get_name(zhp));
4271                         }








4272                 }
4273         } else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
4274                 assert(!cbp->cb_all);
4275 
4276                 if (cbp->cb_first) {
4277                         (void) printf(gettext("The following pools are "
4278                             "formatted using an unsupported software version "
4279                             "and\ncannot be accessed on the current "
4280                             "system.\n\n"));
4281                         (void) printf(gettext("VER  POOL\n"));
4282                         (void) printf(gettext("---  ------------\n"));
4283                         cbp->cb_first = B_FALSE;
4284                 }
4285 
4286                 (void) printf("%2llu   %s\n", (u_longlong_t)version,
4287                     zpool_get_name(zhp));
4288         }
4289 
4290         zpool_close(zhp);
4291         return (ret);


4474 
4475                 if (ret == 0) {
4476                         if (notfound)
4477                                 (void) printf(gettext("All pools are formatted "
4478                                     "using this version.\n"));
4479                         else if (!cb.cb_all)
4480                                 (void) printf(gettext("Use 'zpool upgrade -v' "
4481                                     "for a list of available versions and "
4482                                     "their associated\nfeatures.\n"));
4483                 }
4484         } else {
4485                 ret = for_each_pool(argc, argv, B_FALSE, NULL,
4486                     upgrade_one, &cb);
4487         }
4488 
4489         return (ret);
4490 }
4491 
4492 typedef struct hist_cbdata {
4493         boolean_t first;
4494         int longfmt;
4495         int internal;
4496 } hist_cbdata_t;
4497 
4498 /*
4499  * Print out the command history for a specific pool.
4500  */
4501 static int
4502 get_history_one(zpool_handle_t *zhp, void *data)
4503 {
4504         nvlist_t *nvhis;
4505         nvlist_t **records;
4506         uint_t numrecords;
4507         char *cmdstr;
4508         char *pathstr;
4509         uint64_t dst_time;
4510         time_t tsec;
4511         struct tm t;
4512         char tbuf[30];
4513         int ret, i;
4514         uint64_t who;
4515         struct passwd *pwd;
4516         char *hostname;
4517         char *zonename;
4518         char internalstr[MAXPATHLEN];
4519         hist_cbdata_t *cb = (hist_cbdata_t *)data;
4520         uint64_t txg;
4521         uint64_t ievent;
4522 
4523         cb->first = B_FALSE;
4524 
4525         (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
4526 
4527         if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
4528                 return (ret);
4529 
4530         verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
4531             &records, &numrecords) == 0);
4532         for (i = 0; i < numrecords; i++) {
4533                 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
4534                     &dst_time) != 0)
4535                         continue;
4536 
4537                 /* is it an internal event or a standard event? */
4538                 if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
4539                     &cmdstr) != 0) {
4540                         if (cb->internal == 0)
4541                                 continue;




4542 
4543                         if (nvlist_lookup_uint64(records[i],
4544                             ZPOOL_HIST_INT_EVENT, &ievent) != 0)





4545                                 continue;
4546                         verify(nvlist_lookup_uint64(records[i],
4547                             ZPOOL_HIST_TXG, &txg) == 0);
4548                         verify(nvlist_lookup_string(records[i],
4549                             ZPOOL_HIST_INT_STR, &pathstr) == 0);
4550                         if (ievent >= LOG_END)
4551                                 continue;
4552                         (void) snprintf(internalstr,
4553                             sizeof (internalstr),
4554                             "[internal %s txg:%lld] %s",
4555                             zfs_history_event_names[ievent], txg,
4556                             pathstr);
4557                         cmdstr = internalstr;
4558                 }
4559                 tsec = dst_time;
4560                 (void) localtime_r(&tsec, &t);
4561                 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
4562                 (void) printf("%s %s", tbuf, cmdstr);




































4563 
4564                 if (!cb->longfmt) {
4565                         (void) printf("\n");
4566                         continue;
4567                 }
4568                 (void) printf(" [");
4569                 if (nvlist_lookup_uint64(records[i],
4570                     ZPOOL_HIST_WHO, &who) == 0) {
4571                         pwd = getpwuid((uid_t)who);
4572                         if (pwd)
4573                                 (void) printf("user %s on",
4574                                     pwd->pw_name);
4575                         else
4576                                 (void) printf("user %d on",
4577                                     (int)who);
4578                 } else {
4579                         (void) printf(gettext("no info]\n"));
4580                         continue;
4581                 }
4582                 if (nvlist_lookup_string(records[i],
4583                     ZPOOL_HIST_HOST, &hostname) == 0) {
4584                         (void) printf(" %s", hostname);
4585                 }
4586                 if (nvlist_lookup_string(records[i],
4587                     ZPOOL_HIST_ZONE, &zonename) == 0) {
4588                         (void) printf(":%s", zonename);
4589                 }
4590 
4591                 (void) printf("]");
4592                 (void) printf("\n");
4593         }
4594         (void) printf("\n");
4595         nvlist_free(nvhis);
4596 
4597         return (ret);
4598 }
4599 
4600 /*
4601  * zpool history <pool>
4602  *
4603  * Displays the history of commands that modified pools.
4604  */
4605 
4606 
4607 int
4608 zpool_do_history(int argc, char **argv)
4609 {
4610         hist_cbdata_t cbdata = { 0 };
4611         int ret;
4612         int c;
4613 
4614         cbdata.first = B_TRUE;
4615         /* check options */
4616         while ((c = getopt(argc, argv, "li")) != -1) {
4617                 switch (c) {
4618                 case 'l':
4619                         cbdata.longfmt = 1;
4620                         break;
4621                 case 'i':
4622                         cbdata.internal = 1;
4623                         break;
4624                 case '?':
4625                         (void) fprintf(stderr, gettext("invalid option '%c'\n"),
4626                             optopt);
4627                         usage(B_FALSE);
4628                 }
4629         }
4630         argc -= optind;
4631         argv += optind;
4632 
4633         ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
4634             &cbdata);
4635 
4636         if (argc == 0 && cbdata.first == B_TRUE) {
4637                 (void) printf(gettext("no pools available\n"));
4638                 return (0);
4639         }
4640 
4641         return (ret);
4642 }


4827         libzfs_print_on_error(g_zfs, B_TRUE);
4828 
4829         opterr = 0;
4830 
4831         /*
4832          * Make sure the user has specified some command.
4833          */
4834         if (argc < 2) {
4835                 (void) fprintf(stderr, gettext("missing command\n"));
4836                 usage(B_FALSE);
4837         }
4838 
4839         cmdname = argv[1];
4840 
4841         /*
4842          * Special case '-?'
4843          */
4844         if (strcmp(cmdname, "-?") == 0)
4845                 usage(B_TRUE);
4846 
4847         zpool_set_history_str("zpool", argc, argv, history_str);
4848         verify(zpool_stage_history(g_zfs, history_str) == 0);
4849 
4850         /*
4851          * Run the appropriate command.
4852          */
4853         if (find_command_idx(cmdname, &i) == 0) {
4854                 current_command = &command_table[i];
4855                 ret = command_table[i].func(argc - 1, argv + 1);
4856         } else if (strchr(cmdname, '=')) {
4857                 verify(find_command_idx("set", &i) == 0);
4858                 current_command = &command_table[i];
4859                 ret = command_table[i].func(argc, argv);
4860         } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
4861                 /*
4862                  * 'freeze' is a vile debugging abomination, so we treat
4863                  * it as such.
4864                  */
4865                 char buf[16384];
4866                 int fd = open(ZFS_DEV, O_RDWR);
4867                 (void) strcpy((void *)buf, argv[2]);
4868                 return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
4869         } else {
4870                 (void) fprintf(stderr, gettext("unrecognized "
4871                     "command '%s'\n"), cmdname);
4872                 usage(B_FALSE);
4873         }
4874 



4875         libzfs_fini(g_zfs);
4876 
4877         /*
4878          * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4879          * for the purposes of running ::findleaks.
4880          */
4881         if (getenv("ZFS_ABORT") != NULL) {
4882                 (void) printf("dumping core by request\n");
4883                 abort();
4884         }
4885 
4886         return (ret);
4887 }


 168         { NULL },
 169         { "attach",     zpool_do_attach,        HELP_ATTACH             },
 170         { "detach",     zpool_do_detach,        HELP_DETACH             },
 171         { "replace",    zpool_do_replace,       HELP_REPLACE            },
 172         { "split",      zpool_do_split,         HELP_SPLIT              },
 173         { NULL },
 174         { "scrub",      zpool_do_scrub,         HELP_SCRUB              },
 175         { NULL },
 176         { "import",     zpool_do_import,        HELP_IMPORT             },
 177         { "export",     zpool_do_export,        HELP_EXPORT             },
 178         { "upgrade",    zpool_do_upgrade,       HELP_UPGRADE            },
 179         { "reguid",     zpool_do_reguid,        HELP_REGUID             },
 180         { NULL },
 181         { "history",    zpool_do_history,       HELP_HISTORY            },
 182         { "get",        zpool_do_get,           HELP_GET                },
 183         { "set",        zpool_do_set,           HELP_SET                },
 184 };
 185 
 186 #define NCOMMAND        (sizeof (command_table) / sizeof (command_table[0]))
 187 
 188 static zpool_command_t *current_command;
 189 static char history_str[HIS_MAX_RECORD_LEN];
 190 static boolean_t log_history = B_TRUE;
 191 static uint_t timestamp_fmt = NODATE;
 192 
 193 static const char *
 194 get_usage(zpool_help_t idx) {
 195         switch (idx) {
 196         case HELP_ADD:
 197                 return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
 198         case HELP_ATTACH:
 199                 return (gettext("\tattach [-f] <pool> <device> "
 200                     "<new-device>\n"));
 201         case HELP_CLEAR:
 202                 return (gettext("\tclear [-nF] <pool> [device]\n"));
 203         case HELP_CREATE:
 204                 return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
 205                     "\t    [-O file-system-property=value] ... \n"
 206                     "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
 207         case HELP_DESTROY:
 208                 return (gettext("\tdestroy [-f] <pool>\n"));
 209         case HELP_DETACH:
 210                 return (gettext("\tdetach <pool> <device>\n"));


 918 
 919         pool = argv[0];
 920 
 921         if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
 922                 /*
 923                  * As a special case, check for use of '/' in the name, and
 924                  * direct the user to use 'zfs destroy' instead.
 925                  */
 926                 if (strchr(pool, '/') != NULL)
 927                         (void) fprintf(stderr, gettext("use 'zfs destroy' to "
 928                             "destroy a dataset\n"));
 929                 return (1);
 930         }
 931 
 932         if (zpool_disable_datasets(zhp, force) != 0) {
 933                 (void) fprintf(stderr, gettext("could not destroy '%s': "
 934                     "could not unmount datasets\n"), zpool_get_name(zhp));
 935                 return (1);
 936         }
 937 
 938         /* The history must be logged as part of the export */
 939         log_history = B_FALSE;
 940 
 941         ret = (zpool_destroy(zhp, history_str) != 0);
 942 
 943         zpool_close(zhp);
 944 
 945         return (ret);
 946 }
 947 
 948 /*
 949  * zpool export [-f] <pool> ...
 950  *
 951  *      -f      Forcefully unmount datasets
 952  *
 953  * Export the given pools.  By default, the command will attempt to cleanly
 954  * unmount any active datasets within the pool.  If the '-f' flag is specified,
 955  * then the datasets will be forcefully unmounted.
 956  */
 957 int
 958 zpool_do_export(int argc, char **argv)
 959 {
 960         boolean_t force = B_FALSE;
 961         boolean_t hardforce = B_FALSE;


 985 
 986         /* check arguments */
 987         if (argc < 1) {
 988                 (void) fprintf(stderr, gettext("missing pool argument\n"));
 989                 usage(B_FALSE);
 990         }
 991 
 992         ret = 0;
 993         for (i = 0; i < argc; i++) {
 994                 if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
 995                         ret = 1;
 996                         continue;
 997                 }
 998 
 999                 if (zpool_disable_datasets(zhp, force) != 0) {
1000                         ret = 1;
1001                         zpool_close(zhp);
1002                         continue;
1003                 }
1004 
1005                 /* The history must be logged as part of the export */
1006                 log_history = B_FALSE;
1007 
1008                 if (hardforce) {
1009                         if (zpool_export_force(zhp, history_str) != 0)
1010                                 ret = 1;
1011                 } else if (zpool_export(zhp, force, history_str) != 0) {
1012                         ret = 1;
1013                 }
1014 
1015                 zpool_close(zhp);
1016         }
1017 
1018         return (ret);
1019 }
1020 
1021 /*
1022  * Given a vdev configuration, determine the maximum width needed for the device
1023  * name column.
1024  */
1025 static int
1026 max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1027 {
1028         char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1029         nvlist_t **child;
1030         uint_t c, children;
1031         int ret;


4258                         if (cbp->cb_first) {
4259                                 (void) printf(gettext("The following pools are "
4260                                     "out of date, and can be upgraded.  After "
4261                                     "being\nupgraded, these pools will no "
4262                                     "longer be accessible by older software "
4263                                     "versions.\n\n"));
4264                                 (void) printf(gettext("VER  POOL\n"));
4265                                 (void) printf(gettext("---  ------------\n"));
4266                                 cbp->cb_first = B_FALSE;
4267                         }
4268 
4269                         (void) printf("%2llu   %s\n", (u_longlong_t)version,
4270                             zpool_get_name(zhp));
4271                 } else {
4272                         cbp->cb_first = B_FALSE;
4273                         ret = zpool_upgrade(zhp, cbp->cb_version);
4274                         if (!ret) {
4275                                 (void) printf(gettext("Successfully upgraded "
4276                                     "'%s'\n\n"), zpool_get_name(zhp));
4277                         }
4278                         /*
4279                          * If they did "zpool upgrade -a", then we could
4280                          * be doing ioctls to different pools.  We need
4281                          * to log this history once to each pool, and bypass
4282                          * the normal history logging that happens in main().
4283                          */
4284                         (void) zpool_log_history(g_zfs, history_str);
4285                         log_history = B_FALSE;
4286                 }
4287         } else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
4288                 assert(!cbp->cb_all);
4289 
4290                 if (cbp->cb_first) {
4291                         (void) printf(gettext("The following pools are "
4292                             "formatted using an unsupported software version "
4293                             "and\ncannot be accessed on the current "
4294                             "system.\n\n"));
4295                         (void) printf(gettext("VER  POOL\n"));
4296                         (void) printf(gettext("---  ------------\n"));
4297                         cbp->cb_first = B_FALSE;
4298                 }
4299 
4300                 (void) printf("%2llu   %s\n", (u_longlong_t)version,
4301                     zpool_get_name(zhp));
4302         }
4303 
4304         zpool_close(zhp);
4305         return (ret);


4488 
4489                 if (ret == 0) {
4490                         if (notfound)
4491                                 (void) printf(gettext("All pools are formatted "
4492                                     "using this version.\n"));
4493                         else if (!cb.cb_all)
4494                                 (void) printf(gettext("Use 'zpool upgrade -v' "
4495                                     "for a list of available versions and "
4496                                     "their associated\nfeatures.\n"));
4497                 }
4498         } else {
4499                 ret = for_each_pool(argc, argv, B_FALSE, NULL,
4500                     upgrade_one, &cb);
4501         }
4502 
4503         return (ret);
4504 }
4505 
4506 typedef struct hist_cbdata {
4507         boolean_t first;
4508         boolean_t longfmt;
4509         boolean_t internal;
4510 } hist_cbdata_t;
4511 
4512 /*
4513  * Print out the command history for a specific pool.
4514  */
4515 static int
4516 get_history_one(zpool_handle_t *zhp, void *data)
4517 {
4518         nvlist_t *nvhis;
4519         nvlist_t **records;
4520         uint_t numrecords;






4521         int ret, i;





4522         hist_cbdata_t *cb = (hist_cbdata_t *)data;


4523 
4524         cb->first = B_FALSE;
4525 
4526         (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
4527 
4528         if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
4529                 return (ret);
4530 
4531         verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
4532             &records, &numrecords) == 0);
4533         for (i = 0; i < numrecords; i++) {
4534                 nvlist_t *rec = records[i];
4535                 char tbuf[30] = "";

4536 
4537                 if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
4538                         time_t tsec;
4539                         struct tm t;
4540 
4541                         tsec = fnvlist_lookup_uint64(records[i],
4542                             ZPOOL_HIST_TIME);
4543                         (void) localtime_r(&tsec, &t);
4544                         (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
4545                 }
4546 
4547                 if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
4548                         (void) printf("%s %s", tbuf,
4549                             fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
4550                 } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
4551                         int ievent =
4552                             fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
4553                         if (!cb->internal)
4554                                 continue;
4555                         if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
4556                                 (void) printf("%s unrecognized record:\n",
4557                                     tbuf);
4558                                 dump_nvlist(rec, 4);

4559                                 continue;






4560                         }
4561                         (void) printf("%s [internal %s txg:%lld] %s", tbuf,
4562                             zfs_history_event_names[ievent],
4563                             fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
4564                             fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
4565                 } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
4566                         if (!cb->internal)
4567                                 continue;
4568                         (void) printf("%s [txg:%lld] %s", tbuf,
4569                             fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
4570                             fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
4571                         if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
4572                                 (void) printf(" %s (%llu)",
4573                                     fnvlist_lookup_string(rec,
4574                                     ZPOOL_HIST_DSNAME),
4575                                     fnvlist_lookup_uint64(rec,
4576                                     ZPOOL_HIST_DSID));
4577                         }
4578                         (void) printf(" %s", fnvlist_lookup_string(rec,
4579                             ZPOOL_HIST_INT_STR));
4580                 } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
4581                         if (!cb->internal)
4582                                 continue;
4583                         (void) printf("%s ioctl %s\n", tbuf,
4584                             fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
4585                         if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
4586                                 (void) printf("    input:\n");
4587                                 dump_nvlist(fnvlist_lookup_nvlist(rec,
4588                                     ZPOOL_HIST_INPUT_NVL), 8);
4589                         }
4590                         if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
4591                                 (void) printf("    output:\n");
4592                                 dump_nvlist(fnvlist_lookup_nvlist(rec,
4593                                     ZPOOL_HIST_OUTPUT_NVL), 8);
4594                         }
4595                 } else {
4596                         if (!cb->internal)
4597                                 continue;
4598                         (void) printf("%s unrecognized record:\n", tbuf);
4599                         dump_nvlist(rec, 4);
4600                 }
4601 
4602                 if (!cb->longfmt) {
4603                         (void) printf("\n");
4604                         continue;
4605                 }
4606                 (void) printf(" [");
4607                 if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
4608                         uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
4609                         struct passwd *pwd = getpwuid(who);
4610                         (void) printf("user %d ", (int)who);
4611                         if (pwd != NULL)
4612                                 (void) printf("(%s) ", pwd->pw_name);
4613                 }
4614                 if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
4615                         (void) printf("on %s",
4616                             fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
4617                 }
4618                 if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
4619                         (void) printf(":%s",
4620                             fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));






4621                 }

4622                 (void) printf("]");
4623                 (void) printf("\n");
4624         }
4625         (void) printf("\n");
4626         nvlist_free(nvhis);
4627 
4628         return (ret);
4629 }
4630 
4631 /*
4632  * zpool history <pool>
4633  *
4634  * Displays the history of commands that modified pools.
4635  */


4636 int
4637 zpool_do_history(int argc, char **argv)
4638 {
4639         hist_cbdata_t cbdata = { 0 };
4640         int ret;
4641         int c;
4642 
4643         cbdata.first = B_TRUE;
4644         /* check options */
4645         while ((c = getopt(argc, argv, "li")) != -1) {
4646                 switch (c) {
4647                 case 'l':
4648                         cbdata.longfmt = B_TRUE;
4649                         break;
4650                 case 'i':
4651                         cbdata.internal = B_TRUE;
4652                         break;
4653                 case '?':
4654                         (void) fprintf(stderr, gettext("invalid option '%c'\n"),
4655                             optopt);
4656                         usage(B_FALSE);
4657                 }
4658         }
4659         argc -= optind;
4660         argv += optind;
4661 
4662         ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
4663             &cbdata);
4664 
4665         if (argc == 0 && cbdata.first == B_TRUE) {
4666                 (void) printf(gettext("no pools available\n"));
4667                 return (0);
4668         }
4669 
4670         return (ret);
4671 }


4856         libzfs_print_on_error(g_zfs, B_TRUE);
4857 
4858         opterr = 0;
4859 
4860         /*
4861          * Make sure the user has specified some command.
4862          */
4863         if (argc < 2) {
4864                 (void) fprintf(stderr, gettext("missing command\n"));
4865                 usage(B_FALSE);
4866         }
4867 
4868         cmdname = argv[1];
4869 
4870         /*
4871          * Special case '-?'
4872          */
4873         if (strcmp(cmdname, "-?") == 0)
4874                 usage(B_TRUE);
4875 
4876         zfs_save_arguments(argc, argv, history_str, sizeof (history_str));

4877 
4878         /*
4879          * Run the appropriate command.
4880          */
4881         if (find_command_idx(cmdname, &i) == 0) {
4882                 current_command = &command_table[i];
4883                 ret = command_table[i].func(argc - 1, argv + 1);
4884         } else if (strchr(cmdname, '=')) {
4885                 verify(find_command_idx("set", &i) == 0);
4886                 current_command = &command_table[i];
4887                 ret = command_table[i].func(argc, argv);
4888         } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
4889                 /*
4890                  * 'freeze' is a vile debugging abomination, so we treat
4891                  * it as such.
4892                  */
4893                 char buf[16384];
4894                 int fd = open(ZFS_DEV, O_RDWR);
4895                 (void) strcpy((void *)buf, argv[2]);
4896                 return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
4897         } else {
4898                 (void) fprintf(stderr, gettext("unrecognized "
4899                     "command '%s'\n"), cmdname);
4900                 usage(B_FALSE);
4901         }
4902 
4903         if (ret == 0 && log_history)
4904                 (void) zpool_log_history(g_zfs, history_str);
4905 
4906         libzfs_fini(g_zfs);
4907 
4908         /*
4909          * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4910          * for the purposes of running ::findleaks.
4911          */
4912         if (getenv("ZFS_ABORT") != NULL) {
4913                 (void) printf("dumping core by request\n");
4914                 abort();
4915         }
4916 
4917         return (ret);
4918 }