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

Last change on this file since 127 was 127, checked in by bcornec, 14 years ago

merge -r 125:126 $SVN_M/branches/2.05

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