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

Last change on this file since 2266 was 2266, checked in by Bruno Cornec, 15 years ago

r3207@localhost: bruno | 2009-07-07 00:32:00 +0200

  • Replace sprintf by mr_asprintf in libmondo-devices.c
  • 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 2266 2009-07-12 00:04:45Z 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 2266 2009-07-12 00:04:45Z 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",
1145 SWAPLIST_COMMAND, device_with_space);
1146 log_msg(4, "tmp (command) = '%s'", tmp);
1147 if (!system(tmp)) {
1148 retval = TRUE;
1149 }
1150 mr_free(tmp);
1151 paranoid_free(incoming);
1152 return(retval);
1153}
1154
1155#ifdef __FreeBSD__
1156// CODE IS FREEBSD-SPECIFIC
1157/**
1158 * Create a loopback device for specified @p fname.
1159 * @param fname The file to associate with a device.
1160 * @return /dev entry for the device, or NULL if it couldn't be allocated.
1161 */
1162char *make_vn(char *fname)
1163{
1164 char *device = (char *) malloc(MAX_STR_LEN);
1165 char *mddevice = (char *) malloc(32);
1166 char command[MAX_STR_LEN];
1167 int vndev = 2;
1168 if (atoi
1169 (call_program_and_get_last_line_of_output
1170 ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1171 do {
1172 sprintf(mddevice, "vn%ic", vndev++);
1173 sprintf(command, "vnconfig %s %s", mddevice, fname);
1174 if (vndev > 10) {
1175 return NULL;
1176 }
1177 }
1178 while (system(command));
1179 } else {
1180 sprintf(command, "mdconfig -a -t vnode -f %s", fname);
1181 mddevice = call_program_and_get_last_line_of_output(command);
1182 if (!strstr(mddevice, "md")) {
1183 return NULL;
1184 }
1185 }
1186 sprintf(device, "/dev/%s", mddevice);
1187 return device;
1188}
1189
1190
1191
1192// CODE IS FREEBSD-SPECIFIC
1193/**
1194 * Deallocate specified @p dname.
1195 * This should be called when you are done with the device created by make_vn(),
1196 * so the system does not run out of @c vn devices.
1197 * @param dname The device to deallocate.
1198 * @return 0 for success, nonzero for failure.
1199 */
1200int kick_vn(char *dname)
1201{
1202 char *command = NULL;
1203 int res = 0;
1204
1205 if (strncmp(dname, "/dev/", 5) == 0) {
1206 dname += 5;
1207 }
1208
1209 if (atoi
1210 (call_program_and_get_last_line_of_output
1211 ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1212 mr_asprintf(&command, "vnconfig -d %s", dname);
1213 } else {
1214 mr_asprintf(&command, "mdconfig -d -u %s", dname);
1215 }
1216 res = system(command);
1217 mr_free(command);
1218 return(res);
1219}
1220#endif
1221
1222
1223/**
1224 * Mount the CD-ROM at @p mountpoint.
1225 * @param device The device (or file if g_ISO_restore_mode) to mount.
1226 * @param mountpoint The place to mount it.
1227 * @return 0 for success, nonzero for failure.
1228 */
1229int mount_USB_here(char *device, char *mountpoint)
1230{
1231 /*@ buffer ****************************************************** */
1232 char *command = NULL;
1233 int retval;
1234
1235 assert_string_is_neither_NULL_nor_zerolength(device);
1236 assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1237
1238 make_hole_for_dir(mountpoint);
1239 if (isdigit(device[0])) {
1240 return(1);
1241 }
1242 log_msg(4, "(mount_USB_here --- device=%s, mountpoint=%s", device,
1243 mountpoint);
1244
1245#ifdef __FreeBSD__
1246 mr_asprintf(&command, "mount_vfat %s %s 2>> %s",
1247 device, mountpoint, MONDO_LOGFILE);
1248
1249#else
1250 mr_asprintf(&command, "mount %s -t vfat %s 2>> %s",
1251 device, mountpoint, MONDO_LOGFILE);
1252#endif
1253
1254 log_msg(4, command);
1255 retval = system(command);
1256 log_msg(1, "system(%s) returned %d", command, retval);
1257 mr_free(command);
1258
1259 return (retval);
1260}
1261
1262/**
1263 * Mount the CD-ROM at @p mountpoint.
1264 * @param device The device (or file if g_ISO_restore_mode) to mount.
1265 * @param mountpoint The place to mount it.
1266 * @return 0 for success, nonzero for failure.
1267 */
1268int mount_CDROM_here(char *device, char *mountpoint)
1269{
1270 /*@ buffer ****************************************************** */
1271 char *command = NULL;
1272 int retval;
1273#ifdef __FreeBSD__
1274 char *dev = NULL;
1275#else
1276 char *options = NULL;
1277#endif
1278
1279 assert_string_is_neither_NULL_nor_zerolength(device);
1280 assert_string_is_neither_NULL_nor_zerolength(mountpoint);
1281
1282 make_hole_for_dir(mountpoint);
1283
1284 if (isdigit(device[0])) {
1285 find_cdrom_device(device, FALSE);
1286 }
1287#ifndef __FreeBSD__
1288 mr_asprintf(&options, "ro");
1289#endif
1290
1291 if (g_ISO_restore_mode) {
1292
1293#ifdef __FreeBSD__
1294 mr_asprintf(&dev, make_vn(device));
1295 if (!dev) {
1296 mr_asprintf(&command, "Unable to mount ISO (make_vn(%s) failed)", device);
1297 fatal_error(command);
1298 }
1299 strcpy(device, dev);
1300 paranoid_free(dev);
1301#else
1302 mr_strcat(options, ",loop");
1303#endif
1304
1305 }
1306 log_msg(4, "(mount_CDROM_here --- device=%s, mountpoint=%s", device,
1307 mountpoint);
1308 /*@ end vars *************************************************** */
1309
1310#ifdef __FreeBSD__
1311 mr_asprintf(&command, "mount_cd9660 -r %s %s 2>> %s",
1312 device, mountpoint, MONDO_LOGFILE);
1313
1314#else
1315 mr_asprintf(&command, "mount %s -o %s -t iso9660 %s 2>> %s",
1316 device, options, mountpoint, MONDO_LOGFILE);
1317 paranoid_free(options);
1318#endif
1319
1320 log_msg(4, command);
1321 if (strncmp(device, "/dev/", 5) == 0) {
1322 retract_CD_tray_and_defeat_autorun();
1323 }
1324 retval = system(command);
1325 log_msg(1, "system(%s) returned %d", command, retval);
1326 paranoid_free(command);
1327
1328 return (retval);
1329}
1330
1331
1332
1333
1334
1335
1336/**
1337 * Ask the user for CD number @p cd_number_i_want.
1338 * Sets g_current_media_number once the correct CD is inserted.
1339 * @param bkpinfo The backup information structure. Fields used:
1340 * - @c bkpinfo->backup_media_type
1341 * - @c bkpinfo->prefix
1342 * - @c bkpinfo->isodir
1343 * - @c bkpinfo->media_device
1344 * - @c bkpinfo->please_dont_eject_when_restoring
1345 * @param cd_number_i_want The CD number to ask for.
1346 */
1347void
1348insist_on_this_cd_number(int cd_number_i_want)
1349{
1350
1351 /*@ int ************************************************************* */
1352 int res = 0;
1353
1354
1355 /*@ buffers ********************************************************* */
1356 char *tmp = NULL;
1357 char *mds = NULL;
1358 char *request = NULL;
1359
1360 assert(bkpinfo != NULL);
1361 assert(cd_number_i_want > 0);
1362
1363// log_msg(3, "Insisting on CD number %d", cd_number_i_want);
1364
1365 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1366 log_msg(3,
1367 "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1368 return;
1369 }
1370 mr_asprintf(&tmp, "mkdir -p " MNT_CDROM);
1371 run_program_and_log_output(tmp, 5);
1372 mr_free(tmp);
1373
1374 if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso
1375 || bkpinfo->backup_media_type == nfs) {
1376 log_msg(3, "Remounting CD");
1377 g_ISO_restore_mode = TRUE;
1378 // FIXME --- I'm tempted to do something about this...
1379 // Why unmount and remount again and again?
1380 if (is_this_device_mounted(MNT_CDROM)) {
1381 run_program_and_log_output("umount " MNT_CDROM, 5);
1382 }
1383 mr_asprintf(&tmp, "mkdir -p %s/isodir &> /dev/null", bkpinfo->tmpdir);
1384 (void)system(tmp);
1385 mr_free(tmp);
1386
1387 mr_asprintf(&tmp, "%s/%s/%s-%d.iso", bkpinfo->isodir,
1388 bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1389 cd_number_i_want);
1390 if (!does_file_exist(tmp)) {
1391 mr_free(tmp);
1392 mr_asprintf(&tmp, "%s/isodir/%s/%s-%d.iso", bkpinfo->tmpdir,
1393 bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1394 cd_number_i_want);
1395 if (does_file_exist(tmp)) {
1396 log_msg(1,
1397 "FIXME - hacking bkpinfo->isodir from '%s' to %s/isodir",
1398 bkpinfo->isodir, bkpinfo->tmpdir);
1399 sprintf(bkpinfo->isodir, "%s/isodir", bkpinfo->tmpdir);
1400 }
1401 }
1402 log_msg(3, "Mounting %s at %s", tmp, MNT_CDROM);
1403 if (mount_CDROM_here(tmp, MNT_CDROM)) {
1404 mr_free(tmp);
1405 fatal_error("Mommy!");
1406 }
1407 mr_free(tmp);
1408 }
1409 if ((res = what_number_cd_is_this()) != cd_number_i_want) {
1410 log_msg(3, "Currently, we hold %d but we want %d", res,
1411 cd_number_i_want);
1412 mds = media_descriptor_string(bkpinfo->backup_media_type);
1413 mr_asprintf(&tmp, "Insisting on %s #%d", mds, cd_number_i_want);
1414 mr_asprintf(&request, "Please insert %s #%d and press Enter.", mds, cd_number_i_want);
1415 mr_free(mds);
1416 log_msg(3, tmp);
1417 mr_free(tmp);
1418
1419 while (what_number_cd_is_this() != cd_number_i_want) {
1420 paranoid_system("sync");
1421 if (is_this_device_mounted(MNT_CDROM)) {
1422 res =
1423 run_program_and_log_output("umount " MNT_CDROM, FALSE);
1424 } else {
1425 res = 0;
1426 }
1427 if (res) {
1428 log_to_screen("WARNING - failed to unmount CD-ROM drive");
1429 }
1430 if (!bkpinfo->please_dont_eject) {
1431 res = eject_device(bkpinfo->media_device);
1432 } else {
1433 res = 0;
1434 }
1435 if (res) {
1436 log_to_screen("WARNING - failed to eject CD-ROM disk");
1437 }
1438 popup_and_OK(request);
1439 if (!bkpinfo->please_dont_eject) {
1440 inject_device(bkpinfo->media_device);
1441 }
1442 paranoid_system("sync");
1443 }
1444 mr_free(request);
1445
1446 log_msg(1, "Thankyou. Proceeding...");
1447 g_current_media_number = cd_number_i_want;
1448 }
1449}
1450
1451/* @} - end of deviceGroup */
1452
1453
1454/**
1455 * Ask user for details of backup/restore information.
1456 * Called when @c mondoarchive doesn't get any parameters.
1457 * @param bkpinfo The backup information structure to fill out with the user's data.
1458 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
1459 * @return 0, always.
1460 * @bug No point of `int' return value.
1461 * @ingroup archiveGroup
1462 */
1463int interactively_obtain_media_parameters_from_user(bool archiving_to_media)
1464// archiving_to_media is TRUE if I'm being called by mondoarchive
1465// archiving_to_media is FALSE if I'm being called by mondorestore
1466{
1467 char *tmp = NULL;
1468 char *mds = NULL;
1469 char *sz_size = NULL;
1470 char *command = NULL;
1471 char *comment = NULL;
1472 char *prompt;
1473 int i;
1474 FILE *fin;
1475
1476 malloc_string(prompt);
1477 malloc_string(sz_size);
1478 assert(bkpinfo != NULL);
1479 bkpinfo->nonbootable_backup = FALSE;
1480
1481 // Tape, CD, NFS, ...?
1482 srandom(getpid());
1483 bkpinfo->backup_media_type =
1484 (g_restoring_live_from_cd) ? cdr :
1485 which_backup_media_type(bkpinfo->restore_data);
1486 if (bkpinfo->backup_media_type == none) {
1487 log_to_screen("User has chosen not to backup the PC");
1488 finish(1);
1489 }
1490 /* Why asking to remove the media with tape ?
1491 if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
1492 popup_and_OK("Please remove media from drive(s)");
1493 }
1494 */
1495 log_msg(3, "media type = %s",
1496 bkptype_to_string(bkpinfo->backup_media_type));
1497 if (archiving_to_media) {
1498 sensibly_set_tmpdir_and_scratchdir();
1499 }
1500 bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
1501 bkpinfo->compression_level =
1502 (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
1503 bkpinfo->use_lzo =
1504 (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
1505 mvaddstr_and_log_it(2, 0, " ");
1506
1507 // Find device's /dev (or SCSI) entry
1508 switch (bkpinfo->backup_media_type) {
1509 case cdr:
1510 case cdrw:
1511 case dvd:
1512 case usb:
1513 /* Never try to eject a USB device */
1514 if (bkpinfo->backup_media_type == usb) {
1515 bkpinfo->please_dont_eject = TRUE;
1516 }
1517 if (archiving_to_media) {
1518 if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1519 if (ask_me_yes_or_no
1520 ("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?"))
1521 {
1522 bkpinfo->manual_cd_tray = TRUE;
1523 }
1524 }
1525 if ((bkpinfo->compression_level =
1526 which_compression_level()) == -1) {
1527 log_to_screen("User has chosen not to backup the PC");
1528 finish(1);
1529 }
1530 mds = media_descriptor_string(bkpinfo->backup_media_type);
1531 mr_asprintf(&comment, "What speed is your %s (re)writer?", mds);
1532 if (bkpinfo->backup_media_type == dvd) {
1533 find_dvd_device(bkpinfo->media_device, FALSE);
1534 mr_asprintf(&tmp, "1");
1535 sprintf(sz_size, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4482 MB
1536 log_msg(1, "Setting to DVD defaults");
1537 } else {
1538 strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
1539 mr_asprintf(&tmp, "4");
1540 sprintf(sz_size, "%d", 650);
1541 log_msg(1, "Setting to CD defaults");
1542 }
1543 if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1544 if (!popup_and_get_string("Speed", comment, tmp, 4)) {
1545 log_to_screen("User has chosen not to backup the PC");
1546 mr_free(comment);
1547 finish(1);
1548 }
1549 }
1550 mr_free(comment);
1551
1552 bkpinfo->cdrw_speed = atoi(tmp); // if DVD then this shouldn't ever be used anyway :)
1553 mr_free(tmp);
1554
1555 mr_asprintf(&comment,
1556 "How much data (in Megabytes) will each %s store?", mds);
1557 mr_free(mds);
1558 if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1559 mr_free(comment);
1560 log_to_screen("User has chosen not to backup the PC");
1561 finish(1);
1562 }
1563 mr_free(comment);
1564
1565 for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1566 bkpinfo->media_size[i] = atoi(sz_size);
1567 }
1568
1569 if (bkpinfo->media_size[0] <= 0) {
1570 log_to_screen("User has chosen not to backup the PC");
1571 finish(1);
1572 }
1573 }
1574 /* No break because we continue even for usb */
1575 case cdstream:
1576 mds = media_descriptor_string(bkpinfo->backup_media_type);
1577
1578 if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
1579 strcpy(bkpinfo->media_device, "/dev/cdrom");
1580 log_msg(2, "CD-ROM device assumed to be at %s",
1581 bkpinfo->media_device);
1582 } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))
1583 || bkpinfo->backup_media_type == dvd) {
1584 if (!bkpinfo->media_device[0]) {
1585 strcpy(bkpinfo->media_device, "/dev/cdrom");
1586 } // just for the heck of it :)
1587 log_msg(1, "bkpinfo->media_device = %s",
1588 bkpinfo->media_device);
1589 if (bkpinfo->backup_media_type == dvd
1590 || find_cdrom_device(bkpinfo->media_device, FALSE)) {
1591 log_msg(1, "bkpinfo->media_device = %s",
1592 bkpinfo->media_device);
1593 mr_asprintf(&comment,
1594 "Please specify your %s drive's /dev entry", mds);
1595 if (!popup_and_get_string
1596 ("Device?", comment, bkpinfo->media_device,
1597 MAX_STR_LEN / 4)) {
1598 mr_free(comment);
1599 log_to_screen("User has chosen not to backup the PC");
1600 finish(1);
1601 }
1602 mr_free(comment);
1603 }
1604 log_msg(2, "%s device found at %s", mds, bkpinfo->media_device);
1605 } else {
1606 if ((find_cdrw_device(bkpinfo->media_device)) && (bkpinfo->backup_media_type != usb)) {
1607 bkpinfo->media_device[0] = '\0';
1608 }
1609 if (bkpinfo->media_device[0]) {
1610 if (bkpinfo->backup_media_type == usb) {
1611 mr_asprintf(&tmp,
1612 "I think your %s media corresponds to %s. Is this correct?", mds,
1613 bkpinfo->media_device);
1614 } else {
1615 mr_asprintf(&tmp,
1616 "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,
1617 bkpinfo->media_device);
1618 }
1619 if (!ask_me_yes_or_no(tmp)) {
1620 bkpinfo->media_device[0] = '\0';
1621 }
1622 mr_free(tmp);
1623 }
1624 if (!bkpinfo->media_device[0]) {
1625 if (bkpinfo->backup_media_type == usb) {
1626 i = popup_and_get_string("/dev entry?",
1627 "What is the /dev entry of your USB Disk/Key, please?",
1628 bkpinfo->media_device,
1629 MAX_STR_LEN / 4);
1630 } else {
1631 if (g_kernel_version < 2.6) {
1632 i = popup_and_get_string("Device node?",
1633 "What is the SCSI node of your CD (re)writer, please?",
1634 bkpinfo->media_device,
1635 MAX_STR_LEN / 4);
1636 } else {
1637 i = popup_and_get_string("/dev entry?",
1638 "What is the /dev entry of your CD (re)writer, please?",
1639 bkpinfo->media_device,
1640 MAX_STR_LEN / 4);
1641 }
1642 }
1643 if (!i) {
1644 log_to_screen("User has chosen not to backup the PC");
1645 finish(1);
1646 }
1647 }
1648 }
1649 mr_free(mds);
1650
1651 if (bkpinfo->backup_media_type == cdstream) {
1652 for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1653 bkpinfo->media_size[i] = 650;
1654 }
1655 }
1656 break;
1657 case udev:
1658 if (!ask_me_yes_or_no
1659 ("This option is for advanced users only. Are you sure?")) {
1660 log_to_screen("User has chosen not to backup the PC");
1661 finish(1);
1662 }
1663 case tape:
1664
1665 if ((!bkpinfo->restore_mode) && (find_tape_device_and_size(bkpinfo->media_device, sz_size))) {
1666 log_msg(3, "Ok, using vanilla scsi tape.");
1667 strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
1668 if ((fin = fopen(bkpinfo->media_device, "r"))) {
1669 paranoid_fclose(fin);
1670 } else {
1671 strcpy(bkpinfo->media_device, "/dev/osst0");
1672 }
1673 }
1674 if (bkpinfo->media_device[0]) {
1675 if ((fin = fopen(bkpinfo->media_device, "r"))) {
1676 paranoid_fclose(fin);
1677 } else {
1678 if (does_file_exist("/tmp/mondo-restore.cfg")) {
1679 read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
1680 bkpinfo->media_device);
1681 }
1682 }
1683 }
1684 if (bkpinfo->media_device[0]) {
1685 mr_asprintf(&tmp,
1686 "I think I've found your tape streamer at %s; am I right on the money?",
1687 bkpinfo->media_device);
1688 if (!ask_me_yes_or_no(tmp)) {
1689 bkpinfo->media_device[0] = '\0';
1690 }
1691 mr_free(tmp);
1692 }
1693 if (!bkpinfo->media_device[0]) {
1694 if (!popup_and_get_string
1695 ("Device name?",
1696 "What is the /dev entry of your tape streamer?",
1697 bkpinfo->media_device, MAX_STR_LEN / 4)) {
1698 log_to_screen("User has chosen not to backup the PC");
1699 finish(1);
1700 }
1701 }
1702 mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
1703 if (run_program_and_log_output(tmp, FALSE)) {
1704 log_to_screen("User has not specified a valid /dev entry");
1705 finish(1);
1706 }
1707 mr_free(tmp);
1708
1709 bkpinfo->use_obdr = ask_me_yes_or_no
1710 ("Do you want to activate OBDR support for your tapes ?");
1711 bkpinfo->media_size[0] = 0;
1712 log_msg(4, "media_size[0] = %ld", bkpinfo->media_size[0]);
1713 if (bkpinfo->media_size[0] <= 0) {
1714 bkpinfo->media_size[0] = 0;
1715 }
1716 for (i = 1; i <= MAX_NOOF_MEDIA; i++) {
1717 bkpinfo->media_size[i] = bkpinfo->media_size[0];
1718 }
1719 if (archiving_to_media) {
1720 if ((bkpinfo->compression_level =
1721 which_compression_level()) == -1) {
1722 log_to_screen("User has chosen not to backup the PC");
1723 finish(1);
1724 }
1725 }
1726 break;
1727
1728
1729
1730 case nfs:
1731 /* Never try to eject a NFS device */
1732 bkpinfo->please_dont_eject = TRUE;
1733
1734 /* Initiate bkpinfo nfs_mount path from running environment if not already done */
1735 if (!bkpinfo->nfs_mount[0]) {
1736 strcpy(bkpinfo->nfs_mount,
1737 call_program_and_get_last_line_of_output
1738 ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
1739 }
1740#ifdef __FreeBSD__
1741 if (TRUE)
1742#else
1743 if (!bkpinfo->disaster_recovery)
1744#endif
1745 {
1746 if (!popup_and_get_string
1747 ("NFS dir.",
1748 "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.)",
1749 bkpinfo->nfs_mount, MAX_STR_LEN / 4)) {
1750 log_to_screen("User has chosen not to backup the PC");
1751 finish(1);
1752 }
1753 if (!bkpinfo->restore_data) {
1754 if ((bkpinfo->compression_level =
1755 which_compression_level()) == -1) {
1756 log_to_screen("User has chosen not to backup the PC");
1757 finish(1);
1758 }
1759 }
1760 // check whether already mounted - we better remove
1761 // surrounding spaces and trailing '/' for this
1762 strip_spaces(bkpinfo->nfs_mount);
1763 if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
1764 bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
1765 mr_asprintf(&command, "mount | grep \"%s \" | cut -d' ' -f3",
1766 bkpinfo->nfs_mount);
1767 strcpy(bkpinfo->isodir,
1768 call_program_and_get_last_line_of_output(command));
1769 mr_free(command);
1770
1771 if (!bkpinfo->restore_data) {
1772 mr_asprintf(&comment,
1773 "How much data (in Megabytes) will each media store?");
1774 if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1775 mr_free(comment);
1776 log_to_screen("User has chosen not to backup the PC");
1777 finish(1);
1778 }
1779 mr_free(comment);
1780 } else {
1781 strcpy(sz_size, "0");
1782 }
1783 for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1784 bkpinfo->media_size[i] = atoi(sz_size);
1785 }
1786 if (bkpinfo->media_size[0] < 0) {
1787 log_to_screen("User has chosen not to backup the PC");
1788 finish(1);
1789 }
1790 }
1791 if (bkpinfo->disaster_recovery) {
1792 mr_asprintf(&command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
1793 (void)system(command);
1794 mr_free(command);
1795
1796 if (!popup_and_get_string
1797 ("NFS share", "Which remote NFS share should I mount?",
1798 bkpinfo->nfs_mount, MAX_STR_LEN)) {
1799 log_to_screen("User has chosen not to backup the PC");
1800 finish(1);
1801 }
1802 }
1803 /* Initiate bkpinfo isodir path from running environment if mount already done */
1804 if (is_this_device_mounted(bkpinfo->nfs_mount)) {
1805 strcpy(bkpinfo->isodir,
1806 call_program_and_get_last_line_of_output
1807 ("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
1808 } else {
1809 sprintf(bkpinfo->isodir, "%s/nfsdir", bkpinfo->tmpdir);
1810 mr_asprintf(&command, "mkdir -p %s", bkpinfo->isodir);
1811 run_program_and_log_output(command, 5);
1812 mr_free(command);
1813
1814 mr_asprintf(&tmp, "mount -t nfs -o nolock %s %s", bkpinfo->nfs_mount,
1815 bkpinfo->isodir);
1816 run_program_and_log_output(tmp, 3);
1817 mr_free(tmp);
1818
1819 malloc_string(g_selfmounted_isodir);
1820 strcpy(g_selfmounted_isodir, bkpinfo->isodir);
1821 }
1822 if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1823 popup_and_OK
1824 ("Please mount that partition before you try to backup to or restore from it.");
1825 finish(1);
1826 }
1827 mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1828 if (!popup_and_get_string
1829 ("Directory", "Which directory within that mountpoint?", tmp,
1830 MAX_STR_LEN)) {
1831 log_to_screen("User has chosen not to backup the PC");
1832 finish(1);
1833 }
1834 strcpy(bkpinfo->nfs_remote_dir, tmp);
1835 mr_free(tmp);
1836
1837 // check whether writable - we better remove surrounding spaces for this
1838 strip_spaces(bkpinfo->nfs_remote_dir);
1839
1840 if (!popup_and_get_string
1841 ("Prefix.",
1842 "Please enter the prefix that will be prepended to your ISO filename. Example: machine1 to obtain machine1-[1-9]*.iso files",
1843 bkpinfo->prefix, MAX_STR_LEN / 4)) {
1844 log_to_screen("User has chosen not to backup the PC");
1845 finish(1);
1846 }
1847 log_msg(3, "prefix set to %s", bkpinfo->prefix);
1848
1849 for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1850 bkpinfo->media_size[i] = 650;
1851 }
1852 log_msg(3, "Just set nfs_remote_dir to %s",
1853 bkpinfo->nfs_remote_dir);
1854 log_msg(3, "isodir is still %s", bkpinfo->isodir);
1855 break;
1856
1857 case iso:
1858 if (!bkpinfo->disaster_recovery) {
1859 if (!popup_and_get_string
1860 ("Storage dir.",
1861 "Please enter the full path name to the directory for your ISO images. Example: /mnt/raid0_0",
1862 bkpinfo->isodir, MAX_STR_LEN / 4)) {
1863 log_to_screen("User has chosen not to backup the PC");
1864 finish(1);
1865 }
1866 if (archiving_to_media) {
1867 if ((bkpinfo->compression_level =
1868 which_compression_level()) == -1) {
1869 log_to_screen("User has chosen not to backup the PC");
1870 finish(1);
1871 }
1872 if (!popup_and_get_string
1873 ("ISO size.",
1874 "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.",
1875 sz_size, 16)) {
1876 log_to_screen("User has chosen not to backup the PC");
1877 finish(1);
1878 }
1879 for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1880 bkpinfo->media_size[i] = atoi(sz_size);
1881 }
1882 } else {
1883 for (i = 0; i <= MAX_NOOF_MEDIA; i++) {
1884 bkpinfo->media_size[i] = 650;
1885 }
1886 }
1887 }
1888 if (!popup_and_get_string
1889 ("Prefix.",
1890 "Please enter the prefix that will be prepended to your ISO filename. Example: machine1 to obtain machine1-[1-9]*.iso files",
1891 bkpinfo->prefix, MAX_STR_LEN / 4)) {
1892 log_to_screen("User has chosen not to backup the PC");
1893 finish(1);
1894 }
1895 log_msg(3, "prefix set to %s", bkpinfo->prefix);
1896 break;
1897 default:
1898 fatal_error
1899 ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
1900 }
1901
1902 if (archiving_to_media) {
1903
1904#ifdef __FreeBSD__
1905 strcpy(bkpinfo->boot_device,
1906 call_program_and_get_last_line_of_output
1907 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
1908#else
1909 strcpy(bkpinfo->boot_device,
1910 call_program_and_get_last_line_of_output
1911 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
1912#endif
1913 i = which_boot_loader(bkpinfo->boot_device);
1914 if (i == 'U') // unknown
1915 {
1916
1917#ifdef __FreeBSD__
1918 if (!popup_and_get_string
1919 ("Boot device",
1920 "What is your boot device? (e.g. /dev/ad0)",
1921 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1922 log_to_screen("User has chosen not to backup the PC");
1923 finish(1);
1924 }
1925 i = which_boot_loader(bkpinfo->boot_device);
1926#else
1927 if (!popup_and_get_string
1928 ("Boot device",
1929 "What is your boot device? (e.g. /dev/hda)",
1930 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1931 log_to_screen("User has chosen not to backup the PC");
1932 finish(1);
1933 }
1934 if (does_string_exist_in_boot_block
1935 (bkpinfo->boot_device, "LILO")) {
1936 i = 'L';
1937 } else
1938 if (does_string_exist_in_boot_block
1939 (bkpinfo->boot_device, "ELILO")) {
1940 i = 'E';
1941 } else
1942 if (does_string_exist_in_boot_block
1943 (bkpinfo->boot_device, "GRUB")) {
1944 i = 'G';
1945 } else {
1946 i = 'U';
1947 }
1948#endif
1949 if (i == 'U') {
1950 if (ask_me_yes_or_no
1951 ("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?"))
1952 {
1953 i = 'R'; // raw
1954 } else {
1955 log_to_screen
1956 ("I cannot find your boot loader. Please run mondoarchive with parameters.");
1957 finish(1);
1958 }
1959 }
1960 }
1961 bkpinfo->boot_loader = i;
1962 strcpy(bkpinfo->include_paths, "/");
1963 if (!popup_and_get_string
1964 ("Backup paths",
1965 "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
1966 bkpinfo->include_paths, MAX_STR_LEN)) {
1967 log_to_screen("User has chosen not to backup the PC");
1968 finish(1);
1969 }
1970 mr_asprintf(&tmp, "%s", list_of_NFS_mounts_only());
1971 if (strlen(tmp) > 2) {
1972 if (bkpinfo->exclude_paths[0]) {
1973 strcat(bkpinfo->exclude_paths, " ");
1974 }
1975 strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
1976 }
1977 mr_free(tmp);
1978// NTFS
1979 mr_asprintf(&tmp, "%s",
1980 call_program_and_get_last_line_of_output
1981 ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
1982 if (strlen(tmp) > 2) {
1983 if (!popup_and_get_string
1984 ("NTFS partitions",
1985 "Please enter/confirm the NTFS partitions you wish to backup as well.",
1986 tmp, MAX_STR_LEN / 4)) {
1987 log_to_screen("User has chosen not to backup the PC");
1988 finish(1);
1989 }
1990 strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
1991 }
1992 mr_free(tmp);
1993
1994
1995 if (!popup_and_get_string
1996 ("Exclude paths",
1997 "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.",
1998 bkpinfo->exclude_paths, (4*MAX_STR_LEN)-1)) {
1999 log_to_screen("User has chosen not to backup the PC");
2000 finish(1);
2001 }
2002 if (!popup_and_get_string
2003 ("Temporary directory",
2004 "Please enter your temporary directory.",
2005 bkpinfo->tmpdir, (4*MAX_STR_LEN)-1)) {
2006 log_to_screen("User has chosen not to backup the PC");
2007 finish(1);
2008 }
2009 if (!popup_and_get_string
2010 ("Scratch directory",
2011 "Please enter your scratch directory.",
2012 bkpinfo->scratchdir, (4*MAX_STR_LEN)-1)) {
2013 log_to_screen("User has chosen not to backup the PC");
2014 finish(1);
2015 }
2016// Interactive mode:
2017#ifdef __IA64__
2018 bkpinfo->make_cd_use_lilo = TRUE;
2019#else
2020 bkpinfo->make_cd_use_lilo = FALSE;
2021#endif
2022 bkpinfo->backup_data = TRUE;
2023 bkpinfo->verify_data =
2024 ask_me_yes_or_no
2025 ("Will you want to verify your backups after Mondo has created them?");
2026
2027#ifndef __FreeBSD__
2028 if (!ask_me_yes_or_no
2029 ("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."))
2030#endif
2031 {
2032 strcpy(bkpinfo->kernel_path, "FAILSAFE");
2033 }
2034
2035 if (!ask_me_yes_or_no
2036 ("Are you sure you want to proceed? Hit 'no' to abort.")) {
2037 log_to_screen("User has chosen not to backup the PC");
2038 finish(1);
2039 }
2040 } else {
2041 bkpinfo->restore_data = TRUE; // probably...
2042 }
2043
2044 if (bkpinfo->backup_media_type == iso
2045 || bkpinfo->backup_media_type == nfs) {
2046 g_ISO_restore_mode = TRUE;
2047 }
2048#ifdef __FreeSD__
2049// skip
2050#else
2051 if (bkpinfo->backup_media_type == nfs) {
2052 log_msg(3, "I think the NFS mount is mounted at %s",
2053 bkpinfo->isodir);
2054 }
2055 log_it("isodir = %s", bkpinfo->isodir);
2056 log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
2057 if (bkpinfo->nfs_user) {
2058 log_it("nfs_user = '%s'", bkpinfo->nfs_user);
2059 }
2060#endif
2061
2062 log_it("media device = %s", bkpinfo->media_device);
2063 log_it("media size = %ld", bkpinfo->media_size[1]);
2064 log_it("media type = %s",
2065 bkptype_to_string(bkpinfo->backup_media_type));
2066 log_it("prefix = %s", bkpinfo->prefix);
2067 log_it("compression = %ld", bkpinfo->compression_level);
2068 log_it("include_paths = '%s'", bkpinfo->include_paths);
2069 log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
2070 log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2071 log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2072 log_it("image_devs = '%s'", bkpinfo->image_devs);
2073 log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
2074 bkpinfo->boot_loader);
2075 if (bkpinfo->media_size[0] < 0) {
2076 if (archiving_to_media) {
2077 fatal_error("Media size is less than zero.");
2078 } else {
2079 log_msg(2, "Warning - media size is less than zero.");
2080 bkpinfo->media_size[0] = 0;
2081 }
2082 }
2083 paranoid_free(sz_size);
2084 paranoid_free(prompt);
2085 return (0);
2086}
2087
2088
2089
2090
2091/**
2092 * @addtogroup utilityGroup
2093 * @{
2094 */
2095/**
2096 * Get a space-separated list of NFS devices and mounts.
2097 * @return The list created.
2098 * @note The return value points to static data that will be overwritten with each call.
2099 */
2100char *list_of_NFS_devices_and_mounts(void)
2101{
2102 char *exclude_these_devices = NULL;
2103 char *exclude_these_directories = NULL;
2104 static char result_sz[1024];
2105
2106 mr_asprintf(&exclude_these_directories,"%s",list_of_NFS_mounts_only());
2107 mr_asprintf(&exclude_these_devices,"%s",
2108 call_program_and_get_last_line_of_output
2109 ("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;}'"));
2110 snprintf(result_sz, 1023, "%s %s", exclude_these_directories, exclude_these_devices);
2111 mr_free(exclude_these_devices);
2112 mr_free(exclude_these_directories);
2113 return (result_sz);
2114}
2115
2116
2117
2118
2119/**
2120 * Get a space-separated list of NFS mounts.
2121 * @return The list created.
2122 * @note The return value points to static data that will be overwritten with each call.
2123 * @bug Even though we only want the mounts, the devices are still checked.
2124 */
2125char *list_of_NFS_mounts_only(void)
2126{
2127 char *exclude_these_directories = NULL;
2128 static char result_sz[512];
2129
2130 mr_asprintf(&exclude_these_directories,"%s",
2131 call_program_and_get_last_line_of_output
2132 ("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;}'"));
2133 snprintf(result_sz, 511, "%s", exclude_these_directories);
2134 mr_free(exclude_these_directories);
2135 return (result_sz);
2136}
2137
2138/* @} - end of utilityGroup */
2139
2140
2141
2142
2143
2144/**
2145 * Create a randomly-named FIFO. The format is @p stub "." [random] [random] where
2146 * [random] is a random number between 1 and 32767.
2147 * @param store_name_here Where to store the new filename.
2148 * @param stub A random number will be appended to this to make the FIFO's name.
2149 * @ingroup deviceGroup
2150 */
2151void make_fifo(char *store_name_here, char *stub)
2152{
2153 char *tmp = NULL;
2154
2155 assert_string_is_neither_NULL_nor_zerolength(stub);
2156
2157 sprintf(store_name_here, "%s%d%d", stub, (int) (random() % 32768),
2158 (int) (random() % 32768));
2159 make_hole_for_file(store_name_here);
2160 mkfifo(store_name_here, S_IRWXU | S_IRWXG);
2161 mr_asprintf(&tmp, "chmod 770 %s", store_name_here);
2162 paranoid_system(tmp);
2163 mr_free(tmp);
2164}
2165
2166
2167
2168
2169
2170
2171/**
2172 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2173 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2174 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2175 * @ingroup utilityGroup
2176 */
2177void sensibly_set_tmpdir_and_scratchdir()
2178{
2179 char *tmp = NULL;
2180 char *command = NULL;
2181 char *sz = NULL;
2182
2183 assert(bkpinfo != NULL);
2184
2185#ifdef __FreeBSD__
2186 mr_asprintf(&tmp,
2187 call_program_and_get_last_line_of_output
2188 ("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;}'"));
2189#else
2190 mr_asprintf(&tmp,
2191 call_program_and_get_last_line_of_output
2192 ("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;}'"));
2193#endif
2194
2195 if (tmp[0] != '/') {
2196 mr_asprintf(&sz, tmp);
2197 paranoid_free(tmp);
2198 mr_asprintf(&tmp, "/%s", sz);
2199 mr_free(sz);
2200 }
2201 if (!tmp[0]) {
2202 fatal_error("I couldn't figure out the tempdir!");
2203 }
2204 setup_tmpdir(tmp);
2205 log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2206
2207 sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp,
2208 (int) (random() % 32768));
2209 log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2210
2211 mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2212 paranoid_free(tmp);
2213
2214 paranoid_system(command);
2215 mr_free(command);
2216}
2217
2218
2219
2220
2221
2222
2223/**
2224 * @addtogroup deviceGroup
2225 * @{
2226 */
2227/**
2228 * If we can read @p dev, set @p output to it.
2229 * If @p dev cannot be read, set @p output to "".
2230 * @param dev The device to check for.
2231 * @param output Set to @p dev if @p dev exists, "" otherwise.
2232 * @return TRUE if @p dev exists, FALSE if it doesn't.
2233 */
2234bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2235{
2236 char *command = NULL;
2237 bool res;
2238
2239 if (!dev || dev[0] == '\0') {
2240 output[0] = '\0';
2241 return (FALSE);
2242 }
2243 log_msg(10, "Injecting %s", dev);
2244 inject_device(dev);
2245 if (!does_file_exist(dev)) {
2246 log_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2247 return (FALSE);
2248 }
2249 mr_asprintf(&command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null", 512L, dev);
2250 if (!run_program_and_log_output(command, FALSE)
2251 && !run_program_and_log_output(command, FALSE)) {
2252 strcpy(output, dev);
2253 log_msg(4, "Found it - %s", dev);
2254 res = TRUE;
2255 } else {
2256 output[0] = '\0';
2257 log_msg(4, "It's not %s", dev);
2258 res = FALSE;
2259 }
2260 mr_free(command);
2261 return(res);
2262}
2263
2264
2265
2266
2267
2268/**
2269 * Find out what number CD is in the drive.
2270 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2271 * @return The current CD number, or -1 if it could not be found.
2272 * @note If the CD is not mounted, it will be mounted
2273 * (and remain mounted after this function returns).
2274 */
2275int what_number_cd_is_this()
2276{
2277 int cd_number = -1;
2278 char *mountdev = NULL;
2279 char *tmp = NULL;
2280
2281 assert(bkpinfo != NULL);
2282// log_it("Asking what_number_cd_is_this");
2283 if (g_ISO_restore_mode) {
2284 mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
2285
2286 mr_asprintf(&mountdev, "%s%s", call_program_and_get_last_line_of_output(tmp), "/archives/THIS-CD-NUMBER");
2287 cd_number = atoi(last_line_of_file(mountdev));
2288 paranoid_free(mountdev);
2289 paranoid_free(tmp);
2290
2291 return (cd_number);
2292 }
2293
2294 mr_asprintf(&mountdev, bkpinfo->media_device);
2295 if (!mountdev[0]) {
2296 log_it
2297 ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2298 find_cdrom_device(bkpinfo->media_device, FALSE);
2299 }
2300 if (!is_this_device_mounted(MNT_CDROM)) {
2301 if (bkpinfo->backup_media_type == usb) {
2302 mount_USB_here(mountdev, MNT_CDROM);
2303 } else {
2304 mount_CDROM_here(mountdev, MNT_CDROM);
2305 }
2306 }
2307 paranoid_free(mountdev);
2308
2309 cd_number = atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2310 return (cd_number);
2311}
2312
2313
2314
2315
2316
2317
2318
2319/**
2320 * Find out what device is mounted as root (/).
2321 * @return Root device.
2322 * @note The returned string points to static storage and will be overwritten with every call.
2323 * @bug A bit of a misnomer; it's actually finding out the root device.
2324 * The mountpoint (where it's mounted) will obviously be '/'.
2325 */
2326char *where_is_root_mounted()
2327{
2328 /*@ buffers **************** */
2329 static char tmp[MAX_STR_LEN];
2330
2331
2332#ifdef __FreeBSD__
2333 strcpy(tmp, call_program_and_get_last_line_of_output
2334 ("mount | grep \" on / \" | cut -d' ' -f1"));
2335#else
2336 strcpy(tmp, call_program_and_get_last_line_of_output
2337 ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2338 if (strstr(tmp, "/dev/cciss/")) {
2339 strcpy(tmp, call_program_and_get_last_line_of_output
2340 ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2341 }
2342 if (strstr(tmp, "/dev/md")) {
2343 strcpy(tmp,
2344 call_program_and_get_last_line_of_output
2345 ("mount | grep \" on / \" | cut -d' ' -f1"));
2346 }
2347#endif
2348
2349 return (tmp);
2350}
2351
2352
2353/**
2354 * Find out which boot loader is in use.
2355 * @param which_device Device to look for the boot loader on.
2356 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2357 * @note Under Linux, all drives are examined, not just @p which_device.
2358 */
2359#ifdef __FreeBSD__
2360char which_boot_loader(char *which_device)
2361{
2362 int count_lilos = 0;
2363 int count_grubs = 0;
2364 int count_boot0s = 0;
2365 int count_dangerouslydedicated = 0;
2366
2367 log_it("looking at drive %s's MBR", which_device);
2368 if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2369 count_grubs++;
2370 }
2371 if (does_string_exist_in_boot_block(which_device, "LILO")) {
2372 count_lilos++;
2373 }
2374 if (does_string_exist_in_boot_block(which_device, "Drive")) {
2375 count_boot0s++;
2376 }
2377 if (does_string_exist_in_first_N_blocks
2378 (which_device, "FreeBSD/i386", 17)) {
2379 count_dangerouslydedicated++;
2380 }
2381 log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2382 count_grubs, count_lilos, count_elilos, count_boot0s,
2383 count_dangerouslydedicated);
2384
2385 if (count_grubs && !count_lilos) {
2386 return ('G');
2387 } else if (count_lilos && !count_grubs) {
2388 return ('L');
2389 } else if (count_grubs == 1 && count_lilos == 1) {
2390 log_it("I'll bet you used to use LILO but switched to GRUB...");
2391 return ('G');
2392 } else if (count_boot0s == 1) {
2393 return ('B');
2394 } else if (count_dangerouslydedicated) {
2395 return ('D');
2396 } else {
2397 log_it("Unknown boot loader");
2398 return ('U');
2399 }
2400}
2401
2402#else
2403
2404char which_boot_loader(char *which_device)
2405{
2406 /*@ buffer ***************************************************** */
2407 char *list_drives_cmd = NULL;
2408 char *current_drive;
2409
2410 /*@ pointers *************************************************** */
2411 FILE *pdrives;
2412
2413 /*@ int ******************************************************** */
2414 int count_lilos = 0;
2415 int count_grubs = 0;
2416
2417 /*@ end vars *************************************************** */
2418
2419 malloc_string(current_drive);
2420
2421#ifdef __IA64__
2422 /* No choice for it */
2423 return ('E');
2424#endif
2425 assert(which_device != NULL);
2426
2427 mr_asprintf(&list_drives_cmd,
2428 "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s",
2429 where_is_root_mounted());
2430 log_it("list_drives_cmd = %s", list_drives_cmd);
2431
2432 if (!(pdrives = popen(list_drives_cmd, "r"))) {
2433 log_OS_error("Unable to open list of drives");
2434 mr_free(list_drives_cmd);
2435 paranoid_free(current_drive);
2436 return ('\0');
2437 }
2438 mr_free(list_drives_cmd);
2439
2440 for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
2441 (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
2442 strip_spaces(current_drive);
2443 log_it("looking at drive %s's MBR", current_drive);
2444 if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2445 count_grubs++;
2446 strcpy(which_device, current_drive);
2447 break;
2448 }
2449 if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2450 count_lilos++;
2451 strcpy(which_device, current_drive);
2452 break;
2453 }
2454 }
2455 if (pclose(pdrives)) {
2456 log_OS_error("Cannot pclose pdrives");
2457 }
2458 log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2459 if (count_grubs && !count_lilos) {
2460 paranoid_free(current_drive);
2461 return ('G');
2462 } else if (count_lilos && !count_grubs) {
2463 paranoid_free(current_drive);
2464 return ('L');
2465 } else if (count_grubs == 1 && count_lilos == 1) {
2466 log_it("I'll bet you used to use LILO but switched to GRUB...");
2467 paranoid_free(current_drive);
2468 return ('G');
2469 } else {
2470 // We need to look on each partition then
2471 mr_asprintf(&list_drives_cmd,
2472 "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
2473 log_it("list_drives_cmd = %s", list_drives_cmd);
2474
2475 if (!(pdrives = popen(list_drives_cmd, "r"))) {
2476 log_OS_error("Unable to open list of drives");
2477 mr_free(list_drives_cmd);
2478 paranoid_free(current_drive);
2479 return ('\0');
2480 }
2481 mr_free(list_drives_cmd);
2482
2483 for ((void)fgets(current_drive, MAX_STR_LEN, pdrives); !feof(pdrives);
2484 (void)fgets(current_drive, MAX_STR_LEN, pdrives)) {
2485 strip_spaces(current_drive);
2486 log_it("looking at partition %s's BR", current_drive);
2487 if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2488 count_grubs++;
2489 strcpy(which_device, current_drive);
2490 break;
2491 }
2492 if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2493 count_lilos++;
2494 strcpy(which_device, current_drive);
2495 break;
2496 }
2497 }
2498 if (pclose(pdrives)) {
2499 log_OS_error("Cannot pclose pdrives");
2500 }
2501 log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2502 paranoid_free(current_drive);
2503 if (count_grubs && !count_lilos) {
2504 return ('G');
2505 } else if (count_lilos && !count_grubs) {
2506 return ('L');
2507 } else if (count_grubs == 1 && count_lilos == 1) {
2508 log_it("I'll bet you used to use LILO but switched to GRUB...");
2509 return ('G');
2510 } else {
2511 log_it("Unknown boot loader");
2512 return ('U');
2513 }
2514 }
2515}
2516#endif
2517
2518
2519
2520
2521/**
2522 * Write zeroes over the first 16K of @p device.
2523 * @param device The device to zero.
2524 * @return 0 for success, 1 for failure.
2525 */
2526int zero_out_a_device(char *device)
2527{
2528 FILE *fout;
2529 int i;
2530
2531 assert_string_is_neither_NULL_nor_zerolength(device);
2532
2533 log_it("Zeroing drive %s", device);
2534 if (!(fout = fopen(device, "w"))) {
2535 log_OS_error("Unable to open/write to device");
2536 return (1);
2537 }
2538 for (i = 0; i < 16384; i++) {
2539 fputc('\0', fout);
2540 }
2541 paranoid_fclose(fout);
2542 log_it("Device successfully zeroed.");
2543 return (0);
2544}
2545
2546/**
2547 * Return the device pointed to by @p incoming.
2548 * @param incoming The device to resolve symlinks for.
2549 * @return The path to the real device file.
2550 * @note The returned string points to static storage that will be overwritten with each call.
2551 * @bug Won't work with file v4.0; needs to be written in C.
2552 */
2553char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2554{
2555 static char output[MAX_STR_LEN];
2556 char *command = NULL;
2557 char *curr_fname;
2558 char *scratch = NULL;
2559 char *tmp = NULL;
2560 char *p;
2561
2562 struct stat statbuf;
2563 malloc_string(curr_fname);
2564 if (!does_file_exist(incoming)) {
2565 log_it
2566 ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2567 strcpy(output, incoming);
2568 } else {
2569 strcpy(curr_fname, incoming);
2570 lstat(curr_fname, &statbuf);
2571 while (S_ISLNK(statbuf.st_mode)) {
2572 log_msg(1, "curr_fname = %s", curr_fname);
2573 mr_asprintf(&command, "file %s", curr_fname);
2574 mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2575 mr_free(command);
2576 for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2577 p--);
2578 p++;
2579 mr_asprintf(&scratch, p);
2580 for (p = scratch; *p != '\0' && *p != '\''; p++);
2581 *p = '\0';
2582 log_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp, scratch);
2583 mr_free(tmp);
2584
2585 if (scratch[0] == '/') {
2586 strcpy(curr_fname, scratch); // copy whole thing because it's an absolute softlink
2587 } else { // copy over the basename cos it's a relative softlink
2588 p = curr_fname + strlen(curr_fname);
2589 while (p != curr_fname && *p != '/') {
2590 p--;
2591 }
2592 if (*p == '/') {
2593 p++;
2594 }
2595 strcpy(p, scratch);
2596 }
2597 mr_free(scratch);
2598 lstat(curr_fname, &statbuf);
2599 }
2600 strcpy(output, curr_fname);
2601 log_it("resolved %s to %s", incoming, output);
2602 }
2603 paranoid_free(curr_fname);
2604 return (output);
2605}
2606
2607/* @} - end of deviceGroup */
2608
2609
2610/**
2611 * Return the type of partition format (GPT or MBR)
2612 */
2613char *which_partition_format(const char *drive)
2614{
2615 static char output[4];
2616 char *tmp = NULL;
2617 char *command = NULL;
2618 char *fdisk = NULL;
2619#ifdef __IA64__
2620 struct stat buf;
2621#endif
2622 log_msg(0, "Looking for partition table format type");
2623 mr_asprintf(&fdisk, "/sbin/parted2fdisk");
2624 log_msg(1, "Using %s", fdisk);
2625 mr_asprintf(&command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2626 mr_free(fdisk);
2627
2628 mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2629 mr_free(command);
2630
2631 if (strstr(tmp, "GPT") == NULL) {
2632 strcpy(output, "MBR");
2633 } else {
2634 strcpy(output, "GPT");
2635 }
2636 mr_free(tmp);
2637
2638 log_msg(0, "Found %s partition table format type", output);
2639 return (output);
2640}
2641
2642/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.