source: MondoRescue/branches/stable/mondo/src/common/libmondo-devices.c @ 1769

Last change on this file since 1769 was 1769, checked in by Bruno Cornec, 12 years ago

Continue on configuration file items (compression)

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