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

Last change on this file since 1156 was 1156, checked in by bruno, 13 years ago

Merge trunk for libmondo-devices.c finished (first pass)

  • Property svn:keywords set to Id
File size: 65.5 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 1156 2007-02-13 01:04:40Z 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 1156 2007-02-13 01:04:40Z bruno $";
38
39extern int g_current_media_number;
40extern double g_kernel_version;
41
42extern bool g_ISO_restore_mode;
43extern struct s_bkpinfo *g_bkpinfo_DONTUSETHIS;
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;
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        retval = FALSE;
1131    } else {
1132        mr_getline(&good_formats, &n , pin);
1133        if (pclose(pin)) {
1134            log_OS_error("Cannot pclose good formats");
1135        }
1136        strip_spaces(good_formats);
1137        // " ntfs 7 " -- um, cheating much? :)
1138        mr_asprintf(&tmp, " %s swap lvm raid ntfs 7 ",good_formats);
1139        mr_free(good_formats);
1140        good_formats = tmp;
1141
1142        if (strstr(good_formats, format_sz)) {
1143            retval = TRUE;
1144        } else {
1145            retval = FALSE;
1146        }
1147        mr_free(good_formats);
1148    }
1149    mr_free(format_sz);
1150    return (retval);
1151}
1152
1153
1154/** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */
1155
1156/**
1157 * Determine whether @p device_raw is currently mounted.
1158 * @param device_raw The device to check.
1159 * @return TRUE if it's mounted, FALSE if not.
1160 */
1161bool is_this_device_mounted(char *device_raw)
1162{
1163
1164    /*@ pointers **************************************************** */
1165    FILE *fin;
1166
1167    /*@ buffers ***************************************************** */
1168    char *incoming = NULL;
1169    char *device_with_tab = NULL;
1170    char *device_with_space = NULL;
1171    char *tmp = NULL;
1172    size_t n = 0;
1173
1174#ifdef __FreeBSD__
1175#define SWAPLIST_COMMAND "swapinfo"
1176#else
1177#define SWAPLIST_COMMAND "cat /proc/swaps"
1178#endif
1179
1180    /*@ end vars **************************************************** */
1181
1182    assert(device_raw != NULL);
1183//  assert_string_is_neither_NULL_nor_zerolength(device_raw);
1184    if (device_raw[0] != '/' && !strstr(device_raw, ":/")) {
1185        mr_msg(1, "%s needs to have a '/' prefixed - I'll do it",
1186                device_raw);
1187        mr_asprintf(&tmp, "/%s", device_raw);
1188    } else {
1189        mr_asprintf(&tmp, device_raw);
1190    }
1191    mr_msg(1, "Is %s mounted?", tmp);
1192    if (!strcmp(tmp, "/proc") || !strcmp(tmp, "proc")) {
1193        mr_msg(1,
1194                "I don't know how the heck /proc made it into the mountlist. I'll ignore it.");
1195        return (FALSE);
1196    }
1197    mr_asprintf(&device_with_tab, "%s\t", tmp);
1198    mr_asprintf(&device_with_space, "%s ", tmp);
1199    mr_free(tmp);
1200
1201    if (!(fin = popen("mount", "r"))) {
1202        log_OS_error("Cannot popen 'mount'");
1203        return (FALSE);
1204    }
1205    for (mr_getline(&incoming, &n, fin); !feof(fin);
1206         mr_getline(&incoming, &n, fin)) {
1207        if (strstr(incoming, device_with_space) //> incoming
1208            || strstr(incoming, device_with_tab))   // > incoming)
1209        {
1210            paranoid_pclose(fin);
1211            mr_free(incoming);
1212            return(TRUE);
1213        }
1214    }
1215    mr_free(incoming);
1216    mr_free(device_with_tab);
1217    paranoid_pclose(fin);
1218
1219    mr_asprintf(&tmp, "%s | grep -E \"^%s\" > /dev/null 2> /dev/null",
1220            SWAPLIST_COMMAND, device_with_space);
1221    mr_free(device_with_space);
1222
1223    mr_msg(4, "tmp (command) = '%s'", tmp);
1224    if (!system(tmp)) {
1225        mr_free(tmp);
1226        return(TRUE);
1227    }
1228    mr_free(tmp);
1229    return (FALSE);
1230}
1231
1232
1233#ifdef __FreeBSD__
1234//                       CODE IS FREEBSD-SPECIFIC
1235/**
1236 * Create a loopback device for specified @p fname.
1237 * @param fname The file to associate with a device.
1238 * @return /dev entry for the device, or NULL if it couldn't be allocated.
1239 */
1240char *make_vn(char *fname)
1241{
1242    char *device = NULL;
1243    char *mddevice = NULL;
1244    char *command = NULL;
1245    int vndev = 2;
1246
1247    if (atoi
1248        (call_program_and_get_last_line_of_output
1249         ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1250        do {
1251            mr_free(mddevice);
1252            mr_asprintf(&mddevice, "vn%ic", vndev++);
1253            mr_free(command);
1254            mr_asprintf(&command, "vnconfig %s %s", mddevice, fname);
1255
1256            if (vndev > 10) {
1257                mr_free(command);
1258                mr_free(mddevice);
1259                return NULL;
1260            }
1261        }
1262        while (system(command));
1263        mr_free(command);
1264    } else {
1265        mr_asprintf(&command, "mdconfig -a -t vnode -f %s", fname);
1266        mr_asprintf(&mddevice, call_program_and_get_last_line_of_output(command));
1267        mr_free(command);
1268
1269        if (!strstr(mddevice, "md")) {
1270            mr_free(mddevice);
1271            return NULL;
1272        }
1273    }
1274    mr_asprintf(&device, "/dev/%s", mddevice);
1275    mr_free(mddevice);
1276    return(device);
1277}
1278
1279
1280//                       CODE IS FREEBSD-SPECIFIC
1281/**
1282 * Deallocate specified @p dname.
1283 * This should be called when you are done with the device created by make_vn(),
1284 * so the system does not run out of @c vn devices.
1285 * @param dname The device to deallocate.
1286 * @return 0 for success, nonzero for failure.
1287 */
1288int kick_vn(char *dname)
1289{
1290    char *command;
1291    int ret = 0;
1292
1293    if (strncmp(dname, "/dev/", 5) == 0) {
1294        dname += 5;
1295    }
1296
1297    if (atoi
1298        (call_program_and_get_last_line_of_output
1299         ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1300        mr_asprintf(&command, "vnconfig -d %s", dname);
1301    } else {
1302        mr_asprintf(&command, "mdconfig -d -u %s", dname);
1303    }
1304    ret = system(command);
1305    mr_free(command);
1306    return(ret);
1307}
1308#endif
1309
1310
1311/**
1312 * Ask the user for CD number @p cd_number_i_want.
1313 * Sets g_current_media_number once the correct CD is inserted.
1314 * @param bkpinfo The backup information structure. Fields used:
1315 * - @c bkpinfo->backup_media_type
1316 * - @c bkpinfo->prefix
1317 * - @c bkpinfo->isodir
1318 * - @c bkpinfo->media_device
1319 * - @c bkpinfo->please_dont_eject_when_restoring
1320 * @param cd_number_i_want The CD number to ask for.
1321 */
1322void
1323insist_on_this_cd_number(struct s_bkpinfo *bkpinfo, int cd_number_i_want)
1324{
1325
1326    /*@ int ************************************************************* */
1327    int res = 0;
1328
1329
1330    /*@ buffers ********************************************************* */
1331    char *tmp = NULL;
1332    char *request = NULL;
1333
1334    assert(bkpinfo != NULL);
1335    assert(cd_number_i_want > 0);
1336
1337//  mr_msg(3, "Insisting on CD number %d", cd_number_i_want);
1338
1339    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1340        mr_msg(3,
1341                "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1342        return;
1343    }
1344    mr_asprintf(&tmp, "mkdir -p " MNT_CDROM);
1345    run_program_and_log_output(tmp, 5);
1346    mr_free(tmp);
1347
1348    if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso
1349        || bkpinfo->backup_media_type == nfs) {
1350        mr_msg(3, "Remounting CD");
1351        g_ISO_restore_mode = TRUE;
1352// FIXME --- I'm tempted to do something about this...
1353// Why unmount and remount again and again?
1354        if (is_this_device_mounted(MNT_CDROM)) {
1355            run_program_and_log_output("umount " MNT_CDROM, 5);
1356        }
1357        system("mkdir -p /tmp/isodir &> /dev/null");
1358        mr_asprintf(&tmp, "%s/%s/%s-%d.iso", bkpinfo->isodir,
1359                bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1360                cd_number_i_want);
1361        if (!does_file_exist(tmp)) {
1362            mr_free(tmp);
1363            mr_asprintf(&tmp, "/tmp/isodir/%s/%s-%d.iso",
1364                    bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1365                    cd_number_i_want);
1366            if (does_file_exist(tmp)) {
1367                mr_msg(1,
1368                        "FIXME - hacking bkpinfo->isodir from '%s' to /tmp/isodir",
1369                        bkpinfo->isodir);
1370                strcpy(bkpinfo->isodir, "/tmp/isodir");
1371            }
1372        }
1373        mr_msg(3, "Mounting %s at %s", tmp, MNT_CDROM);
1374        if (mount_CDROM_here(tmp, MNT_CDROM)) {
1375            fatal_error("Mommy!");
1376        }
1377        mr_free(tmp);
1378    }
1379    if ((res = what_number_cd_is_this(bkpinfo)) != cd_number_i_want) {
1380        mr_msg(3, "Currently, we hold %d but we want %d", res,
1381                cd_number_i_want);
1382        mr_asprintf(&tmp, "Insisting on %s #%d",
1383                bkpinfo->backup_media_string,
1384                cd_number_i_want);
1385        mr_asprintf(&request, "Please insert %s #%d and press Enter.",
1386                bkpinfo->backup_media_string,
1387                cd_number_i_want);
1388        mr_msg(3, tmp);
1389        mr_free(tmp);
1390
1391        while (what_number_cd_is_this(bkpinfo) != cd_number_i_want) {
1392            sync();
1393            if (is_this_device_mounted(MNT_CDROM)) {
1394                res =
1395                    run_program_and_log_output("umount " MNT_CDROM, FALSE);
1396            } else {
1397                res = 0;
1398            }
1399            if (res) {
1400                log_to_screen(_("WARNING - failed to unmount CD-ROM drive"));
1401            }
1402            if (!bkpinfo->please_dont_eject) {
1403                res = eject_device(bkpinfo->media_device);
1404            } else {
1405                res = 0;
1406            }
1407            if (res) {
1408                log_to_screen(_("WARNING - failed to eject CD-ROM disk"));
1409            }
1410            popup_and_OK(request);
1411            if (!bkpinfo->please_dont_eject) {
1412                inject_device(bkpinfo->media_device);
1413            }
1414            sync();
1415        }
1416        mr_free(request);
1417
1418        mr_msg(1, "Thankyou. Proceeding...");
1419        g_current_media_number = cd_number_i_want;
1420    }
1421}
1422/* @} - end of deviceGroup */
1423
1424
1425/**
1426 * Ask user for details of backup/restore information.
1427 * Called when @c mondoarchive doesn't get any parameters.
1428 * @param bkpinfo The backup information structure to fill out with the user's data.
1429 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
1430 * @return 0, always.
1431 * @bug No point of `int' return value.
1432 * @ingroup archiveGroup
1433 */
1434int interactively_obtain_media_parameters_from_user(struct s_bkpinfo
1435                                                    *bkpinfo,
1436                                                    bool
1437                                                    archiving_to_media)
1438// archiving_to_media is TRUE if I'm being called by mondoarchive
1439// archiving_to_media is FALSE if I'm being called by mondorestore
1440{
1441    char *tmp = NULL;
1442    char *tmp1 = NULL;
1443    char *tmp2 = NULL;
1444    char *sz_size = NULL;
1445    char *command = NULL;
1446    char *comment = NULL;
1447    char *prompt = NULL;
1448    int i = 0;
1449    FILE *fin = NULL;
1450
1451    assert(bkpinfo != NULL);
1452    bkpinfo->nonbootable_backup = FALSE;
1453
1454// Tape, CD, NFS, ...?
1455    srandom(getpid());
1456    bkpinfo->backup_media_type =
1457        (g_restoring_live_from_cd) ? cdr :
1458        which_backup_media_type(bkpinfo->restore_data);
1459    if (bkpinfo->backup_media_type == none) {
1460        log_to_screen(_("User has chosen not to backup the PC"));
1461        finish(1);
1462    }
1463    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
1464        popup_and_OK(_("Please remove CD/floppy from drive(s)"));
1465    }
1466    mr_msg(3, "media type = %s",
1467            bkptype_to_string(bkpinfo->backup_media_type));
1468    if (archiving_to_media) {
1469        sensibly_set_tmpdir_and_scratchdir(bkpinfo);
1470    }
1471    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
1472    bkpinfo->compression_level =
1473        (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
1474    bkpinfo->use_lzo =
1475        (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
1476    mvaddstr_and_log_it(2, 0, " ");
1477
1478// Find device's /dev (or SCSI) entry
1479    switch (bkpinfo->backup_media_type) {
1480    case cdr:
1481    case cdrw:
1482    case dvd:
1483    case usb:
1484        if (archiving_to_media) {
1485            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1486                if (ask_me_yes_or_no
1487                    (_("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?")))
1488                {
1489                    bkpinfo->manual_cd_tray = TRUE;
1490                }
1491            }
1492            if ((bkpinfo->compression_level =
1493                 which_compression_level()) == -1) {
1494                log_to_screen(_("User has chosen not to backup the PC"));
1495                finish(1);
1496            }
1497            mr_asprintf(&comment, _("What speed is your %s (re)writer?"),
1498                    bkpinfo->backup_media_string);
1499            if (bkpinfo->backup_media_type == dvd) {
1500                find_dvd_device(bkpinfo->media_device, FALSE);
1501                mr_asprintf(&tmp, "1");
1502                mr_asprintf(&sz_size, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4582 MB
1503                mr_msg(1, "Setting to DVD defaults");
1504            } else if (bkpinfo->backup_media_type == usb) {
1505                strcpy(bkpinfo->media_device, VANILLA_USB_DEVICE);
1506                strcpy(sz_size, "512");
1507            } else {
1508                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
1509                mr_asprintf(&tmp, "4");
1510                mr_asprintf(&sz_size, "650");
1511                mr_msg(1, "Setting to CD defaults");
1512            }
1513            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1514                if (!popup_and_get_string(_("Speed"), comment, tmp, 4)) {
1515                    log_to_screen(_("User has chosen not to backup the PC"));
1516                    finish(1);
1517                }
1518            }
1519            mr_free(comment);
1520
1521            bkpinfo->cdrw_speed = atoi(tmp);    // if DVD then this shouldn't ever be used anyway :)
1522            mr_free(tmp);
1523
1524            mr_asprintf(&comment,
1525                    _("How much data (in Megabytes) will each %s store?"),
1526                    bkpinfo->backup_media_string);
1527
1528            if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1529                log_to_screen(_("User has chosen not to backup the PC"));
1530                finish(1);
1531            }
1532            mr_free(comment);
1533
1534            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1535                bkpinfo->media_size[i] = atoi(sz_size);
1536            }
1537            mr_free(sz_size);
1538
1539            if (bkpinfo->media_size[0] <= 0) {
1540                log_to_screen(_("User has chosen not to backup the PC"));
1541                finish(1);
1542            }
1543        }
1544    case cdstream:
1545        if (bkpinfo->disaster_recovery) {
1546            strcpy(bkpinfo->media_device, "/dev/cdrom");
1547            mr_msg(2, "CD-ROM device assumed to be at %s",
1548                    bkpinfo->media_device);
1549        } else if (bkpinfo->restore_data
1550                   || bkpinfo->backup_media_type == dvd) {
1551            if (!bkpinfo->media_device[0]) {
1552                strcpy(bkpinfo->media_device, "/dev/cdrom");
1553            }                   // just for the heck of it :)
1554            mr_msg(1, "bkpinfo->media_device = %s",
1555                    bkpinfo->media_device);
1556            if (bkpinfo->backup_media_type == dvd
1557                || find_cdrom_device(bkpinfo->media_device, FALSE)) {
1558                mr_msg(1, "bkpinfo->media_device = %s",
1559                        bkpinfo->media_device);
1560                mr_asprintf(&comment,
1561                        _("Please specify your %s drive's /dev entry"),
1562                        bkpinfo->backup_media_string);
1563                if (!popup_and_get_string
1564                    (_("Device?"), comment, bkpinfo->media_device, MAX_STR_LEN / 4)) {
1565                    log_to_screen(_("User has chosen not to backup the PC"));
1566                    finish(1);
1567                }
1568                mr_free(comment);
1569            }
1570            mr_msg(2, "%s device found at %s",
1571                    bkpinfo->backup_media_string,
1572                    bkpinfo->media_device);
1573        } else {
1574            if (find_cdrw_device(bkpinfo->media_device)) {
1575                bkpinfo->media_device[0] = '\0';
1576            }
1577            if (bkpinfo->media_device[0]) {
1578                mr_asprintf(&tmp,
1579                        _("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."),
1580                        bkpinfo->backup_media_string,
1581                        bkpinfo->media_device);
1582                if (!ask_me_yes_or_no(tmp)) {
1583                    bkpinfo->media_device[0] = '\0';
1584                }
1585                mr_free(tmp);
1586            } else {
1587                if (g_kernel_version < 2.6) {
1588                    i = popup_and_get_string("Device node?",
1589                                             "What is the SCSI node of your CD (re)writer, please?",
1590                                             bkpinfo->media_device,
1591                                             MAX_STR_LEN / 4);
1592                } else {
1593                    i = popup_and_get_string("/dev entry?",
1594                                             "What is the /dev entry of your CD (re)writer, please?",
1595                                             bkpinfo->media_device,
1596                                             MAX_STR_LEN / 4);
1597                }
1598                if (!i) {
1599                    log_to_screen(_("User has chosen not to backup the PC"));
1600                    finish(1);
1601                }
1602            }
1603        }
1604        if (bkpinfo->backup_media_type == cdstream) {
1605            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1606                bkpinfo->media_size[i] = 650;
1607            }
1608        }
1609        break;
1610    case udev:
1611        if (!ask_me_yes_or_no
1612            (_("This option is for advanced users only. Are you sure?"))) {
1613            log_to_screen(_("User has chosen not to backup the PC"));
1614            finish(1);
1615        }
1616    case tape:
1617
1618        if (find_tape_device_and_size(bkpinfo->media_device, sz_size)) {
1619            mr_msg(3, "Ok, using vanilla scsi tape.");
1620            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
1621            if ((fin = fopen(bkpinfo->media_device, "r"))) {
1622                paranoid_fclose(fin);
1623            } else {
1624                strcpy(bkpinfo->media_device, "/dev/osst0");
1625            }
1626        }
1627        if (bkpinfo->media_device[0]) {
1628            if ((fin = fopen(bkpinfo->media_device, "r"))) {
1629                paranoid_fclose(fin);
1630            } else {
1631                if (does_file_exist("/tmp/mondo-restore.cfg")) {
1632                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
1633                                 bkpinfo->media_device);
1634                }
1635            }
1636            mr_asprintf(&tmp,
1637                    _("I think I've found your tape streamer at %s; am I right on the money?"),
1638                    bkpinfo->media_device);
1639            if (!ask_me_yes_or_no(tmp)) {
1640                bkpinfo->media_device[0] = '\0';
1641            }
1642            mr_free(tmp);
1643        } else {
1644            if (!popup_and_get_string
1645                ("Device name?",
1646                 "What is the /dev entry of your tape streamer?",
1647                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
1648                log_to_screen("User has chosen not to backup the PC");
1649                finish(1);
1650            }
1651        }
1652        mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
1653        if (run_program_and_log_output(tmp, FALSE)) {
1654            log_to_screen(_("User has not specified a valid /dev entry"));
1655            finish(1);
1656        }
1657        mr_free(tmp);
1658        mr_msg(4, "sz_size = %s", sz_size);
1659        mr_free(sz_size);
1660        bkpinfo->media_size[0] = 0;
1661        mr_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
1662        if (bkpinfo->media_size[0] <= 0) {
1663            bkpinfo->media_size[0] = 0;
1664        }
1665        for (i = 1; i <= MAX_NOOF_MEDIA; i++) {
1666            bkpinfo->media_size[i] = bkpinfo->media_size[0];
1667        }
1668        if (archiving_to_media) {
1669            if ((bkpinfo->compression_level =
1670                 which_compression_level()) == -1) {
1671                log_to_screen(_("User has chosen not to backup the PC"));
1672                finish(1);
1673            }
1674        }
1675        break;
1676
1677
1678
1679    case nfs:
1680        if (!bkpinfo->nfs_mount[0]) {
1681            strcpy(bkpinfo->nfs_mount,
1682                   call_program_and_get_last_line_of_output
1683                   ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
1684        }
1685#ifdef __FreeBSD__
1686        if (TRUE)
1687#else
1688        if (!bkpinfo->disaster_recovery)
1689#endif
1690        {
1691            if (!popup_and_get_string
1692                ("NFS dir.",
1693                 "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.)",
1694                 bkpinfo->nfs_mount, MAX_STR_LEN / 4)) {
1695                log_to_screen("User has chosen not to backup the PC");
1696                finish(1);
1697            }
1698            if (!bkpinfo->restore_data) {
1699                if ((bkpinfo->compression_level =
1700                     which_compression_level()) == -1) {
1701                    log_to_screen(_("User has chosen not to backup the PC"));
1702                    finish(1);
1703                }
1704            }
1705            // check whether already mounted - we better remove
1706            // surrounding spaces and trailing '/' for this
1707            /* BERLIOS: Useless
1708            strip_spaces(bkpinfo->nfs_mount);
1709            */
1710            if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
1711                bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
1712            mr_asprintf(&command, "mount | grep \"%s \" | cut -d' ' -f3",
1713                    bkpinfo->nfs_mount);
1714            strcpy(bkpinfo->isodir,
1715                   call_program_and_get_last_line_of_output(command));
1716            mr_free(command);
1717
1718            mr_asprintf(&comment,
1719                    _("How much data (in Megabytes) will each media store?"));
1720            if (!popup_and_get_string(_("Size"), comment, sz_size, 5)) {
1721                log_to_screen(_("User has chosen not to backup the PC"));
1722                finish(1);
1723            }
1724            mr_free(comment);
1725            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1726                bkpinfo->media_size[i] = atoi(sz_size);
1727            }
1728            if (bkpinfo->media_size[0] <= 0) {
1729                log_to_screen(_("User has chosen not to backup the PC"));
1730                finish(1);
1731            }
1732        }
1733        if (bkpinfo->disaster_recovery) {
1734            system("umount /tmp/isodir 2> /dev/null");
1735            if (!popup_and_get_string
1736                ("NFS share", "Which remote NFS share should I mount?",
1737                 bkpinfo->nfs_mount, MAX_STR_LEN)) {
1738                log_to_screen("User has chosen not to backup the PC");
1739                finish(1);
1740            }
1741        }
1742        if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1743            sprintf(bkpinfo->isodir, "/tmp/isodir.mondo.%d",
1744                    (int) (random() % 32768));
1745            mr_asprintf(&command, "mkdir -p %s", bkpinfo->isodir);
1746            run_program_and_log_output(command, 5);
1747            mr_free(command);
1748
1749            mr_asprintf(&tmp, "mount -t nfs -o nolock %s %s", bkpinfo->nfs_mount,
1750                    bkpinfo->isodir);
1751            run_program_and_log_output(tmp, 5);
1752            mr_free(tmp);
1753            malloc_string(g_selfmounted_isodir);
1754            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
1755        }
1756        if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1757            popup_and_OK
1758                (_("Please mount that partition before you try to backup to or restore from it."));
1759            finish(1);
1760        }
1761        mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1762        if (!popup_and_get_string
1763            ("Directory", "Which directory within that mountpoint?", tmp,
1764             MAX_STR_LEN)) {
1765            log_to_screen("User has chosen not to backup the PC");
1766            finish(1);
1767        }
1768        strcpy(bkpinfo->nfs_remote_dir, tmp);
1769        mr_free(tmp);
1770        // check whether writable - we better remove surrounding spaces for this
1771        strip_spaces(bkpinfo->nfs_remote_dir);
1772        mr_asprintf(&command, "echo hi > '%s/%s/.dummy.txt'", bkpinfo->isodir,
1773                bkpinfo->nfs_remote_dir);
1774        while (run_program_and_log_output(command, FALSE)) {
1775            mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1776            mr_asprintf(&prompt,
1777                     _("Directory '%s' under mountpoint '%s' does not exist or is not writable. You can fix this or change the directory and retry or cancel the backup."),
1778                     bkpinfo->nfs_remote_dir, bkpinfo->isodir);
1779            if (!popup_and_get_string
1780                ("Directory", prompt, tmp, MAX_STR_LEN)) {
1781                log_to_screen("User has chosen not to backup the PC");
1782                finish(1);
1783            }
1784            mr_free(prompt);
1785
1786            strcpy(bkpinfo->nfs_remote_dir, tmp);
1787            mr_free(tmp);
1788            // check whether writable - we better remove surrounding space s for this
1789            strip_spaces(bkpinfo->nfs_remote_dir);
1790
1791            mr_free(command);
1792            mr_asprintf(&command, "echo hi > '%s/%s/.dummy.txt'", bkpinfo->isodir,
1793                    bkpinfo->nfs_remote_dir);
1794        }
1795        mr_free(command);
1796
1797        if (!popup_and_get_string
1798            ("Prefix.",
1799             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
1800            bkpinfo->prefix, MAX_STR_LEN / 4)) {
1801            log_to_screen("User has chosen not to backup the PC");
1802            finish(1);
1803        }
1804        mr_msg(3, "prefix set to %s", bkpinfo->prefix);
1805
1806        for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1807            bkpinfo->media_size[i] = 650;
1808        }
1809        mr_msg(3, "Just set nfs_remote_dir to %s",
1810                bkpinfo->nfs_remote_dir);
1811        mr_msg(3, "isodir is still %s", bkpinfo->isodir);
1812        break;
1813
1814    case iso:
1815        if (!bkpinfo->disaster_recovery) {
1816            if (!popup_and_get_string
1817                ("Storage dir.",
1818                 "Please enter the full path that contains your ISO images.  Example: /mnt/raid0_0",
1819                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
1820                log_to_screen("User has chosen not to backup the PC");
1821                finish(1);
1822            }
1823            if (archiving_to_media) {
1824                if ((bkpinfo->compression_level =
1825                     which_compression_level()) == -1) {
1826                    log_to_screen(_("User has chosen not to backup the PC"));
1827                    finish(1);
1828                }
1829                if (!popup_and_get_string
1830                    ("ISO size.",
1831                     "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.",
1832                     sz_size, 16)) {
1833                    log_to_screen("User has chosen not to backup the PC");
1834                    finish(1);
1835                }
1836                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1837                    bkpinfo->media_size[i] = atoi(sz_size);
1838                }
1839            } else {
1840                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1841                    bkpinfo->media_size[i] = 650;
1842                }
1843            }
1844        }
1845        if (!popup_and_get_string
1846            ("Prefix.",
1847             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
1848             bkpinfo->prefix, MAX_STR_LEN / 4)) {
1849            log_to_screen("User has chosen not to backup the PC");
1850            finish(1);
1851        }
1852        mr_msg(3, "prefix set to %s", bkpinfo->prefix);
1853        break;
1854    default:
1855        fatal_error
1856            ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
1857    }
1858    if (archiving_to_media) {
1859
1860#ifdef __FreeBSD__
1861        strcpy(bkpinfo->boot_device,
1862               call_program_and_get_last_line_of_output
1863               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
1864#else
1865        strcpy(bkpinfo->boot_device,
1866               call_program_and_get_last_line_of_output
1867               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
1868#endif
1869        i = which_boot_loader(bkpinfo->boot_device);
1870        if (i == 'U')           // unknown
1871        {
1872
1873#ifdef __FreeBSD__
1874            if (!popup_and_get_string
1875                ("Boot device",
1876                 "What is your boot device? (e.g. /dev/ad0)",
1877                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1878                log_to_screen("User has chosen not to backup the PC");
1879                finish(1);
1880            }
1881            i = which_boot_loader(bkpinfo->boot_device);
1882#else
1883            if (!popup_and_get_string
1884                ("Boot device",
1885                 "What is your boot device? (e.g. /dev/hda)",
1886                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1887                log_to_screen("User has chosen not to backup the PC");
1888                finish(1);
1889            }
1890            if (does_string_exist_in_boot_block
1891                (bkpinfo->boot_device, "LILO")) {
1892                i = 'L';
1893            } else
1894                if (does_string_exist_in_boot_block
1895                    (bkpinfo->boot_device, "ELILO")) {
1896                i = 'E';
1897            } else
1898                if (does_string_exist_in_boot_block
1899                    (bkpinfo->boot_device, "GRUB")) {
1900                i = 'G';
1901            } else {
1902                i = 'U';
1903            }
1904#endif
1905            if (i == 'U') {
1906                if (ask_me_yes_or_no
1907                    (_("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?")))
1908                {
1909                    i = 'R';    // raw
1910                } else {
1911                    log_to_screen
1912                        (_("I cannot find your boot loader. Please run mondoarchive with parameters."));
1913                    finish(1);
1914                }
1915            }
1916        }
1917        bkpinfo->boot_loader = i;
1918        strcpy(bkpinfo->include_paths, "/");
1919        if (!popup_and_get_string
1920            ("Backup paths",
1921             "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
1922             bkpinfo->include_paths, MAX_STR_LEN)) {
1923            log_to_screen("User has chosen not to backup the PC");
1924            finish(1);
1925        }
1926        mr_asprintf(&tmp, list_of_NFS_mounts_only());
1927        if (strlen(tmp) > 2) {
1928            if (bkpinfo->exclude_paths[0]) {
1929                strcat(bkpinfo->exclude_paths, " ");
1930            }
1931            strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
1932        }
1933        mr_free(tmp);
1934// NTFS
1935        mr_asprintf(&tmp,
1936               call_program_and_get_last_line_of_output
1937               ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
1938        if (strlen(tmp) > 2) {
1939            if (!popup_and_get_string
1940                ("NTFS partitions",
1941                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
1942                 tmp, MAX_STR_LEN / 4)) {
1943                log_to_screen("User has chosen not to backup the PC");
1944                finish(1);
1945            }
1946            strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
1947        }
1948        mr_free(tmp);
1949
1950        if (!popup_and_get_string
1951            ("Exclude paths",
1952             "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.",
1953             bkpinfo->exclude_paths, MAX_STR_LEN)) {
1954            log_to_screen("User has chosen not to backup the PC");
1955            finish(1);
1956        }
1957        bkpinfo->make_cd_use_lilo = FALSE;
1958        bkpinfo->backup_data = TRUE;
1959        bkpinfo->verify_data =
1960            ask_me_yes_or_no
1961            (_("Will you want to verify your backups after Mondo has created them?"));
1962
1963#ifndef __FreeBSD__
1964        if (!ask_me_yes_or_no
1965            ("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."))
1966#endif
1967        {
1968            strcpy(bkpinfo->kernel_path, "FAILSAFE");
1969        }
1970
1971        if (!ask_me_yes_or_no
1972            (_("Are you sure you want to proceed? Hit 'no' to abort."))) {
1973            log_to_screen(_("User has chosen not to backup the PC"));
1974            finish(1);
1975        }
1976    } else {
1977        bkpinfo->restore_data = TRUE;   // probably...
1978    }
1979
1980    if (bkpinfo->backup_media_type == iso
1981        || bkpinfo->backup_media_type == nfs) {
1982        g_ISO_restore_mode = TRUE;
1983    }
1984#ifdef __FreeSD__
1985// skip
1986#else
1987    if (bkpinfo->backup_media_type == nfs) {
1988        mr_msg(3, "I think the NFS mount is mounted at %s",
1989                bkpinfo->isodir);
1990    }
1991    log_it("isodir = %s", bkpinfo->isodir);
1992    log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
1993#endif
1994
1995    log_it("media device = %s", bkpinfo->media_device);
1996    log_it("media size = %ld", bkpinfo->media_size[1]);
1997    log_it("media type = %s", bkpinfo->backup_media_string);
1998    log_it("prefix = %s", bkpinfo->prefix);
1999    log_it("compression = %ld", bkpinfo->compression_level);
2000    log_it("include_paths = '%s'", bkpinfo->include_paths);
2001    log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
2002    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2003    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2004    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
2005           bkpinfo->boot_loader);
2006    if (bkpinfo->media_size[0] < 0) {
2007        if (archiving_to_media) {
2008            fatal_error("Media size is less than zero.");
2009        } else {
2010            mr_msg(2, "Warning - media size is less than zero.");
2011            bkpinfo->media_size[0] = 0;
2012        }
2013    }
2014    return (0);
2015}
2016
2017
2018/**
2019 * Get a space-separated list of NFS mounts.
2020 * @return The list created.
2021 * @note The return value points to static data that will be overwritten with each call.
2022 * @bug Even though we only want the mounts, the devices are still checked.
2023 */
2024char *list_of_NFS_mounts_only(void)
2025{
2026    char *exclude_these_devices;
2027    char *exclude_these_directories;
2028    static char result_sz[512];
2029
2030    malloc_string(exclude_these_devices);
2031    malloc_string(exclude_these_directories);
2032    strcpy(exclude_these_directories,
2033           call_program_and_get_last_line_of_output
2034           ("mount -t coda,ncpfs,nfs,smbfs,cifs,afs,mvfs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2035    strcpy(exclude_these_devices,
2036           call_program_and_get_last_line_of_output
2037           ("tr -s '\t' ' ' < /etc/fstab | grep -E '( (coda|ncpfs|nfs|smbfs|cifs|mvfs) )' | cut -d' ' -f1 | tr -s '\n' ' ' | awk '{print $0;}'"));
2038    sprintf(result_sz, "%s", exclude_these_directories);
2039    mr_free(exclude_these_devices);
2040    mr_free(exclude_these_directories);
2041    return (result_sz);
2042}
2043/* @} - end of utilityGroup */
2044
2045
2046/**
2047 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2048 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2049 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2050 * @ingroup utilityGroup
2051 */
2052void sensibly_set_tmpdir_and_scratchdir(struct s_bkpinfo *bkpinfo)
2053{
2054    char *tmp = NULL;
2055    char *command = NULL;
2056    char *sz = NULL;
2057    int i = 0;
2058
2059    malloc_string(command);
2060    assert(bkpinfo != NULL);
2061
2062#ifdef __FreeBSD__
2063    mr_asprintf(&tmp,
2064           call_program_and_get_last_line_of_output
2065           ("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;}'"));
2066#else
2067    mr_asprintf(&tmp,
2068           call_program_and_get_last_line_of_output
2069           ("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;}'"));
2070#endif
2071
2072    if (tmp[0] != '/') {
2073        mr_asprintf(&sz, "/%s", tmp);
2074        mr_free(tmp);
2075        tmp = sz;
2076    }
2077    if (!tmp[0]) {
2078        fatal_error("I couldn't figure out the tempdir!");
2079    }
2080    i = (int) (random() % 32768);
2081    sprintf(bkpinfo->tmpdir, "%s/tmp.mondo.%d", tmp, i);
2082    log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2083
2084    sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp, i);
2085    log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2086
2087    sprintf(g_erase_tmpdir_and_scratchdir, "rm -Rf %s %s", bkpinfo->tmpdir,
2088            bkpinfo->scratchdir);
2089
2090    mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2091    mr_free(tmp);
2092
2093    paranoid_system(command);
2094    mr_free(command);
2095}
2096
2097
2098/**
2099 * @addtogroup deviceGroup
2100 * @{
2101 */
2102/**
2103 * If we can read @p dev, set @p output to it.
2104 * If @p dev cannot be read, set @p output to "".
2105 * @param dev The device to check for.
2106 * @param output Set to @p dev if @p dev exists, "" otherwise.
2107 * @return TRUE if @p dev exists, FALSE if it doesn't.
2108 */
2109bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2110{
2111    char *command = NULL;
2112
2113    if (!dev || dev[0] == '\0') {
2114        output[0] = '\0';
2115        return (FALSE);
2116    }
2117    mr_msg(10, "Injecting %s", dev);
2118    inject_device(dev);
2119    if (!does_file_exist(dev)) {
2120        mr_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2121        return (FALSE);
2122    }
2123    mr_asprintf(&command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2124            512L, dev);
2125    if (!run_program_and_log_output(command, FALSE)
2126        && !run_program_and_log_output(command, FALSE)) {
2127        strcpy(output, dev);
2128        mr_msg(4, "Found it - %s", dev);
2129        mr_free(command);
2130        return (TRUE);
2131    } else {
2132        output[0] = '\0';
2133        mr_msg(4, "It's not %s", dev);
2134        mr_free(command);
2135        return (FALSE);
2136    }
2137}
2138
2139
2140/**
2141 * Find out what number CD is in the drive.
2142 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2143 * @return The current CD number, or -1 if it could not be found.
2144 * @note If the CD is not mounted, it will be mounted
2145 * (and remain mounted after this function returns).
2146 */
2147int what_number_cd_is_this(struct s_bkpinfo *bkpinfo)
2148{
2149    int cd_number = -1;
2150    char *mountdev = NULL;
2151    char *tmp = NULL;
2152    char *tmp1 = NULL;
2153
2154    assert(bkpinfo != NULL);
2155    if (g_ISO_restore_mode) {
2156        mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
2157
2158        mr_asprintf(&mountdev, "%s/archives/THIS-CD-NUMBER", call_program_and_get_last_line_of_output(tmp));
2159        cd_number = atoi(last_line_of_file(mountdev));
2160        mr_free(mountdev);
2161        mr_free(tmp);
2162        return (cd_number);
2163    }
2164
2165    mr_asprintf(&mountdev, bkpinfo->media_device);
2166    if (!mountdev[0]) {
2167        log_it
2168            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2169        find_cdrom_device(bkpinfo->media_device, FALSE);
2170    }
2171    if (!is_this_device_mounted(MNT_CDROM)) {
2172        mount_CDROM_here(mountdev, MNT_CDROM);
2173    }
2174    cd_number =
2175        atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2176    mr_free(mountdev);
2177    return (cd_number);
2178}
2179
2180
2181/**
2182 * Find out what device is mounted as root (/).
2183 * @return Root device.
2184 * @note The returned string points to static storage and will be overwritten with every call.
2185 * @bug A bit of a misnomer; it's actually finding out the root device.
2186 * The mountpoint (where it's mounted) will obviously be '/'.
2187 */
2188char *where_is_root_mounted()
2189{
2190    /*@ buffers **************** */
2191    static char tmp[MAX_STR_LEN];
2192
2193
2194#ifdef __FreeBSD__
2195    strcpy(tmp, call_program_and_get_last_line_of_output
2196           ("mount | grep \" on / \" | cut -d' ' -f1"));
2197#else
2198    strcpy(tmp, call_program_and_get_last_line_of_output
2199           ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2200    if (strstr(tmp, "/dev/cciss/")) {
2201        strcpy(tmp, call_program_and_get_last_line_of_output
2202               ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2203    }
2204    if (strstr(tmp, "/dev/md")) {
2205        strcpy(tmp,
2206               call_program_and_get_last_line_of_output
2207               ("mount | grep \" on / \" | cut -d' ' -f1"));
2208    }
2209#endif
2210
2211    return (tmp);
2212}
2213
2214
2215/**
2216 * Find out which boot loader is in use.
2217 * @param which_device Device to look for the boot loader on.
2218 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2219 * @note Under Linux, all drives are examined, not just @p which_device.
2220 */
2221char which_boot_loader(char *which_device)
2222{
2223#ifdef __FreeBSD__
2224    int count_lilos = 0;
2225    int count_grubs = 0;
2226    int count_boot0s = 0;
2227    int count_dangerouslydedicated = 0;
2228
2229    log_it("looking at drive %s's MBR", which_device);
2230    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2231        count_grubs++;
2232    }
2233    if (does_string_exist_in_boot_block(which_device, "LILO")) {
2234        count_lilos++;
2235    }
2236    if (does_string_exist_in_boot_block(which_device, "Drive")) {
2237        count_boot0s++;
2238    }
2239    if (does_string_exist_in_first_N_blocks
2240        (which_device, "FreeBSD/i386", 17)) {
2241        count_dangerouslydedicated++;
2242    }
2243    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2244           count_grubs, count_lilos, count_elilos, count_boot0s,
2245           count_dangerouslydedicated);
2246
2247    if (count_grubs && !count_lilos) {
2248        return ('G');
2249    } else if (count_lilos && !count_grubs) {
2250        return ('L');
2251    } else if (count_grubs == 1 && count_lilos == 1) {
2252        log_it("I'll bet you used to use LILO but switched to GRUB...");
2253        return ('G');
2254    } else if (count_boot0s == 1) {
2255        return ('B');
2256    } else if (count_dangerouslydedicated) {
2257        return ('D');
2258    } else {
2259        log_it("Unknown boot loader");
2260        return ('U');
2261    }
2262#else
2263    /*@ buffer ***************************************************** */
2264    char *list_drives_cmd;
2265    char *current_drive = NULL;
2266
2267    /*@ pointers *************************************************** */
2268    FILE *pdrives;
2269
2270    /*@ int ******************************************************** */
2271    int count_lilos = 0;
2272    int count_grubs = 0;
2273    size_t n = 0;
2274
2275    /*@ end vars *************************************************** */
2276
2277#ifdef __IA64__
2278    /* No choice for it */
2279    return ('E');
2280#endif
2281    assert(which_device != NULL);
2282    mr_asprintf(&list_drives_cmd,
2283            "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s",
2284            where_is_root_mounted());
2285    log_it("list_drives_cmd = %s", list_drives_cmd);
2286
2287    if (!(pdrives = popen(list_drives_cmd, "r"))) {
2288        log_OS_error("Unable to open list of drives");
2289        mr_free(list_drives_cmd);
2290        return ('\0');
2291    }
2292    mr_free(list_drives_cmd);
2293
2294    for (mr_getline(&current_drive, &n, pdrives); !feof(pdrives);
2295         mr_getline(&current_drive, &n, pdrives)) {
2296        strip_spaces(current_drive);
2297        log_it("looking at drive %s's MBR", current_drive);
2298        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2299            count_grubs++;
2300            strcpy(which_device, current_drive);
2301            break;
2302        }
2303        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2304            count_lilos++;
2305            strcpy(which_device, current_drive);
2306            break;
2307        }
2308    }
2309
2310    if (pclose(pdrives)) {
2311        log_OS_error("Cannot pclose pdrives");
2312    }
2313    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2314    if (count_grubs && !count_lilos) {
2315        return ('G');
2316    } else if (count_lilos && !count_grubs) {
2317        return ('L');
2318    } else if (count_grubs == 1 && count_lilos == 1) {
2319        log_it("I'll bet you used to use LILO but switched to GRUB...");
2320        return ('G');
2321    } else {
2322        log_it("Unknown boot loader");
2323        return ('U');
2324    }
2325#endif
2326}
2327
2328
2329/**
2330 * Write zeroes over the first 16K of @p device.
2331 * @param device The device to zero.
2332 * @return 0 for success, 1 for failure.
2333 */
2334int zero_out_a_device(char *device)
2335{
2336    FILE *fout;
2337    int i;
2338
2339    assert_string_is_neither_NULL_nor_zerolength(device);
2340
2341    log_it("Zeroing drive %s", device);
2342    if (!(fout = fopen(device, "w"))) {
2343        log_OS_error("Unable to open/write to device");
2344        return (1);
2345    }
2346    for (i = 0; i < 16384; i++) {
2347        fputc('\0', fout);
2348    }
2349    paranoid_fclose(fout);
2350    log_it("Device successfully zeroed.");
2351    return (0);
2352}
2353
2354
2355/**
2356 * Return the device pointed to by @p incoming.
2357 * @param incoming The device to resolve symlinks for.
2358 * @return The path to the real device file.
2359 * @note The returned string points to static storage that will be overwritten with each call.
2360 * @bug Won't work with file v4.0; needs to be written in C.
2361 */
2362char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2363{
2364    static char output[MAX_STR_LEN];
2365    char *command = NULL;
2366    char *curr_fname = NULL;
2367    char *scratch = NULL;
2368    char *tmp = NULL;
2369    char *p = NULL;
2370
2371    struct stat statbuf;
2372    malloc_string(tmp);
2373    malloc_string(scratch);
2374    malloc_string(curr_fname);
2375    if (!does_file_exist(incoming)) {
2376        log_it
2377            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2378        strcpy(output, incoming);
2379    } else {
2380        strcpy(curr_fname, incoming);
2381        lstat(curr_fname, &statbuf);
2382        while (S_ISLNK(statbuf.st_mode)) {
2383            mr_msg(1, "curr_fname = %s", curr_fname);
2384            mr_asprintf(&command, "file %s", curr_fname);
2385            strcpy(tmp, call_program_and_get_last_line_of_output(command));
2386            mr_free(command);
2387
2388            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2389                 p--);
2390            p++;
2391            strcpy(scratch, p);
2392            for (p = scratch; *p != '\0' && *p != '\''; p++);
2393            *p = '\0';
2394            mr_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp,
2395                    scratch);
2396            if (scratch[0] == '/') {
2397                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
2398            } else {            // copy over the basename cos it's a relative softlink
2399                p = curr_fname + strlen(curr_fname);
2400                while (p != curr_fname && *p != '/') {
2401                    p--;
2402                }
2403                if (*p == '/') {
2404                    p++;
2405                }
2406                strcpy(p, scratch);
2407            }
2408            lstat(curr_fname, &statbuf);
2409        }
2410        strcpy(output, curr_fname);
2411        log_it("resolved %s to %s", incoming, output);
2412    }
2413    mr_free(curr_fname);
2414    mr_free(tmp);
2415    return (output);
2416}
2417
2418/* @} - end of deviceGroup */
2419
2420
2421/**
2422 * Return the type of partition format (GPT or MBR)
2423 */
2424char *which_partition_format(const char *drive)
2425{
2426    static char output[4];
2427    char *tmp = NULL;
2428    char *command = NULL;
2429    char *fdisk = NULL;
2430
2431    mr_msg(0, "Looking for partition table format type");
2432    mr_asprintf(&fdisk, "/sbin/parted2fdisk");
2433    mr_msg(1, "Using %s", fdisk);
2434    mr_asprintf(&command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2435    mr_free(fdisk);
2436
2437    mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2438    mr_free(command);
2439
2440    if (strstr(tmp, "GPT") == NULL) {
2441        strcpy(output, "MBR");
2442    } else {
2443        strcpy(output, "GPT");
2444    }
2445    mr_free(tmp);
2446    mr_msg(0, "Found %s partition table format type", output);
2447    return(output);
2448}
2449/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.