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

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

merge -r793:807 $SVN_M/branches/stable
src => common for the moment it's easier to manage merges

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