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

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

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

  • Property svn:keywords set to Id
File size: 70.7 KB
Line 
1/* libmondo-devices.c Subroutines for handling devices
2 $Id: libmondo-devices.c 1924 2008-04-17 23:41:41Z 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 1924 2008-04-17 23:41:41Z 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 if (bkpinfo->backup_media_type == tape && bkpinfo->restore_data) {
1579 popup_and_OK(_("Please remove media from drive"));
1580 }
1581 mr_msg(3, "media type = %s",
1582 bkptype_to_string(bkpinfo->backup_media_type));
1583 if (archiving_to_media) {
1584 sensibly_set_tmpdir_and_scratchdir();
1585 }
1586 bkpinfo->compression_level =
1587 (bkpinfo->backup_media_type == cdstream) ? 1 : 5;
1588 mvaddstr_and_log_it(2, 0, " ");
1589
1590// Find device's /dev (or SCSI) entry
1591 switch (bkpinfo->backup_media_type) {
1592 case cdr:
1593 case cdrw:
1594 case dvd:
1595 case usb:
1596 /* Never try to eject a USB device */
1597 if (bkpinfo->backup_media_type == usb) {
1598 bkpinfo->please_dont_eject = TRUE;
1599 }
1600 if (archiving_to_media) {
1601 if ((bkpinfo->backup_media_type != dvd) && (bkpinfo->backup_media_type != usb)) {
1602 if (ask_me_yes_or_no
1603 (_("Does your computer have a manual tray?")))
1604 {
1605 bkpinfo->manual_tray = TRUE;
1606 }
1607 }
1608 if ((bkpinfo->compression_level =
1609 which_compression_level()) == -1) {
1610 log_to_screen(_("User has chosen not to backup the PC"));
1611 finish(1);
1612 }
1613 mr_asprintf(&comment, _("What speed is your %s (re)writer?"),
1614 bkpinfo->backup_media_string);
1615 mr_asprintf(&tmp, "%d", mr_conf->iso_burning_speed);
1616 if (bkpinfo->backup_media_type != usb) {
1617 /* BERLIOS: NOW that tmp isn't static anymore it does NOT work */
1618 if (!popup_and_get_string(_("Speed"), comment, tmp, 4)) {
1619 log_to_screen(_("User has chosen not to backup the PC"));
1620 finish(1);
1621 }
1622 }
1623 mr_free(comment);
1624
1625 bkpinfo->writer_speed = atoi(tmp);
1626 mr_free(tmp);
1627
1628 mr_asprintf(&comment, _("What is your media device ?"));
1629 mr_asprintf(&tmp, mr_conf->media_device);
1630
1631 if (!popup_and_get_string("Device", comment, tmp, 5)) {
1632 log_to_screen(_("User has chosen not to backup the PC"));
1633 finish(1);
1634 }
1635 mr_free(comment);
1636
1637 mr_free(bkpinfo->media_device);
1638 bkpinfo->media_device = tmp;
1639
1640 /* Also adapt the burning device if needed */
1641 if ((strcmp(bkpinfo->media_device, mr_conf->media_device) != 0) &&
1642 (strcmp(mr_conf->media_device,mr_conf->iso_burning_dev) != 0)) {
1643 mr_asprintf(&comment, _("What is your burning media device then ?"));
1644 mr_asprintf(&tmp, mr_conf->iso_burning_dev);
1645
1646 if (!popup_and_get_string("Device", comment, tmp, 5)) {
1647 log_to_screen(_("User has chosen not to backup the PC"));
1648 finish(1);
1649 }
1650 mr_free(comment);
1651
1652 /* BCO: We change the mr_conf struct. Check that it doesn't create pb */
1653 mr_free(bkpinfo->iso_burning_dev);
1654 bkpinfo->iso_burning_dev = tmp;
1655 }
1656
1657 mr_asprintf(&comment,
1658 _("How much data (in Megabytes) will each %s store?"),
1659 bkpinfo->backup_media_string);
1660 mr_asprintf(&sz_size, "%d", mr_conf->media_size);
1661
1662 if (!popup_and_get_string("Size", comment, sz_size, 5)) {
1663 log_to_screen(_("User has chosen not to backup the PC"));
1664 finish(1);
1665 }
1666 mr_free(comment);
1667
1668 bkpinfo->media_size = atol(sz_size);
1669 mr_free(sz_size);
1670
1671 if (bkpinfo->media_size <= 0L) {
1672 log_to_screen(_("User has chosen not to backup the PC"));
1673 finish(1);
1674 }
1675 }
1676 /* No break because we continue even for usb */
1677 case cdstream:
1678 if ((bkpinfo->disaster_recovery) && (bkpinfo->backup_media_type != usb)) {
1679 mr_allocstr(bkpinfo->media_device, "/dev/cdrom");
1680 mr_msg(2, "CD-ROM device assumed to be at %s", bkpinfo->media_device);
1681 } else if ((bkpinfo->restore_data && (bkpinfo->backup_media_type != usb))
1682 || bkpinfo->backup_media_type == dvd) {
1683 if (!bkpinfo->media_device) {
1684 mr_allocstr(bkpinfo->media_device, "/dev/cdrom");
1685 } // just for the heck of it :)
1686 mr_msg(1, "bkpinfo->media_device = %s", bkpinfo->media_device);
1687 mr_asprintf(&comment,
1688 _("Please specify your %s drive's /dev entry"), media_descriptor_string(bkpinfo->backup_media));
1689 mr_asprintf(&tmp,"/dev/cdrom");
1690 if (!popup_and_get_string
1691 (_("Device?"), comment, tmp, MAX_STR_LEN / 4)) {
1692 log_to_screen(_("User has chosen not to backup the PC"));
1693 finish(1);
1694 }
1695 mr_free(comment);
1696 mr_free(bkpinfo->media_device);
1697 bkpinfo->media_device=tmp;
1698
1699 mr_msg(2, "%s device found at %s",
1700 bkpinfo->backup_media_string,
1701 bkpinfo->media_device);
1702 } else {
1703 if (bkpinfo->backup_media_type == usb) {
1704 mr_asprintf(&comment, _("What is the /dev entry of your USB Disk/Key, please ?"));
1705 } else {
1706 mr_asprintf(&comment, _("What is your media device ?"));
1707 }
1708 mr_asprintf(&tmp, mr_conf->media_device);
1709
1710 if (!popup_and_get_string("Device", comment, tmp, 5)) {
1711 log_to_screen(_("User has chosen not to backup the PC"));
1712 finish(1);
1713 }
1714 mr_free(comment);
1715
1716 mr_free(bkpinfo->media_device);
1717 bkpinfo->media_device = tmp;
1718
1719 /* Also adapt the burning device if needed */
1720 if ((strcmp(bkpinfo->media_device, mr_conf->media_device) != 0) &&
1721 (strcmp(mr_conf->media_device,mr_conf->iso_burning_dev) != 0)) {
1722 mr_asprintf(&comment, _("What is your burning media device then ?"));
1723 mr_asprintf(&tmp, mr_conf->iso_burning_dev);
1724
1725 if (!popup_and_get_string("Device", comment, tmp, 5)) {
1726 log_to_screen(_("User has chosen not to backup the PC"));
1727 finish(1);
1728 }
1729 mr_free(comment);
1730
1731 /* BCO: We change the mr_conf struct. Check that it doesn't create pb */
1732 mr_free(bkpinfo->iso_burning_dev);
1733 bkpinfo->iso_burning_dev = tmp;
1734 }
1735
1736 }
1737 /* BERLIOS: Is it useful ?? */
1738 bkpinfo->media_size = (long)650;
1739 break;
1740
1741 case udev:
1742 if (!ask_me_yes_or_no
1743 (_("This option is for advanced users only. Are you sure?"))) {
1744 log_to_screen(_("User has chosen not to backup the PC"));
1745 finish(1);
1746 }
1747
1748 case tape:
1749 if (bkpinfo->media_device) {
1750 if ((fin = fopen(bkpinfo->media_device, "r"))) {
1751 paranoid_fclose(fin);
1752 } else {
1753 if (does_file_exist("/tmp/mondo-restore.cfg")) {
1754 /* BERLIOS: NOW that bkpinfo->media_device isn't static anymore it does NOT work */
1755 read_cfg_var("/tmp/mondo-restore.cfg", "media-dev",
1756 bkpinfo->media_device);
1757 }
1758 }
1759 mr_asprintf(&comment,
1760 _("I think I've found your tape streamer at %s; am I right on the money?"),
1761 bkpinfo->media_device);
1762 if (!ask_me_yes_or_no(comment)) {
1763 mr_asprintf(&tmp,bkpinfo->media_device);
1764 if (!popup_and_get_string
1765 (_("Device name?"),
1766 _("What is the /dev entry of your tape streamer?"),
1767 tmp, MAX_STR_LEN / 4)) {
1768 log_to_screen("User has chosen not to backup the PC");
1769 finish(1);
1770 }
1771 mr_free(bkpinfo->media_device);
1772 bkpinfo->media_device = tmp;
1773 }
1774 mr_free(comment);
1775 } else {
1776 mr_asprintf(&tmp,bkpinfo->media_device);
1777 if (!popup_and_get_string
1778 (_("Device name?"),
1779 _("What is the /dev entry of your tape streamer?"),
1780 tmp, MAX_STR_LEN / 4)) {
1781 log_to_screen("User has chosen not to backup the PC");
1782 finish(1);
1783 }
1784 mr_free(bkpinfo->media_device);
1785 bkpinfo->media_device = tmp;
1786 }
1787 mr_asprintf(&tmp, "ls -l %s", bkpinfo->media_device);
1788 if (run_program_and_log_output(tmp, FALSE)) {
1789 log_to_screen(_("User has not specified a valid /dev entry"));
1790 finish(1);
1791 }
1792 mr_free(tmp);
1793 bkpinfo->media_size = 0L;
1794 mr_msg(4, "media_size = %ld", bkpinfo->media_size);
1795 if (archiving_to_media) {
1796 if ((bkpinfo->compression_level =
1797 which_compression_level()) == -1) {
1798 log_to_screen(_("User has chosen not to backup the PC"));
1799 finish(1);
1800 }
1801 }
1802 break;
1803
1804
1805
1806 case nfs:
1807 /* Never try to eject a NFS device */
1808 bkpinfo->please_dont_eject = TRUE;
1809
1810 /* Initiate bkpinfo nfs_mount path from running environment if not already done */
1811 if (!bkpinfo->nfs_mount[0]) {
1812 strcpy(bkpinfo->nfs_mount,
1813 call_program_and_get_last_line_of_output
1814 ("mount | grep \":\" | cut -d' ' -f1 | head -n1"));
1815 }
1816#ifdef __FreeBSD__
1817 if (TRUE)
1818#else
1819 if (!bkpinfo->disaster_recovery)
1820#endif
1821 {
1822 if (!popup_and_get_string
1823 ("NFS dir.",
1824 "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.)",
1825 bkpinfo->nfs_mount, MAX_STR_LEN / 4)) {
1826 log_to_screen("User has chosen not to backup the PC");
1827 finish(1);
1828 }
1829 if (!bkpinfo->restore_data) {
1830 if ((bkpinfo->compression_level =
1831 which_compression_level()) == -1) {
1832 log_to_screen(_("User has chosen not to backup the PC"));
1833 finish(1);
1834 }
1835 }
1836 // check whether already mounted - we better remove
1837 // surrounding spaces and trailing '/' for this
1838 mr_strip_spaces(bkpinfo->nfs_mount);
1839 if (bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] == '/')
1840 bkpinfo->nfs_mount[strlen(bkpinfo->nfs_mount) - 1] = '\0';
1841 mr_asprintf(&command, "mount | grep \"%s \" | cut -d' ' -f3",
1842 bkpinfo->nfs_mount);
1843 strcpy(bkpinfo->isodir,
1844 call_program_and_get_last_line_of_output(command));
1845 mr_free(command);
1846
1847 if (!bkpinfo->restore_data) {
1848 mr_asprintf(&comment,
1849 _("How much data (in Megabytes) will each media store?"));
1850 if (!popup_and_get_string(_("Size"), comment, sz_size, 5)) {
1851 log_to_screen(_("User has chosen not to backup the PC"));
1852 finish(1);
1853 }
1854 } else {
1855 strcpy(sz_size, "0");
1856 }
1857 mr_free(comment);
1858 bkpinfo->media_size = atol(sz_size);
1859 if (bkpinfo->media_size <= 0L) {
1860 log_to_screen(_("User has chosen not to backup the PC"));
1861 finish(1);
1862 }
1863 }
1864 if (bkpinfo->disaster_recovery) {
1865 sprintf(command ,"umount %s/isodir 2> /dev/null", bkpinfo->tmpdir);
1866 system(command);
1867 if (!popup_and_get_string
1868 ("NFS share", "Which remote NFS share should I mount?",
1869 bkpinfo->nfs_mount, MAX_STR_LEN)) {
1870 log_to_screen("User has chosen not to backup the PC");
1871 finish(1);
1872 }
1873 }
1874 /* Initiate bkpinfo isodir path from running environment if mount already done */
1875 if (is_this_device_mounted(bkpinfo->nfs_mount)) {
1876 strcpy(bkpinfo->isodir,
1877 call_program_and_get_last_line_of_output
1878 ("mount | grep \":\" | cut -d' ' -f3 | head -n1"));
1879 } else {
1880 sprintf(bkpinfo->isodir, "%s/nfsdir", bkpinfo->tmpdir);
1881 mr_asprintf(&command, "mkdir -p %s", bkpinfo->isodir);
1882 run_program_and_log_output(command, 5);
1883 mr_free(command);
1884
1885 mr_asprintf(&tmp, "mount -t nfs -o nolock %s %s", bkpinfo->nfs_mount,
1886 bkpinfo->isodir);
1887 run_program_and_log_output(tmp, 3);
1888 mr_free(tmp);
1889 malloc_string(g_selfmounted_isodir);
1890 strcpy(g_selfmounted_isodir, bkpinfo->isodir);
1891 }
1892 if (!is_this_device_mounted(bkpinfo->nfs_mount)) {
1893 popup_and_OK
1894 (_("Please mount that partition before you try to backup to or restore from it."));
1895 finish(1);
1896 }
1897 mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1898 if (!popup_and_get_string
1899 ("Directory", "Which directory within that mountpoint?", tmp,
1900 MAX_STR_LEN)) {
1901 log_to_screen("User has chosen not to backup the PC");
1902 finish(1);
1903 }
1904 strcpy(bkpinfo->nfs_remote_dir, tmp);
1905 mr_free(tmp);
1906 // check whether writable - we better remove surrounding spaces for this
1907 mr_strip_spaces(bkpinfo->nfs_remote_dir);
1908 mr_asprintf(&tmp1,"%s/%s/.dummy.txt", bkpinfo->isodir,bkpinfo->nfs_remote_dir);
1909 mr_asprintf(&command, "echo hi > '%s'", tmp1);
1910 while (run_program_and_log_output(command, FALSE)) {
1911 mr_asprintf(&tmp, bkpinfo->nfs_remote_dir);
1912 mr_asprintf(&prompt,
1913 _("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."),
1914 bkpinfo->nfs_remote_dir, bkpinfo->isodir);
1915 if (!popup_and_get_string
1916 ("Directory", prompt, tmp, MAX_STR_LEN)) {
1917 log_to_screen("User has chosen not to backup the PC");
1918 finish(1);
1919 }
1920 mr_free(prompt);
1921
1922 strcpy(bkpinfo->nfs_remote_dir, tmp);
1923 mr_free(tmp);
1924 // check whether writable - we better remove surrounding space s for this
1925 mr_strip_spaces(bkpinfo->nfs_remote_dir);
1926 paranoid_free(tmp1);
1927 mr_asprintf(&tmp1,"%s/%s/.dummy.txt", bkpinfo->isodir,bkpinfo->nfs_remote_dir);
1928
1929 mr_free(command);
1930 mr_asprintf(&command, "echo hi > '%s'", tmp1);
1931 }
1932 mr_free(command);
1933 unlink(tmp1);
1934 paranoid_free(tmp1);
1935
1936 mr_asprintf(&tmp, mr_conf->prefix);
1937 if (!popup_and_get_string
1938 ("Prefix.",
1939 "Please enter the prefix that will be prepended to your ISO filename. Example: machine1 to obtain machine1-[1-9]*.iso files",
1940 tmp, MAX_STR_LEN / 4)) {
1941 log_to_screen("User has chosen not to backup the PC");
1942 finish(1);
1943 }
1944 mr_free(bkpinfo->prefix);
1945 bkpinfo->prefix = tmp;
1946 mr_msg(3, "prefix set to %s", bkpinfo->prefix);
1947
1948 if (archiving_to_media) {
1949 if (!popup_and_get_string
1950 ("Size.",
1951 "Please enter how big you want each NFS image to be (in megabytes).",
1952 sz_size, 16)) {
1953 log_to_screen("User has chosen not to backup the PC");
1954 finish(1);
1955 }
1956 bkpinfo->media_size = atol(sz_size);
1957 if (bkpinfo->media_size <= 0L) {
1958 log_to_screen(_("User has chosen not to backup the PC"));
1959 finish(1);
1960 }
1961 }
1962 mr_msg(3, "Just set nfs_remote_dir to %s",
1963 bkpinfo->nfs_remote_dir);
1964 mr_msg(3, "isodir is still %s", bkpinfo->isodir);
1965 break;
1966
1967 case iso:
1968 if (!bkpinfo->disaster_recovery) {
1969 if (!popup_and_get_string
1970 ("Storage dir.",
1971 "Please enter the full path name to the directory for your ISO images. Example: /mnt/raid0_0",
1972 bkpinfo->isodir, MAX_STR_LEN / 4)) {
1973 log_to_screen("User has chosen not to backup the PC");
1974 finish(1);
1975 }
1976 if (archiving_to_media) {
1977 if ((bkpinfo->compression_level =
1978 which_compression_level()) == -1) {
1979 log_to_screen(_("User has chosen not to backup the PC"));
1980 finish(1);
1981 }
1982 if (!popup_and_get_string
1983 ("ISO size.",
1984 "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.",
1985 sz_size, 16)) {
1986 log_to_screen("User has chosen not to backup the PC");
1987 finish(1);
1988 }
1989 bkpinfo->media_size = atol(sz_size);
1990 /* BERLIOS: this should be useless
1991 */
1992 } else {
1993 bkpinfo->media_size = (long)650;
1994 }
1995 }
1996 mr_asprintf(&tmp, mr_conf->prefix);
1997 if (!popup_and_get_string
1998 ("Prefix.",
1999 "Please enter the prefix that will be prepended to your ISO filename. Example: machine1 to obtain machine1-[1-9]*.iso files",
2000 tmp, MAX_STR_LEN / 4)) {
2001 log_to_screen("User has chosen not to backup the PC");
2002 finish(1);
2003 }
2004 mr_free(bkpinfo->prefix);
2005 bkpinfo->prefix = tmp;
2006 mr_msg(3, "prefix set to %s", bkpinfo->prefix);
2007 break;
2008 default:
2009 fatal_error
2010 ("I, Mojo Jojo, shall defeat those pesky Powerpuff Girls!");
2011 }
2012 if (archiving_to_media) {
2013
2014#ifdef __FreeBSD__
2015 strcpy(bkpinfo->boot_device,
2016 call_program_and_get_last_line_of_output
2017 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
2018#else
2019 strcpy(bkpinfo->boot_device,
2020 call_program_and_get_last_line_of_output
2021 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
2022#endif
2023 i = which_boot_loader(bkpinfo->boot_device);
2024 if (i == 'U') // unknown
2025 {
2026
2027#ifdef __FreeBSD__
2028 if (!popup_and_get_string
2029 ("Boot device",
2030 "What is your boot device? (e.g. /dev/ad0)",
2031 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2032 log_to_screen("User has chosen not to backup the PC");
2033 finish(1);
2034 }
2035 i = which_boot_loader(bkpinfo->boot_device);
2036#else
2037 if (!popup_and_get_string
2038 ("Boot device",
2039 "What is your boot device? (e.g. /dev/hda)",
2040 bkpinfo->boot_device, MAX_STR_LEN / 4)) {
2041 log_to_screen("User has chosen not to backup the PC");
2042 finish(1);
2043 }
2044 if (does_string_exist_in_boot_block
2045 (bkpinfo->boot_device, "LILO")) {
2046 i = 'L';
2047 } else
2048 if (does_string_exist_in_boot_block
2049 (bkpinfo->boot_device, "ELILO")) {
2050 i = 'E';
2051 } else
2052 if (does_string_exist_in_boot_block
2053 (bkpinfo->boot_device, "GRUB")) {
2054 i = 'G';
2055 } else {
2056 i = 'U';
2057 }
2058#endif
2059 if (i == 'U') {
2060 if (ask_me_yes_or_no
2061 (_("Unidentified boot loader. Shall I restore it byte-for-byte at restore time and hope for the best?")))
2062 {
2063 i = 'R'; // raw
2064 } else {
2065 log_to_screen
2066 (_("I cannot find your boot loader. Please run mondoarchive with parameters."));
2067 finish(1);
2068 }
2069 }
2070 }
2071 bkpinfo->boot_loader = i;
2072 strcpy(bkpinfo->include_paths, "/");
2073 if (!popup_and_get_string
2074 ("Backup paths",
2075 "Please enter paths which you want me to backup. The default is '/' (i.e. everything).",
2076 bkpinfo->include_paths, MAX_STR_LEN)) {
2077 log_to_screen("User has chosen not to backup the PC");
2078 finish(1);
2079 }
2080 mr_asprintf(&tmp, list_of_NFS_mounts_only());
2081 if (strlen(tmp) > 2) {
2082 if (bkpinfo->exclude_paths != NULL) {
2083 mr_strcat(bkpinfo->exclude_paths, " ");
2084 }
2085 mr_strcat(bkpinfo->exclude_paths,tmp);
2086 }
2087 mr_free(tmp);
2088// NTFS
2089 mr_asprintf(&tmp,
2090 call_program_and_get_last_line_of_output
2091 ("parted2fdisk -l | grep -i ntfs | awk '{ print $1};' | tr -s '\\n' ' ' | awk '{ print $0};'"));
2092 if (strlen(tmp) > 2) {
2093 if (!popup_and_get_string
2094 ("NTFS partitions",
2095 "Please enter/confirm the NTFS partitions you wish to backup as well.",
2096 tmp, MAX_STR_LEN / 4)) {
2097 log_to_screen("User has chosen not to backup the PC");
2098 finish(1);
2099 }
2100 strncpy(bkpinfo->image_devs, tmp, MAX_STR_LEN / 4);
2101 }
2102 mr_free(tmp);
2103
2104 if (!popup_and_get_string
2105 ("Exclude paths",
2106 "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.",
2107 bkpinfo->exclude_paths, (4*MAX_STR_LEN)-1)) {
2108 log_to_screen("User has chosen not to backup the PC");
2109 finish(1);
2110 }
2111// Interactive mode:
2112#ifdef __IA64__
2113 bkpinfo->make_cd_use_lilo = TRUE;
2114#else
2115 bkpinfo->make_cd_use_lilo = FALSE;
2116#endif
2117 bkpinfo->backup_data = TRUE;
2118 bkpinfo->verify_data =
2119 ask_me_yes_or_no
2120 (_("Will you want to verify your backups after Mondo has created them?"));
2121
2122#ifndef __FreeBSD__
2123 if (!ask_me_yes_or_no
2124 ("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."))
2125#endif
2126 {
2127 mr_allocstr(bkpinfo->kernel_path, "FAILSAFE");
2128 }
2129
2130 if (!ask_me_yes_or_no
2131 (_("Are you sure you want to proceed? Hit 'no' to abort."))) {
2132 log_to_screen(_("User has chosen not to backup the PC"));
2133 finish(1);
2134 }
2135 } else {
2136 bkpinfo->restore_data = TRUE; // probably...
2137 }
2138
2139 if (bkpinfo->backup_media_type == iso
2140 || bkpinfo->backup_media_type == nfs) {
2141 g_ISO_restore_mode = TRUE;
2142 }
2143#ifdef __FreeBSD__
2144// skip
2145#else
2146 if (bkpinfo->backup_media_type == nfs) {
2147 mr_msg(3, "I think the NFS mount is mounted at %s",
2148 bkpinfo->isodir);
2149 }
2150 log_it("isodir = %s", bkpinfo->isodir);
2151 log_it("nfs_mount = '%s'", bkpinfo->nfs_mount);
2152#endif
2153
2154 log_it("media device = %s", bkpinfo->media_device);
2155 log_it("media size = %ld", bkpinfo->media_size);
2156 log_it("media type = %s", bkpinfo->backup_media_string);
2157 log_it("prefix = %s", bkpinfo->prefix);
2158 log_it("compression tool = %ld", bkpinfo->compression_tool);
2159 log_it("compression suffix = %ld", bkpinfo->compression_suffix);
2160 log_it("compression level = %ld", bkpinfo->compression_level);
2161 log_it("include_paths = '%s'", bkpinfo->include_paths);
2162 log_it("exclude_paths = '%s'", bkpinfo->exclude_paths);
2163 log_it("scratchdir = '%s'", bkpinfo->scratchdir);
2164 log_it("tmpdir = '%s'", bkpinfo->tmpdir);
2165 log_it("image_devs = '%s'", bkpinfo->image_devs);
2166 log_it("boot_device = '%s' (loader=%c)", bkpinfo->boot_device,
2167 bkpinfo->boot_loader);
2168 if (bkpinfo->media_size < 0L) {
2169 if (archiving_to_media) {
2170 fatal_error("Media size is less than zero.");
2171 } else {
2172 mr_msg(2, "Warning - media size is less than zero.");
2173 bkpinfo->media_size = 0L;
2174 }
2175 }
2176 return (0);
2177}
2178
2179
2180/**
2181 * Get a space-separated list of NFS mounts.
2182 * @return The list created.
2183 * @note The return value points to static data that will be overwritten with each call.
2184 * @bug Even though we only want the mounts, the devices are still checked.
2185 */
2186char *list_of_NFS_mounts_only(void)
2187{
2188 char *exclude_these_devices;
2189 char *exclude_these_directories;
2190 static char result_sz[512];
2191
2192 malloc_string(exclude_these_devices);
2193 malloc_string(exclude_these_directories);
2194 strcpy(exclude_these_directories,
2195 call_program_and_get_last_line_of_output
2196 ("mount -t coda,ncpfs,nfs,smbfs,cifs,afs,ocfs,ocfs2,mvfs | tr -s '\t' ' ' | cut -d' ' -f3 | tr -s '\n' ' ' | awk '{print $0;}'"));
2197 strcpy(exclude_these_devices,
2198 call_program_and_get_last_line_of_output
2199 ("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;}'"));
2200 sprintf(result_sz, "%s", exclude_these_directories);
2201 mr_free(exclude_these_devices);
2202 mr_free(exclude_these_directories);
2203 return (result_sz);
2204}
2205/* @} - end of utilityGroup */
2206
2207
2208/**
2209 * Set the tmpdir and scratchdir to reside on the partition with the most free space.
2210 * Automatically excludes DOS, NTFS, SMB, and NFS filesystems.
2211 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir and @c bkpinfo->scratchdir will be set.
2212 * @ingroup utilityGroup
2213 */
2214void sensibly_set_tmpdir_and_scratchdir()
2215{
2216 char *tmp = NULL;
2217 char *command = NULL;
2218 char *sz = NULL;
2219 int i = 0;
2220
2221 malloc_string(command);
2222 assert(bkpinfo != NULL);
2223
2224#ifdef __FreeBSD__
2225 mr_asprintf(&tmp,
2226 call_program_and_get_last_line_of_output
2227 ("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;}'"));
2228#else
2229 mr_asprintf(&tmp,
2230 call_program_and_get_last_line_of_output
2231 ("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;}'"));
2232#endif
2233
2234 if (tmp[0] != '/') {
2235 mr_asprintf(&sz, "/%s", tmp);
2236 mr_free(tmp);
2237 tmp = sz;
2238 }
2239 if (!tmp[0]) {
2240 fatal_error("I couldn't figure out the tempdir!");
2241 }
2242 setup_tmpdir(tmp);
2243 log_it("bkpinfo->tmpdir is being set to %s", bkpinfo->tmpdir);
2244
2245 sprintf(bkpinfo->scratchdir, "%s/mondo.scratch.%d", tmp, i);
2246 log_it("bkpinfo->scratchdir is being set to %s", bkpinfo->scratchdir);
2247
2248 mr_asprintf(&command, "rm -Rf %s/tmp.mondo.* %s/mondo.scratch.*", tmp, tmp);
2249 mr_free(tmp);
2250
2251 paranoid_system(command);
2252 mr_free(command);
2253}
2254
2255
2256/**
2257 * @addtogroup deviceGroup
2258 * @{
2259 */
2260/**
2261 * If we can read @p dev, set @p output to it.
2262 * If @p dev cannot be read, set @p output to "".
2263 * @param dev The device to check for.
2264 * @param output Set to @p dev if @p dev exists, "" otherwise.
2265 * @return TRUE if @p dev exists, FALSE if it doesn't.
2266 */
2267bool set_dev_to_this_if_rx_OK(char *output, char *dev)
2268{
2269 char *command = NULL;
2270
2271 if (!dev || dev[0] == '\0') {
2272 output[0] = '\0';
2273 return (FALSE);
2274 }
2275 mr_msg(10, "Injecting %s", dev);
2276 inject_device(dev);
2277 if (!does_file_exist(dev)) {
2278 mr_msg(10, "%s doesn't exist. Returning FALSE.", dev);
2279 return (FALSE);
2280 }
2281 mr_asprintf(&command, "dd bs=%ld count=1 if=%s of=/dev/null &> /dev/null",
2282 512L, dev);
2283 if (!run_program_and_log_output(command, FALSE)
2284 && !run_program_and_log_output(command, FALSE)) {
2285 strcpy(output, dev);
2286 mr_msg(4, "Found it - %s", dev);
2287 mr_free(command);
2288 return (TRUE);
2289 } else {
2290 output[0] = '\0';
2291 mr_msg(4, "It's not %s", dev);
2292 mr_free(command);
2293 return (FALSE);
2294 }
2295}
2296
2297
2298/**
2299 * Find out what number CD is in the drive.
2300 * @param bkpinfo The backup information structure. The @c bkpinfo->media_device field is the only one used.
2301 * @return The current CD number, or -1 if it could not be found.
2302 * @note If the CD is not mounted, it will be mounted
2303 * (and remain mounted after this function returns).
2304 */
2305int what_number_cd_is_this()
2306{
2307 int cd_number = -1;
2308 char *mountdev = NULL;
2309 char *tmp = NULL;
2310
2311 assert(bkpinfo != NULL);
2312 if (g_ISO_restore_mode) {
2313 mr_asprintf(&tmp, "mount | grep iso9660 | awk '{print $3;}'");
2314
2315 mr_asprintf(&mountdev, "%s/archives/THIS-CD-NUMBER", call_program_and_get_last_line_of_output(tmp));
2316 cd_number = atoi(last_line_of_file(mountdev));
2317 mr_free(mountdev);
2318 mr_free(tmp);
2319 return (cd_number);
2320 }
2321
2322 mr_asprintf(&mountdev, bkpinfo->media_device);
2323 if (!is_this_device_mounted(MNT_CDROM)) {
2324 if (bkpinfo->backup_media_type == usb) {
2325 mount_USB_here(mountdev, MNT_CDROM);
2326 } else {
2327 mount_CDROM_here(mountdev, MNT_CDROM);
2328 }
2329 }
2330 cd_number =
2331 atoi(last_line_of_file(MNT_CDROM "/archives/THIS-CD-NUMBER"));
2332 mr_free(mountdev);
2333 return (cd_number);
2334}
2335
2336
2337/**
2338 * Find out what device is mounted as root (/).
2339 * @return Root device.
2340 * @note The returned string points to static storage and will be overwritten with every call.
2341 * @bug A bit of a misnomer; it's actually finding out the root device.
2342 * The mountpoint (where it's mounted) will obviously be '/'.
2343 */
2344char *where_is_root_mounted()
2345{
2346 /*@ buffers **************** */
2347 static char tmp[MAX_STR_LEN];
2348
2349
2350#ifdef __FreeBSD__
2351 strcpy(tmp, call_program_and_get_last_line_of_output
2352 ("mount | grep \" on / \" | cut -d' ' -f1"));
2353#else
2354 strcpy(tmp, call_program_and_get_last_line_of_output
2355 ("mount | grep \" on / \" | cut -d' ' -f1 | sed s/[0-9]// | sed s/[0-9]//"));
2356 if (strstr(tmp, "/dev/cciss/")) {
2357 strcpy(tmp, call_program_and_get_last_line_of_output
2358 ("mount | grep \" on / \" | cut -d' ' -f1 | cut -dp -f1"));
2359 }
2360 if (strstr(tmp, "/dev/md")) {
2361 strcpy(tmp,
2362 call_program_and_get_last_line_of_output
2363 ("mount | grep \" on / \" | cut -d' ' -f1"));
2364 }
2365#endif
2366
2367 return (tmp);
2368}
2369
2370
2371/**
2372 * Find out which boot loader is in use.
2373 * @param which_device Device to look for the boot loader on.
2374 * @return 'L' for LILO, 'E'for ELILO, 'G' for GRUB, 'B' or 'D' for FreeBSD boot loaders, or 'U' for Unknown.
2375 * @note Under Linux, all drives are examined, not just @p which_device.
2376 */
2377char which_boot_loader(char *which_device)
2378{
2379#ifdef __FreeBSD__
2380 int count_lilos = 0;
2381 int count_grubs = 0;
2382 int count_boot0s = 0;
2383 int count_dangerouslydedicated = 0;
2384
2385 log_it("looking at drive %s's MBR", which_device);
2386 if (does_string_exist_in_boot_block(which_device, "GRUB")) {
2387 count_grubs++;
2388 }
2389 if (does_string_exist_in_boot_block(which_device, "LILO")) {
2390 count_lilos++;
2391 }
2392 if (does_string_exist_in_boot_block(which_device, "Drive")) {
2393 count_boot0s++;
2394 }
2395 if (does_string_exist_in_first_N_blocks
2396 (which_device, "FreeBSD/i386", 17)) {
2397 count_dangerouslydedicated++;
2398 }
2399 log_it("%d grubs and %d lilos and %d elilos and %d boot0s and %d DD\n",
2400 count_grubs, count_lilos, count_elilos, count_boot0s,
2401 count_dangerouslydedicated);
2402
2403 if (count_grubs && !count_lilos) {
2404 return ('G');
2405 } else if (count_lilos && !count_grubs) {
2406 return ('L');
2407 } else if (count_grubs == 1 && count_lilos == 1) {
2408 log_it("I'll bet you used to use LILO but switched to GRUB...");
2409 return ('G');
2410 } else if (count_boot0s == 1) {
2411 return ('B');
2412 } else if (count_dangerouslydedicated) {
2413 return ('D');
2414 } else {
2415 log_it("Unknown boot loader");
2416 return ('U');
2417 }
2418#else
2419 /*@ buffer ***************************************************** */
2420 char *list_drives_cmd;
2421 char *current_drive = NULL;
2422
2423 /*@ pointers *************************************************** */
2424 FILE *pdrives;
2425
2426 /*@ int ******************************************************** */
2427 int count_lilos = 0;
2428 int count_grubs = 0;
2429 size_t n = 0;
2430
2431 /*@ end vars *************************************************** */
2432
2433#ifdef __IA64__
2434 /* No choice for it */
2435 return ('E');
2436#endif
2437 assert(which_device != NULL);
2438 mr_asprintf(&list_drives_cmd,
2439 "parted2fdisk -l 2>/dev/null | grep \"/dev/.*:\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/; echo %s",
2440 where_is_root_mounted());
2441 log_it("list_drives_cmd = %s", list_drives_cmd);
2442
2443 if (!(pdrives = popen(list_drives_cmd, "r"))) {
2444 log_OS_error("Unable to open list of drives");
2445 mr_free(list_drives_cmd);
2446 return ('\0');
2447 }
2448 mr_free(list_drives_cmd);
2449
2450 for (mr_getline(&current_drive, &n, pdrives); !feof(pdrives);
2451 mr_getline(&current_drive, &n, pdrives)) {
2452 mr_strip_spaces(current_drive);
2453 log_it("looking at drive %s's MBR", current_drive);
2454 if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2455 count_grubs++;
2456 strcpy(which_device, current_drive);
2457 break;
2458 }
2459 if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2460 count_lilos++;
2461 strcpy(which_device, current_drive);
2462 break;
2463 }
2464 }
2465 mr_free(current_drive);
2466
2467 if (pclose(pdrives)) {
2468 log_OS_error("Cannot pclose pdrives");
2469 }
2470 log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2471 if (count_grubs && !count_lilos) {
2472 return ('G');
2473 } else if (count_lilos && !count_grubs) {
2474 return ('L');
2475 } else if (count_grubs == 1 && count_lilos == 1) {
2476 log_it("I'll bet you used to use LILO but switched to GRUB...");
2477 return ('G');
2478 } else {
2479 // We need to look on each partition then
2480 mr_asprintf(&list_drives_cmd,
2481 "parted2fdisk -l 2>/dev/null | grep -E \"^/dev/\" | tr -s ':' ' ' | tr -s ' ' '\n' | grep /dev/");
2482 log_it("list_drives_cmd = %s", list_drives_cmd);
2483
2484 if (!(pdrives = popen(list_drives_cmd, "r"))) {
2485 log_OS_error("Unable to open list of drives");
2486 mr_free(list_drives_cmd);
2487 return ('\0');
2488 }
2489 mr_free(list_drives_cmd);
2490
2491 for (mr_getline(&current_drive, &n, pdrives); !feof(pdrives);
2492 mr_getline(&current_drive, &n, pdrives)) {
2493 mr_strip_spaces(current_drive);
2494 log_it("looking at partition %s's BR", current_drive);
2495 if (does_string_exist_in_boot_block(current_drive, "GRUB")) {
2496 count_grubs++;
2497 strcpy(which_device, current_drive);
2498 break;
2499 }
2500 if (does_string_exist_in_boot_block(current_drive, "LILO")) {
2501 count_lilos++;
2502 strcpy(which_device, current_drive);
2503 break;
2504 }
2505 }
2506 mr_free(current_drive);
2507
2508 if (pclose(pdrives)) {
2509 log_OS_error("Cannot pclose pdrives");
2510 }
2511 log_it("%d grubs and %d lilos\n", count_grubs, count_lilos);
2512 if (count_grubs && !count_lilos) {
2513 return ('G');
2514 } else if (count_lilos && !count_grubs) {
2515 return ('L');
2516 } else if (count_grubs == 1 && count_lilos == 1) {
2517 log_it("I'll bet you used to use LILO but switched to GRUB...");
2518 return ('G');
2519 } else {
2520 log_it("Unknown boot loader");
2521 return ('U');
2522 }
2523 }
2524#endif
2525}
2526
2527
2528/**
2529 * Write zeroes over the first 16K of @p device.
2530 * @param device The device to zero.
2531 * @return 0 for success, 1 for failure.
2532 */
2533int zero_out_a_device(char *device)
2534{
2535 FILE *fout;
2536 int i;
2537
2538 assert_string_is_neither_NULL_nor_zerolength(device);
2539
2540 log_it("Zeroing drive %s", device);
2541 if (!(fout = fopen(device, "w"))) {
2542 log_OS_error("Unable to open/write to device");
2543 return (1);
2544 }
2545 for (i = 0; i < 16384; i++) {
2546 fputc('\0', fout);
2547 }
2548 paranoid_fclose(fout);
2549 log_it("Device successfully zeroed.");
2550 return (0);
2551}
2552
2553
2554/**
2555 * Return the device pointed to by @p incoming.
2556 * @param incoming The device to resolve symlinks for.
2557 * @return The path to the real device file.
2558 * @note The returned string points to static storage that will be overwritten with each call.
2559 * @bug Won't work with file v4.0; needs to be written in C.
2560 */
2561char *resolve_softlinks_to_get_to_actual_device_file(char *incoming)
2562{
2563 static char output[MAX_STR_LEN];
2564 char *command = NULL;
2565 char *curr_fname = NULL;
2566 char *scratch = NULL;
2567 char *tmp = NULL;
2568 char *p = NULL;
2569
2570 struct stat statbuf;
2571 malloc_string(tmp);
2572 malloc_string(scratch);
2573 malloc_string(curr_fname);
2574 if (!does_file_exist(incoming)) {
2575 log_it
2576 ("resolve_softlinks_to_get_to_actual_device_file --- device not found");
2577 strcpy(output, incoming);
2578 } else {
2579 strcpy(curr_fname, incoming);
2580 lstat(curr_fname, &statbuf);
2581 while (S_ISLNK(statbuf.st_mode)) {
2582 mr_msg(1, "curr_fname = %s", curr_fname);
2583 mr_asprintf(&command, "file %s", curr_fname);
2584 strcpy(tmp, call_program_and_get_last_line_of_output(command));
2585 mr_free(command);
2586
2587 for (p = tmp + strlen(tmp); p != tmp && *p != '`' && *p != ' ';
2588 p--);
2589 p++;
2590 strcpy(scratch, p);
2591 for (p = scratch; *p != '\0' && *p != '\''; p++);
2592 *p = '\0';
2593 mr_msg(0, "curr_fname %s --> '%s' --> %s", curr_fname, tmp,
2594 scratch);
2595 if (scratch[0] == '/') {
2596 strcpy(curr_fname, scratch); // copy whole thing because it's an absolute softlink
2597 } else { // copy over the basename cos it's a relative softlink
2598 p = curr_fname + strlen(curr_fname);
2599 while (p != curr_fname && *p != '/') {
2600 p--;
2601 }
2602 if (*p == '/') {
2603 p++;
2604 }
2605 strcpy(p, scratch);
2606 }
2607 lstat(curr_fname, &statbuf);
2608 }
2609 strcpy(output, curr_fname);
2610 log_it("resolved %s to %s", incoming, output);
2611 }
2612 mr_free(curr_fname);
2613 mr_free(tmp);
2614 return (output);
2615}
2616
2617/* @} - end of deviceGroup */
2618
2619
2620/**
2621 * Return the type of partition format (GPT or MBR)
2622 */
2623char *which_partition_format(const char *drive)
2624{
2625 static char output[4];
2626 char *tmp = NULL;
2627 char *command = NULL;
2628 char *fdisk = NULL;
2629
2630 mr_msg(0, "Looking for partition table format type");
2631 mr_asprintf(&fdisk, "/sbin/parted2fdisk");
2632 mr_msg(1, "Using %s", fdisk);
2633 mr_asprintf(&command, "%s -l %s | grep 'EFI GPT'", fdisk, drive);
2634 mr_free(fdisk);
2635
2636 mr_asprintf(&tmp, call_program_and_get_last_line_of_output(command));
2637 mr_free(command);
2638
2639 if (strstr(tmp, "GPT") == NULL) {
2640 strcpy(output, "MBR");
2641 } else {
2642 strcpy(output, "GPT");
2643 }
2644 mr_free(tmp);
2645 mr_msg(0, "Found %s partition table format type", output);
2646 return(output);
2647}
2648/* @} - end of deviceGroup */
Note: See TracBrowser for help on using the repository browser.