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

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

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

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