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

Last change on this file since 1081 was 1081, checked in by bruno, 12 years ago

merge -r1078:1080 $SVN_M/branches/stable

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