]> git.ipfire.org Git - thirdparty/mdadm.git/blame - mdadm.c
Create parse_num() function.
[thirdparty/mdadm.git] / mdadm.c
CommitLineData
64c4757e 1/*
9a9dab36 2 * mdadm - manage Linux "md" devices aka RAID arrays.
64c4757e 3 *
18361a1a 4 * Copyright (C) 2001-2012 Neil Brown <neilb@suse.de>
64c4757e
NB
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
e736b623 22 * Email: <neilb@suse.de>
c82f047c 23 *
aba69144 24 * Additions for bitmap and write-behind RAID options, Copyright (C) 2003-2004,
c82f047c 25 * Paul Clements, SteelEye Technology, Inc.
64c4757e
NB
26 */
27
9a9dab36 28#include "mdadm.h"
64c4757e 29#include "md_p.h"
dd0781e5 30#include <ctype.h>
64c4757e 31
3cbc4d12
N
32
33static int scan_assemble(int autof, struct supertype *ss,
34 int readonly, int runstop,
35 struct mddev_ident *ident,
36 char *homehost, int require_homehost,
37 int verbose, int force,
38 int freeze_reshape);
7d27d1c0
N
39static int misc_scan(char devmode, int verbose, int export, int test,
40 char *homehost, char *prefer);
41static int stop_scan(int quiet);
42static int misc_list(struct mddev_dev *devlist,
43 int brief, int verbose, int export, int test,
44 char *homehost, char *prefer, char *subarray,
45 char *update, struct mddev_ident *ident,
46 struct supertype *ss, int force, int quiet);
47
3cbc4d12 48
52826846
NB
49int main(int argc, char *argv[])
50{
e0d19036 51 int mode = 0;
52826846 52 int opt;
e0d19036 53 int option_index;
52826846 54 int rv;
f9ce90ba 55 int i;
52826846
NB
56
57 int chunk = 0;
5dd497ee 58 long long size = -1;
84e11361 59 long long array_size = -1;
98c6faba
NB
60 int level = UnSet;
61 int layout = UnSet;
19678e53 62 char *layout_str = NULL;
52826846
NB
63 int raiddisks = 0;
64 int sparedisks = 0;
fa56eddb 65 struct mddev_ident ident;
52826846 66 char *configfile = NULL;
5787fa49 67 char *update = NULL;
52826846 68 int scan = 0;
1c7a808c 69 int devmode = 0;
52826846
NB
70 int runstop = 0;
71 int readonly = 0;
dfd4d8ee 72 int write_behind = 0;
c82f047c
NB
73 int bitmap_fd = -1;
74 char *bitmap_file = NULL;
06b0d786 75 char *backup_file = NULL;
87f26d14 76 int invalid_backup = 0;
c82f047c 77 int bitmap_chunk = UnSet;
bd526cee 78 int SparcAdjust = 0;
a655e550
N
79 struct mddev_dev *devlist = NULL;
80 struct mddev_dev **devlistend = & devlist;
81 struct mddev_dev *dv;
52826846
NB
82 int devs_found = 0;
83 int verbose = 0;
dab6685f 84 int quiet = 0;
cd29a5c8 85 int brief = 0;
52826846 86 int force = 0;
feb716e9 87 int test = 0;
54bad364 88 int export = 0;
dd0781e5 89 int assume_clean = 0;
c2ecf5f6 90 char *prefer = NULL;
38098016 91 char *symlinks = NULL;
2dddadb0 92 int grow_continue = 0;
f1ae21c4
NB
93 /* autof indicates whether and how to create device node.
94 * bottom 3 bits are style. Rest (when shifted) are number of parts
95 * 0 - unset
96 * 1 - don't create (no)
97 * 2 - if is_standard, then create (yes)
98 * 3 - create as 'md' - reject is_standard mdp (md)
99 * 4 - create as 'mdp' - reject is_standard md (mdp)
100 * 5 - default to md if not is_standard (md in config file)
101 * 6 - default to mdp if not is_standard (part, or mdp in config file)
102 */
103 int autof = 0;
52826846 104
997aed5d 105 char *homehost = NULL;
05697ec1 106 char sys_hostname[256];
0ac91628 107 int require_homehost = 1;
52826846
NB
108 char *mailaddr = NULL;
109 char *program = NULL;
9a36a9b7 110 int increments = 20;
52826846 111 int delay = 0;
d013a55e 112 int daemonise = 0;
b5e64645 113 char *pidfile = NULL;
aa88f531 114 int oneshot = 0;
edde9560 115 int spare_sharing = 1;
82d9eba6 116 struct supertype *ss = NULL;
dfd4d8ee 117 int writemostly = 0;
c06487ce 118 char *shortopt = short_options;
773135f5 119 int dosyslog = 0;
8382f19b 120 int rebuild_map = 0;
33414a01 121 char *subarray = NULL;
950bc344 122 char *remove_path = NULL;
20b60dcd 123 char *udev_filename = NULL;
52826846 124
3d4064cc 125 int print_help = 0;
0047d254 126 FILE *outf;
e5329c37 127
52826846
NB
128 int mdfd = -1;
129
b76b30e0
AK
130 int freeze_reshape = 0;
131
dfe47e00
NB
132 srandom(time(0) ^ getpid());
133
52826846 134 ident.uuid_set=0;
98c6faba
NB
135 ident.level = UnSet;
136 ident.raid_disks = UnSet;
137 ident.super_minor= UnSet;
52826846 138 ident.devices=0;
a75f2fbc
NB
139 ident.spare_group = NULL;
140 ident.autof = 0;
a825febc 141 ident.st = NULL;
c82f047c 142 ident.bitmap_fd = -1;
7ef02d01 143 ident.bitmap_file = NULL;
947fd4dd 144 ident.name[0] = 0;
aef35714
N
145 ident.container = NULL;
146 ident.member = NULL;
52826846 147
e0d19036
NB
148 while ((option_index = -1) ,
149 (opt=getopt_long(argc, argv,
c06487ce 150 shortopt, long_options,
e0d19036
NB
151 &option_index)) != -1) {
152 int newmode = mode;
35904960 153 /* firstly, some mode-independent options */
52826846 154 switch(opt) {
1c7a808c
N
155 case HelpOptions:
156 print_help = 2;
157 continue;
52826846 158 case 'h':
1c7a808c 159 print_help = 1;
3d4064cc 160 continue;
52826846
NB
161
162 case 'V':
163 fputs(Version, stderr);
164 exit(0);
165
22892d56 166 case 'v': verbose++;
52826846
NB
167 continue;
168
dab6685f
NB
169 case 'q': quiet++;
170 continue;
171
c82f047c 172 case 'b':
1c7a808c
N
173 if (mode == ASSEMBLE || mode == BUILD || mode == CREATE
174 || mode == GROW || mode == INCREMENTAL
175 || mode == MANAGE)
c82f047c 176 break; /* b means bitmap */
1c7a808c 177 case Brief:
c82f047c 178 brief = 1;
cd29a5c8
NB
179 continue;
180
54bad364
KS
181 case 'Y': export++;
182 continue;
183
997aed5d 184 case HomeHost:
0ac91628
N
185 if (strcasecmp(optarg, "<ignore>") == 0)
186 require_homehost = 0;
187 else
188 homehost = optarg;
997aed5d
NB
189 continue;
190
08ca2adf
JS
191 /*
192 * --offroot sets first char of argv[0] to @. This is used
18361a1a 193 * by systemd to signal that the task was launched from
08ca2adf
JS
194 * initrd/initramfs and should be preserved during shutdown
195 */
196 case OffRootOpt:
197 argv[0][0] = '@';
a0963a86 198 __offroot = 1;
08ca2adf
JS
199 continue;
200
c2ecf5f6
N
201 case Prefer:
202 if (prefer)
203 free(prefer);
204 if (asprintf(&prefer, "/%s/", optarg) <= 0)
205 prefer = NULL;
206 continue;
207
e0d19036
NB
208 case ':':
209 case '?':
210 fputs(Usage, stderr);
211 exit(2);
212 }
213 /* second, figure out the mode.
214 * Some options force the mode. Others
aba69144 215 * set the mode if it isn't already
e0d19036
NB
216 */
217
218 switch(opt) {
1c7a808c 219 case ManageOpt:
c06487ce 220 newmode = MANAGE;
024768c4 221 shortopt = short_bitmap_options;
c06487ce 222 break;
e0d19036 223 case 'a':
1c7a808c 224 case Add:
e0d19036 225 case 'r':
1c7a808c 226 case Remove:
e0d19036 227 case 'f':
1c7a808c 228 case Fail:
41a3b72a 229 case ReAdd: /* re-add */
c06487ce
NB
230 if (!mode) {
231 newmode = MANAGE;
024768c4 232 shortopt = short_bitmap_options;
c06487ce 233 }
0320ea45 234 break;
e0d19036 235
18361a1a
N
236 case 'A': newmode = ASSEMBLE;
237 shortopt = short_bitmap_auto_options;
238 break;
239 case 'B': newmode = BUILD;
240 shortopt = short_bitmap_auto_options;
241 break;
242 case 'C': newmode = CREATE;
243 shortopt = short_bitmap_auto_options;
244 break;
245 case 'F': newmode = MONITOR;
246 break;
024768c4
DL
247 case 'G': newmode = GROW;
248 shortopt = short_bitmap_options;
249 break;
95b79df0 250 case 'I': newmode = INCREMENTAL;
18361a1a
N
251 shortopt = short_bitmap_auto_options;
252 break;
1f48664b 253 case AutoDetect:
5a53aeec
JS
254 newmode = AUTODETECT;
255 break;
e0d19036 256
1c7a808c 257 case MiscOpt:
e0d19036
NB
258 case 'D':
259 case 'E':
c82f047c 260 case 'X':
5a53aeec
JS
261 case 'Q':
262 newmode = MISC;
263 break;
264
e0d19036
NB
265 case 'R':
266 case 'S':
267 case 'o':
268 case 'w':
b90c0e9a 269 case 'W':
1c7a808c 270 case WaitOpt:
1770662b 271 case Waitclean:
4cce4069 272 case DetailPlatform:
33414a01 273 case KillSubarray:
aa534678 274 case UpdateSubarray:
20b60dcd 275 case UdevRules:
f7d3febc 276 case KillOpt:
5a53aeec
JS
277 if (!mode)
278 newmode = MISC;
279 break;
280
281 case NoSharing:
282 newmode = MONITOR;
283 break;
e0d19036
NB
284 }
285 if (mode && newmode == mode) {
286 /* everybody happy ! */
287 } else if (mode && newmode != mode) {
288 /* not allowed.. */
e7b84f9d 289 pr_err("");
e0d19036
NB
290 if (option_index >= 0)
291 fprintf(stderr, "--%s", long_options[option_index].name);
292 else
293 fprintf(stderr, "-%c", opt);
e6b64cd0 294 fprintf(stderr, " would set mdadm mode to \"%s\", but it is already set to \"%s\".\n",
e0d19036
NB
295 map_num(modes, newmode),
296 map_num(modes, mode));
297 exit(2);
298 } else if (!mode && newmode) {
299 mode = newmode;
dec18cae 300 if (mode == MISC && devs_found) {
e7b84f9d 301 pr_err("No action given for %s in --misc mode\n",
dec18cae
N
302 devlist->devname);
303 fprintf(stderr," Action options must come before device names\n");
304 exit(2);
305 }
e0d19036
NB
306 } else {
307 /* special case of -c --help */
1c7a808c 308 if ((opt == 'c' || opt == ConfigFile) &&
e0d19036
NB
309 ( strncmp(optarg, "--h", 3)==0 ||
310 strncmp(optarg, "-h", 2)==0)) {
0047d254 311 fputs(Help_config, stdout);
e0d19036 312 exit(0);
cd29a5c8 313 }
0320ea45
NB
314
315 /* If first option is a device, don't force the mode yet */
316 if (opt == 1) {
317 if (devs_found == 0) {
503975b9 318 dv = xmalloc(sizeof(*dv));
0320ea45
NB
319 dv->devname = optarg;
320 dv->disposition = devmode;
dfd4d8ee 321 dv->writemostly = writemostly;
da6b5ca9 322 dv->used = 0;
0320ea45
NB
323 dv->next = NULL;
324 *devlistend = dv;
325 devlistend = &dv->next;
aba69144 326
0320ea45
NB
327 devs_found++;
328 continue;
329 }
330 /* No mode yet, and this is the second device ... */
e7b84f9d 331 pr_err("An option must be given to set the mode before a second device\n"
a1331cc4 332 " (%s) is listed\n", optarg);
0320ea45
NB
333 exit(2);
334 }
e0d19036 335 if (option_index >= 0)
e7b84f9d 336 pr_err("--%s", long_options[option_index].name);
e0d19036 337 else
e7b84f9d 338 pr_err("-%c", opt);
0320ea45 339 fprintf(stderr, " does not set the mode, and so cannot be the first option.\n");
e0d19036
NB
340 exit(2);
341 }
342
343 /* if we just set the mode, then done */
344 switch(opt) {
1c7a808c
N
345 case ManageOpt:
346 case MiscOpt:
e0d19036
NB
347 case 'A':
348 case 'B':
349 case 'C':
350 case 'F':
dd0781e5 351 case 'G':
8382f19b 352 case 'I':
1f48664b 353 case AutoDetect:
e0d19036
NB
354 continue;
355 }
356 if (opt == 1) {
357 /* an undecorated option - must be a device name.
358 */
1c7a808c 359 if (devs_found > 0 && mode == MANAGE && !devmode) {
e7b84f9d 360 pr_err("Must give one of -a/-r/-f"
1c7a808c 361 " for subsequent devices at %s\n", optarg);
52826846
NB
362 exit(2);
363 }
1c7a808c 364 if (devs_found > 0 && mode == GROW && !devmode) {
e7b84f9d
N
365 pr_err("Must give -a/--add for"
366 " devices to add: %s\n", optarg);
e5329c37
NB
367 exit(2);
368 }
503975b9 369 dv = xmalloc(sizeof(*dv));
cd29a5c8
NB
370 dv->devname = optarg;
371 dv->disposition = devmode;
dfd4d8ee 372 dv->writemostly = writemostly;
9008ed1c 373 dv->used = 0;
cd29a5c8
NB
374 dv->next = NULL;
375 *devlistend = dv;
376 devlistend = &dv->next;
aba69144 377
52826846
NB
378 devs_found++;
379 continue;
682c7051 380 }
682c7051 381
52826846
NB
382 /* We've got a mode, and opt is now something else which
383 * could depend on the mode */
1c7a808c 384#define O(a,b) ((a<<16)|b)
52826846 385 switch (O(mode,opt)) {
7236ee7a 386 case O(GROW,'c'):
1c7a808c 387 case O(GROW,ChunkSize):
e0d19036 388 case O(CREATE,'c'):
1c7a808c 389 case O(CREATE,ChunkSize):
e0d19036 390 case O(BUILD,'c'): /* chunk or rounding */
1c7a808c 391 case O(BUILD,ChunkSize): /* chunk or rounding */
52826846 392 if (chunk) {
e7b84f9d 393 pr_err("chunk/rounding may only be specified once. "
52826846
NB
394 "Second value is %s.\n", optarg);
395 exit(2);
396 }
36fad8ec 397 chunk = parse_size(optarg);
a252c078 398 if (chunk < 8 || (chunk&1)) {
e7b84f9d 399 pr_err("invalid chunk/rounding value: %s\n",
52826846
NB
400 optarg);
401 exit(2);
402 }
a252c078 403 /* Convert sectors to K */
36fad8ec 404 chunk /= 2;
52826846 405 continue;
64c4757e 406
8382f19b 407 case O(INCREMENTAL, 'e'):
f9ce90ba
NB
408 case O(CREATE,'e'):
409 case O(ASSEMBLE,'e'):
410 case O(MISC,'e'): /* set metadata (superblock) information */
411 if (ss) {
e7b84f9d 412 pr_err("metadata information already given\n");
f9ce90ba
NB
413 exit(2);
414 }
aba69144 415 for(i=0; !ss && superlist[i]; i++)
82d9eba6
NB
416 ss = superlist[i]->match_metadata_desc(optarg);
417
f9ce90ba 418 if (!ss) {
e7b84f9d 419 pr_err("unrecognised metadata identifier: %s\n", optarg);
f9ce90ba
NB
420 exit(2);
421 }
422 continue;
423
dfd4d8ee 424 case O(MANAGE,'W'):
1c7a808c 425 case O(MANAGE,WriteMostly):
dfd4d8ee 426 case O(BUILD,'W'):
1c7a808c 427 case O(BUILD,WriteMostly):
dfd4d8ee 428 case O(CREATE,'W'):
1c7a808c 429 case O(CREATE,WriteMostly):
dfd4d8ee
NB
430 /* set write-mostly for following devices */
431 writemostly = 1;
432 continue;
433
b3d31955
N
434 case O(MANAGE,'w'):
435 /* clear write-mostly for following devices */
436 writemostly = 2;
437 continue;
438
439
dd0781e5 440 case O(GROW,'z'):
25affb56
PC
441 case O(CREATE,'z'):
442 case O(BUILD,'z'): /* size */
dd0781e5 443 if (size >= 0) {
e7b84f9d 444 pr_err("size may only be specified once. "
52826846
NB
445 "Second value is %s.\n", optarg);
446 exit(2);
447 }
dd0781e5
NB
448 if (strcmp(optarg, "max")==0)
449 size = 0;
450 else {
5f4fc0e1
N
451 size = parse_size(optarg);
452 if (size < 8) {
e7b84f9d 453 pr_err("invalid size: %s\n",
dd0781e5
NB
454 optarg);
455 exit(2);
456 }
5f4fc0e1
N
457 /* convert sectors to K */
458 size /= 2;
52826846
NB
459 }
460 continue;
64c4757e 461
84e11361
N
462 case O(GROW,'Z'): /* array size */
463 if (array_size >= 0) {
e7b84f9d 464 pr_err("array-size may only be specified once. "
84e11361
N
465 "Second value is %s.\n", optarg);
466 exit(2);
467 }
468 if (strcmp(optarg, "max") == 0)
469 array_size = 0;
470 else {
471 array_size = parse_size(optarg);
472 if (array_size <= 0) {
e7b84f9d 473 pr_err("invalid array size: %s\n",
84e11361
N
474 optarg);
475 exit(2);
476 }
477 }
478 continue;
479
7236ee7a 480 case O(GROW,'l'):
e0d19036
NB
481 case O(CREATE,'l'):
482 case O(BUILD,'l'): /* set raid level*/
98c6faba 483 if (level != UnSet) {
e7b84f9d 484 pr_err("raid level may only be set once. "
52826846
NB
485 "Second value is %s.\n", optarg);
486 exit(2);
487 }
488 level = map_name(pers, optarg);
98c6faba 489 if (level == UnSet) {
e7b84f9d 490 pr_err("invalid raid level: %s\n",
52826846
NB
491 optarg);
492 exit(2);
493 }
e0fe762a
N
494 if (level != 0 && level != LEVEL_LINEAR && level != 1 &&
495 level != LEVEL_MULTIPATH && level != LEVEL_FAULTY &&
496 level != 10 &&
497 mode == BUILD) {
e7b84f9d 498 pr_err("Raid level %s not permitted with --build.\n",
52826846
NB
499 optarg);
500 exit(2);
501 }
e0d19036 502 if (sparedisks > 0 && level < 1 && level >= -1) {
e7b84f9d 503 pr_err("raid level %s is incompatible with spare-devices setting.\n",
52826846
NB
504 optarg);
505 exit(2);
506 }
cd29a5c8 507 ident.level = level;
52826846 508 continue;
64c4757e 509
19678e53 510 case O(GROW, 'p'): /* new layout */
1c7a808c 511 case O(GROW, Layout):
19678e53 512 if (layout_str) {
e7b84f9d
N
513 pr_err("layout may only be sent once. "
514 "Second value was %s\n", optarg);
19678e53
N
515 exit(2);
516 }
517 layout_str = optarg;
518 /* 'Grow' will parse the value */
519 continue;
520
e0d19036 521 case O(CREATE,'p'): /* raid5 layout */
1c7a808c 522 case O(CREATE,Layout):
b5e64645 523 case O(BUILD,'p'): /* faulty layout */
1c7a808c 524 case O(BUILD,Layout):
e5329c37 525 if (layout != UnSet) {
e7b84f9d
N
526 pr_err("layout may only be sent once. "
527 "Second value was %s\n", optarg);
52826846
NB
528 exit(2);
529 }
530 switch(level) {
531 default:
e7b84f9d 532 pr_err("layout not meaningful for %s arrays.\n",
52826846
NB
533 map_num(pers, level));
534 exit(2);
98c6faba 535 case UnSet:
e7b84f9d 536 pr_err("raid level must be given before layout.\n");
52826846
NB
537 exit(2);
538
539 case 5:
540 layout = map_name(r5layout, optarg);
98c6faba 541 if (layout==UnSet) {
e7b84f9d 542 pr_err("layout %s not understood for raid5.\n",
52826846
NB
543 optarg);
544 exit(2);
545 }
546 break;
b640a252
N
547 case 6:
548 layout = map_name(r6layout, optarg);
549 if (layout==UnSet) {
e7b84f9d 550 pr_err("layout %s not understood for raid6.\n",
b640a252
N
551 optarg);
552 exit(2);
553 }
554 break;
e5329c37
NB
555
556 case 10:
4a06e2c2
N
557 layout = parse_layout_10(optarg);
558 if (layout < 0) {
e7b84f9d 559 pr_err("layout for raid10 must be 'nNN', 'oNN' or 'fNN' where NN is a number, not %s\n", optarg);
e5329c37
NB
560 exit(2);
561 }
e5329c37 562 break;
19678e53
N
563 case LEVEL_FAULTY:
564 /* Faulty
565 * modeNNN
566 */
4a06e2c2
N
567 layout = parse_layout_faulty(optarg);
568 if (layout == -1) {
e7b84f9d 569 pr_err("layout %s not understood for faulty.\n",
b5e64645
NB
570 optarg);
571 exit(2);
572 }
4a06e2c2 573 break;
52826846
NB
574 }
575 continue;
576
997aed5d
NB
577 case O(CREATE,AssumeClean):
578 case O(BUILD,AssumeClean): /* assume clean */
ce52f92f 579 case O(GROW,AssumeClean):
dd0781e5
NB
580 assume_clean = 1;
581 continue;
582
583 case O(GROW,'n'):
e0d19036
NB
584 case O(CREATE,'n'):
585 case O(BUILD,'n'): /* number of raid disks */
52826846 586 if (raiddisks) {
e7b84f9d 587 pr_err("raid-devices set twice: %d and %s\n",
52826846
NB
588 raiddisks, optarg);
589 exit(2);
590 }
79868890
N
591 raiddisks = parse_num(optarg);
592 if (raiddisks <= 0) {
e7b84f9d 593 pr_err("invalid number of raid devices: %s\n",
52826846
NB
594 optarg);
595 exit(2);
596 }
cd29a5c8 597 ident.raid_disks = raiddisks;
52826846
NB
598 continue;
599
18361a1a 600 case O(CREATE,'x'): /* number of spare (eXtra) disks */
52826846 601 if (sparedisks) {
e7b84f9d
N
602 pr_err("spare-devices set twice: %d and %s\n",
603 sparedisks, optarg);
52826846
NB
604 exit(2);
605 }
98c6faba 606 if (level != UnSet && level <= 0 && level >= -1) {
e7b84f9d 607 pr_err("spare-devices setting is incompatible with raid level %d\n",
52826846
NB
608 level);
609 exit(2);
610 }
79868890
N
611 sparedisks = parse_num(optarg);
612 if (sparedisks < 0) {
e7b84f9d 613 pr_err("invalid number of spare-devices: %s\n",
52826846
NB
614 optarg);
615 exit(2);
616 }
617 continue;
dd0781e5
NB
618
619 case O(CREATE,'a'):
1c7a808c 620 case O(CREATE,Auto):
dd0781e5 621 case O(BUILD,'a'):
1c7a808c 622 case O(BUILD,Auto):
95b79df0 623 case O(INCREMENTAL,'a'):
1c7a808c
N
624 case O(INCREMENTAL,Auto):
625 case O(ASSEMBLE,'a'):
626 case O(ASSEMBLE,Auto): /* auto-creation of device node */
f1ae21c4 627 autof = parse_auto(optarg, "--auto flag", 0);
dd0781e5
NB
628 continue;
629
38098016
NB
630 case O(CREATE,Symlinks):
631 case O(BUILD,Symlinks):
632 case O(ASSEMBLE,Symlinks): /* auto creation of symlinks in /dev to /dev/md */
633 symlinks = optarg;
634 continue;
635
aa88f531 636 case O(BUILD,'f'): /* force honouring '-n 1' */
1c7a808c 637 case O(BUILD,Force): /* force honouring '-n 1' */
bd72c2b2 638 case O(GROW,'f'): /* ditto */
1c7a808c 639 case O(GROW,Force): /* ditto */
e0d19036 640 case O(CREATE,'f'): /* force honouring of device list */
1c7a808c 641 case O(CREATE,Force): /* force honouring of device list */
e0d19036 642 case O(ASSEMBLE,'f'): /* force assembly */
1c7a808c 643 case O(ASSEMBLE,Force): /* force assembly */
e0d19036 644 case O(MISC,'f'): /* force zero */
1c7a808c 645 case O(MISC,Force): /* force zero */
11b391ec 646 case O(MANAGE,Force): /* add device which is too large */
52826846
NB
647 force=1;
648 continue;
52826846 649 /* now for the Assemble options */
b76b30e0
AK
650 case O(ASSEMBLE, FreezeReshape): /* Freeze reshape during
651 * initrd phase */
652 case O(INCREMENTAL, FreezeReshape):
653 freeze_reshape = 1;
654 continue;
3d3dd91e 655 case O(CREATE,'u'): /* uuid of array */
e0d19036 656 case O(ASSEMBLE,'u'): /* uuid of array */
52826846 657 if (ident.uuid_set) {
e7b84f9d 658 pr_err("uuid cannot be set twice. "
52826846
NB
659 "Second value %s.\n", optarg);
660 exit(2);
661 }
662 if (parse_uuid(optarg, ident.uuid))
663 ident.uuid_set = 1;
664 else {
e7b84f9d 665 pr_err("Bad uuid: %s\n", optarg);
52826846
NB
666 exit(2);
667 }
668 continue;
669
947fd4dd
NB
670 case O(CREATE,'N'):
671 case O(ASSEMBLE,'N'):
aa534678 672 case O(MISC,'N'):
947fd4dd 673 if (ident.name[0]) {
e7b84f9d 674 pr_err("name cannot be set twice. "
947fd4dd
NB
675 "Second value %s.\n", optarg);
676 exit(2);
677 }
aa534678 678 if (mode == MISC && !subarray) {
e7b84f9d 679 pr_err("-N/--name only valid with --update-subarray in misc mode\n");
aa534678
DW
680 exit(2);
681 }
947fd4dd 682 if (strlen(optarg) > 32) {
e7b84f9d 683 pr_err("name '%s' is too long, 32 chars max.\n",
947fd4dd
NB
684 optarg);
685 exit(2);
686 }
687 strcpy(ident.name, optarg);
688 continue;
689
e0d19036 690 case O(ASSEMBLE,'m'): /* super-minor for array */
1c7a808c 691 case O(ASSEMBLE,SuperMinor):
98c6faba 692 if (ident.super_minor != UnSet) {
e7b84f9d 693 pr_err("super-minor cannot be set twice. "
cd29a5c8
NB
694 "Second value: %s.\n", optarg);
695 exit(2);
696 }
d013a55e
NB
697 if (strcmp(optarg, "dev")==0)
698 ident.super_minor = -2;
699 else {
79868890
N
700 ident.super_minor = parse_num(optarg);
701 if (ident.super_minor < 0) {
e7b84f9d 702 pr_err("Bad super-minor number: %s.\n", optarg);
d013a55e
NB
703 exit(2);
704 }
cd29a5c8
NB
705 }
706 continue;
707
0ea8f5b1
N
708 case O(ASSEMBLE,'o'):
709 case O(MANAGE,'o'):
710 case O(CREATE,'o'):
711 readonly = 1;
712 continue;
713
5787fa49 714 case O(ASSEMBLE,'U'): /* update the superblock */
aa534678 715 case O(MISC,'U'):
5787fa49 716 if (update) {
e7b84f9d 717 pr_err("Can only update one aspect"
833bb0f8 718 " of superblock, both %s and %s given.\n",
5787fa49
NB
719 update, optarg);
720 exit(2);
721 }
aa534678 722 if (mode == MISC && !subarray) {
e7b84f9d 723 pr_err("Only subarrays can be"
833bb0f8 724 " updated in misc mode\n");
aa534678
DW
725 exit(2);
726 }
5787fa49 727 update = optarg;
aba69144 728 if (strcmp(update, "sparc2.2")==0)
e5329c37 729 continue;
5787fa49
NB
730 if (strcmp(update, "super-minor") == 0)
731 continue;
feb716e9
NB
732 if (strcmp(update, "summaries")==0)
733 continue;
e5329c37
NB
734 if (strcmp(update, "resync")==0)
735 continue;
7d99579f
NB
736 if (strcmp(update, "uuid")==0)
737 continue;
c4f12c13
NB
738 if (strcmp(update, "name")==0)
739 continue;
0237e0ca
NB
740 if (strcmp(update, "homehost")==0)
741 continue;
bee8ec56
NB
742 if (strcmp(update, "devicesize")==0)
743 continue;
5a31170d
N
744 if (strcmp(update, "no-bitmap")==0)
745 continue;
586ed405
NB
746 if (strcmp(update, "byteorder")==0) {
747 if (ss) {
e7b84f9d
N
748 pr_err("must not set metadata"
749 " type with --update=byteorder.\n");
586ed405
NB
750 exit(2);
751 }
aba69144 752 for(i=0; !ss && superlist[i]; i++)
833bb0f8
N
753 ss = superlist[i]->match_metadata_desc(
754 "0.swap");
586ed405 755 if (!ss) {
e7b84f9d 756 pr_err("INTERNAL ERROR"
833bb0f8 757 " cannot find 0.swap\n");
586ed405
NB
758 exit(2);
759 }
760
761 continue;
762 }
0047d254
NB
763 if (strcmp(update,"?") == 0 ||
764 strcmp(update, "help") == 0) {
765 outf = stdout;
766 fprintf(outf, Name ": ");
767 } else {
768 outf = stderr;
769 fprintf(outf,
770 Name ": '--update=%s' is invalid. ",
771 update);
772 }
773 fprintf(outf, "Valid --update options are:\n"
bee8ec56 774 " 'sparc2.2', 'super-minor', 'uuid', 'name', 'resync',\n"
5a31170d
N
775 " 'summaries', 'homehost', 'byteorder', 'devicesize',\n"
776 " 'no-bitmap'\n");
0047d254 777 exit(outf == stdout ? 0 : 2);
5787fa49 778
833bb0f8
N
779 case O(MANAGE,'U'):
780 /* update=devicesize is allowed with --re-add */
c8e1a230 781 if (devmode != 'A') {
e7b84f9d 782 pr_err("--update in Manage mode only"
833bb0f8
N
783 " allowed with --re-add.\n");
784 exit(1);
785 }
786 if (update) {
e7b84f9d 787 pr_err("Can only update one aspect"
833bb0f8
N
788 " of superblock, both %s and %s given.\n",
789 update, optarg);
790 exit(2);
791 }
792 update = optarg;
793 if (strcmp(update, "devicesize") != 0) {
e7b84f9d 794 pr_err("only 'devicesize' can be"
833bb0f8
N
795 " updated with --re-add\n");
796 exit(2);
797 }
798 continue;
799
172356c9 800 case O(INCREMENTAL,NoDegraded):
e7b84f9d 801 pr_err("--no-degraded is deprecated in Incremental mode\n");
997aed5d 802 case O(ASSEMBLE,NoDegraded): /* --no-degraded */
0047d254
NB
803 runstop = -1; /* --stop isn't allowed for --assemble,
804 * so we overload slightly */
b8a8ccf9
NB
805 continue;
806
1c7a808c
N
807 case O(ASSEMBLE,'c'):
808 case O(ASSEMBLE,ConfigFile):
7b187ed7 809 case O(INCREMENTAL, 'c'):
1c7a808c 810 case O(INCREMENTAL, ConfigFile):
2d465520 811 case O(MISC, 'c'):
1c7a808c 812 case O(MISC, ConfigFile):
e0d19036 813 case O(MONITOR,'c'):
1c7a808c 814 case O(MONITOR,ConfigFile):
52826846 815 if (configfile) {
e7b84f9d 816 pr_err("configfile cannot be set twice. "
52826846
NB
817 "Second value is %s.\n", optarg);
818 exit(2);
819 }
820 configfile = optarg;
8aec876d 821 set_conffile(configfile);
52826846
NB
822 /* FIXME possibly check that config file exists. Even parse it */
823 continue;
e0d19036
NB
824 case O(ASSEMBLE,'s'): /* scan */
825 case O(MISC,'s'):
826 case O(MONITOR,'s'):
8382f19b 827 case O(INCREMENTAL,'s'):
52826846
NB
828 scan = 1;
829 continue;
830
e0d19036 831 case O(MONITOR,'m'): /* mail address */
1c7a808c 832 case O(MONITOR,EMail):
52826846 833 if (mailaddr)
e7b84f9d 834 pr_err("only specify one mailaddress. %s ignored.\n",
52826846
NB
835 optarg);
836 else
837 mailaddr = optarg;
838 continue;
839
e0d19036 840 case O(MONITOR,'p'): /* alert program */
1c7a808c 841 case O(MONITOR,ProgramOpt): /* alert program */
52826846 842 if (program)
e7b84f9d 843 pr_err("only specify one alter program. %s ignored.\n",
52826846
NB
844 optarg);
845 else
846 program = optarg;
847 continue;
64c4757e 848
9a36a9b7 849 case O(MONITOR,'r'): /* rebuild increments */
1c7a808c 850 case O(MONITOR,Increment):
9a36a9b7 851 increments = atoi(optarg);
18361a1a 852 if (increments > 99 || increments < 1) {
e7b84f9d 853 pr_err("please specify positive integer between 1 and 99 as rebuild increments.\n");
9a36a9b7
ZB
854 exit(2);
855 }
856 continue;
857
e0d19036 858 case O(MONITOR,'d'): /* delay in seconds */
f5e166fe 859 case O(GROW, 'd'):
c82f047c
NB
860 case O(BUILD,'d'): /* delay for bitmap updates */
861 case O(CREATE,'d'):
52826846 862 if (delay)
e7b84f9d 863 pr_err("only specify delay once. %s ignored.\n",
52826846
NB
864 optarg);
865 else {
79868890
N
866 delay = parse_num(optarg);
867 if (delay<1) {
e7b84f9d 868 pr_err("invalid delay: %s\n",
52826846
NB
869 optarg);
870 exit(2);
871 }
872 }
873 continue;
d013a55e 874 case O(MONITOR,'f'): /* daemonise */
1c7a808c 875 case O(MONITOR,Fork):
d013a55e
NB
876 daemonise = 1;
877 continue;
b5e64645
NB
878 case O(MONITOR,'i'): /* pid */
879 if (pidfile)
e7b84f9d 880 pr_err("only specify one pid file. %s ignored.\n",
b5e64645
NB
881 optarg);
882 else
883 pidfile = optarg;
884 continue;
aa88f531
NB
885 case O(MONITOR,'1'): /* oneshot */
886 oneshot = 1;
3f555346 887 spare_sharing = 0;
aa88f531 888 continue;
98c6faba
NB
889 case O(MONITOR,'t'): /* test */
890 test = 1;
891 continue;
773135f5 892 case O(MONITOR,'y'): /* log messages to syslog */
6ac8aac2 893 openlog("mdadm", LOG_PID, SYSLOG_FACILITY);
773135f5
NB
894 dosyslog = 1;
895 continue;
edde9560
AC
896 case O(MONITOR, NoSharing):
897 spare_sharing = 0;
898 continue;
18361a1a 899
52826846
NB
900 /* now the general management options. Some are applicable
901 * to other modes. None have arguments.
902 */
e5329c37 903 case O(GROW,'a'):
1c7a808c
N
904 case O(GROW,Add):
905 case O(MANAGE,'a'):
906 case O(MANAGE,Add): /* add a drive */
52826846 907 devmode = 'a';
fe80f49b 908 continue;
997aed5d 909 case O(MANAGE,ReAdd):
c8e1a230 910 devmode = 'A';
52826846 911 continue;
e0d19036 912 case O(MANAGE,'r'): /* remove a drive */
1c7a808c 913 case O(MANAGE,Remove):
52826846
NB
914 devmode = 'r';
915 continue;
e0d19036 916 case O(MANAGE,'f'): /* set faulty */
1c7a808c
N
917 case O(MANAGE,Fail):
918 case O(INCREMENTAL,'f'):
919 case O(INCREMENTAL,Remove):
920 case O(INCREMENTAL,Fail): /* r for incremental is taken, use f
7d27d1c0
N
921 * even though we will both fail and
922 * remove the device */
52826846
NB
923 devmode = 'f';
924 continue;
8382f19b 925 case O(INCREMENTAL,'R'):
e0d19036
NB
926 case O(MANAGE,'R'):
927 case O(ASSEMBLE,'R'):
928 case O(BUILD,'R'):
929 case O(CREATE,'R'): /* Run the array */
52826846 930 if (runstop < 0) {
e7b84f9d 931 pr_err("Cannot both Stop and Run an array\n");
52826846
NB
932 exit(2);
933 }
934 runstop = 1;
935 continue;
e0d19036 936 case O(MANAGE,'S'):
52826846 937 if (runstop > 0) {
e7b84f9d 938 pr_err("Cannot both Run and Stop an array\n");
52826846
NB
939 exit(2);
940 }
941 runstop = -1;
942 continue;
7d2e6486
N
943 case O(MANAGE,'t'):
944 test = 1;
945 continue;
52826846 946
e0d19036
NB
947 case O(MISC,'Q'):
948 case O(MISC,'D'):
949 case O(MISC,'E'):
f7d3febc 950 case O(MISC,KillOpt):
e0d19036
NB
951 case O(MISC,'R'):
952 case O(MISC,'S'):
c82f047c 953 case O(MISC,'X'):
e0d19036
NB
954 case O(MISC,'o'):
955 case O(MISC,'w'):
b90c0e9a 956 case O(MISC,'W'):
1c7a808c 957 case O(MISC, WaitOpt):
1770662b 958 case O(MISC, Waitclean):
4cce4069 959 case O(MISC, DetailPlatform):
33414a01 960 case O(MISC, KillSubarray):
aa534678 961 case O(MISC, UpdateSubarray):
5a53aeec
JS
962 if (opt == KillSubarray || opt == UpdateSubarray) {
963 if (subarray) {
e7b84f9d 964 pr_err("subarray can only"
5a53aeec
JS
965 " be specified once\n");
966 exit(2);
967 }
968 subarray = optarg;
969 }
e0d19036
NB
970 if (devmode && devmode != opt &&
971 (devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
e7b84f9d 972 pr_err("--examine/-E cannot be given with ");
aa534678
DW
973 if (devmode == 'E') {
974 if (option_index >= 0)
975 fprintf(stderr, "--%s\n",
976 long_options[option_index].name);
977 else
978 fprintf(stderr, "-%c\n", opt);
979 } else if (isalpha(devmode))
980 fprintf(stderr, "-%c\n", devmode);
981 else
982 fprintf(stderr, "previous option\n");
e0d19036
NB
983 exit(2);
984 }
985 devmode = opt;
986 continue;
7d27d1c0
N
987 case O(MISC, UdevRules):
988 if (devmode && devmode != opt) {
e7b84f9d
N
989 pr_err("--udev-rules must"
990 " be the only option.\n");
7d27d1c0
N
991 } else {
992 if (udev_filename)
e7b84f9d 993 pr_err("only specify one udev "
7d27d1c0
N
994 "rule filename. %s ignored.\n",
995 optarg);
996 else
997 udev_filename = optarg;
998 }
999 devmode = opt;
1000 continue;
feb716e9
NB
1001 case O(MISC,'t'):
1002 test = 1;
1003 continue;
e0d19036 1004
997aed5d 1005 case O(MISC, Sparc22):
bd526cee 1006 if (devmode != 'E') {
e7b84f9d 1007 pr_err("--sparc2.2 only allowed with --examine\n");
bd526cee
NB
1008 exit(2);
1009 }
1010 SparcAdjust = 1;
1011 continue;
c82f047c
NB
1012
1013 case O(ASSEMBLE,'b'): /* here we simply set the bitmap file */
1c7a808c 1014 case O(ASSEMBLE,Bitmap):
c82f047c 1015 if (!optarg) {
e7b84f9d 1016 pr_err("bitmap file needed with -b in --assemble mode\n");
c82f047c
NB
1017 exit(2);
1018 }
55935d51 1019 if (strcmp(optarg, "internal")==0) {
e7b84f9d 1020 pr_err("there is no need to specify --bitmap when assembling arrays with internal bitmaps\n");
55935d51
NB
1021 continue;
1022 }
c82f047c
NB
1023 bitmap_fd = open(optarg, O_RDWR);
1024 if (!*optarg || bitmap_fd < 0) {
e7b84f9d 1025 pr_err("cannot open bitmap file %s: %s\n", optarg, strerror(errno));
c82f047c
NB
1026 exit(2);
1027 }
1028 ident.bitmap_fd = bitmap_fd; /* for Assemble */
1029 continue;
f5e166fe 1030
997aed5d
NB
1031 case O(ASSEMBLE, BackupFile):
1032 case O(GROW, BackupFile):
06b0d786
NB
1033 /* Specify a file into which grow might place a backup,
1034 * or from which assemble might recover a backup
1035 */
1036 if (backup_file) {
e7b84f9d 1037 pr_err("backup file already specified, rejecting %s\n", optarg);
06b0d786
NB
1038 exit(2);
1039 }
1040 backup_file = optarg;
1041 continue;
1042
2dddadb0
AK
1043 case O(GROW, Continue):
1044 /* Continue interrupted grow
1045 */
1046 grow_continue = 1;
1047 continue;
87f26d14
N
1048 case O(ASSEMBLE, InvalidBackup):
1049 /* Acknowledge that the backupfile is invalid, but ask
1050 * to continue anyway
1051 */
1052 invalid_backup = 1;
1053 continue;
1054
c82f047c 1055 case O(BUILD,'b'):
1c7a808c
N
1056 case O(BUILD,Bitmap):
1057 case O(CREATE,'b'):
1058 case O(CREATE,Bitmap): /* here we create the bitmap */
85375d6d 1059 if (strcmp(optarg, "none") == 0) {
e7b84f9d 1060 pr_err("'--bitmap none' only"
18361a1a 1061 " supported for --grow\n");
85375d6d
NB
1062 exit(2);
1063 }
1064 /* FALL THROUGH */
1065 case O(GROW,'b'):
1c7a808c 1066 case O(GROW,Bitmap):
1e0d770c
NB
1067 if (strcmp(optarg, "internal")== 0 ||
1068 strcmp(optarg, "none")== 0 ||
1069 strchr(optarg, '/') != NULL) {
1070 bitmap_file = optarg;
1071 continue;
1072 }
1073 /* probable typo */
e7b84f9d 1074 pr_err("bitmap file must contain a '/', or be 'internal', or 'none'\n"
a1331cc4 1075 " not '%s'\n", optarg);
1e0d770c 1076 exit(2);
c82f047c 1077
997aed5d
NB
1078 case O(GROW,BitmapChunk):
1079 case O(BUILD,BitmapChunk):
1080 case O(CREATE,BitmapChunk): /* bitmap chunksize */
36fad8ec 1081 bitmap_chunk = parse_size(optarg);
15632a96 1082 if (bitmap_chunk <= 0 ||
36fad8ec 1083 bitmap_chunk & (bitmap_chunk - 1)) {
e7b84f9d
N
1084 pr_err("invalid bitmap chunksize: %s\n",
1085 optarg);
c82f047c
NB
1086 exit(2);
1087 }
15632a96 1088 bitmap_chunk = bitmap_chunk * 512;
c82f047c 1089 continue;
dfd4d8ee 1090
7d19ad0d 1091 case O(GROW, WriteBehind):
997aed5d
NB
1092 case O(BUILD, WriteBehind):
1093 case O(CREATE, WriteBehind): /* write-behind mode */
dfd4d8ee
NB
1094 write_behind = DEFAULT_MAX_WRITE_BEHIND;
1095 if (optarg) {
79868890
N
1096 write_behind = parse_num(optarg);
1097 if (write_behind < 0 ||
dfd4d8ee 1098 write_behind > 16383) {
e7b84f9d 1099 pr_err("Invalid value for maximum outstanding write-behind writes: %s.\n\tMust be between 0 and 16383.\n", optarg);
dfd4d8ee
NB
1100 exit(2);
1101 }
1102 }
1103 continue;
8382f19b
NB
1104
1105 case O(INCREMENTAL, 'r'):
1c7a808c 1106 case O(INCREMENTAL, RebuildMapOpt):
8382f19b
NB
1107 rebuild_map = 1;
1108 continue;
950bc344
PC
1109 case O(INCREMENTAL, IncrementalPath):
1110 remove_path = optarg;
1111 continue;
52826846
NB
1112 }
1113 /* We have now processed all the valid options. Anything else is
1114 * an error
1115 */
06b0d786 1116 if (option_index > 0)
e7b84f9d 1117 pr_err(":option --%s not valid in %s mode\n",
06b0d786
NB
1118 long_options[option_index].name,
1119 map_num(modes, mode));
1120 else
e7b84f9d 1121 pr_err("option -%c not valid in %s mode\n",
06b0d786 1122 opt, map_num(modes, mode));
64c4757e 1123 exit(2);
52826846
NB
1124
1125 }
1126
3d4064cc 1127 if (print_help) {
5187a385 1128 char *help_text;
3d4064cc
NB
1129 if (print_help == 2)
1130 help_text = OptionHelp;
1131 else
5187a385
N
1132 help_text = mode_help[mode];
1133 if (help_text == NULL)
1134 help_text = Help;
0047d254 1135 fputs(help_text,stdout);
3d4064cc
NB
1136 exit(0);
1137 }
1138
0320ea45
NB
1139 if (!mode && devs_found) {
1140 mode = MISC;
1141 devmode = 'Q';
1142 if (devlist->disposition == 0)
1143 devlist->disposition = devmode;
1144 }
52826846
NB
1145 if (!mode) {
1146 fputs(Usage, stderr);
64c4757e 1147 exit(2);
64c4757e 1148 }
38098016
NB
1149
1150 if (symlinks) {
1151 struct createinfo *ci = conf_get_create_info();
1152
1153 if (strcasecmp(symlinks, "yes") == 0)
1154 ci->symlinks = 1;
1155 else if (strcasecmp(symlinks, "no") == 0)
1156 ci->symlinks = 0;
1157 else {
e7b84f9d 1158 pr_err("option --symlinks must be 'no' or 'yes'\n");
38098016
NB
1159 exit(2);
1160 }
1161 }
52826846
NB
1162 /* Ok, got the option parsing out of the way
1163 * hopefully it's mostly right but there might be some stuff
1164 * missing
1165 *
e0d19036 1166 * That is mosty checked in the per-mode stuff but...
52826846 1167 *
18361a1a
N
1168 * For @,B,C and A without -s, the first device listed must be
1169 * an md device. We check that here and open it.
64c4757e 1170 */
52826846 1171
18361a1a
N
1172 if (mode == MANAGE || mode == BUILD || mode == CREATE
1173 || mode == GROW
1174 || (mode == ASSEMBLE && ! scan)) {
52826846 1175 if (devs_found < 1) {
e7b84f9d 1176 pr_err("an md device must be given in this mode\n");
52826846
NB
1177 exit(2);
1178 }
dd0781e5 1179 if ((int)ident.super_minor == -2 && autof) {
e7b84f9d 1180 pr_err("--super-minor=dev is incompatible with --auto\n");
dd0781e5
NB
1181 exit(2);
1182 }
7f91af49 1183 if (mode == MANAGE || mode == GROW) {
6be1d39d 1184 mdfd = open_mddev(devlist->devname, 1);
7f91af49
N
1185 if (mdfd < 0)
1186 exit(1);
1187 } else
1188 /* non-existent device is OK */
1189 mdfd = open_mddev(devlist->devname, 0);
1190 if (mdfd == -2) {
e7b84f9d 1191 pr_err("device %s exists but is not an "
7f91af49 1192 "md array.\n", devlist->devname);
52826846 1193 exit(1);
7f91af49 1194 }
98c6faba 1195 if ((int)ident.super_minor == -2) {
d013a55e 1196 struct stat stb;
7f91af49 1197 if (mdfd < 0) {
e7b84f9d 1198 pr_err("--super-minor=dev given, and "
7f91af49
N
1199 "listed device %s doesn't exist.\n",
1200 devlist->devname);
1201 exit(1);
1202 }
d013a55e 1203 fstat(mdfd, &stb);
0df46c2a 1204 ident.super_minor = minor(stb.st_rdev);
d013a55e 1205 }
7f91af49
N
1206 if (mdfd >= 0 && mode != MANAGE && mode != GROW) {
1207 /* We don't really want this open yet, we just might
1208 * have wanted to check some things
1209 */
1210 close(mdfd);
1211 mdfd = -1;
1212 }
64c4757e 1213 }
52826846 1214
e4c4352e 1215 if (raiddisks) {
18361a1a 1216 if (raiddisks == 1 && !force && level != LEVEL_FAULTY) {
e7b84f9d 1217 pr_err("'1' is an unusual number of drives for an array, so it is probably\n"
e4c4352e
NB
1218 " a mistake. If you really mean it you will need to specify --force before\n"
1219 " setting the number of drives.\n");
1220 exit(2);
1221 }
1222 }
c82f047c 1223
997aed5d 1224 if (homehost == NULL)
0ac91628 1225 homehost = conf_get_homehost(&require_homehost);
0f23aa88 1226 if (homehost == NULL || strcasecmp(homehost, "<system>")==0) {
05697ec1
NB
1227 if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) {
1228 sys_hostname[sizeof(sys_hostname)-1] = 0;
1229 homehost = sys_hostname;
1230 }
1231 }
0f23aa88
N
1232 if (homehost && (!homehost[0] || strcasecmp(homehost, "<none>") == 0)) {
1233 homehost = NULL;
1234 require_homehost = 0;
1235 }
997aed5d 1236
18361a1a
N
1237 if ((mode == MISC && devmode == 'E')
1238 || (mode == MONITOR && spare_sharing == 0))
1239 /* Anyone may try this */;
1240 else if (geteuid() != 0) {
e7b84f9d 1241 pr_err("must be super-user to perform this action\n");
ac5678dd
N
1242 exit(1);
1243 }
1244
7f91af49
N
1245 ident.autof = autof;
1246
52826846
NB
1247 rv = 0;
1248 switch(mode) {
e0d19036 1249 case MANAGE:
52826846
NB
1250 /* readonly, add/remove, readwrite, runstop */
1251 if (readonly>0)
cd29a5c8 1252 rv = Manage_ro(devlist->devname, mdfd, readonly);
52826846 1253 if (!rv && devs_found>1)
cd29a5c8 1254 rv = Manage_subdevs(devlist->devname, mdfd,
833bb0f8 1255 devlist->next, verbose-quiet, test,
11b391ec 1256 update, force);
52826846 1257 if (!rv && readonly < 0)
cd29a5c8 1258 rv = Manage_ro(devlist->devname, mdfd, readonly);
52826846 1259 if (!rv && runstop)
ab56093f 1260 rv = Manage_runstop(devlist->devname, mdfd, runstop, quiet);
52826846 1261 break;
e0d19036 1262 case ASSEMBLE:
d013a55e 1263 if (devs_found == 1 && ident.uuid_set == 0 &&
947fd4dd 1264 ident.super_minor == UnSet && ident.name[0] == 0 && !scan ) {
d013a55e 1265 /* Only a device has been given, so get details from config file */
fa56eddb 1266 struct mddev_ident *array_ident = conf_get_ident(devlist->devname);
b5e64645 1267 if (array_ident == NULL) {
e7b84f9d 1268 pr_err("%s not identified in config file.\n",
b5e64645 1269 devlist->devname);
d013a55e 1270 rv |= 1;
7f91af49
N
1271 if (mdfd >= 0)
1272 close(mdfd);
b5e64645 1273 } else {
7f91af49
N
1274 if (array_ident->autof == 0)
1275 array_ident->autof = autof;
1276 rv |= Assemble(ss, devlist->devname, array_ident,
87f26d14 1277 NULL, backup_file, invalid_backup,
0ac91628
N
1278 readonly, runstop, update,
1279 homehost, require_homehost,
b76b30e0
AK
1280 verbose-quiet, force,
1281 freeze_reshape);
d013a55e
NB
1282 }
1283 } else if (!scan)
7f91af49 1284 rv = Assemble(ss, devlist->devname, &ident,
87f26d14 1285 devlist->next, backup_file, invalid_backup,
0ac91628
N
1286 readonly, runstop, update,
1287 homehost, require_homehost,
b76b30e0
AK
1288 verbose-quiet, force,
1289 freeze_reshape);
18361a1a 1290 else if (devs_found > 0) {
5787fa49 1291 if (update && devs_found > 1) {
e7b84f9d 1292 pr_err("can only update a single array at a time\n");
5787fa49
NB
1293 exit(1);
1294 }
06b0d786 1295 if (backup_file && devs_found > 1) {
e7b84f9d 1296 pr_err("can only assemble a single array when providing a backup file.\n");
06b0d786
NB
1297 exit(1);
1298 }
cd29a5c8 1299 for (dv = devlist ; dv ; dv=dv->next) {
fa56eddb 1300 struct mddev_ident *array_ident = conf_get_ident(dv->devname);
52826846 1301 if (array_ident == NULL) {
e7b84f9d 1302 pr_err("%s not identified in config file.\n",
cd29a5c8 1303 dv->devname);
52826846
NB
1304 rv |= 1;
1305 continue;
1306 }
7f91af49
N
1307 if (array_ident->autof == 0)
1308 array_ident->autof = autof;
1309 rv |= Assemble(ss, dv->devname, array_ident,
87f26d14 1310 NULL, backup_file, invalid_backup,
0ac91628
N
1311 readonly, runstop, update,
1312 homehost, require_homehost,
b76b30e0
AK
1313 verbose-quiet, force,
1314 freeze_reshape);
52826846 1315 }
5787fa49 1316 } else {
da6b5ca9 1317 if (update) {
e7b84f9d 1318 pr_err("--update not meaningful with a --scan assembly.\n");
da6b5ca9
NB
1319 exit(1);
1320 }
1321 if (backup_file) {
e7b84f9d 1322 pr_err("--backup_file not meaningful with a --scan assembly.\n");
da6b5ca9
NB
1323 exit(1);
1324 }
3cbc4d12
N
1325 rv = scan_assemble(autof, ss, readonly, runstop,
1326 &ident, homehost,
1327 require_homehost,
1328 verbose - quiet,
1329 force, freeze_reshape);
52826846 1330 }
3cbc4d12 1331
52826846 1332 break;
e0d19036 1333 case BUILD:
c82f047c 1334 if (delay == 0) delay = DEFAULT_BITMAP_DELAY;
dfd4d8ee 1335 if (write_behind && !bitmap_file) {
e7b84f9d 1336 pr_err("write-behind mode requires a bitmap.\n");
dfd4d8ee
NB
1337 rv = 1;
1338 break;
1339 }
5b28bd56 1340 if (raiddisks == 0) {
e7b84f9d 1341 pr_err("no raid-devices specified.\n");
5b28bd56
NB
1342 rv = 1;
1343 break;
1344 }
dfd4d8ee 1345
c82f047c 1346 if (bitmap_file) {
55935d51 1347 if (strcmp(bitmap_file, "internal")==0) {
e7b84f9d 1348 pr_err("'internal' bitmaps not supported with --build\n");
55935d51
NB
1349 rv |= 1;
1350 break;
1351 }
c82f047c 1352 }
7f91af49 1353 rv = Build(devlist->devname, chunk, level, layout,
c82f047c 1354 raiddisks, devlist->next, assume_clean,
7f91af49 1355 bitmap_file, bitmap_chunk, write_behind,
83208785 1356 delay, verbose-quiet, autof, size);
52826846 1357 break;
e0d19036 1358 case CREATE:
c82f047c 1359 if (delay == 0) delay = DEFAULT_BITMAP_DELAY;
dfd4d8ee 1360 if (write_behind && !bitmap_file) {
e7b84f9d 1361 pr_err("write-behind mode requires a bitmap.\n");
dfd4d8ee
NB
1362 rv = 1;
1363 break;
1364 }
5b28bd56 1365 if (raiddisks == 0) {
e7b84f9d 1366 pr_err("no raid-devices specified.\n");
5b28bd56
NB
1367 rv = 1;
1368 break;
1369 }
f9ce90ba 1370
7f91af49 1371 rv = Create(ss, devlist->devname, chunk, level, layout, size<0 ? 0 : size,
05697ec1 1372 raiddisks, sparedisks, ident.name, homehost,
3d3dd91e 1373 ident.uuid_set ? ident.uuid : NULL,
72d566f6
N
1374 devs_found-1, devlist->next, runstop,
1375 readonly, verbose-quiet, force, assume_clean,
7f91af49 1376 bitmap_file, bitmap_chunk, write_behind, delay, autof);
52826846 1377 break;
e0d19036 1378 case MISC:
e0d19036
NB
1379 if (devmode == 'E') {
1380 if (devlist == NULL && !scan) {
e7b84f9d 1381 pr_err("No devices to examine\n");
e0d19036
NB
1382 exit(2);
1383 }
1384 if (devlist == NULL)
8aec876d 1385 devlist = conf_get_devs();
e0d19036 1386 if (devlist == NULL) {
e7b84f9d 1387 pr_err("No devices listed in %s\n", configfile?configfile:DefaultConfFile);
e0d19036
NB
1388 exit(1);
1389 }
e843d5d7
NB
1390 if (brief && verbose)
1391 brief = 2;
0d726f17
KS
1392 rv = Examine(devlist, scan?(verbose>1?0:verbose+1):brief,
1393 export, scan,
1394 SparcAdjust, ss, homehost);
4cce4069
DW
1395 } else if (devmode == DetailPlatform) {
1396 rv = Detail_Platform(ss ? ss->ss : NULL, ss ? scan : 1, verbose);
7d27d1c0
N
1397 } else if (devlist == NULL) {
1398 if (devmode == 'S' && scan)
1399 rv = stop_scan(quiet);
1400 else if ((devmode == 'D' || devmode == Waitclean) && scan)
1401 rv = misc_scan(devmode, verbose, export,
1402 test, homehost, prefer);
1403 else if (devmode == UdevRules)
1404 rv = Write_rules(udev_filename);
1405 else {
e7b84f9d 1406 pr_err("No devices given.\n");
7d27d1c0 1407 exit(2);
e0d19036 1408 }
7d27d1c0
N
1409 } else
1410 rv = misc_list(devlist, brief, verbose, export, test,
1411 homehost, prefer, subarray, update,
1412 &ident,
1413 ss, force, quiet);
9a9dab36 1414 break;
e0d19036 1415 case MONITOR:
e0d19036 1416 if (!devlist && !scan) {
e7b84f9d 1417 pr_err("Cannot monitor: need --scan or at least one device\n");
e0d19036
NB
1418 rv = 1;
1419 break;
1420 }
b5e64645 1421 if (pidfile && !daemonise) {
e7b84f9d 1422 pr_err("Cannot write a pid file when not in daemon mode\n");
b5e64645
NB
1423 rv = 1;
1424 break;
1425 }
ddc7201f 1426 if (delay == 0) {
3e82d76d 1427 if (get_linux_version() > 2006016)
ddc7201f
N
1428 /* mdstat responds to poll */
1429 delay = 1000;
1430 else
1431 delay = 60;
1432 }
d013a55e 1433 rv= Monitor(devlist, mailaddr, program,
773135f5 1434 delay?delay:60, daemonise, scan, oneshot,
c2ecf5f6
N
1435 dosyslog, test, pidfile, increments,
1436 spare_sharing, prefer);
9a9dab36 1437 break;
dd0781e5
NB
1438
1439 case GROW:
84e11361
N
1440 if (array_size >= 0) {
1441 /* alway impose array size first, independent of
1442 * anything else
9ce510be
N
1443 * Do not allow level or raid_disks changes at the
1444 * same time as that can be irreversibly destructive.
84e11361
N
1445 */
1446 struct mdinfo sra;
1447 int err;
9ce510be 1448 if (raiddisks || level != UnSet) {
e7b84f9d 1449 pr_err("cannot change array size in same operation "
9ce510be
N
1450 "as changing raiddisks or level.\n"
1451 " Change size first, then check that data is still intact.\n");
1452 rv = 1;
1453 break;
1454 }
84e11361
N
1455 sysfs_init(&sra, mdfd, 0);
1456 if (array_size == 0)
1457 err = sysfs_set_str(&sra, NULL, "array_size", "default");
1458 else
1459 err = sysfs_set_num(&sra, NULL, "array_size", array_size / 2);
1460 if (err < 0) {
1461 if (errno == E2BIG)
e7b84f9d 1462 pr_err("--array-size setting"
84e11361
N
1463 " is too large.\n");
1464 else
e7b84f9d 1465 pr_err("current kernel does"
84e11361
N
1466 " not support setting --array-size\n");
1467 rv = 1;
1468 break;
1469 }
1470 }
e2e53a2d 1471 if (devs_found > 1 && raiddisks == 0) {
e5329c37 1472 /* must be '-a'. */
e2e53a2d 1473 if (size >= 0 || chunk || layout_str != NULL || bitmap_file) {
e7b84f9d 1474 pr_err("--add cannot be used with "
e2e53a2d 1475 "other geometry changes in --grow mode\n");
e5329c37
NB
1476 rv = 1;
1477 break;
1478 }
1479 for (dv=devlist->next; dv ; dv=dv->next) {
e2e53a2d
N
1480 rv = Grow_Add_device(devlist->devname, mdfd,
1481 dv->devname);
e5329c37
NB
1482 if (rv)
1483 break;
1484 }
7236ee7a 1485 } else if (bitmap_file) {
e2e53a2d 1486 if (size >= 0 || raiddisks || chunk ||
1d8862cf 1487 layout_str != NULL || devs_found > 1) {
e7b84f9d 1488 pr_err("--bitmap changes cannot be "
e2e53a2d
N
1489 "used with other geometry changes "
1490 "in --grow mode\n");
7236ee7a
N
1491 rv = 1;
1492 break;
1493 }
1494 if (delay == 0)
1495 delay = DEFAULT_BITMAP_DELAY;
f5e166fe 1496 rv = Grow_addbitmap(devlist->devname, mdfd, bitmap_file,
8fac0577 1497 bitmap_chunk, delay, write_behind, force);
2dddadb0
AK
1498 } else if (grow_continue)
1499 rv = Grow_continue_command(devlist->devname,
1500 mdfd, backup_file,
1501 verbose);
1502 else if (size >= 0 || raiddisks != 0 || layout_str != NULL
7d27d1c0 1503 || chunk != 0 || level != UnSet) {
7236ee7a 1504 rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file,
691a36b7 1505 size, level, layout_str, chunk, raiddisks,
e2e53a2d 1506 devlist->next,
ce52f92f 1507 assume_clean, force);
84e11361 1508 } else if (array_size < 0)
e7b84f9d 1509 pr_err("no changes to --grow\n");
dd0781e5 1510 break;
8382f19b
NB
1511 case INCREMENTAL:
1512 if (rebuild_map) {
1513 RebuildMap();
1514 }
1515 if (scan) {
1516 if (runstop <= 0) {
e7b84f9d 1517 pr_err("--incremental --scan meaningless without --run.\n");
8382f19b
NB
1518 break;
1519 }
29ba4804 1520 if (devmode == 'f') {
e7b84f9d 1521 pr_err("--incremental --scan --fail not supported.\n");
29ba4804
N
1522 break;
1523 }
8382f19b
NB
1524 rv = IncrementalScan(verbose);
1525 }
1526 if (!devlist) {
1527 if (!rebuild_map && !scan) {
e7b84f9d 1528 pr_err("--incremental requires a device.\n");
8382f19b
NB
1529 rv = 1;
1530 }
1531 break;
1532 }
1533 if (devlist->next) {
e7b84f9d 1534 pr_err("--incremental can only handle one device.\n");
8382f19b
NB
1535 rv = 1;
1536 break;
1537 }
950bc344
PC
1538 if (devmode == 'f')
1539 rv = IncrementalRemove(devlist->devname, remove_path,
1540 verbose-quiet);
1541 else
1542 rv = Incremental(devlist->devname, verbose-quiet,
1543 runstop, ss, homehost,
b76b30e0
AK
1544 require_homehost, autof,
1545 freeze_reshape);
1f48664b
NB
1546 break;
1547 case AUTODETECT:
1548 autodetect();
1549 break;
64c4757e 1550 }
52826846 1551 exit(rv);
64c4757e 1552}
3cbc4d12
N
1553
1554static int scan_assemble(int autof, struct supertype *ss,
1555 int readonly, int runstop,
1556 struct mddev_ident *ident,
1557 char *homehost, int require_homehost,
1558 int verbose, int force,
1559 int freeze_reshape)
1560{
1561 struct mddev_ident *a, *array_list = conf_get_ident(NULL);
1562 struct mddev_dev *devlist = conf_get_devs();
1563 struct map_ent *map = NULL;
1564 int cnt = 0;
1565 int rv = 0;
1566 int failures, successes;
1567
1568 if (conf_verify_devnames(array_list)) {
e7b84f9d
N
1569 pr_err("Duplicate MD device names in "
1570 "conf file were found.\n");
3cbc4d12
N
1571 return 1;
1572 }
1573 if (devlist == NULL) {
e7b84f9d 1574 pr_err("No devices listed in conf file were found.\n");
3cbc4d12
N
1575 return 1;
1576 }
1577 for (a = array_list; a ; a = a->next) {
1578 a->assembled = 0;
1579 if (a->autof == 0)
1580 a->autof = autof;
1581 }
1582 if (map_lock(&map))
e7b84f9d
N
1583 pr_err("%s: failed to get "
1584 "exclusive lock on mapfile\n",
1585 __func__);
3cbc4d12
N
1586 do {
1587 failures = 0;
1588 successes = 0;
1589 rv = 0;
1590 for (a = array_list; a ; a = a->next) {
1591 int r;
1592 if (a->assembled)
1593 continue;
1594 if (a->devname &&
1595 strcasecmp(a->devname, "<ignore>") == 0)
1596 continue;
1597
1598 r = Assemble(ss, a->devname,
1599 a,
1600 NULL, NULL, 0,
1601 readonly, runstop, NULL,
1602 homehost, require_homehost,
1603 verbose, force,
1604 freeze_reshape);
1605 if (r == 0) {
1606 a->assembled = 1;
1607 successes++;
1608 } else
1609 failures++;
1610 rv |= r;
1611 cnt++;
1612 }
1613 } while (failures && successes);
1614 if (homehost && cnt == 0) {
1615 /* Maybe we can auto-assemble something.
1616 * Repeatedly call Assemble in auto-assemble mode
1617 * until it fails
1618 */
1619 int rv2;
1620 int acnt;
1621 ident->autof = autof;
1622 do {
1623 struct mddev_dev *devlist = conf_get_devs();
1624 acnt = 0;
1625 do {
1626 rv2 = Assemble(ss, NULL,
1627 ident,
1628 devlist, NULL, 0,
1629 readonly,
1630 runstop, NULL,
1631 homehost,
1632 require_homehost,
1633 verbose,
1634 force,
1635 freeze_reshape);
1636 if (rv2==0) {
1637 cnt++;
1638 acnt++;
1639 }
1640 } while (rv2!=2);
1641 /* Incase there are stacked devices, we need to go around again */
1642 } while (acnt);
1643 if (cnt == 0 && rv == 0) {
e7b84f9d 1644 pr_err("No arrays found in config file or automatically\n");
3cbc4d12
N
1645 rv = 1;
1646 } else if (cnt)
1647 rv = 0;
1648 } else if (cnt == 0 && rv == 0) {
e7b84f9d 1649 pr_err("No arrays found in config file\n");
3cbc4d12
N
1650 rv = 1;
1651 }
1652 map_unlock(&map);
1653 return rv;
1654}
7d27d1c0
N
1655
1656static int misc_scan(char devmode, int verbose, int export, int test,
1657 char *homehost, char *prefer)
1658{
1659 /* apply --detail or --wait-clean to
1660 * all devices in /proc/mdstat
1661 */
1662 struct mdstat_ent *ms = mdstat_read(0, 1);
1663 struct mdstat_ent *e;
1664 struct map_ent *map = NULL;
1665 int members;
1666 int v = verbose>1?0:verbose+1;
1667 int rv = 0;
1668
1669 for (members = 0; members <= 1; members++) {
1670 for (e=ms ; e ; e=e->next) {
1671 char *name;
1672 struct map_ent *me;
1673 int member = e->metadata_version &&
1674 strncmp(e->metadata_version,
1675 "external:/", 10) == 0;
1676 if (members != member)
1677 continue;
1678 me = map_by_devnum(&map, e->devnum);
1679 if (me && me->path
1680 && strcmp(me->path, "/unknown") != 0)
1681 name = me->path;
1682 else
1683 name = get_md_name(e->devnum);
1684
1685 if (!name) {
e7b84f9d 1686 pr_err("cannot find device file for %s\n",
7d27d1c0
N
1687 e->dev);
1688 continue;
1689 }
1690 if (devmode == 'D')
1691 rv |= Detail(name, v,
1692 export, test,
1693 homehost, prefer);
1694 else
1695 rv |= WaitClean(name, -1, v);
1696 put_md_name(name);
1697 }
1698 }
1699 free_mdstat(ms);
1700 return rv;
1701}
1702
1703static int stop_scan(int quiet)
1704{
1705 /* apply --stop to all devices in /proc/mdstat */
1706 /* Due to possible stacking of devices, repeat until
1707 * nothing more can be stopped
1708 */
1709 int progress=1, err;
1710 int last = 0;
1711 int rv = 0;
1712 do {
1713 struct mdstat_ent *ms = mdstat_read(0, 0);
1714 struct mdstat_ent *e;
1715
1716 if (!progress) last = 1;
1717 progress = 0; err = 0;
1718 for (e=ms ; e ; e=e->next) {
1719 char *name = get_md_name(e->devnum);
1720 int mdfd;
1721
1722 if (!name) {
e7b84f9d 1723 pr_err("cannot find device file for %s\n",
7d27d1c0
N
1724 e->dev);
1725 continue;
1726 }
1727 mdfd = open_mddev(name, 1);
1728 if (mdfd >= 0) {
1729 if (Manage_runstop(name, mdfd, -1, quiet?1:last?0:-1))
1730 err = 1;
1731 else
1732 progress = 1;
1733 close(mdfd);
1734 }
1735
1736 put_md_name(name);
1737 }
1738 free_mdstat(ms);
1739 } while (!last && err);
1740 if (err)
1741 rv |= 1;
1742 return rv;
1743}
1744
1745static int misc_list(struct mddev_dev *devlist,
1746 int brief, int verbose, int export, int test,
1747 char *homehost, char *prefer, char *subarray,
1748 char *update, struct mddev_ident *ident,
1749 struct supertype *ss, int force, int quiet)
1750{
1751 struct mddev_dev *dv;
1752 int rv = 0;
1753
1754 for (dv=devlist ; dv; dv=dv->next) {
1755 int mdfd;
1756
1757 switch(dv->disposition) {
1758 case 'D':
1759 rv |= Detail(dv->devname,
1760 brief?1+verbose:0,
1761 export, test, homehost, prefer);
1762 continue;
1763 case KillOpt: /* Zero superblock */
1764 if (ss)
1765 rv |= Kill(dv->devname, ss, force, quiet,0);
1766 else {
1767 int q = quiet;
1768 do {
1769 rv |= Kill(dv->devname, NULL, force, q, 0);
1770 q = 1;
1771 } while (rv == 0);
1772 rv &= ~2;
1773 }
1774 continue;
1775 case 'Q':
1776 rv |= Query(dv->devname); continue;
1777 case 'X':
1778 rv |= ExamineBitmap(dv->devname, brief, ss); continue;
1779 case 'W':
1780 case WaitOpt:
1781 rv |= Wait(dv->devname); continue;
1782 case Waitclean:
1783 rv |= WaitClean(dv->devname, -1, verbose-quiet); continue;
1784 case KillSubarray:
1785 rv |= Kill_subarray(dv->devname, subarray, quiet);
1786 continue;
1787 case UpdateSubarray:
1788 if (update == NULL) {
e7b84f9d 1789 pr_err("-U/--update must be specified with --update-subarray\n");
7d27d1c0
N
1790 rv |= 1;
1791 continue;
1792 }
1793 rv |= Update_subarray(dv->devname, subarray,
1794 update, ident, quiet);
1795 continue;
1796 }
1797 mdfd = open_mddev(dv->devname, 1);
1798 if (mdfd>=0) {
1799 switch(dv->disposition) {
1800 case 'R':
1801 rv |= Manage_runstop(dv->devname, mdfd, 1, quiet); break;
1802 case 'S':
1803 rv |= Manage_runstop(dv->devname, mdfd, -1, quiet); break;
1804 case 'o':
1805 rv |= Manage_ro(dv->devname, mdfd, 1); break;
1806 case 'w':
1807 rv |= Manage_ro(dv->devname, mdfd, -1); break;
1808 }
1809 close(mdfd);
1810 } else
1811 rv |= 1;
1812 }
1813 return rv;
1814}