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

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

Fix a bug where df was using locale to print messages and wasn't filtered correctly
Improve setup of tmpdir again

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