source: MondoRescue/trunk/mondo/mondo/common/libmondo-raid.c@ 30

Last change on this file since 30 was 30, checked in by bcornec, 19 years ago

Id property added on files to allow for better conf. management

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