source: MondoRescue/branches/2.2.5/mondo/src/common/libmondo-devices.c @ 1646

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

Remove g_bkpinfo_DONTUSETHIS

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