source: MondoRescue/branches/3.3/mondo/src/common/libmondo-devices.c@ 3878

Last change on this file since 3878 was 3878, checked in by Bruno Cornec, 4 months ago

Fix compiler errors

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