source: branches/3.0/mondo/src/common/libmondo-devices.c @ 3015

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