source: trunk/mondo/mondo/common/libmondo-mountlist.c @ 280

Last change on this file since 280 was 280, checked in by andree, 14 years ago

Add the actual format to messages after calls to function
is_this_a_valid_disk_format() about unsupported formats.

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