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

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