source: MondoRescue/branches/3.1/mondo/src/common/libmondo-archive.c@ 3190

Last change on this file since 3190 was 3190, checked in by Bruno Cornec, 11 years ago
  • Modification to 3.1 branch to make it extremely similar to 3.0. What remains are function rewrite with allocation in the function and desallocation outside of the function. Will be next step
  • Property svn:keywords set to Id
File size: 98.6 KB
Line 
1/* libmondo-archive.c
2 $Id: libmondo-archive.c 3190 2013-09-25 06:55:43Z bruno $
3
4subroutines to handle the archiving of files
5*/
6
7/**
8 * @file
9 * Functions to handle backing up data.
10 * This is the main file (at least the longest one) in libmondo.
11 */
12
13#include "my-stuff.h"
14#include "mr_mem.h"
15#include "mr_str.h"
16#include "mondostructures.h"
17#include "libmondo-string-EXT.h"
18#include "libmondo-stream-EXT.h"
19#include "libmondo-devices-EXT.h"
20#include "libmondo-tools-EXT.h"
21#include "libmondo-gui-EXT.h"
22#include "libmondo-fork-EXT.h"
23#include "libmondo-files-EXT.h"
24#include "libmondo-filelist-EXT.h"
25#include "libmondo-tools-EXT.h"
26#include "libmondo-verify-EXT.h"
27#include "libmondo-archive.h"
28#include "lib-common-externs.h"
29#include <sys/sem.h>
30#include <sys/types.h>
31#include <sys/ipc.h>
32#include <stdarg.h>
33#define DVDRWFORMAT 1
34
35
36
37#ifndef _SEMUN_H
38#define _SEMUN_H
39
40 /**
41 * The semaphore union, provided only in case the user's system doesn't.
42 */
43union semun {
44 int val;
45 struct semid_ds *buf;
46 unsigned short int *array;
47 struct seminfo *__buf;
48};
49#endif
50
51/*@unused@*/
52//static char cvsid[] = "$Id: libmondo-archive.c 3190 2013-09-25 06:55:43Z bruno $";
53//
54extern char *get_non_rewind_dev(char *);
55
56/* *************************** external global vars ******************/
57extern int g_current_media_number;
58extern int g_currentY;
59extern bool g_text_mode;
60extern bool g_exiting;
61extern long g_current_progress;
62extern FILE *g_tape_stream;
63extern long long g_tape_posK;
64extern bool g_cd_recovery;
65extern char *g_mondo_home;
66
67/**
68 * The serial string (used to differentiate between backups) of the current backup.
69 */
70char *g_serial_string = NULL;
71
72extern char *g_getfacl;
73extern char *g_getfattr;
74extern char *MONDO_LOGFILE;
75
76/* Reference to global bkpinfo */
77extern struct s_bkpinfo *bkpinfo;
78
79
80/**
81 * @addtogroup globalGroup
82 * @{
83 */
84/**
85 * The current backup media type in use.
86 */
87t_bkptype g_backup_media_type = none;
88
89/**
90 * Incremented by each archival thread when it starts up. After that,
91 * this is the number of threads running.
92 */
93int g_current_thread_no = 0;
94
95/* @} - end of globalGroup */
96
97extern int g_noof_rows;
98
99/* Semaphore-related code */
100
101static int set_semvalue(void);
102static void del_semvalue(void);
103static int semaphore_p(void);
104static int semaphore_v(void);
105
106static int g_sem_id;
107static int g_sem_key;
108
109/**
110 * Initialize the semaphore.
111 * @see del_semvalue
112 * @see semaphore_p
113 * @see semaphore_v
114 * @return 1 for success, 0 for failure.
115 */
116static int set_semvalue(void) // initializes semaphore
117{
118 union semun sem_union;
119 sem_union.val = 1;
120 if (semctl(g_sem_id, 0, SETVAL, sem_union) == -1) {
121 return (0);
122 }
123 return (1);
124}
125
126/**
127 * Frees (deletes) the semaphore. Failure is indicated by a log
128 * message.
129 * @see set_semvalue
130 */
131static void del_semvalue(void) // deletes semaphore
132{
133 union semun sem_union;
134
135 if (semctl(g_sem_id, 0, IPC_RMID, sem_union) == -1) {
136 log_msg(3, "Failed to delete semaphore");
137 }
138}
139
140/**
141 * Acquire (increment) the semaphore (change status to P).
142 * @return 1 for success, 0 for failure.
143 * @see semaphore_v
144 */
145static int semaphore_p(void) // changes status to 'P' (waiting)
146{
147 struct sembuf sem_b;
148
149 sem_b.sem_num = 0;
150 sem_b.sem_op = -1; // P()
151 sem_b.sem_flg = SEM_UNDO;
152 if (semop(g_sem_id, &sem_b, 1) == -1) {
153 log_msg(3, "semaphore_p failed");
154 return (0);
155 }
156 return (1);
157}
158
159/**
160 * Free (decrement) the semaphore (change status to V).
161 * @return 1 for success, 0 for failure.
162 */
163static int semaphore_v(void) // changes status to 'V' (free)
164{
165 struct sembuf sem_b;
166
167 sem_b.sem_num = 0;
168 sem_b.sem_op = 1; // V()
169 sem_b.sem_flg = SEM_UNDO;
170 if (semop(g_sem_id, &sem_b, 1) == -1) {
171 log_msg(3, "semaphore_v failed");
172 return (0);
173 }
174 return (1);
175}
176
177
178//------------------------------------------------------
179
180
181/**
182 * Size in megabytes of the buffer afforded to the executable "buffer".
183 * This figure is used when we calculate how much data we have probably 'lost'
184 * when writing off the end of tape N, so that we can then figure out how much
185 * data we must recreate & write to the start of tape N+1.
186 */
187extern int g_tape_buffer_size_MB;
188
189
190
191
192int
193archive_this_fileset_with_star(char *filelist, char *fname, int setno)
194{
195 int retval = 0;
196 unsigned int res = 0;
197 int tries = 0;
198 char *command = NULL;
199 char *tmp = NULL;
200 char *p;
201
202
203 if (!does_file_exist(filelist)) {
204 log_to_screen("(archive_this_fileset) - filelist %s does not exist", filelist);
205 return (1);
206 }
207
208 mr_asprintf(tmp, "echo hi > %s 2> /dev/null", fname);
209 if (system(tmp)) {
210 mr_free(tmp);
211 fatal_error("Unable to write tarball to scratchdir");
212 }
213 paranoid_free(tmp);
214
215 mr_asprintf(command, "star H=exustar list=%s -c -sparse " STAR_ACL_SZ " file=%s", filelist, fname);
216 if (bkpinfo->use_lzo) {
217 mr_free(command);
218 fatal_error("Can't use lzop");
219 }
220 if (bkpinfo->compression_level > 0) {
221 mr_strcat(command, " -bz");
222 }
223 mr_strcat(command, " 2>> %s", MONDO_LOGFILE);
224 log_msg(4, "command = '%s'", command);
225
226 for (res = 99, tries = 0; tries < 3 && res != 0; tries++) {
227 log_msg(5, "command='%s'", command);
228 res = system(command);
229 tmp = last_line_of_file(MONDO_LOGFILE);
230 log_msg(1, "res=%d; tmp='%s'", res, tmp);
231 if (bkpinfo->use_star && (res == 254 || res == 65024)
232 && strstr(tmp, "star: Processed all possible files")
233 && tries > 0) {
234 log_msg(1, "Star returned nonfatal error");
235 res = 0;
236 }
237 mr_free(tmp);
238
239 if (res) {
240 log_OS_error(command);
241 p = strstr(command, "-acl ");
242 if (p) {
243 p[0] = p[1] = p[2] = p[3] = ' ';
244 log_msg(1, "new command = '%s'", command);
245 } else {
246 log_msg(3,
247 "Attempt #%d failed. Pausing 3 seconds and retrying...",
248 tries + 1);
249 sleep(3);
250 }
251 }
252 }
253 mr_free(command);
254
255 retval += res;
256 if (retval) {
257 log_msg(3, "Failed to write set %d", setno);
258 } else if (tries > 1) {
259 log_msg(3, "Succeeded in writing set %d, on try #%d", setno,
260 tries);
261 }
262 return (retval);
263}
264
265
266/**
267 * Call @c afio to archive the filelist @c filelist to the file @c fname.
268 *
269 * @param bkpinfo The backup information structure. Fields used:
270 * - @c compression_level
271 * - @c scratchdir (only verifies existence)
272 * - @c tmpdir (only verifies existence)
273 * - @c zip_exe
274 * - @c zip_suffix
275 * @param filelist The path to a file containing a list of files to be archived
276 * in this fileset.
277 * @param fname The output file to archive to.
278 * @param setno This fileset number.
279 * @return The number of errors encountered (0 for success).
280 * @ingroup LLarchiveGroup
281 */
282int
283archive_this_fileset(char *filelist, char *fname, int setno)
284{
285
286 /*@ int *************************************************************** */
287 int retval = 0;
288 int res = 0;
289 int tries = 0;
290 /*
291 int i = 0;
292 static int free_ramdisk_space = 9999;
293 */
294
295 /*@ buffers ************************************************************ */
296 char *command = NULL;
297 char *zipparams = NULL;
298 char *tmp = NULL;
299
300 assert(bkpinfo != NULL);
301 assert_string_is_neither_NULL_nor_zerolength(filelist);
302 assert_string_is_neither_NULL_nor_zerolength(fname);
303
304 if (bkpinfo->compression_level > 0 && bkpinfo->use_star) {
305 return (archive_this_fileset_with_star(filelist, fname, setno));
306 }
307
308 if (!does_file_exist(filelist)) {
309 log_to_screen("(archive_this_fileset) - filelist %s does not exist", filelist);
310 return (1);
311 }
312 mr_asprintf(tmp, "echo hi > %s 2> /dev/null", fname);
313 if (system(tmp)) {
314 mr_free(tmp);
315 fatal_error("Unable to write tarball to scratchdir");
316 }
317 mr_free(tmp);
318
319
320 if (bkpinfo->compression_level > 0) {
321 mr_asprintf(tmp, "%s/do-not-compress-these", g_mondo_home);
322 // -b %ld, TAPE_BLOCK_SIZE
323 mr_asprintf(zipparams, "-Z -P %s -G %d -T 3k", bkpinfo->zip_exe, bkpinfo->compression_level);
324 if (does_file_exist(tmp)) {
325 mr_strcat(zipparams, " -E %s",tmp);
326 } else {
327 log_msg(3, "%s not found. Cannot exclude zipfiles, etc.", tmp);
328 }
329 mr_free(tmp);
330 } else {
331 mr_asprintf(zipparams, "");
332 }
333
334 if (!does_file_exist(bkpinfo->tmpdir)) {
335 log_OS_error("tmpdir not found");
336 fatal_error("tmpdir not found");
337 }
338 if (!does_file_exist(bkpinfo->scratchdir)) {
339 log_OS_error("scratchdir not found");
340 fatal_error("scratchdir not found");
341 }
342 mr_asprintf(command, "rm -f %s %s. %s.gz %s.%s", fname, fname, fname, fname, bkpinfo->zip_suffix);
343 paranoid_system(command);
344 mr_free(command);
345
346 mr_asprintf(command, "afio -o -b %ld -M 16m %s %s < %s 2>> %s", TAPE_BLOCK_SIZE, zipparams, fname, filelist, MONDO_LOGFILE);
347 mr_free(zipparams);
348
349 mr_asprintf(tmp, "echo hi > %s 2> /dev/null", fname);
350 if (system(tmp)) {
351 mr_free(tmp);
352 fatal_error("Unable to write tarball to scratchdir");
353 }
354 mr_free(tmp);
355
356 for (res = 99, tries = 0; tries < 3 && res != 0; tries++) {
357 log_msg(5, "command='%s'", command);
358 res = system(command);
359 if (res) {
360 log_OS_error(command);
361 log_msg(3,
362 "Attempt #%d failed. Pausing 3 seconds and retrying...",
363 tries + 1);
364 sleep(3);
365 }
366 }
367 paranoid_free(command);
368
369 retval += res;
370 if (retval) {
371 log_msg(3, "Failed to write set %d", setno);
372 } else if (tries > 1) {
373 log_msg(3, "Succeeded in writing set %d, on try #%d", setno,
374 tries);
375 }
376
377 return (retval);
378}
379
380
381
382
383
384
385/**
386 * Wrapper function for all the backup commands.
387 * Calls these other functions: @c prepare_filelist(),
388 * @c call_filelist_chopper(), @c copy_mondo_and_mindi_stuff_to_scratchdir(),
389 * @c call_mindi_to_supply_boot_disks(), @c do_that_initial_phase(),
390 * @c make_those_afios_phase(), @c make_those_slices_phase(), and
391 * @c do_that_final_phase(). If anything fails before @c do_that_initial_phase(),
392 * @c fatal_error is called with a suitable message.
393 * @param bkpinfo The backup information structure. Uses most fields.
394 * @return The number of non-fatal errors encountered (0 for success).
395 * @ingroup archiveGroup
396 */
397int backup_data()
398{
399 int retval = 0, res = 0;
400 char *tmp = NULL;
401
402 assert(bkpinfo != NULL);
403 set_g_cdrom_and_g_dvd_to_bkpinfo_value();
404 if (bkpinfo->backup_media_type == dvd) {
405#ifdef DVDRWFORMAT
406 tmp = find_home_of_exe("dvd+rw-format");
407 if (!tmp) {
408 mr_free(tmp);
409 fatal_error("Cannot find dvd+rw-format. Please install it or fix your PATH.");
410 }
411 mr_free(tmp);
412#endif
413 tmp = find_home_of_exe("growisofs");
414 if (!tmp) {
415 mr_free(tmp);
416 fatal_error("Cannot find growisofs. Please install it or fix your PATH.");
417 }
418 mr_free(tmp);
419 }
420
421 if ((res = prepare_filelist())) { /* generate scratchdir/filelist.full */
422 fatal_error("Failed to generate filelist catalog");
423 }
424 if (call_filelist_chopper()) {
425 fatal_error("Failed to run filelist chopper");
426 }
427
428 mr_asprintf(tmp, "gzip -9 %s/archives/filelist.full", bkpinfo->scratchdir);
429 if (run_program_and_log_output(tmp, 2)) {
430 mr_free(tmp);
431 fatal_error("Failed to gzip filelist.full");
432 }
433 mr_free(tmp);
434
435 mr_asprintf(tmp, "cp -f %s/archives/*list*.gz %s", bkpinfo->scratchdir, bkpinfo->tmpdir);
436 if (run_program_and_log_output(tmp, 2)) {
437 mr_free(tmp);
438 fatal_error("Failed to copy to tmpdir");
439 }
440 mr_free(tmp);
441
442 copy_mondo_and_mindi_stuff_to_scratchdir(); // payload, too, if it exists
443 mr_free(bkpinfo->kernel_path);
444#if __FreeBSD__ == 5
445 mr_asprintf(bkpinfo->kernel_path, "/boot/kernel/kernel");
446#elif __FreeBSD__ == 4
447 mr_asprintf(bkpinfo->kernel_path, "/kernel");
448#elif linux
449 if ((bkpinfo->kernel_path = figure_out_kernel_path_interactively_if_necessary()) == NULL) {
450 fatal_error("Kernel not found. Please specify manually with the '-k' switch.");
451 }
452#else
453#error "I don't know about this system!"
454#endif
455 if ((res = call_mindi_to_supply_boot_disks())) {
456 fatal_error("Failed to generate boot+data disks");
457 }
458 retval += do_that_initial_phase(); // prepare
459 mr_asprintf(tmp, "rm -f %s/images/*.iso", bkpinfo->scratchdir);
460 run_program_and_log_output(tmp, 1);
461 mr_free(tmp);
462
463 retval += make_those_afios_phase(); // backup regular files
464 retval += make_those_slices_phase(); // backup BIG files
465 retval += do_that_final_phase(); // clean up
466 log_msg(1, "Creation of archives... complete.");
467 if (bkpinfo->verify_data) {
468 sleep(2);
469 }
470 return (retval);
471}
472
473
474
475
476/**
477 * Call Mindi to generate boot and data disks.
478 * @note This binds correctly to the new Perl version of mindi.
479 * @param bkpinfo The backup information structure. Fields used:
480 * - @c backup_media_type
481 * - @c boot_loader
482 * - @c boot_device
483 * - @c compression_level
484 * - @c differential
485 * - @c image_devs
486 * - @c kernel_path
487 * - @c make_cd_use_lilo
488 * - @c media_device
489 * - @c media_size
490 * - @c nonbootable_backup
491 * - @c scratchdir
492 * - @c tmpdir
493 * - @c use_lzo
494 *
495 * @return The number of errors encountered (0 for success)
496 * @bug The code to automagically determine the boot drive
497 * is messy and system-dependent. In particular, it breaks
498 * for Linux RAID and LVM users.
499 * @ingroup MLarchiveGroup
500 */
501int call_mindi_to_supply_boot_disks()
502{
503 /*@ buffer ************************************************************ */
504 char *tmp = NULL;
505 char *tmp1 = NULL;
506 char *tmp2 = NULL;
507 char *command = NULL;
508 char *use_lzo_sz = NULL;
509 char *use_gzip_sz = NULL;
510 char *use_lzma_sz = NULL;
511 char *use_comp_sz = NULL;
512 char *use_star_sz = NULL;
513 char *bootldr_str = NULL;
514 char *bootldr_ver = NULL;
515 char *tape_device = NULL;
516 char *last_filelist_number = NULL;
517 char *broken_bios_sz = NULL;
518 char *cd_recovery_sz = NULL;
519 char *tape_size_sz = NULL;
520 char *use_lilo_sz = NULL; /* BCO: shared between LILO/ELILO */
521 char *value = NULL;
522 char *bootdev = NULL;
523 char *ntapedev = NULL;
524
525
526
527 /*@ char ************************************************************** */
528 char ch = '\0';
529
530 /*@ long ********************************************************** */
531 long lines_in_filelist = 0;
532
533 /*@ int ************************************************************* */
534 int res = 0;
535 long estimated_total_noof_slices = 0;
536
537 assert(bkpinfo != NULL);
538
539 mvaddstr_and_log_it(g_currentY, 0, "Calling MINDI to create boot+data disks");
540 open_evalcall_form("Calling MINDI to create boot+data disks");
541 mr_asprintf(tmp, "%s/filelist.full", bkpinfo->tmpdir);
542 if (!does_file_exist(tmp)) {
543 mr_free(tmp);
544 mr_asprintf(tmp, "%s/tmpfs/filelist.full", bkpinfo->tmpdir);
545 if (!does_file_exist(tmp)) {
546 mr_free(tmp);
547 fatal_error ("Cannot find filelist.full, so I cannot count its lines");
548 }
549 }
550 lines_in_filelist = count_lines_in_file(tmp);
551 mr_free(tmp);
552
553 mr_asprintf(tmp, "%s/LAST-FILELIST-NUMBER", bkpinfo->tmpdir);
554 mr_asprintf(last_filelist_number, "%s", last_line_of_file(tmp));
555 mr_free(tmp);
556
557 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
558 mr_asprintf(tape_size_sz, "%ld", bkpinfo->media_size);
559 if (bkpinfo->media_device) {
560 ntapedev = get_non_rewind_dev(bkpinfo->media_device);
561 }
562 if ((bkpinfo->use_obdr) && (ntapedev != NULL)) {
563 mr_free(bkpinfo->media_device);
564 mr_asprintf(bkpinfo->media_device,"%s",ntapedev);
565 } else {
566 if (ntapedev == NULL) {
567 log_it("Not able to create OBDR - Restore will have to be done manually");
568 }
569 }
570 mr_free(ntapedev);
571 if (bkpinfo->media_device) {
572 mr_asprintf(tape_device, "%s", bkpinfo->media_device);
573 } else {
574 mr_asprintf(tape_device, "");
575 }
576 } else {
577 mr_asprintf(tape_size_sz, "%ld", 0L);;
578 mr_asprintf(tape_device, "");
579 }
580 if (bkpinfo->use_lzo) {
581 mr_asprintf(use_lzo_sz, "yes");
582 } else {
583 mr_asprintf(use_lzo_sz, "no");
584 }
585 if (bkpinfo->use_gzip) {
586 mr_asprintf(use_gzip_sz, "yes");
587 } else {
588 mr_asprintf(use_gzip_sz, "no");
589 }
590 if (bkpinfo->use_lzma) {
591 mr_asprintf(use_lzma_sz, "yes");
592 } else {
593 mr_asprintf(use_lzma_sz, "no");
594 }
595 if (bkpinfo->use_star) {
596 mr_asprintf(use_star_sz, "yes");
597 } else {
598 mr_asprintf(use_star_sz, "no");
599 }
600
601 if (bkpinfo->compression_level > 0) {
602 mr_asprintf(use_comp_sz, "yes");
603 } else {
604 mr_asprintf(use_comp_sz, "no");
605 }
606
607 mr_asprintf(broken_bios_sz, "yes"); /* assume so */
608 if (g_cd_recovery) {
609 mr_asprintf(cd_recovery_sz, "yes");
610 } else {
611 mr_asprintf(cd_recovery_sz, "no");
612 }
613 if (bkpinfo->make_cd_use_lilo) {
614 mr_asprintf(use_lilo_sz, "yes");
615 } else {
616 mr_asprintf(use_lilo_sz, "no");
617 }
618
619 if (!bkpinfo->nonbootable_backup && (bkpinfo->boot_loader == '\0' || bkpinfo->boot_device == NULL)) {
620 update_evalcall_form(2);
621
622#ifdef __FreeBSD__
623 bootdev = call_program_and_get_last_line_of_output("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'",TRUE);
624 if (!bootdev[0]) {
625 mr_free(bootdev);
626 bootdev = call_program_and_get_last_line_of_output("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/\\([0-9]\\).*/\\1/'",TRUE);
627 }
628#else
629 /* Linux */
630#ifdef __IA64__
631 bootdev = call_program_and_get_last_line_of_output("mount | grep ' /boot/efi ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'",TRUE);
632#else
633 bootdev = call_program_and_get_last_line_of_output("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'",TRUE);
634#endif
635 if (strstr(bootdev, "/dev/cciss/")) {
636 mr_free(bootdev);
637#ifdef __IA64__
638 bootdev = call_program_and_get_last_line_of_output("mount | grep ' /boot/efi ' | head -1 | cut -d' ' -f1 | cut -dp -f1",TRUE);
639#else
640 bootdev = call_program_and_get_last_line_of_output("mount | grep ' /boot ' | head -1 | cut -d' ' -f1 | cut -dp -f1",TRUE);
641#endif
642 }
643 if (!bootdev[0]) {
644 mr_free(bootdev);
645 bootdev = call_program_and_get_last_line_of_output("mount | grep ' / ' | head -1 | cut -d' ' -f1 | sed 's/[0-9].*//'",TRUE);
646 if (strstr(bootdev, "/dev/cciss/")) {
647 mr_free(bootdev);
648 bootdev = call_program_and_get_last_line_of_output("mount | grep ' / ' | head -1 | cut -d' ' -f1 | cut -dp -f1",TRUE);
649 }
650 }
651 /* Linux */
652#endif
653 if (bootdev[0])
654 ch = which_boot_loader(bootdev);
655 else
656 ch = 'U';
657 if (bkpinfo->boot_loader != '\0') {
658 log_msg(2, "User specified boot loader. It is '%c'.", bkpinfo->boot_loader);
659 } else {
660 bkpinfo->boot_loader = ch;
661 }
662 if (bkpinfo->boot_device != NULL) {
663 log_msg(2, "User specified boot device. It is '%s'.", bkpinfo->boot_device);
664 } else {
665 mr_asprintf(bkpinfo->boot_device, "%s", bootdev);
666 }
667 }
668 mr_free(bootdev);
669
670 if (
671#ifdef __FreeBSD__
672 bkpinfo->boot_loader != 'B' && bkpinfo->boot_loader != 'D' &&
673#endif
674#ifdef __IA64__
675 bkpinfo->boot_loader != 'E' &&
676#endif
677 bkpinfo->boot_loader != 'L' && bkpinfo->boot_loader != 'G'
678 && bkpinfo->boot_loader != 'R'
679 && !bkpinfo->nonbootable_backup) {
680 fatal_error
681 ("Please specify your boot loader and device, e.g. -l GRUB -f /dev/hda. Type 'man mondoarchive' to read the manual.");
682 }
683 if (bkpinfo->boot_loader == 'L') {
684 mr_asprintf(bootldr_str, "LILO");
685 if (!does_file_exist("/etc/lilo.conf")) {
686 fatal_error("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?");
687 }
688 } else if (bkpinfo->boot_loader == 'G') {
689 mr_asprintf(bootldr_str, "GRUB");
690 if (!does_file_exist("/boot/grub/menu.lst") && does_file_exist("/boot/grub/grub.conf")) {
691 run_program_and_log_output("ln -sf /boot/grub/grub.conf /boot/grub/menu.lst", 5);
692 }
693 if ((!does_file_exist("/boot/grub/menu.lst")) && (!does_file_exist("/boot/grub/grub.cfg")) && (!does_file_exist("/boot/grub2/grub.cfg"))) {
694 fatal_error("The de facto standard location for your boot loader's config file is /boot/grub/menu.lst, /boot/grub/grub.cfg, or /boot/grub2/grub.cfg but I cannot find it there. What is wrong with your Linux distribution?");
695 }
696 mr_asprintf(bootldr_ver, "%s", call_program_and_get_last_line_of_output("grub --version", TRUE));
697 } else if (bkpinfo->boot_loader == 'E') {
698 mr_asprintf(bootldr_str, "ELILO");
699 /* BCO: fix it for Debian, Mandrake, ... */
700 if (!does_file_exist("/etc/elilo.conf") && does_file_exist("/boot/efi/efi/redhat/elilo.conf")) {
701 run_program_and_log_output("ln -sf /boot/efi/efi/redhat/elilo.conf /etc/elilo.conf", 5);
702 }
703 if (!does_file_exist("/etc/elilo.conf") && does_file_exist("/boot/efi/efi/SuSE/elilo.conf")) {
704 run_program_and_log_output("ln -sf /boot/efi/efi/SuSE/elilo.conf /etc/elilo.conf", 5);
705 }
706 if (!does_file_exist("/etc/elilo.conf") && does_file_exist("/boot/efi/efi/debian/elilo.conf")) {
707 run_program_and_log_output ("ln -sf /boot/efi/efi/debian/elilo.conf /etc/elilo.conf", 5);
708 }
709 if (!does_file_exist("/etc/elilo.conf") && does_file_exist("/boot/efi/debian/elilo.conf")) {
710 run_program_and_log_output ("ln -sf /boot/efi/debian/elilo.conf /etc/elilo.conf", 5);
711 }
712 if (!does_file_exist("/etc/elilo.conf")) {
713 fatal_error("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'");
714 }
715 } else if (bkpinfo->boot_loader == 'R') {
716 mr_asprintf(bootldr_str, "RAW");
717 }
718#ifdef __FreeBSD__
719 else if (bkpinfo->boot_loader == 'D') {
720 mr_asprintf(bootldr_str, "DD");
721 }
722
723 else if (bkpinfo->boot_loader == 'B') {
724 mr_asprintf(bootldr_str, "BOOT0");
725 }
726#endif
727 else {
728 mr_asprintf(bootldr_str, "unknown");
729 }
730 log_to_screen("Your boot loader is %s and it boots from %s", bootldr_str, bkpinfo->boot_device);
731
732 if (bootldr_ver != NULL) {
733 log_to_screen("Boot loader version string: %s", bootldr_ver);
734 }
735
736 mr_asprintf(tmp, "%s/BOOTLOADER.DEVICE", bkpinfo->tmpdir);
737 if (write_one_liner_data_file(tmp, bkpinfo->boot_device)) {
738 log_msg(1, "%ld: Unable to write one-liner boot device", __LINE__);
739 }
740 mr_free(tmp);
741
742 switch (bkpinfo->backup_media_type) {
743 case cdr:
744 mr_asprintf(value, "cdr");
745 break;
746 case cdrw:
747 mr_asprintf(value, "cdrw");
748 break;
749 case cdstream:
750 mr_asprintf(value, "cdstream");
751 break;
752 case tape:
753 mr_asprintf(value, "tape");
754 break;
755 case udev:
756 mr_asprintf(value, "udev");
757 break;
758 case iso:
759 mr_asprintf(value, "iso");
760 break;
761 case netfs:
762 mr_asprintf(value, "netfs");
763 break;
764 case dvd:
765 mr_asprintf(value, "dvd");
766 break;
767 case usb:
768 mr_asprintf(value, "usb");
769 break;
770 default:
771 fatal_error("Unknown backup_media_type");
772 }
773
774 if ((bkpinfo->backup_media_type == usb) && (bkpinfo->media_device)) {
775 mr_asprintf(tmp2, "--usb %s", bkpinfo->media_device);
776 } else {
777 mr_asprintf(tmp2," ");
778 }
779
780 mr_asprintf(tmp, "%s/BACKUP-MEDIA-TYPE", bkpinfo->tmpdir);
781 if (write_one_liner_data_file(tmp, value)) {
782 res++;
783 log_msg(1, "%ld: Unable to write one-liner backup-media-type", __LINE__);
784 }
785 mr_free(value);
786 mr_free(tmp);
787
788 mr_asprintf(tmp, "%s/BOOTLOADER.NAME", bkpinfo->tmpdir);
789 if (write_one_liner_data_file(tmp, bootldr_str)) {
790 res++;
791 log_msg(1, "%ld: Unable to write one-liner bootloader.name", __LINE__);
792 }
793 mr_free(bootldr_str);
794 mr_free(tmp);
795
796 mr_asprintf(tmp, "%s/BOOTLOADER.VER", bkpinfo->tmpdir);
797 if (write_one_liner_data_file(tmp, bootldr_ver)) {
798 res++;
799 log_msg(1, "%ld: Unable to write one-liner bootloader.ver",
800 __LINE__);
801 }
802 mr_free(bootldr_ver);
803 mr_free(tmp);
804
805 mr_asprintf(tmp, "%s/DIFFERENTIAL", bkpinfo->tmpdir);
806 if (bkpinfo->differential) {
807 res += write_one_liner_data_file(tmp, "1");
808 } else {
809 res += write_one_liner_data_file(tmp, "0");
810 }
811 mr_free(tmp);
812
813 if (g_getfattr) {
814 mr_asprintf(tmp1, "%s/XATTR", bkpinfo->tmpdir);
815 if (write_one_liner_data_file(tmp1, "TRUE")) {
816 log_msg(1, "%ld: Unable to write one-liner XATTR",
817 __LINE__);
818 }
819 paranoid_free(tmp1);
820 }
821 if (g_getfacl) {
822 mr_asprintf(tmp1, "%s/ACL", bkpinfo->tmpdir);
823 if (write_one_liner_data_file(tmp1, "TRUE")) {
824 log_msg(1, "%ld: Unable to write one-liner ACL",
825 __LINE__);
826 }
827 paranoid_free(tmp1);
828 }
829 if (bkpinfo->use_obdr) {
830 mr_asprintf(tmp1, "%s/OBDR", bkpinfo->tmpdir);
831 if (write_one_liner_data_file(tmp1, "TRUE")) {
832 log_msg(1, "%ld: Unable to write one-liner OBDR",
833 __LINE__);
834 }
835 paranoid_free(tmp1);
836 }
837
838 estimated_total_noof_slices = size_of_all_biggiefiles_K(bkpinfo) / bkpinfo->optimal_set_size + 1;
839
840 /* TODO: add netfs stuff here? */
841 mr_asprintf(command, "mkdir -p %s/images", bkpinfo->scratchdir);
842 if (system(command)) {
843 res++;
844 log_OS_error("Unable to make images directory");
845 }
846 mr_free(command);
847 log_msg(1, "lines_in_filelist = %ld", lines_in_filelist);
848 update_evalcall_form(3);
849
850/* "mindi --custom 2=%s 3=%s/images 4=\"%s\" 5=\"%s\" \
8516=\"%s\" 7=%ld 8=\"%s\" 9=\"%s\" 10=\"%s\" \
85211=\"%s\" 12=%s 13=%ld 14=\"%s\" 15=\"%s\" 16=\"%s\" 17=\"%s\" 18=%ld 19=%d",*/
853 mr_asprintf(command, "mindi %s --custom %s %s/images '%s' '%s' \
854'%s' %ld '%s' '%s' '%s' \
855'%s' %s %ld '%s' '%s' '%s' '%s' %ld %d '%s'", tmp2, bkpinfo->tmpdir, // parameter #2
856 bkpinfo->scratchdir, // parameter #3
857 bkpinfo->kernel_path, // parameter #4
858 tape_device, // parameter #5
859 tape_size_sz, // parameter #6
860 lines_in_filelist, // parameter #7 (INT)
861 use_lzo_sz, // parameter #8
862 cd_recovery_sz, // parameter #9
863 (bkpinfo->image_devs == NULL) ? "\"\"" : bkpinfo->image_devs, // parameter #10
864 broken_bios_sz, // parameter #11
865 last_filelist_number, // parameter #12 (STRING)
866 estimated_total_noof_slices, // parameter #13 (INT)
867 (bkpinfo->exclude_devs == NULL) ? "\"\"" : bkpinfo->exclude_devs, // parameter #14
868 use_comp_sz, // parameter #15
869 use_lilo_sz, // parameter #16
870 use_star_sz, // parameter #17
871 bkpinfo->internal_tape_block_size, // parameter #18 (LONG)
872 bkpinfo->differential, // parameter #19 (INT)
873 use_gzip_sz, // parameter #19 (STRING)
874 use_lzma_sz, // parameter #20 (STRING)
875 value, // parameter #21 (STRING)
876 MONDO_LOGFILE);
877
878 mr_free(last_filelist_number);
879 mr_free(tape_device);
880 mr_free(use_lzo_sz);
881 mr_free(use_gzip_sz);
882 mr_free(use_lzma_sz);
883 mr_free(use_star_sz);
884 mr_free(use_comp_sz);
885 mr_free(broken_bios_sz);
886 mr_free(cd_recovery_sz);
887 mr_free(use_lilo_sz);
888 mr_free(tape_size_sz);
889
890 /* This parameter is always the last one and optional */
891 if (bkpinfo->nonbootable_backup) {
892 mr_strcat(command, " NONBOOTABLE");
893 }
894 log_msg(2, command);
895
896// popup_and_OK("Pausing");
897
898 res = run_external_binary_with_percentage_indicator_NEW("Generating boot+data disks", command);
899 update_evalcall_form(99);
900 paranoid_free(command);
901
902 if (bkpinfo->nonbootable_backup) {
903 res = 0;
904 } // hack
905 if (!res) {
906 log_to_screen("Boot+data disks were created OK");
907 mr_asprintf(command, "cp -f /%s/mindi.iso %s/mondorescue.iso", MINDI_CACHE_REL, MINDI_CACHE);
908 log_msg(2, command);
909 run_program_and_log_output(command, FALSE);
910 mr_free(command);
911
912 mr_asprintf(command, "cp -f /%s/all.tar.gz %s/images", MINDI_CACHE_REL, bkpinfo->scratchdir);
913 if (system(command)) {
914 mr_free(command);
915 fatal_error("Unable to create temporary all tarball");
916 }
917 mr_free(command);
918
919 /* For USB we already have everything on the key */
920 if (bkpinfo->backup_media_type == usb) {
921 mr_asprintf(command, "rm -rf %s/images", bkpinfo->scratchdir);
922 run_program_and_log_output(command, FALSE);
923 mr_free(command);
924 } else {
925 mr_asprintf(tmp, "cp -f %s/images/all.tar.gz %s", bkpinfo->scratchdir, bkpinfo->tmpdir);
926 if (system(tmp)) {
927 fatal_error("Cannot find all.tar.gz in tmpdir");
928 }
929 mr_free(tmp);
930 }
931 if (res) {
932 mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
933 } else {
934 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
935 }
936 } else {
937 log_to_screen("Mindi failed to create your boot+data disks.");
938 mr_asprintf(command, "grep 'Fatal error' /var/log/mindi.log");
939 tmp = call_program_and_get_last_line_of_output(command,TRUE);
940 mr_free(command);
941
942 if (strlen(tmp) > 1) {
943 popup_and_OK(tmp);
944 }
945 mr_free(tmp);
946 }
947 close_evalcall_form();
948 return (res);
949}
950
951
952
953/**
954 * Maximum number of filesets allowed in this function.
955 */
956#define MAX_NOOF_SETS_HERE 32767
957
958/**
959 * Offset of the bkpinfo pointer (in bytes) from the
960 * buffer passed to create_afio_files_in_background.
961 */
962#define BKPINFO_LOC_OFFSET (16+MAX_NOOF_SETS_HERE/8+16)
963
964/**
965 * Main function for each @c afio thread.
966 * @param inbuf A transfer block containing:
967 * - @c p_last_set_archived: [offset 0] pointer to an @c int
968 * containing the last set archived.
969 * - @c p_archival_threads_running: [offset 4] pointer to an @c int
970 * containing the number of archival threads currently running.
971 * - @c p_next_set_to_archive: [offset 8] pointer to an @c int containing
972 * the next set that should be archived.
973 * - @c p_list_of_fileset_flags: [offset 12] @c char pointer pointing to a
974 * bit array, where each bit corresponds to a filelist (1=needs
975 * to be archived, 0=archived).
976 * - @c bkpinfo: [offset BKPINFO_LOC_OFFSET] pointer to backup information
977 * structure. Fields used:
978 * - @c tmpdir
979 * - @c zip_suffix
980 *
981 * Any of the above may be modified by the caller at any time.
982 *
983 * @bug Assumes @c int pointers are 4 bytes.
984 * @see archive_this_fileset
985 * @see make_afioballs_and_images
986 * @return NULL, always.
987 * @ingroup LLarchiveGroup
988 */
989void *create_afio_files_in_background(void *inbuf)
990{
991 long int archiving_set_no = 0L;
992 char *archiving_filelist_fname = NULL;
993 char *archiving_afioball_fname = NULL;
994 char *curr_xattr_list_fname = NULL;
995 char *curr_acl_list_fname = NULL;
996
997 char *tmp = NULL;
998 int res = 0, retval = 0;
999 int *p_archival_threads_running;
1000 int *p_last_set_archived;
1001 int *p_next_set_to_archive;
1002 char *p_list_of_fileset_flags;
1003 int this_thread_no = g_current_thread_no++;
1004
1005 p_last_set_archived = (int *) inbuf;
1006 p_archival_threads_running = (int *) (inbuf + 4);
1007 p_next_set_to_archive = (int *) (inbuf + 8);
1008 p_list_of_fileset_flags = (char *) (inbuf + 12);
1009
1010 mr_asprintf(archiving_filelist_fname, FILELIST_FNAME_RAW_SZ, bkpinfo->tmpdir, 0L);
1011
1012 while (does_file_exist(archiving_filelist_fname)) {
1013 if (g_exiting) {
1014 mr_free(archiving_filelist_fname);
1015 fatal_error("Execution run aborted (pthread)");
1016 }
1017 if (archiving_set_no >= MAX_NOOF_SETS_HERE) {
1018 mr_free(archiving_filelist_fname);
1019 fatal_error("Maximum number of filesets exceeded. Adjust MAX_NOOF_SETS_HERE, please.");
1020 }
1021 if (!semaphore_p()) {
1022 log_msg(3, "P sem failed (pid=%d)", (int) getpid());
1023 mr_free(archiving_filelist_fname);
1024 fatal_error("Cannot get semaphore P");
1025 }
1026 if (archiving_set_no < *p_next_set_to_archive) {
1027 archiving_set_no = *p_next_set_to_archive;
1028 }
1029 *p_next_set_to_archive = *p_next_set_to_archive + 1;
1030 if (!semaphore_v()) {
1031 mr_free(archiving_filelist_fname);
1032 fatal_error("Cannot get semaphore V");
1033 }
1034
1035 /* backup this set of files */
1036 mr_asprintf(archiving_afioball_fname, AFIOBALL_FNAME_RAW_SZ, bkpinfo->tmpdir, archiving_set_no, bkpinfo->zip_suffix);
1037 mr_free(archiving_filelist_fname);
1038 mr_asprintf(archiving_filelist_fname, FILELIST_FNAME_RAW_SZ, bkpinfo->tmpdir, archiving_set_no);
1039 if (!does_file_exist(archiving_filelist_fname)) {
1040 log_msg(3, "%s[%d:%d] - well, I would archive %d, except that it doesn't exist. I'll stop now.", FORTY_SPACES, getpid(), this_thread_no, archiving_set_no);
1041 mr_free(archiving_afioball_fname);
1042 break;
1043 }
1044
1045 mr_asprintf(tmp, AFIOBALL_FNAME_RAW_SZ, bkpinfo->tmpdir, archiving_set_no - ARCH_BUFFER_NUM, bkpinfo->zip_suffix);
1046 if (does_file_exist(tmp)) {
1047 log_msg(4, "%s[%d:%d] - waiting for storer", FORTY_SPACES, getpid(), this_thread_no);
1048 while (does_file_exist(tmp)) {
1049 sleep(1);
1050 }
1051 log_msg(4, "[%d] - continuing", getpid());
1052 }
1053 mr_free(tmp);
1054
1055 log_msg(4, "%s[%d:%d] - EXATing %d...", FORTY_SPACES, getpid(), this_thread_no, archiving_set_no);
1056
1057 if (g_getfattr) {
1058 mr_asprintf(curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ, bkpinfo->tmpdir, archiving_set_no);
1059 get_fattr_list(archiving_filelist_fname, curr_xattr_list_fname);
1060 mr_free(curr_xattr_list_fname);
1061 }
1062 if (g_getfacl) {
1063 mr_asprintf(curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ, bkpinfo->tmpdir, archiving_set_no);
1064 get_acl_list(archiving_filelist_fname, curr_acl_list_fname);
1065 mr_free(curr_acl_list_fname);
1066 }
1067
1068 log_msg(4, "%s[%d:%d] - archiving %d...", FORTY_SPACES, getpid(), this_thread_no, archiving_set_no);
1069 res = archive_this_fileset(archiving_filelist_fname, archiving_afioball_fname, archiving_set_no);
1070 mr_free(archiving_afioball_fname);
1071
1072 retval += res;
1073
1074 if (res) {
1075 log_to_screen("Errors occurred while archiving set %ld. Please review logs.", archiving_set_no);
1076 }
1077
1078 if (!semaphore_p()) {
1079 mr_free(archiving_filelist_fname);
1080 fatal_error("Cannot get semaphore P");
1081 }
1082
1083 set_bit_N_of_array(p_list_of_fileset_flags, archiving_set_no, 5);
1084
1085 if (*p_last_set_archived < archiving_set_no) {
1086 *p_last_set_archived = archiving_set_no;
1087 } // finished archiving this one
1088
1089 if (!semaphore_v()) {
1090 mr_free(archiving_filelist_fname);
1091 fatal_error("Cannot get semaphore V");
1092 }
1093 log_msg(4, "%s[%d:%d] - archived %d OK", FORTY_SPACES, getpid(), this_thread_no, archiving_set_no);
1094 archiving_set_no++;
1095
1096 mr_free(archiving_filelist_fname);
1097 mr_asprintf(archiving_filelist_fname, FILELIST_FNAME_RAW_SZ, bkpinfo->tmpdir, archiving_set_no);
1098 }
1099 mr_free(archiving_filelist_fname);
1100
1101 if (!semaphore_p()) {
1102 fatal_error("Cannot get semaphore P");
1103 }
1104 (*p_archival_threads_running)--;
1105 if (!semaphore_v()) {
1106 fatal_error("Cannot get semaphore V");
1107 }
1108 log_msg(3, "%s[%d:%d] - exiting", FORTY_SPACES, getpid(), this_thread_no);
1109 pthread_exit(NULL);
1110}
1111
1112
1113
1114
1115
1116/**
1117 * Finalize the backup.
1118 * For streaming backups, this writes the closing block
1119 * to the stream. For CD-based backups, this creates
1120 * the final ISO image.
1121 * @param bkpinfo The backup information structure, used only
1122 * for the @c backup_media_type.
1123 * @ingroup MLarchiveGroup
1124 */
1125int do_that_final_phase()
1126{
1127
1128 /*@ int ************************************** */
1129 int res = 0;
1130 int retval = 0;
1131
1132 /*@ buffers ********************************** */
1133
1134 assert(bkpinfo != NULL);
1135 mvaddstr_and_log_it(g_currentY, 0,
1136 "Writing any remaining data to media ");
1137
1138 log_msg(1, "Closing tape/CD/USB ... ");
1139 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1140 /* write tape/cdstream */
1141 closeout_tape();
1142 } else {
1143 /* write final ISO/USB */
1144 res = write_final_iso_if_necessary();
1145 retval += res;
1146 if (res) {
1147 log_msg(1, "write_final_iso_if_necessary returned an error");
1148 }
1149 }
1150 log_msg(2, "Fork is exiting ... ");
1151
1152 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1153
1154 /* final stuff */
1155 if (retval) {
1156 mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
1157 } else {
1158 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1159 }
1160
1161 return (retval);
1162}
1163
1164
1165/**
1166 * Initialize the backup.
1167 * Does the following:
1168 * - Sets up the serial number.
1169 * - For streaming backups, opens the tape stream and writes the data disks
1170 * and backup headers.
1171 * - For CD-based backups, wipes the ISOs in the target directory.
1172 *
1173 * @param bkpinfo The backup information structure. Fields used:
1174 * - @c backup_media_type
1175 * - @c cdrw_speed
1176 * - @c prefix
1177 * - @c isodir
1178 * - @c media_device
1179 * - @c scratchdir
1180 * - @c tmpdir
1181 * @return The number of errors encountered (0 for success).
1182 * @ingroup MLarchiveGroup
1183 */
1184int do_that_initial_phase()
1185{
1186 /*@ int *************************************** */
1187 int retval = 0;
1188
1189 /*@ buffers *********************************** */
1190 char *command = NULL;
1191 char *tmpfile = NULL;
1192 char *data_disks_file = NULL;
1193
1194 assert(bkpinfo != NULL);
1195 mr_asprintf(data_disks_file, "/%s/all.tar.gz", MINDI_CACHE_REL);
1196
1197 g_serial_string = call_program_and_get_last_line_of_output("dd if=/dev/urandom bs=16 count=1 2> /dev/null | hexdump | tr -s ' ' '0' | head -n1",TRUE);
1198 mr_strip_spaces(g_serial_string);
1199 mr_strcat(g_serial_string, "...word.");
1200 log_msg(2, "g_serial_string = '%s'", g_serial_string);
1201
1202 mr_asprintf(tmpfile, "%s/archives/SERIAL-STRING", bkpinfo->scratchdir);
1203 if (write_one_liner_data_file(tmpfile, g_serial_string)) {
1204 log_msg(1, "%ld: Failed to write serial string", __LINE__);
1205 }
1206 mr_free(tmpfile);
1207
1208 mvaddstr_and_log_it(g_currentY, 0, "Preparing to archive your data");
1209 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1210 if (bkpinfo->backup_media_type == cdstream) {
1211 openout_cdstream(bkpinfo->media_device, bkpinfo->cdrw_speed);
1212 } else {
1213 openout_tape(); /* sets g_tape_stream */
1214 }
1215 if (!g_tape_stream) {
1216 fatal_error("Cannot open backup (streaming) device");
1217 }
1218 log_msg(1, "Backup (stream) opened OK");
1219 write_data_disks_to_stream(data_disks_file);
1220 } else {
1221 if (bkpinfo->backup_media_type == usb) {
1222 log_msg(1, "Backing up to USB's");
1223 } else {
1224 log_msg(1, "Backing up to CD's");
1225 }
1226 }
1227 mr_free(data_disks_file);
1228
1229 if ((bkpinfo->isodir != NULL) && (bkpinfo->prefix != NULL)) {
1230 if (bkpinfo->netfs_remote_dir) {
1231 // NFS
1232 mr_asprintf(command, "rm -f %s/%s/%s-[1-9]*.iso", bkpinfo->isodir, bkpinfo->netfs_remote_dir, bkpinfo->prefix);
1233 } else {
1234 // ISO
1235 mr_asprintf(command, "rm -f %s/%s-[1-9]*.iso", bkpinfo->isodir, bkpinfo->prefix);
1236 }
1237 paranoid_system(command);
1238 mr_free(command);
1239 }
1240
1241 wipe_archives(bkpinfo->scratchdir);
1242 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
1243 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1244 write_header_block_to_stream((off_t)0, "start-of-tape",
1245 BLK_START_OF_TAPE);
1246 write_header_block_to_stream((off_t)0, "start-of-backup",
1247 BLK_START_OF_BACKUP);
1248 }
1249 return (retval);
1250}
1251
1252
1253/**
1254 * Get the <tt>N</tt>th bit of @c array.
1255 * @param array The bit-array (as a @c char pointer).
1256 * @param N The number of the bit you want.
1257 * @return TRUE (bit is set) or FALSE (bit is not set).
1258 * @see set_bit_N_of_array
1259 * @ingroup utilityGroup
1260 */
1261bool get_bit_N_of_array(char *array, int N)
1262{
1263 int element_number;
1264 int bit_number;
1265 int mask;
1266
1267 element_number = N / 8;
1268 bit_number = N % 8;
1269 mask = 1 << bit_number;
1270 if (array[element_number] & mask) {
1271 return (TRUE);
1272 } else {
1273 return (FALSE);
1274 }
1275}
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285/**
1286 * @addtogroup LLarchiveGroup
1287 * @{
1288 */
1289/**
1290 * Start up threads to archive your files.
1291 *
1292 * This function starts @c ARCH_THREADS threads,
1293 * each starting execution in @c create_afio_files_in_background().
1294 * Each thread will archive individual filesets, based on the
1295 * pointers passed to it and continually updated, until all files
1296 * have been backed up. This function coordinates the threads
1297 * and copies their output to the @c scratchdir.
1298 *
1299 * @param bkpinfo The backup information structure. Fields used:
1300 * - @c backup_media_type
1301 * - @c scratchdir
1302 * - @c tmpdir
1303 * - @c zip_suffix
1304 *
1305 * @return The number of errors encountered (0 for success)
1306 */
1307int make_afioballs_and_images()
1308{
1309
1310 /*@ int ************************************************** */
1311 int retval = 0;
1312 long int storing_set_no = 0;
1313 int res = 0;
1314 bool done_storing = FALSE;
1315 char *result_str;
1316 char *transfer_block;
1317 void *vp;
1318 void **pvp;
1319
1320 /*@ buffers ********************************************** */
1321 char *storing_filelist_fname = NULL;
1322 char *storing_afioball_fname = NULL;
1323 char *tmp = NULL;
1324 char *media_usage_comment = NULL;
1325 pthread_t archival_thread[ARCH_THREADS];
1326 char *p_list_of_fileset_flags;
1327 int *p_archival_threads_running;
1328 int *p_last_set_archived;
1329 int *p_next_set_to_archive;
1330 int noof_threads;
1331 int i;
1332 char *curr_xattr_list_fname = NULL;
1333 char *curr_acl_list_fname = NULL;
1334 int misc_counter_that_is_not_important = 0;
1335
1336 log_msg(8, "here");
1337 assert(bkpinfo != NULL);
1338 malloc_string(result_str);
1339 transfer_block = malloc(sizeof(struct s_bkpinfo) + BKPINFO_LOC_OFFSET + 64);
1340 memset((void *) transfer_block, 0, sizeof(struct s_bkpinfo) + BKPINFO_LOC_OFFSET + 64);
1341 p_last_set_archived = (int *) transfer_block;
1342 p_archival_threads_running = (int *) (transfer_block + 4);
1343 p_next_set_to_archive = (int *) (transfer_block + 8);
1344 p_list_of_fileset_flags = (char *) (transfer_block + 12);
1345 memcpy((void *) (transfer_block + BKPINFO_LOC_OFFSET), (void *) bkpinfo, sizeof(struct s_bkpinfo));
1346 pvp = &vp;
1347 vp = (void *) result_str;
1348 *p_archival_threads_running = 0;
1349 *p_last_set_archived = -1;
1350 *p_next_set_to_archive = 0;
1351 log_to_screen("Archiving regular files");
1352 log_msg(5, "Go, Shorty. It's your birthday.");
1353 open_progress_form("Backing up filesystem",
1354 "I am backing up your live filesystem now.",
1355 "Please wait. This may take a couple of hours.",
1356 "Working...",
1357 (long)get_last_filelist_number() + 1L);
1358
1359 log_msg(5, "We're gonna party like it's your birthday.");
1360
1361 srand((unsigned int) getpid());
1362 g_sem_key = 1234 + random() % 30000;
1363 if ((g_sem_id =
1364 semget((key_t) g_sem_key, 1,
1365 IPC_CREAT | S_IREAD | S_IWRITE)) == -1) {
1366 fatal_error("MABAI - unable to semget");
1367 }
1368 if (!set_semvalue()) {
1369 fatal_error("Unable to init semaphore");
1370 } // initialize semaphore
1371 for (noof_threads = 0; noof_threads < ARCH_THREADS; noof_threads++) {
1372 log_msg(8, "Creating thread #%d", noof_threads);
1373 (*p_archival_threads_running)++;
1374 if ((res =
1375 pthread_create(&archival_thread[noof_threads], NULL,
1376 create_afio_files_in_background,
1377 (void *) transfer_block))) {
1378 fatal_error("Unable to create an archival thread");
1379 }
1380 }
1381
1382 log_msg(8, "About to enter while() loop");
1383 while (!done_storing) {
1384 if (g_exiting) {
1385 fatal_error("Execution run aborted (main loop)");
1386 }
1387 if (*p_archival_threads_running == 0
1388 && *p_last_set_archived == storing_set_no - 1) {
1389 log_msg(2,
1390 "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... :-)",
1391 *p_last_set_archived, storing_set_no);
1392 done_storing = TRUE;
1393 } else
1394 if (!get_bit_N_of_array
1395 (p_list_of_fileset_flags, storing_set_no)) {
1396 misc_counter_that_is_not_important = (misc_counter_that_is_not_important + 1) % 5;
1397 /* BCO the media_usage_comment is not really initialized there !
1398 if (!misc_counter_that_is_not_important) {
1399 update_progress_form(media_usage_comment);
1400 }
1401 */
1402 sleep(1);
1403 } else {
1404 // store set N
1405 mr_asprintf(storing_filelist_fname, FILELIST_FNAME_RAW_SZ, bkpinfo->tmpdir, storing_set_no);
1406 mr_asprintf(storing_afioball_fname, AFIOBALL_FNAME_RAW_SZ, bkpinfo->tmpdir, storing_set_no, bkpinfo->zip_suffix);
1407 if (g_getfattr) {
1408 mr_asprintf(curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ, bkpinfo->tmpdir, storing_set_no);
1409 }
1410 if (g_getfacl) {
1411 mr_asprintf(curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ, bkpinfo->tmpdir, storing_set_no);
1412 }
1413
1414 log_msg(2, "Storing set %d", storing_set_no);
1415 while (!does_file_exist(storing_filelist_fname)
1416 || !does_file_exist(storing_afioball_fname)) {
1417 log_msg(2,
1418 "Warning - either %s or %s doesn't exist yet. I'll pause 5 secs.",
1419 storing_filelist_fname, storing_afioball_fname);
1420 sleep(5);
1421 }
1422 /* copy to CD (scratchdir) ... and an actual CD-R if necessary */
1423 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1424 register_in_tape_catalog(fileset, storing_set_no, -1,
1425 storing_afioball_fname);
1426 maintain_collection_of_recent_archives(storing_afioball_fname);
1427 log_it("Writing EXAT files");
1428 res +=
1429 write_EXAT_files_to_tape(curr_xattr_list_fname,
1430 curr_acl_list_fname);
1431 // archives themselves
1432 res +=
1433 move_files_to_stream(storing_afioball_fname,
1434 NULL);
1435 } else {
1436 if (g_getfacl) {
1437 if (g_getfattr) {
1438 res = move_files_to_cd(storing_filelist_fname,
1439 curr_xattr_list_fname,
1440 curr_acl_list_fname,
1441 storing_afioball_fname, NULL);
1442 } else {
1443 res = move_files_to_cd(storing_filelist_fname,
1444 curr_acl_list_fname,
1445 storing_afioball_fname, NULL);
1446 }
1447 } else {
1448 if (g_getfattr) {
1449 res = move_files_to_cd(storing_filelist_fname,
1450 curr_xattr_list_fname,
1451 storing_afioball_fname, NULL);
1452 } else {
1453 res = move_files_to_cd(storing_filelist_fname,
1454 storing_afioball_fname, NULL);
1455 }
1456 }
1457 }
1458 retval += res;
1459 g_current_progress++;
1460
1461 media_usage_comment = percent_media_full_comment();
1462 update_progress_form(media_usage_comment);
1463 mr_free(media_usage_comment);
1464 if (res) {
1465 log_to_screen("Failed to add archive %ld's files to CD dir\n", storing_set_no);
1466 fatal_error("Is your hard disk full? If not, please send the author the logfile.");
1467 }
1468 storing_set_no++;
1469 // sleep(2);
1470 if (g_getfacl) {
1471 mr_free(curr_acl_list_fname);
1472 }
1473 if (g_getfattr) {
1474 mr_free(curr_xattr_list_fname);
1475 }
1476 mr_free(storing_filelist_fname);
1477 mr_free(storing_afioball_fname);
1478 }
1479 }
1480 close_progress_form();
1481
1482 mr_asprintf(tmp, "Your regular files have been archived ");
1483 log_msg(2, "Joining background threads to foreground thread");
1484 for (i = 0; i < noof_threads; i++) {
1485 pthread_join(archival_thread[i], pvp);
1486 log_msg(3, "Thread %d of %d: closed OK", i + 1, noof_threads);
1487 }
1488 del_semvalue();
1489 log_msg(2, "Done.");
1490 if (retval) {
1491 mr_strcat(tmp, "(with errors).");
1492 } else {
1493 mr_strcat(tmp, "successfully.");
1494 }
1495 log_to_screen(tmp);
1496 mr_free(tmp);
1497
1498 paranoid_free(transfer_block);
1499 paranoid_free(result_str);
1500 return (retval);
1501}
1502
1503
1504void pause_for_N_seconds(int how_long, char *msg)
1505{
1506 int i;
1507 open_evalcall_form(msg);
1508 for (i = 0; i < how_long; i++) {
1509 update_evalcall_form((int) ((100.0 / (float) (how_long) * i)));
1510 sleep(1);
1511 }
1512 close_evalcall_form();
1513}
1514
1515
1516
1517
1518/**
1519 * Create a USB image in @c destfile, from files in @c bkpinfo->scratchdir.
1520 *
1521 * @param bkpinfo The backup information structure. Fields used:
1522 * - @c backup_media_type
1523 * - @c nonbootable_backup
1524 * - @c scratchdir
1525 *
1526 * @param destfile Where to put the generated USB image.
1527 * @return The number of errors encountered (0 for success)
1528 */
1529int make_usb_fs()
1530{
1531 /*@ int ********************************************** */
1532 int retval = 0;
1533 int res;
1534
1535 /*@ buffers ****************************************** */
1536 char *tmp = NULL;
1537 char *tmp1 = NULL;
1538 char *result_sz = NULL;
1539 char *message_to_screen = NULL;
1540 char *old_pwd;
1541 char *mds = NULL;
1542
1543 malloc_string(old_pwd);
1544 assert(bkpinfo != NULL);
1545
1546 log_msg(2, "make_usb_fs --- scratchdir=%s", bkpinfo->scratchdir);
1547 tmp1 = getcwd(old_pwd, MAX_STR_LEN - 1);
1548 mr_asprintf(tmp, "chmod 700 %s", bkpinfo->scratchdir);
1549 run_program_and_log_output(tmp, FALSE);
1550 mr_free(tmp);
1551 if (chdir(bkpinfo->scratchdir)) {
1552 // FIXME
1553 }
1554
1555 mds = media_descriptor_string(bkpinfo->backup_media_type);
1556 mr_asprintf(message_to_screen, "Copying data to make %s #%d",mds, g_current_media_number);
1557 mr_free(mds);
1558 log_msg(1, message_to_screen);
1559
1560 if (bkpinfo->media_device) {
1561 mr_asprintf(tmp1, "%s1", bkpinfo->media_device);
1562 } else {
1563 mr_asprintf(tmp1, "");
1564 }
1565 if (is_this_device_mounted(tmp1)) {
1566 log_msg(1, "USB device mounted. Remounting it at the right place");
1567 mr_asprintf(tmp, "umount %s", tmp1);
1568 run_program_and_log_output(tmp, FALSE);
1569 mr_free(tmp);
1570 }
1571 mr_free(tmp1);
1572
1573 log_msg(1, "Mounting USB device.");
1574 mr_asprintf(tmp1, "%s/usb", bkpinfo->tmpdir);
1575 mr_asprintf(tmp, "mkdir -p %s", tmp1);
1576 run_program_and_log_output(tmp, FALSE);
1577 mr_free(tmp);
1578
1579
1580 /* Mindi always create one single parition on the USB dev */
1581 mr_asprintf(tmp, "mount %s1 %s", bkpinfo->media_device, tmp1);
1582 run_program_and_log_output(tmp, FALSE);
1583 mr_free(tmp);
1584
1585 if (bkpinfo->nonbootable_backup) {
1586 log_msg(1, "Making nonbootable USB backup not implemented yet");
1587 } else {
1588 log_msg(1, "Making bootable backup");
1589
1590 /* Command to execute */
1591 mr_asprintf(tmp,"mv %s/* %s", bkpinfo->scratchdir, tmp1);
1592 res = eval_call_to_make_USB(tmp, message_to_screen);
1593 if (res) {
1594 mr_asprintf(result_sz, "%s ...failed",tmp);
1595 } else {
1596 mr_asprintf(result_sz, "%s ...OK",tmp);
1597 }
1598 log_to_screen(result_sz);
1599 mr_free(result_sz);
1600 mr_free(tmp);
1601 retval += res;
1602
1603 /* Recreate the required structure under the scratch dir */
1604 mr_asprintf(tmp,"mkdir %s/archive", bkpinfo->scratchdir);
1605 run_program_and_log_output(tmp, FALSE);
1606 mr_free(tmp);
1607 }
1608 paranoid_free(message_to_screen);
1609 paranoid_free(tmp1);
1610
1611 if (is_this_device_mounted(bkpinfo->media_device)) {
1612 mr_asprintf(tmp, "umount %s1", bkpinfo->media_device);
1613 run_program_and_log_output(tmp, FALSE);
1614 mr_free(tmp);
1615 }
1616
1617 if (chdir(old_pwd)) {
1618 // FIXME
1619 }
1620 if (retval) {
1621 log_msg(1, "WARNING - make_usb_fs returned an error");
1622 }
1623 paranoid_free(old_pwd);
1624 return (retval);
1625}
1626
1627
1628/**
1629 * Create an ISO image in @c destfile, from files in @c bkpinfo->scratchdir.
1630 *
1631 * @param bkpinfo The backup information structure. Fields used:
1632 * - @c backup_media_type
1633 * - @c call_after_iso
1634 * - @c call_before_iso
1635 * - @c call_burn_iso
1636 * - @c call_make_iso
1637 * - @c make_cd_use_lilo
1638 * - @c manual_cd_tray
1639 * - @c nonbootable_backup
1640 * - @c scratchdir
1641 *
1642 * @param destfile Where to put the generated ISO image.
1643 * @return The number of errors encountered (0 for success)
1644 */
1645int make_iso_fs(char *destfile)
1646{
1647 /*@ int ********************************************** */
1648 int retval = 0;
1649 int res;
1650
1651 /*@ buffers ****************************************** */
1652 char *tmp = NULL;
1653 char *tmp2 = NULL;
1654 char *old_pwd;
1655 char *result_sz = NULL;
1656 char *message_to_screen = NULL;
1657 char *sz_blank_disk = NULL;
1658 char *isofs_cmd = NULL;
1659 char *full_isofs_cmd = NULL;
1660 char *mds = NULL;
1661 bool cd_is_mountable;
1662
1663 malloc_string(old_pwd);
1664 assert(bkpinfo != NULL);
1665 assert_string_is_neither_NULL_nor_zerolength(destfile);
1666
1667 /* Copy the files needed by isolinux in the right dir */
1668 mr_asprintf(tmp, "mv "MONDO_CACHE"/{isolinux.cfg,isolinux.bin,message.txt,vmlinuz,initrd.img} %s", bkpinfo->scratchdir);
1669 paranoid_system(tmp);
1670 mr_free(tmp);
1671
1672 if (bkpinfo->backup_media_type == iso && bkpinfo->manual_cd_tray) {
1673 popup_and_OK("Please insert new media and press Enter.");
1674 }
1675
1676 log_msg(2, "make_iso_fs --- scratchdir=%s --- destfile=%s", bkpinfo->scratchdir, destfile);
1677 tmp2 = getcwd(old_pwd, MAX_STR_LEN - 1);
1678 if (! tmp2) {
1679 //FIXME
1680 }
1681 mr_asprintf(tmp, "chmod 700 %s", bkpinfo->scratchdir);
1682 run_program_and_log_output(tmp, FALSE);
1683 mr_free(tmp);
1684
1685 if (chdir(bkpinfo->scratchdir)) {
1686 // FIXME
1687 }
1688
1689 if (bkpinfo->call_before_iso) {
1690 mr_asprintf(message_to_screen, "Running pre-ISO call for CD#%d", g_current_media_number);
1691 res = eval_call_to_make_ISO(bkpinfo->call_before_iso, destfile, g_current_media_number, message_to_screen);
1692 if (res) {
1693 mr_strcat(message_to_screen, "...failed");
1694 } else {
1695 mr_strcat(message_to_screen, "...OK");
1696 }
1697 log_to_screen(message_to_screen);
1698 paranoid_free(message_to_screen);
1699
1700 retval += res;
1701 }
1702
1703 if (bkpinfo->call_make_iso) {
1704 log_msg(2, "bkpinfo->call_make_iso = %s", bkpinfo->call_make_iso);
1705 mds = media_descriptor_string(bkpinfo->backup_media_type);
1706 mr_asprintf(message_to_screen, "Making an ISO (%s #%d)", mds, g_current_media_number);
1707 mr_free(mds);
1708
1709 pause_and_ask_for_cdr(2, &cd_is_mountable); /* if g_current_media_number >= 2 then pause & ask */
1710 if (retval) {
1711 log_to_screen
1712 ("Serious error(s) occurred already. I shan't try to write to media.");
1713 } else {
1714 res =
1715 eval_call_to_make_ISO(bkpinfo->call_make_iso, bkpinfo->scratchdir, g_current_media_number, message_to_screen);
1716 if (res) {
1717 log_to_screen("%s...failed to write", message_to_screen);
1718 } else {
1719 log_to_screen("%s...OK", message_to_screen);
1720 mr_asprintf(tmp, "tail -n10 %s | grep -F ':-('", MONDO_LOGFILE);
1721 if (!run_program_and_log_output(tmp, 1)) {
1722 log_to_screen
1723 ("Despite nonfatal errors, growisofs confirms the write was successful.");
1724 }
1725 mr_free(tmp);
1726 }
1727 retval += res;
1728#ifdef DVDRWFORMAT
1729 mr_asprintf(tmp, "tail -n8 %s | grep 'blank=full.*dvd-compat.*DAO'", MONDO_LOGFILE);
1730 if (g_backup_media_type == dvd
1731 && (res || !run_program_and_log_output(tmp, 1))) {
1732 log_to_screen
1733 ("Failed to write to disk. I shall blank it and then try again.");
1734 sleep(5);
1735 /* reset error counter before trying to blank DVD */
1736 retval -= res;
1737 sync();
1738 pause_for_N_seconds(5, "Letting DVD drive settle");
1739
1740// dvd+rw-format --- OPTION 2
1741 if (!bkpinfo->please_dont_eject) {
1742 log_to_screen("Ejecting media to clear drive status.");
1743 eject_device(bkpinfo->media_device);
1744 inject_device(bkpinfo->media_device);
1745 }
1746 pause_for_N_seconds(5, "Letting DVD drive settle");
1747 if (bkpinfo->media_device) {
1748 mr_asprintf(sz_blank_disk, "dvd+rw-format -force %s", bkpinfo->media_device);
1749 } else {
1750 mr_asprintf(sz_blank_disk, "dvd+rw-format");
1751 }
1752 log_msg(3, "sz_blank_disk = '%s'", sz_blank_disk);
1753 res = run_external_binary_with_percentage_indicator_NEW("Blanking DVD disk", sz_blank_disk);
1754 if (res) {
1755 log_to_screen("Warning - format failed. (Was it a DVD-R?) Sleeping for 5 seconds to take a breath...");
1756 pause_for_N_seconds(5, "Letting DVD drive settle... and trying again.");
1757 res = run_external_binary_with_percentage_indicator_NEW("Blanking DVD disk", sz_blank_disk);
1758 if (res) {
1759 log_to_screen("Format failed a second time.");
1760 }
1761 } else {
1762 log_to_screen
1763 ("Format succeeded. Sleeping for 5 seconds to take a breath...");
1764 }
1765 mr_free(sz_blank_disk);
1766 pause_for_N_seconds(5, "Letting DVD drive settle");
1767 if (!bkpinfo->please_dont_eject) {
1768 log_to_screen("Ejecting media to clear drive status.");
1769 eject_device(bkpinfo->media_device);
1770 inject_device(bkpinfo->media_device);
1771 }
1772 pause_for_N_seconds(5, "Letting DVD drive settle");
1773 res = eval_call_to_make_ISO(bkpinfo->call_make_iso, bkpinfo->scratchdir, g_current_media_number, message_to_screen);
1774 retval += res;
1775 if (!bkpinfo->please_dont_eject) {
1776 log_to_screen("Ejecting media.");
1777 eject_device(bkpinfo->media_device);
1778 }
1779 if (res) {
1780 log_to_screen("Dagnabbit. It still failed.");
1781 } else {
1782 log_to_screen
1783 ("OK, this time I successfully backed up to DVD.");
1784 }
1785 }
1786 mr_free(tmp);
1787#endif
1788 if (g_backup_media_type == dvd && !bkpinfo->please_dont_eject) {
1789 eject_device(bkpinfo->media_device);
1790 }
1791 }
1792 paranoid_free(message_to_screen);
1793 } else {
1794 mds = media_descriptor_string(bkpinfo->backup_media_type);
1795 mr_asprintf(message_to_screen, "Running mkisofs to make %s #%d", mds, g_current_media_number);
1796 log_msg(1, message_to_screen);
1797 mr_asprintf(result_sz, "Call to mkisofs to make ISO (%s #%d) ", mds, g_current_media_number);
1798 mr_free(mds);
1799 if (find_home_of_exe("genisoimage")) {
1800 mr_asprintf(isofs_cmd, "%s", MONDO_GENISOIMAGE_CMD);
1801 } else {
1802 mr_asprintf(isofs_cmd, "%s", MONDO_MKISOFS_CMD);
1803 }
1804 if (bkpinfo->nonbootable_backup) {
1805 log_msg(1, "Making nonbootable backup");
1806 mr_asprintf(full_isofs_cmd, "%s%s-o '_ISO_' -V _CD#_ .",isofs_cmd,MONDO_MKISOFS);
1807 res = eval_call_to_make_ISO(full_isofs_cmd, destfile, g_current_media_number, message_to_screen);
1808 mr_free(full_isofs_cmd);
1809 } else {
1810 log_msg(1, "Making bootable backup");
1811
1812#ifdef __FreeBSD__
1813 bkpinfo->make_cd_use_lilo = TRUE;
1814#endif
1815
1816
1817 log_msg(1, "make_cd_use_lilo is actually %d", bkpinfo->make_cd_use_lilo);
1818 if (bkpinfo->make_cd_use_lilo) {
1819 log_msg(1, "make_cd_use_lilo = TRUE");
1820#ifdef __IA64__
1821 log_msg(1, "IA64 --> elilo");
1822 mr_asprintf(full_isofs_cmd, "%s%s-o '_ISO_' -V _CD#_ .",isofs_cmd,MONDO_MKISOFS_REGULAR_ELILO);
1823 res = eval_call_to_make_ISO(full_isofs_cmd, destfile, g_current_media_number, message_to_screen);
1824 mr_free(full_isofs_cmd);
1825#else
1826 log_msg(1, "Non-ia64 --> lilo");
1827 mr_asprintf(full_isofs_cmd, "%s%s-b images/mindi-bootroot.2880.img -c boot.cat -o '_ISO_' -J -V _CD#_ .",isofs_cmd,MONDO_MKISOFS);
1828 // FIXME: fixed boot size probably wrong. lilo to be removed
1829 res = eval_call_to_make_ISO(full_isofs_cmd, destfile, g_current_media_number, message_to_screen);
1830 mr_free(full_isofs_cmd);
1831#endif
1832 } else {
1833 log_msg(1, "make_cd_use_lilo = FALSE");
1834 log_msg(1, "Isolinux");
1835 mr_asprintf(full_isofs_cmd, "%s%s-o '_ISO_' -V _CD#_ .",isofs_cmd,MONDO_MKISOFS_REGULAR_SYSLINUX);
1836 res = eval_call_to_make_ISO(full_isofs_cmd, destfile, g_current_media_number, message_to_screen);
1837 mr_free(full_isofs_cmd);
1838 }
1839 }
1840 mr_free(isofs_cmd);
1841 paranoid_free(message_to_screen);
1842
1843 if (res) {
1844 mr_strcat(result_sz, "...failed");
1845 } else {
1846 mr_strcat(result_sz, "...OK");
1847 }
1848 log_to_screen(result_sz);
1849 paranoid_free(result_sz);
1850 retval += res;
1851 }
1852
1853 if (bkpinfo->backup_media_type == cdr
1854 || bkpinfo->backup_media_type == cdrw) {
1855 if (is_this_device_mounted(bkpinfo->media_device)) {
1856 log_msg(2, "Warning - %s mounted. I'm unmounting it before I burn to it.", bkpinfo->media_device);
1857 mr_asprintf(tmp, "umount %s", bkpinfo->media_device);
1858 run_program_and_log_output(tmp, FALSE);
1859 mr_free(tmp);
1860 }
1861 }
1862
1863 if (bkpinfo->call_burn_iso) {
1864 log_msg(2, "bkpinfo->call_burn_iso = %s", bkpinfo->call_burn_iso);
1865 mds = media_descriptor_string(bkpinfo->backup_media_type);
1866 mr_asprintf(message_to_screen, "Burning %s #%d", mds, g_current_media_number);
1867 mr_free(mds);
1868 pause_and_ask_for_cdr(2, &cd_is_mountable);
1869 res = eval_call_to_make_ISO(bkpinfo->call_burn_iso, destfile, g_current_media_number, message_to_screen);
1870 if (res) {
1871 mr_strcat(message_to_screen, "...failed");
1872 } else {
1873 mr_strcat(message_to_screen, "...OK");
1874 }
1875 log_to_screen(message_to_screen);
1876 paranoid_free(message_to_screen);
1877
1878 retval += res;
1879 }
1880
1881 if (bkpinfo->call_after_iso) {
1882 mds = media_descriptor_string(bkpinfo->backup_media_type);
1883 mr_asprintf(message_to_screen, "Running post-ISO call (%s #%d)", mds, g_current_media_number);
1884 mr_free(mds);
1885 res = eval_call_to_make_ISO(bkpinfo->call_after_iso, destfile, g_current_media_number, message_to_screen);
1886 if (res) {
1887 mr_strcat(message_to_screen, "...failed");
1888 } else {
1889 mr_strcat(message_to_screen, "...OK");
1890 }
1891 log_to_screen(message_to_screen);
1892 paranoid_free(message_to_screen);
1893
1894 retval += res;
1895 }
1896
1897 if (chdir(old_pwd)) {
1898 // FIXME
1899 }
1900 if (retval) {
1901 log_msg(1, "WARNING - make_iso_fs returned an error");
1902 }
1903 paranoid_free(old_pwd);
1904 return (retval);
1905}
1906
1907
1908bool is_dev_an_NTFS_dev(char *bigfile_fname)
1909{
1910 char *tmp = NULL;
1911 char *command = NULL;
1912 bool ret = TRUE;
1913
1914 mr_asprintf(command, "dd if=%s bs=512 count=1 2> /dev/null | strings | head -n1", bigfile_fname);
1915 log_msg(1, "command = '%s'", command);
1916 tmp = call_program_and_get_last_line_of_output(command,TRUE);
1917 mr_free(command);
1918
1919 log_msg(1, "--> tmp = '%s'", tmp);
1920 if (strstr(tmp, "NTFS")) {
1921 log_it("TRUE");
1922 ret = TRUE;
1923 } else {
1924 log_it("FALSE");
1925 ret = FALSE;
1926 }
1927 mr_free(tmp);
1928 return(ret);
1929}
1930
1931
1932/**
1933 * Back up big files by chopping them up.
1934 * This function backs up all "big" files (where "big" depends
1935 * on your backup media) in "chunks" (whose size again depends
1936 * on your media).
1937 *
1938 * @param bkpinfo The backup information structure. Fields used:
1939 * - @c backup_media_type
1940 * - @c optimal_set_size
1941 * @param biggielist_fname The path to a file containing a list of
1942 * all "big" files.
1943 * @return The number of errors encountered (0 for success)
1944 * @see slice_up_file_etc
1945 */
1946int
1947make_slices_and_images(char *biggielist_fname)
1948{
1949
1950 /*@ pointers ******************************************* */
1951 FILE *fin = NULL;
1952
1953 /*@ buffers ******************************************** */
1954 char *tmp = NULL;
1955 char *bigfile_fname = NULL;
1956 char *sz_devfile = NULL;
1957 char *ntfsprog_fifo = NULL;
1958 /*@ long *********************************************** */
1959 long biggie_file_number = 0;
1960 long noof_biggie_files = 0;
1961 long estimated_total_noof_slices = 0;
1962
1963 /*@ int ************************************************ */
1964 int retval = 0;
1965 int res = 0;
1966 pid_t pid;
1967 FILE *ftmp = NULL;
1968 bool delete_when_done;
1969 bool use_ntfsprog;
1970 off_t biggie_fsize;
1971
1972 assert(bkpinfo != NULL);
1973 assert_string_is_neither_NULL_nor_zerolength(biggielist_fname);
1974
1975 estimated_total_noof_slices =
1976 size_of_all_biggiefiles_K() / bkpinfo->optimal_set_size + 1;
1977
1978 log_msg(1, "size of all biggiefiles = %ld",
1979 size_of_all_biggiefiles_K());
1980 log_msg(1, "estimated_total_noof_slices = %ld KB / %ld KB = %ld",
1981 size_of_all_biggiefiles_K(), bkpinfo->optimal_set_size,
1982 estimated_total_noof_slices);
1983
1984 if (length_of_file(biggielist_fname) < 6) {
1985 log_msg(1, "No biggiefiles; fair enough...");
1986 return (0);
1987 }
1988 mr_asprintf(tmp, "I am now backing up all large files.");
1989 log_to_screen(tmp);
1990 noof_biggie_files = count_lines_in_file(biggielist_fname);
1991 open_progress_form("Backing up big files", tmp, "Please wait. This may take some time.", "", estimated_total_noof_slices);
1992 mr_free(tmp);
1993
1994 if (!(fin = fopen(biggielist_fname, "r"))) {
1995 log_OS_error("Unable to openin biggielist");
1996 return (1);
1997 }
1998
1999 for (mr_getline(bigfile_fname, fin); !feof(fin); mr_getline(bigfile_fname, fin), biggie_file_number++) {
2000 use_ntfsprog = FALSE;
2001 if (bigfile_fname[strlen(bigfile_fname) - 1] < 32) {
2002 bigfile_fname[strlen(bigfile_fname) - 1] = '\0';
2003 }
2004 biggie_fsize = length_of_file(bigfile_fname);
2005 delete_when_done = FALSE;
2006
2007 if (!does_file_exist(bigfile_fname)) {
2008 ftmp = fopen(bigfile_fname, "w");
2009 if (ftmp == NULL) {
2010 log_msg(3, "Unable to write to %s", bigfile_fname);
2011 // So skip it as it doesn't exist
2012 mr_free(bigfile_fname);
2013 continue;
2014 } else {
2015 paranoid_fclose(ftmp);
2016 }
2017 delete_when_done = TRUE;
2018 } else {
2019 // Call ntfsclone (formerly partimagehack) if it's a /dev entry
2020 // (i.e. a partition to be imaged)
2021 log_msg(2, "bigfile_fname = %s", bigfile_fname);
2022 use_ntfsprog = FALSE;
2023 if (!strncmp(bigfile_fname, "/dev/", 5) && is_dev_an_NTFS_dev(bigfile_fname)) {
2024 use_ntfsprog = TRUE;
2025 log_msg(2, "Calling ntfsclone in background because %s is an NTFS partition", bigfile_fname);
2026 mr_asprintf(sz_devfile, "%s/%d.%d.000", bkpinfo->tmpdir, (int) (random() % 32768), (int) (random() % 32768));
2027 mkfifo(sz_devfile, 0x770);
2028 ntfsprog_fifo = sz_devfile;
2029 switch (pid = fork()) {
2030 case -1:
2031 mr_free(bigfile_fname);
2032 mr_free(sz_devfile);
2033 fatal_error("Fork failure");
2034 case 0:
2035 log_msg(2, "CHILD - fip - calling feed_into_ntfsprog(%s, %s)", bigfile_fname, sz_devfile);
2036 res = feed_into_ntfsprog(bigfile_fname, sz_devfile);
2037 /* The child needs to unalocate memory as well */
2038 mr_free(bigfile_fname);
2039 mr_free(sz_devfile);
2040 exit(res);
2041 break;
2042 default:
2043 log_msg(2, "feed_into_ntfsprog() called in background --- pid=%ld", (long int) (pid));
2044 }
2045 }
2046 // Otherwise, use good old 'dd' and 'bzip2'
2047 else {
2048 ntfsprog_fifo = NULL;
2049 }
2050
2051 // Whether partition or biggiefile, just do your thang :-)
2052 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2053 write_header_block_to_stream(biggie_fsize, bigfile_fname, use_ntfsprog ? BLK_START_A_PIHBIGGIE : BLK_START_A_NORMBIGGIE);
2054 }
2055 res = slice_up_file_etc(bigfile_fname, ntfsprog_fifo, biggie_file_number, noof_biggie_files, use_ntfsprog);
2056
2057 /* Free it here as ntfsprog_fifo is not used anymore */
2058 mr_free(sz_devfile);
2059
2060 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2061 tmp = calc_checksum_of_file(bigfile_fname);
2062 write_header_block_to_stream((off_t)0, tmp, BLK_STOP_A_BIGGIE);
2063 mr_free(tmp);
2064 }
2065 retval += res;
2066 p = strrchr(bigfile_fname, '/');
2067 if (p) {
2068 p++;
2069 } else {
2070 p = bigfile_fname;
2071 }
2072 mr_asprintf(tmp, "Archiving %s ... ", bigfile_fname);
2073 if (res) {
2074 mr_strcat(tmp, "Failed!");
2075 } else {
2076 mr_strcat(tmp, "OK");
2077 }
2078 if (delete_when_done) {
2079 unlink(bigfile_fname);
2080 delete_when_done = FALSE;
2081 }
2082 }
2083 mr_free(bigfile_fname);
2084 if (!g_text_mode) {
2085 newtDrawRootText(0, g_noof_rows - 2, tmp);
2086 newtRefresh();
2087 }
2088 mr_free(tmp);
2089 }
2090 mr_free(bigfile_fname);
2091
2092 log_msg(1, "Finished backing up bigfiles");
2093 log_msg(1, "estimated slices = %ld; actual slices = %ld",
2094 estimated_total_noof_slices, g_current_progress);
2095 close_progress_form();
2096 paranoid_fclose(fin);
2097 return (retval);
2098}
2099
2100
2101
2102
2103/**
2104 * Single-threaded version of @c make_afioballs_and_images().
2105 * @see make_afioballs_and_images
2106 */
2107int make_afioballs_and_images_OLD()
2108{
2109
2110 /*@ int ************************************************** */
2111 int retval = 0;
2112 long int curr_set_no = 0L;
2113 int res = 0;
2114
2115 /*@ buffers ********************************************** */
2116 char *curr_filelist_fname = NULL;
2117 char *curr_afioball_fname = NULL;
2118 char *curr_xattr_list_fname = NULL;
2119 char *curr_acl_list_fname = NULL;
2120 char *tmp = NULL;
2121 char *media_usage_comment = NULL;
2122
2123 log_to_screen("Archiving regular files");
2124
2125 open_progress_form("Backing up filesystem",
2126 "I am backing up your live filesystem now.",
2127 "Please wait. This may take a couple of hours.",
2128 "Working...",
2129 get_last_filelist_number() + 1);
2130
2131 for (;;) {
2132 /* backup this set of files */
2133 mr_asprintf(curr_filelist_fname, FILELIST_FNAME_RAW_SZ, bkpinfo->tmpdir, curr_set_no);
2134 if (! does_file_exist(curr_filelist_fname)) {
2135 mr_free(curr_filelist_fname);
2136 break;
2137 }
2138
2139 mr_asprintf(curr_afioball_fname, AFIOBALL_FNAME_RAW_SZ, bkpinfo->tmpdir, curr_set_no, bkpinfo->zip_suffix);
2140
2141 log_msg(1, "EXAT'g set %ld", curr_set_no);
2142 if (g_getfattr) {
2143 mr_asprintf(curr_xattr_list_fname, XATTR_LIST_FNAME_RAW_SZ, bkpinfo->tmpdir, curr_set_no);
2144 get_fattr_list(curr_filelist_fname, curr_xattr_list_fname);
2145 }
2146 if (g_getfacl) {
2147 mr_asprintf(curr_acl_list_fname, ACL_LIST_FNAME_RAW_SZ, bkpinfo->tmpdir, curr_set_no);
2148 get_acl_list(curr_filelist_fname, curr_acl_list_fname);
2149 }
2150
2151 log_msg(1, "Archiving set %ld", curr_set_no);
2152 res =
2153 archive_this_fileset(curr_filelist_fname,
2154 curr_afioball_fname, curr_set_no);
2155 retval += res;
2156 if (res) {
2157 log_to_screen("Errors occurred while archiving set %ld. Perhaps your live filesystem changed?", curr_set_no);
2158 }
2159
2160 /* copy to CD (scratchdir) ... and an actual CD-R if necessary */
2161 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2162 register_in_tape_catalog(fileset, curr_set_no, -1, curr_afioball_fname);
2163 maintain_collection_of_recent_archives(curr_afioball_fname);
2164 log_it("Writing EXAT files");
2165 res +=
2166 write_EXAT_files_to_tape(curr_xattr_list_fname,
2167 curr_acl_list_fname);
2168 // archives themselves
2169 res = move_files_to_stream(curr_afioball_fname, NULL);
2170 } else {
2171 if (g_getfacl) {
2172 if (g_getfattr) {
2173 res = move_files_to_cd(curr_filelist_fname,
2174 curr_xattr_list_fname,
2175 curr_acl_list_fname,
2176 curr_afioball_fname, NULL);
2177 } else {
2178 res = move_files_to_cd(curr_filelist_fname,
2179 curr_acl_list_fname,
2180 curr_afioball_fname, NULL);
2181 }
2182 } else {
2183 if (g_getfattr) {
2184 res = move_files_to_cd(curr_filelist_fname,
2185 curr_xattr_list_fname,
2186 curr_afioball_fname, NULL);
2187 } else {
2188 res = move_files_to_cd(curr_filelist_fname,
2189 curr_afioball_fname, NULL);
2190 }
2191 }
2192 }
2193 if (g_getfattr) {
2194 mr_free(curr_xattr_list_fname);
2195 }
2196 if (g_getfacl) {
2197 mr_free(curr_acl_list_fname);
2198 }
2199 retval += res;
2200 g_current_progress++;
2201
2202 media_usage_comment = percent_media_full_comment();
2203 update_progress_form(media_usage_comment);
2204 mr_free(media_usage_comment);
2205
2206 if (res) {
2207 log_to_screen("Failed to add archive %ld's files to CD dir\n", curr_set_no);
2208 fatal_error("Is your hard disk is full? If not, please send the author the logfile.");
2209 }
2210 mr_free(curr_filelist_fname);
2211 mr_free(curr_afioball_fname);
2212 curr_set_no++;
2213 }
2214 close_progress_form();
2215 mr_asprintf(tmp, "Your regular files have been archived ");
2216 if (retval) {
2217 mr_strcat(tmp, "(with errors).");
2218 } else {
2219 mr_strcat(tmp, "successfully.");
2220 }
2221 log_to_screen(tmp);
2222 mr_free(tmp);
2223 return (retval);
2224}
2225
2226/* @} - end of LLarchiveGroup */
2227
2228
2229/**
2230 * Wrapper around @c make_afioballs_and_images().
2231 * @param bkpinfo the backup information structure. Only the
2232 * @c backup_media_type field is used within this function.
2233 * @return return code of make_afioballs_and_images
2234 * @see make_afioballs_and_images
2235 * @ingroup MLarchiveGroup
2236 */
2237int make_those_afios_phase()
2238{
2239 /*@ int ******************************************* */
2240 int res = 0;
2241 int retval = 0;
2242
2243 assert(bkpinfo != NULL);
2244
2245 mvaddstr_and_log_it(g_currentY, 0,
2246 "Archiving regular files to media ");
2247
2248 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2249 write_header_block_to_stream((off_t)0, "start-of-afioballs",
2250 BLK_START_AFIOBALLS);
2251#if __FreeBSD__ == 5
2252 log_msg(1,
2253 "Using single-threaded make_afioballs_and_images() to suit b0rken FreeBSD 5.0");
2254 res = make_afioballs_and_images_OLD();
2255#else
2256 res = make_afioballs_and_images_OLD();
2257#endif
2258 write_header_block_to_stream((off_t)0, "stop-afioballs",
2259 BLK_STOP_AFIOBALLS);
2260 } else {
2261 res = make_afioballs_and_images();
2262 }
2263
2264 retval += res;
2265 if (res) {
2266 mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
2267 log_msg(1, "make_afioballs_and_images returned an error");
2268 } else {
2269 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2270 }
2271 return (retval);
2272}
2273
2274/**
2275 * Wrapper around @c make_slices_and_images().
2276 * @param bkpinfo The backup information structure. Fields used:
2277 * - @c backup_media_type
2278 * - @c scratchdir
2279 * - @c tmpdir
2280 * @return The number of errors encountered (0 for success)
2281 * @ingroup MLarchiveGroup
2282 */
2283int make_those_slices_phase()
2284{
2285
2286 /*@ int ***************************************************** */
2287 int res = 0;
2288 int retval = 0;
2289
2290 /*@ buffers ************************************************** */
2291 char *biggielist = NULL;
2292 char *command = NULL;
2293 char *blah = NULL;
2294 char *xattr_fname = NULL;
2295 char *acl_fname = NULL;
2296
2297 assert(bkpinfo != NULL);
2298 /* slice big files */
2299 mvaddstr_and_log_it(g_currentY, 0,
2300 "Archiving large files to media ");
2301 mr_asprintf(biggielist, "%s/archives/biggielist.txt", bkpinfo->scratchdir);
2302 if (g_getfattr) {
2303 mr_asprintf(xattr_fname, XATTR_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
2304 }
2305 if (g_getfacl) {
2306 mr_asprintf(acl_fname, ACL_BIGGLST_FNAME_RAW_SZ, bkpinfo->tmpdir);
2307 }
2308
2309 mr_asprintf(command, "cp %s/biggielist.txt %s", bkpinfo->tmpdir, biggielist);
2310 paranoid_system(command);
2311 mr_free(command);
2312
2313 mr_asprintf(blah, "biggielist = %s", biggielist);
2314 log_msg(2, blah);
2315 mr_free(blah);
2316
2317 if (!does_file_exist(biggielist)) {
2318 log_msg(1, "BTW, the biggielist does not exist");
2319 }
2320
2321 if (g_getfattr) {
2322 get_fattr_list(biggielist, xattr_fname);
2323 mr_asprintf(command, "cp %s %s/archives/", xattr_fname, bkpinfo->scratchdir);
2324 paranoid_system(command);
2325 mr_free(command);
2326 }
2327 if (g_getfacl) {
2328 get_acl_list(biggielist, acl_fname);
2329 mr_asprintf(command, "cp %s %s/archives/", acl_fname, bkpinfo->scratchdir);
2330 paranoid_system(command);
2331 mr_free(command);
2332 }
2333
2334 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2335 res += write_EXAT_files_to_tape(xattr_fname, acl_fname);
2336 mr_asprintf(blah, "%ld", count_lines_in_file(biggielist));
2337 write_header_block_to_stream((off_t)0, blah, BLK_START_BIGGIEFILES);
2338 mr_free(blah);
2339 }
2340 res = make_slices_and_images(biggielist);
2341 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2342 write_header_block_to_stream((off_t)0, "end-of-biggiefiles",
2343 BLK_STOP_BIGGIEFILES);
2344 }
2345 retval += res;
2346 if (res) {
2347 log_msg(1, "make_slices_and_images returned an error");
2348 mvaddstr_and_log_it(g_currentY++, 74, "Errors.");
2349 } else {
2350 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
2351 }
2352 mr_free(biggielist);
2353 mr_free(xattr_fname);
2354 mr_free(acl_fname);
2355 return (retval);
2356}
2357
2358
2359/**
2360 * @addtogroup LLarchiveGroup
2361 * @{
2362 */
2363/**
2364 * Function pointer to an appropriate @c move_files_to_cd routine.
2365 * You can set this to your own function (for example, one to
2366 * transfer files over the network) or leave it as is.
2367 */
2368int (*move_files_to_cd) (char *, ...) =
2369 _move_files_to_cd;
2370
2371/**
2372 * Move some files to the ISO scratch directory.
2373 * This function moves files specified as parameters, into the directory
2374 * @c bkpinfo->scratchdir, where the files that will be stored on the next
2375 * CD are waiting.
2376 *
2377 * @param bkpinfo The backup information structure. Fields used:
2378 * - @c media_size
2379 * - @c scratchdir
2380 * @param files_to_add The files to add to the scratchdir.
2381 * @warning The list of @c files_to_add must be terminated with @c NULL.
2382 * @note If and when the space occupied by the scratchdir would exceed
2383 * the capacity of the current CD,
2384 * <tt>write_iso_and_go_on(bkpinfo, FALSE)</tt> is called and the
2385 * scratchdir is emptied.
2386 *
2387 * @return The number of errors encountered (0 for success)
2388 */
2389int _move_files_to_cd(char *files_to_add, ...)
2390{
2391
2392 /*@ int ************************************************************ */
2393 int retval = 0;
2394 int res = 0;
2395
2396 /*@ buffers ******************************************************** */
2397 char *tmp = NULL;
2398 char *curr_file = NULL;
2399 char *cf;
2400
2401 /*@ long ************************************************************ */
2402 va_list ap;
2403 long long would_occupy;
2404
2405 assert(bkpinfo != NULL);
2406 would_occupy = space_occupied_by_cd(bkpinfo->scratchdir);
2407 va_start(ap, files_to_add); // initialize the variable arguments
2408 for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
2409 if (!cf) {
2410 continue;
2411 }
2412 mr_asprintf(curr_file, "%s", cf);
2413 if (!does_file_exist(curr_file)) {
2414 log_msg(1,
2415 "Warning - you're trying to add a non-existent file - '%s' to the CD",
2416 curr_file);
2417 } else {
2418 log_msg(8, "Trying to add file %s to CD", curr_file);
2419 would_occupy += length_of_file(curr_file) / 1024;
2420 }
2421 mr_free(curr_file);
2422 }
2423 va_end(ap);
2424
2425 if (bkpinfo->media_size <= 0) {
2426 fatal_error("move_files_to_cd() - unknown media size");
2427 }
2428 if (would_occupy / 1024 > bkpinfo->media_size) {
2429 res = write_iso_and_go_on(FALSE); /* FALSE because this is not the last CD we'll write */
2430 retval += res;
2431 if (res) {
2432 log_msg(1, "WARNING - write_iso_and_go_on returned an error");
2433 }
2434 }
2435
2436 va_start(ap, files_to_add); // initialize the variable arguments
2437 for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
2438 if (!cf) {
2439 continue;
2440 }
2441 mr_asprintf(curr_file, "%s", cf);
2442
2443 mr_asprintf(tmp, "mv -f %s %s/archives/", curr_file, bkpinfo->scratchdir);
2444 mr_free(curr_file);
2445 res = run_program_and_log_output(tmp, 5);
2446 retval += res;
2447 if (res) {
2448 log_msg(1, "(move_files_to_cd) '%s' failed", tmp);
2449 } else {
2450 log_msg(8, "Moved %s to CD OK", tmp);
2451 }
2452 mr_free(tmp);
2453 }
2454 va_end(ap);
2455
2456 if (retval) {
2457 log_msg(1,
2458 "Warning - errors occurred while I was adding files to CD dir");
2459 }
2460 return (retval);
2461}
2462
2463/* @} - end of LLarchiveGroup */
2464
2465
2466/**
2467 * @addtogroup LLarchiveGroup
2468 * @{
2469 */
2470/**
2471 * Function pointer to an appropriate @c move_files_to_stream routine.
2472 * You can set this to your own function (for example, one to
2473 * transfer files over the network) or leave it as is.
2474 */
2475int (*move_files_to_stream) (char *, ...) =
2476 _move_files_to_stream;
2477
2478/**
2479 * Copy some files to tape.
2480 * This function copies the files specified as parameters into the tape stream.
2481 *
2482 * @param bkpinfo The backup information structure. Used only in the call to
2483 * @c write_file_to_stream_from_file().
2484 *
2485 * @param files_to_add The files to copy to the tape stream.
2486 * @warning The list of @c files_to_add must be terminated with @c NULL.
2487 * @note Files may be split across multiple tapes if necessary.
2488 *
2489 * @return The number of errors encountered (0 for success)
2490 */
2491int
2492_move_files_to_stream(char *files_to_add, ...)
2493{
2494
2495 /*@ int ************************************************************ */
2496 int retval = 0;
2497 int res = 0;
2498 /*@ buffers ******************************************************** */
2499
2500 /*@ char *********************************************************** */
2501 char start_chr;
2502 char stop_chr;
2503 char *curr_file = NULL;
2504 char *cf;
2505 /*@ long long ****************************************************** */
2506 off_t length_of_incoming_file = (off_t)0;
2507 va_list ap;
2508
2509 assert(bkpinfo != NULL);
2510 va_start(ap, files_to_add);
2511 for (cf = files_to_add; cf != NULL; cf = va_arg(ap, char *)) {
2512 if (!cf) {
2513 continue;
2514 }
2515 mr_asprintf(curr_file, "%s", cf);
2516 if (!does_file_exist(curr_file)) {
2517 log_msg(1,
2518 "Warning - you're trying to add a non-existent file - '%s' to the tape",
2519 curr_file);
2520 }
2521 /* create header chars */
2522 start_chr = BLK_START_AN_AFIO_OR_SLICE;
2523 stop_chr = BLK_STOP_AN_AFIO_OR_SLICE;
2524 /* ask for new tape if necessary */
2525 length_of_incoming_file = length_of_file(curr_file);
2526 write_header_block_to_stream(length_of_incoming_file, curr_file,
2527 start_chr);
2528 res = write_file_to_stream_from_file(curr_file);
2529 retval += res;
2530 unlink(curr_file);
2531 mr_free(curr_file);
2532 /* write closing header */
2533 write_header_block_to_stream((off_t)0, "finished-writing-file", stop_chr);
2534 }
2535 va_end(ap);
2536
2537 if (retval) {
2538 log_msg(1,
2539 "Warning - errors occurred while I was adding file to tape");
2540 }
2541 return (retval);
2542}
2543
2544/* @} - end of LLarchiveGroup */
2545
2546
2547
2548/**
2549 * @addtogroup utilityGroup
2550 * @{
2551 */
2552/**
2553 * Make sure the user has a valid CD-R(W) in the CD drive.
2554 * @return the CD-R(W) device checked or NULL
2555 */
2556char *interrogate_disk_currently_in_cdrw_drive() {
2557 char *cdrecord = NULL;
2558 char *cdrw_dev = NULL;
2559
2560 cdrw_dev = find_cdrw_device();
2561 if (cdrw_dev != NULL) {
2562 if (!system("which cdrecord > /dev/null 2> /dev/null")) {
2563 mr_asprintf(cdrecord, "cdrecord dev=%s -atip", cdrw_dev);
2564 } else if (!system("which dvdrecord > /dev/null 2> /dev/null")) {
2565 mr_asprintf(cdrecord, "cdrecord dev=%s -atip", cdrw_dev);
2566 } else {
2567 log_msg(2, "Oh well. I guess I'll just pray then.");
2568 }
2569 if (cdrecord != NULL) {
2570 retract_CD_tray_and_defeat_autorun();
2571 if (run_program_and_log_output(cdrecord, 5)) {
2572 /* As it didn't work, return NULL */
2573 mr_free(cdrw_dev);
2574 }
2575 }
2576 mr_free(cdrecord);
2577 }
2578 return(cdrw_dev);
2579}
2580
2581
2582/**
2583 * Asks the user to put a CD-R(W) in the drive.
2584 * @param ask_for_one_if_more_than_this (unused)
2585 * @param pmountable If non-NULL, pointed-to value is set to TRUE if the CD is mountable, FALSE otherwise.
2586 */
2587void
2588pause_and_ask_for_cdr(int ask_for_one_if_more_than_this, bool * pmountable)
2589{
2590
2591 /*@ buffers ********************************************* */
2592 char *tmp = NULL;
2593 char *cdrom_dev = NULL;
2594 char *cdrw_dev = NULL;
2595 char *our_serial_str = NULL;
2596 bool ok_go_ahead_burn_it;
2597 int cd_number = -1;
2598 int attempt_to_mount_returned_this = 999;
2599 char *mtpt = NULL;
2600 char *szcdno = NULL;
2601 char *szserfname = NULL;
2602 char *szunmount = NULL;
2603 char *mds = NULL;
2604
2605 mds = media_descriptor_string(g_backup_media_type);
2606 log_to_screen("I am about to burn %s #%d", mds, g_current_media_number);
2607 mr_free(mds);
2608 if (g_current_media_number < ask_for_one_if_more_than_this) {
2609 return;
2610 }
2611 log_to_screen("Scanning CD-ROM drive...");
2612 mr_asprintf(mtpt, "%s/cd.mtpt", bkpinfo->tmpdir);
2613 make_hole_for_dir(mtpt);
2614
2615 gotos_make_me_puke:
2616 ok_go_ahead_burn_it = TRUE;
2617 if ((cdrom_dev = find_cdrom_device(FALSE)) != NULL) {
2618 /* When enabled, it made CD eject-and-retract when wrong CD inserted.. Weird
2619 log_msg(2, "paafcd: Retracting CD-ROM drive if possible" );
2620 retract_CD_tray_and_defeat_autorun();
2621 */
2622 mr_asprintf(tmp, "umount %s", cdrom_dev);
2623 run_program_and_log_output(tmp, 1);
2624 mr_asprintf(szcdno, "%s/archives/THIS-CD-NUMBER", mtpt);
2625 mr_asprintf(szserfname, "%s/archives/SERIAL-STRING", mtpt);
2626 mr_asprintf(szunmount, "umount %s", mtpt);
2627 cd_number = -1;
2628 mr_asprintf(tmp, "mount %s %s", cdrom_dev, mtpt);
2629 mr_asprintf(our_serial_str, "%s", "");
2630 attempt_to_mount_returned_this = run_program_and_log_output(tmp, 1);
2631 mr_free(tmp);
2632
2633 if (attempt_to_mount_returned_this) {
2634 log_msg(4, "Failed to mount %s at %s", cdrom_dev, mtpt);
2635 log_to_screen("If there's a CD/DVD in the drive, it's blank.");
2636 } else if (!does_file_exist(szcdno) || !does_file_exist(szserfname)) {
2637 mds = media_descriptor_string(g_backup_media_type);
2638 log_to_screen("%s has data on it but it's probably not a Mondo CD.", mds);
2639 mr_free(mds);
2640 } else {
2641 mds = media_descriptor_string(g_backup_media_type);
2642 log_to_screen("%s found in drive. It's a Mondo disk.", mds);
2643 mr_free(mds);
2644
2645 tmp = last_line_of_file(szcdno);
2646 cd_number = atoi(tmp);
2647 mr_free(tmp);
2648
2649 mr_asprintf(tmp, "cat %s 2> /dev/null", szserfname);
2650 mr_free(our_serial_str);
2651 our_serial_str = call_program_and_get_last_line_of_output(tmp,TRUE);
2652 mr_free(tmp);
2653 // FIXME - should be able to use last_line_of_file(), surely?
2654 }
2655 mr_free(szcdno);
2656 mr_free(szserfname);
2657
2658 run_program_and_log_output(szunmount, 1);
2659 mr_free(szunmount);
2660
2661 log_msg(2, "paafcd: cd_number = %d", cd_number);
2662 log_msg(2, "our serial str = %s; g_serial_string = %s", our_serial_str, g_serial_string);
2663 if (cd_number > 0 && !strcmp(our_serial_str, g_serial_string)) {
2664 mds = media_descriptor_string(g_backup_media_type);
2665 log_msg(2, "This %s is part of this backup set!", mds);
2666 ok_go_ahead_burn_it = FALSE;
2667 if (cd_number == g_current_media_number - 1) {
2668 log_to_screen("I think you've left the previous %s in the drive.", mds);
2669 } else {
2670 log_to_screen("Please remove this %s. It is part of the backup set you're making now.", mds);
2671 }
2672 mr_free(mds);
2673
2674 } else {
2675 log_to_screen("...but not part of _our_ backup set.");
2676 }
2677 mr_free(our_serial_str);
2678 } else {
2679 mds = media_descriptor_string(g_backup_media_type);
2680 log_msg(2,
2681 "paafcd: Can't find CD-ROM drive. Perhaps it has a blank %s in it?", mds);
2682 cdrw_dev = interrogate_disk_currently_in_cdrw_drive();
2683 if (cdrw_dev == NULL) {
2684 ok_go_ahead_burn_it = FALSE;
2685 log_to_screen("There isn't a writable %s in the drive.", mds);
2686 }
2687 mr_free(cdrw_dev);
2688 mr_free(mds);
2689 }
2690
2691 if (!ok_go_ahead_burn_it) {
2692 if (!bkpinfo->please_dont_eject) {
2693 eject_device(cdrom_dev);
2694 }
2695 mds = media_descriptor_string(g_backup_media_type);
2696 mr_asprintf(tmp, "I am about to burn %s #%d of the backup set. Please insert %s and press Enter.", mds, g_current_media_number, mds);
2697 mr_free(mds);
2698
2699 popup_and_OK(tmp);
2700 mr_free(tmp);
2701 mr_free(cdrom_dev);
2702 goto gotos_make_me_puke;
2703 } else {
2704 log_msg(2, "paafcd: OK, going ahead and burning it.");
2705 }
2706 mr_free(cdrom_dev);
2707
2708 mds = media_descriptor_string(g_backup_media_type);
2709 log_msg(2, "paafcd: OK, I assume I have a blank/reusable %s in the drive...", mds);
2710
2711 log_to_screen("Proceeding w/ %s in drive.", mds);
2712 mr_free(mds);
2713
2714 mr_free(mtpt);
2715 if (pmountable) {
2716 if (attempt_to_mount_returned_this) {
2717 *pmountable = FALSE;
2718 } else {
2719 *pmountable = TRUE;
2720 }
2721 }
2722
2723}
2724
2725
2726/**
2727 * Set the <tt>N</tt>th bit of @c array to @c true_or_false.
2728 * @param array The bit array (as a @c char pointer).
2729 * @param N The bit number to set or reset.
2730 * @param true_or_false If TRUE then set bit @c N, if FALSE then reset bit @c N.
2731 * @see get_bit_N_of_array
2732 */
2733void set_bit_N_of_array(char *array, int N, bool true_or_false)
2734{
2735 int bit_number;
2736 int mask, orig_val, to_add;
2737 int element_number;
2738
2739 assert(array != NULL);
2740
2741 element_number = N / 8;
2742 bit_number = N % 8;
2743 to_add = (1 << bit_number);
2744 mask = 255 - to_add;
2745 orig_val = array[element_number] & mask;
2746 // log_it("array[%d]=%02x; %02x&%02x = %02x", element_number, array[element_number], mask, orig_val);
2747 if (true_or_false) {
2748 array[element_number] = orig_val | to_add;
2749 }
2750}
2751
2752/* @} - end of utilityGroup */
2753
2754
2755/**
2756 * Chop up @c filename.
2757 * @param bkpinfo The backup information structure. Fields used:
2758 * - @c backup_media_type
2759 * - @c compression_level
2760 * - @c optimal_set_size
2761 * - @c tmpdir
2762 * - @c use_lzo
2763 * - @c zip_exe
2764 * - @c zip_suffix
2765 *
2766 * @param biggie_filename The file to chop up.
2767 * @param ntfsprog_fifo The FIFO to ntfsclone if this is an imagedev, NULL otherwise.
2768 * @param biggie_file_number The sequence number of this biggie file (starting from 0).
2769 * @param noof_biggie_files The number of biggie files there are total.
2770 * @return The number of errors encountered (0 for success)
2771 * @see make_slices_and_images
2772 * @ingroup LLarchiveGroup
2773 */
2774int
2775slice_up_file_etc(char *biggie_filename, char *ntfsprog_fifo, long biggie_file_number, long noof_biggie_files, bool use_ntfsprog) {
2776
2777 /*@ buffers ************************************************** */
2778 char *tmp = NULL;
2779 char *checksum_line = NULL;
2780 char *command = NULL;
2781 char *tempblock = NULL;
2782 char *curr_slice_fname_uncompressed = NULL;
2783 char *curr_slice_fname_compressed = NULL;
2784 char *file_to_archive = NULL;
2785 char *file_to_openin = NULL;
2786 /*@ pointers ************************************************** */
2787 char *pB = NULL;
2788 FILE *fin = NULL;
2789 FILE *fout = NULL;
2790
2791 /*@ bool ****************************************************** */
2792 bool finished = FALSE;
2793
2794 /*@ long ****************************************************** */
2795 size_t blksize = (size_t)0;
2796 long slice_num = 0L;
2797 long i = 0L;
2798 bool should_I_compress_slices = TRUE;
2799 char *suffix = NULL; // for compressed slices
2800
2801 /*@ long long ************************************************** */
2802 off_t totalread = (off_t)0;
2803 off_t totallength = (off_t)0;
2804
2805 /*@ int ******************************************************** */
2806 int retval = 0;
2807 int res = 0;
2808
2809 /*@ structures ************************************************** */
2810 struct s_filename_and_lstat_info biggiestruct;
2811
2812 assert(bkpinfo != NULL);
2813 assert_string_is_neither_NULL_nor_zerolength(biggie_filename);
2814
2815 biggiestruct.for_backward_compatibility = '\n';
2816 biggiestruct.use_ntfsprog = use_ntfsprog;
2817 if (is_this_file_compressed(biggie_filename) || bkpinfo->compression_level == 0) {
2818 mr_asprintf(suffix, "%s", "");
2819 should_I_compress_slices = FALSE;
2820 } else {
2821 mr_asprintf(suffix, "%s", bkpinfo->zip_suffix);
2822 should_I_compress_slices = TRUE;
2823 }
2824
2825 if (bkpinfo->optimal_set_size < 999L) {
2826 fatal_error("bkpinfo->optimal_set_size is insanely small");
2827 }
2828
2829 if (ntfsprog_fifo) {
2830 file_to_openin = ntfsprog_fifo;
2831 mr_asprintf(checksum_line, "IGNORE");
2832 log_msg(2, "Not calculating checksum for %s: it would take too long", biggie_filename);
2833 tmp = find_home_of_exe("ntfsresize");
2834 if (!tmp) {
2835 mr_free(tmp);
2836 fatal_error("ntfsresize not found");
2837 }
2838 mr_free(tmp);
2839
2840 mr_asprintf(command, "ntfsresize --force --info %s|grep '^You might resize at '|cut -d' ' -f5", biggie_filename);
2841 log_it("command = %s", command);
2842 tmp = call_program_and_get_last_line_of_output(command,TRUE);
2843 mr_free(command);
2844 log_it("res of it = %s", tmp);
2845 totallength = (off_t)atoll(tmp);
2846 mr_free(tmp);
2847 } else {
2848 file_to_openin = biggie_filename;
2849 if (strchr(biggie_filename,'\'') != NULL) {
2850 mr_asprintf(command, "md5sum \"%s\"", biggie_filename);
2851 } else {
2852 mr_asprintf(command, "md5sum '%s'", biggie_filename);
2853 }
2854 if (!(fin = popen(command, "r"))) {
2855 log_OS_error("Unable to popen-in command");
2856 mr_free(suffix);
2857 return (1);
2858 }
2859 mr_free(command);
2860 mr_getline(checksum_line, fin);
2861 pclose(fin);
2862 totallength = length_of_file (biggie_filename);
2863 }
2864 lstat(biggie_filename, &biggiestruct.properties);
2865 strcpy(biggiestruct.filename, biggie_filename);
2866 pB = strchr(checksum_line, ' ');
2867 if (!pB) {
2868 pB = strchr(checksum_line, '\t');
2869 }
2870 if (pB) {
2871 *pB = '\0';
2872 }
2873 strcpy(biggiestruct.checksum, checksum_line);
2874 mr_free(checksum_line);
2875
2876 mr_asprintf(tmp, "%s", slice_fname(biggie_file_number, 0, bkpinfo->tmpdir, ""));
2877 fout = fopen(tmp, "w");
2878 if (fout == NULL) {
2879 log_msg(1, "Unable to open and write to %s\n", tmp);
2880 mr_free(tmp);
2881 mr_free(suffix);
2882 return (1);
2883 }
2884 mr_free(tmp);
2885
2886 res = fwrite((void *) &biggiestruct, 1, sizeof(biggiestruct), fout);
2887 if (fout != NULL) {
2888 paranoid_fclose(fout);
2889 }
2890 log_msg(1, "Opening in %s; slicing it and writing to CD/tape", file_to_openin);
2891 if (!(fin = fopen(file_to_openin, "r"))) {
2892 log_OS_error("Unable to openin biggie_filename");
2893 log_to_screen("Cannot archive bigfile '%s': not found", biggie_filename);
2894
2895 mr_free(suffix);
2896 return (1);
2897 }
2898 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2899 res =
2900 move_files_to_stream(slice_fname(biggie_file_number, 0,
2901 bkpinfo->tmpdir, ""), NULL);
2902 } else {
2903 res =
2904 move_files_to_cd(slice_fname(biggie_file_number, 0,
2905 bkpinfo->tmpdir, ""), NULL);
2906 }
2907 i = bkpinfo->optimal_set_size / 256;
2908 if (!(tempblock = (char *) malloc(256 * 1024))) {
2909 fatal_error("malloc error 256*1024");
2910 }
2911 for (slice_num = 1; !finished; slice_num++) {
2912 mr_asprintf(curr_slice_fname_uncompressed, "%s", slice_fname(biggie_file_number, slice_num, bkpinfo->tmpdir, ""));
2913 mr_asprintf(curr_slice_fname_compressed, "%s", slice_fname(biggie_file_number, slice_num, bkpinfo->tmpdir, suffix));
2914
2915
2916 tmp = percent_media_full_comment();
2917 update_progress_form(tmp);
2918 mr_free(tmp);
2919
2920 if (!(fout = fopen(curr_slice_fname_uncompressed, "w"))) {
2921 log_OS_error(curr_slice_fname_uncompressed);
2922 mr_free(suffix);
2923 return (1);
2924 }
2925 if ((i == bkpinfo->optimal_set_size / 256) && (totalread < 1.1 * totallength)) {
2926 for (i = 0L; i < bkpinfo->optimal_set_size / 256; i++) {
2927 blksize = fread(tempblock, 1, 256 * 1024, fin);
2928 if (blksize > 0) {
2929 totalread = totalread + blksize;
2930 res = fwrite(tempblock, 1, blksize, fout);
2931 } else {
2932 break;
2933 }
2934 }
2935 mr_free(tempblock);
2936 } else {
2937 i = 0L;
2938 }
2939 fclose(fout);
2940 if (i > 0L) // length_of_file (curr_slice_fname_uncompressed)
2941 {
2942 if (!does_file_exist(curr_slice_fname_uncompressed)) {
2943 log_msg(2, "Warning - '%s' doesn't exist. How can I compress slice?", curr_slice_fname_uncompressed);
2944 }
2945 if (should_I_compress_slices && bkpinfo->compression_level > 0) {
2946 mr_asprintf(command, "%s -%d %s", bkpinfo->zip_exe, bkpinfo->compression_level, curr_slice_fname_uncompressed);
2947 log_msg(2, command);
2948 if ((res = system(command))) {
2949 log_OS_error(command);
2950 }
2951 // did_I_compress_slice = TRUE;
2952 } else {
2953 mr_asprintf(command, "mv %s %s 2>> %s", curr_slice_fname_uncompressed, curr_slice_fname_compressed, MONDO_LOGFILE);
2954 res = 0; // don't do it :)
2955 // did_I_compress_slice = FALSE;
2956 }
2957 mr_free(command);
2958
2959 retval += res;
2960 if (res) {
2961 log_msg(2, "Failed to compress the slice");
2962 }
2963 if (bkpinfo->use_lzo && strcmp(curr_slice_fname_compressed, curr_slice_fname_uncompressed)) {
2964 unlink(curr_slice_fname_uncompressed);
2965 }
2966 if (res) {
2967 mr_asprintf(tmp, "Problem with slice # %ld", slice_num);
2968 } else {
2969 mr_asprintf(tmp, "%s - Bigfile #%ld, slice #%ld compressed OK ", biggie_filename, biggie_file_number + 1, slice_num);
2970 }
2971 if (!g_text_mode) {
2972 newtDrawRootText(0, g_noof_rows - 2, tmp);
2973 newtRefresh();
2974 } else {
2975 log_msg(2, tmp);
2976 }
2977 mr_free(tmp);
2978
2979 mr_asprintf(file_to_archive, "%s", curr_slice_fname_compressed);
2980 g_current_progress++;
2981 } else { /* if i==0 then ... */
2982
2983 finished = TRUE;
2984 mr_asprintf(file_to_archive, "%s", curr_slice_fname_uncompressed);
2985 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2986 break;
2987 }
2988 }
2989 mr_free(curr_slice_fname_uncompressed);
2990 mr_free(curr_slice_fname_compressed);
2991
2992 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
2993 register_in_tape_catalog(biggieslice, biggie_file_number, slice_num, file_to_archive);
2994 maintain_collection_of_recent_archives(file_to_archive);
2995 res = move_files_to_stream(file_to_archive, NULL);
2996 } else {
2997 res = move_files_to_cd(file_to_archive, NULL);
2998 }
2999 mr_free(file_to_archive);
3000
3001 retval += res;
3002 if (res) {
3003 log_to_screen("Failed to add slice %ld of bigfile %ld to scratchdir", slice_num, biggie_file_number + 1);
3004 fatal_error("Hard disk full. You should have bought a bigger one.");
3005 }
3006 }
3007 mr_free(suffix);
3008 paranoid_fclose(fin);
3009 mr_asprintf(tmp, "Sliced bigfile #%ld", biggie_file_number + 1);
3010 if (retval) {
3011 mr_strcat(tmp, "...FAILED");
3012 } else {
3013 mr_strcat(tmp, "...OK!");
3014 }
3015 log_msg(1, tmp);
3016 mr_free(tmp);
3017
3018 return (retval);
3019}
3020
3021
3022/**
3023 * Remove the archives in @c d.
3024 * This could possibly include any of:
3025 * - all afioballs (compressed and not)
3026 * - all filelists
3027 * - all slices
3028 * - all checksums
3029 * - a zero filler file
3030 *
3031 * @param d The directory to wipe the archives from.
3032 * @ingroup utilityGroup
3033 */
3034void wipe_archives(char *d)
3035{
3036 /*@ buffers ********************************************* */
3037 char *tmp = NULL;
3038 char *dir = NULL;
3039
3040 assert_string_is_neither_NULL_nor_zerolength(d);
3041
3042 mr_asprintf(dir, "%s/archives", d);
3043 mr_asprintf(tmp, "find %s -name '*.afio*' -exec rm -f '{}' \\;", dir);
3044 run_program_and_log_output(tmp, FALSE);
3045 mr_free(tmp);
3046 mr_asprintf(tmp, "find %s -name '*list.[0-9]*' -exec rm -f '{}' \\;", dir);
3047 run_program_and_log_output(tmp, FALSE);
3048 mr_free(tmp);
3049 mr_asprintf(tmp, "find %s -name 'slice*' -exec rm -f '{}' \\;", dir);
3050 run_program_and_log_output(tmp, FALSE);
3051 mr_free(tmp);
3052 mr_asprintf(tmp, "rm -f %s/cklist*", dir);
3053 run_program_and_log_output(tmp, FALSE);
3054 mr_free(tmp);
3055 mr_asprintf(tmp, "rm -f %s/zero", dir);
3056 run_program_and_log_output(tmp, FALSE);
3057 mr_free(tmp);
3058 log_msg(1, "Wiped %s's archives", dir);
3059 mr_asprintf(tmp, "ls -l %s", dir);
3060 mr_free(dir);
3061 run_program_and_log_output(tmp, FALSE);
3062 mr_free(tmp);
3063}
3064
3065
3066/**
3067 * @addtogroup LLarchiveGroup
3068 * @{
3069 */
3070/**
3071 * Write the final ISO image.
3072 * @param bkpinfo The backup information structure. Used only
3073 * in the call to @c write_iso_and_go_on().
3074 * @return The number of errors encountered (0 for success)
3075 * @see write_iso_and_go_on
3076 * @see make_iso_fs
3077 * @bug The final ISO is written even if there are no files on it. In practice,
3078 * however, this occurs rarely.
3079 */
3080int write_final_iso_if_necessary()
3081{
3082 /*@ int ***************************************************** */
3083 int res;
3084
3085 /*@ buffers ************************************************** */
3086 char *tmp;
3087
3088 malloc_string(tmp);
3089 assert(bkpinfo != NULL);
3090
3091// 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
3092
3093 sprintf(tmp, "Writing the final ISO");
3094 log_msg(2, tmp);
3095 center_string(tmp, 80);
3096 if (!g_text_mode) {
3097 newtPushHelpLine(tmp);
3098 }
3099 res = write_iso_and_go_on(TRUE);
3100 if (!g_text_mode) {
3101 newtPopHelpLine();
3102 }
3103 log_msg(2, "Returning from writing final ISO (res=%d)", res);
3104 paranoid_free(tmp);
3105 return (res);
3106}
3107
3108
3109/**
3110 * Write an ISO image to <tt>[bkpinfo->isodir]/bkpinfo->prefix-[g_current_media_number].iso</tt>.
3111 * @param bkpinfo The backup information structure. Fields used:
3112 * - @c backup_media_type
3113 * - @c prefix
3114 * - @c isodir
3115 * - @c manual_cd_tray
3116 * - @c media_size
3117 * - @c netfs_remote_dir
3118 * - @c scratchdir
3119 * - @c verify_data
3120 *
3121 * @param last_cd If TRUE, this is the last CD to write; if FALSE, it's not.
3122 * @return The number of errors encountered (0 for success)
3123 * @see make_iso_fs
3124 */
3125int write_iso_and_go_on(bool last_cd)
3126{
3127 /*@ pointers **************************************************** */
3128 FILE *fout;
3129
3130 /*@ buffers ***************************************************** */
3131 char *tmp = NULL;
3132 char *tmp1 = NULL;
3133 char *cdno_fname = NULL;
3134 char *lastcd_fname = NULL;
3135 char *isofile = NULL;
3136 char *mds = NULL;
3137
3138 /*@ bool ******************************************************** */
3139 bool that_one_was_ok;
3140 bool orig_vfy_flag_val;
3141
3142 /*@ int *********************************************************** */
3143 int res = 0;
3144
3145 assert(bkpinfo != NULL);
3146 orig_vfy_flag_val = bkpinfo->verify_data;
3147 if (bkpinfo->media_size <= 0) {
3148 fatal_error("write_iso_and_go_on() - unknown media size");
3149 }
3150
3151 mds = media_descriptor_string(bkpinfo->backup_media_type);
3152 log_msg(1, "OK, time to make %s #%d", mds, g_current_media_number);
3153 mr_free(mds);
3154
3155 /* label the ISO with its number */
3156
3157 mr_asprintf(cdno_fname, "%s/archives/THIS-CD-NUMBER", bkpinfo->scratchdir);
3158 fout = fopen(cdno_fname, "w");
3159 mr_free(cdno_fname);
3160
3161 fprintf(fout, "%d", g_current_media_number);
3162 paranoid_fclose(fout);
3163
3164 mr_asprintf(tmp1, "cp -f %s/autorun %s/", g_mondo_home, bkpinfo->scratchdir);
3165 if (run_program_and_log_output(tmp1, FALSE)) {
3166 log_msg(2, "Warning - unable to copy autorun to scratchdir");
3167 }
3168 mr_free(tmp1);
3169
3170 /* last CD or not? Label accordingly */
3171 mr_asprintf(lastcd_fname, "%s/archives/NOT-THE-LAST", bkpinfo->scratchdir);
3172 if (last_cd) {
3173 unlink(lastcd_fname);
3174 log_msg(2,
3175 "OK, you're telling me this is the last CD. Fair enough.");
3176 } else {
3177 fout = fopen(lastcd_fname, "w");
3178 fprintf(fout,
3179 "You're listening to 90.3 WPLN, Nashville Public Radio.\n");
3180 paranoid_fclose(fout);
3181 }
3182 mr_free(lastcd_fname);
3183
3184 if (space_occupied_by_cd(bkpinfo->scratchdir) / 1024 > bkpinfo->media_size) {
3185 log_to_screen("Warning! CD is too big. It occupies %ld KB, which is more than the %ld KB allowed.",(long) space_occupied_by_cd(bkpinfo->scratchdir),(long) bkpinfo->media_size);
3186 }
3187 if (((bkpinfo->isodir == NULL) && (bkpinfo->netfs_remote_dir == NULL)) || (bkpinfo->prefix == NULL)) {
3188 fatal_error("Something wrong in your environement. Report to dev team");
3189 }
3190 if (bkpinfo->netfs_remote_dir) {
3191 // Network
3192 mr_asprintf(isofile, "%s/%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->netfs_remote_dir, bkpinfo->prefix, g_current_media_number);
3193 } else {
3194 // ISO
3195 mr_asprintf(isofile, "%s/%s-%d.iso", bkpinfo->isodir, bkpinfo->prefix, g_current_media_number);
3196 }
3197
3198 for (that_one_was_ok = FALSE; !that_one_was_ok;) {
3199 if (bkpinfo->backup_media_type != usb) {
3200 res = make_iso_fs(isofile);
3201 } else {
3202 res = make_usb_fs();
3203 }
3204 if (g_current_media_number == 1 && !res
3205 && (bkpinfo->backup_media_type == cdr
3206 || bkpinfo->backup_media_type == cdrw)) {
3207 if ((tmp = find_cdrom_device(FALSE)) == NULL) {
3208 // make sure find_cdrom_device() finds, records CD-R's loc
3209 log_msg(3, "*Sigh* Mike, I hate your computer.");
3210 // if it can't be found then force pausing
3211 bkpinfo->manual_cd_tray = TRUE;
3212 } else {
3213 log_msg(3, "Great. Found Mike's CD-ROM drive.");
3214 }
3215 mr_free(tmp);
3216 }
3217 if (bkpinfo->verify_data && !res) {
3218 mds = media_descriptor_string(g_backup_media_type);
3219 log_to_screen("Please reboot from the 1st %s in Compare Mode, as a precaution.", mds);
3220 mr_free(mds);
3221 if (chdir("/")) {
3222 // FIXME
3223 }
3224 log_it("Before calling verification of image()");
3225 if (bkpinfo->backup_media_type == usb) {
3226 res += verify_usb_image();
3227 } else {
3228 res += verify_cd_image();
3229 }
3230 log_it("After calling verification of image()");
3231 }
3232 if (!res) {
3233 that_one_was_ok = TRUE;
3234 } else {
3235 mds = media_descriptor_string(bkpinfo->backup_media_type);
3236 mr_asprintf(tmp1, "Failed to create %s #%d. Retry?", mds, g_current_media_number);
3237 mr_free(mds);
3238 res = ask_me_yes_or_no(tmp1);
3239 mr_free(tmp1);
3240
3241 if (!res) {
3242 if (ask_me_yes_or_no("Abort the backup?")) {
3243 fatal_error("FAILED TO BACKUP");
3244 } else {
3245 break;
3246 }
3247 } else {
3248 log_msg(2, "Retrying, at user's request...");
3249 res = 0;
3250 }
3251 }
3252 }
3253 mr_free(isofile);
3254
3255 g_current_media_number++;
3256 wipe_archives(bkpinfo->scratchdir);
3257 mr_asprintf(tmp1, "rm -Rf %s/images/*gz %s/images/*data*img", bkpinfo->scratchdir, bkpinfo->scratchdir);
3258 if (system(tmp1)) {
3259 log_msg(2, "Error occurred when I tried to delete the redundant IMGs and GZs");
3260 }
3261 mr_free(tmp1);
3262
3263 if (last_cd) {
3264 log_msg(2, "This was your last media.");
3265 } else {
3266 log_msg(2, "Continuing to backup your data...");
3267 }
3268
3269 bkpinfo->verify_data = orig_vfy_flag_val;
3270 return (0);
3271}
3272
3273/* @} - end of LLarchiveGroup */
3274
3275
3276
3277
3278/**
3279 * Verify the user's data.
3280 * @param bkpinfo The backup information structure. Fields used:
3281 * - @c backup_data
3282 * - @c backup_media_type
3283 * - @c media_device
3284 * - @c verify_data
3285 *
3286 * @return The number of errors encountered (0 for success)
3287 * @ingroup verifyGroup
3288 */
3289int verify_data()
3290{
3291 int res = 0, retval = 0, cdno = 0;
3292 char *tmp = NULL;
3293 char *mds = NULL;
3294 long diffs = 0;
3295
3296 assert(bkpinfo != NULL);
3297 if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
3298 if (chdir("/")) {
3299 // FIXME
3300 }
3301 mvaddstr_and_log_it(g_currentY, 0,
3302 "Verifying archives against live filesystem");
3303 if (bkpinfo->backup_media_type == cdstream) {
3304 mr_free(bkpinfo->media_device);
3305 mr_asprintf(bkpinfo->media_device, "/dev/cdrom");
3306 }
3307 verify_tape_backups();
3308 mvaddstr_and_log_it(g_currentY++, 74, "Done.");
3309 } else if (bkpinfo->backup_data)
3310 //bkpinfo->backup_media_type == cdrw || bkpinfo->backup_media_type == cdr))
3311 {
3312 log_msg(2,
3313 "Not verifying again. Per-CD/ISO verification already carried out.");
3314 mr_asprintf(tmp, "cat %s/changed.files > %s/changed.files 2> /dev/null",bkpinfo->tmpdir, MONDO_CACHE);
3315 paranoid_system(tmp);
3316 mr_free(tmp);
3317 } else {
3318 g_current_media_number = cdno;
3319 if (bkpinfo->backup_media_type != iso) {
3320 mr_free(bkpinfo->media_device);
3321 bkpinfo->media_device = find_cdrom_device(FALSE); // replace 0,0,0 with /dev/cdrom
3322 }
3323 if (chdir("/")) {
3324 // FIXME
3325 }
3326 for (cdno = 1; cdno < 99 && bkpinfo->verify_data; cdno++) {
3327 if (cdno != g_current_media_number) {
3328 log_msg(2,
3329 "Warning - had to change g_current_media_number from %d to %d",
3330 g_current_media_number, cdno);
3331 g_current_media_number = cdno;
3332 }
3333 if (bkpinfo->backup_media_type != iso) {
3334 insist_on_this_cd_number(cdno);
3335 }
3336 res = verify_cd_image(); // sets verify_data to FALSE if it's time to stop verifying
3337 retval += res;
3338 if (res) {
3339 mds = media_descriptor_string(bkpinfo->backup_media_type);
3340 log_to_screen("Warnings/errors were reported while checking %s #%d", mds, g_current_media_number);
3341 mr_free(mds);
3342
3343 }
3344 }
3345 mr_asprintf(tmp, "grep 'afio: ' %s | sed 's/afio: //' | grep -vE '^/dev/.*$' >> %s/changed.files", MONDO_LOGFILE, MONDO_CACHE);
3346 res = system(tmp);
3347 mr_free(tmp);
3348
3349 mr_asprintf(tmp, "grep 'star: ' %s | sed 's/star: //' | grep -vE '^/dev/.*$' >> %s/changed.files", MONDO_LOGFILE, MONDO_CACHE);
3350 res = system(tmp);
3351 mr_free(tmp);
3352 run_program_and_log_output("umount " MNT_CDROM, FALSE);
3353// if (bkpinfo->backup_media_type != iso && !bkpinfo->please_dont_eject_when_restoring)
3354 if (!bkpinfo->please_dont_eject) {
3355 eject_device(bkpinfo->media_device);
3356 }
3357 }
3358 mr_asprintf(tmp, "%s/changed.files", MONDO_CACHE);
3359 diffs = count_lines_in_file(tmp);
3360 mr_free(tmp);
3361
3362 if (diffs > 0) {
3363 if (retval == 0) {
3364 retval = (int) (-diffs);
3365 }
3366 }
3367 return (retval);
3368}
3369
3370
3371void setenv_mondo_share(void) {
3372
3373setenv("MONDO_SHARE", MONDO_SHARE, 1);
3374}
Note: See TracBrowser for help on using the repository browser.