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