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

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