]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - mdadm.c
Add a 'super-switch' so that different format superblocks can be used.
[thirdparty/mdadm.git] / mdadm.c
diff --git a/mdadm.c b/mdadm.c
index a6f116f78f599c2963497728eed9c8cb12c22e2d..b738fadd5a0ea664b46016e3b7456f8507f8b789 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -32,7 +32,6 @@
 #include <ctype.h>
 
 
-
 int main(int argc, char *argv[])
 {
        int mode = 0;
@@ -41,6 +40,7 @@ int main(int argc, char *argv[])
        char *help_text;
        char *c;
        int rv;
+       int i;
 
        int chunk = 0;
        int size = -1;
@@ -81,6 +81,7 @@ int main(int argc, char *argv[])
        int daemonise = 0;
        char *pidfile = NULL;
        int oneshot = 0;
+       struct superswitch *ss = NULL;
 
        int copies;
 
@@ -145,7 +146,8 @@ int main(int argc, char *argv[])
                case 'a':
                case 'r':
                case 'f':
-               case 1 : if (!mode) newmode = MANAGE; break;
+                       if (!mode) newmode = MANAGE; 
+                       break;
 
                case 'A': newmode = ASSEMBLE; break;
                case 'B': newmode = BUILD; break;
@@ -172,7 +174,7 @@ int main(int argc, char *argv[])
                                fprintf(stderr, "--%s", long_options[option_index].name);
                        else
                                fprintf(stderr, "-%c", opt);
-                       fprintf(stderr, " would set mode to %s, but it is already %s.\n",
+                       fprintf(stderr, " would set mdadm mode to \"%s\", but it is already set to \"%s\".\n",
                                map_num(modes, newmode),
                                map_num(modes, mode));
                        exit(2);
@@ -186,11 +188,33 @@ int main(int argc, char *argv[])
                                fputs(Help_config, stderr);
                                exit(0);
                        }
+
+                       /* If first option is a device, don't force the mode yet */
+                       if (opt == 1) {
+                               if (devs_found == 0) {
+                                       dv = malloc(sizeof(*dv));
+                                       if (dv == NULL) {
+                                               fprintf(stderr, Name ": malloc failed\n");
+                                               exit(3);
+                                       }
+                                       dv->devname = optarg;
+                                       dv->disposition = devmode;
+                                       dv->next = NULL;
+                                       *devlistend = dv;
+                                       devlistend = &dv->next;
+                       
+                                       devs_found++;
+                                       continue;
+                               }
+                               /* No mode yet, and this is the second device ... */
+                               fprintf(stderr, Name ": An option must be given to set the mode before a second device is listed\n");
+                               exit(2);
+                       }
                        if (option_index >= 0)
-                               fprintf(stderr, "--%s", long_options[option_index].name);
+                               fprintf(stderr, Name ": --%s", long_options[option_index].name);
                        else
-                               fprintf(stderr, "-%c", opt);
-                       fprintf(stderr, " does not set the mode, and so cannot be first.\n");
+                               fprintf(stderr, Name ": -%c", opt);
+                       fprintf(stderr, " does not set the mode, and so cannot be the first option.\n");
                        exit(2);
                }
 
@@ -250,6 +274,24 @@ int main(int argc, char *argv[])
                        }
                        continue;
 
+               case O(CREATE,'e'):
+               case O(ASSEMBLE,'e'):
+               case O(MISC,'e'): /* set metadata (superblock) information */
+                       if (ss) {
+                               fprintf(stderr, Name ": metadata information already given\n");
+                               exit(2);
+                       }
+                       for(i=0; superlist[i]; i++) 
+                               if (superlist[i]->match_metadata_desc(optarg)) {
+                                       ss = superlist[i];
+                                       break;
+                               }
+                       if (!ss) {
+                               fprintf(stderr, Name ": unrecognised metadata identifier: %s\n", optarg);
+                               exit(2);
+                       }
+                       continue;
+
                case O(GROW,'z'):
                case O(CREATE,'z'): /* size */
                        if (size >= 0) {
@@ -645,6 +687,12 @@ int main(int argc, char *argv[])
 
        }
 
