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

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

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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