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

Last change on this file since 3191 was 3191, checked in by bruno, 6 years ago
  • Lots of memory management backports from 3.1 to 3.2 - still not finished, nor working ATM. the common subdir was done during travel, so this is essentially a backup !
  • Property svn:keywords set to Id
File size: 96.2 KB
Line 
1/* libmondo-devices.c                 Subroutines for handling devices
2   $Id: libmondo-devices.c 3191 2013-09-25 06:55:45Z 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 3191 2013-09-25 06:55:45Z 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 \)\ \' | 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        mr_asprintf(mount_cmd, "/mnt/isodir/%s/%s/%s-%d.iso", bkpinfo->isodir,
1343            bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number);
1344        mddev = make_vn(mount_cmd);
1345        mr_free(mount_cmd);
1346
1347        mr_asprintf(mount_cmd, "mount_cd9660 -r %s " MNT_CDROM, mddev);
1348#else
1349        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);
1350#endif
1351
1352    } else if (bkpinfo->backup_media_type == iso) {
1353        if (bkpinfo->subdir) {
1354            mr_asprintf(mountdir, "%s/%s", bkpinfo->isodir, bkpinfo->subdir);
1355        } else {
1356            mr_asprintf(mountdir, "%s", bkpinfo->isodir);
1357        }
1358#ifdef __FreeBSD__
1359        mr_asprintf(mount_cmd, "%s/%s-%d.iso", mountdir, bkpinfo->prefix, g_current_media_number);
1360        mddev = make_vn(mount_cmd);
1361        mr_free(mount_cmd);
1362
1363        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, MNT_CDROM);
1364#else
1365        mr_asprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s", mountdir, bkpinfo->prefix, g_current_media_number, MNT_CDROM);
1366#endif
1367        mr_free(mountdir);
1368    } else if (bkpinfo->backup_media_type == usb) {
1369        mr_asprintf(mount_cmd, "mount -t vfat %s %s", bkpinfo->media_device, MNT_CDROM);
1370    } else if (strstr(bkpinfo->media_device, "/dev/")) {
1371#ifdef __FreeBSD__
1372        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device, MNT_CDROM);
1373#else
1374        mr_asprintf(mount_cmd, "mount %s -t iso9660 -o ro %s", bkpinfo->media_device, MNT_CDROM);
1375#endif
1376    } else {
1377        if (bkpinfo->disaster_recovery
1378            && does_file_exist("/tmp/CDROM-LIVES-HERE")) {
1379            strcpy(bkpinfo->media_device,
1380                last_line_of_file("/tmp/CDROM-LIVES-HERE"));
1381        } else {
1382            find_cdrom_device(bkpinfo->media_device, TRUE);
1383        }
1384
1385#ifdef __FreeBSD__
1386        mr_asprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device, MNT_CDROM);
1387#else
1388        mr_asprintf(mount_cmd, "mount %s -t iso9660 -o ro %s", bkpinfo->media_device, MNT_CDROM);
1389#endif
1390    }
1391
1392    log_msg(2, "(mount_media) --- command = %s", mount_cmd);
1393    for (i = 0; i < 2; i++) {
1394        res = run_program_and_log_output(mount_cmd, FALSE);
1395        if (!res) {
1396            break;
1397        } else {
1398            log_msg(2, "Failed to mount device.");
1399            sleep(5);
1400            sync();
1401        }
1402    }
1403    mr_free(mount_cmd);
1404
1405    if (res) {
1406        log_msg(2, "Failed, despite %d attempts", i);
1407    } else {
1408        log_msg(2, "Mounted media drive OK");
1409    }
1410    return (res);
1411}
1412/**************************************************************************
1413*END_MOUNT_CDROM                                                         *
1414**************************************************************************/
1415
1416
1417
1418
1419/**
1420 * Ask the user for CD number @p cd_number_i_want.
1421 * Sets g_current_media_number once the correct CD is inserted.
1422 * @param bkpinfo The backup information structure. Fields used:
1423 * - @c bkpinfo->backup_media_type
1424 * - @c bkpinfo->prefix
1425 * - @c bkpinfo->isodir
1426 * - @c bkpinfo->media_device
1427 * - @c bkpinfo->please_dont_eject_when_restoring
1428 * @param cd_number_i_want The CD number to ask for.
1429 */
1430void
1431insist_on_this_cd_number(int cd_number_i_want)
1432{
1433
1434    /*@ int ************************************************************* */
1435    int res = 0;
1436
1437
1438    /*@ buffers ********************************************************* */
1439    char *tmp = NULL;
1440    char *mds = NULL;
1441    char *request = NULL;
1442
1443    assert(bkpinfo != NULL);
1444    assert(cd_number_i_want > 0);
1445
1446//  log_msg(3, "Insisting on CD number %d", cd_number_i_want);
1447
1448    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1449        log_msg(3,
1450                "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1451        return;
1452    }
1453    mr_asprintf(tmp, "mkdir -p " MNT_CDROM);
1454    run_program_and_log_output(tmp, 5);
1455    mr_free(tmp);
1456
1457    if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso || bkpinfo->backup_media_type == netfs) {
1458        g_ISO_restore_mode = TRUE;
1459    }
1460    if ((res = what_number_cd_is_this()) != cd_number_i_want) {
1461        log_msg(3, "Currently, we hold %d but we want %d", res, cd_number_i_want);
1462
1463        /* Now we need to umount the current media to have the next mounted after */
1464        run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
1465        log_msg(3, "Mounting next media %d",cd_number_i_want);
1466        g_current_media_number = cd_number_i_want;
1467        mount_media();
1468
1469        mds = media_descriptor_string(bkpinfo->backup_media_type);
1470        log_msg(3, "Insisting on %s #%d", mds, cd_number_i_want);
1471        mr_asprintf(request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want);
1472        mr_free(mds);
1473
1474        while (what_number_cd_is_this() != cd_number_i_want) {
1475            sync();
1476            if (is_this_device_mounted(MNT_CDROM)) {
1477                res =
1478                    run_program_and_log_output("umount -d " MNT_CDROM, FALSE);
1479            } else {
1480                res = 0;
1481            }
1482            if (res) {
1483                log_to_screen("WARNING - failed to unmount CD-ROM drive");
1484            }
1485            if (!bkpinfo->please_dont_eject) {
1486                res = eject_device(bkpinfo->media_device);
1487            } else {
1488                res = 0;
1489            }
1490            if (res) {
1491                log_to_screen("WARNING - failed to eject CD-ROM disk");
1492            }
1493            popup_and_OK(request);
1494            if (!bkpinfo->please_dont_eject) {
1495                inject_device(bkpinfo->media_device);
1496            }
1497            sync();
1498        }
1499        mr_free(request);
1500
1501        log_msg(1, "Thankyou. Proceeding...");
1502        g_current_media_number = cd_number_i_want;
1503    }
1504}
1505
1506/* @} - end of deviceGroup */
1507
1508
1509
1510/**
1511 * Creates a singly linked list of all of the non-NETFS mounted file systems.
1512 * @param DSFptr A pointer  to the structure MOUNTED_FS_STRUCT used to hold
1513 * the list of mounted file systems.
1514 * @return None.
1515 */
1516static void add_mounted_fs_struct (MOUNTED_FS_STRUCT *DSFptr)
1517{
1518    assert (DSFptr);
1519    if (DSF_Head == NULL) {
1520        DSF_Head = DSFptr;
1521    } else {
1522        DSF_Tail->next = DSFptr;
1523    }
1524    DSFptr->next = NULL;
1525    DSF_Tail = DSFptr;
1526}
1527
1528/**
1529 * Find the structure, in the singly linked list of all of the non-NETFS
1530 * mounted file systems, that contains the specified device.
1531 * @param device The device to find
1532 * @return NULL if it didn't find the device, a pointer to the
1533 * structure if it did.
1534 */
1535static MOUNTED_FS_STRUCT *find_device_in_list (char *device)
1536{
1537    MOUNTED_FS_STRUCT *DSFptr = NULL;
1538
1539    DSFptr = DSF_Head;
1540    while (DSFptr != NULL) {
1541        if (!strcmp(DSFptr->device, device)) {
1542            break;
1543        }
1544        DSFptr = DSFptr->next;
1545    }
1546    return (DSFptr);
1547}
1548
1549/**
1550 * Find the structure, in the singly linked list of all of the non-NETFS
1551 * mounted file systems, that contains the specified mount point.
1552 * @param mount_point The mount point to find
1553 * @return NULL is it didn't find the mount point, a pointer to the
1554 * structure if it did.
1555 */
1556static MOUNTED_FS_STRUCT *find_mount_point_in_list (char *mount_point)
1557{
1558    MOUNTED_FS_STRUCT *DSFptr = NULL;
1559
1560    DSFptr = DSF_Head;
1561    while (DSFptr != NULL) {
1562        if (!strcmp(DSFptr->mount_point, mount_point)) {
1563            break;
1564        }
1565        DSFptr = DSFptr->next;
1566    }
1567    return (DSFptr);
1568}
1569
1570/**
1571 * Frees the memory for all of the structures on the linked list of
1572 * all of the non-NETFS mounted file systems.
1573 */
1574static void free_mounted_fs_list (void) {
1575    MOUNTED_FS_STRUCT *DSFptr = NULL;
1576    MOUNTED_FS_STRUCT *DSFnext = NULL;
1577 
1578    DSFptr = DSF_Head;
1579    while (DSFptr != NULL) {
1580        DSFnext = DSFptr->next;
1581        paranoid_free(DSFptr);
1582        DSFptr = DSFnext;
1583    }
1584    DSF_Head = NULL;
1585    DSF_Tail = NULL;
1586}
1587
1588
1589/**
1590 * Creates a linked list of all of the non-NETFS mounted file systems.
1591 * We use a linked list because we don't know how many  mounted file
1592 * there are (and there can be a lot).
1593 * @return 0 on success and greated than 0 on failure.
1594 */
1595static int create_list_of_non_NETFS_mounted_file_systems (void)
1596{
1597    int i = 0;
1598    int mount_cnt = 0;
1599    int lastpos = 0;
1600    char *mounted_file_system = NULL;
1601    char *command = NULL;
1602    char *token = NULL;
1603    char token_chars[] =" :\t\r\f\a\0";
1604    MOUNTED_FS_STRUCT *DSFptr = NULL;
1605
1606    free_mounted_fs_list();
1607    /********
1608    * Find the number of mounted file system entries and their respective mount points.
1609    * I can't return all of the entries as one string because it's length can be longer
1610    * than MAX_STR_LEN which is used in call_program_and_get_last_line_of_output().
1611    * So start looping and get the number of  mounted file systems and query them one by one.
1612    ********/
1613    /* Get the number of mounted file systems ((those that start with "/dev/" */
1614    mr_asprintf(command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $0}}'|wc -l");
1615    log_msg(5, "Running: %s", command);
1616    mr_asprintf(mounted_file_system, "%s", call_program_and_get_last_line_of_output(command));
1617    mr_free(command);
1618
1619    mount_cnt = atoi(mounted_file_system);
1620    log_msg (5, "mount_cnt: %d", mount_cnt);
1621    mr_free(mounted_file_system);
1622
1623    for (i=mount_cnt; i > 0; i--) {
1624        mr_asprintf(command, "mount 2>/dev/null | awk '{if($1 ~ \"^/dev/\"){print $1,$3}}'|head -n %d", i);
1625        log_msg(5, "Running: %s", command);
1626        mr_asprintf(mounted_file_system, "%s", call_program_and_get_last_line_of_output(command));
1627        mr_free(command);
1628
1629        log_msg (5, "mounted_file_system: %s", mounted_file_system);
1630        if ((token = mr_strtok(mounted_file_system, token_chars, &lastpos)) == NULL) {
1631            log_msg (4, "Could not get the list of mounted file systems");
1632            mr_free(mounted_file_system);
1633            mr_free(token);
1634            return (1);
1635        }
1636        if (token) {
1637            log_msg (5, "token: %s", token);
1638        }
1639        while (token != NULL) {
1640            log_msg (5, "token: %s", token);
1641            if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) {
1642                fatal_error ("Cannot allocate memory");
1643            }
1644            add_mounted_fs_struct(DSFptr);
1645            strcpy(DSFptr->device, token);
1646            mr_free(token);
1647            if ((token = mr_strtok(mounted_file_system, token_chars, &lastpos)) == NULL) {
1648                log_msg (5, "Ran out of entries on the mounted file systems list");
1649                mr_free(mounted_file_system);
1650                mr_free(token);
1651                return (1);
1652            }
1653            log_msg (5, "token: %s", token);
1654            strcpy(DSFptr->mount_point, token);
1655            mr_free(token);
1656            token = mr_strtok(mounted_file_system, token_chars, &lastpos); 
1657        }
1658        mr_free(mounted_file_system);
1659    }
1660    return (0);
1661}
1662
1663
1664
1665/**
1666 * Given a whole disk device special file, determine which mounted file systems
1667 * are on the dsf's partitions and which mounted file systems are not.
1668 * @param dsf The whole disk device special file.
1669 * @param included_dsf_list A char pointer used to hold the list of mount points
1670 * that are on the dsf. Memory for the array will be allocated within the function.
1671 * @param excluded_dsf_list A char pointer used to hold the list of mount points
1672 * that are not on the dsf. Memory for the array will be allocated within the function.
1673 * @return 0 on success, -1 if no device special file was passed in, -2 if a device
1674 * special file was passed in but it has no partitions on it, or 1 on failure
1675 */
1676static int get_dsf_mount_list (const char *dsf, char **included_dsf_list, char **excluded_dsf_list) {
1677    int i = 0;
1678    int c = 0;
1679    int lastpos = 0;
1680    char VG[MAX_STR_LEN];
1681    char *tmp = NULL;
1682    char *command = NULL;
1683    char *partition_list = NULL;
1684    char partitions[64][MAX_STR_LEN];
1685    char *mount_list = NULL;
1686    char *token = NULL;
1687    char *ndsf = NULL;
1688    char token_chars[] =" \t\r\f\a\0";
1689    MOUNTED_FS_STRUCT *DSFptr = NULL;
1690
1691    memset((char *)partitions, 0, sizeof(partitions));
1692
1693    log_msg(5, "dsf: %s", dsf);
1694
1695    /********
1696    * See if a device special file was passed in (i.e. it must start with /dev/
1697    ********/
1698    if (strncmp(dsf, "/dev/", 5)) {
1699        log_msg (4, "%s does not start with /dev/ and (probably) is not a  device special file", dsf);
1700        return (-1);
1701    }
1702    log_msg(4, "  %s looks like a device special file", dsf);
1703    /* Verify that the dsf exists */ 
1704    mr_asprintf(command, "ls -al %s 2>/dev/null | wc -l", dsf);
1705    log_msg(5, "  Executing: %s", command);
1706    mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1707    mr_free(command);
1708
1709    log_msg(5, "  Return value: %s", tmp);
1710    c = atoi(tmp);
1711    mr_free(tmp);
1712
1713    if (!c) {
1714        log_to_screen("Cannot find device special file %s", dsf);
1715        return (1);
1716    }
1717    log_msg(4, "  %s device special file exists", dsf);
1718
1719    /* Get a list of the mounted file systems */
1720    if (create_list_of_non_NETFS_mounted_file_systems()) {
1721        log_to_screen ("Could not get the list of mounted file systems");
1722        return (1);
1723    }
1724    log_msg (5, "Processing dsf: %s", dsf);
1725    /********
1726    * Get a list of the dsf's partitions. There could be no partitions on the disk
1727    * or a dsf of a partition was passed in (e.g. /dev/sda1 instead of /dev/sda).
1728    * Either way, it's an error.
1729    ********/
1730    mr_asprintf(command, "parted2fdisk -l %s 2>/dev/null|grep -E \"^/dev/\"|awk '{printf(\"%%s \", $1)}END{print \"\"}'", dsf);
1731    log_msg(5, "Executing: %s", command);
1732    mr_asprintf(partition_list, "%s", call_program_and_get_last_line_of_output(command));
1733    mr_free(command);
1734    log_msg(4, "Partition list for %s: %s", dsf, partition_list);
1735    if (!strlen(partition_list)) {
1736        /* There were no partitions on the disk */
1737        log_msg(4, "No partitions on device special file %s", dsf);
1738        log_msg(4, "I guess it's a partition itself");
1739        strcpy(partitions[0], dsf);
1740        ndsf = truncate_to_drive_name(dsf);
1741    } else {
1742        /* Fill the partition list */
1743        i = 0;
1744        lastpos = 0;
1745        while ((token = mr_strtok(partition_list, token_chars, &lastpos)) != NULL) {
1746            log_msg (4, "Found partition: %s", token);
1747            strcpy(partitions[i++], token);
1748            mr_free(token);
1749        }
1750        mr_asprintf(ndsf, "%s", dsf);
1751    }
1752    mr_free(partition_list);
1753
1754    /* In any case we want to exclude the dsf itself from all MondRescue activities
1755     * at restore time (LVM, fdisk, ...) so we want it in our exclude_dev list */
1756    if ((DSFptr = (MOUNTED_FS_STRUCT *) calloc(1, sizeof(MOUNTED_FS_STRUCT))) == NULL) {
1757        fatal_error ("Cannot allocate memory");
1758    }
1759    add_mounted_fs_struct(DSFptr);
1760    strcpy(DSFptr->device, dsf);
1761    DSFptr->check = 1;
1762
1763    /*  For the rest ndsf is the new dsf to deal with */
1764    /********
1765     * At this point, we have a list of all of the partitions on the dsf. Now try to
1766     * see which partitions have a file system on them.
1767     *
1768     * Loop through each partition on the disk and:
1769     *
1770     * - If the partition is swap, it ignores it.
1771     *
1772     * - If the partition is mounted (e.g. /dev/sda1 is mounted on /boot), it adds an entry
1773     *  to the linked list, copies to it the device name and mount point, and sets check == 1.
1774     *
1775     * - If the partition is part of a Volume Group that has Logical Volumes mounted, it adds
1776     *  an entry to the linked list for each mounted Logical Volume in that Volume Group, copying
1777     *  to it the device name and mount point, and sets check == 1. Note that if the Volume Group
1778     *  contains more than one disk, it will still add the entry even if the Logical Volume's
1779     *  extents are not on the dsf that was passed in to the function. For example, Volume Group
1780     *  VolGroup00 contains the disks /dev/sda1 and /dev/sdb1, and the Logical Volumes LogVol01,
1781     *  which is mounted on /var and has all of its extents on /dev/sda1, and LogVol02, which is
1782     *  mounted as /usr and has all of its extents on /dev/sdb1. If you pass /dev/sda into the
1783     *  function, both /var and /usr will be archived even though /usr is actually on/dev/sdb.
1784     *
1785     * - If the partition is part of a Volume Group that has Logical Volumes used in a mounted
1786     *  software raid device, it adds an entry to the linked list, copies to it the software raid
1787     *  device name and mount point, and sets check == 1.
1788     *
1789     * - If the partition is part of a mounted software raid device, it adds an entry to the linked
1790     *  list, copies to it the software raid device name and mount point, and sets check == 1.
1791     *
1792     ********/
1793    for (i=0; strlen(partitions[i]); i++) {
1794        log_msg(4, "Processing partition: %s", partitions[i]);
1795        /* See if it's swap. If it is, ignore it. */
1796        mr_asprintf(command, "parted2fdisk -l %s 2>/dev/null | awk '{if(($1==\"%s\")&&(toupper($0) ~ \"SWAP\")){print $1;exit}}'", ndsf, partitions[i]);
1797        log_msg(5, "  Running: %s", command);
1798        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1799        mr_free(command);
1800
1801        log_msg(5, "  Return value: %s", tmp);
1802        c = strlen(tmp);
1803        mr_free(tmp);
1804
1805        if (c) {
1806            log_msg(4, "It's swap. Ignoring partition %s", partitions[i]); 
1807            continue;
1808        } 
1809
1810        /* It's not swap. See if we can find the mount point from the mount command. */
1811        mr_asprintf(command, "mount 2>/dev/null | awk '{if((NF>0)&&($1==\"%s\")){print $3}}'", partitions[i]);
1812        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1813        mr_free(command);
1814
1815        if (strlen(tmp)) {
1816            log_msg(4, "  %s is mounted: %s", partitions[i], tmp);
1817            if ((DSFptr = find_mount_point_in_list(tmp)) == NULL) {
1818                log_msg (4, "Can't find mount point %s in mounted file systems list", tmp);
1819                mr_free(tmp);
1820                return (1);
1821            }
1822            DSFptr->check = 1;
1823            mr_free(tmp);
1824            continue;
1825        }
1826        mr_free(tmp);
1827
1828        /* It's not swap and it's not mounted. See if it's LVM */
1829        log_msg(4, "  It's not mounted. Checking to see if it's LVM...");
1830
1831        /* Check for LVM */
1832        mr_asprintf(command, "pvdisplay -c %s 2> /dev/null", partitions[i]);
1833        log_msg(5, "  Running: %s", command);
1834        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1835        mr_free(command);
1836
1837        if (strlen(tmp)) {
1838            log_msg(4, "Found an LVM partition at %s. Find the VG it's in...", partitions[i]);
1839            /* It's LVM: Find the VG it's in */
1840            mr_asprintf(command, "pvdisplay -v %s 2>/dev/null|grep \"VG Name\"|awk '{print $NF}'", partitions[i]);
1841            log_msg(5, "  Running: %s", command);
1842            strcpy(VG, call_program_and_get_last_line_of_output(command));
1843            mr_free(command);
1844
1845            log_msg(4, "  Volume Group: %s", VG);
1846            if (strlen(VG)) {
1847                /* Found the Volume Group. Now find all of the VG's mount points */
1848                log_msg(4, "  Found the Volume Group. Now find all of the VG's mount points");
1849                mr_asprintf(command, "mount 2>/dev/null|grep -E \"/dev/mapper/%s|/dev/%s/\"|awk '{printf(\"%%s \",$3)}END{print \"\"}'", VG, VG);
1850                log_msg(5, "  Running: %s", command);
1851                mr_asprintf(mount_list, "%s", call_program_and_get_last_line_of_output(command));
1852                mr_free(command);
1853
1854                log_msg(4, "  VG %s mount_list: %s", VG, mount_list);
1855                lastpos = 0;
1856                while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1857                    log_msg (5, "mount point token: %s", token);
1858                    if ((DSFptr = find_mount_point_in_list(token)) == NULL) {
1859                        log_msg (4, "Can't find mount point %s in mounted file systems list", token);
1860                        mr_free(tmp);
1861                        mr_free(token);
1862                        return (1);
1863                    }
1864                    DSFptr->check = 1;
1865                    mr_free(token);
1866                }
1867                /********
1868                 * Now we want to see if there are any software raid devices using
1869                 * any of the Logical Volumes on the Volume Group.
1870                 *******/
1871                mr_free(mount_list);
1872
1873                mr_asprintf(command, "%s", "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'");
1874                log_msg (5, "Running: %s", command);
1875                mr_asprintf(mount_list, "%s", call_program_and_get_last_line_of_output(command));
1876                mr_free(command);
1877                log_msg(4, "  Software raid device list: %s", mount_list);
1878                lastpos = 0;
1879                while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1880                    mr_asprintf(command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, VG);
1881                    log_msg (5, "Running: %s", command);
1882                    mr_free(tmp);
1883                    mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1884                    mr_free(command);
1885                    log_msg(4, "Number of Software raid device: %s", tmp);
1886                    if (atoi(tmp)) {
1887                        /* This device is on our disk */
1888                        if ((DSFptr = find_device_in_list(token)) == NULL) {
1889                            log_msg (4, "Can't find device %s in mounted file systems list", token);
1890                            mr_free(tmp);
1891                            mr_free(token);
1892                            return (1);
1893                        }
1894                        DSFptr->check = 1;
1895                    }
1896                }
1897                mr_free(token);
1898                paranoid_free(mount_list);
1899            } else {
1900                log_msg (4, "Error finding Volume Group for partition %s", partitions[i]);
1901                mr_free(tmp);
1902                return (1);
1903            }
1904            mr_free(tmp);
1905            continue;
1906        } else {
1907            log_msg (4, "Error finding partition type for the partition %s", partitions[i]);
1908        }
1909        mr_free(tmp);
1910
1911        /********
1912         * It's not swap, mounted, or LVM. See if it's used in a software raid device.
1913         ********/
1914        log_msg (5, "It's not swap, mounted, or LVM. See if it's used in a software raid device.");
1915        mr_asprintf(command, "mdadm --examine %s 2>/dev/null | awk '{if($1 == \"UUID\"){print $3}}'", partitions[i]);
1916        log_msg(4, "  Running: %s", command);
1917        mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1918        mr_free(command);
1919
1920        if (!strlen(tmp)) {
1921            log_msg(4, "  Partition %s is not used in a non-LVM software raid device", partitions[i]);
1922            mr_free(tmp);
1923            continue;
1924        }
1925        log_msg (5, "  UUID: %s", tmp);
1926
1927        /* Get the Software raid device list */
1928        mr_asprintf(command, "%s", "cat /proc/mdstat|grep -iv Personal|awk '{if($0~\"^.*[ ]+:\"){printf(\"/dev/%s \", $1)}}END{print \"\"}'");
1929        log_msg (5, "  Running: %s", command);
1930        mr_asprintf(mount_list, "%s", call_program_and_get_last_line_of_output(command));
1931        mr_free(command);
1932
1933        log_msg(4, "  Software raid device list: %s", mount_list);
1934        /* Loop through the software raid device list to see if we can find the partition */
1935        lastpos = 0;
1936        while ((token = mr_strtok(mount_list, token_chars, &lastpos)) != NULL) {
1937            mr_asprintf(command, "mdadm --detail %s 2>/dev/null | grep -c %s", token, tmp);
1938            log_msg(4, "  Running: %s", command);
1939            mr_free(tmp);
1940            mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
1941            mr_free(command);
1942
1943            if (!atoi(tmp)) {
1944                log_msg (4,"  Didn't find partition %s in software raid device %s", partitions[i], token);
1945            } else {
1946                if ((DSFptr = find_device_in_list(token)) == NULL) {
1947                    log_msg (4, "Can't find device %s in mounted file systems list", token);
1948                    mr_free(tmp);
1949                    mr_free(token);
1950                    return (1);
1951                }
1952                DSFptr->check = 1;
1953                break;
1954            }
1955            mr_free(token);
1956        }
1957        mr_free(tmp);
1958        mr_free(mount_list);
1959    }
1960
1961    /* Determine how much memory to allocate for included_dsf_list and excluded_dsf_list */
1962    i = 0;
1963    DSFptr= DSF_Head;
1964    while (DSFptr != NULL) {
1965        i += strlen(DSFptr->mount_point) + 1;
1966        DSFptr = DSFptr->next;
1967    }
1968    log_msg (5, "i: %d", i);
1969    if ((*included_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) {
1970        fatal_error ("Cannot allocate memory");
1971    }
1972    if ((*excluded_dsf_list = (char *) calloc(i+100, sizeof(char))) == NULL) {
1973        fatal_error ("Cannot allocate memory");
1974    }
1975    DSFptr= DSF_Head;
1976    while (DSFptr != NULL) {
1977        if (DSFptr->check) {
1978            log_msg (4, "%s is mounted on %s and is on disk %s", DSFptr->device, DSFptr->mount_point, ndsf);
1979            strcat(*included_dsf_list, DSFptr->mount_point);
1980            strcat(*included_dsf_list, "|");
1981        } else {
1982            log_msg (4, "%s is mounted on %s and is NOT on disk %s", DSFptr->device, DSFptr->mount_point, ndsf);
1983            strcat(*excluded_dsf_list, DSFptr->mount_point);
1984            strcat(*excluded_dsf_list, "|");
1985        }
1986        DSFptr = DSFptr->next;
1987    }
1988    mr_free(ndsf);
1989
1990    log_msg (5, "included_dsf_list: %s", *included_dsf_list);
1991    log_msg (5, "excluded_dsf_list: %s", *excluded_dsf_list);
1992    return (0);
1993}
1994
1995
1996/* Update the bkpinfo structure for exclude & include paths
1997 * in order to handle correctly paths corresponding to devices */
1998void mr_make_devlist_from_pathlist(char *pathlist, char mode) {
1999
2000char *token = NULL;
2001int lastpos = 0;
2002char *mounted_on_dsf = NULL;
2003char *not_mounted_on_dsf = NULL;
2004char token_chars[] ="|\t\r\f\a\0\n";
2005char *tmp = NULL;
2006char *tmp1 = NULL;
2007char *tmp2 = NULL;
2008
2009if (pathlist == NULL) {
2010    return;
2011}
2012while ((token = mr_strtok(pathlist, token_chars, &lastpos)) != NULL) {
2013    switch (get_dsf_mount_list(token, &mounted_on_dsf, &not_mounted_on_dsf)) {
2014    case 1: 
2015        if (mode == 'E') {
2016            log_msg(1, "WARNING ! %s doesn't exist in -E option", token);
2017        } else {
2018            log_msg(1, "ERROR ! %s doesn't exist in -I option", token);
2019            fatal_error("Error processing -I option");
2020        }
2021        break;
2022    /* Everything is OK; proceed to archive data */
2023    case 0:
2024        if (mode == 'E') {
2025            if (strlen(mounted_on_dsf)) {
2026                log_to_screen("Excluding the following file systems on %s:", token);
2027                log_to_screen("==> %s", mounted_on_dsf);
2028                log_msg (5, "Adding to bkpinfo->exclude_paths due to -E option: %s", mounted_on_dsf);
2029                if (bkpinfo->exclude_paths) {
2030                    mr_strcat(bkpinfo->exclude_paths,"|%s",mounted_on_dsf);
2031                } else {
2032                    mr_asprintf(bkpinfo->exclude_paths,"%s",mounted_on_dsf);
2033                }
2034                if (bkpinfo->exclude_devs) {
2035                    mr_strcat(bkpinfo->exclude_devs,"|%s",token);
2036                } else {
2037                    mr_asprintf(bkpinfo->exclude_devs,"%s",token);
2038                }
2039            }
2040        } else {
2041            log_to_screen("Archiving only the following file systems on %s:", token);
2042            log_to_screen("==> %s", mounted_on_dsf);
2043            mr_free(bkpinfo->include_paths);
2044            mr_asprintf(bkpinfo->include_paths, "%s", "/");
2045            if (strlen(not_mounted_on_dsf)) {
2046                log_msg (5, "Adding to bkpinfo->exclude_paths due to -I option: %s", not_mounted_on_dsf);
2047                log_to_screen("Not archiving the following file systems:");
2048                log_to_screen("==> %s", not_mounted_on_dsf);
2049                if (bkpinfo->exclude_paths) {
2050                    mr_strcat(bkpinfo->exclude_paths, "|%s",not_mounted_on_dsf);
2051                } else {
2052                    mr_asprintf(bkpinfo->exclude_paths,"%s",not_mounted_on_dsf);
2053                }
2054            }
2055        }
2056        break;
2057    /* It's a dsf but not a whole disk dsf */
2058    case -2:
2059        log_to_screen("Could %s be a partition instead of a whole disk device special file?\nIgnored.", token);
2060        break;
2061    /* A device special file was not passed in. Process it as a path. */
2062    case -1:
2063        /*  Adds a | to ensure correct detection even at both ends */
2064        mr_asprintf(tmp1,"|%s",token);
2065        mr_asprintf(tmp2,"|%s|",token);
2066        if (mode == 'E') {
2067            /*  Add the token if not already in the list */
2068            mr_asprintf(tmp,"|%s|",bkpinfo->exclude_paths);
2069            if (strstr(tmp,tmp2) == NULL) {
2070                if (bkpinfo->exclude_paths) {
2071                    mr_strcat(bkpinfo->exclude_paths,tmp1);
2072                    mr_free(tmp1);
2073                } else {
2074                    bkpinfo->exclude_paths = tmp1;
2075                }
2076            }
2077        } else {
2078            /*  Add the token if not already in the list */
2079            mr_asprintf(tmp,"|%s|",bkpinfo->include_paths);
2080            if (strstr(tmp,tmp2) == NULL) {
2081                mr_strcat(bkpinfo->include_paths, "%s", tmp1);
2082            }
2083            mr_free(tmp1);
2084        }
2085        mr_free(tmp);
2086        mr_free(tmp2);
2087        break;
2088    }
2089    mr_free(token);
2090
2091    if (bkpinfo->include_paths != NULL) {
2092        log_msg(1, "include_paths is now '%s'", bkpinfo->include_paths);
2093    }
2094    if (bkpinfo->exclude_paths != NULL) {
2095        log_msg(1, "exclude_paths is now '%s'", bkpinfo->exclude_paths);
2096    }
2097    if (bkpinfo->exclude_devs != NULL) {
2098        log_msg(1, "exclude_devs is now '%s'", bkpinfo->exclude_devs);
2099    }
2100}
2101}
2102
2103
2104
2105
2106/**
2107 * Ask user for details of backup/restore information.
2108 * Called when @c mondoarchive doesn't get any parameters.
2109 * @param bkpinfo The backup information structure to fill out with the user's data.
2110 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
2111 * @return 0, always.
2112 * @bug No point of `int' return value.
2113 * @ingroup archiveGroup
2114 */
2115int interactively_obtain_media_parameters_from_user(bool archiving_to_media)
2116// archiving_to_media is TRUE if I'm being called by mondoarchive
2117// archiving_to_media is FALSE if I'm being called by mondorestore
2118{
2119    char *tmp = NULL;
2120    char *sz = NULL;
2121    char *tmpro = NULL;
2122    char *tmp1 = NULL;
2123    char *mds = NULL;
2124    char *q = NULL;
2125    char p[16*MAX_STR_LEN];
2126    char *sz_size = NULL;
2127    char *command = NULL;
2128    char *compression_type = NULL;
2129    char *comment = NULL;
2130    int i;
2131    FILE *fin;
2132
2133    malloc_string(tmp1);
2134    assert(bkpinfo != NULL);
2135    bkpinfo->nonbootable_backup = FALSE;
2136
2137    // Tape, CD, NETFS, ...?
2138    srandom(getpid());
2139    bkpinfo->backup_media_type =
2140        (g_restoring_live_from_cd) ? cdr :
2141        which_backup_media_type(bkpinfo->restore_data);
2142    if (bkpinfo->backup_media_type == none) {
2143        log_to_screen("User has chosen not to backup the PC");
2144        finish(1);
2145    }
2146    /* Why asking to remove the media with tape ?
2147    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
2148        popup_and_OK("Please remove media from drive(s)");
2149    }
2150    */
2151    if (archiving_to_media) {
2152        setup_tmpdir(NULL);
2153        /*
2154         * Set the scratchdir to reside on the partition with the most free space.
2155         * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2156         */
2157#ifdef __FreeBSD__
2158        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"));
2159#else
2160        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"));
2161#endif
2162
2163        if (tmp[0] != '/') {
2164            mr_asprintf(sz, "%s", tmp);
2165            mr_free(tmp);
2166            mr_asprintf(tmp, "/%s", sz);
2167            mr_free(sz);
2168        }
2169        setup_scratchdir(tmp);
2170    }
2171    log_msg(3, "media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
2172    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
2173    bkpinfo->compression_level = (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
2174    bkpinfo->use_lzo = (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
2175    mvaddstr_and_log_it(2, 0, " ");
2176
2177    // Find device's /dev (or SCSI) entry
2178    switch (bkpinfo->backup_media_type) {
2179    case cdr:
2180    case cdrw:
2181    case dvd:
2182    case usb:
2183        /* Never try to eject a USB device */
2184        if (bkpinfo->backup_media_type == usb) {
2185            bkpinfo->please_dont_eject = TRUE;
2186        }
2187        if (archiving_to_media) {
2188            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2189                if (ask_me_yes_or_no("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?")) {
2190                    bkpinfo->manual_cd_tray = TRUE;
2191                }
2192            }
2193            if ((compression_type = which_compression_type()) == NULL) {
2194                log_to_screen("User has chosen not to backup the PC");
2195                finish(1);
2196            }
2197
2198            if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2199                log_to_screen("User has chosen not to backup the PC");
2200                finish(1);
2201            }
2202            mds = media_descriptor_string(bkpinfo->backup_media_type);
2203            mr_asprintf(comment, "What speed is your %s (re)writer?", mds);
2204            if (bkpinfo->backup_media_type == dvd) {
2205                find_dvd_device(bkpinfo->media_device, FALSE);
2206                strcpy(tmp1, "1");
2207                mr_asprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2208                log_msg(1, "Setting to DVD defaults");
2209            } else {
2210                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
2211                strcpy(tmp1, "4");
2212                mr_asprintf(sz_size, "%d", 650);
2213                log_msg(1, "Setting to CD defaults");
2214            }
2215            if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
2216                if (!popup_and_get_string("Speed", comment, tmp1, 4)) {
2217                    log_to_screen("User has chosen not to backup the PC");
2218                    mr_free(comment);
2219                    finish(1);
2220                }
2221            }
2222            mr_free(comment);
2223            bkpinfo->cdrw_speed = atoi(tmp1);   // if DVD then this shouldn't ever be used anyway :)
2224
2225            strcpy(tmp1, sz_size);
2226            mr_asprintf(comment, "How much data (in Megabytes) will each %s store?", mds);
2227            mr_free(mds);
2228            if (!popup_and_get_string("Size", comment, tmp1, 5)) {
2229                log_to_screen("User has chosen not to backup the PC");
2230                finish(1);
2231            }
2232            mr_asprintf(sz_size, "%s", tmp1);
2233            bkpinfo->media_size = atoi(sz_size);
2234
2235            if (bkpinfo->media_size <= 0) {
2236                log_to_screen("User has chosen not to backup the PC");
2237                finish(1);
2238            }
2239        }
2240        /* No break because we continue even for usb */
2241    case cdstream:
2242        mds = media_descriptor_string(bkpinfo->backup_media_type);
2243
2244        if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
2245            strcpy(bkpinfo->media_device, "/dev/cdrom");
2246            log_msg(2, "CD-ROM device assumed to be at %s", bkpinfo->media_device);
2247        } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))  || bkpinfo->backup_media_type == dvd) {
2248            if (!bkpinfo->media_device[0]) {
2249                strcpy(bkpinfo->media_device, "/dev/cdrom");
2250            }                   // just for the heck of it :)
2251            log_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device);
2252            if (bkpinfo->backup_media_type == dvd || find_cdrom_device(bkpinfo->media_device, FALSE)) {
2253                log_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device);
2254                mr_asprintf(comment, "Please specify your %s drive's /dev entry", mds);
2255                if (!popup_and_get_string("Device?", comment, bkpinfo->media_device, MAX_STR_LEN / 4)) {
2256                    log_to_screen("User has chosen not to backup the PC");
2257                    finish(1);
2258                }
2259            }
2260            log_msg(2, "%s device found at %s", mds, bkpinfo->media_device);
2261        } else {
2262            if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) {
2263                bkpinfo->media_device[0] = '\0';
2264            }
2265            if (bkpinfo->media_device[0]) {
2266                if (bkpinfo->backup_media_type == usb) {
2267                    mr_asprintf(tmp, "I think your %s media corresponds to %s. Is this correct?", mds, bkpinfo->media_device);
2268                } else {
2269                    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);
2270                }
2271                if (!ask_me_yes_or_no(tmp)) {
2272                    bkpinfo->media_device[0] = '\0';
2273                }
2274                mr_free(tmp);
2275            }
2276            if (!bkpinfo->media_device[0]) {
2277                if (bkpinfo->backup_media_type == usb) {
2278                    i = popup_and_get_string("/dev entry?",
2279                                         "What is the /dev entry of your USB Disk/Key, please?",
2280                                         bkpinfo->media_device,
2281                                         MAX_STR_LEN / 4);
2282                } else {
2283                    if (g_kernel_version < 2.6) {
2284                        i = popup_and_get_string("Device node?",
2285                                             "What is the SCSI node of your CD (re)writer, please?",
2286                                             bkpinfo->media_device,
2287                                             MAX_STR_LEN / 4);
2288                    } else {
2289                        i = popup_and_get_string("/dev entry?",
2290                                             "What is the /dev entry of your CD (re)writer, please?",
2291                                             bkpinfo->media_device,
2292                                             MAX_STR_LEN / 4);
2293                    }
2294                }
2295                if (!i) {
2296                    log_to_screen("User has chosen not to backup the PC");
2297                    finish(1);
2298                }
2299            }
2300        }
2301        mr_free(mds);
2302
2303        if (bkpinfo->backup_media_type == cdstream) {
2304            bkpinfo->media_size = 650;
2305        }
2306        break;
2307    case udev:
2308        if (!ask_me_yes_or_no
2309            ("This option is for advanced users only. Are you sure?")) {
2310            log_to_screen("User has chosen not to backup the PC");
2311            finish(1);
2312        }
2313    case tape:
2314
2315        if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) {
2316            log_msg(3, "Ok, using vanilla scsi tape.");
2317            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
2318            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2319                paranoid_fclose(fin);
2320            } else {
2321                strcpy(bkpinfo->media_device, "/dev/osst0");
2322            }
2323        }
2324        if (bkpinfo->media_device[0]) {
2325            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2326                paranoid_fclose(fin);
2327            } else {
2328                if (does_file_exist("/tmp/mondo-restore.cfg")) {
2329                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev", bkpinfo->media_device);
2330                }
2331            }
2332        }
2333        if (bkpinfo->media_device[0]) {
2334            mr_asprintf(tmp, "I think I've found your tape streamer at %s; am I right on the money?", bkpinfo->media_device);
2335            if (!ask_me_yes_or_no(tmp)) {
2336                bkpinfo->media_device[0] = '\0';
2337            }
2338            mr_free(tmp);
2339        }
2340        if (!bkpinfo->media_device[0]) {
2341            if (!popup_and_get_string
2342                ("Device name?",
2343                 "What is the /dev entry of your tape streamer?",
2344                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
2345                log_to_screen("User has chosen not to backup the PC");
2346                finish(1);
2347            }
2348        }
2349        mr_asprintf(tmp, "ls -l %s", bkpinfo->media_device);
2350        if (run_program_and_log_output(tmp, FALSE)) {
2351            log_to_screen("User has not specified a valid /dev entry");
2352            finish(1);
2353        }
2354        mr_free(tmp);
2355
2356        if (!popup_and_get_string
2357            ("Tape block size?",
2358             "What is the block size of your tape streamer?",
2359             sz_size, 15)) {
2360            log_to_screen("User has chosen not to backup the PC");
2361            finish(1);
2362        }
2363        bkpinfo->internal_tape_block_size = atol(sz_size);
2364        if (bkpinfo->internal_tape_block_size <= 0) {
2365            log_to_screen("User has chosen not to backup the PC");
2366            finish(1);
2367        }
2368
2369        bkpinfo->media_size = 0;
2370        log_msg(4, "media_size = %ld", bkpinfo->media_size);
2371
2372        bkpinfo->use_obdr = ask_me_yes_or_no
2373            ("Do you want to activate OBDR support for your tapes ?");
2374        if (bkpinfo->use_obdr) {
2375            log_msg(4, "obdr mode = TRUE");
2376        } else {
2377            log_msg(4, "obdr mode = FALSE");
2378        }
2379        if (archiving_to_media) {
2380            if ((compression_type = which_compression_type()) == NULL) {
2381                log_to_screen("User has chosen not to backup the PC");
2382                finish(1);
2383            }
2384            if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2385                log_to_screen("User has chosen not to backup the PC");
2386                finish(1);
2387            }
2388        }
2389        break;
2390
2391
2392
2393    case netfs:
2394        /* Never try to eject a NETFS device */
2395        bkpinfo->please_dont_eject = TRUE;
2396        /*  Force NFS to be the protocol by default */
2397        if (bkpinfo->netfs_proto == NULL) {
2398            mr_asprintf(bkpinfo->netfs_proto, "nfs");
2399        }
2400
2401        /* Initiate bkpinfo netfs_mount path from running environment if not already done */
2402        if (!bkpinfo->netfs_mount == NULL) {
2403            mr_asprintf(bkpinfo->netfs_mount, call_program_and_get_last_line_of_output("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
2404        }
2405#ifdef __FreeBSD__
2406        if (TRUE)
2407#else
2408        if (!bkpinfo->disaster_recovery)
2409#endif
2410        {
2411            if (!popup_and_get_string
2412                ("Network shared dir.",
2413                 "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.)",
2414                 p, MAX_STR_LEN / 4)) {
2415                log_to_screen("User has chosen not to backup the PC");
2416                finish(1);
2417            }
2418            mr_free(bkpinfo->netfs_mount);
2419            mr_asprintf(bkpinfo->netfs_mount, "%s", p;
2420            if (!bkpinfo->restore_data) {
2421                if ((compression_type = which_compression_type()) == NULL) {
2422                    log_to_screen("User has chosen not to backup the PC");
2423                    finish(1);
2424                }
2425
2426                if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2427                    log_to_screen("User has chosen not to backup the PC");
2428                    finish(1);
2429                }
2430            }
2431            // check whether already mounted - we better remove
2432            // surrounding spaces and trailing '/' for this
2433            mr_strip_spaces(bkpinfo->netfs_mount);
2434            if (bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] == '/')
2435                bkpinfo->netfs_mount[strlen(bkpinfo->netfs_mount) - 1] = '\0';
2436            q = strchr(bkpinfo->netfs_mount, '@');
2437            if (q != NULL) {
2438                /* User found. Store the 2 values */
2439                q++;
2440                /* new netfs mount */
2441                strcpy(tmp1,q);
2442            } else {
2443                strcpy(tmp1,bkpinfo->netfs_mount);
2444            }
2445            mr_asprintf(command, "mount | grep \"%s \" | cut -d' ' -f3", tmp1);
2446            strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output(command));
2447            mr_free(command);
2448
2449            if (!bkpinfo->restore_data) {
2450                mr_sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);   // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2451                mr_asprintf(comment, "How much data (in Megabytes) will each media store?");
2452                strcpy(tmp1, sz_size);
2453                mr_free(sz_size);
2454                if (!popup_and_get_string("Size", comment, tmp1, 5)) {
2455                    log_to_screen("User has chosen not to backup the PC");
2456                    finish(1);
2457                }
2458                mr_free(comment);
2459                mr_asprintf(sz_size, "%s", tmp1);
2460            } else {
2461                mr_asprintf(sz_size, "0");
2462            }
2463            bkpinfo->media_size = atoi(sz_size);
2464            mr_free(sz_size);
2465
2466            if (bkpinfo->media_size < 0) {
2467                log_to_screen("User has chosen not to backup the PC");
2468                finish(1);
2469            }
2470        }
2471        if (bkpinfo->disaster_recovery) {
2472            mr_asprintf(command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
2473            paranoid_system(command);
2474            mr_free(command);
2475
2476        }
2477        strcpy(tmp1, bkpinfo->netfs_proto);
2478        if (!popup_and_get_string("Network protocol", "Which protocol should I use (nfs/sshfs/smbfs) ?",tmp1, MAX_STR_LEN)) {
2479            log_to_screen("User has chosen not to backup the PC");
2480            finish(1);
2481        }
2482        mr_free(bkpinfo->netfs_proto);
2483        mr_asprintf(bkpinfo->netfs_proto, "%s", tmp1);
2484
2485        strcpy(tmp1, bkpinfo->netfs_mount);
2486        if (!popup_and_get_string("Network share", "Which remote share should I mount?", tmp1, MAX_STR_LEN)) {
2487            log_to_screen("User has chosen not to backup the PC");
2488            finish(1);
2489        }
2490        mr_free(bkpinfo->netfs_mount);
2491        mr_asprintf(bkpinfo->netfs_mount, "%s", tmp1);
2492
2493        if (bkpinfo->netfs_user) {
2494            strcpy(tmp1, bkpinfo->netfs_user);
2495        } else {
2496            strcpy(tmp1, "");
2497        }
2498        if (!popup_and_get_string("Network user", "Which user should I use if any ?",tmp1)) {
2499            log_to_screen("User has chosen not to backup the PC");
2500            finish(1);
2501        }
2502        mr_free(bkpinfo->netfs_user);
2503        if (strcmp(tmp1, "") != 0) {
2504            mr_asprintf(bkpinfo->netfs_user, "%s", tmp1);
2505        }
2506   
2507        /* Initiate bkpinfo isodir path from running environment if mount already done */
2508        if (is_this_device_mounted(bkpinfo->netfs_mount)) {
2509            strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
2510        } else {
2511            sprintf(bkpinfo->isodir, "%s/netfsdir", bkpinfo->tmpdir);
2512            mr_asprintf(command, "mkdir -p %s", bkpinfo->isodir);
2513            run_program_and_log_output(command, 5);
2514            mr_free(command);
2515
2516            if (bkpinfo->restore_data) {
2517                /*  mount th FS read-only in restore mode to avoid any erase of whatever */
2518                mr_asprintf(tmpro, "-o ro");
2519            } else {
2520                mr_asprintf(tmpro, "");
2521            }
2522
2523            /*  Build the mount string */
2524            if (strstr(bkpinfo->netfs_proto, "smbfs")) {
2525                mr_asprintf(tmp, "mount -t cifs %s %s %s",bkpinfo->netfs_mount, bkpinfo->isodir,tmpro);
2526                if (bkpinfo->netfs_user) {
2527                    mr_strcat(tmp, " -o user=%s", bkpinfo->netfs_user);
2528                }
2529            else {
2530                if (strstr(bkpinfo->netfs_proto, "sshfs")) {
2531                    mr_asprintf(tmp, "sshfs %s ",tmpro);
2532                } else {
2533                    mr_asprintf(tmp, "mount -t %s -o nolock %s ", bkpinfo->netfs_proto,tmpro);
2534                }
2535                if (bkpinfo->netfs_user) {
2536                    mr_strcat(tmp, "%s@", bkpinfo->netfs_user);
2537                }
2538                mr_strcat(tmp, "%s %s", bkpinfo->netfs_mount, bkpinfo->isodir);
2539            }
2540            run_program_and_log_output(tmp, 3);
2541            mr_free(tmp);
2542
2543            malloc_string(g_selfmounted_isodir);
2544            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
2545            }
2546        }
2547        if (!is_this_device_mounted(bkpinfo->netfs_mount)) {
2548            popup_and_OK("Please mount that partition before you try to backup to or restore from it.");
2549            finish(1);
2550        }
2551        strcpy(tmp1, bkpinfo->netfs_remote_dir);
2552        if (!popup_and_get_string
2553            ("Directory", "Which directory within that mountpoint?", tmp1,
2554             MAX_STR_LEN)) {
2555            log_to_screen("User has chosen not to backup the PC");
2556            finish(1);
2557        }
2558        strcpy(bkpinfo->netfs_remote_dir, tmp1);
2559
2560        // check whether writable - we better remove surrounding spaces for this
2561        strip_spaces(bkpinfo->netfs_remote_dir);
2562
2563        if (!popup_and_get_string
2564            ("Prefix.",
2565             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2566            bkpinfo->prefix, MAX_STR_LEN / 4)) {
2567            log_to_screen("User has chosen not to backup the PC");
2568            finish(1);
2569        }
2570        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2571
2572        log_msg(3, "Just set netfs_remote_dir to %s", bkpinfo->netfs_remote_dir);
2573        log_msg(3, "isodir is still %s", bkpinfo->isodir);
2574        break;
2575
2576    case iso:
2577        if (!bkpinfo->disaster_recovery) {
2578            if (!popup_and_get_string
2579                ("Storage dir.",
2580                 "Please enter the full path name to the directory for your ISO images.  Example: /mnt/raid0_0",
2581                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
2582                log_to_screen("User has chosen not to backup the PC");
2583                finish(1);
2584            }
2585            if (archiving_to_media) {
2586                if ((compression_type = which_compression_type()) == NULL) {
2587                    log_to_screen("User has chosen not to backup the PC");
2588                    finish(1);
2589                }
2590                if ((bkpinfo->compression_level = which_compression_level()) == -1) {
2591                    log_to_screen("User has chosen not to backup the PC");
2592                    finish(1);
2593                }
2594                sprintf(tmp1, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4482 MB
2595                if (!popup_and_get_string
2596                    ("ISO size.",
2597                     "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.",
2598                     tmp1, 16)) {
2599                    log_to_screen("User has chosen not to backup the PC");
2600                    finish(1);
2601                }
2602                bkpinfo->media_size = atoi(tmp1);
2603            } else {
2604                bkpinfo->media_size = 650;
2605            }
2606        }
2607        if (!popup_and_get_string
2608            ("Prefix.",
2609             "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2610             bkpinfo->prefix, MAX_STR_LEN / 4)) {
2611            log_to_screen("User has chosen not to backup the PC");
2612            finish(1);
2613        }
2614        log_msg(3, "prefix set to %s", bkpinfo->prefix);
2615        break;
2616    default:
2617        fatal_error
2618            ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
2619    }
2620
2621    if (archiving_to_media) {
2622
2623#ifdef __FreeBSD__
2624        strcpy(bkpinfo->boot_device,
2625               call_program_and_get_last_line_of_output
2626               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
2627#else
2628        strcpy(bkpinfo->boot_device,
2629               call_program_and_get_last_line_of_output
2630               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
2631#endif
2632        i = which_boot_loader(bkpinfo->boot_device);
2633        if (i == 'U')           // unknown
2634        {
2635
2636#ifdef __FreeBSD__
2637            if (!popup_and_get_string
2638                ("Boot device",
2639                 "What is your boot device? (e.g. /dev/ad0)",
2640                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2641                log_to_screen("User has chosen not to backup the PC");
2642                finish(1);
2643            }
2644            i = which_boot_loader(bkpinfo->boot_device);
2645#else
2646            if (!popup_and_get_string
2647                ("Boot device",
2648                 "What is your boot device? (e.g. /dev/hda)",
2649                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2650                log_to_screen("User has chosen not to backup the PC");
2651                finish(1);
2652            }
2653            if (does_string_exist_in_boot_block(bkpinfo->boot_device, "LILO")) {
2654                i = 'L';
2655            } else
2656                if (does_string_exist_in_boot_block(bkpinfo->boot_device, "ELILO")) {
2657                i = 'E';
2658            } else
2659                if (does_string_exist_in_boot_block(bkpinfo->boot_device, "GRUB")) {
2660                i = 'G';
2661            } else {
2662                i = 'U';
2663            }
2664#endif
2665            if (i == 'U') {
2666                if (ask_me_yes_or_no("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?")) {
2667                    i = 'R';    // raw
2668                } else {
2669                    log_to_screen("I cannot find your boot loader. Please run mondoarchive with parameters.");
2670                    finish(1);
2671                }
2672            }
2673        }
2674        bkpinfo->boot_loader = i;
2675
2676        mr_free(bkpinfo->include_paths);
2677        strcpy(tmp1, "/");
2678        if (!popup_and_get_string
2679            ("Backup paths",
2680             "Please enter paths (separated by '|') which you want me to backup. The default is '/' (i.e. everything).",
2681             tmp1, MAX_STR_LEN)) {
2682            log_to_screen("User has chosen not to backup the PC");
2683            finish(1);
2684        }
2685        mr_asprintf(bkpinfo->include_paths, "%s", tmp1);
2686
2687        tmp = list_of_NETFS_mounts_only();
2688        if (strlen(tmp) > 2) {
2689            mr_strcat(bkpinfo->exclude_paths, "|%s",tmp);
2690        }
2691        mr_free(tmp);
2692// NTFS
2693        strcpy(tmp1, call_program_and_get_last_line_of_output("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
2694        if (strlen(tmp1) > 2) {
2695            if (!popup_and_get_string
2696                ("NTFS partitions",
2697                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
2698                 tmp1, MAX_STR_LEN / 4)) {
2699                log_to_screen("User has chosen not to backup the PC");
2700                finish(1);
2701            }
2702            strncpy(bkpinfo->image_devs, tmp1, MAX_STR_LEN / 4);
2703        }
2704
2705        if (bkpinfo->exclude_paths != NULL ) {
2706            strncpy(p,bkpinfo->exclude_paths,(16*MAX_STR_LEN)-1);
2707        } else {
2708            p[0] = '\0';
2709        }
2710        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);
2711        if (p == NULL) {
2712            log_to_screen("User has chosen not to backup the PC");
2713            finish(1);
2714        }
2715        mr_free(bkpinfo->exclude_paths);
2716        mr_asprintf(tmp, "%s", p);
2717        bkpinfo->exclude_paths = tmp;
2718
2719        if (!popup_and_get_string
2720            ("Temporary directory",
2721             "Please enter your temporary directory.",
2722             bkpinfo->tmpdir, (4*MAX_STR_LEN)-1)) {
2723            log_to_screen("User has chosen not to backup the PC");
2724            finish(1);
2725        }
2726        /*  if modified to another path */
2727        if (strstr(bkpinfo->tmpdir,"mondo.tmp.") == NULL) {
2728            setup_tmpdir(bkpinfo->tmpdir);
2729        }
2730        if (!popup_and_get_string
2731            ("Scratch directory",
2732             "Please enter your scratch directory.",
2733             bkpinfo->scratchdir, (4*MAX_STR_LEN)-1)) {
2734            log_to_screen("User has chosen not to backup the PC");
2735            finish(1);
2736        }
2737        /*  if modified to another path */
2738        if (strstr(bkpinfo->scratchdir,"mondo.scratch.") == NULL) {
2739            setup_scratchdir(bkpinfo->scratchdir);
2740        }
2741        if (ask_me_yes_or_no("Do you want to backup extended attributes?")) {
2742            if (find_home_of_exe("getfattr")) {
2743                mr_free(g_getfattr);
2744                mr_asprintf(g_getfattr,"getfattr");
2745            }
2746            if (find_home_of_exe("getfacl")) {
2747                mr_free(g_getfacl);
2748                mr_asprintf(g_getfacl,"getfacl");
2749            }
2750            log_it("Backup of extended attributes");
2751        }
2752// Interactive mode:
2753#ifdef __IA64__
2754        bkpinfo->make_cd_use_lilo = TRUE;
2755#else
2756        bkpinfo->make_cd_use_lilo = FALSE;
2757#endif
2758        bkpinfo->backup_data = TRUE;
2759        if (strcmp(compression_type,"lzo") == 0) {
2760            strcpy(bkpinfo->zip_exe, "lzop");
2761            strcpy(bkpinfo->zip_suffix, "lzo");
2762        } else if (strcmp(compression_type,"gzip") == 0) {
2763            strcpy(bkpinfo->zip_exe, "gzip");
2764            strcpy(bkpinfo->zip_suffix, "gz");
2765        } else if (strcmp(compression_type,"lzma") == 0) {
2766            //strcpy(bkpinfo->zip_exe, "xy");
2767            //strcpy(bkpinfo->zip_suffix, "xy");
2768        } else if (strcmp(compression_type,"bzip2") == 0) {
2769            strcpy(bkpinfo->zip_exe, "bzip2");
2770            strcpy(bkpinfo->zip_suffix, "bz2");
2771        } else {
2772            bkpinfo->zip_exe[0] = bkpinfo->zip_suffix[0] = '\0';
2773        }
2774
2775        bkpinfo->verify_data =
2776            ask_me_yes_or_no
2777            ("Will you want to verify your backups after Mondo has created them?");
2778
2779        if (!ask_me_yes_or_no
2780            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2781            log_to_screen("User has chosen not to backup the PC");
2782            finish(1);
2783        }
2784    } else {
2785        bkpinfo->restore_data = TRUE;   // probably...
2786    }
2787    mr_free(compression_type);
2788
2789    if (bkpinfo->backup_media_type == iso
2790        || bkpinfo->backup_media_type == netfs) {
2791        g_ISO_restore_mode = TRUE;
2792    }
2793#ifdef __FreeSD__
2794// skip
2795#else
2796    if (bkpinfo->backup_media_type == netfs) {
2797        log_msg(3, "I think the Remote mount is mounted at %s", bkpinfo->isodir);
2798    }
2799    log_it("isodir = %s", bkpinfo->isodir);
2800    if (bkpinfo->netfs_mount) {
2801        log_it("netfs_mount = '%s'", bkpinfo->netfs_mount);
2802    }
2803    if (bkpinfo->netfs_user) {
2804        log_it("netfs_user = '%s'", bkpinfo->netfs_user);
2805    }
2806    if (bkpinfo->netfs_proto) {
2807        log_it("netfs_proto = '%s'", bkpinfo->netfs_proto);
2808    }
2809#endif
2810
2811    log_it("media device = %s", bkpinfo->media_device);
2812    log_it("media size = %ld", bkpinfo->media_size);
2813    log_it("media type = %s", bkptype_to_string(bkpinfo->backup_media_type));
2814    if (bkpinfo->prefix) {
2815        log_it("prefix = %s", bkpinfo->prefix);
2816    }
2817    log_it("compression = %ld", bkpinfo->compression_level);
2818    log_it("exclude_path = %s", bkpinfo->exclude_paths);
2819    log_it("include_path = %s", bkpinfo->include_paths);
2820
2821    /* Handle devices passed in bkpinfo and print result */
2822    /*  the mr_make_devlist_from_pathlist function appends
2823    /*  to the *_paths variables so copy before */
2824    mr_make_devlist_from_pathlist(bkpinfo->exclude_paths, 'E');
2825    mr_make_devlist_from_pathlist(bkpinfo->include_paths, 'I');
2826
2827    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2828    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2829    if (bkpinfo->image_devs) {
2830        log_it("image_devs = '%s'", bkpinfo->image_devs);
2831    }
2832    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device, bkpinfo->boot_loader);
2833    if (bkpinfo->media_size < 0) {
2834        if (archiving_to_media) {
2835            fatal_error("Media size is less than zero.");
2836        } else {
2837            log_msg(2, "Warning - media size is less than zero.");
2838            bkpinfo->media_size = 0;
2839        }
2840    }
2841    paranoid_free(sz_size);
2842    paranoid_free(tmp1);
2843    return (0);
2844}
2845
2846
2847/**
2848 * Get a |-separated list of NETFS mounts.
2849 * @return The list created.
2850 * @note The return value points to allocated string that needs to be freed
2851 * @bug Even though we only want the mounts, the devices are still checked.
2852 */
2853char *list_of_NETFS_mounts_only(void)
2854{
2855    char *exclude_these_directories = NULL;
2856
2857    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;}'"));
2858    log_msg(9,"list_of_NETFS_mounts_only returns %s\n",exclude_these_directories);
2859    return(exclude_these_directories);
2860}
2861
2862/* @} - end of utilityGroup */
2863
2864
2865
2866
2867
2868/**
2869 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2870 * [random] is a random number between 1 and 32767.
2871 * @param store_name_here Where to store the new filename.
2872 * @param stub A random number will be appended to this to make the FIFO's name.
2873 * @ingroup deviceGroup
2874 */
2875void make_fifo(char *store_name_here, char *stub)
2876{
2877    char *tmp;
2878
2879    malloc_string(tmp);
2880    assert_string_is_neither_NULL_nor_zerolength(stub);
2881
2882    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2883            (int) (random() % 32768));
2884    make_hole_for_file(store_name_here);
2885    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2886    sprintf(tmp, "chmod 770 %s", store_name_here);
2887    paranoid_system(tmp);
2888    paranoid_free(tmp);
2889}
2890
2891
2892
2893/**
2894 * @addtogroup deviceGroup
2895 * @{
2896 */
2897/**
2898 * If we can read @p dev, set @p output to it.
2899 * If @p dev cannot be read, set @p output to "".
2900 * @param dev The device to check for.
2901 * @param output Set to @p dev if @p dev exists, "" otherwise.
2902 * @return TRUE if @p dev exists, FALSE if it doesn't.
2903 */
2904bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2905{
2906    char *command;
2907
2908    malloc_string(command);
2909    if (!dev || dev[0] == '\0') {
2910        output[0] = '\0';
2911        return (FALSE);
2912    }
2913//  assert_string_is_neither_NULL_nor_zerolength(dev);
2914    if (!bkpinfo->please_dont_eject) {
2915        log_msg(10, "Injecting %s", dev);
2916        inject_device(dev);
2917    }
2918    if (!does_file_exist(dev)) {
2919        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2920        return (FALSE);
2921    }
2922    sprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2923            512L, dev);
2924    if (!run_program_and_log_output(command, FALSE)
2925        && !run_program_and_log_output(command, FALSE)) {
2926        strcpy(output, dev);
2927        log_msg(4, "Found it - %s", dev);
2928        return (TRUE);
2929    } else {
2930        output[0] = '\0';
2931        log_msg(4, "It's not %s", dev);
2932        return (FALSE);
2933    }
2934}
2935
2936
2937
2938
2939
2940/**
2941 * Find out what number CD is in the drive.
2942 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2943 * @return The current CD number, or -1 if it could not be found.
2944 * @note If the CD is not mounted, it will be mounted
2945 * (and remain mounted after this function returns).
2946 */
2947int what_number_cd_is_this()
2948{
2949    int cd_number = -1;
2950    char *mountdev = NULL;
2951    char *tmp = NULL;
2952
2953    assert(bkpinfo != NULL);
2954//  log_it("Asking what_number_cd_is_this");
2955    if (g_ISO_restore_mode) {
2956        mr_asprintf(tmp, "mount | grep iso9660 | awk '{print $3;}'");
2957
2958        mr_asprintf(mountdev, "%s%s", call_program_and_get_last_line_of_output(tmp), "/archives/THIS-CD-NUMBER");
2959        cd_number = atoi(last_line_of_file(mountdev));
2960        paranoid_free(mountdev);
2961        paranoid_free(tmp);
2962
2963        return (cd_number);
2964    }
2965
2966    mr_asprintf(mountdev, "%s", bkpinfo->media_device);
2967    if (!mountdev[0]) {
2968        log_it
2969            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2970        find_cdrom_device(bkpinfo->media_device, FALSE);
2971    }
2972    if (!is_this_device_mounted(MNT_CDROM)) {
2973        if (bkpinfo->backup_media_type == usb) {
2974            mount_USB_here(mountdev, MNT_CDROM);
2975        } else {
2976            mount_CDROM_here(mountdev, MNT_CDROM);
2977        }
2978    }
2979    paranoid_free(mountdev);
2980
2981    cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2982    return (cd_number);
2983}
2984
2985
2986
2987
2988
2989
2990
2991/**
2992 * Find out what device is mounted as root (/).
2993 * @return Root device.
2994 * @note The returned string points to static storage and will be overwritten with every call.
2995 * @bug A bit of a misnomer; it's actually finding out the root device.
2996 * The mountpoint (where it's mounted) will obviously be '/'.
2997 */
2998char *where_is_root_mounted()
2999{
3000    /*@ buffers **************** */
3001    static char tmp[MAX_STR_LEN];
3002
3003
3004#ifdef __FreeBSD__
3005    strcpy(tmp, call_program_and_get_last_line_of_output
3006           ("mount | grep \" on / \" | cut -d' ' -f1"));
3007#else
3008    strcpy(tmp, call_program_and_get_last_line_of_output
3009           ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
3010    if (strstr(tmp, "/dev/cciss/")) {
3011        strcpy(tmp, call_program_and_get_last_line_of_output
3012               ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
3013    }
3014    if (strstr(tmp, "/dev/md")) {
3015        strcpy(tmp,
3016               call_program_and_get_last_line_of_output
3017               ("mount | grep \" on / \" | cut -d' ' -f1"));
3018    }
3019#endif
3020
3021    return (tmp);
3022}
3023
3024
3025/**
3026 * Find out which boot loader is in use.
3027 * @param which_device Device to look for the boot loader on.
3028 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
3029 * @note Under Linux, all drives are examined, not just @p which_device.
3030 */
3031#ifdef __FreeBSD__
3032char which_boot_loader(char *which_device)
3033{
3034    int count_lilos = 0;
3035    int count_grubs = 0;
3036    int count_boot0s = 0;
3037    int count_dangerouslydedicated = 0;
3038
3039    log_it("looking at drive %s's MBR", which_device);
3040    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
3041        count_grubs++;
3042    }
3043    if (does_string_exist_in_boot_block(which_device, "LILO")) {
3044        count_lilos++;
3045    }
3046    if (does_string_exist_in_boot_block(which_device, "Drive")) {
3047        count_boot0s++;
3048    }
3049    if (does_string_exist_in_first_N_blocks
3050        (which_device, "FreeBSD/i386", 17)) {
3051        count_dangerouslydedicated++;
3052    }
3053    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
3054           count_grubs, count_lilos, count_elilos, count_boot0s,
3055           count_dangerouslydedicated);
3056
3057    if (count_grubs && !count_lilos) {
3058        return ('G');
3059    } else if (count_lilos && !count_grubs) {
3060        return ('L');
3061    } else if (count_grubs == 1 && count_lilos == 1) {
3062        log_it("I'll bet you used to use LILO but switched to GRUB...");
3063        return ('G');
3064    } else if (count_boot0s == 1) {
3065        return ('B');
3066    } else if (count_dangerouslydedicated) {
3067        return ('D');
3068    } else {
3069        log_it("Unknown boot loader");
3070        return ('U');
3071    }
3072}
3073
3074#else
3075
3076char which_boot_loader(char *which_device)
3077{
3078    /*@ buffer ***************************************************** */
3079    char *list_drives_cmd = NULL;
3080    char *current_drive;
3081    char *tmp;
3082
3083    /*@ pointers *************************************************** */
3084    FILE *pdrives;
3085
3086    /*@ int ******************************************************** */
3087    int count_lilos = 0;
3088    int count_grubs = 0;
3089
3090    /*@ end vars *************************************************** */
3091
3092    malloc_string(current_drive);
3093
3094    /* UEFI is not supported here - but should be managed as a BIOS/UEFI option not a Boot Loader one per se */
3095
3096#ifdef __IA64__
3097    /* No choice for it */
3098    return ('E');
3099#endif
3100    assert(which_device != NULL);
3101
3102    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());
3103    log_it("list_drives_cmd = %s", list_drives_cmd);
3104
3105    if (!(pdrives = popen(list_drives_cmd, "r"))) {
3106        log_OS_error("Unable to open list of drives");
3107        mr_free(list_drives_cmd);
3108        paranoid_free(current_drive);
3109        return ('\0');
3110    }
3111    mr_free(list_drives_cmd);
3112
3113    for (tmp = fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives) && (tmp != NULL);
3114         tmp = fgets(current_drive, MAX_STR_LEN, pdrives)) {
3115        strip_spaces(current_drive);
3116        log_it("looking at drive %s's MBR", current_drive);
3117        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3118            count_grubs++;
3119            strcpy(which_device, current_drive);
3120            break;
3121        }
3122        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3123            count_lilos++;
3124            strcpy(which_device, current_drive);
3125            break;
3126        }
3127    }
3128    if (pclose(pdrives)) {
3129        log_OS_error("Cannot pclose pdrives");
3130    }
3131    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3132    if (count_grubs && !count_lilos) {
3133        paranoid_free(current_drive);
3134        return ('G');
3135    } else if (count_lilos && !count_grubs) {
3136        paranoid_free(current_drive);
3137        return ('L');
3138    } else if (count_grubs == 1 && count_lilos == 1) {
3139        log_it("I'll bet you used to use LILO but switched to GRUB...");
3140        paranoid_free(current_drive);
3141        return ('G');
3142    } else {
3143        // We need to look on each partition then
3144        mr_asprintf(list_drives_cmd, "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
3145        log_it("list_drives_cmd = %s", list_drives_cmd);
3146
3147        if (!(pdrives = popen(list_drives_cmd, "r"))) {
3148            log_OS_error("Unable to open list of drives");
3149            mr_free(list_drives_cmd);
3150            paranoid_free(current_drive);
3151            return ('\0');
3152        }
3153        mr_free(list_drives_cmd);
3154
3155        for (tmp = fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives) && (tmp != NULL);
3156            tmp = fgets(current_drive, MAX_STR_LEN, pdrives)) {
3157            strip_spaces(current_drive);
3158            log_it("looking at partition %s's BR", current_drive);
3159            if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
3160                count_grubs++;
3161                strcpy(which_device, current_drive);
3162                break;
3163            }
3164            if (does_string_exist_in_boot_block(current_drive, "LILO")) {
3165                count_lilos++;
3166                strcpy(which_device, current_drive);
3167                break;
3168            }
3169        }
3170        if (pclose(pdrives)) {
3171            log_OS_error("Cannot pclose pdrives");
3172        }
3173        log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
3174        paranoid_free(current_drive);
3175        if (count_grubs && !count_lilos) {
3176            return ('G');
3177        } else if (count_lilos && !count_grubs) {
3178            return ('L');
3179        } else if (count_grubs == 1 && count_lilos == 1) {
3180            log_it("I'll bet you used to use LILO but switched to GRUB...");
3181            return ('G');
3182        } else {
3183            log_it("Unknown boot loader");
3184            return ('U');
3185        }
3186    }
3187}
3188#endif
3189
3190
3191
3192
3193/**
3194 * Write zeroes over the first 16K of @p device.
3195 * @param device The device to zero.
3196 * @return 0 for success, 1 for failure.
3197 */
3198int zero_out_a_device(char *device)
3199{
3200    FILE *fout;
3201    int i;
3202
3203    assert_string_is_neither_NULL_nor_zerolength(device);
3204
3205    log_it("Zeroing drive %s", device);
3206    if (!(fout = fopen(device, "w"))) {
3207        log_OS_error("Unable to open/write to device");
3208        return (1);
3209    }
3210    for (i = 0; i < 16384; i++) {
3211        fputc('\0', fout);
3212    }
3213    paranoid_fclose(fout);
3214    log_it("Device successfully zeroed.");
3215    return (0);
3216}
3217
3218/**
3219 * Return the device pointed to by @p incoming.
3220 * @param incoming The device to resolve symlinks for.
3221 * @return The path to the real device file.
3222 * @note The returned string points to static storage that will be overwritten with each call.
3223 * @bug Won't work with file v4.0; needs to be written in C.
3224 */
3225char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
3226{
3227    static char output[MAX_STR_LEN];
3228    char *command;
3229    char *curr_fname;
3230    char *scratch = NULL;
3231    char *tmp = NULL;
3232    char *p;
3233
3234    struct stat statbuf;
3235    command = malloc(1000);
3236    malloc_string(curr_fname);
3237    if (!does_file_exist(incoming)) {
3238        log_it
3239            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
3240        strcpy(output, incoming);
3241    } else {
3242        strcpy(curr_fname, incoming);
3243        lstat(curr_fname, &statbuf);
3244        while (S_ISLNK(statbuf.st_mode)) {
3245            log_msg(1, "curr_fname = %s", curr_fname);
3246            sprintf(command, "file %s", curr_fname);
3247            mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
3248            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
3249                 p--);
3250            p++;
3251            mr_asprintf(scratch, "%s", p);
3252            for (p = scratch; *p != '\0' && *p != '\''; p++);
3253            *p = '\0';
3254            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
3255            mr_free(tmp);
3256
3257            if (scratch[0] == '/') {
3258                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
3259            } else {            // copy over the basename cos it's a relative softlink
3260                p = curr_fname + strlen(curr_fname);
3261                while (p != curr_fname && *p != '/') {
3262                    p--;
3263                }
3264                if (*p == '/') {
3265                    p++;
3266                }
3267                strcpy(p, scratch);
3268            }
3269            mr_free(scratch);
3270            lstat(curr_fname, &statbuf);
3271        }
3272        strcpy(output, curr_fname);
3273        log_it("resolved %s to %s", incoming, output);
3274    }
3275    paranoid_free(command);
3276    paranoid_free(curr_fname);
3277    return (output);
3278}
3279
3280/* @} - end of deviceGroup */
3281
3282/**
3283 * Return the type of partition format (GPT or MBR)
3284 */
3285char *which_partition_format(const char *drive)
3286{
3287    static char output[4];
3288    char *tmp = NULL;
3289    char *command;
3290    char *fdisk;
3291#ifdef __IA64__
3292    struct stat buf;
3293#endif
3294    malloc_string(command);
3295    malloc_string(fdisk);
3296    sprintf(fdisk, "/sbin/parted2fdisk");
3297    sprintf(command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
3298    mr_asprintf(tmp, "%s", call_program_and_get_last_line_of_output(command));
3299    if (strstr(tmp, "GPT") == NULL) {
3300        strcpy(output, "MBR");
3301    } else {
3302        strcpy(output, "GPT");
3303    }
3304    mr_free(tmp);
3305
3306    log_msg(0, "Found %s partition table format type", output);
3307    paranoid_free(command);
3308    paranoid_free(fdisk);
3309    return (output);
3310}
3311/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.