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

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

more logging for netfs case

  • Property svn:keywords set to Id
File size: 98.6 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 3751 2019-11-22 17:32:52Z 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 3751 2019-11-22 17:32:52Z 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        log_msg(3, "Testing mount for %s", bkpinfo->netfs_mount);
2556        if (is_this_device_mounted(bkpinfo->netfs_mount)) {
2557            tmp = call_program_and_get_last_line_of_output("mount | grep \":\" | cut -d' ' -f3 | head -n1");
2558            strcpy(bkpinfo->isodir, tmp);
2559            mr_free(tmp);
2560        } else {
2561            // Why netfsdir ?
2562            sprintf(bkpinfo->isodir, "%s/netfsdir", bkpinfo->tmpdir);
2563            mr_asprintf(command, "mkdir -p %s", bkpinfo->isodir);
2564            run_program_and_log_output(command, 5);
2565            mr_free(command);
2566
2567            if (bkpinfo->restore_data) {
2568                /*  mount the FS read-only in restore mode to avoid any erase of whatever */
2569                mr_asprintf(tmpro, "-o ro");
2570            } else {
2571                mr_asprintf(tmpro, "");
2572            }
2573
2574            /*  Build the mount string */
2575            if (strstr(bkpinfo->netfs_proto, "smbfs")) {
2576                mr_asprintf(tmp, "mount -t cifs %s %s %s",bkpinfo->netfs_mount, bkpinfo->isodir,tmpro);
2577                if (bkpinfo->netfs_user) {
2578                    mr_strcat(tmp, " -o user=%s", bkpinfo->netfs_user);
2579                }
2580            else {
2581                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2582                    mr_asprintf(tmp, "sshfs %s ",tmpro);
2583                } else {
2584                    mr_asprintf(tmp, "mount -t %s -o nolock %s ", bkpinfo->netfs_proto,tmpro);
2585                }
2586                if (bkpinfo->netfs_user) {
2587                    mr_strcat(tmp, "%s@", bkpinfo->netfs_user);
2588                }
2589                mr_strcat(tmp, "%s %s", bkpinfo->netfs_mount, bkpinfo->isodir);
2590            }
2591            run_program_and_log_output(tmp, 3);
2592            mr_free(tmp);
2593
2594            malloc_string(g_selfmounted_isodir);
2595            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
2596            }
2597        }
2598       
2599        log_msg(3, "Testing mount for %s", bkpinfo->netfs_mount);
2600        if (!is_this_device_mounted(bkpinfo->netfs_mount)) {
2601            popup_and_OK("Please mount that partition before you try to backup to or restore from it.");
2602            finish(1);
2603        }
2604        if (bkpinfo->netfs_remote_dir == NULL) {
2605            fatal_error("bkpinfo->netfs_remote_dir should not be NULL");
2606        }
2607        strcpy(tmp1, bkpinfo->netfs_remote_dir);
2608        if (!popup_and_get_string ("Directory", "Which directory within that mountpoint?", tmp1, MAX_STR_LEN)) {
2609            log_to_screen("User has chosen not to backup the machine");
2610            finish(1);
2611        }
2612        mr_free(bkpinfo->netfs_remote_dir);
2613        // check whether writable - we better remove surrounding spaces for this
2614        bkpinfo->netfs_remote_dir = mr_strip_spaces(tmp1);
2615
2616        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)) {
2617            log_to_screen("User has chosen not to backup the machine");
2618            finish(1);
2619        }
2620        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2621        log_msg(3, "Just set netfs_remote_dir to %s", bkpinfo->netfs_remote_dir);
2622        log_msg(3, "isodir is still %s", bkpinfo->isodir);
2623        break;
2624
2625    case iso:
2626        if (!bkpinfo->disaster_recovery) {
2627            if (!popup_and_get_string("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)) {
2628                log_to_screen("User has chosen not to backup the machine");
2629                finish(1);
2630            }
2631            if (archiving_to_media) {
2632                if ((compression_type = which_compression_type()) == NULL) {
2633                    log_to_screen("User has chosen not to backup the machine");
2634                    finish(1);
2635                }
2636                if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2637                    log_to_screen("User has chosen not to backup the machine");
2638                    finish(1);
2639                }
2640                sprintf(tmp1, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2641                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)) {
2642                    log_to_screen("User has chosen not to backup the machine");
2643                    finish(1);
2644                }
2645                bkpinfo->media_size = atoi(tmp1);
2646            } else {
2647                bkpinfo->media_size = 650;
2648            }
2649        }
2650        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)) {
2651            log_to_screen("User has chosen not to backup the machine");
2652            finish(1);
2653        }
2654        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2655        break;
2656    default:
2657        fatal_error("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
2658    }
2659
2660    if (archiving_to_media) {
2661        /*  Needs to be done before calling which_boot_loader */
2662        bkpinfo->boot_type = mr_boot_type();
2663        mr_free(bkpinfo->boot_device);
2664#ifdef __FreeBSD__
2665        bkpinfo->boot_device = call_program_and_get_last_line_of_output("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'");
2666#else
2667        bkpinfo->boot_device = call_program_and_get_last_line_of_output("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'");
2668#endif
2669        i = which_boot_loader(bkpinfo->boot_device);
2670        if (i == 'U')           // unknown
2671        {
2672
2673#ifdef __FreeBSD__
2674            if (!popup_and_get_string("Boot device", "What is your boot device? (e.g. /dev/ad0)", bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2675                log_to_screen("User has chosen not to backup the machine");
2676                finish(1);
2677            }
2678            i = which_boot_loader(bkpinfo->boot_device);
2679#else
2680            strcpy(tmp1, bkpinfo->boot_device);
2681            if (!popup_and_get_string("Boot device", "What is your boot device? (e.g. /dev/hda)", tmp1, MAX_STR_LEN / 4)) {
2682                log_to_screen("User has chosen not to backup the machine");
2683                finish(1);
2684            }
2685            mr_free(bkpinfo->boot_device);
2686            mr_asprintf(bkpinfo->boot_device, "%s", tmp1);
2687
2688            if (does_string_exist_in_boot_block(bkpinfo->boot_device, "ELILO")) {
2689                i = 'E';
2690            } else
2691                if (does_string_exist_in_boot_block(bkpinfo->boot_device, "LILO")) {
2692                i = 'L';
2693            } else
2694                if (does_string_exist_in_boot_block(bkpinfo->boot_device, "GRUB")) {
2695                i = 'G';
2696            } else {
2697                i = 'U';
2698            }
2699#endif
2700            if (i == 'U') {
2701                if (ask_me_yes_or_no("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?")) {
2702                    i = 'R';    // raw
2703                } else {
2704                    log_to_screen("I cannot find your boot loader. Please run mondoarchive with parameters.");
2705                    finish(1);
2706                }
2707            }
2708        }
2709        bkpinfo->boot_loader = i;
2710        /* TODO: Check consisytency of boot type and boot loader */
2711
2712        if (bkpinfo->include_paths) {
2713            strcpy(tmp1, bkpinfo->include_paths);
2714            mr_free(bkpinfo->include_paths);
2715        } else {
2716            strcpy(tmp1, "/");
2717        }
2718        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)) {
2719            log_to_screen("User has chosen not to backup the machine");
2720            finish(1);
2721        }
2722        mr_asprintf(bkpinfo->include_paths, "%s", tmp1);
2723
2724        tmp = list_of_NETFS_mounts_only();
2725        if (strlen(tmp) > 2) {
2726            mr_strcat(bkpinfo->exclude_paths, "|%s",tmp);
2727        }
2728        mr_free(tmp);
2729// NTFS
2730        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};'");
2731        strncpy(tmp1, tmp, MAX_STR_LEN / 4);
2732        mr_free(tmp);
2733        if (strlen(tmp1) > 2) {
2734            if (!popup_and_get_string("NTFS partitions", "Please enter/confirm the NTFS partitions you wish to backup as well.", tmp1, MAX_STR_LEN / 4)) {
2735                log_to_screen("User has chosen not to backup the machine");
2736                finish(1);
2737            }
2738            strncpy(bkpinfo->image_devs, tmp1, MAX_STR_LEN / 4);
2739        }
2740
2741        if (bkpinfo->exclude_paths != NULL ) {
2742            strncpy(p,bkpinfo->exclude_paths,(16*MAX_STR_LEN)-1);
2743        } else {
2744            p[0] = '\0';
2745        }
2746        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);
2747        if (p == NULL) {
2748            log_to_screen("User has chosen not to backup the machine");
2749            finish(1);
2750        }
2751        mr_free(bkpinfo->exclude_paths);
2752        mr_asprintf(tmp, "%s", p);
2753        bkpinfo->exclude_paths = tmp;
2754
2755        mr_asprintf(oldtmp, "%s", bkpinfo->tmpdir);
2756        if (bkpinfo->tmpdir != NULL ) {
2757            strncpy(p,bkpinfo->tmpdir,(16*MAX_STR_LEN)-1);
2758        } else {
2759            p[0] = '\0';
2760        }
2761        if (!popup_and_get_string("Temporary directory", "Please enter your temporary directory.", p, (4*MAX_STR_LEN)-1)) {
2762            log_to_screen("User has chosen not to backup the machine");
2763            finish(1);
2764        }
2765        /*  if modified to another path */
2766        if (strcmp(p,oldtmp) != 0) {
2767            setup_tmpdir(p);
2768        }
2769        mr_free(oldtmp);
2770
2771        mr_asprintf(oldtmp, "%s", bkpinfo->scratchdir);
2772        if (bkpinfo->scratchdir != NULL ) {
2773            strncpy(p,bkpinfo->scratchdir,(16*MAX_STR_LEN)-1);
2774        } else {
2775            p[0] = '\0';
2776        }
2777        if (!popup_and_get_string("Scratch directory", "Please enter your scratch directory.", p, (4*MAX_STR_LEN)-1)) {
2778            log_to_screen("User has chosen not to backup the machine");
2779            finish(1);
2780        }
2781        /*  if modified to another path */
2782        if (strcmp(p,oldtmp) != 0) {
2783            setup_scratchdir(p);
2784        }
2785        mr_free(oldtmp);
2786
2787        if (ask_me_yes_or_no("Do you want to backup extended attributes?")) {
2788            if (find_home_of_exe("getfattr")) {
2789                mr_free(g_getfattr);
2790                mr_asprintf(g_getfattr,"getfattr");
2791            }
2792            if (find_home_of_exe("getfacl")) {
2793                mr_free(g_getfacl);
2794                mr_asprintf(g_getfacl,"getfacl");
2795            }
2796            log_it("Backup of extended attributes");
2797        }
2798// Interactive mode:
2799#ifdef __IA64__
2800        bkpinfo->make_cd_use_lilo = TRUE;
2801#else
2802        bkpinfo->make_cd_use_lilo = FALSE;
2803#endif
2804        bkpinfo->backup_data = TRUE;
2805        if (strcmp(compression_type,"lzo") == 0) {
2806            strcpy(bkpinfo->zip_exe, "lzop");
2807            strcpy(bkpinfo->zip_suffix, "lzo");
2808        } else if (strcmp(compression_type,"gzip") == 0) {
2809            strcpy(bkpinfo->zip_exe, "gzip");
2810            strcpy(bkpinfo->zip_suffix, "gz");
2811        } else if (strcmp(compression_type,"lzma") == 0) {
2812            //strcpy(bkpinfo->zip_exe, "xy");
2813            //strcpy(bkpinfo->zip_suffix, "xy");
2814        } else if (strcmp(compression_type,"bzip2") == 0) {
2815            strcpy(bkpinfo->zip_exe, "bzip2");
2816            strcpy(bkpinfo->zip_suffix, "bz2");
2817        } else {
2818            bkpinfo->zip_exe[0] = bkpinfo->zip_suffix[0] = '\0';
2819        }
2820#if __FreeBSD__ == 5
2821        strcpy(bkpinfo->kernel_path, "/boot/kernel/kernel");
2822#elif __FreeBSD__ == 4
2823        strcpy(bkpinfo->kernel_path, "/kernel");
2824#elif linux
2825        if (figure_out_kernel_path_interactively_if_necessary(bkpinfo->kernel_path)) {
2826            fatal_error("Kernel not found. Please specify manually with the '-k' switch.");
2827        }
2828#else
2829#error "I don't know about this system!"
2830#endif
2831
2832
2833        bkpinfo->verify_data =
2834            ask_me_yes_or_no
2835            ("Will you want to verify your backups after Mondo has created them?");
2836
2837        if (!ask_me_yes_or_no
2838            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2839            log_to_screen("User has chosen not to backup the machine");
2840            finish(1);
2841        }
2842    } else {
2843        bkpinfo->restore_data = TRUE;   // probably...
2844    }
2845    mr_free(compression_type);
2846
2847    if (bkpinfo->backup_media_type == iso
2848        || bkpinfo->backup_media_type == netfs) {
2849        g_ISO_restore_mode = TRUE;
2850    }
2851#ifdef __FreeSD__
2852// skip
2853#else
2854    if (bkpinfo->backup_media_type == netfs) {
2855        log_msg(3, "I think the Remote mount is mounted at %s", bkpinfo->isodir);
2856    }
2857    log_it("isodir = %s", bkpinfo->isodir);
2858    if (bkpinfo->netfs_mount) {
2859        log_it("netfs_mount = '%s'", bkpinfo->netfs_mount);
2860    }
2861    if (bkpinfo->netfs_user) {
2862        log_it("netfs_user = '%s'", bkpinfo->netfs_user);
2863    }
2864    if (bkpinfo->netfs_proto) {
2865        log_it("netfs_proto = '%s'", bkpinfo->netfs_proto);
2866    }
2867#endif
2868
2869    log_it("media device = %s", bkpinfo->media_device);
2870    log_it("media size = %ld", bkpinfo->media_size);
2871    log_it("media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
2872    if (bkpinfo->prefix) {
2873        log_it("prefix = %s", bkpinfo->prefix);
2874    }
2875    log_it("compression = %ld", bkpinfo->compression_level);
2876    log_it("exclude_path = %s", bkpinfo->exclude_paths);
2877    if (bkpinfo->include_paths) {
2878        log_it("include_path = %s", bkpinfo->include_paths);
2879    }
2880
2881    /* Handle devices passed in bkpinfo and print result */
2882    /*  the mr_make_devlist_from_pathlist function appends */
2883    /*  to the *_paths variables so copy before */
2884    mr_make_devlist_from_pathlist(bkpinfo->exclude_paths, 'E');
2885    mr_make_devlist_from_pathlist(bkpinfo->include_paths, 'I');
2886
2887    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2888    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2889    if (bkpinfo->image_devs) {
2890        log_it("image_devs = '%s'", bkpinfo->image_devs);
2891    }
2892    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device, bkpinfo->boot_loader);
2893    if (bkpinfo->media_size < 0) {
2894        if (archiving_to_media) {
2895            fatal_error("Media size is less than zero.");
2896        } else {
2897            log_msg(2, "Warning - media size is less than zero.");
2898            bkpinfo->media_size = 0;
2899        }
2900    }
2901    paranoid_free(sz_size);
2902    paranoid_free(tmp1);
2903    return (0);
2904}
2905
2906
2907/**
2908 * Get a |-separated list of NETFS mounts.
2909 * @return The list created.
2910 * @note The return value points to allocated string that needs to be freed by
2911 * caller
2912 * @bug Even though we only want the mounts, the devices are still checked.
2913 */
2914char *list_of_NETFS_mounts_only(void)
2915{
2916    char *exclude_these_directories = NULL;
2917
2918    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;}'");
2919    log_msg(9,"list_of_NETFS_mounts_only returns %s",exclude_these_directories);
2920    return(exclude_these_directories);
2921}
2922
2923/* @} - end of utilityGroup */
2924
2925
2926
2927
2928
2929/**
2930 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2931 * [random] is a random number between 1 and 32767.
2932 * @param store_name_here Where to store the new filename.
2933 * @param stub A random number will be appended to this to make the FIFO's name.
2934 * @ingroup deviceGroup
2935 */
2936void make_fifo(char *store_name_here, char *stub)
2937{
2938    char *tmp = NULL;
2939
2940    assert_string_is_neither_NULL_nor_zerolength(stub);
2941
2942    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2943            (int) (random() % 32768));
2944    make_hole_for_file(store_name_here);
2945    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2946    mr_asprintf(tmp, "chmod 770 %s", store_name_here);
2947    paranoid_system(tmp);
2948    mr_free(tmp);
2949}
2950
2951
2952
2953/**
2954 * @addtogroup deviceGroup
2955 * @{
2956 */
2957/**
2958 * If we can read @p dev, set @p output to it.
2959 * If @p dev cannot be read, set @p output to "".
2960 * @param dev The device to check for.
2961 * @param output Set to @p dev if @p dev exists, "" otherwise.
2962 * @return TRUE if @p dev exists, FALSE if it doesn't.
2963 */
2964bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2965{
2966    char *command = NULL;
2967    bool ret=FALSE;
2968
2969    if (!dev || dev[0] == '\0') {
2970        output[0] = '\0';
2971        return(ret);
2972    }
2973//  assert_string_is_neither_NULL_nor_zerolength(dev);
2974    if (!bkpinfo->please_dont_eject) {
2975        log_msg(10, "Injecting %s", dev);
2976        inject_device(dev);
2977    }
2978    if (!does_file_exist(dev)) {
2979        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2980        return(ret);
2981    }
2982    mr_asprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null", 512L, dev);
2983    if (!run_program_and_log_output(command, FALSE) && !run_program_and_log_output(command, FALSE)) {
2984        strcpy(output, dev);
2985        log_msg(4, "Found it - %s", dev);
2986        ret = TRUE;
2987    } else {
2988        output[0] = '\0';
2989        log_msg(4, "It's not %s", dev);
2990    }
2991    mr_free(command);
2992    return(ret);
2993}
2994
2995
2996
2997
2998
2999/**
3000 * Find out what number CD is in the drive.
3001 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
3002 * @return The current CD number, or -1 if it could not be found.
3003 * @note If the CD is not mounted, it will be mounted
3004 * (and remain mounted after this function returns).
3005 */
3006int what_number_cd_is_this()
3007{
3008    int cd_number = -1;
3009    char *mountdev = NULL;
3010    char *tmp = NULL;
3011
3012    assert(bkpinfo != NULL);
3013//  log_it("Asking what_number_cd_is_this");
3014    if ((g_ISO_restore_mode) || (g_restoring_live_from_cd)) {
3015        tmp = call_program_and_get_last_line_of_output("mount | grep iso9660 | awk '{print $3;}'");
3016        mr_asprintf(mountdev, "%s%s", tmp, "/archives/THIS-CD-NUMBER");
3017        mr_free(tmp);
3018        cd_number = atoi(last_line_of_file(mountdev));
3019        mr_free(mountdev);
3020
3021        return (cd_number);
3022    }
3023
3024    if (!bkpinfo->media_device[0]) {
3025        log_it("ERROR: bkpinfo->media_device shoulnd't be empty here\n");
3026        return(0);
3027    }
3028    mr_asprintf(mountdev, "%s", bkpinfo->media_device);
3029    if (!mountdev[0]) {
3030        log_it("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
3031        find_cdrom_device(bkpinfo->media_device, FALSE);
3032    }
3033    if (!is_this_device_mounted(MNT_CDROM)) {
3034        if (bkpinfo->backup_media_type == usb) {
3035            mount_USB_here(mountdev, MNT_CDROM);
3036        } else {
3037            mount_CDROM_here(mountdev, MNT_CDROM);
3038        }
3039    }
3040    mr_free(mountdev);
3041
3042    cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
3043    return (cd_number);
3044}
3045
3046
3047/**
3048 * Find out what device is mounted as root (/).
3049 * @return Root device.
3050 * @note The returned string points to storage that needs to be freed by
3051 * caller
3052 * @bug A bit of a misnomer; it's actually finding out the root device.
3053 * The mountpoint (where it's mounted) will obviously be '/'.
3054 */
3055char *where_is_root_mounted() {
3056
3057/*@ buffers **************** */
3058char *tmp = NULL;
3059
3060#ifdef __FreeBSD__
3061    tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1");
3062#else
3063    tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//");
3064    if (strstr(tmp, "/dev/cciss/")) {
3065        mr_free(tmp);
3066        tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1");
3067    }
3068    if (strstr(tmp, "/dev/md")) {
3069        mr_free(tmp);
3070        tmp = call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1");
3071    }
3072#endif
3073
3074return (tmp);
3075}
3076
3077
3078/**
3079 * Find out which boot loader is in use.
3080 * @param which_device Device to look for the boot loader on.
3081 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
3082 * @note Under Linux, all drives are examined, not just @p which_device.
3083 */
3084#ifdef __FreeBSD__
3085char which_boot_loader(char *which_device)
3086{
3087    int count_lilos = 0;
3088    int count_grubs = 0;
3089    int count_boot0s = 0;
3090    int count_dangerouslydedicated = 0;
3091
3092    log_it("looking at drive %s's MBR", which_device);
3093    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
3094        count_grubs++;
3095    }
3096    if (does_string_exist_in_boot_block(which_device, "LILO")) {
3097        count_lilos++;
3098    }
3099    if (does_string_exist_in_boot_block(which_device, "Drive")) {
3100        count_boot0s++;
3101    }
3102    if (does_string_exist_in_first_N_blocks
3103        (which_device, "FreeBSD/i386", 17)) {
3104        count_dangerouslydedicated++;
3105    }
3106    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
3107           count_grubs, count_lilos, count_elilos, count_boot0s,
3108           count_dangerouslydedicated);
3109
3110    if (count_grubs && !count_lilos) {
3111        return ('G');
3112    } else if (count_lilos && !count_grubs) {
3113        return ('L');
3114    } else if (count_grubs == 1 && count_lilos == 1) {
3115        log_it("I'll bet you used to use LILO but switched to GRUB...");
3116        return ('G');
3117    } else if (count_boot0s == 1) {
3118        return ('B');
3119    } else if (count_dangerouslydedicated) {
3120        return ('D');
3121    } else {
3122        log_it("Unknown boot loader");
3123        return ('U');
3124    }
3125}
3126
3127#else
3128
3129char which_boot_loader(char *which_device)
3130{
3131    /*@ buffer ***************************************************** */
3132    char *list_drives_cmd = NULL;
3133    char *current_drive;
3134    char *tmp;
3135
3136    /*@ pointers *************************************************** */
3137    FILE *pdrives;
3138
3139    /*@ int ******************************************************** */
3140    int count_lilos = 0;
3141    int count_grubs = 0;
3142
3143    /*@ end vars *************************************************** */
3144
3145#ifdef __IA64__
3146    /* No choice for it */
3147    return ('E');
3148#endif
3149    if (bkpinfo->boot_type == EFI) {
3150        /* No choice for it */
3151        return ('E');
3152    }
3153
3154    if (bkpinfo->boot_type == UEFI) {
3155        /*  hardcoded for now. We can for sure do a better job here ! */
3156        /* RHEL, SLES, Mageia, Debian, Ubuntu use grub as boot loader as it seems for UEFI */
3157        return ('G');
3158    }
3159
3160    assert(which_device != NULL);
3161
3162    tmp = where_is_root_mounted();
3163    mr_asprintf(list_drives_cmd, "mr-parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s", tmp);
3164    log_it("list_drives_cmd = %s", list_drives_cmd);
3165    mr_free(tmp);
3166    if (!(pdrives = popen(list_drives_cmd, "r"))) {
3167        log_OS_error("Unable to open list of drives");
3168        mr_free(list_drives_cmd);
3169        return ('\0');
3170    }
3171    mr_free(list_drives_cmd);
3172
3173    malloc_string(current_drive);
3174    if (bkpinfo->boot_type == BIOS) {
3175        for (tmp = fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives) && (tmp != NULL); tmp = fgets(current_drive, MAX_STR_LEN, pdrives)) {
3176            strip_spaces(current_drive);
3177            log_it("looking at drive %s's MBR", current_drive);
3178            if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3179                count_grubs++;
3180                strcpy(which_device, current_drive);
3181                break;
3182            }
3183            if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3184                count_lilos++;
3185                strcpy(which_device, current_drive);
3186                break;
3187            }
3188        }
3189        if (pclose(pdrives)) {
3190            log_OS_error("Cannot pclose pdrives");
3191        }
3192        log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3193        if (count_grubs && !count_lilos) {
3194            paranoid_free(current_drive);
3195            return ('G');
3196        } else if (count_lilos && !count_grubs) {
3197            paranoid_free(current_drive);
3198            return ('L');
3199        } else if (count_grubs == 1 && count_lilos == 1) {
3200            log_it("I'll bet you used to use LILO but switched to GRUB...");
3201            paranoid_free(current_drive);
3202            return ('G');
3203        } else {
3204            // We need to look on each partition then
3205            mr_asprintf(list_drives_cmd, "mr-parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
3206            log_it("list_drives_cmd = %s", list_drives_cmd);
3207   
3208            if (!(pdrives = popen(list_drives_cmd, "r"))) {
3209                log_OS_error("Unable to open list of drives");
3210                mr_free(list_drives_cmd);
3211                paranoid_free(current_drive);
3212                return ('\0');
3213            }
3214            mr_free(list_drives_cmd);
3215   
3216            for (tmp = fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives) && (tmp != NULL);
3217                tmp = fgets(current_drive, MAX_STR_LEN, pdrives)) {
3218                strip_spaces(current_drive);
3219                log_it("looking at partition %s's BR", current_drive);
3220                if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3221                    count_grubs++;
3222                    strcpy(which_device, current_drive);
3223                    break;
3224                }
3225                if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3226                    count_lilos++;
3227                    strcpy(which_device, current_drive);
3228                    break;
3229                }
3230            }
3231            if (pclose(pdrives)) {
3232                log_OS_error("Cannot pclose pdrives");
3233            }
3234            log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3235            paranoid_free(current_drive);
3236            if (count_grubs && !count_lilos) {
3237                return ('G');
3238            } else if (count_lilos && !count_grubs) {
3239                return ('L');
3240            } else if (count_grubs == 1 && count_lilos == 1) {
3241                log_it("I'll bet you used to use LILO but switched to GRUB...");
3242                return ('G');
3243            } else {
3244                log_it("Unknown boot loader");
3245                return ('U');
3246            }
3247        }
3248    }
3249}
3250#endif
3251
3252
3253
3254
3255/**
3256 * Write zeroes over the first 16K of @p device.
3257 * @param device The device to zero.
3258 * @return 0 for success, 1 for failure.
3259 */
3260int zero_out_a_device(char *device)
3261{
3262    FILE *fout;
3263    int i;
3264
3265    assert_string_is_neither_NULL_nor_zerolength(device);
3266
3267    log_it("Zeroing drive %s", device);
3268    if (!(fout = fopen(device, "w"))) {
3269        log_OS_error("Unable to open/write to device");
3270        return (1);
3271    }
3272    for (i = 0; i < 16384; i++) {
3273        fputc('\0', fout);
3274    }
3275    paranoid_fclose(fout);
3276    log_it("Device successfully zeroed.");
3277    return (0);
3278}
3279
3280/**
3281 * Return the device pointed to by @p incoming.
3282 * @param incoming The device to resolve symlinks for.
3283 * @return The path to the real device file.
3284 * @note The returned string points to static storage that will be overwritten with each call.
3285 * @bug Won't work with file v4.0; needs to be written in C.
3286 */
3287char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
3288{
3289    static char output[MAX_STR_LEN];
3290    char *command = NULL;
3291    char *curr_fname = NULL;
3292    char *scratch = NULL;
3293    char *tmp = NULL;
3294    char *p;
3295
3296    struct stat statbuf;
3297    malloc_string(curr_fname);
3298    if (!does_file_exist(incoming)) {
3299        log_it
3300            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
3301        strcpy(output, incoming);
3302    } else {
3303        strcpy(curr_fname, incoming);
3304        lstat(curr_fname, &statbuf);
3305        while (S_ISLNK(statbuf.st_mode)) {
3306            log_msg(1, "curr_fname = %s", curr_fname);
3307            mr_asprintf(command, "file %s", curr_fname);
3308            tmp = call_program_and_get_last_line_of_output(command);
3309            mr_free(command);
3310            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
3311                 p--);
3312            p++;
3313            mr_asprintf(scratch, "%s", p);
3314            for (p = scratch; *p != '\0' && *p != '\''; p++);
3315            *p = '\0';
3316            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
3317            mr_free(tmp);
3318
3319            if (scratch[0] == '/') {
3320                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
3321            } else {            // copy over the basename cos it's a relative softlink
3322                p = curr_fname + strlen(curr_fname);
3323                while (p != curr_fname && *p != '/') {
3324                    p--;
3325                }
3326                if (*p == '/') {
3327                    p++;
3328                }
3329                strcpy(p, scratch);
3330            }
3331            mr_free(scratch);
3332            lstat(curr_fname, &statbuf);
3333        }
3334        strcpy(output, curr_fname);
3335        log_it("resolved %s to %s", incoming, output);
3336    }
3337    paranoid_free(curr_fname);
3338    return (output);
3339}
3340
3341/* @} - end of deviceGroup */
3342
3343/**
3344 * Return the type of partition format (GPT or MBR)
3345 */
3346char *which_partition_format(const char *drive)
3347{
3348    char *output = NULL;
3349    char *command = NULL;
3350
3351    mr_asprintf(command, "mr-disk-type %s", drive);
3352    output = call_program_and_get_last_line_of_output(command);
3353    mr_free(command);
3354
3355    log_msg(0, "Found %s partition table format type on %s", output, drive);
3356    return (output);
3357}
3358/* @} - end of deviceGroup */
3359
3360
Note: See TracBrowser for help on using the repository browser.