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

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

Still linker fixes (grrr)

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