source: branches/stable/mondo/src/common/libmondo-mountlist.c @ 1663

Last change on this file since 1663 was 1663, checked in by bruno, 12 years ago
  • Fix bug #197 (based on an initial patch of Scott Cummings)
  • Fix a bug where df was using locale to print messages and wasn't filtered correctly
  • mkdtemp checked in configure
  • reset_bkpinfo called as early as possible by both main program.
  • It creates a tmpdir cleanly with mkdtemp in setup_tmpdir subfunction, which takes in account TMPIR and TMP env var. Remains to see what tmpfs does and tests
  • configure.in should also be filtered.
  • Remove g_bkpinfo_DONTUSETHIS
  • remove bkpinfo also from header files
  • Render bkpinfo global (potential issue on thread, but should not be a problem as that structure is indeed static during archive)
  • Apply patch from Andree Leidenfrost, modified a bit to use bkpinfo->tmpdir instead of /tmp or MINDI_CACHE when appropriate. Fix security issues in mondo. Thanks al ot Andree for catching all those issues.
  • /tmp => /var/log for mondorestore.log in mindi
  • Update linux terminfo to fix a color issue (Andree Leidenfrost)
  • Removes useless log file (Andree Leidenfrost)
  • replace vi with find_my_editor during restore (Andree Leidenfrost)
  • sync in bg in mindi (VMWare issue to look at)
  • mindi/mindi-busybox have a different version than mondo for pb
  • PB-SUF also added to spec file
  • Fix a bug for pb build (omission of PB-SUF declaration)

(merge -r1631:1662 $SVN_M/branches/2.2.5)

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