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

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