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

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

MAX_NOOF_MEDIA is gone and media_size in bkpinfo struct is now a single long field and not an array anymore

  • Property svn:keywords set to Id
File size: 64.9 KB
Line 
1/* libmondo-devices.c Subroutines for handling devices
2 $Id: libmondo-devices.c 1365 2007-04-29 23:50:20Z 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 1365 2007-04-29 23:50:20Z 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;
46extern char *MONDO_LOGFILE;
47
48static char g_cdrw_drive_is_here[MAX_STR_LEN / 4] = "";
49static char g_cdrom_drive_is_here[MAX_STR_LEN / 4] = "";
50static char g_dvd_drive_is_here[MAX_STR_LEN / 4] = "";
51
52
53/**
54 * ????? @bug ?????
55 * @ingroup globalGroup
56 */
57bool g_restoring_live_from_cd = FALSE;
58
59extern t_bkptype g_backup_media_type; // set by main()
60
61
62
63
64void set_g_cdrom_and_g_dvd_to_bkpinfo_value(struct s_bkpinfo *bkpinfo)
65{
66 strcpy(g_cdrom_drive_is_here, bkpinfo->media_device); // just in case
67 strcpy(g_dvd_drive_is_here, bkpinfo->media_device); // just in case
68}
69
70
71
72/**
73 * Retract all CD trays and wait for autorun to complete.
74 * @ingroup deviceGroup
75 */
76void retract_CD_tray_and_defeat_autorun(void)
77{
78// log_it("rctada: Retracting all CD trays", __LINE__);
79 if (strlen(g_cdrom_drive_is_here) > 0) {
80 inject_device(g_cdrom_drive_is_here);
81 }
82 if (strlen(g_dvd_drive_is_here) > 0) {
83 inject_device(g_dvd_drive_is_here);
84 }
85 if (strlen(g_cdrw_drive_is_here) > 0) {
86 inject_device(g_cdrw_drive_is_here);
87 }
88// log_it("rctada: killing autorun");
89// run_program_and_log_output("killall autorun", TRUE);
90 if (!run_program_and_log_output("ps | grep autorun | grep -v grep", 5)) {
91 log_it("autorun detected; sleeping for 2 seconds");
92 sleep(2);
93 }
94 log_it("rctada: Unmounting all CD drives", __LINE__);
95 run_program_and_log_output("umount /dev/cdr* /dev/dvd*", 5);
96}
97
98
99/**
100 * Mount the CD-ROM at @p mountpoint.
101 * @param device The device (or file if g_ISO_restore_mode) to mount.
102 * @param mountpoint The place to mount it.
103 * @return 0 for success, nonzero for failure.
104 */
105int mount_CDROM_here(char *device, char *mountpoint)
106{
107 /*@ buffer ****************************************************** */
108 char *command = NULL;
109 char *dev;
110 int retval = 0;
111
112 malloc_string(dev);
113 assert_string_is_neither_NULL_nor_zerolength(device);
114 assert_string_is_neither_NULL_nor_zerolength(mountpoint);
115
116 make_hole_for_dir(mountpoint);
117 if (isdigit(device[0])) {
118 find_cdrom_device(device, FALSE);
119 } else {
120 strcpy(dev, device);
121 }
122 if (g_ISO_restore_mode) {
123
124#ifdef __FreeBSD__
125 strcpy(dev, make_vn(device));
126 if (!dev) {
127 sprintf(command, "Unable to mount ISO (make_vn(%s) failed)",
128 device);
129 fatal_error(command);
130 }
131 strcpy(device, dev);
132#endif
133 }
134
135 mr_msg(4, "(mount_CDROM_here --- device=%s, mountpoint=%s", device,
136 mountpoint);
137 /*@ end vars *************************************************** */
138
139#ifdef __FreeBSD__
140 mr_asprintf(&command, "mount_cd9660 -r %s %s 2>> %s",
141 device, mountpoint, MONDO_LOGFILE);
142#else
143 mr_asprintf(&command, "mount %s -o ro,loop -t iso9660 %s 2>> %s",
144 device, mountpoint, MONDO_LOGFILE);
145#endif
146
147 mr_msg(4, command);
148 if (strncmp(device, "/dev/", 5) == 0) {
149 retract_CD_tray_and_defeat_autorun();
150 }
151 retval = system(command);
152 mr_msg(1, "system(%s) returned %d", command, retval);
153 mr_free(command);
154
155 mr_free(dev);
156 return (retval);
157}
158
159
160
161/**
162 * Determine whether we're booted off a ramdisk.
163 * @return @c TRUE (we are) or @c FALSE (we aren't).
164 * @ingroup utilityGroup
165 */
166bool am_I_in_disaster_recovery_mode(void)
167{
168 char *tmp = NULL;
169 char *comment = NULL;
170 bool is_this_a_ramdisk = FALSE;
171
172 mr_asprintf(&tmp, where_is_root_mounted());
173 mr_asprintf(&comment, "root is mounted at %s\n", tmp);
174 mr_msg(0, comment);
175 mr_free(comment);
176
177 mr_msg(0,
178 "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().",
179 tmp);
180
181#ifdef __FreeBSD__
182 if (strstr(tmp, "/dev/md")) {
183 is_this_a_ramdisk = TRUE;
184 }
185#else
186 if (!strncmp(tmp, "/dev/ram", 8)
187 || (!strncmp(tmp, "/dev/rd", 7) && !strcmp(tmp, "/dev/rd/")
188 && strncmp(tmp, "/dev/rd/cd", 10)) || strstr(tmp, "rootfs")
189 || !strcmp(tmp, "/dev/root")) {
190 is_this_a_ramdisk = TRUE;
191 } else {
192 is_this_a_ramdisk = FALSE;
193 }
194#endif
195 mr_free(tmp);
196
197 if (is_this_a_ramdisk) {
198 if (!does_file_exist("/THIS-IS-A-RAMDISK")
199 && !does_file_exist("/tmp/mountlist.txt.sample")) {
200 log_to_screen
201 (_("Using /dev/root is stupid of you but I'll forgive you."));
202 is_this_a_ramdisk = FALSE;
203 }
204 }
205 if (does_file_exist("/THIS-IS-A-RAMDISK")) {
206 is_this_a_ramdisk = TRUE;
207 }
208 mr_msg(1, "Is this a ramdisk? result = %d", is_this_a_ramdisk);
209 return (is_this_a_ramdisk);
210}
211
212
213/**
214 * Turn @c bkpinfo->backup_media_type into a human-readable string.
215 * @return The human readable string (e.g. @c cdr becomes <tt>"cdr"</tt>).
216 * @note The returned string points to static storage that will be overwritten with each call.
217 * @ingroup stringGroup
218 */
219char *bkptype_to_string(t_bkptype bt)
220{
221 static char output[MAX_STR_LEN / 4];
222 switch (bt) {
223 case none:
224 strcpy(output, "none");
225 break;
226 case iso:
227 strcpy(output, "iso");
228 break;
229 case cdr:
230 strcpy(output, "cdr");
231 break;
232 case cdrw:
233 strcpy(output, "cdrw");
234 break;
235 case cdstream:
236 strcpy(output, "cdstream");
237 break;
238 case nfs:
239 strcpy(output, "nfs");
240 break;
241 case tape:
242 strcpy(output, "tape");
243 break;
244 case udev:
245 strcpy(output, "udev");
246 break;
247 case usb:
248 strcpy(output, "usb");
249 break;
250 default:
251 strcpy(output, "default");
252 }
253 return (output);
254}
255
256
257/**
258 * @addtogroup deviceGroup
259 * @{
260 */
261/**
262 * Eject the tray of the specified CD device.
263 * @param dev The device to eject.
264 * @return the return value of the @c eject command. (0=success, nonzero=failure)
265 */
266int eject_device(char *dev)
267{
268 char *command = NULL;
269 int res1 = 0, res2 = 0;
270
271 if (IS_THIS_A_STREAMING_BACKUP(g_backup_media_type)
272 && g_backup_media_type != udev) {
273 mr_asprintf(&command, "mt -f %s offline", dev);
274 res1 = run_program_and_log_output(command, 1);
275 mr_free(command);
276 } else {
277 res1 = 0;
278 }
279
280#ifdef __FreeBSD__
281 if (strstr(dev, "acd")) {
282 mr_asprintf(&command, "cdcontrol -f %s eject", dev);
283 } else {
284 mr_asprintf(&command, "camcontrol eject `echo %s | sed 's|/dev/||'`",
285 dev);
286 }
287#else
288 mr_asprintf(&command, "eject %s", dev);
289#endif
290
291 mr_msg(3, "Ejecting %s", dev);
292 res2 = run_program_and_log_output(command, 1);
293 mr_free(command);
294 if (res1 && res2) {
295 return (1);
296 } else {
297 return (0);
298 }
299}
300
301
302/**
303 * Load (inject) the tray of the specified CD device.
304 * @param dev The device to load/inject.
305 * @return 0 for success, nonzero for failure.
306 */
307int inject_device(char *dev)
308{
309 char *command = NULL;
310 int i;
311
312#ifdef __FreeBSD__
313 if (strstr(dev, "acd")) {
314 mr_asprintf(&command, "cdcontrol -f %s close", dev);
315 } else {
316 mr_asprintf(&command, "camcontrol load `echo %s | sed 's|/dev/||'`",
317 dev);
318 }
319#else
320 mr_asprintf(&command, "eject -t %s", dev);
321#endif
322 i = run_program_and_log_output(command, FALSE);
323 mr_free(command);
324 return (i);
325}
326
327
328/**
329 * Determine whether the specified @p device (really, you can use any file)
330 * exists.
331 * @return TRUE if it exists, FALSE if it doesn't.
332 */
333bool does_device_exist(char *device)
334{
335
336 /*@ buffers *********************************************************** */
337 char *tmp = NULL;
338 bool ret = FALSE;
339
340 assert_string_is_neither_NULL_nor_zerolength(device);
341
342 mr_asprintf(&tmp, "ls %s > /dev/null 2> /dev/null", device);
343
344 if (system(tmp)) {
345 ret = FALSE;
346 } else {
347 ret = TRUE;
348 }
349 mr_free(tmp);
350 return(ret);
351}
352
353
354/**
355 * Determine whether a non-Microsoft partition exists on any connected hard drive.
356 * @return TRUE (there's a Linux/FreeBSD partition) or FALSE (Microsoft has taken over yet another innocent PC).
357 */
358bool does_nonMS_partition_exist(void)
359{
360#if __FreeBSD__
361 return
362 !system
363 ("for drive in /dev/ad? /dev/da?; do fdisk $drive | grep -q FreeBSD && exit 0; done; false");
364#else
365 return
366 !system
367 ("parted2fdisk -l 2>/dev/null | grep '^/dev/' | grep -Eqv '(MS|DOS|FAT|NTFS)'");
368#endif
369}
370
371/**
372 * Determine whether the specified @p partno exists on the specified @p drive.
373 * @param drive The drive to search for the partition in.
374 * @param partno The partition number to look for.
375 * @return 0 if it exists, nonzero otherwise.
376 */
377int does_partition_exist(const char *drive, int partno)
378{
379 /*@ buffers **************************************************** */
380 char *program = NULL;
381 char *incoming = NULL;
382 char *searchstr = NULL;
383
384 /*@ ints ******************************************************* */
385 int res = 0;
386
387 /*@ pointers *************************************************** */
388 FILE *fin;
389
390
391 /*@ end vars *************************************************** */
392 assert_string_is_neither_NULL_nor_zerolength(drive);
393 assert(partno >= 0 && partno < 999);
394
395 malloc_string(incoming);
396 malloc_string(searchstr);
397
398#ifdef __FreeBSD__
399 // We assume here that this is running from mondorestore. (It is.)
400 mr_asprintf(&program, "ls %s %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 = FALSE;
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 } else {
1130 mr_getline(&good_formats, &n , pin);
1131 if (pclose(pin)) {
1132 log_OS_error("Cannot pclose good formats");
1133 }
1134 mr_strip_spaces(good_formats);
1135 // " ntfs 7 " -- um, cheating much? :)
1136 mr_asprintf(&tmp, " %s swap lvm raid ntfs 7 ",good_formats);
1137 mr_free(good_formats);
1138 good_formats = tmp;
1139
1140 if (strstr(good_formats, format_sz)) {
1141 retval = TRUE;
1142 }
1143 mr_free(good_formats);
1144 }
1145 mr_free(format_sz);
1146 return (retval);
1147}
1148
1149
1150/** @def SWAPLIST_COMMAND The command to list the swap files/partitions in use. */
1151
1152/**
1153 * Determine whether @p device_raw is currently mounted.
1154 * @param device_raw The device to check.
1155 * @return TRUE if it's mounted, FALSE if not.
1156 */
1157bool is_this_device_mounted(char *device_raw)
1158{
1159
1160 /*@ pointers **************************************************** */
1161 FILE *fin;
1162
1163 /*@ buffers ***************************************************** */
1164 char *incoming = NULL;
1165 char *device_with_tab = NULL;
1166 char *device_with_space = NULL;
1167 char *tmp = NULL;
1168 size_t n = 0;
1169
1170#ifdef __FreeBSD__
1171#define SWAPLIST_COMMAND "swapinfo"
1172#else
1173#define SWAPLIST_COMMAND "cat /proc/swaps"
1174#endif
1175
1176 /*@ end vars **************************************************** */
1177
1178 assert(device_raw != NULL);
1179// assert_string_is_neither_NULL_nor_zerolength(device_raw);
1180 if (device_raw[0] != '/' && !strstr(device_raw, ":/")) {
1181 mr_msg(1, "%s needs to have a '/' prefixed - I'll do it",
1182 device_raw);
1183 mr_asprintf(&tmp, "/%s", device_raw);
1184 } else {
1185 mr_asprintf(&tmp, device_raw);
1186 }
1187 mr_msg(1, "Is %s mounted?", tmp);
1188 if (!strcmp(tmp, "/proc") || !strcmp(tmp, "proc")) {
1189 mr_msg(1,
1190 "I don't know how the heck /proc made it into the mountlist. I'll ignore it.");
1191 return (FALSE);
1192 }
1193 mr_asprintf(&device_with_tab, "%s\t", tmp);
1194 mr_asprintf(&device_with_space, "%s ", tmp);
1195 mr_free(tmp);
1196
1197 if (!(fin = popen("mount", "r"))) {
1198 log_OS_error("Cannot popen 'mount'");
1199 return (FALSE);
1200 }
1201 for (mr_getline(&incoming, &n, fin); !feof(fin);
1202 mr_getline(&incoming, &n, fin)) {
1203 if (strstr(incoming, device_with_space) //> incoming
1204 || strstr(incoming, device_with_tab)) // > incoming)
1205 {
1206 paranoid_pclose(fin);
1207 mr_free(incoming);
1208 return(TRUE);
1209 }
1210 }
1211 mr_free(incoming);
1212 mr_free(device_with_tab);
1213 paranoid_pclose(fin);
1214
1215 mr_asprintf(&tmp, "%s | grep -E \"^%s\" > /dev/null 2> /dev/null",
1216 SWAPLIST_COMMAND, device_with_space);
1217 mr_free(device_with_space);
1218
1219 mr_msg(4, "tmp (command) = '%s'", tmp);
1220 if (!system(tmp)) {
1221 mr_free(tmp);
1222 return(TRUE);
1223 }
1224 mr_free(tmp);
1225 return (FALSE);
1226}
1227
1228
1229#ifdef __FreeBSD__
1230// CODE IS FREEBSD-SPECIFIC
1231/**
1232 * Create a loopback device for specified @p fname.
1233 * @param fname The file to associate with a device.
1234 * @return /dev entry for the device, or NULL if it couldn't be allocated.
1235 */
1236char *make_vn(char *fname)
1237{
1238 char *device = NULL;
1239 char *mddevice = NULL;
1240 char *command = NULL;
1241 int vndev = 2;
1242
1243 if (atoi
1244 (call_program_and_get_last_line_of_output
1245 ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1246 do {
1247 mr_free(mddevice);
1248 mr_asprintf(&mddevice, "vn%ic", vndev++);
1249 mr_free(command);
1250 mr_asprintf(&command, "vnconfig %s %s", mddevice, fname);
1251
1252 if (vndev > 10) {
1253 mr_free(command);
1254 mr_free(mddevice);
1255 return NULL;
1256 }
1257 }
1258 while (system(command));
1259 mr_free(command);
1260 } else {
1261 mr_asprintf(&command, "mdconfig -a -t vnode -f %s", fname);
1262 mr_asprintf(&mddevice, call_program_and_get_last_line_of_output(command));
1263 mr_free(command);
1264
1265 if (!strstr(mddevice, "md")) {
1266 mr_free(mddevice);
1267 return NULL;
1268 }
1269 }
1270 mr_asprintf(&device, "/dev/%s", mddevice);
1271 mr_free(mddevice);
1272 return(device);
1273}
1274
1275
1276// CODE IS FREEBSD-SPECIFIC
1277/**
1278 * Deallocate specified @p dname.
1279 * This should be called when you are done with the device created by make_vn(),
1280 * so the system does not run out of @c vn devices.
1281 * @param dname The device to deallocate.
1282 * @return 0 for success, nonzero for failure.
1283 */
1284int kick_vn(char *dname)
1285{
1286 char *command;
1287 int ret = 0;
1288
1289 if (strncmp(dname, "/dev/", 5) == 0) {
1290 dname += 5;
1291 }
1292
1293 if (atoi
1294 (call_program_and_get_last_line_of_output
1295 ("/sbin/sysctl -n kern.osreldate")) < 500000) {
1296 mr_asprintf(&command, "vnconfig -d %s", dname);
1297 } else {
1298 mr_asprintf(&command, "mdconfig -d -u %s", dname);
1299 }
1300 ret = system(command);
1301 mr_free(command);
1302 return(ret);
1303}
1304#endif
1305
1306
1307/**
1308 * Ask the user for CD number @p cd_number_i_want.
1309 * Sets g_current_media_number once the correct CD is inserted.
1310 * @param bkpinfo The backup information structure. Fields used:
1311 * - @c bkpinfo->backup_media_type
1312 * - @c bkpinfo->prefix
1313 * - @c bkpinfo->isodir
1314 * - @c bkpinfo->media_device
1315 * - @c bkpinfo->please_dont_eject_when_restoring
1316 * @param cd_number_i_want The CD number to ask for.
1317 */
1318void
1319insist_on_this_cd_number(struct s_bkpinfo *bkpinfo, int cd_number_i_want)
1320{
1321
1322 /*@ int ************************************************************* */
1323 int res = 0;
1324
1325
1326 /*@ buffers ********************************************************* */
1327 char *tmp = NULL;
1328 char *request = NULL;
1329
1330 assert(bkpinfo != NULL);
1331 assert(cd_number_i_want > 0);
1332
1333// mr_msg(3, "Insisting on CD number %d", cd_number_i_want);
1334
1335 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1336 mr_msg(3,
1337 "No need to insist_on_this_cd_number when the backup type isn't CD-R(W) or NFS or ISO");
1338 return;
1339 }
1340 mr_asprintf(&tmp, "mkdir -p " MNT_CDROM);
1341 run_program_and_log_output(tmp, 5);
1342 mr_free(tmp);
1343
1344 if (g_ISO_restore_mode || bkpinfo->backup_media_type == iso
1345 || bkpinfo->backup_media_type == nfs) {
1346 mr_msg(3, "Remounting CD");
1347 g_ISO_restore_mode = TRUE;
1348// FIXME --- I'm tempted to do something about this...
1349// Why unmount and remount again and again?
1350 if (is_this_device_mounted(MNT_CDROM)) {
1351 run_program_and_log_output("umount " MNT_CDROM, 5);
1352 }
1353 system("mkdir -p /tmp/isodir &> /dev/null");
1354 mr_asprintf(&tmp, "%s/%s/%s-%d.iso", bkpinfo->isodir,
1355 bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1356 cd_number_i_want);
1357 if (!does_file_exist(tmp)) {
1358 mr_free(tmp);
1359 mr_asprintf(&tmp, "/tmp/isodir/%s/%s-%d.iso",
1360 bkpinfo->nfs_remote_dir, bkpinfo->prefix,
1361 cd_number_i_want);
1362 if (does_file_exist(tmp)) {
1363 mr_msg(1,
1364 "FIXME - hacking bkpinfo->isodir from '%s' to /tmp/isodir",
1365 bkpinfo->isodir);
1366 strcpy(bkpinfo->isodir, "/tmp/isodir");
1367 }
1368 }
1369 mr_msg(3, "Mounting %s at %s", tmp, MNT_CDROM);
1370 if (mount_CDROM_here(tmp, MNT_CDROM)) {
1371 fatal_error("Mommy!");
1372 }
1373 mr_free(tmp);
1374 }
1375 if ((res = what_number_cd_is_this(bkpinfo)) != cd_number_i_want) {
1376 mr_msg(3, "Currently, we hold %d but we want %d", res,
1377 cd_number_i_want);
1378 mr_asprintf(&tmp, "Insisting on %s #%d",
1379 bkpinfo->backup_media_string,
1380 cd_number_i_want);
1381 mr_asprintf(&request, "Please insert %s #%d and press Enter.",
1382 bkpinfo->backup_media_string,
1383 cd_number_i_want);
1384 mr_msg(3, tmp);
1385 mr_free(tmp);
1386
1387 while (what_number_cd_is_this(bkpinfo) != cd_number_i_want) {
1388 sync();
1389 if (is_this_device_mounted(MNT_CDROM)) {
1390 res =
1391 run_program_and_log_output("umount " MNT_CDROM, FALSE);
1392 } else {
1393 res = 0;
1394 }
1395 if (res) {
1396 log_to_screen(_("WARNING - failed to unmount CD-ROM drive"));
1397 }
1398 if (!bkpinfo->please_dont_eject) {
1399 res = eject_device(bkpinfo->media_device);
1400 } else {
1401 res = 0;
1402 }
1403 if (res) {
1404 log_to_screen(_("WARNING - failed to eject CD-ROM disk"));
1405 }
1406 popup_and_OK(request);
1407 if (!bkpinfo->please_dont_eject) {
1408 inject_device(bkpinfo->media_device);
1409 }
1410 sync();
1411 }
1412 mr_free(request);
1413
1414 mr_msg(1, "Thankyou. Proceeding...");
1415 g_current_media_number = cd_number_i_want;
1416 }
1417}
1418/* @} - end of deviceGroup */
1419
1420
1421/**
1422 * Ask user for details of backup/restore information.
1423 * Called when @c mondoarchive doesn't get any parameters.
1424 * @param bkpinfo The backup information structure to fill out with the user's data.
1425 * @param archiving_to_media TRUE if archiving, FALSE if restoring.
1426 * @return 0, always.
1427 * @bug No point of `int' return value.
1428 * @ingroup archiveGroup
1429 */
1430int interactively_obtain_media_parameters_from_user(struct s_bkpinfo
1431 *bkpinfo,
1432 bool
1433 archiving_to_media)
1434// archiving_to_media is TRUE if I'm being called by mondoarchive
1435// archiving_to_media is FALSE if I'm being called by mondorestore
1436{
1437 char *tmp = NULL;
1438 char *sz_size = NULL;
1439 char *command = NULL;
1440 char *comment = NULL;
1441 char *prompt = NULL;
1442 int i = 0;
1443 FILE *fin = NULL;
1444
1445 assert(bkpinfo != NULL);
1446 bkpinfo->nonbootable_backup = FALSE;
1447
1448// Tape, CD, NFS, ...?
1449 srandom(getpid());
1450 bkpinfo->backup_media_type =
1451 (g_restoring_live_from_cd) ? cdr :
1452 which_backup_media_type(bkpinfo->restore_data);
1453 if (bkpinfo->backup_media_type == none) {
1454 log_to_screen(_("User has chosen not to backup the PC"));
1455 finish(1);
1456 }
1457 if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
1458 popup_and_OK(_("Please remove CD/floppy from drive(s)"));
1459 }
1460 mr_msg(3, "media type = %s",
1461 bkptype_to_string(bkpinfo->backup_media_type));
1462 if (archiving_to_media) {
1463 sensibly_set_tmpdir_and_scratchdir(bkpinfo);
1464 }
1465 bkpinfo->cdrw_speed = (bkpinfo->backup_media_type == cdstream) ? 2 : 4;
1466 bkpinfo->compression_level =
1467 (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
1468 bkpinfo->use_lzo =
1469 (bkpinfo->backup_media_type == cdstream) ? TRUE : FALSE;
1470 mvaddstr_and_log_it(2, 0, " ");
1471
1472// Find device's /dev (or SCSI) entry
1473 switch (bkpinfo->backup_media_type) {
1474 case cdr:
1475 case cdrw:
1476 case dvd:
1477 case usb:
1478 if (archiving_to_media) {
1479 if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1480 if (ask_me_yes_or_no
1481 (_("Is your computer a laptop, or does the CD writer incorporate BurnProof technology?")))
1482 {
1483 bkpinfo->manual_cd_tray = TRUE;
1484 }
1485 }
1486 if ((bkpinfo->compression_level =
1487 which_compression_level()) == -1) {
1488 log_to_screen(_("User has chosen not to backup the PC"));
1489 finish(1);
1490 }
1491 mr_asprintf(&comment, _("What speed is your %s (re)writer?"),
1492 bkpinfo->backup_media_string);
1493 if (bkpinfo->backup_media_type == dvd) {
1494 find_dvd_device(bkpinfo->media_device, FALSE);
1495 mr_asprintf(&tmp, "1");
1496 mr_asprintf(&sz_size, "%d", DEFAULT_DVD_DISK_SIZE); // 4.7 salesman's GB = 4.482 real GB = 4582 MB
1497 mr_msg(1, "Setting to DVD defaults");
1498 } else if (bkpinfo->backup_media_type == usb) {
1499 strcpy(bkpinfo->media_device, VANILLA_USB_DEVICE);
1500 asprintf(&sz_size, "512");
1501 } else {
1502 strcpy(bkpinfo->media_device, VANILLA_SCSI_CDROM);
1503 mr_asprintf(&tmp, "4");
1504 mr_asprintf(&sz_size, "650");
1505 mr_msg(1, "Setting to CD defaults");
1506 }
1507 if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1508 if (!popup_and_get_string(_("Speed"), comment, tmp, 4)) {
1509 log_to_screen(_("User has chosen not to backup the PC"));
1510 finish(1);
1511 }
1512 }
1513 mr_free(comment);
1514
1515 bkpinfo->cdrw_speed = atoi(tmp); // if DVD then this shouldn't ever be used anyway :)
1516 mr_free(tmp);
1517
1518 mr_asprintf(&comment,
1519 _("How much data (in Megabytes) will each %s store?"),
1520 bkpinfo->backup_media_string);
1521
1522 if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1523 log_to_screen(_("User has chosen not to backup the PC"));
1524 finish(1);
1525 }
1526 mr_free(comment);
1527
1528 bkpinfo->media_size = atol(sz_size);
1529 mr_free(sz_size);
1530
1531 if (bkpinfo->media_size <= 0L) {
1532 log_to_screen(_("User has chosen not to backup the PC"));
1533 finish(1);
1534 }
1535 }
1536 case cdstream:
1537 if (bkpinfo->disaster_recovery) {
1538 strcpy(bkpinfo->media_device, "/dev/cdrom");
1539 mr_msg(2, "CD-ROM device assumed to be at %s",
1540 bkpinfo->media_device);
1541 } else if (bkpinfo->restore_data
1542 || bkpinfo->backup_media_type == dvd) {
1543 if (!bkpinfo->media_device[0]) {
1544 strcpy(bkpinfo->media_device, "/dev/cdrom");
1545 } // just for the heck of it :)
1546 mr_msg(1, "bkpinfo->media_device = %s",
1547 bkpinfo->media_device);
1548 if (bkpinfo->backup_media_type == dvd
1549 || find_cdrom_device(bkpinfo->media_device, FALSE)) {
1550 mr_msg(1, "bkpinfo->media_device = %s",
1551 bkpinfo->media_device);
1552 mr_asprintf(&comment,
1553 _("Please specify your %s drive's /dev entry"),
1554 bkpinfo->backup_media_string);
1555 if (!popup_and_get_string
1556 (_("Device?"), comment, bkpinfo->media_device, MAX_STR_LEN / 4)) {
1557 log_to_screen(_("User has chosen not to backup the PC"));
1558 finish(1);
1559 }
1560 mr_free(comment);
1561 }
1562 mr_msg(2, "%s device found at %s",
1563 bkpinfo->backup_media_string,
1564 bkpinfo->media_device);
1565 } else {
1566 if (find_cdrw_device(bkpinfo->media_device)) {
1567 bkpinfo->media_device[0] = '\0';
1568 }
1569 if (bkpinfo->media_device[0]) {
1570 mr_asprintf(&tmp,
1571 _("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."),
1572 bkpinfo->backup_media_string,
1573 bkpinfo->media_device);
1574 if (!ask_me_yes_or_no(tmp)) {
1575 bkpinfo->media_device[0] = '\0';
1576 }
1577 mr_free(tmp);
1578 } else {
1579 if (g_kernel_version < 2.6) {
1580 i = popup_and_get_string("Device node?",
1581 "What is the SCSI node of your CD (re)writer, please?",
1582 bkpinfo->media_device,
1583 MAX_STR_LEN / 4);
1584 } else {
1585 i = popup_and_get_string("/dev entry?",
1586 "What is the /dev entry of your CD (re)writer, please?",
1587 bkpinfo->media_device,
1588 MAX_STR_LEN / 4);
1589 }
1590 if (!i) {
1591 log_to_screen(_("User has chosen not to backup the PC"));
1592 finish(1);
1593 }
1594 }
1595 }
1596 if (bkpinfo->backup_media_type == cdstream) {
1597 bkpinfo->media_size = (long)650;
1598 }
1599 break;
1600 case udev:
1601 if (!ask_me_yes_or_no
1602 (_("This option is for advanced users only. Are you sure?"))) {
1603 log_to_screen(_("User has chosen not to backup the PC"));
1604 finish(1);
1605 }
1606 case tape:
1607
1608 if (find_tape_device_and_size(bkpinfo->media_device, sz_size)) {
1609 mr_msg(3, "Ok, using vanilla scsi tape.");
1610 strcpy(bkpinfo->media_device, VANILLA_SCSI_TAPE);
1611 if ((fin = fopen(bkpinfo->media_device, "r"))) {
1612 paranoid_fclose(fin);
1613 } else {
1614 strcpy(bkpinfo->media_device, "/dev/osst0");
1615 }
1616 }
1617 if (bkpinfo->media_device[0]) {
1618 if ((fin = fopen(bkpinfo->media_device, "r"))) {
1619 paranoid_fclose(fin);
1620 } else {
1621 if (does_file_exist("/tmp/mondo-restore.cfg")) {
1622 read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
1623 bkpinfo->media_device);
1624 }
1625 }
1626 mr_asprintf(&tmp,
1627 _("I think I've found your tape streamer at %s; am I right on the money?"),
1628 bkpinfo->media_device);
1629 if (!ask_me_yes_or_no(tmp)) {
1630 bkpinfo->media_device[0] = '\0';
1631 }
1632 mr_free(tmp);
1633 } else {
1634 if (!popup_and_get_string
1635 ("Device name?",
1636 "What is the /dev entry of your tape streamer?",
1637 bkpinfo->media_device, MAX_STR_LEN / 4)) {
1638 log_to_screen("User has chosen not to backup the PC");
1639 finish(1);
1640 }
1641 }
1642 mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
1643 if (run_program_and_log_output(tmp, FALSE)) {
1644 log_to_screen(_("User has not specified a valid /dev entry"));
1645 finish(1);
1646 }
1647 mr_free(tmp);
1648 mr_msg(4, "sz_size = %s", sz_size);
1649 mr_free(sz_size);
1650 bkpinfo->media_size = 0L;
1651 mr_msg(4, "media_size = %ld", bkpinfo->media_size);
1652 if (bkpinfo->media_size <= 0L) {
1653 bkpinfo->media_size = 0L;
1654 }
1655 if (archiving_to_media) {
1656 if ((bkpinfo->compression_level =
1657 which_compression_level()) == -1) {
1658 log_to_screen(_("User has chosen not to backup the PC"));
1659 finish(1);
1660 }
1661 }
1662 break;
1663
1664
1665
1666 case nfs:
1667 if (!bkpinfo->nfs_mount[0]) {
1668 strcpy(bkpinfo->nfs_mount,
1669 call_program_and_get_last_line_of_output
1670 ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
1671 }
1672#ifdef __FreeBSD__
1673 if (TRUE)
1674#else
1675 if (!bkpinfo->disaster_recovery)
1676#endif
1677 {
1678 if (!popup_and_get_string
1679 ("NFS dir.",
1680 "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.)",
1681 bkpinfo->nfs_mount, MAX_STR_LEN / 4)) {
1682 log_to_screen("User has chosen not to backup the PC");
1683 finish(1);
1684 }
1685 if (!bkpinfo->restore_data) {
1686 if ((bkpinfo->compression_level =
1687 which_compression_level()) == -1) {
1688 log_to_screen(_("User has chosen not to backup the PC"));
1689 finish(1);
1690 }
1691 }
1692 // check whether already mounted - we better remove
1693 // surrounding spaces and trailing '/' for this
1694 mr_strip_spaces(bkpinfo->nfs_mount);
1695 if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
1696 bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
1697 mr_asprintf(&command, "mount | grep \"%s \" | cut -d' ' -f3",
1698 bkpinfo->nfs_mount);
1699 strcpy(bkpinfo->isodir,
1700 call_program_and_get_last_line_of_output(command));
1701 mr_free(command);
1702
1703 mr_asprintf(&comment,
1704 _("How much data (in Megabytes) will each media store?"));
1705 if (!popup_and_get_string(_("Size"), comment, sz_size, 5)) {
1706 log_to_screen(_("User has chosen not to backup the PC"));
1707 finish(1);
1708 }
1709 mr_free(comment);
1710 bkpinfo->media_size = atol(sz_size);
1711 if (bkpinfo->media_size <= 0L) {
1712 log_to_screen(_("User has chosen not to backup the PC"));
1713 finish(1);
1714 }
1715 }
1716 if (bkpinfo->disaster_recovery) {
1717 system("umount /tmp/isodir 2> /dev/null");
1718 if (!popup_and_get_string
1719 ("NFS share", "Which remote NFS share should I mount?",
1720 bkpinfo->nfs_mount, MAX_STR_LEN)) {
1721 log_to_screen("User has chosen not to backup the PC");
1722 finish(1);
1723 }
1724 }
1725 if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1726 sprintf(bkpinfo->isodir, "/tmp/isodir.mondo.%d",
1727 (int) (random() % 32768));
1728 mr_asprintf(&command, "mkdir -p %s", bkpinfo->isodir);
1729 run_program_and_log_output(command, 5);
1730 mr_free(command);
1731
1732 mr_asprintf(&tmp, "mount -t nfs -o nolock %s %s", bkpinfo->nfs_mount,
1733 bkpinfo->isodir);
1734 run_program_and_log_output(tmp, 5);
1735 mr_free(tmp);
1736 malloc_string(g_selfmounted_isodir);
1737 strcpy(g_selfmounted_isodir, bkpinfo->isodir);
1738 }
1739 if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1740 popup_and_OK
1741 (_("Please mount that partition before you try to backup to or restore from it."));
1742 finish(1);
1743 }
1744 mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1745 if (!popup_and_get_string
1746 ("Directory", "Which directory within that mountpoint?", tmp,
1747 MAX_STR_LEN)) {
1748 log_to_screen("User has chosen not to backup the PC");
1749 finish(1);
1750 }
1751 strcpy(bkpinfo->nfs_remote_dir, tmp);
1752 mr_free(tmp);
1753 // check whether writable - we better remove surrounding spaces for this
1754 mr_strip_spaces(bkpinfo->nfs_remote_dir);
1755 mr_asprintf(&command, "echo hi > '%s/%s/.dummy.txt'", bkpinfo->isodir,
1756 bkpinfo->nfs_remote_dir);
1757 while (run_program_and_log_output(command, FALSE)) {
1758 mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1759 mr_asprintf(&prompt,
1760 _("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."),
1761 bkpinfo->nfs_remote_dir, bkpinfo->isodir);
1762 if (!popup_and_get_string
1763 ("Directory", prompt, tmp, MAX_STR_LEN)) {
1764 log_to_screen("User has chosen not to backup the PC");
1765 finish(1);
1766 }
1767 mr_free(prompt);
1768
1769 strcpy(bkpinfo->nfs_remote_dir, tmp);
1770 mr_free(tmp);
1771 // check whether writable - we better remove surrounding space s for this
1772 mr_strip_spaces(bkpinfo->nfs_remote_dir);
1773
1774 mr_free(command);
1775 mr_asprintf(&command, "echo hi > '%s/%s/.dummy.txt'", bkpinfo->isodir,
1776 bkpinfo->nfs_remote_dir);
1777 }
1778 mr_free(command);
1779
1780 if (!popup_and_get_string
1781 ("Prefix.",
1782 "Please enter the prefix that will be prepended to your ISO filename. Example: machine1 to obtain machine1-[1-9]*.iso files",
1783 bkpinfo->prefix, MAX_STR_LEN / 4)) {
1784 log_to_screen("User has chosen not to backup the PC");
1785 finish(1);
1786 }
1787 mr_msg(3, "prefix set to %s", bkpinfo->prefix);
1788
1789 bkpinfo->media_size = (long)650;
1790 mr_msg(3, "Just set nfs_remote_dir to %s",
1791 bkpinfo->nfs_remote_dir);
1792 mr_msg(3, "isodir is still %s", bkpinfo->isodir);
1793 break;
1794
1795 case iso:
1796 if (!bkpinfo->disaster_recovery) {
1797 if (!popup_and_get_string
1798 ("Storage dir.",
1799 "Please enter the full path that contains your ISO images. Example: /mnt/raid0_0",
1800 bkpinfo->isodir, MAX_STR_LEN / 4)) {
1801 log_to_screen("User has chosen not to backup the PC");
1802 finish(1);
1803 }
1804 if (archiving_to_media) {
1805 if ((bkpinfo->compression_level =
1806 which_compression_level()) == -1) {
1807 log_to_screen(_("User has chosen not to backup the PC"));
1808 finish(1);
1809 }
1810 if (!popup_and_get_string
1811 ("ISO size.",
1812 "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.",
1813 sz_size, 16)) {
1814 log_to_screen("User has chosen not to backup the PC");
1815 finish(1);
1816 }
1817 bkpinfo->media_size = atol(sz_size);
1818 } else {
1819 bkpinfo->media_size = (long)650;
1820 }
1821 }
1822 if (!popup_and_get_string
1823 ("Prefix.",
1824 "Please enter the prefix that will be prepended to your ISO filename. Example: machine1 to obtain machine1-[1-9]*.iso files",
1825 bkpinfo->prefix, MAX_STR_LEN / 4)) {
1826 log_to_screen("User has chosen not to backup the PC");
1827 finish(1);
1828 }
1829 mr_msg(3, "prefix set to %s", bkpinfo->prefix);
1830 break;
1831 default:
1832 fatal_error
1833 ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
1834 }
1835 if (archiving_to_media) {
1836
1837#ifdef __FreeBSD__
1838 strcpy(bkpinfo->boot_device,
1839 call_program_and_get_last_line_of_output
1840 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
1841#else
1842 strcpy(bkpinfo->boot_device,
1843 call_program_and_get_last_line_of_output
1844 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
1845#endif
1846 i = which_boot_loader(bkpinfo->boot_device);
1847 if (i == 'U') // unknown
1848 {
1849
1850#ifdef __FreeBSD__
1851 if (!popup_and_get_string
1852 ("Boot device",
1853 "What is your boot device? (e.g. /dev/ad0)",
1854 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1855 log_to_screen("User has chosen not to backup the PC");
1856 finish(1);
1857 }
1858 i = which_boot_loader(bkpinfo->boot_device);
1859#else
1860 if (!popup_and_get_string
1861 ("Boot device",
1862 "What is your boot device? (e.g. /dev/hda)",
1863 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
1864 log_to_screen("User has chosen not to backup the PC");
1865 finish(1);
1866 }
1867 if (does_string_exist_in_boot_block
1868 (bkpinfo->boot_device, "LILO")) {
1869 i = 'L';
1870 } else
1871 if (does_string_exist_in_boot_block
1872 (bkpinfo->boot_device, "ELILO")) {
1873 i = 'E';
1874 } else
1875 if (does_string_exist_in_boot_block
1876 (bkpinfo->boot_device, "GRUB")) {
1877 i = 'G';
1878 } else {
1879 i = 'U';
1880 }
1881#endif
1882 if (i == 'U') {
1883 if (ask_me_yes_or_no
1884 (_("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?")))
1885 {
1886 i = 'R'; // raw
1887 } else {
1888 log_to_screen
1889 (_("I cannot find your boot loader. Please run mondoarchive with parameters."));
1890 finish(1);
1891 }
1892 }
1893 }
1894 bkpinfo->boot_loader = i;
1895 strcpy(bkpinfo->include_paths, "/");
1896 if (!popup_and_get_string
1897 ("Backup paths",
1898 "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
1899 bkpinfo->include_paths, MAX_STR_LEN)) {
1900 log_to_screen("User has chosen not to backup the PC");
1901 finish(1);
1902 }
1903 mr_asprintf(&tmp, list_of_NFS_mounts_only());
1904 if (strlen(tmp) > 2) {
1905 if (bkpinfo->exclude_paths[0]) {
1906 strcat(bkpinfo->exclude_paths, " ");
1907 }
1908 strncpy(bkpinfo->exclude_paths, tmp, MAX_STR_LEN);
1909 }
1910 mr_free(tmp);
1911// NTFS
1912 mr_asprintf(&tmp,
1913 call_program_and_get_last_line_of_output
1914 ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
1915 if (strlen(tmp) > 2) {
1916 if (!popup_and_get_string
1917 ("NTFS partitions",
1918 "Please enter/confirm the NTFS partitions you wish to backup as well.",
1919 tmp, MAX_STR_LEN / 4)) {
1920 log_to_screen("User has chosen not to backup the PC");
1921 finish(1);
1922 }
1923 strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
1924 }
1925 mr_free(tmp);
1926
1927 if (!popup_and_get_string
1928 ("Exclude paths",
1929 "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.",
1930 bkpinfo->exclude_paths, MAX_STR_LEN)) {
1931 log_to_screen("User has chosen not to backup the PC");
1932 finish(1);
1933 }
1934 bkpinfo->make_cd_use_lilo = FALSE;
1935 bkpinfo->backup_data = TRUE;
1936 bkpinfo->verify_data =
1937 ask_me_yes_or_no
1938 (_("Will you want to verify your backups after Mondo has created them?"));
1939
1940#ifndef __FreeBSD__
1941 if (!ask_me_yes_or_no
1942 ("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."))
1943#endif
1944 {
1945 strcpy(bkpinfo->kernel_path, "FAILSAFE");
1946 }
1947
1948 if (!ask_me_yes_or_no
1949 (_("Are you sure you want to proceed? Hit 'no' to abort."))) {
1950 log_to_screen(_("User has chosen not to backup the PC"));
1951 finish(1);
1952 }
1953 } else {
1954 bkpinfo->restore_data = TRUE; // probably...
1955 }
1956
1957 if (bkpinfo->backup_media_type == iso
1958 || bkpinfo->backup_media_type == nfs) {
1959 g_ISO_restore_mode = TRUE;
1960 }
1961#ifdef __FreeSD__
1962// skip
1963#else
1964 if (bkpinfo->backup_media_type == nfs) {
1965 mr_msg(3, "I think the NFS mount is mounted at %s",
1966 bkpinfo->isodir);
1967 }
1968 log_it("isodir = %s", bkpinfo->isodir);
1969 log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
1970#endif
1971
1972 log_it("media device = %s", bkpinfo->media_device);
1973 log_it("media size = %ld", bkpinfo->media_size);
1974 log_it("media type = %s", bkpinfo->backup_media_string);
1975 log_it("prefix = %s", bkpinfo->prefix);
1976 log_it("compression = %ld", bkpinfo->compression_level);
1977 log_it("include_paths = '%s'", bkpinfo->include_paths);
1978 log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
1979 log_it("scratchdir = '%s'", bkpinfo->scratchdir);
1980 log_it("tmpdir = '%s'", bkpinfo->tmpdir);
1981 log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
1982 bkpinfo->boot_loader);
1983 if (bkpinfo->media_size < 0L) {
1984 if (archiving_to_media) {
1985 fatal_error("Media size is less than zero.");
1986 } else {
1987 mr_msg(2, "Warning - media size is less than zero.");
1988 bkpinfo->media_size = 0L;
1989 }
1990 }
1991 return (0);
1992}
1993
1994
1995/**
1996 * Get a space-separated list of NFS mounts.
1997 * @return The list created.
1998 * @note The return value points to static data that will be overwritten with each call.
1999 * @bug Even though we only want the mounts, the devices are still checked.
2000 */
2001char *list_of_NFS_mounts_only(void)
2002{
2003 char *exclude_these_devices;
2004 char *exclude_these_directories;
2005 static char result_sz[512];
2006
2007 malloc_string(exclude_these_devices);
2008 malloc_string(exclude_these_directories);
2009 strcpy(exclude_these_directories,
2010 call_program_and_get_last_line_of_output
2011 ("mount -t coda,ncpfs,nfs,smbfs,cifs,afs,mvfs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2012 strcpy(exclude_these_devices,
2013 call_program_and_get_last_line_of_output
2014 ("tr -s '\t' ' ' < /etc/fstab | grep -E '( (coda|ncpfs|nfs|smbfs|cifs|mvfs) )' | cut -d' ' -f1 | tr -s '\n' ' ' | awk '{print $0;}'"));
2015 sprintf(result_sz, "%s", exclude_these_directories);
2016 mr_free(exclude_these_devices);
2017 mr_free(exclude_these_directories);
2018 return (result_sz);
2019}
2020/* @} - end of utilityGroup */
2021
2022
2023/**
2024 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2025 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2026 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2027 * @ingroup utilityGroup
2028 */
2029void sensibly_set_tmpdir_and_scratchdir(struct s_bkpinfo *bkpinfo)
2030{
2031 char *tmp = NULL;
2032 char *command = NULL;
2033 char *sz = NULL;
2034 int i = 0;
2035
2036 malloc_string(command);
2037 assert(bkpinfo != NULL);
2038
2039#ifdef __FreeBSD__
2040 mr_asprintf(&tmp,
2041 call_program_and_get_last_line_of_output
2042 ("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;}'"));
2043#else
2044 mr_asprintf(&tmp,
2045 call_program_and_get_last_line_of_output
2046 ("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;}'"));
2047#endif
2048
2049 if (tmp[0] != '/') {
2050 mr_asprintf(&sz, "/%s", tmp);
2051 mr_free(tmp);
2052 tmp = sz;
2053 }
2054 if (!tmp[0]) {
2055 fatal_error("I couldn't figure out the tempdir!");
2056 }
2057 i = (int) (random() % 32768);
2058 sprintf(bkpinfo->tmpdir, "%s/tmp.mondo.%d", tmp, i);
2059 log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2060
2061 sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp, i);
2062 log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2063
2064 sprintf(g_erase_tmpdir_and_scratchdir, "rm -Rf %s %s", bkpinfo->tmpdir,
2065 bkpinfo->scratchdir);
2066
2067 mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2068 mr_free(tmp);
2069
2070 paranoid_system(command);
2071 mr_free(command);
2072}
2073
2074
2075/**
2076 * @addtogroup deviceGroup
2077 * @{
2078 */
2079/**
2080 * If we can read @p dev, set @p output to it.
2081 * If @p dev cannot be read, set @p output to "".
2082 * @param dev The device to check for.
2083 * @param output Set to @p dev if @p dev exists, "" otherwise.
2084 * @return TRUE if @p dev exists, FALSE if it doesn't.
2085 */
2086bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2087{
2088 char *command = NULL;
2089
2090 if (!dev || dev[0] == '\0') {
2091 output[0] = '\0';
2092 return (FALSE);
2093 }
2094 mr_msg(10, "Injecting %s", dev);
2095 inject_device(dev);
2096 if (!does_file_exist(dev)) {
2097 mr_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2098 return (FALSE);
2099 }
2100 mr_asprintf(&command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2101 512L, dev);
2102 if (!run_program_and_log_output(command, FALSE)
2103 && !run_program_and_log_output(command, FALSE)) {
2104 strcpy(output, dev);
2105 mr_msg(4, "Found it - %s", dev);
2106 mr_free(command);
2107 return (TRUE);
2108 } else {
2109 output[0] = '\0';
2110 mr_msg(4, "It's not %s", dev);
2111 mr_free(command);
2112 return (FALSE);
2113 }
2114}
2115
2116
2117/**
2118 * Find out what number CD is in the drive.
2119 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2120 * @return The current CD number, or -1 if it could not be found.
2121 * @note If the CD is not mounted, it will be mounted
2122 * (and remain mounted after this function returns).
2123 */
2124int what_number_cd_is_this(struct s_bkpinfo *bkpinfo)
2125{
2126 int cd_number = -1;
2127 char *mountdev = NULL;
2128 char *tmp = NULL;
2129
2130 assert(bkpinfo != NULL);
2131 if (g_ISO_restore_mode) {
2132 mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
2133
2134 mr_asprintf(&mountdev, "%s/archives/THIS-CD-NUMBER", call_program_and_get_last_line_of_output(tmp));
2135 cd_number = atoi(last_line_of_file(mountdev));
2136 mr_free(mountdev);
2137 mr_free(tmp);
2138 return (cd_number);
2139 }
2140
2141 mr_asprintf(&mountdev, bkpinfo->media_device);
2142 if (!mountdev[0]) {
2143 log_it
2144 ("(what_number_cd_is_this) Warning - media_device unknown. Finding out...");
2145 find_cdrom_device(bkpinfo->media_device, FALSE);
2146 }
2147 if (!is_this_device_mounted(MNT_CDROM)) {
2148 mount_CDROM_here(mountdev, MNT_CDROM);
2149 }
2150 cd_number =
2151 atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2152 mr_free(mountdev);
2153 return (cd_number);
2154}
2155
2156
2157/**
2158 * Find out what device is mounted as root (/).
2159 * @return Root device.
2160 * @note The returned string points to static storage and will be overwritten with every call.
2161 * @bug A bit of a misnomer; it's actually finding out the root device.
2162 * The mountpoint (where it's mounted) will obviously be '/'.
2163 */
2164char *where_is_root_mounted()
2165{
2166 /*@ buffers **************** */
2167 static char tmp[MAX_STR_LEN];
2168
2169
2170#ifdef __FreeBSD__
2171 strcpy(tmp, call_program_and_get_last_line_of_output
2172 ("mount | grep \" on / \" | cut -d' ' -f1"));
2173#else
2174 strcpy(tmp, call_program_and_get_last_line_of_output
2175 ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2176 if (strstr(tmp, "/dev/cciss/")) {
2177 strcpy(tmp, call_program_and_get_last_line_of_output
2178 ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2179 }
2180 if (strstr(tmp, "/dev/md")) {
2181 strcpy(tmp,
2182 call_program_and_get_last_line_of_output
2183 ("mount | grep \" on / \" | cut -d' ' -f1"));
2184 }
2185#endif
2186
2187 return (tmp);
2188}
2189
2190
2191/**
2192 * Find out which boot loader is in use.
2193 * @param which_device Device to look for the boot loader on.
2194 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2195 * @note Under Linux, all drives are examined, not just @p which_device.
2196 */
2197char which_boot_loader(char *which_device)
2198{
2199#ifdef __FreeBSD__
2200 int count_lilos = 0;
2201 int count_grubs = 0;
2202 int count_boot0s = 0;
2203 int count_dangerouslydedicated = 0;
2204
2205 log_it("looking at drive %s's MBR", which_device);
2206 if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2207 count_grubs++;
2208 }
2209 if (does_string_exist_in_boot_block(which_device, "LILO")) {
2210 count_lilos++;
2211 }
2212 if (does_string_exist_in_boot_block(which_device, "Drive")) {
2213 count_boot0s++;
2214 }
2215 if (does_string_exist_in_first_N_blocks
2216 (which_device, "FreeBSD/i386", 17)) {
2217 count_dangerouslydedicated++;
2218 }
2219 log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2220 count_grubs, count_lilos, count_elilos, count_boot0s,
2221 count_dangerouslydedicated);
2222
2223 if (count_grubs && !count_lilos) {
2224 return ('G');
2225 } else if (count_lilos && !count_grubs) {
2226 return ('L');
2227 } else if (count_grubs == 1 && count_lilos == 1) {
2228 log_it("I'll bet you used to use LILO but switched to GRUB...");
2229 return ('G');
2230 } else if (count_boot0s == 1) {
2231 return ('B');
2232 } else if (count_dangerouslydedicated) {
2233 return ('D');
2234 } else {
2235 log_it("Unknown boot loader");
2236 return ('U');
2237 }
2238#else
2239 /*@ buffer ***************************************************** */
2240 char *list_drives_cmd;
2241 char *current_drive = NULL;
2242
2243 /*@ pointers *************************************************** */
2244 FILE *pdrives;
2245
2246 /*@ int ******************************************************** */
2247 int count_lilos = 0;
2248 int count_grubs = 0;
2249 size_t n = 0;
2250
2251 /*@ end vars *************************************************** */
2252
2253#ifdef __IA64__
2254 /* No choice for it */
2255 return ('E');
2256#endif
2257 assert(which_device != NULL);
2258 mr_asprintf(&list_drives_cmd,
2259 "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s",
2260 where_is_root_mounted());
2261 log_it("list_drives_cmd = %s", list_drives_cmd);
2262
2263 if (!(pdrives = popen(list_drives_cmd, "r"))) {
2264 log_OS_error("Unable to open list of drives");
2265 mr_free(list_drives_cmd);
2266 return ('\0');
2267 }
2268 mr_free(list_drives_cmd);
2269
2270 for (mr_getline(&current_drive, &n, pdrives); !feof(pdrives);
2271 mr_getline(&current_drive, &n, pdrives)) {
2272 mr_strip_spaces(current_drive);
2273 log_it("looking at drive %s's MBR", current_drive);
2274 if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2275 count_grubs++;
2276 strcpy(which_device, current_drive);
2277 break;
2278 }
2279 if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2280 count_lilos++;
2281 strcpy(which_device, current_drive);
2282 break;
2283 }
2284 }
2285
2286 if (pclose(pdrives)) {
2287 log_OS_error("Cannot pclose pdrives");
2288 }
2289 log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2290 if (count_grubs && !count_lilos) {
2291 return ('G');
2292 } else if (count_lilos && !count_grubs) {
2293 return ('L');
2294 } else if (count_grubs == 1 && count_lilos == 1) {
2295 log_it("I'll bet you used to use LILO but switched to GRUB...");
2296 return ('G');
2297 } else {
2298 log_it("Unknown boot loader");
2299 return ('U');
2300 }
2301#endif
2302}
2303
2304
2305/**
2306 * Write zeroes over the first 16K of @p device.
2307 * @param device The device to zero.
2308 * @return 0 for success, 1 for failure.
2309 */
2310int zero_out_a_device(char *device)
2311{
2312 FILE *fout;
2313 int i;
2314
2315 assert_string_is_neither_NULL_nor_zerolength(device);
2316
2317 log_it("Zeroing drive %s", device);
2318 if (!(fout = fopen(device, "w"))) {
2319 log_OS_error("Unable to open/write to device");
2320 return (1);
2321 }
2322 for (i = 0; i < 16384; i++) {
2323 fputc('\0', fout);
2324 }
2325 paranoid_fclose(fout);
2326 log_it("Device successfully zeroed.");
2327 return (0);
2328}
2329
2330
2331/**
2332 * Return the device pointed to by @p incoming.
2333 * @param incoming The device to resolve symlinks for.
2334 * @return The path to the real device file.
2335 * @note The returned string points to static storage that will be overwritten with each call.
2336 * @bug Won't work with file v4.0; needs to be written in C.
2337 */
2338char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2339{
2340 static char output[MAX_STR_LEN];
2341 char *command = NULL;
2342 char *curr_fname = NULL;
2343 char *scratch = NULL;
2344 char *tmp = NULL;
2345 char *p = NULL;
2346
2347 struct stat statbuf;
2348 malloc_string(tmp);
2349 malloc_string(scratch);
2350 malloc_string(curr_fname);
2351 if (!does_file_exist(incoming)) {
2352 log_it
2353 ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2354 strcpy(output, incoming);
2355 } else {
2356 strcpy(curr_fname, incoming);
2357 lstat(curr_fname, &statbuf);
2358 while (S_ISLNK(statbuf.st_mode)) {
2359 mr_msg(1, "curr_fname = %s", curr_fname);
2360 mr_asprintf(&command, "file %s", curr_fname);
2361 strcpy(tmp, call_program_and_get_last_line_of_output(command));
2362 mr_free(command);
2363
2364 for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2365 p--);
2366 p++;
2367 strcpy(scratch, p);
2368 for (p = scratch; *p != '\0' && *p != '\''; p++);
2369 *p = '\0';
2370 mr_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp,
2371 scratch);
2372 if (scratch[0] == '/') {
2373 strcpy(curr_fname, scratch); // copy whole thing because it's an absolute softlink
2374 } else { // copy over the basename cos it's a relative softlink
2375 p = curr_fname + strlen(curr_fname);
2376 while (p != curr_fname && *p != '/') {
2377 p--;
2378 }
2379 if (*p == '/') {
2380 p++;
2381 }
2382 strcpy(p, scratch);
2383 }
2384 lstat(curr_fname, &statbuf);
2385 }
2386 strcpy(output, curr_fname);
2387 log_it("resolved %s to %s", incoming, output);
2388 }
2389 mr_free(curr_fname);
2390 mr_free(tmp);
2391 return (output);
2392}
2393
2394/* @} - end of deviceGroup */
2395
2396
2397/**
2398 * Return the type of partition format (GPT or MBR)
2399 */
2400char *which_partition_format(const char *drive)
2401{
2402 static char output[4];
2403 char *tmp = NULL;
2404 char *command = NULL;
2405 char *fdisk = NULL;
2406
2407 mr_msg(0, "Looking for partition table format type");
2408 mr_asprintf(&fdisk, "/sbin/parted2fdisk");
2409 mr_msg(1, "Using %s", fdisk);
2410 mr_asprintf(&command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2411 mr_free(fdisk);
2412
2413 mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2414 mr_free(command);
2415
2416 if (strstr(tmp, "GPT") == NULL) {
2417 strcpy(output, "MBR");
2418 } else {
2419 strcpy(output, "GPT");
2420 }
2421 mr_free(tmp);
2422 mr_msg(0, "Found %s partition table format type", output);
2423 return(output);
2424}
2425/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.