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

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

Fixes missing extern function declaation for setup_tmpdir

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