source: branches/2.2.7/mondo/src/common/libmondo-archive.c @ 2030

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