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

Last change on this file since 162 was 162, checked in by andree, 18 years ago

Avoid overwriting the already correctly determined disk size by moving
the relevant code inside the if clause that checks the validity of the
previously calculated disk size.

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