mdctl-0.5
[thirdparty/mdadm.git] / mdctl.c
CommitLineData
64c4757e
NB
1/*
2 * mdctl - manage Linux "md" devices aka RAID arrays.
3 *
4 * Copyright (C) 2001 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 "mdctl.h"
31#include "md_p.h"
32
52826846 33int open_mddev(char *dev)
64c4757e 34{
52826846
NB
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;
64c4757e 44 }
52826846
NB
45 return mdfd;
46}
64c4757e 47
64c4757e 48
52826846
NB
49
50int main(int argc, char *argv[])
51{
52 char mode = '\0';
53 int opt;
54 char *help_text;
55 char *c;
56 int rv;
57 int i;
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 int scan = 0;
68 char devmode = 0;
69 int runstop = 0;
70 int readonly = 0;
71 char *devs[MD_SB_DISKS+1];
72 int devmodes[MD_SB_DISKS+1];
73 int devs_found = 0;
74 int verbose = 0;
75 int force = 0;
76
77 char *mailaddr = NULL;
78 char *program = NULL;
79 int delay = 0;
80
81 int mdfd = -1;
82
83 ident.uuid_set=0;
84 ident.super_minor= -1;
85 ident.devices=0;
86
87 while ((opt=getopt_long(argc, argv,
88 short_options, long_options,
89 NULL)) != -1) {
90
91 switch(opt) {
92 case '@': /* just incase they say --manage */
93 case 'A':
94 case 'B':
95 case 'C':
96 case 'D':
97 case 'E':
98 case 'F':
99 /* setting mode - only once */
100 if (mode) {
101 fprintf(stderr, Name ": --%s/-%c not allowed, mode already set to %s\n",
102 long_options[opt-'A'+1].name,
103 long_options[opt-'A'+1].val,
104 long_options[mode-'A'+1].name);
105 exit(2);
106 }
107 mode = opt;
108 continue;
109
110 case 'h':
111 help_text = Help;
112 switch (mode) {
113 case 'C': help_text = Help_create; break;
114 case 'B': help_text = Help_build; break;
115 case 'A': help_text = Help_assemble; break;
116 }
117 fputs(help_text,stderr);
118 exit(0);
119
120 case 'V':
121 fputs(Version, stderr);
122 exit(0);
123
124 case 'v': verbose = 1;
125 continue;
126
127 case 1: /* an undecorated option - must be a device name.
128 * Depending on mode, it could be that:
129 * All devices listed are "md" devices : --Detail, -As
130 * No devices are "md" devices : --Examine
131 * First device is "md", others are component: -A,-B,-C
132 */
133 if (devs_found >= MD_SB_DISKS+1) {
134 fprintf(stderr, Name ": too many devices at %s - current limit -s %d\n",
135 optarg, MD_SB_DISKS+1);
136 exit(2);
137 }
138 devs[devs_found] = optarg;
139 devmodes[devs_found] = devmode;
140 devs_found++;
141 continue;
142
143 case ':':
144 case '?':
145 fputs(Usage, stderr);
682c7051 146 exit(2);
52826846
NB
147 default:
148 /* force mode setting - @==manage if nothing else */
149 if (!mode) mode = '@';
682c7051 150 }
682c7051 151
52826846
NB
152 /* We've got a mode, and opt is now something else which
153 * could depend on the mode */
154#define O(a,b) ((a<<8)|b)
155 switch (O(mode,opt)) {
156 case O('C','c'):
157 case O('B','c'): /* chunk or rounding */
158 if (chunk) {
159 fprintf(stderr, Name ": chunk/rounding may only be specified once. "
160 "Second value is %s.\n", optarg);
161 exit(2);
162 }
163 chunk = strtol(optarg, &c, 10);
164 if (!optarg[0] || *c || chunk<4 || ((chunk-1)&chunk)) {
165 fprintf(stderr, Name ": invalid chunk/rounding value: %s\n",
166 optarg);
167 exit(2);
168 }
169 continue;
64c4757e 170
52826846
NB
171 case O('C','z'): /* size */
172 if (size) {
173 fprintf(stderr, Name ": size may only be specified once. "
174 "Second value is %s.\n", optarg);
175 exit(2);
176 }
177 size = strtol(optarg, &c, 10);
178 if (!optarg[0] || *c || size < 4) {
179 fprintf(stderr, Name ": invalid size: %s\n",
180 optarg);
181 exit(2);
182 }
183 continue;
64c4757e 184
52826846
NB
185 case O('C','l'):
186 case O('B','l'): /* set raid level*/
187 if (level != -10) {
188 fprintf(stderr, Name ": raid level may only be set once. "
189 "Second value is %s.\n", optarg);
190 exit(2);
191 }
192 level = map_name(pers, optarg);
193 if (level == -10) {
194 fprintf(stderr, Name ": invalid raid level: %s\n",
195 optarg);
196 exit(2);
197 }
198 if (level > 0 && mode == 'B') {
199 fprintf(stderr, Name ": Raid level %s not permitted with --build.\n",
200 optarg);
201 exit(2);
202 }
203 if (sparedisks > 0 && level < 1) {
204 fprintf(stderr, Name ": raid level %s is incompatible with spare-disks setting.\n",
205 optarg);
206 exit(2);
207 }
208 continue;
64c4757e 209
52826846
NB
210 case O('C','p'): /* raid5 layout */
211 if (layout >= 0) {
212 fprintf(stderr,Name ": layout may only be sent once. "
213 "Second value was %s\n", optarg);
214 exit(2);
215 }
216 switch(level) {
217 default:
218 fprintf(stderr, Name ": layout now meaningful for %s arrays.\n",
219 map_num(pers, level));
220 exit(2);
221 case -10:
222 fprintf(stderr, Name ": raid level must be given before layout.\n");
223 exit(2);
224
225 case 5:
226 layout = map_name(r5layout, optarg);
227 if (layout==-10) {
228 fprintf(stderr, Name ": layout %s not understood for raid5.\n",
229 optarg);
230 exit(2);
231 }
232 break;
233 }
234 continue;
235
236 case O('C','n'):
237 case O('B','n'): /* number of raid disks */
238 if (raiddisks) {
239 fprintf(stderr, Name ": raid-disks set twice: %d and %s\n",
240 raiddisks, optarg);
241 exit(2);
242 }
243 raiddisks = strtol(optarg, &c, 10);
244 if (!optarg[0] || *c || raiddisks<=0 || raiddisks > MD_SB_DISKS) {
245 fprintf(stderr, Name ": invalid number of raid disks: %s\n",
246 optarg);
247 exit(2);
248 }
249 continue;
250
251 case O('C','x'): /* number of spare (eXtra) discs */
252 if (sparedisks) {
253 fprintf(stderr,Name ": spare-disks set twice: %d and %s\n",
254 sparedisks, optarg);
255 exit(2);
256 }
257 if (level > -10 && level < 1) {
258 fprintf(stderr, Name ": spare-disks setting is incompatible with raid level %d\n",
259 level);
260 exit(2);
261 }
262 sparedisks = strtol(optarg, &c, 10);
263 if (!optarg[0] || *c || sparedisks < 0 || sparedisks > MD_SB_DISKS - raiddisks) {
264 fprintf(stderr, Name ": invalid number of spare disks: %s\n",
265 optarg);
266 exit(2);
267 }
268 continue;
269 case O('C','f'): /* force honouring of device list */
270 force=1;
271 continue;
272
273 /* now for the Assemble options */
274 case O('A','f'): /* force assembly */
275 force = 1;
276 continue;
277 case O('A','u'): /* uuid of array */
278 if (ident.uuid_set) {
279 fprintf(stderr, Name ": uuid cannot bet set twice. "
280 "Second value %s.\n", optarg);
281 exit(2);
282 }
283 if (parse_uuid(optarg, ident.uuid))
284 ident.uuid_set = 1;
285 else {
286 fprintf(stderr,Name ": Bad uuid: %s\n", optarg);
287 exit(2);
288 }
289 continue;
290
291 case O('A','c'): /* config file */
292 case O('F','c'):
293 if (configfile) {
294 fprintf(stderr, Name ": configfile cannot be set twice. "
295 "Second value is %s.\n", optarg);
296 exit(2);
297 }
298 configfile = optarg;
299 /* FIXME possibly check that config file exists. Even parse it */
300 continue;
301 case O('A','s'): /* scan */
302 scan = 1;
303 continue;
304
305 case O('F','m'): /* mail address */
306 if (mailaddr)
307 fprintf(stderr, Name ": only specify one mailaddress. %s ignored.\n",
308 optarg);
309 else
310 mailaddr = optarg;
311 continue;
312
313 case O('F','p'): /* alert program */
314 if (program)
315 fprintf(stderr, Name ": only specify one alter program. %s ignored.\n",
316 optarg);
317 else
318 program = optarg;
319 continue;
64c4757e 320
52826846
NB
321 case O('F','d'): /* delay in seconds */
322 if (delay)
323 fprintf(stderr, Name ": only specify delay once. %s ignored.\n",
324 optarg);
325 else {
326 delay = strtol(optarg, &c, 10);
327 if (!optarg[0] || *c || delay<1) {
328 fprintf(stderr, Name ": invalid delay: %s\n",
329 optarg);
330 exit(2);
331 }
332 }
333 continue;
334
335
336 /* now the general management options. Some are applicable
337 * to other modes. None have arguments.
338 */
339 case O('@','a'):
340 case O('C','a'):
341 case O('B','a'):
342 case O('A','a'): /* add a drive */
343 devmode = 'a';
344 continue;
345 case O('@','r'): /* remove a drive */
346 devmode = 'r';
347 continue;
348 case O('@','f'): /* set faulty */
349 devmode = 'f';
350 continue;
351 case O('@','R'):
352 case O('A','R'):
353 case O('B','R'):
354 case O('C','R'): /* Run the array */
355 if (runstop < 0) {
356 fprintf(stderr, Name ": Cannot both Stop and Run an array\n");
357 exit(2);
358 }
359 runstop = 1;
360 continue;
361 case O('@','S'):
362 if (runstop > 0) {
363 fprintf(stderr, Name ": Cannot both Run and Stop an array\n");
364 exit(2);
365 }
366 runstop = -1;
367 continue;
368
369 case O('@','o'):
370 if (readonly < 0) {
371 fprintf(stderr, Name ": Cannot have both readonly and readwrite\n");
372 exit(2);
373 }
374 readonly = 1;
375 continue;
376 case O('@','w'):
377 if (readonly > 0) {
378 fprintf(stderr, "mkdctl: Cannot have both readwrite and readonly.\n");
379 exit(2);
380 }
381 readonly = -1;
382 continue;
383 }
384 /* We have now processed all the valid options. Anything else is
385 * an error
386 */
387 fprintf(stderr, Name ": option %c not valid in mode %c\n",
388 opt, mode);
64c4757e 389 exit(2);
52826846
NB
390
391 }
392
393 if (!mode) {
394 fputs(Usage, stderr);
64c4757e 395 exit(2);
64c4757e 396 }
52826846
NB
397 /* Ok, got the option parsing out of the way
398 * hopefully it's mostly right but there might be some stuff
399 * missing
400 *
401 * That is mosty checked in ther per-mode stuff but...
402 *
403 * For @,B,C and A without -s, the first device listed must be an md device
404 * we check that here and open it.
64c4757e 405 */
52826846
NB
406
407 if (mode=='@' || mode == 'B' || mode == 'C' || (mode == 'A' && ! scan)) {
408 if (devs_found < 1) {
409 fprintf(stderr, Name ": an md device must be given in this mode\n");
410 exit(2);
411 }
412 mdfd = open_mddev(devs[0]);
413 if (mdfd < 0)
414 exit(1);
64c4757e 415 }
52826846
NB
416
417
418 rv = 0;
419 switch(mode) {
420 case '@':/* Management */
421 /* readonly, add/remove, readwrite, runstop */
422 if (readonly>0)
423 rv = Manage_ro(devs[0], mdfd, readonly);
424 if (!rv && devs_found>1)
425 rv = Manage_subdevs(devs[0], mdfd,
426 devs_found-1, devs+1, devmodes+1);
427 if (!rv && readonly < 0)
428 rv = Manage_ro(devs[0], mdfd, readonly);
429 if (!rv && runstop)
430 rv = Manage_runstop(devs[0], mdfd, runstop);
431 break;
432 case 'A': /* Assemble */
433 if (!scan)
434 rv = Assemble(devs[0], mdfd, &ident, configfile,
435 devs_found-1, devs+1,
436 readonly, runstop, verbose, force);
437 else if (devs_found>0)
438 for (i=0; i<devs_found; i++) {
439 mddev_ident_t array_ident = conf_get_ident(configfile, devs[i]);
440 mdfd = open_mddev(devs[i]);
441 if (mdfd < 0) {
442 rv |= 1;
443 continue;
444 }
445 if (array_ident == NULL) {
446 fprintf(stderr, Name ": %s not identified in config file.\n",
447 devs[i]);
448 rv |= 1;
449 continue;
450 }
451 rv |= Assemble(devs[i], mdfd, array_ident, configfile,
452 0, NULL,
453 readonly, runstop, verbose, force);
454 }
455 else {
456 mddev_ident_t array_list = conf_get_ident(configfile, NULL);
457 if (!array_list) {
458 fprintf(stderr, Name ": No arrays found in config file\n");
459 rv = 1;
460 } else
461 for (; array_list; array_list = array_list->next) {
462 mdfd = open_mddev(array_list->devname);
463 if (mdfd < 0) {
464 rv |= 1;
465 continue;
466 }
467 rv |= Assemble(array_list->devname, mdfd,
468 array_list, configfile,
469 0, NULL,
470 readonly, runstop, verbose, force);
471 }
472 }
473 break;
474 case 'B': /* Build */
475 rv = Build(devs[0], mdfd, chunk, level, raiddisks, devs_found-1,devs+1);
476 break;
477 case 'C': /* Create */
478 rv = Create(devs[0], mdfd, chunk, level, layout, size,
479 raiddisks, sparedisks,
480 devs_found-1,devs+1, runstop, verbose, force);
481 break;
482 case 'D': /* Detail */
483 for (i=0; i<devs_found; i++)
484 rv |= Detail(devs[i]);
485 break;
486 case 'E': /* Examine */
487 for (i=0; i<devs_found; i++)
488 rv |= Examine(devs[i]);
489 break;
490 case 'F': /* Follow */
491 rv= Monitor(devs_found, devs, mailaddr, program,
492 delay?delay:60, configfile);
64c4757e 493 }
52826846 494 exit(rv);
64c4757e 495}