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

Last change on this file since 2306 was 2306, checked in by Bruno Cornec, 15 years ago
  • popup_and_get_string needs an allocated buffer for the moment so fixing the calls with dyn. ones
  • Fix a bug in mem.c for mr_strcat, which wasn't modifying the right pointer level

Ported from 2.2.9

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