source: branches/stable/mondo/src/common/libmondo-devices.c @ 1770

Last change on this file since 1770 was 1770, checked in by bruno, 12 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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