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

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

memory management going on (libmondo-verify.c, libmondo-devices.c, libmondo-string.c, libmondo-stream.c)

  • 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 122 2005-11-14 23:01:12Z 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 122 2005-11-14 23:01:12Z 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    assert(bkpinfo != NULL);
1832    sz_size[0] = '\0';
1833    bkpinfo->nonbootable_backup = FALSE;
1834
1835// Tape, CD, NFS, ...?
1836    srandom(getpid());
1837    bkpinfo->backup_media_type =
1838        (g_restoring_live_from_cd) ? cdr :
1839        which_backup_media_type(bkpinfo->restore_data);
1840    if (bkpinfo->backup_media_type == none) {
1841        log_to_screen("User has chosen not to backup the PC");
1842        finish(1);
1843    }
1844    if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
1845        popup_and_OK("Please remove CD/floppy from drive(s)");
1846    }
1847    log_msg(3, "media type = %s",
1848            bkptype_to_string(bkpinfo->backup_media_type));
1849    if (archiving_to_media) {
1850        sensibly_set_tmpdir_and_scratchdir(bkpinfo);
1851    }
1852    bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
1853    bkpinfo->compression_level =
1854        (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
1855    bkpinfo->use_lzo =
1856        (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
1857
1858/*
1859  if (find_home_of_exe("star") && (!find_home_of_exe("afio") || find_home_of_exe("selinuxenabled")))
1860    {
1861      bkpinfo->use_star = FALSE;   
1862      bkpinfo->use_lzo = FALSE;
1863      log_to_screen("Using star, not afio");
1864      if (!find_home_of_exe("afio"))
1865    { log_to_screen("...because afio not found"); }
1866      if (find_home_of_exe("selinuxenabled"))
1867    { log_to_screen("...because SELINUX found"); }
1868    }
1869*/
1870
1871    mvaddstr_and_log_it(2, 0, " ");
1872
1873// Find device's /dev (or SCSI) entry
1874    switch (bkpinfo->backup_media_type) {
1875    case cdr:
1876    case cdrw:
1877    case dvd:
1878        if (archiving_to_media) {
1879            if (ask_me_yes_or_no
1880                ("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?"))
1881            {
1882                bkpinfo->manual_cd_tray = TRUE;
1883            }
1884            if ((bkpinfo->compression_level =
1885                 which_compression_level()) == -1) {
1886                log_to_screen("User has chosen not to backup the PC");
1887                finish(1);
1888            }
1889            sprintf(comment, "What speed is your %s (re)writer?",
1890                    media_descriptor_string(bkpinfo->backup_media_type));
1891            if (bkpinfo->backup_media_type == dvd) {
1892                find_dvd_device(bkpinfo->media_device, FALSE);
1893                strcpy(tmp, "1");
1894                sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE);  // 4.7 salesman's GB = 4.482 real GB = 4582 MB
1895                log_msg(1, "Setting to DVD defaults");
1896            } else {
1897                strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
1898                strcpy(tmp, "4");
1899                strcpy(sz_size, "650");
1900                log_msg(1, "Setting to CD defaults");
1901            }
1902            if (bkpinfo->backup_media_type != dvd) {
1903                if (!popup_and_get_string("Speed", comment, tmp, 4)) {
1904                    log_to_screen("User has chosen not to backup the PC");
1905                    finish(1);
1906                }
1907            }
1908            bkpinfo->cdrw_speed = atoi(tmp);    // if DVD then this shouldn't ever be used anyway :)
1909            sprintf(comment,
1910                    "How much data (in Megabytes) will each %s store?",
1911                    media_descriptor_string(bkpinfo->backup_media_type));
1912            if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1913                log_to_screen("User has chosen not to backup the PC");
1914                finish(1);
1915            }
1916            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1917                bkpinfo->media_size[i] = atoi(sz_size);
1918            }
1919            if (bkpinfo->media_size[0] <= 0) {
1920                log_to_screen("User has chosen not to backup the PC");
1921                finish(1);
1922            }
1923        }
1924    case cdstream:
1925        if (bkpinfo->disaster_recovery) {
1926            strcpy(bkpinfo->media_device, "/dev/cdrom");
1927            log_msg(2, "CD-ROM device assumed to be at %s",
1928                    bkpinfo->media_device);
1929        } else if (bkpinfo->restore_data
1930                   || bkpinfo->backup_media_type == dvd) {
1931            if (!bkpinfo->media_device[0]) {
1932                strcpy(bkpinfo->media_device, "/dev/cdrom");
1933            }                   // just for the heck of it :)
1934            log_msg(1, "bkpinfo->media_device = %s",
1935                    bkpinfo->media_device);
1936            if (bkpinfo->backup_media_type == dvd
1937                || find_cdrom_device(bkpinfo->media_device, FALSE)) {
1938                log_msg(1, "bkpinfo->media_device = %s",
1939                        bkpinfo->media_device);
1940                sprintf(comment,
1941                        "Please specify your %s drive's /dev entry",
1942                        media_descriptor_string(bkpinfo->
1943                                                backup_media_type));
1944                if (!popup_and_get_string
1945                    ("Device?", comment, bkpinfo->media_device,
1946                     MAX_STR_LEN / 4)) {
1947                    log_to_screen("User has chosen not to backup the PC");
1948                    finish(1);
1949                }
1950            }
1951            log_msg(2, "%s device found at %s",
1952                    media_descriptor_string(bkpinfo->backup_media_type),
1953                    bkpinfo->media_device);
1954        } else {
1955            if (find_cdrw_device(bkpinfo->media_device)) {
1956                bkpinfo->media_device[0] = '\0';
1957            }
1958            if (bkpinfo->media_device[0]) {
1959                sprintf(tmp,
1960                        "I think I've found your %s burner at SCSI node %s; am I right on the money?",
1961                        media_descriptor_string(bkpinfo->
1962                                                backup_media_type),
1963                        bkpinfo->media_device);
1964                if (!ask_me_yes_or_no(tmp)) {
1965                    bkpinfo->media_device[0] = '\0';
1966                }
1967            }
1968            if (!bkpinfo->media_device[0]) {
1969                if (g_kernel_version < 2.6) {
1970                    i = popup_and_get_string("Device node?",
1971                                             "What is the SCSI node of your CD (re)writer, please?",
1972                                             bkpinfo->media_device,
1973                                             MAX_STR_LEN / 4);
1974                } else {
1975                    i = popup_and_get_string("/dev entry?",
1976                                             "What is the /dev entry of your CD (re)writer, please?",
1977                                             bkpinfo->media_device,
1978                                             MAX_STR_LEN / 4);
1979                }
1980                if (!i) {
1981                    log_to_screen("User has chosen not to backup the PC");
1982                    finish(1);
1983                }
1984            }
1985        }
1986        if (bkpinfo->backup_media_type == cdstream) {
1987            for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1988                bkpinfo->media_size[i] = 650;
1989            }
1990        }
1991        break;
1992    case udev:
1993        if (!ask_me_yes_or_no
1994            ("This option is for advanced users only. Are you sure?")) {
1995            log_to_screen("User has chosen not to backup the PC");
1996            finish(1);
1997        }
1998    case tape:
1999
2000        if (find_tape_device_and_size(bkpinfo->media_device, sz_size)) {
2001            log_msg(3, "Ok, using vanilla scsi tape.");
2002            strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
2003            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2004                paranoid_fclose(fin);
2005            } else {
2006                strcpy(bkpinfo->media_device, "/dev/osst0");
2007            }
2008        }
2009        if (bkpinfo->media_device[0]) {
2010            if ((fin = fopen(bkpinfo->media_device, "r"))) {
2011                paranoid_fclose(fin);
2012            } else {
2013                if (does_file_exist("/tmp/mondo-restore.cfg")) {
2014                    read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
2015                                 bkpinfo->media_device);
2016                }
2017            }
2018            sprintf(tmp,
2019                    "I think I've found your tape streamer at %s; am I right on the money?",
2020                    bkpinfo->media_device);
2021        }
2022        if (bkpinfo->media_device[0]) {
2023            sprintf(tmp,
2024                    "I think I've found your tape streamer at %s; am I right on the money?",
2025                    bkpinfo->media_device);
2026            if (!ask_me_yes_or_no(tmp)) {
2027                bkpinfo->media_device[0] = '\0';
2028            }
2029        }
2030        if (!bkpinfo->media_device[0]) {
2031            if (!popup_and_get_string
2032                ("Device name?",
2033                 "What is the /dev entry of your tape streamer?",
2034                 bkpinfo->media_device, MAX_STR_LEN / 4)) {
2035                log_to_screen("User has chosen not to backup the PC");
2036                finish(1);
2037            }
2038        }
2039        sprintf(tmp, "ls -l %s", bkpinfo->media_device);
2040        if (run_program_and_log_output(tmp, FALSE)) {
2041            log_to_screen("User has not specified a valid /dev entry");
2042            finish(1);
2043        }
2044        log_msg(4, "sz_size = %s", sz_size);
2045        sz_size[0] = '\0';
2046/*
2047    if ((size_sz[0]=='\0' || atol(size_sz)==0) && archiving_to_media)
2048      {
2049        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))
2050          { log_to_screen("User has chosen not to backup the PC"); finish(1); }
2051      }
2052*/
2053        if (sz_size[0] == '\0') {
2054            bkpinfo->media_size[0] = 0;
2055        } else {
2056            bkpinfo->media_size[0] =
2057                friendly_sizestr_to_sizelong(sz_size) / 2 - 50;
2058        }
2059        log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
2060        if (bkpinfo->media_size[0] <= 0) {
2061            bkpinfo->media_size[0] = 0;
2062        }
2063        for (i = 1; i <= MAX_NOOF_MEDIA; i++) {
2064            bkpinfo->media_size[i] = bkpinfo->media_size[0];
2065        }
2066        if (archiving_to_media) {
2067            if ((bkpinfo->compression_level =
2068                 which_compression_level()) == -1) {
2069                log_to_screen("User has chosen not to backup the PC");
2070                finish(1);
2071            }
2072        }
2073        break;
2074
2075
2076
2077    case nfs:
2078        if (!bkpinfo->nfs_mount[0]) {
2079            strcpy(bkpinfo->nfs_mount,
2080                   call_program_and_get_last_line_of_output
2081                   ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
2082        }
2083#ifdef __FreeBSD__
2084        if (TRUE)
2085#else
2086        if (!bkpinfo->disaster_recovery)
2087#endif
2088        {
2089            if (!popup_and_get_string
2090                ("NFS dir.",
2091                 "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.)",
2092                 bkpinfo->nfs_mount, MAX_STR_LEN / 4)) {
2093                log_to_screen("User has chosen not to backup the PC");
2094                finish(1);
2095            }
2096            if (!bkpinfo->restore_data) {
2097                if ((bkpinfo->compression_level =
2098                     which_compression_level()) == -1) {
2099                    log_to_screen("User has chosen not to backup the PC");
2100                    finish(1);
2101                }
2102            }
2103            // check whether already mounted - we better remove
2104            // surrounding spaces and trailing '/' for this
2105            strip_spaces(bkpinfo->nfs_mount);
2106            if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
2107                bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
2108            sprintf(command, "mount | grep \"%s \" | cut -d' ' -f3",
2109                    bkpinfo->nfs_mount);
2110            strcpy(bkpinfo->isodir,
2111                   call_program_and_get_last_line_of_output(command));
2112        }
2113        if (bkpinfo->disaster_recovery) {
2114            system("umount /tmp/isodir 2> /dev/null");
2115            if (!popup_and_get_string
2116                ("NFS share", "Which remote NFS share should I mount?",
2117                 bkpinfo->nfs_mount, MAX_STR_LEN)) {
2118                log_to_screen("User has chosen not to backup the PC");
2119                finish(1);
2120            }
2121        }
2122        if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
2123            sprintf(bkpinfo->isodir, "/tmp/isodir.mondo.%d",
2124                    (int) (random() % 32768));
2125            sprintf(command, "mkdir -p %s", bkpinfo->isodir);
2126            run_program_and_log_output(command, 5);
2127            sprintf(tmp, "mount %s -t nfs %s", bkpinfo->nfs_mount,
2128                    bkpinfo->isodir);
2129            run_program_and_log_output(tmp, 5);
2130            malloc_string(g_selfmounted_isodir);
2131            strcpy(g_selfmounted_isodir, bkpinfo->isodir);
2132        }
2133        if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
2134            popup_and_OK
2135                ("Please mount that partition before you try to backup to or restore from it.");
2136            finish(1);
2137        }
2138        strcpy(tmp, bkpinfo->nfs_remote_dir);
2139        if (!popup_and_get_string
2140            ("Directory", "Which directory within that mountpoint?", tmp,
2141             MAX_STR_LEN)) {
2142            log_to_screen("User has chosen not to backup the PC");
2143            finish(1);
2144        }
2145        strcpy(bkpinfo->nfs_remote_dir, tmp);
2146        // check whether writable - we better remove surrounding spaces for this
2147        strip_spaces(bkpinfo->nfs_remote_dir);
2148        sprintf(command, "echo hi > %s/%s/.dummy.txt", bkpinfo->isodir,
2149                bkpinfo->nfs_remote_dir);
2150        while (run_program_and_log_output(command, FALSE)) {
2151            strcpy(tmp, bkpinfo->nfs_remote_dir);
2152            asprintf(&prompt,
2153                     "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.",
2154                     bkpinfo->nfs_remote_dir, bkpinfo->isodir);
2155            if (!popup_and_get_string
2156                ("Directory", prompt, tmp, MAX_STR_LEN)) {
2157                log_to_screen("User has chosen not to backup the PC");
2158                finish(1);
2159            }
2160            strcpy(bkpinfo->nfs_remote_dir, tmp);
2161            // check whether writable - we better remove surrounding spaces for this */
2162            strip_spaces(bkpinfo->nfs_remote_dir);
2163            asprintf(&command, "echo hi > %s/%s/.dummy.txt",
2164                     bkpinfo->isodir, bkpinfo->nfs_remote_dir);
2165        }
2166        for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2167            bkpinfo->media_size[i] = 650;
2168        }
2169        log_msg(3, "Just set nfs_remote_dir to %s",
2170                bkpinfo->nfs_remote_dir);
2171        log_msg(3, "isodir is still %s", bkpinfo->isodir);
2172        break;
2173
2174    case iso:
2175        if (!bkpinfo->disaster_recovery) {
2176            if (!popup_and_get_string
2177                ("Storage dir.",
2178                 "Please enter the full path that contains your ISO images.  Example: /mnt/raid0_0",
2179                 bkpinfo->isodir, MAX_STR_LEN / 4)) {
2180                log_to_screen("User has chosen not to backup the PC");
2181                finish(1);
2182            }
2183            if (archiving_to_media) {
2184                if ((bkpinfo->compression_level =
2185                     which_compression_level()) == -1) {
2186                    log_to_screen("User has chosen not to backup the PC");
2187                    finish(1);
2188                }
2189                if (!popup_and_get_string
2190                    ("ISO size.",
2191                     "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.",
2192                     sz_size, 16)) {
2193                    log_to_screen("User has chosen not to backup the PC");
2194                    finish(1);
2195                }
2196                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2197                    bkpinfo->media_size[i] = atoi(sz_size);
2198                }
2199                if (!popup_and_get_string
2200                    ("Prefix.",
2201                     "Please enter the prefix that will be prepended to your ISO filename.  Example: machine1 to obtain machine1-[1-9]*.iso files",
2202                     bkpinfo->prefix, MAX_STR_LEN / 4)) {
2203                    log_to_screen("User has chosen not to backup the PC");
2204                    finish(1);
2205                }
2206            } else {
2207                for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
2208                    bkpinfo->media_size[i] = 650;
2209                }
2210            }
2211        }
2212        break;
2213    default:
2214        fatal_error
2215            ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
2216    }
2217    if (archiving_to_media) {
2218
2219#ifdef __FreeBSD__
2220        strcpy(bkpinfo->boot_device,
2221               call_program_and_get_last_line_of_output
2222               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
2223#else
2224        strcpy(bkpinfo->boot_device,
2225               call_program_and_get_last_line_of_output
2226               ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
2227#endif
2228        i = which_boot_loader(bkpinfo->boot_device);
2229        if (i == 'U')           // unknown
2230        {
2231
2232#ifdef __FreeBSD__
2233            if (!popup_and_get_string
2234                ("Boot device",
2235                 "What is your boot device? (e.g. /dev/ad0)",
2236                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2237                log_to_screen("User has chosen not to backup the PC");
2238                finish(1);
2239            }
2240            i = which_boot_loader(bkpinfo->boot_device);
2241#else
2242            if (!popup_and_get_string
2243                ("Boot device",
2244                 "What is your boot device? (e.g. /dev/hda)",
2245                 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2246                log_to_screen("User has chosen not to backup the PC");
2247                finish(1);
2248            }
2249            if (does_string_exist_in_boot_block
2250                (bkpinfo->boot_device, "LILO")) {
2251                i = 'L';
2252            } else
2253                if (does_string_exist_in_boot_block
2254                    (bkpinfo->boot_device, "ELILO")) {
2255                i = 'E';
2256            } else
2257                if (does_string_exist_in_boot_block
2258                    (bkpinfo->boot_device, "GRUB")) {
2259                i = 'G';
2260            } else {
2261                i = 'U';
2262            }
2263#endif
2264            if (i == 'U') {
2265                if (ask_me_yes_or_no
2266                    ("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?"))
2267                {
2268                    i = 'R';    // raw
2269                } else {
2270                    log_to_screen
2271                        ("I cannot find your boot loader. Please run mondoarchive with parameters.");
2272                    finish(1);
2273                }
2274            }
2275        }
2276        bkpinfo->boot_loader = i;
2277        strcpy(bkpinfo->include_paths, "/");
2278        if (!popup_and_get_string
2279            ("Backup paths",
2280             "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
2281             bkpinfo->include_paths, MAX_STR_LEN)) {
2282            log_to_screen("User has chosen not to backup the PC");
2283            finish(1);
2284        }
2285        strcpy(tmp, list_of_NFS_mounts_only());
2286        if (strlen(tmp) > 2) {
2287            if (bkpinfo->exclude_paths[0]) {
2288                strcat(bkpinfo->exclude_paths, " ");
2289            }
2290            strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
2291        }
2292// NTFS
2293        strcpy(tmp,
2294               call_program_and_get_last_line_of_output
2295               ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
2296        if (strlen(tmp) > 2) {
2297            if (!popup_and_get_string
2298                ("NTFS partitions",
2299                 "Please enter/confirm the NTFS partitions you wish to backup as well.",
2300                 tmp, MAX_STR_LEN / 4)) {
2301                log_to_screen("User has chosen not to backup the PC");
2302                finish(1);
2303            }
2304            strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
2305        }
2306
2307
2308        if (!popup_and_get_string
2309            ("Exclude paths",
2310             "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.",
2311             bkpinfo->exclude_paths, MAX_STR_LEN)) {
2312            log_to_screen("User has chosen not to backup the PC");
2313            finish(1);
2314        }
2315        bkpinfo->make_cd_use_lilo = FALSE;
2316        bkpinfo->backup_data = TRUE;
2317        bkpinfo->verify_data =
2318            ask_me_yes_or_no
2319            ("Will you want to verify your backups after Mondo has created them?");
2320
2321#ifndef __FreeBSD__
2322        if (!ask_me_yes_or_no
2323            ("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."))
2324#endif
2325        {
2326            strcpy(bkpinfo->kernel_path, "FAILSAFE");
2327        }
2328
2329        if (!ask_me_yes_or_no
2330            ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2331            log_to_screen("User has chosen not to backup the PC");
2332            finish(1);
2333        }
2334    } else {
2335        bkpinfo->restore_data = TRUE;   // probably...
2336    }
2337
2338    if (bkpinfo->backup_media_type == iso
2339        || bkpinfo->backup_media_type == nfs) {
2340        g_ISO_restore_mode = TRUE;
2341    }
2342#ifdef __FreeSD__
2343// skip
2344#else
2345    if (bkpinfo->backup_media_type == nfs) {
2346        sprintf(tmp, "mount | grep \"%s\" | cut -d' ' -f3",
2347                bkpinfo->nfs_mount);
2348//      strcpy(bkpinfo->isodir, call_program_and_get_last_line_of_output(tmp));
2349        log_msg(3, "I think the NFS mount is mounted at %s",
2350                bkpinfo->isodir);
2351    }
2352    log_it("isodir = %s", bkpinfo->isodir);
2353    log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
2354#endif
2355
2356    log_it("media device = %s", bkpinfo->media_device);
2357    log_it("media size = %ld", bkpinfo->media_size[1]);
2358    log_it("media type = %s",
2359           bkptype_to_string(bkpinfo->backup_media_type));
2360    log_it("compression = %ld", bkpinfo->compression_level);
2361    log_it("include_paths = '%s'", bkpinfo->include_paths);
2362    log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
2363    log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2364    log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2365    log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
2366           bkpinfo->boot_loader);
2367    log_it("prefix = %s", bkpinfo->prefix);
2368    if (bkpinfo->media_size[0] < 0) {
2369        if (archiving_to_media) {
2370            fatal_error("Media size is less than zero.");
2371        } else {
2372            log_msg(2, "Warning - media size is less than zero.");
2373            bkpinfo->media_size[0] = 0;
2374        }
2375    }
2376    paranoid_free(tmp);
2377    paranoid_free(sz_size);
2378    paranoid_free(command);
2379    paranoid_free(comment);
2380    paranoid_free(prompt);
2381    return (0);
2382}
2383
2384
2385
2386
2387/**
2388 * @addtogroup utilityGroup
2389 * @{
2390 */
2391/**
2392 * Get a space-separated list of NFS devices and mounts.
2393 * @return The list created.
2394 * @note The return value points to static data that will be overwritten with each call.
2395 */
2396char *list_of_NFS_devices_and_mounts(void)
2397{
2398    char *exclude_these_devices;
2399    char *exclude_these_directories;
2400    static char result_sz[512];
2401
2402    malloc_string(exclude_these_devices);
2403    malloc_string(exclude_these_directories);
2404    strcpy(exclude_these_directories,
2405           call_program_and_get_last_line_of_output
2406           ("mount -t coda,ncpfs,nfs,smbfs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2407    strcpy(exclude_these_devices,
2408           call_program_and_get_last_line_of_output
2409           ("cat /etc/fstab | tr -s '\t' ' ' | grep -E '( (coda|ncpfs|nfs|smbfs) )' | cut -d' ' -f1 | tr -s '\n' ' ' | awk '{print $0;}'"));
2410    sprintf(result_sz, "%s %s", exclude_these_directories,
2411            exclude_these_devices);
2412    paranoid_free(exclude_these_devices);
2413    paranoid_free(exclude_these_directories);
2414    return (result_sz);
2415}
2416
2417
2418
2419
2420/**
2421 * Get a space-separated list of NFS mounts.
2422 * @return The list created.
2423 * @note The return value points to static data that will be overwritten with each call.
2424 * @bug Even though we only want the mounts, the devices are still checked.
2425 */
2426char *list_of_NFS_mounts_only(void)
2427{
2428    char *exclude_these_devices;
2429    char *exclude_these_directories;
2430    static char result_sz[512];
2431
2432    malloc_string(exclude_these_devices);
2433    malloc_string(exclude_these_directories);
2434    strcpy(exclude_these_directories,
2435           call_program_and_get_last_line_of_output
2436           ("mount -t coda,ncpfs,nfs,smbfs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2437    strcpy(exclude_these_devices,
2438           call_program_and_get_last_line_of_output
2439           ("cat /etc/fstab | tr -s '\t' ' ' | grep -E '( (coda|ncpfs|nfs|smbfs) )' | cut -d' ' -f1 | tr -s '\n' ' ' | awk '{print $0;}'"));
2440    sprintf(result_sz, "%s", exclude_these_directories);
2441    paranoid_free(exclude_these_devices);
2442    paranoid_free(exclude_these_directories);
2443    return (result_sz);
2444}
2445
2446/* @} - end of utilityGroup */
2447
2448
2449
2450
2451
2452/**
2453 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2454 * [random] is a random number between 1 and 32767.
2455 * @param store_name_here Where to store the new filename.
2456 * @param stub A random number will be appended to this to make the FIFO's name.
2457 * @ingroup deviceGroup
2458 */
2459void make_fifo(char *store_name_here, char *stub)
2460{
2461    char *tmp;
2462
2463    malloc_string(tmp);
2464    assert_string_is_neither_NULL_nor_zerolength(stub);
2465
2466    sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2467            (int) (random() % 32768));
2468    make_hole_for_file(store_name_here);
2469    mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2470    sprintf(tmp, "chmod 770 %s", store_name_here);
2471    paranoid_system(tmp);
2472    paranoid_free(tmp);
2473}
2474
2475
2476
2477
2478
2479
2480/**
2481 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2482 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2483 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2484 * @ingroup utilityGroup
2485 */
2486void sensibly_set_tmpdir_and_scratchdir(struct s_bkpinfo *bkpinfo)
2487{
2488    char *tmp, *command, *sz;
2489
2490    malloc_string(tmp);
2491    malloc_string(command);
2492    malloc_string(sz);
2493    assert(bkpinfo != NULL);
2494
2495#ifdef __FreeBSD__
2496    strcpy(tmp,
2497           call_program_and_get_last_line_of_output
2498           ("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;}'"));
2499#else
2500    strcpy(tmp,
2501           call_program_and_get_last_line_of_output
2502           ("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;}'"));
2503#endif
2504
2505    if (tmp[0] != '/') {
2506        strcpy(sz, tmp);
2507        strcpy(tmp, "/");
2508        strcat(tmp, sz);
2509    }
2510    if (!tmp[0]) {
2511        fatal_error("I couldn't figure out the tempdir!");
2512    }
2513    sprintf(bkpinfo->tmpdir, "%s/tmp.mondo.%d", tmp,
2514            (int) (random() % 32768));
2515    log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2516
2517    sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp,
2518            (int) (random() % 32768));
2519    log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2520
2521    sprintf(g_erase_tmpdir_and_scratchdir, "rm -Rf %s %s", bkpinfo->tmpdir,
2522            bkpinfo->scratchdir);
2523
2524    sprintf(command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2525    paranoid_system(command);
2526    paranoid_free(tmp);
2527    paranoid_free(command);
2528    paranoid_free(sz);
2529}
2530
2531
2532
2533
2534
2535
2536/**
2537 * @addtogroup deviceGroup
2538 * @{
2539 */
2540/**
2541 * If we can read @p dev, set @p output to it.
2542 * If @p dev cannot be read, set @p output to "".
2543 * @param dev The device to check for.
2544 * @param output Set to @p dev if @p dev exists, "" otherwise.
2545 * @return TRUE if @p dev exists, FALSE if it doesn't.
2546 */
2547bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2548{
2549    char *command;
2550
2551    malloc_string(command);
2552    if (!dev || dev[0] == '\0') {
2553        output[0] = '\0';
2554        return (FALSE);
2555    }
2556//  assert_string_is_neither_NULL_nor_zerolength(dev);
2557    log_msg(10, "Injecting %s", dev);
2558    inject_device(dev);
2559    if (!does_file_exist(dev)) {
2560        log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2561        return (FALSE);
2562    }
2563    sprintf(command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2564            512L, dev);
2565    if (!run_program_and_log_output(command, FALSE)
2566        && !run_program_and_log_output(command, FALSE)) {
2567        strcpy(output, dev);
2568        log_msg(4, "Found it - %s", dev);
2569        return (TRUE);
2570    } else {
2571        output[0] = '\0';
2572        log_msg(4, "It's not %s", dev);
2573        return (FALSE);
2574    }
2575}
2576
2577
2578
2579
2580
2581/**
2582 * Find out what number CD is in the drive.
2583 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2584 * @return The current CD number, or -1 if it could not be found.
2585 * @note If the CD is not mounted, it will be mounted
2586 * (and remain mounted after this function returns).
2587 */
2588int what_number_cd_is_this(struct s_bkpinfo *bkpinfo)
2589{
2590    int cd_number = -1;
2591    char *mountdev;
2592    char *tmp;
2593
2594    malloc_string(mountdev);
2595    malloc_string(tmp);
2596    assert(bkpinfo != NULL);
2597//  log_it("Asking what_number_cd_is_this");
2598    if (g_ISO_restore_mode) {
2599        sprintf(tmp, "mount | grep iso9660 | awk '{print $3;}'");
2600//      log_it("tmp = %s", tmp);
2601
2602        strcpy(mountdev, call_program_and_get_last_line_of_output(tmp));
2603        strcat(mountdev, "/archives/THIS-CD-NUMBER");
2604//      log_it("mountdev = %s", mountdev);
2605        cd_number = atoi(last_line_of_file(mountdev));
2606//      log_it("cd_number = %d", cd_number);
2607        paranoid_free(mountdev);
2608        paranoid_free(tmp);
2609        return (cd_number);
2610    }
2611
2612    strcpy(mountdev, bkpinfo->media_device);
2613    if (!mountdev[0]) {
2614        log_it
2615            ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2616        find_cdrom_device(bkpinfo->media_device, FALSE);
2617    }
2618    if (!is_this_device_mounted(MNT_CDROM)) {
2619        mount_CDROM_here(mountdev, MNT_CDROM);
2620    }
2621    cd_number =
2622        atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2623//  log_it("cd_number..later.. = %d", cd_number);
2624    paranoid_free(mountdev);
2625    paranoid_free(tmp);
2626    return (cd_number);
2627}
2628
2629
2630
2631
2632
2633
2634
2635/**
2636 * Find out what device is mounted as root (/).
2637 * @return Root device.
2638 * @note The returned string points to static storage and will be overwritten with every call.
2639 * @bug A bit of a misnomer; it's actually finding out the root device.
2640 * The mountpoint (where it's mounted) will obviously be '/'.
2641 */
2642char *where_is_root_mounted()
2643{
2644    /*@ buffers **************** */
2645    static char tmp[MAX_STR_LEN];
2646
2647
2648#ifdef __FreeBSD__
2649    strcpy(tmp, call_program_and_get_last_line_of_output
2650           ("mount | grep \" on / \" | cut -d' ' -f1"));
2651#else
2652    strcpy(tmp, call_program_and_get_last_line_of_output
2653           ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2654    if (strstr(tmp, "/dev/cciss/")) {
2655        strcpy(tmp, call_program_and_get_last_line_of_output
2656               ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2657    }
2658    if (strstr(tmp, "/dev/md")) {
2659        strcpy(tmp,
2660               call_program_and_get_last_line_of_output
2661               ("mount | grep \" on / \" | cut -d' ' -f1"));
2662    }
2663#endif
2664
2665    return (tmp);
2666}
2667
2668
2669/**
2670 * Find out which boot loader is in use.
2671 * @param which_device Device to look for the boot loader on.
2672 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2673 * @note Under Linux, all drives are examined, not just @p which_device.
2674 */
2675#ifdef __FreeBSD__
2676char which_boot_loader(char *which_device)
2677{
2678    int count_lilos = 0;
2679    int count_grubs = 0;
2680    int count_boot0s = 0;
2681    int count_dangerouslydedicated = 0;
2682
2683    log_it("looking at drive %s's MBR", which_device);
2684    if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2685        count_grubs++;
2686    }
2687    if (does_string_exist_in_boot_block(which_device, "LILO")) {
2688        count_lilos++;
2689    }
2690    if (does_string_exist_in_boot_block(which_device, "Drive")) {
2691        count_boot0s++;
2692    }
2693    if (does_string_exist_in_first_N_blocks
2694        (which_device, "FreeBSD/i386", 17)) {
2695        count_dangerouslydedicated++;
2696    }
2697    log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2698           count_grubs, count_lilos, count_elilos, count_boot0s,
2699           count_dangerouslydedicated);
2700
2701    if (count_grubs && !count_lilos) {
2702        return ('G');
2703    } else if (count_lilos && !count_grubs) {
2704        return ('L');
2705    } else if (count_grubs == 1 && count_lilos == 1) {
2706        log_it("I'll bet you used to use LILO but switched to GRUB...");
2707        return ('G');
2708    } else if (count_boot0s == 1) {
2709        return ('B');
2710    } else if (count_dangerouslydedicated) {
2711        return ('D');
2712    } else {
2713        log_it("Unknown boot loader");
2714        return ('U');
2715    }
2716}
2717
2718#else
2719
2720char which_boot_loader(char *which_device)
2721{
2722    /*@ buffer ***************************************************** */
2723    char *list_drives_cmd;
2724    char *current_drive;
2725
2726    /*@ pointers *************************************************** */
2727    FILE *pdrives;
2728
2729    /*@ int ******************************************************** */
2730    int count_lilos = 0;
2731    int count_grubs = 0;
2732
2733    /*@ end vars *************************************************** */
2734
2735    malloc_string(list_drives_cmd);
2736    malloc_string(current_drive);
2737
2738#ifdef __IA64__
2739    /* No choice for it */
2740    return ('E');
2741#endif
2742    assert(which_device != NULL);
2743    //  sprintf (list_drives_cmd,
2744    //       "fdisk -l | grep /dev | grep cyl | tr ':' ' ' | cut -d' ' -f2");
2745
2746    sprintf(list_drives_cmd,
2747            // "parted2fdisk
2748            "fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s",
2749            where_is_root_mounted());
2750    log_it("list_drives_cmd = %s", list_drives_cmd);
2751
2752    if (!(pdrives = popen(list_drives_cmd, "r"))) {
2753        log_OS_error("Unable to open list of drives");
2754        paranoid_free(list_drives_cmd);
2755        paranoid_free(current_drive);
2756        return ('\0');
2757    }
2758    for (fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
2759         fgets(current_drive, MAX_STR_LEN, pdrives)) {
2760        strip_spaces(current_drive);
2761        log_it("looking at drive %s's MBR", current_drive);
2762        if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2763            count_grubs++;
2764            strcpy(which_device, current_drive);
2765            break;
2766        }
2767        if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2768            count_lilos++;
2769            strcpy(which_device, current_drive);
2770            break;
2771        }
2772    }
2773    if (pclose(pdrives)) {
2774        log_OS_error("Cannot pclose pdrives");
2775    }
2776    log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2777    paranoid_free(list_drives_cmd);
2778    paranoid_free(current_drive);
2779    if (count_grubs && !count_lilos) {
2780        return ('G');
2781    } else if (count_lilos && !count_grubs) {
2782        return ('L');
2783    } else if (count_grubs == 1 && count_lilos == 1) {
2784        log_it("I'll bet you used to use LILO but switched to GRUB...");
2785        return ('G');
2786    } else {
2787        log_it("Unknown boot loader");
2788        return ('U');
2789    }
2790}
2791#endif
2792
2793
2794
2795
2796/**
2797 * Write zeroes over the first 16K of @p device.
2798 * @param device The device to zero.
2799 * @return 0 for success, 1 for failure.
2800 */
2801int zero_out_a_device(char *device)
2802{
2803    FILE *fout;
2804    int i;
2805
2806    assert_string_is_neither_NULL_nor_zerolength(device);
2807
2808    log_it("Zeroing drive %s", device);
2809    if (!(fout = fopen(device, "w"))) {
2810        log_OS_error("Unable to open/write to device");
2811        return (1);
2812    }
2813    for (i = 0; i < 16384; i++) {
2814        fputc('\0', fout);
2815    }
2816    paranoid_fclose(fout);
2817    log_it("Device successfully zeroed.");
2818    return (0);
2819}
2820
2821/**
2822 * Return the device pointed to by @p incoming.
2823 * @param incoming The device to resolve symlinks for.
2824 * @return The path to the real device file.
2825 * @note The returned string points to static storage that will be overwritten with each call.
2826 * @bug Won't work with file v4.0; needs to be written in C.
2827 */
2828char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2829{
2830    static char output[MAX_STR_LEN];
2831    char *command;
2832    char *curr_fname;
2833    char *scratch;
2834    char *tmp;
2835    char *p;
2836
2837    struct stat statbuf;
2838    command = malloc(1000);
2839    malloc_string(tmp);
2840    malloc_string(scratch);
2841    malloc_string(curr_fname);
2842    if (!does_file_exist(incoming)) {
2843        log_it
2844            ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2845        strcpy(output, incoming);
2846    } else {
2847        strcpy(curr_fname, incoming);
2848        lstat(curr_fname, &statbuf);
2849        while (S_ISLNK(statbuf.st_mode)) {
2850            log_msg(1, "curr_fname = %s", curr_fname);
2851            sprintf(command, "file %s", curr_fname);
2852            strcpy(tmp, call_program_and_get_last_line_of_output(command));
2853            for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2854                 p--);
2855            p++;
2856            strcpy(scratch, p);
2857            for (p = scratch; *p != '\0' && *p != '\''; p++);
2858            *p = '\0';
2859            log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp,
2860                    scratch);
2861            if (scratch[0] == '/') {
2862                strcpy(curr_fname, scratch);    // copy whole thing because it's an absolute softlink
2863            } else {            // copy over the basename cos it's a relative softlink
2864                p = curr_fname + strlen(curr_fname);
2865                while (p != curr_fname && *p != '/') {
2866                    p--;
2867                }
2868                if (*p == '/') {
2869                    p++;
2870                }
2871                strcpy(p, scratch);
2872            }
2873            lstat(curr_fname, &statbuf);
2874        }
2875        strcpy(output, curr_fname);
2876        log_it("resolved %s to %s", incoming, output);
2877    }
2878    paranoid_free(command);
2879    paranoid_free(curr_fname);
2880    paranoid_free(tmp);
2881    return (output);
2882}
2883
2884/* @} - end of deviceGroup */
2885
2886
2887/**
2888 * Return the type of partition format (GPT or MBR)
2889 */
2890char *which_partition_format(const char *drive)
2891{
2892    static char output[4];
2893    char *tmp;
2894    char *command;
2895    char *fdisk;
2896
2897    malloc_string(tmp);
2898    malloc_string(command);
2899    malloc_string(fdisk);
2900    log_msg(0, "Looking for partition table format type");
2901// BERLIOS: Do that temporarily: we need to put back parted2fdisk everywhere
2902#ifdef __IA64__
2903    struct stat buf;
2904
2905    sprintf(fdisk, "/usr/local/bin/fdisk");
2906    if (stat(fdisk, &buf) != 0) {
2907#endif
2908        sprintf(fdisk, "/sbin/fdisk");
2909#ifdef __IA64__
2910    }
2911#endif
2912    log_msg(1, "Using %s", fdisk);
2913    sprintf(command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2914    strcpy(tmp, call_program_and_get_last_line_of_output(command));
2915    if (strstr(tmp, "GPT") == NULL) {
2916        strcpy(output, "MBR");
2917    } else {
2918        strcpy(output, "GPT");
2919    }
2920    log_msg(0, "Found %s partition table format type", output);
2921    paranoid_free(command);
2922    paranoid_free(tmp);
2923    paranoid_free(fdisk);
2924    return (output);
2925}
2926
2927/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.