source: MondoRescue/trunk/mondo/mondo/common/libmondo-devices.c@ 236

Last change on this file since 236 was 236, checked in by bcornec, 18 years ago

merge -r229:235 $SVN_M/branches/2.05

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