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

Last change on this file since 1939 was 1939, checked in by Bruno Cornec, 16 years ago

svn merge -r 1923:1938 $SVN_M/branches/2.2.6

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