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

Last change on this file since 1268 was 1268, checked in by bruno, 12 years ago

bkptype_to_string is now a public function (not static anymore)

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