source: branches/stable/mondo/src/common/libmondo-devices.c @ 1127

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

End on memory mngt for libmondo-devices.c for the moment

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