source: branches/2.2.6/mondo/src/common/libmondo-devices.c @ 1916

Last change on this file since 1916 was 1916, checked in by Bruno Cornec, 12 years ago

Apply patch mondo.live-nfs.patch (Mark Pinkerton <Mark.Pinkerton_at_emageon.com>)

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