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

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

merge -r229:235 $SVN_M/branches/2.05

  • Property svn:keywords set to Id
File size: 65.1 KB
Line 
1/* $Id: libmondo-devices.c 236 2005-12-19 18:31:56Z 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 236 2005-12-19 18:31:56Z 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            "cat /proc/filesystems | grep -v nodev | 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        if (bkpinfo->disaster_recovery) {
1701            system("umount /tmp/isodir 2> /dev/null");
1702            if (!popup_and_get_string
1703                ("NFS share", "Which remote NFS share should I mount?",
1704                 bkpinfo->nfs_mount, MAX_STR_LEN)) {
1705                log_to_screen("User has chosen not to backup the PC");
1706                finish(1);
1707            }
1708        }
1709        if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1710            sprintf(bkpinfo->isodir, "/tmp/isodir.mondo.%d",
1711                    (int) (random() % 32768));
1712            asprintf(&command, "mkdir -p %s", bkpinfo->isodir);
1713            run_program_and_log_output(command, 5);
1714            paranoid_free(command);
1715
1716            asprintf(&tmp, "mount -t nfs -o nolock %s %s", bkpinfo->nfs_mount,
1717                    bkpinfo->isodir);
1718            run_program_and_log_output(tmp, 5);
1719            paranoid_free(tmp);
1720            malloc_string(g_selfmounted_isodir);
1721            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
1722        }
1723        if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1724            popup_and_OK
1725                ("Please mount that partition before you try to backup to or restore from it.");
1726            finish(1);
1727        }
1728        asprintf(&tmp, bkpinfo->nfs_remote_dir);
1729        if (!popup_and_get_string
1730            ("Directory", "Which directory within that mountpoint?", tmp,
1731             MAX_STR_LEN)) {
1732            log_to_screen("User has chosen not to backup the PC");
1733            finish(1);
1734        }
1735        strcpy(bkpinfo->nfs_remote_dir, tmp);
1736        paranoid_free(tmp);
1737
1738        // check whether writable - we better remove surrounding spaces for this
1739        strip_spaces(bkpinfo->nfs_remote_dir);
1740        asprintf(&command, "echo hi > %s/%s/.dummy.txt", bkpinfo->isodir,
1741                bkpinfo->nfs_remote_dir);
1742        while (run_program_and_log_output(command, FALSE)) {
1743            paranoid_free(tmp);
1744            paranoid_free(prompt);
1745            asprintf(&tmp, bkpinfo->nfs_remote_dir);
1746            asprintf(&prompt,
1747                     "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.",
1748                     bkpinfo->nfs_remote_dir, bkpinfo->isodir);
1749            if (!popup_and_get_string
1750                ("Directory", prompt, tmp, MAX_STR_LEN)) {
1751                log_to_screen("User has chosen not to backup the PC");
1752                finish(1);
1753            }
1754            strcpy(bkpinfo->nfs_remote_dir, tmp);
1755            // check whether writable - we better remove surrounding spaces for this */
1756            strip_spaces(bkpinfo->nfs_remote_dir);
1757            asprintf(&command, "echo hi > %s/%s/.dummy.txt",
1758                     bkpinfo->isodir, bkpinfo->nfs_remote_dir);
1759        }
1760        paranoid_free(command);
1761        paranoid_free(tmp);
1762        paranoid_free(prompt);
1763
1764        for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1765            bkpinfo->media_size[i] = 650;
1766        }
1767        log_msg(3, "Just set nfs_remote_dir to %s",
1768                bkpinfo->nfs_remote_dir);
1769        log_msg(3, "isodir is still %s", bkpinfo->isodir);
1770        break;
1771
1772    case iso:
1773        if (!bkpinfo->disaster_recovery) {
1774            if (!popup_and_get_string
1775                ("Storage dir.",
1776                 "Please enter the full path that contains your ISO images.  Example: /mnt/raid0_0",
1777                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
1778                log_to_screen("User has chosen not to backup the PC");
1779                finish(1);
1780            }
1781            if (archiving_to_media) {
1782                if ((bkpinfo->compression_level =
1783                     which_compression_level()) == -1) {
1784                    log_to_screen("User has chosen not to backup the PC");
1785                    finish(1);
1786                }
1787                if (!popup_and_get_string
1788                    ("ISO size.",
1789                     "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.",
1790                     sz_size, 16)) {
1791                    log_to_screen("User has chosen not to backup the PC");
1792                    finish(1);
1793                }
1794                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1795                    bkpinfo->media_size[i] = atoi(sz_size);
1796                }
1797                paranoid_free(sz_size);
1798
1799                if (!popup_and_get_string
1800                    ("Prefix.",
1801                     "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
1802                     bkpinfo->prefix, MAX_STR_LEN / 4)) {
1803                    log_to_screen("User has chosen not to backup the PC");
1804                    finish(1);
1805                }
1806            } else {
1807                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1808                    bkpinfo->media_size[i] = 650;
1809                }
1810            }
1811        }
1812        break;
1813    default:
1814        fatal_error
1815            ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
1816    }
1817    if (archiving_to_media) {
1818
1819#ifdef __FreeBSD__
1820        strcpy(bkpinfo->boot_device,
1821               call_program_and_get_last_line_of_output
1822               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
1823#else
1824        strcpy(bkpinfo->boot_device,
1825               call_program_and_get_last_line_of_output
1826               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
1827#endif
1828        i = which_boot_loader(bkpinfo->boot_device);
1829        if (i == 'U')           // unknown
1830        {
1831
1832#ifdef __FreeBSD__
1833            if (!popup_and_get_string
1834                ("Boot device",
1835                 "What is your boot device? (e.g. /dev/ad0)",
1836                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1837                log_to_screen("User has chosen not to backup the PC");
1838                finish(1);
1839            }
1840            i = which_boot_loader(bkpinfo->boot_device);
1841#else
1842            if (!popup_and_get_string
1843                ("Boot device",
1844                 "What is your boot device? (e.g. /dev/hda)",
1845                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1846                log_to_screen("User has chosen not to backup the PC");
1847                finish(1);
1848            }
1849            if (does_string_exist_in_boot_block
1850                (bkpinfo->boot_device, "LILO")) {
1851                i = 'L';
1852            } else
1853                if (does_string_exist_in_boot_block
1854                    (bkpinfo->boot_device, "ELILO")) {
1855                i = 'E';
1856            } else
1857                if (does_string_exist_in_boot_block
1858                    (bkpinfo->boot_device, "GRUB")) {
1859                i = 'G';
1860            } else {
1861                i = 'U';
1862            }
1863#endif
1864            if (i == 'U') {
1865                if (ask_me_yes_or_no
1866                    ("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?"))
1867                {
1868                    i = 'R';    // raw
1869                } else {
1870                    log_to_screen
1871                        ("I cannot find your boot loader. Please run mondoarchive with parameters.");
1872                    finish(1);
1873                }
1874            }
1875        }
1876        bkpinfo->boot_loader = i;
1877        strcpy(bkpinfo->include_paths, "/");
1878        if (!popup_and_get_string
1879            ("Backup paths",
1880             "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
1881             bkpinfo->include_paths, MAX_STR_LEN)) {
1882            log_to_screen("User has chosen not to backup the PC");
1883            finish(1);
1884        }
1885        tmp = list_of_NFS_mounts_only();
1886        if (strlen(tmp) > 2) {
1887            if (bkpinfo->exclude_paths[0]) {
1888                strcat(bkpinfo->exclude_paths, " ");
1889            }
1890            strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
1891        }
1892        paranoid_free(tmp);
1893// NTFS
1894        asprintf(&tmp,
1895               call_program_and_get_last_line_of_output
1896               ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
1897        if (strlen(tmp) > 2) {
1898            if (!popup_and_get_string
1899                ("NTFS partitions",
1900                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
1901                 tmp, MAX_STR_LEN / 4)) {
1902                log_to_screen("User has chosen not to backup the PC");
1903                finish(1);
1904            }
1905            strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
1906        }
1907        paranoid_free(tmp);
1908
1909        if (!popup_and_get_string
1910            ("Exclude paths",
1911             "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.",
1912             bkpinfo->exclude_paths, MAX_STR_LEN)) {
1913            log_to_screen("User has chosen not to backup the PC");
1914            finish(1);
1915        }
1916        bkpinfo->make_cd_use_lilo = FALSE;
1917        bkpinfo->backup_data = TRUE;
1918        bkpinfo->verify_data =
1919            ask_me_yes_or_no
1920            ("Will you want to verify your backups after Mondo has created them?");
1921
1922#ifndef __FreeBSD__
1923        if (!ask_me_yes_or_no
1924            ("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.")) {
1925            paranoid_alloc(bkpinfo->kernel_path, "FAILSAFE");
1926        }
1927#endif
1928
1929        if (!ask_me_yes_or_no
1930            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
1931            log_to_screen("User has chosen not to backup the PC");
1932            finish(1);
1933        }
1934    } else {
1935        bkpinfo->restore_data = TRUE;   // probably...
1936    }
1937
1938    if (bkpinfo->backup_media_type == iso
1939        || bkpinfo->backup_media_type == nfs) {
1940        g_ISO_restore_mode = TRUE;
1941    }
1942#ifdef __FreeSD__
1943// skip
1944#else
1945    if (bkpinfo->backup_media_type == nfs) {
1946        log_msg(3, "I think the NFS mount is mounted at %s",
1947                bkpinfo->isodir);
1948    }
1949    log_it("isodir = %s", bkpinfo->isodir);
1950    log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
1951#endif
1952
1953    log_it("media device = %s", bkpinfo->media_device);
1954    log_it("media size = %ld", bkpinfo->media_size[1]);
1955    log_it("media type = %s",
1956           bkptype_to_string(bkpinfo->backup_media_type));
1957    log_it("compression = %ld", bkpinfo->compression_level);
1958    log_it("include_paths = '%s'", bkpinfo->include_paths);
1959    log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
1960    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
1961    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
1962    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
1963           bkpinfo->boot_loader);
1964    log_it("prefix = %s", bkpinfo->prefix);
1965    if (bkpinfo->media_size[0] < 0) {
1966        if (archiving_to_media) {
1967            fatal_error("Media size is less than zero.");
1968        } else {
1969            log_msg(2, "Warning - media size is less than zero.");
1970            bkpinfo->media_size[0] = 0;
1971        }
1972    }
1973    return (0);
1974}
1975
1976
1977/**
1978 * Get a space-separated list of NFS mounts.
1979 * @return The list created.
1980 * @note The return value points to static data that will be overwritten with each call.
1981 * @bug Even though we only want the mounts, the devices are still checked.
1982 */
1983char *list_of_NFS_mounts_only(void)
1984{
1985    char *exclude_these_devices;
1986    char *exclude_these_directories;
1987    char *result_sz;
1988
1989    asprintf(&exclude_these_directories,
1990           call_program_and_get_last_line_of_output
1991           ("mount -t coda,ncpfs,nfs,smbfs,cifs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
1992    asprintf(&exclude_these_devices,
1993           call_program_and_get_last_line_of_output
1994           ("cat /etc/fstab | tr -s '\t' ' ' | grep -E '( (coda|ncpfs|nfs|smbfs|cifs) )' | cut -d' ' -f1 | tr -s '\n' ' ' | awk '{print $0;}'"));
1995    asprintf(&result_sz, "%s", exclude_these_directories);
1996    paranoid_free(exclude_these_devices);
1997    paranoid_free(exclude_these_directories);
1998    return (result_sz);
1999}
2000
2001
2002/* @} - end of utilityGroup */
2003
2004/**
2005 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2006 * [random] is a random number between 1 and 32767.
2007 * @param store_name_here Where to store the new filename.
2008 * @param stub A random number will be appended to this to make the FIFO's name.
2009 * @ingroup deviceGroup
2010 */
2011void make_fifo(char *store_name_here, char *stub)
2012{
2013    char *tmp;
2014
2015    assert_string_is_neither_NULL_nor_zerolength(stub);
2016
2017    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2018            (int) (random() % 32768));
2019    make_hole_for_file(store_name_here);
2020    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2021    asprintf(&tmp, "chmod 770 %s", store_name_here);
2022    paranoid_system(tmp);
2023    paranoid_free(tmp);
2024}
2025
2026
2027/**
2028 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2029 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2030 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2031 * @ingroup utilityGroup
2032 */
2033void sensibly_set_tmpdir_and_scratchdir(struct s_bkpinfo *bkpinfo)
2034{
2035    char *tmp, *command, *sz;
2036
2037    assert(bkpinfo != NULL);
2038
2039#ifdef __FreeBSD__
2040    asprintf(&tmp,
2041           call_program_and_get_last_line_of_output
2042           ("df -m -t nonfs,msdosfs,ntfs,smbfs,smb,cifs | tr -s '\t' ' ' | grep -v none | grep -v Filesystem | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -n | tail -n1 | awk '{print $NF;}'"));
2043#else
2044    asprintf(&tmp,
2045           call_program_and_get_last_line_of_output
2046           ("df -m -x nfs -x vfat -x ntfs -x smbfs -x smb -x cifs | sed 's/                  /devdev/' | tr -s '\t' ' ' | grep -v none | grep -v Filesystem | grep -v /dev/shm | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -n | tail -n1 | awk '{print $NF;}'"));
2047#endif
2048
2049    if (tmp[0] != '/') {
2050        asprintf(&sz, "/%s", tmp);
2051        paranoid_free(tmp);
2052        tmp = sz;
2053    }
2054    if (!tmp[0]) {
2055        fatal_error("I couldn't figure out the tempdir!");
2056    }
2057    sprintf(bkpinfo->tmpdir, "%s/tmp.mondo.%d", tmp,
2058            (int) (random() % 32768));
2059    log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2060
2061    sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp,
2062            (int) (random() % 32768));
2063    log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2064
2065    sprintf(g_erase_tmpdir_and_scratchdir, "rm -Rf %s %s", bkpinfo->tmpdir,
2066            bkpinfo->scratchdir);
2067
2068    asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2069    paranoid_free(tmp);
2070
2071    paranoid_system(command);
2072    paranoid_free(command);
2073}
2074
2075
2076/**
2077 * @addtogroup deviceGroup
2078 * @{
2079 */
2080/**
2081 * If we can read @p dev, set @p output to it.
2082 * If @p dev cannot be read, set @p output to "".
2083 * @param dev The device to check for.
2084 * @param output Set to @p dev if @p dev exists, NULL otherwise. Needs to be freed by caller
2085 * @return TRUE if @p dev exists, FALSE if it doesn't.
2086 */
2087bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2088{
2089    char *command;
2090
2091    paranoid_free(output);
2092    if (!dev || dev[0] == '\0') {
2093        return (FALSE);
2094    }
2095    log_msg(10, "Injecting %s", dev);
2096    inject_device(dev);
2097    if (!does_file_exist(dev)) {
2098        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2099        return (FALSE);
2100    }
2101    asprintf(&command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2102            512L, dev);
2103    if (!run_program_and_log_output(command, FALSE)
2104        && !run_program_and_log_output(command, FALSE)) {
2105        asprintf(&output, dev);
2106        log_msg(4, "Found it - %s", dev);
2107        paranoid_free(command);
2108        return (TRUE);
2109    } else {
2110        log_msg(4, "It's not %s", dev);
2111        paranoid_free(command);
2112        return (FALSE);
2113    }
2114}
2115
2116
2117/**
2118 * Find out what number CD is in the drive.
2119 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2120 * @return The current CD number, or -1 if it could not be found.
2121 * @note If the CD is not mounted, it will be mounted
2122 * (and remain mounted after this function returns).
2123 */
2124int what_number_cd_is_this(struct s_bkpinfo *bkpinfo)
2125{
2126    int cd_number = -1;
2127    char *mountdev;
2128    char *tmp;
2129
2130    assert(bkpinfo != NULL);
2131    if (g_ISO_restore_mode) {
2132        asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
2133
2134        asprintf(&mountdev, "%s/archives/THIS-CD-NUMBER", call_program_and_get_last_line_of_output(tmp));
2135        paranoid_free(tmp);
2136
2137        cd_number = atoi(last_line_of_file(mountdev));
2138        paranoid_free(mountdev);
2139
2140        return (cd_number);
2141    }
2142
2143    if (bkpinfo->media_device == NULL) {
2144        log_it
2145            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2146        bkpinfo->media_device = find_cdrom_device(FALSE);
2147    }
2148    if (!is_this_device_mounted(MNT_CDROM)) {
2149        (void)mount_CDROM_here(bkpinfo->media_device, MNT_CDROM);
2150    }
2151    cd_number =
2152        atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2153    return (cd_number);
2154}
2155
2156
2157/**
2158 * Find out what device is mounted as root (/).
2159 * @return Root device.
2160 * @note The returned string points to static storage and will be overwritten with every call.
2161 * @bug A bit of a misnomer; it's actually finding out the root device.
2162 * The mountpoint (where it's mounted) will obviously be '/'.
2163 */
2164char *where_is_root_mounted()
2165{
2166    /*@ buffers **************** */
2167    char *tmp;
2168
2169
2170#ifdef __FreeBSD__
2171    asprintf(&tmp, call_program_and_get_last_line_of_output
2172           ("mount | grep \" on / \" | cut -d' ' -f1"));
2173#else
2174    asprintf(&tmp, call_program_and_get_last_line_of_output
2175           ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2176    if (strstr(tmp, "/dev/cciss/")) {
2177        paranoid_free(tmp);
2178        asprintf(&tmp, call_program_and_get_last_line_of_output
2179               ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2180    }
2181    if (strstr(tmp, "/dev/md")) {
2182        paranoid_free(tmp);
2183        asprintf(&tmp,
2184               call_program_and_get_last_line_of_output
2185               ("mount | grep \" on / \" | cut -d' ' -f1"));
2186    }
2187#endif
2188
2189    return (tmp);
2190}
2191
2192
2193/**
2194 * Find out which boot loader is in use.
2195 * @param which_device Device to look for the boot loader on.
2196 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2197 * @note Under Linux, all drives are examined, not just @p which_device.
2198 */
2199#ifdef __FreeBSD__
2200char which_boot_loader(char *which_device)
2201{
2202    int count_lilos = 0;
2203    int count_grubs = 0;
2204    int count_boot0s = 0;
2205    int count_dangerouslydedicated = 0;
2206
2207    log_it("looking at drive %s's MBR", which_device);
2208    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2209        count_grubs++;
2210    }
2211    if (does_string_exist_in_boot_block(which_device, "LILO")) {
2212        count_lilos++;
2213    }
2214    if (does_string_exist_in_boot_block(which_device, "Drive")) {
2215        count_boot0s++;
2216    }
2217    if (does_string_exist_in_first_N_blocks
2218        (which_device, "FreeBSD/i386", 17)) {
2219        count_dangerouslydedicated++;
2220    }
2221    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2222           count_grubs, count_lilos, count_elilos, count_boot0s,
2223           count_dangerouslydedicated);
2224
2225    if (count_grubs && !count_lilos) {
2226        return ('G');
2227    } else if (count_lilos && !count_grubs) {
2228        return ('L');
2229    } else if (count_grubs == 1 && count_lilos == 1) {
2230        log_it("I'll bet you used to use LILO but switched to GRUB...");
2231        return ('G');
2232    } else if (count_boot0s == 1) {
2233        return ('B');
2234    } else if (count_dangerouslydedicated) {
2235        return ('D');
2236    } else {
2237        log_it("Unknown boot loader");
2238        return ('U');
2239    }
2240}
2241
2242#else
2243
2244char which_boot_loader(char *which_device)
2245{
2246    /*@ buffer ***************************************************** */
2247    char *list_drives_cmd;
2248    char *current_drive = NULL;
2249
2250    /*@ pointers *************************************************** */
2251    FILE *pdrives;
2252
2253    /*@ int ******************************************************** */
2254    int count_lilos = 0;
2255    int count_grubs = 0;
2256    size_t n = 0;
2257
2258    /*@ end vars *************************************************** */
2259
2260#ifdef __IA64__
2261    /* No choice for it */
2262    return ('E');
2263#endif
2264    assert(which_device != NULL);
2265    asprintf(&list_drives_cmd,
2266            "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s",
2267            where_is_root_mounted());
2268    log_it("list_drives_cmd = %s", list_drives_cmd);
2269
2270    if (!(pdrives = popen(list_drives_cmd, "r"))) {
2271        log_OS_error("Unable to open list of drives");
2272        paranoid_free(list_drives_cmd);
2273        return ('\0');
2274    }
2275    paranoid_free(list_drives_cmd);
2276
2277    for (getline(&current_drive, &n, pdrives); !feof(pdrives);
2278         getline(&current_drive, &n, pdrives)) {
2279        strip_spaces(current_drive);
2280        log_it("looking at drive %s's MBR", current_drive);
2281        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2282            count_grubs++;
2283            strcpy(which_device, current_drive);
2284            break;
2285        }
2286        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2287            count_lilos++;
2288            strcpy(which_device, current_drive);
2289            break;
2290        }
2291    }
2292    paranoid_free(current_drive);
2293
2294    if (pclose(pdrives)) {
2295        log_OS_error("Cannot pclose pdrives");
2296    }
2297    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2298    if (count_grubs && !count_lilos) {
2299        return ('G');
2300    } else if (count_lilos && !count_grubs) {
2301        return ('L');
2302    } else if (count_grubs == 1 && count_lilos == 1) {
2303        log_it("I'll bet you used to use LILO but switched to GRUB...");
2304        return ('G');
2305    } else {
2306        log_it("Unknown boot loader");
2307        return ('U');
2308    }
2309}
2310#endif
2311
2312
2313/**
2314 * Write zeroes over the first 16K of @p device.
2315 * @param device The device to zero.
2316 * @return 0 for success, 1 for failure.
2317 */
2318int zero_out_a_device(char *device)
2319{
2320    FILE *fout;
2321    int i;
2322
2323    assert_string_is_neither_NULL_nor_zerolength(device);
2324
2325    log_it("Zeroing drive %s", device);
2326    if (!(fout = fopen(device, "w"))) {
2327        log_OS_error("Unable to open/write to device");
2328        return (1);
2329    }
2330    for (i = 0; i < 16384; i++) {
2331        fputc('\0', fout);
2332    }
2333    paranoid_fclose(fout);
2334    log_it("Device successfully zeroed.");
2335    return (0);
2336}
2337
2338
2339/**
2340 * Return the device pointed to by @p incoming.
2341 * @param incoming The device to resolve symlinks for.
2342 * @return The path to the real device file.
2343 * @note The returned string points to a storage that need to be freed by the caller
2344 * @bug Won't work with file v4.0; needs to be written in C.
2345 */
2346char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2347{
2348    char *output;
2349    char *command;
2350    char *curr_fname;
2351    char *scratch;
2352    char *tmp;
2353    char *p;
2354
2355    struct stat statbuf;
2356    if (!does_file_exist(incoming)) {
2357        log_it
2358            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2359        asprintf(&output, incoming);
2360    } else {
2361        asprintf(&curr_fname, incoming);
2362        lstat(curr_fname, &statbuf);
2363        while (S_ISLNK(statbuf.st_mode)) {
2364            log_msg(1, "curr_fname = %s", curr_fname);
2365            asprintf(&command, "file %s", curr_fname);
2366            asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2367            paranoid_free(command);
2368
2369            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2370                 p--);
2371            p++;
2372            asprintf(&scratch, p);
2373            for (p = scratch; *p != '\0' && *p != '\''; p++);
2374            *p = '\0';
2375            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp,
2376                    scratch);
2377            paranoid_free(tmp);
2378
2379            if (scratch[0] == '/') {
2380                paranoid_free(curr_fname);
2381                asprintf(&curr_fname, scratch); // copy whole thing because it's an absolute softlink
2382            } else {            // copy over the basename cos it's a relative softlink
2383                p = curr_fname + strlen(curr_fname);
2384                while (p != curr_fname && *p != '/') {
2385                    p--;
2386                }
2387                if (*p == '/') {
2388                    p++;
2389                }
2390                *p = '\0';
2391                asprintf(&tmp, "%s%s", curr_fname, scratch);
2392                paranoid_free(curr_fname);
2393                curr_fname = tmp;
2394            }
2395            paranoid_free(scratch);
2396            lstat(curr_fname, &statbuf);
2397        }
2398        asprintf(&output, curr_fname);
2399        log_it("resolved %s to %s", incoming, output);
2400        paranoid_free(curr_fname);
2401    }
2402    return (output);
2403}
2404
2405/* @} - end of deviceGroup */
2406
2407
2408/**
2409 * Return the type of partition format (GPT or MBR)
2410 * Caller needs to free the return value
2411 */
2412char *which_partition_format(const char *drive)
2413{
2414    char *output;
2415    char *tmp;
2416    char *command;
2417    char *fdisk;
2418
2419    log_msg(0, "Looking for partition table format type");
2420    asprintf(&fdisk, "/sbin/parted2fdisk");
2421    log_msg(1, "Using %s", fdisk);
2422    asprintf(&command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2423    paranoid_free(fdisk);
2424
2425    asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2426    paranoid_free(command);
2427
2428    if (strstr(tmp, "GPT") == NULL) {
2429        asprintf(&output, "MBR");
2430    } else {
2431        asprintf(&output, "GPT");
2432    }
2433    paranoid_free(tmp);
2434    log_msg(0, "Found %s partition table format type", output);
2435    return (output);
2436}
2437
2438/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.