source: MondoRescue/branches/2.2.9/mondo/src/common/libmondo-devices.c @ 2220

Last change on this file since 2220 was 2220, checked in by Bruno Cornec, 11 years ago

Allow the possibility to enter temp and scratch dir in the newt interface. Fixes #326.

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