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

Last change on this file since 2291 was 2291, checked in by Bruno Cornec, 11 years ago
  • Fix a printing error in mindi for the tar command
  • Fix all mr_asprintf which had no second param as a string

(report bug fix done originaly in 2.2.9)

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