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

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

MAX_NOOF_MEDIA is gone and media_size in bkpinfo struct is now a single long field and not an array anymore

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