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

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

Fix trunk transfer errors to libmondo-devices.c

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