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

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

Improvements on tape handling (based on patches from Michel Loiseleur <mloiseleur_at_linagora.com>)

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