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

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

Suppress g_bkpinfo_DONTUSETHIS (Idea from M. Loiseleur)

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