source: trunk/mondo/src/common/libmondo-devices.c @ 900

Last change on this file since 900 was 900, checked in by Bruno Cornec, 14 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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