source: MondoRescue/branches/2.2.4/mondo/src/common/libmondo-archive.c@ 1437

Last change on this file since 1437 was 1437, checked in by andree, 17 years ago

New define 'MINDI_CACHE' set to '/var/cache/mindi' rather than
hardcoding this in the code. Makes it easy to change the location. Also
adjusted some of the messages related to boot floppies or CDs.

(Also added missing debug level to log_debug() call.)

  • Property svn:keywords set to Id
File size: 116.6 KB
Line 
1/* libmondo-archive.c
2 $Id: libmondo-archive.c 1437 2007-05-10 21:41:11Z andree $
3
4subroutines to handle the archiving of files
5
6
7
807/14
9- moved all ACL, xattr stuff here from libmondo-filelist.c
10
1107/12
12- when trying to find boot loader, look for /boot's /dev, not just /'s dev
13
1407/10
15- better detection of changed files
16- added ACL, xattr support for afio
17
1806/17
19- backup with partimagehack if NTFS device; dd, if non-NTFS device
20
2106/14
22- use mondorescue.iso instead of mindi.iso
23
2404/28
25- cleaned up if/then architecture-specific stuff re: CD-R(W)s
26
2704/03
28- added star support
29
3003/12
31- modified offer_to_write_floppies() to support dual-disk boot/root thing
32
3301/20/2004
34- reformat dvd twice if necessary
35
3612/01/2003
37- added pause_for_N_seconds(5, "Letting DVD drive settle");
38
3911/23
40- added #define DVDRWFORMAT
41
4211/20
43- use --no-emul-boot -b isolinux.bin instead of -b mindi-boot.2880.img
44
4510/23
46- wipe DVD at start, whether or not disk is DVD-RW; this is
47 just a test, to see why dvd+rw-format followed by growiosfs
48 locks up the drive
49- use the singlethreaded make_afioballs_and_images_OLD()
50 instead of the multithreaded make_afioballs_and_images()
51 if backing up to tape
52
5310/21
54- if backing up to dvd, look for relevant tools;
55 abort if missing
56
5710/15
58- UI tweaks
59
6010/10
61- eject/inject DVD after wiping it
62
6309/27
64- pause_and_ask_for_cdr() will now blank DVD if necessary
65
6609/26
67- proper reporting of media type in displayed strings
68 (i.e. DVD if DVD, CD if CD, etc.)
69
7009/25
71- add DVD support
72
7309/23
74- malloc/free global strings in new subroutines - malloc_libmondo_global_strings()
75 and free_libmondo_global_strings() - which are in libmondo-tools.c
76
7709/15
78- changed a bunch of char[MAX_STR_LEN]'s to char*; malloc; free;
79
8009/14
81- cosmetic bug re: call to 'which dvdrecord'
82
8309/09
84- copy `locate isolinux.bin | tail -n1` to CD before calling mkisfso
85 if file is missing (in which case, bug in Mindi.pl!)
86- reduced noof_threads from 3 to 2
87- fixed cosmetic bug in make_slices_and_images()
88
8909/02
90- fixed cosmetic bug in verify_data()
91
9205/01 - 08/31
93- added partimagehack hooks
94- make twice as many archives at once as before
95- fixed syntax error re: system(xxx,FALSE)
96- unmount CD-ROM before burning (necessary for RH8/9)
97- only ask for new media if sensible
98- fixed mondoarchive -Vi multi-CD verify bug (Tom Mortell)
99- use single-threaded make_afioballs_and_images() if FreeBSD
100- fixed bug on line 476 (Joshua Oreman)
101- re-enabled the pause, for people w/ weird CD-ROM drives
102- added Joshua Oreman's FreeBSD patches
103- don't listen to please_dont_eject_when_restoring
104 ...after all, we're not restoring :)
105
10604/01 - 04/30
107- cleaned up archive_this_fileset()
108- decreased ARCH_THREADS from 3 to 2
109- pause_and_ask_for_cd() --- calls retract_CD_tray_and_defeat_autorun()
110- call assert() and log_OS_error() in various places
111- cleaned up code a bit
112- increased ARCH_THREADS from 2 to 3
113- misc clean-up (Tom Mortell)
114
11503/15/2003
116- fixed problem w/ multi-ISO verify cycle (Tom Mortell)
117
11811/01 - 12/31/2002
119- removed references to make_afioballs_and_images_OLD()
120- added some error-checking to make_afioballs_in_background
121- make_iso_and_go_on() now copies Mondo's autorun file to CD
122- set scratchdir dir to 1744 when burning CD
123- cleaned up code a bit
124- in call_mindi_...(), gracefully handle the user's input
125 if they specify the boot loader but not the boot device
126- offer to abort if GRUB is boot loader and /dev/md* is
127 the boot device (bug in grub-install)
128- if boot loader is R then write RAW as bootloader.name
129- multithreaded make_afioballs_and_images()
130- fixed slice_up_file_etc() for 0-compression users
131- line 1198: added call to is_this_file_compressed() to stop
132 slice_up_file_etc() from compressing files which are
133 already compressed
134- other hackery related to the above enhancement
135- afio no longer forcibly compresses all files (i.e. I dropped
136 the -U following suggestions from users); let's see if
137 it works :)
138
13910/01 - 10/31
140- mondoarchive (with no parameters) wasn't working
141 if user said yes when asked if BurnProof drive; FIXED
142- if manual CD tray and writing to ISO's then prompt
143 for each & every new CD
144- moved a lot of subroutines here
145 from mondo-archive.c and mondo-floppies.c
146
14709/01 - 09/30
148- if CD not burned OK then don't try to verify
149- change 64k to TAPE_BLOCK_SIZE
150- run_program_and_log_output() now takes boolean operator to specify
151 whether it will log its activities in the event of _success_
152- orig_vfy_flag_val added to write_iso_and_go_on, to restore bkpinfo->verify_data's
153 value if altered by verify_cd_image()
154
15508/01 - 08/31
156- use data structure to store the fname, checksum, mods & perms of each bigfile
157 ... biggiestruct :)
158- bigger tmp[]'s in a few places
159- cleaned up the (user-friendly) counting of biggiefiles a bit
160- if media_size[N]<=0 then catch it & abort, unless it's tape,
161 in which case, allow it
162- cleaned up a lot of log_it() calls
163- fixed NULL filename-related bug in can_we_fit_these_files_on_media()
164- deleted can_we_fit.....() subroutine because it was causing problems
165 --- moved its code into the one subroutine which called it
166- created [08/01/2002]
167*/
168
169/**
170 * @file
171 * Functions to handle backing up data.
172 * This is the main file (at least the longest one) in libmondo.
173 */
174
175#include "my-stuff.h"
176#include "mondostructures.h"
177#include "libmondo-string-EXT.h"
178#include "libmondo-stream-EXT.h"
179#include "libmondo-devices-EXT.h"
180#include "libmondo-tools-EXT.h"
181#include "libmondo-gui-EXT.h"
182#include "libmondo-fork-EXT.h"
183#include "libmondo-files-EXT.h"
184#include "libmondo-filelist-EXT.h"
185#include "libmondo-tools-EXT.h"
186#include "libmondo-verify-EXT.h"
187#include "libmondo-archive.h"
188#include "lib-common-externs.h"
189#include <sys/sem.h>
190#include <sys/types.h>
191#include <sys/ipc.h>
192#include <stdarg.h>
193#define DVDRWFORMAT 1
194
195
196
197/** @def DEFAULT_1722MB_DISK The default 1.722M floppy disk to write images to. */
198/** @def BACKUP_1722MB_DISK The 1.722M floppy disk to try if the default fails. */
199
200#ifdef __FreeBSD__
201#define DEFAULT_1722MB_DISK "/dev/fd0.1722"
202#define BACKUP_1722MB_DISK "/dev/fd0.1722"
203#else
204#define DEFAULT_1722MB_DISK "/dev/fd0u1722"
205#define BACKUP_1722MB_DISK "/dev/fd0H1722"
206#ifndef _SEMUN_H
207#define _SEMUN_H
208
209 /**
210 * The semaphore union, provided only in case the user's system doesn't.
211 */
212union semun {
213 int val;
214 struct semid_ds *buf;
215 unsigned short int *array;
216 struct seminfo *__buf;
217};
218#endif
219#endif /* __FreeBSD__ */
220
221/*@unused@*/
222//static char cvsid[] = "$Id: libmondo-archive.c 1437 2007-05-10 21:41:11Z andree $";
223
224/* *************************** external global vars ******************/
225extern int g_current_media_number;
226extern int g_currentY;
227extern bool g_text_mode;
228extern bool g_exiting;
229extern long g_current_progress;
230extern FILE *g_tape_stream;
231extern long long g_tape_posK;
232extern char *g_mondo_home;
233extern char *g_tmpfs_mountpt;
234extern bool g_cd_recovery;
235extern char *g_serial_string;
236
237extern char *g_getfacl;
238extern char *g_getfattr;
239extern char *MONDO_LOGFILE;
240
241
242
243/**
244 * @addtogroup globalGroup
245 * @{
246 */
247/**
248 * The current backup media type in use.
249 */
250t_bkptype g_backup_media_type = none;
251
252/**
253 * Incremented by each archival thread when it starts up. After that,
254 * this is the number of threads running.
255 */
256int g_current_thread_no = 0;
257
258/* @} - end of globalGroup */
259
260extern int g_noof_rows;
261
262/* Semaphore-related code */
263
264static int set_semvalue(void);
265static void del_semvalue(void);
266static int semaphore_p(void);
267static int semaphore_v(void);
268
269static int g_sem_id;
270static int g_sem_key;
271
272
273
274
275/**
276 * Initialize the semaphore.
277 * @see del_semvalue
278 * @see semaphore_p
279 * @see semaphore_v
280 * @return 1 for success, 0 for failure.
281 */
282static int set_semvalue(void) // initializes semaphore
283{
284 union semun sem_union;
285 sem_union.val = 1;
286 if (semctl(g_sem_id, 0, SETVAL, sem_union) == -1) {
287 return (0);
288 }
289 return (1);
290}
291
292/**
293 * Frees (deletes) the semaphore. Failure is indicated by a log
294 * message.
295 * @see set_semvalue
296 */
297static void del_semvalue(void) // deletes semaphore
298{
299 union semun sem_union;
300
301 if (semctl(g_sem_id, 0, IPC_RMID, sem_union) == -1) {
302 log_msg(3, "Failed to delete semaphore");
303 }
304}
305
306/**
307 * Acquire (increment) the semaphore (change status to P).
308 * @return 1 for success, 0 for failure.
309 * @see semaphore_v
310 */
311static int semaphore_p(void) // changes status to 'P' (waiting)
312{
313 struct sembuf sem_b;
314
315 sem_b.sem_num = 0;
316 sem_b.sem_op = -1; // P()
317 sem_b.sem_flg = SEM_UNDO;
318 if (semop(g_sem_id, &sem_b, 1) == -1) {
319 log_msg(3, "semaphore_p failed");
320 return (0);
321 }
322 return (1);
323}
324
325/**
326 * Free (decrement) the semaphore (change status to V).
327 * @return 1 for success, 0 for failure.
328 */
329static int semaphore_v(void) // changes status to 'V' (free)
330{
331 struct sembuf sem_b;
332
333 sem_b.sem_num = 0;
334 sem_b.sem_op = 1; // V()
335 sem_b.sem_flg = SEM_UNDO;
336 if (semop(g_sem_id, &sem_b, 1) == -1) {
337 log_msg(3, "semaphore_v failed");
338 return (0);
339 }
340 return (1);
341}
342
343
344//------------------------------------------------------
345
346
347/**
348 * Size in megabytes of the buffer afforded to the executable "buffer".
349 * This figure is used when we calculate how much data we have probably 'lost'
350 * when writing off the end of tape N, so that we can then figure out how much
351 * data we must recreate & write to the start of tape N+1.
352 */
353extern int g_tape_buffer_size_MB;
354
355
356
357
358int
359archive_this_fileset_with_star(struct s_bkpinfo *bkpinfo, char *filelist,
360 char *fname, int setno)
361{
362 int retval = 0;
363 unsigned int res = 0;
364 int tries = 0;
365 char *command;
366 char *zipparams;
367 char *tmp;
368 char *p;
369
370 malloc_string(command);
371 malloc_string(zipparams);
372 malloc_string(tmp);
373
374 if (!does_file_exist(filelist)) {
375 sprintf(tmp, "(archive_this_fileset) - filelist %s does not exist",
376 filelist);
377 log_to_screen(tmp);
378 return (1);
379 }
380
381 sprintf(tmp, "echo hi > %s 2> /dev/null", fname);
382 if (system(tmp)) {
383 fatal_error("Unable to write tarball to scratchdir");
384 }
385
386 sprintf(command, "star H=star list=%s -c " STAR_ACL_SZ " file=%s",
387 filelist, fname);
388 if (bkpinfo->use_lzo) {
389 fatal_error("Can't use lzop");
390 }
391 if (bkpinfo->compression_level > 0) {
392 strcat(command, " -bz");
393 }
394 sprintf(command + strlen(command), " 2>> %s", MONDO_LOGFILE);
395 log_msg(4, "command = '%s'", command);
396
397 for (res = 99, tries = 0; tries < 3 && res != 0; tries++) {
398 log_msg(5, "command='%s'", command);
399 res = system(command);
400 strcpy(tmp, last_line_of_file(MONDO_LOGFILE));
401 log_msg(1, "res=%d; tmp='%s'", res, tmp);
402 if (bkpinfo->use_star && (res == 254 || res == 65024)
403 && strstr(tmp, "star: Processed all possible files")
404 && tries > 0) {
405 log_msg(1, "Star returned nonfatal error");
406 res = 0;
407 }
408 if (res) {
409 log_OS_error(command);
410 p = strstr(command, "-acl ");
411 if (p) {
412 p[0] = p[1] = p[2] = p[3] = ' ';
413 log_msg(1, "new command = '%s'", command);
414 } else {
415 log_msg(3,
416 "Attempt #%d failed. Pausing 3 seconds and retrying...",
417 tries + 1);
418 sleep(3);
419 }
420 }
421 }
422 retval += res;
423 if (retval) {
424 log_msg(3, "Failed to write set %d", setno);
425 } else if (tries > 1) {
426 log_msg(3, "Succeeded in writing set %d, on try #%d", setno,
427 tries);
428 }
429
430 paranoid_free(command);
431 paranoid_free(zipparams);
432 paranoid_free(tmp);
433 return (retval);
434}
435
436
437/**
438 * Call @c afio to archive the filelist @c filelist to the file @c fname.
439 *
440 * @param bkpinfo The backup information structure. Fields used:
441 * - @c compression_level
442 * - @c scratchdir (only verifies existence)
443 * - @c tmpdir (only verifies existence)
444 * - @c zip_exe
445 * - @c zip_suffix
446 * @param filelist The path to a file containing a list of files to be archived
447 * in this fileset.
448 * @param fname The output file to archive to.
449 * @param setno This fileset number.
450 * @return The number of errors encountered (0 for success).
451 * @ingroup LLarchiveGroup
452 */
453int
454archive_this_fileset(struct s_bkpinfo *bkpinfo, char *filelist,
455 char *fname, int setno)
456{
457
458 /*@ int *************************************************************** */
459 int retval = 0;
460 int res = 0;
461 int i = 0;
462 int tries = 0;
463 static int free_ramdisk_space = 9999;
464
465 /*@ buffers ************************************************************ */
466 char *command;
467 char *zipparams;
468 char *tmp;
469
470 assert(bkpinfo != NULL);
471 assert_string_is_neither_NULL_nor_zerolength(filelist);
472 assert_string_is_neither_NULL_nor_zerolength(fname);
473
474 if (bkpinfo->compression_level > 0 && bkpinfo->use_star) {
475 return (archive_this_fileset_with_star
476 (bkpinfo, filelist, fname, setno));
477 }
478
479 malloc_string(command);
480 malloc_string(zipparams);
481 malloc_string(tmp);
482
483 if (!does_file_exist(filelist)) {
484 sprintf(tmp, "(archive_this_fileset) - filelist %s does not exist",
485 filelist);
486 log_to_screen(tmp);
487 return (1);
488 }
489 sprintf(tmp, "echo hi > %s 2> /dev/null", fname);
490 if (system(tmp)) {
491 fatal_error("Unable to write tarball to scratchdir");
492 }
493
494
495 if (bkpinfo->compression_level > 0) {
496 sprintf(tmp, "%s/do-not-compress-these", g_mondo_home);
497 // -b %ld, TAPE_BLOCK_SIZE
498 sprintf(zipparams, "-Z -P %s -G %d -T 3k", bkpinfo->zip_exe,
499 bkpinfo->compression_level);
500 if (does_file_exist(tmp)) {
501 strcat(zipparams, " -E ");
502 strcat(zipparams, tmp);
503 } else {
504 log_msg(3, "%s not found. Cannot exclude zipfiles, etc.", tmp);
505 }
506 } else {
507 zipparams[0] = '\0';
508 }
509
510// make_hole_for_file(fname);
511
512 if (!does_file_exist(bkpinfo->tmpdir)) {
513 log_OS_error("tmpdir not found");
514 fatal_error("tmpdir not found");
515 }
516 if (!does_file_exist(bkpinfo->scratchdir)) {
517 log_OS_error("scratchdir not found");
518 fatal_error("scratchdir not found");
519 }
520 sprintf(command, "rm -f %s %s. %s.gz %s.%s", fname, fname, fname,
521 fname, bkpinfo->zip_suffix);
522 paranoid_system(command);
523
524 sprintf(command, "afio -o -b %ld -M 16m %s %s < %s 2>> %s",
525 TAPE_BLOCK_SIZE, zipparams, fname, filelist, MONDO_LOGFILE);
526
527 sprintf(tmp, "echo hi > %s 2> /dev/null", fname);
528 if (system(tmp)) {
529 fatal_error("Unable to write tarball to scratchdir");
530 }
531
532 for (res = 99, tries = 0; tries < 3 && res != 0; tries++) {
533 log_msg(5, "command='%s'", command);
534 res = system(command);
535 if (res) {
536 log_OS_error(command);
537 log_msg(3,
538 "Attempt #%d failed. Pausing 3 seconds and retrying...",
539 tries + 1);
540 sleep(3);
541 }
542 }
543 retval += res;
544 if (retval) {
545 log_msg(3, "Failed to write set %d", setno);
546 } else if (tries > 1) {
547 log_msg(3, "Succeeded in writing set %d, on try #%d", setno,
548 tries);
549 }
550
551 if (g_tmpfs_mountpt[0] != '\0') {
552 i = atoi(call_program_and_get_last_line_of_output
553 ("df -m -P | grep dev/shm | grep -v none | tr -s ' ' '\t' | cut -f4"));
554 if (i > 0) {
555 if (free_ramdisk_space > i) {
556 free_ramdisk_space = i;
557 log_msg(2, "min(free_ramdisk_space) is now %d",
558 free_ramdisk_space);
559 if (free_ramdisk_space < 10) {
560 fatal_error
561 ("Please increase PPCFG_RAMDISK_SIZE in my-stuff.h to increase size of ramdisk ");
562 }
563 }
564 }
565 }
566 paranoid_free(command);
567 paranoid_free(zipparams);
568 paranoid_free(tmp);
569 return (retval);
570}
571
572
573
574
575
576
577/**
578 * Wrapper function for all the backup commands.
579 * Calls these other functions: @c prepare_filelist(),
580 * @c call_filelist_chopper(), @c copy_mondo_and_mindi_stuff_to_scratchdir(),
581 * @c call_mindi_to_supply_boot_disks(), @c do_that_initial_phase(),
582 * @c make_those_afios_phase(), @c make_those_slices_phase(), and
583 * @c do_that_final_phase(). If anything fails before @c do_that_initial_phase(),
584 * @c fatal_error is called with a suitable message.
585 * @param bkpinfo The backup information structure. Uses most fields.
586 * @return The number of non-fatal errors encountered (0 for success).
587 * @ingroup archiveGroup
588 */
589int backup_data(struct s_bkpinfo *bkpinfo)
590{
591 int retval = 0, res = 0;
592 char *tmp;
593
594 assert(bkpinfo != NULL);
595 set_g_cdrom_and_g_dvd_to_bkpinfo_value(bkpinfo);
596 malloc_string(tmp);
597 if (bkpinfo->backup_media_type == dvd) {
598#ifdef DVDRWFORMAT
599 if (!find_home_of_exe("dvd+rw-format")) {
600 fatal_error
601 ("Cannot find dvd+rw-format. Please install it or fix your PATH.");
602 }
603#endif
604 if (!find_home_of_exe("growisofs")) {
605 fatal_error
606 ("Cannot find growisofs. Please install it or fix your PATH.");
607 }
608 }
609
610 if ((res = prepare_filelist(bkpinfo))) { /* generate scratchdir/filelist.full */
611 fatal_error("Failed to generate filelist catalog");
612 }
613 if (call_filelist_chopper(bkpinfo)) {
614 fatal_error("Failed to run filelist chopper");
615 }
616
617/*
618 sprintf(tmp, "wc -l %s/archives/filelist.full > %s/archives/filelist.count",bkpinfo->scratchdir, bkpinfo->scratchdir);
619 if (run_program_and_log_output(tmp, 2))
620 { fatal_error("Failed to count filelist.full"); }
621*/
622 sprintf(tmp, "gzip -9 %s/archives/filelist.full", bkpinfo->scratchdir);
623 if (run_program_and_log_output(tmp, 2)) {
624 fatal_error("Failed to gzip filelist.full");
625 }
626 sprintf(tmp, "cp -f %s/archives/*list*.gz %s", bkpinfo->scratchdir,
627 bkpinfo->tmpdir);
628 if (run_program_and_log_output(tmp, 2)) {
629 fatal_error("Failed to copy to tmpdir");
630 }
631
632 copy_mondo_and_mindi_stuff_to_scratchdir(bkpinfo); // payload, too, if it exists
633#if __FreeBSD__ == 5
634 strcpy(bkpinfo->kernel_path, "/boot/kernel/kernel");
635#elif __FreeBSD__ == 4
636 strcpy(bkpinfo->kernel_path, "/kernel");
637#elif linux
638 if (figure_out_kernel_path_interactively_if_necessary
639 (bkpinfo->kernel_path)) {
640 fatal_error
641 ("Kernel not found. Please specify manually with the '-k' switch.");
642 }
643#else
644#error "I don't know about this system!"
645#endif
646 if ((res = call_mindi_to_supply_boot_disks(bkpinfo))) {
647 fatal_error("Failed to generate boot+data disks");
648 }
649 retval += do_that_initial_phase(bkpinfo); // prepare
650 sprintf(tmp, "rm -f %s/images/*.iso", bkpinfo->scratchdir);
651 run_program_and_log_output(tmp, 1);
652 retval += make_those_afios_phase(bkpinfo); // backup regular files
653 retval += make_those_slices_phase(bkpinfo); // backup BIG files
654 retval += do_that_final_phase(bkpinfo); // clean up
655 log_msg(1, "Creation of archives... complete.");
656 if (bkpinfo->verify_data) {
657 sleep(2);
658 }
659 paranoid_free(tmp);
660 return (retval);
661}
662
663
664
665
666/**
667 * Call Mindi to generate boot and data disks.
668 * @note This binds correctly to the new Perl version of mindi.
669 * @param bkpinfo The backup information structure. Fields used:
670 * - @c backup_media_type
671 * - @c boot_loader
672 * - @c boot_device
673 * - @c compression_level
674 * - @c differential
675 * - @c exclude_paths
676 * - @c image_devs
677 * - @c kernel_path
678 * - @c make_cd_use_lilo
679 * - @c media_device
680 * - @c media_size
681 * - @c nonbootable_backup
682 * - @c scratchdir
683 * - @c tmpdir
684 * - @c use_lzo
685 *
686 * @return The number of errors encountered (0 for success)
687 * @bug The code to automagically determine the boot drive
688 * is messy and system-dependent. In particular, it breaks
689 * for Linux RAID and LVM users.
690 * @ingroup MLarchiveGroup
691 */
692int call_mindi_to_supply_boot_disks(struct s_bkpinfo *bkpinfo)
693{
694 /*@ buffer ************************************************************ */
695 char *tmp;
696 char *tmp1 = NULL;
697 char *scratchdir;
698 char *command;
699 char *use_lzo_sz;
700 char *use_gzip_sz;
701 char *use_comp_sz;
702 char *use_star_sz;
703 char *bootldr_str;
704 char *tape_device;
705 char *last_filelist_number;
706 char *broken_bios_sz;
707 char *cd_recovery_sz;
708 char *tape_size_sz;
709 char *devs_to_exclude;
710 char *use_lilo_sz;
711 char *value;
712 char *bootdev;
713
714
715
716 /*@ char ************************************************************** */
717 char ch = '\0';
718
719 /*@ long ********************************************************** */
720 long lines_in_filelist = 0;
721
722 /*@ int ************************************************************* */
723 int res = 0;
724 long estimated_total_noof_slices = 0;
725
726 assert(bkpinfo != NULL);
727 command = malloc(1200);
728 malloc_string(tmp);
729 malloc_string(scratchdir);
730 malloc_string(use_lzo_sz);
731 malloc_string(use_gzip_sz);
732 malloc_string(use_star_sz);
733 malloc_string(use_comp_sz);
734 malloc_string(bootldr_str);
735 malloc_string(tape_device);
736 malloc_string(last_filelist_number);
737 malloc_string(broken_bios_sz);
738 malloc_string(cd_recovery_sz);
739 malloc_string(tape_size_sz);
740 malloc_string(devs_to_exclude);
741 malloc_string(use_lilo_sz); /* BCO: shared between LILO/ELILO */
742 malloc_string(value);
743 malloc_string(bootdev);
744
745 strcpy(scratchdir, bkpinfo->scratchdir);
746 sprintf(tmp,
747 "echo '%s' | tr -s ' ' '\n' | grep -E '^/dev/.*$' | tr -s '\n' ' ' | awk '{print $0\"\\n\";}'",
748 bkpinfo->exclude_paths);
749 strcpy(devs_to_exclude, call_program_and_get_last_line_of_output(tmp));
750 sprintf(tmp, "devs_to_exclude = '%s'", devs_to_exclude);
751 log_msg(2, tmp);
752 mvaddstr_and_log_it(g_currentY, 0,
753 "Calling MINDI to create boot+data disks");
754 sprintf(tmp, "%s/filelist.full", bkpinfo->tmpdir);
755 if (!does_file_exist(tmp)) {
756 sprintf(tmp, "%s/tmpfs/filelist.full", bkpinfo->tmpdir);
757 if (!does_file_exist(tmp)) {
758 fatal_error
759 ("Cannot find filelist.full, so I cannot count its lines");
760 }
761 }
762 lines_in_filelist = count_lines_in_file(tmp);
763 sprintf(tmp, "%s/LAST-FILELIST-NUMBER", bkpinfo->tmpdir);
764 strcpy(last_filelist_number, last_line_of_file(tmp));
765 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
766 sprintf(tape_size_sz, "%ld", bkpinfo->media_size[1]);
767 strcpy(tape_device, bkpinfo->media_device);
768 } else {
769 tape_size_sz[0] = '\0';
770 tape_device[0] = '\0';
771 }
772 if (bkpinfo->use_lzo) {
773 strcpy(use_lzo_sz, "yes");
774 } else {
775 strcpy(use_lzo_sz, "no");
776 }
777 if (bkpinfo->use_gzip) {
778 strcpy(use_gzip_sz, "yes");
779 } else {
780 strcpy(use_gzip_sz, "no");
781 }
782 if (bkpinfo->use_star) {
783 strcpy(use_star_sz, "yes");
784 } else {
785 strcpy(use_star_sz, "no");
786 }
787
788 if (bkpinfo->compression_level > 0) {
789 strcpy(use_comp_sz, "yes");
790 } else {
791 strcpy(use_comp_sz, "no");
792 }
793
794 strcpy(broken_bios_sz, "yes"); /* assume so */
795 if (g_cd_recovery) {
796 strcpy(cd_recovery_sz, "yes");
797 } else {
798 strcpy(cd_recovery_sz, "no");
799 }
800 if (bkpinfo->make_cd_use_lilo) {
801 strcpy(use_lilo_sz, "yes");
802 } else {
803 strcpy(use_lilo_sz, "no");
804 }
805
806 if (!bkpinfo->nonbootable_backup
807 && (bkpinfo->boot_loader == '\0'
808 || bkpinfo->boot_device[0] == '\0')) {
809
810#ifdef __FreeBSD__
811 strcpy(bootdev, call_program_and_get_last_line_of_output
812 ("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
813 if (!bootdev[0]) {
814 strcpy(bootdev, call_program_and_get_last_line_of_output
815 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'"));
816 }
817#else
818 strcpy(bootdev, call_program_and_get_last_line_of_output
819 ("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
820 if (strstr(bootdev, "/dev/cciss/")) {
821 strcpy(bootdev, call_program_and_get_last_line_of_output
822 ("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | cut -dp -f1"));
823 }
824 if (!bootdev[0]) {
825 strcpy(bootdev, call_program_and_get_last_line_of_output
826 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'"));
827 if (strstr(bootdev, "/dev/cciss/")) {
828 strcpy(bootdev, call_program_and_get_last_line_of_output
829 ("mount | grep ' / ' | head -1 | cut -d' ' -f1 | cut -dp -f1"));
830 }
831 }
832#endif
833 if (bootdev[0])
834 ch = which_boot_loader(bootdev);
835 else
836 ch = 'U';
837 if (bkpinfo->boot_loader != '\0') {
838 sprintf(tmp, "User specified boot loader. It is '%c'.",
839 bkpinfo->boot_loader);
840 log_msg(2, tmp);
841 } else {
842 bkpinfo->boot_loader = ch;
843 }
844 if (bkpinfo->boot_device[0] != '\0') {
845 sprintf(tmp, "User specified boot device. It is '%s'.",
846 bkpinfo->boot_device);
847 log_msg(2, tmp);
848 } else {
849 strcpy(bkpinfo->boot_device, bootdev);
850 }
851 }
852
853 if (
854#ifdef __FreeBSD__
855 bkpinfo->boot_loader != 'B' && bkpinfo->boot_loader != 'D' &&
856#endif
857#ifdef __IA64__
858 bkpinfo->boot_loader != 'E' &&
859#endif
860 bkpinfo->boot_loader != 'L' && bkpinfo->boot_loader != 'G'
861 && bkpinfo->boot_loader != 'R'
862 && !bkpinfo->nonbootable_backup) {
863 fatal_error
864 ("Please specify your boot loader and device, e.g. -l GRUB -f /dev/hda. Type 'man mondoarchive' to read the manual.");
865 }
866 if (bkpinfo->boot_loader == 'L') {
867 strcpy(bootldr_str, "LILO");
868 if (!does_file_exist("/etc/lilo.conf")) {
869 fatal_error
870 ("The de facto standard location for your boot loader's config file is /etc/lilo.conf but I cannot find it there. What is wrong with your Linux distribution?");
871 }
872 } else if (bkpinfo->boot_loader == 'G') {
873 strcpy(bootldr_str, "GRUB");
874 if (!does_file_exist("/etc/grub.conf")
875 && does_file_exist("/boot/grub/grub.conf")) {
876 run_program_and_log_output
877 ("ln -sf /boot/grub/grub.conf /etc/grub.conf", 5);
878 }
879 /* Detect Debian's grub config file */
880 else if (!does_file_exist("/etc/grub.conf")
881 && does_file_exist("/boot/grub/menu.lst")) {
882 run_program_and_log_output
883 ("ln -s /boot/grub/menu.lst /etc/grub.conf", 5);
884 }
885 if (!does_file_exist("/etc/grub.conf")) {
886 fatal_error
887 ("The de facto standard location for your boot loader's config file is /etc/grub.conf but I cannot find it there. What is wrong with your Linux distribution? Try 'ln -s /boot/grub/menu.lst /etc/grub.conf'...");
888 }
889 } else if (bkpinfo->boot_loader == 'E') {
890 strcpy(bootldr_str, "ELILO");
891 /* BCO: fix it for SuSE, Debian, Mandrake, ... */
892 if (!does_file_exist("/etc/elilo.conf")
893 && does_file_exist("/boot/efi/efi/redhat/elilo.conf")) {
894 run_program_and_log_output
895 ("ln -sf /boot/efi/efi/redhat/elilo.conf /etc/elilo.conf",
896 5);
897 }
898 if (!does_file_exist("/etc/elilo.conf")) {
899 fatal_error
900 ("The de facto mondo standard location for your boot loader's config file is /etc/elilo.conf but I cannot find it there. What is wrong with your Linux distribution? Try finding it under /boot/efi and do 'ln -s /boot/efi/..../elilo.conf /etc/elilo.conf'");
901 }
902 } else if (bkpinfo->boot_loader == 'R') {
903 strcpy(bootldr_str, "RAW");
904 }
905#ifdef __FreeBSD__
906 else if (bkpinfo->boot_loader == 'D') {
907 strcpy(bootldr_str, "DD");
908 }
909
910 else if (bkpinfo->boot_loader == 'B') {
911 strcpy(bootldr_str, "BOOT0");
912 }
913#endif
914 else {
915 strcpy(bootldr_str, "unknown");
916 }
917 sprintf(tmp, "Your boot loader is %s and it boots from %s",
918 bootldr_str, bkpinfo->boot_device);
919 log_to_screen(tmp);
920 sprintf(tmp, "%s/BOOTLOADER.DEVICE", bkpinfo->tmpdir);
921 if (write_one_liner_data_file(tmp, bkpinfo->boot_device)) {
922 log_msg(1, "%ld: Unable to write one-liner boot device", __LINE__);
923 }
924 switch (bkpinfo->backup_media_type) {
925 case cdr:
926 strcpy(value, "cdr");
927 break;
928 case cdrw:
929 strcpy(value, "cdrw");
930 break;
931 case cdstream:
932 strcpy(value, "cdstream");
933 break;
934 case tape:
935 strcpy(value, "tape");
936 break;
937 case udev:
938 strcpy(value, "udev");
939 break;
940 case iso:
941 strcpy(value, "iso");
942 break;
943 case nfs:
944 strcpy(value, "nfs");
945 break;
946 case dvd:
947 strcpy(value, "dvd");
948 break;
949 default:
950 fatal_error("Unknown backup_media_type");
951 }
952 sprintf(tmp, "%s/BACKUP-MEDIA-TYPE", bkpinfo->tmpdir);
953 if (write_one_liner_data_file(tmp, value)) {
954 res++;
955 log_msg(1, "%ld: Unable to write one-liner backup-media-type",
956 __LINE__);
957 }
958 log_to_screen(bkpinfo->tmpdir);
959 sprintf(tmp, "%s/BOOTLOADER.NAME", bkpinfo->tmpdir);
960 if (write_one_liner_data_file(tmp, bootldr_str)) {
961 res++;
962 log_msg(1, "%ld: Unable to write one-liner bootloader.name",
963 __LINE__);
964 }
965 sprintf(tmp, "%s/DIFFERENTIAL", bkpinfo->tmpdir);
966 if (bkpinfo->differential) {
967 res += write_one_liner_data_file(tmp, "1");
968 } else {
969 res += write_one_liner_data_file(tmp, "0");
970 }
971
972 if (g_getfattr) {
973 asprintf(&tmp1, "%s/XATTR", bkpinfo->tmpdir);
974 if (write_one_liner_data_file(tmp1, "TRUE")) {
975 log_msg(1, "%ld: Unable to write one-liner XATTR",
976 __LINE__);
977 }
978 paranoid_free(tmp1);
979 }
980 if (g_getfacl) {
981 asprintf(&tmp1, "%s/ACL", bkpinfo->tmpdir);
982 if (write_one_liner_data_file(tmp1, "TRUE")) {
983 log_msg(1, "%ld: Unable to write one-liner ACL",
984 __LINE__);
985 }
986 paranoid_free(tmp1);
987 }
988
989 estimated_total_noof_slices =
990 size_of_all_biggiefiles_K(bkpinfo) / bkpinfo->optimal_set_size + 1;
991/* add nfs stuff here? */
992 sprintf(command, "mkdir -p %s/images", bkpinfo->scratchdir);
993 if (system(command)) {
994 res++;
995 log_OS_error("Unable to make images directory");
996 }
997 sprintf(command, "mkdir -p %s%s", bkpinfo->scratchdir, MNT_FLOPPY);
998 if (system(command)) {
999 res++;
1000 log_OS_error("Unable to make mnt floppy directory");
1001 }
1002 sprintf(tmp, "BTW, I'm telling Mindi your kernel is '%s'",
1003 bkpinfo->kernel_path);
1004
1005 log_msg(1, "lines_in_filelist = %ld", lines_in_filelist);
1006
1007 sprintf(command,
1008/* "mindi --custom 2=%s 3=%s/images 4=\"%s\" 5=\"%s\" \
10096=\"%s\" 7=%ld 8=\"%s\" 9=\"%s\" 10=\"%s\" \
101011=\"%s\" 12=%s 13=%ld 14=\"%s\" 15=\"%s\" 16=\"%s\" 17=\"%s\" 18=%ld 19=%d",*/
1011 "mindi --custom %s %s/images '%s' '%s' \
1012'%s' %ld '%s' '%s' '%s' \
1013'%s' %s %ld '%s' '%s' '%s' '%s' %ld %d '%s'", bkpinfo->tmpdir, // parameter #2
1014 bkpinfo->scratchdir, // parameter #3
1015 bkpinfo->kernel_path, // parameter #4
1016 tape_device, // parameter #5
1017 tape_size_sz, // parameter #6
1018 lines_in_filelist, // parameter #7 (INT)
1019 use_lzo_sz, // parameter #8
1020 cd_recovery_sz, // parameter #9
1021 bkpinfo->image_devs, // parameter #10
1022 broken_bios_sz, // parameter #11
1023 last_filelist_number, // parameter #12 (STRING)
1024 estimated_total_noof_slices, // parameter #13 (INT)
1025 devs_to_exclude, // parameter #14
1026 use_comp_sz, // parameter #15
1027 use_lilo_sz, // parameter #16
1028 use_star_sz, // parameter #17
1029 bkpinfo->internal_tape_block_size, // parameter #18 (LONG)
1030 bkpinfo->differential, // parameter #19 (INT)
1031 use_gzip_sz); // parameter #20 (STRING)
1032
1033// Watch it! This next line adds a parameter...
1034 if (bkpinfo->nonbootable_backup) {
1035 strcat(command, " NONBOOTABLE");
1036 }
1037 log_msg(2, command);
1038
1039// popup_and_OK("Pausing");
1040
1041 res =
1042 run_program_and_log_to_screen(command,
1043 "Generating boot+data disks");
1044 if (bkpinfo->nonbootable_backup) {
1045 res = 0;
1046 } // hack
1047 if (!res) {
1048 log_to_screen("Boot+data disks were created OK");
1049 sprintf(command, "cp -f %s/images/mindi.iso %s/mondorescue.iso",
1050 bkpinfo->scratchdir, MINDI_CACHE);
1051 log_msg(2, command);
1052 run_program_and_log_output(command, FALSE);
1053 if (bkpinfo->nonbootable_backup) {
1054 sprintf(command, "cp -f %s/all.tar.gz %s/images",
1055 bkpinfo->tmpdir, bkpinfo->scratchdir);
1056 if (system(command)) {
1057 fatal_error("Unable to create temporary duff tarball");
1058 }
1059 }
1060 sprintf(command, "cp -f %s/mindi-*oot*.img %s/images",
1061 bkpinfo->tmpdir, bkpinfo->scratchdir);
1062 sprintf(tmp, "cp -f %s/images/all.tar.gz %s", bkpinfo->scratchdir,
1063 bkpinfo->tmpdir);
1064 if (system(tmp)) {
1065 fatal_error("Cannot find all.tar.gz in tmpdir");
1066 }
1067 if (res) {
1068 mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
1069 } else {
1070 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1071 }
1072 } else {
1073 log_to_screen("Mindi failed to create your boot+data disks.");
1074 strcpy(command, "grep 'Fatal error' /var/log/mindi.log");
1075 strcpy(tmp, call_program_and_get_last_line_of_output(command));
1076 if (strlen(tmp) > 1) {
1077 popup_and_OK(tmp);
1078 }
1079 }
1080 paranoid_free(tmp);
1081 paranoid_free(use_lzo_sz);
1082 paranoid_free(use_gzip_sz);
1083 paranoid_free(scratchdir);
1084 paranoid_free(use_comp_sz);
1085 paranoid_free(bootldr_str);
1086 paranoid_free(tape_device);
1087 paranoid_free(last_filelist_number);
1088 paranoid_free(broken_bios_sz);
1089 paranoid_free(cd_recovery_sz);
1090 paranoid_free(tape_size_sz);
1091 paranoid_free(devs_to_exclude);
1092 paranoid_free(use_lilo_sz);
1093 paranoid_free(value);
1094 paranoid_free(bootdev);
1095 paranoid_free(command);
1096 paranoid_free(use_star_sz);
1097 return (res);
1098}
1099
1100
1101
1102/**
1103 * Maximum number of filesets allowed in this function.
1104 */
1105#define MAX_NOOF_SETS_HERE 32767
1106
1107/**
1108 * Offset of the bkpinfo pointer (in bytes) from the
1109 * buffer passed to create_afio_files_in_background.
1110 */
1111#define BKPINFO_LOC_OFFSET (16+MAX_NOOF_SETS_HERE/8+16)
1112
1113/**
1114 * Main function for each @c afio thread.
1115 * @param inbuf A transfer block containing:
1116 * - @c p_last_set_archived: [offset 0] pointer to an @c int
1117 * containing the last set archived.
1118 * - @c p_archival_threads_running: [offset 4] pointer to an @c int
1119 * containing the number of archival threads currently running.
1120 * - @c p_next_set_to_archive: [offset 8] pointer to an @c int containing
1121 * the next set that should be archived.
1122 * - @c p_list_of_fileset_flags: [offset 12] @c char pointer pointing to a
1123 * bit array, where each bit corresponds to a filelist (1=needs
1124 * to be archived, 0=archived).
1125 * - @c bkpinfo: [offset BKPINFO_LOC_OFFSET] pointer to backup information
1126 * structure. Fields used:
1127 * - @c tmpdir
1128 * - @c zip_suffix
1129 *
1130 * Any of the above may be modified by the caller at any time.
1131 *
1132 * @bug Assumes @c int pointers are 4 bytes.
1133 * @see archive_this_fileset
1134 * @see make_afioballs_and_images
1135 * @return NULL, always.
1136 * @ingroup LLarchiveGroup
1137 */
1138void *create_afio_files_in_background(void *inbuf)
1139{
1140 long int archiving_set_no;
1141 char *archiving_filelist_fname;
1142 char *archiving_afioball_fname;
1143 char *curr_xattr_list_fname = NULL;
1144 char *curr_acl_list_fname;
1145
1146 struct s_bkpinfo *bkpinfo;
1147 char *tmp;
1148 int res = 0, retval = 0;
1149 int *p_archival_threads_running;
1150 int *p_last_set_archived;
1151 int *p_next_set_to_archive;
1152 char *p_list_of_fileset_flags;
1153 int this_thread_no = g_current_thread_no++;
1154
1155 malloc_string(curr_xattr_list_fname);
1156 malloc_string(curr_acl_list_fname);
1157 malloc_string(archiving_filelist_fname);
1158 malloc_string(archiving_afioball_fname);
1159 malloc_string(tmp);
1160 p_last_set_archived = (int *) inbuf;
1161 p_archival_threads_running = (int *) (inbuf + 4);
1162 p_next_set_to_archive = (int *) (inbuf + 8);
1163 p_list_of_fileset_flags = (char *) (inbuf + 12);
1164 bkpinfo = (struct s_bkpinfo *) (inbuf + BKPINFO_LOC_OFFSET);
1165
1166 sprintf(archiving_filelist_fname, FILELIST_FNAME_RAW_SZ,
1167 bkpinfo->tmpdir, 0L);
1168 for (archiving_set_no = 0; does_file_exist(archiving_filelist_fname);
1169 sprintf(archiving_filelist_fname, FILELIST_FNAME_RAW_SZ,
1170 bkpinfo->tmpdir, archiving_set_no)) {
1171 if (g_exiting) {
1172 fatal_error("Execution run aborted (pthread)");
1173 }
1174 if (archiving_set_no >= MAX_NOOF_SETS_HERE) {
1175 fatal_error
1176 ("Maximum number of filesets exceeded. Adjust MAX_NOOF_SETS_HERE, please.");
1177 }
1178 if (!semaphore_p()) {
1179 log_msg(3, "P sem failed (pid=%d)", (int) getpid());
1180 fatal_error("Cannot get semaphore P");
1181 }
1182 if (archiving_set_no < *p_next_set_to_archive) {
1183 archiving_set_no = *p_next_set_to_archive;
1184 }
1185 *p_next_set_to_archive = *p_next_set_to_archive + 1;
1186 if (!semaphore_v()) {
1187 fatal_error("Cannot get semaphore V");
1188 }
1189
1190 /* backup this set of files */
1191 sprintf(archiving_afioball_fname, AFIOBALL_FNAME_RAW_SZ,
1192 bkpinfo->tmpdir, archiving_set_no, bkpinfo->zip_suffix);
1193 sprintf(archiving_filelist_fname, FILELIST_FNAME_RAW_SZ,
1194 bkpinfo->tmpdir, archiving_set_no);
1195 if (!does_file_exist(archiving_filelist_fname)) {
1196 log_msg(3,
1197 "%s[%d:%d] - well, I would archive %d, except that it doesn't exist. I'll stop now.",
1198 FORTY_SPACES, getpid(), this_thread_no,
1199 archiving_set_no);
1200 break;
1201 }
1202
1203 sprintf(tmp, AFIOBALL_FNAME_RAW_SZ, bkpinfo->tmpdir,
1204 archiving_set_no - ARCH_BUFFER_NUM, bkpinfo->zip_suffix);
1205 if (does_file_exist(tmp)) {
1206 log_msg(4, "%s[%d:%d] - waiting for storer", FORTY_SPACES,
1207 getpid(), this_thread_no);
1208 while (does_file_exist(tmp)) {
1209 sleep(1);
1210 }
1211 log_msg(4, "[%d] - continuing", getpid());
1212 }
1213
1214 log_msg(4, "%s[%d:%d] - EXATing %d...", FORTY_SPACES, getpid(),
1215 this_thread_no, archiving_set_no);
1216 if (g_getfattr) {
1217 sprintf(curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ,
1218 bkpinfo->tmpdir, archiving_set_no);
1219 get_fattr_list(archiving_filelist_fname, curr_xattr_list_fname);
1220 }
1221 if (g_getfacl) {
1222 sprintf(curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ,
1223 bkpinfo->tmpdir, archiving_set_no);
1224 get_acl_list(archiving_filelist_fname, curr_acl_list_fname);
1225 }
1226
1227 log_msg(4, "%s[%d:%d] - archiving %d...", FORTY_SPACES, getpid(),
1228 this_thread_no, archiving_set_no);
1229 res =
1230 archive_this_fileset(bkpinfo, archiving_filelist_fname,
1231 archiving_afioball_fname,
1232 archiving_set_no);
1233 retval += res;
1234
1235 if (res) {
1236 sprintf(tmp,
1237 "Errors occurred while archiving set %ld. Please review logs.",
1238 archiving_set_no);
1239 log_to_screen(tmp);
1240 }
1241 if (!semaphore_p()) {
1242 fatal_error("Cannot get semaphore P");
1243 }
1244
1245 set_bit_N_of_array(p_list_of_fileset_flags, archiving_set_no, 5);
1246
1247 if (*p_last_set_archived < archiving_set_no) {
1248 *p_last_set_archived = archiving_set_no;
1249 } // finished archiving this one
1250
1251 if (!semaphore_v()) {
1252 fatal_error("Cannot get semaphore V");
1253 }
1254 log_msg(4, "%s[%d:%d] - archived %d OK", FORTY_SPACES, getpid(),
1255 this_thread_no, archiving_set_no);
1256 archiving_set_no++;
1257 }
1258 if (!semaphore_p()) {
1259 fatal_error("Cannot get semaphore P");
1260 }
1261 (*p_archival_threads_running)--;
1262 if (!semaphore_v()) {
1263 fatal_error("Cannot get semaphore V");
1264 }
1265 log_msg(3, "%s[%d:%d] - exiting", FORTY_SPACES, getpid(),
1266 this_thread_no);
1267 paranoid_free(archiving_filelist_fname);
1268 paranoid_free(archiving_afioball_fname);
1269 paranoid_free(curr_xattr_list_fname);
1270 paranoid_free(curr_acl_list_fname);
1271 paranoid_free(tmp);
1272 pthread_exit(NULL);
1273}
1274
1275
1276
1277
1278
1279/**
1280 * Finalize the backup.
1281 * For streaming backups, this writes the closing block
1282 * to the stream. For CD-based backups, this creates
1283 * the final ISO image.
1284 * @param bkpinfo The backup information structure, used only
1285 * for the @c backup_media_type.
1286 * @ingroup MLarchiveGroup
1287 */
1288int do_that_final_phase(struct s_bkpinfo *bkpinfo)
1289{
1290
1291 /*@ int ************************************** */
1292 int res = 0;
1293 int retval = 0;
1294
1295 /*@ buffers ********************************** */
1296
1297 assert(bkpinfo != NULL);
1298 mvaddstr_and_log_it(g_currentY, 0,
1299 "Writing any remaining data to media ");
1300
1301 log_msg(1, "Closing tape/CD ... ");
1302 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type))
1303 /* write tape/cdstream */
1304 {
1305 closeout_tape(bkpinfo);
1306 } else
1307 /* write final ISO */
1308 {
1309 res = write_final_iso_if_necessary(bkpinfo);
1310 retval += res;
1311 if (res) {
1312 log_msg(1, "write_final_iso_if_necessary returned an error");
1313 }
1314 }
1315 log_msg(2, "Fork is exiting ... ");
1316
1317 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1318
1319 /* final stuff */
1320 if (retval) {
1321 mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
1322 } else {
1323 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1324 }
1325
1326 return (retval);
1327}
1328
1329
1330/**
1331 * Initialize the backup.
1332 * Does the following:
1333 * - Sets up the serial number.
1334 * - For streaming backups, opens the tape stream and writes the data disks
1335 * and backup headers.
1336 * - For CD-based backups, wipes the ISOs in the target directory.
1337 *
1338 * @param bkpinfo The backup information structure. Fields used:
1339 * - @c backup_media_type
1340 * - @c cdrw_speed
1341 * - @c prefix
1342 * - @c isodir
1343 * - @c media_device
1344 * - @c scratchdir
1345 * - @c tmpdir
1346 * @return The number of errors encountered (0 for success).
1347 * @ingroup MLarchiveGroup
1348 */
1349int do_that_initial_phase(struct s_bkpinfo *bkpinfo)
1350{
1351 /*@ int *************************************** */
1352 int retval = 0;
1353
1354 /*@ buffers *********************************** */
1355 char *command, *tmpfile, *data_disks_file;
1356
1357 assert(bkpinfo != NULL);
1358 malloc_string(command);
1359 malloc_string(tmpfile);
1360 malloc_string(data_disks_file);
1361 sprintf(data_disks_file, "%s/all.tar.gz", bkpinfo->tmpdir);
1362
1363 snprintf(g_serial_string, MAX_STR_LEN - 1,
1364 call_program_and_get_last_line_of_output("dd \
1365if=/dev/urandom bs=16 count=1 2> /dev/null | \
1366hexdump | tr -s ' ' '0' | head -n1"));
1367 strip_spaces(g_serial_string);
1368 strcat(g_serial_string, "...word.");
1369 log_msg(2, "g_serial_string = '%s'", g_serial_string);
1370 assert(strlen(g_serial_string) < MAX_STR_LEN);
1371
1372 sprintf(tmpfile, "%s/archives/SERIAL-STRING", bkpinfo->scratchdir);
1373 if (write_one_liner_data_file(tmpfile, g_serial_string)) {
1374 log_msg(1, "%ld: Failed to write serial string", __LINE__);
1375 }
1376
1377 mvaddstr_and_log_it(g_currentY, 0, "Preparing to archive your data");
1378 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1379 if (bkpinfo->backup_media_type == cdstream) {
1380 openout_cdstream(bkpinfo->media_device, bkpinfo->cdrw_speed);
1381 } else {
1382 openout_tape(bkpinfo->media_device, bkpinfo->internal_tape_block_size); /* sets g_tape_stream */
1383 }
1384 if (!g_tape_stream) {
1385 fatal_error("Cannot open backup (streaming) device");
1386 }
1387 log_msg(1, "Backup (stream) opened OK");
1388 write_data_disks_to_stream(data_disks_file);
1389 } else {
1390 log_msg(1, "Backing up to CD's");
1391 }
1392
1393 sprintf(command, "rm -f %s/%s/%s-[1-9]*.iso", bkpinfo->isodir,
1394 bkpinfo->nfs_remote_dir, bkpinfo->prefix);
1395 paranoid_system(command);
1396 wipe_archives(bkpinfo->scratchdir);
1397 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1398 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1399 write_header_block_to_stream((off_t)0, "start-of-tape",
1400 BLK_START_OF_TAPE);
1401 write_header_block_to_stream((off_t)0, "start-of-backup",
1402 BLK_START_OF_BACKUP);
1403 }
1404 paranoid_free(command);
1405 paranoid_free(tmpfile);
1406 paranoid_free(data_disks_file);
1407 return (retval);
1408}
1409
1410
1411/**
1412 * Calls floppy-formatting @c cmd and tracks its progress if possible.
1413 *
1414 * @param cmd The command to run (e.g. @c fdformat @c /dev/fd0).
1415 * @param title The human-friendly description of the floppy you are writing.
1416 * This will be used as the title in the progress bar window. Example:
1417 * "Formatting disk /dev/fd0".
1418 * @see format_disk
1419 * @return The exit code of fdformat/superformat.
1420 */
1421int format_disk_SUB(char *cmd, char *title)
1422{
1423
1424 /*@ int *************************************************************** */
1425 int res = 0;
1426 int percentage = 0;
1427 int maxtracks = 0;
1428 int trackno = 0;
1429 int last_trkno = 0;
1430
1431 /*@ buffers *********************************************************** */
1432 char *command;
1433 char *tempfile;
1434
1435 /*@ pointers ********************************************************** */
1436 FILE *pin;
1437
1438 assert_string_is_neither_NULL_nor_zerolength(cmd);
1439 assert_string_is_neither_NULL_nor_zerolength(title);
1440
1441 malloc_string(command);
1442 malloc_string(tempfile);
1443#ifdef __FreeBSD__
1444/* Ugh. FreeBSD fdformat prints out this pretty progress indicator that's
1445 impossible to parse. It looks like
1446 VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVF-------------------
1447 where V means verified, E means error, F means formatted, and - means
1448 not done yet.
1449*/
1450 return (run_program_and_log_to_screen(cmd, title));
1451#endif
1452
1453/* if Debian then do bog-standard superformat; don't be pretty */
1454 if (strstr(cmd, "superformat")) {
1455 return (run_program_and_log_to_screen(cmd, title));
1456 }
1457/* if not Debian then go ahead & use fdformat */
1458 strcpy(tempfile,
1459 call_program_and_get_last_line_of_output
1460 ("mktemp -q /tmp/mondo.XXXXXXXX"));
1461 sprintf(command, "%s >> %s 2>> %s; rm -f %s", cmd, tempfile, tempfile,
1462 tempfile);
1463 log_msg(3, command);
1464 open_evalcall_form(title);
1465 if (!(pin = popen(command, "r"))) {
1466 log_OS_error("fmt err");
1467 return (1);
1468 }
1469 if (strstr(command, "1722")) {
1470 maxtracks = 82;
1471 } else {
1472 maxtracks = 80;
1473 }
1474 for (sleep(1); does_file_exist(tempfile); sleep(1)) {
1475 trackno = get_trackno_from_logfile(tempfile);
1476 if (trackno < 0 || trackno > 80) {
1477 log_msg(1, "Weird track#");
1478 continue;
1479 }
1480 percentage = trackno * 100 / maxtracks;
1481 if (trackno <= 5 && last_trkno > 40) {
1482 close_evalcall_form();
1483 strcpy(title, "Verifying format");
1484 open_evalcall_form(title);
1485 }
1486 last_trkno = trackno;
1487 update_evalcall_form(percentage);
1488 }
1489 close_evalcall_form();
1490 if (pclose(pin)) {
1491 res++;
1492 log_OS_error("Unable to pclose");
1493 }
1494 unlink(tempfile);
1495 paranoid_free(command);
1496 paranoid_free(tempfile);
1497 return (res);
1498}
1499
1500/**
1501 * Wrapper around @c format_disk_SUB().
1502 * This function calls @c format_disk_SUB() with a @c device of its @c device
1503 * parameter and a @c title of Formatting disk @c device. If the format
1504 * fails, the user will be given the option of retrying.
1505 *
1506 * @param device The floppy drive to write to.
1507 * @see format_disk_SUB
1508 * @return The exit code of fdformat/superformat.
1509 * @ingroup deviceGroup
1510 */
1511int format_disk(char *device)
1512{
1513
1514 /*@ int ************************************************************** */
1515 int res = 0;
1516
1517 /*@ buffer *********************************************************** */
1518 char *command;
1519 char *title;
1520
1521
1522 assert_string_is_neither_NULL_nor_zerolength(device);
1523 malloc_string(title);
1524 command = malloc(1000);
1525 if (!system("which superformat > /dev/null 2> /dev/null")) {
1526 sprintf(command, "superformat %s", device);
1527 } else {
1528#ifdef __FreeBSD__
1529 sprintf(command, "fdformat -y %s", device);
1530#else
1531 sprintf(command, "fdformat %s", device);
1532#endif
1533 }
1534 sprintf(title, "Formatting disk %s", device);
1535 while ((res = format_disk_SUB(command, title))) {
1536 if (!ask_me_yes_or_no("Failed to format disk. Retry?")) {
1537 return (res);
1538 }
1539 }
1540 paranoid_free(title);
1541 paranoid_free(command);
1542 return (res);
1543}
1544
1545/**
1546 * Get the <tt>N</tt>th bit of @c array.
1547 * @param array The bit-array (as a @c char pointer).
1548 * @param N The number of the bit you want.
1549 * @return TRUE (bit is set) or FALSE (bit is not set).
1550 * @see set_bit_N_of_array
1551 * @ingroup utilityGroup
1552 */
1553bool get_bit_N_of_array(char *array, int N)
1554{
1555 int element_number;
1556 int bit_number;
1557 int mask;
1558
1559 element_number = N / 8;
1560 bit_number = N % 8;
1561 mask = 1 << bit_number;
1562 if (array[element_number] & mask) {
1563 return (TRUE);
1564 } else {
1565 return (FALSE);
1566 }
1567}
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577/**
1578 * @addtogroup LLarchiveGroup
1579 * @{
1580 */
1581/**
1582 * Start up threads to archive your files.
1583 *
1584 * This function starts @c ARCH_THREADS threads,
1585 * each starting execution in @c create_afio_files_in_background().
1586 * Each thread will archive individual filesets, based on the
1587 * pointers passed to it and continually updated, until all files
1588 * have been backed up. This function coordinates the threads
1589 * and copies their output to the @c scratchdir.
1590 *
1591 * @param bkpinfo The backup information structure. Fields used:
1592 * - @c backup_media_type
1593 * - @c scratchdir
1594 * - @c tmpdir
1595 * - @c zip_suffix
1596 *
1597 * @return The number of errors encountered (0 for success)
1598 */
1599int make_afioballs_and_images(struct s_bkpinfo *bkpinfo)
1600{
1601
1602 /*@ int ************************************************** */
1603 int retval = 0;
1604 long int storing_set_no = 0;
1605 int res = 0;
1606 bool done_storing = FALSE;
1607 char *result_str;
1608 char *transfer_block;
1609 void *vp;
1610 void **pvp;
1611
1612 /*@ buffers ********************************************** */
1613 char *storing_filelist_fname;
1614 char *storing_afioball_fname;
1615 char *tmp;
1616 char *media_usage_comment;
1617 pthread_t archival_thread[ARCH_THREADS];
1618 char *p_list_of_fileset_flags;
1619 int *p_archival_threads_running;
1620 int *p_last_set_archived;
1621 int *p_next_set_to_archive;
1622 int noof_threads;
1623 int i;
1624 char *curr_xattr_list_fname = NULL;
1625 char *curr_acl_list_fname;
1626 int misc_counter_that_is_not_important = 0;
1627
1628 log_msg(8, "here");
1629 assert(bkpinfo != NULL);
1630 tmp = malloc(MAX_STR_LEN * 2);
1631 malloc_string(result_str);
1632 malloc_string(curr_xattr_list_fname);
1633 malloc_string(curr_acl_list_fname);
1634 malloc_string(storing_filelist_fname);
1635 malloc_string(media_usage_comment);
1636 malloc_string(storing_afioball_fname);
1637 transfer_block =
1638 malloc(sizeof(struct s_bkpinfo) + BKPINFO_LOC_OFFSET + 64);
1639 memset((void *) transfer_block, 0,
1640 sizeof(struct s_bkpinfo) + BKPINFO_LOC_OFFSET + 64);
1641 p_last_set_archived = (int *) transfer_block;
1642 p_archival_threads_running = (int *) (transfer_block + 4);
1643 p_next_set_to_archive = (int *) (transfer_block + 8);
1644 p_list_of_fileset_flags = (char *) (transfer_block + 12);
1645 memcpy((void *) (transfer_block + BKPINFO_LOC_OFFSET),
1646 (void *) bkpinfo, sizeof(struct s_bkpinfo));
1647 pvp = &vp;
1648 vp = (void *) result_str;
1649 *p_archival_threads_running = 0;
1650 *p_last_set_archived = -1;
1651 *p_next_set_to_archive = 0;
1652 sprintf(tmp, "%s/archives/filelist.full", bkpinfo->scratchdir);
1653 log_to_screen("Archiving regular files");
1654 log_msg(5, "Go, Shorty. It's your birthday.");
1655 open_progress_form("Backing up filesystem",
1656 "I am backing up your live filesystem now.",
1657 "Please wait. This may take a couple of hours.",
1658 "Working...",
1659 get_last_filelist_number(bkpinfo) + 1);
1660
1661 log_msg(5, "We're gonna party like it's your birthday.");
1662
1663 srand((unsigned int) getpid());
1664 g_sem_key = 1234 + random() % 30000;
1665 if ((g_sem_id =
1666 semget((key_t) g_sem_key, 1,
1667 IPC_CREAT | S_IREAD | S_IWRITE)) == -1) {
1668 fatal_error("MABAI - unable to semget");
1669 }
1670 if (!set_semvalue()) {
1671 fatal_error("Unable to init semaphore");
1672 } // initialize semaphore
1673 for (noof_threads = 0; noof_threads < ARCH_THREADS; noof_threads++) {
1674 log_msg(8, "Creating thread #%d", noof_threads);
1675 (*p_archival_threads_running)++;
1676 if ((res =
1677 pthread_create(&archival_thread[noof_threads], NULL,
1678 create_afio_files_in_background,
1679 (void *) transfer_block))) {
1680 fatal_error("Unable to create an archival thread");
1681 }
1682 }
1683
1684 log_msg(8, "About to enter while() loop");
1685 while (!done_storing) {
1686 if (g_exiting) {
1687 fatal_error("Execution run aborted (main loop)");
1688 }
1689 if (*p_archival_threads_running == 0
1690 && *p_last_set_archived == storing_set_no - 1) {
1691 log_msg(2,
1692 "No archival threads are running. The last stored set was %d and I'm looking for %d. Take off your make-up; the party's over... :-)",
1693 *p_last_set_archived, storing_set_no);
1694 done_storing = TRUE;
1695 } else
1696 if (!get_bit_N_of_array
1697 (p_list_of_fileset_flags, storing_set_no)) {
1698 misc_counter_that_is_not_important =
1699 (misc_counter_that_is_not_important + 1) % 5;
1700 if (!misc_counter_that_is_not_important) {
1701 update_progress_form(media_usage_comment);
1702 }
1703 sleep(1);
1704 } else
1705 // store set N
1706 {
1707 sprintf(storing_filelist_fname, FILELIST_FNAME_RAW_SZ,
1708 bkpinfo->tmpdir, storing_set_no);
1709 sprintf(storing_afioball_fname, AFIOBALL_FNAME_RAW_SZ,
1710 bkpinfo->tmpdir, storing_set_no, bkpinfo->zip_suffix);
1711 if (g_getfattr) {
1712 sprintf(curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ,
1713 bkpinfo->tmpdir, storing_set_no);
1714 }
1715 if (g_getfacl) {
1716 sprintf(curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ,
1717 bkpinfo->tmpdir, storing_set_no);
1718 }
1719
1720 log_msg(2, "Storing set %d", storing_set_no);
1721 while (!does_file_exist(storing_filelist_fname)
1722 || !does_file_exist(storing_afioball_fname)) {
1723 log_msg(2,
1724 "Warning - either %s or %s doesn't exist yet. I'll pause 5 secs.",
1725 storing_filelist_fname, storing_afioball_fname);
1726 sleep(5);
1727 }
1728 strcpy(media_usage_comment,
1729 percent_media_full_comment(bkpinfo));
1730 /* copy to CD (scratchdir) ... and an actual CD-R if necessary */
1731 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1732 register_in_tape_catalog(fileset, storing_set_no, -1,
1733 storing_afioball_fname);
1734 maintain_collection_of_recent_archives(bkpinfo->tmpdir,
1735 storing_afioball_fname);
1736 iamhere("Writing EXAT files");
1737 res +=
1738 write_EXAT_files_to_tape(bkpinfo,
1739 curr_xattr_list_fname,
1740 curr_acl_list_fname);
1741// archives themselves
1742 res +=
1743 move_files_to_stream(bkpinfo, storing_afioball_fname,
1744 NULL);
1745 } else {
1746 if (g_getfacl) {
1747 if (g_getfattr) {
1748 res = move_files_to_cd(bkpinfo, storing_filelist_fname,
1749 curr_xattr_list_fname,
1750 curr_acl_list_fname,
1751 storing_afioball_fname, NULL);
1752 } else {
1753 res = move_files_to_cd(bkpinfo, storing_filelist_fname,
1754 curr_acl_list_fname,
1755 storing_afioball_fname, NULL);
1756 }
1757 } else {
1758 if (g_getfattr) {
1759 res = move_files_to_cd(bkpinfo, storing_filelist_fname,
1760 curr_xattr_list_fname,
1761 storing_afioball_fname, NULL);
1762 } else {
1763 res = move_files_to_cd(bkpinfo, storing_filelist_fname,
1764 storing_afioball_fname, NULL);
1765 }
1766 }
1767 }
1768 retval += res;
1769 g_current_progress++;
1770 update_progress_form(media_usage_comment);
1771 if (res) {
1772 sprintf(tmp,
1773 "Failed to add archive %ld's files to CD dir\n",
1774 storing_set_no);
1775 log_to_screen(tmp);
1776 fatal_error
1777 ("Is your hard disk full? If not, please send the author the logfile.");
1778 }
1779 storing_set_no++;
1780 // sleep(2);
1781 }
1782 }
1783 close_progress_form();
1784
1785 sprintf(tmp, "Your regular files have been archived ");
1786 log_msg(2, "Joining background threads to foreground thread");
1787 for (i = 0; i < noof_threads; i++) {
1788 pthread_join(archival_thread[i], pvp);
1789 log_msg(3, "Thread %d of %d: closed OK", i + 1, noof_threads);
1790 }
1791 del_semvalue();
1792 log_msg(2, "Done.");
1793 if (retval) {
1794 strcat(tmp, "(with errors).");
1795 } else {
1796 strcat(tmp, "successfully.");
1797 }
1798 log_to_screen(tmp);
1799 paranoid_free(transfer_block);
1800 paranoid_free(result_str);
1801 paranoid_free(storing_filelist_fname);
1802 paranoid_free(media_usage_comment);
1803 paranoid_free(storing_afioball_fname);
1804 paranoid_free(curr_xattr_list_fname);
1805 paranoid_free(curr_acl_list_fname);
1806 return (retval);
1807}
1808
1809
1810void pause_for_N_seconds(int how_long, char *msg)
1811{
1812 int i;
1813 open_evalcall_form(msg);
1814 for (i = 0; i < how_long; i++) {
1815 update_evalcall_form((int) ((100.0 / (float) (how_long) * i)));
1816 sleep(1);
1817 }
1818 close_evalcall_form();
1819}
1820
1821
1822
1823
1824/**
1825 * Create an ISO image in @c destfile, from files in @c bkpinfo->scratchdir.
1826 *
1827 * @param bkpinfo The backup information structure. Fields used:
1828 * - @c backup_media_type
1829 * - @c call_after_iso
1830 * - @c call_before_iso
1831 * - @c call_burn_iso
1832 * - @c call_make_iso
1833 * - @c make_cd_use_lilo
1834 * - @c manual_cd_tray
1835 * - @c nonbootable_backup
1836 * - @c scratchdir
1837 *
1838 * @param destfile Where to put the generated ISO image.
1839 * @return The number of errors encountered (0 for success)
1840 */
1841int make_iso_fs(struct s_bkpinfo *bkpinfo, char *destfile)
1842{
1843 /*@ int ********************************************** */
1844 int retval = 0;
1845 int res;
1846
1847 /*@ buffers ****************************************** */
1848 char *tmp;
1849 char *old_pwd;
1850 char *result_sz;
1851 char *message_to_screen;
1852 char *sz_blank_disk;
1853 char *fnam;
1854 char *tmp2;
1855 char *tmp3;
1856 bool cd_is_mountable;
1857
1858 malloc_string(old_pwd);
1859 malloc_string(result_sz);
1860 malloc_string(message_to_screen);
1861 malloc_string(sz_blank_disk);
1862 malloc_string(fnam);
1863 tmp = malloc(1200);
1864 tmp2 = malloc(1200);
1865 tmp3 = malloc(1200);
1866 assert(bkpinfo != NULL);
1867 assert_string_is_neither_NULL_nor_zerolength(destfile);
1868
1869 sprintf(tmp, "%s/isolinux.bin", bkpinfo->scratchdir);
1870 sprintf(tmp2, "%s/isolinux.bin", bkpinfo->tmpdir);
1871 if (does_file_exist(tmp)) {
1872 sprintf(tmp3, "cp -f %s %s", tmp, tmp2);
1873 paranoid_system(tmp3);
1874 }
1875 if (!does_file_exist(tmp) && does_file_exist(tmp2)) {
1876 sprintf(tmp3, "cp -f %s %s", tmp2, tmp);
1877 paranoid_system(tmp3);
1878 }
1879 /*
1880 if (!does_file_exist(tmp))
1881 {
1882 log_msg (2, "Silly bug in Mindi.pl; workaround in progress...");
1883 strcpy(fnam, call_program_and_get_last_line_of_output("locate isolinux.bin | tail -n1"));
1884 if (strlen(fnam)>0 && does_file_exist(fnam))
1885 {
1886 sprintf(tmp, "cp -f %s %s", fnam, bkpinfo->scratchdir);
1887 res = run_program_and_log_output(tmp, FALSE);
1888 }
1889 else
1890 {
1891 res = 1;
1892 }
1893 if (res)
1894 {
1895 log_msg (2, "Could not work around silly bug in Mindi.pl - sorry! Isolinux.bin missing");
1896 }
1897 }
1898 */
1899 free(tmp2);
1900 free(tmp3);
1901 tmp2 = NULL;
1902 tmp3 = NULL;
1903 if (bkpinfo->backup_media_type == iso && bkpinfo->manual_cd_tray) {
1904 popup_and_OK("Please insert new media and press Enter.");
1905 }
1906
1907 log_msg(2, "make_iso_fs --- scratchdir=%s --- destfile=%s",
1908 bkpinfo->scratchdir, destfile);
1909 (void) getcwd(old_pwd, MAX_STR_LEN - 1);
1910 sprintf(tmp, "chmod 744 %s", bkpinfo->scratchdir);
1911 run_program_and_log_output(tmp, FALSE);
1912 chdir(bkpinfo->scratchdir);
1913
1914 if (bkpinfo->call_before_iso[0] != '\0') {
1915 sprintf(message_to_screen, "Running pre-ISO call for CD#%d",
1916 g_current_media_number);
1917 res =
1918 eval_call_to_make_ISO(bkpinfo, bkpinfo->call_before_iso,
1919 destfile, g_current_media_number,
1920 MONDO_LOGFILE, message_to_screen);
1921 if (res) {
1922 strcat(message_to_screen, "...failed");
1923 } else {
1924 strcat(message_to_screen, "...OK");
1925 }
1926 log_to_screen(message_to_screen);
1927 retval += res;
1928 }
1929
1930 if (bkpinfo->call_make_iso[0] != '\0') {
1931 log_msg(2, "bkpinfo->call_make_iso = %s", bkpinfo->call_make_iso);
1932 sprintf(tmp, "%s/archives/NOT-THE-LAST", bkpinfo->scratchdir);
1933 sprintf(message_to_screen, "Making an ISO (%s #%d)",
1934 media_descriptor_string(bkpinfo->backup_media_type),
1935 g_current_media_number);
1936
1937 pause_and_ask_for_cdr(2, &cd_is_mountable); /* if g_current_media_number >= 2 then pause & ask */
1938 if (retval) {
1939 log_to_screen
1940 ("Serious error(s) occurred already. I shan't try to write to media.");
1941 } else {
1942 res =
1943 eval_call_to_make_ISO(bkpinfo, bkpinfo->call_make_iso,
1944 bkpinfo->scratchdir,
1945 g_current_media_number,
1946 MONDO_LOGFILE, message_to_screen);
1947 if (res) {
1948 log_to_screen("%s...failed to write", message_to_screen);
1949 } else {
1950 log_to_screen("%s...OK", message_to_screen);
1951 sprintf(tmp, "tail -n10 %s | grep -F ':-('", MONDO_LOGFILE);
1952 if (!run_program_and_log_output(tmp, 1)) {
1953 log_to_screen
1954 ("Despite nonfatal errors, growisofs confirms the write was successful.");
1955 }
1956 }
1957 retval += res;
1958#ifdef DVDRWFORMAT
1959 sprintf(tmp,
1960 "tail -n8 %s | grep 'blank=full.*dvd-compat.*DAO'",
1961 MONDO_LOGFILE);
1962 if (g_backup_media_type == dvd
1963 && (res || !run_program_and_log_output(tmp, 1))) {
1964 log_to_screen
1965 ("Failed to write to disk. I shall blank it and then try again.");
1966 sleep(5);
1967 system("sync");
1968 pause_for_N_seconds(5, "Letting DVD drive settle");
1969
1970// dvd+rw-format --- OPTION 2
1971 if (!bkpinfo->please_dont_eject) {
1972 log_to_screen("Ejecting media to clear drive status.");
1973 eject_device(bkpinfo->media_device);
1974 inject_device(bkpinfo->media_device);
1975 }
1976 pause_for_N_seconds(5, "Letting DVD drive settle");
1977 sprintf(sz_blank_disk, "dvd+rw-format -force %s",
1978 bkpinfo->media_device);
1979 log_msg(3, "sz_blank_disk = '%s'", sz_blank_disk);
1980 res =
1981 run_external_binary_with_percentage_indicator_NEW
1982 ("Blanking DVD disk", sz_blank_disk);
1983 if (res) {
1984 log_to_screen
1985 ("Warning - format failed. (Was it a DVD-R?) Sleeping for 5 seconds to take a breath...");
1986 pause_for_N_seconds(5,
1987 "Letting DVD drive settle... and trying again.");
1988 res =
1989 run_external_binary_with_percentage_indicator_NEW
1990 ("Blanking DVD disk", sz_blank_disk);
1991 if (res) {
1992 log_to_screen("Format failed a second time.");
1993 }
1994 } else {
1995 log_to_screen
1996 ("Format succeeded. Sleeping for 5 seconds to take a breath...");
1997 }
1998 pause_for_N_seconds(5, "Letting DVD drive settle");
1999 if (!bkpinfo->please_dont_eject) {
2000 log_to_screen("Ejecting media to clear drive status.");
2001 eject_device(bkpinfo->media_device);
2002 inject_device(bkpinfo->media_device);
2003 }
2004 pause_for_N_seconds(5, "Letting DVD drive settle");
2005 res =
2006 eval_call_to_make_ISO(bkpinfo, bkpinfo->call_make_iso,
2007 bkpinfo->scratchdir,
2008 g_current_media_number,
2009 MONDO_LOGFILE,
2010 message_to_screen);
2011 retval += res;
2012 if (!bkpinfo->please_dont_eject) {
2013 log_to_screen("Ejecting media.");
2014 eject_device(bkpinfo->media_device);
2015 }
2016 if (res) {
2017 log_to_screen("Dagnabbit. It still failed.");
2018 } else {
2019 log_to_screen
2020 ("OK, this time I successfully backed up to DVD.");
2021 }
2022 }
2023#endif
2024 if (g_backup_media_type == dvd && !bkpinfo->please_dont_eject) {
2025 eject_device(bkpinfo->media_device);
2026 }
2027 }
2028 } else {
2029 sprintf(message_to_screen, "Running mkisofs to make %s #%d",
2030 media_descriptor_string(bkpinfo->backup_media_type),
2031 g_current_media_number);
2032 log_msg(1, message_to_screen);
2033 sprintf(result_sz, "Call to mkisofs to make ISO (%s #%d) ",
2034 media_descriptor_string(bkpinfo->backup_media_type),
2035 g_current_media_number);
2036 if (bkpinfo->nonbootable_backup) {
2037 log_msg(1, "Making nonbootable backup");
2038// FIXME --- change mkisofs string to MONDO_MKISOFS_NONBOOTABLE and add ' .' at end
2039 res =
2040 eval_call_to_make_ISO(bkpinfo,
2041 "mkisofs -o '_ISO_' -r -p MondoRescue -publisher www.mondorescue.org -A MondoRescue_GPL -V _CD#_ .",
2042 destfile, g_current_media_number,
2043 MONDO_LOGFILE, message_to_screen);
2044 } else {
2045 log_msg(1, "Making bootable backup");
2046
2047#ifdef __FreeBSD__
2048 bkpinfo->make_cd_use_lilo = TRUE;
2049#endif
2050
2051
2052 log_msg(1, "make_cd_use_lilo is actually %d",
2053 bkpinfo->make_cd_use_lilo);
2054 if (bkpinfo->make_cd_use_lilo) {
2055 log_msg(1, "make_cd_use_lilo = TRUE");
2056// FIXME --- change mkisofs string to MONDO_MKISOFS_REGULAR_SYSLINUX/LILO depending on bkpinfo->make_cd_usE_lilo
2057// and add ' .' at end
2058#ifdef __IA64__
2059 log_msg(1, "IA64 --> elilo");
2060 res = eval_call_to_make_ISO(bkpinfo,
2061 //-b images/mindi-boot.2880.img
2062 "mkisofs -no-emul-boot -b images/mindi-bootroot."
2063 IA64_BOOT_SIZE
2064 ".img -c boot.cat -o '_ISO_' -J -r -p MondoRescue -publisher www.mondorescue.org -A Mondo_Rescue_GPL -V _CD#_ .",
2065 destfile,
2066 g_current_media_number,
2067 MONDO_LOGFILE,
2068 message_to_screen);
2069#else
2070// FIXME --- change mkisofs string to MONDO_MKISOFS_REGULAR_SYSLINUX/LILO depending on bkpinfo->make_cd_usE_lilo
2071// and add ' .' at end
2072 log_msg(1, "Non-ia64 --> lilo");
2073 res =
2074 eval_call_to_make_ISO(bkpinfo,
2075 "mkisofs -b images/mindi-bootroot.2880.img -c boot.cat -o '_ISO_' -J -r -p MondoRescue -publisher www.mondorescue.org -A Mondo_Rescue_GPL -V _CD#_ .",
2076 destfile, g_current_media_number,
2077 MONDO_LOGFILE,
2078 message_to_screen);
2079#endif
2080 } else {
2081 log_msg(1, "make_cd_use_lilo = FALSE");
2082 log_msg(1, "Isolinux");
2083 res =
2084 eval_call_to_make_ISO(bkpinfo,
2085 "mkisofs -no-emul-boot -b isolinux.bin -boot-load-size 4 -boot-info-table -c boot.cat -o '_ISO_' -J -r -p MondoRescue -publisher www.mondorescue.org -A Mondo_Rescue_GPL -V _CD#_ .",
2086 destfile, g_current_media_number,
2087 MONDO_LOGFILE,
2088 message_to_screen);
2089 }
2090 }
2091 if (res) {
2092 strcat(result_sz, "...failed");
2093 } else {
2094 strcat(result_sz, "...OK");
2095 }
2096 log_to_screen(result_sz);
2097 retval += res;
2098 }
2099
2100 if (bkpinfo->backup_media_type == cdr
2101 || bkpinfo->backup_media_type == cdrw) {
2102 if (is_this_device_mounted(bkpinfo->media_device)) {
2103 log_msg(2,
2104 "Warning - %s mounted. I'm unmounting it before I burn to it.",
2105 bkpinfo->media_device);
2106 sprintf(tmp, "umount %s", bkpinfo->media_device);
2107 run_program_and_log_output(tmp, FALSE);
2108 }
2109 }
2110
2111 if (bkpinfo->call_burn_iso[0] != '\0') {
2112 log_msg(2, "bkpinfo->call_burn_iso = %s", bkpinfo->call_burn_iso);
2113 sprintf(message_to_screen, "Burning %s #%d",
2114 media_descriptor_string(bkpinfo->backup_media_type),
2115 g_current_media_number);
2116 pause_and_ask_for_cdr(2, &cd_is_mountable);
2117 res =
2118 eval_call_to_make_ISO(bkpinfo, bkpinfo->call_burn_iso,
2119 destfile, g_current_media_number,
2120 MONDO_LOGFILE, message_to_screen);
2121 if (res) {
2122 strcat(message_to_screen, "...failed");
2123 } else {
2124 strcat(message_to_screen, "...OK");
2125 }
2126 log_to_screen(message_to_screen);
2127 retval += res;
2128 }
2129
2130 if (bkpinfo->call_after_iso[0] != '\0') {
2131 sprintf(message_to_screen, "Running post-ISO call (%s #%d)",
2132 media_descriptor_string(bkpinfo->backup_media_type),
2133 g_current_media_number);
2134 res =
2135 eval_call_to_make_ISO(bkpinfo, bkpinfo->call_after_iso,
2136 destfile, g_current_media_number,
2137 MONDO_LOGFILE, message_to_screen);
2138 if (res) {
2139 strcat(message_to_screen, "...failed");
2140 } else {
2141 strcat(message_to_screen, "...OK");
2142 }
2143 log_to_screen(message_to_screen);
2144 retval += res;
2145 }
2146
2147 chdir(old_pwd);
2148 if (retval) {
2149 log_msg(1, "WARNING - make_iso_fs returned an error");
2150 }
2151 paranoid_free(old_pwd);
2152 paranoid_free(result_sz);
2153 paranoid_free(message_to_screen);
2154 paranoid_free(sz_blank_disk);
2155 paranoid_free(fnam);
2156 paranoid_free(tmp);
2157 return (retval);
2158}
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168bool is_dev_an_NTFS_dev(char *bigfile_fname)
2169{
2170 char *tmp;
2171 char *command;
2172 malloc_string(tmp);
2173 malloc_string(command);
2174 sprintf(command,
2175 "dd if=%s bs=512 count=1 2> /dev/null | strings | head -n1",
2176 bigfile_fname);
2177 log_msg(1, "command = '%s'", command);
2178 strcpy(tmp, call_program_and_get_last_line_of_output(command));
2179 log_msg(1, "--> tmp = '%s'", tmp);
2180 if (strstr(tmp, "NTFS")) {
2181 iamhere("TRUE");
2182 return (TRUE);
2183 } else {
2184 iamhere("FALSE");
2185 return (FALSE);
2186 }
2187}
2188
2189
2190/**
2191 * Back up big files by chopping them up.
2192 * This function backs up all "big" files (where "big" depends
2193 * on your backup media) in "chunks" (whose size again depends
2194 * on your media).
2195 *
2196 * @param bkpinfo The backup information structure. Fields used:
2197 * - @c backup_media_type
2198 * - @c optimal_set_size
2199 * @param biggielist_fname The path to a file containing a list of
2200 * all "big" files.
2201 * @return The number of errors encountered (0 for success)
2202 * @see slice_up_file_etc
2203 */
2204int
2205make_slices_and_images(struct s_bkpinfo *bkpinfo, char *biggielist_fname)
2206{
2207
2208 /*@ pointers ******************************************* */
2209 FILE *fin;
2210 char *p;
2211
2212 /*@ buffers ******************************************** */
2213 char *tmp;
2214 char *bigfile_fname;
2215 char *sz_devfile;
2216 char *ntfsprog_fifo = NULL;
2217 /*@ long *********************************************** */
2218 long biggie_file_number = 0;
2219 long noof_biggie_files = 0;
2220 long estimated_total_noof_slices = 0;
2221
2222 /*@ int ************************************************ */
2223 int retval = 0;
2224 int res = 0;
2225 pid_t pid;
2226 FILE *ftmp = NULL;
2227 bool delete_when_done;
2228 bool use_ntfsprog;
2229 off_t biggie_fsize;
2230
2231 assert(bkpinfo != NULL);
2232 assert_string_is_neither_NULL_nor_zerolength(biggielist_fname);
2233
2234 malloc_string(tmp);
2235 malloc_string(bigfile_fname);
2236 malloc_string(sz_devfile);
2237 estimated_total_noof_slices =
2238 size_of_all_biggiefiles_K(bkpinfo) / bkpinfo->optimal_set_size + 1;
2239
2240 log_msg(1, "size of all biggiefiles = %ld",
2241 size_of_all_biggiefiles_K(bkpinfo));
2242 log_msg(1, "estimated_total_noof_slices = %ld KB / %ld KB = %ld",
2243 size_of_all_biggiefiles_K(bkpinfo), bkpinfo->optimal_set_size,
2244 estimated_total_noof_slices);
2245
2246 if (length_of_file(biggielist_fname) < 6) {
2247 log_msg(1, "No biggiefiles; fair enough...");
2248 return (0);
2249 }
2250 sprintf(tmp, "I am now backing up all large files.");
2251 log_to_screen(tmp);
2252 noof_biggie_files = count_lines_in_file(biggielist_fname);
2253 open_progress_form("Backing up big files", tmp,
2254 "Please wait. This may take some time.", "",
2255 estimated_total_noof_slices);
2256 if (!(fin = fopen(biggielist_fname, "r"))) {
2257 log_OS_error("Unable to openin biggielist");
2258 return (1);
2259 }
2260 for (fgets(bigfile_fname, MAX_STR_LEN, fin); !feof(fin);
2261 fgets(bigfile_fname, MAX_STR_LEN, fin), biggie_file_number++) {
2262 use_ntfsprog = FALSE;
2263 if (bigfile_fname[strlen(bigfile_fname) - 1] < 32) {
2264 bigfile_fname[strlen(bigfile_fname) - 1] = '\0';
2265 }
2266 biggie_fsize = length_of_file(bigfile_fname);
2267 delete_when_done = FALSE;
2268
2269 if (!does_file_exist(bigfile_fname)) {
2270 ftmp = fopen(bigfile_fname, "w");
2271 if (ftmp == NULL) {
2272 log_msg(3, "Unable to write to %s", bigfile_fname);
2273 // So skip it as it doesn't exist
2274 continue;
2275 } else {
2276 paranoid_fclose(ftmp);
2277 }
2278 delete_when_done = TRUE;
2279 } else {
2280 // Call ntfsclone (formerly partimagehack) if it's a /dev entry
2281 // (i.e. a partition to be imaged)
2282 log_msg(2, "bigfile_fname = %s", bigfile_fname);
2283 use_ntfsprog = FALSE;
2284 if (!strncmp(bigfile_fname, "/dev/", 5)
2285 && is_dev_an_NTFS_dev(bigfile_fname)) {
2286 use_ntfsprog = TRUE;
2287 log_msg(2,
2288 "Calling ntfsclone in background because %s is an NTFS partition",
2289 bigfile_fname);
2290 sprintf(sz_devfile, "%s/%d.%d.000",
2291 bkpinfo->tmpdir,
2292 (int) (random() % 32768),
2293 (int) (random() % 32768));
2294 mkfifo(sz_devfile, 0x770);
2295 ntfsprog_fifo = sz_devfile;
2296 switch (pid = fork()) {
2297 case -1:
2298 fatal_error("Fork failure");
2299 case 0:
2300 log_msg(2,
2301 "CHILD - fip - calling feed_into_ntfsprog(%s, %s)",
2302 bigfile_fname, sz_devfile);
2303 res = feed_into_ntfsprog(bigfile_fname, sz_devfile);
2304 exit(res);
2305 break;
2306 default:
2307 log_msg(2,
2308 "feed_into_ntfsprog() called in background --- pid=%ld",
2309 (long int) (pid));
2310 }
2311 }
2312// Otherwise, use good old 'dd' and 'bzip2'
2313 else {
2314 sz_devfile[0] = '\0';
2315 ntfsprog_fifo = NULL;
2316 }
2317
2318// Whether partition or biggiefile, just do your thang :-)
2319 sprintf(tmp, "Bigfile #%ld is '%s' (%ld KB)",
2320 biggie_file_number + 1, bigfile_fname,
2321 (long) biggie_fsize >> 10);
2322 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2323 write_header_block_to_stream(biggie_fsize, bigfile_fname,
2324 use_ntfsprog ?
2325 BLK_START_A_PIHBIGGIE :
2326 BLK_START_A_NORMBIGGIE);
2327 }
2328 res =
2329 slice_up_file_etc(bkpinfo, bigfile_fname,
2330 ntfsprog_fifo, biggie_file_number,
2331 noof_biggie_files, use_ntfsprog);
2332 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2333 write_header_block_to_stream((off_t)0,
2334 calc_checksum_of_file
2335 (bigfile_fname),
2336 BLK_STOP_A_BIGGIE);
2337 }
2338 retval += res;
2339 p = strrchr(bigfile_fname, '/');
2340 if (p) {
2341 p++;
2342 } else {
2343 p = bigfile_fname;
2344 }
2345 sprintf(tmp, "Archiving %s ... ", bigfile_fname);
2346 if (res) {
2347 strcat(tmp, "Failed!");
2348 } else {
2349 strcat(tmp, "OK");
2350 }
2351 if (delete_when_done) {
2352 unlink(bigfile_fname);
2353 delete_when_done = FALSE;
2354 }
2355 }
2356#ifndef _XWIN
2357 if (!g_text_mode) {
2358 newtDrawRootText(0, g_noof_rows - 2, tmp);
2359 newtRefresh();
2360 }
2361#endif
2362 }
2363 log_msg(1, "Finished backing up bigfiles");
2364 log_msg(1, "estimated slices = %ld; actual slices = %ld",
2365 estimated_total_noof_slices, g_current_progress);
2366 close_progress_form();
2367 paranoid_fclose(fin);
2368 paranoid_free(tmp);
2369 paranoid_free(bigfile_fname);
2370 paranoid_free(sz_devfile);
2371 return (retval);
2372}
2373
2374
2375
2376
2377/**
2378 * Single-threaded version of @c make_afioballs_and_images().
2379 * @see make_afioballs_and_images
2380 */
2381int make_afioballs_and_images_OLD(struct s_bkpinfo *bkpinfo)
2382{
2383
2384 /*@ int ************************************************** */
2385 int retval = 0;
2386 long int curr_set_no = 0;
2387 int res = 0;
2388
2389 /*@ buffers ********************************************** */
2390 char *curr_filelist_fname;
2391 char *curr_afioball_fname;
2392 char *curr_xattr_list_fname;
2393 char *curr_acl_list_fname;
2394 char *tmp;
2395 char *media_usage_comment;
2396
2397 malloc_string(curr_afioball_fname);
2398 malloc_string(media_usage_comment);
2399 malloc_string(curr_filelist_fname);
2400 malloc_string(curr_xattr_list_fname);
2401 malloc_string(curr_acl_list_fname);
2402
2403 tmp = malloc(MAX_STR_LEN * 2);
2404
2405 sprintf(tmp, "%s/archives/filelist.full", bkpinfo->scratchdir);
2406
2407 log_to_screen("Archiving regular files");
2408
2409 open_progress_form("Backing up filesystem",
2410 "I am backing up your live filesystem now.",
2411 "Please wait. This may take a couple of hours.",
2412 "Working...",
2413 get_last_filelist_number(bkpinfo) + 1);
2414
2415 sprintf(curr_filelist_fname, FILELIST_FNAME_RAW_SZ, bkpinfo->tmpdir,
2416 0L);
2417
2418 for (curr_set_no = 0; does_file_exist(curr_filelist_fname);
2419 sprintf(curr_filelist_fname, FILELIST_FNAME_RAW_SZ,
2420 bkpinfo->tmpdir, ++curr_set_no)) {
2421 /* backup this set of files */
2422 sprintf(curr_filelist_fname, FILELIST_FNAME_RAW_SZ,
2423 bkpinfo->tmpdir, curr_set_no);
2424 sprintf(curr_afioball_fname, AFIOBALL_FNAME_RAW_SZ,
2425 bkpinfo->tmpdir, curr_set_no, bkpinfo->zip_suffix);
2426
2427 log_msg(1, "EXAT'g set %ld", curr_set_no);
2428 if (g_getfattr) {
2429 sprintf(curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ,
2430 bkpinfo->tmpdir, curr_set_no);
2431 get_fattr_list(curr_filelist_fname, curr_xattr_list_fname);
2432 }
2433 if (g_getfacl) {
2434 sprintf(curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ,
2435 bkpinfo->tmpdir, curr_set_no);
2436 get_acl_list(curr_filelist_fname, curr_acl_list_fname);
2437 }
2438
2439 log_msg(1, "Archiving set %ld", curr_set_no);
2440 res =
2441 archive_this_fileset(bkpinfo, curr_filelist_fname,
2442 curr_afioball_fname, curr_set_no);
2443 retval += res;
2444 if (res) {
2445 sprintf(tmp,
2446 "Errors occurred while archiving set %ld. Perhaps your live filesystem changed?",
2447 curr_set_no);
2448 log_to_screen(tmp);
2449 }
2450
2451 strcpy(media_usage_comment, percent_media_full_comment(bkpinfo));
2452
2453 /* copy to CD (scratchdir) ... and an actual CD-R if necessary */
2454 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2455 register_in_tape_catalog(fileset, curr_set_no, -1,
2456 curr_afioball_fname);
2457 maintain_collection_of_recent_archives(bkpinfo->tmpdir,
2458 curr_afioball_fname);
2459 iamhere("Writing EXAT files");
2460 res +=
2461 write_EXAT_files_to_tape(bkpinfo, curr_xattr_list_fname,
2462 curr_acl_list_fname);
2463// archives themselves
2464 res = move_files_to_stream(bkpinfo, curr_afioball_fname, NULL);
2465 } else {
2466 if (g_getfacl) {
2467 if (g_getfattr) {
2468 res = move_files_to_cd(bkpinfo, curr_filelist_fname,
2469 curr_xattr_list_fname,
2470 curr_acl_list_fname,
2471 curr_afioball_fname, NULL);
2472 } else {
2473 res = move_files_to_cd(bkpinfo, curr_filelist_fname,
2474 curr_acl_list_fname,
2475 curr_afioball_fname, NULL);
2476 }
2477 } else {
2478 if (g_getfattr) {
2479 res = move_files_to_cd(bkpinfo, curr_filelist_fname,
2480 curr_xattr_list_fname,
2481 curr_afioball_fname, NULL);
2482 } else {
2483 res = move_files_to_cd(bkpinfo, curr_filelist_fname,
2484 curr_afioball_fname, NULL);
2485 }
2486 }
2487 }
2488 retval += res;
2489 g_current_progress++;
2490 update_progress_form(media_usage_comment);
2491
2492 if (res) {
2493 sprintf(tmp, "Failed to add archive %ld's files to CD dir\n",
2494 curr_set_no);
2495 log_to_screen(tmp);
2496 fatal_error
2497 ("Is your hard disk is full? If not, please send the author the logfile.");
2498 }
2499 }
2500 close_progress_form();
2501 sprintf(tmp, "Your regular files have been archived ");
2502 if (retval) {
2503 strcat(tmp, "(with errors).");
2504 } else {
2505 strcat(tmp, "successfully.");
2506 }
2507 log_to_screen(tmp);
2508 paranoid_free(tmp);
2509 paranoid_free(curr_filelist_fname);
2510 paranoid_free(curr_afioball_fname);
2511 paranoid_free(media_usage_comment);
2512 paranoid_free(curr_xattr_list_fname);
2513 paranoid_free(curr_acl_list_fname);
2514 return (retval);
2515}
2516
2517/* @} - end of LLarchiveGroup */
2518
2519
2520/**
2521 * Wrapper around @c make_afioballs_and_images().
2522 * @param bkpinfo the backup information structure. Only the
2523 * @c backup_media_type field is used within this function.
2524 * @return return code of make_afioballs_and_images
2525 * @see make_afioballs_and_images
2526 * @ingroup MLarchiveGroup
2527 */
2528int make_those_afios_phase(struct s_bkpinfo *bkpinfo)
2529{
2530 /*@ int ******************************************* */
2531 int res = 0;
2532 int retval = 0;
2533
2534 assert(bkpinfo != NULL);
2535
2536 mvaddstr_and_log_it(g_currentY, 0,
2537 "Archiving regular files to media ");
2538
2539 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2540 write_header_block_to_stream((off_t)0, "start-of-afioballs",
2541 BLK_START_AFIOBALLS);
2542#if __FreeBSD__ == 5
2543 log_msg(1,
2544 "Using single-threaded make_afioballs_and_images() to suit b0rken FreeBSD 5.0");
2545 res = make_afioballs_and_images_OLD(bkpinfo);
2546#else
2547 res = make_afioballs_and_images_OLD(bkpinfo);
2548#endif
2549 write_header_block_to_stream((off_t)0, "stop-afioballs",
2550 BLK_STOP_AFIOBALLS);
2551 } else {
2552 res = make_afioballs_and_images(bkpinfo);
2553 }
2554
2555 retval += res;
2556 if (res) {
2557 mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
2558 log_msg(1, "make_afioballs_and_images returned an error");
2559 } else {
2560 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2561 }
2562 return (retval);
2563}
2564
2565/**
2566 * Wrapper around @c make_slices_and_images().
2567 * @param bkpinfo The backup information structure. Fields used:
2568 * - @c backup_media_type
2569 * - @c scratchdir
2570 * - @c tmpdir
2571 * @return The number of errors encountered (0 for success)
2572 * @ingroup MLarchiveGroup
2573 */
2574int make_those_slices_phase(struct s_bkpinfo *bkpinfo)
2575{
2576
2577 /*@ int ***************************************************** */
2578 int res = 0;
2579 int retval = 0;
2580
2581 /*@ buffers ************************************************** */
2582 char *biggielist;
2583 char *command;
2584 char *blah;
2585 char *xattr_fname;
2586 char *acl_fname;
2587
2588 assert(bkpinfo != NULL);
2589 /* slice big files */
2590 malloc_string(biggielist);
2591 malloc_string(xattr_fname);
2592 malloc_string(acl_fname);
2593 mvaddstr_and_log_it(g_currentY, 0,
2594 "Archiving large files to media ");
2595 sprintf(biggielist, "%s/archives/biggielist.txt", bkpinfo->scratchdir);
2596 if (g_getfattr) {
2597 sprintf(xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
2598 }
2599 if (g_getfacl) {
2600 sprintf(acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
2601 }
2602
2603 asprintf(&command, "cp %s/biggielist.txt %s", bkpinfo->tmpdir,
2604 biggielist);
2605 paranoid_system(command);
2606 paranoid_free(command);
2607
2608 asprintf(&blah, "biggielist = %s", biggielist);
2609 log_msg(2, blah);
2610 paranoid_free(blah);
2611
2612 if (!does_file_exist(biggielist)) {
2613 log_msg(1, "BTW, the biggielist does not exist");
2614 }
2615
2616 if (g_getfattr) {
2617 get_fattr_list(biggielist, xattr_fname);
2618 asprintf(&command, "cp %s %s/archives/", xattr_fname,
2619 bkpinfo->scratchdir);
2620 paranoid_system(command);
2621 paranoid_free(command);
2622 }
2623 if (g_getfacl) {
2624 get_acl_list(biggielist, acl_fname);
2625 asprintf(&command, "cp %s %s/archives/", acl_fname,
2626 bkpinfo->scratchdir);
2627 paranoid_system(command);
2628 paranoid_free(command);
2629 }
2630
2631 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2632 res += write_EXAT_files_to_tape(bkpinfo, xattr_fname, acl_fname);
2633 asprintf(&blah, "%ld", count_lines_in_file(biggielist));
2634 write_header_block_to_stream((off_t)0, blah, BLK_START_BIGGIEFILES);
2635 paranoid_free(blah);
2636 }
2637 res = make_slices_and_images(bkpinfo, biggielist);
2638 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2639 write_header_block_to_stream((off_t)0, "end-of-biggiefiles",
2640 BLK_STOP_BIGGIEFILES);
2641 }
2642 retval += res;
2643 if (res) {
2644 log_msg(1, "make_slices_and_images returned an error");
2645 mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
2646 } else {
2647 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2648 }
2649 paranoid_free(blah);
2650 paranoid_free(biggielist);
2651 paranoid_free(command);
2652 paranoid_free(xattr_fname);
2653 paranoid_free(acl_fname);
2654 return (retval);
2655}
2656
2657
2658/**
2659 * @addtogroup LLarchiveGroup
2660 * @{
2661 */
2662/**
2663 * Function pointer to an appropriate @c move_files_to_cd routine.
2664 * You can set this to your own function (for example, one to
2665 * transfer files over the network) or leave it as is.
2666 */
2667int (*move_files_to_cd) (struct s_bkpinfo *, char *, ...) =
2668 _move_files_to_cd;
2669
2670/**
2671 * Move some files to the ISO scratch directory.
2672 * This function moves files specified as parameters, into the directory
2673 * @c bkpinfo->scratchdir, where the files that will be stored on the next
2674 * CD are waiting.
2675 *
2676 * @param bkpinfo The backup information structure. Fields used:
2677 * - @c media_size
2678 * - @c scratchdir
2679 * @param files_to_add The files to add to the scratchdir.
2680 * @warning The list of @c files_to_add must be terminated with @c NULL.
2681 * @note If and when the space occupied by the scratchdir would exceed
2682 * the capacity of the current CD,
2683 * <tt>write_iso_and_go_on(bkpinfo, FALSE)</tt> is called and the
2684 * scratchdir is emptied.
2685 *
2686 * @return The number of errors encountered (0 for success)
2687 */
2688int _move_files_to_cd(struct s_bkpinfo *bkpinfo, char *files_to_add, ...)
2689{
2690
2691 /*@ int ************************************************************ */
2692 int retval = 0;
2693 int res = 0;
2694
2695 /*@ buffers ******************************************************** */
2696 char *tmp, *curr_file, *cf;
2697
2698 /*@ long ************************************************************ */
2699 va_list ap;
2700 long long would_occupy;
2701
2702 assert(bkpinfo != NULL);
2703 malloc_string(curr_file);
2704 tmp = malloc(1200);
2705 would_occupy = space_occupied_by_cd(bkpinfo->scratchdir);
2706 va_start(ap, files_to_add); // initialize the variable arguments
2707 for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
2708 if (!cf) {
2709 continue;
2710 }
2711 strcpy(curr_file, cf);
2712 if (!does_file_exist(curr_file)) {
2713 log_msg(1,
2714 "Warning - you're trying to add a non-existent file - '%s' to the CD",
2715 curr_file);
2716 } else {
2717 log_msg(8, "Trying to add file %s to CD", curr_file);
2718 would_occupy += length_of_file(curr_file) / 1024;
2719 }
2720 }
2721 va_end(ap);
2722
2723 if (bkpinfo->media_size[g_current_media_number] <= 0) {
2724 fatal_error("move_files_to_cd() - unknown media size");
2725 }
2726 if (would_occupy / 1024 > bkpinfo->media_size[g_current_media_number]) {
2727 res = write_iso_and_go_on(bkpinfo, FALSE); /* FALSE because this is not the last CD we'll write */
2728 retval += res;
2729 if (res) {
2730 log_msg(1, "WARNING - write_iso_and_go_on returned an error");
2731 }
2732 }
2733
2734 va_start(ap, files_to_add); // initialize the variable arguments
2735 for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
2736 if (!cf) {
2737 continue;
2738 }
2739 strcpy(curr_file, cf);
2740
2741 sprintf(tmp, "mv -f %s %s/archives/", curr_file,
2742 bkpinfo->scratchdir);
2743 res = run_program_and_log_output(tmp, 5);
2744 retval += res;
2745 if (res) {
2746 log_msg(1, "(move_files_to_cd) '%s' failed", tmp);
2747 } else {
2748 log_msg(8, "Moved %s to CD OK", tmp);
2749 }
2750 // unlink (curr_file);
2751 }
2752 va_end(ap);
2753
2754 if (retval) {
2755 log_msg(1,
2756 "Warning - errors occurred while I was adding files to CD dir");
2757 }
2758 paranoid_free(tmp);
2759 paranoid_free(curr_file);
2760 return (retval);
2761}
2762
2763/* @} - end of LLarchiveGroup */
2764
2765
2766
2767
2768
2769
2770
2771
2772/**
2773 * Offer to write boot and data disk images to 3.5" floppy disks.
2774 * @param bkpinfo The backup information structure. Only the
2775 * @c backup_media_type field is used in this function.
2776 * @param imagesdir The directory containing the floppy images (usually
2777 * /root/images/mindi).
2778 *
2779 * @return The number of errors encountered (0 for success)
2780 * @see write_image_to_floppy
2781 * @see format_disk
2782 * @ingroup MLarchiveGroup
2783 */
2784int offer_to_write_floppies(struct s_bkpinfo *bkpinfo, char *imagesdir)
2785{
2786 /*@ buffer ************************************************************ */
2787 char *tmp;
2788 char *comment;
2789 char *bootdisk_dev;
2790 char *datadisk_dev;
2791 char *bootdisk_file;
2792 char *rootdisk_file;
2793
2794 /*@ int *************************************************************** */
2795 int i = 0;
2796 int res = 0;
2797
2798 /*@ bool ************************************************************** */
2799 bool format_first;
2800 bool root_disk_exists = FALSE;
2801
2802 malloc_string(tmp);
2803 malloc_string(comment);
2804 malloc_string(bootdisk_dev);
2805 malloc_string(datadisk_dev);
2806 malloc_string(rootdisk_file);
2807 malloc_string(bootdisk_file);
2808 assert(bkpinfo != NULL);
2809 assert_string_is_neither_NULL_nor_zerolength(imagesdir);
2810
2811
2812 if (!ask_me_yes_or_no
2813 ("Write boot and data disk images to 3.5\" floppy disks?")) {
2814 return (0);
2815 }
2816 if (does_device_exist(DEFAULT_1722MB_DISK)) {
2817#ifdef __FreeBSD__
2818 // tell the system that this is a 1.72m floppy
2819 system("/usr/sbin/fdcontrol -F 1722 /dev/fd0.1722");
2820#endif
2821 strcpy(bootdisk_dev, DEFAULT_1722MB_DISK);
2822 } else if (does_device_exist(BACKUP_1722MB_DISK)) {
2823 sprintf(bootdisk_dev, "/dev/fd0H1722");
2824 } else {
2825 log_msg(1, "Warning - can't find a 1.72MB floppy device *sigh*");
2826 strcpy(bootdisk_dev, DEFAULT_1722MB_DISK);
2827// return (1);
2828 }
2829 strcpy(datadisk_dev, "/dev/fd0");
2830 if (!does_device_exist(datadisk_dev)) {
2831 log_msg(1, "Warning - can't find a 1.44MB floppy device *sigh*");
2832 strcpy(datadisk_dev, "/dev/fd0");
2833// return (1);
2834 }
2835 format_first =
2836 ask_me_yes_or_no
2837 ("Do you want me to format the disks before I write to them?");
2838
2839/* boot disk */
2840 if (ask_me_OK_or_cancel("About to write boot disk")) {
2841 log_to_screen("Writing boot floppy");
2842#ifdef __FreeBSD__
2843 sprintf(tmp, "%s/mindi-kern.1722.img", imagesdir);
2844 if (format_first) {
2845 format_disk(bootdisk_dev);
2846 }
2847 res += write_image_to_floppy(bootdisk_dev, tmp);
2848 if (ask_me_OK_or_cancel("About to write 1.44MB mfsroot disk")) {
2849 log_to_screen("Writing mfsroot floppy");
2850 if (format_first) {
2851 format_disk(datadisk_dev);
2852 }
2853 sprintf(tmp, "%s/mindi-mfsroot.1440.img", imagesdir);
2854 write_image_to_floppy(datadisk_dev, tmp);
2855 }
2856#else
2857 sprintf(bootdisk_file, "%s/mindi-bootroot.1722.img", imagesdir);
2858 if (does_file_exist(bootdisk_file)) {
2859 if (format_first) {
2860 format_disk(bootdisk_dev);
2861 }
2862 res += write_image_to_floppy(bootdisk_dev, bootdisk_file);
2863 } else {
2864 sprintf(bootdisk_file, "%s/mindi-boot.1440.img", imagesdir);
2865 sprintf(rootdisk_file, "%s/mindi-root.1440.img", imagesdir);
2866 root_disk_exists = TRUE;
2867 if (!does_file_exist(rootdisk_file)
2868 || !does_file_exist(bootdisk_file)) {
2869 popup_and_OK
2870 ("Cannot write boot/root floppies. Files not found.");
2871 log_to_screen
2872 ("Failed to find boot/root floppy images. Oh dear.");
2873 return (1);
2874 }
2875 if (format_first) {
2876 format_disk(datadisk_dev);
2877 }
2878 /*
2879 sprintf(tmp, "cat %s > %s", bootdisk_file, datadisk_dev);
2880 res += run_external_binary_with_percentage_indicator_NEW("Writing boot floppy", tmp);
2881 */
2882 res += write_image_to_floppy(datadisk_dev, bootdisk_file);
2883 if (ask_me_OK_or_cancel("About to write root disk")) {
2884 log_to_screen("Writing root floppy");
2885 if (format_first) {
2886 format_disk(datadisk_dev);
2887 }
2888 sprintf(tmp, "cat %s > %s", rootdisk_file, datadisk_dev);
2889 log_msg(1, "tmp = '%s'", tmp);
2890 res +=
2891 run_external_binary_with_percentage_indicator_NEW
2892 ("Writing root floppy", tmp);
2893// res += write_image_to_floppy (datadisk_dev, rootdisk_file);
2894 }
2895 }
2896#endif
2897 }
2898 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2899 log_to_screen
2900 ("FYI, the data disks are stored on tape/CD for your convenience.");
2901 return (0);
2902 }
2903 for (i = 1; i < 99; i++) {
2904 sprintf(tmp, "%s/mindi-data-%d.img", imagesdir, i);
2905 log_msg(3, tmp);
2906 if (!does_file_exist(tmp)) {
2907 log_msg(3, "...not found");
2908 break;
2909 }
2910 sprintf(comment, "About to write data disk #%d", i);
2911 if (ask_me_OK_or_cancel(comment)) {
2912 sprintf(comment, "Writing data disk #%3d", i);
2913 log_to_screen(comment);
2914 if (format_first) {
2915 res += format_disk(datadisk_dev);
2916 }
2917 res += write_image_to_floppy(datadisk_dev, tmp);
2918 }
2919 }
2920 paranoid_free(tmp);
2921 paranoid_free(comment);
2922 paranoid_free(bootdisk_dev);
2923 paranoid_free(datadisk_dev);
2924 return (res);
2925}
2926
2927
2928
2929
2930
2931
2932
2933
2934/**
2935 * Wrapper around @c offer_to_write_floppies().
2936 * @param bkpinfo The backup information structure. Used only
2937 * in the call to @c offer_to_write_floppies().
2938 * @return 0 if the boot floppies were found (not necessarily written OK),
2939 * 1 otherwise.
2940 * @see offer_to_write_floppies
2941 * @ingroup MLarchiveGroup
2942 */
2943
2944int offer_to_write_boot_floppies_to_physical_disks(struct s_bkpinfo
2945 *bkpinfo)
2946{
2947 int res = 0;
2948
2949 assert(bkpinfo != NULL);
2950
2951 mvaddstr_and_log_it(g_currentY, 0,
2952 "Writing boot+data floppy images to disk");
2953
2954 if (!bkpinfo->nonbootable_backup) {
2955#ifdef __FreeBSD__
2956 if (!does_file_exist(MINDI_CACHE"/mindi-kern.1722.img"))
2957#else
2958 if (!does_file_exist(MINDI_CACHE"/mindi-bootroot.1722.img") && !does_file_exist(MINDI_CACHE"/mindi-boot.1440.img"))
2959#endif
2960 {
2961 mvaddstr_and_log_it(g_currentY++, 74, "No Imgs");
2962 if (does_file_exist(MINDI_CACHE"/mondorescue.iso")) {
2963 popup_and_OK
2964 ("No regular Boot+data floppies were created due of space constraints. However, you can burn "MINDI_CACHE"/mondorescue.iso to a CD and boot from that.");
2965 res++;
2966 }
2967 } else {
2968 offer_to_write_floppies(bkpinfo, MINDI_CACHE);
2969 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2970 }
2971 } else {
2972 popup_and_OK
2973 ("Since you opted for a nonbootable backup, no boot floppies were created.");
2974 }
2975
2976 return (res);
2977}
2978
2979
2980
2981
2982/**
2983 * @addtogroup LLarchiveGroup
2984 * @{
2985 */
2986/**
2987 * Function pointer to an appropriate @c move_files_to_stream routine.
2988 * You can set this to your own function (for example, one to
2989 * transfer files over the network) or leave it as is.
2990 */
2991int (*move_files_to_stream) (struct s_bkpinfo *, char *, ...) =
2992 _move_files_to_stream;
2993
2994/**
2995 * Copy some files to tape.
2996 * This function copies the files specified as parameters into the tape stream.
2997 *
2998 * @param bkpinfo The backup information structure. Used only in the call to
2999 * @c write_file_to_stream_from_file().
3000 *
3001 * @param files_to_add The files to copy to the tape stream.
3002 * @warning The list of @c files_to_add must be terminated with @c NULL.
3003 * @note Files may be split across multiple tapes if necessary.
3004 *
3005 * @return The number of errors encountered (0 for success)
3006 */
3007int
3008_move_files_to_stream(struct s_bkpinfo *bkpinfo, char *files_to_add, ...)
3009{
3010
3011 /*@ int ************************************************************ */
3012 int retval = 0;
3013 int res = 0;
3014 /*@ buffers ******************************************************** */
3015
3016 /*@ char *********************************************************** */
3017 char start_chr;
3018 char stop_chr;
3019 char *curr_file, *cf;
3020 /*@ long long ****************************************************** */
3021 off_t length_of_incoming_file = (off_t)0;
3022 t_archtype type;
3023 va_list ap;
3024
3025 assert(bkpinfo != NULL);
3026 malloc_string(curr_file);
3027 va_start(ap, files_to_add);
3028 for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
3029 if (!cf) {
3030 continue;
3031 }
3032 strcpy(curr_file, cf);
3033 if (!does_file_exist(curr_file)) {
3034 log_msg(1,
3035 "Warning - you're trying to add a non-existent file - '%s' to the tape",
3036 curr_file);
3037 }
3038/* create header chars */
3039 start_chr = BLK_START_AN_AFIO_OR_SLICE;
3040 stop_chr = BLK_STOP_AN_AFIO_OR_SLICE;
3041/* ask for new tape if necessary */
3042 length_of_incoming_file = length_of_file(curr_file);
3043 write_header_block_to_stream(length_of_incoming_file, curr_file,
3044 start_chr);
3045 if (strstr(curr_file, ".afio.") || strstr(curr_file, ".star.")) {
3046 type = fileset;
3047 } else if (strstr(curr_file, "slice")) {
3048 type = biggieslice;
3049 } else {
3050 type = other;
3051 }
3052 res = write_file_to_stream_from_file(bkpinfo, curr_file);
3053 retval += res;
3054 unlink(curr_file);
3055/* write closing header */
3056 write_header_block_to_stream((off_t)0, "finished-writing-file", stop_chr);
3057 }
3058 va_end(ap);
3059
3060 if (retval) {
3061 log_msg(1,
3062 "Warning - errors occurred while I was adding file to tape");
3063 }
3064 paranoid_free(curr_file);
3065 return (retval);
3066}
3067
3068/* @} - end of LLarchiveGroup */
3069
3070
3071
3072/**
3073 * @addtogroup utilityGroup
3074 * @{
3075 */
3076/**
3077 * Make sure the user has a valid CD-R(W) in the CD drive.
3078 * @param cdrw_dev Set to the CD-R(W) device checked.
3079 * @param keep_looping If TRUE, keep pestering user until they insist
3080 * or insert a correct CD; if FALSE, only check once.
3081 * @return 0 (there was an OK CD in the drive) or 1 (there wasn't).
3082 */
3083int interrogate_disk_currently_in_cdrw_drive(char *cdrw_dev,
3084 bool keep_looping)
3085{
3086 char *tmp;
3087 int res = 0;
3088 char *bkp;
3089 char *cdrecord;
3090
3091 malloc_string(tmp);
3092 malloc_string(bkp);
3093 malloc_string(cdrecord);
3094 strcpy(bkp, cdrw_dev);
3095 if (find_cdrw_device(cdrw_dev)) {
3096 strcpy(cdrw_dev, bkp);
3097 } else {
3098 if (!system("which cdrecord > /dev/null 2> /dev/null")) {
3099 sprintf(cdrecord, "cdrecord dev=%s -atip", cdrw_dev);
3100 } else if (!system("which dvdrecord > /dev/null 2> /dev/null")) {
3101 sprintf(cdrecord, "cdrecord dev=%s -atip", cdrw_dev);
3102 } else {
3103 cdrecord[0] = '\0';
3104 log_msg(2, "Oh well. I guess I'll just pray then.");
3105 }
3106 if (cdrecord[0]) {
3107 if (!keep_looping) {
3108 retract_CD_tray_and_defeat_autorun();
3109 res = run_program_and_log_output(cdrecord, 5);
3110 } else {
3111 while ((res = run_program_and_log_output(cdrecord, 5))) {
3112 retract_CD_tray_and_defeat_autorun();
3113 if (ask_me_yes_or_no
3114 ("Unable to examine CD. Are you sure this is a valid CD-R(W) CD?"))
3115 {
3116 log_msg(1, "Well, he insisted...");
3117 break;
3118 }
3119 }
3120 }
3121 }
3122 }
3123// retract_CD_tray_and_defeat_autorun();
3124 paranoid_free(tmp);
3125 paranoid_free(cdrecord);
3126 paranoid_free(bkp);
3127 return (res);
3128}
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138/**
3139 * Asks the user to put a CD-R(W) in the drive.
3140 * @param ask_for_one_if_more_than_this (unused)
3141 * @param pmountable If non-NULL, pointed-to value is set to TRUE if the CD is mountable, FALSE otherwise.
3142 */
3143void
3144pause_and_ask_for_cdr(int ask_for_one_if_more_than_this, bool * pmountable)
3145{
3146
3147 /*@ buffers ********************************************* */
3148 char *tmp;
3149 char *szmsg;
3150 char *cdrom_dev;
3151 char *cdrw_dev;
3152 char *our_serial_str;
3153 bool ok_go_ahead_burn_it;
3154 int cd_number = -1;
3155 int attempt_to_mount_returned_this = 999;
3156 char *mtpt;
3157 char *szcdno;
3158 char *szserfname;
3159 char *szunmount;
3160
3161 malloc_string(tmp);
3162 malloc_string(szmsg);
3163 malloc_string(cdrom_dev);
3164 malloc_string(cdrw_dev);
3165 malloc_string(mtpt);
3166 malloc_string(szcdno);
3167 malloc_string(szserfname);
3168 malloc_string(our_serial_str);
3169 malloc_string(szunmount);
3170
3171 sprintf(szmsg, "I am about to burn %s #%d",
3172 media_descriptor_string(g_backup_media_type),
3173 g_current_media_number);
3174 log_to_screen(szmsg);
3175 if (g_current_media_number < ask_for_one_if_more_than_this) {
3176 return;
3177 }
3178 log_to_screen("Scanning CD-ROM drive...");
3179 sprintf(mtpt, "/tmp/cd.mtpt.%ld.%ld", (long int) random(),
3180 (long int) random());
3181 make_hole_for_dir(mtpt);
3182
3183 gotos_make_me_puke:
3184 ok_go_ahead_burn_it = TRUE;
3185 if (!find_cdrom_device(cdrom_dev, FALSE)) {
3186/* When enabled, it made CD eject-and-retract when wrong CD inserted.. Weird
3187 log_msg(2, "paafcd: Retracting CD-ROM drive if possible" );
3188 retract_CD_tray_and_defeat_autorun();
3189*/
3190 sprintf(tmp, "umount %s", cdrom_dev);
3191 run_program_and_log_output(tmp, 1);
3192 sprintf(szcdno, "%s/archives/THIS-CD-NUMBER", mtpt);
3193 sprintf(szserfname, "%s/archives/SERIAL-STRING", mtpt);
3194 sprintf(szunmount, "umount %s", mtpt);
3195 cd_number = -1;
3196 our_serial_str[0] = '\0';
3197 sprintf(tmp, "mount %s %s", cdrom_dev, mtpt);
3198 if ((attempt_to_mount_returned_this =
3199 run_program_and_log_output(tmp, 1))) {
3200 log_msg(4, "Failed to mount %s at %s", cdrom_dev, mtpt);
3201 log_to_screen("If there's a CD/DVD in the drive, it's blank.");
3202 /*
3203 if (interrogate_disk_currently_in_cdrw_drive(cdrw_dev, FALSE))
3204 {
3205 ok_go_ahead_burn_it = FALSE;
3206 log_to_screen("There isn't a writable CD/DVD in the drive.");
3207 }
3208 else
3209 {
3210 log_to_screen("Confirmed. There is a blank CD/DVD in the drive.");
3211 }
3212 */
3213 } else if (!does_file_exist(szcdno)
3214 || !does_file_exist(szserfname)) {
3215 log_to_screen
3216 ("%s has data on it but it's probably not a Mondo CD.",
3217 media_descriptor_string(g_backup_media_type));
3218 } else {
3219 log_to_screen("%s found in drive. It's a Mondo disk.",
3220 media_descriptor_string(g_backup_media_type));
3221 cd_number = atoi(last_line_of_file(szcdno));
3222 sprintf(tmp, "cat %s 2> /dev/null", szserfname);
3223 strcpy(our_serial_str,
3224 call_program_and_get_last_line_of_output(tmp));
3225 // FIXME - should be able to use last_line_of_file(), surely?
3226 }
3227 run_program_and_log_output(szunmount, 1);
3228 log_msg(2, "paafcd: cd_number = %d", cd_number);
3229 log_msg(2, "our serial str = %s; g_serial_string = %s",
3230 our_serial_str, g_serial_string);
3231 if (cd_number > 0 && !strcmp(our_serial_str, g_serial_string)) {
3232 log_msg(2, "This %s is part of this backup set!",
3233 media_descriptor_string(g_backup_media_type));
3234 ok_go_ahead_burn_it = FALSE;
3235 if (cd_number == g_current_media_number - 1) {
3236 log_to_screen
3237 ("I think you've left the previous %s in the drive.",
3238 media_descriptor_string(g_backup_media_type));
3239 } else {
3240 log_to_screen
3241 ("Please remove this %s. It is part of the backup set you're making now.",
3242 media_descriptor_string(g_backup_media_type));
3243 }
3244 } else {
3245 log_to_screen("...but not part of _our_ backup set.");
3246 }
3247 } else {
3248 log_msg(2,
3249 "paafcd: Can't find CD-ROM drive. Perhaps it has a blank %s in it?",
3250 media_descriptor_string(g_backup_media_type));
3251 if (interrogate_disk_currently_in_cdrw_drive(cdrw_dev, FALSE)) {
3252 ok_go_ahead_burn_it = FALSE;
3253 log_to_screen("There isn't a writable %s in the drive.",
3254 media_descriptor_string(g_backup_media_type));
3255 }
3256 }
3257
3258/*
3259 if (g_current_media_number > ask_for_one_if_more_than_this)
3260 {
3261 ok_go_ahead_burn_it = FALSE;
3262 log_it("paafcd: %d > %d, so I'll definitely pause.", g_current_media_number > ask_for_one_if_more_than_this);
3263 }
3264*/
3265
3266 if (!ok_go_ahead_burn_it) {
3267 eject_device(cdrom_dev);
3268 sprintf(tmp,
3269 "I am about to burn %s #%d of the backup set. Please insert %s and press Enter.",
3270 media_descriptor_string(g_backup_media_type),
3271 g_current_media_number,
3272 media_descriptor_string(g_backup_media_type));
3273 popup_and_OK(tmp);
3274 goto gotos_make_me_puke;
3275 } else {
3276 log_msg(2, "paafcd: OK, going ahead and burning it.");
3277 }
3278
3279 log_msg(2,
3280 "paafcd: OK, I assume I have a blank/reusable %s in the drive...",
3281 media_descriptor_string(g_backup_media_type));
3282
3283 // if (ask_for_one_if_more_than_this>1) { popup_and_OK(szmsg); }
3284
3285 log_to_screen("Proceeding w/ %s in drive.",
3286 media_descriptor_string(g_backup_media_type));
3287 paranoid_free(tmp);
3288 paranoid_free(szmsg);
3289 paranoid_free(cdrom_dev);
3290 paranoid_free(cdrw_dev);
3291 paranoid_free(mtpt);
3292 paranoid_free(szcdno);
3293 paranoid_free(szserfname);
3294 paranoid_free(our_serial_str);
3295 paranoid_free(szunmount);
3296 if (pmountable) {
3297 if (attempt_to_mount_returned_this) {
3298 *pmountable = FALSE;
3299 } else {
3300 *pmountable = TRUE;
3301 }
3302 }
3303
3304}
3305
3306
3307
3308
3309
3310
3311
3312
3313/**
3314 * Set the <tt>N</tt>th bit of @c array to @c true_or_false.
3315 * @param array The bit array (as a @c char pointer).
3316 * @param N The bit number to set or reset.
3317 * @param true_or_false If TRUE then set bit @c N, if FALSE then reset bit @c N.
3318 * @see get_bit_N_of_array
3319 */
3320void set_bit_N_of_array(char *array, int N, bool true_or_false)
3321{
3322 int bit_number;
3323 int mask, orig_val, to_add;
3324 int element_number;
3325
3326 assert(array != NULL);
3327
3328 element_number = N / 8;
3329 bit_number = N % 8;
3330 to_add = (1 << bit_number);
3331 mask = 255 - to_add;
3332 orig_val = array[element_number] & mask;
3333 // log_it("array[%d]=%02x; %02x&%02x = %02x", element_number, array[element_number], mask, orig_val);
3334 if (true_or_false) {
3335 array[element_number] = orig_val | to_add;
3336 }
3337}
3338
3339/* @} - end of utilityGroup */
3340
3341
3342
3343
3344
3345
3346
3347
3348/**
3349 * Chop up @c filename.
3350 * @param bkpinfo The backup information structure. Fields used:
3351 * - @c backup_media_type
3352 * - @c compression_level
3353 * - @c optimal_set_size
3354 * - @c tmpdir
3355 * - @c use_lzo
3356 * - @c zip_exe
3357 * - @c zip_suffix
3358 *
3359 * @param biggie_filename The file to chop up.
3360 * @param ntfsprog_fifo The FIFO to ntfsclone if this is an imagedev, NULL otherwise.
3361 * @param biggie_file_number The sequence number of this biggie file (starting from 0).
3362 * @param noof_biggie_files The number of biggie files there are total.
3363 * @return The number of errors encountered (0 for success)
3364 * @see make_slices_and_images
3365 * @ingroup LLarchiveGroup
3366 */
3367int
3368slice_up_file_etc(struct s_bkpinfo *bkpinfo, char *biggie_filename,
3369 char *ntfsprog_fifo, long biggie_file_number,
3370 long noof_biggie_files, bool use_ntfsprog)
3371{
3372
3373 /*@ buffers ************************************************** */
3374 char *tmp, *checksum_line, *command;
3375 char *tempblock;
3376 char *curr_slice_fname_uncompressed;
3377 char *curr_slice_fname_compressed;
3378 char *file_to_archive;
3379 char *file_to_openin;
3380 /*@ pointers ************************************************** */
3381 char *pB;
3382 FILE *fin, *fout;
3383
3384 /*@ bool ****************************************************** */
3385 bool finished = FALSE;
3386
3387 /*@ long ****************************************************** */
3388 size_t blksize = 0;
3389 long slice_num = 0;
3390 long i;
3391 long optimal_set_size;
3392 bool should_I_compress_slices;
3393 char *suffix; // for compressed slices
3394
3395 /*@ long long ************************************************** */
3396 off_t totalread = (off_t)0;
3397 off_t totallength = (off_t)0;
3398 off_t length;
3399
3400 /*@ int ******************************************************** */
3401 int retval = 0;
3402 int res = 0;
3403
3404 /*@ structures ************************************************** */
3405 struct s_filename_and_lstat_info biggiestruct;
3406// struct stat statbuf;
3407
3408 assert(bkpinfo != NULL);
3409 assert_string_is_neither_NULL_nor_zerolength(biggie_filename);
3410 malloc_string(tmp);
3411 malloc_string(checksum_line);
3412 malloc_string(curr_slice_fname_uncompressed);
3413 malloc_string(curr_slice_fname_compressed);
3414 malloc_string(file_to_archive);
3415 malloc_string(suffix);
3416 command = malloc(MAX_STR_LEN * 8);
3417
3418 biggiestruct.for_backward_compatibility = '\n';
3419 biggiestruct.use_ntfsprog = use_ntfsprog;
3420 if (!(tempblock = (char *) malloc(256 * 1024))) {
3421 fatal_error("malloc error 256*1024");
3422 }
3423 optimal_set_size = bkpinfo->optimal_set_size;
3424 if (is_this_file_compressed(biggie_filename)
3425 || bkpinfo->compression_level == 0) {
3426 suffix[0] = '\0';
3427 // log_it("%s is indeed compressed :-)", filename);
3428 should_I_compress_slices = FALSE;
3429 } else {
3430 strcpy(suffix, bkpinfo->zip_suffix);
3431 should_I_compress_slices = TRUE;
3432 }
3433
3434 if (optimal_set_size < 999) {
3435 fatal_error("bkpinfo->optimal_set_size is insanely small");
3436 }
3437 if (ntfsprog_fifo) {
3438 file_to_openin = ntfsprog_fifo;
3439 strcpy(checksum_line, "IGNORE");
3440 log_msg(2,
3441 "Not calculating checksum for %s: it would take too long",
3442 biggie_filename);
3443 if ( !find_home_of_exe("ntfsresize")) {
3444 fatal_error("ntfsresize not found");
3445 }
3446 sprintf(command, "ntfsresize --force --info %s|grep '^You might resize at '|cut -d' ' -f5", biggie_filename);
3447 log_it("command = %s", command);
3448 strcpy (tmp, call_program_and_get_last_line_of_output(command));
3449 log_it("res of it = %s", tmp);
3450 totallength = (off_t)atoll(tmp);
3451 } else {
3452 file_to_openin = biggie_filename;
3453 if (strchr(biggie_filename,'\'') != NULL) {
3454 sprintf(command, "md5sum \"%s\"", biggie_filename);
3455 } else {
3456 sprintf(command, "md5sum '%s'", biggie_filename);
3457 }
3458 if (!(fin = popen(command, "r"))) {
3459 log_OS_error("Unable to popen-in command");
3460 return (1);
3461 }
3462 (void) fgets(checksum_line, MAX_STR_LEN, fin);
3463 pclose(fin);
3464 totallength = length_of_file (biggie_filename);
3465 }
3466 lstat(biggie_filename, &biggiestruct.properties);
3467 strcpy(biggiestruct.filename, biggie_filename);
3468 pB = strchr(checksum_line, ' ');
3469 if (!pB) {
3470 pB = strchr(checksum_line, '\t');
3471 }
3472 if (pB) {
3473 *pB = '\0';
3474 }
3475 strcpy(biggiestruct.checksum, checksum_line);
3476
3477 strcpy(tmp, slice_fname(biggie_file_number, 0, bkpinfo->tmpdir, ""));
3478 fout = fopen(tmp, "w");
3479 if (fout == NULL) {
3480 log_msg(1, "Unable to open and write to %s\n", tmp);
3481 paranoid_free(tmp);
3482 paranoid_free(suffix);
3483 return (1);
3484 }
3485
3486 (void) fwrite((void *) &biggiestruct, 1, sizeof(biggiestruct), fout);
3487 fclose(fout);
3488 length = totallength / optimal_set_size / 1024;
3489 log_msg(1, "Opening in %s; slicing it and writing to CD/tape",
3490 file_to_openin);
3491 if (!(fin = fopen(file_to_openin, "r"))) {
3492 log_OS_error("Unable to openin biggie_filename");
3493 sprintf(tmp, "Cannot archive bigfile '%s': not found",
3494 biggie_filename);
3495 log_to_screen(tmp);
3496 paranoid_free(tempblock);
3497 paranoid_free(tmp);
3498 paranoid_free(checksum_line);
3499 paranoid_free(command);
3500 return (1);
3501 }
3502 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3503 res =
3504 move_files_to_stream(bkpinfo,
3505 slice_fname(biggie_file_number, 0,
3506 bkpinfo->tmpdir, ""), NULL);
3507 } else {
3508 res =
3509 move_files_to_cd(bkpinfo,
3510 slice_fname(biggie_file_number, 0,
3511 bkpinfo->tmpdir, ""), NULL);
3512 }
3513 i = bkpinfo->optimal_set_size / 256;
3514 for (slice_num = 1; !finished; slice_num++) {
3515 strcpy(curr_slice_fname_uncompressed,
3516 slice_fname(biggie_file_number, slice_num, bkpinfo->tmpdir,
3517 ""));
3518 strcpy(curr_slice_fname_compressed,
3519 slice_fname(biggie_file_number, slice_num, bkpinfo->tmpdir,
3520 suffix));
3521
3522 strcpy(tmp, percent_media_full_comment(bkpinfo));
3523 update_progress_form(tmp);
3524 if (!(fout = fopen(curr_slice_fname_uncompressed, "w"))) {
3525 log_OS_error(curr_slice_fname_uncompressed);
3526 return (1);
3527 }
3528 if ((i == bkpinfo->optimal_set_size / 256)
3529 && (totalread < 1.1 * totallength)) {
3530 for (i = 0; i < bkpinfo->optimal_set_size / 256; i++) {
3531 blksize = fread(tempblock, 1, 256 * 1024, fin);
3532 if (blksize > 0) {
3533 totalread = totalread + blksize;
3534 (void) fwrite(tempblock, 1, blksize, fout);
3535 } else {
3536 break;
3537 }
3538 }
3539 } else {
3540 i = 0;
3541 }
3542 paranoid_fclose(fout);
3543 if (i > 0) // length_of_file (curr_slice_fname_uncompressed)
3544 {
3545 if (!does_file_exist(curr_slice_fname_uncompressed)) {
3546 log_msg(2,
3547 "Warning - '%s' doesn't exist. How can I compress slice?",
3548 curr_slice_fname_uncompressed);
3549 }
3550 if (should_I_compress_slices && bkpinfo->compression_level > 0) {
3551 sprintf(command, "%s -%d %s", bkpinfo->zip_exe,
3552 bkpinfo->compression_level,
3553 curr_slice_fname_uncompressed);
3554 log_msg(2, command);
3555 if ((res = system(command))) {
3556 log_OS_error(command);
3557 }
3558 // did_I_compress_slice = TRUE;
3559 } else {
3560 sprintf(command, "mv %s %s 2>> %s",
3561 curr_slice_fname_uncompressed,
3562 curr_slice_fname_compressed, MONDO_LOGFILE);
3563 res = 0; // don't do it :)
3564 // did_I_compress_slice = FALSE;
3565 }
3566 retval += res;
3567 if (res) {
3568 log_msg(2, "Failed to compress the slice");
3569 }
3570 if (bkpinfo->use_lzo
3571 && strcmp(curr_slice_fname_compressed,
3572 curr_slice_fname_uncompressed)) {
3573 unlink(curr_slice_fname_uncompressed);
3574 }
3575 if (res) {
3576 sprintf(tmp, "Problem with slice # %ld", slice_num);
3577 } else {
3578 sprintf(tmp,
3579 "%s - Bigfile #%ld, slice #%ld compressed OK ",
3580 biggie_filename, biggie_file_number + 1,
3581 slice_num);
3582 }
3583#ifndef _XWIN
3584 if (!g_text_mode) {
3585 newtDrawRootText(0, g_noof_rows - 2, tmp);
3586 newtRefresh();
3587 } else {
3588 log_msg(2, tmp);
3589 }
3590#else
3591 log_msg(2, tmp);
3592#endif
3593 strcpy(file_to_archive, curr_slice_fname_compressed);
3594 g_current_progress++;
3595 } else { /* if i==0 then ... */
3596
3597 finished = TRUE;
3598 strcpy(file_to_archive, curr_slice_fname_uncompressed);
3599 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3600 break;
3601 }
3602 }
3603
3604 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3605 register_in_tape_catalog(biggieslice, biggie_file_number,
3606 slice_num, file_to_archive);
3607 maintain_collection_of_recent_archives(bkpinfo->tmpdir,
3608 file_to_archive);
3609 res = move_files_to_stream(bkpinfo, file_to_archive, NULL);
3610 } else {
3611 res = move_files_to_cd(bkpinfo, file_to_archive, NULL);
3612 }
3613 retval += res;
3614 if (res) {
3615 sprintf(tmp,
3616 "Failed to add slice %ld of bigfile %ld to scratchdir",
3617 slice_num, biggie_file_number + 1);
3618 log_to_screen(tmp);
3619 fatal_error
3620 ("Hard disk full. You should have bought a bigger one.");
3621 }
3622 }
3623 paranoid_fclose(fin);
3624 sprintf(tmp, "Sliced bigfile #%ld", biggie_file_number + 1);
3625 if (retval) {
3626 strcat(tmp, "...FAILED");
3627 } else {
3628 strcat(tmp, "...OK!");
3629 }
3630 log_msg(1, tmp);
3631 paranoid_free(tempblock);
3632 paranoid_free(tmp);
3633 paranoid_free(checksum_line);
3634 paranoid_free(command);
3635 paranoid_free(curr_slice_fname_uncompressed);
3636 paranoid_free(curr_slice_fname_compressed);
3637 paranoid_free(file_to_archive);
3638 paranoid_free(suffix);
3639 return (retval);
3640}
3641
3642
3643
3644
3645
3646
3647/**
3648 * Remove the archives in @c d.
3649 * This could possibly include any of:
3650 * - all afioballs (compressed and not)
3651 * - all filelists
3652 * - all slices
3653 * - all checksums
3654 * - a zero filler file
3655 *
3656 * @param d The directory to wipe the archives from.
3657 * @ingroup utilityGroup
3658 */
3659void wipe_archives(char *d)
3660{
3661 /*@ buffers ********************************************* */
3662 char *tmp;
3663 char *dir;
3664
3665 malloc_string(tmp);
3666 malloc_string(dir);
3667 assert_string_is_neither_NULL_nor_zerolength(d);
3668
3669 sprintf(dir, "%s/archives", d);
3670 sprintf(tmp, "find %s -name '*.afio*' -exec rm -f '{}' \\;", dir);
3671 run_program_and_log_output(tmp, FALSE);
3672 sprintf(tmp, "find %s -name '*list.[0-9]*' -exec rm -f '{}' \\;", dir);
3673 run_program_and_log_output(tmp, FALSE);
3674 sprintf(tmp, "find %s -name 'slice*' -exec rm -f '{}' \\;", dir);
3675 run_program_and_log_output(tmp, FALSE);
3676 sprintf(tmp, "rm -f %s/cklist*", dir);
3677 run_program_and_log_output(tmp, FALSE);
3678 sprintf(tmp, "rm -f %s/zero", dir);
3679 run_program_and_log_output(tmp, FALSE);
3680 log_msg(1, "Wiped %s's archives", dir);
3681 sprintf(tmp, "ls -l %s", dir);
3682 run_program_and_log_output(tmp, FALSE);
3683 paranoid_free(tmp);
3684 paranoid_free(dir);
3685}
3686
3687
3688
3689/**
3690 * @addtogroup LLarchiveGroup
3691 * @{
3692 */
3693/**
3694 * Write the final ISO image.
3695 * @param bkpinfo The backup information structure. Used only
3696 * in the call to @c write_iso_and_go_on().
3697 * @return The number of errors encountered (0 for success)
3698 * @see write_iso_and_go_on
3699 * @see make_iso_fs
3700 * @bug The final ISO is written even if there are no files on it. In practice,
3701 * however, this occurs rarely.
3702 */
3703int write_final_iso_if_necessary(struct s_bkpinfo *bkpinfo)
3704{
3705 /*@ int ***************************************************** */
3706 int res;
3707
3708 /*@ buffers ************************************************** */
3709 char *tmp;
3710
3711 malloc_string(tmp);
3712 assert(bkpinfo != NULL);
3713
3714// I should really check if there are any slices or tarballs to be copied to CD-R(W)'s; the odds are approx. 1 in a million that there are no files here, so I'll just go ahead & make one more CD anyway
3715
3716 sprintf(tmp, "Writing the final ISO");
3717 log_msg(2, tmp);
3718 center_string(tmp, 80);
3719#ifndef _XWIN
3720 if (!g_text_mode) {
3721 newtPushHelpLine(tmp);
3722 }
3723#endif
3724 res = write_iso_and_go_on(bkpinfo, TRUE);
3725#ifndef _XWIN
3726 if (!g_text_mode) {
3727 newtPopHelpLine();
3728 }
3729#endif
3730 log_msg(2, "Returning from writing final ISO (res=%d)", res);
3731 paranoid_free(tmp);
3732 return (res);
3733}
3734
3735
3736/**
3737 * Write an ISO image to <tt>[bkpinfo->isodir]/bkpinfo->prefix-[g_current_media_number].iso</tt>.
3738 * @param bkpinfo The backup information structure. Fields used:
3739 * - @c backup_media_type
3740 * - @c prefix
3741 * - @c isodir
3742 * - @c manual_cd_tray
3743 * - @c media_size
3744 * - @c nfs_mount
3745 * - @c nfs_remote_dir
3746 * - @c scratchdir
3747 * - @c verify_data
3748 *
3749 * @param last_cd If TRUE, this is the last CD to write; if FALSE, it's not.
3750 * @return The number of errors encountered (0 for success)
3751 * @see make_iso_fs
3752 */
3753int write_iso_and_go_on(struct s_bkpinfo *bkpinfo, bool last_cd)
3754{
3755 /*@ pointers **************************************************** */
3756 FILE *fout;
3757
3758 /*@ buffers ***************************************************** */
3759 char *tmp;
3760 char *cdno_fname;
3761 char *lastcd_fname;
3762 char *isofile;
3763
3764 /*@ bool ******************************************************** */
3765 bool that_one_was_ok;
3766 bool using_nfs;
3767 bool orig_vfy_flag_val;
3768
3769 /*@ int *********************************************************** */
3770 int res = 0;
3771
3772 malloc_string(tmp);
3773 malloc_string(cdno_fname);
3774 malloc_string(lastcd_fname);
3775 malloc_string(isofile);
3776
3777 assert(bkpinfo != NULL);
3778 orig_vfy_flag_val = bkpinfo->verify_data;
3779 if (bkpinfo->media_size[g_current_media_number] <= 0) {
3780 fatal_error("write_iso_and_go_on() - unknown media size");
3781 }
3782
3783 if (strlen(bkpinfo->nfs_mount) > 1) {
3784 using_nfs = TRUE;
3785 } else {
3786 using_nfs = FALSE;
3787 }
3788 log_msg(1, "OK, time to make %s #%d",
3789 media_descriptor_string(bkpinfo->backup_media_type),
3790 g_current_media_number);
3791
3792 /* label the ISO with its number */
3793
3794 sprintf(cdno_fname, "%s/archives/THIS-CD-NUMBER", bkpinfo->scratchdir);
3795 fout = fopen(cdno_fname, "w");
3796 fprintf(fout, "%d", g_current_media_number);
3797 paranoid_fclose(fout);
3798
3799 sprintf(tmp, "cp -f %s/autorun %s/", g_mondo_home,
3800 bkpinfo->scratchdir);
3801 if (run_program_and_log_output(tmp, FALSE)) {
3802 log_msg(2, "Warning - unable to copy autorun to scratchdir");
3803 }
3804
3805 /* last CD or not? Label accordingly */
3806 sprintf(lastcd_fname, "%s/archives/NOT-THE-LAST", bkpinfo->scratchdir);
3807 if (last_cd) {
3808 unlink(lastcd_fname);
3809 log_msg(2,
3810 "OK, you're telling me this is the last CD. Fair enough.");
3811 } else {
3812 fout = fopen(lastcd_fname, "w");
3813 fprintf(fout,
3814 "You're listening to 90.3 WPLN, Nashville Public Radio.\n");
3815 paranoid_fclose(fout);
3816 }
3817 if (space_occupied_by_cd(bkpinfo->scratchdir) / 1024 >
3818 bkpinfo->media_size[g_current_media_number]) {
3819 sprintf(tmp,
3820 "Warning! CD is too big. It occupies %ld KB, which is more than the %ld KB allowed.",
3821 (long) space_occupied_by_cd(bkpinfo->scratchdir),
3822 (long) bkpinfo->media_size[g_current_media_number]);
3823 log_to_screen(tmp);
3824 }
3825 sprintf(isofile, "%s/%s/%s-%d.iso", bkpinfo->isodir,
3826 bkpinfo->nfs_remote_dir, bkpinfo->prefix,
3827 g_current_media_number);
3828 for (that_one_was_ok = FALSE; !that_one_was_ok;) {
3829 res = make_iso_fs(bkpinfo, isofile);
3830 if (g_current_media_number == 1 && !res
3831 && (bkpinfo->backup_media_type == cdr
3832 || bkpinfo->backup_media_type == cdrw)) {
3833 if (find_cdrom_device(tmp, FALSE)) // make sure find_cdrom_device() finds, records CD-R's loc
3834 {
3835 log_msg(3, "*Sigh* Mike, I hate your computer.");
3836 bkpinfo->manual_cd_tray = TRUE;
3837 } // if it can't be found then force pausing
3838 else {
3839 log_msg(3, "Great. Found Mike's CD-ROM drive.");
3840 }
3841 }
3842 if (bkpinfo->verify_data && !res) {
3843 log_to_screen
3844 ("Please reboot from the 1st %s in Compare Mode, as a precaution.",
3845 media_descriptor_string(g_backup_media_type));
3846 chdir("/");
3847 iamhere("Before calling verify_cd_image()");
3848 res += verify_cd_image(bkpinfo);
3849 iamhere("After calling verify_cd_image()");
3850 }
3851 if (!res) {
3852 that_one_was_ok = TRUE;
3853 } else {
3854 sprintf(tmp, "Failed to burn %s #%d. Retry?",
3855 media_descriptor_string(bkpinfo->backup_media_type),
3856 g_current_media_number);
3857 res = ask_me_yes_or_no(tmp);
3858 if (!res) {
3859 if (ask_me_yes_or_no("Abort the backup?")) {
3860 fatal_error("FAILED TO BACKUP");
3861 } else {
3862 break;
3863 }
3864 } else {
3865 log_msg(2, "Retrying, at user's request...");
3866 res = 0;
3867 }
3868 }
3869 }
3870/*
3871 if (using_nfs)
3872 {
3873 sprintf(tmp,"mv -f %s %s/%s/", isofile, bkpinfo->isodir, bkpinfo->nfs_remote_dir);
3874 if (run_program_and_log_output(tmp, FALSE))
3875 { log_to_screen("Unable to move ISO to NFS dir"); }
3876 }
3877*/
3878 g_current_media_number++;
3879 if (g_current_media_number > MAX_NOOF_MEDIA) {
3880 fatal_error("Too many CD-R(W)'s. Use tape or net.");
3881 }
3882 wipe_archives(bkpinfo->scratchdir);
3883 sprintf(tmp, "rm -Rf %s/images/*gz %s/images/*data*img",
3884 bkpinfo->scratchdir, bkpinfo->scratchdir);
3885 if (system(tmp)) {
3886 log_msg
3887 (2,
3888 "Error occurred when I tried to delete the redundant IMGs and GZs");
3889 }
3890
3891 if (last_cd) {
3892 log_msg(2, "This was your last CD.");
3893 } else {
3894 log_msg(2, "Continuing to backup your data...");
3895 }
3896
3897 bkpinfo->verify_data = orig_vfy_flag_val;
3898 paranoid_free(tmp);
3899 paranoid_free(cdno_fname);
3900 paranoid_free(lastcd_fname);
3901 paranoid_free(isofile);
3902 return (0);
3903}
3904
3905/* @} - end of LLarchiveGroup */
3906
3907
3908
3909
3910/**
3911 * Verify the user's data.
3912 * @param bkpinfo The backup information structure. Fields used:
3913 * - @c backup_data
3914 * - @c backup_media_type
3915 * - @c media_device
3916 * - @c verify_data
3917 *
3918 * @return The number of errors encountered (0 for success)
3919 * @ingroup verifyGroup
3920 */
3921int verify_data(struct s_bkpinfo *bkpinfo)
3922{
3923 int res = 0, retval = 0, cdno = 0;
3924 char *tmp;
3925 long diffs = 0;
3926
3927 malloc_string(tmp);
3928 assert(bkpinfo != NULL);
3929 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3930 chdir("/");
3931 mvaddstr_and_log_it(g_currentY, 0,
3932 "Verifying archives against live filesystem");
3933 if (bkpinfo->backup_media_type == cdstream) {
3934 strcpy(bkpinfo->media_device, "/dev/cdrom");
3935 }
3936 verify_tape_backups(bkpinfo);
3937 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
3938 } else if (bkpinfo->backup_data)
3939 //bkpinfo->backup_media_type == cdrw || bkpinfo->backup_media_type == cdr))
3940 {
3941 log_msg(2,
3942 "Not verifying again. Per-CD/ISO verification already carried out.");
3943 paranoid_system
3944 ("cat /tmp/changed.files.* > /tmp/changed.files 2> /dev/null");
3945 } else {
3946 g_current_media_number = cdno;
3947 if (bkpinfo->backup_media_type != iso) {
3948 find_cdrom_device(bkpinfo->media_device, FALSE); // replace 0,0,0 with /dev/cdrom
3949 }
3950 chdir("/");
3951 for (cdno = 1; cdno < 99 && bkpinfo->verify_data; cdno++) {
3952 if (cdno != g_current_media_number) {
3953 log_msg(2,
3954 "Warning - had to change g_current_media_number from %d to %d",
3955 g_current_media_number, cdno);
3956 g_current_media_number = cdno;
3957 }
3958 if (bkpinfo->backup_media_type != iso) {
3959 insist_on_this_cd_number(bkpinfo, cdno);
3960 }
3961 res = verify_cd_image(bkpinfo); // sets verify_data to FALSE if it's time to stop verifying
3962 retval += res;
3963 if (res) {
3964 sprintf(tmp,
3965 "Warnings/errors were reported while checking %s #%d",
3966 media_descriptor_string(bkpinfo->
3967 backup_media_type),
3968 g_current_media_number);
3969 log_to_screen(tmp);
3970
3971 }
3972 }
3973/*
3974 sprintf (tmp,
3975 "cat %s | grep \"afio: \" | cut -d'\"' -f2 | sort -u | awk '{print \"/\"$0;};' | tr -s '/' '/' | grep -vx \"/afio:.*\" > /tmp/changed.files",
3976 MONDO_LOGFILE);
3977 system (tmp);
3978*/
3979 sprintf(tmp,
3980 "grep 'afio: ' %s | sed 's/afio: //' | grep -vE '^/dev/.*$' >> /tmp/changed.files",
3981 MONDO_LOGFILE);
3982 system(tmp);
3983
3984 sprintf(tmp,
3985 "grep 'star: ' %s | sed 's/star: //' | grep -vE '^/dev/.*$' >> /tmp/changed.files",
3986 MONDO_LOGFILE);
3987 system(tmp);
3988 run_program_and_log_output("umount " MNT_CDROM, FALSE);
3989// if (bkpinfo->backup_media_type != iso && !bkpinfo->please_dont_eject_when_restoring)
3990//{
3991 eject_device(bkpinfo->media_device);
3992//}
3993 }
3994 diffs = count_lines_in_file("/tmp/changed.files");
3995
3996 if (diffs > 0) {
3997 if (retval == 0) {
3998 retval = (int) (-diffs);
3999 }
4000 }
4001 paranoid_free(tmp);
4002 return (retval);
4003}
4004
4005
4006
4007
4008
4009/**
4010 * @addtogroup utilityGroup
4011 * @{
4012 */
4013/**
4014 * Write an image to a real 3.5" floppy disk.
4015 * @param device The device to write to (e.g. @c /dev/fd0)
4016 * @param datafile The image to write to @p device.
4017 * @return The number of errors encountered (0 for success)
4018 * @see write_image_to_floppy
4019 */
4020int write_image_to_floppy_SUB(char *device, char *datafile)
4021{
4022 /*@ int *************************************************************** */
4023 int res = 0;
4024 int percentage = 0;
4025 int blockno = 0;
4026 int maxblocks = 0;
4027
4028 /*@ buffers************************************************************ */
4029 char *tmp;
4030 char blk[1024];
4031 char *title;
4032
4033 /*@ pointers ********************************************************** */
4034 char *p;
4035 FILE *fout, *fin;
4036
4037
4038 malloc_string(tmp);
4039 malloc_string(title);
4040 /* pretty stuff */
4041 if (!(p = strrchr(datafile, '/'))) {
4042 p = datafile;
4043 } else {
4044 p++;
4045 }
4046 sprintf(title, "Writing %s to floppy", p);
4047 open_evalcall_form(title);
4048 /* functional stuff */
4049 for (p = device + strlen(device); p != device && isdigit(*(p - 1));
4050 p--);
4051 maxblocks = atoi(p);
4052 if (!maxblocks) {
4053 maxblocks = 1440;
4054 }
4055 sprintf(tmp, "maxblocks = %d; p=%s", maxblocks, p);
4056 log_msg(2, tmp);
4057 /* copy data from image to floppy */
4058 if (!(fin = fopen(datafile, "r"))) {
4059 log_OS_error("Cannot open img");
4060 return (1);
4061 }
4062 if (!(fout = fopen(device, "w"))) {
4063 log_OS_error("Cannot open fdd");
4064 return (1);
4065 }
4066 for (blockno = 0; blockno < maxblocks; blockno++) {
4067 percentage = blockno * 100 / maxblocks;
4068 if (fread(blk, 1, 1024, fin) != 1024) {
4069 if (feof(fin)) {
4070 log_msg(1,
4071 "img read err - img ended prematurely - non-fatal error");
4072 sleep(3);
4073 return (res);
4074 }
4075 res++;
4076 log_to_screen("img read err");
4077 }
4078 if (fwrite(blk, 1, 1024, fout) != 1024) {
4079 res++;
4080 log_to_screen("fdd write err");
4081 }
4082 if (((blockno + 1) % 128) == 0) {
4083 paranoid_system("sync"); /* fflush doesn't work; dunno why */
4084 update_evalcall_form(percentage);
4085 }
4086 }
4087 paranoid_fclose(fin);
4088 paranoid_fclose(fout);
4089 paranoid_free(tmp);
4090 paranoid_free(title);
4091 close_evalcall_form();
4092 return (res);
4093}
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103/**
4104 * Wrapper around @c write_image_to_floppy_SUB().
4105 * This function, unlike @c write_image_to_floppy_SUB(),
4106 * gives the user the opportunity to retry if the write fails.
4107 * @see write_image_to_floppy_SUB
4108 */
4109int write_image_to_floppy(char *device, char *datafile)
4110{
4111 /*@ int ************************************************************** */
4112 int res = 0;
4113
4114 assert_string_is_neither_NULL_nor_zerolength(device);
4115 assert_string_is_neither_NULL_nor_zerolength(datafile);
4116
4117 while ((res = write_image_to_floppy_SUB(device, datafile))) {
4118 if (!ask_me_yes_or_no("Failed to write image to floppy. Retry?")) {
4119 return (res);
4120 }
4121 }
4122 return (res);
4123}
4124
4125/* @} - end of utilityGroup */
4126
4127void setenv_mondo_share(void) {
4128
4129setenv("MONDO_SHARE", MONDO_SHARE, 1);
4130}
Note: See TracBrowser for help on using the repository browser.