source: MondoRescue/branches/2.2.10/mondo/src/common/libmondo-devices.c@ 2291

Last change on this file since 2291 was 2291, checked in by Bruno Cornec, 15 years ago
  • Fix a printing error in mindi for the tar command
  • Fix all mr_asprintf which had no second param as a string

(report bug fix done originaly in 2.2.9)

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