source: branches/3.2/mondo/src/common/libmondo-devices.c @ 3207

Last change on this file since 3207 was 3207, checked in by bruno, 5 years ago
  • Add LZMA compression possibility through the GUI
  • Property svn:keywords set to Id
File size: 96.9 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 3207 2013-12-10 07:49:44Z bruno $
3*/
4
5/**
6 * @file
7 * Functions to handle interactions with backup devices.
8 */
9
10#include "my-stuff.h"
11#include "mr_mem.h"
12#include "mr_str.h"
13#include "mondostructures.h"
14#include "libmondo-files-EXT.h"
15#include "libmondo-devices.h"
16#include "lib-common-externs.h"
17#include "libmondo-string-EXT.h"
18#include "libmondo-tools-EXT.h"
19#include "libmondo-gui-EXT.h"
20#include "libmondo-fork-EXT.h"
21#include "libmondo-stream-EXT.h"
22
23extern void mr_strip_spaces(char *);
24
25#include <sys/types.h>
26#ifdef __FreeBSD__
27#define DKTYPENAMES
28#define FSTYPENAMES
29#include <sys/disklabel.h>
30#include <sys/disk.h>
31#elif linux
32#define u64 unsigned long long
33#include <linux/fs.h>           /* for BLKGETSIZE64 */
34#include <linux/hdreg.h>
35#endif
36
37/*@unused@*/
38//static char cvsid[] = "$Id: libmondo-devices.c 3207 2013-12-10 07:49:44Z bruno $";
39//
40
41extern char *which_compression_type();
42/* Do we use extended attributes and acl ?  */
43extern char *g_getfacl;
44extern char *g_getfattr;
45
46extern int g_current_media_number;
47extern double g_kernel_version;
48
49extern bool g_ISO_restore_mode;
50extern char *g_selfmounted_isodir;
51extern char *MONDO_LOGFILE;
52
53extern void setup_tmpdir(char *path);
54extern void setup_scratchdir(char *path);
55
56static char g_cdrw_drive_is_here[MAX_STR_LEN / 4] = "";
57static char g_cdrom_drive_is_here[MAX_STR_LEN / 4] = "";
58static char g_dvd_drive_is_here[MAX_STR_LEN / 4] = "";
59
60
61/**
62 * ????? @bug ?????
63 * @ingroup globalGroup
64 */
65bool g_restoring_live_from_cd = FALSE;
66bool g_restoring_live_from_netfs = FALSE;
67
68extern t_bkptype g_backup_media_type;   // set by main()
69
70/* Reference to global bkpinfo */
71extern struct s_bkpinfo *bkpinfo;
72
73/* Stuff that handles the -I and -E option when a whole disk DSF is used */
74typedef struct mounted_fs_struct {
75    char device[MAX_STR_LEN];       /* The name of the device */
76    char mount_point[MAX_STR_LEN];  /* The devices mount point */
77    unsigned char check;            /* 1 == included on DSF */
78    struct mounted_fs_struct *next;
79} MOUNTED_FS_STRUCT;
80
81static MOUNTED_FS_STRUCT *DSF_Head = NULL;      /* Points to the first entry of mounted_fs_struct list */
82static MOUNTED_FS_STRUCT *DSF_Tail = NULL;      /* Points to the last entry of mounted_fs_struct list */
83
84
85void set_g_cdrom_and_g_dvd_to_bkpinfo_value()
86{
87    strcpy(g_cdrom_drive_is_here, bkpinfo->media_device);   // just in case
88    strcpy(g_dvd_drive_is_here, bkpinfo->media_device); // just in case
89}
90
91
92
93/**
94 * Retract all CD trays and wait for autorun to complete.
95 * @ingroup deviceGroup
96 */
97void retract_CD_tray_and_defeat_autorun(void)
98{
99//  log_it("rctada: Retracting all CD trays", __LINE__);
100    if (!bkpinfo->please_dont_eject) {
101        if (strlen(g_cdrom_drive_is_here) > 0) {
102            inject_device(g_cdrom_drive_is_here);
103        }
104        if (strlen(g_dvd_drive_is_here) > 0) {
105            inject_device(g_dvd_drive_is_here);
106        }
107        if (strlen(g_cdrw_drive_is_here) > 0) {
108            inject_device(g_cdrw_drive_is_here);
109        }
110    }
111//  log_it("rctada: killing autorun");
112//  run_program_and_log_output("killall autorun", TRUE);
113    if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5)) {
114        log_it("autorun detected; sleeping for 2 seconds");
115        sleep(2);
116    }
117    log_it("rctada: Unmounting all CD drives", __LINE__);
118    run_program_and_log_output("umount /dev/cdr* /dev/dvd*", 5);
119}
120
121
122
123/**
124 * Determine whether we're booted off a ramdisk.
125 * @return @c TRUE (we are) or @c FALSE (we aren't).
126 * @ingroup utilityGroup
127 */
128bool am_I_in_disaster_recovery_mode(void)
129{
130    char *tmp = NULL;
131    bool is_this_a_ramdisk = FALSE;
132
133    mr_asprintf(tmp, "%s", where_is_root_mounted());
134    log_msg(0, "root is mounted at %s\n", tmp);
135    log_msg(0, "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().", tmp);
136
137#ifdef __FreeBSD__
138    if (strstr(tmp, "/dev/md")) {
139        is_this_a_ramdisk = TRUE;
140    }
141#else
142    if (!strncmp(tmp, "/dev/ram", 8)
143        || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/")
144            && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs")
145        || !strcmp(tmp, "/dev/root")) {
146        is_this_a_ramdisk = TRUE;
147    } else {
148        is_this_a_ramdisk = FALSE;
149    }
150#endif
151    mr_free(tmp);
152
153    if (is_this_a_ramdisk) {
154        if (!does_file_exist("/THIS-IS-A-RAMDISK")) {
155            log_to_screen("Using /dev/root is stupid of you but I'll forgive you.");
156            is_this_a_ramdisk = FALSE;
157        }
158    }
159    if (does_file_exist("/THIS-IS-A-RAMDISK")) {
160        is_this_a_ramdisk = TRUE;
161    }
162
163    log_msg(1, "Is this a ramdisk? result = %s", (is_this_a_ramdisk) ? "TRUE" : "FALSE");
164    return (is_this_a_ramdisk);
165}
166
167
168
169
170
171/**
172 * Turn @c bkpinfo->backup_media_type into a human-readable string.
173 * @return The human readable string (e.g. @c cdr becomes <tt>"cdr"</tt>).
174 * @note The returned string points to static storage that will be overwritten with each call.
175 * @ingroup stringGroup
176 */
177static char *bkptype_to_string(t_bkptype bt)
178{
179    static char output[MAX_STR_LEN / 4];
180    switch (bt) {
181    case none:
182        strcpy(output, "none");
183        break;
184    case iso:
185        strcpy(output, "iso");
186        break;
187    case cdr:
188        strcpy(output, "cdr");
189        break;
190    case cdrw:
191        strcpy(output, "cdrw");
192        break;
193    case cdstream:
194        strcpy(output, "cdstream");
195        break;
196    case netfs:
197        strcpy(output, "netfs");
198        break;
199    case tape:
200        strcpy(output, "tape");
201        break;
202    case udev:
203        strcpy(output, "udev");
204        break;
205    case usb:
206        strcpy(output, "usb");
207        break;
208    default:
209        strcpy(output, "default");
210    }
211    return (output);
212}
213
214
215
216/**
217 * @addtogroup deviceGroup
218 * @{
219 */
220/**
221 * Eject the tray of the specified CD device.
222 * @param dev The device to eject.
223 * @return the return value of the @c eject command. (0=success, nonzero=failure)
224 */
225int eject_device(char *dev)
226{
227    char *command = NULL;
228    int res1 = 0, res2 = 0;
229
230    if (dev == NULL) {
231        return (1);
232    }
233
234    if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type)
235        && g_backup_media_type != udev) {
236        mr_asprintf(command, "mt -f %s offline", dev);
237        res1 = run_program_and_log_output(command, 1);
238        mr_free(command);
239    } else {
240        res1 = 0;
241    }
242
243#ifdef __FreeBSD__
244    if (strstr(dev, "acd")) {
245        mr_asprintf(command, "cdcontrol -f %s eject", dev);
246    } else {
247        mr_asprintf(command, "camcontrol eject `echo %s | sed 's|/dev/||'`", dev);
248    }
249#else
250    mr_asprintf(command, "eject %s", dev);
251#endif
252
253    log_msg(3, "Ejecting %s", dev);
254    res2 = run_program_and_log_output(command, 1);
255    mr_free(command);
256    if (res1 && res2) {
257        return (1);
258    } else {
259        return (0);
260    }
261}
262
263/**
264 * Load (inject) the tray of the specified CD device.
265 * @param dev The device to load/inject.
266 * @return 0 for success, nonzero for failure.
267 */
268int inject_device(char *dev)
269{
270    char *command = NULL;
271    int i;
272
273    if (dev == NULL) {
274        return (1);
275    }
276
277#ifdef __FreeBSD__
278    if (strstr(dev, "acd")) {
279        mr_asprintf(command, "cdcontrol -f %s close", dev);
280    } else {
281        mr_asprintf(command, "camcontrol load `echo %s | sed 's|/dev/||'`", dev);
282    }
283#else
284    mr_asprintf(command, "eject -t %s", dev);
285#endif
286    i = run_program_and_log_output(command, FALSE);
287    mr_free(command);
288    return (i);
289}
290
291
292/**
293 * Determine whether the specified @p device (really, you can use any file)
294 * exists.
295 * @return TRUE if it exists, FALSE if it doesn't.
296 */
297bool does_device_exist(char *device)
298{
299
300    /*@ buffers *********************************************************** */
301    char *tmp = NULL;
302    bool ret;
303
304    assert_string_is_neither_NULL_nor_zerolength(device);
305
306    mr_asprintf(tmp, "ls %s > /dev/null 2> /dev/null", device);
307
308    if (system(tmp)) {
309        ret = FALSE;
310    } else {
311        ret = TRUE;
312    }
313    mr_free(tmp);
314    return (ret);
315}
316
317
318/**
319 * Determine whether a non-Microsoft partition exists on any connected hard drive.
320 * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent PC).
321 */
322bool does_nonMS_partition_exist(void)
323{
324#if __FreeBSD__
325    return
326        !system
327        ("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false");
328#else
329    return
330        !system
331        ("parted2fdisk -l 2>/dev/null | grep '^/dev/' | grep -Eqv '(MS|DOS|FAT|NTFS)'");
332#endif
333}
334
335/**
336 * Determine whether the specified @p partno exists on the specified @p drive.
337 * @param drive The drive to search for the partition in.
338 * @param partno The partition number to look for.
339 * @return 0 if it exists, nonzero otherwise.
340 */
341int does_partition_exist(const char *drive, int partno)
342{
343    /*@ buffers **************************************************** */
344    char *program = NULL;
345    char *incoming = NULL;
346    char *searchstr = NULL;
347
348    /*@ ints ******************************************************* */
349    int res = 0;
350
351    /*@ pointers *************************************************** */
352    FILE *fin;
353
354    /*@ end vars *************************************************** */
355    assert_string_is_neither_NULL_nor_zerolength(drive);
356    assert(partno >= 0 && partno < 999);
357
358    malloc_string(searchstr);
359
360#ifdef __FreeBSD__
361    // We assume here that this is running from mondorestore. (It is.)
362    mr_asprintf(program, "ls %s %s >/dev/null 2>&1", drive, build_partition_name(tmp, drive, partno));
363    res = system(program);
364    mr_free(program);
365    return(res);
366#endif
367
368    mr_asprintf(program, "parted2fdisk -l %s 2> /dev/null", drive);
369    fin = popen(program, "r");
370    if (!fin) {
371        log_it("program=%s", program);
372        log_OS_error("Cannot popen-in program");
373        mr_free(program);
374        return (0);
375    }
376    mr_free(program);
377
378    (void) build_partition_name(searchstr, drive, partno);
379    strcat(searchstr, " ");
380    for (res = 0, mr_getline(incoming, fin); !res && !feof(fin) ; mr_getline(incoming, fin)) {
381        if (strstr(incoming, searchstr)) {
382            res = 1;
383        }
384        mr_free(incoming);
385    }
386    mr_free(incoming);
387
388    if (pclose(fin)) {
389        log_OS_error("Cannot pclose fin");
390    }
391    paranoid_free(searchstr);
392    return (res);
393}
394
395
396
397
398
399/**
400 * Determine whether given NULL-terminated @p str exists in the MBR of @p dev.
401 * @param dev The device to look in.
402 * @param str The string to look for.
403 * @return TRUE if it exists, FALSE if it doesn't.
404 */
405bool does_string_exist_in_boot_block(char *dev, char *str)
406{
407    /*@ buffers **************************************************** */
408    char *command = NULL;
409
410    /*@ end vars *************************************************** */
411    int i;
412
413    assert_string_is_neither_NULL_nor_zerolength(dev);
414    assert_string_is_neither_NULL_nor_zerolength(str);
415
416    /* For UEFI detection, this should be extended to count=2 */
417    mr_asprintf(command, "dd if=%s bs=446 count=1 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, str);
418    i = system(command);
419    mr_free(command);
420    if (i) {
421        return (FALSE);
422    } else {
423        return (TRUE);
424    }
425}
426
427/**
428 * Determine whether specified @p str exists in the first @p n sectors of
429 * @p dev.
430 * @param dev The device to look in.
431 * @param str The string to look for.
432 * @param n The number of 512-byte sectors to search.
433 */
434bool does_string_exist_in_first_N_blocks(char *dev, char *str, int n)
435{
436    /*@ buffers **************************************************** */
437    char *command = NULL;
438    /*@ end vars *************************************************** */
439    int i;
440
441    mr_asprintf(command, "dd if=%s bs=512 count=%i 2> /dev/null | strings | grep \"%s\" > /dev/null 2> /dev/null", dev, n, str);
442    i = system(command);
443    mr_free(command);
444    if (i) {
445        return (FALSE);
446    } else {
447        return (TRUE);
448    }
449}
450
451
452
453/**
454 * Try to mount CD-ROM at @p mountpoint. If the CD-ROM is not found or has
455 * not been specified, call find_cdrom_device() to find it.
456 * @param mountpoint Where to mount the CD-ROM.
457 * @return 0 for success, nonzero for failure.
458 * @see mount_CDROM_here
459 */
460int find_and_mount_actual_cd(char *mountpoint) {
461
462    /*@ buffers ***************************************************** */
463
464    /*@ int's  ****************************************************** */
465    int res;
466    char *dev = NULL;
467
468    /*@ end vars **************************************************** */
469
470    malloc_string(dev);
471    assert(bkpinfo != NULL);
472    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
473
474    if (g_backup_media_type == dvd) {
475        strcpy(dev, g_dvd_drive_is_here);
476        if (!dev[0]) {
477            find_dvd_device(dev, FALSE);
478        }
479    } else {
480        strcpy(dev, g_cdrom_drive_is_here);
481        if (!dev[0]) {
482            find_cdrom_device(dev, FALSE);
483        }
484    }
485
486    if (bkpinfo->backup_media_type != iso) {
487        retract_CD_tray_and_defeat_autorun();
488    }
489
490    if (!dev[0] || (res = mount_CDROM_here(dev, mountpoint))) {
491        if (!popup_and_get_string
492            ("CD-ROM device", "Please enter your CD-ROM's /dev device",
493             dev, MAX_STR_LEN / 4)) {
494            res = 1;
495        } else {
496            res = mount_CDROM_here(dev, mountpoint);
497        }
498    }
499    if (res) {
500        log_msg(1, "mount failed");
501    } else {
502        log_msg(1, "mount succeeded with %s", dev);
503    }
504    paranoid_free(dev);
505    return (res);
506}
507
508
509
510
511
512
513/**
514 * Locate a CD-R/W writer's SCSI node.
515 * @param cdrw_device SCSI node will be placed here.
516 * @return 0 for success, nonzero for failure.
517 */
518int find_cdrw_device(char *cdrw_device)
519{
520    /*@ buffers ************************ */
521    char *tmp = NULL;
522    char *cdr_exe = NULL;
523    char *command = NULL;
524
525    if (g_cdrw_drive_is_here[0]) {
526        strcpy(cdrw_device, g_cdrw_drive_is_here);
527        log_msg(3, "Been there, done that. Returning %s", cdrw_device);
528        return (0);
529    }
530    if (g_backup_media_type == dvd) {
531        log_msg(1, "This is dumb. You're calling find_cdrw_device() but you're backing up to DVD. WTF?");
532        return (1);
533    }
534    run_program_and_log_output("insmod ide-scsi", -1);
535    if (find_home_of_exe("cdrecord")) {
536        mr_asprintf(cdr_exe, "cdrecord");
537    } else {
538        mr_asprintf(cdr_exe, "dvdrecord");
539    }
540    if (find_home_of_exe(cdr_exe)) {
541        mr_asprintf(command, "%s -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep -E '[D|C][V|D]' | cut -d' ' -f2 | head -n1", cdr_exe);
542        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
543        mr_free(command);
544    }
545    if ((tmp == NULL) || (strlen(tmp) < 2)) {
546        mr_free(tmp);
547        mr_free(cdr_exe);
548        return 1;
549    } else {
550        strcpy(cdrw_device, tmp);
551        log_it("Found CDRW device - %s", cdrw_device);
552        strcpy(g_cdrw_drive_is_here, cdrw_device);
553        mr_free(tmp);
554        mr_free(cdr_exe);
555        return (0);
556    }
557}
558
559
560/**
561 * Attempt to locate a CD-ROM device's /dev entry.
562 * Several different methods may be used to find the device, including
563 * calling @c cdrecord, searching @c dmesg, and trial-and-error.
564 * @param output Where to put the located /dev entry.
565 * @param try_to_mount Whether to mount the CD as part of the test; if mount
566 * fails then return failure.
567 * @return 0 for success, nonzero for failure.
568 */
569int find_cdrom_device(char *output, bool try_to_mount)
570{
571    /*@ pointers **************************************************** */
572    FILE *fin;
573    char *p;
574    char *q;
575    char *r;
576    int retval = 0;
577
578    /*@ bool's ****************************************************** */
579    bool found_it = FALSE;
580
581    /*@ buffers ***************************************************** */
582    char *tmp = NULL;
583    char *tmp1 = NULL;
584    char *cdr_exe = NULL;
585    char *phrase_one;
586    char *phrase_two = NULL;
587    char *command = NULL;
588#ifndef __FreeBSD__
589    char *dvd_last_resort = NULL;
590#endif
591    char *mountpoint = NULL;
592    static char the_last_place_i_found_it[MAX_STR_LEN] = "";
593
594    /*@ intialize *************************************************** */
595    malloc_string(tmp);
596    malloc_string(phrase_one);
597    malloc_string(mountpoint);
598
599    output[0] = '\0';
600    phrase_one[0] = '\0';
601
602    /*@ end vars **************************************************** */
603
604    if (g_cdrom_drive_is_here[0] && !isdigit(g_cdrom_drive_is_here[0])) {
605        strcpy(output, g_cdrom_drive_is_here);
606        log_msg(3, "Been there, done that. Returning %s", output);
607        retval = 0;
608        goto end_of_find_cdrom_device;
609    }
610    if (the_last_place_i_found_it[0] != '\0' && !try_to_mount) {
611        strcpy(output, the_last_place_i_found_it);
612        log_msg(3, "find_cdrom_device() --- returning last found location - '%s'", output);
613        retval = 0;
614        goto end_of_find_cdrom_device;
615    }
616
617    sprintf(mountpoint, "%s/cd.mnt", bkpinfo->tmpdir);
618    make_hole_for_dir(mountpoint);
619
620    if (find_home_of_exe("cdrecord")) {
621        mr_asprintf(cdr_exe, "cdrecord");
622    } else {
623        mr_asprintf(cdr_exe, "dvdrecord");
624    }
625    tmp[0] = '\0';
626    if (!find_home_of_exe(cdr_exe)) {
627        strcpy(output, "/dev/cdrom");
628        log_msg(4, "Can't find cdrecord; assuming %s", output);
629        if (!does_device_exist(output)) {
630            log_msg(4, "That didn't work. Sorry.");
631            retval = 1;
632            goto end_of_find_cdrom_device;
633        } else {
634            retval = 0;
635            goto end_of_find_cdrom_device;
636        }
637    }
638
639    mr_asprintf(command, "%s -scanbus 2> /dev/null", cdr_exe);
640    fin = popen(command, "r");
641    if (!fin) {
642        log_msg(4, "command=%s", command);
643        log_OS_error("Cannot popen command");
644        mr_free(cdr_exe);
645        mr_free(command);
646        return (1);
647    }
648    mr_free(command);
649
650    for (tmp1 = fgets(tmp, MAX_STR_LEN, fin); !feof(fin) && (tmp1 != NULL);
651         tmp1 = fgets(tmp, MAX_STR_LEN, fin)) {
652        p = strchr(tmp, '\'');
653        if (p) {
654            q = strchr(++p, '\'');
655            if (q) {
656                for (r = q; *(r - 1) == ' '; r--);
657                *r = '\0';
658                strcpy(phrase_one, p);
659                p = strchr(++q, '\'');
660                if (p) {
661                    q = strchr(++p, '\'');
662                    if (q) {
663                        while (*(q - 1) == ' ') {
664                            q--;
665                        }
666                        *q = '\0';
667                        mr_asprintf(phrase_two, "%s", p);
668                    }
669                }
670            }
671        }
672    }
673    paranoid_pclose(fin);
674
675#ifndef __FreeBSD__
676    if (!phrase_two || strlen(phrase_two) == 0) {
677        log_msg(4, "Not running phase two. String is empty.");
678    } else {
679        mr_asprintf(command, "dmesg | grep \"%s\" 2> /dev/null", phrase_two);
680        fin = popen(command, "r");
681        mr_free(command);
682
683        if (!fin) {
684            log_msg(4, "Cannot run 2nd command - non-fatal, fortunately");
685        } else {
686            for (tmp1 = fgets(tmp, MAX_STR_LEN, fin); !feof(fin) && (tmp1 != NULL);
687                 tmp1 = fgets(tmp, MAX_STR_LEN, fin)) {
688                log_msg(5, "--> '%s'", tmp);
689                if (tmp[0] != ' ' && tmp[1] != ' ') {
690                    p = strchr(tmp, ':');
691                    if (p) {
692                        *p = '\0';
693                        if (strstr(tmp, "DVD")) {
694                            mr_free(dvd_last_resort);
695                            mr_asprintf(dvd_last_resort, "/dev/%s", tmp);
696                            log_msg(4, "Ignoring '%s' because it's a DVD drive", tmp);
697                        } else {
698                            sprintf(output, "/dev/%s", tmp);
699                            found_it = TRUE;
700                        }
701                    }
702                }
703            }
704            paranoid_pclose(fin);
705        }
706    }
707
708#endif
709#ifdef __FreeBSD__
710    if (!found_it) {
711        log_msg(4, "OK, approach 2");
712        if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) {
713            if (!
714                (found_it =
715                 set_dev_to_this_if_rx_OK(output, "/dev/cdrom1"))) {
716                if (!
717                    (found_it =
718                     set_dev_to_this_if_rx_OK(output, "/dev/dvd"))) {
719                    if (!
720                        (found_it =
721                         set_dev_to_this_if_rx_OK(output, "/dev/acd0"))) {
722                        if (!
723                            (found_it =
724                             set_dev_to_this_if_rx_OK(output,
725                                                      "/dev/cd01"))) {
726                            if (!
727                                (found_it =
728                                 set_dev_to_this_if_rx_OK(output,
729                                                          "/dev/acd1"))) {
730                                if (!
731                                    (found_it =
732                                     set_dev_to_this_if_rx_OK(output,
733                                                              "/dev/cd1")))
734                                {
735                                    retval = 1;
736                                    goto end_of_find_cdrom_device;
737                                }
738                            }
739                        }
740                    }
741                }
742            }
743        }
744    }
745#else
746    if (!found_it && strlen(dvd_last_resort) > 0) {
747        log_msg(4, "Well, I'll use the DVD - %s - as a last resort", dvd_last_resort);
748        strcpy(output, dvd_last_resort);
749        found_it = TRUE;
750    }
751    if (found_it) {
752        sprintf(tmp, "grep \"%s=ide-scsi\" /proc/cmdline &> /dev/null", strrchr(output, '/') + 1);
753        if (system(tmp) == 0) {
754            log_msg(4, "%s is not right. It's being SCSI-emulated. Continuing.", output);
755            found_it = FALSE;
756            output[0] = '\0';
757        }
758    }
759
760    if (found_it) {
761        log_msg(4, "(find_cdrom_device) --> '%s'", output);
762        if (!does_device_exist(output)) {
763            found_it = FALSE;
764            log_msg(4, "OK, I was wrong, I haven't found it... yet.");
765        }
766    }
767
768    if (!found_it) {
769        log_msg(4, "OK, approach 2");
770        if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/scd0"))) {
771            if (!(found_it = set_dev_to_this_if_rx_OK(output, "/dev/sr0"))) {
772                if (!
773                    (found_it =
774                     set_dev_to_this_if_rx_OK(output, "/dev/cdrom"))) {
775                    if (!
776                        (found_it =
777                         set_dev_to_this_if_rx_OK(output,
778                                                  "/dev/cdrom0"))) {
779                        if (!
780                            (found_it =
781                             set_dev_to_this_if_rx_OK(output,
782                                                      "/dev/cdrom1"))) {
783                            if (!
784                                (found_it =
785                                 set_dev_to_this_if_rx_OK(output,
786                                                          "/dev/sr1"))) {
787                                if (!
788                                    (found_it =
789                                     set_dev_to_this_if_rx_OK(output,
790                                                              "/dev/dvd")))
791                                {
792                                    if (!
793                                        (found_it =
794                                         set_dev_to_this_if_rx_OK(output,
795                                                                  g_cdrw_drive_is_here)))
796                                    {
797                                        retval = 1;
798                                        goto end_of_find_cdrom_device;
799                                    }
800                                }
801                            }
802                        }
803                    }
804                }
805            }
806        }
807    }
808#endif
809
810    if (found_it && try_to_mount) {
811        if (mount_CDROM_here(output, mountpoint)) {
812            log_msg(4, "[Cardigans] I've changed my mind");
813            found_it = FALSE;
814        } else {
815            sprintf(tmp, "%s/archives", mountpoint);
816            if (!does_file_exist(tmp)) {
817                log_msg(4, "[Cardigans] I'll take it back");
818                found_it = FALSE;
819            } else {
820                mr_asprintf(command, "umount %s", output);
821                paranoid_system(command);
822                mr_free(command);
823
824                log_msg(4, "I'm confident the Mondo CD is in %s", output);
825            }
826        }
827    }
828    unlink(mountpoint);
829
830    if (found_it) {
831        if (!does_file_exist(output)) {
832            log_msg(3, "I still haven't found it.");
833            return (1);
834        }
835        log_msg(3, "(find_cdrom_device) --> '%s'", output);
836        strcpy(the_last_place_i_found_it, output);
837        strcpy(g_cdrom_drive_is_here, output);
838        retval = 0;
839        goto end_of_find_cdrom_device;
840    }
841
842    mr_asprintf(command, "%s -scanbus | grep \"[0-9],[0-9],[0-9]\" | grep -E \"[D|C][V|D]\" | grep -n \"\" | grep \"%s\" | cut -d':' -f2", cdr_exe, g_cdrw_drive_is_here);
843
844    log_msg(1, "command=%s", command);
845    mr_asprintf(tmp1, "%s", call_program_and_get_last_line_of_output(command));
846    mr_free(command);
847
848    if (strlen(tmp1) > 0) {
849        strcpy(output, tmp1);
850        log_msg(4, "Finally found it at %s", output);
851        retval = 0;
852    } else {
853        log_msg(4, "Still couldn't find it.");
854        retval = 1;
855    }
856    mr_free(tmp1);
857
858  end_of_find_cdrom_device:
859    mr_free(cdr_exe);
860    mr_free(phrase_two);
861    mr_free(dvd_last_resort);
862
863    paranoid_free(tmp);
864    paranoid_free(phrase_one);
865    paranoid_free(mountpoint);
866    return (retval);
867}
868
869
870int find_dvd_device(char *output, bool try_to_mount)
871{
872    char *tmp;
873    int retval = 0, devno = -1;
874
875    if (g_dvd_drive_is_here[0]) {
876        strcpy(output, g_dvd_drive_is_here);
877        log_msg(3, "Been there, done that. Returning %s", output);
878        return (0);
879    }
880
881    malloc_string(tmp);
882    mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output("dvdrecord -scanbus 2> /dev/null | grep -E '\)\ \'' | grep -n '' | grep -E '[D|C][V|D]' | cut -d':' -f1"));
883    log_msg(5, "tmp = '%s'", tmp);
884    if (!tmp[0]) {
885        mr_free(tmp);
886        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output("cdrecord -scanbus 2> /dev/null | grep -E '\)\ \'' | grep -n '' | grep -E '[D|C][V|D]' | cut -d':' -f1"));
887    }
888    if (tmp[0]) {
889        devno = atoi(tmp) - 1;
890    }
891    mr_free(tmp);
892
893    if (devno >= 0) {
894        retval = 0;
895        sprintf(output, "/dev/scd%d", devno);
896        strcpy(g_dvd_drive_is_here, output);
897        log_msg(2, "I think DVD is at %s", output);
898    } else {
899        log_msg(2, "I cannot find DVD");
900        retval = 1;
901    }
902
903    return (retval);
904}
905
906
907
908
909
910#include <sys/ioctl.h>
911
912/**
913 * Find the size of the specified @p drive, in megabytes. Uses @c ioctl calls
914 * and @c dmesg.
915 * @param drive The device to find the size of.
916 * @return size in megabytes.
917 */
918long get_phys_size_of_drive(char *drive)
919{
920    int fd;
921#if linux
922    unsigned long long s = 0;
923    int fileid, cylinders = 0;
924    int cylindersize = 0;
925    int gotgeo = 0;
926
927
928    struct hd_geometry hdgeo;
929#elif __FreeBSD__
930    off_t s;
931#endif
932
933    long outvalA = -1;
934    long outvalB = -1;
935    long outvalC = -1;
936
937    if ((fd = open(drive, O_RDONLY)) != -1) {
938        if (ioctl(fd,
939#if linux
940#ifdef BLKGETSIZE64
941                  BLKGETSIZE64,
942#else
943                  BLKGETSIZE,
944#endif
945#elif __FreeBSD__
946                  DIOCGMEDIASIZE,
947#endif
948                  &s) != -1) {
949            close(fd);
950            // s>>11 works for older disks but not for newer ones
951            outvalB =
952#if linux
953#ifdef BLKGETSIZE64
954                s >> 20
955#else
956                s >> 11
957#endif
958#else
959                s >> 20
960#endif
961                ;
962        }
963    }
964
965    if (outvalB <= 0) {
966        log_msg(1, "Error getting size of %s: %s", drive, strerror(errno));
967#if linux
968        fileid = open(drive, O_RDONLY);
969        if (fileid != -1) {
970            if (ioctl(fileid, HDIO_GETGEO, &hdgeo) != -1) {
971                if (hdgeo.cylinders && hdgeo.heads && hdgeo.sectors) {
972                    cylindersize = hdgeo.heads * hdgeo.sectors / 2;
973                    outvalA = cylindersize * cylinders / 1024;
974                    log_msg(2, "Got Harddisk geometry, C:%d, H:%d, S:%d",
975                            hdgeo.cylinders, hdgeo.heads, hdgeo.sectors);
976                    gotgeo = 1;
977                } else {
978                    log_msg(1, "Harddisk geometry wrong");
979                }
980            } else {
981                log_msg(1,
982                        "Error in ioctl() getting new hard disk geometry (%s), resizing in unsafe mode",
983                        strerror(errno));
984            }
985            close(fileid);
986        } else {
987            log_msg(1, "Failed to open %s for reading: %s", drive,
988                    strerror(errno));
989        }
990        if (!gotgeo) {
991            log_msg(1, "Failed to get harddisk geometry, using old mode");
992        }
993#endif
994    }
995// OLDER DISKS will give ridiculously low value for outvalB (so outvalA is returned) :)
996// NEWER DISKS will give sane value for outvalB (close to outvalA, in other words) :)
997
998    outvalC = (outvalA > outvalB) ? outvalA : outvalB;
999
1000//  log_msg (5, "drive = %s, error = %s", drive, strerror (errno));
1001//  fatal_error ("GPSOD: Unable to get size of drive");
1002    log_msg(1, "%s --> %ld or %ld --> %ld", drive, outvalA, outvalB,
1003            outvalC);
1004
1005    return (outvalC);
1006}
1007
1008/**
1009 * Determine whether @p format is supported by the kernel. Uses /proc/filesystems
1010 * under Linux and @c lsvfs under FreeBSD.
1011 * @param format The format to test.
1012 * @return TRUE if the format is supported, FALSE if not.
1013 */
1014bool is_this_a_valid_disk_format(char *format)
1015{
1016    char *good_formats = NULL;
1017    char *command = NULL;
1018    char *format_sz = NULL;
1019    char *p;
1020
1021    FILE *pin;
1022    int retval;
1023    malloc_string(good_formats);
1024
1025    assert_string_is_neither_NULL_nor_zerolength(format);
1026
1027    mr_asprintf(format_sz, "%s ", format);
1028
1029#ifdef __FreeBSD__
1030    mr_asprintf(command, "lsvfs | tr -s '\t' ' ' | grep -v Filesys | grep -v -- -- | cut -d' ' -f1 | tr -s '\n' ' '");
1031#else
1032    mr_asprintf(command, "grep -v nodev /proc/filesystems | tr -s '\t' ' ' | cut -d' ' -f2 | tr -s '\n' ' '");
1033#endif
1034
1035    pin = popen(command, "r");
1036    mr_free(command);
1037
1038    if (!pin) {
1039        log_OS_error("Unable to read good formats");
1040        retval = 0;
1041    } else {
1042        strcpy(good_formats, " ");
1043        p = fgets(good_formats + 1, MAX_STR_LEN - 1, pin);
1044        if (pclose(pin) && (p != NULL)) {
1045            log_OS_error("Cannot pclose good formats");
1046        }
1047        strip_spaces(good_formats);
1048        strcat(good_formats, " swap lvm raid ntfs-3g ntfs 7 "); // " ntfs 7 " -- um, cheating much? :)
1049        if (strstr(good_formats, format_sz)) {
1050            retval = 1;
1051        } else {
1052            retval = 0;
1053        }
1054    }
1055    paranoid_free(good_formats);
1056    mr_free(format_sz);
1057
1058    return (retval);
1059}
1060
1061
1062/** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */
1063
1064/**
1065 * Determine whether @p device_raw is currently mounted.
1066 * @param device_raw The device to check.
1067 * @return TRUE if it's mounted, FALSE if not.
1068 */
1069bool is_this_device_mounted(char *device_raw)
1070{
1071
1072    /*@ pointers **************************************************** */
1073    FILE *fin;
1074
1075    /*@ buffers ***************************************************** */
1076    char *incoming = NULL;
1077    char *device_with_tab = NULL;
1078    char *device_with_space = NULL;
1079    char *tmp = NULL;
1080    bool retval = FALSE;
1081
1082#ifdef __FreeBSD__
1083#define SWAPLIST_COMMAND "swapinfo"
1084#else
1085#define SWAPLIST_COMMAND "cat /proc/swaps"
1086#endif
1087
1088    /*@ end vars **************************************************** */
1089
1090    if (device_raw == NULL) {
1091        return(FALSE);
1092    }
1093
1094    if (device_raw[0] != '/' && !strstr(device_raw, ":/")) {
1095        log_msg(1, "%s needs to have a '/' prefixed - I'll do it",
1096                device_raw);
1097        mr_asprintf(tmp, "/%s", device_raw);
1098    } else {
1099        mr_asprintf(tmp, "%s", device_raw);
1100    }
1101    log_msg(1, "Is %s mounted?", tmp);
1102    if (!strcmp(tmp, "/proc") || !strcmp(tmp, "proc")) {
1103        log_msg(1,
1104                "I don't know how the heck /proc made it into the mountlist. I'll ignore it.");
1105        mr_free(tmp);
1106        return(FALSE);
1107    }
1108    mr_asprintf(device_with_tab, "%s\t", tmp);
1109    mr_asprintf(device_with_space, "%s ", tmp);
1110    mr_free(tmp);
1111
1112    if (!(fin = popen("mount", "r"))) {
1113        log_OS_error("Cannot popen 'mount'");
1114        return(FALSE);
1115    }
1116
1117    for (mr_getline(incoming, fin); !feof(fin); mr_getline(incoming, fin)) {
1118        if (strstr(incoming, device_with_space) || strstr(incoming, device_with_tab)) {
1119            paranoid_pclose(fin);
1120            mr_free(incoming);
1121            return(TRUE);
1122        }
1123        mr_free(incoming);
1124    }
1125    mr_free(incoming);
1126    mr_free(device_with_tab);
1127    paranoid_pclose(fin);
1128    mr_asprintf(tmp, "%s | grep -E \"^%s\" > /dev/null 2> /dev/null", SWAPLIST_COMMAND, device_with_space);
1129    mr_free(device_with_space);
1130    log_msg(4, "tmp (command) = '%s'", tmp);
1131    if (!system(tmp)) {
1132        retval = TRUE;
1133    }
1134    mr_free(tmp);
1135    return(retval);
1136}
1137
1138#ifdef __FreeBSD__
1139//                       CODE IS FREEBSD-SPECIFIC
1140/**
1141 * Create a loopback device for specified @p fname.
1142 * @param fname The file to associate with a device.
1143 * @return /dev entry for the device, or NULL if it couldn't be allocated.
1144 */
1145char *make_vn(char *fname)
1146{
1147    char *device = (char *) malloc(MAX_STR_LEN);
1148    char *mddevice = (char *) malloc(32);
1149    char command[MAX_STR_LEN];
1150    int vndev = 2;
1151    if (atoi(call_program_and_get_last_line_of_output("/sbin/sysctl -n kern.osreldate")) < 500000) {
1152        do {
1153            sprintf(mddevice, "vn%ic", vndev++);
1154            sprintf(command, "vnconfig %s %s", mddevice, fname);
1155            if (vndev > 10) {
1156                return NULL;
1157            }
1158        }
1159        while (system(command));
1160    } else {
1161        sprintf(command, "mdconfig -a -t vnode -f %s", fname);
1162        mddevice = call_program_and_get_last_line_of_output(command);
1163        if (!strstr(mddevice, "md")) {
1164            return NULL;
1165        }
1166    }
1167    sprintf(device, "/dev/%s", mddevice);
1168    return device;
1169}
1170
1171
1172
1173//                       CODE IS FREEBSD-SPECIFIC
1174/**
1175 * Deallocate specified @p dname.
1176 * This should be called when you are done with the device created by make_vn(),
1177 * so the system does not run out of @c vn devices.
1178 * @param dname The device to deallocate.
1179 * @return 0 for success, nonzero for failure.
1180 */
1181int kick_vn(char *dname)
1182{
1183    char *command = NULL;
1184    int res = 0;
1185
1186    if (strncmp(dname, "/dev/", 5) == 0) {
1187        dname += 5;
1188    }
1189
1190    if (atoi(call_program_and_get_last_line_of_output("/sbin/sysctl -n kern.osreldate")) < 500000) {
1191        mr_asprintf(command, "vnconfig -d %s", dname);
1192    } else {
1193        mr_asprintf(command, "mdconfig -d -u %s", dname);
1194    }
1195    res = system(command);
1196    mr_free(command);
1197    return(res);
1198}
1199#endif
1200
1201
1202/**
1203 * Mount the CD-ROM at @p mountpoint.
1204 * @param device The device (or file if g_ISO_restore_mode) to mount.
1205 * @param mountpoint The place to mount it.
1206 * @return 0 for success, nonzero for failure.
1207 */
1208int mount_USB_here(char *device, char *mountpoint)
1209{
1210    /*@ buffer ****************************************************** */
1211    char *command = NULL;
1212    int retval;
1213
1214    assert_string_is_neither_NULL_nor_zerolength(device);
1215    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1216
1217    make_hole_for_dir(mountpoint);
1218    if (isdigit(device[0])) {
1219        return(1);
1220    }
1221    log_msg(4, "(mount_USB_here --- device=%s, mountpoint=%s", device, mountpoint);
1222
1223#ifdef __FreeBSD__
1224    mr_asprintf(command, "mount_vfat %s %s 2>> %s", device, mountpoint, MONDO_LOGFILE);
1225
1226#else
1227    mr_asprintf(command, "mount %s -t vfat %s 2>> %s", device, mountpoint, MONDO_LOGFILE);
1228#endif
1229
1230    log_msg(4, command);
1231    retval = system(command);
1232    log_msg(1, "system(%s) returned %d", command, retval);
1233    mr_free(command);
1234
1235    return (retval);
1236}
1237
1238/**
1239 * Mount the CD-ROM at @p mountpoint.
1240 * @param device The device (or file if g_ISO_restore_mode) to mount.
1241 * @param mountpoint The place to mount it.
1242 * @return 0 for success, nonzero for failure.
1243 */
1244int mount_CDROM_here(char *device, const char *mountpoint)
1245{
1246    /*@ buffer ****************************************************** */
1247    char *command = NULL;
1248    int retval;
1249#ifdef __FreeBSD__
1250    char *dev = NULL;
1251#else
1252    char *options = NULL;
1253#endif
1254
1255    assert_string_is_neither_NULL_nor_zerolength(device);
1256    assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1257
1258    make_hole_for_dir(mountpoint);
1259
1260    if (isdigit(device[0])) {
1261        find_cdrom_device(device, FALSE);
1262    }
1263#ifndef __FreeBSD__
1264    mr_asprintf(options, "ro");
1265#endif
1266
1267    if (g_ISO_restore_mode) {
1268
1269#ifdef __FreeBSD__
1270        mr_asprintf(dev, "%s", make_vn(device));
1271        if (!dev) {
1272            mr_asprintf(command, "Unable to mount ISO (make_vn(%s) failed)", device);
1273            fatal_error(command);
1274        }
1275        strcpy(device, dev);
1276        paranoid_free(dev);
1277#else
1278        mr_strcat(options, ",loop");
1279#endif
1280
1281    }
1282    log_msg(4, "(mount_CDROM_here --- device=%s, mountpoint=%s", device, mountpoint);
1283    /*@ end vars *************************************************** */
1284
1285#ifdef __FreeBSD__
1286    mr_asprintf(command, "mount_cd9660 -r %s %s 2>> %s", device, mountpoint, MONDO_LOGFILE);
1287
1288#else
1289    mr_asprintf(command, "mount %s -o %s -t iso9660 %s 2>> %s", device, options, mountpoint, MONDO_LOGFILE);
1290    paranoid_free(options);
1291#endif
1292
1293    log_msg(4, command);
1294    if (strncmp(device, "/dev/", 5) == 0) {
1295        retract_CD_tray_and_defeat_autorun();
1296    }
1297    retval = system(command);
1298    log_msg(1, "system(%s) returned %d", command, retval);
1299    mr_free(command);
1300
1301    return (retval);
1302}
1303
1304
1305/**
1306* Mount the CD-ROM or USB device at /mnt/cdrom.
1307* @param bkpinfo The backup information structure. Fields used:
1308* - @c bkpinfo->backup_media_type
1309* - @c bkpinfo->disaster_recovery
1310* - @c bkpinfo->isodir
1311* - @c bkpinfo->media_device
1312* @return 0 for success, nonzero for failure.
1313*/
1314int mount_media()
1315{
1316char *mount_cmd = NULL;
1317char *mountdir = NULL;
1318int i, res;
1319#ifdef __FreeBSD__
1320    char mdd[32];
1321    char *mddev = mdd;
1322#endif
1323
1324    if (bkpinfo->backup_media_type == tape || bkpinfo->backup_media_type == udev) {
1325        log_msg(8, "Tape/udev. Therefore, no need to mount a media.");
1326        return 0;
1327    }
1328
1329    if (!run_program_and_log_output("mount | grep -F " MNT_CDROM, FALSE)) {
1330        log_msg(2, "mount_media() - media already mounted. Fair enough.");
1331        return (0);
1332    }
1333
1334    if (bkpinfo->backup_media_type == netfs) {
1335        log_msg(2, "Mounting for Network thingy");
1336        log_msg(2, "isodir = %s", bkpinfo->isodir);
1337        if ((!bkpinfo->isodir[0] || !strcmp(bkpinfo->isodir, "/")) && am_I_in_disaster_recovery_mode()) {
1338            strcpy(bkpinfo->isodir, "/tmp/isodir");
1339            log_msg(1, "isodir is being set to %s", bkpinfo->isodir);
1340        }
1341#ifdef __FreeBSD__
1342        if (bkpinfo->netfs_remote_dir != NULL) {
1343            // NETFS
1344            mr_asprintf(mount_cmd, "/mnt/isodir/%s/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number);
1345        } else {
1346            // ISO
1347            mr_asprintf(mount_cmd, "/mnt/isodir/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->prefix, g_current_media_number);
1348        }
1349        mddev = make_vn(mount_cmd);
1350        mr_free(mount_cmd);
1351
1352        mr_asprintf(mount_cmd, "mount_cd9660 -r %s " MNT_CDROM, mddev);
1353#else
1354        if (bkpinfo->netfs_remote_dir != NULL) {
1355            // NETFS
1356            mr_asprintf(mount_cmd, "mount %s/%s/%s-%d.iso -t iso9660 -o loop,ro %s", bkpinfo->isodir, bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number, MNT_CDROM);
1357        } else {
1358            // ISO
1359            mr_asprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s", bkpinfo->isodir, bkpinfo->prefix, g_current_media_number, MNT_CDROM);
1360        }
1361#endif
1362
1363    } else if (bkpinfo->backup_media_type == iso) {
1364        if (bkpinfo->subdir) {
1365            mr_asprintf(mountdir, "%s/%s", bkpinfo->isodir, bkpinfo->subdir);
1366        } else {
1367            mr_asprintf(mountdir, "%s", bkpinfo->isodir);
1368        }
1369#ifdef __FreeBSD__
1370        mr_asprintf(mount_cmd, "%s/%s-%d.iso", mountdir, bkpinfo->prefix, g_current_media_number);
1371        mddev = make_vn(mount_cmd);
1372        mr_free(mount_cmd);
1373
1374        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, MNT_CDROM);
1375#else
1376        mr_asprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s", mountdir, bkpinfo->prefix, g_current_media_number, MNT_CDROM);
1377#endif
1378        mr_free(mountdir);
1379    } else if (bkpinfo->backup_media_type == usb) {
1380        mr_asprintf(mount_cmd, "mount -t vfat %s %s", bkpinfo->media_device, MNT_CDROM);
1381    } else if (strstr(bkpinfo->media_device, "/dev/")) {
1382#ifdef __FreeBSD__
1383        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device, MNT_CDROM);
1384#else
1385        mr_asprintf(mount_cmd, "mount %s -t iso9660 -o ro %s", bkpinfo->media_device, MNT_CDROM);
1386#endif
1387    } else {
1388        if (bkpinfo->disaster_recovery
1389            && does_file_exist("/tmp/CDROM-LIVES-HERE")) {
1390            strcpy(bkpinfo->media_device,
1391                last_line_of_file("/tmp/CDROM-LIVES-HERE"));
1392        } else {
1393            find_cdrom_device(bkpinfo->media_device, TRUE);
1394        }
1395
1396#ifdef __FreeBSD__
1397        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device, MNT_CDROM);
1398#else
1399        mr_asprintf(mount_cmd, "mount %s -t iso9660 -o ro %s", bkpinfo->media_device, MNT_CDROM);
1400#endif
1401    }
1402
1403    log_msg(2, "(mount_media) --- command = %s", mount_cmd);
1404    for (i = 0; i < 2; i++) {
1405        res = run_program_and_log_output(mount_cmd, FALSE);
1406        if (!res) {
1407            break;
1408        } else {
1409            log_msg(2, "Failed to mount device.");
1410            sleep(5);
1411            sync();
1412        }
1413    }
1414    mr_free(mount_cmd);
1415
1416    if (res) {
1417        log_msg(2, "Failed, despite %d attempts", i);
1418    } else {
1419        log_msg(2, "Mounted media drive OK");
1420    }
1421    return (res);
1422}
1423/**************************************************************************
1424*END_MOUNT_CDROM                                                         *
1425**************************************************************************/
1426
1427
1428
1429
1430/**
1431 * Ask the user for CD number @p cd_number_i_want.
1432 * Sets g_current_media_number once the correct CD is inserted.
1433 * @param bkpinfo The backup information structure. Fields used:
1434 * - @c bkpinfo->backup_media_type
1435 * - @c bkpinfo->prefix
1436 * - @c bkpinfo->isodir
1437 * - @c bkpinfo->media_device
1438 * - @c bkpinfo->please_dont_eject_when_restoring
1439 * @param cd_number_i_want The CD number to ask for.
1440 */
1441void
1442insist_on_this_cd_number(int cd_number_i_want)
1443{
1444
1445    /*@ int ************************************************************* */
1446    int res = 0;
1447
1448
1449    /*@ buffers ********************************************************* */
1450    char *tmp = NULL;
1451    char *mds = NULL;
1452    char *request = NULL;
1453
1454    assert(bkpinfo != NULL);
1455    assert(cd_number_i_want > 0);
1456
1457//  log_msg(3, "Insisting on CD number %d", cd_number_i_want);
1458
1459    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1460        log_msg(3,
1461                "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1462        return;
1463    }
1464    mr_asprintf(tmp, "mkdir -p " MNT_CDROM);
1465    run_program_and_log_output(tmp, 5);
1466    mr_free(tmp);
1467
1468    if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso || bkpinfo->backup_media_type == netfs) {
1469        g_ISO_restore_mode = TRUE;
1470    }
1471    if ((res = what_number_cd_is_this()) != cd_number_i_want) {
1472        log_msg(3, "Currently, we hold %d but we want %d", res, cd_number_i_want);
1473
1474        /* Now we need to umount the current media to have the next mounted after */
1475        run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
1476        log_msg(3, "Mounting next media %d",cd_number_i_want);
1477        g_current_media_number = cd_number_i_want;
1478        mount_media();
1479
1480        mds = media_descriptor_string(bkpinfo->backup_media_type);
1481        log_msg(3, "Insisting on %s #%d", mds, cd_number_i_want);
1482        mr_asprintf(request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want);
1483        mr_free(mds);
1484
1485        while (what_number_cd_is_this() != cd_number_i_want) {
1486            sync();
1487            if (is_this_device_mounted(MNT_CDROM)) {
1488                res =
1489                    run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
1490            } else {
1491                res = 0;
1492            }
1493            if (res) {
1494                log_to_screen("WARNING - failed to unmount CD-ROM drive");
1495            }
1496            if (!bkpinfo->please_dont_eject) {
1497                res = eject_device(bkpinfo->media_device);
1498            } else {
1499                res = 0;
1500            }
1501            if (res) {
1502                log_to_screen("WARNING - failed to eject CD-ROM disk");
1503            }
1504            popup_and_OK(request);
1505            if (!bkpinfo->please_dont_eject) {
1506                inject_device(bkpinfo->media_device);
1507            }
1508            sync();
1509        }
1510        mr_free(request);
1511
1512        log_msg(1, "Thankyou. Proceeding...");
1513        g_current_media_number = cd_number_i_want;
1514    }
1515}
1516
1517/* @} - end of deviceGroup */
1518
1519
1520
1521/**
1522 * Creates a singly linked list of all of the non-NETFS mounted file systems.
1523 * @param DSFptr A pointer  to the structure MOUNTED_FS_STRUCT used to hold
1524 * the list of mounted file systems.
1525 * @return None.
1526 */
1527static void add_mounted_fs_struct (MOUNTED_FS_STRUCT *DSFptr)
1528{
1529    assert (DSFptr);
1530    if (DSF_Head == NULL) {
1531        DSF_Head = DSFptr;
1532    } else {
1533        DSF_Tail->next = DSFptr;
1534    }
1535    DSFptr->next = NULL;
1536    DSF_Tail = DSFptr;
1537}
1538
1539/**
1540 * Find the structure, in the singly linked list of all of the non-NETFS
1541 * mounted file systems, that contains the specified device.
1542 * @param device The device to find
1543 * @return NULL if it didn't find the device, a pointer to the
1544 * structure if it did.
1545 */
1546static MOUNTED_FS_STRUCT *find_device_in_list (char *device)
1547{
1548    MOUNTED_FS_STRUCT *DSFptr = NULL;
1549
1550    DSFptr = DSF_Head;
1551    while (DSFptr != NULL) {
1552        if (!strcmp(DSFptr->device, device)) {
1553            break;
1554        }
1555        DSFptr = DSFptr->next;
1556    }
1557    return (DSFptr);
1558}
1559
1560/**
1561 * Find the structure, in the singly linked list of all of the non-NETFS
1562 * mounted file systems, that contains the specified mount point.
1563 * @param mount_point The mount point to find
1564 * @return NULL is it didn't find the mount point, a pointer to the
1565 * structure if it did.
1566 */
1567static MOUNTED_FS_STRUCT *find_mount_point_in_list (char *mount_point)
1568{
1569    MOUNTED_FS_STRUCT *DSFptr = NULL;
1570
1571    DSFptr = DSF_Head;
1572    while (DSFptr != NULL) {
1573        if (!strcmp(DSFptr->mount_point, mount_point)) {
1574            break;
1575        }
1576        DSFptr = DSFptr->next;
1577    }
1578    return (DSFptr);
1579}
1580
1581/**
1582 * Frees the memory for all of the structures on the linked list of
1583 * all of the non-NETFS mounted file systems.
1584 */
1585static void free_mounted_fs_list (void) {
1586    MOUNTED_FS_STRUCT *DSFptr = NULL;
1587    MOUNTED_FS_STRUCT *DSFnext = NULL;
1588 
1589    DSFptr = DSF_Head;
1590    while (DSFptr != NULL) {
1591        DSFnext = DSFptr->next;
1592        paranoid_free(DSFptr);
1593        DSFptr = DSFnext;
1594    }
1595    DSF_Head = NULL;
1596    DSF_Tail = NULL;
1597}
1598
1599
1600/**
1601 * Creates a linked list of all of the non-NETFS mounted file systems.
1602 * We use a linked list because we don't know how many  mounted file
1603 * there are (and there can be a lot).
1604 * @return 0 on success and greated than 0 on failure.
1605 */
1606static int create_list_of_non_NETFS_mounted_file_systems (void)
1607{
1608    int i = 0;
1609    int mount_cnt = 0;
1610    int lastpos = 0;
1611    char *mounted_file_system = NULL;
1612    char *command = NULL;
1613    char *token = NULL;
1614    char token_chars[] =" :\t\r\f\a\0";
1615    MOUNTED_FS_STRUCT *DSFptr = NULL;
1616
1617    free_mounted_fs_list();
1618    /********
1619    * Find the number of mounted file system entries and their respective mount points.
1620    * I can't return all of the entries as one string because it's length can be longer
1621    * than MAX_STR_LEN which is used in call_program_and_get_last_line_of_output().
1622    * So start looping and get the number of  mounted file systems and query them one by one.
1623    ********/
1624    /* Get the number of mounted file systems ((those that start with "/dev/" */
1625    mr_asprintf(command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $0}}'|wc -l");
1626    log_msg(5, "Running: %s", command);
1627    mr_asprintf(mounted_file_system, "%s", call_program_and_get_last_line_of_output(command));
1628    mr_free(command);
1629
1630    mount_cnt = atoi(mounted_file_system);
1631    log_msg (5, "mount_cnt: %d", mount_cnt);
1632    mr_free(mounted_file_system);
1633
1634    for (i=mount_cnt; i > 0; i--) {
1635        mr_asprintf(command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $1,$3}}'|head -n %d", i);
1636        log_msg(5, "Running: %s", command);
1637        mr_asprintf(mounted_file_system, "%s", call_program_and_get_last_line_of_output(command));
1638        mr_free(command);
1639
1640        log_msg (5, "mounted_file_system: %s", mounted_file_system);
1641        if ((token = mr_strtok(mounted_file_system, token_chars, &lastpos)) == NULL) {
1642            log_msg (4, "Could not get the list of mounted file systems");
1643            mr_free(mounted_file_system);
1644            mr_free(token);
1645            return (1);
1646        }
1647        if (token) {
1648            log_msg (5, "token: %s", token);
1649        }
1650        while (token != NULL) {
1651            log_msg (5, "token: %s", token);
1652            if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) {
1653                fatal_error ("Cannot allocate memory");
1654            }
1655            add_mounted_fs_struct(DSFptr);
1656            strcpy(DSFptr->device, token);
1657            mr_free(token);
1658            if ((token = mr_strtok(mounted_file_system, token_chars, &lastpos)) == NULL) {
1659                log_msg (5, "Ran out of entries on the mounted file systems list");
1660                mr_free(mounted_file_system);
1661                mr_free(token);
1662                return (1);
1663            }
1664            log_msg (5, "token: %s", token);
1665            strcpy(DSFptr->mount_point, token);
1666            mr_free(token);
1667            token = mr_strtok(mounted_file_system, token_chars, &lastpos); 
1668        }
1669        mr_free(mounted_file_system);
1670    }
1671    return (0);
1672}
1673
1674
1675
1676/**
1677 * Given a whole disk device special file, determine which mounted file systems
1678 * are on the dsf's partitions and which mounted file systems are not.
1679 * @param dsf The whole disk device special file.
1680 * @param included_dsf_list A char pointer used to hold the list of mount points
1681 * that are on the dsf. Memory for the array will be allocated within the function.
1682 * @param excluded_dsf_list A char pointer used to hold the list of mount points
1683 * that are not on the dsf. Memory for the array will be allocated within the function.
1684 * @return 0 on success, -1 if no device special file was passed in, -2 if a device
1685 * special file was passed in but it has no partitions on it, or 1 on failure
1686 */
1687static int get_dsf_mount_list (const char *dsf, char **included_dsf_list, char **excluded_dsf_list) {
1688    int i = 0;
1689    int c = 0;
1690    int lastpos = 0;
1691    char VG[MAX_STR_LEN];
1692    char *tmp = NULL;
1693    char *command = NULL;
1694    char *partition_list = NULL;
1695    char partitions[64][MAX_STR_LEN];
1696    char *mount_list = NULL;
1697    char *token = NULL;
1698    char *ndsf = NULL;
1699    char token_chars[] =" \t\r\f\a\0";
1700    MOUNTED_FS_STRUCT *DSFptr = NULL;
1701
1702    memset((char *)partitions, 0, sizeof(partitions));
1703
1704    log_msg(5, "dsf: %s", dsf);
1705
1706    /********
1707    * See if a device special file was passed in (i.e. it must start with /dev/
1708    ********/
1709    if (strncmp(dsf, "/dev/", 5)) {
1710        log_msg (4, "%s does not start with /dev/ and (probably) is not a  device special file", dsf);
1711        return (-1);
1712    }
1713    log_msg(4, "  %s looks like a device special file", dsf);
1714    /* Verify that the dsf exists */ 
1715    mr_asprintf(command, "ls -al %s 2>/dev/null | wc -l", dsf);
1716    log_msg(5, "  Executing: %s", command);
1717    mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1718    mr_free(command);
1719
1720    log_msg(5, "  Return value: %s", tmp);
1721    c = atoi(tmp);
1722    mr_free(tmp);
1723
1724    if (!c) {
1725        log_to_screen("Cannot find device special file %s", dsf);
1726        return (1);
1727    }
1728    log_msg(4, "  %s device special file exists", dsf);
1729
1730    /* Get a list of the mounted file systems */
1731    if (create_list_of_non_NETFS_mounted_file_systems()) {
1732        log_to_screen ("Could not get the list of mounted file systems");
1733        return (1);
1734    }
1735    log_msg (5, "Processing dsf: %s", dsf);
1736    /********
1737    * Get a list of the dsf's partitions. There could be no partitions on the disk
1738    * or a dsf of a partition was passed in (e.g. /dev/sda1 instead of /dev/sda).
1739    * Either way, it's an error.
1740    ********/
1741    mr_asprintf(command, "parted2fdisk -l %s 2>/dev/null|grep -E \"^/dev/\"|awk '{printf(\"%%s \", $1)}END{print \"\"}'", dsf);
1742    log_msg(5, "Executing: %s", command);
1743    mr_asprintf(partition_list, "%s", call_program_and_get_last_line_of_output(command));
1744    mr_free(command);
1745    log_msg(4, "Partition list for %s: %s", dsf, partition_list);
1746    if (!strlen(partition_list)) {
1747        /* There were no partitions on the disk */
1748        log_msg(4, "No partitions on device special file %s", dsf);
1749        log_msg(4, "I guess it's a partition itself");
1750        strcpy(partitions[0], dsf);
1751        ndsf = truncate_to_drive_name(dsf);
1752    } else {
1753        /* Fill the partition list */
1754        i = 0;
1755        lastpos = 0;
1756        while ((token = mr_strtok(partition_list, token_chars, &lastpos)) != NULL) {
1757            log_msg (4, "Found partition: %s", token);
1758            strcpy(partitions[i++], token);
1759            mr_free(token);
1760        }
1761        mr_asprintf(ndsf, "%s", dsf);
1762    }
1763    mr_free(partition_list);
1764
1765    /* In any case we want to exclude the dsf itself from all MondRescue activities
1766     * at restore time (LVM, fdisk, ...) so we want it in our exclude_dev list */
1767    if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) {
1768        fatal_error ("Cannot allocate memory");
1769    }
1770    add_mounted_fs_struct(DSFptr);
1771    strcpy(DSFptr->device, dsf);
1772    DSFptr->check = 1;
1773
1774    /*  For the rest ndsf is the new dsf to deal with */
1775    /********
1776     * At this point, we have a list of all of the partitions on the dsf. Now try to
1777     * see which partitions have a file system on them.
1778     *
1779     * Loop through each partition on the disk and:
1780     *
1781     * - If the partition is swap, it ignores it.
1782     *
1783     * - If the partition is mounted (e.g. /dev/sda1 is mounted on /boot), it adds an entry
1784     *  to the linked list, copies to it the device name and mount point, and sets check == 1.
1785     *
1786     * - If the partition is part of a Volume Group that has Logical Volumes mounted, it adds
1787     *  an entry to the linked list for each mounted Logical Volume in that Volume Group, copying
1788     *  to it the device name and mount point, and sets check == 1. Note that if the Volume Group
1789     *  contains more than one disk, it will still add the entry even if the Logical Volume's
1790     *  extents are not on the dsf that was passed in to the function. For example, Volume Group
1791     *  VolGroup00 contains the disks /dev/sda1 and /dev/sdb1, and the Logical Volumes LogVol01,
1792     *  which is mounted on /var and has all of its extents on /dev/sda1, and LogVol02, which is
1793     *  mounted as /usr and has all of its extents on /dev/sdb1. If you pass /dev/sda into the
1794     *  function, both /var and /usr will be archived even though /usr is actually on/dev/sdb.
1795     *
1796     * - If the partition is part of a Volume Group that has Logical Volumes used in a mounted
1797     *  software raid device, it adds an entry to the linked list, copies to it the software raid
1798     *  device name and mount point, and sets check == 1.
1799     *
1800     * - If the partition is part of a mounted software raid device, it adds an entry to the linked
1801     *  list, copies to it the software raid device name and mount point, and sets check == 1.
1802     *
1803     ********/
1804    for (i=0; strlen(partitions[i]); i++) {
1805        log_msg(4, "Processing partition: %s", partitions[i]);
1806        /* See if it's swap. If it is, ignore it. */
1807        mr_asprintf(command, "parted2fdisk -l %s 2>/dev/null | awk '{if(($1==\"%s\")&&(toupper($0) ~ \"SWAP\")){print $1;exit}}'", ndsf, partitions[i]);
1808        log_msg(5, "  Running: %s", command);
1809        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1810        mr_free(command);
1811
1812        log_msg(5, "  Return value: %s", tmp);
1813        c = strlen(tmp);
1814        mr_free(tmp);
1815
1816        if (c) {
1817            log_msg(4, "It's swap. Ignoring partition %s", partitions[i]); 
1818            continue;
1819        } 
1820
1821        /* It's not swap. See if we can find the mount point from the mount command. */
1822        mr_asprintf(command, "mount 2>/dev/null | awk '{if((NF>0)&&($1==\"%s\")){print $3}}'", partitions[i]);
1823        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1824        mr_free(command);
1825
1826        if (strlen(tmp)) {
1827            log_msg(4, "  %s is mounted: %s", partitions[i], tmp);
1828            if ((DSFptr = find_mount_point_in_list(tmp)) == NULL) {
1829                log_msg (4, "Can't find mount point %s in mounted file systems list", tmp);
1830                mr_free(tmp);
1831                return (1);
1832            }
1833            DSFptr->check = 1;
1834            mr_free(tmp);
1835            continue;
1836        }
1837        mr_free(tmp);
1838
1839        /* It's not swap and it's not mounted. See if it's LVM */
1840        log_msg(4, "  It's not mounted. Checking to see if it's LVM...");
1841
1842        /* Check for LVM */
1843        mr_asprintf(command, "pvdisplay -c %s 2> /dev/null", partitions[i]);
1844        log_msg(5, "  Running: %s", command);
1845        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1846        mr_free(command);
1847
1848        if (strlen(tmp)) {
1849            log_msg(4, "Found an LVM partition at %s. Find the VG it's in...", partitions[i]);
1850            /* It's LVM: Find the VG it's in */
1851            mr_asprintf(command, "pvdisplay -v %s 2>/dev/null|grep \"VG Name\"|awk '{print $NF}'", partitions[i]);
1852            log_msg(5, "  Running: %s", command);
1853            strcpy(VG, call_program_and_get_last_line_of_output(command));
1854            mr_free(command);
1855
1856            log_msg(4, "  Volume Group: %s", VG);
1857            if (strlen(VG)) {
1858                /* Found the Volume Group. Now find all of the VG's mount points */
1859                log_msg(4, "  Found the Volume Group. Now find all of the VG's mount points");
1860                mr_asprintf(command, "mount 2>/dev/null|grep -E \"/dev/mapper/%s|/dev/%s/\"|awk '{printf(\"%%s \",$3)}END{print \"\"}'", VG, VG);
1861                log_msg(5, "  Running: %s", command);
1862                mr_asprintf(mount_list, "%s", call_program_and_get_last_line_of_output(command));
1863                mr_free(command);
1864
1865                log_msg(4, "  VG %s mount_list: %s", VG, mount_list);
1866                lastpos = 0;
1867                while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1868                    log_msg (5, "mount point token: %s", token);
1869                    if ((DSFptr = find_mount_point_in_list(token)) == NULL) {
1870                        log_msg (4, "Can't find mount point %s in mounted file systems list", token);
1871                        mr_free(tmp);
1872                        mr_free(token);
1873                        return (1);
1874                    }
1875                    DSFptr->check = 1;
1876                    mr_free(token);
1877                }
1878                /********
1879                 * Now we want to see if there are any software raid devices using
1880                 * any of the Logical Volumes on the Volume Group.
1881                 *******/
1882                mr_free(mount_list);
1883
1884                mr_asprintf(command, "%s", "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'");
1885                log_msg (5, "Running: %s", command);
1886                mr_asprintf(mount_list, "%s", call_program_and_get_last_line_of_output(command));
1887                mr_free(command);
1888                log_msg(4, "  Software raid device list: %s", mount_list);
1889                lastpos = 0;
1890                while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1891                    mr_asprintf(command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, VG);
1892                    log_msg (5, "Running: %s", command);
1893                    mr_free(tmp);
1894                    mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1895                    mr_free(command);
1896                    log_msg(4, "Number of Software raid device: %s", tmp);
1897                    if (atoi(tmp)) {
1898                        /* This device is on our disk */
1899                        if ((DSFptr = find_device_in_list(token)) == NULL) {
1900                            log_msg (4, "Can't find device %s in mounted file systems list", token);
1901                            mr_free(tmp);
1902                            mr_free(token);
1903                            return (1);
1904                        }
1905                        DSFptr->check = 1;
1906                    }
1907                }
1908                mr_free(token);
1909                paranoid_free(mount_list);
1910            } else {
1911                log_msg (4, "Error finding Volume Group for partition %s", partitions[i]);
1912                mr_free(tmp);
1913                return (1);
1914            }
1915            mr_free(tmp);
1916            continue;
1917        } else {
1918            log_msg (4, "Error finding partition type for the partition %s", partitions[i]);
1919        }
1920        mr_free(tmp);
1921
1922        /********
1923         * It's not swap, mounted, or LVM. See if it's used in a software raid device.
1924         ********/
1925        log_msg (5, "It's not swap, mounted, or LVM. See if it's used in a software raid device.");
1926        mr_asprintf(command, "mdadm --examine %s 2>/dev/null | awk '{if($1 == \"UUID\"){print $3}}'", partitions[i]);
1927        log_msg(4, "  Running: %s", command);
1928        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1929        mr_free(command);
1930
1931        if (!strlen(tmp)) {
1932            log_msg(4, "  Partition %s is not used in a non-LVM software raid device", partitions[i]);
1933            mr_free(tmp);
1934            continue;
1935        }
1936        log_msg (5, "  UUID: %s", tmp);
1937
1938        /* Get the Software raid device list */
1939        mr_asprintf(command, "%s", "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'");
1940        log_msg (5, "  Running: %s", command);
1941        mr_asprintf(mount_list, "%s", call_program_and_get_last_line_of_output(command));
1942        mr_free(command);
1943
1944        log_msg(4, "  Software raid device list: %s", mount_list);
1945        /* Loop through the software raid device list to see if we can find the partition */
1946        lastpos = 0;
1947        while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1948            mr_asprintf(command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, tmp);
1949            log_msg(4, "  Running: %s", command);
1950            mr_free(tmp);
1951            mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1952            mr_free(command);
1953
1954            if (!atoi(tmp)) {
1955                log_msg (4,"  Didn't find partition %s in software raid device %s", partitions[i], token);
1956            } else {
1957                if ((DSFptr = find_device_in_list(token)) == NULL) {
1958                    log_msg (4, "Can't find device %s in mounted file systems list", token);
1959                    mr_free(tmp);
1960                    mr_free(token);
1961                    return (1);
1962                }
1963                DSFptr->check = 1;
1964                break;
1965            }
1966            mr_free(token);
1967        }
1968        mr_free(tmp);
1969        mr_free(mount_list);
1970    }
1971
1972    /* Determine how much memory to allocate for included_dsf_list and excluded_dsf_list */
1973    i = 0;
1974    DSFptr= DSF_Head;
1975    while (DSFptr != NULL) {
1976        i += strlen(DSFptr->mount_point) + 1;
1977        DSFptr = DSFptr->next;
1978    }
1979    log_msg (5, "i: %d", i);
1980    if ((*included_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) {
1981        fatal_error ("Cannot allocate memory");
1982    }
1983    if ((*excluded_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) {
1984        fatal_error ("Cannot allocate memory");
1985    }
1986    DSFptr= DSF_Head;
1987    while (DSFptr != NULL) {
1988        if (DSFptr->check) {
1989            log_msg (4, "%s is mounted on %s and is on disk %s", DSFptr->device, DSFptr->mount_point, ndsf);
1990            strcat(*included_dsf_list, DSFptr->mount_point);
1991            strcat(*included_dsf_list, "|");
1992        } else {
1993            log_msg (4, "%s is mounted on %s and is NOT on disk %s", DSFptr->device, DSFptr->mount_point, ndsf);
1994            strcat(*excluded_dsf_list, DSFptr->mount_point);
1995            strcat(*excluded_dsf_list, "|");
1996        }
1997        DSFptr = DSFptr->next;
1998    }
1999    mr_free(ndsf);
2000
2001    log_msg (5, "included_dsf_list: %s", *included_dsf_list);
2002    log_msg (5, "excluded_dsf_list: %s", *excluded_dsf_list);
2003    return (0);
2004}
2005
2006
2007/* Update the bkpinfo structure for exclude & include paths
2008 * in order to handle correctly paths corresponding to devices */
2009void mr_make_devlist_from_pathlist(char *pathlist, char mode) {
2010
2011char *token = NULL;
2012int lastpos = 0;
2013char *mounted_on_dsf = NULL;
2014char *not_mounted_on_dsf = NULL;
2015char token_chars[] ="|\t\r\f\a\0\n";
2016char *tmp = NULL;
2017char *tmp1 = NULL;
2018char *tmp2 = NULL;
2019
2020if (pathlist == NULL) {
2021    return;
2022}
2023while ((token = mr_strtok(pathlist, token_chars, &lastpos)) != NULL) {
2024    switch (get_dsf_mount_list(token, &mounted_on_dsf, &not_mounted_on_dsf)) {
2025    case 1: 
2026        if (mode == 'E') {
2027            log_msg(1, "WARNING ! %s doesn't exist in -E option", token);
2028        } else {
2029            log_msg(1, "ERROR ! %s doesn't exist in -I option", token);
2030            fatal_error("Error processing -I option");
2031        }
2032        break;
2033    /* Everything is OK; proceed to archive data */
2034    case 0:
2035        if (mode == 'E') {
2036            if (strlen(mounted_on_dsf)) {
2037                log_to_screen("Excluding the following file systems on %s:", token);
2038                log_to_screen("==> %s", mounted_on_dsf);
2039                log_msg (5, "Adding to bkpinfo->exclude_paths due to -E option: %s", mounted_on_dsf);
2040                if (bkpinfo->exclude_paths) {
2041                    mr_strcat(bkpinfo->exclude_paths,"|%s",mounted_on_dsf);
2042                } else {
2043                    mr_asprintf(bkpinfo->exclude_paths,"%s",mounted_on_dsf);
2044                }
2045                if (bkpinfo->exclude_devs) {
2046                    mr_strcat(bkpinfo->exclude_devs,"|%s",token);
2047                } else {
2048                    mr_asprintf(bkpinfo->exclude_devs,"%s",token);
2049                }
2050            }
2051        } else {
2052            log_to_screen("Archiving only the following file systems on %s:", token);
2053            log_to_screen("==> %s", mounted_on_dsf);
2054            mr_free(bkpinfo->include_paths);
2055            mr_asprintf(bkpinfo->include_paths, "%s", "/");
2056            if (strlen(not_mounted_on_dsf)) {
2057                log_msg (5, "Adding to bkpinfo->exclude_paths due to -I option: %s", not_mounted_on_dsf);
2058                log_to_screen("Not archiving the following file systems:");
2059                log_to_screen("==> %s", not_mounted_on_dsf);
2060                if (bkpinfo->exclude_paths) {
2061                    mr_strcat(bkpinfo->exclude_paths, "|%s",not_mounted_on_dsf);
2062                } else {
2063                    mr_asprintf(bkpinfo->exclude_paths,"%s",not_mounted_on_dsf);
2064                }
2065            }
2066        }
2067        break;
2068    /* It's a dsf but not a whole disk dsf */
2069    case -2:
2070        log_to_screen("Could %s be a partition instead of a whole disk device special file?\nIgnored.", token);
2071        break;
2072    /* A device special file was not passed in. Process it as a path. */
2073    case -1:
2074        /*  Adds a | to ensure correct detection even at both ends */
2075        mr_asprintf(tmp1,"|%s",token);
2076        mr_asprintf(tmp2,"|%s|",token);
2077        if (mode == 'E') {
2078            /*  Add the token if not already in the list */
2079            mr_asprintf(tmp,"|%s|",bkpinfo->exclude_paths);
2080            if (strstr(tmp,tmp2) == NULL) {
2081                if (bkpinfo->exclude_paths) {
2082                    mr_strcat(bkpinfo->exclude_paths,tmp1);
2083                    mr_free(tmp1);
2084                } else {
2085                    bkpinfo->exclude_paths = tmp1;
2086                }
2087            }
2088        } else {
2089            /*  Add the token if not already in the list */
2090            mr_asprintf(tmp,"|%s|",bkpinfo->include_paths);
2091            if (strstr(tmp,tmp2) == NULL) {
2092                mr_strcat(bkpinfo->include_paths, "%s", tmp1);
2093            }
2094            mr_free(tmp1);
2095        }
2096        mr_free(tmp);
2097        mr_free(tmp2);
2098        break;
2099    }
2100    mr_free(token);
2101
2102    if (bkpinfo->include_paths != NULL) {
2103        log_msg(1, "include_paths is now '%s'", bkpinfo->include_paths);
2104    }
2105    if (bkpinfo->exclude_paths != NULL) {
2106        log_msg(1, "exclude_paths is now '%s'", bkpinfo->exclude_paths);
2107    }
2108    if (bkpinfo->exclude_devs != NULL) {
2109        log_msg(1, "exclude_devs is now '%s'", bkpinfo->exclude_devs);
2110    }
2111}
2112}
2113
2114
2115
2116
2117/**
2118 * Ask user for details of backup/restore information.
2119 * Called when @c mondoarchive doesn't get any parameters.
2120 * @param bkpinfo The backup information structure to fill out with the user's data.
2121 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
2122 * @return 0, always.
2123 * @bug No point of `int' return value.
2124 * @ingroup archiveGroup
2125 */
2126int interactively_obtain_media_parameters_from_user(bool archiving_to_media)
2127// archiving_to_media is TRUE if I'm being called by mondoarchive
2128// archiving_to_media is FALSE if I'm being called by mondorestore
2129{
2130    char *tmp = NULL;
2131    char *sz = NULL;
2132    char *tmpro = NULL;
2133    char *tmp1 = NULL;
2134    char *mds = NULL;
2135    char *q = NULL;
2136    char p[16*MAX_STR_LEN];
2137    char *sz_size = NULL;
2138    char *command = NULL;
2139    char *compression_type = NULL;
2140    char *comment = NULL;
2141    int i;
2142    FILE *fin;
2143
2144    malloc_string(tmp1);
2145    assert(bkpinfo != NULL);
2146    bkpinfo->nonbootable_backup = FALSE;
2147
2148    // Tape, CD, NETFS, ...?
2149    srandom(getpid());
2150    bkpinfo->backup_media_type =
2151        (g_restoring_live_from_cd) ? cdr :
2152        which_backup_media_type(bkpinfo->restore_data);
2153    if (bkpinfo->backup_media_type == none) {
2154        log_to_screen("User has chosen not to backup the PC");
2155        finish(1);
2156    }
2157    /* Why asking to remove the media with tape ?
2158    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
2159        popup_and_OK("Please remove media from drive(s)");
2160    }
2161    */
2162    if (archiving_to_media) {
2163        setup_tmpdir(NULL);
2164        /*
2165         * Set the scratchdir to reside on the partition with the most free space.
2166         * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2167         */
2168#ifdef __FreeBSD__
2169        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output("LANGUAGE=C df -m -P -t nonfs,msdosfs,ntfs,ntfs-3g,vmhgfs,smbfs,smb,cifs,afs,gfs,ocfs,ocfs2,mvfs,nsspool,nssvol | grep -vE \"none|Filesystem\" | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -nr | awk '{print $NF;}' | while read x ; do test -w $x && echo $x && break ; done"));
2170#else
2171        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output("LANGUAGE=C df -m -P -x nfs -x nfs4 -x fuse.sshfs -x fuse -x vfat -x ntfs -x ntfs-3g -x vmhgfs -x smbfs -x smb -x cifs -x afs -x gfs -x ocfs -x ocfs2 -x mvfs -x nsspool -x nssvol -x iso9660 | grep -vE \"none|Filesystem|/dev/shm\" | awk '{printf \"%s %s\\n\", $4, $6;}' | sort -nr | awk '{print $NF;}' | while read x ; do test -w $x && echo $x && break ; done"));
2172#endif
2173
2174        if (tmp[0] != '/') {
2175            mr_asprintf(sz, "%s", tmp);
2176            mr_free(tmp);
2177            mr_asprintf(tmp, "/%s", sz);
2178            mr_free(sz);
2179        }
2180        setup_scratchdir(tmp);
2181    }
2182    log_msg(3, "media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
2183    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
2184    bkpinfo->compression_level = (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
2185    bkpinfo->use_lzo = (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
2186    mvaddstr_and_log_it(2, 0, " ");
2187
2188    // Find device's /dev (or SCSI) entry
2189    switch (bkpinfo->backup_media_type) {
2190    case cdr:
2191    case cdrw:
2192    case dvd:
2193    case usb:
2194        /* Never try to eject a USB device */
2195        if (bkpinfo->backup_media_type == usb) {
2196            bkpinfo->please_dont_eject = TRUE;
2197        }
2198        if (archiving_to_media) {
2199            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2200                if (ask_me_yes_or_no("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?")) {
2201                    bkpinfo->manual_cd_tray = TRUE;
2202                }
2203            }
2204            if ((compression_type = which_compression_type()) == NULL) {
2205                log_to_screen("User has chosen not to backup the PC");
2206                finish(1);
2207            }
2208
2209            if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2210                log_to_screen("User has chosen not to backup the PC");
2211                finish(1);
2212            }
2213            mds = media_descriptor_string(bkpinfo->backup_media_type);
2214            mr_asprintf(comment, "What speed is your %s (re)writer?", mds);
2215            if (bkpinfo->backup_media_type == dvd) {
2216                find_dvd_device(bkpinfo->media_device, FALSE);
2217                strcpy(tmp1, "1");
2218                mr_asprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2219                log_msg(1, "Setting to DVD defaults");
2220            } else {
2221                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
2222                strcpy(tmp1, "4");
2223                mr_asprintf(sz_size, "%d", 650);
2224                log_msg(1, "Setting to CD defaults");
2225            }
2226            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2227                if (!popup_and_get_string("Speed", comment, tmp1, 4)) {
2228                    log_to_screen("User has chosen not to backup the PC");
2229                    mr_free(comment);
2230                    finish(1);
2231                }
2232            }
2233            mr_free(comment);
2234            bkpinfo->cdrw_speed = atoi(tmp1);   // if DVD then this shouldn't ever be used anyway :)
2235
2236            strcpy(tmp1, sz_size);
2237            mr_asprintf(comment, "How much data (in Megabytes) will each %s store?", mds);
2238            mr_free(mds);
2239            if (!popup_and_get_string("Size", comment, tmp1, 5)) {
2240                log_to_screen("User has chosen not to backup the PC");
2241                finish(1);
2242            }
2243            mr_asprintf(sz_size, "%s", tmp1);
2244            bkpinfo->media_size = atoi(sz_size);
2245
2246            if (bkpinfo->media_size <= 0) {
2247                log_to_screen("User has chosen not to backup the PC");
2248                finish(1);
2249            }
2250        }
2251        /* No break because we continue even for usb */
2252    case cdstream:
2253        mds = media_descriptor_string(bkpinfo->backup_media_type);
2254
2255        if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
2256            strcpy(bkpinfo->media_device, "/dev/cdrom");
2257            log_msg(2, "CD-ROM device assumed to be at %s", bkpinfo->media_device);
2258        } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))  || bkpinfo->backup_media_type == dvd) {
2259            if (!bkpinfo->media_device[0]) {
2260                strcpy(bkpinfo->media_device, "/dev/cdrom");
2261            }                   // just for the heck of it :)
2262            log_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device);
2263            if (bkpinfo->backup_media_type == dvd || find_cdrom_device(bkpinfo->media_device, FALSE)) {
2264                log_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device);
2265                mr_asprintf(comment, "Please specify your %s drive's /dev entry", mds);
2266                if (!popup_and_get_string("Device?", comment, bkpinfo->media_device, MAX_STR_LEN / 4)) {
2267                    log_to_screen("User has chosen not to backup the PC");
2268                    finish(1);
2269                }
2270            }
2271            log_msg(2, "%s device found at %s", mds, bkpinfo->media_device);
2272        } else {
2273            if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) {
2274                bkpinfo->media_device[0] = '\0';
2275            }
2276            if (bkpinfo->media_device[0]) {
2277                if (bkpinfo->backup_media_type == usb) {
2278                    mr_asprintf(tmp, "I think your %s media corresponds to %s. Is this correct?", mds, bkpinfo->media_device);
2279                } else {
2280                    mr_asprintf(tmp, "I think I've found your %s burner at SCSI node %s. Is this correct? (Say no if you have an IDE burner and you are running a 2.6 kernel. You will then be prompted for further details.)", mds, bkpinfo->media_device);
2281                }
2282                if (!ask_me_yes_or_no(tmp)) {
2283                    bkpinfo->media_device[0] = '\0';
2284                }
2285                mr_free(tmp);
2286            }
2287            if (!bkpinfo->media_device[0]) {
2288                if (bkpinfo->backup_media_type == usb) {
2289                    i = popup_and_get_string("/dev entry?",
2290                                         "What is the /dev entry of your USB Disk/Key, please?",
2291                                         bkpinfo->media_device,
2292                                         MAX_STR_LEN / 4);
2293                } else {
2294                    if (g_kernel_version < 2.6) {
2295                        i = popup_and_get_string("Device node?",
2296                                             "What is the SCSI node of your CD (re)writer, please?",
2297                                             bkpinfo->media_device,
2298                                             MAX_STR_LEN / 4);
2299                    } else {
2300                        i = popup_and_get_string("/dev entry?",
2301                                             "What is the /dev entry of your CD (re)writer, please?",
2302                                             bkpinfo->media_device,
2303                                             MAX_STR_LEN / 4);
2304                    }
2305                }
2306                if (!i) {
2307                    log_to_screen("User has chosen not to backup the PC");
2308                    finish(1);
2309                }
2310            }
2311        }
2312        mr_free(mds);
2313
2314        if (bkpinfo->backup_media_type == cdstream) {
2315            bkpinfo->media_size = 650;
2316        }
2317        break;
2318    case udev:
2319        if (!ask_me_yes_or_no
2320            ("This option is for advanced users only. Are you sure?")) {
2321            log_to_screen("User has chosen not to backup the PC");
2322            finish(1);
2323        }
2324    case tape:
2325
2326        if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) {
2327            log_msg(3, "Ok, using vanilla scsi tape.");
2328            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
2329            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2330                paranoid_fclose(fin);
2331            } else {
2332                strcpy(bkpinfo->media_device, "/dev/osst0");
2333            }
2334        }
2335        if (bkpinfo->media_device[0]) {
2336            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2337                paranoid_fclose(fin);
2338            } else {
2339                if (does_file_exist("/tmp/mondo-restore.cfg")) {
2340                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev", bkpinfo->media_device);
2341                }
2342            }
2343        }
2344        if (bkpinfo->media_device[0]) {
2345            mr_asprintf(tmp, "I think I've found your tape streamer at %s; am I right on the money?", bkpinfo->media_device);
2346            if (!ask_me_yes_or_no(tmp)) {
2347                bkpinfo->media_device[0] = '\0';
2348            }
2349            mr_free(tmp);
2350        }
2351        if (!bkpinfo->media_device[0]) {
2352            if (!popup_and_get_string
2353                ("Device name?",
2354                 "What is the /dev entry of your tape streamer?",
2355                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
2356                log_to_screen("User has chosen not to backup the PC");
2357                finish(1);
2358            }
2359        }
2360        mr_asprintf(tmp, "ls -l %s", bkpinfo->media_device);
2361        if (run_program_and_log_output(tmp, FALSE)) {
2362            log_to_screen("User has not specified a valid /dev entry");
2363            finish(1);
2364        }
2365        mr_free(tmp);
2366
2367        if (!popup_and_get_string
2368            ("Tape block size?",
2369             "What is the block size of your tape streamer?",
2370             sz_size, 15)) {
2371            log_to_screen("User has chosen not to backup the PC");
2372            finish(1);
2373        }
2374        bkpinfo->internal_tape_block_size = atol(sz_size);
2375        if (bkpinfo->internal_tape_block_size <= 0) {
2376            log_to_screen("User has chosen not to backup the PC");
2377            finish(1);
2378        }
2379
2380        bkpinfo->media_size = 0;
2381        log_msg(4, "media_size = %ld", bkpinfo->media_size);
2382
2383        bkpinfo->use_obdr = ask_me_yes_or_no
2384            ("Do you want to activate OBDR support for your tapes ?");
2385        if (bkpinfo->use_obdr) {
2386            log_msg(4, "obdr mode = TRUE");
2387        } else {
2388            log_msg(4, "obdr mode = FALSE");
2389        }
2390        if (archiving_to_media) {
2391            if ((compression_type = which_compression_type()) == NULL) {
2392                log_to_screen("User has chosen not to backup the PC");
2393                finish(1);
2394            }
2395            if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2396                log_to_screen("User has chosen not to backup the PC");
2397                finish(1);
2398            }
2399        }
2400        break;
2401
2402
2403
2404    case netfs:
2405        /* Never try to eject a NETFS device */
2406        bkpinfo->please_dont_eject = TRUE;
2407        /*  Force NFS to be the protocol by default */
2408        if (bkpinfo->netfs_proto == NULL) {
2409            mr_asprintf(bkpinfo->netfs_proto, "nfs");
2410        }
2411
2412        /* Initiate bkpinfo netfs_mount path from running environment if not already done */
2413        if (bkpinfo->netfs_mount == NULL) {
2414            mr_asprintf(bkpinfo->netfs_mount, "%s", call_program_and_get_last_line_of_output("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
2415        }
2416#ifdef __FreeBSD__
2417        if (TRUE)
2418#else
2419        if (!bkpinfo->disaster_recovery)
2420#endif
2421        {
2422            if (!popup_and_get_string
2423                ("Network shared dir.",
2424                 "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.)",
2425                 p, MAX_STR_LEN / 4)) {
2426                log_to_screen("User has chosen not to backup the PC");
2427                finish(1);
2428            }
2429            mr_free(bkpinfo->netfs_mount);
2430            mr_asprintf(bkpinfo->netfs_mount, "%s", p);
2431            if (!bkpinfo->restore_data) {
2432                if ((compression_type = which_compression_type()) == NULL) {
2433                    log_to_screen("User has chosen not to backup the PC");
2434                    finish(1);
2435                }
2436
2437                if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2438                    log_to_screen("User has chosen not to backup the PC");
2439                    finish(1);
2440                }
2441            }
2442            // check whether already mounted - we better remove
2443            // surrounding spaces and trailing '/' for this
2444            mr_strip_spaces(bkpinfo->netfs_mount);
2445            if (bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] == '/')
2446                bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] = '\0';
2447            q = strchr(bkpinfo->netfs_mount, '@');
2448            if (q != NULL) {
2449                /* User found. Store the 2 values */
2450                q++;
2451                /* new netfs mount */
2452                strcpy(tmp1,q);
2453            } else {
2454                strcpy(tmp1,bkpinfo->netfs_mount);
2455            }
2456            mr_asprintf(command, "mount | grep \"%s \" | cut -d' ' -f3", tmp1);
2457            strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output(command));
2458            mr_free(command);
2459
2460            if (!bkpinfo->restore_data) {
2461                mr_asprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2462                mr_asprintf(comment, "How much data (in Megabytes) will each media store?");
2463                strcpy(tmp1, sz_size);
2464                mr_free(sz_size);
2465                if (!popup_and_get_string("Size", comment, tmp1, 5)) {
2466                    log_to_screen("User has chosen not to backup the PC");
2467                    finish(1);
2468                }
2469                mr_free(comment);
2470                mr_asprintf(sz_size, "%s", tmp1);
2471            } else {
2472                mr_asprintf(sz_size, "0");
2473            }
2474            bkpinfo->media_size = atoi(sz_size);
2475            mr_free(sz_size);
2476
2477            if (bkpinfo->media_size < 0) {
2478                log_to_screen("User has chosen not to backup the PC");
2479                finish(1);
2480            }
2481        }
2482        if (bkpinfo->disaster_recovery) {
2483            mr_asprintf(command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
2484            paranoid_system(command);
2485            mr_free(command);
2486
2487        }
2488        strcpy(tmp1, bkpinfo->netfs_proto);
2489        if (!popup_and_get_string("Network protocol", "Which protocol should I use (nfs/sshfs/smbfs) ?",tmp1, MAX_STR_LEN)) {
2490            log_to_screen("User has chosen not to backup the PC");
2491            finish(1);
2492        }
2493        mr_free(bkpinfo->netfs_proto);
2494        mr_asprintf(bkpinfo->netfs_proto, "%s", tmp1);
2495
2496        strcpy(tmp1, bkpinfo->netfs_mount);
2497        if (!popup_and_get_string("Network share", "Which remote share should I mount?", tmp1, MAX_STR_LEN)) {
2498            log_to_screen("User has chosen not to backup the PC");
2499            finish(1);
2500        }
2501        mr_free(bkpinfo->netfs_mount);
2502        mr_asprintf(bkpinfo->netfs_mount, "%s", tmp1);
2503
2504        if (bkpinfo->netfs_user) {
2505            strcpy(tmp1, bkpinfo->netfs_user);
2506        } else {
2507            strcpy(tmp1, "");
2508        }
2509        if (!popup_and_get_string("Network user", "Which user should I use if any ?",tmp1, MAX_STR_LEN)) {
2510            log_to_screen("User has chosen not to backup the PC");
2511            finish(1);
2512        }
2513        mr_free(bkpinfo->netfs_user);
2514        if (strcmp(tmp1, "") != 0) {
2515            mr_asprintf(bkpinfo->netfs_user, "%s", tmp1);
2516        }
2517   
2518        /* Initiate bkpinfo isodir path from running environment if mount already done */
2519        if (is_this_device_mounted(bkpinfo->netfs_mount)) {
2520            strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
2521        } else {
2522            sprintf(bkpinfo->isodir, "%s/netfsdir", bkpinfo->tmpdir);
2523            mr_asprintf(command, "mkdir -p %s", bkpinfo->isodir);
2524            run_program_and_log_output(command, 5);
2525            mr_free(command);
2526
2527            if (bkpinfo->restore_data) {
2528                /*  mount th FS read-only in restore mode to avoid any erase of whatever */
2529                mr_asprintf(tmpro, "-o ro");
2530            } else {
2531                mr_asprintf(tmpro, "");
2532            }
2533
2534            /*  Build the mount string */
2535            if (strstr(bkpinfo->netfs_proto, "smbfs")) {
2536                mr_asprintf(tmp, "mount -t cifs %s %s %s",bkpinfo->netfs_mount, bkpinfo->isodir,tmpro);
2537                if (bkpinfo->netfs_user) {
2538                    mr_strcat(tmp, " -o user=%s", bkpinfo->netfs_user);
2539                }
2540            else {
2541                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2542                    mr_asprintf(tmp, "sshfs %s ",tmpro);
2543                } else {
2544                    mr_asprintf(tmp, "mount -t %s -o nolock %s ", bkpinfo->netfs_proto,tmpro);
2545                }
2546                if (bkpinfo->netfs_user) {
2547                    mr_strcat(tmp, "%s@", bkpinfo->netfs_user);
2548                }
2549                mr_strcat(tmp, "%s %s", bkpinfo->netfs_mount, bkpinfo->isodir);
2550            }
2551            run_program_and_log_output(tmp, 3);
2552            mr_free(tmp);
2553
2554            malloc_string(g_selfmounted_isodir);
2555            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
2556            }
2557        }
2558        if (!is_this_device_mounted(bkpinfo->netfs_mount)) {
2559            popup_and_OK("Please mount that partition before you try to backup to or restore from it.");
2560            finish(1);
2561        }
2562        if (bkpinfo->netfs_remote_dir == NULL) {
2563            fatal_error("bkpinfo->netfs_remote_dir should not be NULL");
2564        }
2565        strcpy(tmp1, bkpinfo->netfs_remote_dir);
2566        if (!popup_and_get_string
2567            ("Directory", "Which directory within that mountpoint?", tmp1,
2568             MAX_STR_LEN)) {
2569            log_to_screen("User has chosen not to backup the PC");
2570            finish(1);
2571        }
2572        mr_free(bkpinfo->netfs_remote_dir);
2573        mr_asprintf(bkpinfo->netfs_remote_dir, "%s", tmp1);
2574
2575        // check whether writable - we better remove surrounding spaces for this
2576        mr_strip_spaces(bkpinfo->netfs_remote_dir);
2577
2578        if (!popup_and_get_string
2579            ("Prefix.",
2580             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2581            bkpinfo->prefix, MAX_STR_LEN / 4)) {
2582            log_to_screen("User has chosen not to backup the PC");
2583            finish(1);
2584        }
2585        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2586        log_msg(3, "Just set netfs_remote_dir to %s", bkpinfo->netfs_remote_dir);
2587        log_msg(3, "isodir is still %s", bkpinfo->isodir);
2588        break;
2589
2590    case iso:
2591        if (!bkpinfo->disaster_recovery) {
2592            if (!popup_and_get_string
2593                ("Storage dir.",
2594                 "Please enter the full path name to the directory for your ISO images.  Example: /mnt/raid0_0",
2595                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
2596                log_to_screen("User has chosen not to backup the PC");
2597                finish(1);
2598            }
2599            if (archiving_to_media) {
2600                if ((compression_type = which_compression_type()) == NULL) {
2601                    log_to_screen("User has chosen not to backup the PC");
2602                    finish(1);
2603                }
2604                if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2605                    log_to_screen("User has chosen not to backup the PC");
2606                    finish(1);
2607                }
2608                sprintf(tmp1, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2609                if (!popup_and_get_string
2610                    ("ISO size.",
2611                     "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 (700) or DVD's (4480) you plan to backup to.",
2612                     tmp1, 16)) {
2613                    log_to_screen("User has chosen not to backup the PC");
2614                    finish(1);
2615                }
2616                bkpinfo->media_size = atoi(tmp1);
2617            } else {
2618                bkpinfo->media_size = 650;
2619            }
2620        }
2621        if (!popup_and_get_string
2622            ("Prefix.",
2623             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2624             bkpinfo->prefix, MAX_STR_LEN / 4)) {
2625            log_to_screen("User has chosen not to backup the PC");
2626            finish(1);
2627        }
2628        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2629        break;
2630    default:
2631        fatal_error("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
2632    }
2633
2634    if (archiving_to_media) {
2635
2636#ifdef __FreeBSD__
2637        strcpy(bkpinfo->boot_device,
2638               call_program_and_get_last_line_of_output
2639               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
2640#else
2641        strcpy(bkpinfo->boot_device,
2642               call_program_and_get_last_line_of_output
2643               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
2644#endif
2645        i = which_boot_loader(bkpinfo->boot_device);
2646        if (i == 'U')           // unknown
2647        {
2648
2649#ifdef __FreeBSD__
2650            if (!popup_and_get_string
2651                ("Boot device",
2652                 "What is your boot device? (e.g. /dev/ad0)",
2653                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2654                log_to_screen("User has chosen not to backup the PC");
2655                finish(1);
2656            }
2657            i = which_boot_loader(bkpinfo->boot_device);
2658#else
2659            if (!popup_and_get_string
2660                ("Boot device",
2661                 "What is your boot device? (e.g. /dev/hda)",
2662                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2663                log_to_screen("User has chosen not to backup the PC");
2664                finish(1);
2665            }
2666            if (does_string_exist_in_boot_block(bkpinfo->boot_device, "LILO")) {
2667                i = 'L';
2668            } else
2669                if (does_string_exist_in_boot_block(bkpinfo->boot_device, "ELILO")) {
2670                i = 'E';
2671            } else
2672                if (does_string_exist_in_boot_block(bkpinfo->boot_device, "GRUB")) {
2673                i = 'G';
2674            } else {
2675                i = 'U';
2676            }
2677#endif
2678            if (i == 'U') {
2679                if (ask_me_yes_or_no("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?")) {
2680                    i = 'R';    // raw
2681                } else {
2682                    log_to_screen("I cannot find your boot loader. Please run mondoarchive with parameters.");
2683                    finish(1);
2684                }
2685            }
2686        }
2687        bkpinfo->boot_loader = i;
2688
2689        if (bkpinfo->include_paths) {
2690            strcpy(tmp1, bkpinfo->include_paths);
2691            mr_free(bkpinfo->include_paths);
2692        } else {
2693            strcpy(tmp1, "/");
2694        }
2695        if (!popup_and_get_string
2696            ("Backup paths",
2697             "Please enter paths (separated by '|') which you want me to backup. The default is '/' (i.e. everything).",
2698             tmp1, MAX_STR_LEN)) {
2699            log_to_screen("User has chosen not to backup the PC");
2700            finish(1);
2701        }
2702        mr_asprintf(bkpinfo->include_paths, "%s", tmp1);
2703
2704        tmp = list_of_NETFS_mounts_only();
2705        if (strlen(tmp) > 2) {
2706            mr_strcat(bkpinfo->exclude_paths, "|%s",tmp);
2707        }
2708        mr_free(tmp);
2709// NTFS
2710        strcpy(tmp1, call_program_and_get_last_line_of_output("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
2711        if (strlen(tmp1) > 2) {
2712            if (!popup_and_get_string
2713                ("NTFS partitions",
2714                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
2715                 tmp1, MAX_STR_LEN / 4)) {
2716                log_to_screen("User has chosen not to backup the PC");
2717                finish(1);
2718            }
2719            strncpy(bkpinfo->image_devs, tmp1, MAX_STR_LEN / 4);
2720        }
2721
2722        if (bkpinfo->exclude_paths != NULL ) {
2723            strncpy(p,bkpinfo->exclude_paths,(16*MAX_STR_LEN)-1);
2724        } else {
2725            p[0] = '\0';
2726        }
2727        popup_and_get_string("Exclude paths", "Please enter paths which you do NOT want to backup. Separate them with '|'. NB: /tmp and /proc are always excluded. :-) Just hit 'Enter' if you want to do a full system backup.", p, (16*MAX_STR_LEN)-1);
2728        if (p == NULL) {
2729            log_to_screen("User has chosen not to backup the PC");
2730            finish(1);
2731        }
2732        mr_free(bkpinfo->exclude_paths);
2733        mr_asprintf(tmp, "%s", p);
2734        bkpinfo->exclude_paths = tmp;
2735
2736        if (!popup_and_get_string
2737            ("Temporary directory",
2738             "Please enter your temporary directory.",
2739             bkpinfo->tmpdir, (4*MAX_STR_LEN)-1)) {
2740            log_to_screen("User has chosen not to backup the PC");
2741            finish(1);
2742        }
2743        /*  if modified to another path */
2744        if (strstr(bkpinfo->tmpdir,"mondo.tmp.") == NULL) {
2745            setup_tmpdir(bkpinfo->tmpdir);
2746        }
2747        if (!popup_and_get_string
2748            ("Scratch directory",
2749             "Please enter your scratch directory.",
2750             bkpinfo->scratchdir, (4*MAX_STR_LEN)-1)) {
2751            log_to_screen("User has chosen not to backup the PC");
2752            finish(1);
2753        }
2754        /*  if modified to another path */
2755        if (strstr(bkpinfo->scratchdir,"mondo.scratch.") == NULL) {
2756            setup_scratchdir(bkpinfo->scratchdir);
2757        }
2758        if (ask_me_yes_or_no("Do you want to backup extended attributes?")) {
2759            if (find_home_of_exe("getfattr")) {
2760                mr_free(g_getfattr);
2761                mr_asprintf(g_getfattr,"getfattr");
2762            }
2763            if (find_home_of_exe("getfacl")) {
2764                mr_free(g_getfacl);
2765                mr_asprintf(g_getfacl,"getfacl");
2766            }
2767            log_it("Backup of extended attributes");
2768        }
2769// Interactive mode:
2770#ifdef __IA64__
2771        bkpinfo->make_cd_use_lilo = TRUE;
2772#else
2773        bkpinfo->make_cd_use_lilo = FALSE;
2774#endif
2775        bkpinfo->backup_data = TRUE;
2776        if (strcmp(compression_type,"lzo") == 0) {
2777            strcpy(bkpinfo->zip_exe, "lzop");
2778            strcpy(bkpinfo->zip_suffix, "lzo");
2779        } else if (strcmp(compression_type,"gzip") == 0) {
2780            strcpy(bkpinfo->zip_exe, "gzip");
2781            strcpy(bkpinfo->zip_suffix, "gz");
2782        } else if (strcmp(compression_type,"lzma") == 0) {
2783            //strcpy(bkpinfo->zip_exe, "xy");
2784            //strcpy(bkpinfo->zip_suffix, "xy");
2785        } else if (strcmp(compression_type,"bzip2") == 0) {
2786            strcpy(bkpinfo->zip_exe, "bzip2");
2787            strcpy(bkpinfo->zip_suffix, "bz2");
2788        } else {
2789            bkpinfo->zip_exe[0] = bkpinfo->zip_suffix[0] = '\0';
2790        }
2791
2792        bkpinfo->verify_data =
2793            ask_me_yes_or_no
2794            ("Will you want to verify your backups after Mondo has created them?");
2795
2796        if (!ask_me_yes_or_no
2797            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2798            log_to_screen("User has chosen not to backup the PC");
2799            finish(1);
2800        }
2801    } else {
2802        bkpinfo->restore_data = TRUE;   // probably...
2803    }
2804    mr_free(compression_type);
2805
2806    if (bkpinfo->backup_media_type == iso
2807        || bkpinfo->backup_media_type == netfs) {
2808        g_ISO_restore_mode = TRUE;
2809    }
2810#ifdef __FreeSD__
2811// skip
2812#else
2813    if (bkpinfo->backup_media_type == netfs) {
2814        log_msg(3, "I think the Remote mount is mounted at %s", bkpinfo->isodir);
2815    }
2816    log_it("isodir = %s", bkpinfo->isodir);
2817    if (bkpinfo->netfs_mount) {
2818        log_it("netfs_mount = '%s'", bkpinfo->netfs_mount);
2819    }
2820    if (bkpinfo->netfs_user) {
2821        log_it("netfs_user = '%s'", bkpinfo->netfs_user);
2822    }
2823    if (bkpinfo->netfs_proto) {
2824        log_it("netfs_proto = '%s'", bkpinfo->netfs_proto);
2825    }
2826#endif
2827
2828    log_it("media device = %s", bkpinfo->media_device);
2829    log_it("media size = %ld", bkpinfo->media_size);
2830    log_it("media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
2831    if (bkpinfo->prefix) {
2832        log_it("prefix = %s", bkpinfo->prefix);
2833    }
2834    log_it("compression = %ld", bkpinfo->compression_level);
2835    log_it("exclude_path = %s", bkpinfo->exclude_paths);
2836    if (bkpinfo->include_paths) {
2837        log_it("include_path = %s", bkpinfo->include_paths);
2838    }
2839
2840    /* Handle devices passed in bkpinfo and print result */
2841    /*  the mr_make_devlist_from_pathlist function appends */
2842    /*  to the *_paths variables so copy before */
2843    mr_make_devlist_from_pathlist(bkpinfo->exclude_paths, 'E');
2844    mr_make_devlist_from_pathlist(bkpinfo->include_paths, 'I');
2845
2846    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2847    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2848    if (bkpinfo->image_devs) {
2849        log_it("image_devs = '%s'", bkpinfo->image_devs);
2850    }
2851    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device, bkpinfo->boot_loader);
2852    if (bkpinfo->media_size < 0) {
2853        if (archiving_to_media) {
2854            fatal_error("Media size is less than zero.");
2855        } else {
2856            log_msg(2, "Warning - media size is less than zero.");
2857            bkpinfo->media_size = 0;
2858        }
2859    }
2860    paranoid_free(sz_size);
2861    paranoid_free(tmp1);
2862    return (0);
2863}
2864
2865
2866/**
2867 * Get a |-separated list of NETFS mounts.
2868 * @return The list created.
2869 * @note The return value points to allocated string that needs to be freed
2870 * @bug Even though we only want the mounts, the devices are still checked.
2871 */
2872char *list_of_NETFS_mounts_only(void)
2873{
2874    char *exclude_these_directories = NULL;
2875
2876    mr_asprintf(exclude_these_directories,"%s", call_program_and_get_last_line_of_output("mount -t coda,ncpfs,fuse.sshfs,nfs,nfs4,vmhgfs,smbfs,cifs,afs,gfs,ocfs,ocfs2,mvfs,nsspool,nssvol | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' '|' | awk '{print $0;}'"));
2877    log_msg(9,"list_of_NETFS_mounts_only returns %s\n",exclude_these_directories);
2878    return(exclude_these_directories);
2879}
2880
2881/* @} - end of utilityGroup */
2882
2883
2884
2885
2886
2887/**
2888 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2889 * [random] is a random number between 1 and 32767.
2890 * @param store_name_here Where to store the new filename.
2891 * @param stub A random number will be appended to this to make the FIFO's name.
2892 * @ingroup deviceGroup
2893 */
2894void make_fifo(char *store_name_here, char *stub)
2895{
2896    char *tmp;
2897
2898    malloc_string(tmp);
2899    assert_string_is_neither_NULL_nor_zerolength(stub);
2900
2901    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2902            (int) (random() % 32768));
2903    make_hole_for_file(store_name_here);
2904    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2905    sprintf(tmp, "chmod 770 %s", store_name_here);
2906    paranoid_system(tmp);
2907    paranoid_free(tmp);
2908}
2909
2910
2911
2912/**
2913 * @addtogroup deviceGroup
2914 * @{
2915 */
2916/**
2917 * If we can read @p dev, set @p output to it.
2918 * If @p dev cannot be read, set @p output to "".
2919 * @param dev The device to check for.
2920 * @param output Set to @p dev if @p dev exists, "" otherwise.
2921 * @return TRUE if @p dev exists, FALSE if it doesn't.
2922 */
2923bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2924{
2925    char *command;
2926
2927    malloc_string(command);
2928    if (!dev || dev[0] == '\0') {
2929        output[0] = '\0';
2930        return (FALSE);
2931    }
2932//  assert_string_is_neither_NULL_nor_zerolength(dev);
2933    if (!bkpinfo->please_dont_eject) {
2934        log_msg(10, "Injecting %s", dev);
2935        inject_device(dev);
2936    }
2937    if (!does_file_exist(dev)) {
2938        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2939        return (FALSE);
2940    }
2941    sprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2942            512L, dev);
2943    if (!run_program_and_log_output(command, FALSE)
2944        && !run_program_and_log_output(command, FALSE)) {
2945        strcpy(output, dev);
2946        log_msg(4, "Found it - %s", dev);
2947        return (TRUE);
2948    } else {
2949        output[0] = '\0';
2950        log_msg(4, "It's not %s", dev);
2951        return (FALSE);
2952    }
2953}
2954
2955
2956
2957
2958
2959/**
2960 * Find out what number CD is in the drive.
2961 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2962 * @return The current CD number, or -1 if it could not be found.
2963 * @note If the CD is not mounted, it will be mounted
2964 * (and remain mounted after this function returns).
2965 */
2966int what_number_cd_is_this()
2967{
2968    int cd_number = -1;
2969    char *mountdev = NULL;
2970    char *tmp = NULL;
2971
2972    assert(bkpinfo != NULL);
2973//  log_it("Asking what_number_cd_is_this");
2974    if (g_ISO_restore_mode) {
2975        mr_asprintf(tmp, "mount | grep iso9660 | awk '{print $3;}'");
2976
2977        mr_asprintf(mountdev, "%s%s", call_program_and_get_last_line_of_output(tmp), "/archives/THIS-CD-NUMBER");
2978        cd_number = atoi(last_line_of_file(mountdev));
2979        paranoid_free(mountdev);
2980        paranoid_free(tmp);
2981
2982        return (cd_number);
2983    }
2984
2985    mr_asprintf(mountdev, "%s", bkpinfo->media_device);
2986    if (!mountdev[0]) {
2987        log_it
2988            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2989        find_cdrom_device(bkpinfo->media_device, FALSE);
2990    }
2991    if (!is_this_device_mounted(MNT_CDROM)) {
2992        if (bkpinfo->backup_media_type == usb) {
2993            mount_USB_here(mountdev, MNT_CDROM);
2994        } else {
2995            mount_CDROM_here(mountdev, MNT_CDROM);
2996        }
2997    }
2998    paranoid_free(mountdev);
2999
3000    cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
3001    return (cd_number);
3002}
3003
3004
3005
3006
3007
3008
3009
3010/**
3011 * Find out what device is mounted as root (/).
3012 * @return Root device.
3013 * @note The returned string points to static storage and will be overwritten with every call.
3014 * @bug A bit of a misnomer; it's actually finding out the root device.
3015 * The mountpoint (where it's mounted) will obviously be '/'.
3016 */
3017char *where_is_root_mounted() {
3018
3019/*@ buffers **************** */
3020static char tmp[MAX_STR_LEN];
3021
3022
3023#ifdef __FreeBSD__
3024    strcpy(tmp, call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1"));
3025#else
3026    strcpy(tmp, call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
3027    if (strstr(tmp, "/dev/cciss/")) {
3028        strcpy(tmp, call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
3029    }
3030    if (strstr(tmp, "/dev/md")) {
3031        strcpy(tmp, call_program_and_get_last_line_of_output("mount | grep \" on / \" | cut -d' ' -f1"));
3032    }
3033#endif
3034
3035return (tmp);
3036}
3037
3038
3039/**
3040 * Find out which boot loader is in use.
3041 * @param which_device Device to look for the boot loader on.
3042 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
3043 * @note Under Linux, all drives are examined, not just @p which_device.
3044 */
3045#ifdef __FreeBSD__
3046char which_boot_loader(char *which_device)
3047{
3048    int count_lilos = 0;
3049    int count_grubs = 0;
3050    int count_boot0s = 0;
3051    int count_dangerouslydedicated = 0;
3052
3053    log_it("looking at drive %s's MBR", which_device);
3054    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
3055        count_grubs++;
3056    }
3057    if (does_string_exist_in_boot_block(which_device, "LILO")) {
3058        count_lilos++;
3059    }
3060    if (does_string_exist_in_boot_block(which_device, "Drive")) {
3061        count_boot0s++;
3062    }
3063    if (does_string_exist_in_first_N_blocks
3064        (which_device, "FreeBSD/i386", 17)) {
3065        count_dangerouslydedicated++;
3066    }
3067    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
3068           count_grubs, count_lilos, count_elilos, count_boot0s,
3069           count_dangerouslydedicated);
3070
3071    if (count_grubs && !count_lilos) {
3072        return ('G');
3073    } else if (count_lilos && !count_grubs) {
3074        return ('L');
3075    } else if (count_grubs == 1 && count_lilos == 1) {
3076        log_it("I'll bet you used to use LILO but switched to GRUB...");
3077        return ('G');
3078    } else if (count_boot0s == 1) {
3079        return ('B');
3080    } else if (count_dangerouslydedicated) {
3081        return ('D');
3082    } else {
3083        log_it("Unknown boot loader");
3084        return ('U');
3085    }
3086}
3087
3088#else
3089
3090char which_boot_loader(char *which_device)
3091{
3092    /*@ buffer ***************************************************** */
3093    char *list_drives_cmd = NULL;
3094    char *current_drive;
3095    char *tmp;
3096
3097    /*@ pointers *************************************************** */
3098    FILE *pdrives;
3099
3100    /*@ int ******************************************************** */
3101    int count_lilos = 0;
3102    int count_grubs = 0;
3103
3104    /*@ end vars *************************************************** */
3105
3106    malloc_string(current_drive);
3107
3108    /* UEFI is not supported here - but should be managed as a BIOS/UEFI option not a Boot Loader one per se */
3109
3110#ifdef __IA64__
3111    /* No choice for it */
3112    return ('E');
3113#endif
3114    assert(which_device != NULL);
3115
3116    mr_asprintf(list_drives_cmd, "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s", where_is_root_mounted());
3117    log_it("list_drives_cmd = %s", list_drives_cmd);
3118
3119    if (!(pdrives = popen(list_drives_cmd, "r"))) {
3120        log_OS_error("Unable to open list of drives");
3121        mr_free(list_drives_cmd);
3122        paranoid_free(current_drive);
3123        return ('\0');
3124    }
3125    mr_free(list_drives_cmd);
3126
3127    for (tmp = fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives) && (tmp != NULL);
3128         tmp = fgets(current_drive, MAX_STR_LEN, pdrives)) {
3129        strip_spaces(current_drive);
3130        log_it("looking at drive %s's MBR", current_drive);
3131        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3132            count_grubs++;
3133            strcpy(which_device, current_drive);
3134            break;
3135        }
3136        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3137            count_lilos++;
3138            strcpy(which_device, current_drive);
3139            break;
3140        }
3141    }
3142    if (pclose(pdrives)) {
3143        log_OS_error("Cannot pclose pdrives");
3144    }
3145    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3146    if (count_grubs && !count_lilos) {
3147        paranoid_free(current_drive);
3148        return ('G');
3149    } else if (count_lilos && !count_grubs) {
3150        paranoid_free(current_drive);
3151        return ('L');
3152    } else if (count_grubs == 1 && count_lilos == 1) {
3153        log_it("I'll bet you used to use LILO but switched to GRUB...");
3154        paranoid_free(current_drive);
3155        return ('G');
3156    } else {
3157        // We need to look on each partition then
3158        mr_asprintf(list_drives_cmd, "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
3159        log_it("list_drives_cmd = %s", list_drives_cmd);
3160
3161        if (!(pdrives = popen(list_drives_cmd, "r"))) {
3162            log_OS_error("Unable to open list of drives");
3163            mr_free(list_drives_cmd);
3164            paranoid_free(current_drive);
3165            return ('\0');
3166        }
3167        mr_free(list_drives_cmd);
3168
3169        for (tmp = fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives) && (tmp != NULL);
3170            tmp = fgets(current_drive, MAX_STR_LEN, pdrives)) {
3171            strip_spaces(current_drive);
3172            log_it("looking at partition %s's BR", current_drive);
3173            if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3174                count_grubs++;
3175                strcpy(which_device, current_drive);
3176                break;
3177            }
3178            if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3179                count_lilos++;
3180                strcpy(which_device, current_drive);
3181                break;
3182            }
3183        }
3184        if (pclose(pdrives)) {
3185            log_OS_error("Cannot pclose pdrives");
3186        }
3187        log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3188        paranoid_free(current_drive);
3189        if (count_grubs && !count_lilos) {
3190            return ('G');
3191        } else if (count_lilos && !count_grubs) {
3192            return ('L');
3193        } else if (count_grubs == 1 && count_lilos == 1) {
3194            log_it("I'll bet you used to use LILO but switched to GRUB...");
3195            return ('G');
3196        } else {
3197            log_it("Unknown boot loader");
3198            return ('U');
3199        }
3200    }
3201}
3202#endif
3203
3204
3205
3206
3207/**
3208 * Write zeroes over the first 16K of @p device.
3209 * @param device The device to zero.
3210 * @return 0 for success, 1 for failure.
3211 */
3212int zero_out_a_device(char *device)
3213{
3214    FILE *fout;
3215    int i;
3216
3217    assert_string_is_neither_NULL_nor_zerolength(device);
3218
3219    log_it("Zeroing drive %s", device);
3220    if (!(fout = fopen(device, "w"))) {
3221        log_OS_error("Unable to open/write to device");
3222        return (1);
3223    }
3224    for (i = 0; i < 16384; i++) {
3225        fputc('\0', fout);
3226    }
3227    paranoid_fclose(fout);
3228    log_it("Device successfully zeroed.");
3229    return (0);
3230}
3231
3232/**
3233 * Return the device pointed to by @p incoming.
3234 * @param incoming The device to resolve symlinks for.
3235 * @return The path to the real device file.
3236 * @note The returned string points to static storage that will be overwritten with each call.
3237 * @bug Won't work with file v4.0; needs to be written in C.
3238 */
3239char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
3240{
3241    static char output[MAX_STR_LEN];
3242    char *command;
3243    char *curr_fname;
3244    char *scratch = NULL;
3245    char *tmp = NULL;
3246    char *p;
3247
3248    struct stat statbuf;
3249    command = malloc(1000);
3250    malloc_string(curr_fname);
3251    if (!does_file_exist(incoming)) {
3252        log_it
3253            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
3254        strcpy(output, incoming);
3255    } else {
3256        strcpy(curr_fname, incoming);
3257        lstat(curr_fname, &statbuf);
3258        while (S_ISLNK(statbuf.st_mode)) {
3259            log_msg(1, "curr_fname = %s", curr_fname);
3260            sprintf(command, "file %s", curr_fname);
3261            mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
3262            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
3263                 p--);
3264            p++;
3265            mr_asprintf(scratch, "%s", p);
3266            for (p = scratch; *p != '\0' && *p != '\''; p++);
3267            *p = '\0';
3268            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
3269            mr_free(tmp);
3270
3271            if (scratch[0] == '/') {
3272                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
3273            } else {            // copy over the basename cos it's a relative softlink
3274                p = curr_fname + strlen(curr_fname);
3275                while (p != curr_fname && *p != '/') {
3276                    p--;
3277                }
3278                if (*p == '/') {
3279                    p++;
3280                }
3281                strcpy(p, scratch);
3282            }
3283            mr_free(scratch);
3284            lstat(curr_fname, &statbuf);
3285        }
3286        strcpy(output, curr_fname);
3287        log_it("resolved %s to %s", incoming, output);
3288    }
3289    paranoid_free(command);
3290    paranoid_free(curr_fname);
3291    return (output);
3292}
3293
3294/* @} - end of deviceGroup */
3295
3296/**
3297 * Return the type of partition format (GPT or MBR)
3298 */
3299char *which_partition_format(const char *drive)
3300{
3301    static char output[4];
3302    char *tmp = NULL;
3303    char *command;
3304    char *fdisk;
3305#ifdef __IA64__
3306    struct stat buf;
3307#endif
3308    malloc_string(command);
3309    malloc_string(fdisk);
3310    sprintf(fdisk, "/sbin/parted2fdisk");
3311    sprintf(command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
3312    mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
3313    if (strstr(tmp, "GPT") == NULL) {
3314        strcpy(output, "MBR");
3315    } else {
3316        strcpy(output, "GPT");
3317    }
3318    mr_free(tmp);
3319
3320    log_msg(0, "Found %s partition table format type", output);
3321    paranoid_free(command);
3322    paranoid_free(fdisk);
3323    return (output);
3324}
3325/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.