source: MondoRescue/branches/stable/mondo/src/common/libmondo-stream.c @ 1370

Last change on this file since 1370 was 1370, checked in by Bruno Cornec, 14 years ago

Fix a compilation error

  • Property svn:keywords set to Id
File size: 46.4 KB
Line 
1/* $Id: libmondo-stream.c 1370 2007-04-30 00:11:07Z bruno $
2
3...tools for talking to tapes, Monitas streams, etc.
4*/
5
6/*
7 *
8 * @file
9 * Functions for writing data to/reading data from streams (tape, CD stream, etc.)
10 */
11
12#include <unistd.h>
13
14#include "my-stuff.h"
15#include "mr_mem.h"
16#include "mr_msg.h"
17#include "mr_list.h"
18
19#include "mondostructures.h"
20#include "libmondo-devices.h"
21#include "libmondo-stream.h"
22#include "libmondo-string-EXT.h"
23#include "libmondo-files-EXT.h"
24#include "newt-specific-EXT.h"
25#include "libmondo-fork-EXT.h"
26#include "libmondo-tools-EXT.h"
27#include "libmondo-fifo-EXT.h"
28
29#define EXTRA_TAPE_CHECKSUMS
30
31/*@unused@*/
32//static char cvsid[] = "$Id: libmondo-stream.c 1370 2007-04-30 00:11:07Z bruno $";
33extern bool g_sigpipe;
34extern int g_tape_buffer_size_MB;
35
36extern char *g_getfacl;
37extern char *g_getfattr;
38extern char *MONDO_LOGFILE;
39
40/**
41 * @addtogroup globalGroup
42 * @{
43 */
44/**
45 * The file pointer for the opened tape/CD stream.
46 * Opened and closed by openin_tape(), openin_cdstream(),
47 * openout_tape(), openout_cdstream(), closein_tape(), closein_cdstream(),
48 * closeout_tape(), and closeout_cdstream().
49 */
50FILE *g_tape_stream = NULL;
51
52
53/**
54 * The position (in kilobytes) where we are on the tape.
55 */
56long long g_tape_posK = 0;
57
58/**
59 * The current media number we're using. This value is 1-based.
60 */
61int g_current_media_number = -1;
62
63/**
64 * An entry in the tape catalog.
65 */
66struct s_tapecat_entry {
67    /**
68     * The type of archive it is (afioball, slice, or something else).
69     */
70    t_archtype type;
71
72    /**
73     * The filelist number or biggiefile (not slice!) number.
74     */
75    int number;
76
77    /**
78     * The slice number if it's a biggiefile.
79     */
80    long aux;
81
82    /**
83     * The tape position at the point this entry was added.
84     */
85    long long tape_posK;
86
87    /**
88     * The filename of the file cataloged here.
89     */
90    char *fname;
91};
92
93
94/*
95 * The tape catalog that keeps track of files written to tape.
96 * made of a list of @p s_tapecat_entry.
97 * */
98static struct mr_list *tapecatalog;
99
100/* function to free the fname field allocated in te */
101static void mr_free_te(void *data) {
102   
103    struct s_tapecat_entry *te = NULL;
104
105    te = (struct s_tapecat_entry *)data;
106    mr_free(te->fname);
107}
108
109/* @} - end of globalGroup */
110
111int write_backcatalog_to_tape(struct s_bkpinfo *bkpinfo);
112
113
114/**
115 * @addtogroup streamGroup
116 * @{
117 */
118/**
119 * Close the global output file descriptor which Mondo has used to read
120 * from the CD stream.
121 * @param bkpinfo The backup information structure. Passed directly to closein_tape().
122 * @return 0 for success, nonzero for failure.
123 * @note This should be called by restore processes only.
124 */
125int closein_cdstream(struct s_bkpinfo *bkpinfo)
126{
127    return (closein_tape(bkpinfo));
128}
129
130
131/**
132 * Close the global output file descriptor which Mondo has used to read
133 * from buffer or dd, which read from the tape.
134 * @param bkpinfo The backup information structure. Unused.
135 * @return 0 for success, nonzero for failure.
136 * @note This should be called by restore processes only.
137 * @note This function also works for cdstreams for now, but don't count on this behavior.
138 * @bug @p bkpinfo parameter is unused.
139 */
140int closein_tape(struct s_bkpinfo *bkpinfo)
141{
142    /*@ int's ******************************************************* */
143    int retval = 0;
144    int res = 0;
145    int ctrl_chr = '\0';
146
147    /*@ buffers ***************************************************** */
148    char fname[MAX_STR_LEN];
149
150    /*@ long long's ************************************************* */
151    long long size;
152    char *blk;
153    int i;
154
155    blk = (char *) mr_malloc(256 * 1024);
156
157    log_it("closein_tape() -- entering");
158    res = read_header_block_from_stream(&size, fname, &ctrl_chr);
159    retval += res;
160    if (ctrl_chr != BLK_END_OF_BACKUP) {
161        wrong_marker(BLK_END_OF_BACKUP, ctrl_chr);
162    }
163    res = read_header_block_from_stream(&size, fname, &ctrl_chr);
164    retval += res;
165    if (ctrl_chr != BLK_END_OF_TAPE) {
166        wrong_marker(BLK_END_OF_TAPE, ctrl_chr);
167    }
168    for (i = 0; i < 8 && !feof(g_tape_stream); i++) {
169        (void) fread(blk, 1, 256 * 1024, g_tape_stream);
170    }
171    sleep(1);
172    sync();
173    sleep(1);
174    paranoid_pclose(g_tape_stream);
175    log_it("closein_tape() -- leaving");
176    if (!bkpinfo->please_dont_eject) {
177        eject_device(bkpinfo->media_device);
178    }
179    mr_free(blk);
180    mr_list_free(tapecatalog);
181    return (retval);
182}
183
184
185
186/**
187 * Close the global output file descriptor which Mondo has been using to write
188 * to the tape device (via buffer or dd).
189 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
190 * @return 0 for success, nonzero for failure.
191 * @note This should be called by backup processes only.
192 */
193int closeout_tape(struct s_bkpinfo *bkpinfo)
194{
195    /*@ int's ******************************************************* */
196    int retval = 0;
197
198    /*@ long long's ************************************************* */
199    int i = 0;
200    char *blk = NULL;
201    struct mr_list_elt *elt = NULL;
202    struct s_tapecat_entry *te = NULL;
203
204    blk = (char *) mr_malloc(256 * 1024);
205
206    sleep(1);
207    sync();
208    sleep(1);
209    log_it("closeout_tape() -- entering");
210    retval +=
211        write_header_block_to_stream((off_t)0, "end-of-backup",
212                                     BLK_END_OF_BACKUP);
213    retval += write_header_block_to_stream((off_t)0, "end-of-tape", BLK_END_OF_TAPE);   /* just in case */
214    /* write 1MB of crap */
215    for (i = 0; i < 256 * 1024; i++) {
216        blk[i] = (int) (random() & 0xFF);
217    }
218    for (i = 0; i < 4 * 8; i++) {
219        (void) fwrite(blk, 1, 256 * 1024, g_tape_stream);
220        if (should_we_write_to_next_tape
221            (bkpinfo->media_size, (off_t)256 * 1024)) {
222            start_to_write_to_next_tape(bkpinfo);
223        }
224    }
225    sleep(2);
226    paranoid_pclose(g_tape_stream);
227    log_it("closeout_tape() -- leaving");
228    elt = tapecatalog->first;
229    while (elt != NULL) {
230        te = (struct s_tapecat_entry *)elt->data;
231        log_it("i=%d type=%s num=%d aux=%ld posK=%lld", i,
232               (te->type == fileset) ? "fileset" : "bigslice",
233               te->number, te->aux, te->tape_posK);
234        i++;
235        elt = elt->next;
236    }
237    mr_free(blk);
238    mr_list_free(tapecatalog);
239    return (retval);
240}
241
242
243
244bool mt_says_tape_exists(char *dev)
245{
246    char *command;
247    int res;
248
249    mr_asprintf(&command, "mt -f %s status", dev);
250    res = run_program_and_log_output(command, 1);
251    mr_free(command);
252    if (res) {
253        return (FALSE);
254    } else {
255        return (TRUE);
256    }
257}
258
259
260
261/**
262 * Determine the name and size of the tape device. Tries the SCSI tape for
263 * this platform, then the IDE tape, then "/dev/st0", then "/dev/osst0".
264 * @param dev Where to put the found tape device.
265 * @param siz Where to put the tape size (a string like "4GB")
266 * @return 0 if success, nonzero if failure (in which @p dev and @p siz are undefined).
267 */
268int find_tape_device_and_size(char *dev, char *siz)
269{
270    char tmp[MAX_STR_LEN];
271    char *command = NULL;
272    char cdr_exe[MAX_STR_LEN];
273    int res;
274
275    log_to_screen("I am looking for your tape streamer. Please wait.");
276    dev[0] = siz[0] = '\0';
277    if (find_home_of_exe("cdrecord")) {
278        strcpy(cdr_exe, "cdrecord");
279    } else {
280        strcpy(cdr_exe, "dvdrecord");
281    }
282    mr_asprintf(&command, "%s -scanbus 2> /dev/null | grep -i tape | wc -l",
283            cdr_exe);
284    strcpy(tmp, call_program_and_get_last_line_of_output(command));
285    mr_free(command);
286    if (atoi(tmp) != 1) {
287        log_it
288            ("Either too few or too many tape streamers for me to detect...");
289        strcpy(dev, VANILLA_SCSI_TAPE);
290        return 1;
291    }
292    mr_asprintf(&command,
293            "%s -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep -i TAPE | cut -d' ' -f2 | head -n1",
294            cdr_exe);
295    strcpy(tmp, call_program_and_get_last_line_of_output(command));
296    mr_free(command);
297    if (strlen(tmp) < 2) {
298        log_it("Could not find tape device");
299        return 1;
300    }
301    mr_asprintf(&command,
302            "%s -scanbus 2> /dev/null | tr -s '\t' ' ' | grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep -i TAPE | cut -d' ' -f3 | cut -d')' -f1 | head -n1",
303            cdr_exe);
304    strcpy(tmp, call_program_and_get_last_line_of_output(command));
305    mr_free(command);
306
307    strcpy(dev, VANILLA_SCSI_TAPE);
308    dev[strlen(dev) - 1] = '\0';
309    strcat(dev, tmp);           // e.g. '/dev/st0' becomes '/dev/stN'
310    res = 0;
311    if (!mt_says_tape_exists(dev)) {
312        strcpy(dev, ALT_TAPE);
313        if (!mt_says_tape_exists(dev)) {
314            log_it("Cannot openin %s", dev);
315            strcpy(dev, "/dev/st0");
316            if (!mt_says_tape_exists(dev)) {
317                log_it("Cannot openin %s", dev);
318                strcpy(dev, "/dev/osst0");
319                if (!mt_says_tape_exists(dev)) {
320                    res++;
321                } else {
322                    res = 0;
323                }
324            }
325        }
326    }
327
328    log_it("At this point, dev = %s and res = %d", dev, res);
329
330    strcpy(tmp, call_program_and_get_last_line_of_output("\
331cdrecord -scanbus 2> /dev/null | tr -s '\t' ' ' | \
332grep \"[0-9]*,[0-9]*,[0-9]*\" | grep -v \"[0-9]*) \\*\" | grep -i TAPE | \
333awk '{for(i=1; i<NF; i++) { if (index($i, \"GB\")>0) { print $i;};};};'"));
334
335    if (mt_says_tape_exists(dev)) {
336        res = 0;
337    } else {
338        log_it("Turning %s", dev);
339        strcpy(tmp, (strrchr(dev, '/') != NULL) ? strrchr(dev, '/') : dev);
340        sprintf(dev, "/dev/os%s", tmp);
341        log_it("...into %s", dev);
342        if (mt_says_tape_exists(dev)) {
343            res = 0;
344        } else {
345            res++;
346        }
347    }
348
349    siz[0] = '\0';
350    log_it("res=%d; dev=%s", res, dev);
351
352    if (res) {
353        return (res);
354    }
355
356    if (strlen(tmp) < 2) {
357        siz[0] = '\0';
358        log_it("Warning - size of tape unknown");
359        return (0);
360    } else {
361        strcpy(siz, tmp);
362        return (0);
363    }
364}
365
366
367int read_EXAT_files_from_tape(struct s_bkpinfo *bkpinfo,
368                              long long *ptmp_size, char *tmp_fname,
369                              int *pctrl_chr, char *xattr_fname,
370                              char *acl_fname)
371{
372    int res = 0;
373    int retval = 0;
374    char *fname = (char *)&res;                 /* Should NOT be NULL */
375
376// xattr
377    if (g_getfattr) {
378        res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
379        if (*pctrl_chr != BLK_START_EXAT_FILE) {
380            wrong_marker(BLK_START_EXAT_FILE, *pctrl_chr);
381        }
382        if (!strstr(fname, "xattr")) {
383            fatal_error("Wrong order, sunshine.");
384        }
385        read_file_from_stream_to_file(bkpinfo, xattr_fname, *ptmp_size);
386        res = read_header_block_from_stream(ptmp_size, tmp_fname, pctrl_chr);
387        if (*pctrl_chr != BLK_STOP_EXAT_FILE) {
388            wrong_marker(BLK_STOP_EXAT_FILE, *pctrl_chr);
389        }
390        mr_msg(1, "Got xattr");
391    }
392    // acl
393    if (g_getfacl) {
394        res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
395        if (!strstr(fname, "acl")) {
396            fatal_error("Wrong order, sunshine.");
397        }
398        if (*pctrl_chr != BLK_START_EXAT_FILE) {
399            wrong_marker(BLK_START_EXAT_FILE, *pctrl_chr);
400        }
401        read_file_from_stream_to_file(bkpinfo, acl_fname, *ptmp_size);
402        res = read_header_block_from_stream(ptmp_size, tmp_fname, pctrl_chr);
403        if (*pctrl_chr != BLK_STOP_EXAT_FILE) {
404            wrong_marker(BLK_STOP_EXAT_FILE, *pctrl_chr);
405        }
406        res = read_header_block_from_stream(ptmp_size, tmp_fname, pctrl_chr);
407        if (*pctrl_chr != BLK_STOP_EXTENDED_ATTRIBUTES) {
408            wrong_marker(BLK_STOP_EXTENDED_ATTRIBUTES, *pctrl_chr);
409        }
410        mr_msg(1, "Got acl");
411    }
412    // tarball itself
413    res = read_header_block_from_stream(ptmp_size, tmp_fname, pctrl_chr);
414    mr_msg(1, "now looking for afioball");
415    return (retval);
416}
417
418
419int write_EXAT_files_to_tape(struct s_bkpinfo *bkpinfo, char *xattr_fname,
420                             char *acl_fname)
421{
422    int res = 0;
423    if (g_getfattr) {
424    // xattr
425        write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname,
426                             BLK_START_EXTENDED_ATTRIBUTES);
427        write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname,
428                             BLK_START_EXAT_FILE);
429        write_file_to_stream_from_file(bkpinfo, xattr_fname);
430        write_header_block_to_stream((off_t)-1, xattr_fname, BLK_STOP_EXAT_FILE);
431    }
432    if (g_getfacl) {
433    // acl
434        write_header_block_to_stream(length_of_file(acl_fname), acl_fname,
435                             BLK_START_EXAT_FILE);
436        write_file_to_stream_from_file(bkpinfo, acl_fname);
437        write_header_block_to_stream((off_t)-1, acl_fname, BLK_STOP_EXAT_FILE);
438        write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname,
439                             BLK_STOP_EXTENDED_ATTRIBUTES);
440    }
441    return (res);
442}
443
444
445
446
447/**
448 * Tell the user to insert tape @p tapeno and wait for it to settle (5 seconds).
449 * @param tapeno The tape number to insist on.
450 * @bug There is currently no way to actually verify that the user has actually
451 * inserted the right tape.
452 */
453void insist_on_this_tape_number(int tapeno)
454{
455    int i;
456    char *tmp = NULL;
457
458    log_it("Insisting on tape #%d", tapeno);
459    if (g_current_media_number != tapeno) {
460        //      log_it("g_current_media_number = %d", g_current_media_number);
461        mr_asprintf(&tmp,
462                 _("When the tape drive goes quiet, please insert volume %d in this series."),
463                 tapeno);
464        popup_and_OK(tmp);
465        mr_free(tmp);
466        open_evalcall_form(_("Waiting while the tape drive settles"));
467    } else {
468        open_evalcall_form(_("Waiting while the tape drive rewinds"));
469    }
470
471    for (i = 0; i <= 100; i += 2) {
472        usleep(100000);
473        update_evalcall_form(i);
474    }
475    close_evalcall_form();
476    log_it("I assume user has inserted it. They _say_ they have...");
477    g_current_media_number = tapeno;
478
479    //  log_it("g_current_media_number = %d", g_current_media_number);
480    log_it("OK, I've finished insisting. On with the revelry.");
481}
482
483
484/**
485 * Debugging aid - log the offset we're at on the tape (reading or writing).
486 */
487void log_tape_pos(void)
488{
489    log_it("Tape position -- %ld KB (%ld MB)", (long) g_tape_posK,
490           (long) g_tape_posK >> 10);
491}
492
493
494/**
495 * Add a file to a collection of recently archived filesets/slices.
496 * The type is determined by the filename: if it contains ".afio." it is
497 * assumed to be a fileset, otherwise if it contains "slice" it's a slice,
498 * otherwise we generate a fatal_error().
499 * @param td The current @c bkpinfo->tempdir (file will be placed in <tt>td</tt>/tmpfs/backcatalog/).
500 * @param latest_fname The file to place in the collection.
501 * @return 0, always.
502 * @bug Return value is redundant.
503 * @bug The detection won't work for uncompressed afioballs (they end in ".afio", no dot afterwards). // Not true. They end in '.' -Hugo
504 */
505int maintain_collection_of_recent_archives(char *td, char *latest_fname)
506{
507    long long final_alleged_writeK, final_projected_certain_writeK,
508        final_actually_certain_writeK = 0, cposK, bufsize_K;
509    int last, i;
510    t_archtype type = other;
511    char *command = NULL;
512    char *tmpdir = NULL;
513    char *old_fname = NULL;
514    struct mr_list_elt *elt = NULL;
515    struct s_tapecat_entry *te = NULL;
516
517    bufsize_K = (long long) (1024LL * (1 + g_tape_buffer_size_MB));
518    if (strstr(latest_fname, ".afio.") || strstr(latest_fname, ".star.")) {
519        type = fileset;
520    } else if (strstr(latest_fname, "slice")) {
521        type = biggieslice;
522    } else {
523        log_it("fname = %s", latest_fname);
524        fatal_error
525            ("Unknown type. Internal error in maintain_collection_of_recent_archives()");
526    }
527
528    mr_asprintf(&tmpdir, "%s/tmpfs/backcatalog", td);
529    mkdir(tmpdir, 0x700);
530    mr_asprintf(&command, "cp -f %s %s", latest_fname, tmpdir);
531    if (run_program_and_log_output(command, 6)) {
532        log_it("Warning - failed to copy %s to backcatalog at %s",
533               latest_fname, tmpdir);
534    }
535    mr_free(command);
536
537    last = mr_list_length(tapecatalog) - 1;
538    if (last <= 0) {
539        iamhere("Too early to start deleting from collection.");
540        return (0);
541    }
542    elt = tapecatalog->last;
543    te = (struct s_tapecat_entry *)elt->data;
544    final_alleged_writeK = te->tape_posK;
545    final_projected_certain_writeK = final_alleged_writeK - bufsize_K;
546    while (elt != NULL) {
547        te = (struct s_tapecat_entry *)elt->data;
548        cposK = te->tape_posK;
549        if (cposK < final_projected_certain_writeK) {
550            final_actually_certain_writeK = cposK;
551            break;
552        }
553        elt = elt->prev;
554    }
555    if (elt == NULL) {
556        iamhere
557            ("Not far enough into tape to start deleting old archives from collection.");
558        return (0);
559    }
560
561    elt = elt->prev;
562    i = 0;
563    while ((elt != NULL) && (i < 10)) {
564        te = (struct s_tapecat_entry *)elt->data;
565        mr_asprintf(&old_fname, "%s/%s", tmpdir, te->fname);
566        unlink(old_fname);
567        mr_free(old_fname);
568        elt = elt->prev;
569        i++;
570    }
571    mr_free(tmpdir);
572    return (0);
573}
574
575
576/**
577 * Open the CD stream for input.
578 * @param bkpinfo The backup information structure. Passed to openin_tape().
579 * @return 0 for success, nonzero for failure.
580 * @note Equivalent to openin_tape() for now, but don't count on this behavior.
581 */
582int openin_cdstream(struct s_bkpinfo *bkpinfo)
583{
584    return (openin_tape(bkpinfo));
585}
586
587
588int set_tape_block_size_with_mt(char *tapedev,
589                                long internal_tape_block_size)
590{
591    char *tmp;
592    int res;
593
594    if (strncmp(tapedev, "/dev/", 5)) {
595        mr_msg(1,
596                "Not using 'mt setblk'. This isn't an actual /dev entry.");
597        return (0);
598    }
599    mr_asprintf(&tmp, "mt -f %s setblk %ld", tapedev,
600             internal_tape_block_size);
601    res = run_program_and_log_output(tmp, 3);
602    mr_free(tmp);
603    return (res);
604}
605
606
607/**
608 * Open the tape device for input.
609 * @param bkpinfo The backup information structure. Fields used:
610 * - @c bkpinfo->media_device
611 * - @c bkpinfo->tmpdir
612 * @return 0 for success, nonzero for failure.
613 * @note This will also work with a cdstream for now, but don't count on this behavior.
614 */
615int openin_tape(struct s_bkpinfo *bkpinfo)
616{
617    /*@ buffer ***************************************************** */
618    char fname[MAX_STR_LEN];
619    char *datablock = NULL;
620    char *tmp = NULL;
621    char old_cwd[MAX_STR_LEN];
622    char *outfname = NULL;
623    /*@ int ******************************************************* */
624    int i;
625    int j;
626    int res;
627    long length, templong;
628    size_t k;
629    int retval = 0;
630    int ctrl_chr;
631
632    /*@ long long ************************************************* */
633    long long size;
634
635    /*@ pointers ************************************************** */
636    FILE *fout;
637
638    /*@ end vars *************************************************** */
639
640    assert_string_is_neither_NULL_nor_zerolength(bkpinfo->media_device);
641    mr_list_alloc(tapecatalog);
642    g_tape_posK = 0;
643    if (g_tape_stream) {
644        log_it("FYI - I won't 'openin' the tape. It's already open.");
645        return (0);
646    }
647    insist_on_this_tape_number(1);
648    mr_asprintf(&outfname, "%s/tmp/all.tar.gz", bkpinfo->tmpdir);
649    make_hole_for_file(outfname);
650
651    set_tape_block_size_with_mt(bkpinfo->media_device,
652                                bkpinfo->internal_tape_block_size);
653
654    log_it("Opening IN tape");
655    if (!
656        (g_tape_stream =
657         open_device_via_buffer(bkpinfo->media_device, 'r',
658                                bkpinfo->internal_tape_block_size))) {
659        log_to_screen(_("Cannot openin stream device"));
660        return (1);
661    }
662    log_to_screen(_("Reading stream"));
663    log_it("stream device = '%s'", bkpinfo->media_device);
664    /* skip data disks */
665    open_evalcall_form("Skipping data disks on stream");
666    log_to_screen(_("Skipping data disks on stream"));
667    if (!(fout = fopen(outfname, "w"))) {
668        log_OS_error(outfname);
669        log_to_screen(_("Cannot openout datadisk all.tar.gz file"));
670        return (-1);
671    }
672    datablock = (char *) mr_malloc(256 * 1024);
673    for (i = 0; i < 32; i++) {
674        for (j = 0; j < 4; j++) {
675            for (length = 0, k = 0; length < 256 * 1024; length += k) {
676                k = fread(datablock + length, 1, 256 * 1024 - length,
677                          g_tape_stream);
678            }
679            (void) fwrite(datablock, 1, (size_t) length, fout);
680            g_tape_posK += length / 1024;
681        }
682        if (i > 8)              // otherwise, 'buffer' distorts calculations
683        {
684            templong = ((i - 8) * 4 + j) * 100 / (128 - 8 * 4);
685            update_evalcall_form((int) (templong));
686        }
687    }
688    paranoid_fclose(fout);
689    mr_free(datablock);
690    /* find initial blocks */
691    res = read_header_block_from_stream(&size, fname, &ctrl_chr);
692    retval += res;
693    if (ctrl_chr != BLK_START_OF_TAPE) {
694        wrong_marker(BLK_START_OF_TAPE, ctrl_chr);
695    }
696    res = read_header_block_from_stream(&size, fname, &ctrl_chr);
697    retval += res;
698    if (ctrl_chr != BLK_START_OF_BACKUP) {
699        wrong_marker(BLK_START_OF_BACKUP, ctrl_chr);
700    }
701    close_evalcall_form();
702    log_it("Saved all.tar.gz to '%s'", outfname);
703    (void) getcwd(old_cwd, MAX_STR_LEN);
704    chdir(bkpinfo->tmpdir);
705    mr_asprintf(&tmp, "tar -zxf %s tmp/mondo-restore.cfg 2> /dev/null",
706             outfname);
707    paranoid_system(tmp);
708    mr_free(tmp);
709    paranoid_system("cp -f tmp/mondo-restore.cfg . 2> /dev/null");
710    chdir(old_cwd);
711    unlink(outfname);
712    mr_free(outfname);
713    return (retval);
714}
715
716
717/**
718 * Start writing to a CD stream.
719 * @param cddev The CD device to openout via cdrecord.
720 * @param speed The speed to write at.
721 * @return 0 for success, nonzero for failure.
722 * @note This should be called only from backup processes.
723 */
724int openout_cdstream(char *cddev, int speed)
725{
726    /*@ buffers ***************************************************** */
727    char *command = NULL;
728
729    /*@ end vars *************************************************** */
730
731    /*  add 'dummy' if testing */
732    mr_asprintf(&command,
733             "cdrecord -eject dev=%s speed=%d fs=24m -waiti - >> %s 2>> %s",
734             cddev, speed, MONDO_LOGFILE, MONDO_LOGFILE);
735    /*  initialise the catalog */
736    g_current_media_number = 1;
737    mr_list_alloc(tapecatalog);
738    /* log stuff */
739    log_it("Opening OUT cdstream with the command");
740    log_it(command);
741    /*  log_it("Let's see what happens, shall we?"); */
742    g_tape_stream = popen(command, "w");
743    mr_free(command);
744    if (g_tape_stream) {
745        return (0);
746    } else {
747        log_to_screen(_("Failed to openout to cdstream (fifo)"));
748        return (1);
749    }
750}
751
752
753/**
754 * Start writing to a tape device for the backup.
755 * @param tapedev The tape device to open for writing.
756 * @return 0 for success, nonzero for failure.
757 * @note This should be called ONLY from backup processes. It will OVERWRITE ANY
758 * EXISTING DATA on the tape!
759 */
760int openout_tape(char *tapedev, long internal_tape_block_size)
761{
762    g_current_media_number = 1;
763    if (g_tape_stream) {
764        log_it("FYI - I won't 'openout' the tape. It's already open.");
765        return (0);
766    }
767    mr_list_alloc(tapecatalog);
768    g_tape_posK = 0;
769
770    set_tape_block_size_with_mt(tapedev, internal_tape_block_size);
771    log_it("Opening OUT tape");
772    if (!
773        (g_tape_stream =
774         open_device_via_buffer(tapedev, 'w', internal_tape_block_size))) {
775        log_to_screen(_("Cannot openin stream device"));
776        return (1);
777    }
778    return (0);
779}
780
781
782/**
783 * Copy a file from the opened stream (CD or tape) to @p outfile.
784 * @param bkpinfo The backup information structure. @c bkpinfo->media_device is the only field used.
785 * @param outfile The file to write to.
786 * @param size The size of the file in the input stream.
787 * @return 0 for success, nonzero for failure.
788 */
789int
790read_file_from_stream_to_file(struct s_bkpinfo *bkpinfo, char *outfile,
791                              long long size)
792{
793
794    /*@ int ******************************************************** */
795    int res;
796
797    /*@ end vars *************************************************** */
798
799    res = read_file_from_stream_FULL(bkpinfo, outfile, NULL, size);
800
801    return (res);
802}
803
804
805/**
806 * Copy a file from the currently opened stream (CD or tape) to the stream indicated
807 * by @p fout.
808 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
809 * @param fout The stream to write the file to.
810 * @param size The size of the file in bytes.
811 * @return 0 for success, nonzero for failure.
812 */
813int
814read_file_from_stream_to_stream(struct s_bkpinfo *bkpinfo, FILE * fout,
815                                long long size)
816{
817
818    /*@ int ******************************************************** */
819    int res;
820
821    /*@ end vars *************************************************** */
822
823    res = read_file_from_stream_FULL(bkpinfo, NULL, fout, size);
824    return (res);
825}
826
827
828/**
829 * Copy a file from the currently opened stream (CD or tape) to either a
830 * @c FILE pointer indicating a currently-opened file, or a filename indicating
831 * a new file to create. This is the backbone function that read_file_from_stream_to_file()
832 * and read_file_from_stream_to_stream() are wrappers for.
833 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
834 * @param outfname If non-NULL, write to this file.
835 * @param foutstream If non-NULL, write to this stream.
836 * @param orig_size The original length of the file in bytes.
837 * @return 0 for success, nonzero for failure.
838 * @note Only @b one of @p outfname or @p foutstream may be non-NULL.
839 */
840int
841read_file_from_stream_FULL(struct s_bkpinfo *bkpinfo, char *outfname,
842                           FILE * foutstream, long long orig_size)
843{
844    /*@ buffers ***************************************************** */
845    char *tmp = NULL;
846    char *datablock = NULL;
847    char *temp_fname;
848    char *temp_cksum;
849    char *actual_cksum = NULL;
850
851    /*@ int ********************************************************* */
852    int retval = 0;
853#ifdef EXTRA_TAPE_CHECKSUMS
854    int i, ch;
855#endif
856    int noof_blocks;
857    int ctrl_chr;
858    int res;
859    /*@ pointers **************************************************** */
860    FILE *fout;
861
862    /*@ long    ***************************************************** */
863    long bytes_to_write = 0;
864
865    /*@ long long *************************************************** */
866    long long temp_size, size;
867    long bytes_read, bytes_to_read;
868    long long total_read_from_tape_for_this_file = 0;
869    long long where_I_was_before_tape_change = 0;
870    /*@ unsigned int ************************************************ */
871    unsigned int crc16;
872    unsigned int crctt;
873
874    bool had_to_resync = FALSE;
875
876    /*@ init  ******************************************************* */
877    malloc_string(temp_fname);
878    malloc_string(temp_cksum);
879    datablock = mr_malloc(TAPE_BLOCK_SIZE);
880    crc16 = 0;
881    crctt = 0;
882    size = orig_size;
883
884    /*@ end vars *************************************************** */
885
886    res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
887    if (orig_size != temp_size && orig_size != -1) {
888        mr_asprintf(&tmp,
889                 "output file's size should be %ld K but is apparently %ld K",
890                 (long) size >> 10, (long) temp_size >> 10);
891        log_to_screen(tmp);
892        mr_free(tmp);
893    }
894    if (ctrl_chr != BLK_START_FILE) {
895        wrong_marker(BLK_START_FILE, ctrl_chr);
896        return (1);
897    }
898    mr_asprintf(&tmp, "Reading file from tape; writing to '%s'; %ld KB",
899             outfname, (long) size >> 10);
900    log_to_screen(tmp);
901    mr_free(tmp);
902
903    if (foutstream) {
904        fout = foutstream;
905    } else {
906        fout = fopen(outfname, "w");
907    }
908    if (!fout) {
909        log_OS_error(outfname);
910        log_to_screen(_("Cannot openout file"));
911        return (1);
912    }
913    total_read_from_tape_for_this_file = 0;
914    for (noof_blocks = 0; size > 0;
915         noof_blocks++, size -=
916         bytes_to_write, total_read_from_tape_for_this_file +=
917         bytes_read) {
918        bytes_to_write =
919            (size < TAPE_BLOCK_SIZE) ? (long) size : TAPE_BLOCK_SIZE;
920        bytes_to_read = TAPE_BLOCK_SIZE;
921        bytes_read = fread(datablock, 1, bytes_to_read, g_tape_stream);
922        while (bytes_read < bytes_to_read) {    // next tape!
923//    crctt=crc16=0;
924            where_I_was_before_tape_change = size;
925            mr_msg(4, "where_I_was_... = %lld",
926                    where_I_was_before_tape_change);
927            start_to_read_from_next_tape(bkpinfo);
928            mr_msg(4, "Started reading from next tape.");
929            skip_incoming_files_until_we_find_this_one(temp_fname);
930            mr_msg(4, "Skipped irrelevant files OK.");
931            for (size = orig_size; size > where_I_was_before_tape_change;
932                 size -= bytes_to_write) {
933                bytes_read =
934                    fread(datablock, 1, bytes_to_read, g_tape_stream);
935            }
936            mr_msg(4, "'size' is now %lld (should be %lld)", size,
937                    where_I_was_before_tape_change);
938            log_to_screen("Successfully re-sync'd tape");
939            had_to_resync = TRUE;
940            bytes_read = fread(datablock, 1, bytes_to_read, g_tape_stream);
941        }
942
943        (void) fwrite(datablock, 1, (size_t) bytes_to_write, fout); // for blocking reasons, bytes_successfully_read_in isn't necessarily the same as bytes_to_write
944
945#ifdef EXTRA_TAPE_CHECKSUMS
946        for (i = 0; i < (int) bytes_to_write; i++) {
947            ch = datablock[i];
948            crc16 = updcrcr(crc16, (unsigned) ch);
949            crctt = updcrc(crctt, (unsigned) ch);
950        }
951#endif
952    }
953    mr_msg(6, "Total read from tape for this file = %lld",
954            total_read_from_tape_for_this_file);
955    mr_msg(6, ".......................... Should be %lld", orig_size);
956    g_tape_posK += total_read_from_tape_for_this_file / 1024;
957    mr_asprintf(&actual_cksum, "%04x%04x", crc16, crctt);
958    if (foutstream) {           /*log_it("Finished writing to foutstream"); */
959    } else {
960        paranoid_fclose(fout);
961    }
962    res = read_header_block_from_stream(&temp_size, temp_cksum, &ctrl_chr);
963    if (ctrl_chr != BLK_STOP_FILE) {
964        wrong_marker(BLK_STOP_FILE, ctrl_chr);
965//      fatal_error("Bad marker"); // return(1);
966    }
967    if (strcmp(temp_cksum, actual_cksum)) {
968        mr_asprintf(&tmp, _("actual cksum=%s; recorded cksum=%s"), actual_cksum,
969                 temp_cksum);
970        log_to_screen(tmp);
971        mr_free(tmp);
972
973        mr_asprintf(&tmp, _("%s (%ld K) is corrupt on tape"), temp_fname,
974                 (long) orig_size >> 10);
975        log_to_screen(tmp);
976        mr_free(tmp);
977        retval++;
978    }
979    mr_free(actual_cksum);
980    mr_free(datablock);
981    mr_free(temp_fname);
982    mr_free(temp_cksum);
983    return (retval);
984}
985
986
987/**
988 * Read a header block from the currently opened stream (CD or tape).
989 * This block indicates the length of the following file (if it's file-related)
990 * the filename (if it's file-related), and the block type.
991 * @param plen Where to put the length of the file. Valid only for file-related header blocks.
992 * @param filename Where to put the name of the file. Valid only for file-related header blocks.
993 * @param pcontrol_char Where to put the type of block (e.g. start-file, end-file, start-tape, ...)
994 * @return 0 for success, nonzero for failure.
995 * @note If you read a marker (@p pcontrol_char) you're not expecting, you can call wrong_marker().
996 */
997int
998read_header_block_from_stream(long long *plen, char *filename,
999                              int *pcontrol_char)
1000{
1001
1002    /*@ buffers ***************************************************** */
1003    char *tempblock;
1004
1005    /*@ int ********************************************************* */
1006    int i, retval;
1007
1008    /*@ end vars *************************************************** */
1009
1010    tempblock = (char *) mr_malloc((size_t) TAPE_BLOCK_SIZE);
1011
1012    for (i = 0; i < (int) TAPE_BLOCK_SIZE; i++) {
1013        tempblock[i] = 0;
1014    }
1015    while (!(*pcontrol_char = tempblock[7000])) {
1016        g_tape_posK +=
1017            fread(tempblock, 1, (size_t) TAPE_BLOCK_SIZE,
1018                  g_tape_stream) / 1024;
1019    }
1020    memcpy((char *) plen, tempblock + 7001, sizeof(long long));
1021    if (strcmp(tempblock + 6000 + *pcontrol_char, "Mondolicious, baby")) {
1022        log_it("Bad header block at %ld K", (long) g_tape_posK);
1023    }
1024    strcpy(filename, tempblock + 1000);
1025    if (*pcontrol_char == BLK_ABORTED_BACKUP) {
1026        log_to_screen("I can't verify an aborted backup.");
1027        retval = 1;
1028    } else {
1029        retval = 0;
1030    }
1031    for (i = 1000; i < 1020; i++) {
1032        if (tempblock[i] < 32 || tempblock[i] > 126) {
1033            tempblock[i] = ' ';
1034        }
1035    }
1036    tempblock[i] = '\0';
1037    mr_msg(6, "%s (fname=%s, size=%ld K)",
1038            marker_to_string(*pcontrol_char), tempblock + 1000,
1039            (long) (*plen) >> 10);
1040    mr_free(tempblock);
1041    return (retval);
1042}
1043
1044
1045/**
1046 * Add specified file/slice to the internal catalog of all archives written.
1047 * This lets us restart on a new CD/tape/whatever if it runs out of room. We just
1048 * write the last [buffer size] MB from the catalog to the new tape, so we know
1049 * we have @e all archives on some CD/tape/whatever.
1050 * @param type The type of file we're cataloging (afioball, slice, something else)
1051 * @param number The fileset number or biggiefile number.
1052 * @param aux The slice number if it's a biggiefile, or any other additional info.
1053 * @param fn The original full pathname of the file we're recording.
1054 * @return The index of the record we just added.
1055 */
1056int register_in_tape_catalog(t_archtype type, int number, long aux,
1057                             char *fn)
1058{
1059    char *fname = NULL;
1060    char *p = NULL;
1061    struct s_tapecat_entry *te = NULL;
1062    struct mr_list_elt *elt = NULL;
1063
1064    p = strrchr(fn, '/');
1065    if (p) {
1066        p++;
1067    } else {
1068        p = fn;
1069    }
1070    mr_asprintf(&fname, p);
1071
1072    te = (struct s_tapecat_entry *)mr_malloc(sizeof(struct s_tapecat_entry));
1073    te->type = type;
1074    te->number = number;
1075    te->aux = aux;
1076    te->tape_posK = g_tape_posK;
1077    /* BERLIOS: Check if this is written womewhere, as it's only a pointer */
1078    /* BERLIOS: Verify to purge fname correctly */
1079    te->fname = fname;
1080
1081    /* place the data in a list elt */
1082    mr_list_alloc_elt(elt, (void *)te, mr_free_te);
1083    mr_list_add_elt_last(tapecatalog, elt);
1084
1085    // returns the index of the record we've just added
1086    return (mr_list_length(tapecatalog));
1087}
1088
1089
1090/**
1091 * Decide whether we should start a new tape. This is TRUE if we've run out of tape
1092 * (got SIGPIPE) or look like we will.
1093 * @param mediasize The size of the tape in megabytes.
1094 * @param length_of_incoming_file The length of the file we're about to write, in bytes.
1095 * @bug This seems like it'll only work for media_size != autodetect, but Mondo only allows
1096 * autodetecting the size. Huh?
1097 */
1098
1099/* BERLIOS: Should be reviewed for mediasize being a off_t ??? */
1100bool
1101should_we_write_to_next_tape(long mediasize,
1102                             off_t length_of_incoming_file)
1103{
1104    /*@ bool's ***************************************************** */
1105    bool we_need_a_new_tape = FALSE;
1106
1107    /*@ end vars *************************************************** */
1108
1109    if (mediasize == 0) {
1110        return (FALSE);
1111    }
1112    if (mediasize > 0 && (g_tape_posK >> 10 >= mediasize)) {
1113        log_it("mediasize = %ld", mediasize);
1114        we_need_a_new_tape = TRUE;
1115        log_to_screen(_("Should have started a new tape/CD already"));
1116    }
1117    if ((g_tape_posK + length_of_incoming_file / 1024) >> 10 >=
1118        mediasize - (SLICE_SIZE * 4 / 1024)) {
1119        log_it("g_tape_posK = %ld\nmediasize = %ld\n", g_tape_posK,
1120               mediasize);
1121        we_need_a_new_tape = TRUE;
1122    }
1123    return (we_need_a_new_tape);
1124}
1125
1126
1127/**
1128 * Seek through the stream until we find a header block where the NAME field matches
1129 * @p the_file_I_was_reading. This is useful if you've just started reading from
1130 * a new tape and want to find the file you were reading when the tape ended.
1131 * @param the_file_I_was_reading File name to look for.
1132 * @return 0 for success, nonzero for failure.
1133 */
1134int skip_incoming_files_until_we_find_this_one(char
1135                                               *the_file_I_was_reading)
1136{
1137    char *pA;
1138    char *pB;
1139    int res;
1140    int ctrl_chr;
1141    char *temp_fname;
1142    char *datablock;
1143    long long temp_size, size;
1144    long bytes_to_write;
1145
1146    datablock = mr_malloc(TAPE_BLOCK_SIZE);
1147    malloc_string(temp_fname);
1148    pB = strrchr(the_file_I_was_reading, '/');
1149    if (pB) {
1150        pB++;
1151    } else {
1152        pB = the_file_I_was_reading;
1153    }
1154    mr_msg(1, "skip_incoming_..(%s)", pB);
1155    mr_msg(2, "Looking for initial START_AN_AFIO_OR_SLICE");
1156    ctrl_chr = -1;
1157    while (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
1158        res =
1159            read_header_block_from_stream(&temp_size, temp_fname,
1160                                          &ctrl_chr);
1161        if (ctrl_chr == BLK_START_AN_AFIO_OR_SLICE) {
1162            break;
1163        }
1164        mr_msg(1, "%lld %s %c", temp_size, temp_fname, ctrl_chr);
1165        wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
1166        mr_msg(3, "Still trying to re-sync w/ tape");
1167    }
1168    while (ctrl_chr != BLK_START_FILE) {
1169        res =
1170            read_header_block_from_stream(&temp_size, temp_fname,
1171                                          &ctrl_chr);
1172        if (ctrl_chr == BLK_START_FILE) {
1173            break;
1174        }
1175        mr_msg(1, "%lld %s %c", temp_size, temp_fname, ctrl_chr);
1176        wrong_marker(BLK_START_FILE, ctrl_chr);
1177        mr_msg(3, "Still trying to re-sync w/ tape");
1178    }
1179    pA = strrchr(temp_fname, '/');
1180    if (pA) {
1181        pA++;
1182    } else {
1183        pA = temp_fname;
1184    }
1185    pB = strrchr(the_file_I_was_reading, '/');
1186    if (pB) {
1187        pB++;
1188    } else {
1189        pB = the_file_I_was_reading;
1190    }
1191    while (strcmp(pA, pB)) {
1192        mr_msg(6, "Skipping %s (it's not %s)", temp_fname,
1193                the_file_I_was_reading);
1194        for (size = temp_size; size > 0; size -= bytes_to_write) {
1195            bytes_to_write =
1196                (size < TAPE_BLOCK_SIZE) ? (long) size : TAPE_BLOCK_SIZE;
1197            // FIXME - needs error-checking and -catching
1198            fread(datablock, 1, (size_t) TAPE_BLOCK_SIZE, g_tape_stream);
1199        }
1200        res =
1201            read_header_block_from_stream(&temp_size, temp_fname,
1202                                          &ctrl_chr);
1203        if (ctrl_chr != BLK_STOP_FILE) {
1204            wrong_marker(BLK_STOP_FILE, ctrl_chr);
1205        }
1206        res =
1207            read_header_block_from_stream(&temp_size, temp_fname,
1208                                          &ctrl_chr);
1209        if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
1210            wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
1211        }
1212        res =
1213            read_header_block_from_stream(&temp_size, temp_fname,
1214                                          &ctrl_chr);
1215        if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
1216            wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
1217        }
1218        res =
1219            read_header_block_from_stream(&temp_size, temp_fname,
1220                                          &ctrl_chr);
1221        if (ctrl_chr != BLK_START_FILE) {
1222            wrong_marker(BLK_START_FILE, ctrl_chr);
1223        }
1224        pA = strrchr(temp_fname, '/');
1225        if (pA) {
1226            pA++;
1227        } else {
1228            pA = temp_fname;
1229        }
1230        pB = strrchr(the_file_I_was_reading, '/');
1231        if (pB) {
1232            pB++;
1233        } else {
1234            pB = the_file_I_was_reading;
1235        }
1236    }
1237    mr_msg(2, "Reading %s (it matches %s)", temp_fname,
1238            the_file_I_was_reading);
1239    mr_free(temp_fname);
1240    mr_free(datablock);
1241    return (0);
1242}
1243
1244
1245/**
1246 * Start to read from the next tape. Assumes the user has already inserted it.
1247 * @param bkpinfo The backup information structure. @c bkpinfo->media_device is the only field used.
1248 * @return 0 for success, nonzero for failure.
1249 */
1250int start_to_read_from_next_tape(struct s_bkpinfo *bkpinfo)
1251{
1252    /*@ int ********************************************************* */
1253    int res = 0;
1254    char *sz_msg;
1255    int ctrlchr;
1256    long long temp_size;
1257    malloc_string(sz_msg);
1258    /*@ end vars *************************************************** */
1259
1260    paranoid_pclose(g_tape_stream);
1261    sync();
1262    sync();
1263    sync();
1264    log_it("Next tape requested.");
1265    insist_on_this_tape_number(g_current_media_number + 1); // will increment it, too
1266    log_it("Opening IN the next tape");
1267    if (!
1268        (g_tape_stream =
1269         open_device_via_buffer(bkpinfo->media_device, 'r',
1270                                bkpinfo->internal_tape_block_size))) {
1271        log_to_screen(_("Cannot openin stream device"));
1272        return (1);
1273    }
1274    g_tape_posK = 0;
1275    g_sigpipe = FALSE;
1276    res += read_header_block_from_stream(&temp_size, sz_msg, &ctrlchr); /* just in case */
1277    if (ctrlchr != BLK_START_OF_TAPE) {
1278        wrong_marker(BLK_START_OF_TAPE, ctrlchr);
1279    }
1280    res += read_header_block_from_stream(&temp_size, sz_msg, &ctrlchr); /* just in case */
1281    if (ctrlchr != BLK_START_OF_BACKUP) {
1282        wrong_marker(BLK_START_OF_BACKUP, ctrlchr);
1283    } else {
1284        mr_msg(3, "Next tape opened OK. Whoopee!");
1285    }
1286    mr_free(sz_msg);
1287    return (res);
1288}
1289
1290
1291/**
1292 * Start to write to the next tape. Assume the user has already inserted it.
1293 * @param bkpinfo The backup information structure. @c bkpinfo->media_device is the only field used.
1294 * @return 0 for success, nonzero for failure.
1295 */
1296int start_to_write_to_next_tape(struct s_bkpinfo *bkpinfo)
1297{
1298    int res = 0;
1299    char *command = NULL;
1300
1301    paranoid_pclose(g_tape_stream);
1302    sync();
1303    sync();
1304    sync();
1305    log_it("New tape requested.");
1306    insist_on_this_tape_number(g_current_media_number + 1); // will increment g_current_media, too
1307    if (bkpinfo->backup_media_type == cdstream) {
1308        mr_asprintf(&command,
1309                 "cdrecord -eject dev=%s speed=%d fs=24m -waiti - >> %s 2>> %s",
1310                 bkpinfo->media_device, bkpinfo->cdrw_speed, MONDO_LOGFILE,
1311                 MONDO_LOGFILE);
1312        log_it("Opening OUT to next CD with the command");
1313        log_it(command);
1314        log_it("Let's see what happens, shall we?");
1315        g_tape_stream = popen(command, "w");
1316        mr_free(command);
1317        if (!g_tape_stream) {
1318            log_to_screen(_("Failed to openout to cdstream (fifo)"));
1319            return (1);
1320        }
1321    } else {
1322        log_it("Opening OUT to next tape");
1323        if (!
1324            (g_tape_stream =
1325             open_device_via_buffer(bkpinfo->media_device, 'w',
1326                                    bkpinfo->internal_tape_block_size))) {
1327            log_to_screen(_("Cannot openin stream device"));
1328            return (1);
1329        }
1330    }
1331    g_tape_posK = 0;
1332    g_sigpipe = FALSE;
1333    res += write_header_block_to_stream((off_t)0, "start-of-tape", BLK_START_OF_TAPE);  /* just in case */
1334    res += write_header_block_to_stream((off_t)0, "start-of-backup", BLK_START_OF_BACKUP);  /* just in case */
1335    return (res);
1336}
1337
1338
1339/**
1340 * Write a bufferfull of the most recent archives to the tape. The
1341 * rationale behind this is a bit complex. If the previous tape ended
1342 * suddenly (EOF or otherwise) some archives were probably left in the
1343 * buffer. That means that Mondo thinks they have been written, but
1344 * the external binary @c buffer has not actually written them. So to
1345 * be safe, we start the new tape by writing the last bufferfull from
1346 * the old one. This insures that all archives will be on at least
1347 * one tape. Sounds inelegant, but it works.
1348 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir is the only field used.
1349 * @return 0 for success, nonzero for failure.
1350 */
1351int write_backcatalog_to_tape(struct s_bkpinfo *bkpinfo)
1352{
1353    int i, last, res = 0;
1354    char *fname = NULL;
1355    struct mr_list_elt *elt = NULL;
1356    struct s_tapecat_entry *te = NULL;
1357
1358    mr_msg(2, "I am now writing back catalog to tape");
1359    elt = tapecatalog->first;
1360    while (elt != NULL) {
1361        te = (struct s_tapecat_entry *) elt->data;
1362        mr_asprintf(&fname, "%s/tmpfs/backcatalog/%s", bkpinfo->tmpdir, te->fname);
1363        if (!does_file_exist(fname)) {
1364            mr_msg(6, "Can't write %s - it doesn't exist.", fname);
1365        } else {
1366            write_header_block_to_stream(length_of_file(fname),
1367                                         "start-backcatalog-afio-or-slice",
1368                                         BLK_START_AN_AFIO_OR_SLICE);
1369            mr_msg(2, "Writing %s", fname);
1370            if (write_file_to_stream_from_file(bkpinfo, fname)) {
1371                res++;
1372                mr_msg(2, "%s failed", fname);
1373            }
1374            if (i != last) {
1375                write_header_block_to_stream((off_t)0,
1376                                             "stop-backcatalog-afio-or-slice",
1377                                             BLK_STOP_AN_AFIO_OR_SLICE);
1378            }
1379        }
1380        mr_free(fname);
1381        elt = elt->next;
1382    }
1383    mr_msg(2, "Finished writing back catalog to tape");
1384    return (res);
1385}
1386
1387
1388/**
1389 * Write all.tar.gz (produced by Mindi) to the first 32M of the first tape.
1390 * @param fname The path to all.tar.gz.
1391 * @return 0 for success, nonzero for failure.
1392 */
1393int write_data_disks_to_stream(char *fname)
1394{
1395    /*@ pointers *************************************************** */
1396    FILE *fin = NULL;
1397    char *tmp = NULL;
1398
1399    /*@ long ******************************************************* */
1400    long m = -1;
1401    long templong;
1402
1403    /*@ int ******************************************************** */
1404    int i, j;
1405
1406    /*@ buffers **************************************************** */
1407    char tempblock[256 * 1024];
1408
1409    /*@ end vars *************************************************** */
1410
1411    open_evalcall_form(_("Writing data disks to tape"));
1412    log_to_screen(_("Writing data disks to tape"));
1413    log_it("Data disks = %s", fname);
1414    if (!does_file_exist(fname)) {
1415        mr_asprintf(&tmp, _("Cannot find %s"), fname);
1416        log_to_screen(tmp);
1417        mr_free(tmp);
1418        return (1);
1419    }
1420    if (!(fin = fopen(fname, "r"))) {
1421        log_OS_error(fname);
1422        fatal_error("Cannot openin the data disk");
1423    }
1424    for (i = 0; i < 32; i++) {  /* 32MB */
1425        for (j = 0; j < 4; j++) {   /* 256K x 4 = 1MB (1024K) */
1426            if (!feof(fin)) {
1427                m = (long) fread(tempblock, 1, 256 * 1024, fin);
1428            } else {
1429                m = 0;
1430            }
1431            for (; m < 256 * 1024; m++) {
1432                tempblock[m] = '\0';
1433            }
1434            g_tape_posK +=
1435                fwrite(tempblock, 1, 256 * 1024, g_tape_stream) / 1024;
1436        }
1437        if (i > g_tape_buffer_size_MB)  // otherwise, 'buffer' distorts calculations
1438        {
1439            templong = ((i - 8) * 4 + j) * 100 / (128 - 8 * 4);
1440            update_evalcall_form((int) (templong));
1441        }
1442    }
1443    paranoid_fclose(fin);
1444    close_evalcall_form();
1445    return (0);
1446}
1447
1448
1449/**
1450 * Copy @p infile to the opened stream (CD or tape).
1451 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
1452 * @param infile The file to write to the stream.
1453 * @return 0 for success, nonzero for failure.
1454 */
1455int write_file_to_stream_from_file(struct s_bkpinfo *bkpinfo, char *infile)
1456{
1457    /*@ buffers **************************************************** */
1458    char *tmp = NULL;
1459    char datablock[TAPE_BLOCK_SIZE];
1460    char *checksum = NULL;
1461    char *infile_basename = NULL;
1462
1463    /*@ int ******************************************************** */
1464    int retval = 0;
1465    int noof_blocks;
1466
1467    /*  unsigned int ch; */
1468    unsigned int crc16;
1469    unsigned int crctt;
1470
1471    /*@ pointers *************************************************** */
1472    FILE *fin;
1473    char *p;
1474
1475    /*@ long ******************************************************* */
1476    long bytes_to_read = 0;
1477    long i;
1478
1479    off_t filesize;
1480
1481#ifdef EXTRA_TAPE_CHECKSUMS
1482    int ch;
1483#endif
1484
1485    /*@ initialize ************************************************ */
1486    crc16 = 0;
1487    crctt = 0;
1488
1489    /*@ end vars *************************************************** */
1490
1491    infile_basename = strrchr(infile, '/');
1492    if (infile_basename) {
1493        infile_basename++;
1494    } else {
1495        infile_basename = infile;
1496    }
1497    filesize = length_of_file(infile);
1498    if (should_we_write_to_next_tape
1499        (bkpinfo->media_size, filesize)) {
1500        start_to_write_to_next_tape(bkpinfo);
1501        write_backcatalog_to_tape(bkpinfo);
1502    }
1503    p = strrchr(infile, '/');
1504    if (!p) {
1505        p = infile;
1506    } else {
1507        p++;
1508    }
1509    mr_asprintf(&tmp, "Writing file '%s' to tape (%ld KB)", p,
1510             (long) filesize >> 10);
1511    log_it(tmp);
1512    mr_free(tmp);
1513
1514    write_header_block_to_stream(filesize, infile_basename,
1515                                 BLK_START_FILE);
1516//go_here_to_restart_saving_of_file:
1517    if (!(fin = fopen(infile, "r"))) {
1518        log_OS_error(infile);
1519        return (1);
1520    }
1521    for (noof_blocks = 0; filesize > 0;
1522         noof_blocks++, filesize -= bytes_to_read) {
1523        if (filesize < TAPE_BLOCK_SIZE) {
1524            bytes_to_read = (long) filesize;
1525            for (i = 0; i < TAPE_BLOCK_SIZE; i++) {
1526                datablock[i] = '\0';
1527            }
1528        } else {
1529            bytes_to_read = TAPE_BLOCK_SIZE;
1530        }
1531        (void) fread(datablock, 1, (size_t) bytes_to_read, fin);
1532        g_tape_posK += fwrite(datablock, 1, /*bytes_to_read */
1533                              (size_t) TAPE_BLOCK_SIZE,
1534                              g_tape_stream) / 1024;
1535        if (g_sigpipe) {
1536            iamhere("Sigpipe occurred recently. I'll start a new tape.");
1537            fclose(fin);
1538            g_sigpipe = FALSE;
1539            start_to_write_to_next_tape(bkpinfo);
1540            write_backcatalog_to_tape(bkpinfo); // kinda-sorta recursive :)
1541            return (0);
1542        }
1543#ifdef EXTRA_TAPE_CHECKSUMS
1544        for (i = 0; i < bytes_to_read; i++) {
1545            ch = datablock[i];
1546            crc16 = updcrcr(crc16, (unsigned) ch);
1547            crctt = updcrc(crctt, (unsigned) ch);
1548        }
1549#endif
1550    }
1551    paranoid_fclose(fin);
1552    mr_asprintf(&checksum, "%04x%04x", crc16, crctt);
1553    /* BERLIOS: what does it do ??? */
1554    write_header_block_to_stream((off_t)g_current_media_number, checksum,
1555                                 BLK_STOP_FILE);
1556    mr_free(checksum);
1557//  log_it("File '%s' written to tape.", infile);
1558    return (retval);
1559}
1560
1561
1562/**
1563 * Write a header block to the opened stream (CD or tape).
1564 * @param length_of_incoming_file The length to store in the header block.
1565 * Usually matters only if this is a file-related header, in which case it should
1566 * be the length of the file that will follow.
1567 * @param filename The filename to store in the header block. Usually matters
1568 * only if this is a file-related header, in which case this should be the name
1569 * if the file that will follow.
1570 * @param control_char The type of header block this is (start-file, end-file, start-tape, ...)
1571 * @return 0 for success, nonzero for failure.
1572 */
1573int
1574write_header_block_to_stream(off_t length_of_incoming_file,
1575                             char *filename, int control_char)
1576{
1577    /*@ buffers **************************************************** */
1578    char tempblock[TAPE_BLOCK_SIZE];
1579    char *p;
1580
1581    /*@ int ******************************************************** */
1582    int i;
1583
1584    off_t olen;
1585
1586    /*@ end vars *************************************************** */
1587
1588
1589    olen = length_of_incoming_file;
1590    p = strrchr(filename, '/'); /* Make 'em go, "Unnnh!" Oh wait, that was _Master_ P... */
1591    if (!p) {
1592        p = filename;
1593    } else {
1594        p++;
1595    }
1596    if (!g_tape_stream) {
1597        log_to_screen
1598            (_("You're not backing up to tape. Why write a tape header?"));
1599        return (1);
1600    }
1601    for (i = 0; i < (int) TAPE_BLOCK_SIZE; i++) {
1602        tempblock[i] = 0;
1603    }
1604    sprintf(tempblock + 6000 + control_char, "Mondolicious, baby");
1605    tempblock[7000] = control_char;
1606    memcpy(tempblock + 7001, (char *) &olen, sizeof(off_t));
1607    strcpy(tempblock + 1000, filename);
1608    g_tape_posK +=
1609        fwrite(tempblock, 1, (size_t) TAPE_BLOCK_SIZE,
1610               g_tape_stream) / 1024;
1611    mr_msg(6, "%s (fname=%s, size=%ld K)",
1612            marker_to_string(control_char), p,
1613            (long) length_of_incoming_file >> 10);
1614    return (0);
1615}
1616
1617
1618/**
1619 * Log (to screen) an erroneous marker, along with what it should have been.
1620 * @param should_be What we were expecting.
1621 * @param it_is What we got.
1622 */
1623void wrong_marker(int should_be, int it_is)
1624{
1625    /*@ buffer ***************************************************** */
1626    char *tmp = NULL;
1627
1628
1629    /*@ end vars *************************************************** */
1630    mr_asprintf(&tmp, _("Wrong marker! (Should be %s, is actually %s)"),
1631             marker_to_string(should_be), marker_to_string(it_is));
1632    log_to_screen(tmp);
1633    mr_free(tmp);
1634}
1635
1636/* @} - end of streamGroup */
Note: See TracBrowser for help on using the repository browser.