+       if (!mode && devs_found) {
+               mode = MISC;
+               devmode = 'Q';
+               if (devlist->disposition == 0)
+                       devlist->disposition = devmode;
+       }
        if (!mode) {
                fputs(Usage, stderr);
                exit(2);
@@ -707,14 +755,14 @@ int main(int argc, char *argv[])
                                if (mdfd < 0)
                                        rv |= 1;
                                else {
-                                       rv |= Assemble(devlist->devname, mdfd, array_ident, configfile,
+                                       rv |= Assemble(ss, devlist->devname, mdfd, array_ident, configfile,
                                                       NULL,
                                                       readonly, runstop, update, verbose, force);
                                        close(mdfd);
                                }
                        }
                } else if (!scan)
-                       rv = Assemble(devlist->devname, mdfd, &ident, configfile,
+                       rv = Assemble(ss, devlist->devname, mdfd, &ident, configfile,
                                      devlist->next,
                                      readonly, runstop, update, verbose, force);
                else if (devs_found>0) {
@@ -735,7 +783,7 @@ int main(int argc, char *argv[])
                                        rv |= 1;
                                        continue;
                                }
-                               rv |= Assemble(dv->devname, mdfd, array_ident, configfile,
+                               rv |= Assemble(ss, dv->devname, mdfd, array_ident, configfile,
                                               NULL,
                                               readonly, runstop, update, verbose, force);
                                close(mdfd);
@@ -755,11 +803,13 @@ int main(int argc, char *argv[])
                                        }
                                        if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0)
                                                /* already assembled, skip */
-                                               continue;
-                                       rv |= Assemble(array_list->devname, mdfd,
-                                                      array_list, configfile,
-                                                      NULL,
-                                                      readonly, runstop, NULL, verbose, force);
+                                               ;
+                                       else
+                                               rv |= Assemble(ss, array_list->devname, mdfd,
+                                                              array_list, configfile,
+                                                              NULL,
+                                                              readonly, runstop, NULL, verbose, force);
+                                       close(mdfd);
                                }
                }
                break;
@@ -767,7 +817,19 @@ int main(int argc, char *argv[])
                rv = Build(devlist->devname, mdfd, chunk, level, layout, raiddisks, devlist->next, assume_clean);
                break;
        case CREATE:
-               rv = Create(devlist->devname, mdfd, chunk, level, layout, size<0 ? 0 : size,
+               if (ss == NULL) {
+                       for(i=0; superlist[i]; i++) 
+                               if (superlist[i]->match_metadata_desc("default")) {
+                                       ss = superlist[i];
+                                       break;
+                               }
+               }
+               if (!ss) {
+                       fprintf(stderr, Name ": internal error - no default metadata style\n");
+                       exit(2);
+               }
+
+               rv = Create(ss, devlist->devname, mdfd, chunk, level, layout, size<0 ? 0 : size,
                            raiddisks, sparedisks,
                            devs_found-1, devlist->next, runstop, verbose, force);
                break;
@@ -791,6 +853,16 @@ int main(int argc, char *argv[])
                                        /* apply to all devices in /proc/mdstat */
                                        struct mdstat_ent *ms = mdstat_read(0);
                                        struct mdstat_ent *e;
+                                       if (devmode == 'S') {
+                                               /* reverse order so that arrays made of arrays are stopped properly */
+                                               struct mdstat_ent *sm = NULL;
+                                               while ((e=ms) != NULL) {
+                                                       ms = e->next;
+                                                       e->next = sm;
+                                                       sm = e;
+                                               }
+                                               ms = sm;
+                                       }
                                        for (e=ms ; e ; e=e->next) {
                                                char *name = get_md_name(e->devnum);
 
@@ -803,8 +875,10 @@ int main(int argc, char *argv[])
                                                        rv |= Detail(name, !verbose, test);
                                                else if (devmode=='S') {
                                                        mdfd = open_mddev(name, 0);
-                                                       if (mdfd >= 0)
+                                                       if (mdfd >= 0) {
                                                                rv |= Manage_runstop(name, mdfd, -1);
+                                                               close(mdfd);
+                                                       }
                                                }
                                                put_md_name(name);
                                        }
@@ -823,7 +897,7 @@ int main(int argc, char *argv[])
                                        rv |= Query(dv->devname); continue;
                                }
                                mdfd = open_mddev(dv->devname, 0);
-                               if (mdfd>=0)
+                               if (mdfd>=0) {
                                        switch(dv->disposition) {
                                        case 'R':
                                                rv |= Manage_runstop(dv->devname, mdfd, 1); break;
@@ -834,6 +908,8 @@ int main(int argc, char *argv[])
                                        case 'w':
                                                rv |= Manage_ro(dv->devname, mdfd, -1); break;
                                        }
+                                       close(mdfd);
+                               }
                        }
                }
                break;