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

Last change on this file since 3498 was 3494, checked in by Bruno Cornec, 10 years ago

Update mondo to point to the isolinux subdir now created for ISO images and use the images subdir also for coherency for boot.cat files

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