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

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