source: branches/2.2.9/mondo/src/common/libmondo-devices.c @ 2241

Last change on this file since 2241 was 2241, checked in by bruno, 10 years ago

r3144@localhost: bruno | 2009-06-26 12:18:08 +0200

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