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

Last change on this file since 1176 was 1176, checked in by bruno, 13 years ago

Some merges from stable (synchro for mem. mngt)

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