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

Last change on this file since 2949 was 2949, checked in by Bruno Cornec, 8 years ago
  • Fix #127 by removing code which was forcing media size in NFS mode blindly (Michael Caerwyn mcaerwyn_at_gmail.com)
  • Property svn:keywords set to Id
File size: 97.7 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 2949 2012-02-16 00:53:18Z 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 2949 2012-02-16 00:53:18Z bruno $";
37//
38
39extern char *which_compression_type();
40/* Do we use extended attributes and acl ?  */
41extern char *g_getfacl;
42extern char *g_getfattr;
43
44extern int g_current_media_number;
45extern double g_kernel_version;
46
47extern bool g_ISO_restore_mode;
48extern char *g_selfmounted_isodir;
49extern char *MONDO_LOGFILE;
50
51extern void setup_tmpdir(char *path);
52
53static char g_cdrw_drive_is_here[MAX_STR_LEN / 4] = "";
54static char g_cdrom_drive_is_here[MAX_STR_LEN / 4] = "";
55static char g_dvd_drive_is_here[MAX_STR_LEN / 4] = "";
56
57
58/**
59 * ????? @bug ?????
60 * @ingroup globalGroup
61 */
62bool g_restoring_live_from_cd = FALSE;
63bool g_restoring_live_from_netfs = FALSE;
64
65extern t_bkptype g_backup_media_type;   // set by main()
66
67/* Reference to global bkpinfo */
68extern struct s_bkpinfo *bkpinfo;
69
70/* Stuff that handles the -I and -E option when a whole disk DSF is used */
71typedef struct mounted_fs_struct {
72    char device[MAX_STR_LEN];       /* The name of the device */
73    char mount_point[MAX_STR_LEN];  /* The devices mount point */
74    unsigned char check;            /* 1 == included on DSF */
75    struct mounted_fs_struct *next;
76} MOUNTED_FS_STRUCT;
77
78static MOUNTED_FS_STRUCT *DSF_Head = NULL;      /* Points to the first entry of mounted_fs_struct list */
79static MOUNTED_FS_STRUCT *DSF_Tail = NULL;      /* Points to the last entry of mounted_fs_struct list */
80
81
82void set_g_cdrom_and_g_dvd_to_bkpinfo_value()
83{
84    strcpy(g_cdrom_drive_is_here, bkpinfo->media_device);   // just in case
85    strcpy(g_dvd_drive_is_here, bkpinfo->media_device); // just in case
86}
87
88
89
90/**
91 * Retract all CD trays and wait for autorun to complete.
92 * @ingroup deviceGroup
93 */
94void retract_CD_tray_and_defeat_autorun(void)
95{
96//  log_it("rctada: Retracting all CD trays", __LINE__);
97    if (!bkpinfo->please_dont_eject) {
98        if (strlen(g_cdrom_drive_is_here) > 0) {
99            inject_device(g_cdrom_drive_is_here);
100        }
101        if (strlen(g_dvd_drive_is_here) > 0) {
102            inject_device(g_dvd_drive_is_here);
103        }
104        if (strlen(g_cdrw_drive_is_here) > 0) {
105            inject_device(g_cdrw_drive_is_here);
106        }
107    }
108//  log_it("rctada: killing autorun");
109//  run_program_and_log_output("killall autorun", TRUE);
110    if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5)) {
111        log_it("autorun detected; sleeping for 2 seconds");
112        sleep(2);
113    }
114    log_it("rctada: Unmounting all CD drives", __LINE__);
115    run_program_and_log_output("umount /dev/cdr* /dev/dvd*", 5);
116}
117
118
119
120/**
121 * Determine whether we're booted off a ramdisk.
122 * @return @c TRUE (we are) or @c FALSE (we aren't).
123 * @ingroup utilityGroup
124 */
125bool am_I_in_disaster_recovery_mode(void)
126{
127    char *tmp = NULL;
128    char *comment;
129    bool is_this_a_ramdisk = FALSE;
130
131    malloc_string(comment);
132    mr_asprintf(&tmp, "%s", where_is_root_mounted());
133    sprintf(comment, "root is mounted at %s\n", tmp);
134    log_msg(0, comment);
135    log_msg(0,
136            "No, Schlomo, that doesn't mean %s is the root partition. It's just a debugging message. Relax. It's part of am_I_in_disaster_recovery_mode().",
137            tmp);
138
139#ifdef __FreeBSD__
140    if (strstr(tmp, "/dev/md")) {
141        is_this_a_ramdisk = TRUE;
142    }
143#else
144    if (!strncmp(tmp, "/dev/ram", 8)
145        || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/")
146            && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs")
147        || !strcmp(tmp, "/dev/root")) {
148        is_this_a_ramdisk = TRUE;
149    } else {
150        is_this_a_ramdisk = FALSE;
151    }
152#endif
153    mr_free(tmp);
154
155    if (is_this_a_ramdisk) {
156        if (!does_file_exist("/THIS-IS-A-RAMDISK")) {
157            log_to_screen
158                ("Using /dev/root is stupid of you but I'll forgive you.");
159            is_this_a_ramdisk = FALSE;
160        }
161    }
162    if (does_file_exist("/THIS-IS-A-RAMDISK")) {
163        is_this_a_ramdisk = TRUE;
164    }
165    paranoid_free(comment);
166    log_msg(1, "Is this a ramdisk? result = %d", is_this_a_ramdisk);
167    return (is_this_a_ramdisk);
168}
169
170
171
172
173
174/**
175 * Turn @c bkpinfo->backup_media_type into a human-readable string.
176 * @return The human readable string (e.g. @c cdr becomes <tt>"cdr"</tt>).
177 * @note The returned string points to static storage that will be overwritten with each call.
178 * @ingroup stringGroup
179 */
180static char *bkptype_to_string(t_bkptype bt)
181{
182    static char output[MAX_STR_LEN / 4];
183    switch (bt) {
184    case none:
185        strcpy(output, "none");
186        break;
187    case iso:
188        strcpy(output, "iso");
189        break;
190    case cdr:
191        strcpy(output, "cdr");
192        break;
193    case cdrw:
194        strcpy(output, "cdrw");
195        break;
196    case cdstream:
197        strcpy(output, "cdstream");
198        break;
199    case netfs:
200        strcpy(output, "netfs");
201        break;
202    case tape:
203        strcpy(output, "tape");
204        break;
205    case udev:
206        strcpy(output, "udev");
207        break;
208    case usb:
209        strcpy(output, "usb");
210        break;
211    default:
212        strcpy(output, "default");
213    }
214    return (output);
215}
216
217
218
219/**
220 * @addtogroup deviceGroup
221 * @{
222 */
223/**
224 * Eject the tray of the specified CD device.
225 * @param dev The device to eject.
226 * @return the return value of the @c eject command. (0=success, nonzero=failure)
227 */
228int eject_device(char *dev)
229{
230    char *command;
231    int res1 = 0, res2 = 0;
232
233    malloc_string(command);
234
235    if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type)
236        && g_backup_media_type != udev) {
237        sprintf(command, "mt -f %s offline", dev);
238        res1 = run_program_and_log_output(command, 1);
239    } else {
240        res1 = 0;
241    }
242
243#ifdef __FreeBSD__
244    if (strstr(dev, "acd")) {
245        sprintf(command, "cdcontrol -f %s eject", dev);
246    } else {
247        sprintf(command, "camcontrol eject `echo %s | sed 's|/dev/||'`",
248                dev);
249    }
250#else
251    sprintf(command, "eject %s", dev);
252#endif
253
254    log_msg(3, "Ejecting %s", dev);
255    res2 = run_program_and_log_output(command, 1);
256    paranoid_free(command);
257    if (res1 && res2) {
258        return (1);
259    } else {
260        return (0);
261    }
262}
263
264/**
265 * Load (inject) the tray of the specified CD device.
266 * @param dev The device to load/inject.
267 * @return 0 for success, nonzero for failure.
268 */
269int inject_device(char *dev)
270{
271    char *command;
272    int i;
273
274    malloc_string(command);
275
276
277#ifdef __FreeBSD__
278    if (strstr(dev, "acd")) {
279        sprintf(command, "cdcontrol -f %s close", dev);
280    } else {
281        sprintf(command, "camcontrol load `echo %s | sed 's|/dev/||'`",
282                dev);
283    }
284#else
285    sprintf(command, "eject -t %s", dev);
286#endif
287    i = run_program_and_log_output(command, FALSE);
288    paranoid_free(command);
289    return (i);
290}
291
292
293/**
294 * Determine whether the specified @p device (really, you can use any file)
295 * exists.
296 * @return TRUE if it exists, FALSE if it doesn't.
297 */
298bool does_device_exist(char *device)
299{
300
301    /*@ buffers *********************************************************** */
302    char *tmp;
303    bool ret;
304
305    malloc_string(tmp);
306    assert_string_is_neither_NULL_nor_zerolength(device);
307
308    sprintf(tmp, "ls %s > /dev/null 2> /dev/null", device);
309
310    if (system(tmp)) {
311        ret = FALSE;
312    } else {
313        ret = TRUE;
314    }
315    paranoid_free(tmp);
316    return (ret);
317}
318
319
320/**
321 * Determine whether a non-Microsoft partition exists on any connected hard drive.
322 * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent PC).
323 */
324bool does_nonMS_partition_exist(void)
325{
326#if __FreeBSD__
327    return
328        !system
329        ("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false");
330#else
331    return
332        !system
333        ("parted2fdisk -l 2>/dev/null | grep '^/dev/' | grep -Eqv '(MS|DOS|FAT|NTFS)'");
334#endif
335}
336
337/**
338 * Determine whether the specified @p partno exists on the specified @p drive.
339 * @param drive The drive to search for the partition in.
340 * @param partno The partition number to look for.
341 * @return 0 if it exists, nonzero otherwise.
342 */
343int does_partition_exist(const char *drive, int partno)
344{
345    /*@ buffers **************************************************** */
346    char *program;
347    char *incoming;
348    char *searchstr = NULL;
349    char *tmp;
350
351    /*@ ints ******************************************************* */
352    int res = 0;
353
354    /*@ pointers *************************************************** */
355    FILE *fin;
356
357
358    /*@ end vars *************************************************** */
359    assert_string_is_neither_NULL_nor_zerolength(drive);
360    assert(partno >= 0 && partno < 999);
361
362    malloc_string(program);
363    malloc_string(incoming);
364    malloc_string(searchstr);
365    malloc_string(tmp);
366
367#ifdef __FreeBSD__
368    // We assume here that this is running from mondorestore. (It is.)
369    sprintf(program, "ls %s %s >/dev/null 2>&1", drive,
370            build_partition_name(tmp, drive, partno));
371    return system(program);
372#else
373    tmp[0] = '\0';
374#endif
375
376    sprintf(program, "parted2fdisk -l %s 2> /dev/null", drive);
377    fin = popen(program, "r");
378    if (!fin) {
379        log_it("program=%s", program);
380        log_OS_error("Cannot popen-in program");
381        return (0);
382    }
383    (void) build_partition_name(searchstr, drive, partno);
384    strcat(searchstr, " ");
385    for (res = 0; !res && fgets(incoming, MAX_STR_LEN - 1, fin);) {
386        if (strstr(incoming, searchstr)) {
387            res = 1;
388        }
389    }
390    if (pclose(fin)) {
391        log_OS_error("Cannot pclose fin");
392    }
393    paranoid_free(program);
394    paranoid_free(incoming);
395    paranoid_free(searchstr);
396    paranoid_free(tmp);
397    return (res);
398}
399
400
401
402
403
404/**
405 * Determine whether given NULL-terminated @p str exists in the MBR of @p dev.
406 * @param dev The device to look in.
407 * @param str The string to look for.
408 * @return TRUE if it exists, FALSE if it doesn't.
409 */
410bool does_string_exist_in_boot_block(char *dev, char *str)
411{
412    /*@ buffers **************************************************** */
413    char *command;
414
415    /*@ end vars *************************************************** */
416    int i;
417
418    assert_string_is_neither_NULL_nor_zerolength(dev);
419    assert_string_is_neither_NULL_nor_zerolength(str);
420
421    malloc_string(command);
422    sprintf(command,
423            "dd if=%s bs=446 count=1 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null",
424            dev, str);
425    i = system(command);
426    paranoid_free(command);
427    if (i) {
428        return (FALSE);
429    } else {
430        return (TRUE);
431    }
432}
433
434/**
435 * Determine whether specified @p str exists in the first @p n sectors of
436 * @p dev.
437 * @param dev The device to look in.
438 * @param str The string to look for.
439 * @param n The number of 512-byte sectors to search.
440 */
441bool does_string_exist_in_first_N_blocks(char *dev, char *str, int n)
442{
443    /*@ buffers **************************************************** */
444    char *command;
445    /*@ end vars *************************************************** */
446    int i;
447
448    malloc_string(command);
449    sprintf(command,
450            "dd if=%s bs=512 count=%i 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null",
451            dev, n, str);
452    i = system(command);
453    paranoid_free(command);
454    if (i) {
455        return (FALSE);
456    } else {
457        return (TRUE);
458    }
459}
460
461
462
463/**
464 * Try to mount CD-ROM at @p mountpoint. If the CD-ROM is not found or has
465 * not been specified, call find_cdrom_device() to find it.
466 * @param bkpinfo The backup information structure. The only field used is @c bkpinfo->media_device.
467 * @param mountpoint Where to mount the CD-ROM.
468 * @return 0 for success, nonzero for failure.
469 * @see mount_CDROM_here
470 */
471int find_and_mount_actual_cd(char *mountpoint)
472{
473    /*@ buffers ***************************************************** */
474
475    /*@ int's  ****************************************************** */
476    int res;
477    char *dev;
478
479    /*@ end vars **************************************************** */
480
481    malloc_string(dev);
482    assert(bkpinfo != NULL);
483    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
484
485    if (g_backup_media_type == dvd) {
486        strcpy(dev, g_dvd_drive_is_here);
487        if (!dev[0]) {
488            find_dvd_device(dev, FALSE);
489        }
490    } else {
491        strcpy(dev, g_cdrom_drive_is_here);
492        if (!dev[0]) {
493            find_cdrom_device(dev, FALSE);
494        }
495    }
496
497    if (bkpinfo->backup_media_type != iso) {
498        retract_CD_tray_and_defeat_autorun();
499    }
500
501    if (!dev[0] || (res = mount_CDROM_here(dev, mountpoint))) {
502        if (!popup_and_get_string
503            ("CD-ROM device", "Please enter your CD-ROM's /dev device",
504             dev, MAX_STR_LEN / 4)) {
505            res = 1;
506        } else {
507            res = mount_CDROM_here(dev, mountpoint);
508        }
509    }
510    if (res) {
511        log_msg(1, "mount failed");
512    } else {
513        log_msg(1, "mount succeeded with %s", dev);
514    }
515    paranoid_free(dev);
516    return (res);
517}
518
519
520
521
522
523
524/**
525 * Locate a CD-R/W writer's SCSI node.
526 * @param cdrw_device SCSI node will be placed here.
527 * @return 0 for success, nonzero for failure.
528 */
529int find_cdrw_device(char *cdrw_device)
530{
531    /*@ buffers ************************ */
532    char *comment;
533    char *tmp = NULL;
534    char *cdr_exe = NULL;
535    char *command;
536
537    malloc_string(comment);
538    malloc_string(command);
539    if (g_cdrw_drive_is_here[0]) {
540        strcpy(cdrw_device, g_cdrw_drive_is_here);
541        log_msg(3, "Been there, done that. Returning %s", cdrw_device);
542        paranoid_free(comment);
543        paranoid_free(command);
544        return (0);
545    }
546    if (g_backup_media_type == dvd) {
547        log_msg(1,
548                "This is dumb. You're calling find_cdrw_device() but you're backing up to DVD. WTF?");
549        paranoid_free(comment);
550        paranoid_free(command);
551        return (1);
552    }
553    run_program_and_log_output("insmod ide-scsi", -1);
554    if (find_home_of_exe("cdrecord")) {
555        mr_asprintf(&cdr_exe, "cdrecord");
556    } else {
557        mr_asprintf(&cdr_exe, "dvdrecord");
558    }
559    if (find_home_of_exe(cdr_exe)) {
560        sprintf(command,
561                "%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",
562                cdr_exe);
563        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
564    }
565    if ((tmp == NULL) || (strlen(tmp) < 2)) {
566        paranoid_free(comment);
567        mr_free(tmp);
568        mr_free(cdr_exe);
569        paranoid_free(command);
570        return 1;
571    } else {
572        strcpy(cdrw_device, tmp);
573        sprintf(comment, "Found CDRW device - %s", cdrw_device);
574        log_it(comment);
575        strcpy(g_cdrw_drive_is_here, cdrw_device);
576        paranoid_free(comment);
577        mr_free(tmp);
578        mr_free(cdr_exe);
579        paranoid_free(command);
580        return (0);
581    }
582}
583
584
585
586
587/**
588 * Attempt to locate a CD-ROM device's /dev entry.
589 * Several different methods may be used to find the device, including
590 * calling @c cdrecord, searching @c dmesg, and trial-and-error.
591 * @param output Where to put the located /dev entry.
592 * @param try_to_mount Whether to mount the CD as part of the test; if mount
593 * fails then return failure.
594 * @return 0 for success, nonzero for failure.
595 */
596int find_cdrom_device(char *output, bool try_to_mount)
597{
598    /*@ pointers **************************************************** */
599    FILE *fin;
600    char *p;
601    char *q;
602    char *r;
603    int retval = 0;
604
605    /*@ bool's ****************************************************** */
606    bool found_it = FALSE;
607
608    /*@ buffers ***************************************************** */
609    char *tmp;
610    char *tmp1 = NULL;
611    char *cdr_exe = NULL;
612    char *phrase_one;
613    char *phrase_two;
614    char *command;
615    char *dvd_last_resort;
616    char *mountpoint;
617    static char the_last_place_i_found_it[MAX_STR_LEN] = "";
618
619    /*@ intialize *************************************************** */
620    malloc_string(tmp);
621    malloc_string(phrase_one);
622    malloc_string(phrase_two);
623    malloc_string(command);
624    malloc_string(dvd_last_resort);
625    malloc_string(mountpoint);
626
627    output[0] = '\0';
628    phrase_one[0] = '\0';
629    phrase_two[0] = '\0';
630    dvd_last_resort[0] = '\0';
631
632    /*@ end vars **************************************************** */
633
634    if (g_cdrom_drive_is_here[0] && !isdigit(g_cdrom_drive_is_here[0])) {
635        strcpy(output, g_cdrom_drive_is_here);
636        log_msg(3, "Been there, done that. Returning %s", output);
637        retval = 0;
638        goto end_of_find_cdrom_device;
639    }
640    if (the_last_place_i_found_it[0] != '\0' && !try_to_mount) {
641        strcpy(output, the_last_place_i_found_it);
642        log_msg(3,
643                "find_cdrom_device() --- returning last found location - '%s'",
644                output);
645        retval = 0;
646        goto end_of_find_cdrom_device;
647    }
648
649    sprintf(mountpoint, "%s/cd.mnt", bkpinfo->tmpdir);
650    make_hole_for_dir(mountpoint);
651
652    if (find_home_of_exe("cdrecord")) {
653        mr_asprintf(&cdr_exe, "cdrecord");
654    } else {
655        mr_asprintf(&cdr_exe, "dvdrecord");
656    }
657    tmp[0] = '\0';
658    if (!find_home_of_exe(cdr_exe)) {
659        strcpy(output, "/dev/cdrom");
660        log_msg(4, "Can't find cdrecord; assuming %s", output);
661        if (!does_device_exist(output)) {
662            log_msg(4, "That didn't work. Sorry.");
663            retval = 1;
664            goto end_of_find_cdrom_device;
665        } else {
666            retval = 0;
667            goto end_of_find_cdrom_device;
668        }
669    }
670
671    sprintf(command, "%s -scanbus 2> /dev/null", cdr_exe);
672    fin = popen(command, "r");
673    if (!fin) {
674        log_msg(4, "command=%s", command);
675        log_OS_error("Cannot popen command");
676        mr_free(cdr_exe);
677        return (1);
678    }
679    for ((void)fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
680         (void)fgets(tmp, MAX_STR_LEN, fin)) {
681        p = strchr(tmp, '\'');
682        if (p) {
683            q = strchr(++p, '\'');
684            if (q) {
685                for (r = q; *(r - 1) == ' '; r--);
686                *r = '\0';
687                strcpy(phrase_one, p);
688                p = strchr(++q, '\'');
689                if (p) {
690                    q = strchr(++p, '\'');
691                    if (q) {
692                        while (*(q - 1) == ' ') {
693                            q--;
694                        }
695                        *q = '\0';
696                        strcpy(phrase_two, p);
697                    }
698                }
699            }
700        }
701    }
702    paranoid_pclose(fin);
703
704#ifndef __FreeBSD__
705    if (strlen(phrase_two) == 0) {
706        log_msg(4, "Not running phase two. String is empty.");
707    } else {
708        sprintf(command, "dmesg | grep \"%s\" 2> /dev/null", phrase_two);
709        fin = popen(command, "r");
710        if (!fin) {
711            log_msg(4, "Cannot run 2nd command - non-fatal, fortunately");
712        } else {
713            for ((void)fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
714                 (void)fgets(tmp, MAX_STR_LEN, fin)) {
715                log_msg(5, "--> '%s'", tmp);
716                if (tmp[0] != ' ' && tmp[1] != ' ') {
717                    p = strchr(tmp, ':');
718                    if (p) {
719                        *p = '\0';
720                        if (strstr(tmp, "DVD")) {
721                            sprintf(dvd_last_resort, "/dev/%s", tmp);
722                            log_msg(4,
723                                    "Ignoring '%s' because it's a DVD drive",
724                                    tmp);
725                        } else {
726                            sprintf(output, "/dev/%s", tmp);
727                            found_it = TRUE;
728                        }
729                    }
730                }
731            }
732            paranoid_pclose(fin);
733        }
734    }
735
736#endif
737#ifdef __FreeBSD__
738    if (!found_it) {
739        log_msg(4, "OK, approach 2");
740        if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) {
741            if (!
742                (found_it =
743                 set_dev_to_this_if_rx_OK(output, "/dev/cdrom1"))) {
744                if (!
745                    (found_it =
746                     set_dev_to_this_if_rx_OK(output, "/dev/dvd"))) {
747                    if (!
748                        (found_it =
749                         set_dev_to_this_if_rx_OK(output, "/dev/acd0"))) {
750                        if (!
751                            (found_it =
752                             set_dev_to_this_if_rx_OK(output,
753                                                      "/dev/cd01"))) {
754                            if (!
755                                (found_it =
756                                 set_dev_to_this_if_rx_OK(output,
757                                                          "/dev/acd1"))) {
758                                if (!
759                                    (found_it =
760                                     set_dev_to_this_if_rx_OK(output,
761                                                              "/dev/cd1")))
762                                {
763                                    retval = 1;
764                                    goto end_of_find_cdrom_device;
765                                }
766                            }
767                        }
768                    }
769                }
770            }
771        }
772    }
773#else
774    if (!found_it && strlen(dvd_last_resort) > 0) {
775        log_msg(4, "Well, I'll use the DVD - %s - as a last resort",
776                dvd_last_resort);
777        strcpy(output, dvd_last_resort);
778        found_it = TRUE;
779    }
780    if (found_it) {
781        sprintf(tmp, "grep \"%s=ide-scsi\" /proc/cmdline &> /dev/null",
782                strrchr(output, '/') + 1);
783        if (system(tmp) == 0) {
784            log_msg(4,
785                    "%s is not right. It's being SCSI-emulated. Continuing.",
786                    output);
787            found_it = FALSE;
788            output[0] = '\0';
789        }
790    }
791
792    if (found_it) {
793        log_msg(4, "(find_cdrom_device) --> '%s'", output);
794        if (!does_device_exist(output)) {
795            found_it = FALSE;
796            log_msg(4, "OK, I was wrong, I haven't found it... yet.");
797        }
798    }
799
800    if (!found_it) {
801        log_msg(4, "OK, approach 2");
802        if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/scd0"))) {
803            if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/sr0"))) {
804                if (!
805                    (found_it =
806                     set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) {
807                    if (!
808                        (found_it =
809                         set_dev_to_this_if_rx_OK(output,
810                                                  "/dev/cdrom0"))) {
811                        if (!
812                            (found_it =
813                             set_dev_to_this_if_rx_OK(output,
814                                                      "/dev/cdrom1"))) {
815                            if (!
816                                (found_it =
817                                 set_dev_to_this_if_rx_OK(output,
818                                                          "/dev/sr1"))) {
819                                if (!
820                                    (found_it =
821                                     set_dev_to_this_if_rx_OK(output,
822                                                              "/dev/dvd")))
823                                {
824                                    if (!
825                                        (found_it =
826                                         set_dev_to_this_if_rx_OK(output,
827                                                                  g_cdrw_drive_is_here)))
828                                    {
829                                        retval = 1;
830                                        goto end_of_find_cdrom_device;
831                                    }
832                                }
833                            }
834                        }
835                    }
836                }
837            }
838        }
839    }
840#endif
841
842    if (found_it && try_to_mount) {
843        if (mount_CDROM_here(output, mountpoint)) {
844            log_msg(4, "[Cardigans] I've changed my mind");
845            found_it = FALSE;
846        } else {
847            sprintf(tmp, "%s/archives", mountpoint);
848            if (!does_file_exist(tmp)) {
849                log_msg(4, "[Cardigans] I'll take it back");
850                found_it = FALSE;
851            } else {
852                sprintf(command, "umount %s", output);
853                paranoid_system(command);
854                log_msg(4, "I'm confident the Mondo CD is in %s", output);
855            }
856        }
857    }
858    unlink(mountpoint);
859
860    if (found_it) {
861        if (!does_file_exist(output)) {
862            log_msg(3, "I still haven't found it.");
863            return (1);
864        }
865        log_msg(3, "(find_cdrom_device) --> '%s'", output);
866        strcpy(the_last_place_i_found_it, output);
867        strcpy(g_cdrom_drive_is_here, output);
868        retval = 0;
869        goto end_of_find_cdrom_device;
870    }
871
872    sprintf(command,
873            "%s -scanbus | grep \"[0-9],[0-9],[0-9]\" | grep -E \"[D|C][V|D]\" | grep -n \"\" | grep \"%s\" | cut -d':' -f2",
874            cdr_exe, g_cdrw_drive_is_here);
875    log_msg(1, "command=%s", command);
876    mr_asprintf(&tmp1, "%s", call_program_and_get_last_line_of_output(command));
877    if (strlen(tmp1) > 0) {
878        strcpy(output, tmp1);
879        log_msg(4, "Finally found it at %s", output);
880        retval = 0;
881    } else {
882        log_msg(4, "Still couldn't find it.");
883        retval = 1;
884    }
885    mr_free(tmp1);
886
887  end_of_find_cdrom_device:
888    paranoid_free(tmp);
889    mr_free(cdr_exe);
890    paranoid_free(phrase_one);
891    paranoid_free(phrase_two);
892    paranoid_free(command);
893    paranoid_free(dvd_last_resort);
894    paranoid_free(mountpoint);
895    return (retval);
896}
897
898
899
900
901
902int find_dvd_device(char *output, bool try_to_mount)
903{
904    char *command;
905    char *tmp;
906    int retval = 0, devno = -1;
907
908    malloc_string(command);
909    malloc_string(tmp);
910
911    if (g_dvd_drive_is_here[0]) {
912        strcpy(output, g_dvd_drive_is_here);
913        log_msg(3, "Been there, done that. Returning %s", output);
914        return (0);
915    }
916
917    sprintf(tmp, "%s", call_program_and_get_last_line_of_output
918            ("dvdrecord -scanbus 2> /dev/null | grep \)\ \' | grep -n '' | grep -E '[D|C][V|D]' | cut -d':' -f1")
919        );
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, cylindersleft = 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                    cylindersleft = cylinders = hdgeo.cylinders;
1011                    cylindersize = hdgeo.heads * hdgeo.sectors / 2;
1012                    outvalA = cylindersize * cylinders / 1024;
1013                    log_msg(2, "Got Harddisk geometry, C:%d, H:%d, S:%d",
1014                            hdgeo.cylinders, hdgeo.heads, hdgeo.sectors);
1015                    gotgeo = 1;
1016                } else {
1017                    log_msg(1, "Harddisk geometry wrong");
1018                }
1019            } else {
1020                log_msg(1,
1021                        "Error in ioctl() getting new hard disk geometry (%s), resizing in unsafe mode",
1022                        strerror(errno));
1023            }
1024            close(fileid);
1025        } else {
1026            log_msg(1, "Failed to open %s for reading: %s", drive,
1027                    strerror(errno));
1028        }
1029        if (!gotgeo) {
1030            log_msg(1, "Failed to get harddisk geometry, using old mode");
1031        }
1032#endif
1033    }
1034// OLDER DISKS will give ridiculously low value for outvalB (so outvalA is returned) :)
1035// NEWER DISKS will give sane value for outvalB (close to outvalA, in other words) :)
1036
1037    outvalC = (outvalA > outvalB) ? outvalA : outvalB;
1038
1039//  log_msg (5, "drive = %s, error = %s", drive, strerror (errno));
1040//  fatal_error ("GPSOD: Unable to get size of drive");
1041    log_msg(1, "%s --> %ld or %ld --> %ld", drive, outvalA, outvalB,
1042            outvalC);
1043
1044    return (outvalC);
1045}
1046
1047/**
1048 * Determine whether @p format is supported by the kernel. Uses /proc/filesystems
1049 * under Linux and @c lsvfs under FreeBSD.
1050 * @param format The format to test.
1051 * @return TRUE if the format is supported, FALSE if not.
1052 */
1053bool is_this_a_valid_disk_format(char *format)
1054{
1055    char *good_formats = NULL;
1056    char *command;
1057    char *format_sz;
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        (void) fgets(good_formats + 1, MAX_STR_LEN - 1, pin);
1084        if (pclose(pin)) {
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 ((void)fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
1156         (void)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 | grep '%s:' 2> /dev/null", partitions[i], 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 *tmp1 = NULL;
2178    char *mds = NULL;
2179    char *q = NULL;
2180    char p[8*MAX_STR_LEN];
2181    char *sz_size;
2182    char *command;
2183    char *compression_type = NULL;
2184    char *comment;
2185    char *prompt;
2186    int i;
2187    FILE *fin;
2188
2189    malloc_string(sz_size);
2190    malloc_string(command);
2191    malloc_string(comment);
2192    malloc_string(prompt);
2193    malloc_string(tmp1);
2194    assert(bkpinfo != NULL);
2195    sz_size[0] = '\0';
2196    bkpinfo->nonbootable_backup = FALSE;
2197
2198    // Tape, CD, NETFS, ...?
2199    srandom(getpid());
2200    bkpinfo->backup_media_type =
2201        (g_restoring_live_from_cd) ? cdr :
2202        which_backup_media_type(bkpinfo->restore_data);
2203    if (bkpinfo->backup_media_type == none) {
2204        log_to_screen("User has chosen not to backup the PC");
2205        finish(1);
2206    }
2207    /* Why asking to remove the media with tape ?
2208    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
2209        popup_and_OK("Please remove media from drive(s)");
2210    }
2211    */
2212    log_msg(3, "media type = %s",
2213            bkptype_to_string(bkpinfo->backup_media_type));
2214    if (archiving_to_media) {
2215        sensibly_set_tmpdir_and_scratchdir();
2216    }
2217    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
2218    bkpinfo->compression_level =
2219        (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
2220    bkpinfo->use_lzo =
2221        (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
2222    mvaddstr_and_log_it(2, 0, " ");
2223
2224    // Find device's /dev (or SCSI) entry
2225    switch (bkpinfo->backup_media_type) {
2226    case cdr:
2227    case cdrw:
2228    case dvd:
2229    case usb:
2230        /* Never try to eject a USB device */
2231        if (bkpinfo->backup_media_type == usb) {
2232            bkpinfo->please_dont_eject = TRUE;
2233        }
2234        if (archiving_to_media) {
2235            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2236                if (ask_me_yes_or_no
2237                    ("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?"))
2238                {
2239                    bkpinfo->manual_cd_tray = TRUE;
2240                }
2241            }
2242            if ((compression_type = which_compression_type()) == NULL) {
2243                log_to_screen("User has chosen not to backup the PC");
2244                finish(1);
2245            }
2246            if ((bkpinfo->compression_level =
2247                 which_compression_level()) == -1) {
2248                log_to_screen("User has chosen not to backup the PC");
2249                finish(1);
2250            }
2251            mds = media_descriptor_string(bkpinfo->backup_media_type);
2252            sprintf(comment, "What speed is your %s (re)writer?", mds);
2253            if (bkpinfo->backup_media_type == dvd) {
2254                find_dvd_device(bkpinfo->media_device, FALSE);
2255                strcpy(tmp1, "1");
2256                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2257                log_msg(1, "Setting to DVD defaults");
2258            } else {
2259                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
2260                strcpy(tmp1, "4");
2261                strcpy(sz_size, "650");
2262                log_msg(1, "Setting to CD defaults");
2263            }
2264            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2265                if (!popup_and_get_string("Speed", comment, tmp1, 4)) {
2266                    log_to_screen("User has chosen not to backup the PC");
2267                    finish(1);
2268                }
2269            }
2270            bkpinfo->cdrw_speed = atoi(tmp1);   // if DVD then this shouldn't ever be used anyway :)
2271
2272            sprintf(comment,
2273                    "How much data (in Megabytes) will each %s store?", mds);
2274            mr_free(mds);
2275            if (!popup_and_get_string("Size", comment, sz_size, 5)) {
2276                log_to_screen("User has chosen not to backup the PC");
2277                finish(1);
2278            }
2279            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2280                bkpinfo->media_size[i] = atoi(sz_size);
2281            }
2282            if (bkpinfo->media_size[0] <= 0) {
2283                log_to_screen("User has chosen not to backup the PC");
2284                finish(1);
2285            }
2286        }
2287        /* No break because we continue even for usb */
2288    case cdstream:
2289        mds = media_descriptor_string(bkpinfo->backup_media_type);
2290
2291        if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
2292            strcpy(bkpinfo->media_device, "/dev/cdrom");
2293            log_msg(2, "CD-ROM device assumed to be at %s",
2294                    bkpinfo->media_device);
2295        } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))
2296                   || bkpinfo->backup_media_type == dvd) {
2297            if (!bkpinfo->media_device[0]) {
2298                strcpy(bkpinfo->media_device, "/dev/cdrom");
2299            }                   // just for the heck of it :)
2300            log_msg(1, "bkpinfo->media_device = %s",
2301                    bkpinfo->media_device);
2302            if (bkpinfo->backup_media_type == dvd
2303                || find_cdrom_device(bkpinfo->media_device, FALSE)) {
2304                log_msg(1, "bkpinfo->media_device = %s",
2305                        bkpinfo->media_device);
2306                sprintf(comment,
2307                        "Please specify your %s drive's /dev entry", mds);
2308                if (!popup_and_get_string
2309                    ("Device?", comment, bkpinfo->media_device,
2310                     MAX_STR_LEN / 4)) {
2311                    log_to_screen("User has chosen not to backup the PC");
2312                    finish(1);
2313                }
2314            }
2315            log_msg(2, "%s device found at %s", mds, bkpinfo->media_device);
2316        } else {
2317            if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) {
2318                bkpinfo->media_device[0] = '\0';
2319            }
2320            if (bkpinfo->media_device[0]) {
2321                if (bkpinfo->backup_media_type == usb) {
2322                    mr_asprintf(&tmp, "I think your %s media corresponds to %s. Is this correct?", mds, bkpinfo->media_device);
2323                } else {
2324                    mr_asprintf(&tmp, "I think I've found your %s burner at SCSI node %s. Is this correct? (Say no if you have an IDE burner and you are running a 2.6 kernel. You will then be prompted for further details.)", mds, bkpinfo->media_device);
2325                }
2326                if (!ask_me_yes_or_no(tmp)) {
2327                    bkpinfo->media_device[0] = '\0';
2328                }
2329                mr_free(tmp);
2330            }
2331            if (!bkpinfo->media_device[0]) {
2332                if (bkpinfo->backup_media_type == usb) {
2333                    i = popup_and_get_string("/dev entry?",
2334                                         "What is the /dev entry of your USB Disk/Key, please?",
2335                                         bkpinfo->media_device,
2336                                         MAX_STR_LEN / 4);
2337                } else {
2338                    if (g_kernel_version < 2.6) {
2339                        i = popup_and_get_string("Device node?",
2340                                             "What is the SCSI node of your CD (re)writer, please?",
2341                                             bkpinfo->media_device,
2342                                             MAX_STR_LEN / 4);
2343                    } else {
2344                        i = popup_and_get_string("/dev entry?",
2345                                             "What is the /dev entry of your CD (re)writer, please?",
2346                                             bkpinfo->media_device,
2347                                             MAX_STR_LEN / 4);
2348                    }
2349                }
2350                if (!i) {
2351                    log_to_screen("User has chosen not to backup the PC");
2352                    finish(1);
2353                }
2354            }
2355        }
2356        mr_free(mds);
2357
2358        if (bkpinfo->backup_media_type == cdstream) {
2359            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2360                bkpinfo->media_size[i] = 650;
2361            }
2362        }
2363        break;
2364    case udev:
2365        if (!ask_me_yes_or_no
2366            ("This option is for advanced users only. Are you sure?")) {
2367            log_to_screen("User has chosen not to backup the PC");
2368            finish(1);
2369        }
2370    case tape:
2371
2372        if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) {
2373            log_msg(3, "Ok, using vanilla scsi tape.");
2374            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
2375            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2376                paranoid_fclose(fin);
2377            } else {
2378                strcpy(bkpinfo->media_device, "/dev/osst0");
2379            }
2380        }
2381        if (bkpinfo->media_device[0]) {
2382            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2383                paranoid_fclose(fin);
2384            } else {
2385                if (does_file_exist("/tmp/mondo-restore.cfg")) {
2386                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
2387                                 bkpinfo->media_device);
2388                }
2389            }
2390        }
2391        if (bkpinfo->media_device[0]) {
2392            mr_asprintf(&tmp, "I think I've found your tape streamer at %s; am I right on the money?", bkpinfo->media_device);
2393            if (!ask_me_yes_or_no(tmp)) {
2394                bkpinfo->media_device[0] = '\0';
2395            }
2396            mr_free(tmp);
2397        }
2398        if (!bkpinfo->media_device[0]) {
2399            if (!popup_and_get_string
2400                ("Device name?",
2401                 "What is the /dev entry of your tape streamer?",
2402                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
2403                log_to_screen("User has chosen not to backup the PC");
2404                finish(1);
2405            }
2406        }
2407        mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
2408        if (run_program_and_log_output(tmp, FALSE)) {
2409            log_to_screen("User has not specified a valid /dev entry");
2410            finish(1);
2411        }
2412        mr_free(tmp);
2413        log_msg(4, "sz_size = %s", sz_size);
2414        sz_size[0] = '\0';
2415
2416        bkpinfo->use_obdr = ask_me_yes_or_no
2417            ("Do you want to activate OBDR support for your tapes ?");
2418        if (sz_size[0] == '\0') {
2419            bkpinfo->media_size[0] = 0;
2420        } else {
2421            bkpinfo->media_size[0] =
2422                friendly_sizestr_to_sizelong(sz_size) / 2 - 50;
2423        }
2424        log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
2425        if (bkpinfo->media_size[0] <= 0) {
2426            bkpinfo->media_size[0] = 0;
2427        }
2428        for (i = 1; i <= MAX_NOOF_MEDIA; i++) {
2429            bkpinfo->media_size[i] = bkpinfo->media_size[0];
2430        }
2431        if (archiving_to_media) {
2432            if ((compression_type = which_compression_type()) == NULL) {
2433                log_to_screen("User has chosen not to backup the PC");
2434                finish(1);
2435            }
2436            if ((bkpinfo->compression_level =
2437                 which_compression_level()) == -1) {
2438                log_to_screen("User has chosen not to backup the PC");
2439                finish(1);
2440            }
2441        }
2442        break;
2443
2444
2445
2446    case netfs:
2447        /* Never try to eject a NETFS device */
2448        bkpinfo->please_dont_eject = TRUE;
2449
2450        /* Initiate bkpinfo netfs_mount path from running environment if not already done */
2451        if (!bkpinfo->netfs_mount[0]) {
2452            strcpy(bkpinfo->netfs_mount,
2453                   call_program_and_get_last_line_of_output
2454                   ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
2455        }
2456#ifdef __FreeBSD__
2457        if (TRUE)
2458#else
2459        if (!bkpinfo->disaster_recovery)
2460#endif
2461        {
2462            if (!popup_and_get_string
2463                ("Network shared dir.",
2464                 "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.)",
2465                 bkpinfo->netfs_mount, MAX_STR_LEN / 4)) {
2466                log_to_screen("User has chosen not to backup the PC");
2467                finish(1);
2468            }
2469            if (!bkpinfo->restore_data) {
2470                if ((compression_type = which_compression_type()) == NULL) {
2471                    log_to_screen("User has chosen not to backup the PC");
2472                    finish(1);
2473                }
2474                if ((bkpinfo->compression_level =
2475                     which_compression_level()) == -1) {
2476                    log_to_screen("User has chosen not to backup the PC");
2477                    finish(1);
2478                }
2479            }
2480            // check whether already mounted - we better remove
2481            // surrounding spaces and trailing '/' for this
2482            strip_spaces(bkpinfo->netfs_mount);
2483            if (bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] == '/')
2484                bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] = '\0';
2485            q = strchr(bkpinfo->netfs_mount, '@');
2486            if (q != NULL) {
2487                /* User found. Store the 2 values */
2488                q++;
2489                /* new netfs mount */
2490                strcpy(tmp,q);
2491            } else {
2492                strcpy(tmp,bkpinfo->netfs_mount);
2493            }
2494            sprintf(command, "mount | grep \"%s \" | cut -d' ' -f3",
2495                    tmp);
2496            strcpy(bkpinfo->isodir,
2497                   call_program_and_get_last_line_of_output(command));
2498
2499            if (!bkpinfo->restore_data) {
2500                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2501                sprintf(comment,
2502                    "How much data (in Megabytes) will each media store?");
2503                if (!popup_and_get_string("Size", comment, sz_size, 5)) {
2504                    log_to_screen("User has chosen not to backup the PC");
2505                    finish(1);
2506                }
2507            } else {
2508                strcpy(sz_size, "0");
2509            }
2510            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2511                bkpinfo->media_size[i] = atoi(sz_size);
2512            }
2513            if (bkpinfo->media_size[0] < 0) {
2514                log_to_screen("User has chosen not to backup the PC");
2515                finish(1);
2516            }
2517        }
2518        /*  Force NFS to be the protocol by default */
2519        if (bkpinfo->netfs_proto == NULL) {
2520            mr_asprintf(&(bkpinfo->netfs_proto), "nfs");
2521        }
2522        if (bkpinfo->disaster_recovery) {
2523            sprintf(command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
2524            (void)system(command);
2525        }
2526        strcpy(tmp1, bkpinfo->netfs_proto);
2527        if (!popup_and_get_string
2528            ("Network protocol", "Which protocol should I use (nfs/sshfs) ?",
2529             tmp1, MAX_STR_LEN)) {
2530            log_to_screen("User has chosen not to backup the PC");
2531            finish(1);
2532        }
2533        mr_free(bkpinfo->netfs_proto);
2534        mr_asprintf(&(bkpinfo->netfs_proto), "%s", tmp1);
2535        if (!popup_and_get_string
2536            ("Network share", "Which remote share should I mount?",
2537             bkpinfo->netfs_mount, MAX_STR_LEN)) {
2538            log_to_screen("User has chosen not to backup the PC");
2539            finish(1);
2540        }
2541
2542        if (bkpinfo->netfs_user) {
2543            strcpy(tmp1, bkpinfo->netfs_user);
2544        } else {
2545            strcpy(tmp1, "");
2546        }
2547        if (!popup_and_get_string
2548            ("Network user", "Which user should I use if any ?",
2549             tmp1, MAX_STR_LEN)) {
2550            log_to_screen("User has chosen not to backup the PC");
2551            finish(1);
2552        }
2553        mr_free(bkpinfo->netfs_user);
2554        if (strcmp(tmp1, "") != 0) {
2555            mr_asprintf(&(bkpinfo->netfs_user), "%s", tmp1);
2556        }
2557   
2558        /* Initiate bkpinfo isodir path from running environment if mount already done */
2559        if (is_this_device_mounted(bkpinfo->netfs_mount)) {
2560            strcpy(bkpinfo->isodir,
2561                   call_program_and_get_last_line_of_output
2562                   ("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
2563        } else {
2564            sprintf(bkpinfo->isodir, "%s/netfsdir", bkpinfo->tmpdir);
2565            sprintf(command, "mkdir -p %s", bkpinfo->isodir);
2566            run_program_and_log_output(command, 5);
2567            if (bkpinfo->restore_data) {
2568                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2569                    mr_asprintf(&tmp, "sshfs -o ro");
2570                } else {
2571                    mr_asprintf(&tmp, "mount -t %s -o nolock,ro", bkpinfo->netfs_proto);
2572                }
2573            } else {
2574                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2575                    mr_asprintf(&tmp, "sshfs");
2576                } else {
2577                    mr_asprintf(&tmp, "mount -t %s -o nolock", bkpinfo->netfs_proto);
2578                }
2579            }
2580            if (bkpinfo->netfs_user) {
2581                mr_strcat(tmp, "%s@", bkpinfo->netfs_user);
2582            }
2583            mr_strcat(tmp, "%s %s", bkpinfo->netfs_mount, bkpinfo->isodir);
2584            run_program_and_log_output(tmp, 3);
2585            mr_free(tmp);
2586
2587            malloc_string(g_selfmounted_isodir);
2588            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
2589        }
2590        if (!is_this_device_mounted(bkpinfo->netfs_mount)) {
2591            popup_and_OK
2592                ("Please mount that partition before you try to backup to or restore from it.");
2593            finish(1);
2594        }
2595        strcpy(tmp1, bkpinfo->netfs_remote_dir);
2596        if (!popup_and_get_string
2597            ("Directory", "Which directory within that mountpoint?", tmp1,
2598             MAX_STR_LEN)) {
2599            log_to_screen("User has chosen not to backup the PC");
2600            finish(1);
2601        }
2602        strcpy(bkpinfo->netfs_remote_dir, tmp1);
2603
2604        // check whether writable - we better remove surrounding spaces for this
2605        strip_spaces(bkpinfo->netfs_remote_dir);
2606
2607        if (!popup_and_get_string
2608            ("Prefix.",
2609             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2610            bkpinfo->prefix, MAX_STR_LEN / 4)) {
2611            log_to_screen("User has chosen not to backup the PC");
2612            finish(1);
2613        }
2614        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2615
2616        log_msg(3, "Just set netfs_remote_dir to %s",
2617                bkpinfo->netfs_remote_dir);
2618        log_msg(3, "isodir is still %s", bkpinfo->isodir);
2619        break;
2620
2621    case iso:
2622        if (!bkpinfo->disaster_recovery) {
2623            if (!popup_and_get_string
2624                ("Storage dir.",
2625                 "Please enter the full path name to the directory for your ISO images.  Example: /mnt/raid0_0",
2626                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
2627                log_to_screen("User has chosen not to backup the PC");
2628                finish(1);
2629            }
2630            if (archiving_to_media) {
2631                if ((compression_type = which_compression_type()) == NULL) {
2632                    log_to_screen("User has chosen not to backup the PC");
2633                    finish(1);
2634                }
2635                if ((bkpinfo->compression_level =
2636                     which_compression_level()) == -1) {
2637                    log_to_screen("User has chosen not to backup the PC");
2638                    finish(1);
2639                }
2640                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2641                if (!popup_and_get_string
2642                    ("ISO size.",
2643                     "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.",
2644                     sz_size, 16)) {
2645                    log_to_screen("User has chosen not to backup the PC");
2646                    finish(1);
2647                }
2648                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2649                    bkpinfo->media_size[i] = atoi(sz_size);
2650                }
2651            } else {
2652                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2653                    bkpinfo->media_size[i] = 650;
2654                }
2655            }
2656        }
2657        if (!popup_and_get_string
2658            ("Prefix.",
2659             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2660             bkpinfo->prefix, MAX_STR_LEN / 4)) {
2661            log_to_screen("User has chosen not to backup the PC");
2662            finish(1);
2663        }
2664        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2665        break;
2666    default:
2667        fatal_error
2668            ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
2669    }
2670
2671    if (archiving_to_media) {
2672
2673#ifdef __FreeBSD__
2674        strcpy(bkpinfo->boot_device,
2675               call_program_and_get_last_line_of_output
2676               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
2677#else
2678        strcpy(bkpinfo->boot_device,
2679               call_program_and_get_last_line_of_output
2680               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
2681#endif
2682        i = which_boot_loader(bkpinfo->boot_device);
2683        if (i == 'U')           // unknown
2684        {
2685
2686#ifdef __FreeBSD__
2687            if (!popup_and_get_string
2688                ("Boot device",
2689                 "What is your boot device? (e.g. /dev/ad0)",
2690                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2691                log_to_screen("User has chosen not to backup the PC");
2692                finish(1);
2693            }
2694            i = which_boot_loader(bkpinfo->boot_device);
2695#else
2696            if (!popup_and_get_string
2697                ("Boot device",
2698                 "What is your boot device? (e.g. /dev/hda)",
2699                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2700                log_to_screen("User has chosen not to backup the PC");
2701                finish(1);
2702            }
2703            if (does_string_exist_in_boot_block
2704                (bkpinfo->boot_device, "LILO")) {
2705                i = 'L';
2706            } else
2707                if (does_string_exist_in_boot_block
2708                    (bkpinfo->boot_device, "ELILO")) {
2709                i = 'E';
2710            } else
2711                if (does_string_exist_in_boot_block
2712                    (bkpinfo->boot_device, "GRUB")) {
2713                i = 'G';
2714            } else {
2715                i = 'U';
2716            }
2717#endif
2718            if (i == 'U') {
2719                if (ask_me_yes_or_no
2720                    ("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?"))
2721                {
2722                    i = 'R';    // raw
2723                } else {
2724                    log_to_screen
2725                        ("I cannot find your boot loader. Please run mondoarchive with parameters.");
2726                    finish(1);
2727                }
2728            }
2729        }
2730        bkpinfo->boot_loader = i;
2731        strcpy(bkpinfo->include_paths, "/");
2732        if (!popup_and_get_string
2733            ("Backup paths",
2734             "Please enter paths (separated by '|') which you want me to backup. The default is '/' (i.e. everything).",
2735             bkpinfo->include_paths, MAX_STR_LEN)) {
2736            log_to_screen("User has chosen not to backup the PC");
2737            finish(1);
2738        }
2739        tmp = list_of_NETFS_mounts_only();
2740        if (strlen(tmp) > 2) {
2741            mr_strcat(bkpinfo->exclude_paths, "|%s",tmp);
2742        }
2743        mr_free(tmp);
2744// NTFS
2745        strcpy(tmp1, call_program_and_get_last_line_of_output("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
2746        if (strlen(tmp1) > 2) {
2747            if (!popup_and_get_string
2748                ("NTFS partitions",
2749                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
2750                 tmp1, MAX_STR_LEN / 4)) {
2751                log_to_screen("User has chosen not to backup the PC");
2752                finish(1);
2753            }
2754            strncpy(bkpinfo->image_devs, tmp1, MAX_STR_LEN / 4);
2755        }
2756
2757        if (bkpinfo->exclude_paths != NULL ) {
2758            strncpy(p,bkpinfo->exclude_paths,(8*MAX_STR_LEN)-1);
2759        } else {
2760            p[0] = '\0';
2761        }
2762        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, (8*MAX_STR_LEN)-1);
2763        if (p == NULL) {
2764            log_to_screen("User has chosen not to backup the PC");
2765            finish(1);
2766        }
2767        mr_free(bkpinfo->exclude_paths);
2768        mr_asprintf(&tmp, "%s", p);
2769        bkpinfo->exclude_paths = tmp;
2770
2771        if (!popup_and_get_string
2772            ("Temporary directory",
2773             "Please enter your temporary directory.",
2774             bkpinfo->tmpdir, (4*MAX_STR_LEN)-1)) {
2775            log_to_screen("User has chosen not to backup the PC");
2776            finish(1);
2777        }
2778        if (!popup_and_get_string
2779            ("Scratch directory",
2780             "Please enter your scratch directory.",
2781             bkpinfo->scratchdir, (4*MAX_STR_LEN)-1)) {
2782            log_to_screen("User has chosen not to backup the PC");
2783            finish(1);
2784        }
2785        if (ask_me_yes_or_no("Do you want to backup extended attributes?")) {
2786            if (find_home_of_exe("getfattr")) {
2787                mr_asprintf(&g_getfattr,"getfattr");
2788            }
2789            if (find_home_of_exe("getfacl")) {
2790                mr_asprintf(&g_getfacl,"getfacl");
2791            }
2792        }
2793// Interactive mode:
2794#ifdef __IA64__
2795        bkpinfo->make_cd_use_lilo = TRUE;
2796#else
2797        bkpinfo->make_cd_use_lilo = FALSE;
2798#endif
2799        bkpinfo->backup_data = TRUE;
2800        if (strcmp(compression_type,"lzo") == 0) {
2801            strcpy(bkpinfo->zip_exe, "lzop");
2802            strcpy(bkpinfo->zip_suffix, "lzo");
2803        } else if (strcmp(compression_type,"gzip") == 0) {
2804            strcpy(bkpinfo->zip_exe, "gzip");
2805            strcpy(bkpinfo->zip_suffix, "gz");
2806        //} else if (strcmp(compression_type,"lzma") == 0) {
2807            //strcpy(bkpinfo->zip_exe, "xy");
2808            //strcpy(bkpinfo->zip_suffix, "xy");
2809        } else if (strcmp(compression_type,"bzip2") == 0) {
2810            strcpy(bkpinfo->zip_exe, "bzip2");
2811            strcpy(bkpinfo->zip_suffix, "bz2");
2812        } else {
2813            bkpinfo->zip_exe[0] = bkpinfo->zip_suffix[0] = '\0';
2814        }
2815
2816        bkpinfo->verify_data =
2817            ask_me_yes_or_no
2818            ("Will you want to verify your backups after Mondo has created them?");
2819
2820#ifndef __FreeBSD__
2821        if (!ask_me_yes_or_no
2822            ("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."))
2823#endif
2824        {
2825            strcpy(bkpinfo->kernel_path, "FAILSAFE");
2826        }
2827
2828        if (!ask_me_yes_or_no
2829            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2830            log_to_screen("User has chosen not to backup the PC");
2831            finish(1);
2832        }
2833    } else {
2834        bkpinfo->restore_data = TRUE;   // probably...
2835    }
2836    mr_free(compression_type);
2837
2838    if (bkpinfo->backup_media_type == iso
2839        || bkpinfo->backup_media_type == netfs) {
2840        g_ISO_restore_mode = TRUE;
2841    }
2842#ifdef __FreeSD__
2843// skip
2844#else
2845    if (bkpinfo->backup_media_type == netfs) {
2846        log_msg(3, "I think the Remote mount is mounted at %s",
2847                bkpinfo->isodir);
2848    }
2849    log_it("isodir = %s", bkpinfo->isodir);
2850    log_it("netfs_mount = '%s'", bkpinfo->netfs_mount);
2851    if (bkpinfo->netfs_proto) {
2852        log_it("netfs_proto = '%s'", bkpinfo->netfs_proto);
2853    }
2854    if (bkpinfo->netfs_user) {
2855        log_it("netfs_user = '%s'", bkpinfo->netfs_user);
2856    }
2857#endif
2858
2859    log_it("media device = %s", bkpinfo->media_device);
2860    log_it("media size = %ld", bkpinfo->media_size[1]);
2861    log_it("media type = %s",
2862           bkptype_to_string(bkpinfo->backup_media_type));
2863    log_it("prefix = %s", bkpinfo->prefix);
2864    log_it("compression = %ld", bkpinfo->compression_level);
2865    log_it("exclude_path = %s", bkpinfo->exclude_paths);
2866    log_it("include_path = %s", bkpinfo->include_paths);
2867
2868    /* Handle devices passed in bkpinfo and print result */
2869    /*  the mr_make_devlist_from_pathlist function appends
2870     *  to the *_paths variables so copy before */
2871    mr_make_devlist_from_pathlist(bkpinfo->exclude_paths, 'E');
2872    mr_make_devlist_from_pathlist(bkpinfo->include_paths, 'I');
2873
2874    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2875    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2876    log_it("image_devs = '%s'", bkpinfo->image_devs);
2877    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
2878           bkpinfo->boot_loader);
2879    if (bkpinfo->media_size[0] < 0) {
2880        if (archiving_to_media) {
2881            fatal_error("Media size is less than zero.");
2882        } else {
2883            log_msg(2, "Warning - media size is less than zero.");
2884            bkpinfo->media_size[0] = 0;
2885        }
2886    }
2887    paranoid_free(sz_size);
2888    paranoid_free(tmp1);
2889    paranoid_free(command);
2890    paranoid_free(comment);
2891    paranoid_free(prompt);
2892    return (0);
2893}
2894
2895
2896/**
2897 * Get a |-separated list of NETFS mounts.
2898 * @return The list created.
2899 * @note The return value points to allocated string that needs to be freed
2900 * @bug Even though we only want the mounts, the devices are still checked.
2901 */
2902char *list_of_NETFS_mounts_only(void)
2903{
2904    char *exclude_these_directories = NULL;
2905
2906    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;}'"));
2907    log_msg(9,"list_of_NETFS_mounts_only returns %s\n",exclude_these_directories);
2908    return(exclude_these_directories);
2909}
2910
2911/* @} - end of utilityGroup */
2912
2913
2914
2915
2916
2917/**
2918 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2919 * [random] is a random number between 1 and 32767.
2920 * @param store_name_here Where to store the new filename.
2921 * @param stub A random number will be appended to this to make the FIFO's name.
2922 * @ingroup deviceGroup
2923 */
2924void make_fifo(char *store_name_here, char *stub)
2925{
2926    char *tmp;
2927
2928    malloc_string(tmp);
2929    assert_string_is_neither_NULL_nor_zerolength(stub);
2930
2931    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2932            (int) (random() % 32768));
2933    make_hole_for_file(store_name_here);
2934    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2935    sprintf(tmp, "chmod 770 %s", store_name_here);
2936    paranoid_system(tmp);
2937    paranoid_free(tmp);
2938}
2939
2940
2941
2942
2943
2944
2945/**
2946 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2947 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2948 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2949 * @ingroup utilityGroup
2950 */
2951void sensibly_set_tmpdir_and_scratchdir()
2952{
2953    char *tmp = NULL; 
2954    char *tmp1 = NULL; 
2955    char *command = NULL;
2956    char *sz = NULL;
2957
2958    assert(bkpinfo != NULL);
2959
2960#ifdef __FreeBSD__
2961    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"));
2962#else
2963    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"));
2964#endif
2965
2966    if (tmp[0] != '/') {
2967        mr_asprintf(&sz, "%s", tmp);
2968        paranoid_free(tmp);
2969        mr_asprintf(&tmp, "/%s", sz);
2970        mr_free(sz);
2971    }
2972    if (!tmp[0]) {
2973        fatal_error("I couldn't figure out the tempdir!");
2974    }
2975    setup_tmpdir(tmp);
2976    log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2977
2978    /* Before changing remove old ones if any */
2979    if (bkpinfo->scratchdir) {
2980        chdir("/tmp");
2981        mr_asprintf(&tmp1, "rm -Rf %s", bkpinfo->scratchdir);
2982        paranoid_system(tmp1);
2983        mr_free(tmp1);
2984    }
2985    sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp,
2986            (int) (random() % 32768));
2987    log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2988
2989    mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2990    paranoid_free(tmp);
2991
2992    paranoid_system(command);
2993    mr_free(command);
2994}
2995
2996
2997
2998
2999
3000
3001/**
3002 * @addtogroup deviceGroup
3003 * @{
3004 */
3005/**
3006 * If we can read @p dev, set @p output to it.
3007 * If @p dev cannot be read, set @p output to "".
3008 * @param dev The device to check for.
3009 * @param output Set to @p dev if @p dev exists, "" otherwise.
3010 * @return TRUE if @p dev exists, FALSE if it doesn't.
3011 */
3012bool set_dev_to_this_if_rx_OK(char *output, char *dev)
3013{
3014    char *command;
3015
3016    malloc_string(command);
3017    if (!dev || dev[0] == '\0') {
3018        output[0] = '\0';
3019        return (FALSE);
3020    }
3021//  assert_string_is_neither_NULL_nor_zerolength(dev);
3022    if (!bkpinfo->please_dont_eject) {
3023        log_msg(10, "Injecting %s", dev);
3024        inject_device(dev);
3025    }
3026    if (!does_file_exist(dev)) {
3027        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
3028        return (FALSE);
3029    }
3030    sprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
3031            512L, dev);
3032    if (!run_program_and_log_output(command, FALSE)
3033        && !run_program_and_log_output(command, FALSE)) {
3034        strcpy(output, dev);
3035        log_msg(4, "Found it - %s", dev);
3036        return (TRUE);
3037    } else {
3038        output[0] = '\0';
3039        log_msg(4, "It's not %s", dev);
3040        return (FALSE);
3041    }
3042}
3043
3044
3045
3046
3047
3048/**
3049 * Find out what number CD is in the drive.
3050 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
3051 * @return The current CD number, or -1 if it could not be found.
3052 * @note If the CD is not mounted, it will be mounted
3053 * (and remain mounted after this function returns).
3054 */
3055int what_number_cd_is_this()
3056{
3057    int cd_number = -1;
3058    char *mountdev = NULL;
3059    char *tmp = NULL;
3060
3061    assert(bkpinfo != NULL);
3062//  log_it("Asking what_number_cd_is_this");
3063    if (g_ISO_restore_mode) {
3064        mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
3065
3066        mr_asprintf(&mountdev, "%s%s", call_program_and_get_last_line_of_output(tmp), "/archives/THIS-CD-NUMBER");
3067        cd_number = atoi(last_line_of_file(mountdev));
3068        paranoid_free(mountdev);
3069        paranoid_free(tmp);
3070
3071        return (cd_number);
3072    }
3073
3074    mr_asprintf(&mountdev, "%s", bkpinfo->media_device);
3075    if (!mountdev[0]) {
3076        log_it
3077            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
3078        find_cdrom_device(bkpinfo->media_device, FALSE);
3079    }
3080    if (!is_this_device_mounted(MNT_CDROM)) {
3081        if (bkpinfo->backup_media_type == usb) {
3082            mount_USB_here(mountdev, MNT_CDROM);
3083        } else {
3084            mount_CDROM_here(mountdev, MNT_CDROM);
3085        }
3086    }
3087    paranoid_free(mountdev);
3088
3089    cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
3090    return (cd_number);
3091}
3092
3093
3094
3095
3096
3097
3098
3099/**
3100 * Find out what device is mounted as root (/).
3101 * @return Root device.
3102 * @note The returned string points to static storage and will be overwritten with every call.
3103 * @bug A bit of a misnomer; it's actually finding out the root device.
3104 * The mountpoint (where it's mounted) will obviously be '/'.
3105 */
3106char *where_is_root_mounted()
3107{
3108    /*@ buffers **************** */
3109    static char tmp[MAX_STR_LEN];
3110
3111
3112#ifdef __FreeBSD__
3113    strcpy(tmp, call_program_and_get_last_line_of_output
3114           ("mount | grep \" on / \" | cut -d' ' -f1"));
3115#else
3116    strcpy(tmp, call_program_and_get_last_line_of_output
3117           ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
3118    if (strstr(tmp, "/dev/cciss/")) {
3119        strcpy(tmp, call_program_and_get_last_line_of_output
3120               ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
3121    }
3122    if (strstr(tmp, "/dev/md")) {
3123        strcpy(tmp,
3124               call_program_and_get_last_line_of_output
3125               ("mount | grep \" on / \" | cut -d' ' -f1"));
3126    }
3127#endif
3128
3129    return (tmp);
3130}
3131
3132
3133/**
3134 * Find out which boot loader is in use.
3135 * @param which_device Device to look for the boot loader on.
3136 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
3137 * @note Under Linux, all drives are examined, not just @p which_device.
3138 */
3139#ifdef __FreeBSD__
3140char which_boot_loader(char *which_device)
3141{
3142    int count_lilos = 0;
3143    int count_grubs = 0;
3144    int count_boot0s = 0;
3145    int count_dangerouslydedicated = 0;
3146
3147    log_it("looking at drive %s's MBR", which_device);
3148    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
3149        count_grubs++;
3150    }
3151    if (does_string_exist_in_boot_block(which_device, "LILO")) {
3152        count_lilos++;
3153    }
3154    if (does_string_exist_in_boot_block(which_device, "Drive")) {
3155        count_boot0s++;
3156    }
3157    if (does_string_exist_in_first_N_blocks
3158        (which_device, "FreeBSD/i386", 17)) {
3159        count_dangerouslydedicated++;
3160    }
3161    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
3162           count_grubs, count_lilos, count_elilos, count_boot0s,
3163           count_dangerouslydedicated);
3164
3165    if (count_grubs && !count_lilos) {
3166        return ('G');
3167    } else if (count_lilos && !count_grubs) {
3168        return ('L');
3169    } else if (count_grubs == 1 && count_lilos == 1) {
3170        log_it("I'll bet you used to use LILO but switched to GRUB...");
3171        return ('G');
3172    } else if (count_boot0s == 1) {
3173        return ('B');
3174    } else if (count_dangerouslydedicated) {
3175        return ('D');
3176    } else {
3177        log_it("Unknown boot loader");
3178        return ('U');
3179    }
3180}
3181
3182#else
3183
3184char which_boot_loader(char *which_device)
3185{
3186    /*@ buffer ***************************************************** */
3187    char *list_drives_cmd = NULL;
3188    char *current_drive;
3189
3190    /*@ pointers *************************************************** */
3191    FILE *pdrives;
3192
3193    /*@ int ******************************************************** */
3194    int count_lilos = 0;
3195    int count_grubs = 0;
3196
3197    /*@ end vars *************************************************** */
3198
3199    malloc_string(current_drive);
3200
3201#ifdef __IA64__
3202    /* No choice for it */
3203    return ('E');
3204#endif
3205    assert(which_device != NULL);
3206
3207    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());
3208    log_it("list_drives_cmd = %s", list_drives_cmd);
3209
3210    if (!(pdrives = popen(list_drives_cmd, "r"))) {
3211        log_OS_error("Unable to open list of drives");
3212        mr_free(list_drives_cmd);
3213        paranoid_free(current_drive);
3214        return ('\0');
3215    }
3216    mr_free(list_drives_cmd);
3217
3218    for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
3219         (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
3220        strip_spaces(current_drive);
3221        log_it("looking at drive %s's MBR", current_drive);
3222        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3223            count_grubs++;
3224            strcpy(which_device, current_drive);
3225            break;
3226        }
3227        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3228            count_lilos++;
3229            strcpy(which_device, current_drive);
3230            break;
3231        }
3232    }
3233    if (pclose(pdrives)) {
3234        log_OS_error("Cannot pclose pdrives");
3235    }
3236    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3237    if (count_grubs && !count_lilos) {
3238        paranoid_free(current_drive);
3239        return ('G');
3240    } else if (count_lilos && !count_grubs) {
3241        paranoid_free(current_drive);
3242        return ('L');
3243    } else if (count_grubs == 1 && count_lilos == 1) {
3244        log_it("I'll bet you used to use LILO but switched to GRUB...");
3245        paranoid_free(current_drive);
3246        return ('G');
3247    } else {
3248        // We need to look on each partition then
3249        mr_asprintf(&list_drives_cmd, "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
3250        log_it("list_drives_cmd = %s", list_drives_cmd);
3251
3252        if (!(pdrives = popen(list_drives_cmd, "r"))) {
3253            log_OS_error("Unable to open list of drives");
3254            mr_free(list_drives_cmd);
3255            paranoid_free(current_drive);
3256            return ('\0');
3257        }
3258        mr_free(list_drives_cmd);
3259
3260        for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
3261            (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
3262            strip_spaces(current_drive);
3263            log_it("looking at partition %s's BR", current_drive);
3264            if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3265                count_grubs++;
3266                strcpy(which_device, current_drive);
3267                break;
3268            }
3269            if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3270                count_lilos++;
3271                strcpy(which_device, current_drive);
3272                break;
3273            }
3274        }
3275        if (pclose(pdrives)) {
3276            log_OS_error("Cannot pclose pdrives");
3277        }
3278        log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3279        paranoid_free(current_drive);
3280        if (count_grubs && !count_lilos) {
3281            return ('G');
3282        } else if (count_lilos && !count_grubs) {
3283            return ('L');
3284        } else if (count_grubs == 1 && count_lilos == 1) {
3285            log_it("I'll bet you used to use LILO but switched to GRUB...");
3286            return ('G');
3287        } else {
3288            log_it("Unknown boot loader");
3289            return ('U');
3290        }
3291    }
3292}
3293#endif
3294
3295
3296
3297
3298/**
3299 * Write zeroes over the first 16K of @p device.
3300 * @param device The device to zero.
3301 * @return 0 for success, 1 for failure.
3302 */
3303int zero_out_a_device(char *device)
3304{
3305    FILE *fout;
3306    int i;
3307
3308    assert_string_is_neither_NULL_nor_zerolength(device);
3309
3310    log_it("Zeroing drive %s", device);
3311    if (!(fout = fopen(device, "w"))) {
3312        log_OS_error("Unable to open/write to device");
3313        return (1);
3314    }
3315    for (i = 0; i < 16384; i++) {
3316        fputc('\0', fout);
3317    }
3318    paranoid_fclose(fout);
3319    log_it("Device successfully zeroed.");
3320    return (0);
3321}
3322
3323/**
3324 * Return the device pointed to by @p incoming.
3325 * @param incoming The device to resolve symlinks for.
3326 * @return The path to the real device file.
3327 * @note The returned string points to static storage that will be overwritten with each call.
3328 * @bug Won't work with file v4.0; needs to be written in C.
3329 */
3330char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
3331{
3332    static char output[MAX_STR_LEN];
3333    char *command;
3334    char *curr_fname;
3335    char *scratch = NULL;
3336    char *tmp = NULL;
3337    char *p;
3338
3339    struct stat statbuf;
3340    command = malloc(1000);
3341    malloc_string(curr_fname);
3342    if (!does_file_exist(incoming)) {
3343        log_it
3344            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
3345        strcpy(output, incoming);
3346    } else {
3347        strcpy(curr_fname, incoming);
3348        lstat(curr_fname, &statbuf);
3349        while (S_ISLNK(statbuf.st_mode)) {
3350            log_msg(1, "curr_fname = %s", curr_fname);
3351            sprintf(command, "file %s", curr_fname);
3352            mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
3353            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
3354                 p--);
3355            p++;
3356            mr_asprintf(&scratch, "%s", p);
3357            for (p = scratch; *p != '\0' && *p != '\''; p++);
3358            *p = '\0';
3359            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
3360            mr_free(tmp);
3361
3362            if (scratch[0] == '/') {
3363                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
3364            } else {            // copy over the basename cos it's a relative softlink
3365                p = curr_fname + strlen(curr_fname);
3366                while (p != curr_fname && *p != '/') {
3367                    p--;
3368                }
3369                if (*p == '/') {
3370                    p++;
3371                }
3372                strcpy(p, scratch);
3373            }
3374            mr_free(scratch);
3375            lstat(curr_fname, &statbuf);
3376        }
3377        strcpy(output, curr_fname);
3378        log_it("resolved %s to %s", incoming, output);
3379    }
3380    paranoid_free(command);
3381    paranoid_free(curr_fname);
3382    return (output);
3383}
3384
3385/* @} - end of deviceGroup */
3386
3387/**
3388 * Return the type of partition format (GPT or MBR)
3389 */
3390char *which_partition_format(const char *drive)
3391{
3392    static char output[4];
3393    char *tmp = NULL;
3394    char *command;
3395    char *fdisk;
3396#ifdef __IA64__
3397    struct stat buf;
3398#endif
3399    malloc_string(command);
3400    malloc_string(fdisk);
3401    sprintf(fdisk, "/sbin/parted2fdisk");
3402    sprintf(command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
3403    mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
3404    if (strstr(tmp, "GPT") == NULL) {
3405        strcpy(output, "MBR");
3406    } else {
3407        strcpy(output, "GPT");
3408    }
3409    mr_free(tmp);
3410
3411    log_msg(0, "Found %s partition table format type", output);
3412    paranoid_free(command);
3413    paranoid_free(fdisk);
3414    return (output);
3415}
3416/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.