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

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

merge -r249:251 $SVN_M/branches/2.05

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