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

Last change on this file since 1166 was 1166, checked in by Bruno Cornec, 13 years ago

Suppress g_bkpinfo_DONTUSETHIS (Idea from M. Loiseleur)

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