source: MondoRescue/branches/2.2.9/mondo/src/common/libmondo-mountlist.c@ 2204

Last change on this file since 2204 was 2204, checked in by Bruno Cornec, 15 years ago

First set of improvements for mountlist management (test with valgrind). Fix errors on scanf usage. More to come.

  • Property svn:keywords set to Id
File size: 28.7 KB
Line 
1/* subroutines for handling mountlist
2 $Id: libmondo-mountlist.c 2204 2009-05-13 10:26:33Z bruno $
3*/
4
5
6/**
7 * @file
8 * Functions which manipulate the mountlist.
9 */
10
11#include "my-stuff.h"
12#include "mondostructures.h"
13#include "libmondo-mountlist.h"
14#include "lib-common-externs.h"
15#include "libmondo-raid-EXT.h"
16#include "libmondo-devices-EXT.h"
17#include "libmondo-tools-EXT.h"
18#include "libmondo-string-EXT.h"
19#include "newt-specific-EXT.h"
20
21/*@unused@*/
22//static char cvsid[] = "$Id: libmondo-mountlist.c 2204 2009-05-13 10:26:33Z bruno $";
23
24/* Reference to global bkpinfo */
25extern struct s_bkpinfo *bkpinfo;
26
27/**
28 * @addtogroup mountlistGroup
29 * @{
30 */
31/**
32 * Evaluate a drive within the mountlist for flaws. For example, too many
33 * primary partitions, the first logical isn't 5, duplicate partitions,
34 * ovar-allocated or under-allocated, unsupported format, silly size, or
35 * silly mountpoint. Under FreeBSD, this checks the disklabel too, for the above-mentioned
36 * errors as well as too many BSD partitions (more than 'h').
37 * @param mountlist The mountlist to check.
38 * @param drive The drive to check (e.g. @c /dev/hda).
39 * @param flaws_str Where to put the found flaws (human-readable).
40 * @return The number of flaws found (0 for success).
41 * @see evaluate_mountlist
42 */
43int evaluate_drive_within_mountlist(struct mountlist_itself *mountlist,
44 char *drive, char *flaws_str)
45#ifdef __FreeBSD__
46{
47// FreeBSD-specific version of evaluate_drive_within_mountlist()
48 /*@ int ************************************************************* */
49 int prev_part_no = 0;
50 int curr_part_no = 0;
51 int pos = 0, npos = 0;
52 int res = 0;
53 int mountpoint_copies = 0;
54 int device_copies = 0;
55 int i = 0;
56 int cur_sp_no = 0;
57 int prev_sp_no = 0;
58 int foundsome = FALSE;
59
60 /*@ buffers ******************************************************** */
61 char tmp[MAX_STR_LEN];
62 char device[MAX_STR_LEN];
63 char mountpoint[MAX_STR_LEN];
64
65 /*@ long *********************************************************** */
66 long physical_drive_size = 0;
67 long amount_allocated = 0;
68
69 /*@ pointers ******************************************************* */
70 char *part_table_fmt;
71
72 /*@ initialize ***************************************************** */
73 flaws_str[0] = '\0';
74 prev_part_no = 0;
75 tmp[0] = '\0';
76
77
78 physical_drive_size = get_phys_size_of_drive(drive);
79
80 if (physical_drive_size < 0) {
81 sprintf(tmp, " %s does not exist.", drive);
82 strcat(flaws_str, tmp);
83 } else {
84 sprintf(tmp, "%s is %ld MB", drive, physical_drive_size);
85 }
86 log_it(tmp);
87
88
89 /* check DD */
90 for (cur_sp_no = 'a'; cur_sp_no < 'z'; ++cur_sp_no) {
91 sprintf(device, "%s%c", drive, cur_sp_no);
92 if (find_device_in_mountlist(mountlist, device) >= 0)
93 foundsome = TRUE;
94 }
95 if (foundsome) {
96 for (cur_sp_no = 'a'; cur_sp_no < 'z'; ++cur_sp_no) {
97 sprintf(device, "%s%c", drive, cur_sp_no);
98 pos = find_device_in_mountlist(mountlist, device);
99 if (pos < 0) {
100 continue;
101 }
102 strcpy(mountpoint, mountlist->el[pos].mountpoint);
103 /* is it too big? */
104 if (curr_part_no > 'h') {
105 sprintf(tmp, " Can only have up to 'h' in disklabel.");
106 log_it(tmp);
107 strcat(flaws_str, tmp);
108 res++;
109 }
110 /* does partition /dev/adXsYZ exist more than once in the mountlist? */
111 for (i = 0, mountpoint_copies = 0, device_copies = 0;
112 i < mountlist->entries; i++) {
113 if (!strcmp(device, mountlist->el[i].device)) {
114 device_copies++;
115 }
116 }
117 if (device_copies > 1) {
118 sprintf(tmp, " %s %s's.", number_to_text(device_copies),
119 device);
120 if (!strstr(flaws_str, tmp)) {
121 log_it(tmp);
122 strcat(flaws_str, tmp);
123 res++;
124 }
125 }
126 /* silly partition size? */
127 if (mountlist->el[pos].size < 8192
128 && strcmp(mountlist->el[pos].mountpoint, "lvm")) {
129 sprintf(tmp, " %s is tiny!", device);
130 log_it(tmp);
131 strcat(flaws_str, tmp);
132 res++;
133 }
134 /* mountpoint should begin with / unless it is swap, lvm or raid */
135 if (strcmp(mountlist->el[pos].mountpoint, "swap")
136 && strcmp(mountlist->el[pos].mountpoint, "lvm")
137 && strcmp(mountlist->el[pos].mountpoint, "raid")
138 && strcmp(mountlist->el[pos].mountpoint, "image")
139 && strcmp(mountlist->el[pos].mountpoint, "none")
140 && mountlist->el[pos].mountpoint[0] != '/') {
141 sprintf(tmp, " %s has a weird mountpoint.", device);
142 log_it(tmp);
143 strcat(flaws_str, tmp);
144 res++;
145 }
146 /* is format sensible? */
147 if (!is_this_a_valid_disk_format(mountlist->el[pos].format)) {
148 sprintf(tmp, " %s has unsupported format %s.", device, mountlist->el[pos].format);
149 log_it(tmp);
150 strcat(flaws_str, tmp);
151 res++;
152 }
153 amount_allocated += mountlist->el[pos].size / 1024L;
154 prev_sp_no = cur_sp_no;
155 }
156 }
157
158 npos = pos = 0;
159 for (curr_part_no = 1; curr_part_no < 99; curr_part_no++) {
160 build_partition_name(device, drive, curr_part_no);
161 pos = find_device_in_mountlist(mountlist, device);
162 npos = 0;
163 for (cur_sp_no = 'a'; cur_sp_no <= 'h'; cur_sp_no++) {
164 sprintf(device, "%ss%i%c", device, curr_part_no, cur_sp_no);
165 if (find_device_in_mountlist(mountlist, device) >= 0)
166 npos++;
167 }
168 if (((pos >= 0) || npos) && foundsome) {
169 sprintf(flaws_str + strlen(flaws_str),
170 " %s has both DD and PC-style partitions.", drive);
171 return ++res; // fatal error
172 }
173
174 build_partition_name(device, drive, curr_part_no);
175 strcpy(mountpoint, mountlist->el[pos].mountpoint);
176 if (pos > 0 && !npos) {
177 /* gap in the partition list? */
178 if (curr_part_no - prev_part_no > 1) {
179 if (prev_part_no == 0) {
180 sprintf(tmp, " Gap prior to %s.", device);
181 log_it(tmp);
182 strcat(flaws_str, tmp);
183 res++;
184 } else if (curr_part_no > 5
185 || (curr_part_no <= 4 && prev_part_no > 0)) {
186 sprintf(tmp, " Gap between %ss%d and %d.", drive,
187 prev_part_no, curr_part_no);
188 log_it(tmp);
189 strcat(flaws_str, tmp);
190 res++;
191 }
192 }
193 /* GPT allows more than 4 primary partitions */
194 part_table_fmt = which_partition_format(drive);
195 /* no spare primary partitions to help accommodate the logical(s)? */
196 if ((curr_part_no >= 5 && prev_part_no == 4)
197 && (strcmp(part_table_fmt, "MBR") == 0)) {
198 sprintf(tmp, " Partition %ss4 is occupied.", drive);
199 log_it(tmp);
200 strcat(flaws_str, tmp);
201 res++;
202 }
203 /* does partition /dev/adXsY exist more than once in the mountlist? */
204 for (i = 0, mountpoint_copies = 0, device_copies = 0;
205 i < mountlist->entries; i++) {
206 if (!strcmp(device, mountlist->el[i].device)) {
207 device_copies++;
208 }
209 }
210 if (device_copies > 1) {
211 sprintf(tmp, " %s %s's.", number_to_text(device_copies),
212 device);
213 if (!strstr(flaws_str, tmp)) {
214 log_it(tmp);
215 strcat(flaws_str, tmp);
216 res++;
217 }
218 }
219 /* silly partition size? */
220 if (mountlist->el[pos].size < 8192
221 && strcmp(mountlist->el[pos].mountpoint, "lvm")) {
222 sprintf(tmp, " %s is tiny!", device);
223 log_it(tmp);
224 strcat(flaws_str, tmp);
225 res++;
226 }
227 /* mountpoint should begin with / unless it is swap, lvm or raid */
228 if (strcmp(mountlist->el[pos].mountpoint, "swap")
229 && strcmp(mountlist->el[pos].mountpoint, "lvm")
230 && strcmp(mountlist->el[pos].mountpoint, "raid")
231 && strcmp(mountlist->el[pos].mountpoint, "image")
232 && strcmp(mountlist->el[pos].mountpoint, "none")
233 && mountlist->el[pos].mountpoint[0] != '/') {
234 sprintf(tmp, " %s has a weird mountpoint.", device);
235 log_it(tmp);
236 strcat(flaws_str, tmp);
237 res++;
238 }
239 /* is format sensible? */
240 if (!is_this_a_valid_disk_format(mountlist->el[pos].format)) {
241 sprintf(tmp, " %s has unsupported format %s.", device, mountlist->el[pos].format);
242 log_it(tmp);
243 strcat(flaws_str, tmp);
244 res++;
245 }
246 } else {
247 /* Check subpartitions */
248 for (cur_sp_no = 'a'; cur_sp_no < 'z'; ++cur_sp_no) {
249 sprintf(device, "%ss%d%c", drive, curr_part_no, cur_sp_no);
250 pos = find_device_in_mountlist(mountlist, device);
251 if (pos < 0) {
252 continue;
253 }
254 strcpy(mountpoint, mountlist->el[pos].mountpoint);
255 /* is it too big? */
256 if (curr_part_no > 'h') {
257 sprintf(tmp, " Can only have up to 'h' in disklabel.");
258 log_it(tmp);
259 strcat(flaws_str, tmp);
260 res++;
261 }
262 /* does partition /dev/adXsYZ exist more than once in the mountlist? */
263 for (i = 0, mountpoint_copies = 0, device_copies = 0;
264 i < mountlist->entries; i++) {
265 if (!strcmp(device, mountlist->el[i].device)) {
266 device_copies++;
267 }
268 }
269 if (device_copies > 1) {
270 sprintf(tmp, " %s %s's.",
271 number_to_text(device_copies), device);
272 if (!strstr(flaws_str, tmp)) {
273 log_it(tmp);
274 strcat(flaws_str, tmp);
275 res++;
276 }
277 }
278 /* silly partition size? */
279 if (mountlist->el[pos].size < 8192
280 && strcmp(mountlist->el[pos].mountpoint, "lvm")) {
281 sprintf(tmp, " %s is tiny!", device);
282 log_it(tmp);
283 strcat(flaws_str, tmp);
284 res++;
285 }
286 /* mountpoint should begin with / unless it is swap, lvm or raid */
287 if (strcmp(mountlist->el[pos].mountpoint, "swap")
288 && strcmp(mountlist->el[pos].mountpoint, "lvm")
289 && strcmp(mountlist->el[pos].mountpoint, "raid")
290 && strcmp(mountlist->el[pos].mountpoint, "image")
291 && strcmp(mountlist->el[pos].mountpoint, "none")
292 && mountlist->el[pos].mountpoint[0] != '/') {
293 sprintf(tmp, " %s has a weird mountpoint.", device);
294 log_it(tmp);
295 strcat(flaws_str, tmp);
296 res++;
297 }
298 /* is format sensible? */
299 if (!is_this_a_valid_disk_format
300 (mountlist->el[pos].format)) {
301 sprintf(tmp, " %s has unsupported format %s.", device, mountlist->el[pos].format);
302 log_it(tmp);
303 strcat(flaws_str, tmp);
304 res++;
305 }
306 amount_allocated += mountlist->el[pos].size / 1024L;
307 prev_sp_no = cur_sp_no;
308 }
309 }
310
311 /* OK, continue with main loop */
312 amount_allocated += mountlist->el[pos].size / 1024L;
313 prev_part_no = curr_part_no;
314 }
315
316 /* Over-allocated the disk? Unallocated space on disk? */
317 if (amount_allocated > physical_drive_size) // Used to be +1, but what if you're 1 MB too high?
318 {
319 sprintf(tmp, " %ld MB over-allocated on %s.",
320 amount_allocated - physical_drive_size, drive);
321 log_it(tmp);
322 strcat(flaws_str, tmp);
323 res++;
324 } else if (amount_allocated < physical_drive_size - 1) { /* NOT AN ERROR, JUST A WARNING :-) */
325 sprintf(tmp, " %ld MB unallocated on %s.",
326 physical_drive_size - amount_allocated, drive);
327 log_it(tmp);
328 strcat(flaws_str, tmp);
329 }
330 if (res) {
331 return (FALSE);
332 } else {
333 return (TRUE);
334 }
335}
336
337#else
338// Linux-specific version of evaluate_drive_within_mountlist()
339{
340
341 /*@ int ************************************************************* */
342 int prev_part_no = 0;
343 int curr_part_no = 0;
344 int pos = 0;
345 int res = 0;
346 int mountpoint_copies = 0;
347 int device_copies = 0;
348 int i = 0;
349
350 /*@ buffers ******************************************************** */
351 char *tmp;
352 char *device;
353
354 /*@ long *********************************************************** */
355 long physical_drive_size = 0L;
356 long amount_allocated = 0L;
357
358 /*@ pointers ******************************************************* */
359 char *part_table_fmt = NULL;
360
361 /*@ initialize ***************************************************** */
362 assert_string_is_neither_NULL_nor_zerolength(drive);
363 assert(mountlist != NULL);
364 assert(flaws_str != NULL);
365
366 malloc_string(tmp);
367 malloc_string(device);
368 flaws_str[0] = '\0';
369 prev_part_no = 0;
370 tmp[0] = '\0';
371
372
373 physical_drive_size = get_phys_size_of_drive(drive);
374
375 if (physical_drive_size < 0) {
376 sprintf(tmp, " %s does not exist.", drive);
377 strcat(flaws_str, tmp);
378 res++;
379 log_msg(1, tmp);
380 goto endoffunc;
381 } else {
382 sprintf(tmp, "%s is %ld MB", drive, physical_drive_size);
383 log_it(tmp);
384 }
385
386 for (curr_part_no = 1; curr_part_no < 99; curr_part_no++) {
387 build_partition_name(device, drive, curr_part_no);
388 pos = find_device_in_mountlist(mountlist, device);
389 if (pos < 0) {
390 continue;
391 }
392 /* gap in the partition list? */
393 if (curr_part_no - prev_part_no > 1) {
394 if (prev_part_no == 0) {
395 sprintf(tmp, " Gap prior to %s.", device);
396 log_it(tmp);
397 strcat(flaws_str, tmp);
398 res++;
399 } else if (curr_part_no > 5
400 || (curr_part_no <= 4 && prev_part_no > 0)) {
401 sprintf(tmp, " Gap on %s between %d and %d.", drive,
402 prev_part_no, curr_part_no);
403 log_it(tmp);
404 strcat(flaws_str, tmp);
405 res++;
406 }
407 }
408 /* GPT allows more than 4 primary partitions */
409 part_table_fmt = which_partition_format(drive);
410 /* no spare primary partitions to help accommodate the logical(s)? */
411 if ((curr_part_no >= 5 && prev_part_no == 4)
412 && (strcmp(part_table_fmt, "MBR") == 0)) {
413 sprintf(tmp, " Partition 4 of %s is occupied.", drive);
414 log_it(tmp);
415 strcat(flaws_str, tmp);
416 res++;
417 }
418 /* does partition /dev/hdNX exist more than once in the mountlist? */
419 for (i = 0, mountpoint_copies = 0, device_copies = 0;
420 i < mountlist->entries; i++) {
421 if (!strcmp(device, mountlist->el[i].device)) {
422 device_copies++;
423 }
424 }
425 if (device_copies > 1) {
426 sprintf(tmp, " %s %s's.", number_to_text(device_copies),
427 device);
428 if (!strstr(flaws_str, tmp)) {
429 log_it(tmp);
430 strcat(flaws_str, tmp);
431 res++;
432 }
433 }
434 /* silly partition size? */
435 if (mountlist->el[pos].size < 8192
436 && strcmp(mountlist->el[pos].mountpoint, "lvm")) {
437 sprintf(tmp, " %s is tiny!", device);
438 log_it(tmp);
439 strcat(flaws_str, tmp);
440 res++;
441 }
442 /* mountpoint should begin with / unless it is swap, lvm or raid */
443 if (strcmp(mountlist->el[pos].mountpoint, "swap")
444 && strcmp(mountlist->el[pos].mountpoint, "lvm")
445 && strcmp(mountlist->el[pos].mountpoint, "raid")
446 && strcmp(mountlist->el[pos].mountpoint, "image")
447 && mountlist->el[pos].mountpoint[0] != '/') {
448 sprintf(tmp, " %s has a weird mountpoint.", device);
449 log_it(tmp);
450 strcat(flaws_str, tmp);
451 res++;
452 }
453 /* is format sensible? */
454 if (!is_this_a_valid_disk_format(mountlist->el[pos].format)) {
455 sprintf(tmp, " %s has unsupported format %s.", device, mountlist->el[pos].format);
456 log_it(tmp);
457 strcat(flaws_str, tmp);
458 res++;
459 }
460 /* OK, continue with main loop */
461 amount_allocated += mountlist->el[pos].size / 1024L;
462 prev_part_no = curr_part_no;
463 }
464
465 /* Over-allocated the disk? Unallocated space on disk? */
466 if (amount_allocated > physical_drive_size + 1) {
467 sprintf(tmp, " %ld MB over-allocated on %s.",
468 amount_allocated - physical_drive_size, drive);
469 log_it(tmp);
470 strcat(flaws_str, tmp);
471 res++;
472 } else if (amount_allocated < physical_drive_size - 1) { /* NOT AN ERROR, JUST A WARNING :-) */
473 sprintf(tmp, " %ld MB unallocated on %s.",
474 physical_drive_size - amount_allocated, drive);
475 log_it(tmp);
476 strcat(flaws_str, tmp);
477 }
478
479 endoffunc:
480 paranoid_free(tmp);
481 paranoid_free(device);
482
483 if (res) {
484 return (FALSE);
485 } else {
486 return (TRUE);
487 }
488}
489#endif
490
491
492/**
493 * Evaluate a whole mountlist for flaws. Calls evaluate_drive_within_mountlist()
494 * for each drive, and then spreads the flaws across three lines.
495 * @param mountlist The mountlist to evaluate.
496 * @param flaws_str_A Where to put the first line listing errors found.
497 * @param flaws_str_B Where to put the second line listing errors found.
498 * @param flaws_str_C Where to put the third line listing errors found.
499 * @return The number of flaws found (0 for success).
500 * @see evaluate_drive_within_mountlist
501 */
502int
503evaluate_mountlist(struct mountlist_itself *mountlist, char *flaws_str_A,
504 char *flaws_str_B, char *flaws_str_C)
505{
506
507 /*@ buffer *********************************************************** */
508 struct list_of_disks *drivelist;
509 char *tmp = NULL;
510 char *flaws_str = NULL;
511
512 /*@ int ************************************************************** */
513 int i = 0;
514 int res = 0;
515
516 /*@ initialize ******************************************************* */
517
518 drivelist = malloc(sizeof(struct list_of_disks));
519 malloc_string(tmp);
520 malloc_string(flaws_str);
521 assert(mountlist != NULL);
522 assert(flaws_str_A != NULL);
523 assert(flaws_str_B != NULL);
524 assert(flaws_str_C != NULL);
525 flaws_str[0] = '\0';
526
527 make_list_of_drives_in_mountlist(mountlist, drivelist);
528
529 log_it("Evaluating mountlist...");
530
531 for (i = 0; i < drivelist->entries; i++) {
532 if (strstr
533 (drivelist->el[i].device,
534 DONT_KNOW_HOW_TO_EVALUATE_THIS_DEVICE_TYPE)) {
535 sprintf(tmp, " Not evaluating %s (I don't know how yet)",
536 drivelist->el[i].device);
537 log_it(tmp);
538 tmp[0] = '\0';
539 } else {
540 if (!evaluate_drive_within_mountlist
541 (mountlist, drivelist->el[i].device, tmp)) {
542 res++;
543 }
544 }
545 strcat(flaws_str, tmp);
546 }
547 res += look_for_duplicate_mountpoints(mountlist, flaws_str);
548 return (spread_flaws_across_three_lines
549 (flaws_str, flaws_str_A, flaws_str_B, flaws_str_C, res));
550}
551
552
553/**
554 * Find the index number of @p device in the mountlist.
555 * The device given must match @p mountlist->el[N].device exactly, case-sensitive.
556 * @param mountlist The mountlist to search in.
557 * @param device The device to search for.
558 * @return The zero-based index of the device, or -1 if it could not be found.
559 */
560int
561find_device_in_mountlist(struct mountlist_itself *mountlist, char *device)
562{
563
564 /*@ int ************************************************************** */
565 int i = 0;
566
567 assert(mountlist != NULL);
568 assert_string_is_neither_NULL_nor_zerolength(device);
569 for (i = 0;
570 i < mountlist->entries
571 && strcmp(mountlist->el[i].device, device) != 0; i++);
572
573 if (i == mountlist->entries) {
574 return (-1);
575 } else {
576 return (i);
577 }
578}
579
580
581/**
582 * Look for duplicate mountpoints in @p mountlist.
583 * @param mountlist The mountlist to check.
584 * @param flaws_str The flaws string to append the results to.
585 * @return The number of mountpoints that have duplicates, or 0 for success.
586 */
587int
588look_for_duplicate_mountpoints(struct mountlist_itself *mountlist,
589 char *flaws_str)
590{
591
592 /*@ int ************************************************************* */
593 int res = 0;
594 int currline = 0;
595 int i = 0;
596 int copies = 0;
597 int last_copy = 0;
598
599 /*@ buffetr ********************************************************* */
600 char *curr_mountpoint = NULL;
601 char *tmp = NULL;
602
603 assert(mountlist != NULL);
604 assert(flaws_str != NULL);
605
606 for (currline = 0; currline < mountlist->entries; currline++) {
607 asprintf(&curr_mountpoint, "%s", mountlist->el[currline].mountpoint);
608 for (i = 0, copies = 0, last_copy = -1; i < mountlist->entries;
609 i++) {
610 if (!strcmp(mountlist->el[i].mountpoint, curr_mountpoint)
611 && strcmp(mountlist->el[i].mountpoint, "lvm")
612 && strcmp(mountlist->el[i].mountpoint, "swap")) {
613 last_copy = i;
614 copies++;
615 }
616 }
617 if (copies > 1 && last_copy == currline
618 && strcmp(curr_mountpoint, "raid")) {
619 asprintf(&tmp, " %s %s's.", number_to_text(copies),
620 curr_mountpoint);
621 strcat(flaws_str, tmp);
622 log_it(tmp);
623 paranoid_free(tmp);
624 res++;
625 }
626 paranoid_free(curr_mountpoint);
627 }
628 return (res);
629}
630
631
632/**
633 * Make a list of the drives mentioned in the mountlist.
634 * @param mountlist The mountlist to examine.
635 * @param drivelist Where to put the list of drives found.
636 * @return The number of physical (non-RAID non-LVM) drives found, or \<= 0 for error.
637 */
638int
639make_list_of_drives_in_mountlist(struct mountlist_itself *mountlist,
640 struct list_of_disks *drivelist)
641{
642
643 /*@ int ************************************************************* */
644 int lino;
645 int noof_drives;
646 int j;
647
648 /*@ buffers ********************************************************* */
649 char *drive = NULL;
650
651 long long size;
652
653 assert(mountlist != NULL);
654 assert(drivelist != NULL);
655 log_it("Making list of drives");
656 for (lino = 0, noof_drives = 0; lino < mountlist->entries; lino++) {
657
658 asprintf(&drive, "%s", mountlist->el[lino].device);
659 if (!strncmp(drive, RAID_DEVICE_STUB, strlen(RAID_DEVICE_STUB))) {
660 log_msg(8, "Not putting %s in list of drives: it's a virtual drive",
661 drive);
662 continue;
663 }
664
665 size = mountlist->el[lino].size;
666 if (size == 0) {
667 log_msg(8,
668 "Not putting %s in list of drives: it has zero size (maybe an LVM volume)",
669 drive);
670 continue;
671 }
672
673 log_msg(8, "Putting %s with size %lli in list of drives",
674 drive, size);
675
676 (void) truncate_to_drive_name(drive);
677 for (j = 0;
678 j < noof_drives
679 && strcmp(drivelist->el[j].device, drive) != 0; j++)
680 continue;
681 if (j == noof_drives) {
682 strcpy(drivelist->el[noof_drives++].device, drive);
683 }
684 }
685 drivelist->entries = noof_drives;
686 log_msg(8, "Made list of drives");
687
688 return (noof_drives);
689}
690
691
692/**
693 * Make a list of RAID partitions not currently associated with any RAID device.
694 * The user may add any of these partitions to the RAID device.
695 * @param output_list Where to put the list of unallocated RAID partitions.
696 * @param mountlist The mountlist to examine.
697 * @param raidlist The raidlist to examine.
698 */
699void make_list_of_unallocated_raid_partitions(struct mountlist_itself
700 *output_list,
701 struct mountlist_itself
702 *mountlist,
703 struct raidlist_itself
704 *raidlist)
705{
706
707 /*@ int ************************************************************* */
708 int items = 0;
709 int i = 0;
710 int used_by = 0;
711
712 /*@ buffers ********************************************************* */
713 char *tmp = NULL;
714
715 assert(output_list != NULL);
716 assert(mountlist != NULL);
717 assert(raidlist != NULL);
718 log_it("MLOURP -- starting");
719 items = 0;
720
721
722 for (i = 0; i < mountlist->entries; i++) {
723 if (strstr(mountlist->el[i].mountpoint, "raid")) {
724 used_by =
725 which_raid_device_is_using_this_partition(raidlist,
726 mountlist->el[i].
727 device);
728 if (used_by < 0) {
729 memcpy((void *) &output_list->el[items++],
730 (void *) &mountlist->el[i],
731 sizeof(struct mountlist_line));
732 asprintf(&tmp,
733 "%s is available; user may choose to add it to raid device",
734 output_list->el[items - 1].device);
735 log_it(tmp);
736 paranoid_free(tmp);
737 }
738 }
739 }
740 output_list->entries = items;
741 log_it("MLUORP -- ending");
742}
743
744
745/**
746 * Get the size of a mountlist entry by the @c device field.
747 * @param mountlist The mountlist to search in.
748 * @param device The device to search for
749 * @return The size of the device (in KB), or -1 if it could not be found.
750 */
751long long
752size_of_specific_device_in_mountlist(struct mountlist_itself *mountlist,
753 char *device)
754{
755 /*@ int ************************************************************** */
756 int i = 0;
757
758
759 assert(mountlist != NULL);
760 assert_string_is_neither_NULL_nor_zerolength(device);
761
762 for (i = 0;
763 i < mountlist->entries && strcmp(mountlist->el[i].device, device);
764 i++);
765 if (i == mountlist->entries) {
766 return (-1);
767 } else {
768 return (mountlist->el[i].size);
769 }
770}
771
772
773/**
774 * Load a file on disk into @p mountlist.
775 * The file on disk should consist of multiple lines, each containing 4 or 5
776 * columns: the device, the mountpoint, the filesystem type, the size in kilobytes, and optionally the filesystem label.
777 * Comments begin with a '#' without any leading whitespace. Any duplicate
778 * entries are renamed.
779 * @param mountlist The mountlist to load into.
780 * @param fname The name of the file to load the mountlist from.
781 * @return 0 for success, 1 for failure.
782 */
783int load_mountlist(struct mountlist_itself *mountlist, char *fname)
784{
785 FILE *fin = NULL;
786 /* malloc ** */
787 char *incoming = NULL;
788 char *siz = NULL;
789 char *tmp = NULL;
790 char *p = NULL;
791
792 int items = 0;
793 int j = 0;
794 int res = 0;
795
796 assert(mountlist != NULL);
797 assert_string_is_neither_NULL_nor_zerolength(fname);
798
799 if (!(fin = fopen(fname, "r"))) {
800 log_it("Unable to open mountlist - '%s'", fname);
801 log_to_screen("Cannot open mountlist");
802 return (1);
803 }
804 malloc_string(incoming);
805 malloc_string(siz);
806 (void) fgets(incoming, MAX_STR_LEN - 1, fin);
807 log_it("Loading mountlist...");
808 while (!feof(fin)) {
809#if linux
810 res = sscanf(incoming,
811 "%s %s %s %s %s",
812 mountlist->el[items].device,
813 mountlist->el[items].mountpoint,
814 mountlist->el[items].format,
815 siz, mountlist->el[items].label);
816 if (res < 5) {
817 /* no label found */
818 asprintf(&(mountlist->el[items].label), "%s", "");
819 }
820#elif __FreeBSD__
821 res = sscanf(incoming,
822 "%s %s %s %s",
823 mountlist->el[items].device,
824 mountlist->el[items].mountpoint,
825 mountlist->el[items].format, siz);
826 asprintf(&(mountlist->el[items].label), "%s", "");
827#endif
828
829 if (!strcmp(mountlist->el[items].device, "/proc") ||
830 !strcmp(mountlist->el[items].device, "proc") ||
831 !strcmp(mountlist->el[items].device, "/sys") ||
832 !strcmp(mountlist->el[items].device, "sys") ||
833 !strcmp(mountlist->el[items].device, "/devpts") ||
834 !strcmp(mountlist->el[items].device, "devpts")
835 ) {
836 log_msg(1,
837 "Ignoring %s in mountlist - not loading that line :) ",
838 mountlist->el[items].device);
839 (void) fgets(incoming, MAX_STR_LEN - 1, fin);
840 continue;
841 }
842 mountlist->el[items].size = atoll(siz);
843 if (mountlist->el[items].device[0] != '\0'
844 && mountlist->el[items].device[0] != '#') {
845 if (items >= ARBITRARY_MAXIMUM) {
846 log_to_screen("Too many lines in mountlist.. ABORTING");
847 finish(1);
848 }
849 for (j = 0;
850 j < items
851 && strcmp(mountlist->el[j].device,
852 mountlist->el[items].device); j++);
853 if (j < items) {
854 strcat(mountlist->el[items].device, "_dup");
855 asprintf(&tmp,
856 "Duplicate entry in mountlist - renaming to %s",
857 mountlist->el[items].device);
858 log_it(tmp);
859 paranoid_free(tmp);
860 }
861 asprintf(&tmp, "%s", mountlist->el[items].device);
862 if (strstr(tmp, "/dev/md/")) {
863 log_it("format_device() --- Contracting %s", tmp);
864 p = strrchr(tmp, '/');
865 if (p) {
866 *p = *(p + 1);
867 *(p + 1) = *(p + 2);
868 *(p + 2) = *(p + 3);
869 }
870 log_it("It was %s; it is now %s",
871 mountlist->el[items].device, tmp);
872 strcpy(mountlist->el[items].device, tmp);
873 }
874 paranoid_free(tmp);
875
876 log_it("%s %s %s %lld %s",
877 mountlist->el[items].device,
878 mountlist->el[items].mountpoint,
879 mountlist->el[items].format,
880 mountlist->el[items].size,
881 mountlist->el[items].label);
882 items++;
883 }
884 (void) fgets(incoming, MAX_STR_LEN - 1, fin);
885 }
886 paranoid_fclose(fin);
887 mountlist->entries = items;
888
889 log_it("Mountlist loaded successfully.");
890 log_it("%d entries in mountlist", items);
891
892 paranoid_free(incoming);
893 paranoid_free(siz);
894 return (0);
895}
896
897
898
899/**
900 * Save @p mountlist to a file on disk.
901 * @param mountlist The mountlist to save.
902 * @param fname The file to save it to.
903 * @return 0 for success, 1 for failure.
904 * @see load_mountlist
905 */
906int save_mountlist_to_disk(struct mountlist_itself *mountlist, char *fname)
907{
908 FILE *fout;
909 int i;
910
911 assert(mountlist != NULL);
912 assert_string_is_neither_NULL_nor_zerolength(fname);
913
914 log_it("save_mountlist_to_disk() --- saving to %s", fname);
915 if (!(fout = fopen(fname, "w"))) {
916 log_OS_error("WMTD - Cannot openout mountlist");
917 return (1);
918 }
919 for (i = 0; i < mountlist->entries; i++) {
920 fprintf(fout,
921 "%-15s %-15s %-15s %-15lld %-15s\n",
922 mountlist->el[i].device, mountlist->el[i].mountpoint,
923 mountlist->el[i].format, mountlist->el[i].size,
924 mountlist->el[i].label);
925 }
926 paranoid_fclose(fout);
927 return (0);
928}
929
930
931/**
932 * Sort the mountlist alphabetically by device.
933 * The sorting is done in-place.
934 * @param mountlist The mountlist to sort.
935 */
936void sort_mountlist_by_device(struct mountlist_itself *mountlist)
937{
938 int diff;
939 int lino = -999;
940
941 assert(mountlist != NULL);
942
943 while (lino < mountlist->entries) {
944 for (lino = 1; lino < mountlist->entries; lino++) {
945 diff =
946 strcmp_inc_numbers(mountlist->el[lino - 1].device,
947 mountlist->el[lino].device);
948 if (diff > 0) {
949 swap_mountlist_entries(mountlist, lino - 1, lino);
950 break;
951 }
952 }
953 }
954}
955
956
957/**
958 * Sort the mountlist alphabetically by mountpoint.
959 * The sorting is done in-place.
960 * @param mountlist The mountlist to sort.
961 * @param reverse If TRUE, then do a reverse sort.
962 */
963void
964sort_mountlist_by_mountpoint(struct mountlist_itself *mountlist,
965 bool reverse)
966{
967 int diff;
968 int lino = -999;
969
970 assert(mountlist != NULL);
971
972 while (lino < mountlist->entries) {
973 for (lino = 1; lino < mountlist->entries; lino++) {
974 diff =
975 strcmp(mountlist->el[lino - 1].mountpoint,
976 mountlist->el[lino].mountpoint);
977 if ((diff > 0 && !reverse) || ((diff < 0 && reverse))) {
978 swap_mountlist_entries(mountlist, lino - 1, lino);
979 break;
980 }
981 }
982 }
983}
984
985
986/**
987 * Swap two entries in the mountlist in-place.
988 * @param mountlist The mountlist to swap the entries in.
989 * @param a The index number of the first entry.
990 * @param b The index number of the second entry.
991 */
992void
993swap_mountlist_entries(struct mountlist_itself *mountlist, int a, int b)
994{
995 /*@ mallocs *** */
996 char *device = NULL;
997 char *mountpoint = NULL;
998 char *format = NULL;
999
1000 long long size;
1001
1002 assert(mountlist != NULL);
1003 assert(a >= 0);
1004 assert(b >= 0);
1005
1006 asprintf(&device, "%s", mountlist->el[a].device);
1007 asprintf(&mountpoint, "%s", mountlist->el[a].mountpoint);
1008 asprintf(&format, "%s", mountlist->el[a].format);
1009
1010 size = mountlist->el[a].size;
1011
1012 strcpy(mountlist->el[a].device, mountlist->el[b].device);
1013 strcpy(mountlist->el[a].mountpoint, mountlist->el[b].mountpoint);
1014 strcpy(mountlist->el[a].format, mountlist->el[b].format);
1015
1016 mountlist->el[a].size = mountlist->el[b].size;
1017
1018 strcpy(mountlist->el[b].device, device);
1019 strcpy(mountlist->el[b].mountpoint, mountpoint);
1020 strcpy(mountlist->el[b].format, format);
1021
1022 mountlist->el[b].size = size;
1023 paranoid_free(device);
1024 paranoid_free(mountpoint);
1025 paranoid_free(format);
1026}
1027
1028/* @} - end of mountlistGroup */
Note: See TracBrowser for help on using the repository browser.