source: branches/3.0/mondo/src/common/libmondo-stream.c @ 3192

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