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

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

Compiler warning solved (M. Loiseleur again !)
Code displaced to ease memeory management in case of exit in libmondo-archive.c

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