source: MondoRescue/trunk/mondo/mondo/common/libmondo-devices.c @ 162

Last change on this file since 162 was 162, checked in by andree, 15 years ago

Avoid overwriting the already correctly determined disk size by moving
the relevant code inside the if clause that checks the validity of the
previously calculated disk size.

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