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

Last change on this file since 2497 was 2497, checked in by Bruno Cornec, 11 years ago

Tags MondoRescue? version 2.2.9.1

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