source: MondoRescue/branches/stable/mondo/mondo/common/libmondo-raid.c@ 541

Last change on this file since 541 was 541, checked in by bcornec, 18 years ago

Stable is reverted to r436 (2.0.7) to put it in line with 2.0.8 and start from there over

  • Property svn:keywords set to Id
File size: 26.9 KB
Line 
1/* libmondo-raid.c subroutines for handling RAID
2 $Id: libmondo-raid.c 541 2006-05-13 18:47:23Z bcornec $
3.
4
5
606/29
7- added create_raidtab_from_mdstat()
8- changed char[MAX_STR_LEN] to char*
9
1010/21/2003
11- get_next_raidtab_line() --- correctly handle multiple spaces
12 between label and value
13
1407/03
15- line 447 - changed assert()
16
1705/08
18- cleaned up some FreeBSd-specific stuff
19
2005/05
21- added Joshua Oreman's FreeBSD patches
22
2304/25
24- added a bunch of RAID utilities from mondorestore/mondo-restore.c
25
2604/24/2003
27- added some assert()'s and log_OS_error()'s
28
2910/19/2002
30- added some comments
31
3207/24
33- created
34*/
35
36
37/**
38 * @file
39 * Functions for handling RAID (especially during restore).
40 */
41
42#include "my-stuff.h"
43#include "mondostructures.h"
44#include "libmondo-gui-EXT.h"
45#include "libmondo-files-EXT.h"
46#include "libmondo-tools-EXT.h"
47#include "libmondo-string-EXT.h"
48#include "lib-common-externs.h"
49#include "libmondo-raid.h"
50
51#ifdef __FreeBSD__
52/* Nonstandard library functions: */
53extern void errx(int exitval, const char *fmt, ...);
54extern char *strsep(char **stringp, const char *delim);
55#endif
56
57/*@unused@*/
58//static char cvsid[] = "$Id: libmondo-raid.c 541 2006-05-13 18:47:23Z bcornec $";
59
60
61/**
62 * @addtogroup raidGroup
63 * @{
64 */
65/**
66 * See if a particular RAID level is supported by the kernel.
67 * @param raidno The RAID level (-1 through 5) to check. -1 means "linear" under Linux and
68 * "concatenated" under FreeBSD. It's really the same thing, just different wording.
69 * @return TRUE if it's supported, FALSE if not.
70 */
71bool is_this_raid_personality_registered(int raidno)
72{
73#ifdef __FreeBSD__
74 return ((raidno == -1) || (raidno == 0) || (raidno == 1)
75 || (raidno == 5)) ? TRUE : FALSE;
76#else
77 /*@ buffer ********************************************************** */
78 char *command;
79 int res;
80
81 command = malloc(MAX_STR_LEN * 2);
82 strcpy(command, "grep \" /proc/mdstat");
83 if (raidno == -1) {
84 strcat(command, "linear");
85 } else {
86 sprintf(command + strlen(command), "raid%d", raidno);
87 }
88 strcat(command, "\" > /dev/null 2> /dev/null");
89 log_it("Is raid %d registered? Command = '%s'", raidno, command);
90 res = system(command);
91 paranoid_free(command);
92 if (res) {
93 return (FALSE);
94 } else {
95 return (TRUE);
96 }
97#endif
98}
99
100
101
102
103
104
105/**
106 * Search for @p device in @p disklist.
107 * @param disklist The disklist to search in.
108 * @param device The device to search for.
109 * @return The index number of @p device, or -1 if it does not exist.
110 */
111int
112where_in_drivelist_is_drive(struct list_of_disks *disklist, char *device)
113{
114
115 /*@ int ************************************************************* */
116 int i = 0;
117
118 assert(disklist != NULL);
119 assert_string_is_neither_NULL_nor_zerolength(device);
120
121 for (i = 0; i < disklist->entries; i++) {
122 if (!strcmp(disklist->el[i].device, device)) {
123 break;
124 }
125 }
126 if (i == disklist->entries) {
127 return (-1);
128 } else {
129 return (i);
130 }
131}
132
133
134
135
136
137
138
139
140/**
141 * Determine which RAID device is using a particular partition.
142 * @param raidlist The RAID information structure.
143 * @param device The partition to find out about.
144 * @return The index number of the RAID device using @p device, or -1 if there is none.
145 */
146int
147which_raid_device_is_using_this_partition(struct raidlist_itself *raidlist,
148 char *device)
149{
150#ifdef __FreeBSD__
151// FreeBSD-specific version of which_raid_device_is_using_this_partition()
152 /*@ int ********************************************************* */
153 int i = 0;
154
155 for (i = 0; i < raidlist->entries; i++) {
156 bool thisone = FALSE;
157 int j, k, l;
158
159 for (j = 0; j < raidlist->el[i].plexes; ++j) {
160 for (k = 0; k < raidlist->el[i].plex[j].subdisks; ++k) {
161 for (l = 0; l < raidlist->disks.entries; ++l) {
162 if (!strcmp(raidlist->disks.el[l].device,
163 device) &&
164 !strcmp(raidlist->el[i].plex[j].sd[k].which_device,
165 raidlist->disks.el[l].name))
166 thisone = TRUE;
167 }
168 }
169 }
170
171 if (thisone) {
172 break;
173 }
174 }
175 if (i == raidlist->entries) {
176 return (-1);
177 } else {
178 return (i);
179 }
180}
181
182#else
183// Linux-specific version of which_raid_device_is_using_this_partition()
184// and one other function which FreeBSD doesn't use
185
186 int current_raiddev = 0;
187
188 assert_string_is_neither_NULL_nor_zerolength(device);
189 assert(raidlist != NULL);
190
191 for (current_raiddev = 0; current_raiddev < raidlist->entries;
192 current_raiddev++) {
193 if (where_in_drivelist_is_drive
194 (&raidlist->el[current_raiddev].data_disks, device) >= 0
195 || where_in_drivelist_is_drive(&raidlist->el[current_raiddev].
196 spare_disks, device) >= 0
197 || where_in_drivelist_is_drive(&raidlist->el[current_raiddev].
198 parity_disks, device) >= 0
199 || where_in_drivelist_is_drive(&raidlist->el[current_raiddev].
200 failed_disks, device) >= 0) {
201 break;
202 }
203 }
204 if (current_raiddev == raidlist->entries) {
205 return (-1);
206 } else {
207 return (current_raiddev);
208 }
209}
210
211/**
212 * Write an @c int variable to a list of RAID variables.
213 * @param raidrec The RAID device record to write to.
214 * @param lino The variable index number to modify/create.
215 * @param label The label to write.
216 * @param value The value to write.
217 */
218void
219write_variableINT_to_raid_var_line(struct raid_device_record *raidrec,
220 int lino, char *label, int value)
221{
222 /*@ buffers ***************************************************** */
223 char *sz_value;
224
225 malloc_string(sz_value);
226 assert(raidrec != NULL);
227 assert(label != NULL);
228
229 sprintf(sz_value, "%d", value);
230 strcpy(raidrec->additional_vars.el[lino].label, label);
231 strcpy(raidrec->additional_vars.el[lino].value, sz_value);
232 paranoid_free(sz_value);
233}
234#endif
235
236
237
238
239
240
241
242
243#ifdef __FreeBSD__
244/**
245 * Add a disk to a RAID plex.
246 * @param p The plex to add the device to.
247 * @param device_to_add The device to add to @p p.
248 */
249void add_disk_to_raid_device(struct vinum_plex *p, char *device_to_add)
250{
251 strcpy(p->sd[p->subdisks].which_device, device_to_add);
252 ++p->subdisks;
253
254}
255#else
256/**
257 * Add a disk to a RAID device.
258 * @param disklist The disklist to add the device to.
259 * @param device_to_add The device to add to @p disklist.
260 * @param index The index number of the disklist entry we're creating.
261 */
262void add_disk_to_raid_device(struct list_of_disks *disklist,
263 char *device_to_add, int index)
264{
265 int items;
266
267 assert(disklist != NULL);
268 assert_string_is_neither_NULL_nor_zerolength(device_to_add);
269 items = disklist->entries;
270 strcpy(disklist->el[items].device, device_to_add);
271 disklist->el[items].index = index;
272 items++;
273 disklist->entries = items;
274}
275#endif
276
277
278/**
279 * Save the additional RAID variables to a stream.
280 * @param vars The RAID variable list to save.
281 * @param fout The FILE pointer to save them to.
282 */
283void
284save_additional_vars_to_file(struct additional_raid_variables *vars,
285 FILE * fout)
286{
287 int i;
288
289 assert(vars != NULL);
290 assert(fout != NULL);
291
292 for (i = 0; i < vars->entries; i++) {
293 fprintf(fout, " %-21s %s\n", vars->el[i].label,
294 vars->el[i].value);
295 }
296}
297
298
299/**
300 * Save a raidlist structure to disk in raidtab format.
301 * @param raidlist The raidlist to save.
302 * @param fname The file to save it to.
303 * @return 0, always.
304 * @bug Return value is redundant.
305 */
306int save_raidlist_to_raidtab(struct raidlist_itself *raidlist, char *fname)
307{
308 FILE *fout;
309 int current_raid_device;
310#ifdef __FreeBSD__
311 int i;
312#else
313// Linux
314#endif
315
316 assert(raidlist != NULL);
317 assert_string_is_neither_NULL_nor_zerolength(fname);
318
319 if (raidlist->entries <= 0) {
320 unlink(fname);
321 log_it("Deleting raidtab (no RAID devs anyway)");
322 return (0);
323 }
324 if (!(fout = fopen(fname, "w"))) {
325 log_OS_error("Failed to save raidlist");
326 return (1);
327 }
328 fprintf(fout, "# Generated by Mondo Rescue\n");
329
330#ifdef __FreeBSD__
331 for (i = 0; i < raidlist->disks.entries; ++i) {
332 fprintf(fout, "drive %s device %s\n", raidlist->disks.el[i].name,
333 raidlist->disks.el[i].device);
334 }
335 for (i = 0; i < (raidlist->spares.entries); ++i) {
336 fprintf(fout, "drive %s device %s hotspare\n",
337 raidlist->spares.el[i].name,
338 raidlist->spares.el[i].device);
339 }
340#endif
341
342 for (current_raid_device = 0; current_raid_device < raidlist->entries;
343 current_raid_device++) {
344 save_raidrec_to_file(&raidlist->el[current_raid_device], fout);
345 }
346 paranoid_fclose(fout);
347 return (0);
348}
349
350
351/**
352 * Save an individual RAID device record to a stream.
353 * @param raidrec The RAID device record to save.
354 * @param fout The stream to save it to.
355 */
356void save_raidrec_to_file(struct
357#ifdef __FreeBSD__
358 vinum_volume
359#else
360 raid_device_record
361#endif
362 * raidrec, FILE * fout)
363{
364#ifdef __FreeBSD__
365 int i, j;
366
367 fprintf(fout, "\nvolume %s\n", raidrec->volname);
368 for (i = 0; i < raidrec->plexes; ++i) {
369 char org[24];
370 switch (raidrec->plex[i].raidlevel) {
371 case -1:
372 strcpy(org, "concat");
373 break;
374 case 0:
375 strcpy(org, "striped");
376 break;
377 case 5:
378 strcpy(org, "raid5");
379 break;
380 }
381 fprintf(fout, " plex org %s", org);
382 if (raidrec->plex[i].raidlevel != -1) {
383 fprintf(fout, " %ik", raidrec->plex[i].stripesize);
384 }
385 fprintf(fout, "\n");
386
387 for (j = 0; j < raidrec->plex[i].subdisks; ++j) {
388 fprintf(fout, " sd drive %s size 0\n",
389 raidrec->plex[i].sd[j].which_device);
390 }
391 }
392#else
393 assert(raidrec != NULL);
394 assert(fout != NULL);
395
396 fprintf(fout, "raiddev %s\n", raidrec->raid_device);
397 if (raidrec->raid_level == -1) {
398 fprintf(fout, " raid-level linear\n");
399 } else {
400 fprintf(fout, " raid-level %d\n",
401 raidrec->raid_level);
402 }
403 fprintf(fout, " chunk-size %d\n", raidrec->chunk_size);
404 fprintf(fout, " nr-raid-disks %d\n",
405 raidrec->data_disks.entries);
406 fprintf(fout, " nr-spare-disks %d\n",
407 raidrec->spare_disks.entries);
408 if (raidrec->parity_disks.entries > 0) {
409 fprintf(fout, " nr-parity-disks %d\n",
410 raidrec->parity_disks.entries);
411 }
412
413 fprintf(fout, " persistent-superblock %d\n",
414 raidrec->persistent_superblock);
415 save_additional_vars_to_file(&raidrec->additional_vars, fout);
416 fprintf(fout, "\n");
417 save_disklist_to_file("raid-disk", &raidrec->data_disks, fout);
418 save_disklist_to_file("spare-disk", &raidrec->spare_disks, fout);
419 save_disklist_to_file("parity-disk", &raidrec->parity_disks, fout);
420 save_disklist_to_file("failed-disk", &raidrec->failed_disks, fout);
421 fprintf(fout, "\n");
422#endif
423}
424
425/**
426 * Retrieve the next line from a raidtab stream.
427 * @param fin The file to read the input from.
428 * @param label Where to put the line's label.
429 * @param value Where to put the line's value.
430 * @return 0 if the line was read and stored successfully, 1 if we're at end of file.
431 */
432int get_next_raidtab_line(FILE * fin, char *label, char *value)
433{
434 char *incoming;
435 char *p;
436
437 malloc_string(incoming);
438 assert(fin != NULL);
439 assert(label != NULL);
440 assert(value != NULL);
441
442 label[0] = value[0] = '\0';
443 if (feof(fin)) {
444 paranoid_free(incoming);
445 return (1);
446 }
447 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
448 fgets(incoming, MAX_STR_LEN - 1, fin)) {
449 strip_spaces(incoming);
450 p = strchr(incoming, ' ');
451 if (strlen(incoming) < 3 || incoming[0] == '#' || !p) {
452 continue;
453 }
454 *(p++) = '\0';
455 while (*p == ' ') {
456 p++;
457 }
458 strcpy(label, incoming);
459 strcpy(value, p);
460 paranoid_free(incoming);
461 return (0);
462 }
463 return (1);
464}
465
466
467
468/**
469 * Load a raidtab file into a raidlist structure.
470 * @param raidlist The raidlist to fill.
471 * @param fname The file to read from.
472 * @return 0 for success, 1 for failure.
473 */
474#ifdef __FreeBSD__
475int load_raidtab_into_raidlist(struct raidlist_itself *raidlist,
476 char *fname)
477{
478 FILE *fin;
479 char *tmp;
480 int items;
481
482 malloc_string(tmp);
483 raidlist->spares.entries = 0;
484 raidlist->disks.entries = 0;
485 if (length_of_file(fname) < 5) {
486 log_it("Raidtab is very small or non-existent. Ignoring it.");
487 raidlist->entries = 0;
488 paranoid_free(tmp);
489 return (0);
490 }
491 if (!(fin = fopen(fname, "r"))) {
492 log_it("Cannot open raidtab");
493 paranoid_free(tmp);
494 return (1);
495 }
496 items = 0;
497 log_it("Loading raidtab...");
498 while (!feof(fin)) {
499 int argc;
500 char **argv = get_next_vinum_conf_line(fin, &argc);
501 if (!argv)
502 break;
503 if (!strcmp(argv[0], "drive")) {
504 char *drivename, *devname;
505 if (argc < 4)
506 continue;
507 drivename = argv[1];
508 devname = get_option_val(argc, argv, "device");
509 if (!devname)
510 continue;
511
512 if (get_option_state(argc, argv, "hotspare")) {
513 strcpy(raidlist->spares.el[raidlist->spares.entries].name,
514 drivename);
515 strcpy(raidlist->spares.el[raidlist->spares.entries].
516 device, devname);
517 raidlist->spares.el[raidlist->spares.entries].index =
518 raidlist->disks.entries;
519 raidlist->spares.entries++;
520 } else {
521 strcpy(raidlist->disks.el[raidlist->disks.entries].name,
522 drivename);
523 strcpy(raidlist->disks.el[raidlist->disks.entries].device,
524 devname);
525 raidlist->disks.el[raidlist->disks.entries].index =
526 raidlist->disks.entries;
527 raidlist->disks.entries++;
528 }
529 } else if (!strcmp(argv[0], "volume")) {
530 char *volname;
531 if (argc < 2)
532 continue;
533 volname = argv[1];
534 strcpy(raidlist->el[raidlist->entries].volname, volname);
535 raidlist->el[raidlist->entries].plexes = 0;
536 raidlist->entries++;
537 } else if (!strcmp(argv[0], "plex")) {
538 int raidlevel, stripesize;
539 char *org = 0;
540 char **tmp = 0;
541 if (argc < 3)
542 continue;
543 org = get_option_val(argc, argv, "org");
544 if (!org)
545 continue;
546 if (strcmp(org, "concat")) {
547 tmp = get_option_vals(argc, argv, "org", 2);
548 if (tmp && tmp[1]) {
549 stripesize = (int) (size_spec(tmp[1]) / 1024);
550 } else
551 stripesize = 279;
552 } else
553 stripesize = 0;
554
555 if (!strcmp(org, "concat")) {
556 raidlevel = -1;
557 } else if (!strcmp(org, "striped")) {
558 raidlevel = 0;
559 } else if (!strcmp(org, "raid5")) {
560 raidlevel = 5;
561 } else
562 continue;
563
564 raidlist->el[raidlist->entries - 1].plex
565 [raidlist->el[raidlist->entries - 1].plexes].raidlevel =
566 raidlevel;
567 raidlist->el[raidlist->entries -
568 1].plex[raidlist->el[raidlist->entries -
569 1].plexes].stripesize =
570 stripesize;
571 raidlist->el[raidlist->entries -
572 1].plex[raidlist->el[raidlist->entries -
573 1].plexes].subdisks = 0;
574 raidlist->el[raidlist->entries - 1].plexes++;
575 } else if ((!strcmp(argv[0], "sd"))
576 || (!strcmp(argv[0], "subdisk"))) {
577 char *drive = 0;
578 if (argc < 3)
579 continue;
580 drive = get_option_val(argc, argv, "drive");
581 if (!drive)
582 continue;
583
584 strcpy(raidlist->el[raidlist->entries - 1].plex
585 [raidlist->el[raidlist->entries - 1].plexes - 1].sd
586 [raidlist->el[raidlist->entries - 1].plex
587 [raidlist->el[raidlist->entries - 1].plexes -
588 1].subdisks].which_device, drive);
589 raidlist->el[raidlist->entries -
590 1].plex[raidlist->el[raidlist->entries -
591 1].plexes - 1].subdisks++;
592 }
593 }
594 fclose(fin);
595 log_it("Raidtab loaded successfully.");
596 sprintf(tmp, "%d RAID devices in raidtab", raidlist->entries);
597 log_it(tmp);
598 paranoid_free(tmp);
599 return (0);
600}
601
602
603#else
604
605int load_raidtab_into_raidlist(struct raidlist_itself *raidlist,
606 char *fname)
607{
608 FILE *fin;
609 char *tmp;
610 char *label;
611 char *value;
612 int items;
613 int v;
614
615 malloc_string(tmp);
616 malloc_string(label);
617 malloc_string(value);
618 assert(raidlist != NULL);
619 assert_string_is_neither_NULL_nor_zerolength(fname);
620
621 if (length_of_file(fname) < 5) {
622 log_it("Raidtab is very small or non-existent. Ignoring it.");
623 raidlist->entries = 0;
624 paranoid_free(tmp);
625 paranoid_free(label);
626 paranoid_free(value);
627 return (0);
628 }
629 if (!(fin = fopen(fname, "r"))) {
630 log_it("Cannot open raidtab");
631 paranoid_free(tmp);
632 paranoid_free(label);
633 paranoid_free(value);
634 return (1);
635 }
636 items = 0;
637 log_it("Loading raidtab...");
638 get_next_raidtab_line(fin, label, value);
639 while (!feof(fin)) {
640 log_msg(1, "Looking for raid record #%d", items);
641 initialize_raidrec(&raidlist->el[items]);
642 v = 0;
643 /* find the 'raiddev' entry, indicating the start of the block of info */
644 while (!feof(fin) && strcmp(label, "raiddev")) {
645 strcpy(raidlist->el[items].additional_vars.el[v].label, label);
646 strcpy(raidlist->el[items].additional_vars.el[v].value, value);
647 v++;
648 get_next_raidtab_line(fin, label, value);
649 log_it(tmp);
650 }
651 raidlist->el[items].additional_vars.entries = v;
652 if (feof(fin)) {
653 log_msg(1, "No more records.");
654 continue;
655 }
656 log_msg(2, "Record #%d (%s) found", items, value);
657 strcpy(raidlist->el[items].raid_device, value);
658 for (get_next_raidtab_line(fin, label, value);
659 !feof(fin) && strcmp(label, "raiddev");
660 get_next_raidtab_line(fin, label, value)) {
661 process_raidtab_line(fin, &raidlist->el[items], label, value);
662 }
663 items++;
664 }
665 paranoid_fclose(fin);
666 raidlist->entries = items;
667 log_msg(1, "Raidtab loaded successfully.");
668 log_msg(1, "%d RAID devices in raidtab", items);
669 paranoid_free(tmp);
670 paranoid_free(label);
671 paranoid_free(value);
672 return (0);
673}
674#endif
675
676
677
678
679
680
681
682
683#ifndef __FreeBSD__
684/**
685 * Process a single line from the raidtab and store the results into @p raidrec.
686 * @param fin The stream to read the line from.
687 * @param raidrec The RAID device record to update.
688 * @param label Where to put the label processed.
689 * @param value Where to put the value processed.
690 */
691void
692process_raidtab_line(FILE * fin,
693 struct raid_device_record *raidrec,
694 char *label, char *value)
695{
696
697 /*@ add mallocs * */
698 char *tmp;
699 char *labelB;
700 char *valueB;
701
702 struct list_of_disks *disklist;
703 int index;
704 int v;
705
706 malloc_string(tmp);
707 malloc_string(labelB);
708 malloc_string(valueB);
709 assert(fin != NULL);
710 assert(raidrec != NULL);
711 assert_string_is_neither_NULL_nor_zerolength(label);
712 assert(value != NULL);
713
714 if (!strcmp(label, "raid-level")) {
715 if (!strcmp(value, "linear")) {
716 raidrec->raid_level = -1;
717 } else {
718 raidrec->raid_level = atoi(value);
719 }
720 } else if (!strcmp(label, "nr-raid-disks")) { /* ignore it */
721 } else if (!strcmp(label, "nr-spare-disks")) { /* ignore it */
722 } else if (!strcmp(label, "nr-parity-disks")) { /* ignore it */
723 } else if (!strcmp(label, "nr-failed-disks")) { /* ignore it */
724 } else if (!strcmp(label, "persistent-superblock")) {
725 raidrec->persistent_superblock = atoi(value);
726 } else if (!strcmp(label, "chunk-size")) {
727 raidrec->chunk_size = atoi(value);
728 } else if (!strcmp(label, "device")) {
729 get_next_raidtab_line(fin, labelB, valueB);
730 if (!strcmp(labelB, "raid-disk")) {
731 disklist = &raidrec->data_disks;
732 } else if (!strcmp(labelB, "spare-disk")) {
733 disklist = &raidrec->spare_disks;
734 } else if (!strcmp(labelB, "parity-disk")) {
735 disklist = &raidrec->parity_disks;
736 } else if (!strcmp(labelB, "failed-disk")) {
737 disklist = &raidrec->failed_disks;
738 } else {
739 disklist = NULL;
740 }
741 if (!disklist) {
742 sprintf(tmp,
743 "Ignoring '%s %s' pair of disk %s", labelB, valueB,
744 label);
745 log_it(tmp);
746 } else {
747 index = atoi(valueB);
748 add_disk_to_raid_device(disklist, value, index);
749 }
750 } else {
751 v = raidrec->additional_vars.entries;
752 strcpy(raidrec->additional_vars.el[v].label, label);
753 strcpy(raidrec->additional_vars.el[v].value, value);
754 raidrec->additional_vars.entries = ++v;
755 }
756 paranoid_free(tmp);
757 paranoid_free(labelB);
758 paranoid_free(valueB);
759}
760#endif
761
762
763/**
764 * Save a disklist to a stream in raidtab format.
765 * @param listname One of "raid-disk", "spare-disk", "parity-disk", or "failed-disk".
766 * @param disklist The disklist to save to @p fout.
767 * @param fout The stream to write to.
768 */
769void
770save_disklist_to_file(char *listname,
771 struct list_of_disks *disklist, FILE * fout)
772{
773 int i;
774
775 assert_string_is_neither_NULL_nor_zerolength(listname);
776 assert(disklist != NULL);
777 assert(fout != NULL);
778
779 for (i = 0; i < disklist->entries; i++) {
780 fprintf(fout, " device %s\n",
781 disklist->el[i].device);
782 fprintf(fout, " %-21s %d\n", listname, disklist->el[i].index);
783 }
784}
785
786
787
788
789
790#ifdef __FreeBSD__
791/**
792 * Add a new plex to a volume. The index of the plex will be <tt>v-\>plexes - 1</tt>.
793 * @param v The volume to operate on.
794 * @param raidlevel The RAID level of the new plex.
795 * @param stripesize The stripe size (chunk size) of the new plex.
796 */
797void add_plex_to_volume(struct vinum_volume *v, int raidlevel,
798 int stripesize)
799{
800 v->plex[v->plexes].raidlevel = raidlevel;
801 v->plex[v->plexes].stripesize = stripesize;
802 v->plex[v->plexes].subdisks = 0;
803 ++v->plexes;
804}
805
806/**
807 * For internal use only.
808 */
809char **get_next_vinum_conf_line(FILE * f, int *argc)
810{
811 int cnt = 0;
812 static char *argv[64];
813 char **ap;
814 char *line = (char *) malloc(MAX_STR_LEN);
815 if (!line)
816 errx(1,
817 "unable to allocate %i bytes of memory for `char *line' at %s:%i",
818 MAX_STR_LEN, __FILE__, __LINE__);
819 (void) fgets(line, MAX_STR_LEN, f);
820 if (feof(f)) {
821 log_it("[GNVCL] Uh... I reached the EOF.");
822 return 0;
823 }
824
825 for (ap = argv; (*ap = strsep(&line, " \t")) != NULL;)
826 if (**ap != '\0') {
827 if (++ap >= &argv[64])
828 break;
829 cnt++;
830 }
831
832 if (strchr(argv[cnt - 1], '\n')) {
833 *(strchr(argv[cnt - 1], '\n')) = '\0';
834 }
835
836 if (argc)
837 *argc = cnt;
838 return argv;
839}
840
841/**
842 * For internal use only.
843 */
844char *get_option_val(int argc, char **argv, char *option)
845{
846 int i;
847 for (i = 0; i < (argc - 1); ++i) {
848 if (!strcmp(argv[i], option)) {
849 return argv[i + 1];
850 }
851 }
852 return 0;
853}
854
855/**
856 * For internal use only.
857 */
858char **get_option_vals(int argc, char **argv, char *option, int nval)
859{
860 int i, j;
861 static char **ret;
862 ret = (char **) malloc(nval * sizeof(char *));
863 for (i = 0; i < (argc - nval); ++i) {
864 if (!strcmp(argv[i], option)) {
865 for (j = 0; j < nval; ++j) {
866 ret[j] = (char *) malloc(strlen(argv[i + j + 1]) + 1);
867 strcpy(ret[j], argv[i + j + 1]);
868 }
869 return ret;
870 }
871 }
872 return 0;
873}
874
875/**
876 * For internal use only.
877 */
878bool get_option_state(int argc, char **argv, char *option)
879{
880 int i;
881 for (i = 0; i < argc; ++i)
882 if (!strcmp(argv[i], option))
883 return TRUE;
884
885 return FALSE;
886}
887
888/**
889 * Taken from Vinum source -- for internal use only.
890 */
891long long size_spec(char *spec)
892{
893 u_int64_t size;
894 char *s;
895 int sign = 1; /* -1 if negative */
896
897 size = 0;
898 if (spec != NULL) { /* we have a parameter */
899 s = spec;
900 if (*s == '-') { /* negative, */
901 sign = -1;
902 s++; /* skip */
903 }
904 if ((*s >= '0') && (*s <= '9')) { /* it's numeric */
905 while ((*s >= '0') && (*s <= '9')) /* it's numeric */
906 size = size * 10 + *s++ - '0'; /* convert it */
907 switch (*s) {
908 case '\0':
909 return size * sign;
910
911 case 'B':
912 case 'b':
913 case 'S':
914 case 's':
915 return size * sign * 512;
916
917 case 'K':
918 case 'k':
919 return size * sign * 1024;
920
921 case 'M':
922 case 'm':
923 return size * sign * 1024 * 1024;
924
925 case 'G':
926 case 'g':
927 return size * sign * 1024 * 1024 * 1024;
928
929 case 'T':
930 case 't':
931 log_it
932 ("Ok, I'm scared... Someone did a TERABYTE+ size-spec");
933 return size * sign * 1024 * 1024 * 1024 * 1024;
934
935 case 'P':
936 case 'p':
937 log_it
938 ("If I was scared last time, I'm freaked out now. Someone actually has a PETABYTE?!?!?!?!");
939 return size * sign * 1024 * 1024 * 1024 * 1024 * 1024;
940
941 case 'E':
942 case 'e':
943 log_it
944 ("Okay, I'm REALLY freaked out. Who could devote a whole EXABYTE to their data?!?!");
945 return size * sign * 1024 * 1024 * 1024 * 1024 * 1024 *
946 1024;
947
948 case 'Z':
949 case 'z':
950 log_it
951 ("WHAT!?!? A ZETABYTE!?!? You've GOT to be kidding me!!!");
952 return size * sign * 1024 * 1024 * 1024 * 1024 * 1024 *
953 1024 * 1024;
954
955 case 'Y':
956 case 'y':
957 log_it
958 ("Oh my gosh. You actually think a YOTTABYTE will get you anywhere? What're you going to do with 1,208,925,819,614,629,174,706,176 bytes?!?!");
959 popup_and_OK
960 ("That sizespec is more than 1,208,925,819,614,629,174,706,176 bytes. You have a shocking amount of data. Please send a screenshot to the list :-)");
961 return size * sign * 1024 * 1024 * 1024 * 1024 * 1024 *
962 1024 * 1024 * 1024;
963 }
964 }
965 }
966 return size * sign;
967}
968
969#endif
970
971
972
973
974int read_mdstat(struct s_mdstat *mdstat, char *mdstat_file)
975{
976 FILE *fin;
977 char *tmp;
978 char *stub;
979 char *incoming;
980 char *raid_devname;
981 char *p, *q, *r;
982 int diskno;
983
984 malloc_string(tmp);
985 malloc_string(stub);
986 malloc_string(incoming);
987 malloc_string(raid_devname);
988 if (!(fin = fopen(mdstat_file, "r"))) {
989 log_msg(1, "%s not found", mdstat_file);
990 return (1);
991 }
992 mdstat->entries = 0;
993 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
994 fgets(incoming, MAX_STR_LEN - 1, fin)) {
995 p = incoming;
996 if (*p != 'm' && *(p + 1) == 'm') {
997 p++;
998 }
999 if (strncmp(p, "md", 2)) {
1000 continue;
1001 }
1002// read first line --- mdN : active raidX ............
1003 mdstat->el[mdstat->entries].md = atoi(p + 2);
1004 log_msg(8, "Storing /dev/md%d's info", atoi(p + 2));
1005 while (*p != ':' && *p) {
1006 p++;
1007 }
1008 while ((*p != 'r' || *(p + 1) != 'a') && *p) {
1009 p++;
1010 }
1011 if (!strncmp(p, "raid", 4)) {
1012 mdstat->el[mdstat->entries].raidlevel = *(p + 4) - '0';
1013 }
1014 p += 4;
1015 while (*p != ' ' && *p) {
1016 p++;
1017 }
1018 while (*p == ' ' && *p) {
1019 p++;
1020 }
1021 for (diskno = 0; *p; diskno++) {
1022 strcpy(stub, p);
1023// log_msg(1, "diskno=%d; tmp=%s", diskno, tmp);
1024 q = strchr(stub, '[');
1025 if (q) {
1026 *q = '\0';
1027 q++;
1028 r = strchr(q, ']');
1029 if (r) {
1030 *r = '\0';
1031 }
1032 mdstat->el[mdstat->entries].disks.el[diskno].index =
1033 atoi(q);
1034 } else {
1035 mdstat->el[mdstat->entries].disks.el[diskno].index = -1;
1036 q = strchr(stub, ' ');
1037 if (q) {
1038 *q = '\0';
1039 }
1040 }
1041 sprintf(tmp, "/dev/%s", stub);
1042 log_msg(8, "/dev/md%d : disk#%d : %s (%d)",
1043 mdstat->el[mdstat->entries].md, diskno, tmp,
1044 mdstat->el[mdstat->entries].disks.el[diskno].index);
1045 strcpy(mdstat->el[mdstat->entries].disks.el[diskno].device,
1046 tmp);
1047 while (*p != ' ' && *p) {
1048 p++;
1049 }
1050 while (*p == ' ' && *p) {
1051 p++;
1052 }
1053 }
1054 mdstat->el[mdstat->entries].disks.entries = diskno;
1055// next line --- skip it
1056 if (!feof(fin)) {
1057 fgets(incoming, MAX_STR_LEN - 1, fin);
1058 } else {
1059 continue;
1060 }
1061// next line --- the 'progress' line
1062 if (!feof(fin)) {
1063 fgets(incoming, MAX_STR_LEN - 1, fin);
1064 } else {
1065 continue;
1066 }
1067// log_msg(1, "Percentage line = '%s'", incoming);
1068 if (!(p = strchr(incoming, '\%'))) {
1069 mdstat->el[mdstat->entries].progress = 999; // not found
1070 } else if (strstr(incoming, "DELAYED")) {
1071 mdstat->el[mdstat->entries].progress = -1; // delayed (therefore, stuck at 0%)
1072 } else {
1073 for (*p = '\0'; *p != ' '; p--);
1074 mdstat->el[mdstat->entries].progress = atoi(p);
1075 }
1076 log_msg(8, "progress =%d", mdstat->el[mdstat->entries].progress);
1077 mdstat->entries++;
1078 }
1079 fclose(fin);
1080 paranoid_free(tmp);
1081 paranoid_free(stub);
1082 paranoid_free(incoming);
1083 paranoid_free(raid_devname);
1084 return (0);
1085}
1086
1087
1088
1089int create_raidtab_from_mdstat(char *raidtab_fname, char *mdstat_fname)
1090{
1091 struct raidlist_itself *raidlist;
1092 struct s_mdstat *mdstat;
1093 int retval = 0;
1094 int i;
1095
1096 raidlist = malloc(sizeof(struct raidlist_itself));
1097 mdstat = malloc(sizeof(struct s_mdstat));
1098
1099 if (read_mdstat(mdstat, mdstat_fname)) {
1100 log_to_screen("Sorry, cannot read %s", mdstat_fname);
1101 return (1);
1102 }
1103
1104 for (i = 0; i < mdstat->entries; i++) {
1105 sprintf(raidlist->el[i].raid_device, "/dev/md%d",
1106 mdstat->el[i].md);
1107 raidlist->el[i].raid_level = mdstat->el[i].raidlevel;
1108 raidlist->el[i].persistent_superblock = 1;
1109 raidlist->el[i].chunk_size = 4;
1110 memcpy((void *) &raidlist->el[i].data_disks,
1111 (void *) &mdstat->el[i].disks,
1112 sizeof(struct list_of_disks));
1113 // FIXME --- the above line does not allow for spare disks
1114 log_to_screen
1115 ("FIXME - create_raidtab_from_mdstat does not allow for spare disks");
1116 }
1117 raidlist->entries = i;
1118 retval += save_raidlist_to_raidtab(raidlist, raidtab_fname);
1119 return (retval);
1120}
1121
1122
1123
1124/* @} - end of raidGroup */
Note: See TracBrowser for help on using the repository browser.