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

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

merge -r489:506 $SVN_M/branches/stable

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