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

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

Merge trunk for libmondo-devices.c finished (first pass)

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