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

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