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