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

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