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

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

merge r87:88 of the 2.04_berlios branch
indent some files

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