Add FreeBSD 'zpool labelclear' command
[zfs.git] / cmd / zpool / zpool_main.c
index 19f1f28..da9f3e1 100644 (file)
@@ -63,6 +63,7 @@ static int zpool_do_destroy(int, char **);
 
 static int zpool_do_add(int, char **);
 static int zpool_do_remove(int, char **);
+static int zpool_do_labelclear(int, char **);
 
 static int zpool_do_list(int, char **);
 static int zpool_do_iostat(int, char **);
@@ -123,6 +124,7 @@ typedef enum {
        HELP_HISTORY,
        HELP_IMPORT,
        HELP_IOSTAT,
+       HELP_LABELCLEAR,
        HELP_LIST,
        HELP_OFFLINE,
        HELP_ONLINE,
@@ -162,6 +164,8 @@ static zpool_command_t command_table[] = {
        { "add",        zpool_do_add,           HELP_ADD                },
        { "remove",     zpool_do_remove,        HELP_REMOVE             },
        { NULL },
+       { "labelclear", zpool_do_labelclear,    HELP_LABELCLEAR         },
+       { NULL },
        { "list",       zpool_do_list,          HELP_LIST               },
        { "iostat",     zpool_do_iostat,        HELP_IOSTAT             },
        { "status",     zpool_do_status,        HELP_STATUS             },
@@ -233,6 +237,8 @@ get_usage(zpool_help_t idx) {
        case HELP_IOSTAT:
                return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
                    "[count]]\n"));
+       case HELP_LABELCLEAR:
+               return (gettext("\tlabelclear [-f] <vdev>\n"));
        case HELP_LIST:
                return (gettext("\tlist [-H] [-o property[,...]] "
                    "[-T d|u] [pool] ... [interval [count]]\n"));
@@ -642,6 +648,127 @@ zpool_do_remove(int argc, char **argv)
 }
 
 /*
+ * zpool labelclear <vdev>
+ *
+ * Verifies that the vdev is not active and zeros out the label information
+ * on the device.
+ */
+int
+zpool_do_labelclear(int argc, char **argv)
+{
+       char *vdev, *name;
+       int c, fd = -1, ret = 0;
+       pool_state_t state;
+       boolean_t inuse = B_FALSE;
+       boolean_t force = B_FALSE;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "f")) != -1) {
+               switch (c) {
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               default:
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get vdev name */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing vdev device name\n"));
+               usage(B_FALSE);
+       }
+
+       vdev = argv[0];
+       if ((fd = open(vdev, O_RDWR)) < 0) {
+               (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev);
+               return (B_FALSE);
+       }
+
+       name = NULL;
+       if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) {
+               if (force)
+                       goto wipe_label;
+
+               (void) fprintf(stderr,
+                   gettext("Unable to determine pool state for %s\n"
+                   "Use -f to force the clearing any label data\n"), vdev);
+
+               return (1);
+       }
+
+       if (inuse) {
+               switch (state) {
+               default:
+               case POOL_STATE_ACTIVE:
+               case POOL_STATE_SPARE:
+               case POOL_STATE_L2CACHE:
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n"
+                           "\tVdev %s is a member (%s), of pool \"%s\".\n"
+                           "\tTo remove label information from this device, "
+                           "export or destroy\n\tthe pool, or remove %s from "
+                           "the configuration of this pool\n\tand retry the "
+                           "labelclear operation.\n"),
+                           vdev, zpool_pool_state_to_name(state), name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_EXPORTED:
+                       if (force)
+                               break;
+
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n\tVdev "
+                           "%s is a member of the exported pool \"%s\".\n"
+                           "\tUse \"zpool labelclear -f %s\" to force the "
+                           "removal of label\n\tinformation.\n"),
+                           vdev, name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_POTENTIALLY_ACTIVE:
+                       if (force)
+                               break;
+
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n"
+                           "\tVdev %s is a member of the pool \"%s\".\n"
+                           "\tThis pool is unknown to this system, but may "
+                           "be active on\n\tanother system. Use "
+                           "\'zpool labelclear -f %s\' to force the\n"
+                           "\tremoval of label information.\n"),
+                           vdev, name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_DESTROYED:
+                       /* inuse should never be set for a destroyed pool... */
+                       break;
+               }
+       }
+
+wipe_label:
+       if (zpool_clear_label(fd) != 0) {
+               (void) fprintf(stderr,
+                   gettext("Label clear failed on vdev %s\n"), vdev);
+               ret = 1;
+       }
+
+errout:
+       close(fd);
+       if (name != NULL)
+               free(name);
+
+       return (ret);
+}
+
+/*
  * zpool create [-fnd] [-o property=value] ...
  *             [-O file-system-property=value] ...
  *             [-R root] [-m mountpoint] <pool> <dev> ...