]> git.ipfire.org Git - thirdparty/mdadm.git/blame_incremental - mdadm.c
mdadm-1.0.0
[thirdparty/mdadm.git] / mdadm.c
... / ...
CommitLineData
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
33int 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
50int 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-devices 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-devices 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 devices: %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-devices 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-devices 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-devices: %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(MISC, 'c'):
373 case O(MONITOR,'c'):
374 if (configfile) {
375 fprintf(stderr, Name ": configfile cannot be set twice. "
376 "Second value is %s.\n", optarg);
377 exit(2);
378 }
379 configfile = optarg;
380 /* FIXME possibly check that config file exists. Even parse it */
381 continue;
382 case O(ASSEMBLE,'s'): /* scan */
383 case O(MISC,'s'):
384 case O(MONITOR,'s'):
385 scan = 1;
386 continue;
387
388 case O(MONITOR,'m'): /* mail address */
389 if (mailaddr)
390 fprintf(stderr, Name ": only specify one mailaddress. %s ignored.\n",
391 optarg);
392 else
393 mailaddr = optarg;
394 continue;
395
396 case O(MONITOR,'p'): /* alert program */
397 if (program)
398 fprintf(stderr, Name ": only specify one alter program. %s ignored.\n",
399 optarg);
400 else
401 program = optarg;
402 continue;
403
404 case O(MONITOR,'d'): /* delay in seconds */
405 if (delay)
406 fprintf(stderr, Name ": only specify delay once. %s ignored.\n",
407 optarg);
408 else {
409 delay = strtol(optarg, &c, 10);
410 if (!optarg[0] || *c || delay<1) {
411 fprintf(stderr, Name ": invalid delay: %s\n",
412 optarg);
413 exit(2);
414 }
415 }
416 continue;
417
418
419 /* now the general management options. Some are applicable
420 * to other modes. None have arguments.
421 */
422 case O(MANAGE,'a'):
423 case O(CREATE,'a'):
424 case O(BUILD,'a'):
425 case O(ASSEMBLE,'a'): /* add a drive */
426 devmode = 'a';
427 continue;
428 case O(MANAGE,'r'): /* remove a drive */
429 devmode = 'r';
430 continue;
431 case O(MANAGE,'f'): /* set faulty */
432 devmode = 'f';
433 continue;
434 case O(MANAGE,'R'):
435 case O(ASSEMBLE,'R'):
436 case O(BUILD,'R'):
437 case O(CREATE,'R'): /* Run the array */
438 if (runstop < 0) {
439 fprintf(stderr, Name ": Cannot both Stop and Run an array\n");
440 exit(2);
441 }
442 runstop = 1;
443 continue;
444 case O(MANAGE,'S'):
445 if (runstop > 0) {
446 fprintf(stderr, Name ": Cannot both Run and Stop an array\n");
447 exit(2);
448 }
449 runstop = -1;
450 continue;
451
452 case O(MANAGE,'o'):
453 if (readonly < 0) {
454 fprintf(stderr, Name ": Cannot have both readonly and readwrite\n");
455 exit(2);
456 }
457 readonly = 1;
458 continue;
459 case O(MANAGE,'w'):
460 if (readonly > 0) {
461 fprintf(stderr, Name ": Cannot have both readwrite and readonly.\n");
462 exit(2);
463 }
464 readonly = -1;
465 continue;
466
467 case O(MISC,'Q'):
468 case O(MISC,'D'):
469 case O(MISC,'E'):
470 case O(MISC,'K'):
471 case O(MISC,'R'):
472 case O(MISC,'S'):
473 case O(MISC,'o'):
474 case O(MISC,'w'):
475 if (devmode && devmode != opt &&
476 (devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
477 fprintf(stderr, Name ": --examine/-E cannot be given with -%c\n",
478 devmode =='E'?opt:devmode);
479 exit(2);
480 }
481 devmode = opt;
482 continue;
483
484 }
485 /* We have now processed all the valid options. Anything else is
486 * an error
487 */
488 fprintf(stderr, Name ": option %c not valid in %s mode\n",
489 opt, map_num(modes, mode));
490 exit(2);
491
492 }
493
494 if (!mode) {
495 fputs(Usage, stderr);
496 exit(2);
497 }
498 /* Ok, got the option parsing out of the way
499 * hopefully it's mostly right but there might be some stuff
500 * missing
501 *
502 * That is mosty checked in the per-mode stuff but...
503 *
504 * For @,B,C and A without -s, the first device listed must be an md device
505 * we check that here and open it.
506 */
507
508 if (mode==MANAGE || mode == BUILD || mode == CREATE || (mode == ASSEMBLE && ! scan)) {
509 if (devs_found < 1) {
510 fprintf(stderr, Name ": an md device must be given in this mode\n");
511 exit(2);
512 }
513 mdfd = open_mddev(devlist->devname);
514 if (mdfd < 0)
515 exit(1);
516 }
517
518 rv = 0;
519 switch(mode) {
520 case MANAGE:
521 /* readonly, add/remove, readwrite, runstop */
522 if (readonly>0)
523 rv = Manage_ro(devlist->devname, mdfd, readonly);
524 if (!rv && devs_found>1)
525 rv = Manage_subdevs(devlist->devname, mdfd,
526 devlist->next);
527 if (!rv && readonly < 0)
528 rv = Manage_ro(devlist->devname, mdfd, readonly);
529 if (!rv && runstop)
530 rv = Manage_runstop(devlist->devname, mdfd, runstop);
531 break;
532 case ASSEMBLE:
533 if (!scan)
534 rv = Assemble(devlist->devname, mdfd, &ident, configfile,
535 devlist->next,
536 readonly, runstop, verbose, force);
537 else if (devs_found>0)
538 for (dv = devlist ; dv ; dv=dv->next) {
539 mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname);
540 mdfd = open_mddev(dv->devname);
541 if (mdfd < 0) {
542 rv |= 1;
543 continue;
544 }
545 if (array_ident == NULL) {
546 fprintf(stderr, Name ": %s not identified in config file.\n",
547 dv->devname);
548 rv |= 1;
549 continue;
550 }
551 rv |= Assemble(dv->devname, mdfd, array_ident, configfile,
552 NULL,
553 readonly, runstop, verbose, force);
554 }
555 else {
556 mddev_ident_t array_list = conf_get_ident(configfile, NULL);
557 if (!array_list) {
558 fprintf(stderr, Name ": No arrays found in config file\n");
559 rv = 1;
560 } else
561 for (; array_list; array_list = array_list->next) {
562 mdu_array_info_t array;
563 mdfd = open_mddev(array_list->devname);
564 if (mdfd < 0) {
565 rv |= 1;
566 continue;
567 }
568 if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0)
569 /* already assembled, skip */
570 continue;
571 rv |= Assemble(array_list->devname, mdfd,
572 array_list, configfile,
573 NULL,
574 readonly, runstop, verbose, force);
575 }
576 }
577 break;
578 case BUILD:
579 rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next);
580 break;
581 case CREATE:
582 rv = Create(devlist->devname, mdfd, chunk, level, layout, size,
583 raiddisks, sparedisks,
584 devs_found-1, devlist->next, runstop, verbose, force);
585 break;
586 case MISC:
587
588 if (devmode == 'E') {
589 if (devlist == NULL && !scan) {
590 fprintf(stderr, Name ": No devices to examine\n");
591 exit(2);
592 }
593 if (devlist == NULL)
594 devlist = conf_get_devs(configfile);
595 if (devlist == NULL) {
596 fprintf(stderr, Name ": No devices listed in %s\n", configfile?configfile:DefaultConfFile);
597 exit(1);
598 }
599 rv = Examine(devlist, scan?!verbose:brief, scan);
600 } else {
601 if (devlist == NULL) {
602 if ((devmode == 'S' ||devmode=='D') && scan) {
603 /* apply to all devices in /proc/mdstat */
604 struct mdstat_ent *ms = mdstat_read();
605 struct mdstat_ent *e;
606 for (e=ms ; e ; e=e->next) {
607 char *name = get_md_name(e->devnum);
608
609 if (!name) {
610 fprintf(stderr, Name ": cannot find device file for %s\n",
611 e->dev);
612 continue;
613 }
614 if (devmode == 'D')
615 rv |= Detail(name, !verbose);
616 else if (devmode=='S') {
617 mdfd = open_mddev(name);
618 if (mdfd >= 0)
619 rv |= Manage_runstop(name, mdfd, -1);
620 }
621 put_md_name(name);
622 }
623 } else {
624 fprintf(stderr, Name ": No devices given.\n");
625 exit(2);
626 }
627 }
628 for (dv=devlist ; dv; dv=dv->next) {
629 switch(dv->disposition) {
630 case 'D':
631 rv |= Detail(dv->devname, brief); continue;
632 case 'K': /* Zero superblock */
633 rv |= Kill(dv->devname, force); continue;
634 case 'Q':
635 rv |= Query(dv->devname); continue;
636 }
637 mdfd = open_mddev(dv->devname);
638 if (mdfd>=0)
639 switch(dv->disposition) {
640 case 'R':
641 rv |= Manage_runstop(dv->devname, mdfd, 1); break;
642 case 'S':
643 rv |= Manage_runstop(dv->devname, mdfd, -1); break;
644 case 'o':
645 rv |= Manage_ro(dv->devname, mdfd, 1); break;
646 case 'w':
647 rv |= Manage_ro(dv->devname, mdfd, -1); break;
648 }
649 }
650 }
651 break;
652 case MONITOR:
653/*
654 if (!devlist && !scan) {
655 fprintf(stderr, Name ": Cannot monitor: need --scan or at least one device\n");
656 rv = 1;
657 break;
658 }
659*/ rv= Monitor(devlist, mailaddr, program,
660 delay?delay:60, scan, configfile);
661 break;
662 }
663 exit(rv);
664}