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

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

merge -r272:273 $SVN_M/branches/2.06

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