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

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

mr_gettext.h added where necessary
mr_conf is now a pointer on a struct aveywhere

  • Property svn:keywords set to Id
File size: 66.4 KB
Line 
1/* libmondo-devices.c Subroutines for handling devices
2 $Id: libmondo-devices.c 1543 2007-07-22 23:05:36Z 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 1543 2007-07-22 23:05:36Z 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 }
1634 mr_free(tmp);
1635 } else {
1636 if (!popup_and_get_string
1637 ("Device name?",
1638 "What is the /dev entry of your tape streamer?",
1639 bkpinfo->media_device, MAX_STR_LEN / 4)) {
1640 log_to_screen("User has chosen not to backup the PC");
1641 finish(1);
1642 }
1643 }
1644 mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
1645 if (run_program_and_log_output(tmp, FALSE)) {
1646 log_to_screen(_("User has not specified a valid /dev entry"));
1647 finish(1);
1648 }
1649 mr_free(tmp);
1650 mr_msg(4, "sz_size = %s", sz_size);
1651 mr_free(sz_size);
1652 bkpinfo->media_size = 0L;
1653 mr_msg(4, "media_size = %ld", bkpinfo->media_size);
1654 if (bkpinfo->media_size <= 0L) {
1655 bkpinfo->media_size = 0L;
1656 }
1657 if (archiving_to_media) {
1658 if ((bkpinfo->compression_level =
1659 which_compression_level()) == -1) {
1660 log_to_screen(_("User has chosen not to backup the PC"));
1661 finish(1);
1662 }
1663 }
1664 break;
1665
1666
1667
1668 case nfs:
1669 if (!bkpinfo->nfs_mount[0]) {
1670 strcpy(bkpinfo->nfs_mount,
1671 call_program_and_get_last_line_of_output
1672 ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
1673 }
1674#ifdef __FreeBSD__
1675 if (TRUE)
1676#else
1677 if (!bkpinfo->disaster_recovery)
1678#endif
1679 {
1680 if (!popup_and_get_string
1681 ("NFS dir.",
1682 "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.)",
1683 bkpinfo->nfs_mount, MAX_STR_LEN / 4)) {
1684 log_to_screen("User has chosen not to backup the PC");
1685 finish(1);
1686 }
1687 if (!bkpinfo->restore_data) {
1688 if ((bkpinfo->compression_level =
1689 which_compression_level()) == -1) {
1690 log_to_screen(_("User has chosen not to backup the PC"));
1691 finish(1);
1692 }
1693 }
1694 // check whether already mounted - we better remove
1695 // surrounding spaces and trailing '/' for this
1696 mr_strip_spaces(bkpinfo->nfs_mount);
1697 if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
1698 bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
1699 mr_asprintf(&command, "mount | grep \"%s \" | cut -d' ' -f3",
1700 bkpinfo->nfs_mount);
1701 strcpy(bkpinfo->isodir,
1702 call_program_and_get_last_line_of_output(command));
1703 mr_free(command);
1704
1705 mr_asprintf(&comment,
1706 _("How much data (in Megabytes) will each media store?"));
1707 if (!popup_and_get_string(_("Size"), comment, sz_size, 5)) {
1708 log_to_screen(_("User has chosen not to backup the PC"));
1709 finish(1);
1710 }
1711 mr_free(comment);
1712 bkpinfo->media_size = atol(sz_size);
1713 if (bkpinfo->media_size <= 0L) {
1714 log_to_screen(_("User has chosen not to backup the PC"));
1715 finish(1);
1716 }
1717 }
1718 if (bkpinfo->disaster_recovery) {
1719 system("umount /tmp/isodir 2> /dev/null");
1720 if (!popup_and_get_string
1721 ("NFS share", "Which remote NFS share should I mount?",
1722 bkpinfo->nfs_mount, MAX_STR_LEN)) {
1723 log_to_screen("User has chosen not to backup the PC");
1724 finish(1);
1725 }
1726 }
1727 if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1728 sprintf(bkpinfo->isodir, "/tmp/isodir.mondo.%d",
1729 (int) (random() % 32768));
1730 mr_asprintf(&command, "mkdir -p %s", bkpinfo->isodir);
1731 run_program_and_log_output(command, 5);
1732 mr_free(command);
1733
1734 mr_asprintf(&tmp, "mount -t nfs -o nolock %s %s", bkpinfo->nfs_mount,
1735 bkpinfo->isodir);
1736 run_program_and_log_output(tmp, 5);
1737 mr_free(tmp);
1738 malloc_string(g_selfmounted_isodir);
1739 strcpy(g_selfmounted_isodir, bkpinfo->isodir);
1740 }
1741 if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1742 popup_and_OK
1743 (_("Please mount that partition before you try to backup to or restore from it."));
1744 finish(1);
1745 }
1746 mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1747 if (!popup_and_get_string
1748 ("Directory", "Which directory within that mountpoint?", tmp,
1749 MAX_STR_LEN)) {
1750 log_to_screen("User has chosen not to backup the PC");
1751 finish(1);
1752 }
1753 strcpy(bkpinfo->nfs_remote_dir, tmp);
1754 mr_free(tmp);
1755 // check whether writable - we better remove surrounding spaces for this
1756 mr_strip_spaces(bkpinfo->nfs_remote_dir);
1757 mr_asprintf(&command, "echo hi > '%s/%s/.dummy.txt'", bkpinfo->isodir,
1758 bkpinfo->nfs_remote_dir);
1759 while (run_program_and_log_output(command, FALSE)) {
1760 mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1761 mr_asprintf(&prompt,
1762 _("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."),
1763 bkpinfo->nfs_remote_dir, bkpinfo->isodir);
1764 if (!popup_and_get_string
1765 ("Directory", prompt, tmp, MAX_STR_LEN)) {
1766 log_to_screen("User has chosen not to backup the PC");
1767 finish(1);
1768 }
1769 mr_free(prompt);
1770
1771 strcpy(bkpinfo->nfs_remote_dir, tmp);
1772 mr_free(tmp);
1773 // check whether writable - we better remove surrounding space s for this
1774 mr_strip_spaces(bkpinfo->nfs_remote_dir);
1775
1776 mr_free(command);
1777 mr_asprintf(&command, "echo hi > '%s/%s/.dummy.txt'", bkpinfo->isodir,
1778 bkpinfo->nfs_remote_dir);
1779 }
1780 mr_free(command);
1781
1782 if (!popup_and_get_string
1783 ("Prefix.",
1784 "Please enter the prefix that will be prepended to your ISO filename. Example: machine1 to obtain machine1-[1-9]*.iso files",
1785 bkpinfo->prefix, MAX_STR_LEN / 4)) {
1786 log_to_screen("User has chosen not to backup the PC");
1787 finish(1);
1788 }
1789 mr_msg(3, "prefix set to %s", bkpinfo->prefix);
1790
1791 bkpinfo->media_size = (long)650;
1792 mr_msg(3, "Just set nfs_remote_dir to %s",
1793 bkpinfo->nfs_remote_dir);
1794 mr_msg(3, "isodir is still %s", bkpinfo->isodir);
1795 break;
1796
1797 case iso:
1798 if (!bkpinfo->disaster_recovery) {
1799 if (!popup_and_get_string
1800 ("Storage dir.",
1801 "Please enter the full path name to the directory for your ISO images. Example: /mnt/raid0_0",
1802 bkpinfo->isodir, MAX_STR_LEN / 4)) {
1803 log_to_screen("User has chosen not to backup the PC");
1804 finish(1);
1805 }
1806 if (archiving_to_media) {
1807 if ((bkpinfo->compression_level =
1808 which_compression_level()) == -1) {
1809 log_to_screen(_("User has chosen not to backup the PC"));
1810 finish(1);
1811 }
1812 if (!popup_and_get_string
1813 ("ISO size.",
1814 "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.",
1815 sz_size, 16)) {
1816 log_to_screen("User has chosen not to backup the PC");
1817 finish(1);
1818 }
1819 bkpinfo->media_size = atol(sz_size);
1820 } else {
1821 bkpinfo->media_size = (long)650;
1822 }
1823 }
1824 if (!popup_and_get_string
1825 ("Prefix.",
1826 "Please enter the prefix that will be prepended to your ISO filename. Example: machine1 to obtain machine1-[1-9]*.iso files",
1827 bkpinfo->prefix, MAX_STR_LEN / 4)) {
1828 log_to_screen("User has chosen not to backup the PC");
1829 finish(1);
1830 }
1831 mr_msg(3, "prefix set to %s", bkpinfo->prefix);
1832 break;
1833 default:
1834 fatal_error
1835 ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
1836 }
1837 if (archiving_to_media) {
1838
1839#ifdef __FreeBSD__
1840 strcpy(bkpinfo->boot_device,
1841 call_program_and_get_last_line_of_output
1842 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
1843#else
1844 strcpy(bkpinfo->boot_device,
1845 call_program_and_get_last_line_of_output
1846 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
1847#endif
1848 i = which_boot_loader(bkpinfo->boot_device);
1849 if (i == 'U') // unknown
1850 {
1851
1852#ifdef __FreeBSD__
1853 if (!popup_and_get_string
1854 ("Boot device",
1855 "What is your boot device? (e.g. /dev/ad0)",
1856 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1857 log_to_screen("User has chosen not to backup the PC");
1858 finish(1);
1859 }
1860 i = which_boot_loader(bkpinfo->boot_device);
1861#else
1862 if (!popup_and_get_string
1863 ("Boot device",
1864 "What is your boot device? (e.g. /dev/hda)",
1865 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1866 log_to_screen("User has chosen not to backup the PC");
1867 finish(1);
1868 }
1869 if (does_string_exist_in_boot_block
1870 (bkpinfo->boot_device, "LILO")) {
1871 i = 'L';
1872 } else
1873 if (does_string_exist_in_boot_block
1874 (bkpinfo->boot_device, "ELILO")) {
1875 i = 'E';
1876 } else
1877 if (does_string_exist_in_boot_block
1878 (bkpinfo->boot_device, "GRUB")) {
1879 i = 'G';
1880 } else {
1881 i = 'U';
1882 }
1883#endif
1884 if (i == 'U') {
1885 if (ask_me_yes_or_no
1886 (_("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?")))
1887 {
1888 i = 'R'; // raw
1889 } else {
1890 log_to_screen
1891 (_("I cannot find your boot loader. Please run mondoarchive with parameters."));
1892 finish(1);
1893 }
1894 }
1895 }
1896 bkpinfo->boot_loader = i;
1897 strcpy(bkpinfo->include_paths, "/");
1898 if (!popup_and_get_string
1899 ("Backup paths",
1900 "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
1901 bkpinfo->include_paths, MAX_STR_LEN)) {
1902 log_to_screen("User has chosen not to backup the PC");
1903 finish(1);
1904 }
1905 mr_asprintf(&tmp, list_of_NFS_mounts_only());
1906 if (strlen(tmp) > 2) {
1907 if (bkpinfo->exclude_paths[0]) {
1908 strcat(bkpinfo->exclude_paths, " ");
1909 }
1910 strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
1911 }
1912 mr_free(tmp);
1913// NTFS
1914 mr_asprintf(&tmp,
1915 call_program_and_get_last_line_of_output
1916 ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
1917 if (strlen(tmp) > 2) {
1918 if (!popup_and_get_string
1919 ("NTFS partitions",
1920 "Please enter/confirm the NTFS partitions you wish to backup as well.",
1921 tmp, MAX_STR_LEN / 4)) {
1922 log_to_screen("User has chosen not to backup the PC");
1923 finish(1);
1924 }
1925 strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
1926 }
1927 mr_free(tmp);
1928
1929 if (!popup_and_get_string
1930 ("Exclude paths",
1931 "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.",
1932 bkpinfo->exclude_paths, MAX_STR_LEN)) {
1933 log_to_screen("User has chosen not to backup the PC");
1934 finish(1);
1935 }
1936 bkpinfo->make_cd_use_lilo = FALSE;
1937 bkpinfo->backup_data = TRUE;
1938 bkpinfo->verify_data =
1939 ask_me_yes_or_no
1940 (_("Will you want to verify your backups after Mondo has created them?"));
1941
1942#ifndef __FreeBSD__
1943 if (!ask_me_yes_or_no
1944 ("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."))
1945#endif
1946 {
1947 strcpy(bkpinfo->kernel_path, "FAILSAFE");
1948 }
1949
1950 if (!ask_me_yes_or_no
1951 (_("Are you sure you want to proceed? Hit 'no' to abort."))) {
1952 log_to_screen(_("User has chosen not to backup the PC"));
1953 finish(1);
1954 }
1955 } else {
1956 bkpinfo->restore_data = TRUE; // probably...
1957 }
1958
1959 if (bkpinfo->backup_media_type == iso
1960 || bkpinfo->backup_media_type == nfs) {
1961 g_ISO_restore_mode = TRUE;
1962 }
1963#ifdef __FreeSD__
1964// skip
1965#else
1966 if (bkpinfo->backup_media_type == nfs) {
1967 mr_msg(3, "I think the NFS mount is mounted at %s",
1968 bkpinfo->isodir);
1969 }
1970 log_it("isodir = %s", bkpinfo->isodir);
1971 log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
1972#endif
1973
1974 log_it("media device = %s", bkpinfo->media_device);
1975 log_it("media size = %ld", bkpinfo->media_size);
1976 log_it("media type = %s", bkpinfo->backup_media_string);
1977 log_it("prefix = %s", bkpinfo->prefix);
1978 log_it("compression = %ld", bkpinfo->compression_level);
1979 log_it("include_paths = '%s'", bkpinfo->include_paths);
1980 log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
1981 log_it("scratchdir = '%s'", bkpinfo->scratchdir);
1982 log_it("tmpdir = '%s'", bkpinfo->tmpdir);
1983 log_it("image_devs = '%s'", bkpinfo->image_devs);
1984 log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
1985 bkpinfo->boot_loader);
1986 if (bkpinfo->media_size < 0L) {
1987 if (archiving_to_media) {
1988 fatal_error("Media size is less than zero.");
1989 } else {
1990 mr_msg(2, "Warning - media size is less than zero.");
1991 bkpinfo->media_size = 0L;
1992 }
1993 }
1994 return (0);
1995}
1996
1997
1998/**
1999 * Get a space-separated list of NFS mounts.
2000 * @return The list created.
2001 * @note The return value points to static data that will be overwritten with each call.
2002 * @bug Even though we only want the mounts, the devices are still checked.
2003 */
2004char *list_of_NFS_mounts_only(void)
2005{
2006 char *exclude_these_devices;
2007 char *exclude_these_directories;
2008 static char result_sz[512];
2009
2010 malloc_string(exclude_these_devices);
2011 malloc_string(exclude_these_directories);
2012 strcpy(exclude_these_directories,
2013 call_program_and_get_last_line_of_output
2014 ("mount -t coda,ncpfs,nfs,smbfs,cifs,afs,ocfs,ocfs2,mvfs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2015 strcpy(exclude_these_devices,
2016 call_program_and_get_last_line_of_output
2017 ("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;}'"));
2018 sprintf(result_sz, "%s", exclude_these_directories);
2019 mr_free(exclude_these_devices);
2020 mr_free(exclude_these_directories);
2021 return (result_sz);
2022}
2023/* @} - end of utilityGroup */
2024
2025
2026/**
2027 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2028 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2029 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2030 * @ingroup utilityGroup
2031 */
2032void sensibly_set_tmpdir_and_scratchdir(struct s_bkpinfo *bkpinfo)
2033{
2034 char *tmp = NULL;
2035 char *command = NULL;
2036 char *sz = NULL;
2037 int i = 0;
2038
2039 malloc_string(command);
2040 assert(bkpinfo != NULL);
2041
2042#ifdef __FreeBSD__
2043 mr_asprintf(&tmp,
2044 call_program_and_get_last_line_of_output
2045 ("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;}'"));
2046#else
2047 mr_asprintf(&tmp,
2048 call_program_and_get_last_line_of_output
2049 ("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;}'"));
2050#endif
2051
2052 if (tmp[0] != '/') {
2053 mr_asprintf(&sz, "/%s", tmp);
2054 mr_free(tmp);
2055 tmp = sz;
2056 }
2057 if (!tmp[0]) {
2058 fatal_error("I couldn't figure out the tempdir!");
2059 }
2060 i = (int) (random() % 32768);
2061 sprintf(bkpinfo->tmpdir, "%s/tmp.mondo.%d", tmp, i);
2062 log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2063
2064 sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp, i);
2065 log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2066
2067 sprintf(g_erase_tmpdir_and_scratchdir, "rm -Rf %s %s", bkpinfo->tmpdir,
2068 bkpinfo->scratchdir);
2069
2070 mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2071 mr_free(tmp);
2072
2073 paranoid_system(command);
2074 mr_free(command);
2075}
2076
2077
2078/**
2079 * @addtogroup deviceGroup
2080 * @{
2081 */
2082/**
2083 * If we can read @p dev, set @p output to it.
2084 * If @p dev cannot be read, set @p output to "".
2085 * @param dev The device to check for.
2086 * @param output Set to @p dev if @p dev exists, "" otherwise.
2087 * @return TRUE if @p dev exists, FALSE if it doesn't.
2088 */
2089bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2090{
2091 char *command = NULL;
2092
2093 if (!dev || dev[0] == '\0') {
2094 output[0] = '\0';
2095 return (FALSE);
2096 }
2097 mr_msg(10, "Injecting %s", dev);
2098 inject_device(dev);
2099 if (!does_file_exist(dev)) {
2100 mr_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2101 return (FALSE);
2102 }
2103 mr_asprintf(&command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2104 512L, dev);
2105 if (!run_program_and_log_output(command, FALSE)
2106 && !run_program_and_log_output(command, FALSE)) {
2107 strcpy(output, dev);
2108 mr_msg(4, "Found it - %s", dev);
2109 mr_free(command);
2110 return (TRUE);
2111 } else {
2112 output[0] = '\0';
2113 mr_msg(4, "It's not %s", dev);
2114 mr_free(command);
2115 return (FALSE);
2116 }
2117}
2118
2119
2120/**
2121 * Find out what number CD is in the drive.
2122 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2123 * @return The current CD number, or -1 if it could not be found.
2124 * @note If the CD is not mounted, it will be mounted
2125 * (and remain mounted after this function returns).
2126 */
2127int what_number_cd_is_this(struct s_bkpinfo *bkpinfo)
2128{
2129 int cd_number = -1;
2130 char *mountdev = NULL;
2131 char *tmp = NULL;
2132
2133 assert(bkpinfo != NULL);
2134 if (g_ISO_restore_mode) {
2135 mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
2136
2137 mr_asprintf(&mountdev, "%s/archives/THIS-CD-NUMBER", call_program_and_get_last_line_of_output(tmp));
2138 cd_number = atoi(last_line_of_file(mountdev));
2139 mr_free(mountdev);
2140 mr_free(tmp);
2141 return (cd_number);
2142 }
2143
2144 mr_asprintf(&mountdev, bkpinfo->media_device);
2145 if (!mountdev[0]) {
2146 log_it
2147 ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2148 find_cdrom_device(bkpinfo->media_device, FALSE);
2149 }
2150 if (!is_this_device_mounted(MNT_CDROM)) {
2151 mount_CDROM_here(mountdev, MNT_CDROM);
2152 }
2153 cd_number =
2154 atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2155 mr_free(mountdev);
2156 return (cd_number);
2157}
2158
2159
2160/**
2161 * Find out what device is mounted as root (/).
2162 * @return Root device.
2163 * @note The returned string points to static storage and will be overwritten with every call.
2164 * @bug A bit of a misnomer; it's actually finding out the root device.
2165 * The mountpoint (where it's mounted) will obviously be '/'.
2166 */
2167char *where_is_root_mounted()
2168{
2169 /*@ buffers **************** */
2170 static char tmp[MAX_STR_LEN];
2171
2172
2173#ifdef __FreeBSD__
2174 strcpy(tmp, call_program_and_get_last_line_of_output
2175 ("mount | grep \" on / \" | cut -d' ' -f1"));
2176#else
2177 strcpy(tmp, call_program_and_get_last_line_of_output
2178 ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2179 if (strstr(tmp, "/dev/cciss/")) {
2180 strcpy(tmp, call_program_and_get_last_line_of_output
2181 ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2182 }
2183 if (strstr(tmp, "/dev/md")) {
2184 strcpy(tmp,
2185 call_program_and_get_last_line_of_output
2186 ("mount | grep \" on / \" | cut -d' ' -f1"));
2187 }
2188#endif
2189
2190 return (tmp);
2191}
2192
2193
2194/**
2195 * Find out which boot loader is in use.
2196 * @param which_device Device to look for the boot loader on.
2197 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2198 * @note Under Linux, all drives are examined, not just @p which_device.
2199 */
2200char which_boot_loader(char *which_device)
2201{
2202#ifdef __FreeBSD__
2203 int count_lilos = 0;
2204 int count_grubs = 0;
2205 int count_boot0s = 0;
2206 int count_dangerouslydedicated = 0;
2207
2208 log_it("looking at drive %s's MBR", which_device);
2209 if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2210 count_grubs++;
2211 }
2212 if (does_string_exist_in_boot_block(which_device, "LILO")) {
2213 count_lilos++;
2214 }
2215 if (does_string_exist_in_boot_block(which_device, "Drive")) {
2216 count_boot0s++;
2217 }
2218 if (does_string_exist_in_first_N_blocks
2219 (which_device, "FreeBSD/i386", 17)) {
2220 count_dangerouslydedicated++;
2221 }
2222 log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2223 count_grubs, count_lilos, count_elilos, count_boot0s,
2224 count_dangerouslydedicated);
2225
2226 if (count_grubs && !count_lilos) {
2227 return ('G');
2228 } else if (count_lilos && !count_grubs) {
2229 return ('L');
2230 } else if (count_grubs == 1 && count_lilos == 1) {
2231 log_it("I'll bet you used to use LILO but switched to GRUB...");
2232 return ('G');
2233 } else if (count_boot0s == 1) {
2234 return ('B');
2235 } else if (count_dangerouslydedicated) {
2236 return ('D');
2237 } else {
2238 log_it("Unknown boot loader");
2239 return ('U');
2240 }
2241#else
2242 /*@ buffer ***************************************************** */
2243 char *list_drives_cmd;
2244 char *current_drive = NULL;
2245
2246 /*@ pointers *************************************************** */
2247 FILE *pdrives;
2248
2249 /*@ int ******************************************************** */
2250 int count_lilos = 0;
2251 int count_grubs = 0;
2252 size_t n = 0;
2253
2254 /*@ end vars *************************************************** */
2255
2256#ifdef __IA64__
2257 /* No choice for it */
2258 return ('E');
2259#endif
2260 assert(which_device != NULL);
2261 mr_asprintf(&list_drives_cmd,
2262 "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s",
2263 where_is_root_mounted());
2264 log_it("list_drives_cmd = %s", list_drives_cmd);
2265
2266 if (!(pdrives = popen(list_drives_cmd, "r"))) {
2267 log_OS_error("Unable to open list of drives");
2268 mr_free(list_drives_cmd);
2269 return ('\0');
2270 }
2271 mr_free(list_drives_cmd);
2272
2273 for (mr_getline(&current_drive, &n, pdrives); !feof(pdrives);
2274 mr_getline(&current_drive, &n, pdrives)) {
2275 mr_strip_spaces(current_drive);
2276 log_it("looking at drive %s's MBR", current_drive);
2277 if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2278 count_grubs++;
2279 strcpy(which_device, current_drive);
2280 break;
2281 }
2282 if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2283 count_lilos++;
2284 strcpy(which_device, current_drive);
2285 break;
2286 }
2287 }
2288 mr_free(current_drive);
2289
2290 if (pclose(pdrives)) {
2291 log_OS_error("Cannot pclose pdrives");
2292 }
2293 log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2294 if (count_grubs && !count_lilos) {
2295 return ('G');
2296 } else if (count_lilos && !count_grubs) {
2297 return ('L');
2298 } else if (count_grubs == 1 && count_lilos == 1) {
2299 log_it("I'll bet you used to use LILO but switched to GRUB...");
2300 return ('G');
2301 } else {
2302 // We need to look on each partition then
2303 mr_asprintf(&list_drives_cmd,
2304 "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
2305 log_it("list_drives_cmd = %s", list_drives_cmd);
2306
2307 if (!(pdrives = popen(list_drives_cmd, "r"))) {
2308 log_OS_error("Unable to open list of drives");
2309 mr_free(list_drives_cmd);
2310 return ('\0');
2311 }
2312 mr_free(list_drives_cmd);
2313
2314 for (mr_getline(&current_drive, &n, pdrives); !feof(pdrives);
2315 mr_getline(&current_drive, &n, pdrives)) {
2316 mr_strip_spaces(current_drive);
2317 log_it("looking at partition %s's BR", current_drive);
2318 if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2319 count_grubs++;
2320 strcpy(which_device, current_drive);
2321 break;
2322 }
2323 if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2324 count_lilos++;
2325 strcpy(which_device, current_drive);
2326 break;
2327 }
2328 }
2329 mr_free(current_drive);
2330
2331 if (pclose(pdrives)) {
2332 log_OS_error("Cannot pclose pdrives");
2333 }
2334 log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2335 if (count_grubs && !count_lilos) {
2336 return ('G');
2337 } else if (count_lilos && !count_grubs) {
2338 return ('L');
2339 } else if (count_grubs == 1 && count_lilos == 1) {
2340 log_it("I'll bet you used to use LILO but switched to GRUB...");
2341 return ('G');
2342 } else {
2343 log_it("Unknown boot loader");
2344 return ('U');
2345 }
2346 }
2347#endif
2348}
2349
2350
2351/**
2352 * Write zeroes over the first 16K of @p device.
2353 * @param device The device to zero.
2354 * @return 0 for success, 1 for failure.
2355 */
2356int zero_out_a_device(char *device)
2357{
2358 FILE *fout;
2359 int i;
2360
2361 assert_string_is_neither_NULL_nor_zerolength(device);
2362
2363 log_it("Zeroing drive %s", device);
2364 if (!(fout = fopen(device, "w"))) {
2365 log_OS_error("Unable to open/write to device");
2366 return (1);
2367 }
2368 for (i = 0; i < 16384; i++) {
2369 fputc('\0', fout);
2370 }
2371 paranoid_fclose(fout);
2372 log_it("Device successfully zeroed.");
2373 return (0);
2374}
2375
2376
2377/**
2378 * Return the device pointed to by @p incoming.
2379 * @param incoming The device to resolve symlinks for.
2380 * @return The path to the real device file.
2381 * @note The returned string points to static storage that will be overwritten with each call.
2382 * @bug Won't work with file v4.0; needs to be written in C.
2383 */
2384char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2385{
2386 static char output[MAX_STR_LEN];
2387 char *command = NULL;
2388 char *curr_fname = NULL;
2389 char *scratch = NULL;
2390 char *tmp = NULL;
2391 char *p = NULL;
2392
2393 struct stat statbuf;
2394 malloc_string(tmp);
2395 malloc_string(scratch);
2396 malloc_string(curr_fname);
2397 if (!does_file_exist(incoming)) {
2398 log_it
2399 ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2400 strcpy(output, incoming);
2401 } else {
2402 strcpy(curr_fname, incoming);
2403 lstat(curr_fname, &statbuf);
2404 while (S_ISLNK(statbuf.st_mode)) {
2405 mr_msg(1, "curr_fname = %s", curr_fname);
2406 mr_asprintf(&command, "file %s", curr_fname);
2407 strcpy(tmp, call_program_and_get_last_line_of_output(command));
2408 mr_free(command);
2409
2410 for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2411 p--);
2412 p++;
2413 strcpy(scratch, p);
2414 for (p = scratch; *p != '\0' && *p != '\''; p++);
2415 *p = '\0';
2416 mr_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp,
2417 scratch);
2418 if (scratch[0] == '/') {
2419 strcpy(curr_fname, scratch); // copy whole thing because it's an absolute softlink
2420 } else { // copy over the basename cos it's a relative softlink
2421 p = curr_fname + strlen(curr_fname);
2422 while (p != curr_fname && *p != '/') {
2423 p--;
2424 }
2425 if (*p == '/') {
2426 p++;
2427 }
2428 strcpy(p, scratch);
2429 }
2430 lstat(curr_fname, &statbuf);
2431 }
2432 strcpy(output, curr_fname);
2433 log_it("resolved %s to %s", incoming, output);
2434 }
2435 mr_free(curr_fname);
2436 mr_free(tmp);
2437 return (output);
2438}
2439
2440/* @} - end of deviceGroup */
2441
2442
2443/**
2444 * Return the type of partition format (GPT or MBR)
2445 */
2446char *which_partition_format(const char *drive)
2447{
2448 static char output[4];
2449 char *tmp = NULL;
2450 char *command = NULL;
2451 char *fdisk = NULL;
2452
2453 mr_msg(0, "Looking for partition table format type");
2454 mr_asprintf(&fdisk, "/sbin/parted2fdisk");
2455 mr_msg(1, "Using %s", fdisk);
2456 mr_asprintf(&command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2457 mr_free(fdisk);
2458
2459 mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2460 mr_free(command);
2461
2462 if (strstr(tmp, "GPT") == NULL) {
2463 strcpy(output, "MBR");
2464 } else {
2465 strcpy(output, "GPT");
2466 }
2467 mr_free(tmp);
2468 mr_msg(0, "Found %s partition table format type", output);
2469 return(output);
2470}
2471/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.