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

Last change on this file since 309 was 309, checked in by bcornec, 14 years ago

merge -r303:308 $SVN_M/branches/2.06

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