Rebase master to b121
[zfs.git] / cmd / zpool / zpool_vdev.c
index 10007c1..6215191 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -67,6 +67,7 @@
 #include <libdiskmgt.h>
 #include <libintl.h>
 #include <libnvpair.h>
+#include <limits.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
@@ -1093,20 +1094,35 @@ check_in_use(nvlist_t *config, nvlist_t *nv, int force, int isreplacing,
 }
 
 static const char *
-is_grouping(const char *type, int *mindev)
+is_grouping(const char *type, int *mindev, int *maxdev)
 {
-       if (strcmp(type, "raidz") == 0 || strcmp(type, "raidz1") == 0) {
-               if (mindev != NULL)
-                       *mindev = 2;
-               return (VDEV_TYPE_RAIDZ);
-       }
+       if (strncmp(type, "raidz", 5) == 0) {
+               const char *p = type + 5;
+               char *end;
+               long nparity;
+
+               if (*p == '\0') {
+                       nparity = 1;
+               } else if (*p == '0') {
+                       return (NULL); /* no zero prefixes allowed */
+               } else {
+                       errno = 0;
+                       nparity = strtol(p, &end, 10);
+                       if (errno != 0 || nparity < 1 || nparity >= 255 ||
+                           *end != '\0')
+                               return (NULL);
+               }
 
-       if (strcmp(type, "raidz2") == 0) {
                if (mindev != NULL)
-                       *mindev = 3;
+                       *mindev = nparity + 1;
+               if (maxdev != NULL)
+                       *maxdev = 255;
                return (VDEV_TYPE_RAIDZ);
        }
 
+       if (maxdev != NULL)
+               *maxdev = INT_MAX;
+
        if (strcmp(type, "mirror") == 0) {
                if (mindev != NULL)
                        *mindev = 2;
@@ -1144,7 +1160,7 @@ nvlist_t *
 construct_spec(int argc, char **argv)
 {
        nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
-       int t, toplevels, mindev, nspares, nlogs, nl2cache;
+       int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
        const char *type;
        uint64_t is_log;
        boolean_t seen_logs;
@@ -1166,7 +1182,7 @@ construct_spec(int argc, char **argv)
                 * If it's a mirror or raidz, the subsequent arguments are
                 * its leaves -- until we encounter the next mirror or raidz.
                 */
-               if ((type = is_grouping(argv[0], &mindev)) != NULL) {
+               if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
                        nvlist_t **child = NULL;
                        int c, children = 0;
 
@@ -1223,7 +1239,7 @@ construct_spec(int argc, char **argv)
                        }
 
                        for (c = 1; c < argc; c++) {
-                               if (is_grouping(argv[c], NULL) != NULL)
+                               if (is_grouping(argv[c], NULL, NULL) != NULL)
                                        break;
                                children++;
                                child = realloc(child,
@@ -1243,6 +1259,13 @@ construct_spec(int argc, char **argv)
                                return (NULL);
                        }
 
+                       if (children > maxdev) {
+                               (void) fprintf(stderr, gettext("invalid vdev "
+                                   "specification: %s supports no more than "
+                                   "%d devices\n"), argv[0], maxdev);
+                               return (NULL);
+                       }
+
                        argc -= c;
                        argv += c;