source: MondoRescue/branches/2.2.7/mondo/src/mondorestore/mondo-rstr-tools.c@ 2030

Last change on this file since 2030 was 2030, checked in by Bruno Cornec, 16 years ago
  • Fix #252
  • Improve OCFS2 support (ocfs2 is a SANE_FORMAT)
  • Property svn:keywords set to Id
File size: 74.6 KB
Line 
1/***************************************************************************
2$Id: mondo-rstr-tools.c 2030 2008-10-02 23:50:44Z bruno $
3
4/***************************************************************************
5* *
6* This program is free software; you can redistribute it and/or modify *
7* it under the terms of the GNU General Public License as published by *
8* the Free Software Foundation; either version 2 of the License, or *
9* (at your option) any later version. *
10* *
11***************************************************************************/
12
13#include <pthread.h>
14#include <linux/fd.h>
15#include "my-stuff.h"
16#include "../common/mondostructures.h"
17#include "../common/libmondo.h"
18#include "mr-externs.h"
19#include "mondo-rstr-tools.h"
20
21/**
22 * The biggielist stub (appended to the directory where all.tar.gz was unpacked).
23 */
24#define BIGGIELIST_TXT_STUB "tmp/biggielist.txt"
25
26/**
27 * The filelist stub (appended to the directory where all.tar.gz was unpacked).
28 */
29#define FILELIST_FULL_STUB "tmp/filelist.full.gz"
30
31/**
32 * The mountlist stub (appended to the directory where all.tar.gz was unpacked).
33 */
34#define MOUNTLIST_FNAME_STUB "tmp/mountlist.txt"
35
36/**
37 * The mondo-restore.cfg stub (appended to the directory where all.tar.gz was unpacked).
38 */
39#define MONDO_CFG_FILE_STUB "tmp/mondo-restore.cfg"
40/**
41 * The i-want-my-lvm stub
42 */
43#define IWANTMYLVM_STUB "tmp/i-want-my-lvm"
44
45extern bool g_ISO_restore_mode; /* are we in Iso Mode? */
46extern bool g_I_have_just_nuked;
47/*
48extern char *g_tmpfs_mountpt;
49*/
50extern char *g_isodir_device;
51extern char *g_isodir_format;
52extern long g_current_progress, g_maximum_progress;
53extern char *g_biggielist_txt; // where 'biggielist.txt' is stored, on ramdisk / tempdir;
54 // biggielist.txt is the list of big files stored on the
55 // backup media set in question
56extern char *g_filelist_full; // filelist.full.gz is the list of all regular files
57 // (excluding big files) stored on the backup media set
58extern char *g_biggielist_pot; // list of big files which _could_ be restored, if the
59 // user chooses them
60extern char *g_filelist_imagedevs; // list of devices (e.g. /dev/hda1, /dev/sda5) which
61 // were archived as images, not just /dev entries
62 // ... e.g. NTFS, BeOS partitions
63extern char *g_imagedevs_restthese; // of the imagedevs listed in FILELIST_IMAGEDEVS,
64 // restore only these
65extern char *g_mondo_cfg_file; // where m*ndo-restore.cfg (the config file) is stored
66extern char *g_mountlist_fname; // where mountlist.txt (the mountlist file) is stored
67extern char *g_mondo_home; // homedir of Mondo; usually /usr/local/share/mondo
68
69extern t_bkptype g_backup_media_type;
70
71extern int g_partition_table_locked_up;
72extern char *MONDO_LOGFILE;
73
74/* Reference to global bkpinfo */
75extern struct s_bkpinfo *bkpinfo;
76
77/* Should we use or not extended attributes and acl when restoring */
78char *g_getfattr = NULL;
79char *g_getfacl = NULL;
80
81extern void kill_anything_like_this(char *str);
82extern int skip_obdr(void);
83extern int set_tape_block_size_with_mt(long internal_tape_block_size);
84
85/**
86* @addtogroup restoreUtilityGroup
87* @{
88*/
89/**
90* Free the malloc()s for the filename variables.
91*/
92void free_MR_global_filenames(void)
93{
94paranoid_free(g_biggielist_txt);
95paranoid_free(g_filelist_full);
96paranoid_free(g_filelist_imagedevs);
97paranoid_free(g_imagedevs_restthese);
98paranoid_free(g_mondo_cfg_file);
99paranoid_free(g_mountlist_fname);
100paranoid_free(g_mondo_home);
101/*
102paranoid_free(g_tmpfs_mountpt);
103*/
104paranoid_free(g_isodir_device);
105paranoid_free(g_isodir_format);
106
107}
108
109
110
111/**
112* Ask the user which imagedevs from the list contained in @p infname should
113* actually be restored.
114* @param infname The file containing a list of all imagedevs.
115* @param outfname The location of the output file containing the imagedevs the user wanted to restore.
116* @ingroup restoreUtilityGroup
117*/
118void ask_about_these_imagedevs(char *infname, char *outfname)
119{
120FILE *fin;
121FILE *fout;
122/************************************************************************
123* allocate memory regions. test and set -sab 16 feb 2003 *
124************************************************************************/
125char *incoming_ptr;
126char *question_ptr;
127
128char incoming[MAX_STR_LEN] = "\0";
129char question[MAX_STR_LEN];
130
131assert_string_is_neither_NULL_nor_zerolength(infname);
132assert_string_is_neither_NULL_nor_zerolength(outfname);
133
134incoming_ptr = malloc(sizeof(incoming));
135if (incoming_ptr == NULL) {
136fprintf(stderr, "Out of Memory\n");
137exit(EXIT_FAILURE);
138}
139
140question_ptr = malloc(sizeof(question));
141if (question_ptr == NULL) {
142fprintf(stderr, "Out of Memory\n");
143exit(EXIT_FAILURE);
144}
145
146memset(incoming_ptr, '\0', sizeof(incoming));
147memset(question_ptr, '\0', sizeof(question));
148
149
150
151if (!(fin = fopen(infname, "r"))) {
152fatal_error("Cannot openin infname");
153}
154if (!(fout = fopen(outfname, "w"))) {
155fatal_error("Cannot openin outfname");
156}
157for (fgets(incoming_ptr, MAX_STR_LEN, fin);
158 !feof(fin); fgets(incoming_ptr, MAX_STR_LEN, fin)) {
159strip_spaces(incoming_ptr);
160
161if (incoming[0] == '\0') {
162 continue;
163}
164
165sprintf(question_ptr,
166 "Should I restore the image of %s ?", incoming_ptr);
167
168if (ask_me_yes_or_no(question_ptr)) {
169 fprintf(fout, "%s\n", incoming_ptr);
170}
171}
172
173/*** free memory ***********/
174paranoid_free(incoming_ptr);
175incoming_ptr = NULL;
176paranoid_free(question_ptr);
177question_ptr = NULL;
178
179
180paranoid_fclose(fout);
181paranoid_fclose(fin);
182}
183
184/**************************************************************************
185*ASK_ABOUT_THESE_IMAGEDEVS *
186**************************************************************************/
187
188
189
190
191
192
193
194
195/**
196* Extract @c mondo-restore.cfg and @c mountlist.txt from @p ramdisk_fname.
197* @param bkpinfo The backup information structure. @c tmpdir is the only field used.
198* @param ramdisk_fname The filename of the @b compressed ramdisk to look in.
199* @param output_cfg_file Where to put the configuration file extracted.
200* @param output_mountlist_file Where to put the mountlist file extracted.
201* @return 0 for success, nonzero for failure.
202* @ingroup restoreUtilityGroup
203*/
204int
205extract_config_file_from_ramdisk(char *ramdisk_fname,
206 char *output_cfg_file,
207 char *output_mountlist_file)
208{
209char *mountpt;
210char *command;
211char *orig_fname;
212int retval = 0;
213
214assert(bkpinfo != NULL);
215malloc_string(mountpt);
216malloc_string(command);
217malloc_string(orig_fname);
218assert_string_is_neither_NULL_nor_zerolength(ramdisk_fname);
219assert_string_is_neither_NULL_nor_zerolength(output_cfg_file);
220assert_string_is_neither_NULL_nor_zerolength(output_mountlist_file);
221sprintf(mountpt, "%s/mount.bootdisk", bkpinfo->tmpdir);
222sprintf(command, "mkdir -p %s", mountpt);
223run_program_and_log_output(command, FALSE);
224sprintf(command, "gzip -dc %s > %s/mindi.rd 2> /dev/null",
225 ramdisk_fname, bkpinfo->tmpdir);
226
227run_program_and_log_output(command, FALSE);
228sprintf(command, "umount %s", mountpt);
229
230run_program_and_log_output(command, FALSE);
231
232sprintf(command, "mount -o loop %s/mindi.rd -t ext2 %s",
233 bkpinfo->tmpdir, mountpt);
234
235run_program_and_log_output(command, FALSE);
236
237sprintf(command, "mkdir -p %s/tmp", bkpinfo->tmpdir);
238
239run_program_and_log_output(command, FALSE);
240
241sprintf(command, "cp -f %s/%s %s", // %s/%s becomes {mountpt}/tmp/m*ndo-restore.cfg
242 mountpt, g_mondo_cfg_file, output_cfg_file);
243run_program_and_log_output(command, FALSE);
244
245sprintf(orig_fname, "%s/%s", mountpt, g_mountlist_fname);
246if (does_file_exist(orig_fname)) {
247sprintf(command, "cp -f %s %s", orig_fname, output_mountlist_file);
248run_program_and_log_output(command, FALSE);
249}
250sprintf(command, "umount %s", mountpt);
251run_program_and_log_output(command, FALSE);
252if (!does_file_exist(output_cfg_file)
253|| (!does_file_exist(output_mountlist_file)
254 && does_file_exist(orig_fname))) {
255log_msg(2, "Failed to extract %s and/or %s from ramdisk",
256 output_cfg_file, output_mountlist_file);
257retval = 1;
258} else {
259retval = 0;
260}
261paranoid_free(mountpt);
262paranoid_free(command);
263paranoid_free(orig_fname);
264return (retval);
265
266}
267
268
269
270
271/**
272* Keep trying to get mondo-restore.cfg from the archive, until the user gives up.
273*/
274void get_cfg_file_from_archive_or_bust()
275{
276while (get_cfg_file_from_archive()) {
277if (!ask_me_yes_or_no
278 ("Failed to find config file/archives. Choose another source?"))
279{
280 fatal_error("Could not find config file/archives. Aborting.");
281}
282interactively_obtain_media_parameters_from_user(FALSE);
283}
284}
285
286
287/**
288* Determine whether @p list_fname contains a line containing @p f.
289* @param f The line to search for.
290* @param list_fname The file to search in.
291* @param preamble Ignore this beginning part of @p f ("" to disable).
292* @return TRUE if it's in the list, FALSE if it's not.
293*/
294bool is_file_in_list(char *f, char *list_fname, char *preamble)
295{
296
297/** needs malloc **/
298char *command;
299char *file;
300char *tmp;
301int res;
302
303malloc_string(command);
304malloc_string(file);
305malloc_string(tmp);
306assert_string_is_neither_NULL_nor_zerolength(f);
307assert_string_is_neither_NULL_nor_zerolength(list_fname);
308assert(preamble != NULL);
309
310if (strncmp(preamble, f, strlen(preamble)) == 0) {
311strcpy(file, f + strlen(preamble));
312} else {
313strcpy(file, f);
314}
315if (file[0] == '/' && file[1] == '/') {
316strcpy(tmp, file);
317strcpy(file, tmp + 1);
318}
319sprintf(tmp,
320 "Checking to see if f=%s, file=%s, is in the list of biggiefiles",
321 f, file);
322log_msg(2, tmp);
323sprintf(command, "grep -E '^%s$' %s", file, list_fname);
324res = run_program_and_log_output(command, FALSE);
325paranoid_free(command);
326paranoid_free(file);
327paranoid_free(tmp);
328if (res) {
329return (FALSE);
330} else {
331return (TRUE);
332}
333}
334
335/**************************************************************************
336*END_IS_FILE_IN_LIST *
337**************************************************************************/
338
339
340
341/**
342* Set up an ISO backup.
343* @param bkpinfo The backup information structure. Fields used:
344* - @c bkpinfo->backup_media_type
345* - @c bkpinfo->disaster_recovery
346* - @c bkpinfo->isodir
347* @param nuke_me_please If TRUE, we're in nuke mode; if FALSE we're in interactive mode.
348* @return 0 for success, nonzero for failure.
349*/
350int iso_fiddly_bits(bool nuke_me_please)
351{
352char *mount_isodir_command, *tmp, *command;
353int retval = 0, i;
354bool already_mounted = FALSE;
355
356assert(bkpinfo != NULL);
357malloc_string(mount_isodir_command);
358malloc_string(tmp);
359malloc_string(command);
360g_ISO_restore_mode = TRUE;
361read_cfg_var(g_mondo_cfg_file, "iso-dev", g_isodir_device);
362if (bkpinfo->disaster_recovery) {
363/* Patch Conor Daly 26-june-2004
364* Don't let this clobber an existing bkpinfo->isodir */
365if (!bkpinfo->isodir[0]) {
366 strcpy(bkpinfo->isodir, "/tmp/isodir");
367}
368/* End patch */
369sprintf(command, "mkdir -p %s", bkpinfo->isodir);
370run_program_and_log_output(command, 5);
371log_msg(2, "Setting isodir to %s", bkpinfo->isodir);
372}
373
374if (!get_isodir_info
375(g_isodir_device, g_isodir_format, bkpinfo->isodir,
376 nuke_me_please)) {
377return (1);
378}
379paranoid_system("umount " MNT_CDROM " 2> /dev/null"); /* just in case */
380
381if (is_this_device_mounted(g_isodir_device)) {
382log_to_screen("WARNING - isodir is already mounted");
383already_mounted = TRUE;
384} else {
385sprintf(mount_isodir_command, "mount %s", g_isodir_device);
386if (strlen(g_isodir_format) > 1) {
387 sprintf(mount_isodir_command + strlen(mount_isodir_command),
388 " -t %s", g_isodir_format);
389}
390strcat(mount_isodir_command, " -o ro ");
391strcat(mount_isodir_command, bkpinfo->isodir);
392run_program_and_log_output("df -m", FALSE);
393sprintf(tmp,
394 "The 'mount' command is '%s'. PLEASE report this command to be if you have problems, ok?",
395 mount_isodir_command);
396log_msg(1, tmp);
397if (run_program_and_log_output(mount_isodir_command, FALSE)) {
398 popup_and_OK
399 ("Cannot mount the device where the ISO files are stored.");
400 return (1);
401}
402log_to_screen
403 ("I have mounted the device where the ISO files are stored.");
404}
405if (!IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
406 mount_media();
407}
408i = what_number_cd_is_this(); /* has the side-effect of calling mount_media() */
409sprintf(tmp, "%s #%d has been mounted via loopback mount",
410 media_descriptor_string(bkpinfo->backup_media_type), i);
411log_msg(1, tmp);
412if (i < 0) {
413popup_and_OK
414 ("Cannot find ISO images in the directory you specified.");
415retval = 1;
416}
417log_msg(2, "%ld: bkpinfo->isodir is now %s", __LINE__,
418 bkpinfo->isodir);
419paranoid_free(mount_isodir_command);
420paranoid_free(tmp);
421paranoid_free(command);
422return (retval);
423}
424
425
426
427
428/**
429* Kill all Petris processes.
430*/
431void kill_petris(void) {
432 kill_anything_like_this("petris");
433}
434
435/**************************************************************************
436*END_KILL_PETRIS *
437**************************************************************************/
438
439
440/**
441 * Mount @p device at @p mpt as @p format.
442 * @param device The device (/dev entry) to mount.
443 * @param mpt The directory to mount it on.
444 * @param format The filesystem type of @p device.
445 * @param writeable If TRUE, mount read-write; if FALSE, mount read-only.
446 * @return 0 for success, nonzero for failure.
447 */
448int mount_device(char *device, char *mpt, char *format, bool writeable)
449{
450int res = 0;
451
452/** malloc **/
453char *tmp, *command, *mountdir, *mountpoint, *additional_parameters;
454
455assert_string_is_neither_NULL_nor_zerolength(device);
456assert_string_is_neither_NULL_nor_zerolength(mpt);
457assert(format != NULL);
458malloc_string(tmp);
459malloc_string(command);
460malloc_string(mountdir);
461malloc_string(mountpoint);
462malloc_string(additional_parameters);
463
464 if (!strcmp(mpt, "/1")) {
465 strcpy(mountpoint, "/");
466 log_msg(3, "Mommm! SME is being a dildo!");
467 } else {
468 strcpy(mountpoint, mpt);
469 }
470
471 if (!strcmp(mountpoint, "lvm")) {
472 return (0);
473 }
474 if (!strcmp(mountpoint, "image")) {
475 return (0);
476 }
477 sprintf(tmp, "Mounting device %s ", device);
478 log_msg(1, tmp);
479 /* Deal with additional params only if not /proc or /sys */
480 if (strcmp(format, "proc") && strcmp(format, "sys")) {
481 if (writeable) {
482 strcpy(additional_parameters, "-o rw");
483 } else {
484 strcpy(additional_parameters, "-o ro");
485 }
486 if (find_home_of_exe("setfattr")) {
487 strcat(additional_parameters, ",user_xattr");
488 }
489 if (find_home_of_exe("setfacl")) {
490 strcat(additional_parameters, ",acl");
491 }
492 }
493
494 if (!strcmp(mountpoint, "swap")) {
495 sprintf(command, "swapon %s", device);
496 } else {
497 if (!strcmp(mountpoint, "/")) {
498 strcpy(mountdir, MNT_RESTORING);
499 } else {
500 sprintf(mountdir, "%s%s", MNT_RESTORING, mountpoint);
501 }
502 sprintf(command, "mkdir -p %s", mountdir);
503 run_program_and_log_output(command, FALSE);
504 sprintf(command, "mount -t %s %s %s %s 2>> %s", format, device,
505 additional_parameters, mountdir, MONDO_LOGFILE);
506 log_msg(2, "command='%s'", command);
507 }
508
509 res = run_program_and_log_output(command, TRUE);
510 if (res && (strstr(command, "xattr") || strstr(command, "acl"))) {
511 log_msg(1, "Re-trying without the fancy extra parameters");
512 sprintf(command, "mount -t %s %s %s 2>> %s", format, device,
513 mountdir, MONDO_LOGFILE);
514 res = run_program_and_log_output(command, TRUE);
515 }
516 if (res) {
517 log_msg(1, "Unable to mount device %s (type %s) at %s", device,
518 format, mountdir);
519 log_msg(1, "command was '%s'", command);
520 if (!strcmp(mountpoint, "swap")) {
521 log_to_screen(tmp);
522 } else {
523 log_msg(2, "Retrying w/o the '-t' switch");
524 sprintf(command, "mount %s %s 2>> %s", device, mountdir,
525 MONDO_LOGFILE);
526 log_msg(2, "2nd command = '%s'", command);
527 res = run_program_and_log_output(command, TRUE);
528 if (res == 0) {
529 log_msg(1,
530 "That's OK. I called mount w/o a filesystem type and it worked fine in the end.");
531 } else {
532 log_to_screen(tmp);
533 }
534 }
535 }
536
537 if (res && !strcmp(mountpoint, "swap")) {
538 log_msg(2, "That's ok. It's just a swap partition.");
539 log_msg(2, "Non-fatal error. Returning 0.");
540 res = 0;
541 }
542
543paranoid_free(tmp);
544paranoid_free(command);
545paranoid_free(mountdir);
546paranoid_free(mountpoint);
547paranoid_free(additional_parameters);
548
549 return (res);
550}
551/**************************************************************************
552 *END_MOUNT_DEVICE *
553**************************************************************************/
554
555
556/**
557 * Mount all devices in @p p_external_copy_of_mountlist on @p MNT_RESTORING.
558 * @param p_external_copy_of_mountlist The mountlist containing devices to be mounted.
559 * @param writeable If TRUE, then mount read-write; if FALSE mount read-only.
560 * @return The number of errors encountered (0 for success).
561 */
562int mount_all_devices(struct mountlist_itself
563 *p_external_copy_of_mountlist, bool writeable)
564{
565int retval = 0, lino, res;
566char *tmp, *these_failed, *format;
567 struct mountlist_itself *mountlist = NULL;
568
569malloc_string(tmp);
570malloc_string(format);
571malloc_string(these_failed);
572/** menset **/
573these_failed[0] = '\0';
574
575assert(p_external_copy_of_mountlist != NULL);
576mountlist = malloc(sizeof(struct mountlist_itself));
577memcpy((void *) mountlist, (void *) p_external_copy_of_mountlist,
578 sizeof(struct mountlist_itself));
579 sort_mountlist_by_mountpoint(mountlist, 0);
580
581
582 mvaddstr_and_log_it(g_currentY, 0, "Mounting devices ");
583 open_progress_form("Mounting devices",
584 "I am now mounting all the drives.",
585 "This should not take long.",
586 "", mountlist->entries);
587
588 for (lino = 0; lino < mountlist->entries; lino++) {
589 if (!strcmp(mountlist->el[lino].device, "/proc")) {
590 log_msg(1,
591 "Again with the /proc - why is this in your mountlist?");
592 } else if (is_this_device_mounted(mountlist->el[lino].device)) {
593 sprintf(tmp, "%s is already mounted",
594 mountlist->el[lino].device);
595 log_to_screen(tmp);
596 } else if (strcmp(mountlist->el[lino].mountpoint, "none")
597 && strcmp(mountlist->el[lino].mountpoint, "lvm")
598 && strcmp(mountlist->el[lino].mountpoint, "raid")
599 && strcmp(mountlist->el[lino].mountpoint, "image")) {
600 sprintf(tmp, "Mounting %s", mountlist->el[lino].device);
601 update_progress_form(tmp);
602 strcpy(format, mountlist->el[lino].format);
603 /* BERLIOS: removed as it doen't make sens to not mount ext3 partitions as ext3
604 if (!strcmp(format, "ext3")) {
605 strcpy(format, "ext2");
606 }
607 */
608 res = mount_device(mountlist->el[lino].device,
609 mountlist->el[lino].mountpoint,
610 format, writeable);
611 retval += res;
612 if (res) {
613 strcat(these_failed, mountlist->el[lino].device);
614 strcat(these_failed, " ");
615 }
616 }
617 g_current_progress++;
618 }
619 close_progress_form();
620 if (retval) {
621 if (g_partition_table_locked_up > 0) {
622 log_to_screen
623 ("fdisk's ictol() call to refresh its copy of the partition table causes the kernel to");
624 log_to_screen
625 ("lock up the partition table. You might have to reboot and use Interactive Mode to");
626 log_to_screen
627 ("format and restore *without* partitioning first. Sorry for the inconvenience.");
628 }
629 sprintf(tmp, "Could not mount device(s) %s- shall I abort?",
630 these_failed);
631
632 if (!ask_me_yes_or_no(tmp)) {
633 retval = 0;
634 log_to_screen
635 ("Continuing, although some device(s) failed to be mounted");
636 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
637 } else {
638 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
639 log_to_screen
640 ("Unable to mount some or all of your partitions.");
641 }
642 } else {
643 log_to_screen("All partitions were mounted OK.");
644 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
645 }
646 /* Also mounting under MNT_RESTORING special FS */
647 (void)mount_device("/proc","/proc","proc",TRUE);
648 (void)mount_device("/sys","/sys","sysfs",TRUE);
649 run_program_and_log_output("df -m", 3);
650 paranoid_free(mountlist);
651 paranoid_free(tmp);
652 paranoid_free(format);
653 paranoid_free(these_failed);
654 return (retval);
655}
656/**************************************************************************
657*END_MOUNT_ALL_DEVICES *
658**************************************************************************/
659
660
661/**
662* Mount the CD-ROM or USB device at /mnt/cdrom.
663* @param bkpinfo The backup information structure. Fields used:
664* - @c bkpinfo->backup_media_type
665* - @c bkpinfo->disaster_recovery
666* - @c bkpinfo->isodir
667* - @c bkpinfo->media_device
668* @return 0 for success, nonzero for failure.
669*/
670int mount_media()
671{
672char *mount_cmd;
673int i, res;
674#ifdef __FreeBSD__
675char mdd[32];
676char *mddev = mdd;
677#endif
678
679malloc_string(mount_cmd);
680assert(bkpinfo != NULL);
681
682 if (bkpinfo->backup_media_type == tape
683 || bkpinfo->backup_media_type == udev) {
684 log_msg(8, "Tape/udev. Therefore, no need to mount a media.");
685 paranoid_free(mount_cmd);
686 return 0;
687 }
688
689 if (!run_program_and_log_output("mount | grep -F " MNT_CDROM, FALSE)) {
690 log_msg(2, "mount_media() - media already mounted. Fair enough.");
691 paranoid_free(mount_cmd);
692 return (0);
693 }
694
695 if (bkpinfo->backup_media_type == nfs) {
696 log_msg(2, "Mounting for NFS thingy");
697 log_msg(2, "isodir = %s", bkpinfo->isodir);
698 if ((!bkpinfo->isodir[0] || !strcmp(bkpinfo->isodir, "/"))
699 && am_I_in_disaster_recovery_mode()) {
700 strcpy(bkpinfo->isodir, "/tmp/isodir");
701 log_msg(1, "isodir is being set to %s", bkpinfo->isodir);
702 }
703#ifdef __FreeBSD__
704 sprintf(mount_cmd, "/mnt/isodir/%s/%s/%s-%d.iso", bkpinfo->isodir,
705 bkpinfo->nfs_remote_dir, bkpinfo->prefix, g_current_media_number);
706 mddev = make_vn(mount_cmd);
707 sprintf(mount_cmd, "mount_cd9660 -r %s " MNT_CDROM, mddev);
708#else
709 sprintf(mount_cmd, "mount %s/%s/%s-%d.iso -t iso9660 -o loop,ro %s",
710 bkpinfo->isodir, bkpinfo->nfs_remote_dir,
711 bkpinfo->prefix, g_current_media_number, MNT_CDROM);
712#endif
713
714 } else if (bkpinfo->backup_media_type == iso) {
715#ifdef __FreeBSD__
716 sprintf(mount_cmd, "%s/%s-%d.iso", bkpinfo->isodir,
717 bkpinfo->prefix, g_current_media_number);
718 mddev = make_vn(mount_cmd);
719 sprintf(mount_cmd, "mount_cd9660 -r %s %s", mddev, MNT_CDROM);
720#else
721 sprintf(mount_cmd, "mount %s/%s-%d.iso -t iso9660 -o loop,ro %s",
722 bkpinfo->isodir, bkpinfo->prefix, g_current_media_number, MNT_CDROM);
723#endif
724 } else if (bkpinfo->backup_media_type == usb) {
725 sprintf(mount_cmd, "mount -t vfat %s %s", bkpinfo->media_device, MNT_CDROM);
726 } else if (strstr(bkpinfo->media_device, "/dev/")) {
727#ifdef __FreeBSD__
728 sprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device,
729 MNT_CDROM);
730#else
731 sprintf(mount_cmd, "mount %s -t iso9660 -o ro %s",
732 bkpinfo->media_device, MNT_CDROM);
733#endif
734 } else {
735 if (bkpinfo->disaster_recovery
736 && does_file_exist("/tmp/CDROM-LIVES-HERE")) {
737 strcpy(bkpinfo->media_device,
738 last_line_of_file("/tmp/CDROM-LIVES-HERE"));
739 } else {
740 find_cdrom_device(bkpinfo->media_device, TRUE);
741 }
742
743#ifdef __FreeBSD__
744 sprintf(mount_cmd, "mount_cd9660 -r %s %s", bkpinfo->media_device,
745 MNT_CDROM);
746#else
747 sprintf(mount_cmd, "mount %s -t iso9660 -o ro %s",
748 bkpinfo->media_device, MNT_CDROM);
749#endif
750 }
751
752 log_msg(2, "(mount_media) --- command = %s", mount_cmd);
753 for (i = 0; i < 2; i++) {
754 res = run_program_and_log_output(mount_cmd, FALSE);
755 if (!res) {
756 break;
757 } else {
758 log_msg(2, "Failed to mount device.");
759 sleep(5);
760 run_program_and_log_output("sync", FALSE);
761 }
762 }
763
764 if (res) {
765 log_msg(2, "Failed, despite %d attempts", i);
766 } else {
767 log_msg(2, "Mounted media drive OK");
768 }
769 paranoid_free(mount_cmd);
770 return (res);
771}
772/**************************************************************************
773*END_MOUNT_CDROM *
774**************************************************************************/
775
776
777
778/**
779* Fix some miscellaneous things in the filesystem so the system will come
780* up correctly on the first boot.
781*/
782void protect_against_braindead_sysadmins()
783{
784run_program_and_log_output("touch " MNT_RESTORING "/var/log/pacct",
785 FALSE);
786run_program_and_log_output("touch " MNT_RESTORING "/var/account/pacct",
787 FALSE);
788if (run_program_and_log_output("ls " MNT_RESTORING " /tmp", FALSE)) {
789run_program_and_log_output("chmod 1777 " MNT_RESTORING "/tmp",
790 FALSE);
791}
792run_program_and_log_output("mkdir -p " MNT_RESTORING
793 "/var/run/console", FALSE);
794run_program_and_log_output("chmod 777 " MNT_RESTORING "/dev/null",
795 FALSE);
796run_program_and_log_output("cd " MNT_RESTORING
797 "; for i in `ls home/`; do echo \"Moving $i's spurious files to $i/.disabled\"; mkdir \"$i\"/.disabled ; mv -f \"$i\"/.DCOP* \"$i\"/.MCOP* \"$i\"/.*authority \"$i\"/.kde/tmp* \"$i\"/.kde/socket* \"$i\"/.disabled/ ; done",
798 TRUE);
799run_program_and_log_output("rm -f " MNT_RESTORING "/var/run/*.pid",
800 TRUE);
801run_program_and_log_output("rm -f " MNT_RESTORING "/var/lock/subsys/*",
802 TRUE);
803}
804
805/**************************************************************************
806*END_PROTECT_AGAINST_BRAINDEAD_SYSADMINS *
807**************************************************************************/
808
809
810
811
812/**
813* Fill out @p bkpinfo based on @p cfg_file.
814* @param cfg_file The mondo-restore.cfg file to read into @p bkpinfo.
815* @param bkpinfo The backup information structure to fill out with information
816* from @p cfg_file.
817* @return 0 for success, nonzero for failure.
818*/
819int read_cfg_file_into_bkpinfo(char *cfgf)
820{
821/** add mallocs **/
822char *value = NULL;
823char *tmp = NULL;
824char *envtmp1 = NULL;
825char *envtmp2 = NULL;
826char *command = NULL;
827char *iso_mnt = NULL;
828char *iso_path = NULL;
829char *old_isodir = NULL;
830char cfg_file[100];
831t_bkptype media_specified_by_user;
832
833malloc_string(command);
834malloc_string(iso_mnt);
835malloc_string(iso_path);
836malloc_string(old_isodir);
837malloc_string(value);
838malloc_string(tmp);
839// assert_string_is_neither_NULL_nor_zerolength(cfg_file);
840assert(bkpinfo != NULL);
841
842if (!cfgf) {
843strcpy(cfg_file, g_mondo_cfg_file);
844} else {
845strcpy(cfg_file, cfgf);
846}
847
848media_specified_by_user = bkpinfo->backup_media_type; // or 'none', if not specified
849
850if (0 == read_cfg_var(cfg_file, "backup-media-type", value)) {
851if (!strcmp(value, "cdstream")) {
852 bkpinfo->backup_media_type = cdstream;
853} else if (!strcmp(value, "cdr")) {
854 bkpinfo->backup_media_type = cdr;
855} else if (!strcmp(value, "cdrw")) {
856 bkpinfo->backup_media_type = cdrw;
857} else if (!strcmp(value, "dvd")) {
858 bkpinfo->backup_media_type = dvd;
859} else if (!strcmp(value, "usb")) {
860 bkpinfo->backup_media_type = usb;
861 bkpinfo->please_dont_eject = TRUE;
862} else if (!strcmp(value, "iso")) {
863/*
864if (am_I_in_disaster_recovery_mode()
865&& !run_program_and_log_output("mount /dev/cdrom "MNT_CDROM, 1)
866&& does_file_exist(MNT_CDROM"/archives/filelist.0"))
867*/
868
869// Patch by Conor Daly - 2004/07/12
870 bkpinfo->backup_media_type = iso;
871 if (am_I_in_disaster_recovery_mode()) {
872 /* Check to see if CD is already mounted before mounting it... */
873 if (!is_this_device_mounted("/dev/cdrom")) {
874 log_msg(2,
875 "NB: CDROM device not mounted, mounting...");
876 run_program_and_log_output("mount /dev/cdrom "
877 MNT_CDROM, 1);
878 }
879 if (does_file_exist(MNT_CDROM "/archives/filelist.0")) {
880 bkpinfo->backup_media_type = cdr;
881 run_program_and_log_output("umount " MNT_CDROM, 1);
882 log_it
883 ("Re-jigging configuration AGAIN. CD-R, not ISO.");
884 }
885 }
886 if (read_cfg_var(cfg_file, "iso-prefix", value) == 0) {
887 strcpy(bkpinfo->prefix,value);
888 } else {
889 strcpy(bkpinfo->prefix,STD_PREFIX);
890 }
891} else if (!strcmp(value, "nfs")) {
892 bkpinfo->backup_media_type = nfs;
893 bkpinfo->please_dont_eject = TRUE;
894 if (read_cfg_var(cfg_file, "iso-prefix", value) == 0) {
895 strcpy(bkpinfo->prefix,value);
896 } else {
897 strcpy(bkpinfo->prefix,STD_PREFIX);
898 }
899 if (strstr(call_program_and_get_last_line_of_output
900 ("cat /proc/cmdline"), "pxe")) {
901 /* We need to override prefix value in PXE mode as it's
902 * already done in start-nfs */
903 envtmp1 = getenv("imgname");
904 if (envtmp1 == NULL) {
905 fatal_error("no imgname variable in environment");
906 }
907 strcpy(bkpinfo->prefix,envtmp1);
908 }
909
910} else if (!strcmp(value, "tape")) {
911 bkpinfo->backup_media_type = tape;
912} else if (!strcmp(value, "udev")) {
913 bkpinfo->backup_media_type = udev;
914} else {
915 fatal_error("UNKNOWN bkp-media-type");
916}
917} else {
918fatal_error("backup-media-type not specified!");
919}
920if (bkpinfo->disaster_recovery) {
921 if (bkpinfo->backup_media_type == cdstream) {
922 sprintf(bkpinfo->media_device, "/dev/cdrom");
923// bkpinfo->media_size[0] = -1;
924 bkpinfo->media_size[0] = 1999 * 1024;
925 bkpinfo->media_size[1] = 650; /* good guess */
926 } else if (bkpinfo->backup_media_type == usb) {
927 if (read_cfg_var(cfg_file, "usb-dev", value)) {
928 fatal_error("Cannot get USB device name from cfg file");
929 }
930 sprintf(bkpinfo->media_device, "%s1", value);
931 sprintf(tmp, "Backup medium is USB --- dev=%s", bkpinfo->media_device);
932 log_msg(2, tmp);
933 } else if (bkpinfo->backup_media_type == tape
934 || bkpinfo->backup_media_type == udev) {
935 if (read_cfg_var(cfg_file, "media-dev", value)) {
936 fatal_error("Cannot get tape device name from cfg file");
937 }
938 strcpy(bkpinfo->media_device, value);
939 read_cfg_var(cfg_file, "media-size", value);
940 bkpinfo->media_size[1] = atol(value);
941 sprintf(tmp, "Backup medium is TAPE --- dev=%s",
942 bkpinfo->media_device);
943 log_msg(2, tmp);
944 } else {
945 strcpy(bkpinfo->media_device, "/dev/cdrom"); /* we don't really need this var */
946 bkpinfo->media_size[0] = 1999 * 1024; /* 650, probably, but we don't need this var anyway */
947 bkpinfo->media_size[1] = 1999 * 1024; /* 650, probably, but we don't need this var anyway */
948 log_msg(2, "Backup medium is CD-R[W]");
949 }
950} else {
951 log_msg(2,
952 "Not in Disaster Recovery Mode. No need to derive device name from config file.");
953}
954
955read_cfg_var(cfg_file, "use-star", value);
956if (strstr(value, "yes")) {
957 bkpinfo->use_star = TRUE;
958 log_msg(1, "Goody! ... bkpinfo->use_star is now true.");
959}
960
961read_cfg_var(cfg_file, "obdr", value);
962if (strstr(value, "TRUE")) {
963 bkpinfo->use_obdr = TRUE;
964 log_msg(1, "OBDR mode activated");
965}
966
967read_cfg_var(cfg_file, "acl", value);
968if (strstr(value, "TRUE")) {
969 asprintf(&g_getfacl,"setfacl");
970 log_msg(1, "We will restore ACLs");
971 if (! find_home_of_exe("setfacl")) {
972 log_msg(1, "Unable to restore ACLs as no setfacl found");
973 }
974}
975read_cfg_var(cfg_file, "xattr", value);
976if (strstr(value, "TRUE")) {
977 asprintf(&g_getfattr,"setfattr");
978 log_msg(1, "We will restore XATTRs");
979 if (! find_home_of_exe("setfattr")) {
980 log_msg(1, "Unable to restore XATTRs as no setfattr found");
981 }
982}
983
984if (0 == read_cfg_var(cfg_file, "internal-tape-block-size", value)) {
985bkpinfo->internal_tape_block_size = atol(value);
986log_msg(1, "Internal tape block size has been custom-set to %ld",
987 bkpinfo->internal_tape_block_size);
988} else {
989bkpinfo->internal_tape_block_size =
990 DEFAULT_INTERNAL_TAPE_BLOCK_SIZE;
991log_msg(1, "Internal tape block size = default (%ld)",
992 DEFAULT_INTERNAL_TAPE_BLOCK_SIZE);
993}
994
995read_cfg_var(cfg_file, "use-lzo", value);
996if (strstr(value, "yes")) {
997bkpinfo->use_lzo = TRUE;
998bkpinfo->use_gzip = FALSE;
999strcpy(bkpinfo->zip_exe, "lzop");
1000strcpy(bkpinfo->zip_suffix, "lzo");
1001} else {
1002read_cfg_var(cfg_file, "use-gzip", value);
1003if (strstr(value, "yes")) {
1004 bkpinfo->use_lzo = FALSE;
1005 bkpinfo->use_gzip = TRUE;
1006 strcpy(bkpinfo->zip_exe, "gzip");
1007 strcpy(bkpinfo->zip_suffix, "gz");
1008} else {
1009 read_cfg_var(cfg_file, "use-comp", value);
1010 if (strstr(value, "yes")) {
1011 bkpinfo->use_lzo = FALSE;
1012 bkpinfo->use_gzip = FALSE;
1013 strcpy(bkpinfo->zip_exe, "bzip2");
1014 strcpy(bkpinfo->zip_suffix, "bz2");
1015 } else {
1016 bkpinfo->zip_exe[0] = bkpinfo->zip_suffix[0] = '\0';
1017 }
1018}
1019}
1020
1021value[0] = '\0';
1022read_cfg_var(cfg_file, "differential", value);
1023if (!strcmp(value, "yes") || !strcmp(value, "1")) {
1024bkpinfo->differential = TRUE;
1025}
1026log_msg(2, "differential var = '%s'", value);
1027if (bkpinfo->differential) {
1028log_msg(2, "THIS IS A DIFFERENTIAL BACKUP");
1029} else {
1030log_msg(2, "This is a regular (full) backup");
1031}
1032
1033read_cfg_var(g_mondo_cfg_file, "please-dont-eject", tmp);
1034if (tmp[0]
1035||
1036strstr(call_program_and_get_last_line_of_output
1037 ("cat /proc/cmdline"), "donteject")) {
1038bkpinfo->please_dont_eject = TRUE;
1039log_msg(2, "Ok, I shan't eject when restoring! Groovy.");
1040}
1041
1042if (bkpinfo->backup_media_type == nfs) {
1043 if (!cfgf) {
1044 log_msg(2, "nfs_mount remains %s", bkpinfo->nfs_mount);
1045 log_msg(2, "nfs_remote_dir remains %s",
1046 bkpinfo->nfs_remote_dir);
1047 log_msg(2,
1048 "...cos it wouldn't make sense to abandon the values that GOT ME to this config file in the first place");
1049 } else {
1050 read_cfg_var(g_mondo_cfg_file, "nfs-server-mount",
1051 bkpinfo->nfs_mount);
1052 read_cfg_var(g_mondo_cfg_file, "nfs-server-path",
1053 bkpinfo->nfs_remote_dir);
1054 log_msg(2, "nfs_mount is %s", bkpinfo->nfs_mount);
1055 log_msg(2, "nfs_remote_dir is %s", bkpinfo->nfs_remote_dir);
1056 }
1057 if (strstr(call_program_and_get_last_line_of_output
1058 ("cat /proc/cmdline"), "pxe")) {
1059 /* We need to override values in PXE mode as it's
1060 * already done in start-nfs */
1061 envtmp1 = getenv("nfsmount");
1062 if (envtmp1 == NULL) {
1063 fatal_error("no nfsmount variable in environment");
1064 }
1065 envtmp2 = getenv("dirimg");
1066 if (envtmp2 == NULL) {
1067 fatal_error("no dirimg variable in environment");
1068 }
1069 strcpy(bkpinfo->nfs_mount,envtmp1);
1070 strcpy(bkpinfo->nfs_remote_dir,envtmp2);
1071 }
1072} else if (bkpinfo->backup_media_type == iso) {
1073 /* Patch by Conor Daly 23-june-2004
1074 * to correctly mount iso-dev and set a sensible
1075 * isodir in disaster recovery mode
1076 */
1077 strcpy(old_isodir, bkpinfo->isodir);
1078 read_cfg_var(g_mondo_cfg_file, "iso-mnt", iso_mnt);
1079 read_cfg_var(g_mondo_cfg_file, "isodir", iso_path);
1080 sprintf(bkpinfo->isodir, "%s%s", iso_mnt, iso_path);
1081 if (!bkpinfo->isodir[0]) {
1082 strcpy(bkpinfo->isodir, old_isodir);
1083 }
1084 if (!bkpinfo->disaster_recovery) {
1085 if (strcmp(old_isodir, bkpinfo->isodir)) {
1086 log_it
1087 ("user nominated isodir differs from archive, keeping user's choice: %s %s\n",
1088 old_isodir, bkpinfo->isodir);
1089 strcpy(bkpinfo->isodir, old_isodir);
1090 }
1091 }
1092 read_cfg_var(g_mondo_cfg_file, "iso-dev", g_isodir_device);
1093 log_msg(2, "isodir=%s; iso-dev=%s", bkpinfo->isodir,
1094 g_isodir_device);
1095 if (bkpinfo->disaster_recovery) {
1096 if (is_this_device_mounted(g_isodir_device)) {
1097 log_msg(2, "NB: isodir is already mounted");
1098 /* Find out where it's mounted */
1099 sprintf(command,
1100 "mount | grep -E '^%s' | tail -n1 | cut -d' ' -f3",
1101 g_isodir_device);
1102 log_it("command = %s", command);
1103 log_it("res of it = %s",
1104 call_program_and_get_last_line_of_output(command));
1105 sprintf(iso_mnt, "%s",
1106 call_program_and_get_last_line_of_output(command));
1107 } else {
1108 sprintf(iso_mnt, "/tmp/isodir");
1109 sprintf(tmp, "mkdir -p %s", iso_mnt);
1110 run_program_and_log_output(tmp, 5);
1111 sprintf(tmp, "mount %s %s", g_isodir_device, iso_mnt);
1112 if (run_program_and_log_output(tmp, 3)) {
1113 log_msg(1,
1114 "Unable to mount isodir. Perhaps this is really a CD backup?");
1115 bkpinfo->backup_media_type = cdr;
1116 strcpy(bkpinfo->media_device, "/dev/cdrom"); /* superfluous */
1117 bkpinfo->isodir[0] = iso_mnt[0] = iso_path[0] = '\0';
1118 if (mount_media()) {
1119 fatal_error
1120 ("Unable to mount isodir. Failed to mount CD-ROM as well.");
1121 } else {
1122 log_msg(1,
1123 "You backed up to disk, then burned some CDs.");
1124 }
1125 }
1126 }
1127 /* bkpinfo->isodir should now be the true path to prefix-1.iso etc... */
1128 if (bkpinfo->backup_media_type == iso) {
1129 sprintf(bkpinfo->isodir, "%s%s", iso_mnt, iso_path);
1130 }
1131 }
1132}
1133
1134if (media_specified_by_user != none) {
1135 if (g_restoring_live_from_cd) {
1136 if (bkpinfo->backup_media_type != media_specified_by_user) {
1137 log_msg(2,
1138 "bkpinfo->backup_media_type != media_specified_by_user, so I'd better ask :)");
1139 interactively_obtain_media_parameters_from_user(FALSE);
1140 media_specified_by_user = bkpinfo->backup_media_type;
1141 get_cfg_file_from_archive();
1142 /*
1143 if (media_specified_by_user != cdr && media_specified_by_user == cdrw)
1144 { g_restoring_live_from_cd = FALSE; }
1145 */
1146 }
1147 }
1148 bkpinfo->backup_media_type = media_specified_by_user;
1149}
1150g_backup_media_type = bkpinfo->backup_media_type;
1151paranoid_free(value);
1152paranoid_free(tmp);
1153paranoid_free(command);
1154paranoid_free(iso_mnt);
1155paranoid_free(iso_path);
1156paranoid_free(old_isodir);
1157return (0);
1158
1159}
1160
1161/**************************************************************************
1162*END_READ_CFG_FILE_INTO_BKPINFO *
1163**************************************************************************/
1164
1165
1166
1167
1168/**
1169 * Allow the user to edit the filelist and biggielist.
1170 * The filelist is unlinked after it is read.
1171 * @param bkpinfo The backup information structure. Fields used:
1172 * - @c bkpinfo->backup_media_type
1173 * - @c bkpinfo->isodir
1174 * - @c bkpinfo->media_device
1175 * - @c bkpinfo->tmpdir
1176 * @return The filelist structure containing the information read from disk.
1177 */
1178struct
1179s_node *process_filelist_and_biggielist()
1180{
1181struct s_node *filelist;
1182
1183/** add mallocs**/
1184char *command;
1185char *tmp;
1186int res = 0;
1187pid_t pid;
1188
1189assert(bkpinfo != NULL);
1190malloc_string(command);
1191malloc_string(tmp);
1192
1193if (does_file_exist(g_filelist_full)
1194&& does_file_exist(g_biggielist_txt)) {
1195 log_msg(1, "%s exists", g_filelist_full);
1196 log_msg(1, "%s exists", g_biggielist_txt);
1197 log_msg(2,
1198 "Filelist and biggielist already recovered from media. Yay!");
1199} else {
1200 getcwd(tmp, MAX_STR_LEN);
1201 chdir(bkpinfo->tmpdir);
1202 log_msg(1, "chdir(%s)", bkpinfo->tmpdir);
1203 log_to_screen("Extracting filelist and biggielist from media...");
1204 unlink("/tmp/filelist.full");
1205 unlink(FILELIST_FULL_STUB);
1206 unlink("/" IWANTMYLVM_STUB);
1207 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1208 sprintf(command,
1209 "tar -b %ld -zxf %s ./%s ./%s ./%s ./%s ./%s",
1210 bkpinfo->internal_tape_block_size,
1211 bkpinfo->media_device,
1212 MOUNTLIST_FNAME_STUB,
1213 BIGGIELIST_TXT_STUB,
1214 FILELIST_FULL_STUB,
1215 IWANTMYLVM_STUB,
1216 MONDO_CFG_FILE_STUB);
1217 log_msg(1, "tarcommand = %s", command);
1218 run_program_and_log_output(command, 1);
1219 if (!does_file_exist(FILELIST_FULL_STUB)) {
1220 /* Doing that allow us to remain compatible with pre-2.2.5 versions */
1221 log_msg(2, "pre-2.2.4 compatible mode on");
1222 sprintf(command,
1223 "tar -b %ld -zxf %s %s %s %s %s %s",
1224 bkpinfo->internal_tape_block_size,
1225 bkpinfo->media_device,
1226 MOUNTLIST_FNAME_STUB,
1227 BIGGIELIST_TXT_STUB,
1228 FILELIST_FULL_STUB,
1229 IWANTMYLVM_STUB,
1230 MONDO_CFG_FILE_STUB);
1231 log_msg(1, "tarcommand = %s", command);
1232 run_program_and_log_output(command, 1);
1233 }
1234 } else {
1235 log_msg(2,
1236 "Calling insist_on_this_cd_number; bkpinfo->isodir=%s",
1237 bkpinfo->isodir);
1238 insist_on_this_cd_number(1);
1239 log_msg(2, "Back from iotcn");
1240 run_program_and_log_output("mount", 1);
1241 sprintf(command,
1242 "tar -zxf %s/images/all.tar.gz ./%s ./%s ./%s ./%s ./%s",
1243 MNT_CDROM,
1244 MOUNTLIST_FNAME_STUB,
1245 BIGGIELIST_TXT_STUB,
1246 FILELIST_FULL_STUB,
1247 IWANTMYLVM_STUB,
1248 MONDO_CFG_FILE_STUB);
1249
1250 log_msg(1, "tarcommand = %s", command);
1251 run_program_and_log_output(command, 1);
1252 if (!does_file_exist(FILELIST_FULL_STUB)) {
1253 /* Doing that allow us to remain compatible with pre-2.2.5 versions */
1254 log_msg(2, "pre-2.2.4 compatible mode on");
1255 sprintf(command,
1256 "tar -zxf %s/images/all.tar.gz %s %s %s %s %s",
1257 MNT_CDROM,
1258 MOUNTLIST_FNAME_STUB,
1259 BIGGIELIST_TXT_STUB,
1260 FILELIST_FULL_STUB,
1261 IWANTMYLVM_STUB,
1262 MONDO_CFG_FILE_STUB);
1263
1264 log_msg(1, "tarcommand = %s", command);
1265 run_program_and_log_output(command, 1);
1266 }
1267 if (!does_file_exist(BIGGIELIST_TXT_STUB)) {
1268 fatal_error
1269 ("all.tar.gz did not include " BIGGIELIST_TXT_STUB);
1270 }
1271 if (!does_file_exist(FILELIST_FULL_STUB)) {
1272 fatal_error
1273 ("all.tar.gz did not include " FILELIST_FULL_STUB);
1274 }
1275 }
1276 sprintf(command, "cp -f %s %s", MONDO_CFG_FILE_STUB,
1277 g_mondo_cfg_file);
1278 run_program_and_log_output(command, FALSE);
1279
1280 sprintf(command, "cp -f %s/%s %s", bkpinfo->tmpdir,
1281 BIGGIELIST_TXT_STUB, g_biggielist_txt);
1282 log_msg(1, "command = %s", command);
1283 paranoid_system(command);
1284 sprintf(command, "ln -sf %s/%s %s", bkpinfo->tmpdir,
1285 FILELIST_FULL_STUB, g_filelist_full);
1286 log_msg(1, "command = %s", command);
1287 paranoid_system(command);
1288 }
1289
1290 if (am_I_in_disaster_recovery_mode()
1291 &&
1292 ask_me_yes_or_no("Do you want to retrieve the mountlist as well?"))
1293 {
1294 sprintf(command, "ln -sf %s/%s /tmp", MOUNTLIST_FNAME_STUB,
1295 bkpinfo->tmpdir);
1296 paranoid_system(command);
1297 }
1298
1299 chdir(tmp);
1300
1301 if (!does_file_exist(g_biggielist_txt)) {
1302 log_msg(1, "Warning - %s not found", g_biggielist_txt);
1303 }
1304 if (!does_file_exist(g_filelist_full)) {
1305 log_msg(1, "Warning - %s does not exist", g_filelist_full);
1306 }
1307// popup_and_OK("Wonderful.");
1308
1309 log_msg(2, "Forking");
1310 pid = fork();
1311 switch (pid) {
1312 case -1:
1313 fatal_error("Forking error");
1314 break;
1315
1316 case 0:
1317 log_to_screen("Pre-processing filelist");
1318 if (!does_file_exist(g_biggielist_txt)) {
1319 sprintf(command, "echo -n > %s", g_biggielist_txt);
1320 paranoid_system(command);
1321 }
1322 sprintf(command, "grep -E '^/dev/.*' %s > %s",
1323 g_biggielist_txt, g_filelist_imagedevs);
1324 paranoid_system(command);
1325 exit(0);
1326 break;
1327
1328 default:
1329 open_evalcall_form("Pre-processing filelist");
1330 while (!waitpid(pid, (int *) 0, WNOHANG)) {
1331 usleep(100000);
1332 update_evalcall_form(0);
1333 }
1334 }
1335 close_evalcall_form();
1336
1337 log_msg(3, "loading filelist");
1338 filelist = load_filelist(g_filelist_full);
1339 log_msg(3, "deleting original filelist");
1340 unlink(g_filelist_full);
1341 if (g_text_mode) {
1342 printf("Restore which directory? --> ");
1343 fgets(tmp, sizeof(tmp), stdin);
1344 toggle_path_selection(filelist, tmp, TRUE);
1345 if (strlen(tmp) == 0) {
1346 res = 1;
1347 } else {
1348 res = 0;
1349 }
1350 } else {
1351 res = edit_filelist(filelist);
1352 }
1353 if (res) {
1354 log_msg(2, "User hit 'cancel'. Freeing filelist and aborting.");
1355 free_filelist(filelist);
1356 return (NULL);
1357 }
1358 ask_about_these_imagedevs(g_filelist_imagedevs, g_imagedevs_restthese);
1359 close_evalcall_form();
1360
1361 // NB: It's not necessary to add g_biggielist_txt to the filelist.full
1362 // file. The filelist.full file already contains the filename of EVERY
1363 // file backed up - regular and biggie files.
1364
1365 // However, we do want to make sure the imagedevs selected by the user
1366 // are flagged for restoring.
1367 if (length_of_file(g_imagedevs_restthese) > 2) {
1368 add_list_of_files_to_filelist(filelist, g_imagedevs_restthese,
1369 TRUE);
1370 }
1371
1372 paranoid_free(command);
1373 paranoid_free(tmp);
1374 return (filelist);
1375}
1376
1377/**************************************************************************
1378 *END_ PROCESS_FILELIST_AND_BIGGIELIST *
1379 **************************************************************************/
1380
1381
1382
1383
1384/**
1385 * Make a backup copy of <tt>path_root</tt>/<tt>filename</tt>.
1386 * The backup filename is the filename of the original with ".pristine" added.
1387 * @param path_root The place where the filesystem is mounted (e.g. MNT_RESTORING).
1388 * @param filename The filename (absolute path) within @p path_root.
1389 * @return 0 for success, nonzero for failure.
1390 */
1391int backup_crucial_file(char *path_root, char *filename)
1392{
1393 char *tmp;
1394 char *command;
1395 int res;
1396
1397 malloc_string(tmp);
1398 malloc_string(command);
1399 assert(path_root != NULL);
1400 assert_string_is_neither_NULL_nor_zerolength(filename);
1401
1402 sprintf(tmp, "%s/%s", path_root, filename);
1403 sprintf(command, "cp -f %s %s.pristine", tmp, tmp);
1404
1405 res = run_program_and_log_output(command, 5);
1406 paranoid_free(tmp);
1407 paranoid_free(command);
1408 return (res);
1409}
1410
1411
1412/**
1413 * Install the user's boot loader in the MBR.
1414 * Currently LILO, ELILO, GRUB, RAW (dd of MBR), and the FreeBSD bootloader are supported.
1415 * @param offer_to_hack_scripts If TRUE, then offer to hack the user's fstab for them.
1416 * @return 0 for success, nonzero for failure.
1417 */
1418int run_boot_loader(bool offer_to_hack_scripts)
1419{
1420 int res;
1421 int retval = 0;
1422
1423 /** malloc *******/
1424 char *device;
1425 char *tmp = NULL;
1426 char *name;
1427 char *cmd = NULL;
1428
1429 malloc_string(device);
1430 malloc_string(name);
1431
1432 /* In order to have a working bootloader, we need to have all devices
1433 * ready in the chroot. If they are not there (udev) then copy them from
1434 * the current /dev location
1435 */
1436 asprintf(&cmd,"tar cf - /dev | ( cd %s ; tar xf - )",MNT_RESTORING);
1437 run_program_and_log_output(cmd, 3);
1438 paranoid_free(cmd);
1439
1440 backup_crucial_file(MNT_RESTORING, "/etc/fstab");
1441 backup_crucial_file(MNT_RESTORING, "/etc/grub.conf");
1442 backup_crucial_file(MNT_RESTORING, "/etc/lilo.conf");
1443 backup_crucial_file(MNT_RESTORING, "/etc/elilo.conf");
1444 backup_crucial_file(MNT_RESTORING, "/boot/grub/device.map");
1445 backup_crucial_file(MNT_RESTORING, "/etc/mtab");
1446 read_cfg_var(g_mondo_cfg_file, "bootloader.device", device);
1447 read_cfg_var(g_mondo_cfg_file, "bootloader.name", name);
1448 asprintf(&tmp, "run_boot_loader: device='%s', name='%s'", device, name);
1449 log_msg(2, tmp);
1450 paranoid_free(tmp);
1451 system("sync");
1452 if (!strcmp(name, "LILO")) {
1453 res = run_lilo(offer_to_hack_scripts);
1454 } else if (!strcmp(name, "ELILO")) {
1455 res = run_elilo(offer_to_hack_scripts);
1456 } else if (!strcmp(name, "GRUB")) {
1457 res = run_grub(offer_to_hack_scripts, device);
1458 } else if (!strcmp(name, "RAW")) {
1459 res = run_raw_mbr(offer_to_hack_scripts, device);
1460 }
1461#ifdef __FreeBSD__
1462 else if (!strcmp(name, "BOOT0")) {
1463 asprintf(&tmp, "boot0cfg -B %s", device);
1464 res = run_program_and_log_output(tmp, FALSE);
1465 paranoid_free(tmp);
1466 } else {
1467 asprintf(&tmp, "ls /dev | grep -Eq '^%ss[1-4].*'", device);
1468 if (!system(tmp)) {
1469 paranoid_free(tmp);
1470 asprintf(&tmp, MNT_RESTORING "/sbin/fdisk -B %s", device);
1471 res = run_program_and_log_output(tmp, 3);
1472 } else {
1473 log_msg(1,
1474 "I'm not running any boot loader. You have a DD boot drive. It's already loaded up.");
1475 }
1476 paranoid_free(tmp);
1477 }
1478#else
1479 else {
1480 log_to_screen
1481 ("Unable to determine type of boot loader. Defaulting to LILO.");
1482 res = run_lilo(offer_to_hack_scripts);
1483 }
1484#endif
1485 retval += res;
1486 if (res) {
1487 log_to_screen("Your boot loader returned an error");
1488 } else {
1489 log_to_screen("Your boot loader ran OK");
1490 }
1491 paranoid_free(device);
1492 paranoid_free(name);
1493 return (retval);
1494}
1495
1496/**************************************************************************
1497 *END_ RUN_BOOT_LOADER *
1498 **************************************************************************/
1499
1500
1501
1502/**
1503 * Attempt to find the user's editor.
1504 * @return The editor found ("vi" if none could be found).
1505 * @note The returned string points to static storage that will be overwritten with each call.
1506 */
1507char *find_my_editor(void)
1508{
1509 static char output[MAX_STR_LEN];
1510 if (find_home_of_exe("pico")) {
1511 strcpy(output, "pico");
1512 } else if (find_home_of_exe("nano")) {
1513 strcpy(output, "nano");
1514 } else if (find_home_of_exe("e3em")) {
1515 strcpy(output, "e3em");
1516 } else if (find_home_of_exe("e3vi")) {
1517 strcpy(output, "e3vi");
1518 } else {
1519 strcpy(output, "vi");
1520 }
1521 if (!find_home_of_exe(output)) {
1522 log_msg(2, " (find_my_editor) --- warning - %s not found", output);
1523 }
1524 return (output);
1525}
1526
1527
1528/**
1529 * Install GRUB on @p bd.
1530 * @param offer_to_run_stabgrub If TRUE, then offer to hack the user's fstab for them.
1531 * @param bd The boot device where GRUB is installed.
1532 * @return 0 for success, nonzero for failure.
1533 */
1534int run_grub(bool offer_to_run_stabgrub, char *bd)
1535{
1536 /** malloc **/
1537 char *command;
1538 char *boot_device;
1539 char *rootdev;
1540 char *rootdrive;
1541 char *conffile;
1542 char *tmp;
1543 char *editor;
1544
1545 int res;
1546 int done;
1547
1548 malloc_string(command);
1549 malloc_string(boot_device);
1550 malloc_string(tmp);
1551 malloc_string(editor);
1552 malloc_string(rootdev);
1553 malloc_string(rootdrive);
1554 malloc_string(conffile);
1555 assert_string_is_neither_NULL_nor_zerolength(bd);
1556 strcpy(editor, find_my_editor());
1557 strcpy(boot_device, bd);
1558
1559 if (!run_program_and_log_output("which grub-MR", FALSE)) {
1560 log_msg(1, "Yay! grub-MR found...");
1561 sprintf(command, "grub-MR %s /tmp/mountlist.txt", boot_device);
1562 log_msg(1, "command = %s", command);
1563 } else {
1564 sprintf(command, "chroot " MNT_RESTORING " grub-install %s",
1565 boot_device);
1566 log_msg(1, "WARNING - grub-MR not found; using grub-install");
1567 }
1568 if (offer_to_run_stabgrub
1569 && ask_me_yes_or_no("Did you change the mountlist?"))
1570 /* interactive mode */
1571 {
1572 mvaddstr_and_log_it(g_currentY,
1573 0,
1574 "Modifying fstab, mtab, device.map and grub.conf, and running GRUB... ");
1575 for (done = FALSE; !done;) {
1576 popup_and_get_string("Boot device",
1577 "Please confirm/enter the boot device. If in doubt, try /dev/hda",
1578 boot_device, MAX_STR_LEN / 4);
1579 sprintf(command, "stabgrub-me %s", boot_device);
1580 res = run_program_and_log_output(command, 1);
1581 if (res) {
1582 popup_and_OK
1583 ("GRUB installation failed. Please install manually using 'grub-install' or similar command. You are now chroot()'ed to your restored system. Please type 'exit' when you are done.");
1584 newtSuspend();
1585 system("chroot " MNT_RESTORING);
1586 newtResume();
1587 popup_and_OK("Thank you.");
1588 } else {
1589 done = TRUE;
1590 }
1591 popup_and_OK("You will now edit fstab, mtab, device.map and grub.conf");
1592 if (!g_text_mode) {
1593 newtSuspend();
1594 }
1595 sprintf(tmp, "chroot %s %s /etc/fstab", MNT_RESTORING, editor);
1596 paranoid_system(tmp);
1597 sprintf(tmp, "chroot %s %s /etc/mtab", MNT_RESTORING, editor);
1598 paranoid_system(tmp);
1599 sprintf(tmp, "chroot %s %s /etc/grub.conf", MNT_RESTORING, editor);
1600 paranoid_system(tmp);
1601 sprintf(tmp, "chroot %s %s /boot/grub/device.map", MNT_RESTORING, editor);
1602 paranoid_system(tmp);
1603 if (!g_text_mode) {
1604 newtResume();
1605 }
1606 }
1607 } else
1608 /* nuke mode */
1609 {
1610 mvaddstr_and_log_it(g_currentY,
1611 0,
1612 "Running GRUB... ");
1613 iamhere(command);
1614 res = run_program_and_log_output(command, 1);
1615 if (res) {
1616 popup_and_OK
1617 ("Because of bugs in GRUB's own installer, GRUB was not installed properly. Please install the boot loader manually now, using this chroot()'ed shell prompt. Type 'exit' when you have finished.");
1618 newtSuspend();
1619 system("chroot " MNT_RESTORING);
1620 newtResume();
1621 popup_and_OK("Thank you.");
1622 }
1623 }
1624 if (res) {
1625 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1626 log_to_screen
1627 ("GRUB ran w/error(s). See %s for more info.", MONDO_LOGFILE);
1628 log_msg(1, "Type:-");
1629 log_msg(1, " mount-me");
1630 log_msg(1, " chroot " MNT_RESTORING);
1631 log_msg(1, " mount /boot");
1632 log_msg(1, " grub-install '(hd0)'");
1633 log_msg(1, " exit");
1634 log_msg(1, " unmount-me");
1635 log_msg(1,
1636 "If you're really stuck, please e-mail the mailing list.");
1637 } else {
1638 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1639 }
1640 paranoid_free(rootdev);
1641 paranoid_free(rootdrive);
1642 paranoid_free(conffile);
1643 paranoid_free(command);
1644 paranoid_free(boot_device);
1645 paranoid_free(tmp);
1646 paranoid_free(editor);
1647
1648 return (res);
1649}
1650
1651/**************************************************************************
1652 *END_RUN_GRUB *
1653 **************************************************************************/
1654
1655
1656/**
1657 * Install ELILO on the user's boot drive (determined by elilo.conf).
1658 * @param offer_to_run_stabelilo If TRUE, then offer to hack the user's fstab for them.
1659 * @return 0 for success, nonzero for failure.
1660 */
1661int run_elilo(bool offer_to_run_stabelilo)
1662{
1663 /** malloc **/
1664 char *command;
1665 char *tmp;
1666 char *editor;
1667
1668 int res;
1669 int done;
1670
1671 malloc_string(command);
1672 malloc_string(tmp);
1673 malloc_string(editor);
1674 strcpy(editor, find_my_editor());
1675 if (offer_to_run_stabelilo
1676 && ask_me_yes_or_no("Did you change the mountlist?"))
1677
1678 /* interactive mode */
1679 {
1680 mvaddstr_and_log_it(g_currentY,
1681 0,
1682 "Modifying fstab and elilo.conf... ");
1683 sprintf(command, "stabelilo-me");
1684 res = run_program_and_log_output(command, 3);
1685 if (res) {
1686 popup_and_OK
1687 ("You will now edit fstab and elilo.conf, to make sure they match your new mountlist.");
1688 for (done = FALSE; !done;) {
1689 if (!g_text_mode) {
1690 newtSuspend();
1691 }
1692 sprintf(tmp, "chroot %s %s /etc/fstab", MNT_RESTORING, editor);
1693 paranoid_system(tmp);
1694 sprintf(tmp, "chroot %s %s /etc/elilo.conf", MNT_RESTORING, editor);
1695 paranoid_system(tmp);
1696 if (!g_text_mode) {
1697 newtResume();
1698 }
1699// newtCls();
1700 if (ask_me_yes_or_no("Edit them again?")) {
1701 continue;
1702 }
1703 done = TRUE;
1704 }
1705 } else {
1706 log_to_screen("elilo.conf and fstab were modified OK");
1707 }
1708 } else
1709 /* nuke mode */
1710 {
1711 res = TRUE;
1712 }
1713 paranoid_free(command);
1714 paranoid_free(tmp);
1715 paranoid_free(editor);
1716 return (res);
1717}
1718
1719/**************************************************************************
1720 *END_RUN_ELILO *
1721 **************************************************************************/
1722
1723
1724/**
1725 * Install LILO on the user's boot drive (determined by /etc/lilo.conf).
1726 * @param offer_to_run_stablilo If TRUE, then offer to hack the user's fstab for them.
1727 * @return 0 for success, nonzero for failure.
1728 */
1729int run_lilo(bool offer_to_run_stablilo)
1730{
1731 /** malloc **/
1732 char *command;
1733 char *tmp;
1734 char *editor;
1735
1736 int res;
1737 int done;
1738 bool run_lilo_M = FALSE;
1739 malloc_string(command);
1740 malloc_string(tmp);
1741 malloc_string(editor);
1742
1743 if (!run_program_and_log_output
1744 ("grep \"boot.*=.*/dev/md\" " MNT_RESTORING "/etc/lilo.conf", 1)) {
1745 run_lilo_M = TRUE;
1746 }
1747
1748 strcpy(editor, find_my_editor());
1749 if (offer_to_run_stablilo
1750 && ask_me_yes_or_no("Did you change the mountlist?"))
1751
1752 /* interactive mode */
1753 {
1754 mvaddstr_and_log_it(g_currentY,
1755 0,
1756 "Modifying fstab and lilo.conf, and running LILO... ");
1757 sprintf(command, "stablilo-me");
1758 res = run_program_and_log_output(command, 3);
1759 if (res) {
1760 popup_and_OK
1761 ("You will now edit fstab and lilo.conf, to make sure they match your new mountlist.");
1762 for (done = FALSE; !done;) {
1763 if (!g_text_mode) {
1764 newtSuspend();
1765 }
1766 sprintf(tmp, "%s " MNT_RESTORING "/etc/fstab", editor);
1767 paranoid_system(tmp);
1768 sprintf(tmp, "%s " MNT_RESTORING "/etc/lilo.conf", editor);
1769 paranoid_system(tmp);
1770 if (!g_text_mode) {
1771 newtResume();
1772 }
1773// newtCls();
1774 if (ask_me_yes_or_no("Edit them again?")) {
1775 continue;
1776 }
1777 res =
1778 run_program_and_log_output("chroot " MNT_RESTORING
1779 " lilo -L", 3);
1780 if (res) {
1781 res =
1782 run_program_and_log_output("chroot " MNT_RESTORING
1783 " lilo", 3);
1784 }
1785 if (res) {
1786 done =
1787 ask_me_yes_or_no
1788 ("LILO failed. Re-edit system files?");
1789 } else {
1790 done = TRUE;
1791 }
1792 }
1793 } else {
1794 log_to_screen("lilo.conf and fstab were modified OK");
1795 }
1796 } else
1797 /* nuke mode */
1798 {
1799 mvaddstr_and_log_it(g_currentY,
1800 0,
1801 "Running LILO... ");
1802 res =
1803 run_program_and_log_output("chroot " MNT_RESTORING " lilo -L",
1804 3);
1805 if (res) {
1806 res =
1807 run_program_and_log_output("chroot " MNT_RESTORING " lilo",
1808 3);
1809 }
1810 if (res) {
1811 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1812 log_to_screen
1813 ("Failed to re-jig fstab and/or lilo. Edit/run manually, please.");
1814 } else {
1815 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1816 }
1817 }
1818 if (run_lilo_M) {
1819 run_program_and_log_output("chroot " MNT_RESTORING
1820 " lilo -M /dev/hda", 3);
1821 run_program_and_log_output("chroot " MNT_RESTORING
1822 " lilo -M /dev/sda", 3);
1823 }
1824 paranoid_free(command);
1825 paranoid_free(tmp);
1826 paranoid_free(editor);
1827 return (res);
1828}
1829
1830/**************************************************************************
1831 *END_RUN_LILO *
1832 **************************************************************************/
1833
1834
1835/**
1836 * Install a raw MBR onto @p bd.
1837 * @param offer_to_hack_scripts If TRUE, then offer to hack the user's fstab for them.
1838 * @param bd The device to copy the stored MBR to.
1839 * @return 0 for success, nonzero for failure.
1840 */
1841int run_raw_mbr(bool offer_to_hack_scripts, char *bd)
1842{
1843 /** malloc **/
1844 char *command;
1845 char *boot_device;
1846 char *tmp;
1847 char *editor;
1848 int res;
1849 int done;
1850
1851 malloc_string(command);
1852 malloc_string(boot_device);
1853 malloc_string(tmp);
1854 malloc_string(editor);
1855 assert_string_is_neither_NULL_nor_zerolength(bd);
1856
1857 strcpy(editor, find_my_editor());
1858 strcpy(boot_device, bd);
1859 sprintf(command, "raw-MR %s /tmp/mountlist.txt", boot_device);
1860 log_msg(2, "run_raw_mbr() --- command='%s'", command);
1861
1862 if (offer_to_hack_scripts
1863 && ask_me_yes_or_no("Did you change the mountlist?"))
1864 /* interactive mode */
1865 {
1866 mvaddstr_and_log_it(g_currentY, 0,
1867 "Modifying fstab and restoring MBR... ");
1868 for (done = FALSE; !done;) {
1869 if (!run_program_and_log_output("which vi", FALSE)) {
1870 popup_and_OK("You will now edit fstab");
1871 if (!g_text_mode) {
1872 newtSuspend();
1873 }
1874 sprintf(tmp, "%s " MNT_RESTORING "/etc/fstab", editor);
1875 paranoid_system(tmp);
1876 if (!g_text_mode) {
1877 newtResume();
1878 }
1879// newtCls();
1880 }
1881 popup_and_get_string("Boot device",
1882 "Please confirm/enter the boot device. If in doubt, try /dev/hda",
1883 boot_device, MAX_STR_LEN / 4);
1884 sprintf(command, "stabraw-me %s", boot_device);
1885 res = run_program_and_log_output(command, 3);
1886 if (res) {
1887 done = ask_me_yes_or_no("Modifications failed. Re-try?");
1888 } else {
1889 done = TRUE;
1890 }
1891 }
1892 } else
1893 /* nuke mode */
1894 {
1895 mvaddstr_and_log_it(g_currentY, 0,
1896 "Restoring MBR... ");
1897 res = run_program_and_log_output(command, 3);
1898 }
1899 if (res) {
1900 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
1901 log_to_screen
1902 ("MBR+fstab processed w/error(s). See %s for more info.", MONDO_LOGFILE);
1903 } else {
1904 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1905 }
1906 paranoid_free(command);
1907 paranoid_free(boot_device);
1908 paranoid_free(tmp);
1909 paranoid_free(editor);
1910 return (res);
1911}
1912
1913/**************************************************************************
1914 *END_RUN_RAW_MBR *
1915 **************************************************************************/
1916
1917
1918
1919/**
1920 * malloc() and set sensible defaults for the mondorestore filename variables.
1921 * @param bkpinfo The backup information structure. Fields used:
1922 * - @c bkpinfo->tmpdir
1923 * - @c bkpinfo->disaster_recovery
1924 */
1925void setup_MR_global_filenames()
1926{
1927 char *temppath;
1928
1929 assert(bkpinfo != NULL);
1930
1931 malloc_string(g_biggielist_txt);
1932 malloc_string(g_filelist_full);
1933 malloc_string(g_filelist_imagedevs);
1934 malloc_string(g_imagedevs_restthese);
1935 malloc_string(g_mondo_cfg_file);
1936 malloc_string(g_mountlist_fname);
1937 malloc_string(g_mondo_home);
1938 /*
1939 malloc_string(g_tmpfs_mountpt);
1940 */
1941 malloc_string(g_isodir_device);
1942 malloc_string(g_isodir_format);
1943
1944 temppath = bkpinfo->tmpdir;
1945
1946 sprintf(g_biggielist_txt, "%s/%s", temppath, BIGGIELIST_TXT_STUB);
1947 sprintf(g_filelist_full, "%s/%s", temppath, FILELIST_FULL_STUB);
1948 sprintf(g_filelist_imagedevs, "%s/tmp/filelist.imagedevs", temppath);
1949// sprintf(g_imagedevs_pot, "%s/tmp/imagedevs.pot", temppath);
1950 sprintf(g_imagedevs_restthese, "%s/tmp/imagedevs.restore-these",
1951 temppath);
1952 if (bkpinfo->disaster_recovery) {
1953 sprintf(g_mondo_cfg_file, "/%s", MONDO_CFG_FILE_STUB);
1954 sprintf(g_mountlist_fname, "/%s", MOUNTLIST_FNAME_STUB);
1955 } else {
1956 sprintf(g_mondo_cfg_file, "%s/%s", temppath, MONDO_CFG_FILE_STUB);
1957 sprintf(g_mountlist_fname, "%s/%s", temppath,
1958 MOUNTLIST_FNAME_STUB);
1959 }
1960}
1961
1962/**************************************************************************
1963 *END_SET_GLOBAL_FILENAME *
1964 **************************************************************************/
1965
1966
1967/**
1968 * Copy @p input_file (containing the result of a compare) to @p output_file,
1969 * deleting spurious "changes" along the way.
1970 * @param output_file The output file to write with spurious changes removed.
1971 * @param input_file The input file, a list of changed files created by a compare.
1972 */
1973void streamline_changes_file(char *output_file, char *input_file)
1974{
1975 FILE *fin;
1976 FILE *fout;
1977 /** malloc **/
1978 char *incoming;
1979
1980 assert_string_is_neither_NULL_nor_zerolength(output_file);
1981 assert_string_is_neither_NULL_nor_zerolength(input_file);
1982 malloc_string(incoming);
1983
1984 if (!(fin = fopen(input_file, "r"))) {
1985 log_OS_error(input_file);
1986 return;
1987 }
1988 if (!(fout = fopen(output_file, "w"))) {
1989 fatal_error("cannot open output_file");
1990 }
1991 for (fgets(incoming, MAX_STR_LEN - 1, fin); !feof(fin);
1992 fgets(incoming, MAX_STR_LEN - 1, fin)) {
1993 if (strncmp(incoming, "etc/adjtime", 11)
1994 && strncmp(incoming, "etc/mtab", 8)
1995 && strncmp(incoming, "tmp/", 4)
1996 && strncmp(incoming, "boot/map", 8)
1997 && !strstr(incoming, "incheckentry")
1998 && strncmp(incoming, "etc/mail/statistics", 19)
1999 && strncmp(incoming, "var/", 4))
2000 fprintf(fout, "%s", incoming); /* don't need \n here, for some reason.. */
2001 }
2002 paranoid_fclose(fout);
2003 paranoid_fclose(fin);
2004 paranoid_free(incoming);
2005}
2006
2007/**************************************************************************
2008 *END_STREAMLINE_CHANGES_FILE *
2009 **************************************************************************/
2010
2011
2012/**
2013 * Give the user twenty seconds to press Ctrl-Alt-Del before we nuke their drives.
2014 */
2015void twenty_seconds_til_yikes()
2016{
2017 int i;
2018 /* MALLOC * */
2019 char *tmp;
2020
2021 malloc_string(tmp);
2022 if (does_file_exist("/tmp/NOPAUSE")) {
2023 return;
2024 }
2025 open_progress_form("CAUTION",
2026 "Be advised: I am about to ERASE your hard disk(s)!",
2027 "You may press Ctrl+Alt+Del to abort safely.",
2028 "", 20);
2029 for (i = 0; i < 20; i++) {
2030 g_current_progress = i;
2031 sprintf(tmp, "You have %d seconds left to abort.", 20 - i);
2032 update_progress_form(tmp);
2033 sleep(1);
2034 }
2035 close_progress_form();
2036 paranoid_free(tmp);
2037}
2038
2039/**************************************************************************
2040 *END_TWENTY_SECONDS_TIL_YIKES *
2041 **************************************************************************/
2042
2043
2044/**
2045 * Unmount all devices in @p p_external_copy_of_mountlist.
2046 * @param p_external_copy_of_mountlist The mountlist to guide the devices to unmount.
2047 * @return 0 for success, nonzero for failure.
2048 */
2049int unmount_all_devices(struct mountlist_itself
2050 *p_external_copy_of_mountlist)
2051{
2052 struct mountlist_itself *mountlist;
2053 int retval = 0, lino, res = 0, i;
2054 char *command;
2055 char *tmp;
2056
2057 malloc_string(command);
2058 malloc_string(tmp);
2059 assert(p_external_copy_of_mountlist != NULL);
2060
2061 mountlist = malloc(sizeof(struct mountlist_itself));
2062 memcpy((void *) mountlist, (void *) p_external_copy_of_mountlist,
2063 sizeof(struct mountlist_itself));
2064 sort_mountlist_by_mountpoint(mountlist, 0);
2065
2066 run_program_and_log_output("df -m", 3);
2067 mvaddstr_and_log_it(g_currentY, 0, "Unmounting devices ");
2068 open_progress_form("Unmounting devices",
2069 "Unmounting all devices that were mounted,",
2070 "in preparation for the post-restoration reboot.",
2071 "", mountlist->entries);
2072 chdir("/");
2073 for (i = 0;
2074 i < 10
2075 &&
2076 run_program_and_log_output
2077 ("ps | grep buffer | grep -v \"grep buffer\"", TRUE) == 0;
2078 i++) {
2079 sleep(1);
2080 log_msg(2, "Waiting for buffer() to finish");
2081 }
2082
2083 paranoid_system("sync");
2084
2085 sprintf(tmp, "cp -f %s " MNT_RESTORING "/var/log", MONDO_LOGFILE);
2086 if (run_program_and_log_output(tmp, FALSE)) {
2087 log_msg(1,
2088 "Error. Failed to copy log to PC's /var/log dir. (Mounted read-only?)");
2089 }
2090 if (does_file_exist("/tmp/DUMBASS-GENTOO")) {
2091 run_program_and_log_output("mkdir -p " MNT_RESTORING
2092 "/mnt/.boot.d", 5);
2093 }
2094
2095 /* Unmounting the local /proc and /sys first */
2096 run_program_and_log_output("umount " MNT_RESTORING "/proc",3);
2097 run_program_and_log_output("umount " MNT_RESTORING "/sys",3);
2098
2099 for (lino = mountlist->entries - 1; lino >= 0; lino--) {
2100 if (!strcmp(mountlist->el[lino].mountpoint, "lvm")) {
2101 continue;
2102 }
2103 sprintf(tmp, "Unmounting device %s ", mountlist->el[lino].device);
2104
2105 update_progress_form(tmp);
2106 if (is_this_device_mounted(mountlist->el[lino].device)) {
2107 if (!strcmp(mountlist->el[lino].mountpoint, "swap")) {
2108 sprintf(command, "swapoff %s", mountlist->el[lino].device);
2109 } else {
2110 if (!strcmp(mountlist->el[lino].mountpoint, "/1")) {
2111 sprintf(command, "umount %s/", MNT_RESTORING);
2112 log_msg(3,
2113 "Well, I know a certain kitty-kitty who'll be sleeping with Mommy tonight...");
2114 } else {
2115 sprintf(command, "umount " MNT_RESTORING "%s",
2116 mountlist->el[lino].mountpoint);
2117 }
2118 }
2119 log_msg(10, "The 'umount' command is '%s'", command);
2120 res = run_program_and_log_output(command, 3);
2121 } else {
2122 strcat(tmp, "...not mounted anyway :-) OK");
2123 res = 0;
2124 }
2125 g_current_progress++;
2126 if (res) {
2127 strcat(tmp, "...Failed");
2128 retval++;
2129 log_to_screen(tmp);
2130 } else {
2131 log_msg(2, tmp);
2132 }
2133 }
2134 close_progress_form();
2135 if (retval) {
2136 mvaddstr_and_log_it(g_currentY++, 74, "Failed.");
2137 } else {
2138 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2139 }
2140 if (retval) {
2141 log_to_screen("Unable to unmount some of your partitions.");
2142 } else {
2143 log_to_screen("All partitions were unmounted OK.");
2144 }
2145 free(mountlist);
2146 paranoid_free(command);
2147 paranoid_free(tmp);
2148 return (retval);
2149}
2150
2151/**************************************************************************
2152 *END_UNMOUNT_ALL_DEVICES *
2153 **************************************************************************/
2154
2155
2156
2157/**
2158 * Extract mondo-restore.cfg and the mountlist from the tape inserted
2159 * to the ./tmp/ directory.
2160 * @param dev The tape device to read from.
2161 * @return 0 for success, nonzero for failure.
2162 */
2163int extract_cfg_file_and_mountlist_from_tape_dev(char *dev)
2164{
2165 char *command;
2166 int res = 0;
2167
2168 malloc_string(command);
2169
2170 if (bkpinfo->use_obdr) {
2171 skip_obdr();
2172 } else {
2173 // BCO: below 32KB seems to block at least on RHAS 2.1 and MDK 10.0
2174 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
2175 }
2176
2177 sprintf(command,
2178 "dd if=%s bs=%ld count=%ld 2> /dev/null | tar -zx ./%s ./%s ./%s ./%s ./%s",
2179 dev,
2180 bkpinfo->internal_tape_block_size,
2181 1024L * 1024 * 32 / bkpinfo->internal_tape_block_size,
2182 MOUNTLIST_FNAME_STUB, MONDO_CFG_FILE_STUB,
2183 BIGGIELIST_TXT_STUB, FILELIST_FULL_STUB, IWANTMYLVM_STUB);
2184 log_msg(2, "command = '%s'", command);
2185 res = run_program_and_log_output(command, -1);
2186 if (res != 0) {
2187 if (does_file_exist(MONDO_CFG_FILE_STUB)) {
2188 res = 0;
2189 } else {
2190 /* Doing that allow us to remain compatible with pre-2.2.5 versions */
2191 log_msg(2, "pre-2.2.4 compatible mode on");
2192 sprintf(command,
2193 "dd if=%s bs=%ld count=%ld 2> /dev/null | tar -zx %s %s %s %s %s",
2194 dev,
2195 bkpinfo->internal_tape_block_size,
2196 1024L * 1024 * 32 / bkpinfo->internal_tape_block_size,
2197 MOUNTLIST_FNAME_STUB, MONDO_CFG_FILE_STUB,
2198 BIGGIELIST_TXT_STUB, FILELIST_FULL_STUB, IWANTMYLVM_STUB);
2199 log_msg(2, "command = '%s'", command);
2200 res = run_program_and_log_output(command, -1);
2201 if ((res != 0) && (does_file_exist(MONDO_CFG_FILE_STUB))) {
2202 res = 0;
2203 }
2204 }
2205 }
2206 paranoid_free(command);
2207 return (res);
2208}
2209
2210
2211
2212/**
2213 * Get the configuration file from the floppy, tape, or CD.
2214 * @param bkpinfo The backup information structure. Fields used:
2215 * - @c bkpinfo->backup_media_type
2216 * - @c bkpinfo->media_device
2217 * - @c bkpinfo->tmpdir
2218 * @return 0 for success, nonzero for failure.
2219 */
2220int get_cfg_file_from_archive()
2221{
2222 int retval = 0;
2223
2224 /** malloc *****/
2225 char *device;
2226 char *command;
2227 char *cfg_file;
2228 char *mounted_cfgf_path;
2229 char *tmp;
2230 char *mountpt;
2231 char *ramdisk_fname;
2232 char *mountlist_file;
2233
2234 bool try_plan_B;
2235
2236 assert(bkpinfo != NULL);
2237 malloc_string(cfg_file);
2238 malloc_string(mounted_cfgf_path);
2239 malloc_string(mountpt);
2240 malloc_string(ramdisk_fname);
2241 malloc_string(mountlist_file);
2242 malloc_string(device);
2243 malloc_string(command);
2244 malloc_string(tmp);
2245 log_msg(2, "gcffa --- starting");
2246 log_to_screen("I'm thinking...");
2247 sprintf(mountpt, "%s/mount.bootdisk", bkpinfo->tmpdir);
2248 device[0] = '\0';
2249 chdir(bkpinfo->tmpdir);
2250 strcpy(cfg_file, MONDO_CFG_FILE_STUB);
2251 unlink(cfg_file); // cfg_file[] is missing the '/' at the start, FYI, by intent
2252 unlink(FILELIST_FULL_STUB);
2253 unlink(BIGGIELIST_TXT_STUB);
2254 unlink(IWANTMYLVM_STUB);
2255 sprintf(command, "mkdir -p %s", mountpt);
2256 run_program_and_log_output(command, FALSE);
2257
2258// unlink( "tmp/mondo-restore.cfg" ); // superfluous, surely?
2259
2260 sprintf(cfg_file, "%s/%s", bkpinfo->tmpdir, MONDO_CFG_FILE_STUB);
2261 sprintf(mountlist_file, "%s/%s", bkpinfo->tmpdir,
2262 MOUNTLIST_FNAME_STUB);
2263 // make_hole_for_file( cfg_file );
2264 // make_hole_for_file( mountlist_file);
2265 log_msg(2, "mountpt = %s; cfg_file=%s", mountpt, cfg_file);
2266
2267 if (!does_file_exist(cfg_file)) {
2268 log_msg(2, "gcffa --- we don't have cfg file yet.");
2269 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2270 try_plan_B = TRUE;
2271 } else {
2272 log_msg(2, "gcffa --- calling mount_media now :)");
2273 if (!mount_media()) {
2274 log_msg(2,
2275 "gcffa --- managed to mount CD; so, no need for Plan B");
2276 try_plan_B = FALSE;
2277 } else {
2278 try_plan_B = TRUE;
2279 }
2280 if (what_number_cd_is_this() > 1) {
2281 insist_on_this_cd_number((g_current_media_number = 1));
2282 }
2283 }
2284 if (try_plan_B) {
2285 log_msg(2, "gcffa --- OK, switching to Plan B");
2286 chdir(bkpinfo->tmpdir);
2287 run_program_and_log_output("mkdir -p tmp", FALSE);
2288
2289 if (strlen(bkpinfo->media_device) == 0) {
2290 strcpy(bkpinfo->media_device, "/dev/st0");
2291 log_msg(2, "media_device is blank; assuming %s");
2292 }
2293 strcpy(tmp, bkpinfo->media_device);
2294 if (extract_cfg_file_and_mountlist_from_tape_dev
2295 (bkpinfo->media_device)) {
2296 strcpy(bkpinfo->media_device, "/dev/st0");
2297 if (extract_cfg_file_and_mountlist_from_tape_dev
2298 (bkpinfo->media_device)) {
2299 strcpy(bkpinfo->media_device, "/dev/osst0");
2300 if (extract_cfg_file_and_mountlist_from_tape_dev
2301 (bkpinfo->media_device)) {
2302 strcpy(bkpinfo->media_device, "/dev/ht0");
2303 if (extract_cfg_file_and_mountlist_from_tape_dev
2304 (bkpinfo->media_device)) {
2305 log_msg(3,
2306 "I tried lots of devices but none worked.");
2307 strcpy(bkpinfo->media_device, tmp);
2308 }
2309 }
2310 }
2311 }
2312
2313 if (!does_file_exist("tmp/mondo-restore.cfg")) {
2314 log_to_screen("Cannot find config info on media");
2315 return (1);
2316 }
2317 } else {
2318 log_msg(2,
2319 "gcffa --- Plan B, a.k.a. untarring some file from all.tar.gz");
2320 sprintf(command, "tar -zxvf " MNT_CDROM "/images/all.tar.gz ./%s ./%s ./%s ./%s ./%s", MOUNTLIST_FNAME_STUB, MONDO_CFG_FILE_STUB, BIGGIELIST_TXT_STUB, FILELIST_FULL_STUB, IWANTMYLVM_STUB); // add -b TAPE_BLOCK_SIZE if you _really_ think it's necessary
2321 run_program_and_log_output(command, TRUE);
2322 if (!does_file_exist(MONDO_CFG_FILE_STUB)) {
2323 /* Doing that allow us to remain compatible with pre-2.2.5 versions */
2324 log_msg(2, "pre-2.2.4 compatible mode on");
2325 sprintf(command, "tar -zxvf " MNT_CDROM "/images/all.tar.gz %s %s %s %s %s", MOUNTLIST_FNAME_STUB, MONDO_CFG_FILE_STUB, BIGGIELIST_TXT_STUB, FILELIST_FULL_STUB, IWANTMYLVM_STUB); // add -b TAPE_BLOCK_SIZE if you _really_ think it's necessary
2326 run_program_and_log_output(command, TRUE);
2327 if (!does_file_exist(MONDO_CFG_FILE_STUB)) {
2328 fatal_error
2329 ("Please reinsert the disk/CD and try again.");
2330 }
2331 }
2332 }
2333 }
2334 if (does_file_exist(MONDO_CFG_FILE_STUB)) {
2335 log_msg(1, "gcffa --- great! We've got the config file");
2336 sprintf(tmp, "%s/%s",
2337 call_program_and_get_last_line_of_output("pwd"),
2338 MONDO_CFG_FILE_STUB);
2339 sprintf(command, "cp -f %s %s", tmp, cfg_file);
2340 iamhere(command);
2341 if (strcmp(tmp, cfg_file)
2342 && run_program_and_log_output(command, 1)) {
2343 log_msg(1,
2344 "... but an error occurred when I tried to move it to %s",
2345 cfg_file);
2346 } else {
2347 log_msg(1, "... and I moved it successfully to %s", cfg_file);
2348 }
2349 sprintf(command, "cp -f %s/%s %s",
2350 call_program_and_get_last_line_of_output("pwd"),
2351 MOUNTLIST_FNAME_STUB, mountlist_file);
2352 iamhere(command);
2353 if (strcmp(tmp, cfg_file)
2354 && run_program_and_log_output(command, 1)) {
2355 log_msg(1, "Failed to get mountlist");
2356 } else {
2357 log_msg(1, "Got mountlist too");
2358 sprintf(command, "cp -f %s %s", mountlist_file,
2359 g_mountlist_fname);
2360 if (run_program_and_log_output(command, 1)) {
2361 log_msg(1, "Failed to copy mountlist to /tmp");
2362 } else {
2363 log_msg(1, "Copied mountlist to /tmp as well OK");
2364 sprintf(command, "cp -f %s /tmp/",IWANTMYLVM_STUB);
2365 run_program_and_log_output(command, 1);
2366 }
2367 }
2368 }
2369 run_program_and_log_output("umount " MNT_CDROM, FALSE);
2370 if (!does_file_exist(cfg_file)) {
2371 iamhere(cfg_file);
2372 log_msg(1, "%s not found", cfg_file);
2373 log_to_screen
2374 ("Oh dear. Unable to recover configuration file from boot disk");
2375 return (1);
2376 }
2377
2378 log_to_screen("Recovered mondo-restore.cfg");
2379 if (!does_file_exist(MOUNTLIST_FNAME_STUB)) {
2380 log_to_screen("...but not mountlist.txt - a pity, really...");
2381 }
2382/* start SAH */
2383 else {
2384 sprintf(command, "cp -f %s %s/%s", MOUNTLIST_FNAME_STUB,
2385 bkpinfo->tmpdir, MOUNTLIST_FNAME_STUB);
2386 run_program_and_log_output(command, FALSE);
2387 }
2388/*--commented out by SAH
2389 sprintf( command, "cp -f %s %s/%s", cfg_file, bkpinfo->tmpdir, MONDO_CFG_FILE_STUB );
2390 run_program_and_log_output( command, FALSE );
2391 sprintf( command, "cp -f %s %s/%s", mountlist_file, bkpinfo->tmpdir, MOUNTLIST_FNAME_STUB );
2392 run_program_and_log_output( command, FALSE );
2393*/
2394/* end SAH */
2395
2396 sprintf(command, "cp -f %s /%s", cfg_file, MONDO_CFG_FILE_STUB);
2397 run_program_and_log_output(command, FALSE);
2398 sprintf(command, "cp -f %s /%s", mountlist_file, MOUNTLIST_FNAME_STUB);
2399 run_program_and_log_output(command, FALSE);
2400 sprintf(command, "cp -f etc/raidtab /etc/");
2401 run_program_and_log_output(command, FALSE);
2402 sprintf(command, "cp -f %s /tmp/",IWANTMYLVM_STUB);
2403 run_program_and_log_output(command, FALSE);
2404 g_backup_media_type = bkpinfo->backup_media_type;
2405 paranoid_free(device);
2406 paranoid_free(command);
2407 paranoid_free(tmp);
2408 paranoid_free(cfg_file);
2409 paranoid_free(mounted_cfgf_path);
2410 paranoid_free(mountpt);
2411 paranoid_free(ramdisk_fname);
2412 paranoid_free(mountlist_file);
2413 return (retval);
2414}
2415
2416/**************************************************************************
2417 *END_GET_CFG_FILE_FROM_ARCHIVE *
2418 **************************************************************************/
2419
2420/* @} - end restoreUtilityGroup */
2421
2422
2423/***************************************************************************
2424 * F@ *
2425 * () -- Hugo Rabson *
2426 * *
2427 * Purpose: *
2428 * *
2429 * Called by: *
2430 * Params: - - *
2431 * Returns: 0=success; nonzero=failure *
2432 ***************************************************************************/
2433
2434
2435
2436void wait_until_software_raids_are_prepped(char *mdstat_file,
2437 int wait_for_percentage)
2438{
2439 struct raidlist_itself *raidlist;
2440 int unfinished_mdstat_devices = 9999, i;
2441 char *screen_message;
2442
2443 malloc_string(screen_message);
2444 raidlist = malloc(sizeof(struct raidlist_itself));
2445
2446 assert(wait_for_percentage <= 100);
2447 iamhere("wait_until_software_raids_are_prepped");
2448 while (unfinished_mdstat_devices > 0) {
2449 // FIXME: Prefix '/dev/' should really be dynamic!
2450 if (parse_mdstat(raidlist, "/dev/")) {
2451 log_to_screen("Sorry, cannot read %s", MDSTAT_FILE);
2452 log_msg(1,"Sorry, cannot read %s", MDSTAT_FILE);
2453 return;
2454 }
2455 for (unfinished_mdstat_devices = i = 0; i <= raidlist->entries; i++) {
2456 if (raidlist->el[i].progress < wait_for_percentage) {
2457 unfinished_mdstat_devices++;
2458 if (raidlist->el[i].progress == -1) // delayed while another partition inits
2459 {
2460 continue;
2461 }
2462 log_msg(1,"Sync'ing %s (i=%d)", raidlist->el[i].raid_device, i);
2463 sprintf(screen_message, "Sync'ing %s",
2464 raidlist->el[i].raid_device);
2465 open_evalcall_form(screen_message);
2466 while (raidlist->el[i].progress < wait_for_percentage) {
2467 log_msg(1,"Percentage sync'ed: %d", raidlist->el[i].progress);
2468 update_evalcall_form(raidlist->el[i].progress);
2469 sleep(2);
2470 // FIXME: Prefix '/dev/' should really be dynamic!
2471 if (parse_mdstat(raidlist, "/dev/")) {
2472 break;
2473 }
2474 }
2475 close_evalcall_form();
2476 }
2477 }
2478 }
2479 paranoid_free(screen_message);
2480 paranoid_free(raidlist);
2481}
Note: See TracBrowser for help on using the repository browser.