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

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

Initial import from latest mondo-2.04_cvs_20050503/mindi-1.04_cvs_20050503 on http://www.mondorescue.org

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