source: trunk/mondo/mondo/common/libmondo-devices.c @ 59

Last change on this file since 59 was 59, checked in by bcornec, 14 years ago

Trunk: indent on all source files

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