source: trunk/mondo/mondo/src/libmondo-mountlist.c @ 795

Last change on this file since 795 was 783, checked in by bruno, 13 years ago
  • Massive rewrite continues for memory management.
  • main structure should now have all parameters allocated dynamically
  • new lib libmr.a + dir + build process reviewed to support it.
  • new include subdir to host external definitions of the new lib
  • code now compiles. Still one remaining link issues for mondorestore. This should allow for some tests soon.

(goal is to separate completely reviewed code and functions and provide clean interfaces)

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