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

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

Quality errors handled

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