source: trunk/mondo/mondo/src/libmondo-stream.c @ 795

Last change on this file since 795 was 783, checked in by bruno, 13 years ago
  • Massive rewrite continues for memory management.
  • main structure should now have all parameters allocated dynamically
  • new lib libmr.a + dir + build process reviewed to support it.
  • new include subdir to host external definitions of the new lib
  • code now compiles. Still one remaining link issues for mondorestore. This should allow for some tests soon.

(goal is to separate completely reviewed code and functions and provide clean interfaces)

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