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

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

strip_spaces => mr_strip_spaces in mr_str.c and corrected at the same time :-)

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