source: branches/2.2.9/mondo/src/common/libmondo-devices.c @ 2771

Last change on this file since 2771 was 2771, checked in by Bruno Cornec, 9 years ago
  • Adds GUI support for compresion type. Fix half of #468.
  • Property svn:keywords set to Id
File size: 96.3 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 2771 2011-04-21 23:49:03Z bruno $
3*/
4
5/**
6 * @file
7 * Functions to handle interactions with backup devices.
8 */
9
10#include "my-stuff.h"
11#include "mr_mem.h"
12#include "mr_str.h"
13#include "mondostructures.h"
14#include "libmondo-files-EXT.h"
15#include "libmondo-devices.h"
16#include "lib-common-externs.h"
17#include "libmondo-string-EXT.h"
18#include "libmondo-tools-EXT.h"
19#include "libmondo-gui-EXT.h"
20#include "libmondo-fork-EXT.h"
21#include "libmondo-stream-EXT.h"
22
23#include <sys/types.h>
24#ifdef __FreeBSD__
25#define DKTYPENAMES
26#define FSTYPENAMES
27#include <sys/disklabel.h>
28#include <sys/disk.h>
29#elif linux
30#define u64 unsigned long long
31#include <linux/fs.h>           /* for BLKGETSIZE64 */
32#include <linux/hdreg.h>
33#endif
34
35/*@unused@*/
36//static char cvsid[] = "$Id: libmondo-devices.c 2771 2011-04-21 23:49:03Z bruno $";
37//
38
39extern char *which_compression_type();
40
41extern int g_current_media_number;
42extern double g_kernel_version;
43
44extern bool g_ISO_restore_mode;
45extern char *g_selfmounted_isodir;
46extern char *MONDO_LOGFILE;
47
48extern void setup_tmpdir(char *path);
49
50static char g_cdrw_drive_is_here[MAX_STR_LEN / 4] = "";
51static char g_cdrom_drive_is_here[MAX_STR_LEN / 4] = "";
52static char g_dvd_drive_is_here[MAX_STR_LEN / 4] = "";
53
54
55/**
56 * ????? @bug ?????
57 * @ingroup globalGroup
58 */
59bool g_restoring_live_from_cd = FALSE;
60bool g_restoring_live_from_netfs = FALSE;
61
62extern t_bkptype g_backup_media_type;   // set by main()
63
64/* Reference to global bkpinfo */
65extern struct s_bkpinfo *bkpinfo;
66
67/* Stuff that handles the -I and -E option when a whole disk DSF is used */
68typedef struct mounted_fs_struct {
69    char device[MAX_STR_LEN];       /* The name of the device */
70    char mount_point[MAX_STR_LEN];  /* The devices mount point */
71    unsigned char check;            /* 1 == included on DSF */
72    struct mounted_fs_struct *next;
73} MOUNTED_FS_STRUCT;
74
75static MOUNTED_FS_STRUCT *DSF_Head = NULL;      /* Points to the first entry of mounted_fs_struct list */
76static MOUNTED_FS_STRUCT *DSF_Tail = NULL;      /* Points to the last entry of mounted_fs_struct list */
77
78
79void set_g_cdrom_and_g_dvd_to_bkpinfo_value()
80{
81    strcpy(g_cdrom_drive_is_here, bkpinfo->media_device);   // just in case
82    strcpy(g_dvd_drive_is_here, bkpinfo->media_device); // just in case
83}
84
85
86
87/**
88 * Retract all CD trays and wait for autorun to complete.
89 * @ingroup deviceGroup
90 */
91void retract_CD_tray_and_defeat_autorun(void)
92{
93//  log_it("rctada: Retracting all CD trays", __LINE__);
94    if (strlen(g_cdrom_drive_is_here) > 0) {
95        inject_device(g_cdrom_drive_is_here);
96    }
97    if (strlen(g_dvd_drive_is_here) > 0) {
98        inject_device(g_dvd_drive_is_here);
99    }
100    if (strlen(g_cdrw_drive_is_here) > 0) {
101        inject_device(g_cdrw_drive_is_here);
102    }
103//  log_it("rctada: killing autorun");
104//  run_program_and_log_output("killall autorun", TRUE);
105    if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5)) {
106        log_it("autorun detected; sleeping for 2 seconds");
107        sleep(2);
108    }
109    log_it("rctada: Unmounting all CD drives", __LINE__);
110    run_program_and_log_output("umount /dev/cdr* /dev/dvd*", 5);
111}
112
113
114
115/**
116 * Determine whether we're booted off a ramdisk.
117 * @return @c TRUE (we are) or @c FALSE (we aren't).
118 * @ingroup utilityGroup
119 */
120bool am_I_in_disaster_recovery_mode(void)
121{
122    char *tmp = NULL;
123    char *comment;
124    bool is_this_a_ramdisk = FALSE;
125
126    malloc_string(comment);
127    mr_asprintf(&tmp, "%s", where_is_root_mounted());
128    sprintf(comment, "root is mounted at %s\n", tmp);
129    log_msg(0, comment);
130    log_msg(0,
131            "No, Schlomo, that doesn't mean %s is the root partition. It's just a debugging message. Relax. It's part of am_I_in_disaster_recovery_mode().",
132            tmp);
133
134#ifdef __FreeBSD__
135    if (strstr(tmp, "/dev/md")) {
136        is_this_a_ramdisk = TRUE;
137    }
138#else
139    if (!strncmp(tmp, "/dev/ram", 8)
140        || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/")
141            && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs")
142        || !strcmp(tmp, "/dev/root")) {
143        is_this_a_ramdisk = TRUE;
144    } else {
145        is_this_a_ramdisk = FALSE;
146    }
147#endif
148    mr_free(tmp);
149
150    if (is_this_a_ramdisk) {
151        if (!does_file_exist("/THIS-IS-A-RAMDISK")) {
152            log_to_screen
153                ("Using /dev/root is stupid of you but I'll forgive you.");
154            is_this_a_ramdisk = FALSE;
155        }
156    }
157    if (does_file_exist("/THIS-IS-A-RAMDISK")) {
158        is_this_a_ramdisk = TRUE;
159    }
160    paranoid_free(comment);
161    log_msg(1, "Is this a ramdisk? result = %d", is_this_a_ramdisk);
162    return (is_this_a_ramdisk);
163}
164
165
166
167
168
169/**
170 * Turn @c bkpinfo->backup_media_type into a human-readable string.
171 * @return The human readable string (e.g. @c cdr becomes <tt>"cdr"</tt>).
172 * @note The returned string points to static storage that will be overwritten with each call.
173 * @ingroup stringGroup
174 */
175static char *bkptype_to_string(t_bkptype bt)
176{
177    static char output[MAX_STR_LEN / 4];
178    switch (bt) {
179    case none:
180        strcpy(output, "none");
181        break;
182    case iso:
183        strcpy(output, "iso");
184        break;
185    case cdr:
186        strcpy(output, "cdr");
187        break;
188    case cdrw:
189        strcpy(output, "cdrw");
190        break;
191    case cdstream:
192        strcpy(output, "cdstream");
193        break;
194    case netfs:
195        strcpy(output, "netfs");
196        break;
197    case tape:
198        strcpy(output, "tape");
199        break;
200    case udev:
201        strcpy(output, "udev");
202        break;
203    case usb:
204        strcpy(output, "usb");
205        break;
206    default:
207        strcpy(output, "default");
208    }
209    return (output);
210}
211
212
213
214/**
215 * @addtogroup deviceGroup
216 * @{
217 */
218/**
219 * Eject the tray of the specified CD device.
220 * @param dev The device to eject.
221 * @return the return value of the @c eject command. (0=success, nonzero=failure)
222 */
223int eject_device(char *dev)
224{
225    char *command;
226    int res1 = 0, res2 = 0;
227
228    malloc_string(command);
229
230    if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type)
231        && g_backup_media_type != udev) {
232        sprintf(command, "mt -f %s offline", dev);
233        res1 = run_program_and_log_output(command, 1);
234    } else {
235        res1 = 0;
236    }
237
238#ifdef __FreeBSD__
239    if (strstr(dev, "acd")) {
240        sprintf(command, "cdcontrol -f %s eject", dev);
241    } else {
242        sprintf(command, "camcontrol eject `echo %s | sed 's|/dev/||'`",
243                dev);
244    }
245#else
246    sprintf(command, "eject %s", dev);
247#endif
248
249    log_msg(3, "Ejecting %s", dev);
250    res2 = run_program_and_log_output(command, 1);
251    paranoid_free(command);
252    if (res1 && res2) {
253        return (1);
254    } else {
255        return (0);
256    }
257}
258
259/**
260 * Load (inject) the tray of the specified CD device.
261 * @param dev The device to load/inject.
262 * @return 0 for success, nonzero for failure.
263 */
264int inject_device(char *dev)
265{
266    char *command;
267    int i;
268
269    malloc_string(command);
270
271
272#ifdef __FreeBSD__
273    if (strstr(dev, "acd")) {
274        sprintf(command, "cdcontrol -f %s close", dev);
275    } else {
276        sprintf(command, "camcontrol load `echo %s | sed 's|/dev/||'`",
277                dev);
278    }
279#else
280    sprintf(command, "eject -t %s", dev);
281#endif
282    i = run_program_and_log_output(command, FALSE);
283    paranoid_free(command);
284    return (i);
285}
286
287
288/**
289 * Determine whether the specified @p device (really, you can use any file)
290 * exists.
291 * @return TRUE if it exists, FALSE if it doesn't.
292 */
293bool does_device_exist(char *device)
294{
295
296    /*@ buffers *********************************************************** */
297    char *tmp;
298    bool ret;
299
300    malloc_string(tmp);
301    assert_string_is_neither_NULL_nor_zerolength(device);
302
303    sprintf(tmp, "ls %s > /dev/null 2> /dev/null", device);
304
305    if (system(tmp)) {
306        ret = FALSE;
307    } else {
308        ret = TRUE;
309    }
310    paranoid_free(tmp);
311    return (ret);
312}
313
314
315/**
316 * Determine whether a non-Microsoft partition exists on any connected hard drive.
317 * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent PC).
318 */
319bool does_nonMS_partition_exist(void)
320{
321#if __FreeBSD__
322    return
323        !system
324        ("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false");
325#else
326    return
327        !system
328        ("parted2fdisk -l 2>/dev/null | grep '^/dev/' | grep -Eqv '(MS|DOS|FAT|NTFS)'");
329#endif
330}
331
332/**
333 * Determine whether the specified @p partno exists on the specified @p drive.
334 * @param drive The drive to search for the partition in.
335 * @param partno The partition number to look for.
336 * @return 0 if it exists, nonzero otherwise.
337 */
338int does_partition_exist(const char *drive, int partno)
339{
340    /*@ buffers **************************************************** */
341    char *program;
342    char *incoming;
343    char *searchstr = NULL;
344    char *tmp;
345
346    /*@ ints ******************************************************* */
347    int res = 0;
348
349    /*@ pointers *************************************************** */
350    FILE *fin;
351
352
353    /*@ end vars *************************************************** */
354    assert_string_is_neither_NULL_nor_zerolength(drive);
355    assert(partno >= 0 && partno < 999);
356
357    malloc_string(program);
358    malloc_string(incoming);
359    malloc_string(searchstr);
360    malloc_string(tmp);
361
362#ifdef __FreeBSD__
363    // We assume here that this is running from mondorestore. (It is.)
364    sprintf(program, "ls %s %s >/dev/null 2>&1", drive,
365            build_partition_name(tmp, drive, partno));
366    return system(program);
367#else
368    tmp[0] = '\0';
369#endif
370
371    sprintf(program, "parted2fdisk -l %s 2> /dev/null", drive);
372    fin = popen(program, "r");
373    if (!fin) {
374        log_it("program=%s", program);
375        log_OS_error("Cannot popen-in program");
376        return (0);
377    }
378    (void) build_partition_name(searchstr, drive, partno);
379    strcat(searchstr, " ");
380    for (res = 0; !res && fgets(incoming, MAX_STR_LEN - 1, fin);) {
381        if (strstr(incoming, searchstr)) {
382            res = 1;
383        }
384    }
385    if (pclose(fin)) {
386        log_OS_error("Cannot pclose fin");
387    }
388    paranoid_free(program);
389    paranoid_free(incoming);
390    paranoid_free(searchstr);
391    paranoid_free(tmp);
392    return (res);
393}
394
395
396
397
398
399/**
400 * Determine whether given NULL-terminated @p str exists in the MBR of @p dev.
401 * @param dev The device to look in.
402 * @param str The string to look for.
403 * @return TRUE if it exists, FALSE if it doesn't.
404 */
405bool does_string_exist_in_boot_block(char *dev, char *str)
406{
407    /*@ buffers **************************************************** */
408    char *command;
409
410    /*@ end vars *************************************************** */
411    int i;
412
413    assert_string_is_neither_NULL_nor_zerolength(dev);
414    assert_string_is_neither_NULL_nor_zerolength(str);
415
416    malloc_string(command);
417    sprintf(command,
418            "dd if=%s bs=446 count=1 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null",
419            dev, str);
420    i = system(command);
421    paranoid_free(command);
422    if (i) {
423        return (FALSE);
424    } else {
425        return (TRUE);
426    }
427}
428
429/**
430 * Determine whether specified @p str exists in the first @p n sectors of
431 * @p dev.
432 * @param dev The device to look in.
433 * @param str The string to look for.
434 * @param n The number of 512-byte sectors to search.
435 */
436bool does_string_exist_in_first_N_blocks(char *dev, char *str, int n)
437{
438    /*@ buffers **************************************************** */
439    char *command;
440    /*@ end vars *************************************************** */
441    int i;
442
443    malloc_string(command);
444    sprintf(command,
445            "dd if=%s bs=512 count=%i 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null",
446            dev, n, str);
447    i = system(command);
448    paranoid_free(command);
449    if (i) {
450        return (FALSE);
451    } else {
452        return (TRUE);
453    }
454}
455
456
457
458/**
459 * Try to mount CD-ROM at @p mountpoint. If the CD-ROM is not found or has
460 * not been specified, call find_cdrom_device() to find it.
461 * @param bkpinfo The backup information structure. The only field used is @c bkpinfo->media_device.
462 * @param mountpoint Where to mount the CD-ROM.
463 * @return 0 for success, nonzero for failure.
464 * @see mount_CDROM_here
465 */
466int find_and_mount_actual_cd(char *mountpoint)
467{
468    /*@ buffers ***************************************************** */
469
470    /*@ int's  ****************************************************** */
471    int res;
472    char *dev;
473
474    /*@ end vars **************************************************** */
475
476    malloc_string(dev);
477    assert(bkpinfo != NULL);
478    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
479
480    if (g_backup_media_type == dvd) {
481        strcpy(dev, g_dvd_drive_is_here);
482        if (!dev[0]) {
483            find_dvd_device(dev, FALSE);
484        }
485    } else {
486        strcpy(dev, g_cdrom_drive_is_here);
487        if (!dev[0]) {
488            find_cdrom_device(dev, FALSE);
489        }
490    }
491
492    if (bkpinfo->backup_media_type != iso) {
493        retract_CD_tray_and_defeat_autorun();
494    }
495
496    if (!dev[0] || (res = mount_CDROM_here(dev, mountpoint))) {
497        if (!popup_and_get_string
498            ("CD-ROM device", "Please enter your CD-ROM's /dev device",
499             dev, MAX_STR_LEN / 4)) {
500            res = 1;
501        } else {
502            res = mount_CDROM_here(dev, mountpoint);
503        }
504    }
505    if (res) {
506        log_msg(1, "mount failed");
507    } else {
508        log_msg(1, "mount succeeded with %s", dev);
509    }
510    paranoid_free(dev);
511    return (res);
512}
513
514
515
516
517
518
519/**
520 * Locate a CD-R/W writer's SCSI node.
521 * @param cdrw_device SCSI node will be placed here.
522 * @return 0 for success, nonzero for failure.
523 */
524int find_cdrw_device(char *cdrw_device)
525{
526    /*@ buffers ************************ */
527    char *comment;
528    char *tmp = NULL;
529    char *cdr_exe = NULL;
530    char *command;
531
532    malloc_string(comment);
533    malloc_string(command);
534    if (g_cdrw_drive_is_here[0]) {
535        strcpy(cdrw_device, g_cdrw_drive_is_here);
536        log_msg(3, "Been there, done that. Returning %s", cdrw_device);
537        paranoid_free(comment);
538        paranoid_free(command);
539        return (0);
540    }
541    if (g_backup_media_type == dvd) {
542        log_msg(1,
543                "This is dumb. You're calling find_cdrw_device() but you're backing up to DVD. WTF?");
544        paranoid_free(comment);
545        paranoid_free(command);
546        return (1);
547    }
548    run_program_and_log_output("insmod ide-scsi", -1);
549    if (find_home_of_exe("cdrecord")) {
550        mr_asprintf(&cdr_exe, "cdrecord");
551    } else {
552        mr_asprintf(&cdr_exe, "dvdrecord");
553    }
554    if (find_home_of_exe(cdr_exe)) {
555        sprintf(command,
556                "%s -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep CD | cut -d' ' -f2 | head -n1",
557                cdr_exe);
558        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
559    }
560    if ((tmp == NULL) || (strlen(tmp) < 2)) {
561        paranoid_free(comment);
562        mr_free(tmp);
563        mr_free(cdr_exe);
564        paranoid_free(command);
565        return 1;
566    } else {
567        strcpy(cdrw_device, tmp);
568        sprintf(comment, "Found CDRW device - %s", cdrw_device);
569        log_it(comment);
570        strcpy(g_cdrw_drive_is_here, cdrw_device);
571        paranoid_free(comment);
572        mr_free(tmp);
573        mr_free(cdr_exe);
574        paranoid_free(command);
575        return (0);
576    }
577}
578
579
580
581
582/**
583 * Attempt to locate a CD-ROM device's /dev entry.
584 * Several different methods may be used to find the device, including
585 * calling @c cdrecord, searching @c dmesg, and trial-and-error.
586 * @param output Where to put the located /dev entry.
587 * @param try_to_mount Whether to mount the CD as part of the test; if mount
588 * fails then return failure.
589 * @return 0 for success, nonzero for failure.
590 */
591int find_cdrom_device(char *output, bool try_to_mount)
592{
593    /*@ pointers **************************************************** */
594    FILE *fin;
595    char *p;
596    char *q;
597    char *r;
598    int retval = 0;
599
600    /*@ bool's ****************************************************** */
601    bool found_it = FALSE;
602
603    /*@ buffers ***************************************************** */
604    char *tmp;
605    char *tmp1 = NULL;
606    char *cdr_exe = NULL;
607    char *phrase_one;
608    char *phrase_two;
609    char *command;
610    char *dvd_last_resort;
611    char *mountpoint;
612    static char the_last_place_i_found_it[MAX_STR_LEN] = "";
613
614    /*@ intialize *************************************************** */
615    malloc_string(tmp);
616    malloc_string(phrase_one);
617    malloc_string(phrase_two);
618    malloc_string(command);
619    malloc_string(dvd_last_resort);
620    malloc_string(mountpoint);
621
622    output[0] = '\0';
623    phrase_one[0] = '\0';
624    phrase_two[0] = '\0';
625    dvd_last_resort[0] = '\0';
626
627    /*@ end vars **************************************************** */
628
629    if (g_cdrom_drive_is_here[0] && !isdigit(g_cdrom_drive_is_here[0])) {
630        strcpy(output, g_cdrom_drive_is_here);
631        log_msg(3, "Been there, done that. Returning %s", output);
632        retval = 0;
633        goto end_of_find_cdrom_device;
634    }
635    if (the_last_place_i_found_it[0] != '\0' && !try_to_mount) {
636        strcpy(output, the_last_place_i_found_it);
637        log_msg(3,
638                "find_cdrom_device() --- returning last found location - '%s'",
639                output);
640        retval = 0;
641        goto end_of_find_cdrom_device;
642    }
643
644    sprintf(mountpoint, "%s/cd.mnt", bkpinfo->tmpdir);
645    make_hole_for_dir(mountpoint);
646
647    if (find_home_of_exe("cdrecord")) {
648        mr_asprintf(&cdr_exe, "cdrecord");
649    } else {
650        mr_asprintf(&cdr_exe, "dvdrecord");
651    }
652    tmp[0] = '\0';
653    if (!find_home_of_exe(cdr_exe)) {
654        strcpy(output, "/dev/cdrom");
655        log_msg(4, "Can't find cdrecord; assuming %s", output);
656        if (!does_device_exist(output)) {
657            log_msg(4, "That didn't work. Sorry.");
658            retval = 1;
659            goto end_of_find_cdrom_device;
660        } else {
661            retval = 0;
662            goto end_of_find_cdrom_device;
663        }
664    }
665
666    sprintf(command, "%s -scanbus 2> /dev/null", cdr_exe);
667    fin = popen(command, "r");
668    if (!fin) {
669        log_msg(4, "command=%s", command);
670        log_OS_error("Cannot popen command");
671        mr_free(cdr_exe);
672        return (1);
673    }
674    for ((void)fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
675         (void)fgets(tmp, MAX_STR_LEN, fin)) {
676        p = strchr(tmp, '\'');
677        if (p) {
678            q = strchr(++p, '\'');
679            if (q) {
680                for (r = q; *(r - 1) == ' '; r--);
681                *r = '\0';
682                strcpy(phrase_one, p);
683                p = strchr(++q, '\'');
684                if (p) {
685                    q = strchr(++p, '\'');
686                    if (q) {
687                        while (*(q - 1) == ' ') {
688                            q--;
689                        }
690                        *q = '\0';
691                        strcpy(phrase_two, p);
692                    }
693                }
694            }
695        }
696    }
697    paranoid_pclose(fin);
698
699#ifndef __FreeBSD__
700    if (strlen(phrase_two) == 0) {
701        log_msg(4, "Not running phase two. String is empty.");
702    } else {
703        sprintf(command, "dmesg | grep \"%s\" 2> /dev/null", phrase_two);
704        fin = popen(command, "r");
705        if (!fin) {
706            log_msg(4, "Cannot run 2nd command - non-fatal, fortunately");
707        } else {
708            for ((void)fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
709                 (void)fgets(tmp, MAX_STR_LEN, fin)) {
710                log_msg(5, "--> '%s'", tmp);
711                if (tmp[0] != ' ' && tmp[1] != ' ') {
712                    p = strchr(tmp, ':');
713                    if (p) {
714                        *p = '\0';
715                        if (strstr(tmp, "DVD")) {
716                            sprintf(dvd_last_resort, "/dev/%s", tmp);
717                            log_msg(4,
718                                    "Ignoring '%s' because it's a DVD drive",
719                                    tmp);
720                        } else {
721                            sprintf(output, "/dev/%s", tmp);
722                            found_it = TRUE;
723                        }
724                    }
725                }
726            }
727            paranoid_pclose(fin);
728        }
729    }
730
731#endif
732#ifdef __FreeBSD__
733    if (!found_it) {
734        log_msg(4, "OK, approach 2");
735        if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) {
736            if (!
737                (found_it =
738                 set_dev_to_this_if_rx_OK(output, "/dev/cdrom1"))) {
739                if (!
740                    (found_it =
741                     set_dev_to_this_if_rx_OK(output, "/dev/dvd"))) {
742                    if (!
743                        (found_it =
744                         set_dev_to_this_if_rx_OK(output, "/dev/acd0"))) {
745                        if (!
746                            (found_it =
747                             set_dev_to_this_if_rx_OK(output,
748                                                      "/dev/cd01"))) {
749                            if (!
750                                (found_it =
751                                 set_dev_to_this_if_rx_OK(output,
752                                                          "/dev/acd1"))) {
753                                if (!
754                                    (found_it =
755                                     set_dev_to_this_if_rx_OK(output,
756                                                              "/dev/cd1")))
757                                {
758                                    retval = 1;
759                                    goto end_of_find_cdrom_device;
760                                }
761                            }
762                        }
763                    }
764                }
765            }
766        }
767    }
768#else
769    if (!found_it && strlen(dvd_last_resort) > 0) {
770        log_msg(4, "Well, I'll use the DVD - %s - as a last resort",
771                dvd_last_resort);
772        strcpy(output, dvd_last_resort);
773        found_it = TRUE;
774    }
775    if (found_it) {
776        sprintf(tmp, "grep \"%s=ide-scsi\" /proc/cmdline &> /dev/null",
777                strrchr(output, '/') + 1);
778        if (system(tmp) == 0) {
779            log_msg(4,
780                    "%s is not right. It's being SCSI-emulated. Continuing.",
781                    output);
782            found_it = FALSE;
783            output[0] = '\0';
784        }
785    }
786
787    if (found_it) {
788        log_msg(4, "(find_cdrom_device) --> '%s'", output);
789        if (!does_device_exist(output)) {
790            found_it = FALSE;
791            log_msg(4, "OK, I was wrong, I haven't found it... yet.");
792        }
793    }
794
795    if (!found_it) {
796        log_msg(4, "OK, approach 2");
797        if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/scd0"))) {
798            if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/sr0"))) {
799                if (!
800                    (found_it =
801                     set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) {
802                    if (!
803                        (found_it =
804                         set_dev_to_this_if_rx_OK(output,
805                                                  "/dev/cdrom0"))) {
806                        if (!
807                            (found_it =
808                             set_dev_to_this_if_rx_OK(output,
809                                                      "/dev/cdrom1"))) {
810                            if (!
811                                (found_it =
812                                 set_dev_to_this_if_rx_OK(output,
813                                                          "/dev/sr1"))) {
814                                if (!
815                                    (found_it =
816                                     set_dev_to_this_if_rx_OK(output,
817                                                              "/dev/dvd")))
818                                {
819                                    if (!
820                                        (found_it =
821                                         set_dev_to_this_if_rx_OK(output,
822                                                                  g_cdrw_drive_is_here)))
823                                    {
824                                        retval = 1;
825                                        goto end_of_find_cdrom_device;
826                                    }
827                                }
828                            }
829                        }
830                    }
831                }
832            }
833        }
834    }
835#endif
836
837    if (found_it && try_to_mount) {
838        if (mount_CDROM_here(output, mountpoint)) {
839            log_msg(4, "[Cardigans] I've changed my mind");
840            found_it = FALSE;
841        } else {
842            sprintf(tmp, "%s/archives", mountpoint);
843            if (!does_file_exist(tmp)) {
844                log_msg(4, "[Cardigans] I'll take it back");
845                found_it = FALSE;
846            } else {
847                sprintf(command, "umount %s", output);
848                paranoid_system(command);
849                log_msg(4, "I'm confident the Mondo CD is in %s", output);
850            }
851        }
852    }
853    unlink(mountpoint);
854
855    if (found_it) {
856        if (!does_file_exist(output)) {
857            log_msg(3, "I still haven't found it.");
858            return (1);
859        }
860        log_msg(3, "(find_cdrom_device) --> '%s'", output);
861        strcpy(the_last_place_i_found_it, output);
862        strcpy(g_cdrom_drive_is_here, output);
863        retval = 0;
864        goto end_of_find_cdrom_device;
865    }
866
867    sprintf(command,
868            "%s -scanbus | grep \"[0-9],[0-9],[0-9]\" | grep \"[D|C][V|D]\" | grep -n \"\" | grep \"%s\" | cut -d':' -f2",
869            cdr_exe, g_cdrw_drive_is_here);
870    log_msg(1, "command=%s", command);
871    mr_asprintf(&tmp1, "%s", call_program_and_get_last_line_of_output(command));
872    if (strlen(tmp1) > 0) {
873        strcpy(output, tmp1);
874        log_msg(4, "Finally found it at %s", output);
875        retval = 0;
876    } else {
877        log_msg(4, "Still couldn't find it.");
878        retval = 1;
879    }
880    mr_free(tmp1);
881
882  end_of_find_cdrom_device:
883    paranoid_free(tmp);
884    mr_free(cdr_exe);
885    paranoid_free(phrase_one);
886    paranoid_free(phrase_two);
887    paranoid_free(command);
888    paranoid_free(dvd_last_resort);
889    paranoid_free(mountpoint);
890    return (retval);
891}
892
893
894
895
896
897int find_dvd_device(char *output, bool try_to_mount)
898{
899    char *command;
900    char *tmp;
901    int retval = 0, devno = -1;
902
903    malloc_string(command);
904    malloc_string(tmp);
905
906    if (g_dvd_drive_is_here[0]) {
907        strcpy(output, g_dvd_drive_is_here);
908        log_msg(3, "Been there, done that. Returning %s", output);
909        return (0);
910    }
911
912    sprintf(tmp, "%s", call_program_and_get_last_line_of_output
913            ("dvdrecord -scanbus 2> /dev/null | grep \") '\" | grep -n \"\" | grep DVD | cut -d':' -f1")
914        );
915    log_msg(5, "tmp = '%s'", tmp);
916    if (!tmp[0])
917        sprintf(tmp, "%s", call_program_and_get_last_line_of_output
918                ("cdrecord -scanbus 2> /dev/null | grep \") '\" | grep -n \"\" | grep DVD | cut -d':' -f1")
919            );
920    if (tmp[0]) {
921        devno = atoi(tmp) - 1;
922    }
923    if (devno >= 0) {
924        retval = 0;
925        sprintf(output, "/dev/scd%d", devno);
926        strcpy(g_dvd_drive_is_here, output);
927        log_msg(2, "I think DVD is at %s", output);
928    } else {
929        log_msg(2, "I cannot find DVD");
930        retval = 1;
931    }
932
933    if (try_to_mount) {
934        log_msg(1, "Ignoring the fact that try_to_mount==TRUE");
935    }
936    return (retval);
937}
938
939
940
941
942
943#include <sys/ioctl.h>
944
945/**
946 * Find the size of the specified @p drive, in megabytes. Uses @c ioctl calls
947 * and @c dmesg.
948 * @param drive The device to find the size of.
949 * @return size in megabytes.
950 */
951long get_phys_size_of_drive(char *drive)
952{
953    int fd;
954#if linux
955    unsigned long long s = 0;
956    int fileid, cylinders = 0, cylindersleft = 0;
957    int cylindersize = 0;
958    int gotgeo = 0;
959
960
961    struct hd_geometry hdgeo;
962#elif __FreeBSD__
963    off_t s;
964#endif
965
966    long outvalA = -1;
967    long outvalB = -1;
968    long outvalC = -1;
969
970    if ((fd = open(drive, O_RDONLY)) != -1) {
971        if (ioctl(fd,
972#if linux
973#ifdef BLKGETSIZE64
974                  BLKGETSIZE64,
975#else
976                  BLKGETSIZE,
977#endif
978#elif __FreeBSD__
979                  DIOCGMEDIASIZE,
980#endif
981                  &s) != -1) {
982            close(fd);
983            // s>>11 works for older disks but not for newer ones
984            outvalB =
985#if linux
986#ifdef BLKGETSIZE64
987                s >> 20
988#else
989                s >> 11
990#endif
991#else
992                s >> 20
993#endif
994                ;
995        }
996    }
997
998    if (outvalB <= 0) {
999        log_msg(1, "Error getting size of %s: %s", drive, strerror(errno));
1000#if linux
1001        fileid = open(drive, O_RDONLY);
1002        if (fileid != -1) {
1003            if (ioctl(fileid, HDIO_GETGEO, &hdgeo) != -1) {
1004                if (hdgeo.cylinders && hdgeo.heads && hdgeo.sectors) {
1005                    cylindersleft = cylinders = hdgeo.cylinders;
1006                    cylindersize = hdgeo.heads * hdgeo.sectors / 2;
1007                    outvalA = cylindersize * cylinders / 1024;
1008                    log_msg(2, "Got Harddisk geometry, C:%d, H:%d, S:%d",
1009                            hdgeo.cylinders, hdgeo.heads, hdgeo.sectors);
1010                    gotgeo = 1;
1011                } else {
1012                    log_msg(1, "Harddisk geometry wrong");
1013                }
1014            } else {
1015                log_msg(1,
1016                        "Error in ioctl() getting new hard disk geometry (%s), resizing in unsafe mode",
1017                        strerror(errno));
1018            }
1019            close(fileid);
1020        } else {
1021            log_msg(1, "Failed to open %s for reading: %s", drive,
1022                    strerror(errno));
1023        }
1024        if (!gotgeo) {
1025            log_msg(1, "Failed to get harddisk geometry, using old mode");
1026        }
1027#endif
1028    }
1029// OLDER DISKS will give ridiculously low value for outvalB (so outvalA is returned) :)
1030// NEWER DISKS will give sane value for outvalB (close to outvalA, in other words) :)
1031
1032    outvalC = (outvalA > outvalB) ? outvalA : outvalB;
1033
1034//  log_msg (5, "drive = %s, error = %s", drive, strerror (errno));
1035//  fatal_error ("GPSOD: Unable to get size of drive");
1036    log_msg(1, "%s --> %ld or %ld --> %ld", drive, outvalA, outvalB,
1037            outvalC);
1038
1039    return (outvalC);
1040}
1041
1042/**
1043 * Determine whether @p format is supported by the kernel. Uses /proc/filesystems
1044 * under Linux and @c lsvfs under FreeBSD.
1045 * @param format The format to test.
1046 * @return TRUE if the format is supported, FALSE if not.
1047 */
1048bool is_this_a_valid_disk_format(char *format)
1049{
1050    char *good_formats = NULL;
1051    char *command;
1052    char *format_sz;
1053
1054    FILE *pin;
1055    int retval;
1056    malloc_string(good_formats);
1057    malloc_string(command);
1058    malloc_string(format_sz);
1059
1060    assert_string_is_neither_NULL_nor_zerolength(format);
1061
1062    sprintf(format_sz, "%s ", format);
1063
1064#ifdef __FreeBSD__
1065    sprintf(command,
1066            "lsvfs | tr -s '\t' ' ' | grep -v Filesys | grep -v -- -- | cut -d' ' -f1 | tr -s '\n' ' '");
1067#else
1068    sprintf(command,
1069            "grep -v nodev /proc/filesystems | tr -s '\t' ' ' | cut -d' ' -f2 | tr -s '\n' ' '");
1070#endif
1071
1072    pin = popen(command, "r");
1073    if (!pin) {
1074        log_OS_error("Unable to read good formats");
1075        retval = 0;
1076    } else {
1077        strcpy(good_formats, " ");
1078        (void) fgets(good_formats + 1, MAX_STR_LEN - 1, pin);
1079        if (pclose(pin)) {
1080            log_OS_error("Cannot pclose good formats");
1081        }
1082        strip_spaces(good_formats);
1083        strcat(good_formats, " swap lvm raid ntfs-3g ntfs 7 "); // " ntfs 7 " -- um, cheating much? :)
1084        if (strstr(good_formats, format_sz)) {
1085            retval = 1;
1086        } else {
1087            retval = 0;
1088        }
1089    }
1090    paranoid_free(good_formats);
1091    paranoid_free(command);
1092    paranoid_free(format_sz);
1093    return (retval);
1094}
1095
1096
1097/** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */
1098
1099/**
1100 * Determine whether @p device_raw is currently mounted.
1101 * @param device_raw The device to check.
1102 * @return TRUE if it's mounted, FALSE if not.
1103 */
1104bool is_this_device_mounted(char *device_raw)
1105{
1106
1107    /*@ pointers **************************************************** */
1108    FILE *fin;
1109
1110    /*@ buffers ***************************************************** */
1111    char *incoming;
1112    char *device_with_tab = NULL;
1113    char *device_with_space = NULL;
1114    char *tmp = NULL;
1115    bool retval = FALSE;
1116
1117#ifdef __FreeBSD__
1118#define SWAPLIST_COMMAND "swapinfo"
1119#else
1120#define SWAPLIST_COMMAND "cat /proc/swaps"
1121#endif
1122
1123    /*@ end vars **************************************************** */
1124
1125    malloc_string(incoming);
1126    assert(device_raw != NULL);
1127//  assert_string_is_neither_NULL_nor_zerolength(device_raw);
1128    if (device_raw[0] != '/' && !strstr(device_raw, ":/")) {
1129        log_msg(1, "%s needs to have a '/' prefixed - I'll do it",
1130                device_raw);
1131        mr_asprintf(&tmp, "/%s", device_raw);
1132    } else {
1133        mr_asprintf(&tmp, "%s", device_raw);
1134    }
1135    log_msg(1, "Is %s mounted?", tmp);
1136    if (!strcmp(tmp, "/proc") || !strcmp(tmp, "proc")) {
1137        log_msg(1,
1138                "I don't know how the heck /proc made it into the mountlist. I'll ignore it.");
1139        mr_free(tmp);
1140        return(FALSE);
1141    }
1142    mr_asprintf(&device_with_tab, "%s\t", tmp);
1143    mr_asprintf(&device_with_space, "%s ", tmp);
1144    mr_free(tmp);
1145
1146    if (!(fin = popen("mount", "r"))) {
1147        log_OS_error("Cannot popen 'mount'");
1148        return(FALSE);
1149    }
1150    for ((void)fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
1151         (void)fgets(incoming, MAX_STR_LEN - 1, fin)) {
1152        if (strstr(incoming, device_with_space) //> incoming
1153            || strstr(incoming, device_with_tab))   // > incoming)
1154        {
1155            paranoid_pclose(fin);
1156            paranoid_free(incoming);
1157            return(TRUE);
1158        }
1159    }
1160    mr_free(device_with_tab);
1161    paranoid_pclose(fin);
1162    mr_asprintf(&tmp, "%s | grep -E \"^%s\" > /dev/null 2> /dev/null", SWAPLIST_COMMAND, device_with_space);
1163    mr_free(device_with_space);
1164    log_msg(4, "tmp (command) = '%s'", tmp);
1165    if (!system(tmp)) {
1166        retval = TRUE;
1167    }
1168    mr_free(tmp);
1169    paranoid_free(incoming);
1170    return(retval);
1171}
1172
1173#ifdef __FreeBSD__
1174//                       CODE IS FREEBSD-SPECIFIC
1175/**
1176 * Create a loopback device for specified @p fname.
1177 * @param fname The file to associate with a device.
1178 * @return /dev entry for the device, or NULL if it couldn't be allocated.
1179 */
1180char *make_vn(char *fname)
1181{
1182    char *device = (char *) malloc(MAX_STR_LEN);
1183    char *mddevice = (char *) malloc(32);
1184    char command[MAX_STR_LEN];
1185    int vndev = 2;
1186    if (atoi
1187        (call_program_and_get_last_line_of_output
1188         ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1189        do {
1190            sprintf(mddevice, "vn%ic", vndev++);
1191            sprintf(command, "vnconfig %s %s", mddevice, fname);
1192            if (vndev > 10) {
1193                return NULL;
1194            }
1195        }
1196        while (system(command));
1197    } else {
1198        sprintf(command, "mdconfig -a -t vnode -f %s", fname);
1199        mddevice = call_program_and_get_last_line_of_output(command);
1200        if (!strstr(mddevice, "md")) {
1201            return NULL;
1202        }
1203    }
1204    sprintf(device, "/dev/%s", mddevice);
1205    return device;
1206}
1207
1208
1209
1210//                       CODE IS FREEBSD-SPECIFIC
1211/**
1212 * Deallocate specified @p dname.
1213 * This should be called when you are done with the device created by make_vn(),
1214 * so the system does not run out of @c vn devices.
1215 * @param dname The device to deallocate.
1216 * @return 0 for success, nonzero for failure.
1217 */
1218int kick_vn(char *dname)
1219{
1220    char command[MAX_STR_LEN];
1221
1222    if (strncmp(dname, "/dev/", 5) == 0) {
1223        dname += 5;
1224    }
1225
1226    if (atoi
1227        (call_program_and_get_last_line_of_output
1228         ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1229        sprintf(command, "vnconfig -d %s", dname);
1230        return system(command);
1231    } else {
1232        sprintf(command, "mdconfig -d -u %s", dname);
1233        return system(command);
1234    }
1235     /*NOTREACHED*/ return 255;
1236}
1237#endif
1238
1239
1240/**
1241 * Mount the CD-ROM at @p mountpoint.
1242 * @param device The device (or file if g_ISO_restore_mode) to mount.
1243 * @param mountpoint The place to mount it.
1244 * @return 0 for success, nonzero for failure.
1245 */
1246int mount_USB_here(char *device, char *mountpoint)
1247{
1248    /*@ buffer ****************************************************** */
1249    char *command;
1250    int retval;
1251
1252    malloc_string(command);
1253    assert_string_is_neither_NULL_nor_zerolength(device);
1254    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1255
1256    make_hole_for_dir(mountpoint);
1257    if (isdigit(device[0])) {
1258        return(1);
1259    }
1260    log_msg(4, "(mount_USB_here --- device=%s, mountpoint=%s", device,
1261            mountpoint);
1262
1263#ifdef __FreeBSD__
1264    sprintf(command, "mount_vfat %s %s 2>> %s",
1265            device, mountpoint, MONDO_LOGFILE);
1266
1267#else
1268    sprintf(command, "mount %s -t vfat %s 2>> %s",
1269            device, mountpoint, MONDO_LOGFILE);
1270#endif
1271
1272    log_msg(4, command);
1273    retval = system(command);
1274    log_msg(1, "system(%s) returned %d", command, retval);
1275
1276    paranoid_free(command);
1277    return (retval);
1278}
1279
1280/**
1281 * Mount the CD-ROM at @p mountpoint.
1282 * @param device The device (or file if g_ISO_restore_mode) to mount.
1283 * @param mountpoint The place to mount it.
1284 * @return 0 for success, nonzero for failure.
1285 */
1286int mount_CDROM_here(char *device, char *mountpoint)
1287{
1288    /*@ buffer ****************************************************** */
1289    char *command = NULL;
1290    int retval;
1291#ifdef __FreeBSD__
1292    char *dev = NULL;
1293#else
1294    char *options = NULL;
1295#endif
1296
1297    assert_string_is_neither_NULL_nor_zerolength(device);
1298    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1299
1300    make_hole_for_dir(mountpoint);
1301
1302    if (isdigit(device[0])) {
1303        find_cdrom_device(device, FALSE);
1304    }
1305#ifndef __FreeBSD__
1306    mr_asprintf(&options, "ro");
1307#endif
1308
1309    if (g_ISO_restore_mode) {
1310
1311#ifdef __FreeBSD__
1312        mr_asprintf(&dev, "%s", make_vn(device));
1313        if (!dev) {
1314            mr_asprintf(&command, "Unable to mount ISO (make_vn(%s) failed)", device);
1315            fatal_error(command);
1316        }
1317        strcpy(device, dev);
1318        paranoid_free(dev);
1319#else
1320        mr_strcat(options, ",loop");
1321#endif
1322
1323    }
1324    log_msg(4, "(mount_CDROM_here --- device=%s, mountpoint=%s", device,
1325            mountpoint);
1326    /*@ end vars *************************************************** */
1327
1328#ifdef __FreeBSD__
1329    mr_asprintf(&command, "mount_cd9660 -r %s %s 2>> %s", device, mountpoint, MONDO_LOGFILE);
1330
1331#else
1332    mr_asprintf(&command, "mount %s -o %s -t iso9660 %s 2>> %s", device, options, mountpoint, MONDO_LOGFILE);
1333    paranoid_free(options);
1334#endif
1335
1336    log_msg(4, command);
1337    if (strncmp(device, "/dev/", 5) == 0) {
1338        retract_CD_tray_and_defeat_autorun();
1339    }
1340    retval = system(command);
1341    log_msg(1, "system(%s) returned %d", command, retval);
1342    paranoid_free(command);
1343
1344    return (retval);
1345}
1346
1347
1348/**
1349* Mount the CD-ROM or USB device at /mnt/cdrom.
1350* @param bkpinfo The backup information structure. Fields used:
1351* - @c bkpinfo->backup_media_type
1352* - @c bkpinfo->disaster_recovery
1353* - @c bkpinfo->isodir
1354* - @c bkpinfo->media_device
1355* @return 0 for success, nonzero for failure.
1356*/
1357int mount_media()
1358{
1359char *mount_cmd;
1360char *mountdir = NULL;
1361int i, res;
1362#ifdef __FreeBSD__
1363char mdd[32];
1364char *mddev = mdd;
1365#endif
1366
1367malloc_string(mount_cmd);
1368assert(bkpinfo != NULL);
1369
1370    if (bkpinfo->backup_media_type == tape
1371        || bkpinfo->backup_media_type == udev) {
1372        log_msg(8, "Tape/udev. Therefore, no need to mount a media.");
1373        paranoid_free(mount_cmd);
1374        return 0;
1375    }
1376
1377    if (!run_program_and_log_output("mount | grep -F " MNT_CDROM, FALSE)) {
1378        log_msg(2, "mount_media() - media already mounted. Fair enough.");
1379        paranoid_free(mount_cmd);
1380        return (0);
1381    }
1382
1383    if (bkpinfo->backup_media_type == netfs) {
1384        log_msg(2, "Mounting for Network thingy");
1385        log_msg(2, "isodir = %s", bkpinfo->isodir);
1386        if ((!bkpinfo->isodir[0] || !strcmp(bkpinfo->isodir, "/"))
1387            && am_I_in_disaster_recovery_mode()) {
1388            strcpy(bkpinfo->isodir, "/tmp/isodir");
1389            log_msg(1, "isodir is being set to %s", bkpinfo->isodir);
1390        }
1391#ifdef __FreeBSD__
1392        sprintf(mount_cmd, "/mnt/isodir/%s/%s/%s-%d.iso", bkpinfo->isodir,
1393            bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number);
1394        mddev = make_vn(mount_cmd);
1395        sprintf(mount_cmd, "mount_cd9660 -r %s " MNT_CDROM, mddev);
1396#else
1397        sprintf(mount_cmd, "mount %s/%s/%s-%d.iso -t iso9660 -o loop,ro %s",
1398            bkpinfo->isodir, bkpinfo->netfs_remote_dir,
1399            bkpinfo->prefix, g_current_media_number, MNT_CDROM);
1400#endif
1401
1402    } else if (bkpinfo->backup_media_type == iso) {
1403        if (bkpinfo->subdir) {
1404            mr_asprintf(&mountdir, "%s/%s", bkpinfo->isodir, bkpinfo->subdir);
1405        } else {
1406            mr_asprintf(&mountdir, "%s", bkpinfo->isodir);
1407        }
1408#ifdef __FreeBSD__
1409        sprintf(mount_cmd, "%s/%s-%d.iso", mountdir,
1410            bkpinfo->prefix, g_current_media_number);
1411        mddev = make_vn(mount_cmd);
1412        sprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, MNT_CDROM);
1413#else
1414        sprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s",
1415            mountdir, bkpinfo->prefix, g_current_media_number, MNT_CDROM);
1416#endif
1417    } else if (bkpinfo->backup_media_type == usb) {
1418        sprintf(mount_cmd, "mount -t vfat %s %s", bkpinfo->media_device, MNT_CDROM);
1419    } else if (strstr(bkpinfo->media_device, "/dev/")) {
1420#ifdef __FreeBSD__
1421        sprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device,
1422        MNT_CDROM);
1423#else
1424        sprintf(mount_cmd, "mount %s -t iso9660 -o ro %s",
1425        bkpinfo->media_device, MNT_CDROM);
1426#endif
1427    } else {
1428        if (bkpinfo->disaster_recovery
1429            && does_file_exist("/tmp/CDROM-LIVES-HERE")) {
1430            strcpy(bkpinfo->media_device,
1431                last_line_of_file("/tmp/CDROM-LIVES-HERE"));
1432        } else {
1433            find_cdrom_device(bkpinfo->media_device, TRUE);
1434        }
1435
1436#ifdef __FreeBSD__
1437    sprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device,
1438        MNT_CDROM);
1439#else
1440    sprintf(mount_cmd, "mount %s -t iso9660 -o ro %s",
1441        bkpinfo->media_device, MNT_CDROM);
1442#endif
1443    }
1444
1445    log_msg(2, "(mount_media) --- command = %s", mount_cmd);
1446    for (i = 0; i < 2; i++) {
1447        res = run_program_and_log_output(mount_cmd, FALSE);
1448        if (!res) {
1449            break;
1450        } else {
1451            log_msg(2, "Failed to mount device.");
1452            sleep(5);
1453            run_program_and_log_output("sync", FALSE);
1454        }
1455    }
1456
1457    if (res) {
1458        log_msg(2, "Failed, despite %d attempts", i);
1459    } else {
1460        log_msg(2, "Mounted media drive OK");
1461    }
1462    paranoid_free(mount_cmd);
1463    return (res);
1464}
1465/**************************************************************************
1466*END_MOUNT_CDROM                                                         *
1467**************************************************************************/
1468
1469
1470
1471
1472/**
1473 * Ask the user for CD number @p cd_number_i_want.
1474 * Sets g_current_media_number once the correct CD is inserted.
1475 * @param bkpinfo The backup information structure. Fields used:
1476 * - @c bkpinfo->backup_media_type
1477 * - @c bkpinfo->prefix
1478 * - @c bkpinfo->isodir
1479 * - @c bkpinfo->media_device
1480 * - @c bkpinfo->please_dont_eject_when_restoring
1481 * @param cd_number_i_want The CD number to ask for.
1482 */
1483void
1484insist_on_this_cd_number(int cd_number_i_want)
1485{
1486
1487    /*@ int ************************************************************* */
1488    int res = 0;
1489
1490
1491    /*@ buffers ********************************************************* */
1492    char *tmp;
1493    char *mds = NULL;
1494    char *request;
1495
1496    assert(bkpinfo != NULL);
1497    assert(cd_number_i_want > 0);
1498
1499//  log_msg(3, "Insisting on CD number %d", cd_number_i_want);
1500
1501    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1502        log_msg(3,
1503                "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1504        return;
1505    }
1506    malloc_string(tmp);
1507    malloc_string(request);
1508    sprintf(tmp, "mkdir -p " MNT_CDROM);
1509    run_program_and_log_output(tmp, 5);
1510    if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso
1511        || bkpinfo->backup_media_type == netfs) {
1512        g_ISO_restore_mode = TRUE;
1513        if (!is_this_device_mounted(MNT_CDROM)) {
1514            log_msg(3, "Mounting media");
1515            g_current_media_number = cd_number_i_want;
1516            mount_media();
1517        }
1518    }
1519    if ((res = what_number_cd_is_this()) != cd_number_i_want) {
1520        log_msg(3, "Currently, we hold %d but we want %d", res,
1521                cd_number_i_want);
1522        mds = media_descriptor_string(bkpinfo->backup_media_type);
1523        sprintf(tmp, "Insisting on %s #%d", mds, cd_number_i_want);
1524        sprintf(request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want);
1525        mr_free(mds);
1526        log_msg(3, tmp);
1527        while (what_number_cd_is_this() != cd_number_i_want) {
1528            paranoid_system("sync");
1529            if (is_this_device_mounted(MNT_CDROM)) {
1530                res =
1531                    run_program_and_log_output("umount " MNT_CDROM, FALSE);
1532            } else {
1533                res = 0;
1534            }
1535            if (res) {
1536                log_to_screen("WARNING - failed to unmount CD-ROM drive");
1537            }
1538            if (!bkpinfo->please_dont_eject) {
1539                res = eject_device(bkpinfo->media_device);
1540            } else {
1541                res = 0;
1542            }
1543            if (res) {
1544                log_to_screen("WARNING - failed to eject CD-ROM disk");
1545            }
1546            popup_and_OK(request);
1547            if (!bkpinfo->please_dont_eject) {
1548                inject_device(bkpinfo->media_device);
1549            }
1550            paranoid_system("sync");
1551        }
1552        log_msg(1, "Thankyou. Proceeding...");
1553        g_current_media_number = cd_number_i_want;
1554    }
1555    paranoid_free(tmp);
1556    paranoid_free(request);
1557}
1558
1559/* @} - end of deviceGroup */
1560
1561
1562
1563/**
1564 * Creates a singly linked list of all of the non-NETFS mounted file systems.
1565 * @param DSFptr A pointer  to the structure MOUNTED_FS_STRUCT used to hold
1566 * the list of mounted file systems.
1567 * @return None.
1568 */
1569static void add_mounted_fs_struct (MOUNTED_FS_STRUCT *DSFptr)
1570{
1571    assert (DSFptr);
1572    if (DSF_Head == NULL) {
1573        DSF_Head = DSFptr;
1574    } else {
1575        DSF_Tail->next = DSFptr;
1576    }
1577    DSFptr->next = NULL;
1578    DSF_Tail = DSFptr;
1579}
1580
1581/**
1582 * Find the structure, in the singly linked list of all of the non-NETFS
1583 * mounted file systems, that contains the specified device.
1584 * @param device The device to find
1585 * @return NULL if it didn't find the device, a pointer to the
1586 * structure if it did.
1587 */
1588static MOUNTED_FS_STRUCT *find_device_in_list (char *device)
1589{
1590    MOUNTED_FS_STRUCT *DSFptr = NULL;
1591
1592    DSFptr = DSF_Head;
1593    while (DSFptr != NULL) {
1594        if (!strcmp(DSFptr->device, device)) {
1595            break;
1596        }
1597        DSFptr = DSFptr->next;
1598    }
1599    return (DSFptr);
1600}
1601
1602/**
1603 * Find the structure, in the singly linked list of all of the non-NETFS
1604 * mounted file systems, that contains the specified mount point.
1605 * @param mount_point The mount point to find
1606 * @return NULL is it didn't find the mount point, a pointer to the
1607 * structure if it did.
1608 */
1609static MOUNTED_FS_STRUCT *find_mount_point_in_list (char *mount_point)
1610{
1611    MOUNTED_FS_STRUCT *DSFptr = NULL;
1612
1613    DSFptr = DSF_Head;
1614    while (DSFptr != NULL) {
1615        if (!strcmp(DSFptr->mount_point, mount_point)) {
1616            break;
1617        }
1618        DSFptr = DSFptr->next;
1619    }
1620    return (DSFptr);
1621}
1622
1623/**
1624 * Frees the memory for all of the structures on the linked list of
1625 * all of the non-NETFS mounted file systems.
1626 */
1627static void free_mounted_fs_list (void) {
1628    MOUNTED_FS_STRUCT *DSFptr = NULL;
1629    MOUNTED_FS_STRUCT *DSFnext = NULL;
1630 
1631    DSFptr = DSF_Head;
1632    while (DSFptr != NULL) {
1633        DSFnext = DSFptr->next;
1634        paranoid_free(DSFptr);
1635        DSFptr = DSFnext;
1636    }
1637    DSF_Head = NULL;
1638    DSF_Tail = NULL;
1639}
1640
1641
1642/**
1643 * Creates a linked list of all of the non-NETFS mounted file systems.
1644 * We use a linked list because we don't know how many  mounted file
1645 * there are (and there can be a lot).
1646 * @return 0 on success and greated than 0 on failure.
1647 */
1648static int create_list_of_non_NETFS_mounted_file_systems (void)
1649{
1650    int i = 0;
1651    int mount_cnt = 0;
1652    int lastpos = 0;
1653    char *mounted_file_system = NULL;
1654    char *command = NULL;
1655    char *token = NULL;
1656    char token_chars[] =" :\t\r\f\a\0";
1657    MOUNTED_FS_STRUCT *DSFptr = NULL;
1658
1659    free_mounted_fs_list();
1660    /********
1661    * Find the number of mounted file system entries and their respective mount points.
1662    * I can't return all of the entries as one string because it's length can be longer
1663    * than MAX_STR_LEN which is used in call_program_and_get_last_line_of_output().
1664    * So start looping and get the number of  mounted file systems and query them one by one.
1665    ********/
1666    /* Get the number of mounted file systems ((those that start with "/dev/" */
1667    mr_asprintf(&command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $0}}'|wc -l");
1668    log_msg(5, "Running: %s", command);
1669    mr_asprintf(&mounted_file_system, "%s", call_program_and_get_last_line_of_output(command));
1670    paranoid_free(command);
1671
1672    mount_cnt = atoi(mounted_file_system);
1673    log_msg (5, "mount_cnt: %d", mount_cnt);
1674    paranoid_free(mounted_file_system);
1675
1676    for (i=mount_cnt; i > 0; i--) {
1677        mr_asprintf(&command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $1,$3}}'|head -n %d", i);
1678        log_msg(5, "Running: %s", command);
1679        mr_asprintf(&mounted_file_system, "%s", call_program_and_get_last_line_of_output(command));
1680        paranoid_free(command);
1681
1682        log_msg (5, "mounted_file_system: %s", mounted_file_system);
1683        if ((token = mr_strtok(mounted_file_system, token_chars, &lastpos)) == NULL) {
1684            log_msg (4, "Could not get the list of mounted file systems");
1685            paranoid_free(mounted_file_system);
1686            mr_free(token);
1687            return (1);
1688        }
1689        if (token) {
1690            log_msg (5, "token: %s", token);
1691        }
1692        while (token != NULL) {
1693            log_msg (5, "token: %s", token);
1694            if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) {
1695                fatal_error ("Cannot allocate memory");
1696            }
1697            add_mounted_fs_struct(DSFptr);
1698            strcpy(DSFptr->device, token);
1699            mr_free(token);
1700            if ((token = mr_strtok(mounted_file_system, token_chars, &lastpos)) == NULL) {
1701                log_msg (5, "Ran out of entries on the mounted file systems list");
1702                mr_free(mounted_file_system);
1703                mr_free(token);
1704                return (1);
1705            }
1706            log_msg (5, "token: %s", token);
1707            strcpy(DSFptr->mount_point, token);
1708            mr_free(token);
1709            token = mr_strtok(mounted_file_system, token_chars, &lastpos); 
1710        }
1711        mr_free(mounted_file_system);
1712    }
1713    /********
1714    * DSFptr = DSF_Head;
1715    * while (DSFptr != NULL) {
1716    * printf ("Dev: %s  MP: %s  Check: %d\n", DSFptr->device, DSFptr->mount_point, DSFptr->check);
1717    * DSFptr = DSFptr->next;
1718    * }
1719    ********/
1720    return (0);
1721}
1722
1723
1724
1725/**
1726 * Given a whole disk device special file, determine which mounted file systems
1727 * are on the dsf's partitions and which mounted file systems are not.
1728 * @param dsf The whole disk device special file.
1729 * @param included_dsf_list A char pointer used to hold the list of mount points
1730 * that are on the dsf. Memory for the array will be allocated within the function.
1731 * @param excluded_dsf_list A char pointer used to hold the list of mount points
1732 * that are not on the dsf. Memory for the array will be allocated within the function.
1733 * @return 0 on success, -1 if no device special file was passed in, -2 if a device
1734 * special file was passed in but it has no partitions on it, or 1 on failure
1735 */
1736static int get_dsf_mount_list (const char *dsf, char **included_dsf_list, char **excluded_dsf_list) {
1737    int i = 0;
1738    int c = 0;
1739    int lastpos = 0;
1740    char VG[MAX_STR_LEN];
1741    char *tmp = NULL;
1742    char *command = NULL;
1743    char *partition_list = NULL;
1744    char partitions[64][MAX_STR_LEN];
1745    char *mount_list = NULL;
1746    char *token = NULL;
1747    char *ndsf = NULL;
1748    char token_chars[] =" \t\r\f\a\0";
1749    MOUNTED_FS_STRUCT *DSFptr = NULL;
1750
1751    memset((char *)partitions, 0, sizeof(partitions));
1752
1753    log_msg(5, "dsf: %s", dsf);
1754
1755    /********
1756    * See if a device special file was passed in (i.e. it must start with /dev/
1757    ********/
1758    if (strncmp(dsf, "/dev/", 5)) {
1759        log_msg (4, "%s does not start with /dev/ and (probably) is not a  device special file", dsf);
1760        return (-1);
1761    }
1762    log_msg(4, "  %s looks like a device special file", dsf);
1763    /* Verify that the dsf exists */ 
1764    mr_asprintf(&command, "ls -al %s 2>/dev/null | wc -l", dsf);
1765    log_msg(5, "  Executing: %s", command);
1766    mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
1767    paranoid_free(command);
1768
1769    log_msg(5, "  Return value: %s", tmp);
1770    c = atoi(tmp);
1771    paranoid_free(tmp);
1772
1773    if (!c) {
1774        log_to_screen("Cannot find device special file %s", dsf);
1775        return (1);
1776    }
1777    log_msg(4, "  %s device special file exists", dsf);
1778
1779    /* Get a list of the mounted file systems */
1780    if (create_list_of_non_NETFS_mounted_file_systems()) {
1781        log_to_screen ("Could not get the list of mounted file systems");
1782        return (1);
1783    }
1784    log_msg (5, "Processing dsf: %s", dsf);
1785    /********
1786    * Get a list of the dsf's partitions. There could be no partitions on the disk
1787    * or a dsf of a partition was passed in (e.g. /dev/sda1 instead of /dev/sda).
1788    * Either way, it's an error.
1789    ********/
1790    mr_asprintf(&command, "parted2fdisk -l %s 2>/dev/null|grep -E \"^/dev/\"|awk '{printf(\"%%s \", $1)}END{print \"\"}'", dsf);
1791    log_msg(5, "Executing: %s", command);
1792    mr_asprintf(&partition_list, "%s", call_program_and_get_last_line_of_output(command));
1793    paranoid_free(command);
1794    log_msg(4, "Partition list for %s: %s", dsf, partition_list);
1795    if (!strlen(partition_list)) {
1796        /* There were no partitions on the disk */
1797        log_msg(4, "No partitions on device special file %s", dsf);
1798        log_msg(4, "I guess it's a partition itself");
1799        strcpy(partitions[0], dsf);
1800        ndsf = truncate_to_drive_name(dsf);
1801    } else {
1802        /* Fill the partition list */
1803        i = 0;
1804        lastpos = 0;
1805        while ((token = mr_strtok(partition_list, token_chars, &lastpos)) != NULL) {
1806            log_msg (4, "Found partition: %s", token);
1807            strcpy(partitions[i++], token);
1808            mr_free(token);
1809        }
1810        mr_asprintf(&ndsf, "%s", dsf);
1811    }
1812    mr_free(partition_list);
1813
1814    /* In any case we want to exclude the dsf itself from all MondRescue activities
1815     * at restore time (LVM, fdisk, ...) so we want it in our exclude_dev list */
1816    if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) {
1817        fatal_error ("Cannot allocate memory");
1818    }
1819    add_mounted_fs_struct(DSFptr);
1820    strcpy(DSFptr->device, dsf);
1821    DSFptr->check = 1;
1822
1823    /*  For the rest ndsf is the new dsf to deal with */
1824    /********
1825     * At this point, we have a list of all of the partitions on the dsf. Now try to
1826     * see which partitions have a file system on them.
1827     *
1828     * Loop through each partition on the disk and:
1829     *
1830     * - If the partition is swap, it ignores it.
1831     *
1832     * - If the partition is mounted (e.g. /dev/sda1 is mounted on /boot), it adds an entry
1833     *  to the linked list, copies to it the device name and mount point, and sets check == 1.
1834     *
1835     * - If the partition is part of a Volume Group that has Logical Volumes mounted, it adds
1836     *  an entry to the linked list for each mounted Logical Volume in that Volume Group, copying
1837     *  to it the device name and mount point, and sets check == 1. Note that if the Volume Group
1838     *  contains more than one disk, it will still add the entry even if the Logical Volume's
1839     *  extents are not on the dsf that was passed in to the function. For example, Volume Group
1840     *  VolGroup00 contains the disks /dev/sda1 and /dev/sdb1, and the Logical Volumes LogVol01,
1841     *  which is mounted on /var and has all of its extents on /dev/sda1, and LogVol02, which is
1842     *  mounted as /usr and has all of its extents on /dev/sdb1. If you pass /dev/sda into the
1843     *  function, both /var and /usr will be archived even though /usr is actually on/dev/sdb.
1844     *
1845     * - If the partition is part of a Volume Group that has Logical Volumes used in a mounted
1846     *  software raid device, it adds an entry to the linked list, copies to it the software raid
1847     *  device name and mount point, and sets check == 1.
1848     *
1849     * - If the partition is part of a mounted software raid device, it adds an entry to the linked
1850     *  list, copies to it the software raid device name and mount point, and sets check == 1.
1851     *
1852     ********/
1853    for (i=0; strlen(partitions[i]); i++) {
1854        log_msg(4, "Processing partition: %s", partitions[i]);
1855        /* See if it's swap. If it is, ignore it. */
1856        mr_asprintf(&command, "parted2fdisk -l %s 2>/dev/null | awk '{if(($1==\"%s\")&&(toupper($0) ~ \"SWAP\")){print $1;exit}}'", 
1857          ndsf, partitions[i]);
1858        log_msg(5, "  Running: %s", command);
1859        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
1860        paranoid_free(command);
1861        log_msg(5, "  Return value: %s", tmp);
1862        c = strlen(tmp);
1863        paranoid_free(tmp);
1864        if (c) {
1865            log_msg(4, "It's swap. Ignoring partition %s", partitions[i]); 
1866            continue;
1867        } 
1868        /* It's not swap. See if we can find the mount point from the mount command. */
1869        mr_asprintf(&command, "mount 2>/dev/null | awk '{if((NF>0)&&($1==\"%s\")){print $3}}'", partitions[i]);
1870        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
1871        paranoid_free(command);
1872        if (strlen(tmp)) {
1873            log_msg(4, "  %s is mounted: %s", partitions[i], tmp);
1874            if ((DSFptr = find_mount_point_in_list(tmp)) == NULL) {
1875                log_msg (4, "Can't find mount point %s in mounted file systems list", tmp);
1876                paranoid_free(tmp);
1877                return (1);
1878            }
1879            DSFptr->check = 1;
1880            paranoid_free(tmp);
1881            continue;
1882        }
1883        paranoid_free(tmp);
1884        /* It's not swap and it's not mounted. See if it's LVM */
1885        log_msg(4, "  It's not mounted. Checking to see if it's LVM...");
1886        /* Check for LVM */
1887        mr_asprintf(&command, "pvdisplay -c %s | grep '%s:' 2> /dev/null", partitions[i], partitions[i]);
1888        log_msg(5, "  Running: %s", command);
1889        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
1890        paranoid_free(command);
1891        if (strlen(tmp)) {
1892            log_msg(4, "Found an LVM partition at %s. Find the VG it's in...", partitions[i]);
1893            /* It's LVM: Find the VG it's in */
1894            mr_asprintf(&command, "pvdisplay -v %s 2>/dev/null|grep \"VG Name\"|awk '{print $NF}'", partitions[i]);
1895            log_msg(5, "  Running: %s", command);
1896            strcpy(VG, call_program_and_get_last_line_of_output(command));
1897            paranoid_free(command);
1898            log_msg(4, "  Volume Group: %s", VG);
1899            if (strlen(VG)) {
1900                /* Found the Volume Group. Now find all of the VG's mount points */
1901                log_msg(4, "  Found the Volume Group. Now find all of the VG's mount points");
1902                mr_asprintf(&command, "mount 2>/dev/null|grep -E \"/dev/mapper/%s-|/dev/%s/\"|awk '{printf(\"%%s \",$3)}END{print \"\"}'", VG, VG);
1903                log_msg(5, "  Running: %s", command);
1904                mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command));
1905                paranoid_free(command);
1906                log_msg(4, "  VG %s mount_list: %s", VG, mount_list);
1907                lastpos = 0;
1908                while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1909                    log_msg (5, "mount point token: %s", token);
1910                    if ((DSFptr = find_mount_point_in_list(token)) == NULL) {
1911                        log_msg (4, "Can't find mount point %s in mounted file systems list", token);
1912                        paranoid_free(tmp);
1913                        mr_free(token);
1914                        return (1);
1915                    }
1916                    DSFptr->check = 1;
1917                    mr_free(token);
1918                }
1919                /********
1920                 * Now we want to see if there are any software raid devices using
1921                 * any of the Logical Volumes on the Volume Group.
1922                 *******/
1923                paranoid_free(mount_list);
1924
1925                mr_asprintf(&command, "%s", "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'");
1926                log_msg (5, "Running: %s", command);
1927                mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command));
1928                paranoid_free(command);
1929                log_msg(4, "  Software raid device list: %s", mount_list);
1930                lastpos = 0;
1931                while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1932                    mr_asprintf(&command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, VG);
1933                    log_msg (5, "Running: %s", command);
1934                    paranoid_free(tmp);
1935                    mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
1936                    paranoid_free(command);
1937                    log_msg(4, "Number of Software raid device: %s", tmp);
1938                    if (atoi(tmp)) {
1939                        /* This device is on our disk */
1940                        if ((DSFptr = find_device_in_list(token)) == NULL) {
1941                            log_msg (4, "Can't find device %s in mounted file systems list", token);
1942                            paranoid_free(tmp);
1943                            mr_free(token);
1944                            return (1);
1945                        }
1946                        DSFptr->check = 1;
1947                    }
1948                }
1949                mr_free(token);
1950                paranoid_free(mount_list);
1951            } else {
1952                log_msg (4, "Error finding Volume Group for partition %s", partitions[i]);
1953                paranoid_free(tmp);
1954                return (1);
1955            }
1956            paranoid_free(tmp);
1957            continue;
1958        } else {
1959            log_msg (4, "Error finding partition type for the partition %s", partitions[i]);
1960        }
1961        paranoid_free(tmp);
1962        /********
1963         * It's not swap, mounted, or LVM. See if it's used in a software raid device.
1964         ********/
1965        log_msg (5, "It's not swap, mounted, or LVM. See if it's used in a software raid device.");
1966        mr_asprintf(&command, "mdadm --examine %s 2>/dev/null | awk '{if($1 == \"UUID\"){print $3}}'", partitions[i]);
1967        log_msg(4, "  Running: %s", command);
1968        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
1969        paranoid_free(command);
1970        if (!strlen(tmp)) {
1971            log_msg(4, "  Partition %s is not used in a non-LVM software raid device", partitions[i]);
1972            paranoid_free(tmp);
1973            continue;
1974        }
1975        log_msg (5, "  UUID: %s", tmp);
1976        /* Get the Software raid device list */
1977        mr_asprintf(&command, "%s", "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'");
1978        log_msg (5, "  Running: %s", command);
1979        mr_asprintf(&mount_list, "%s", call_program_and_get_last_line_of_output(command));
1980        paranoid_free(command);
1981        log_msg(4, "  Software raid device list: %s", mount_list);
1982        /* Loop through the software raid device list to see if we can find the partition */
1983        lastpos = 0;
1984        while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1985            mr_asprintf(&command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, tmp);
1986            log_msg(4, "  Running: %s", command);
1987            paranoid_free(tmp);
1988            mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
1989            paranoid_free(command);
1990            if (!atoi(tmp)) {
1991                log_msg (4,"  Didn't find partition %s in software raid device %s", partitions[i], token);
1992            } else {
1993                if ((DSFptr = find_device_in_list(token)) == NULL) {
1994                    log_msg (4, "Can't find device %s in mounted file systems list", token);
1995                    paranoid_free(tmp);
1996                    mr_free(token);
1997                    return (1);
1998                }
1999                DSFptr->check = 1;
2000                break;
2001            }
2002            mr_free(token);
2003        }
2004        paranoid_free(tmp);
2005        paranoid_free(mount_list);
2006    }
2007
2008    /* Determine how much memory to allocate for included_dsf_list and excluded_dsf_list */
2009    i = 0;
2010    DSFptr= DSF_Head;
2011    while (DSFptr != NULL) {
2012        i += strlen(DSFptr->mount_point) + 1;
2013        DSFptr = DSFptr->next;
2014    }
2015    log_msg (5, "i: %d", i);
2016    if ((*included_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) {
2017        fatal_error ("Cannot allocate memory");
2018    }
2019    if ((*excluded_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) {
2020        fatal_error ("Cannot allocate memory");
2021    }
2022    DSFptr= DSF_Head;
2023    while (DSFptr != NULL) {
2024        if (DSFptr->check) {
2025            log_msg (4, "%s is mounted on %s and is on disk %s", DSFptr->device, DSFptr->mount_point, ndsf);
2026            strcat(*included_dsf_list, DSFptr->mount_point);
2027            strcat(*included_dsf_list, "|");
2028        } else {
2029            log_msg (4, "%s is mounted on %s and is NOT on disk %s", DSFptr->device, DSFptr->mount_point, ndsf);
2030            strcat(*excluded_dsf_list, DSFptr->mount_point);
2031            strcat(*excluded_dsf_list, "|");
2032        }
2033        DSFptr = DSFptr->next;
2034    }
2035    mr_free(ndsf);
2036
2037    log_msg (5, "included_dsf_list: %s", *included_dsf_list);
2038    log_msg (5, "excluded_dsf_list: %s", *excluded_dsf_list);
2039    return (0);
2040}
2041
2042
2043
2044
2045
2046/* Update the bkpinfo structure for exclude & include paths
2047 * in order to handle correctly paths corresponding to devices */
2048void mr_make_devlist_from_pathlist(char *pathlist, char mode) {
2049
2050char *token = NULL;
2051int lastpos = 0;
2052char *mounted_on_dsf = NULL;
2053char *not_mounted_on_dsf = NULL;
2054char token_chars[] ="|\t\r\f\a\0\n";
2055char *tmp = NULL;
2056char *tmp1 = NULL;
2057
2058if (pathlist == NULL) {
2059    return;
2060}
2061while ((token = mr_strtok(pathlist, token_chars, &lastpos)) != NULL) {
2062    switch (get_dsf_mount_list(token, &mounted_on_dsf, &not_mounted_on_dsf)) {
2063    case 1: 
2064        if (mode == 'E') {
2065            log_msg(1, "WARNING ! %s doesn't exist in -E option", token);
2066        } else {
2067            log_msg(1, "ERROR ! %s doesn't exist in -I option", token);
2068            fatal_error("Error processing -I option");
2069        }
2070        break;
2071    /* Everything is OK; proceed to archive data */
2072    case 0:
2073        if (mode == 'E') {
2074            if (strlen(mounted_on_dsf)) {
2075                log_to_screen("Excluding the following file systems on %s:", token);
2076                log_to_screen("==> %s", mounted_on_dsf);
2077                log_msg (5, "Adding to bkpinfo->exclude_paths due to -E option: %s", mounted_on_dsf);
2078                if (bkpinfo->exclude_paths) {
2079                    mr_strcat(bkpinfo->exclude_paths,"|%s",mounted_on_dsf);
2080                } else {
2081                    mr_asprintf(bkpinfo->exclude_paths,"%s",mounted_on_dsf);
2082                }
2083                if (bkpinfo->exclude_devs) {
2084                    mr_strcat(bkpinfo->exclude_devs,"|%s",token);
2085                } else {
2086                    mr_asprintf(bkpinfo->exclude_devs,"%s",token);
2087                }
2088            }
2089        } else {
2090            log_to_screen("Archiving only the following file systems on %s:", token);
2091            log_to_screen("==> %s", mounted_on_dsf);
2092            strcpy(bkpinfo->include_paths, "/");
2093            if (strlen(not_mounted_on_dsf)) {
2094                log_msg (5, "Adding to bkpinfo->exclude_paths due to -I option: %s", not_mounted_on_dsf);
2095                log_to_screen("Not archiving the following file systems:");
2096                log_to_screen("==> %s", not_mounted_on_dsf);
2097                if (bkpinfo->exclude_paths) {
2098                    mr_strcat(bkpinfo->exclude_paths, "|%s",not_mounted_on_dsf);
2099                } else {
2100                    mr_asprintf(bkpinfo->exclude_paths,"%s",not_mounted_on_dsf);
2101                }
2102            }
2103        }
2104        break;
2105    /* It's a dsf but not a whole disk dsf */
2106    case -2:
2107        log_to_screen("Could %s be a partition instead of a whole disk device special file?\nIgnored.", token);
2108        break;
2109    /* A device special file was not passed in. Process it as a path. */
2110    case -1:
2111        /*  Adds a | to ensure correct detection even at both ends */
2112        mr_asprintf(&tmp1,"|%s",token);
2113        if (mode == 'E') {
2114            /*  Add the token if not already in the list */
2115            mr_asprintf(&tmp,"|%s|",bkpinfo->exclude_paths);
2116            if (strstr(tmp,tmp1) == NULL) {
2117                if (bkpinfo->exclude_paths) {
2118                    mr_strcat(bkpinfo->exclude_paths,tmp1);
2119                    mr_free(tmp1);
2120                } else {
2121                    bkpinfo->exclude_paths = tmp1;
2122                }
2123            }
2124        } else {
2125            /*  Add the token if not already in the list */
2126            mr_asprintf(&tmp,"|%s|",bkpinfo->include_paths);
2127            if (strstr(tmp,tmp1) == NULL) {
2128                strcat(bkpinfo->include_paths,tmp1);
2129            }
2130            mr_free(tmp1);
2131        }
2132        mr_free(tmp);
2133        break;
2134    }
2135    mr_free(token);
2136
2137    if (bkpinfo->include_paths != NULL) {
2138        log_msg(1, "include_paths is now '%s'", bkpinfo->include_paths);
2139    }
2140    if (bkpinfo->exclude_paths != NULL) {
2141        log_msg(1, "exclude_paths is now '%s'", bkpinfo->exclude_paths);
2142    }
2143    if (bkpinfo->exclude_devs != NULL) {
2144        log_msg(1, "exclude_devs is now '%s'", bkpinfo->exclude_devs);
2145    }
2146}
2147}
2148
2149
2150
2151
2152/**
2153 * Ask user for details of backup/restore information.
2154 * Called when @c mondoarchive doesn't get any parameters.
2155 * @param bkpinfo The backup information structure to fill out with the user's data.
2156 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
2157 * @return 0, always.
2158 * @bug No point of `int' return value.
2159 * @ingroup archiveGroup
2160 */
2161int interactively_obtain_media_parameters_from_user(bool archiving_to_media)
2162// archiving_to_media is TRUE if I'm being called by mondoarchive
2163// archiving_to_media is FALSE if I'm being called by mondorestore
2164{
2165    char *tmp = NULL;
2166    char *tmp1 = NULL;
2167    char *mds = NULL;
2168    char p[8*MAX_STR_LEN];
2169    char *sz_size;
2170    char *command;
2171    char *compression_type = NULL;
2172    char *comment;
2173    char *prompt;
2174    int i;
2175    FILE *fin;
2176
2177    malloc_string(sz_size);
2178    malloc_string(command);
2179    malloc_string(comment);
2180    malloc_string(prompt);
2181    malloc_string(tmp1);
2182    assert(bkpinfo != NULL);
2183    sz_size[0] = '\0';
2184    bkpinfo->nonbootable_backup = FALSE;
2185
2186    // Tape, CD, NETFS, ...?
2187    srandom(getpid());
2188    bkpinfo->backup_media_type =
2189        (g_restoring_live_from_cd) ? cdr :
2190        which_backup_media_type(bkpinfo->restore_data);
2191    if (bkpinfo->backup_media_type == none) {
2192        log_to_screen("User has chosen not to backup the PC");
2193        finish(1);
2194    }
2195    /* Why asking to remove the media with tape ?
2196    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
2197        popup_and_OK("Please remove media from drive(s)");
2198    }
2199    */
2200    log_msg(3, "media type = %s",
2201            bkptype_to_string(bkpinfo->backup_media_type));
2202    if (archiving_to_media) {
2203        sensibly_set_tmpdir_and_scratchdir();
2204    }
2205    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
2206    bkpinfo->compression_level =
2207        (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
2208    bkpinfo->use_lzo =
2209        (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
2210    mvaddstr_and_log_it(2, 0, " ");
2211
2212    // Find device's /dev (or SCSI) entry
2213    switch (bkpinfo->backup_media_type) {
2214    case cdr:
2215    case cdrw:
2216    case dvd:
2217    case usb:
2218        /* Never try to eject a USB device */
2219        if (bkpinfo->backup_media_type == usb) {
2220            bkpinfo->please_dont_eject = TRUE;
2221        }
2222        if (archiving_to_media) {
2223            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2224                if (ask_me_yes_or_no
2225                    ("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?"))
2226                {
2227                    bkpinfo->manual_cd_tray = TRUE;
2228                }
2229            }
2230            if ((compression_type = which_compression_type()) == NULL) {
2231                log_to_screen("User has chosen not to backup the PC");
2232                finish(1);
2233            }
2234            if ((bkpinfo->compression_level =
2235                 which_compression_level()) == -1) {
2236                log_to_screen("User has chosen not to backup the PC");
2237                finish(1);
2238            }
2239            mds = media_descriptor_string(bkpinfo->backup_media_type);
2240            sprintf(comment, "What speed is your %s (re)writer?", mds);
2241            if (bkpinfo->backup_media_type == dvd) {
2242                find_dvd_device(bkpinfo->media_device, FALSE);
2243                strcpy(tmp1, "1");
2244                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2245                log_msg(1, "Setting to DVD defaults");
2246            } else {
2247                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
2248                strcpy(tmp1, "4");
2249                strcpy(sz_size, "650");
2250                log_msg(1, "Setting to CD defaults");
2251            }
2252            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2253                if (!popup_and_get_string("Speed", comment, tmp1, 4)) {
2254                    log_to_screen("User has chosen not to backup the PC");
2255                    finish(1);
2256                }
2257            }
2258            bkpinfo->cdrw_speed = atoi(tmp1);   // if DVD then this shouldn't ever be used anyway :)
2259
2260            sprintf(comment,
2261                    "How much data (in Megabytes) will each %s store?", mds);
2262            mr_free(mds);
2263            if (!popup_and_get_string("Size", comment, sz_size, 5)) {
2264                log_to_screen("User has chosen not to backup the PC");
2265                finish(1);
2266            }
2267            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2268                bkpinfo->media_size[i] = atoi(sz_size);
2269            }
2270            if (bkpinfo->media_size[0] <= 0) {
2271                log_to_screen("User has chosen not to backup the PC");
2272                finish(1);
2273            }
2274        }
2275        /* No break because we continue even for usb */
2276    case cdstream:
2277        mds = media_descriptor_string(bkpinfo->backup_media_type);
2278
2279        if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
2280            strcpy(bkpinfo->media_device, "/dev/cdrom");
2281            log_msg(2, "CD-ROM device assumed to be at %s",
2282                    bkpinfo->media_device);
2283        } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))
2284                   || bkpinfo->backup_media_type == dvd) {
2285            if (!bkpinfo->media_device[0]) {
2286                strcpy(bkpinfo->media_device, "/dev/cdrom");
2287            }                   // just for the heck of it :)
2288            log_msg(1, "bkpinfo->media_device = %s",
2289                    bkpinfo->media_device);
2290            if (bkpinfo->backup_media_type == dvd
2291                || find_cdrom_device(bkpinfo->media_device, FALSE)) {
2292                log_msg(1, "bkpinfo->media_device = %s",
2293                        bkpinfo->media_device);
2294                sprintf(comment,
2295                        "Please specify your %s drive's /dev entry", mds);
2296                if (!popup_and_get_string
2297                    ("Device?", comment, bkpinfo->media_device,
2298                     MAX_STR_LEN / 4)) {
2299                    log_to_screen("User has chosen not to backup the PC");
2300                    finish(1);
2301                }
2302            }
2303            log_msg(2, "%s device found at %s", mds, bkpinfo->media_device);
2304        } else {
2305            if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) {
2306                bkpinfo->media_device[0] = '\0';
2307            }
2308            if (bkpinfo->media_device[0]) {
2309                if (bkpinfo->backup_media_type == usb) {
2310                    mr_asprintf(&tmp, "I think your %s media corresponds to %s. Is this correct?", mds, bkpinfo->media_device);
2311                } else {
2312                    mr_asprintf(&tmp, "I think I've found your %s burner at SCSI node %s. Is this correct? (Say no if you have an IDE burner and you are running a 2.6 kernel. You will then be prompted for further details.)", mds, bkpinfo->media_device);
2313                }
2314                if (!ask_me_yes_or_no(tmp)) {
2315                    bkpinfo->media_device[0] = '\0';
2316                }
2317                mr_free(tmp);
2318            }
2319            if (!bkpinfo->media_device[0]) {
2320                if (bkpinfo->backup_media_type == usb) {
2321                    i = popup_and_get_string("/dev entry?",
2322                                         "What is the /dev entry of your USB Disk/Key, please?",
2323                                         bkpinfo->media_device,
2324                                         MAX_STR_LEN / 4);
2325                } else {
2326                    if (g_kernel_version < 2.6) {
2327                        i = popup_and_get_string("Device node?",
2328                                             "What is the SCSI node of your CD (re)writer, please?",
2329                                             bkpinfo->media_device,
2330                                             MAX_STR_LEN / 4);
2331                    } else {
2332                        i = popup_and_get_string("/dev entry?",
2333                                             "What is the /dev entry of your CD (re)writer, please?",
2334                                             bkpinfo->media_device,
2335                                             MAX_STR_LEN / 4);
2336                    }
2337                }
2338                if (!i) {
2339                    log_to_screen("User has chosen not to backup the PC");
2340                    finish(1);
2341                }
2342            }
2343        }
2344        mr_free(mds);
2345
2346        if (bkpinfo->backup_media_type == cdstream) {
2347            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2348                bkpinfo->media_size[i] = 650;
2349            }
2350        }
2351        break;
2352    case udev:
2353        if (!ask_me_yes_or_no
2354            ("This option is for advanced users only. Are you sure?")) {
2355            log_to_screen("User has chosen not to backup the PC");
2356            finish(1);
2357        }
2358    case tape:
2359
2360        if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) {
2361            log_msg(3, "Ok, using vanilla scsi tape.");
2362            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
2363            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2364                paranoid_fclose(fin);
2365            } else {
2366                strcpy(bkpinfo->media_device, "/dev/osst0");
2367            }
2368        }
2369        if (bkpinfo->media_device[0]) {
2370            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2371                paranoid_fclose(fin);
2372            } else {
2373                if (does_file_exist("/tmp/mondo-restore.cfg")) {
2374                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
2375                                 bkpinfo->media_device);
2376                }
2377            }
2378        }
2379        if (bkpinfo->media_device[0]) {
2380            mr_asprintf(&tmp, "I think I've found your tape streamer at %s; am I right on the money?", bkpinfo->media_device);
2381            if (!ask_me_yes_or_no(tmp)) {
2382                bkpinfo->media_device[0] = '\0';
2383            }
2384            mr_free(tmp);
2385        }
2386        if (!bkpinfo->media_device[0]) {
2387            if (!popup_and_get_string
2388                ("Device name?",
2389                 "What is the /dev entry of your tape streamer?",
2390                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
2391                log_to_screen("User has chosen not to backup the PC");
2392                finish(1);
2393            }
2394        }
2395        mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
2396        if (run_program_and_log_output(tmp, FALSE)) {
2397            log_to_screen("User has not specified a valid /dev entry");
2398            finish(1);
2399        }
2400        mr_free(tmp);
2401        log_msg(4, "sz_size = %s", sz_size);
2402        sz_size[0] = '\0';
2403
2404        bkpinfo->use_obdr = ask_me_yes_or_no
2405            ("Do you want to activate OBDR support for your tapes ?");
2406        if (sz_size[0] == '\0') {
2407            bkpinfo->media_size[0] = 0;
2408        } else {
2409            bkpinfo->media_size[0] =
2410                friendly_sizestr_to_sizelong(sz_size) / 2 - 50;
2411        }
2412        log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
2413        if (bkpinfo->media_size[0] <= 0) {
2414            bkpinfo->media_size[0] = 0;
2415        }
2416        for (i = 1; i <= MAX_NOOF_MEDIA; i++) {
2417            bkpinfo->media_size[i] = bkpinfo->media_size[0];
2418        }
2419        if (archiving_to_media) {
2420            if ((compression_type = which_compression_type()) == NULL) {
2421                log_to_screen("User has chosen not to backup the PC");
2422                finish(1);
2423            }
2424            if ((bkpinfo->compression_level =
2425                 which_compression_level()) == -1) {
2426                log_to_screen("User has chosen not to backup the PC");
2427                finish(1);
2428            }
2429        }
2430        break;
2431
2432
2433
2434    case netfs:
2435        /* Never try to eject a NETFS device */
2436        bkpinfo->please_dont_eject = TRUE;
2437
2438        /* Initiate bkpinfo netfs_mount path from running environment if not already done */
2439        if (!bkpinfo->netfs_mount[0]) {
2440            strcpy(bkpinfo->netfs_mount,
2441                   call_program_and_get_last_line_of_output
2442                   ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
2443        }
2444#ifdef __FreeBSD__
2445        if (TRUE)
2446#else
2447        if (!bkpinfo->disaster_recovery)
2448#endif
2449        {
2450            if (!popup_and_get_string
2451                ("Network shared dir.",
2452                 "Please enter path and directory where archives are stored remotely. (Mondo has taken a guess at the correct value. If it is incorrect, delete it and type the correct one.)",
2453                 bkpinfo->netfs_mount, MAX_STR_LEN / 4)) {
2454                log_to_screen("User has chosen not to backup the PC");
2455                finish(1);
2456            }
2457            if (!bkpinfo->restore_data) {
2458                if ((compression_type = which_compression_type()) == NULL) {
2459                    log_to_screen("User has chosen not to backup the PC");
2460                    finish(1);
2461                }
2462                if ((bkpinfo->compression_level =
2463                     which_compression_level()) == -1) {
2464                    log_to_screen("User has chosen not to backup the PC");
2465                    finish(1);
2466                }
2467            }
2468            // check whether already mounted - we better remove
2469            // surrounding spaces and trailing '/' for this
2470            strip_spaces(bkpinfo->netfs_mount);
2471            if (bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] == '/')
2472                bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] = '\0';
2473            sprintf(command, "mount | grep \"%s \" | cut -d' ' -f3",
2474                    bkpinfo->netfs_mount);
2475            strcpy(bkpinfo->isodir,
2476                   call_program_and_get_last_line_of_output(command));
2477
2478            if (!bkpinfo->restore_data) {
2479                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2480                sprintf(comment,
2481                    "How much data (in Megabytes) will each media store?");
2482                if (!popup_and_get_string("Size", comment, sz_size, 5)) {
2483                    log_to_screen("User has chosen not to backup the PC");
2484                    finish(1);
2485                }
2486            } else {
2487                strcpy(sz_size, "0");
2488            }
2489            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2490                bkpinfo->media_size[i] = atoi(sz_size);
2491            }
2492            if (bkpinfo->media_size[0] < 0) {
2493                log_to_screen("User has chosen not to backup the PC");
2494                finish(1);
2495            }
2496        }
2497        /*  Force NFS to be the protocol by default */
2498        if (bkpinfo->netfs_proto == NULL) {
2499            mr_asprintf(&(bkpinfo->netfs_proto), "nfs");
2500        }
2501        if (bkpinfo->disaster_recovery) {
2502            sprintf(command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
2503            (void)system(command);
2504        }
2505        strcpy(tmp1, bkpinfo->netfs_proto);
2506        if (!popup_and_get_string
2507            ("Network protocol", "Which protocol should I use (nfs/sshfs) ?",
2508             tmp1, MAX_STR_LEN)) {
2509            log_to_screen("User has chosen not to backup the PC");
2510            finish(1);
2511        }
2512        mr_free(bkpinfo->netfs_proto);
2513        mr_asprintf(&(bkpinfo->netfs_proto), "%s", tmp1);
2514        if (!popup_and_get_string
2515            ("Network share", "Which remote share should I mount?",
2516             bkpinfo->netfs_mount, MAX_STR_LEN)) {
2517            log_to_screen("User has chosen not to backup the PC");
2518            finish(1);
2519        }
2520
2521        /* Initiate bkpinfo isodir path from running environment if mount already done */
2522        if (is_this_device_mounted(bkpinfo->netfs_mount)) {
2523            strcpy(bkpinfo->isodir,
2524                   call_program_and_get_last_line_of_output
2525                   ("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
2526        } else {
2527            sprintf(bkpinfo->isodir, "%s/netfsdir", bkpinfo->tmpdir);
2528            sprintf(command, "mkdir -p %s", bkpinfo->isodir);
2529            run_program_and_log_output(command, 5);
2530            if (bkpinfo->restore_data) {
2531                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2532                    mr_asprintf(&tmp, "sshfs -o ro %s %s", bkpinfo->netfs_mount, bkpinfo->isodir);
2533                } else {
2534                    mr_asprintf(&tmp, "mount -t %s -o nolock,ro %s %s", bkpinfo->netfs_proto, bkpinfo->netfs_mount, bkpinfo->isodir);
2535                }
2536            } else {
2537                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2538                    mr_asprintf(&tmp, "sshfs %s %s", bkpinfo->netfs_mount, bkpinfo->isodir);
2539                } else {
2540                    mr_asprintf(&tmp, "mount -t %s -o nolock %s %s", bkpinfo->netfs_proto, bkpinfo->netfs_mount, bkpinfo->isodir);
2541                }
2542            }
2543            run_program_and_log_output(tmp, 3);
2544            mr_free(tmp);
2545
2546            malloc_string(g_selfmounted_isodir);
2547            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
2548        }
2549        if (!is_this_device_mounted(bkpinfo->netfs_mount)) {
2550            popup_and_OK
2551                ("Please mount that partition before you try to backup to or restore from it.");
2552            finish(1);
2553        }
2554        strcpy(tmp1, bkpinfo->netfs_remote_dir);
2555        if (!popup_and_get_string
2556            ("Directory", "Which directory within that mountpoint?", tmp1,
2557             MAX_STR_LEN)) {
2558            log_to_screen("User has chosen not to backup the PC");
2559            finish(1);
2560        }
2561        strcpy(bkpinfo->netfs_remote_dir, tmp1);
2562
2563        // check whether writable - we better remove surrounding spaces for this
2564        strip_spaces(bkpinfo->netfs_remote_dir);
2565
2566        if (!popup_and_get_string
2567            ("Prefix.",
2568             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2569            bkpinfo->prefix, MAX_STR_LEN / 4)) {
2570            log_to_screen("User has chosen not to backup the PC");
2571            finish(1);
2572        }
2573        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2574
2575        for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2576            bkpinfo->media_size[i] = 650;
2577        }
2578        log_msg(3, "Just set netfs_remote_dir to %s",
2579                bkpinfo->netfs_remote_dir);
2580        log_msg(3, "isodir is still %s", bkpinfo->isodir);
2581        break;
2582
2583    case iso:
2584        if (!bkpinfo->disaster_recovery) {
2585            if (!popup_and_get_string
2586                ("Storage dir.",
2587                 "Please enter the full path name to the directory for your ISO images.  Example: /mnt/raid0_0",
2588                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
2589                log_to_screen("User has chosen not to backup the PC");
2590                finish(1);
2591            }
2592            if (archiving_to_media) {
2593                if ((compression_type = which_compression_type()) == NULL) {
2594                    log_to_screen("User has chosen not to backup the PC");
2595                    finish(1);
2596                }
2597                if ((bkpinfo->compression_level =
2598                     which_compression_level()) == -1) {
2599                    log_to_screen("User has chosen not to backup the PC");
2600                    finish(1);
2601                }
2602                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2603                if (!popup_and_get_string
2604                    ("ISO size.",
2605                     "Please enter how big you want each ISO image to be (in megabytes). This should be less than or equal to the size of the CD-R[W]'s (700) or DVD's (4480) you plan to backup to.",
2606                     sz_size, 16)) {
2607                    log_to_screen("User has chosen not to backup the PC");
2608                    finish(1);
2609                }
2610                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2611                    bkpinfo->media_size[i] = atoi(sz_size);
2612                }
2613            } else {
2614                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2615                    bkpinfo->media_size[i] = 650;
2616                }
2617            }
2618        }
2619        if (!popup_and_get_string
2620            ("Prefix.",
2621             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2622             bkpinfo->prefix, MAX_STR_LEN / 4)) {
2623            log_to_screen("User has chosen not to backup the PC");
2624            finish(1);
2625        }
2626        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2627        break;
2628    default:
2629        fatal_error
2630            ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
2631    }
2632
2633    if (archiving_to_media) {
2634
2635#ifdef __FreeBSD__
2636        strcpy(bkpinfo->boot_device,
2637               call_program_and_get_last_line_of_output
2638               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
2639#else
2640        strcpy(bkpinfo->boot_device,
2641               call_program_and_get_last_line_of_output
2642               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
2643#endif
2644        i = which_boot_loader(bkpinfo->boot_device);
2645        if (i == 'U')           // unknown
2646        {
2647
2648#ifdef __FreeBSD__
2649            if (!popup_and_get_string
2650                ("Boot device",
2651                 "What is your boot device? (e.g. /dev/ad0)",
2652                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2653                log_to_screen("User has chosen not to backup the PC");
2654                finish(1);
2655            }
2656            i = which_boot_loader(bkpinfo->boot_device);
2657#else
2658            if (!popup_and_get_string
2659                ("Boot device",
2660                 "What is your boot device? (e.g. /dev/hda)",
2661                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2662                log_to_screen("User has chosen not to backup the PC");
2663                finish(1);
2664            }
2665            if (does_string_exist_in_boot_block
2666                (bkpinfo->boot_device, "LILO")) {
2667                i = 'L';
2668            } else
2669                if (does_string_exist_in_boot_block
2670                    (bkpinfo->boot_device, "ELILO")) {
2671                i = 'E';
2672            } else
2673                if (does_string_exist_in_boot_block
2674                    (bkpinfo->boot_device, "GRUB")) {
2675                i = 'G';
2676            } else {
2677                i = 'U';
2678            }
2679#endif
2680            if (i == 'U') {
2681                if (ask_me_yes_or_no
2682                    ("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?"))
2683                {
2684                    i = 'R';    // raw
2685                } else {
2686                    log_to_screen
2687                        ("I cannot find your boot loader. Please run mondoarchive with parameters.");
2688                    finish(1);
2689                }
2690            }
2691        }
2692        bkpinfo->boot_loader = i;
2693        strcpy(bkpinfo->include_paths, "/");
2694        if (!popup_and_get_string
2695            ("Backup paths",
2696             "Please enter paths (separated by '|') which you want me to backup. The default is '/' (i.e. everything).",
2697             bkpinfo->include_paths, MAX_STR_LEN)) {
2698            log_to_screen("User has chosen not to backup the PC");
2699            finish(1);
2700        }
2701        tmp = list_of_NETFS_mounts_only();
2702        if (strlen(tmp) > 2) {
2703            mr_strcat(bkpinfo->exclude_paths, "|%s",tmp);
2704        }
2705        mr_free(tmp);
2706// NTFS
2707        strcpy(tmp1, call_program_and_get_last_line_of_output("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
2708        if (strlen(tmp1) > 2) {
2709            if (!popup_and_get_string
2710                ("NTFS partitions",
2711                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
2712                 tmp1, MAX_STR_LEN / 4)) {
2713                log_to_screen("User has chosen not to backup the PC");
2714                finish(1);
2715            }
2716            strncpy(bkpinfo->image_devs, tmp1, MAX_STR_LEN / 4);
2717        }
2718
2719        if (bkpinfo->exclude_paths != NULL ) {
2720            strncpy(p,bkpinfo->exclude_paths,(8*MAX_STR_LEN)-1);
2721        } else {
2722            p[0] = '\0';
2723        }
2724        popup_and_get_string("Exclude paths", "Please enter paths which you do NOT want to backup. Separate them with '|'. NB: /tmp and /proc are always excluded. :-) Just hit 'Enter' if you want to do a full system backup.", p, (8*MAX_STR_LEN)-1);
2725        if (p == NULL) {
2726            log_to_screen("User has chosen not to backup the PC");
2727            finish(1);
2728        }
2729        mr_free(bkpinfo->exclude_paths);
2730        mr_asprintf(&tmp, "%s", p);
2731        bkpinfo->exclude_paths = tmp;
2732
2733        if (!popup_and_get_string
2734            ("Temporary directory",
2735             "Please enter your temporary directory.",
2736             bkpinfo->tmpdir, (4*MAX_STR_LEN)-1)) {
2737            log_to_screen("User has chosen not to backup the PC");
2738            finish(1);
2739        }
2740        if (!popup_and_get_string
2741            ("Scratch directory",
2742             "Please enter your scratch directory.",
2743             bkpinfo->scratchdir, (4*MAX_STR_LEN)-1)) {
2744            log_to_screen("User has chosen not to backup the PC");
2745            finish(1);
2746        }
2747// Interactive mode:
2748#ifdef __IA64__
2749        bkpinfo->make_cd_use_lilo = TRUE;
2750#else
2751        bkpinfo->make_cd_use_lilo = FALSE;
2752#endif
2753        bkpinfo->backup_data = TRUE;
2754        if (strcmp(compression_type,"lzo") == 0) {
2755            strcpy(bkpinfo->zip_exe, "lzop");
2756            strcpy(bkpinfo->zip_suffix, "lzo");
2757        } else if (strcmp(compression_type,"gzip") == 0) {
2758            strcpy(bkpinfo->zip_exe, "gzip");
2759            strcpy(bkpinfo->zip_suffix, "gz");
2760        //} else if (strcmp(compression_type,"lzma") == 0) {
2761            //strcpy(bkpinfo->zip_exe, "xy");
2762            //strcpy(bkpinfo->zip_suffix, "xy");
2763        } else if (strcmp(compression_type,"bzip2") == 0) {
2764            strcpy(bkpinfo->zip_exe, "bzip2");
2765            strcpy(bkpinfo->zip_suffix, "bz2");
2766        } else {
2767            bkpinfo->zip_exe[0] = bkpinfo->zip_suffix[0] = '\0';
2768        }
2769        bkpinfo->verify_data =
2770            ask_me_yes_or_no
2771            ("Will you want to verify your backups after Mondo has created them?");
2772
2773#ifndef __FreeBSD__
2774        if (!ask_me_yes_or_no
2775            ("Are you confident that your kernel is a sane, sensible, standard Linux kernel? Say 'no' if you are using a Gentoo <1.4 or Debian <3.0, please."))
2776#endif
2777        {
2778            strcpy(bkpinfo->kernel_path, "FAILSAFE");
2779        }
2780
2781        if (!ask_me_yes_or_no
2782            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2783            log_to_screen("User has chosen not to backup the PC");
2784            finish(1);
2785        }
2786    } else {
2787        bkpinfo->restore_data = TRUE;   // probably...
2788    }
2789
2790    if (bkpinfo->backup_media_type == iso
2791        || bkpinfo->backup_media_type == netfs) {
2792        g_ISO_restore_mode = TRUE;
2793    }
2794#ifdef __FreeSD__
2795// skip
2796#else
2797    if (bkpinfo->backup_media_type == netfs) {
2798        log_msg(3, "I think the Remote mount is mounted at %s",
2799                bkpinfo->isodir);
2800    }
2801    log_it("isodir = %s", bkpinfo->isodir);
2802    log_it("netfs_mount = '%s'", bkpinfo->netfs_mount);
2803    if (bkpinfo->netfs_proto) {
2804        log_it("netfs_proto = '%s'", bkpinfo->netfs_proto);
2805    }
2806    if (bkpinfo->netfs_user) {
2807        log_it("netfs_user = '%s'", bkpinfo->netfs_user);
2808    }
2809#endif
2810
2811    log_it("media device = %s", bkpinfo->media_device);
2812    log_it("media size = %ld", bkpinfo->media_size[1]);
2813    log_it("media type = %s",
2814           bkptype_to_string(bkpinfo->backup_media_type));
2815    log_it("prefix = %s", bkpinfo->prefix);
2816    log_it("compression = %ld", bkpinfo->compression_level);
2817    log_it("exclude_path = %s", bkpinfo->exclude_paths);
2818    log_it("include_path = %s", bkpinfo->include_paths);
2819
2820    /* Handle devices passed in bkpinfo and print result */
2821    /*  the mr_make_devlist_from_pathlist function appends
2822     *  to the *_paths variables so copy before */
2823    mr_make_devlist_from_pathlist(bkpinfo->exclude_paths, 'E');
2824    mr_make_devlist_from_pathlist(bkpinfo->include_paths, 'I');
2825
2826    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2827    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2828    log_it("image_devs = '%s'", bkpinfo->image_devs);
2829    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
2830           bkpinfo->boot_loader);
2831    if (bkpinfo->media_size[0] < 0) {
2832        if (archiving_to_media) {
2833            fatal_error("Media size is less than zero.");
2834        } else {
2835            log_msg(2, "Warning - media size is less than zero.");
2836            bkpinfo->media_size[0] = 0;
2837        }
2838    }
2839    paranoid_free(sz_size);
2840    paranoid_free(tmp1);
2841    paranoid_free(command);
2842    paranoid_free(comment);
2843    paranoid_free(prompt);
2844    return (0);
2845}
2846
2847
2848/**
2849 * Get a |-separated list of NETFS mounts.
2850 * @return The list created.
2851 * @note The return value points to allocated string that needs to be freed
2852 * @bug Even though we only want the mounts, the devices are still checked.
2853 */
2854char *list_of_NETFS_mounts_only(void)
2855{
2856    char *exclude_these_directories = NULL;
2857
2858    mr_asprintf(&exclude_these_directories,"%s", call_program_and_get_last_line_of_output("mount -t coda,ncpfs,fuse.sshfs,nfs,nfs4,vmhgfs,smbfs,cifs,afs,gfs,ocfs,ocfs2,mvfs,nsspool,nssvol | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' '|' | awk '{print $0;}'"));
2859    log_msg(9,"list_of_NETFS_mounts_only returns %s\n",exclude_these_directories);
2860    return(exclude_these_directories);
2861}
2862
2863/* @} - end of utilityGroup */
2864
2865
2866
2867
2868
2869/**
2870 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2871 * [random] is a random number between 1 and 32767.
2872 * @param store_name_here Where to store the new filename.
2873 * @param stub A random number will be appended to this to make the FIFO's name.
2874 * @ingroup deviceGroup
2875 */
2876void make_fifo(char *store_name_here, char *stub)
2877{
2878    char *tmp;
2879
2880    malloc_string(tmp);
2881    assert_string_is_neither_NULL_nor_zerolength(stub);
2882
2883    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2884            (int) (random() % 32768));
2885    make_hole_for_file(store_name_here);
2886    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2887    sprintf(tmp, "chmod 770 %s", store_name_here);
2888    paranoid_system(tmp);
2889    paranoid_free(tmp);
2890}
2891
2892
2893
2894
2895
2896
2897/**
2898 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2899 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2900 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2901 * @ingroup utilityGroup
2902 */
2903void sensibly_set_tmpdir_and_scratchdir()
2904{
2905    char *tmp = NULL; 
2906    char *command = NULL;
2907    char *sz = NULL;
2908
2909    assert(bkpinfo != NULL);
2910
2911#ifdef __FreeBSD__
2912    mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output("LANGUAGE=C df -m -P -t nonfs,msdosfs,ntfs,ntfs-3g,vmhgfs,smbfs,smb,cifs,afs,gfs,ocfs,ocfs2,mvfs,nsspool,nssvol | grep -vE \"none|Filesystem\" | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -nr | awk '{print $NF;}' | while read x ; do test -w $x && echo $x && break ; done"));
2913#else
2914    mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output("LANGUAGE=C df -m -P -x nfs -x nfs4 -x fuse.sshfs -x fuse -x vfat -x ntfs -x ntfs-3g -x vmhgfs -x smbfs -x smb -x cifs -x afs -x gfs -x ocfs -x ocfs2 -x mvfs -x nsspool -x nssvol -x iso9660 | grep -vE \"none|Filesystem|/dev/shm\" | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -nr | awk '{print $NF;}' | while read x ; do test -w $x && echo $x && break ; done"));
2915#endif
2916
2917    if (tmp[0] != '/') {
2918        mr_asprintf(&sz, "%s", tmp);
2919        paranoid_free(tmp);
2920        mr_asprintf(&tmp, "/%s", sz);
2921        mr_free(sz);
2922    }
2923    if (!tmp[0]) {
2924        fatal_error("I couldn't figure out the tempdir!");
2925    }
2926    setup_tmpdir(tmp);
2927    log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2928
2929    sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp,
2930            (int) (random() % 32768));
2931    log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2932
2933    mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2934    paranoid_free(tmp);
2935
2936    paranoid_system(command);
2937    mr_free(command);
2938}
2939
2940
2941
2942
2943
2944
2945/**
2946 * @addtogroup deviceGroup
2947 * @{
2948 */
2949/**
2950 * If we can read @p dev, set @p output to it.
2951 * If @p dev cannot be read, set @p output to "".
2952 * @param dev The device to check for.
2953 * @param output Set to @p dev if @p dev exists, "" otherwise.
2954 * @return TRUE if @p dev exists, FALSE if it doesn't.
2955 */
2956bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2957{
2958    char *command;
2959
2960    malloc_string(command);
2961    if (!dev || dev[0] == '\0') {
2962        output[0] = '\0';
2963        return (FALSE);
2964    }
2965//  assert_string_is_neither_NULL_nor_zerolength(dev);
2966    log_msg(10, "Injecting %s", dev);
2967    inject_device(dev);
2968    if (!does_file_exist(dev)) {
2969        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2970        return (FALSE);
2971    }
2972    sprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2973            512L, dev);
2974    if (!run_program_and_log_output(command, FALSE)
2975        && !run_program_and_log_output(command, FALSE)) {
2976        strcpy(output, dev);
2977        log_msg(4, "Found it - %s", dev);
2978        return (TRUE);
2979    } else {
2980        output[0] = '\0';
2981        log_msg(4, "It's not %s", dev);
2982        return (FALSE);
2983    }
2984}
2985
2986
2987
2988
2989
2990/**
2991 * Find out what number CD is in the drive.
2992 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2993 * @return The current CD number, or -1 if it could not be found.
2994 * @note If the CD is not mounted, it will be mounted
2995 * (and remain mounted after this function returns).
2996 */
2997int what_number_cd_is_this()
2998{
2999    int cd_number = -1;
3000    char *mountdev = NULL;
3001    char *tmp = NULL;
3002
3003    assert(bkpinfo != NULL);
3004//  log_it("Asking what_number_cd_is_this");
3005    if (g_ISO_restore_mode) {
3006        mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
3007
3008        mr_asprintf(&mountdev, "%s%s", call_program_and_get_last_line_of_output(tmp), "/archives/THIS-CD-NUMBER");
3009        cd_number = atoi(last_line_of_file(mountdev));
3010        paranoid_free(mountdev);
3011        paranoid_free(tmp);
3012
3013        return (cd_number);
3014    }
3015
3016    mr_asprintf(&mountdev, "%s", bkpinfo->media_device);
3017    if (!mountdev[0]) {
3018        log_it
3019            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
3020        find_cdrom_device(bkpinfo->media_device, FALSE);
3021    }
3022    if (!is_this_device_mounted(MNT_CDROM)) {
3023        if (bkpinfo->backup_media_type == usb) {
3024            mount_USB_here(mountdev, MNT_CDROM);
3025        } else {
3026            mount_CDROM_here(mountdev, MNT_CDROM);
3027        }
3028    }
3029    paranoid_free(mountdev);
3030
3031    cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
3032    return (cd_number);
3033}
3034
3035
3036
3037
3038
3039
3040
3041/**
3042 * Find out what device is mounted as root (/).
3043 * @return Root device.
3044 * @note The returned string points to static storage and will be overwritten with every call.
3045 * @bug A bit of a misnomer; it's actually finding out the root device.
3046 * The mountpoint (where it's mounted) will obviously be '/'.
3047 */
3048char *where_is_root_mounted()
3049{
3050    /*@ buffers **************** */
3051    static char tmp[MAX_STR_LEN];
3052
3053
3054#ifdef __FreeBSD__
3055    strcpy(tmp, call_program_and_get_last_line_of_output
3056           ("mount | grep \" on / \" | cut -d' ' -f1"));
3057#else
3058    strcpy(tmp, call_program_and_get_last_line_of_output
3059           ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
3060    if (strstr(tmp, "/dev/cciss/")) {
3061        strcpy(tmp, call_program_and_get_last_line_of_output
3062               ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
3063    }
3064    if (strstr(tmp, "/dev/md")) {
3065        strcpy(tmp,
3066               call_program_and_get_last_line_of_output
3067               ("mount | grep \" on / \" | cut -d' ' -f1"));
3068    }
3069#endif
3070
3071    return (tmp);
3072}
3073
3074
3075/**
3076 * Find out which boot loader is in use.
3077 * @param which_device Device to look for the boot loader on.
3078 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
3079 * @note Under Linux, all drives are examined, not just @p which_device.
3080 */
3081#ifdef __FreeBSD__
3082char which_boot_loader(char *which_device)
3083{
3084    int count_lilos = 0;
3085    int count_grubs = 0;
3086    int count_boot0s = 0;
3087    int count_dangerouslydedicated = 0;
3088
3089    log_it("looking at drive %s's MBR", which_device);
3090    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
3091        count_grubs++;
3092    }
3093    if (does_string_exist_in_boot_block(which_device, "LILO")) {
3094        count_lilos++;
3095    }
3096    if (does_string_exist_in_boot_block(which_device, "Drive")) {
3097        count_boot0s++;
3098    }
3099    if (does_string_exist_in_first_N_blocks
3100        (which_device, "FreeBSD/i386", 17)) {
3101        count_dangerouslydedicated++;
3102    }
3103    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
3104           count_grubs, count_lilos, count_elilos, count_boot0s,
3105           count_dangerouslydedicated);
3106
3107    if (count_grubs && !count_lilos) {
3108        return ('G');
3109    } else if (count_lilos && !count_grubs) {
3110        return ('L');
3111    } else if (count_grubs == 1 && count_lilos == 1) {
3112        log_it("I'll bet you used to use LILO but switched to GRUB...");
3113        return ('G');
3114    } else if (count_boot0s == 1) {
3115        return ('B');
3116    } else if (count_dangerouslydedicated) {
3117        return ('D');
3118    } else {
3119        log_it("Unknown boot loader");
3120        return ('U');
3121    }
3122}
3123
3124#else
3125
3126char which_boot_loader(char *which_device)
3127{
3128    /*@ buffer ***************************************************** */
3129    char *list_drives_cmd = NULL;
3130    char *current_drive;
3131
3132    /*@ pointers *************************************************** */
3133    FILE *pdrives;
3134
3135    /*@ int ******************************************************** */
3136    int count_lilos = 0;
3137    int count_grubs = 0;
3138
3139    /*@ end vars *************************************************** */
3140
3141    malloc_string(current_drive);
3142
3143#ifdef __IA64__
3144    /* No choice for it */
3145    return ('E');
3146#endif
3147    assert(which_device != NULL);
3148
3149    mr_asprintf(&list_drives_cmd, "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s", where_is_root_mounted());
3150    log_it("list_drives_cmd = %s", list_drives_cmd);
3151
3152    if (!(pdrives = popen(list_drives_cmd, "r"))) {
3153        log_OS_error("Unable to open list of drives");
3154        mr_free(list_drives_cmd);
3155        paranoid_free(current_drive);
3156        return ('\0');
3157    }
3158    mr_free(list_drives_cmd);
3159
3160    for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
3161         (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
3162        strip_spaces(current_drive);
3163        log_it("looking at drive %s's MBR", current_drive);
3164        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3165            count_grubs++;
3166            strcpy(which_device, current_drive);
3167            break;
3168        }
3169        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3170            count_lilos++;
3171            strcpy(which_device, current_drive);
3172            break;
3173        }
3174    }
3175    if (pclose(pdrives)) {
3176        log_OS_error("Cannot pclose pdrives");
3177    }
3178    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3179    if (count_grubs && !count_lilos) {
3180        paranoid_free(current_drive);
3181        return ('G');
3182    } else if (count_lilos && !count_grubs) {
3183        paranoid_free(current_drive);
3184        return ('L');
3185    } else if (count_grubs == 1 && count_lilos == 1) {
3186        log_it("I'll bet you used to use LILO but switched to GRUB...");
3187        paranoid_free(current_drive);
3188        return ('G');
3189    } else {
3190        // We need to look on each partition then
3191        mr_asprintf(&list_drives_cmd, "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
3192        log_it("list_drives_cmd = %s", list_drives_cmd);
3193
3194        if (!(pdrives = popen(list_drives_cmd, "r"))) {
3195            log_OS_error("Unable to open list of drives");
3196            mr_free(list_drives_cmd);
3197            paranoid_free(current_drive);
3198            return ('\0');
3199        }
3200        mr_free(list_drives_cmd);
3201
3202        for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
3203            (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
3204            strip_spaces(current_drive);
3205            log_it("looking at partition %s's BR", current_drive);
3206            if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3207                count_grubs++;
3208                strcpy(which_device, current_drive);
3209                break;
3210            }
3211            if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3212                count_lilos++;
3213                strcpy(which_device, current_drive);
3214                break;
3215            }
3216        }
3217        if (pclose(pdrives)) {
3218            log_OS_error("Cannot pclose pdrives");
3219        }
3220        log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3221        paranoid_free(current_drive);
3222        if (count_grubs && !count_lilos) {
3223            return ('G');
3224        } else if (count_lilos && !count_grubs) {
3225            return ('L');
3226        } else if (count_grubs == 1 && count_lilos == 1) {
3227            log_it("I'll bet you used to use LILO but switched to GRUB...");
3228            return ('G');
3229        } else {
3230            log_it("Unknown boot loader");
3231            return ('U');
3232        }
3233    }
3234}
3235#endif
3236
3237
3238
3239
3240/**
3241 * Write zeroes over the first 16K of @p device.
3242 * @param device The device to zero.
3243 * @return 0 for success, 1 for failure.
3244 */
3245int zero_out_a_device(char *device)
3246{
3247    FILE *fout;
3248    int i;
3249
3250    assert_string_is_neither_NULL_nor_zerolength(device);
3251
3252    log_it("Zeroing drive %s", device);
3253    if (!(fout = fopen(device, "w"))) {
3254        log_OS_error("Unable to open/write to device");
3255        return (1);
3256    }
3257    for (i = 0; i < 16384; i++) {
3258        fputc('\0', fout);
3259    }
3260    paranoid_fclose(fout);
3261    log_it("Device successfully zeroed.");
3262    return (0);
3263}
3264
3265/**
3266 * Return the device pointed to by @p incoming.
3267 * @param incoming The device to resolve symlinks for.
3268 * @return The path to the real device file.
3269 * @note The returned string points to static storage that will be overwritten with each call.
3270 * @bug Won't work with file v4.0; needs to be written in C.
3271 */
3272char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
3273{
3274    static char output[MAX_STR_LEN];
3275    char *command;
3276    char *curr_fname;
3277    char *scratch = NULL;
3278    char *tmp = NULL;
3279    char *p;
3280
3281    struct stat statbuf;
3282    command = malloc(1000);
3283    malloc_string(curr_fname);
3284    if (!does_file_exist(incoming)) {
3285        log_it
3286            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
3287        strcpy(output, incoming);
3288    } else {
3289        strcpy(curr_fname, incoming);
3290        lstat(curr_fname, &statbuf);
3291        while (S_ISLNK(statbuf.st_mode)) {
3292            log_msg(1, "curr_fname = %s", curr_fname);
3293            sprintf(command, "file %s", curr_fname);
3294            mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
3295            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
3296                 p--);
3297            p++;
3298            mr_asprintf(&scratch, "%s", p);
3299            for (p = scratch; *p != '\0' && *p != '\''; p++);
3300            *p = '\0';
3301            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
3302            mr_free(tmp);
3303
3304            if (scratch[0] == '/') {
3305                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
3306            } else {            // copy over the basename cos it's a relative softlink
3307                p = curr_fname + strlen(curr_fname);
3308                while (p != curr_fname && *p != '/') {
3309                    p--;
3310                }
3311                if (*p == '/') {
3312                    p++;
3313                }
3314                strcpy(p, scratch);
3315            }
3316            mr_free(scratch);
3317            lstat(curr_fname, &statbuf);
3318        }
3319        strcpy(output, curr_fname);
3320        log_it("resolved %s to %s", incoming, output);
3321    }
3322    paranoid_free(command);
3323    paranoid_free(curr_fname);
3324    return (output);
3325}
3326
3327/* @} - end of deviceGroup */
3328
3329/**
3330 * Return the type of partition format (GPT or MBR)
3331 */
3332char *which_partition_format(const char *drive)
3333{
3334    static char output[4];
3335    char *tmp = NULL;
3336    char *command;
3337    char *fdisk;
3338#ifdef __IA64__
3339    struct stat buf;
3340#endif
3341    malloc_string(command);
3342    malloc_string(fdisk);
3343    sprintf(fdisk, "/sbin/parted2fdisk");
3344    sprintf(command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
3345    mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
3346    if (strstr(tmp, "GPT") == NULL) {
3347        strcpy(output, "MBR");
3348    } else {
3349        strcpy(output, "GPT");
3350    }
3351    mr_free(tmp);
3352
3353    log_msg(0, "Found %s partition table format type", output);
3354    paranoid_free(command);
3355    paranoid_free(fdisk);
3356    return (output);
3357}
3358/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.