2 * mdadm - manage Linux "md" devices aka RAID arrays.
4 * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
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.
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.
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
22 * Email: <neilb@cse.unsw.edu.au>
24 * School of Computer Science and Engineering
25 * The University of New South Wales
33 int open_mddev(char *dev
)
35 int mdfd
= open(dev
, O_RDWR
, 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",
50 int main(int argc
, char *argv
[])
65 struct mddev_ident_s ident
;
66 char *configfile
= NULL
;
72 mddev_dev_t devlist
= NULL
;
73 mddev_dev_t
*devlistend
= & devlist
;
80 char *mailaddr
= NULL
;
88 ident
.raid_disks
= -1;
89 ident
.super_minor
= -1;
92 while ((opt
=getopt_long(argc
, argv
,
93 short_options
, long_options
,
97 case '@': /* just incase they say --manage */
105 /* setting mode - only once */
107 fprintf(stderr
, Name
": --%s/-%c not allowed, mode already set to %s\n",
108 long_options
[opt
-'A'+1].name
,
109 long_options
[opt
-'A'+1].val
,
110 long_options
[mode
-'A'+1].name
);
119 case 'C': help_text
= Help_create
; break;
120 case 'B': help_text
= Help_build
; break;
121 case 'A': help_text
= Help_assemble
; break;
123 fputs(help_text
,stderr
);
127 fputs(Version
, stderr
);
130 case 'v': verbose
= 1;
136 case 1: /* an undecorated option - must be a device name.
137 * Depending on mode, it could be that:
138 * All devices listed are "md" devices : --Detail, -As
139 * No devices are "md" devices : --Examine
140 * First device is "md", others are component: -A,-B,-C
141 * Only accept on device before mode is determined.
142 * If mode is @, then require devmode for other devices.
144 if (devs_found
> 0 && !mode
) {
145 fprintf(stderr
, Name
": Must give mode flag before second device name at %s\n", optarg
);
148 if (devs_found
> 0 && mode
== '@' && !devmode
) {
149 fprintf(stderr
, Name
": Must give on of -a/-r/-f for subsequent devices at %s\n", optarg
);
152 dv
= malloc(sizeof(*dv
));
154 fprintf(stderr
, Name
": malloc failed\n");
157 dv
->devname
= optarg
;
158 dv
->disposition
= devmode
;
161 devlistend
= &dv
->next
;
168 fputs(Usage
, stderr
);
171 /* force mode setting - @==manage if nothing else */
172 if (!mode
) mode
= '@';
175 /* We've got a mode, and opt is now something else which
176 * could depend on the mode */
177 #define O(a,b) ((a<<8)|b)
178 switch (O(mode
,opt
)) {
180 case O('B','c'): /* chunk or rounding */
182 fprintf(stderr
, Name
": chunk/rounding may only be specified once. "
183 "Second value is %s.\n", optarg
);
186 chunk
= strtol(optarg
, &c
, 10);
187 if (!optarg
[0] || *c
|| chunk
<4 || ((chunk
-1)&chunk
)) {
188 fprintf(stderr
, Name
": invalid chunk/rounding value: %s\n",
194 case O('C','z'): /* size */
196 fprintf(stderr
, Name
": size may only be specified once. "
197 "Second value is %s.\n", optarg
);
200 size
= strtol(optarg
, &c
, 10);
201 if (!optarg
[0] || *c
|| size
< 4) {
202 fprintf(stderr
, Name
": invalid size: %s\n",
209 case O('B','l'): /* set raid level*/
211 fprintf(stderr
, Name
": raid level may only be set once. "
212 "Second value is %s.\n", optarg
);
215 level
= map_name(pers
, optarg
);
217 fprintf(stderr
, Name
": invalid raid level: %s\n",
221 if (level
> 0 && mode
== 'B') {
222 fprintf(stderr
, Name
": Raid level %s not permitted with --build.\n",
226 if (sparedisks
> 0 && level
< 1) {
227 fprintf(stderr
, Name
": raid level %s is incompatible with spare-disks setting.\n",
234 case O('C','p'): /* raid5 layout */
236 fprintf(stderr
,Name
": layout may only be sent once. "
237 "Second value was %s\n", optarg
);
242 fprintf(stderr
, Name
": layout not meaningful for %s arrays.\n",
243 map_num(pers
, level
));
246 fprintf(stderr
, Name
": raid level must be given before layout.\n");
250 layout
= map_name(r5layout
, optarg
);
252 fprintf(stderr
, Name
": layout %s not understood for raid5.\n",
261 case O('B','n'): /* number of raid disks */
263 fprintf(stderr
, Name
": raid-disks set twice: %d and %s\n",
267 raiddisks
= strtol(optarg
, &c
, 10);
268 if (!optarg
[0] || *c
|| raiddisks
<=0 || raiddisks
> MD_SB_DISKS
) {
269 fprintf(stderr
, Name
": invalid number of raid disks: %s\n",
273 ident
.raid_disks
= raiddisks
;
276 case O('C','x'): /* number of spare (eXtra) discs */
278 fprintf(stderr
,Name
": spare-disks set twice: %d and %s\n",
282 if (level
> -10 && level
< 1) {
283 fprintf(stderr
, Name
": spare-disks setting is incompatible with raid level %d\n",
287 sparedisks
= strtol(optarg
, &c
, 10);
288 if (!optarg
[0] || *c
|| sparedisks
< 0 || sparedisks
> MD_SB_DISKS
- raiddisks
) {
289 fprintf(stderr
, Name
": invalid number of spare disks: %s\n",
294 case O('C','f'): /* force honouring of device list */
295 case O('A','f'): /* force assembly */
296 case O('H','f'): /* force zero */
300 /* now for the Assemble options */
301 case O('A','u'): /* uuid of array */
302 if (ident
.uuid_set
) {
303 fprintf(stderr
, Name
": uuid cannot be set twice. "
304 "Second value %s.\n", optarg
);
307 if (parse_uuid(optarg
, ident
.uuid
))
310 fprintf(stderr
,Name
": Bad uuid: %s\n", optarg
);
315 case O('A','m'): /* super-minor for array */
316 if (ident
.super_minor
>= 0) {
317 fprintf(stderr
, Name
": super-minor cannot be set twice. "
318 "Second value: %s.\n", optarg
);
321 ident
.super_minor
= strtoul(optarg
, &cp
, 10);
322 if (!optarg
[0] || *cp
) {
323 fprintf(stderr
, Name
": Bad super-minor number: %s.\n", optarg
);
328 case O('A','c'): /* config file */
331 fprintf(stderr
, Name
": configfile cannot be set twice. "
332 "Second value is %s.\n", optarg
);
336 /* FIXME possibly check that config file exists. Even parse it */
338 case O('A','s'): /* scan */
343 case O('F','m'): /* mail address */
345 fprintf(stderr
, Name
": only specify one mailaddress. %s ignored.\n",
351 case O('F','p'): /* alert program */
353 fprintf(stderr
, Name
": only specify one alter program. %s ignored.\n",
359 case O('F','d'): /* delay in seconds */
361 fprintf(stderr
, Name
": only specify delay once. %s ignored.\n",
364 delay
= strtol(optarg
, &c
, 10);
365 if (!optarg
[0] || *c
|| delay
<1) {
366 fprintf(stderr
, Name
": invalid delay: %s\n",
374 /* now the general management options. Some are applicable
375 * to other modes. None have arguments.
380 case O('A','a'): /* add a drive */
383 case O('@','r'): /* remove a drive */
386 case O('@','f'): /* set faulty */
392 case O('C','R'): /* Run the array */
394 fprintf(stderr
, Name
": Cannot both Stop and Run an array\n");
401 fprintf(stderr
, Name
": Cannot both Run and Stop an array\n");
409 fprintf(stderr
, Name
": Cannot have both readonly and readwrite\n");
416 fprintf(stderr
, "mkdctl: Cannot have both readwrite and readonly.\n");
422 /* We have now processed all the valid options. Anything else is
425 fprintf(stderr
, Name
": option %c not valid in mode %c\n",
432 fputs(Usage
, stderr
);
435 /* Ok, got the option parsing out of the way
436 * hopefully it's mostly right but there might be some stuff
439 * That is mosty checked in ther per-mode stuff but...
441 * For @,B,C and A without -s, the first device listed must be an md device
442 * we check that here and open it.
445 if (mode
=='@' || mode
== 'B' || mode
== 'C' || (mode
== 'A' && ! scan
)) {
446 if (devs_found
< 1) {
447 fprintf(stderr
, Name
": an md device must be given in this mode\n");
450 mdfd
= open_mddev(devlist
->devname
);
458 case '@':/* Management */
459 /* readonly, add/remove, readwrite, runstop */
461 rv
= Manage_ro(devlist
->devname
, mdfd
, readonly
);
462 if (!rv
&& devs_found
>1)
463 rv
= Manage_subdevs(devlist
->devname
, mdfd
,
465 if (!rv
&& readonly
< 0)
466 rv
= Manage_ro(devlist
->devname
, mdfd
, readonly
);
468 rv
= Manage_runstop(devlist
->devname
, mdfd
, runstop
);
470 case 'A': /* Assemble */
472 rv
= Assemble(devlist
->devname
, mdfd
, &ident
, configfile
,
474 readonly
, runstop
, verbose
, force
);
475 else if (devs_found
>0)
476 for (dv
= devlist
; dv
; dv
=dv
->next
) {
477 mddev_ident_t array_ident
= conf_get_ident(configfile
, dv
->devname
);
478 mdfd
= open_mddev(dv
->devname
);
483 if (array_ident
== NULL
) {
484 fprintf(stderr
, Name
": %s not identified in config file.\n",
489 rv
|= Assemble(dv
->devname
, mdfd
, array_ident
, configfile
,
491 readonly
, runstop
, verbose
, force
);
494 mddev_ident_t array_list
= conf_get_ident(configfile
, NULL
);
496 fprintf(stderr
, Name
": No arrays found in config file\n");
499 for (; array_list
; array_list
= array_list
->next
) {
500 mdu_array_info_t array
;
501 mdfd
= open_mddev(array_list
->devname
);
506 if (ioctl(mdfd
, GET_ARRAY_INFO
, &array
)>=0)
507 /* already assembled, skip */
509 rv
|= Assemble(array_list
->devname
, mdfd
,
510 array_list
, configfile
,
512 readonly
, runstop
, verbose
, force
);
516 case 'B': /* Build */
517 rv
= Build(devlist
->devname
, mdfd
, chunk
, level
, raiddisks
, devlist
->next
);
519 case 'C': /* Create */
520 rv
= Create(devlist
->devname
, mdfd
, chunk
, level
, layout
, size
,
521 raiddisks
, sparedisks
,
522 devs_found
-1, devlist
->next
, runstop
, verbose
, force
);
524 case 'D': /* Detail */
525 for (dv
=devlist
; dv
; dv
=dv
->next
)
526 rv
|= Detail(dv
->devname
, brief
);
528 case 'E': /* Examine */
529 if (devlist
== NULL
&& scan
==0) {
530 fprintf(stderr
, Name
": No devices to examine\n");
533 rv
= Examine(devlist
, devlist
?brief
:!verbose
, configfile
);
535 case 'F': /* Follow */
536 rv
= Monitor(devlist
, mailaddr
, program
,
537 delay
?delay
:60, configfile
);
539 case 'H': /* Zero superblock */
540 for (dv
=devlist
; dv
; dv
=dv
->next
)
541 rv
|= Kill(dv
->devname
, force
);