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

Last change on this file since 2242 was 2242, checked in by bruno, 10 years ago

r3145@localhost: bruno | 2009-06-29 17:18:58 +0200

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