source: MondoRescue/branches/3.3/mondo/src/common/libmondo-devices.c @ 3746

Last change on this file since 3746 was 3746, checked in by Bruno Cornec, 15 months ago

Reinstall mbr.bin (or pgtmbr.bin) from syslinux before calling boot loader restoration to avoid having nothing if we boot from a partition
(tested with SLES 12)

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