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

Last change on this file since 1 was 1, checked in by bcornec, 14 years ago

Initial import from latest mondo-2.04_cvs_20050503/mindi-1.04_cvs_20050503 on http://www.mondorescue.org

File size: 27.8 KB
Line 
1/* libmondo-raid.c                                                subroutines for handling RAID
2   $Id: libmondo-raid.c,v 1.2 2004/06/10 15:29:12 hugo Exp $
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,v 1.2 2004/06/10 15:29:12 hugo Exp $";
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.