source: MondoRescue/branches/stable/mondo/src/common/libmondo-devices.c@ 1574

Last change on this file since 1574 was 1574, checked in by Bruno Cornec, 17 years ago

More improvements on tape patch (/dev/st0 has to be the default)

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