source: branches/2.2.10/mondo/src/common/libmondo-devices.c @ 2266

Last change on this file since 2266 was 2266, checked in by Bruno Cornec, 11 years ago

r3207@localhost: bruno | 2009-07-07 00:32:00 +0200

  • Replace sprintf by mr_asprintf in libmondo-devices.c
  • Property svn:keywords set to Id
File size: 70.0 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 2266 2009-07-12 00:04:45Z 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 "mondostructures.h"
13#include "libmondo-files-EXT.h"
14#include "libmondo-devices.h"
15#include "lib-common-externs.h"
16#include "libmondo-string-EXT.h"
17#include "libmondo-tools-EXT.h"
18#include "libmondo-gui-EXT.h"
19#include "libmondo-fork-EXT.h"
20#include "libmondo-stream-EXT.h"
21
22#include <sys/types.h>
23#ifdef __FreeBSD__
24#define DKTYPENAMES
25#define FSTYPENAMES
26#include <sys/disklabel.h>
27#include <sys/disk.h>
28#elif linux
29#define u64 unsigned long long
30#include <linux/fs.h>           /* for BLKGETSIZE64 */
31#include <linux/hdreg.h>
32#endif
33
34/*@unused@*/
35//static char cvsid[] = "$Id: libmondo-devices.c 2266 2009-07-12 00:04:45Z bruno $";
36
37extern int g_current_media_number;
38extern double g_kernel_version;
39
40extern bool g_ISO_restore_mode;
41extern char *g_selfmounted_isodir;
42extern char *MONDO_LOGFILE;
43
44extern void setup_tmpdir(char *path);
45
46static char g_cdrw_drive_is_here[MAX_STR_LEN / 4] = "";
47static char g_cdrom_drive_is_here[MAX_STR_LEN / 4] = "";
48static char g_dvd_drive_is_here[MAX_STR_LEN / 4] = "";
49
50
51/**
52 * ????? @bug ?????
53 * @ingroup globalGroup
54 */
55bool g_restoring_live_from_cd = FALSE;
56bool g_restoring_live_from_nfs = FALSE;
57
58extern t_bkptype g_backup_media_type;   // set by main()
59
60/* Reference to global bkpinfo */
61extern struct s_bkpinfo *bkpinfo;
62
63
64
65
66void set_g_cdrom_and_g_dvd_to_bkpinfo_value()
67{
68    strcpy(g_cdrom_drive_is_here, bkpinfo->media_device);   // just in case
69    strcpy(g_dvd_drive_is_here, bkpinfo->media_device); // just in case
70}
71
72
73
74/**
75 * Retract all CD trays and wait for autorun to complete.
76 * @ingroup deviceGroup
77 */
78void retract_CD_tray_and_defeat_autorun(void)
79{
80//  log_it("rctada: Retracting all CD trays", __LINE__);
81    if (strlen(g_cdrom_drive_is_here) > 0) {
82        inject_device(g_cdrom_drive_is_here);
83    }
84    if (strlen(g_dvd_drive_is_here) > 0) {
85        inject_device(g_dvd_drive_is_here);
86    }
87    if (strlen(g_cdrw_drive_is_here) > 0) {
88        inject_device(g_cdrw_drive_is_here);
89    }
90//  log_it("rctada: killing autorun");
91//  run_program_and_log_output("killall autorun", TRUE);
92    if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5)) {
93        log_it("autorun detected; sleeping for 2 seconds");
94        sleep(2);
95    }
96    log_it("rctada: Unmounting all CD drives", __LINE__);
97    run_program_and_log_output("umount /dev/cdr* /dev/dvd*", 5);
98}
99
100
101
102/**
103 * Determine whether we're booted off a ramdisk.
104 * @return @c TRUE (we are) or @c FALSE (we aren't).
105 * @ingroup utilityGroup
106 */
107bool am_I_in_disaster_recovery_mode(void)
108{
109    char *tmp = NULL;
110    char *comment = NULL;
111    bool is_this_a_ramdisk = FALSE;
112
113    malloc_string(comment);
114    mr_asprintf(&tmp, "%s", where_is_root_mounted());
115    mr_asprintf(&comment, "root is mounted at %s\n", tmp);
116    log_msg(0, comment);
117    mr_free(comment);
118    log_msg(0,
119            "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().",
120            tmp);
121
122#ifdef __FreeBSD__
123    if (strstr(tmp, "/dev/md")) {
124        is_this_a_ramdisk = TRUE;
125    }
126#else
127    if (!strncmp(tmp, "/dev/ram", 8)
128        || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/")
129            && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs")
130        || !strcmp(tmp, "/dev/root")) {
131        is_this_a_ramdisk = TRUE;
132    } else {
133        is_this_a_ramdisk = FALSE;
134    }
135#endif
136    mr_free(tmp);
137
138    if (is_this_a_ramdisk) {
139        if (!does_file_exist("/THIS-IS-A-RAMDISK")) {
140            log_to_screen
141                ("Using /dev/root is stupid of you but I'll forgive you.");
142            is_this_a_ramdisk = FALSE;
143        }
144    }
145    if (does_file_exist("/THIS-IS-A-RAMDISK")) {
146        is_this_a_ramdisk = TRUE;
147    }
148    log_msg(1, "Is this a ramdisk? result = %d", is_this_a_ramdisk);
149    return (is_this_a_ramdisk);
150}
151
152
153
154
155
156/**
157 * Turn @c bkpinfo->backup_media_type into a human-readable string.
158 * @return The human readable string (e.g. @c cdr becomes <tt>"cdr"</tt>).
159 * @note The returned string points to static storage that will be overwritten with each call.
160 * @ingroup stringGroup
161 */
162static char *bkptype_to_string(t_bkptype bt)
163{
164    static char output[MAX_STR_LEN / 4];
165    switch (bt) {
166    case none:
167        strcpy(output, "none");
168        break;
169    case iso:
170        strcpy(output, "iso");
171        break;
172    case cdr:
173        strcpy(output, "cdr");
174        break;
175    case cdrw:
176        strcpy(output, "cdrw");
177        break;
178    case cdstream:
179        strcpy(output, "cdstream");
180        break;
181    case nfs:
182        strcpy(output, "nfs");
183        break;
184    case tape:
185        strcpy(output, "tape");
186        break;
187    case udev:
188        strcpy(output, "udev");
189        break;
190    case usb:
191        strcpy(output, "usb");
192        break;
193    default:
194        strcpy(output, "default");
195    }
196    return (output);
197}
198
199
200
201/**
202 * @addtogroup deviceGroup
203 * @{
204 */
205/**
206 * Eject the tray of the specified CD device.
207 * @param dev The device to eject.
208 * @return the return value of the @c eject command. (0=success, nonzero=failure)
209 */
210int eject_device(char *dev)
211{
212    char *command = NULL;
213    int res1 = 0, res2 = 0;
214
215    if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type)
216        && g_backup_media_type != udev) {
217        mr_asprintf(&command, "mt -f %s offline", dev);
218        res1 = run_program_and_log_output(command, 1);
219        mr_free(command);
220    } else {
221        res1 = 0;
222    }
223
224#ifdef __FreeBSD__
225    if (strstr(dev, "acd")) {
226        mr_asprintf(&command, "cdcontrol -f %s eject", dev);
227    } else {
228        mr_asprintf(&command, "camcontrol eject `echo %s | sed 's|/dev/||'`",
229                dev);
230    }
231#else
232    mr_asprintf(&command, "eject %s", dev);
233#endif
234
235    log_msg(3, "Ejecting %s", dev);
236    res2 = run_program_and_log_output(command, 1);
237    mr_free(command);
238    if (res1 && res2) {
239        return (1);
240    } else {
241        return (0);
242    }
243}
244
245/**
246 * Load (inject) the tray of the specified CD device.
247 * @param dev The device to load/inject.
248 * @return 0 for success, nonzero for failure.
249 */
250int inject_device(char *dev)
251{
252    char *command = NULL;
253    int i;
254
255#ifdef __FreeBSD__
256    if (strstr(dev, "acd")) {
257        mr_asprintf(&command, "cdcontrol -f %s close", dev);
258    } else {
259        mr_asprintf(&command, "camcontrol load `echo %s | sed 's|/dev/||'`",
260                dev);
261    }
262#else
263    mr_asprintf(&command, "eject -t %s", dev);
264#endif
265    i = run_program_and_log_output(command, FALSE);
266    mr_free(command);
267    return (i);
268}
269
270
271/**
272 * Determine whether the specified @p device (really, you can use any file)
273 * exists.
274 * @return TRUE if it exists, FALSE if it doesn't.
275 */
276bool does_device_exist(char *device)
277{
278
279    /*@ buffers *********************************************************** */
280    char *tmp = NULL;
281    bool ret;
282
283    assert_string_is_neither_NULL_nor_zerolength(device);
284
285    mr_asprintf(&tmp, "ls %s > /dev/null 2> /dev/null", device);
286
287    if (system(tmp)) {
288        ret = FALSE;
289    } else {
290        ret = TRUE;
291    }
292    mr_free(tmp);
293    return (ret);
294}
295
296
297/**
298 * Determine whether a non-Microsoft partition exists on any connected hard drive.
299 * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent PC).
300 */
301bool does_nonMS_partition_exist(void)
302{
303#if __FreeBSD__
304    return
305        !system
306        ("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false");
307#else
308    return
309        !system
310        ("parted2fdisk -l 2>/dev/null | grep '^/dev/' | grep -Eqv '(MS|DOS|FAT|NTFS)'");
311#endif
312}
313
314/**
315 * Determine whether the specified @p partno exists on the specified @p drive.
316 * @param drive The drive to search for the partition in.
317 * @param partno The partition number to look for.
318 * @return 0 if it exists, nonzero otherwise.
319 */
320int does_partition_exist(const char *drive, int partno)
321{
322    /*@ buffers **************************************************** */
323    char *program = NULL;
324    char *incoming;
325    char *searchstr = NULL;
326    char *tmp;
327
328    /*@ ints ******************************************************* */
329    int res = 0;
330
331    /*@ pointers *************************************************** */
332    FILE *fin;
333
334
335    /*@ end vars *************************************************** */
336    assert_string_is_neither_NULL_nor_zerolength(drive);
337    assert(partno >= 0 && partno < 999);
338
339    malloc_string(incoming);
340    malloc_string(searchstr);
341    malloc_string(tmp);
342
343#ifdef __FreeBSD__
344    // We assume here that this is running from mondorestore. (It is.)
345    mr_asprintf(&program, "ls %s %s >/dev/null 2>&1", drive,
346            build_partition_name(tmp, drive, partno));
347    res = system(program);
348    mr_free(program);
349    return (res);
350#else
351    tmp[0] = '\0';
352#endif
353
354    mr_asprintf(&program, "parted2fdisk -l %s 2> /dev/null", drive);
355    fin = popen(program, "r");
356    if (!fin) {
357        log_it("program=%s", program);
358        log_OS_error("Cannot popen-in program");
359        mr_free(program);
360        return (0);
361    }
362    mr_free(program);
363
364    (void) build_partition_name(searchstr, drive, partno);
365    strcat(searchstr, " ");
366    for (res = 0; !res && fgets(incoming, MAX_STR_LEN - 1, fin);) {
367        if (strstr(incoming, searchstr)) {
368            res = 1;
369        }
370    }
371    if (pclose(fin)) {
372        log_OS_error("Cannot pclose fin");
373    }
374    paranoid_free(incoming);
375    paranoid_free(searchstr);
376    paranoid_free(tmp);
377    return (res);
378}
379
380
381
382
383
384/**
385 * Determine whether given NULL-terminated @p str exists in the MBR of @p dev.
386 * @param dev The device to look in.
387 * @param str The string to look for.
388 * @return TRUE if it exists, FALSE if it doesn't.
389 */
390bool does_string_exist_in_boot_block(char *dev, char *str)
391{
392    /*@ buffers **************************************************** */
393    char *command = NULL;
394
395    /*@ end vars *************************************************** */
396    int i;
397
398    assert_string_is_neither_NULL_nor_zerolength(dev);
399    assert_string_is_neither_NULL_nor_zerolength(str);
400
401    mr_asprintf(&command,
402            "dd if=%s bs=446 count=1 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null",
403            dev, str);
404    i = system(command);
405    mr_free(command);
406    if (i) {
407        return (FALSE);
408    } else {
409        return (TRUE);
410    }
411}
412
413/**
414 * Determine whether specified @p str exists in the first @p n sectors of
415 * @p dev.
416 * @param dev The device to look in.
417 * @param str The string to look for.
418 * @param n The number of 512-byte sectors to search.
419 */
420bool does_string_exist_in_first_N_blocks(char *dev, char *str, int n)
421{
422    /*@ buffers **************************************************** */
423    char *command = NULL;
424    /*@ end vars *************************************************** */
425    int i;
426
427    mr_asprintf(&command,
428            "dd if=%s bs=512 count=%i 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null",
429            dev, n, str);
430    i = system(command);
431    mr_free(command);
432    if (i) {
433        return (FALSE);
434    } else {
435        return (TRUE);
436    }
437}
438
439
440
441/**
442 * Try to mount CD-ROM at @p mountpoint. If the CD-ROM is not found or has
443 * not been specified, call find_cdrom_device() to find it.
444 * @param bkpinfo The backup information structure. The only field used is @c bkpinfo->media_device.
445 * @param mountpoint Where to mount the CD-ROM.
446 * @return 0 for success, nonzero for failure.
447 * @see mount_CDROM_here
448 */
449int find_and_mount_actual_cd(char *mountpoint)
450{
451    /*@ buffers ***************************************************** */
452
453    /*@ int's  ****************************************************** */
454    int res;
455    char *dev;
456
457    /*@ end vars **************************************************** */
458
459    malloc_string(dev);
460    assert(bkpinfo != NULL);
461    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
462
463    if (g_backup_media_type == dvd) {
464        strcpy(dev, g_dvd_drive_is_here);
465        if (!dev[0]) {
466            find_dvd_device(dev, FALSE);
467        }
468    } else {
469        strcpy(dev, g_cdrom_drive_is_here);
470        if (!dev[0]) {
471            find_cdrom_device(dev, FALSE);
472        }
473    }
474
475    if (bkpinfo->backup_media_type != iso) {
476        retract_CD_tray_and_defeat_autorun();
477    }
478
479    if (!dev[0] || (res = mount_CDROM_here(dev, mountpoint))) {
480        if (!popup_and_get_string
481            ("CD-ROM device", "Please enter your CD-ROM's /dev device",
482             dev, MAX_STR_LEN / 4)) {
483            res = 1;
484        } else {
485            res = mount_CDROM_here(dev, mountpoint);
486        }
487    }
488    if (res) {
489        log_msg(1, "mount failed");
490    } else {
491        log_msg(1, "mount succeeded with %s", dev);
492    }
493    paranoid_free(dev);
494    return (res);
495}
496
497
498
499
500
501
502/**
503 * Locate a CD-R/W writer's SCSI node.
504 * @param cdrw_device SCSI node will be placed here.
505 * @return 0 for success, nonzero for failure.
506 */
507int find_cdrw_device(char *cdrw_device)
508{
509    /*@ buffers ************************ */
510    char *comment = NULL;
511    char *tmp = NULL;
512    char *cdr_exe = NULL;
513    char *command = NULL;
514
515    if (g_cdrw_drive_is_here[0]) {
516        strcpy(cdrw_device, g_cdrw_drive_is_here);
517        log_msg(3, "Been there, done that. Returning %s", cdrw_device);
518        return (0);
519    }
520    if (g_backup_media_type == dvd) {
521        log_msg(1,
522                "This is dumb. You're calling find_cdrw_device() but you're backing up to DVD. WTF?");
523        return (1);
524    }
525    run_program_and_log_output("insmod ide-scsi", -1);
526    if (find_home_of_exe("cdrecord")) {
527        mr_asprintf(&cdr_exe, "cdrecord");
528    } else {
529        mr_asprintf(&cdr_exe, "dvdrecord");
530    }
531    if (find_home_of_exe(cdr_exe)) {
532        mr_asprintf(&command,
533                "%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",
534                cdr_exe);
535        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output(command));
536        mr_free(command);
537    }
538    if ((tmp == NULL) || (strlen(tmp) < 2)) {
539        mr_free(tmp);
540        mr_free(cdr_exe);
541        return 1;
542    } else {
543        strcpy(cdrw_device, tmp);
544        mr_asprintf(&comment, "Found CDRW device - %s", cdrw_device);
545        log_it(comment);
546        strcpy(g_cdrw_drive_is_here, cdrw_device);
547        mr_free(comment);
548        mr_free(tmp);
549        mr_free(cdr_exe);
550        return (0);
551    }
552}
553
554
555/**
556 * Attempt to locate a CD-ROM device's /dev entry.
557 * Several different methods may be used to find the device, including
558 * calling @c cdrecord, searching @c dmesg, and trial-and-error.
559 * @param output Where to put the located /dev entry.
560 * @param try_to_mount Whether to mount the CD as part of the test; if mount
561 * fails then return failure.
562 * @return 0 for success, nonzero for failure.
563 */
564int find_cdrom_device(char *output, bool try_to_mount)
565{
566    /*@ pointers **************************************************** */
567    FILE *fin;
568    char *p;
569    char *q;
570    char *r;
571    int retval = 0;
572
573    /*@ bool's ****************************************************** */
574    bool found_it = FALSE;
575
576    /*@ buffers ***************************************************** */
577    char *tmp;
578    char *tmp1 = NULL;
579    char *cdr_exe = NULL;
580    char *phrase_one;
581    char *phrase_two;
582    char *command = NULL;
583#ifndef __FreeBSD__
584    char *dvd_last_resort = NULL;
585#endif
586    char *mountpoint = NULL;
587    static char the_last_place_i_found_it[MAX_STR_LEN] = "";
588
589    /*@ intialize *************************************************** */
590    malloc_string(tmp);
591    malloc_string(phrase_one);
592    malloc_string(phrase_two);
593
594    output[0] = '\0';
595    phrase_one[0] = '\0';
596    phrase_two[0] = '\0';
597#ifndef __FreeBSD__
598    mr_asprintf(&dvd_last_resort, "%s", "");;
599#endif
600
601    /*@ end vars **************************************************** */
602
603    if (g_cdrom_drive_is_here[0] && !isdigit(g_cdrom_drive_is_here[0])) {
604        strcpy(output, g_cdrom_drive_is_here);
605        log_msg(3, "Been there, done that. Returning %s", output);
606        retval = 0;
607        goto end_of_find_cdrom_device;
608    }
609    if (the_last_place_i_found_it[0] != '\0' && !try_to_mount) {
610        strcpy(output, the_last_place_i_found_it);
611        log_msg(3,
612                "find_cdrom_device() --- returning last found location - '%s'",
613                output);
614        retval = 0;
615        goto end_of_find_cdrom_device;
616    }
617
618    mr_asprintf(&mountpoint, "%s/cd.mnt", bkpinfo->tmpdir);
619    make_hole_for_dir(mountpoint);
620
621    if (find_home_of_exe("cdrecord")) {
622        mr_asprintf(&cdr_exe, "cdrecord");
623    } else {
624        mr_asprintf(&cdr_exe, "dvdrecord");
625    }
626    tmp[0] = '\0';
627    if (!find_home_of_exe(cdr_exe)) {
628        strcpy(output, "/dev/cdrom");
629        log_msg(4, "Can't find cdrecord; assuming %s", output);
630        if (!does_device_exist(output)) {
631            log_msg(4, "That didn't work. Sorry.");
632            retval = 1;
633            goto end_of_find_cdrom_device;
634        } else {
635            retval = 0;
636            goto end_of_find_cdrom_device;
637        }
638    }
639
640    mr_asprintf(&command, "%s -scanbus 2> /dev/null", cdr_exe);
641    fin = popen(command, "r");
642    log_msg(4, "command=%s", command);
643    mr_free(command);
644
645    if (!fin) {
646        log_OS_error("Cannot popen command");
647        mr_free(cdr_exe);
648        return (1);
649    }
650
651    for ((void)fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
652         (void)fgets(tmp, MAX_STR_LEN, fin)) {
653        p = strchr(tmp, '\'');
654        if (p) {
655            q = strchr(++p, '\'');
656            if (q) {
657                for (r = q; *(r - 1) == ' '; r--);
658                *r = '\0';
659                strcpy(phrase_one, p);
660                p = strchr(++q, '\'');
661                if (p) {
662                    q = strchr(++p, '\'');
663                    if (q) {
664                        while (*(q - 1) == ' ') {
665                            q--;
666                        }
667                        *q = '\0';
668                        strcpy(phrase_two, p);
669                    }
670                }
671            }
672        }
673    }
674    paranoid_pclose(fin);
675
676#ifndef __FreeBSD__
677    if (strlen(phrase_two) == 0) {
678        log_msg(4, "Not running phase two. String is empty.");
679    } else {
680        mr_asprintf(&command, "dmesg | grep \"%s\" 2> /dev/null", phrase_two);
681        fin = popen(command, "r");
682        mr_free(command);
683
684        if (!fin) {
685            log_msg(4, "Cannot run 2nd command - non-fatal, fortunately");
686        } else {
687            for ((void)fgets(tmp, MAX_STR_LEN, fin); !feof(fin);
688                 (void)fgets(tmp, MAX_STR_LEN, fin)) {
689                log_msg(5, "--> '%s'", tmp);
690                if (tmp[0] != ' ' && tmp[1] != ' ') {
691                    p = strchr(tmp, ':');
692                    if (p) {
693                        *p = '\0';
694                        if (strstr(tmp, "DVD")) {
695                            mr_free(dvd_last_resort);
696                            mr_asprintf(&dvd_last_resort, "/dev/%s", tmp);
697                            log_msg(4,
698                                    "Ignoring '%s' because it's a DVD drive",
699                                    tmp);
700                        } else {
701                            sprintf(output, "/dev/%s", tmp);
702                            found_it = TRUE;
703                        }
704                    }
705                }
706            }
707            paranoid_pclose(fin);
708        }
709    }
710
711#endif
712#ifdef __FreeBSD__
713    if (!found_it) {
714        log_msg(4, "OK, approach 2");
715        if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) {
716            if (!
717                (found_it =
718                 set_dev_to_this_if_rx_OK(output, "/dev/cdrom1"))) {
719                if (!
720                    (found_it =
721                     set_dev_to_this_if_rx_OK(output, "/dev/dvd"))) {
722                    if (!
723                        (found_it =
724                         set_dev_to_this_if_rx_OK(output, "/dev/acd0"))) {
725                        if (!
726                            (found_it =
727                             set_dev_to_this_if_rx_OK(output,
728                                                      "/dev/cd01"))) {
729                            if (!
730                                (found_it =
731                                 set_dev_to_this_if_rx_OK(output,
732                                                          "/dev/acd1"))) {
733                                if (!
734                                    (found_it =
735                                     set_dev_to_this_if_rx_OK(output,
736                                                              "/dev/cd1")))
737                                {
738                                    retval = 1;
739                                    goto end_of_find_cdrom_device;
740                                }
741                            }
742                        }
743                    }
744                }
745            }
746        }
747    }
748#else
749    if (!found_it && strlen(dvd_last_resort) > 0) {
750        log_msg(4, "Well, I'll use the DVD - %s - as a last resort", dvd_last_resort);
751        strcpy(output, dvd_last_resort);
752        found_it = TRUE;
753    }
754    mr_free(dvd_last_resort);
755    if (found_it) {
756        sprintf(tmp, "grep \"%s=ide-scsi\" /proc/cmdline &> /dev/null",
757                strrchr(output, '/') + 1);
758        if (system(tmp) == 0) {
759            log_msg(4,
760                    "%s is not right. It's being SCSI-emulated. Continuing.",
761                    output);
762            found_it = FALSE;
763            output[0] = '\0';
764        }
765    }
766
767    if (found_it) {
768        log_msg(4, "(find_cdrom_device) --> '%s'", output);
769        if (!does_device_exist(output)) {
770            found_it = FALSE;
771            log_msg(4, "OK, I was wrong, I haven't found it... yet.");
772        }
773    }
774
775    if (!found_it) {
776        log_msg(4, "OK, approach 2");
777        if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/scd0"))) {
778            if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/sr0"))) {
779                if (!
780                    (found_it =
781                     set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) {
782                    if (!
783                        (found_it =
784                         set_dev_to_this_if_rx_OK(output,
785                                                  "/dev/cdrom0"))) {
786                        if (!
787                            (found_it =
788                             set_dev_to_this_if_rx_OK(output,
789                                                      "/dev/cdrom1"))) {
790                            if (!
791                                (found_it =
792                                 set_dev_to_this_if_rx_OK(output,
793                                                          "/dev/sr1"))) {
794                                if (!
795                                    (found_it =
796                                     set_dev_to_this_if_rx_OK(output,
797                                                              "/dev/dvd")))
798                                {
799                                    if (!
800                                        (found_it =
801                                         set_dev_to_this_if_rx_OK(output,
802                                                                  g_cdrw_drive_is_here)))
803                                    {
804                                        retval = 1;
805                                        goto end_of_find_cdrom_device;
806                                    }
807                                }
808                            }
809                        }
810                    }
811                }
812            }
813        }
814    }
815#endif
816
817    if (found_it && try_to_mount) {
818        if (mount_CDROM_here(output, mountpoint)) {
819            log_msg(4, "[Cardigans] I've changed my mind");
820            found_it = FALSE;
821        } else {
822            sprintf(tmp, "%s/archives", mountpoint);
823            if (!does_file_exist(tmp)) {
824                log_msg(4, "[Cardigans] I'll take it back");
825                found_it = FALSE;
826            } else {
827                mr_asprintf(&command, "umount %s", output);
828                paranoid_system(command);
829                mr_free(command);
830
831                log_msg(4, "I'm confident the Mondo CD is in %s", output);
832            }
833        }
834    }
835    unlink(mountpoint);
836    mr_free(mountpoint);
837
838    if (found_it) {
839        if (!does_file_exist(output)) {
840            log_msg(3, "I still haven't found it.");
841            return (1);
842        }
843        log_msg(3, "(find_cdrom_device) --> '%s'", output);
844        strcpy(the_last_place_i_found_it, output);
845        strcpy(g_cdrom_drive_is_here, output);
846        retval = 0;
847        goto end_of_find_cdrom_device;
848    }
849
850    mr_asprintf(&command,
851            "%s -scanbus | grep \"[0-9],[0-9],[0-9]\" | grep \"[D|C][V|D]\" | grep -n \"\" | grep \"%s\" | cut -d':' -f2",
852            cdr_exe, g_cdrw_drive_is_here);
853    log_msg(1, "command=%s", command);
854    mr_asprintf(&tmp1, "%s", call_program_and_get_last_line_of_output(command));
855    mr_free(command);
856
857    if (strlen(tmp1) > 0) {
858        strcpy(output, tmp1);
859        log_msg(4, "Finally found it at %s", output);
860        retval = 0;
861    } else {
862        log_msg(4, "Still couldn't find it.");
863        retval = 1;
864    }
865    mr_free(tmp1);
866
867  end_of_find_cdrom_device:
868    paranoid_free(tmp);
869    mr_free(cdr_exe);
870    paranoid_free(phrase_one);
871    paranoid_free(phrase_two);
872    return (retval);
873}
874
875
876
877
878
879int find_dvd_device(char *output, bool try_to_mount)
880{
881    char *tmp = NULL;
882    int retval = 0, devno = -1;
883
884    if (g_dvd_drive_is_here[0]) {
885        strcpy(output, g_dvd_drive_is_here);
886        log_msg(3, "Been there, done that. Returning %s", output);
887        return (0);
888    }
889
890    mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output
891            ("dvdrecord -scanbus 2> /dev/null | grep \") '\" | grep -n \"\" | grep DVD | cut -d':' -f1")
892        );
893    log_msg(5, "tmp = '%s'", tmp);
894    if (!tmp[0])
895        mr_free(tmp);
896        mr_asprintf(&tmp, "%s", call_program_and_get_last_line_of_output
897                ("cdrecord -scanbus 2> /dev/null | grep \") '\" | grep -n \"\" | grep DVD | cut -d':' -f1")
898            );
899    if (tmp[0]) {
900        devno = atoi(tmp) - 1;
901    }
902    mr_free(tmp);
903
904    if (devno >= 0) {
905        retval = 0;
906        sprintf(output, "/dev/scd%d", devno);
907        strcpy(g_dvd_drive_is_here, output);
908        log_msg(2, "I think DVD is at %s", output);
909    } else {
910        log_msg(2, "I cannot find DVD");
911        retval = 1;
912    }
913
914    if (try_to_mount) {
915        log_msg(1, "Ignoring the fact that try_to_mount==TRUE");
916    }
917    return (retval);
918}
919
920
921
922
923
924#include <sys/ioctl.h>
925
926/**
927 * Find the size of the specified @p drive, in megabytes. Uses @c ioctl calls
928 * and @c dmesg.
929 * @param drive The device to find the size of.
930 * @return size in megabytes.
931 */
932long get_phys_size_of_drive(char *drive)
933{
934    int fd;
935#if linux
936    unsigned long long s = 0;
937    int fileid, cylinders = 0, cylindersleft = 0;
938    int cylindersize = 0;
939    int gotgeo = 0;
940
941
942    struct hd_geometry hdgeo;
943#elif __FreeBSD__
944    off_t s;
945#endif
946
947    long outvalA = -1;
948    long outvalB = -1;
949    long outvalC = -1;
950
951    if ((fd = open(drive, O_RDONLY)) != -1) {
952        if (ioctl(fd,
953#if linux
954#ifdef BLKGETSIZE64
955                  BLKGETSIZE64,
956#else
957                  BLKGETSIZE,
958#endif
959#elif __FreeBSD__
960                  DIOCGMEDIASIZE,
961#endif
962                  &s) != -1) {
963            close(fd);
964            // s>>11 works for older disks but not for newer ones
965            outvalB =
966#if linux
967#ifdef BLKGETSIZE64
968                s >> 20
969#else
970                s >> 11
971#endif
972#else
973                s >> 20
974#endif
975                ;
976        }
977    }
978
979    if (outvalB <= 0) {
980        log_msg(1, "Error getting size of %s: %s", drive, strerror(errno));
981#if linux
982        fileid = open(drive, O_RDONLY);
983        if (fileid != -1) {
984            if (ioctl(fileid, HDIO_GETGEO, &hdgeo) != -1) {
985                if (hdgeo.cylinders && hdgeo.heads && hdgeo.sectors) {
986                    cylindersleft = cylinders = hdgeo.cylinders;
987                    cylindersize = hdgeo.heads * hdgeo.sectors / 2;
988                    outvalA = cylindersize * cylinders / 1024;
989                    log_msg(2, "Got Harddisk geometry, C:%d, H:%d, S:%d",
990                            hdgeo.cylinders, hdgeo.heads, hdgeo.sectors);
991                    gotgeo = 1;
992                } else {
993                    log_msg(1, "Harddisk geometry wrong");
994                }
995            } else {
996                log_msg(1,
997                        "Error in ioctl() getting new hard disk geometry (%s), resizing in unsafe mode",
998                        strerror(errno));
999            }
1000            close(fileid);
1001        } else {
1002            log_msg(1, "Failed to open %s for reading: %s", drive,
1003                    strerror(errno));
1004        }
1005        if (!gotgeo) {
1006            log_msg(1, "Failed to get harddisk geometry, using old mode");
1007        }
1008#endif
1009    }
1010// OLDER DISKS will give ridiculously low value for outvalB (so outvalA is returned) :)
1011// NEWER DISKS will give sane value for outvalB (close to outvalA, in other words) :)
1012
1013    outvalC = (outvalA > outvalB) ? outvalA : outvalB;
1014
1015//  log_msg (5, "drive = %s, error = %s", drive, strerror (errno));
1016//  fatal_error ("GPSOD: Unable to get size of drive");
1017    log_msg(1, "%s --> %ld or %ld --> %ld", drive, outvalA, outvalB,
1018            outvalC);
1019
1020    return (outvalC);
1021}
1022
1023/**
1024 * Determine whether @p format is supported by the kernel. Uses /proc/filesystems
1025 * under Linux and @c lsvfs under FreeBSD.
1026 * @param format The format to test.
1027 * @return TRUE if the format is supported, FALSE if not.
1028 */
1029bool is_this_a_valid_disk_format(char *format)
1030{
1031    char *good_formats = NULL;
1032    char *command = NULL;
1033    char *format_sz = NULL;
1034
1035    FILE *pin;
1036    int retval;
1037    malloc_string(good_formats);
1038
1039    assert_string_is_neither_NULL_nor_zerolength(format);
1040
1041    mr_asprintf(&format_sz, "%s ", format);
1042
1043#ifdef __FreeBSD__
1044    mr_asprintf(&command,
1045            "lsvfs | tr -s '\t' ' ' | grep -v Filesys | grep -v -- -- | cut -d' ' -f1 | tr -s '\n' ' '");
1046#else
1047    mr_asprintf(&command,
1048            "grep -v nodev /proc/filesystems | tr -s '\t' ' ' | cut -d' ' -f2 | tr -s '\n' ' '");
1049#endif
1050
1051    pin = popen(command, "r");
1052    mr_free(command);
1053
1054    if (!pin) {
1055        log_OS_error("Unable to read good formats");
1056        retval = 0;
1057    } else {
1058        strcpy(good_formats, " ");
1059        (void) fgets(good_formats + 1, MAX_STR_LEN - 1, pin);
1060        if (pclose(pin)) {
1061            log_OS_error("Cannot pclose good formats");
1062        }
1063        strip_spaces(good_formats);
1064        strcat(good_formats, " swap lvm raid ntfs-3g ntfs 7 "); // " ntfs 7 " -- um, cheating much? :)
1065        if (strstr(good_formats, format_sz)) {
1066            retval = 1;
1067        } else {
1068            retval = 0;
1069        }
1070    }
1071    mr_free(format_sz);
1072
1073    paranoid_free(good_formats);
1074    return (retval);
1075}
1076
1077
1078/** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */
1079
1080/**
1081 * Determine whether @p device_raw is currently mounted.
1082 * @param device_raw The device to check.
1083 * @return TRUE if it's mounted, FALSE if not.
1084 */
1085bool is_this_device_mounted(char *device_raw)
1086{
1087
1088    /*@ pointers **************************************************** */
1089    FILE *fin;
1090
1091    /*@ buffers ***************************************************** */
1092    char *incoming;
1093    char *device_with_tab = NULL;
1094    char *device_with_space = NULL;
1095    char *tmp = NULL;
1096    bool retval = FALSE;
1097
1098#ifdef __FreeBSD__
1099#define SWAPLIST_COMMAND "swapinfo"
1100#else
1101#define SWAPLIST_COMMAND "cat /proc/swaps"
1102#endif
1103
1104    /*@ end vars **************************************************** */
1105
1106    malloc_string(incoming);
1107    assert(device_raw != NULL);
1108//  assert_string_is_neither_NULL_nor_zerolength(device_raw);
1109    if (device_raw[0] != '/' && !strstr(device_raw, ":/")) {
1110        log_msg(1, "%s needs to have a '/' prefixed - I'll do it",
1111                device_raw);
1112        mr_asprintf(&tmp, "/%s", device_raw);
1113    } else {
1114        mr_asprintf(&tmp, "%s", device_raw);
1115    }
1116    log_msg(1, "Is %s mounted?", tmp);
1117    if (!strcmp(tmp, "/proc") || !strcmp(tmp, "proc")) {
1118        log_msg(1,
1119                "I don't know how the heck /proc made it into the mountlist. I'll ignore it.");
1120        mr_free(tmp);
1121        return(FALSE);
1122    }
1123    mr_asprintf(&device_with_tab, "%s\t", tmp);
1124    mr_asprintf(&device_with_space, "%s ", tmp);
1125    mr_free(tmp);
1126
1127    if (!(fin = popen("mount", "r"))) {
1128        log_OS_error("Cannot popen 'mount'");
1129        return(FALSE);
1130    }
1131    for ((void)fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
1132         (void)fgets(incoming, MAX_STR_LEN - 1, fin)) {
1133        if (strstr(incoming, device_with_space) //> incoming
1134            || strstr(incoming, device_with_tab))   // > incoming)
1135        {
1136            paranoid_pclose(fin);
1137            paranoid_free(incoming);
1138            return(TRUE);
1139        }
1140    }
1141    mr_free(device_with_tab);
1142    mr_free(device_with_space);
1143    paranoid_pclose(fin);
1144    mr_asprintf(&tmp, "%s | grep -E \"^%s\" > /dev/null 2> /dev/null",
1145            SWAPLIST_COMMAND, device_with_space);
1146    log_msg(4, "tmp (command) = '%s'", tmp);
1147    if (!system(tmp)) {
1148        retval = TRUE;
1149    }
1150    mr_free(tmp);
1151    paranoid_free(incoming);
1152    return(retval);
1153}
1154
1155#ifdef __FreeBSD__
1156//                       CODE IS FREEBSD-SPECIFIC
1157/**
1158 * Create a loopback device for specified @p fname.
1159 * @param fname The file to associate with a device.
1160 * @return /dev entry for the device, or NULL if it couldn't be allocated.
1161 */
1162char *make_vn(char *fname)
1163{
1164    char *device = (char *) malloc(MAX_STR_LEN);
1165    char *mddevice = (char *) malloc(32);
1166    char command[MAX_STR_LEN];
1167    int vndev = 2;
1168    if (atoi
1169        (call_program_and_get_last_line_of_output
1170         ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1171        do {
1172            sprintf(mddevice, "vn%ic", vndev++);
1173            sprintf(command, "vnconfig %s %s", mddevice, fname);
1174            if (vndev > 10) {
1175                return NULL;
1176            }
1177        }
1178        while (system(command));
1179    } else {
1180        sprintf(command, "mdconfig -a -t vnode -f %s", fname);
1181        mddevice = call_program_and_get_last_line_of_output(command);
1182        if (!strstr(mddevice, "md")) {
1183            return NULL;
1184        }
1185    }
1186    sprintf(device, "/dev/%s", mddevice);
1187    return device;
1188}
1189
1190
1191
1192//                       CODE IS FREEBSD-SPECIFIC
1193/**
1194 * Deallocate specified @p dname.
1195 * This should be called when you are done with the device created by make_vn(),
1196 * so the system does not run out of @c vn devices.
1197 * @param dname The device to deallocate.
1198 * @return 0 for success, nonzero for failure.
1199 */
1200int kick_vn(char *dname)
1201{
1202    char *command = NULL;
1203    int res = 0;
1204
1205    if (strncmp(dname, "/dev/", 5) == 0) {
1206        dname += 5;
1207    }
1208
1209    if (atoi
1210        (call_program_and_get_last_line_of_output
1211         ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1212        mr_asprintf(&command, "vnconfig -d %s", dname);
1213    } else {
1214        mr_asprintf(&command, "mdconfig -d -u %s", dname);
1215    }
1216    res = system(command);
1217    mr_free(command);
1218    return(res);
1219}
1220#endif
1221
1222
1223/**
1224 * Mount the CD-ROM at @p mountpoint.
1225 * @param device The device (or file if g_ISO_restore_mode) to mount.
1226 * @param mountpoint The place to mount it.
1227 * @return 0 for success, nonzero for failure.
1228 */
1229int mount_USB_here(char *device, char *mountpoint)
1230{
1231    /*@ buffer ****************************************************** */
1232    char *command = NULL;
1233    int retval;
1234
1235    assert_string_is_neither_NULL_nor_zerolength(device);
1236    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1237
1238    make_hole_for_dir(mountpoint);
1239    if (isdigit(device[0])) {
1240        return(1);
1241    }
1242    log_msg(4, "(mount_USB_here --- device=%s, mountpoint=%s", device,
1243            mountpoint);
1244
1245#ifdef __FreeBSD__
1246    mr_asprintf(&command, "mount_vfat %s %s 2>> %s",
1247            device, mountpoint, MONDO_LOGFILE);
1248
1249#else
1250    mr_asprintf(&command, "mount %s -t vfat %s 2>> %s",
1251            device, mountpoint, MONDO_LOGFILE);
1252#endif
1253
1254    log_msg(4, command);
1255    retval = system(command);
1256    log_msg(1, "system(%s) returned %d", command, retval);
1257    mr_free(command);
1258
1259    return (retval);
1260}
1261
1262/**
1263 * Mount the CD-ROM at @p mountpoint.
1264 * @param device The device (or file if g_ISO_restore_mode) to mount.
1265 * @param mountpoint The place to mount it.
1266 * @return 0 for success, nonzero for failure.
1267 */
1268int mount_CDROM_here(char *device, char *mountpoint)
1269{
1270    /*@ buffer ****************************************************** */
1271    char *command = NULL;
1272    int retval;
1273#ifdef __FreeBSD__
1274    char *dev = NULL;
1275#else
1276    char *options = NULL;
1277#endif
1278
1279    assert_string_is_neither_NULL_nor_zerolength(device);
1280    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1281
1282    make_hole_for_dir(mountpoint);
1283
1284    if (isdigit(device[0])) {
1285        find_cdrom_device(device, FALSE);
1286    }
1287#ifndef __FreeBSD__
1288    mr_asprintf(&options, "ro");
1289#endif
1290
1291    if (g_ISO_restore_mode) {
1292
1293#ifdef __FreeBSD__
1294        mr_asprintf(&dev, make_vn(device));
1295        if (!dev) {
1296            mr_asprintf(&command, "Unable to mount ISO (make_vn(%s) failed)", device);
1297            fatal_error(command);
1298        }
1299        strcpy(device, dev);
1300        paranoid_free(dev);
1301#else
1302        mr_strcat(options, ",loop");
1303#endif
1304
1305    }
1306    log_msg(4, "(mount_CDROM_here --- device=%s, mountpoint=%s", device,
1307            mountpoint);
1308    /*@ end vars *************************************************** */
1309
1310#ifdef __FreeBSD__
1311    mr_asprintf(&command, "mount_cd9660 -r %s %s 2>> %s",
1312            device, mountpoint, MONDO_LOGFILE);
1313
1314#else
1315    mr_asprintf(&command, "mount %s -o %s -t iso9660 %s 2>> %s",
1316            device, options, mountpoint, MONDO_LOGFILE);
1317    paranoid_free(options);
1318#endif
1319
1320    log_msg(4, command);
1321    if (strncmp(device, "/dev/", 5) == 0) {
1322        retract_CD_tray_and_defeat_autorun();
1323    }
1324    retval = system(command);
1325    log_msg(1, "system(%s) returned %d", command, retval);
1326    paranoid_free(command);
1327
1328    return (retval);
1329}
1330
1331
1332
1333
1334
1335
1336/**
1337 * Ask the user for CD number @p cd_number_i_want.
1338 * Sets g_current_media_number once the correct CD is inserted.
1339 * @param bkpinfo The backup information structure. Fields used:
1340 * - @c bkpinfo->backup_media_type
1341 * - @c bkpinfo->prefix
1342 * - @c bkpinfo->isodir
1343 * - @c bkpinfo->media_device
1344 * - @c bkpinfo->please_dont_eject_when_restoring
1345 * @param cd_number_i_want The CD number to ask for.
1346 */
1347void
1348insist_on_this_cd_number(int cd_number_i_want)
1349{
1350
1351    /*@ int ************************************************************* */
1352    int res = 0;
1353
1354
1355    /*@ buffers ********************************************************* */
1356    char *tmp = NULL;
1357    char *mds = NULL;
1358    char *request = NULL;
1359
1360    assert(bkpinfo != NULL);
1361    assert(cd_number_i_want > 0);
1362
1363//  log_msg(3, "Insisting on CD number %d", cd_number_i_want);
1364
1365    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1366        log_msg(3,
1367                "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1368        return;
1369    }
1370    mr_asprintf(&tmp, "mkdir -p " MNT_CDROM);
1371    run_program_and_log_output(tmp, 5);
1372    mr_free(tmp);
1373
1374    if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso
1375        || bkpinfo->backup_media_type == nfs) {
1376        log_msg(3, "Remounting CD");
1377        g_ISO_restore_mode = TRUE;
1378        // FIXME --- I'm tempted to do something about this...
1379        // Why unmount and remount again and again?
1380        if (is_this_device_mounted(MNT_CDROM)) {
1381            run_program_and_log_output("umount " MNT_CDROM, 5);
1382        }
1383        mr_asprintf(&tmp, "mkdir -p %s/isodir &> /dev/null", bkpinfo->tmpdir);
1384        (void)system(tmp);
1385        mr_free(tmp);
1386
1387        mr_asprintf(&tmp, "%s/%s/%s-%d.iso", bkpinfo->isodir,
1388                bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1389                cd_number_i_want);
1390        if (!does_file_exist(tmp)) {
1391            mr_free(tmp);
1392            mr_asprintf(&tmp, "%s/isodir/%s/%s-%d.iso", bkpinfo->tmpdir,
1393                    bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1394                    cd_number_i_want);
1395            if (does_file_exist(tmp)) {
1396                log_msg(1,
1397                        "FIXME - hacking bkpinfo->isodir from '%s' to %s/isodir",
1398                        bkpinfo->isodir, bkpinfo->tmpdir);
1399                sprintf(bkpinfo->isodir, "%s/isodir", bkpinfo->tmpdir);
1400            }
1401        }
1402        log_msg(3, "Mounting %s at %s", tmp, MNT_CDROM);
1403        if (mount_CDROM_here(tmp, MNT_CDROM)) {
1404            mr_free(tmp);
1405            fatal_error("Mommy!");
1406        }
1407        mr_free(tmp);
1408    }
1409    if ((res = what_number_cd_is_this()) != cd_number_i_want) {
1410        log_msg(3, "Currently, we hold %d but we want %d", res,
1411                cd_number_i_want);
1412        mds = media_descriptor_string(bkpinfo->backup_media_type);
1413        mr_asprintf(&tmp, "Insisting on %s #%d", mds, cd_number_i_want);
1414        mr_asprintf(&request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want);
1415        mr_free(mds);
1416        log_msg(3, tmp);
1417        mr_free(tmp);
1418
1419        while (what_number_cd_is_this() != cd_number_i_want) {
1420            paranoid_system("sync");
1421            if (is_this_device_mounted(MNT_CDROM)) {
1422                res =
1423                    run_program_and_log_output("umount " MNT_CDROM, FALSE);
1424            } else {
1425                res = 0;
1426            }
1427            if (res) {
1428                log_to_screen("WARNING - failed to unmount CD-ROM drive");
1429            }
1430            if (!bkpinfo->please_dont_eject) {
1431                res = eject_device(bkpinfo->media_device);
1432            } else {
1433                res = 0;
1434            }
1435            if (res) {
1436                log_to_screen("WARNING - failed to eject CD-ROM disk");
1437            }
1438            popup_and_OK(request);
1439            if (!bkpinfo->please_dont_eject) {
1440                inject_device(bkpinfo->media_device);
1441            }
1442            paranoid_system("sync");
1443        }
1444        mr_free(request);
1445
1446        log_msg(1, "Thankyou. Proceeding...");
1447        g_current_media_number = cd_number_i_want;
1448    }
1449}
1450
1451/* @} - end of deviceGroup */
1452
1453
1454/**
1455 * Ask user for details of backup/restore information.
1456 * Called when @c mondoarchive doesn't get any parameters.
1457 * @param bkpinfo The backup information structure to fill out with the user's data.
1458 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
1459 * @return 0, always.
1460 * @bug No point of `int' return value.
1461 * @ingroup archiveGroup
1462 */
1463int interactively_obtain_media_parameters_from_user(bool archiving_to_media)
1464// archiving_to_media is TRUE if I'm being called by mondoarchive
1465// archiving_to_media is FALSE if I'm being called by mondorestore
1466{
1467    char *tmp = NULL;
1468    char *mds = NULL;
1469    char *sz_size = NULL;
1470    char *command = NULL;
1471    char *comment = NULL;
1472    char *prompt;
1473    int i;
1474    FILE *fin;
1475
1476    malloc_string(prompt);
1477    malloc_string(sz_size);
1478    assert(bkpinfo != NULL);
1479    bkpinfo->nonbootable_backup = FALSE;
1480
1481    // Tape, CD, NFS, ...?
1482    srandom(getpid());
1483    bkpinfo->backup_media_type =
1484        (g_restoring_live_from_cd) ? cdr :
1485        which_backup_media_type(bkpinfo->restore_data);
1486    if (bkpinfo->backup_media_type == none) {
1487        log_to_screen("User has chosen not to backup the PC");
1488        finish(1);
1489    }
1490    /* Why asking to remove the media with tape ?
1491    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
1492        popup_and_OK("Please remove media from drive(s)");
1493    }
1494    */
1495    log_msg(3, "media type = %s",
1496            bkptype_to_string(bkpinfo->backup_media_type));
1497    if (archiving_to_media) {
1498        sensibly_set_tmpdir_and_scratchdir();
1499    }
1500    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
1501    bkpinfo->compression_level =
1502        (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
1503    bkpinfo->use_lzo =
1504        (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
1505    mvaddstr_and_log_it(2, 0, " ");
1506
1507    // Find device's /dev (or SCSI) entry
1508    switch (bkpinfo->backup_media_type) {
1509    case cdr:
1510    case cdrw:
1511    case dvd:
1512    case usb:
1513        /* Never try to eject a USB device */
1514        if (bkpinfo->backup_media_type == usb) {
1515            bkpinfo->please_dont_eject = TRUE;
1516        }
1517        if (archiving_to_media) {
1518            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1519                if (ask_me_yes_or_no
1520                    ("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?"))
1521                {
1522                    bkpinfo->manual_cd_tray = TRUE;
1523                }
1524            }
1525            if ((bkpinfo->compression_level =
1526                 which_compression_level()) == -1) {
1527                log_to_screen("User has chosen not to backup the PC");
1528                finish(1);
1529            }
1530            mds = media_descriptor_string(bkpinfo->backup_media_type);
1531            mr_asprintf(&comment, "What speed is your %s (re)writer?", mds);
1532            if (bkpinfo->backup_media_type == dvd) {
1533                find_dvd_device(bkpinfo->media_device, FALSE);
1534                mr_asprintf(&tmp, "1");
1535                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
1536                log_msg(1, "Setting to DVD defaults");
1537            } else {
1538                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
1539                mr_asprintf(&tmp, "4");
1540                sprintf(sz_size, "%d", 650);
1541                log_msg(1, "Setting to CD defaults");
1542            }
1543            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1544                if (!popup_and_get_string("Speed", comment, tmp, 4)) {
1545                    log_to_screen("User has chosen not to backup the PC");
1546                    mr_free(comment);
1547                    finish(1);
1548                }
1549            }
1550            mr_free(comment);
1551
1552            bkpinfo->cdrw_speed = atoi(tmp);    // if DVD then this shouldn't ever be used anyway :)
1553            mr_free(tmp);
1554
1555            mr_asprintf(&comment,
1556                    "How much data (in Megabytes) will each %s store?", mds);
1557            mr_free(mds);
1558            if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1559                mr_free(comment);
1560                log_to_screen("User has chosen not to backup the PC");
1561                finish(1);
1562            }
1563            mr_free(comment);
1564
1565            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1566                bkpinfo->media_size[i] = atoi(sz_size);
1567            }
1568
1569            if (bkpinfo->media_size[0] <= 0) {
1570                log_to_screen("User has chosen not to backup the PC");
1571                finish(1);
1572            }
1573        }
1574        /* No break because we continue even for usb */
1575    case cdstream:
1576        mds = media_descriptor_string(bkpinfo->backup_media_type);
1577
1578        if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
1579            strcpy(bkpinfo->media_device, "/dev/cdrom");
1580            log_msg(2, "CD-ROM device assumed to be at %s",
1581                    bkpinfo->media_device);
1582        } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))
1583                   || bkpinfo->backup_media_type == dvd) {
1584            if (!bkpinfo->media_device[0]) {
1585                strcpy(bkpinfo->media_device, "/dev/cdrom");
1586            }                   // just for the heck of it :)
1587            log_msg(1, "bkpinfo->media_device = %s",
1588                    bkpinfo->media_device);
1589            if (bkpinfo->backup_media_type == dvd
1590                || find_cdrom_device(bkpinfo->media_device, FALSE)) {
1591                log_msg(1, "bkpinfo->media_device = %s",
1592                        bkpinfo->media_device);
1593                mr_asprintf(&comment,
1594                        "Please specify your %s drive's /dev entry", mds);
1595                if (!popup_and_get_string
1596                    ("Device?", comment, bkpinfo->media_device,
1597                     MAX_STR_LEN / 4)) {
1598                    mr_free(comment);
1599                    log_to_screen("User has chosen not to backup the PC");
1600                    finish(1);
1601                }
1602                mr_free(comment);
1603            }
1604            log_msg(2, "%s device found at %s", mds, bkpinfo->media_device);
1605        } else {
1606            if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) {
1607                bkpinfo->media_device[0] = '\0';
1608            }
1609            if (bkpinfo->media_device[0]) {
1610                if (bkpinfo->backup_media_type == usb) {
1611                    mr_asprintf(&tmp,
1612                        "I think your %s media corresponds to %s. Is this correct?", mds,
1613                        bkpinfo->media_device);
1614                } else {
1615                    mr_asprintf(&tmp,
1616                        "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,
1617                        bkpinfo->media_device);
1618                }
1619                if (!ask_me_yes_or_no(tmp)) {
1620                    bkpinfo->media_device[0] = '\0';
1621                }
1622                mr_free(tmp);
1623            }
1624            if (!bkpinfo->media_device[0]) {
1625                if (bkpinfo->backup_media_type == usb) {
1626                    i = popup_and_get_string("/dev entry?",
1627                                         "What is the /dev entry of your USB Disk/Key, please?",
1628                                         bkpinfo->media_device,
1629                                         MAX_STR_LEN / 4);
1630                } else {
1631                    if (g_kernel_version < 2.6) {
1632                        i = popup_and_get_string("Device node?",
1633                                             "What is the SCSI node of your CD (re)writer, please?",
1634                                             bkpinfo->media_device,
1635                                             MAX_STR_LEN / 4);
1636                    } else {
1637                        i = popup_and_get_string("/dev entry?",
1638                                             "What is the /dev entry of your CD (re)writer, please?",
1639                                             bkpinfo->media_device,
1640                                             MAX_STR_LEN / 4);
1641                    }
1642                }
1643                if (!i) {
1644                    log_to_screen("User has chosen not to backup the PC");
1645                    finish(1);
1646                }
1647            }
1648        }
1649        mr_free(mds);
1650
1651        if (bkpinfo->backup_media_type == cdstream) {
1652            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1653                bkpinfo->media_size[i] = 650;
1654            }
1655        }
1656        break;
1657    case udev:
1658        if (!ask_me_yes_or_no
1659            ("This option is for advanced users only. Are you sure?")) {
1660            log_to_screen("User has chosen not to backup the PC");
1661            finish(1);
1662        }
1663    case tape:
1664
1665        if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) {
1666            log_msg(3, "Ok, using vanilla scsi tape.");
1667            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
1668            if ((fin = fopen(bkpinfo->media_device, "r"))) {
1669                paranoid_fclose(fin);
1670            } else {
1671                strcpy(bkpinfo->media_device, "/dev/osst0");
1672            }
1673        }
1674        if (bkpinfo->media_device[0]) {
1675            if ((fin = fopen(bkpinfo->media_device, "r"))) {
1676                paranoid_fclose(fin);
1677            } else {
1678                if (does_file_exist("/tmp/mondo-restore.cfg")) {
1679                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
1680                                 bkpinfo->media_device);
1681                }
1682            }
1683        }
1684        if (bkpinfo->media_device[0]) {
1685            mr_asprintf(&tmp,
1686                    "I think I've found your tape streamer at %s; am I right on the money?",
1687                    bkpinfo->media_device);
1688            if (!ask_me_yes_or_no(tmp)) {
1689                bkpinfo->media_device[0] = '\0';
1690            }
1691            mr_free(tmp);
1692        }
1693        if (!bkpinfo->media_device[0]) {
1694            if (!popup_and_get_string
1695                ("Device name?",
1696                 "What is the /dev entry of your tape streamer?",
1697                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
1698                log_to_screen("User has chosen not to backup the PC");
1699                finish(1);
1700            }
1701        }
1702        mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
1703        if (run_program_and_log_output(tmp, FALSE)) {
1704            log_to_screen("User has not specified a valid /dev entry");
1705            finish(1);
1706        }
1707        mr_free(tmp);
1708
1709        bkpinfo->use_obdr = ask_me_yes_or_no
1710            ("Do you want to activate OBDR support for your tapes ?");
1711        bkpinfo->media_size[0] = 0;
1712        log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
1713        if (bkpinfo->media_size[0] <= 0) {
1714            bkpinfo->media_size[0] = 0;
1715        }
1716        for (i = 1; i <= MAX_NOOF_MEDIA; i++) {
1717            bkpinfo->media_size[i] = bkpinfo->media_size[0];
1718        }
1719        if (archiving_to_media) {
1720            if ((bkpinfo->compression_level =
1721                 which_compression_level()) == -1) {
1722                log_to_screen("User has chosen not to backup the PC");
1723                finish(1);
1724            }
1725        }
1726        break;
1727
1728
1729
1730    case nfs:
1731        /* Never try to eject a NFS device */
1732        bkpinfo->please_dont_eject = TRUE;
1733
1734        /* Initiate bkpinfo nfs_mount path from running environment if not already done */
1735        if (!bkpinfo->nfs_mount[0]) {
1736            strcpy(bkpinfo->nfs_mount,
1737                   call_program_and_get_last_line_of_output
1738                   ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
1739        }
1740#ifdef __FreeBSD__
1741        if (TRUE)
1742#else
1743        if (!bkpinfo->disaster_recovery)
1744#endif
1745        {
1746            if (!popup_and_get_string
1747                ("NFS dir.",
1748                 "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.)",
1749                 bkpinfo->nfs_mount, MAX_STR_LEN / 4)) {
1750                log_to_screen("User has chosen not to backup the PC");
1751                finish(1);
1752            }
1753            if (!bkpinfo->restore_data) {
1754                if ((bkpinfo->compression_level =
1755                     which_compression_level()) == -1) {
1756                    log_to_screen("User has chosen not to backup the PC");
1757                    finish(1);
1758                }
1759            }
1760            // check whether already mounted - we better remove
1761            // surrounding spaces and trailing '/' for this
1762            strip_spaces(bkpinfo->nfs_mount);
1763            if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
1764                bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
1765            mr_asprintf(&command, "mount | grep \"%s \" | cut -d' ' -f3",
1766                    bkpinfo->nfs_mount);
1767            strcpy(bkpinfo->isodir,
1768                   call_program_and_get_last_line_of_output(command));
1769            mr_free(command);
1770
1771            if (!bkpinfo->restore_data) {
1772                mr_asprintf(&comment,
1773                    "How much data (in Megabytes) will each media store?");
1774                if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1775                    mr_free(comment);
1776                    log_to_screen("User has chosen not to backup the PC");
1777                    finish(1);
1778                }
1779                mr_free(comment);
1780            } else {
1781                strcpy(sz_size, "0");
1782            }
1783            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1784                bkpinfo->media_size[i] = atoi(sz_size);
1785            }
1786            if (bkpinfo->media_size[0] < 0) {
1787                log_to_screen("User has chosen not to backup the PC");
1788                finish(1);
1789            }
1790        }
1791        if (bkpinfo->disaster_recovery) {
1792            mr_asprintf(&command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
1793            (void)system(command);
1794            mr_free(command);
1795
1796            if (!popup_and_get_string
1797                ("NFS share", "Which remote NFS share should I mount?",
1798                 bkpinfo->nfs_mount, MAX_STR_LEN)) {
1799                log_to_screen("User has chosen not to backup the PC");
1800                finish(1);
1801            }
1802        }
1803        /* Initiate bkpinfo isodir path from running environment if mount already done */
1804        if (is_this_device_mounted(bkpinfo->nfs_mount)) {
1805            strcpy(bkpinfo->isodir,
1806                   call_program_and_get_last_line_of_output
1807                   ("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
1808        } else {
1809            sprintf(bkpinfo->isodir, "%s/nfsdir", bkpinfo->tmpdir);
1810            mr_asprintf(&command, "mkdir -p %s", bkpinfo->isodir);
1811            run_program_and_log_output(command, 5);
1812            mr_free(command);
1813
1814            mr_asprintf(&tmp, "mount -t nfs -o nolock %s %s", bkpinfo->nfs_mount,
1815                    bkpinfo->isodir);
1816            run_program_and_log_output(tmp, 3);
1817            mr_free(tmp);
1818
1819            malloc_string(g_selfmounted_isodir);
1820            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
1821        }
1822        if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1823            popup_and_OK
1824                ("Please mount that partition before you try to backup to or restore from it.");
1825            finish(1);
1826        }
1827        mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1828        if (!popup_and_get_string
1829            ("Directory", "Which directory within that mountpoint?", tmp,
1830             MAX_STR_LEN)) {
1831            log_to_screen("User has chosen not to backup the PC");
1832            finish(1);
1833        }
1834        strcpy(bkpinfo->nfs_remote_dir, tmp);
1835        mr_free(tmp);
1836
1837        // check whether writable - we better remove surrounding spaces for this
1838        strip_spaces(bkpinfo->nfs_remote_dir);
1839
1840        if (!popup_and_get_string
1841            ("Prefix.",
1842             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
1843            bkpinfo->prefix, MAX_STR_LEN / 4)) {
1844            log_to_screen("User has chosen not to backup the PC");
1845            finish(1);
1846        }
1847        log_msg(3, "prefix set to %s", bkpinfo->prefix);
1848
1849        for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1850            bkpinfo->media_size[i] = 650;
1851        }
1852        log_msg(3, "Just set nfs_remote_dir to %s",
1853                bkpinfo->nfs_remote_dir);
1854        log_msg(3, "isodir is still %s", bkpinfo->isodir);
1855        break;
1856
1857    case iso:
1858        if (!bkpinfo->disaster_recovery) {
1859            if (!popup_and_get_string
1860                ("Storage dir.",
1861                 "Please enter the full path name to the directory for your ISO images.  Example: /mnt/raid0_0",
1862                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
1863                log_to_screen("User has chosen not to backup the PC");
1864                finish(1);
1865            }
1866            if (archiving_to_media) {
1867                if ((bkpinfo->compression_level =
1868                     which_compression_level()) == -1) {
1869                    log_to_screen("User has chosen not to backup the PC");
1870                    finish(1);
1871                }
1872                if (!popup_and_get_string
1873                    ("ISO size.",
1874                     "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 or DVD's you plan to backup to.",
1875                     sz_size, 16)) {
1876                    log_to_screen("User has chosen not to backup the PC");
1877                    finish(1);
1878                }
1879                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1880                    bkpinfo->media_size[i] = atoi(sz_size);
1881                }
1882            } else {
1883                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1884                    bkpinfo->media_size[i] = 650;
1885                }
1886            }
1887        }
1888        if (!popup_and_get_string
1889            ("Prefix.",
1890             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
1891             bkpinfo->prefix, MAX_STR_LEN / 4)) {
1892            log_to_screen("User has chosen not to backup the PC");
1893            finish(1);
1894        }
1895        log_msg(3, "prefix set to %s", bkpinfo->prefix);
1896        break;
1897    default:
1898        fatal_error
1899            ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
1900    }
1901
1902    if (archiving_to_media) {
1903
1904#ifdef __FreeBSD__
1905        strcpy(bkpinfo->boot_device,
1906               call_program_and_get_last_line_of_output
1907               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
1908#else
1909        strcpy(bkpinfo->boot_device,
1910               call_program_and_get_last_line_of_output
1911               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
1912#endif
1913        i = which_boot_loader(bkpinfo->boot_device);
1914        if (i == 'U')           // unknown
1915        {
1916
1917#ifdef __FreeBSD__
1918            if (!popup_and_get_string
1919                ("Boot device",
1920                 "What is your boot device? (e.g. /dev/ad0)",
1921                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1922                log_to_screen("User has chosen not to backup the PC");
1923                finish(1);
1924            }
1925            i = which_boot_loader(bkpinfo->boot_device);
1926#else
1927            if (!popup_and_get_string
1928                ("Boot device",
1929                 "What is your boot device? (e.g. /dev/hda)",
1930                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1931                log_to_screen("User has chosen not to backup the PC");
1932                finish(1);
1933            }
1934            if (does_string_exist_in_boot_block
1935                (bkpinfo->boot_device, "LILO")) {
1936                i = 'L';
1937            } else
1938                if (does_string_exist_in_boot_block
1939                    (bkpinfo->boot_device, "ELILO")) {
1940                i = 'E';
1941            } else
1942                if (does_string_exist_in_boot_block
1943                    (bkpinfo->boot_device, "GRUB")) {
1944                i = 'G';
1945            } else {
1946                i = 'U';
1947            }
1948#endif
1949            if (i == 'U') {
1950                if (ask_me_yes_or_no
1951                    ("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?"))
1952                {
1953                    i = 'R';    // raw
1954                } else {
1955                    log_to_screen
1956                        ("I cannot find your boot loader. Please run mondoarchive with parameters.");
1957                    finish(1);
1958                }
1959            }
1960        }
1961        bkpinfo->boot_loader = i;
1962        strcpy(bkpinfo->include_paths, "/");
1963        if (!popup_and_get_string
1964            ("Backup paths",
1965             "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
1966             bkpinfo->include_paths, MAX_STR_LEN)) {
1967            log_to_screen("User has chosen not to backup the PC");
1968            finish(1);
1969        }
1970        mr_asprintf(&tmp, "%s", list_of_NFS_mounts_only());
1971        if (strlen(tmp) > 2) {
1972            if (bkpinfo->exclude_paths[0]) {
1973                strcat(bkpinfo->exclude_paths, " ");
1974            }
1975            strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
1976        }
1977        mr_free(tmp);
1978// NTFS
1979        mr_asprintf(&tmp, "%s",
1980               call_program_and_get_last_line_of_output
1981               ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
1982        if (strlen(tmp) > 2) {
1983            if (!popup_and_get_string
1984                ("NTFS partitions",
1985                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
1986                 tmp, MAX_STR_LEN / 4)) {
1987                log_to_screen("User has chosen not to backup the PC");
1988                finish(1);
1989            }
1990            strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
1991        }
1992        mr_free(tmp);
1993
1994
1995        if (!popup_and_get_string
1996            ("Exclude paths",
1997             "Please enter paths which you do NOT want to backup. Separate them with spaces. NB: /tmp and /proc are always excluded. :-) Just hit 'Enter' if you want to do a full system backup.",
1998             bkpinfo->exclude_paths, (4*MAX_STR_LEN)-1)) {
1999            log_to_screen("User has chosen not to backup the PC");
2000            finish(1);
2001        }
2002        if (!popup_and_get_string
2003            ("Temporary directory",
2004             "Please enter your temporary directory.",
2005             bkpinfo->tmpdir, (4*MAX_STR_LEN)-1)) {
2006            log_to_screen("User has chosen not to backup the PC");
2007            finish(1);
2008        }
2009        if (!popup_and_get_string
2010            ("Scratch directory",
2011             "Please enter your scratch directory.",
2012             bkpinfo->scratchdir, (4*MAX_STR_LEN)-1)) {
2013            log_to_screen("User has chosen not to backup the PC");
2014            finish(1);
2015        }
2016// Interactive mode:
2017#ifdef __IA64__
2018        bkpinfo->make_cd_use_lilo = TRUE;
2019#else
2020        bkpinfo->make_cd_use_lilo = FALSE;
2021#endif
2022        bkpinfo->backup_data = TRUE;
2023        bkpinfo->verify_data =
2024            ask_me_yes_or_no
2025            ("Will you want to verify your backups after Mondo has created them?");
2026
2027#ifndef __FreeBSD__
2028        if (!ask_me_yes_or_no
2029            ("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."))
2030#endif
2031        {
2032            strcpy(bkpinfo->kernel_path, "FAILSAFE");
2033        }
2034
2035        if (!ask_me_yes_or_no
2036            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2037            log_to_screen("User has chosen not to backup the PC");
2038            finish(1);
2039        }
2040    } else {
2041        bkpinfo->restore_data = TRUE;   // probably...
2042    }
2043
2044    if (bkpinfo->backup_media_type == iso
2045        || bkpinfo->backup_media_type == nfs) {
2046        g_ISO_restore_mode = TRUE;
2047    }
2048#ifdef __FreeSD__
2049// skip
2050#else
2051    if (bkpinfo->backup_media_type == nfs) {
2052        log_msg(3, "I think the NFS mount is mounted at %s",
2053                bkpinfo->isodir);
2054    }
2055    log_it("isodir = %s", bkpinfo->isodir);
2056    log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
2057    if (bkpinfo->nfs_user) {
2058        log_it("nfs_user = '%s'", bkpinfo->nfs_user);
2059    }
2060#endif
2061
2062    log_it("media device = %s", bkpinfo->media_device);
2063    log_it("media size = %ld", bkpinfo->media_size[1]);
2064    log_it("media type = %s",
2065           bkptype_to_string(bkpinfo->backup_media_type));
2066    log_it("prefix = %s", bkpinfo->prefix);
2067    log_it("compression = %ld", bkpinfo->compression_level);
2068    log_it("include_paths = '%s'", bkpinfo->include_paths);
2069    log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
2070    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2071    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2072    log_it("image_devs = '%s'", bkpinfo->image_devs);
2073    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
2074           bkpinfo->boot_loader);
2075    if (bkpinfo->media_size[0] < 0) {
2076        if (archiving_to_media) {
2077            fatal_error("Media size is less than zero.");
2078        } else {
2079            log_msg(2, "Warning - media size is less than zero.");
2080            bkpinfo->media_size[0] = 0;
2081        }
2082    }
2083    paranoid_free(sz_size);
2084    paranoid_free(prompt);
2085    return (0);
2086}
2087
2088
2089
2090
2091/**
2092 * @addtogroup utilityGroup
2093 * @{
2094 */
2095/**
2096 * Get a space-separated list of NFS devices and mounts.
2097 * @return The list created.
2098 * @note The return value points to static data that will be overwritten with each call.
2099 */
2100char *list_of_NFS_devices_and_mounts(void)
2101{
2102    char *exclude_these_devices = NULL;
2103    char *exclude_these_directories = NULL;
2104    static char result_sz[1024];
2105
2106    mr_asprintf(&exclude_these_directories,"%s",list_of_NFS_mounts_only());
2107    mr_asprintf(&exclude_these_devices,"%s",
2108           call_program_and_get_last_line_of_output
2109           ("tr -s '\t' ' ' < /etc/fstab | grep -E '( (coda|ncpfs|nfs|nfs4|smbfs|cifs|afs|gfs|ocfs|ocfs2|mvfs|nsspool|nsvol) )' | cut -d' ' -f1 | tr -s '\n' ' ' | awk '{print $0;}'"));
2110    snprintf(result_sz, 1023, "%s %s", exclude_these_directories, exclude_these_devices);
2111    mr_free(exclude_these_devices);
2112    mr_free(exclude_these_directories);
2113    return (result_sz);
2114}
2115
2116
2117
2118
2119/**
2120 * Get a space-separated list of NFS mounts.
2121 * @return The list created.
2122 * @note The return value points to static data that will be overwritten with each call.
2123 * @bug Even though we only want the mounts, the devices are still checked.
2124 */
2125char *list_of_NFS_mounts_only(void)
2126{
2127    char *exclude_these_directories = NULL;
2128    static char result_sz[512];
2129
2130    mr_asprintf(&exclude_these_directories,"%s",
2131           call_program_and_get_last_line_of_output
2132           ("mount -t coda,ncpfs,nfs,nfs4,smbfs,cifs,afs,gfs,ocfs,ocfs2,mvfs,nsspool,nssvol | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2133    snprintf(result_sz, 511, "%s", exclude_these_directories);
2134    mr_free(exclude_these_directories);
2135    return (result_sz);
2136}
2137
2138/* @} - end of utilityGroup */
2139
2140
2141
2142
2143
2144/**
2145 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2146 * [random] is a random number between 1 and 32767.
2147 * @param store_name_here Where to store the new filename.
2148 * @param stub A random number will be appended to this to make the FIFO's name.
2149 * @ingroup deviceGroup
2150 */
2151void make_fifo(char *store_name_here, char *stub)
2152{
2153    char *tmp = NULL;
2154
2155    assert_string_is_neither_NULL_nor_zerolength(stub);
2156
2157    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2158            (int) (random() % 32768));
2159    make_hole_for_file(store_name_here);
2160    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2161    mr_asprintf(&tmp, "chmod 770 %s", store_name_here);
2162    paranoid_system(tmp);
2163    mr_free(tmp);
2164}
2165
2166
2167
2168
2169
2170
2171/**
2172 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2173 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2174 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2175 * @ingroup utilityGroup
2176 */
2177void sensibly_set_tmpdir_and_scratchdir()
2178{
2179    char *tmp = NULL; 
2180    char *command = NULL;
2181    char *sz = NULL;
2182
2183    assert(bkpinfo != NULL);
2184
2185#ifdef __FreeBSD__
2186    mr_asprintf(&tmp,
2187           call_program_and_get_last_line_of_output
2188           ("LANGUAGE=C df -m -P -t nonfs,msdosfs,ntfs,ntfs-3g,smbfs,smb,cifs,afs,gfs,ocfs,ocfs2,mvfs,nsspool,nssvol | tr -s '\t' ' ' | grep -vE \"none|Filesystem\" | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -n | tail -n1 | awk '{print $NF;}'"));
2189#else
2190    mr_asprintf(&tmp,
2191           call_program_and_get_last_line_of_output
2192           ("LANGUAGE=C df -m -P -x nfs -x nfs4 -x vfat -x ntfs -x ntfs-3g -x smbfs -x smb -x cifs -x afs -x gfs -x ocfs -x ocfs2 -x mvfs -x nsspool -x nssvol -x iso9660| sed 's/                  /devdev/' | tr -s '\t' ' ' | grep -vE \"none|Filesystem|/dev/shm\" | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -n | tail -n1 | awk '{print $NF;}'"));
2193#endif
2194
2195    if (tmp[0] != '/') {
2196        mr_asprintf(&sz, tmp);
2197        paranoid_free(tmp);
2198        mr_asprintf(&tmp, "/%s", sz);
2199        mr_free(sz);
2200    }
2201    if (!tmp[0]) {
2202        fatal_error("I couldn't figure out the tempdir!");
2203    }
2204    setup_tmpdir(tmp);
2205    log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2206
2207    sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp,
2208            (int) (random() % 32768));
2209    log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2210
2211    mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2212    paranoid_free(tmp);
2213
2214    paranoid_system(command);
2215    mr_free(command);
2216}
2217
2218
2219
2220
2221
2222
2223/**
2224 * @addtogroup deviceGroup
2225 * @{
2226 */
2227/**
2228 * If we can read @p dev, set @p output to it.
2229 * If @p dev cannot be read, set @p output to "".
2230 * @param dev The device to check for.
2231 * @param output Set to @p dev if @p dev exists, "" otherwise.
2232 * @return TRUE if @p dev exists, FALSE if it doesn't.
2233 */
2234bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2235{
2236    char *command = NULL;
2237    bool res;
2238
2239    if (!dev || dev[0] == '\0') {
2240        output[0] = '\0';
2241        return (FALSE);
2242    }
2243    log_msg(10, "Injecting %s", dev);
2244    inject_device(dev);
2245    if (!does_file_exist(dev)) {
2246        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2247        return (FALSE);
2248    }
2249    mr_asprintf(&command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null", 512L, dev);
2250    if (!run_program_and_log_output(command, FALSE)
2251        && !run_program_and_log_output(command, FALSE)) {
2252        strcpy(output, dev);
2253        log_msg(4, "Found it - %s", dev);
2254        res = TRUE;
2255    } else {
2256        output[0] = '\0';
2257        log_msg(4, "It's not %s", dev);
2258        res = FALSE;
2259    }
2260    mr_free(command);
2261    return(res);
2262}
2263
2264
2265
2266
2267
2268/**
2269 * Find out what number CD is in the drive.
2270 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2271 * @return The current CD number, or -1 if it could not be found.
2272 * @note If the CD is not mounted, it will be mounted
2273 * (and remain mounted after this function returns).
2274 */
2275int what_number_cd_is_this()
2276{
2277    int cd_number = -1;
2278    char *mountdev = NULL;
2279    char *tmp = NULL;
2280
2281    assert(bkpinfo != NULL);
2282//  log_it("Asking what_number_cd_is_this");
2283    if (g_ISO_restore_mode) {
2284        mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
2285
2286        mr_asprintf(&mountdev, "%s%s", call_program_and_get_last_line_of_output(tmp), "/archives/THIS-CD-NUMBER");
2287        cd_number = atoi(last_line_of_file(mountdev));
2288        paranoid_free(mountdev);
2289        paranoid_free(tmp);
2290
2291        return (cd_number);
2292    }
2293
2294    mr_asprintf(&mountdev, bkpinfo->media_device);
2295    if (!mountdev[0]) {
2296        log_it
2297            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2298        find_cdrom_device(bkpinfo->media_device, FALSE);
2299    }
2300    if (!is_this_device_mounted(MNT_CDROM)) {
2301        if (bkpinfo->backup_media_type == usb) {
2302            mount_USB_here(mountdev, MNT_CDROM);
2303        } else {
2304            mount_CDROM_here(mountdev, MNT_CDROM);
2305        }
2306    }
2307    paranoid_free(mountdev);
2308
2309    cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2310    return (cd_number);
2311}
2312
2313
2314
2315
2316
2317
2318
2319/**
2320 * Find out what device is mounted as root (/).
2321 * @return Root device.
2322 * @note The returned string points to static storage and will be overwritten with every call.
2323 * @bug A bit of a misnomer; it's actually finding out the root device.
2324 * The mountpoint (where it's mounted) will obviously be '/'.
2325 */
2326char *where_is_root_mounted()
2327{
2328    /*@ buffers **************** */
2329    static char tmp[MAX_STR_LEN];
2330
2331
2332#ifdef __FreeBSD__
2333    strcpy(tmp, call_program_and_get_last_line_of_output
2334           ("mount | grep \" on / \" | cut -d' ' -f1"));
2335#else
2336    strcpy(tmp, call_program_and_get_last_line_of_output
2337           ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2338    if (strstr(tmp, "/dev/cciss/")) {
2339        strcpy(tmp, call_program_and_get_last_line_of_output
2340               ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2341    }
2342    if (strstr(tmp, "/dev/md")) {
2343        strcpy(tmp,
2344               call_program_and_get_last_line_of_output
2345               ("mount | grep \" on / \" | cut -d' ' -f1"));
2346    }
2347#endif
2348
2349    return (tmp);
2350}
2351
2352
2353/**
2354 * Find out which boot loader is in use.
2355 * @param which_device Device to look for the boot loader on.
2356 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2357 * @note Under Linux, all drives are examined, not just @p which_device.
2358 */
2359#ifdef __FreeBSD__
2360char which_boot_loader(char *which_device)
2361{
2362    int count_lilos = 0;
2363    int count_grubs = 0;
2364    int count_boot0s = 0;
2365    int count_dangerouslydedicated = 0;
2366
2367    log_it("looking at drive %s's MBR", which_device);
2368    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2369        count_grubs++;
2370    }
2371    if (does_string_exist_in_boot_block(which_device, "LILO")) {
2372        count_lilos++;
2373    }
2374    if (does_string_exist_in_boot_block(which_device, "Drive")) {
2375        count_boot0s++;
2376    }
2377    if (does_string_exist_in_first_N_blocks
2378        (which_device, "FreeBSD/i386", 17)) {
2379        count_dangerouslydedicated++;
2380    }
2381    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2382           count_grubs, count_lilos, count_elilos, count_boot0s,
2383           count_dangerouslydedicated);
2384
2385    if (count_grubs && !count_lilos) {
2386        return ('G');
2387    } else if (count_lilos && !count_grubs) {
2388        return ('L');
2389    } else if (count_grubs == 1 && count_lilos == 1) {
2390        log_it("I'll bet you used to use LILO but switched to GRUB...");
2391        return ('G');
2392    } else if (count_boot0s == 1) {
2393        return ('B');
2394    } else if (count_dangerouslydedicated) {
2395        return ('D');
2396    } else {
2397        log_it("Unknown boot loader");
2398        return ('U');
2399    }
2400}
2401
2402#else
2403
2404char which_boot_loader(char *which_device)
2405{
2406    /*@ buffer ***************************************************** */
2407    char *list_drives_cmd = NULL;
2408    char *current_drive;
2409
2410    /*@ pointers *************************************************** */
2411    FILE *pdrives;
2412
2413    /*@ int ******************************************************** */
2414    int count_lilos = 0;
2415    int count_grubs = 0;
2416
2417    /*@ end vars *************************************************** */
2418
2419    malloc_string(current_drive);
2420
2421#ifdef __IA64__
2422    /* No choice for it */
2423    return ('E');
2424#endif
2425    assert(which_device != NULL);
2426
2427    mr_asprintf(&list_drives_cmd,
2428            "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s",
2429            where_is_root_mounted());
2430    log_it("list_drives_cmd = %s", list_drives_cmd);
2431
2432    if (!(pdrives = popen(list_drives_cmd, "r"))) {
2433        log_OS_error("Unable to open list of drives");
2434        mr_free(list_drives_cmd);
2435        paranoid_free(current_drive);
2436        return ('\0');
2437    }
2438    mr_free(list_drives_cmd);
2439
2440    for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
2441         (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
2442        strip_spaces(current_drive);
2443        log_it("looking at drive %s's MBR", current_drive);
2444        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2445            count_grubs++;
2446            strcpy(which_device, current_drive);
2447            break;
2448        }
2449        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2450            count_lilos++;
2451            strcpy(which_device, current_drive);
2452            break;
2453        }
2454    }
2455    if (pclose(pdrives)) {
2456        log_OS_error("Cannot pclose pdrives");
2457    }
2458    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2459    if (count_grubs && !count_lilos) {
2460        paranoid_free(current_drive);
2461        return ('G');
2462    } else if (count_lilos && !count_grubs) {
2463        paranoid_free(current_drive);
2464        return ('L');
2465    } else if (count_grubs == 1 && count_lilos == 1) {
2466        log_it("I'll bet you used to use LILO but switched to GRUB...");
2467        paranoid_free(current_drive);
2468        return ('G');
2469    } else {
2470        // We need to look on each partition then
2471        mr_asprintf(&list_drives_cmd,
2472            "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
2473        log_it("list_drives_cmd = %s", list_drives_cmd);
2474
2475        if (!(pdrives = popen(list_drives_cmd, "r"))) {
2476            log_OS_error("Unable to open list of drives");
2477            mr_free(list_drives_cmd);
2478            paranoid_free(current_drive);
2479            return ('\0');
2480        }
2481        mr_free(list_drives_cmd);
2482
2483        for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
2484            (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
2485            strip_spaces(current_drive);
2486            log_it("looking at partition %s's BR", current_drive);
2487            if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2488                count_grubs++;
2489                strcpy(which_device, current_drive);
2490                break;
2491            }
2492            if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2493                count_lilos++;
2494                strcpy(which_device, current_drive);
2495                break;
2496            }
2497        }
2498        if (pclose(pdrives)) {
2499            log_OS_error("Cannot pclose pdrives");
2500        }
2501        log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2502        paranoid_free(current_drive);
2503        if (count_grubs && !count_lilos) {
2504            return ('G');
2505        } else if (count_lilos && !count_grubs) {
2506            return ('L');
2507        } else if (count_grubs == 1 && count_lilos == 1) {
2508            log_it("I'll bet you used to use LILO but switched to GRUB...");
2509            return ('G');
2510        } else {
2511            log_it("Unknown boot loader");
2512            return ('U');
2513        }
2514    }
2515}
2516#endif
2517
2518
2519
2520
2521/**
2522 * Write zeroes over the first 16K of @p device.
2523 * @param device The device to zero.
2524 * @return 0 for success, 1 for failure.
2525 */
2526int zero_out_a_device(char *device)
2527{
2528    FILE *fout;
2529    int i;
2530
2531    assert_string_is_neither_NULL_nor_zerolength(device);
2532
2533    log_it("Zeroing drive %s", device);
2534    if (!(fout = fopen(device, "w"))) {
2535        log_OS_error("Unable to open/write to device");
2536        return (1);
2537    }
2538    for (i = 0; i < 16384; i++) {
2539        fputc('\0', fout);
2540    }
2541    paranoid_fclose(fout);
2542    log_it("Device successfully zeroed.");
2543    return (0);
2544}
2545
2546/**
2547 * Return the device pointed to by @p incoming.
2548 * @param incoming The device to resolve symlinks for.
2549 * @return The path to the real device file.
2550 * @note The returned string points to static storage that will be overwritten with each call.
2551 * @bug Won't work with file v4.0; needs to be written in C.
2552 */
2553char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2554{
2555    static char output[MAX_STR_LEN];
2556    char *command = NULL;
2557    char *curr_fname;
2558    char *scratch = NULL;
2559    char *tmp = NULL;
2560    char *p;
2561
2562    struct stat statbuf;
2563    malloc_string(curr_fname);
2564    if (!does_file_exist(incoming)) {
2565        log_it
2566            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2567        strcpy(output, incoming);
2568    } else {
2569        strcpy(curr_fname, incoming);
2570        lstat(curr_fname, &statbuf);
2571        while (S_ISLNK(statbuf.st_mode)) {
2572            log_msg(1, "curr_fname = %s", curr_fname);
2573            mr_asprintf(&command, "file %s", curr_fname);
2574            mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2575            mr_free(command);
2576            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2577                 p--);
2578            p++;
2579            mr_asprintf(&scratch, p);
2580            for (p = scratch; *p != '\0' && *p != '\''; p++);
2581            *p = '\0';
2582            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
2583            mr_free(tmp);
2584
2585            if (scratch[0] == '/') {
2586                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
2587            } else {            // copy over the basename cos it's a relative softlink
2588                p = curr_fname + strlen(curr_fname);
2589                while (p != curr_fname && *p != '/') {
2590                    p--;
2591                }
2592                if (*p == '/') {
2593                    p++;
2594                }
2595                strcpy(p, scratch);
2596            }
2597            mr_free(scratch);
2598            lstat(curr_fname, &statbuf);
2599        }
2600        strcpy(output, curr_fname);
2601        log_it("resolved %s to %s", incoming, output);
2602    }
2603    paranoid_free(curr_fname);
2604    return (output);
2605}
2606
2607/* @} - end of deviceGroup */
2608
2609
2610/**
2611 * Return the type of partition format (GPT or MBR)
2612 */
2613char *which_partition_format(const char *drive)
2614{
2615    static char output[4];
2616    char *tmp = NULL;
2617    char *command = NULL;
2618    char *fdisk = NULL;
2619#ifdef __IA64__
2620    struct stat buf;
2621#endif
2622    log_msg(0, "Looking for partition table format type");
2623    mr_asprintf(&fdisk, "/sbin/parted2fdisk");
2624    log_msg(1, "Using %s", fdisk);
2625    mr_asprintf(&command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2626    mr_free(fdisk);
2627
2628    mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2629    mr_free(command);
2630
2631    if (strstr(tmp, "GPT") == NULL) {
2632        strcpy(output, "MBR");
2633    } else {
2634        strcpy(output, "GPT");
2635    }
2636    mr_free(tmp);
2637
2638    log_msg(0, "Found %s partition table format type", output);
2639    return (output);
2640}
2641
2642/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.