source: MondoRescue/branches/3.2/mondo/src/common/libmondo-archive.c@ 3397

Last change on this file since 3397 was 3397, checked in by Bruno Cornec, 9 years ago

Adds a boot-type config option

It's filled by mondoarchive, passed to mindi as new 23rd param and
stored in the config file. It's also now read at restore time. No
exploitation of this parameter is done yet.
Remains also to prepare a correct bootable device for restoration
(currently ia64 == EFI we should manage the boot loader separately from
the boot type and from the boot env of the DR media)

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