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

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