source: MondoRescue/branches/3.0/mondo/src/common/libmondo-mountlist.c

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