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

Last change on this file since 2257 was 2257, checked in by Bruno Cornec, 11 years ago
  • Reorder code to allow compilation by older gcc versions
  • Property svn:keywords set to Id
File size: 70.3 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 2257 2009-07-05 16:56:03Z 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 2257 2009-07-05 16:56:03Z 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#ifdef __FreeBSD__
1280    char *dev = NULL;
1281#else
1282    char *options = NULL;
1283#endif
1284
1285    assert_string_is_neither_NULL_nor_zerolength(device);
1286    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1287
1288    make_hole_for_dir(mountpoint);
1289
1290    if (isdigit(device[0])) {
1291        find_cdrom_device(device, FALSE);
1292    }
1293#ifndef __FreeBSD__
1294    mr_asprintf(&options, "ro");
1295#endif
1296
1297    if (g_ISO_restore_mode) {
1298
1299#ifdef __FreeBSD__
1300        mr_asprintf(&dev, make_vn(device));
1301        if (!dev) {
1302            mr_asprintf(&command, "Unable to mount ISO (make_vn(%s) failed)", device);
1303            fatal_error(command);
1304        }
1305        strcpy(device, dev);
1306        paranoid_free(dev);
1307#else
1308        mr_strcat(options, ",loop");
1309#endif
1310
1311    }
1312    log_msg(4, "(mount_CDROM_here --- device=%s, mountpoint=%s", device,
1313            mountpoint);
1314    /*@ end vars *************************************************** */
1315
1316#ifdef __FreeBSD__
1317    mr_asprintf(&command, "mount_cd9660 -r %s %s 2>> %s",
1318            device, mountpoint, MONDO_LOGFILE);
1319
1320#else
1321    mr_asprintf(&command, "mount %s -o %s -t iso9660 %s 2>> %s",
1322            device, options, mountpoint, MONDO_LOGFILE);
1323    paranoid_free(options);
1324#endif
1325
1326    log_msg(4, command);
1327    if (strncmp(device, "/dev/", 5) == 0) {
1328        retract_CD_tray_and_defeat_autorun();
1329    }
1330    retval = system(command);
1331    log_msg(1, "system(%s) returned %d", command, retval);
1332    paranoid_free(command);
1333
1334    return (retval);
1335}
1336
1337
1338
1339
1340
1341
1342/**
1343 * Ask the user for CD number @p cd_number_i_want.
1344 * Sets g_current_media_number once the correct CD is inserted.
1345 * @param bkpinfo The backup information structure. Fields used:
1346 * - @c bkpinfo->backup_media_type
1347 * - @c bkpinfo->prefix
1348 * - @c bkpinfo->isodir
1349 * - @c bkpinfo->media_device
1350 * - @c bkpinfo->please_dont_eject_when_restoring
1351 * @param cd_number_i_want The CD number to ask for.
1352 */
1353void
1354insist_on_this_cd_number(int cd_number_i_want)
1355{
1356
1357    /*@ int ************************************************************* */
1358    int res = 0;
1359
1360
1361    /*@ buffers ********************************************************* */
1362    char *tmp;
1363    char *mds = NULL;
1364    char *request;
1365
1366    assert(bkpinfo != NULL);
1367    assert(cd_number_i_want > 0);
1368
1369//  log_msg(3, "Insisting on CD number %d", cd_number_i_want);
1370
1371    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1372        log_msg(3,
1373                "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1374        return;
1375    }
1376    malloc_string(tmp);
1377    malloc_string(request);
1378    sprintf(tmp, "mkdir -p " MNT_CDROM);
1379    run_program_and_log_output(tmp, 5);
1380    if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso
1381        || bkpinfo->backup_media_type == nfs) {
1382        log_msg(3, "Remounting CD");
1383        g_ISO_restore_mode = TRUE;
1384// FIXME --- I'm tempted to do something about this...
1385// Why unmount and remount again and again?
1386        if (is_this_device_mounted(MNT_CDROM)) {
1387            run_program_and_log_output("umount " MNT_CDROM, 5);
1388        }
1389        sprintf(tmp, "mkdir -p %s/isodir &> /dev/null", bkpinfo->tmpdir);
1390        (void)system(tmp);
1391        sprintf(tmp, "%s/%s/%s-%d.iso", bkpinfo->isodir,
1392                bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1393                cd_number_i_want);
1394        if (!does_file_exist(tmp)) {
1395            sprintf(tmp, "%s/isodir/%s/%s-%d.iso", bkpinfo->tmpdir,
1396                    bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1397                    cd_number_i_want);
1398            if (does_file_exist(tmp)) {
1399                log_msg(1,
1400                        "FIXME - hacking bkpinfo->isodir from '%s' to %s/isodir",
1401                        bkpinfo->isodir, bkpinfo->tmpdir);
1402                sprintf(bkpinfo->isodir, "%s/isodir", bkpinfo->tmpdir);
1403            }
1404        }
1405        log_msg(3, "Mounting %s at %s", tmp, MNT_CDROM);
1406        if (mount_CDROM_here(tmp, MNT_CDROM)) {
1407            fatal_error("Mommy!");
1408        }
1409//    g_current_media_number = cd_number_i_want;
1410//    return;
1411    }
1412    if ((res = what_number_cd_is_this()) != cd_number_i_want) {
1413        log_msg(3, "Currently, we hold %d but we want %d", res,
1414                cd_number_i_want);
1415        mds = media_descriptor_string(bkpinfo->backup_media_type);
1416        sprintf(tmp, "Insisting on %s #%d", mds, cd_number_i_want);
1417        sprintf(request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want);
1418        mr_free(mds);
1419        log_msg(3, tmp);
1420        while (what_number_cd_is_this() != cd_number_i_want) {
1421            paranoid_system("sync");
1422            if (is_this_device_mounted(MNT_CDROM)) {
1423                res =
1424                    run_program_and_log_output("umount " MNT_CDROM, FALSE);
1425            } else {
1426                res = 0;
1427            }
1428            if (res) {
1429                log_to_screen("WARNING - failed to unmount CD-ROM drive");
1430            }
1431            if (!bkpinfo->please_dont_eject) {
1432                res = eject_device(bkpinfo->media_device);
1433            } else {
1434                res = 0;
1435            }
1436            if (res) {
1437                log_to_screen("WARNING - failed to eject CD-ROM disk");
1438            }
1439            popup_and_OK(request);
1440            if (!bkpinfo->please_dont_eject) {
1441                inject_device(bkpinfo->media_device);
1442            }
1443            paranoid_system("sync");
1444        }
1445        log_msg(1, "Thankyou. Proceeding...");
1446        g_current_media_number = cd_number_i_want;
1447    }
1448    paranoid_free(tmp);
1449    paranoid_free(request);
1450}
1451
1452/* @} - end of deviceGroup */
1453
1454
1455
1456
1457
1458
1459/**
1460 * Ask user for details of backup/restore information.
1461 * Called when @c mondoarchive doesn't get any parameters.
1462 * @param bkpinfo The backup information structure to fill out with the user's data.
1463 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
1464 * @return 0, always.
1465 * @bug No point of `int' return value.
1466 * @ingroup archiveGroup
1467 */
1468int interactively_obtain_media_parameters_from_user(bool archiving_to_media)
1469// archiving_to_media is TRUE if I'm being called by mondoarchive
1470// archiving_to_media is FALSE if I'm being called by mondorestore
1471{
1472    char *tmp = NULL;
1473    char *mds = NULL;
1474    char *sz_size;
1475    char *command;
1476    char *comment;
1477    char *prompt;
1478    int i;
1479    FILE *fin;
1480
1481    malloc_string(sz_size);
1482    malloc_string(command);
1483    malloc_string(comment);
1484    malloc_string(prompt);
1485    assert(bkpinfo != NULL);
1486    sz_size[0] = '\0';
1487    bkpinfo->nonbootable_backup = FALSE;
1488
1489    // Tape, CD, NFS, ...?
1490    srandom(getpid());
1491    bkpinfo->backup_media_type =
1492        (g_restoring_live_from_cd) ? cdr :
1493        which_backup_media_type(bkpinfo->restore_data);
1494    if (bkpinfo->backup_media_type == none) {
1495        log_to_screen("User has chosen not to backup the PC");
1496        finish(1);
1497    }
1498    /* Why asking to remove the media with tape ?
1499    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
1500        popup_and_OK("Please remove media from drive(s)");
1501    }
1502    */
1503    log_msg(3, "media type = %s",
1504            bkptype_to_string(bkpinfo->backup_media_type));
1505    if (archiving_to_media) {
1506        sensibly_set_tmpdir_and_scratchdir();
1507    }
1508    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
1509    bkpinfo->compression_level =
1510        (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
1511    bkpinfo->use_lzo =
1512        (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
1513    mvaddstr_and_log_it(2, 0, " ");
1514
1515    // Find device's /dev (or SCSI) entry
1516    switch (bkpinfo->backup_media_type) {
1517    case cdr:
1518    case cdrw:
1519    case dvd:
1520    case usb:
1521        /* Never try to eject a USB device */
1522        if (bkpinfo->backup_media_type == usb) {
1523            bkpinfo->please_dont_eject = TRUE;
1524        }
1525        if (archiving_to_media) {
1526            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1527                if (ask_me_yes_or_no
1528                    ("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?"))
1529                {
1530                    bkpinfo->manual_cd_tray = TRUE;
1531                }
1532            }
1533            if ((bkpinfo->compression_level =
1534                 which_compression_level()) == -1) {
1535                log_to_screen("User has chosen not to backup the PC");
1536                finish(1);
1537            }
1538            mds = media_descriptor_string(bkpinfo->backup_media_type);
1539            sprintf(comment, "What speed is your %s (re)writer?", mds);
1540            if (bkpinfo->backup_media_type == dvd) {
1541                find_dvd_device(bkpinfo->media_device, FALSE);
1542                mr_asprintf(&tmp, "1");
1543                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
1544                log_msg(1, "Setting to DVD defaults");
1545            } else {
1546                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
1547                mr_asprintf(&tmp, "4");
1548                strcpy(sz_size, "650");
1549                log_msg(1, "Setting to CD defaults");
1550            }
1551            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1552                if (!popup_and_get_string("Speed", comment, tmp, 4)) {
1553                    log_to_screen("User has chosen not to backup the PC");
1554                    finish(1);
1555                }
1556            }
1557            bkpinfo->cdrw_speed = atoi(tmp);    // if DVD then this shouldn't ever be used anyway :)
1558            mr_free(tmp);
1559
1560            sprintf(comment,
1561                    "How much data (in Megabytes) will each %s store?", mds);
1562            mr_free(mds);
1563            if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1564                log_to_screen("User has chosen not to backup the PC");
1565                finish(1);
1566            }
1567            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1568                bkpinfo->media_size[i] = atoi(sz_size);
1569            }
1570            if (bkpinfo->media_size[0] <= 0) {
1571                log_to_screen("User has chosen not to backup the PC");
1572                finish(1);
1573            }
1574        }
1575        /* No break because we continue even for usb */
1576    case cdstream:
1577        mds = media_descriptor_string(bkpinfo->backup_media_type);
1578
1579        if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
1580            strcpy(bkpinfo->media_device, "/dev/cdrom");
1581            log_msg(2, "CD-ROM device assumed to be at %s",
1582                    bkpinfo->media_device);
1583        } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))
1584                   || bkpinfo->backup_media_type == dvd) {
1585            if (!bkpinfo->media_device[0]) {
1586                strcpy(bkpinfo->media_device, "/dev/cdrom");
1587            }                   // just for the heck of it :)
1588            log_msg(1, "bkpinfo->media_device = %s",
1589                    bkpinfo->media_device);
1590            if (bkpinfo->backup_media_type == dvd
1591                || find_cdrom_device(bkpinfo->media_device, FALSE)) {
1592                log_msg(1, "bkpinfo->media_device = %s",
1593                        bkpinfo->media_device);
1594                sprintf(comment,
1595                        "Please specify your %s drive's /dev entry", mds);
1596                if (!popup_and_get_string
1597                    ("Device?", comment, bkpinfo->media_device,
1598                     MAX_STR_LEN / 4)) {
1599                    log_to_screen("User has chosen not to backup the PC");
1600                    finish(1);
1601                }
1602            }
1603            log_msg(2, "%s device found at %s", mds, bkpinfo->media_device);
1604        } else {
1605            if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) {
1606                bkpinfo->media_device[0] = '\0';
1607            }
1608            if (bkpinfo->media_device[0]) {
1609                if (bkpinfo->backup_media_type == usb) {
1610                    mr_asprintf(&tmp,
1611                        "I think your %s media corresponds to %s. Is this correct?", mds,
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.)", mds,
1616                        bkpinfo->media_device);
1617                }
1618                if (!ask_me_yes_or_no(tmp)) {
1619                    bkpinfo->media_device[0] = '\0';
1620                }
1621                mr_free(tmp);
1622            }
1623            if (!bkpinfo->media_device[0]) {
1624                if (bkpinfo->backup_media_type == usb) {
1625                    i = popup_and_get_string("/dev entry?",
1626                                         "What is the /dev entry of your USB Disk/Key, please?",
1627                                         bkpinfo->media_device,
1628                                         MAX_STR_LEN / 4);
1629                } else {
1630                    if (g_kernel_version < 2.6) {
1631                        i = popup_and_get_string("Device node?",
1632                                             "What is the SCSI node of your CD (re)writer, please?",
1633                                             bkpinfo->media_device,
1634                                             MAX_STR_LEN / 4);
1635                    } else {
1636                        i = popup_and_get_string("/dev entry?",
1637                                             "What is the /dev entry of your CD (re)writer, please?",
1638                                             bkpinfo->media_device,
1639                                             MAX_STR_LEN / 4);
1640                    }
1641                }
1642                if (!i) {
1643                    log_to_screen("User has chosen not to backup the PC");
1644                    finish(1);
1645                }
1646            }
1647        }
1648        mr_free(mds);
1649
1650        if (bkpinfo->backup_media_type == cdstream) {
1651            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1652                bkpinfo->media_size[i] = 650;
1653            }
1654        }
1655        break;
1656    case udev:
1657        if (!ask_me_yes_or_no
1658            ("This option is for advanced users only. Are you sure?")) {
1659            log_to_screen("User has chosen not to backup the PC");
1660            finish(1);
1661        }
1662    case tape:
1663
1664        if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) {
1665            log_msg(3, "Ok, using vanilla scsi tape.");
1666            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
1667            if ((fin = fopen(bkpinfo->media_device, "r"))) {
1668                paranoid_fclose(fin);
1669            } else {
1670                strcpy(bkpinfo->media_device, "/dev/osst0");
1671            }
1672        }
1673        if (bkpinfo->media_device[0]) {
1674            if ((fin = fopen(bkpinfo->media_device, "r"))) {
1675                paranoid_fclose(fin);
1676            } else {
1677                if (does_file_exist("/tmp/mondo-restore.cfg")) {
1678                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
1679                                 bkpinfo->media_device);
1680                }
1681            }
1682        }
1683        if (bkpinfo->media_device[0]) {
1684            mr_asprintf(&tmp,
1685                    "I think I've found your tape streamer at %s; am I right on the money?",
1686                    bkpinfo->media_device);
1687            if (!ask_me_yes_or_no(tmp)) {
1688                bkpinfo->media_device[0] = '\0';
1689            }
1690            mr_free(tmp);
1691        }
1692        if (!bkpinfo->media_device[0]) {
1693            if (!popup_and_get_string
1694                ("Device name?",
1695                 "What is the /dev entry of your tape streamer?",
1696                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
1697                log_to_screen("User has chosen not to backup the PC");
1698                finish(1);
1699            }
1700        }
1701        mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
1702        if (run_program_and_log_output(tmp, FALSE)) {
1703            log_to_screen("User has not specified a valid /dev entry");
1704            finish(1);
1705        }
1706        mr_free(tmp);
1707        log_msg(4, "sz_size = %s", sz_size);
1708        sz_size[0] = '\0';
1709
1710        bkpinfo->use_obdr = ask_me_yes_or_no
1711            ("Do you want to activate OBDR support for your tapes ?");
1712        if (sz_size[0] == '\0') {
1713            bkpinfo->media_size[0] = 0;
1714        } else {
1715            bkpinfo->media_size[0] =
1716                friendly_sizestr_to_sizelong(sz_size) / 2 - 50;
1717        }
1718        log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
1719        if (bkpinfo->media_size[0] <= 0) {
1720            bkpinfo->media_size[0] = 0;
1721        }
1722        for (i = 1; i <= MAX_NOOF_MEDIA; i++) {
1723            bkpinfo->media_size[i] = bkpinfo->media_size[0];
1724        }
1725        if (archiving_to_media) {
1726            if ((bkpinfo->compression_level =
1727                 which_compression_level()) == -1) {
1728                log_to_screen("User has chosen not to backup the PC");
1729                finish(1);
1730            }
1731        }
1732        break;
1733
1734
1735
1736    case nfs:
1737        /* Never try to eject a NFS device */
1738        bkpinfo->please_dont_eject = TRUE;
1739
1740        /* Initiate bkpinfo nfs_mount path from running environment if not already done */
1741        if (!bkpinfo->nfs_mount[0]) {
1742            strcpy(bkpinfo->nfs_mount,
1743                   call_program_and_get_last_line_of_output
1744                   ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
1745        }
1746#ifdef __FreeBSD__
1747        if (TRUE)
1748#else
1749        if (!bkpinfo->disaster_recovery)
1750#endif
1751        {
1752            if (!popup_and_get_string
1753                ("NFS dir.",
1754                 "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.)",
1755                 bkpinfo->nfs_mount, MAX_STR_LEN / 4)) {
1756                log_to_screen("User has chosen not to backup the PC");
1757                finish(1);
1758            }
1759            if (!bkpinfo->restore_data) {
1760                if ((bkpinfo->compression_level =
1761                     which_compression_level()) == -1) {
1762                    log_to_screen("User has chosen not to backup the PC");
1763                    finish(1);
1764                }
1765            }
1766            // check whether already mounted - we better remove
1767            // surrounding spaces and trailing '/' for this
1768            strip_spaces(bkpinfo->nfs_mount);
1769            if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
1770                bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
1771            sprintf(command, "mount | grep \"%s \" | cut -d' ' -f3",
1772                    bkpinfo->nfs_mount);
1773            strcpy(bkpinfo->isodir,
1774                   call_program_and_get_last_line_of_output(command));
1775
1776            if (!bkpinfo->restore_data) {
1777                sprintf(comment,
1778                    "How much data (in Megabytes) will each media store?");
1779                if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1780                    log_to_screen("User has chosen not to backup the PC");
1781                    finish(1);
1782                }
1783            } else {
1784                strcpy(sz_size, "0");
1785            }
1786            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1787                bkpinfo->media_size[i] = atoi(sz_size);
1788            }
1789            if (bkpinfo->media_size[0] < 0) {
1790                log_to_screen("User has chosen not to backup the PC");
1791                finish(1);
1792            }
1793        }
1794        if (bkpinfo->disaster_recovery) {
1795            sprintf(command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
1796            (void)system(command);
1797            if (!popup_and_get_string
1798                ("NFS share", "Which remote NFS share should I mount?",
1799                 bkpinfo->nfs_mount, MAX_STR_LEN)) {
1800                log_to_screen("User has chosen not to backup the PC");
1801                finish(1);
1802            }
1803        }
1804        /* Initiate bkpinfo isodir path from running environment if mount already done */
1805        if (is_this_device_mounted(bkpinfo->nfs_mount)) {
1806            strcpy(bkpinfo->isodir,
1807                   call_program_and_get_last_line_of_output
1808                   ("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
1809        } else {
1810            sprintf(bkpinfo->isodir, "%s/nfsdir", bkpinfo->tmpdir);
1811            sprintf(command, "mkdir -p %s", bkpinfo->isodir);
1812            run_program_and_log_output(command, 5);
1813            mr_asprintf(&tmp, "mount -t nfs -o nolock %s %s", bkpinfo->nfs_mount,
1814                    bkpinfo->isodir);
1815            run_program_and_log_output(tmp, 3);
1816            mr_free(tmp);
1817
1818            malloc_string(g_selfmounted_isodir);
1819            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
1820        }
1821        if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1822            popup_and_OK
1823                ("Please mount that partition before you try to backup to or restore from it.");
1824            finish(1);
1825        }
1826        mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1827        if (!popup_and_get_string
1828            ("Directory", "Which directory within that mountpoint?", tmp,
1829             MAX_STR_LEN)) {
1830            log_to_screen("User has chosen not to backup the PC");
1831            finish(1);
1832        }
1833        strcpy(bkpinfo->nfs_remote_dir, tmp);
1834        mr_free(tmp);
1835
1836        // check whether writable - we better remove surrounding spaces for this
1837        strip_spaces(bkpinfo->nfs_remote_dir);
1838
1839        if (!popup_and_get_string
1840            ("Prefix.",
1841             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
1842            bkpinfo->prefix, MAX_STR_LEN / 4)) {
1843            log_to_screen("User has chosen not to backup the PC");
1844            finish(1);
1845        }
1846        log_msg(3, "prefix set to %s", bkpinfo->prefix);
1847
1848        for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1849            bkpinfo->media_size[i] = 650;
1850        }
1851        log_msg(3, "Just set nfs_remote_dir to %s",
1852                bkpinfo->nfs_remote_dir);
1853        log_msg(3, "isodir is still %s", bkpinfo->isodir);
1854        break;
1855
1856    case iso:
1857        if (!bkpinfo->disaster_recovery) {
1858            if (!popup_and_get_string
1859                ("Storage dir.",
1860                 "Please enter the full path name to the directory for your ISO images.  Example: /mnt/raid0_0",
1861                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
1862                log_to_screen("User has chosen not to backup the PC");
1863                finish(1);
1864            }
1865            if (archiving_to_media) {
1866                if ((bkpinfo->compression_level =
1867                     which_compression_level()) == -1) {
1868                    log_to_screen("User has chosen not to backup the PC");
1869                    finish(1);
1870                }
1871                if (!popup_and_get_string
1872                    ("ISO size.",
1873                     "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.",
1874                     sz_size, 16)) {
1875                    log_to_screen("User has chosen not to backup the PC");
1876                    finish(1);
1877                }
1878                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1879                    bkpinfo->media_size[i] = atoi(sz_size);
1880                }
1881            } else {
1882                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1883                    bkpinfo->media_size[i] = 650;
1884                }
1885            }
1886        }
1887        if (!popup_and_get_string
1888            ("Prefix.",
1889             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
1890             bkpinfo->prefix, MAX_STR_LEN / 4)) {
1891            log_to_screen("User has chosen not to backup the PC");
1892            finish(1);
1893        }
1894        log_msg(3, "prefix set to %s", bkpinfo->prefix);
1895        break;
1896    default:
1897        fatal_error
1898            ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
1899    }
1900
1901    if (archiving_to_media) {
1902
1903#ifdef __FreeBSD__
1904        strcpy(bkpinfo->boot_device,
1905               call_program_and_get_last_line_of_output
1906               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
1907#else
1908        strcpy(bkpinfo->boot_device,
1909               call_program_and_get_last_line_of_output
1910               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
1911#endif
1912        i = which_boot_loader(bkpinfo->boot_device);
1913        if (i == 'U')           // unknown
1914        {
1915
1916#ifdef __FreeBSD__
1917            if (!popup_and_get_string
1918                ("Boot device",
1919                 "What is your boot device? (e.g. /dev/ad0)",
1920                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1921                log_to_screen("User has chosen not to backup the PC");
1922                finish(1);
1923            }
1924            i = which_boot_loader(bkpinfo->boot_device);
1925#else
1926            if (!popup_and_get_string
1927                ("Boot device",
1928                 "What is your boot device? (e.g. /dev/hda)",
1929                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1930                log_to_screen("User has chosen not to backup the PC");
1931                finish(1);
1932            }
1933            if (does_string_exist_in_boot_block
1934                (bkpinfo->boot_device, "LILO")) {
1935                i = 'L';
1936            } else
1937                if (does_string_exist_in_boot_block
1938                    (bkpinfo->boot_device, "ELILO")) {
1939                i = 'E';
1940            } else
1941                if (does_string_exist_in_boot_block
1942                    (bkpinfo->boot_device, "GRUB")) {
1943                i = 'G';
1944            } else {
1945                i = 'U';
1946            }
1947#endif
1948            if (i == 'U') {
1949                if (ask_me_yes_or_no
1950                    ("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?"))
1951                {
1952                    i = 'R';    // raw
1953                } else {
1954                    log_to_screen
1955                        ("I cannot find your boot loader. Please run mondoarchive with parameters.");
1956                    finish(1);
1957                }
1958            }
1959        }
1960        bkpinfo->boot_loader = i;
1961        strcpy(bkpinfo->include_paths, "/");
1962        if (!popup_and_get_string
1963            ("Backup paths",
1964             "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
1965             bkpinfo->include_paths, MAX_STR_LEN)) {
1966            log_to_screen("User has chosen not to backup the PC");
1967            finish(1);
1968        }
1969        mr_asprintf(&tmp, "%s", list_of_NFS_mounts_only());
1970        if (strlen(tmp) > 2) {
1971            if (bkpinfo->exclude_paths[0]) {
1972                strcat(bkpinfo->exclude_paths, " ");
1973            }
1974            strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
1975        }
1976        mr_free(tmp);
1977// NTFS
1978        mr_asprintf(&tmp, "%s",
1979               call_program_and_get_last_line_of_output
1980               ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
1981        if (strlen(tmp) > 2) {
1982            if (!popup_and_get_string
1983                ("NTFS partitions",
1984                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
1985                 tmp, MAX_STR_LEN / 4)) {
1986                log_to_screen("User has chosen not to backup the PC");
1987                finish(1);
1988            }
1989            strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
1990        }
1991        mr_free(tmp);
1992
1993
1994        if (!popup_and_get_string
1995            ("Exclude paths",
1996             "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.",
1997             bkpinfo->exclude_paths, (4*MAX_STR_LEN)-1)) {
1998            log_to_screen("User has chosen not to backup the PC");
1999            finish(1);
2000        }
2001        if (!popup_and_get_string
2002            ("Temporary directory",
2003             "Please enter your temporary directory.",
2004             bkpinfo->tmpdir, (4*MAX_STR_LEN)-1)) {
2005            log_to_screen("User has chosen not to backup the PC");
2006            finish(1);
2007        }
2008        if (!popup_and_get_string
2009            ("Scratch directory",
2010             "Please enter your scratch directory.",
2011             bkpinfo->scratchdir, (4*MAX_STR_LEN)-1)) {
2012            log_to_screen("User has chosen not to backup the PC");
2013            finish(1);
2014        }
2015// Interactive mode:
2016#ifdef __IA64__
2017        bkpinfo->make_cd_use_lilo = TRUE;
2018#else
2019        bkpinfo->make_cd_use_lilo = FALSE;
2020#endif
2021        bkpinfo->backup_data = TRUE;
2022        bkpinfo->verify_data =
2023            ask_me_yes_or_no
2024            ("Will you want to verify your backups after Mondo has created them?");
2025
2026#ifndef __FreeBSD__
2027        if (!ask_me_yes_or_no
2028            ("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."))
2029#endif
2030        {
2031            strcpy(bkpinfo->kernel_path, "FAILSAFE");
2032        }
2033
2034        if (!ask_me_yes_or_no
2035            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2036            log_to_screen("User has chosen not to backup the PC");
2037            finish(1);
2038        }
2039    } else {
2040        bkpinfo->restore_data = TRUE;   // probably...
2041    }
2042
2043    if (bkpinfo->backup_media_type == iso
2044        || bkpinfo->backup_media_type == nfs) {
2045        g_ISO_restore_mode = TRUE;
2046    }
2047#ifdef __FreeSD__
2048// skip
2049#else
2050    if (bkpinfo->backup_media_type == nfs) {
2051        log_msg(3, "I think the NFS mount is mounted at %s",
2052                bkpinfo->isodir);
2053    }
2054    log_it("isodir = %s", bkpinfo->isodir);
2055    log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
2056    if (bkpinfo->nfs_user) {
2057        log_it("nfs_user = '%s'", bkpinfo->nfs_user);
2058    }
2059#endif
2060
2061    log_it("media device = %s", bkpinfo->media_device);
2062    log_it("media size = %ld", bkpinfo->media_size[1]);
2063    log_it("media type = %s",
2064           bkptype_to_string(bkpinfo->backup_media_type));
2065    log_it("prefix = %s", bkpinfo->prefix);
2066    log_it("compression = %ld", bkpinfo->compression_level);
2067    log_it("include_paths = '%s'", bkpinfo->include_paths);
2068    log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
2069    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2070    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2071    log_it("image_devs = '%s'", bkpinfo->image_devs);
2072    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
2073           bkpinfo->boot_loader);
2074    if (bkpinfo->media_size[0] < 0) {
2075        if (archiving_to_media) {
2076            fatal_error("Media size is less than zero.");
2077        } else {
2078            log_msg(2, "Warning - media size is less than zero.");
2079            bkpinfo->media_size[0] = 0;
2080        }
2081    }
2082    paranoid_free(sz_size);
2083    paranoid_free(command);
2084    paranoid_free(comment);
2085    paranoid_free(prompt);
2086    return (0);
2087}
2088
2089
2090
2091
2092/**
2093 * @addtogroup utilityGroup
2094 * @{
2095 */
2096/**
2097 * Get a space-separated list of NFS devices and mounts.
2098 * @return The list created.
2099 * @note The return value points to static data that will be overwritten with each call.
2100 */
2101char *list_of_NFS_devices_and_mounts(void)
2102{
2103    char *exclude_these_devices = NULL;
2104    char *exclude_these_directories = NULL;
2105    static char result_sz[1024];
2106
2107    mr_asprintf(&exclude_these_directories,"%s",list_of_NFS_mounts_only());
2108    mr_asprintf(&exclude_these_devices,"%s",
2109           call_program_and_get_last_line_of_output
2110           ("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;}'"));
2111    snprintf(result_sz, 1023, "%s %s", exclude_these_directories, exclude_these_devices);
2112    mr_free(exclude_these_devices);
2113    mr_free(exclude_these_directories);
2114    return (result_sz);
2115}
2116
2117
2118
2119
2120/**
2121 * Get a space-separated list of NFS mounts.
2122 * @return The list created.
2123 * @note The return value points to static data that will be overwritten with each call.
2124 * @bug Even though we only want the mounts, the devices are still checked.
2125 */
2126char *list_of_NFS_mounts_only(void)
2127{
2128    char *exclude_these_directories = NULL;
2129    static char result_sz[512];
2130
2131    mr_asprintf(&exclude_these_directories,"%s",
2132           call_program_and_get_last_line_of_output
2133           ("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;}'"));
2134    snprintf(result_sz, 511, "%s", exclude_these_directories);
2135    mr_free(exclude_these_directories);
2136    return (result_sz);
2137}
2138
2139/* @} - end of utilityGroup */
2140
2141
2142
2143
2144
2145/**
2146 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2147 * [random] is a random number between 1 and 32767.
2148 * @param store_name_here Where to store the new filename.
2149 * @param stub A random number will be appended to this to make the FIFO's name.
2150 * @ingroup deviceGroup
2151 */
2152void make_fifo(char *store_name_here, char *stub)
2153{
2154    char *tmp;
2155
2156    malloc_string(tmp);
2157    assert_string_is_neither_NULL_nor_zerolength(stub);
2158
2159    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2160            (int) (random() % 32768));
2161    make_hole_for_file(store_name_here);
2162    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2163    sprintf(tmp, "chmod 770 %s", store_name_here);
2164    paranoid_system(tmp);
2165    paranoid_free(tmp);
2166}
2167
2168
2169
2170
2171
2172
2173/**
2174 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2175 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2176 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2177 * @ingroup utilityGroup
2178 */
2179void sensibly_set_tmpdir_and_scratchdir()
2180{
2181    char *tmp = NULL; 
2182    char *command = NULL;
2183    char *sz = NULL;
2184
2185    assert(bkpinfo != NULL);
2186
2187#ifdef __FreeBSD__
2188    mr_asprintf(&tmp,
2189           call_program_and_get_last_line_of_output
2190           ("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;}'"));
2191#else
2192    mr_asprintf(&tmp,
2193           call_program_and_get_last_line_of_output
2194           ("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;}'"));
2195#endif
2196
2197    if (tmp[0] != '/') {
2198        mr_asprintf(&sz, tmp);
2199        paranoid_free(tmp);
2200        mr_asprintf(&tmp, "/%s", sz);
2201        mr_free(sz);
2202    }
2203    if (!tmp[0]) {
2204        fatal_error("I couldn't figure out the tempdir!");
2205    }
2206    setup_tmpdir(tmp);
2207    log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2208
2209    sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp,
2210            (int) (random() % 32768));
2211    log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2212
2213    mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2214    paranoid_free(tmp);
2215
2216    paranoid_system(command);
2217    mr_free(command);
2218}
2219
2220
2221
2222
2223
2224
2225/**
2226 * @addtogroup deviceGroup
2227 * @{
2228 */
2229/**
2230 * If we can read @p dev, set @p output to it.
2231 * If @p dev cannot be read, set @p output to "".
2232 * @param dev The device to check for.
2233 * @param output Set to @p dev if @p dev exists, "" otherwise.
2234 * @return TRUE if @p dev exists, FALSE if it doesn't.
2235 */
2236bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2237{
2238    char *command;
2239
2240    malloc_string(command);
2241    if (!dev || dev[0] == '\0') {
2242        output[0] = '\0';
2243        return (FALSE);
2244    }
2245//  assert_string_is_neither_NULL_nor_zerolength(dev);
2246    log_msg(10, "Injecting %s", dev);
2247    inject_device(dev);
2248    if (!does_file_exist(dev)) {
2249        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2250        return (FALSE);
2251    }
2252    sprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2253            512L, dev);
2254    if (!run_program_and_log_output(command, FALSE)
2255        && !run_program_and_log_output(command, FALSE)) {
2256        strcpy(output, dev);
2257        log_msg(4, "Found it - %s", dev);
2258        return (TRUE);
2259    } else {
2260        output[0] = '\0';
2261        log_msg(4, "It's not %s", dev);
2262        return (FALSE);
2263    }
2264}
2265
2266
2267
2268
2269
2270/**
2271 * Find out what number CD is in the drive.
2272 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2273 * @return The current CD number, or -1 if it could not be found.
2274 * @note If the CD is not mounted, it will be mounted
2275 * (and remain mounted after this function returns).
2276 */
2277int what_number_cd_is_this()
2278{
2279    int cd_number = -1;
2280    char *mountdev = NULL;
2281    char *tmp = NULL;
2282
2283    assert(bkpinfo != NULL);
2284//  log_it("Asking what_number_cd_is_this");
2285    if (g_ISO_restore_mode) {
2286        mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
2287
2288        mr_asprintf(&mountdev, "%s%s", call_program_and_get_last_line_of_output(tmp), "/archives/THIS-CD-NUMBER");
2289        cd_number = atoi(last_line_of_file(mountdev));
2290        paranoid_free(mountdev);
2291        paranoid_free(tmp);
2292
2293        return (cd_number);
2294    }
2295
2296    mr_asprintf(&mountdev, bkpinfo->media_device);
2297    if (!mountdev[0]) {
2298        log_it
2299            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2300        find_cdrom_device(bkpinfo->media_device, FALSE);
2301    }
2302    if (!is_this_device_mounted(MNT_CDROM)) {
2303        if (bkpinfo->backup_media_type == usb) {
2304            mount_USB_here(mountdev, MNT_CDROM);
2305        } else {
2306            mount_CDROM_here(mountdev, MNT_CDROM);
2307        }
2308    }
2309    paranoid_free(mountdev);
2310
2311    cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2312    return (cd_number);
2313}
2314
2315
2316
2317
2318
2319
2320
2321/**
2322 * Find out what device is mounted as root (/).
2323 * @return Root device.
2324 * @note The returned string points to static storage and will be overwritten with every call.
2325 * @bug A bit of a misnomer; it's actually finding out the root device.
2326 * The mountpoint (where it's mounted) will obviously be '/'.
2327 */
2328char *where_is_root_mounted()
2329{
2330    /*@ buffers **************** */
2331    static char tmp[MAX_STR_LEN];
2332
2333
2334#ifdef __FreeBSD__
2335    strcpy(tmp, call_program_and_get_last_line_of_output
2336           ("mount | grep \" on / \" | cut -d' ' -f1"));
2337#else
2338    strcpy(tmp, call_program_and_get_last_line_of_output
2339           ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2340    if (strstr(tmp, "/dev/cciss/")) {
2341        strcpy(tmp, call_program_and_get_last_line_of_output
2342               ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2343    }
2344    if (strstr(tmp, "/dev/md")) {
2345        strcpy(tmp,
2346               call_program_and_get_last_line_of_output
2347               ("mount | grep \" on / \" | cut -d' ' -f1"));
2348    }
2349#endif
2350
2351    return (tmp);
2352}
2353
2354
2355/**
2356 * Find out which boot loader is in use.
2357 * @param which_device Device to look for the boot loader on.
2358 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2359 * @note Under Linux, all drives are examined, not just @p which_device.
2360 */
2361#ifdef __FreeBSD__
2362char which_boot_loader(char *which_device)
2363{
2364    int count_lilos = 0;
2365    int count_grubs = 0;
2366    int count_boot0s = 0;
2367    int count_dangerouslydedicated = 0;
2368
2369    log_it("looking at drive %s's MBR", which_device);
2370    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2371        count_grubs++;
2372    }
2373    if (does_string_exist_in_boot_block(which_device, "LILO")) {
2374        count_lilos++;
2375    }
2376    if (does_string_exist_in_boot_block(which_device, "Drive")) {
2377        count_boot0s++;
2378    }
2379    if (does_string_exist_in_first_N_blocks
2380        (which_device, "FreeBSD/i386", 17)) {
2381        count_dangerouslydedicated++;
2382    }
2383    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2384           count_grubs, count_lilos, count_elilos, count_boot0s,
2385           count_dangerouslydedicated);
2386
2387    if (count_grubs && !count_lilos) {
2388        return ('G');
2389    } else if (count_lilos && !count_grubs) {
2390        return ('L');
2391    } else if (count_grubs == 1 && count_lilos == 1) {
2392        log_it("I'll bet you used to use LILO but switched to GRUB...");
2393        return ('G');
2394    } else if (count_boot0s == 1) {
2395        return ('B');
2396    } else if (count_dangerouslydedicated) {
2397        return ('D');
2398    } else {
2399        log_it("Unknown boot loader");
2400        return ('U');
2401    }
2402}
2403
2404#else
2405
2406char which_boot_loader(char *which_device)
2407{
2408    /*@ buffer ***************************************************** */
2409    char *list_drives_cmd = NULL;
2410    char *current_drive;
2411
2412    /*@ pointers *************************************************** */
2413    FILE *pdrives;
2414
2415    /*@ int ******************************************************** */
2416    int count_lilos = 0;
2417    int count_grubs = 0;
2418
2419    /*@ end vars *************************************************** */
2420
2421    malloc_string(current_drive);
2422
2423#ifdef __IA64__
2424    /* No choice for it */
2425    return ('E');
2426#endif
2427    assert(which_device != NULL);
2428
2429    mr_asprintf(&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        mr_free(list_drives_cmd);
2437        paranoid_free(current_drive);
2438        return ('\0');
2439    }
2440    mr_free(list_drives_cmd);
2441
2442    for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
2443         (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
2444        strip_spaces(current_drive);
2445        log_it("looking at drive %s's MBR", current_drive);
2446        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2447            count_grubs++;
2448            strcpy(which_device, current_drive);
2449            break;
2450        }
2451        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2452            count_lilos++;
2453            strcpy(which_device, current_drive);
2454            break;
2455        }
2456    }
2457    if (pclose(pdrives)) {
2458        log_OS_error("Cannot pclose pdrives");
2459    }
2460    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2461    if (count_grubs && !count_lilos) {
2462        paranoid_free(current_drive);
2463        return ('G');
2464    } else if (count_lilos && !count_grubs) {
2465        paranoid_free(current_drive);
2466        return ('L');
2467    } else if (count_grubs == 1 && count_lilos == 1) {
2468        log_it("I'll bet you used to use LILO but switched to GRUB...");
2469        paranoid_free(current_drive);
2470        return ('G');
2471    } else {
2472        // We need to look on each partition then
2473        mr_asprintf(&list_drives_cmd,
2474            "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
2475        log_it("list_drives_cmd = %s", list_drives_cmd);
2476
2477        if (!(pdrives = popen(list_drives_cmd, "r"))) {
2478            log_OS_error("Unable to open list of drives");
2479            mr_free(list_drives_cmd);
2480            paranoid_free(current_drive);
2481            return ('\0');
2482        }
2483        mr_free(list_drives_cmd);
2484
2485        for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
2486            (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
2487            strip_spaces(current_drive);
2488            log_it("looking at partition %s's BR", current_drive);
2489            if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2490                count_grubs++;
2491                strcpy(which_device, current_drive);
2492                break;
2493            }
2494            if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2495                count_lilos++;
2496                strcpy(which_device, current_drive);
2497                break;
2498            }
2499        }
2500        if (pclose(pdrives)) {
2501            log_OS_error("Cannot pclose pdrives");
2502        }
2503        log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2504        paranoid_free(current_drive);
2505        if (count_grubs && !count_lilos) {
2506            return ('G');
2507        } else if (count_lilos && !count_grubs) {
2508            return ('L');
2509        } else if (count_grubs == 1 && count_lilos == 1) {
2510            log_it("I'll bet you used to use LILO but switched to GRUB...");
2511            return ('G');
2512        } else {
2513            log_it("Unknown boot loader");
2514            return ('U');
2515        }
2516    }
2517}
2518#endif
2519
2520
2521
2522
2523/**
2524 * Write zeroes over the first 16K of @p device.
2525 * @param device The device to zero.
2526 * @return 0 for success, 1 for failure.
2527 */
2528int zero_out_a_device(char *device)
2529{
2530    FILE *fout;
2531    int i;
2532
2533    assert_string_is_neither_NULL_nor_zerolength(device);
2534
2535    log_it("Zeroing drive %s", device);
2536    if (!(fout = fopen(device, "w"))) {
2537        log_OS_error("Unable to open/write to device");
2538        return (1);
2539    }
2540    for (i = 0; i < 16384; i++) {
2541        fputc('\0', fout);
2542    }
2543    paranoid_fclose(fout);
2544    log_it("Device successfully zeroed.");
2545    return (0);
2546}
2547
2548/**
2549 * Return the device pointed to by @p incoming.
2550 * @param incoming The device to resolve symlinks for.
2551 * @return The path to the real device file.
2552 * @note The returned string points to static storage that will be overwritten with each call.
2553 * @bug Won't work with file v4.0; needs to be written in C.
2554 */
2555char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2556{
2557    static char output[MAX_STR_LEN];
2558    char *command;
2559    char *curr_fname;
2560    char *scratch = NULL;
2561    char *tmp = NULL;
2562    char *p;
2563
2564    struct stat statbuf;
2565    command = malloc(1000);
2566    malloc_string(curr_fname);
2567    if (!does_file_exist(incoming)) {
2568        log_it
2569            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2570        strcpy(output, incoming);
2571    } else {
2572        strcpy(curr_fname, incoming);
2573        lstat(curr_fname, &statbuf);
2574        while (S_ISLNK(statbuf.st_mode)) {
2575            log_msg(1, "curr_fname = %s", curr_fname);
2576            sprintf(command, "file %s", curr_fname);
2577            mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2578            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2579                 p--);
2580            p++;
2581            mr_asprintf(&scratch, p);
2582            for (p = scratch; *p != '\0' && *p != '\''; p++);
2583            *p = '\0';
2584            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
2585            mr_free(tmp);
2586
2587            if (scratch[0] == '/') {
2588                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
2589            } else {            // copy over the basename cos it's a relative softlink
2590                p = curr_fname + strlen(curr_fname);
2591                while (p != curr_fname && *p != '/') {
2592                    p--;
2593                }
2594                if (*p == '/') {
2595                    p++;
2596                }
2597                strcpy(p, scratch);
2598            }
2599            mr_free(scratch);
2600            lstat(curr_fname, &statbuf);
2601        }
2602        strcpy(output, curr_fname);
2603        log_it("resolved %s to %s", incoming, output);
2604    }
2605    paranoid_free(command);
2606    paranoid_free(curr_fname);
2607    return (output);
2608}
2609
2610/* @} - end of deviceGroup */
2611
2612
2613/**
2614 * Return the type of partition format (GPT or MBR)
2615 */
2616char *which_partition_format(const char *drive)
2617{
2618    static char output[4];
2619    char *tmp = NULL;
2620    char *command;
2621    char *fdisk;
2622#ifdef __IA64__
2623    struct stat buf;
2624#endif
2625    malloc_string(command);
2626    malloc_string(fdisk);
2627    log_msg(0, "Looking for partition table format type");
2628    sprintf(fdisk, "/sbin/parted2fdisk");
2629    log_msg(1, "Using %s", fdisk);
2630    sprintf(command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2631    mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2632    if (strstr(tmp, "GPT") == NULL) {
2633        strcpy(output, "MBR");
2634    } else {
2635        strcpy(output, "GPT");
2636    }
2637    mr_free(tmp);
2638
2639    log_msg(0, "Found %s partition table format type", output);
2640    paranoid_free(command);
2641    paranoid_free(fdisk);
2642    return (output);
2643}
2644
2645/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.