source: MondoRescue/branches/2.2.6/mondo/src/common/libmondo-devices.c@ 1917

Last change on this file since 1917 was 1917, checked in by Bruno Cornec, 16 years ago

mondo.libmondo-cli.patch (Mark Pinkerton <Mark.Pinkerton_at_emageon.com>) modified to not duplicate the newt initialization stuff (we should rather remove them in mondoarchive)

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