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

Last change on this file since 3878 was 3878, checked in by Bruno Cornec, 2 years ago

Fix compiler errors

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