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

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

Continue to remove floppy support

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