source: branches/stable/mondo/src/common/libmondo-archive.c @ 1669

Last change on this file since 1669 was 1669, checked in by Bruno Cornec, 13 years ago

use conf file for kernel_path

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