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

Last change on this file since 956 was 956, checked in by bruno, 13 years ago

merge -r938:954 $SVN_M/branches/stable

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