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

Last change on this file since 2931 was 2931, checked in by Bruno Cornec, 9 years ago
  • Really never inject or eject when the -e option is passed or device is inappropriate (USB, Net, ...)
  • 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 2931 2012-01-24 11:48:04Z 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 2931 2012-01-24 11:48:04Z 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 CD | 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 \"[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 DVD | 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 DVD | 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;
2065
2066if (pathlist == NULL) {
2067    return;
2068}
2069while ((token = mr_strtok(pathlist, token_chars, &lastpos)) != NULL) {
2070    switch (get_dsf_mount_list(token, &mounted_on_dsf, &not_mounted_on_dsf)) {
2071    case 1: 
2072        if (mode == 'E') {
2073            log_msg(1, "WARNING ! %s doesn't exist in -E option", token);
2074        } else {
2075            log_msg(1, "ERROR ! %s doesn't exist in -I option", token);
2076            fatal_error("Error processing -I option");
2077        }
2078        break;
2079    /* Everything is OK; proceed to archive data */
2080    case 0:
2081        if (mode == 'E') {
2082            if (strlen(mounted_on_dsf)) {
2083                log_to_screen("Excluding the following file systems on %s:", token);
2084                log_to_screen("==> %s", mounted_on_dsf);
2085                log_msg (5, "Adding to bkpinfo->exclude_paths due to -E option: %s", mounted_on_dsf);
2086                if (bkpinfo->exclude_paths) {
2087                    mr_strcat(bkpinfo->exclude_paths,"|%s",mounted_on_dsf);
2088                } else {
2089                    mr_asprintf(&(bkpinfo->exclude_paths),"%s",mounted_on_dsf);
2090                }
2091                if (bkpinfo->exclude_devs) {
2092                    mr_strcat(bkpinfo->exclude_devs,"|%s",token);
2093                } else {
2094                    mr_asprintf(&(bkpinfo->exclude_devs),"%s",token);
2095                }
2096            }
2097        } else {
2098            log_to_screen("Archiving only the following file systems on %s:", token);
2099            log_to_screen("==> %s", mounted_on_dsf);
2100            strcpy(bkpinfo->include_paths, "/");
2101            if (strlen(not_mounted_on_dsf)) {
2102                log_msg (5, "Adding to bkpinfo->exclude_paths due to -I option: %s", not_mounted_on_dsf);
2103                log_to_screen("Not archiving the following file systems:");
2104                log_to_screen("==> %s", not_mounted_on_dsf);
2105                if (bkpinfo->exclude_paths) {
2106                    mr_strcat(bkpinfo->exclude_paths, "|%s",not_mounted_on_dsf);
2107                } else {
2108                    mr_asprintf(&(bkpinfo->exclude_paths),"%s",not_mounted_on_dsf);
2109                }
2110            }
2111        }
2112        break;
2113    /* It's a dsf but not a whole disk dsf */
2114    case -2:
2115        log_to_screen("Could %s be a partition instead of a whole disk device special file?\nIgnored.", token);
2116        break;
2117    /* A device special file was not passed in. Process it as a path. */
2118    case -1:
2119        /*  Adds a | to ensure correct detection even at both ends */
2120        mr_asprintf(&tmp1,"|%s",token);
2121        if (mode == 'E') {
2122            /*  Add the token if not already in the list */
2123            mr_asprintf(&tmp,"|%s|",bkpinfo->exclude_paths);
2124            if (strstr(tmp,tmp1) == NULL) {
2125                if (bkpinfo->exclude_paths) {
2126                    mr_strcat(bkpinfo->exclude_paths,tmp1);
2127                    mr_free(tmp1);
2128                } else {
2129                    bkpinfo->exclude_paths = tmp1;
2130                }
2131            }
2132        } else {
2133            /*  Add the token if not already in the list */
2134            mr_asprintf(&tmp,"|%s|",bkpinfo->include_paths);
2135            if (strstr(tmp,tmp1) == NULL) {
2136                strcat(bkpinfo->include_paths,tmp1);
2137            }
2138            mr_free(tmp1);
2139        }
2140        mr_free(tmp);
2141        break;
2142    }
2143    mr_free(token);
2144
2145    if (bkpinfo->include_paths != NULL) {
2146        log_msg(1, "include_paths is now '%s'", bkpinfo->include_paths);
2147    }
2148    if (bkpinfo->exclude_paths != NULL) {
2149        log_msg(1, "exclude_paths is now '%s'", bkpinfo->exclude_paths);
2150    }
2151    if (bkpinfo->exclude_devs != NULL) {
2152        log_msg(1, "exclude_devs is now '%s'", bkpinfo->exclude_devs);
2153    }
2154}
2155}
2156
2157
2158
2159
2160/**
2161 * Ask user for details of backup/restore information.
2162 * Called when @c mondoarchive doesn't get any parameters.
2163 * @param bkpinfo The backup information structure to fill out with the user's data.
2164 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
2165 * @return 0, always.
2166 * @bug No point of `int' return value.
2167 * @ingroup archiveGroup
2168 */
2169int interactively_obtain_media_parameters_from_user(bool archiving_to_media)
2170// archiving_to_media is TRUE if I'm being called by mondoarchive
2171// archiving_to_media is FALSE if I'm being called by mondorestore
2172{
2173    char *tmp = NULL;
2174    char *tmp1 = NULL;
2175    char *mds = NULL;
2176    char *q = NULL;
2177    char p[8*MAX_STR_LEN];
2178    char *sz_size;
2179    char *command;
2180    char *compression_type = NULL;
2181    char *comment;
2182    char *prompt;
2183    int i;
2184    FILE *fin;
2185
2186    malloc_string(sz_size);
2187    malloc_string(command);
2188    malloc_string(comment);
2189    malloc_string(prompt);
2190    malloc_string(tmp1);
2191    assert(bkpinfo != NULL);
2192    sz_size[0] = '\0';
2193    bkpinfo->nonbootable_backup = FALSE;
2194
2195    // Tape, CD, NETFS, ...?
2196    srandom(getpid());
2197    bkpinfo->backup_media_type =
2198        (g_restoring_live_from_cd) ? cdr :
2199        which_backup_media_type(bkpinfo->restore_data);
2200    if (bkpinfo->backup_media_type == none) {
2201        log_to_screen("User has chosen not to backup the PC");
2202        finish(1);
2203    }
2204    /* Why asking to remove the media with tape ?
2205    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
2206        popup_and_OK("Please remove media from drive(s)");
2207    }
2208    */
2209    log_msg(3, "media type = %s",
2210            bkptype_to_string(bkpinfo->backup_media_type));
2211    if (archiving_to_media) {
2212        sensibly_set_tmpdir_and_scratchdir();
2213    }
2214    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
2215    bkpinfo->compression_level =
2216        (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
2217    bkpinfo->use_lzo =
2218        (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
2219    mvaddstr_and_log_it(2, 0, " ");
2220
2221    // Find device's /dev (or SCSI) entry
2222    switch (bkpinfo->backup_media_type) {
2223    case cdr:
2224    case cdrw:
2225    case dvd:
2226    case usb:
2227        /* Never try to eject a USB device */
2228        if (bkpinfo->backup_media_type == usb) {
2229            bkpinfo->please_dont_eject = TRUE;
2230        }
2231        if (archiving_to_media) {
2232            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2233                if (ask_me_yes_or_no
2234                    ("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?"))
2235                {
2236                    bkpinfo->manual_cd_tray = TRUE;
2237                }
2238            }
2239            if ((compression_type = which_compression_type()) == NULL) {
2240                log_to_screen("User has chosen not to backup the PC");
2241                finish(1);
2242            }
2243            if ((bkpinfo->compression_level =
2244                 which_compression_level()) == -1) {
2245                log_to_screen("User has chosen not to backup the PC");
2246                finish(1);
2247            }
2248            mds = media_descriptor_string(bkpinfo->backup_media_type);
2249            sprintf(comment, "What speed is your %s (re)writer?", mds);
2250            if (bkpinfo->backup_media_type == dvd) {
2251                find_dvd_device(bkpinfo->media_device, FALSE);
2252                strcpy(tmp1, "1");
2253                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2254                log_msg(1, "Setting to DVD defaults");
2255            } else {
2256                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
2257                strcpy(tmp1, "4");
2258                strcpy(sz_size, "650");
2259                log_msg(1, "Setting to CD defaults");
2260            }
2261            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2262                if (!popup_and_get_string("Speed", comment, tmp1, 4)) {
2263                    log_to_screen("User has chosen not to backup the PC");
2264                    finish(1);
2265                }
2266            }
2267            bkpinfo->cdrw_speed = atoi(tmp1);   // if DVD then this shouldn't ever be used anyway :)
2268
2269            sprintf(comment,
2270                    "How much data (in Megabytes) will each %s store?", mds);
2271            mr_free(mds);
2272            if (!popup_and_get_string("Size", comment, sz_size, 5)) {
2273                log_to_screen("User has chosen not to backup the PC");
2274                finish(1);
2275            }
2276            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2277                bkpinfo->media_size[i] = atoi(sz_size);
2278            }
2279            if (bkpinfo->media_size[0] <= 0) {
2280                log_to_screen("User has chosen not to backup the PC");
2281                finish(1);
2282            }
2283        }
2284        /* No break because we continue even for usb */
2285    case cdstream:
2286        mds = media_descriptor_string(bkpinfo->backup_media_type);
2287
2288        if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
2289            strcpy(bkpinfo->media_device, "/dev/cdrom");
2290            log_msg(2, "CD-ROM device assumed to be at %s",
2291                    bkpinfo->media_device);
2292        } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))
2293                   || bkpinfo->backup_media_type == dvd) {
2294            if (!bkpinfo->media_device[0]) {
2295                strcpy(bkpinfo->media_device, "/dev/cdrom");
2296            }                   // just for the heck of it :)
2297            log_msg(1, "bkpinfo->media_device = %s",
2298                    bkpinfo->media_device);
2299            if (bkpinfo->backup_media_type == dvd
2300                || find_cdrom_device(bkpinfo->media_device, FALSE)) {
2301                log_msg(1, "bkpinfo->media_device = %s",
2302                        bkpinfo->media_device);
2303                sprintf(comment,
2304                        "Please specify your %s drive's /dev entry", mds);
2305                if (!popup_and_get_string
2306                    ("Device?", comment, bkpinfo->media_device,
2307                     MAX_STR_LEN / 4)) {
2308                    log_to_screen("User has chosen not to backup the PC");
2309                    finish(1);
2310                }
2311            }
2312            log_msg(2, "%s device found at %s", mds, bkpinfo->media_device);
2313        } else {
2314            if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) {
2315                bkpinfo->media_device[0] = '\0';
2316            }
2317            if (bkpinfo->media_device[0]) {
2318                if (bkpinfo->backup_media_type == usb) {
2319                    mr_asprintf(&tmp, "I think your %s media corresponds to %s. Is this correct?", mds, bkpinfo->media_device);
2320                } else {
2321                    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);
2322                }
2323                if (!ask_me_yes_or_no(tmp)) {
2324                    bkpinfo->media_device[0] = '\0';
2325                }
2326                mr_free(tmp);
2327            }
2328            if (!bkpinfo->media_device[0]) {
2329                if (bkpinfo->backup_media_type == usb) {
2330                    i = popup_and_get_string("/dev entry?",
2331                                         "What is the /dev entry of your USB Disk/Key, please?",
2332                                         bkpinfo->media_device,
2333                                         MAX_STR_LEN / 4);
2334                } else {
2335                    if (g_kernel_version < 2.6) {
2336                        i = popup_and_get_string("Device node?",
2337                                             "What is the SCSI node of your CD (re)writer, please?",
2338                                             bkpinfo->media_device,
2339                                             MAX_STR_LEN / 4);
2340                    } else {
2341                        i = popup_and_get_string("/dev entry?",
2342                                             "What is the /dev entry of your CD (re)writer, please?",
2343                                             bkpinfo->media_device,
2344                                             MAX_STR_LEN / 4);
2345                    }
2346                }
2347                if (!i) {
2348                    log_to_screen("User has chosen not to backup the PC");
2349                    finish(1);
2350                }
2351            }
2352        }
2353        mr_free(mds);
2354
2355        if (bkpinfo->backup_media_type == cdstream) {
2356            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2357                bkpinfo->media_size[i] = 650;
2358            }
2359        }
2360        break;
2361    case udev:
2362        if (!ask_me_yes_or_no
2363            ("This option is for advanced users only. Are you sure?")) {
2364            log_to_screen("User has chosen not to backup the PC");
2365            finish(1);
2366        }
2367    case tape:
2368
2369        if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) {
2370            log_msg(3, "Ok, using vanilla scsi tape.");
2371            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
2372            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2373                paranoid_fclose(fin);
2374            } else {
2375                strcpy(bkpinfo->media_device, "/dev/osst0");
2376            }
2377        }
2378        if (bkpinfo->media_device[0]) {
2379            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2380                paranoid_fclose(fin);
2381            } else {
2382                if (does_file_exist("/tmp/mondo-restore.cfg")) {
2383                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
2384                                 bkpinfo->media_device);
2385                }
2386            }
2387        }
2388        if (bkpinfo->media_device[0]) {
2389            mr_asprintf(&tmp, "I think I've found your tape streamer at %s; am I right on the money?", bkpinfo->media_device);
2390            if (!ask_me_yes_or_no(tmp)) {
2391                bkpinfo->media_device[0] = '\0';
2392            }
2393            mr_free(tmp);
2394        }
2395        if (!bkpinfo->media_device[0]) {
2396            if (!popup_and_get_string
2397                ("Device name?",
2398                 "What is the /dev entry of your tape streamer?",
2399                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
2400                log_to_screen("User has chosen not to backup the PC");
2401                finish(1);
2402            }
2403        }
2404        mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
2405        if (run_program_and_log_output(tmp, FALSE)) {
2406            log_to_screen("User has not specified a valid /dev entry");
2407            finish(1);
2408        }
2409        mr_free(tmp);
2410        log_msg(4, "sz_size = %s", sz_size);
2411        sz_size[0] = '\0';
2412
2413        bkpinfo->use_obdr = ask_me_yes_or_no
2414            ("Do you want to activate OBDR support for your tapes ?");
2415        if (sz_size[0] == '\0') {
2416            bkpinfo->media_size[0] = 0;
2417        } else {
2418            bkpinfo->media_size[0] =
2419                friendly_sizestr_to_sizelong(sz_size) / 2 - 50;
2420        }
2421        log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
2422        if (bkpinfo->media_size[0] <= 0) {
2423            bkpinfo->media_size[0] = 0;
2424        }
2425        for (i = 1; i <= MAX_NOOF_MEDIA; i++) {
2426            bkpinfo->media_size[i] = bkpinfo->media_size[0];
2427        }
2428        if (archiving_to_media) {
2429            if ((compression_type = which_compression_type()) == NULL) {
2430                log_to_screen("User has chosen not to backup the PC");
2431                finish(1);
2432            }
2433            if ((bkpinfo->compression_level =
2434                 which_compression_level()) == -1) {
2435                log_to_screen("User has chosen not to backup the PC");
2436                finish(1);
2437            }
2438        }
2439        break;
2440
2441
2442
2443    case netfs:
2444        /* Never try to eject a NETFS device */
2445        bkpinfo->please_dont_eject = TRUE;
2446
2447        /* Initiate bkpinfo netfs_mount path from running environment if not already done */
2448        if (!bkpinfo->netfs_mount[0]) {
2449            strcpy(bkpinfo->netfs_mount,
2450                   call_program_and_get_last_line_of_output
2451                   ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
2452        }
2453#ifdef __FreeBSD__
2454        if (TRUE)
2455#else
2456        if (!bkpinfo->disaster_recovery)
2457#endif
2458        {
2459            if (!popup_and_get_string
2460                ("Network shared dir.",
2461                 "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.)",
2462                 bkpinfo->netfs_mount, MAX_STR_LEN / 4)) {
2463                log_to_screen("User has chosen not to backup the PC");
2464                finish(1);
2465            }
2466            if (!bkpinfo->restore_data) {
2467                if ((compression_type = which_compression_type()) == NULL) {
2468                    log_to_screen("User has chosen not to backup the PC");
2469                    finish(1);
2470                }
2471                if ((bkpinfo->compression_level =
2472                     which_compression_level()) == -1) {
2473                    log_to_screen("User has chosen not to backup the PC");
2474                    finish(1);
2475                }
2476            }
2477            // check whether already mounted - we better remove
2478            // surrounding spaces and trailing '/' for this
2479            strip_spaces(bkpinfo->netfs_mount);
2480            if (bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] == '/')
2481                bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] = '\0';
2482            q = strchr(bkpinfo->netfs_mount, '@');
2483            if (q != NULL) {
2484                /* User found. Store the 2 values */
2485                q++;
2486                /* new netfs mount */
2487                strcpy(tmp,q);
2488            } else {
2489                strcpy(tmp,bkpinfo->netfs_mount);
2490            }
2491            sprintf(command, "mount | grep \"%s \" | cut -d' ' -f3",
2492                    tmp);
2493            strcpy(bkpinfo->isodir,
2494                   call_program_and_get_last_line_of_output(command));
2495
2496            if (!bkpinfo->restore_data) {
2497                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2498                sprintf(comment,
2499                    "How much data (in Megabytes) will each media store?");
2500                if (!popup_and_get_string("Size", comment, sz_size, 5)) {
2501                    log_to_screen("User has chosen not to backup the PC");
2502                    finish(1);
2503                }
2504            } else {
2505                strcpy(sz_size, "0");
2506            }
2507            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2508                bkpinfo->media_size[i] = atoi(sz_size);
2509            }
2510            if (bkpinfo->media_size[0] < 0) {
2511                log_to_screen("User has chosen not to backup the PC");
2512                finish(1);
2513            }
2514        }
2515        /*  Force NFS to be the protocol by default */
2516        if (bkpinfo->netfs_proto == NULL) {
2517            mr_asprintf(&(bkpinfo->netfs_proto), "nfs");
2518        }
2519        if (bkpinfo->disaster_recovery) {
2520            sprintf(command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
2521            (void)system(command);
2522        }
2523        strcpy(tmp1, bkpinfo->netfs_proto);
2524        if (!popup_and_get_string
2525            ("Network protocol", "Which protocol should I use (nfs/sshfs) ?",
2526             tmp1, MAX_STR_LEN)) {
2527            log_to_screen("User has chosen not to backup the PC");
2528            finish(1);
2529        }
2530        mr_free(bkpinfo->netfs_proto);
2531        mr_asprintf(&(bkpinfo->netfs_proto), "%s", tmp1);
2532        if (!popup_and_get_string
2533            ("Network share", "Which remote share should I mount?",
2534             bkpinfo->netfs_mount, MAX_STR_LEN)) {
2535            log_to_screen("User has chosen not to backup the PC");
2536            finish(1);
2537        }
2538
2539        if (bkpinfo->netfs_user) {
2540            strcpy(tmp1, bkpinfo->netfs_user);
2541        } else {
2542            strcpy(tmp1, "");
2543        }
2544        if (!popup_and_get_string
2545            ("Network user", "Which user should I use if any ?",
2546             tmp1, MAX_STR_LEN)) {
2547            log_to_screen("User has chosen not to backup the PC");
2548            finish(1);
2549        }
2550        mr_free(bkpinfo->netfs_user);
2551        if (strcmp(tmp1, "") != 0) {
2552            mr_asprintf(&(bkpinfo->netfs_user), "%s", tmp1);
2553        }
2554   
2555        /* Initiate bkpinfo isodir path from running environment if mount already done */
2556        if (is_this_device_mounted(bkpinfo->netfs_mount)) {
2557            strcpy(bkpinfo->isodir,
2558                   call_program_and_get_last_line_of_output
2559                   ("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
2560        } else {
2561            sprintf(bkpinfo->isodir, "%s/netfsdir", bkpinfo->tmpdir);
2562            sprintf(command, "mkdir -p %s", bkpinfo->isodir);
2563            run_program_and_log_output(command, 5);
2564            if (bkpinfo->restore_data) {
2565                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2566                    mr_asprintf(&tmp, "sshfs -o ro");
2567                } else {
2568                    mr_asprintf(&tmp, "mount -t %s -o nolock,ro", bkpinfo->netfs_proto);
2569                }
2570            } else {
2571                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2572                    mr_asprintf(&tmp, "sshfs");
2573                } else {
2574                    mr_asprintf(&tmp, "mount -t %s -o nolock", bkpinfo->netfs_proto);
2575                }
2576            }
2577            if (bkpinfo->netfs_user) {
2578                mr_strcat(tmp, "%s@", bkpinfo->netfs_user);
2579            }
2580            mr_strcat(tmp, "%s %s", bkpinfo->netfs_mount, bkpinfo->isodir);
2581            run_program_and_log_output(tmp, 3);
2582            mr_free(tmp);
2583
2584            malloc_string(g_selfmounted_isodir);
2585            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
2586        }
2587        if (!is_this_device_mounted(bkpinfo->netfs_mount)) {
2588            popup_and_OK
2589                ("Please mount that partition before you try to backup to or restore from it.");
2590            finish(1);
2591        }
2592        strcpy(tmp1, bkpinfo->netfs_remote_dir);
2593        if (!popup_and_get_string
2594            ("Directory", "Which directory within that mountpoint?", tmp1,
2595             MAX_STR_LEN)) {
2596            log_to_screen("User has chosen not to backup the PC");
2597            finish(1);
2598        }
2599        strcpy(bkpinfo->netfs_remote_dir, tmp1);
2600
2601        // check whether writable - we better remove surrounding spaces for this
2602        strip_spaces(bkpinfo->netfs_remote_dir);
2603
2604        if (!popup_and_get_string
2605            ("Prefix.",
2606             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2607            bkpinfo->prefix, MAX_STR_LEN / 4)) {
2608            log_to_screen("User has chosen not to backup the PC");
2609            finish(1);
2610        }
2611        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2612
2613        for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2614            bkpinfo->media_size[i] = 650;
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.