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

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