mdadm-1.0.1
[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
33 int open_mddev(char *dev)
34 {
35         int mdfd = open(dev, O_RDWR, 0);
36         if (mdfd < 0)
37                 fprintf(stderr, Name ": error opening %s: %s\n",
38                         dev, strerror(errno));
39         else if (md_get_version(mdfd) <= 0) {
40                 fprintf(stderr, Name ": %s does not appear to be an md device\n",
41                         dev);
42                 close(mdfd);
43                 mdfd = -1;
44         }
45         return mdfd;
46 }
47
48
49
50 int main(int argc, char *argv[])
51 {
52         int mode = 0;
53         int opt;
54         int option_index;
55         char *help_text;
56         char *c;
57         int rv;
58
59         int chunk = 0;
60         int size = 0;
61         int level = -10;
62         int layout = -1;
63         int raiddisks = 0;
64         int sparedisks = 0;
65         struct mddev_ident_s ident;
66         char *configfile = NULL;
67         char *cp;
68         int scan = 0;
69         char devmode = 0;
70         int runstop = 0;
71         int readonly = 0;
72         int SparcAdjust = 0;
73         mddev_dev_t devlist = NULL;
74         mddev_dev_t *devlistend = & devlist;
75         mddev_dev_t dv;
76         int devs_found = 0;
77         int verbose = 0;
78         int brief = 0;
79         int force = 0;
80
81         char *mailaddr = NULL;
82         char *program = NULL;
83         int delay = 0;
84
85         int mdfd = -1;
86
87         ident.uuid_set=0;
88         ident.level = -10;
89         ident.raid_disks = -1;
90         ident.super_minor= -1;
91         ident.devices=0;
92
93         while ((option_index = -1) ,
94                (opt=getopt_long(argc, argv,
95                                 short_options, long_options,
96                                 &option_index)) != -1) {
97                 int newmode = mode;
98                 /* firstly, so mode-independant options */
99                 switch(opt) {
100                 case 'h':
101                         help_text = Help;
102                         switch (mode) {
103                         case ASSEMBLE : help_text = Help_assemble; break;
104                         case BUILD    : help_text = Help_build; break;
105                         case CREATE   : help_text = Help_create; break;
106                         case MANAGE   : help_text = Help_manage; break;
107                         case MISC     : help_text = Help_misc; break;
108                         case MONITOR  : help_text = Help_monitor; break;
109                         }
110                         fputs(help_text,stderr);
111                         exit(0);
112
113                 case 'V':
114                         fputs(Version, stderr);
115                         exit(0);
116
117                 case 'v': verbose = 1;
118                         continue;
119
120                 case 'b': brief = 1;
121                         continue;
122
123                 case ':':
124                 case '?':
125                         fputs(Usage, stderr);
126                         exit(2);
127                 }
128                 /* second, figure out the mode.
129                  * Some options force the mode.  Others
130                  * set the mode if it isn't already 
131                  */
132
133                 switch(opt) {
134                 case '@': /* just incase they say --manage */
135                         newmode = MANAGE; break;
136                 case 'a':
137                 case 'r':
138                 case 'f':
139                 case 1 : if (!mode) newmode = MANAGE; break;
140
141                 case 'A': newmode = ASSEMBLE; break;
142                 case 'B': newmode = BUILD; break;
143                 case 'C': newmode = CREATE; break;
144                 case 'F': newmode = MONITOR;break;
145
146                 case '#':
147                 case 'D':
148                 case 'E':
149                 case 'Q': newmode = MISC; break;
150                 case 'R':
151                 case 'S':
152                 case 'o':
153                 case 'w':
154                 case 'K': if (!mode) newmode = MISC; break;
155                 }
156                 if (mode && newmode == mode) {
157                         /* everybody happy ! */
158                 } else if (mode && newmode != mode) {
159                         /* not allowed.. */
160                         fprintf(stderr, Name ": ");
161                         if (option_index >= 0)
162                                 fprintf(stderr, "--%s", long_options[option_index].name);
163                         else
164                                 fprintf(stderr, "-%c", opt);
165                         fprintf(stderr, " would set mode to %s, but it is already %s.\n",
166                                 map_num(modes, newmode),
167                                 map_num(modes, mode));
168                         exit(2);
169                 } else if (!mode && newmode) {
170                         mode = newmode;
171                 } else {
172                         /* special case of -c --help */
173                         if (opt == 'c' && 
174                             ( strncmp(optarg, "--h", 3)==0 ||
175                               strncmp(optarg, "-h", 2)==0)) {
176                                 fputs(Help_config, stderr);
177                                 exit(0);
178                         }
179                         if (option_index >= 0)
180                                 fprintf(stderr, "--%s", long_options[option_index].name);
181                         else
182                                 fprintf(stderr, "-%c", opt);
183                         fprintf(stderr, " does not set the mode, and so cannot be first.\n");
184                         exit(2);
185                 }
186
187                 /* if we just set the mode, then done */
188                 switch(opt) {
189                 case '@':
190                 case '#':
191                 case 'A':
192                 case 'B':
193                 case 'C':
194                 case 'F':
195                         continue;
196                 }
197                 if (opt == 1) {
198                         /* an undecorated option - must be a device name.
199                          */
200                         if (devs_found > 0 && mode == '@' && !devmode) {
201                                 fprintf(stderr, Name ": Must give on of -a/-r/-f for subsequent devices at %s\n", optarg);
202                                 exit(2);
203                         }
204                         dv = malloc(sizeof(*dv));
205                         if (dv == NULL) {
206                                 fprintf(stderr, Name ": malloc failed\n");
207                                 exit(3);
208                         }
209                         dv->devname = optarg;
210                         dv->disposition = devmode;
211                         dv->next = NULL;
212                         *devlistend = dv;
213                         devlistend = &dv->next;
214                         
215                         devs_found++;
216                         continue;
217                 }
218
219                 /* We've got a mode, and opt is now something else which
220                  * could depend on the mode */
221 #define O(a,b) ((a<<8)|b)
222                 switch (O(mode,opt)) {
223                 case O(CREATE,'c'):
224                 case O(BUILD,'c'): /* chunk or rounding */
225                         if (chunk) {
226                                 fprintf(stderr, Name ": chunk/rounding may only be specified once. "
227                                         "Second value is %s.\n", optarg);
228                                 exit(2);
229                         }
230                         chunk = strtol(optarg, &c, 10);
231                         if (!optarg[0] || *c || chunk<4 || ((chunk-1)&chunk)) {
232                                 fprintf(stderr, Name ": invalid chunk/rounding value: %s\n",
233                                         optarg);
234                                 exit(2);
235                         }
236                         continue;
237
238                 case O(CREATE,'z'): /* size */
239                         if (size) {
240                                 fprintf(stderr, Name ": size may only be specified once. "
241                                         "Second value is %s.\n", optarg);
242                                 exit(2);
243                         }
244                         size = strtol(optarg, &c, 10);
245                         if (!optarg[0] || *c || size < 4) {
246                                 fprintf(stderr, Name ": invalid size: %s\n",
247                                         optarg);
248                                 exit(2);
249                         }
250                         continue;
251
252                 case O(CREATE,'l'):
253                 case O(BUILD,'l'): /* set raid level*/
254                         if (level != -10) {
255                                 fprintf(stderr, Name ": raid level may only be set once.  "
256                                         "Second value is %s.\n", optarg);
257                                 exit(2);
258                         }
259                         level = map_name(pers, optarg);
260                         if (level == -10) {
261                                 fprintf(stderr, Name ": invalid raid level: %s\n",
262                                         optarg);
263                                 exit(2);
264                         }
265                         if (level != 0 && level != -1 && mode == BUILD) {
266                                 fprintf(stderr, Name ": Raid level %s not permitted with --build.\n",
267                                         optarg);
268                                 exit(2);
269                         }
270                         if (sparedisks > 0 && level < 1 && level >= -1) {
271                                 fprintf(stderr, Name ": raid level %s is incompatible with spare-devices setting.\n",
272                                         optarg);
273                                 exit(2);
274                         }
275                         ident.level = level;
276                         continue;
277
278                 case O(CREATE,'p'): /* raid5 layout */
279                         if (layout >= 0) {
280                                 fprintf(stderr,Name ": layout may only be sent once.  "
281                                         "Second value was %s\n", optarg);
282                                 exit(2);
283                         }
284                         switch(level) {
285                         default:
286                                 fprintf(stderr, Name ": layout not meaningful for %s arrays.\n",
287                                         map_num(pers, level));
288                                 exit(2);
289                         case -10:
290                                 fprintf(stderr, Name ": raid level must be given before layout.\n");
291                                 exit(2);
292
293                         case 5:
294                                 layout = map_name(r5layout, optarg);
295                                 if (layout==-10) {
296                                         fprintf(stderr, Name ": layout %s not understood for raid5.\n",
297                                                 optarg);
298                                         exit(2);
299                                 }
300                                 break;
301                         }
302                         continue;
303
304                 case O(CREATE,'n'):
305                 case O(BUILD,'n'): /* number of raid disks */
306                         if (raiddisks) {
307                                 fprintf(stderr, Name ": raid-devices set twice: %d and %s\n",
308                                         raiddisks, optarg);
309                                 exit(2);
310                         }
311                         raiddisks = strtol(optarg, &c, 10);
312                         if (!optarg[0] || *c || raiddisks<=0 || raiddisks > MD_SB_DISKS) {
313                                 fprintf(stderr, Name ": invalid number of raid devices: %s\n",
314                                         optarg);
315                                 exit(2);
316                         }
317                         ident.raid_disks = raiddisks;
318                         continue;
319
320                 case O(CREATE,'x'): /* number of spare (eXtra) discs */
321                         if (sparedisks) {
322                                 fprintf(stderr,Name ": spare-devices set twice: %d and %s\n",
323                                         sparedisks, optarg);
324                                 exit(2);
325                         }
326                         if (level > -10 && level <= 0 && level >= -1) {
327                                 fprintf(stderr, Name ": spare-devices setting is incompatible with raid level %d\n",
328                                         level);
329                                 exit(2);
330                         }
331                         sparedisks = strtol(optarg, &c, 10);
332                         if (!optarg[0] || *c || sparedisks < 0 || sparedisks > MD_SB_DISKS - raiddisks) {
333                                 fprintf(stderr, Name ": invalid number of spare-devices: %s\n",
334                                         optarg);
335                                 exit(2);
336                         }
337                         continue;
338                 case O(CREATE,'f'): /* force honouring of device list */
339                 case O(ASSEMBLE,'f'): /* force assembly */
340                 case O(MISC,'f'): /* force zero */
341                         force=1;
342                         continue;
343
344                         /* now for the Assemble options */
345                 case O(ASSEMBLE,'u'): /* uuid of array */
346                         if (ident.uuid_set) {
347                                 fprintf(stderr, Name ": uuid cannot be set twice.  "
348                                         "Second value %s.\n", optarg);
349                                 exit(2);
350                         }
351                         if (parse_uuid(optarg, ident.uuid))
352                                 ident.uuid_set = 1;
353                         else {
354                                 fprintf(stderr,Name ": Bad uuid: %s\n", optarg);
355                                 exit(2);
356                         }
357                         continue;
358
359                 case O(ASSEMBLE,'m'): /* super-minor for array */
360                         if (ident.super_minor >= 0) {
361                                 fprintf(stderr, Name ": super-minor cannot be set twice.  "
362                                         "Second value: %s.\n", optarg);
363                                 exit(2);
364                         }
365                         ident.super_minor = strtoul(optarg, &cp, 10);
366                         if (!optarg[0] || *cp) {
367                                 fprintf(stderr, Name ": Bad super-minor number: %s.\n", optarg);
368                                 exit(2);
369                         }
370                         continue;
371
372                 case O(ASSEMBLE,'c'): /* config file */
373                 case O(MISC, 'c'):
374                 case O(MONITOR,'c'):
375                         if (configfile) {
376                                 fprintf(stderr, Name ": configfile cannot be set twice.  "
377                                         "Second value is %s.\n", optarg);
378                                 exit(2);
379                         }
380                         configfile = optarg;
381                         /* FIXME possibly check that config file exists.  Even parse it */
382                         continue;
383                 case O(ASSEMBLE,'s'): /* scan */
384                 case O(MISC,'s'):
385                 case O(MONITOR,'s'):
386                         scan = 1;
387                         continue;
388
389                 case O(MONITOR,'m'): /* mail address */
390                         if (mailaddr)
391                                 fprintf(stderr, Name ": only specify one mailaddress. %s ignored.\n",
392                                         optarg);
393                         else
394                                 mailaddr = optarg;
395                         continue;
396
397                 case O(MONITOR,'p'): /* alert program */
398                         if (program)
399                                 fprintf(stderr, Name ": only specify one alter program. %s ignored.\n",
400                                         optarg);
401                         else
402                                 program = optarg;
403                         continue;
404
405                 case O(MONITOR,'d'): /* delay in seconds */
406                         if (delay)
407                                 fprintf(stderr, Name ": only specify delay once. %s ignored.\n",
408                                         optarg);
409                         else {
410                                 delay = strtol(optarg, &c, 10);
411                                 if (!optarg[0] || *c || delay<1) {
412                                         fprintf(stderr, Name ": invalid delay: %s\n",
413                                                 optarg);
414                                         exit(2);
415                                 }
416                         }
417                         continue;
418                         
419
420                         /* now the general management options.  Some are applicable
421                          * to other modes. None have arguments.
422                          */
423                 case O(MANAGE,'a'):
424                 case O(CREATE,'a'):
425                 case O(BUILD,'a'):
426                 case O(ASSEMBLE,'a'): /* add a drive */
427                         devmode = 'a';
428                         continue;
429                 case O(MANAGE,'r'): /* remove a drive */
430                         devmode = 'r';
431                         continue;
432                 case O(MANAGE,'f'): /* set faulty */
433                         devmode = 'f';
434                         continue;
435                 case O(MANAGE,'R'):
436                 case O(ASSEMBLE,'R'):
437                 case O(BUILD,'R'):
438                 case O(CREATE,'R'): /* Run the array */
439                         if (runstop < 0) {
440                                 fprintf(stderr, Name ": Cannot both Stop and Run an array\n");
441                                 exit(2);
442                         }
443                         runstop = 1;
444                         continue;
445                 case O(MANAGE,'S'):
446                         if (runstop > 0) {
447                                 fprintf(stderr, Name ": Cannot both Run and Stop an array\n");
448                                 exit(2);
449                         }
450                         runstop = -1;
451                         continue;
452
453                 case O(MANAGE,'o'):
454                         if (readonly < 0) {
455                                 fprintf(stderr, Name ": Cannot have both readonly and readwrite\n");
456                                 exit(2);
457                         }
458                         readonly = 1;
459                         continue;
460                 case O(MANAGE,'w'):
461                         if (readonly > 0) {
462                                 fprintf(stderr, Name ": Cannot have both readwrite and readonly.\n");
463                                 exit(2);
464                         }
465                         readonly = -1;
466                         continue;
467
468                 case O(MISC,'Q'):
469                 case O(MISC,'D'):
470                 case O(MISC,'E'):
471                 case O(MISC,'K'):
472                 case O(MISC,'R'):
473                 case O(MISC,'S'):
474                 case O(MISC,'o'):
475                 case O(MISC,'w'):
476                         if (devmode && devmode != opt &&
477                             (devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
478                                 fprintf(stderr, Name ": --examine/-E cannot be given with -%c\n",
479                                         devmode =='E'?opt:devmode);
480                                 exit(2);
481                         }
482                         devmode = opt;
483                         continue;
484
485                 case O(MISC, 22):
486                         if (devmode != 'E') {
487                                 fprintf(stderr, Name ": --sparc2.2 only allowed with --examine\n");
488                                 exit(2);
489                         }
490                         SparcAdjust = 1;
491                         continue;
492                 case O(MISC,23):
493                         if (devmode != 'E') {
494                                 fprintf(stderr, Name ": --sparc2.2update only allowed with --examine\n");
495                                 exit(2);
496                         }
497                         SparcAdjust = 2;
498                         continue;
499                 }
500                 /* We have now processed all the valid options. Anything else is
501                  * an error
502                  */
503                 fprintf(stderr, Name ": option %c not valid in %s mode\n",
504                         opt, map_num(modes, mode));
505                 exit(2);
506
507         }
508
509         if (!mode) {
510                 fputs(Usage, stderr);
511                 exit(2);
512         }
513         /* Ok, got the option parsing out of the way
514          * hopefully it's mostly right but there might be some stuff
515          * missing
516          *
517          * That is mosty checked in the per-mode stuff but...
518          *
519          * For @,B,C  and A without -s, the first device listed must be an md device
520          * we check that here and open it.
521          */
522
523         if (mode==MANAGE || mode == BUILD || mode == CREATE || (mode == ASSEMBLE && ! scan)) {
524                 if (devs_found < 1) {
525                         fprintf(stderr, Name ": an md device must be given in this mode\n");
526                         exit(2);
527                 }
528                 mdfd = open_mddev(devlist->devname);
529                 if (mdfd < 0)
530                         exit(1);
531         }
532
533         rv = 0;
534         switch(mode) {
535         case MANAGE:
536                 /* readonly, add/remove, readwrite, runstop */
537                 if (readonly>0)
538                         rv = Manage_ro(devlist->devname, mdfd, readonly);
539                 if (!rv && devs_found>1)
540                         rv = Manage_subdevs(devlist->devname, mdfd,
541                                             devlist->next);
542                 if (!rv && readonly < 0)
543                         rv = Manage_ro(devlist->devname, mdfd, readonly);
544                 if (!rv && runstop)
545                         rv = Manage_runstop(devlist->devname, mdfd, runstop);
546                 break;
547         case ASSEMBLE:
548                 if (!scan)
549                         rv = Assemble(devlist->devname, mdfd, &ident, configfile,
550                                       devlist->next,
551                                       readonly, runstop, verbose, force);
552                 else if (devs_found>0)
553                         for (dv = devlist ; dv ; dv=dv->next) {
554                                 mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname);
555                                 mdfd = open_mddev(dv->devname);
556                                 if (mdfd < 0) {
557                                         rv |= 1;
558                                         continue;
559                                 }
560                                 if (array_ident == NULL) {
561                                         fprintf(stderr, Name ": %s not identified in config file.\n",
562                                                 dv->devname);
563                                         rv |= 1;
564                                         continue;
565                                 }
566                                 rv |= Assemble(dv->devname, mdfd, array_ident, configfile,
567                                                NULL,
568                                                readonly, runstop, verbose, force);
569                         }
570                 else {
571                         mddev_ident_t array_list =  conf_get_ident(configfile, NULL);
572                         if (!array_list) {
573                                 fprintf(stderr, Name ": No arrays found in config file\n");
574                                 rv = 1;
575                         } else
576                                 for (; array_list; array_list = array_list->next) {
577                                         mdu_array_info_t array;
578                                         mdfd = open_mddev(array_list->devname);
579                                         if (mdfd < 0) {
580                                                 rv |= 1;
581                                                 continue;
582                                         }
583                                         if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0)
584                                                 /* already assembled, skip */
585                                                 continue;
586                                         rv |= Assemble(array_list->devname, mdfd,
587                                                        array_list, configfile,
588                                                        NULL,
589                                                        readonly, runstop, verbose, force);
590                                 }
591                 }
592                 break;
593         case BUILD:
594                 rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next);
595                 break;
596         case CREATE:
597                 rv = Create(devlist->devname, mdfd, chunk, level, layout, size,
598                             raiddisks, sparedisks,
599                             devs_found-1, devlist->next, runstop, verbose, force);
600                 break;
601         case MISC:
602
603                 if (devmode == 'E') {
604                         if (devlist == NULL && !scan) {
605                                 fprintf(stderr, Name ": No devices to examine\n");
606                                 exit(2);
607                         }
608                         if (devlist == NULL)
609                                 devlist = conf_get_devs(configfile);
610                         if (devlist == NULL) {
611                                 fprintf(stderr, Name ": No devices listed in %s\n", configfile?configfile:DefaultConfFile);
612                                 exit(1);
613                         }
614                         rv = Examine(devlist, scan?!verbose:brief, scan, SparcAdjust);
615                 } else {
616                         if (devlist == NULL) {
617                                 if ((devmode == 'S' ||devmode=='D') && scan) {
618                                         /* apply to all devices in /proc/mdstat */
619                                         struct mdstat_ent *ms = mdstat_read();
620                                         struct mdstat_ent *e;
621                                         for (e=ms ; e ; e=e->next) {
622                                                 char *name = get_md_name(e->devnum);
623
624                                                 if (!name) {
625                                                         fprintf(stderr, Name ": cannot find device file for %s\n",
626                                                                 e->dev);
627                                                         continue;
628                                                 }
629                                                 if (devmode == 'D')
630                                                         rv |= Detail(name, !verbose);
631                                                 else if (devmode=='S') {
632                                                         mdfd = open_mddev(name);
633                                                         if (mdfd >= 0)
634                                                                 rv |= Manage_runstop(name, mdfd, -1);
635                                                 }
636                                                 put_md_name(name);
637                                         }
638                                 } else {                                                
639                                         fprintf(stderr, Name ": No devices given.\n");
640                                         exit(2);
641                                 }
642                         }
643                         for (dv=devlist ; dv; dv=dv->next) {
644                                 switch(dv->disposition) {
645                                 case 'D':
646                                         rv |= Detail(dv->devname, brief); continue;
647                                 case 'K': /* Zero superblock */
648                                         rv |= Kill(dv->devname, force); continue;
649                                 case 'Q':
650                                         rv |= Query(dv->devname); continue;
651                                 }
652                                 mdfd = open_mddev(dv->devname);
653                                 if (mdfd>=0)
654                                         switch(dv->disposition) {
655                                         case 'R':
656                                                 rv |= Manage_runstop(dv->devname, mdfd, 1); break;
657                                         case 'S':
658                                                 rv |= Manage_runstop(dv->devname, mdfd, -1); break;
659                                         case 'o':
660                                                 rv |= Manage_ro(dv->devname, mdfd, 1); break;
661                                         case 'w':
662                                                 rv |= Manage_ro(dv->devname, mdfd, -1); break;
663                                         }
664                         }
665                 }
666                 break;
667         case MONITOR:
668 /*
669                 if (!devlist && !scan) {
670                         fprintf(stderr, Name ": Cannot monitor: need --scan or at least one device\n");
671                         rv = 1;
672                         break;
673                 }
674 */              rv= Monitor(devlist, mailaddr, program,
675                             delay?delay:60, scan, configfile);
676                 break;
677         }
678         exit(rv);
679 }