mdadm-1.6.0
[thirdparty/mdadm.git] / mdadm.c
1 /*
2  * mdadm - manage Linux "md" devices aka RAID arrays.
3  *
4  * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
5  *
6  *
7  *    This program is free software; you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation; either version 2 of the License, or
10  *    (at your option) any later version.
11  *
12  *    This program is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with this program; if not, write to the Free Software
19  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  *    Author: Neil Brown
22  *    Email: <neilb@cse.unsw.edu.au>
23  *    Paper: Neil Brown
24  *           School of Computer Science and Engineering
25  *           The University of New South Wales
26  *           Sydney, 2052
27  *           Australia
28  */
29
30 #include "mdadm.h"
31 #include "md_p.h"
32 #include <ctype.h>
33
34
35 void make_parts(char *dev, int cnt)
36 {
37         /* make 'cnt' partition devices for 'dev'
38          * We use the major/minor from dev and add 1..cnt
39          * If dev ends with a digit, we add "_p%d" else "%d"
40          * If the name exists, we use it's owner/mode,
41          * else that of dev
42          */
43         struct stat stb;
44         int major, minor;
45         int i;
46         char *name = malloc(strlen(dev) + 20);
47         int dig = isdigit(dev[strlen(dev)-1]);
48
49         if (stat(dev, &stb)!= 0)
50                 return;
51         if (!S_ISBLK(stb.st_mode))
52                 return;
53         major = MAJOR(stb.st_rdev);
54         minor = MINOR(stb.st_rdev);
55         for (i=1; i <= cnt ; i++) {
56                 struct stat stb2;
57                 sprintf(name, "%s%s%d", dev, dig?"_p":"", i);
58                 if (stat(name, &stb2)==0) {
59                         if (!S_ISBLK(stb2.st_mode))
60                                 continue;
61                         if (stb2.st_rdev == MKDEV(major, minor+i))
62                                 continue;
63                         unlink(name);
64                 } else {
65                         stb2 = stb;
66                 }
67                 mknod(name, S_IFBLK | 0600, MKDEV(major, minor+i));
68                 chown(name, stb2.st_uid, stb2.st_gid);
69                 chmod(name, stb2.st_mode & 07777);
70         }
71 }
72
73 /*
74  * Open a given md device, and check that it really is one.
75  * If 'autof' is given, then we need to create, or recreate, the md device.
76  * If the name already exists, and is not a block device, we fail.
77  * If it exists and is not an md device, is not the right type (partitioned or not),
78  * or is currently in-use, we remove the device, but remember the owner and mode.
79  * If it now doesn't exist, we find a few md array and create the device.
80  * Default ownership is user=0, group=0 perm=0600
81  */
82 int open_mddev(char *dev, int autof)
83 {
84         int mdfd;
85         struct stat stb;
86         int major = MD_MAJOR;
87         int minor;
88         int must_remove = 0;
89         struct mdstat_ent *mdlist;
90         int num;
91
92         if (autof) {
93                 /* autof is set, so we need to check that the name is ok,
94                  * and possibly create one if not
95                  */
96                 stb.st_mode = 0;
97                 if (lstat(dev, &stb)==0 && ! S_ISBLK(stb.st_mode)) {
98                         fprintf(stderr, Name ": %s is not a block device.\n",
99                                 dev);
100                         return -1;
101                 }
102                 /* check major number is correct */
103                 if (autof>0)
104                         major = get_mdp_major();
105                 if (stb.st_mode && MAJOR(stb.st_rdev) != major)
106                         must_remove = 1;
107                 if (stb.st_mode && !must_remove) {
108                         mdu_array_info_t array;
109                         /* looks ok, see if it is available */
110                         mdfd = open(dev, O_RDWR, 0);
111                         if (mdfd < 0) {
112                                 fprintf(stderr, Name ": error opening %s: %s\n",
113                                         dev, strerror(errno));
114                                 return -1;
115                         } else if (md_get_version(mdfd) <= 0) {
116                                 fprintf(stderr, Name ": %s does not appear to be an md device\n",
117                                         dev);
118                                 close(mdfd);
119                                 return -1;
120                         }
121                         if (ioctl(mdfd, GET_ARRAY_INFO, &array)==0) {
122                                 /* already active */
123                                 must_remove = 1;
124                                 close(mdfd);
125                         } else {
126                                 if (autof > 0)
127                                         make_parts(dev, autof);
128                                 return mdfd;
129                         }
130                 }
131                 /* Ok, need to find a minor that is not in use.
132                  * Easiest to read /proc/mdstat, and hunt through for
133                  * an unused number 
134                  */
135                 mdlist = mdstat_read(0);
136                 for (num= (autof>0)?-1:0 ; ; num+= (autof>2)?-1:1) {
137                         struct mdstat_ent *me;
138                         for (me=mdlist; me; me=me->next)
139                                 if (me->devnum == num)
140                                         break;
141                         if (!me) {
142                                 /* doesn't exist if mdstat.
143                                  * make sure it is new to /dev too
144                                  */
145                                 char *dn;
146                                 if (autof > 0) 
147                                         minor = (-1-num) << MdpMinorShift;
148                                 else
149                                         minor = num;
150                                 dn = map_dev(major,minor);
151                                 if (dn==NULL || is_standard(dn)) {
152                                         /* this number only used by a 'standard' name,
153                                          * so it is safe to use
154                                          */
155                                         break;
156                                 }
157                         }
158                 }
159                 /* 'num' is the number to use, >=0 for md, <0 for mdp */
160                 if (must_remove) {
161                         /* never remove a device name that ends /mdNN or /dNN,
162                          * that would be confusing 
163                          */
164                         if (is_standard(dev)) {
165                                 fprintf(stderr, Name ": --auto refusing to remove %s as it looks like a standard name.\n",
166                                         dev);
167                                 return -1;
168                         }
169                         unlink(dev);
170                 }
171
172                 if (mknod(dev, S_IFBLK|0600, MKDEV(major, minor))!= 0) {
173                         fprintf(stderr, Name ": failed to create %s\n", dev);
174                         return -1;
175                 }
176                 if (must_remove) {
177                         chown(dev, stb.st_uid, stb.st_gid);
178                         chmod(dev, stb.st_mode & 07777);
179                 }
180                 make_parts(dev,autof);
181         }
182         mdfd = open(dev, O_RDWR, 0);
183         if (mdfd < 0)
184                 fprintf(stderr, Name ": error opening %s: %s\n",
185                         dev, strerror(errno));
186         else if (md_get_version(mdfd) <= 0) {
187                 fprintf(stderr, Name ": %s does not appear to be an md device\n",
188                         dev);
189                 close(mdfd);
190                 mdfd = -1;
191         }
192         return mdfd;
193 }
194
195
196
197 int main(int argc, char *argv[])
198 {
199         int mode = 0;
200         int opt;
201         int option_index;
202         char *help_text;
203         char *c;
204         int rv;
205
206         int chunk = 0;
207         int size = -1;
208         int level = UnSet;
209         int layout = UnSet;
210         int raiddisks = 0;
211         int sparedisks = 0;
212         struct mddev_ident_s ident;
213         char *configfile = NULL;
214         char *cp;
215         char *update = NULL;
216         int scan = 0;
217         char devmode = 0;
218         int runstop = 0;
219         int readonly = 0;
220         int SparcAdjust = 0;
221         mddev_dev_t devlist = NULL;
222         mddev_dev_t *devlistend = & devlist;
223         mddev_dev_t dv;
224         int devs_found = 0;
225         int verbose = 0;
226         int brief = 0;
227         int force = 0;
228         int test = 0;
229         int assume_clean = 0;
230         int autof = 0; /* -1 for non-partitions, 1 or more to create partitions */
231
232         char *mailaddr = NULL;
233         char *program = NULL;
234         int delay = 0;
235         int daemonise = 0;
236         int oneshot = 0;
237
238         int mdfd = -1;
239
240         ident.uuid_set=0;
241         ident.level = UnSet;
242         ident.raid_disks = UnSet;
243         ident.super_minor= UnSet;
244         ident.devices=0;
245
246         while ((option_index = -1) ,
247                (opt=getopt_long(argc, argv,
248                                 short_options, long_options,
249                                 &option_index)) != -1) {
250                 int newmode = mode;
251                 /* firstly, so mode-independant options */
252                 switch(opt) {
253                 case 'h':
254                         help_text = Help;
255                         if (option_index > 0 && 
256                             strcmp(long_options[option_index].name, "help-options")==0)
257                                 help_text = OptionHelp;
258                         else
259                                 switch (mode) {
260                                 case ASSEMBLE : help_text = Help_assemble; break;
261                                 case BUILD    : help_text = Help_build; break;
262                                 case CREATE   : help_text = Help_create; break;
263                                 case MANAGE   : help_text = Help_manage; break;
264                                 case MISC     : help_text = Help_misc; break;
265                                 case MONITOR  : help_text = Help_monitor; break;
266                                 case GROW     : help_text = Help_grow; break;
267                                 }
268                         fputs(help_text,stderr);
269                         exit(0);
270
271                 case 'V':
272                         fputs(Version, stderr);
273                         exit(0);
274
275                 case 'v': verbose = 1;
276                         continue;
277
278                 case 'b': brief = 1;
279                         continue;
280
281                 case ':':
282                 case '?':
283                         fputs(Usage, stderr);
284                         exit(2);
285                 }
286                 /* second, figure out the mode.
287                  * Some options force the mode.  Others
288                  * set the mode if it isn't already 
289                  */
290
291                 switch(opt) {
292                 case '@': /* just incase they say --manage */
293                         newmode = MANAGE; break;
294                 case 'a':
295                 case 'r':
296                 case 'f':
297                 case 1 : if (!mode) newmode = MANAGE; break;
298
299                 case 'A': newmode = ASSEMBLE; break;
300                 case 'B': newmode = BUILD; break;
301                 case 'C': newmode = CREATE; break;
302                 case 'F': newmode = MONITOR;break;
303                 case 'G': newmode = GROW; break;
304
305                 case '#':
306                 case 'D':
307                 case 'E':
308                 case 'Q': newmode = MISC; break;
309                 case 'R':
310                 case 'S':
311                 case 'o':
312                 case 'w':
313                 case 'K': if (!mode) newmode = MISC; break;
314                 }
315                 if (mode && newmode == mode) {
316                         /* everybody happy ! */
317                 } else if (mode && newmode != mode) {
318                         /* not allowed.. */
319                         fprintf(stderr, Name ": ");
320                         if (option_index >= 0)
321                                 fprintf(stderr, "--%s", long_options[option_index].name);
322                         else
323                                 fprintf(stderr, "-%c", opt);
324                         fprintf(stderr, " would set mode to %s, but it is already %s.\n",
325                                 map_num(modes, newmode),
326                                 map_num(modes, mode));
327                         exit(2);
328                 } else if (!mode && newmode) {
329                         mode = newmode;
330                 } else {
331                         /* special case of -c --help */
332                         if (opt == 'c' && 
333                             ( strncmp(optarg, "--h", 3)==0 ||
334                               strncmp(optarg, "-h", 2)==0)) {
335                                 fputs(Help_config, stderr);
336                                 exit(0);
337                         }
338                         if (option_index >= 0)
339                                 fprintf(stderr, "--%s", long_options[option_index].name);
340                         else
341                                 fprintf(stderr, "-%c", opt);
342                         fprintf(stderr, " does not set the mode, and so cannot be first.\n");
343                         exit(2);
344                 }
345
346                 /* if we just set the mode, then done */
347                 switch(opt) {
348                 case '@':
349                 case '#':
350                 case 'A':
351                 case 'B':
352                 case 'C':
353                 case 'F':
354                 case 'G':
355                         continue;
356                 }
357                 if (opt == 1) {
358                         /* an undecorated option - must be a device name.
359                          */
360                         if (devs_found > 0 && mode == '@' && !devmode) {
361                                 fprintf(stderr, Name ": Must give one of -a/-r/-f for subsequent devices at %s\n", optarg);
362                                 exit(2);
363                         }
364                         dv = malloc(sizeof(*dv));
365                         if (dv == NULL) {
366                                 fprintf(stderr, Name ": malloc failed\n");
367                                 exit(3);
368                         }
369                         dv->devname = optarg;
370                         dv->disposition = devmode;
371                         dv->next = NULL;
372                         *devlistend = dv;
373                         devlistend = &dv->next;
374                         
375                         devs_found++;
376                         continue;
377                 }
378
379                 /* We've got a mode, and opt is now something else which
380                  * could depend on the mode */
381 #define O(a,b) ((a<<8)|b)
382                 switch (O(mode,opt)) {
383                 case O(CREATE,'c'):
384                 case O(BUILD,'c'): /* chunk or rounding */
385                         if (chunk) {
386                                 fprintf(stderr, Name ": chunk/rounding may only be specified once. "
387                                         "Second value is %s.\n", optarg);
388                                 exit(2);
389                         }
390                         chunk = strtol(optarg, &c, 10);
391                         if (!optarg[0] || *c || chunk<4 || ((chunk-1)&chunk)) {
392                                 fprintf(stderr, Name ": invalid chunk/rounding value: %s\n",
393                                         optarg);
394                                 exit(2);
395                         }
396                         continue;
397
398                 case O(GROW,'z'):
399                 case O(CREATE,'z'): /* size */
400                         if (size >= 0) {
401                                 fprintf(stderr, Name ": size may only be specified once. "
402                                         "Second value is %s.\n", optarg);
403                                 exit(2);
404                         }
405                         if (strcmp(optarg, "max")==0)
406                                 size = 0;
407                         else {
408                                 size = strtol(optarg, &c, 10);
409                                 if (!optarg[0] || *c || size < 4) {
410                                         fprintf(stderr, Name ": invalid size: %s\n",
411                                                 optarg);
412                                         exit(2);
413                                 }
414                         }
415                         continue;
416
417                 case O(CREATE,'l'):
418                 case O(BUILD,'l'): /* set raid level*/
419                         if (level != UnSet) {
420                                 fprintf(stderr, Name ": raid level may only be set once.  "
421                                         "Second value is %s.\n", optarg);
422                                 exit(2);
423                         }
424                         level = map_name(pers, optarg);
425                         if (level == UnSet) {
426                                 fprintf(stderr, Name ": invalid raid level: %s\n",
427                                         optarg);
428                                 exit(2);
429                         }
430                         if (level != 0 && level != -1 && level != 1 && level != -4 && mode == BUILD) {
431                                 fprintf(stderr, Name ": Raid level %s not permitted with --build.\n",
432                                         optarg);
433                                 exit(2);
434                         }
435                         if (sparedisks > 0 && level < 1 && level >= -1) {
436                                 fprintf(stderr, Name ": raid level %s is incompatible with spare-devices setting.\n",
437                                         optarg);
438                                 exit(2);
439                         }
440                         ident.level = level;
441                         continue;
442
443                 case O(CREATE,'p'): /* raid5 layout */
444                         if (layout >= 0) {
445                                 fprintf(stderr,Name ": layout may only be sent once.  "
446                                         "Second value was %s\n", optarg);
447                                 exit(2);
448                         }
449                         switch(level) {
450                         default:
451                                 fprintf(stderr, Name ": layout not meaningful for %s arrays.\n",
452                                         map_num(pers, level));
453                                 exit(2);
454                         case UnSet:
455                                 fprintf(stderr, Name ": raid level must be given before layout.\n");
456                                 exit(2);
457
458                         case 5:
459                         case 6:
460                                 layout = map_name(r5layout, optarg);
461                                 if (layout==UnSet) {
462                                         fprintf(stderr, Name ": layout %s not understood for raid5.\n",
463                                                 optarg);
464                                         exit(2);
465                                 }
466                                 break;
467                         }
468                         continue;
469
470                 case O(CREATE,3):
471                 case O(BUILD,3): /* assume clean */
472                         assume_clean = 1;
473                         continue;
474
475                 case O(GROW,'n'):
476                 case O(CREATE,'n'):
477                 case O(BUILD,'n'): /* number of raid disks */
478                         if (raiddisks) {
479                                 fprintf(stderr, Name ": raid-devices set twice: %d and %s\n",
480                                         raiddisks, optarg);
481                                 exit(2);
482                         }
483                         raiddisks = strtol(optarg, &c, 10);
484                         if (!optarg[0] || *c || raiddisks<=0 || raiddisks > MD_SB_DISKS) {
485                                 fprintf(stderr, Name ": invalid number of raid devices: %s\n",
486                                         optarg);
487                                 exit(2);
488                         }
489                         if (raiddisks == 1 &&  !force) {
490                                 fprintf(stderr, Name ": '1' is an unusual number of drives for an array, so it is probably\n"
491                                         "     a mistake.  If you really mean it you will need to specify --force before\n"
492                                         "     setting the number of drives.\n");
493                                 exit(2);
494                         }
495                         ident.raid_disks = raiddisks;
496                         continue;
497
498                 case O(CREATE,'x'): /* number of spare (eXtra) discs */
499                         if (sparedisks) {
500                                 fprintf(stderr,Name ": spare-devices set twice: %d and %s\n",
501                                         sparedisks, optarg);
502                                 exit(2);
503                         }
504                         if (level != UnSet && level <= 0 && level >= -1) {
505                                 fprintf(stderr, Name ": spare-devices setting is incompatible with raid level %d\n",
506                                         level);
507                                 exit(2);
508                         }
509                         sparedisks = strtol(optarg, &c, 10);
510                         if (!optarg[0] || *c || sparedisks < 0 || sparedisks > MD_SB_DISKS - raiddisks) {
511                                 fprintf(stderr, Name ": invalid number of spare-devices: %s\n",
512                                         optarg);
513                                 exit(2);
514                         }
515                         continue;
516
517                 case O(CREATE,'a'):
518                 case O(BUILD,'a'):
519                 case O(ASSEMBLE,'a'): /* auto-creation of device node */
520                         if (optarg == NULL)
521                                 autof = -1;
522                         else if (strcasecmp(optarg,"no")==0)
523                                 autof = 0;
524                         else if (strcasecmp(optarg,"yes")==0 || strcasecmp(optarg,"md")==0)
525                                 autof = -1;
526                         else {
527                                 /* There might be digits, and maybe a hypen, at the end */
528                                 char *e = optarg + strlen(optarg);
529                                 int num = 4;
530                                 int len;
531                                 while (e > optarg && isdigit(e[-1]))
532                                         e--;
533                                 if (*e) {
534                                         num = atoi(e);
535                                         if (num <= 0) num = 1;
536                                 }
537                                 if (e > optarg && e[-1] == '-')
538                                         e--;
539                                 len = e - optarg;
540                                 if ((len == 3 && strncasecmp(optarg,"mdp",3)==0) ||
541                                     (len == 1 && strncasecmp(optarg,"p",1)==0) ||
542                                     (len >= 4 && strncasecmp(optarg,"part",4)==0))
543                                         autof = num;
544                                 else {
545                                         fprintf(stderr, Name ": --auto flag arg of \"%s\" unrecognised: use no,yes,md,mdp,part\n"
546                                                 "        optionally followed by a number.\n",
547                                                 optarg);
548                                         exit(2);
549                                 }
550                         }
551                         continue;
552
553                 case O(BUILD,'f'): /* force honouring '-n 1' */
554                 case O(CREATE,'f'): /* force honouring of device list */
555                 case O(ASSEMBLE,'f'): /* force assembly */
556                 case O(MISC,'f'): /* force zero */
557                         force=1;
558                         continue;
559
560                         /* now for the Assemble options */
561                 case O(ASSEMBLE,'u'): /* uuid of array */
562                         if (ident.uuid_set) {
563                                 fprintf(stderr, Name ": uuid cannot be set twice.  "
564                                         "Second value %s.\n", optarg);
565                                 exit(2);
566                         }
567                         if (parse_uuid(optarg, ident.uuid))
568                                 ident.uuid_set = 1;
569                         else {
570                                 fprintf(stderr,Name ": Bad uuid: %s\n", optarg);
571                                 exit(2);
572                         }
573                         continue;
574
575                 case O(ASSEMBLE,'m'): /* super-minor for array */
576                         if (ident.super_minor != UnSet) {
577                                 fprintf(stderr, Name ": super-minor cannot be set twice.  "
578                                         "Second value: %s.\n", optarg);
579                                 exit(2);
580                         }
581                         if (strcmp(optarg, "dev")==0)
582                                 ident.super_minor = -2;
583                         else {
584                                 ident.super_minor = strtoul(optarg, &cp, 10);
585                                 if (!optarg[0] || *cp) {
586                                         fprintf(stderr, Name ": Bad super-minor number: %s.\n", optarg);
587                                         exit(2);
588                                 }
589                         }
590                         continue;
591
592                 case O(ASSEMBLE,'U'): /* update the superblock */
593                         if (update) {
594                                 fprintf(stderr, Name ": Can only update one aspect of superblock, both %s and %s given.\n",
595                                         update, optarg);
596                                 exit(2);
597                         }
598                         update = optarg;
599                         if (strcmp(update, "sparc2.2")==0) continue;
600                         if (strcmp(update, "super-minor") == 0)
601                                 continue;
602                         if (strcmp(update, "summaries")==0)
603                                 continue;
604                         fprintf(stderr, Name ": '--update %s' invalid.  Only 'sparc2.2', 'super-minor' or 'summaries' supported\n",update);
605                         exit(2);
606
607                 case O(ASSEMBLE,'c'): /* config file */
608                 case O(MISC, 'c'):
609                 case O(MONITOR,'c'):
610                         if (configfile) {
611                                 fprintf(stderr, Name ": configfile cannot be set twice.  "
612                                         "Second value is %s.\n", optarg);
613                                 exit(2);
614                         }
615                         configfile = optarg;
616                         /* FIXME possibly check that config file exists.  Even parse it */
617                         continue;
618                 case O(ASSEMBLE,'s'): /* scan */
619                 case O(MISC,'s'):
620                 case O(MONITOR,'s'):
621                         scan = 1;
622                         continue;
623
624                 case O(MONITOR,'m'): /* mail address */
625                         if (mailaddr)
626                                 fprintf(stderr, Name ": only specify one mailaddress. %s ignored.\n",
627                                         optarg);
628                         else
629                                 mailaddr = optarg;
630                         continue;
631
632                 case O(MONITOR,'p'): /* alert program */
633                         if (program)
634                                 fprintf(stderr, Name ": only specify one alter program. %s ignored.\n",
635                                         optarg);
636                         else
637                                 program = optarg;
638                         continue;
639
640                 case O(MONITOR,'d'): /* delay in seconds */
641                         if (delay)
642                                 fprintf(stderr, Name ": only specify delay once. %s ignored.\n",
643                                         optarg);
644                         else {
645                                 delay = strtol(optarg, &c, 10);
646                                 if (!optarg[0] || *c || delay<1) {
647                                         fprintf(stderr, Name ": invalid delay: %s\n",
648                                                 optarg);
649                                         exit(2);
650                                 }
651                         }
652                         continue;
653                 case O(MONITOR,'f'): /* daemonise */
654                         daemonise = 1;
655                         continue;
656                 case O(MONITOR,'1'): /* oneshot */
657                         oneshot = 1;
658                         continue;
659                 case O(MONITOR,'t'): /* test */
660                         test = 1;
661                         continue;
662
663                         /* now the general management options.  Some are applicable
664                          * to other modes. None have arguments.
665                          */
666                 case O(MANAGE,'a'): /* add a drive */
667                         devmode = 'a';
668                         continue;
669                 case O(MANAGE,'r'): /* remove a drive */
670                         devmode = 'r';
671                         continue;
672                 case O(MANAGE,'f'): /* set faulty */
673                         devmode = 'f';
674                         continue;
675                 case O(MANAGE,'R'):
676                 case O(ASSEMBLE,'R'):
677                 case O(BUILD,'R'):
678                 case O(CREATE,'R'): /* Run the array */
679                         if (runstop < 0) {
680                                 fprintf(stderr, Name ": Cannot both Stop and Run an array\n");
681                                 exit(2);
682                         }
683                         runstop = 1;
684                         continue;
685                 case O(MANAGE,'S'):
686                         if (runstop > 0) {
687                                 fprintf(stderr, Name ": Cannot both Run and Stop an array\n");
688                                 exit(2);
689                         }
690                         runstop = -1;
691                         continue;
692
693                 case O(MANAGE,'o'):
694                         if (readonly < 0) {
695                                 fprintf(stderr, Name ": Cannot have both readonly and readwrite\n");
696                                 exit(2);
697                         }
698                         readonly = 1;
699                         continue;
700                 case O(MANAGE,'w'):
701                         if (readonly > 0) {
702                                 fprintf(stderr, Name ": Cannot have both readwrite and readonly.\n");
703                                 exit(2);
704                         }
705                         readonly = -1;
706                         continue;
707
708                 case O(MISC,'Q'):
709                 case O(MISC,'D'):
710                 case O(MISC,'E'):
711                 case O(MISC,'K'):
712                 case O(MISC,'R'):
713                 case O(MISC,'S'):
714                 case O(MISC,'o'):
715                 case O(MISC,'w'):
716                         if (devmode && devmode != opt &&
717                             (devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
718                                 fprintf(stderr, Name ": --examine/-E cannot be given with -%c\n",
719                                         devmode =='E'?opt:devmode);
720                                 exit(2);
721                         }
722                         devmode = opt;
723                         continue;
724                 case O(MISC,'t'):
725                         test = 1;
726                         continue;
727
728                 case O(MISC, 22):
729                         if (devmode != 'E') {
730                                 fprintf(stderr, Name ": --sparc2.2 only allowed with --examine\n");
731                                 exit(2);
732                         }
733                         SparcAdjust = 1;
734                         continue;
735                 }
736                 /* We have now processed all the valid options. Anything else is
737                  * an error
738                  */
739                 fprintf(stderr, Name ": option %c not valid in %s mode\n",
740                         opt, map_num(modes, mode));
741                 exit(2);
742
743         }
744
745         if (!mode) {
746                 fputs(Usage, stderr);
747                 exit(2);
748         }
749         /* Ok, got the option parsing out of the way
750          * hopefully it's mostly right but there might be some stuff
751          * missing
752          *
753          * That is mosty checked in the per-mode stuff but...
754          *
755          * For @,B,C  and A without -s, the first device listed must be an md device
756          * we check that here and open it.
757          */
758
759         if (mode==MANAGE || mode == BUILD || mode == CREATE || mode == GROW ||
760             (mode == ASSEMBLE && ! scan)) {
761                 if (devs_found < 1) {
762                         fprintf(stderr, Name ": an md device must be given in this mode\n");
763                         exit(2);
764                 }
765                 if ((int)ident.super_minor == -2 && autof) {
766                         fprintf(stderr, Name ": --super-minor=dev is incompatible with --auto\n");      
767                         exit(2);
768                 }
769                 mdfd = open_mddev(devlist->devname, autof);
770                 if (mdfd < 0)
771                         exit(1);
772                 if ((int)ident.super_minor == -2) {
773                         struct stat stb;
774                         fstat(mdfd, &stb);
775                         ident.super_minor = MINOR(stb.st_rdev);
776                 }
777         }
778
779         rv = 0;
780         switch(mode) {
781         case MANAGE:
782                 /* readonly, add/remove, readwrite, runstop */
783                 if (readonly>0)
784                         rv = Manage_ro(devlist->devname, mdfd, readonly);
785                 if (!rv && devs_found>1)
786                         rv = Manage_subdevs(devlist->devname, mdfd,
787                                             devlist->next);
788                 if (!rv && readonly < 0)
789                         rv = Manage_ro(devlist->devname, mdfd, readonly);
790                 if (!rv && runstop)
791                         rv = Manage_runstop(devlist->devname, mdfd, runstop);
792                 break;
793         case ASSEMBLE:
794                 if (devs_found == 1 && ident.uuid_set == 0 &&
795                     ident.super_minor == UnSet && !scan ) {
796                         /* Only a device has been given, so get details from config file */
797                         mddev_ident_t array_ident = conf_get_ident(configfile, devlist->devname);
798                         mdfd = open_mddev(devlist->devname, array_ident->autof);
799                         if (mdfd < 0)
800                                 rv |= 1;
801                         else {
802                                 if (array_ident == NULL) {
803                                         fprintf(stderr, Name ": %s not identified in config file.\n",
804                                                 devlist->devname);
805                                         rv |= 1;
806                                 }
807                                 else 
808                                         rv |= Assemble(devlist->devname, mdfd, array_ident, configfile,
809                                                        NULL,
810                                                        readonly, runstop, update, verbose, force);
811                         }
812                 } else if (!scan)
813                         rv = Assemble(devlist->devname, mdfd, &ident, configfile,
814                                       devlist->next,
815                                       readonly, runstop, update, verbose, force);
816                 else if (devs_found>0) {
817                         if (update && devs_found > 1) {
818                                 fprintf(stderr, Name ": can only update a single array at a time\n");
819                                 exit(1);
820                         }
821                         for (dv = devlist ; dv ; dv=dv->next) {
822                                 mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname);
823                                 mdfd = open_mddev(dv->devname, array_ident->autof);
824                                 if (mdfd < 0) {
825                                         rv |= 1;
826                                         continue;
827                                 }
828                                 if (array_ident == NULL) {
829                                         fprintf(stderr, Name ": %s not identified in config file.\n",
830                                                 dv->devname);
831                                         rv |= 1;
832                                         continue;
833                                 }
834                                 rv |= Assemble(dv->devname, mdfd, array_ident, configfile,
835                                                NULL,
836                                                readonly, runstop, update, verbose, force);
837                         }
838                 } else {
839                         mddev_ident_t array_list =  conf_get_ident(configfile, NULL);
840                         if (!array_list) {
841                                 fprintf(stderr, Name ": No arrays found in config file\n");
842                                 rv = 1;
843                         } else
844                                 for (; array_list; array_list = array_list->next) {
845                                         mdu_array_info_t array;
846                                         mdfd = open_mddev(array_list->devname, array_list->autof);
847                                         if (mdfd < 0) {
848                                                 rv |= 1;
849                                                 continue;
850                                         }
851                                         if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0)
852                                                 /* already assembled, skip */
853                                                 continue;
854                                         rv |= Assemble(array_list->devname, mdfd,
855                                                        array_list, configfile,
856                                                        NULL,
857                                                        readonly, runstop, NULL, verbose, force);
858                                 }
859                 }
860                 break;
861         case BUILD:
862                 rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next, assume_clean);
863                 break;
864         case CREATE:
865                 rv = Create(devlist->devname, mdfd, chunk, level, layout, size<0 ? 0 : size,
866                             raiddisks, sparedisks,
867                             devs_found-1, devlist->next, runstop, verbose, force);
868                 break;
869         case MISC:
870
871                 if (devmode == 'E') {
872                         if (devlist == NULL && !scan) {
873                                 fprintf(stderr, Name ": No devices to examine\n");
874                                 exit(2);
875                         }
876                         if (devlist == NULL)
877                                 devlist = conf_get_devs(configfile);
878                         if (devlist == NULL) {
879                                 fprintf(stderr, Name ": No devices listed in %s\n", configfile?configfile:DefaultConfFile);
880                                 exit(1);
881                         }
882                         rv = Examine(devlist, scan?!verbose:brief, scan, SparcAdjust);
883                 } else {
884                         if (devlist == NULL) {
885                                 if ((devmode == 'S' ||devmode=='D') && scan) {
886                                         /* apply to all devices in /proc/mdstat */
887                                         struct mdstat_ent *ms = mdstat_read(0);
888                                         struct mdstat_ent *e;
889                                         for (e=ms ; e ; e=e->next) {
890                                                 char *name = get_md_name(e->devnum);
891
892                                                 if (!name) {
893                                                         fprintf(stderr, Name ": cannot find device file for %s\n",
894                                                                 e->dev);
895                                                         continue;
896                                                 }
897                                                 if (devmode == 'D')
898                                                         rv |= Detail(name, !verbose, test);
899                                                 else if (devmode=='S') {
900                                                         mdfd = open_mddev(name, 0);
901                                                         if (mdfd >= 0)
902                                                                 rv |= Manage_runstop(name, mdfd, -1);
903                                                 }
904                                                 put_md_name(name);
905                                         }
906                                 } else {                                                
907                                         fprintf(stderr, Name ": No devices given.\n");
908                                         exit(2);
909                                 }
910                         }
911                         for (dv=devlist ; dv; dv=dv->next) {
912                                 switch(dv->disposition) {
913                                 case 'D':
914                                         rv |= Detail(dv->devname, brief, test); continue;
915                                 case 'K': /* Zero superblock */
916                                         rv |= Kill(dv->devname, force); continue;
917                                 case 'Q':
918                                         rv |= Query(dv->devname); continue;
919                                 }
920                                 mdfd = open_mddev(dv->devname, 0);
921                                 if (mdfd>=0)
922                                         switch(dv->disposition) {
923                                         case 'R':
924                                                 rv |= Manage_runstop(dv->devname, mdfd, 1); break;
925                                         case 'S':
926                                                 rv |= Manage_runstop(dv->devname, mdfd, -1); break;
927                                         case 'o':
928                                                 rv |= Manage_ro(dv->devname, mdfd, 1); break;
929                                         case 'w':
930                                                 rv |= Manage_ro(dv->devname, mdfd, -1); break;
931                                         }
932                         }
933                 }
934                 break;
935         case MONITOR:
936                 if (!devlist && !scan) {
937                         fprintf(stderr, Name ": Cannot monitor: need --scan or at least one device\n");
938                         rv = 1;
939                         break;
940                 }
941                 rv= Monitor(devlist, mailaddr, program,
942                             delay?delay:60, daemonise, scan, oneshot, configfile, test);
943                 break;
944
945         case GROW:
946                 if (devs_found > 1) {
947                         fprintf(stderr, Name ": Only one device may be given for --grow\n");
948                         rv = 1;
949                         break;
950                 }
951                 if (size >= 0 && raiddisks) {
952                         fprintf(stderr, Name ": can only grow size OR raiddisks, not both\n");
953                         rv = 1;
954                         break;
955                 }
956                 rv = Manage_resize(devlist->devname, mdfd, size, raiddisks);
957                 break;
958         }
959         exit(rv);
960 }