source: branches/2.2.6/mondo/src/common/libmondo-stream.c @ 1940

Last change on this file since 1940 was 1940, checked in by bruno, 11 years ago

Improve log when errors on ext. attr.

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