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

Last change on this file since 729 was 729, checked in by Bruno Cornec, 14 years ago

merge -r686:728 $SVN_M/branches/stable

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