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

Last change on this file since 1594 was 1594, checked in by bruno, 12 years ago

Use of conf file entries (iso_burning_*, media_device, media_size)
and adapatation of the rest of the code to that (including bkpinfo)

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