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

Last change on this file since 3185 was 3185, checked in by bruno, 6 years ago

Simplify the interface of mr_getline and mr_asprintf. With 3.1 compatibility now will allow backports from this branch into 3.0

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