Imported Upstream version 2.5.2p1
[debian/amanda] / server-src / taper.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998, 2000 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /* $Id: taper.c,v 1.144 2006/08/24 11:23:32 martinea Exp $
27  *
28  * moves files from holding disk to tape, or from a socket to tape
29  */
30
31 #include "amanda.h"
32 #include "util.h"
33 #include "conffile.h"
34 #include "tapefile.h"
35 #include "clock.h"
36 #include "stream.h"
37 #include "holding.h"
38 #include "logfile.h"
39 #include "tapeio.h"
40 #include "changer.h"
41 #include "version.h"
42 #include "arglist.h"
43 #include "token.h"
44 #include "amfeatures.h"
45 #include "fileheader.h"
46 #include "server_util.h"
47 #include "taperscan.c"
48
49 #ifdef HAVE_SYS_MMAN_H
50 #include <sys/mman.h>
51 #endif
52
53 #define taper_debug(i,x) do {           \
54         if ((i) <= debug_taper) {       \
55             dbprintf(x);                \
56         }                               \
57 } while (0)
58
59 #ifdef HAVE_LIBVTBLC
60 #include <vtblc.h>
61 #include <strings.h>
62 #include <math.h>
63
64 static int vtbl_no   = -1;
65 static int len       =  0;
66 static int offset    =  0;
67 static char *datestr = NULL;
68 static char start_datestr[20];
69 static time_t raw_time;
70 static struct tm tape_time;
71 static struct tm backup_time;
72 static struct tm *tape_timep = &tape_time;
73 typedef struct vtbl_lbls {
74     u_int8_t  label[45];
75     u_int8_t  date[20];
76 } vtbl_lbls;
77 static vtbl_lbls vtbl_entry[MAX_VOLUMES];
78 #endif /* HAVE_LIBVTBLC */
79
80 /*
81  * XXX update stat collection/printing
82  * XXX advance to next tape first in next_tape
83  * XXX label is being read twice?
84  */
85 static off_t splitsize = (off_t)0; /* max size of dumpfile before split (Kb) */
86 static off_t mmap_splitsize = (off_t)0;
87 static char *mmap_filename = NULL;
88 static char *mmap_splitbuf = NULL;
89 static char *mem_splitbuf = NULL;
90 static char *splitbuf = NULL;
91 static off_t mem_splitsize = (off_t)0;
92 static char *splitbuf_wr_ptr = NULL; /* the number of Kb we've written into splitbuf */
93 int orig_holdfile = -1;
94
95 /* NBUFS replaced by conf_tapebufs */
96 /* #define NBUFS                20 */
97 static int conf_tapebufs;
98
99 static off_t maxseek = (off_t)1 << ((SIZEOF(off_t) * 8) - 11);
100
101 static char *holdfile_path = NULL;
102 static char *holdfile_path_thischunk = NULL;
103 static int num_holdfile_chunks = 0;
104 static off_t holdfile_offset_thischunk = (off_t)0;
105 static int mmap_splitbuffer_fd = -1;
106
107 #define MODE_NONE 0
108 #define MODE_FILE_WRITE 1
109 #define MODE_PORT_WRITE 2
110
111 static mode_t mode = MODE_NONE;
112
113 /* This is now the number of empties, not full bufs */
114 #define THRESHOLD       1
115
116 #define CONNECT_TIMEOUT 2*60
117
118 #define EMPTY 1
119 #define FILLING 2
120 #define FULL 3
121
122 typedef struct buffer_s {
123     long status;
124     ssize_t size;
125     char *buffer;
126 } buffer_t;
127
128 #define nextbuf(p)    ((p) == buftable+conf_tapebufs-1? buftable : (p)+1)
129 #define prevbuf(p)    ((p) == buftable? buftable+conf_tapebufs-1 : (p)-1)
130
131 /* major modules */
132 int main(int main_argc, char **main_argv);
133 void file_reader_side(int rdpipe, int wrpipe);
134 void tape_writer_side(int rdpipe, int wrpipe);
135 void put_syncpipe_fault_result(char *handle);
136
137 /* shared-memory routines */
138 char *attach_buffers(size_t size);
139 void detach_buffers(char *bufp);
140 void destroy_buffers(void);
141 #define REMOVE_SHARED_MEMORY() \
142     detach_buffers(buffers); \
143     if (strcmp(procname, "reader") == 0) { \
144         destroy_buffers(); \
145     }
146
147 /* synchronization pipe routines */
148 void syncpipe_init(int rd, int wr);
149 void syncpipe_read_error(ssize_t rc, ssize_t expected);
150 void syncpipe_write_error(ssize_t rc, ssize_t expected);
151 int syncpipe_get(int *intp);
152 int syncpipe_getint(void);
153 char *syncpipe_getstr(void);
154 int syncpipe_put(int ch, int intval);
155 int syncpipe_putint(int i);
156 int syncpipe_putstr(const char *str);
157
158 /* tape manipulation subsystem */
159 int first_tape(char *new_datestamp);
160 int next_tape(int writerr);
161 int end_tape(int writerr);
162 int write_filemark(void);
163
164 /* support crap */
165 int seek_holdfile(int fd, buffer_t *bp, off_t kbytes);
166
167 /* signal handling */
168 static void install_signal_handlers(void);
169 static void signal_handler(int);
170
171 /* exit routine */
172 static void cleanup(void);
173
174 /*
175  * ========================================================================
176  * GLOBAL STATE
177  *
178  */
179 int interactive;
180 pid_t writerpid;
181 times_t total_wait;
182
183 char *buffers = NULL;
184 buffer_t *buftable = NULL;
185 int err;
186
187 char *procname = "parent";
188
189 char *taper_timestamp = NULL;
190 char *label = NULL;
191 int filenum;
192 char *errstr = NULL;
193 int tape_fd = -1;
194 char *tapedev = NULL;
195 char *tapetype = NULL;
196 tapetype_t *tt = NULL;
197 size_t tt_blocksize;
198 size_t tt_blocksize_kb;
199 size_t buffer_size;
200 int tt_file_pad;
201 static unsigned long malloc_hist_1, malloc_size_1;
202 static unsigned long malloc_hist_2, malloc_size_2;
203 dumpfile_t file;
204 dumpfile_t *save_holdfile = NULL;
205 off_t cur_span_chunkstart = (off_t)0; /* start of current split dump chunk (Kb) */
206 char *holdfile_name;
207 int num_splits = 0;
208 int expected_splits = 0;
209 int num_holdfiles = 0;
210 times_t curdump_rt;
211
212 am_feature_t *their_features = NULL;
213
214 int runtapes, cur_tape, have_changer, tapedays;
215 char *labelstr, *conf_tapelist;
216 #ifdef HAVE_LIBVTBLC
217 char *rawtapedev;
218 int first_seg, last_seg;
219 #endif /* HAVE_LIBVTBLC */
220
221 /*
222  * ========================================================================
223  * MAIN PROGRAM
224  *
225  */
226 int
227 main(
228     int main_argc,
229     char **main_argv)
230 {
231     int p2c[2], c2p[2];         /* parent-to-child, child-to-parent pipes */
232     char *conffile;
233     size_t size;
234     int i;
235     size_t j;
236     size_t page_size;
237     char *first_buffer;
238     int    new_argc,   my_argc;
239     char **new_argv, **my_argv;
240
241     safe_fd(-1, 0);
242
243     set_pname("taper");
244
245     dbopen("server");
246
247     /* Don't die when child closes pipe */
248     signal(SIGPIPE, SIG_IGN);
249
250     malloc_size_1 = malloc_inuse(&malloc_hist_1);
251
252     parse_conf(main_argc, main_argv, &new_argc, &new_argv);
253     my_argc = new_argc;
254     my_argv = new_argv;
255
256     fprintf(stderr, "%s: pid %ld executable %s version %s\n",
257             get_pname(), (long) getpid(), my_argv[0], version());
258     dbprintf(("%s: pid %ld executable %s version %s\n",
259             get_pname(), (long) getpid(), my_argv[0], version()));
260     fflush(stderr);
261
262     if (my_argc > 1 && my_argv[1][0] != '-') {
263         config_name = stralloc(my_argv[1]);
264         config_dir = vstralloc(CONFIG_DIR, "/", my_argv[1], "/", NULL);
265         my_argc--;
266         my_argv++;
267     } else {
268         char my_cwd[STR_SIZE];
269
270         if (getcwd(my_cwd, SIZEOF(my_cwd)) == NULL) {
271             error("cannot determine current working directory");
272             /*NOTREACHED*/
273         }
274         config_dir = stralloc2(my_cwd, "/");
275         if ((config_name = strrchr(my_cwd, '/')) != NULL) {
276             config_name = stralloc(config_name + 1);
277         }
278     }
279
280     safe_cd();
281
282     install_signal_handlers();
283     atexit(cleanup);
284
285     /* print prompts and debug messages if running interactive */
286
287     interactive = (my_argc > 1 && strcmp(my_argv[1],"-t") == 0);
288     if (interactive) {
289         erroutput_type = ERR_INTERACTIVE;
290     } else {
291         erroutput_type = ERR_AMANDALOG;
292         set_logerror(logerror);
293     }
294
295     free_new_argv(new_argc, new_argv);
296
297     conffile = stralloc2(config_dir, CONFFILE_NAME);
298     if (read_conffile(conffile)) {
299         error("errors processing config file \"%s\"", conffile);
300         /*NOTREACHED*/
301     }
302     amfree(conffile);
303
304     dbrename(config_name, DBG_SUBDIR_SERVER);
305
306     report_bad_conf_arg();
307
308     conf_tapelist = getconf_str(CNF_TAPELIST);
309     if (*conf_tapelist == '/') {
310         conf_tapelist = stralloc(conf_tapelist);
311     } else {
312         conf_tapelist = stralloc2(config_dir, conf_tapelist);
313     }
314     if (read_tapelist(conf_tapelist)) {
315         error("could not load tapelist \"%s\"", conf_tapelist);
316         /*NOTREACHED*/
317     }
318
319     tapedev     = getconf_str(CNF_TAPEDEV);
320     if (tapedev != NULL)
321         tapedev = stralloc(tapedev);
322     tapetype    = getconf_str(CNF_TAPETYPE);
323     tt          = lookup_tapetype(tapetype);
324 #ifdef HAVE_LIBVTBLC
325     rawtapedev = stralloc(getconf_str(CNF_RAWTAPEDEV));
326 #endif /* HAVE_LIBVTBLC */
327     tapedays    = getconf_int(CNF_TAPECYCLE);
328     labelstr    = getconf_str(CNF_LABELSTR);
329
330     runtapes    = getconf_int(CNF_RUNTAPES);
331     cur_tape    = 0;
332
333     conf_tapebufs = getconf_int(CNF_TAPEBUFS);
334
335     tt_blocksize_kb = (size_t)tapetype_get_blocksize(tt);
336     tt_blocksize = tt_blocksize_kb * 1024;
337     tt_file_pad = tapetype_get_file_pad(tt);
338
339     if (interactive) {
340         fprintf(stderr,"taper: running in interactive test mode\n");
341         dbprintf(("taper: running in interactive test mode\n"));
342         fflush(stderr);
343     }
344
345     /* create read/write syncronization pipes */
346
347     if (pipe(p2c)) {
348         error("creating sync pipes: %s", strerror(errno));
349         /*NOTREACHED*/
350     }
351     if (pipe(c2p)) {
352         error("creating sync pipes: %s", strerror(errno));
353         /*NOTREACHED*/
354     }
355
356     /* create shared memory segment */
357
358 #if defined(HAVE_GETPAGESIZE)
359     page_size = (size_t)getpagesize();
360     fprintf(stderr, "%s: page size = " SIZE_T_FMT "\n",
361                 get_pname(), (SIZE_T_FMT_TYPE)page_size);
362     dbprintf(("%s: page size = " SIZE_T_FMT "\n", get_pname(),
363                 (SIZE_T_FMT_TYPE)page_size));
364 #else
365     page_size = 1024;
366     fprintf(stderr, "%s: getpagesize() not available, using " SIZE_T_FMT "\n",
367             get_pname(), page_size);
368     dbprintf((stderr, "%s: getpagesize() not available, using " SIZE_T_FMT "\n",
369             get_pname(), page_size));
370 #endif
371     buffer_size = am_round(tt_blocksize, page_size);
372     fprintf(stderr, "%s: buffer size is " SIZE_T_FMT "\n",
373             get_pname(), (SIZE_T_FMT_TYPE)buffer_size);
374     dbprintf(("%s: buffer size is " SIZE_T_FMT "\n",
375             get_pname(), (SIZE_T_FMT_TYPE)buffer_size));
376     while (conf_tapebufs > 0) {
377         size  = page_size;
378         size += conf_tapebufs * buffer_size;
379         size += conf_tapebufs * SIZEOF(buffer_t);
380         if ((buffers = attach_buffers(size)) != NULL) {
381             break;
382         }
383         log_add(L_INFO, "attach_buffers: (%d tapebuf%s: " SIZE_T_FMT " bytes) %s",
384                         conf_tapebufs,
385                         (conf_tapebufs == 1) ? "" : "s",
386                         size,
387                         strerror(errno));
388         conf_tapebufs--;
389     }
390     if (buffers == NULL) {
391         error("cannot allocate shared memory");
392         /*NOTREACHED*/
393     }
394
395     /* page boundary offset */
396     i = (int)((buffers - (char *)0) & (page_size - 1));
397     if (i != 0) {
398         first_buffer = buffers + page_size - i;
399         dbprintf(("%s: shared memory at %p, first buffer at %p\n",
400                 get_pname(),
401                 (void *)buffers,
402                 (void *)first_buffer));
403     } else {
404         first_buffer = buffers;
405     }
406
407     /*LINTED  first_buffer, conf_tapebufs and buffer size are all * pagesize */
408     buftable = (buffer_t *)(first_buffer + (conf_tapebufs * buffer_size));
409     memset(buftable, 0, conf_tapebufs * SIZEOF(buffer_t));
410     if (conf_tapebufs < 10) {
411         j = 1;
412     } else if (conf_tapebufs < 100) {
413         j = 2;
414     } else {
415         j = 3;
416     }
417     for (i = 0; i < conf_tapebufs; i++) {
418         buftable[i].buffer = first_buffer + i * buffer_size;
419         dbprintf(("%s: buffer[%0*d] at %p\n",
420                 get_pname(),
421                 (int)j, i,
422                 (void *)buftable[i].buffer));
423     }
424     dbprintf(("%s: buffer structures at %p for %d bytes\n",
425             get_pname(),
426             (void *)buftable,
427             (int)(conf_tapebufs * SIZEOF(buffer_t))));
428
429     /* fork off child writer process, parent becomes reader process */
430     switch(writerpid = fork()) {
431     case -1:
432         error("fork: %s", strerror(errno));
433         /*NOTREACHED*/
434
435     case 0:     /* child */
436         aclose(p2c[1]);
437         aclose(c2p[0]);
438
439         tape_writer_side(p2c[0], c2p[1]);
440         error("tape writer terminated unexpectedly");
441         /*NOTREACHED*/
442
443     default:    /* parent */
444         aclose(p2c[0]);
445         aclose(c2p[1]);
446
447         file_reader_side(c2p[0], p2c[1]);
448         error("file reader terminated unexpectedly");
449         /*NOTREACHED*/
450     }
451
452     /*NOTREACHED*/
453     return 0;
454 }
455
456
457 /*
458  * ========================================================================
459  * FILE READER SIDE
460  *
461  */
462 int read_file(int fd, char *handle,
463                   char *host, char *disk, char *datestamp, 
464                   int level);
465 ssize_t taper_fill_buffer(int fd, buffer_t *bp, size_t buflen);
466 void dumpbufs(char *str1);
467 void dumpstatus(buffer_t *bp);
468 ssize_t get_next_holding_file(int fd, buffer_t *bp, char **strclosing, size_t rc);
469 int predict_splits(char *filename);
470 void create_split_buffer(char *split_diskbuffer, size_t fallback_splitsize, char *id_string);
471 void free_split_buffer(void);
472
473
474 /*
475  * Create a buffer, either in an mmapped file or in memory, where PORT-WRITE
476  * dumps can buffer the current split chunk in case of retry.
477  */
478 void
479 create_split_buffer(
480     char *split_diskbuffer,
481     size_t fallback_splitsize,
482     char *id_string)
483 {
484     char *buff_err = NULL;
485     off_t offset;
486     char *splitbuffer_path = NULL;
487     
488     /* don't bother if we're not actually splitting */
489     if (splitsize <= (off_t)0) {
490         splitbuf = NULL;
491         splitbuf_wr_ptr = NULL;
492         return;
493     }
494
495 #ifdef HAVE_MMAP
496 #ifdef HAVE_SYS_MMAN_H
497     if (strcmp(split_diskbuffer, "NULL")) {
498         void *nulls = NULL;
499         char *quoted;
500         off_t c;
501
502         splitbuffer_path = vstralloc(split_diskbuffer,
503                                      "/splitdump_buffer",
504                                      NULL);
505         /* different file, munmap the previous */
506         if (mmap_filename && strcmp(mmap_filename, splitbuffer_path) != 0) {
507             dbprintf(("create_split_buffer: new file %s\n", splitbuffer_path));
508             munmap(splitbuf, (size_t)mmap_splitsize);
509             aclose(mmap_splitbuffer_fd);
510             mmap_splitbuf = NULL;
511             amfree(mmap_filename);
512             mmap_splitsize = 0;
513         }
514         if (!mmap_filename) {
515             dbprintf(("create_split_buffer: open file %s\n",
516                       splitbuffer_path));
517             mmap_splitbuffer_fd = open(splitbuffer_path, O_RDWR|O_CREAT, 0600);
518             if (mmap_splitbuffer_fd == -1) {
519                 buff_err = newvstralloc(buff_err, "open of ", 
520                                         splitbuffer_path, "failed (",
521                                         strerror(errno), ")", NULL);
522                 goto fallback;
523             }
524         }
525         offset = lseek(mmap_splitbuffer_fd, (off_t)0, SEEK_END) / 1024;
526         if (offset < splitsize) { /* Increase file size */
527             dbprintf(("create_split_buffer: increase file size of %s to "
528                       OFF_T_FMT "kb\n",
529                       splitbuffer_path, (OFF_T_FMT_TYPE)splitsize));
530             if (mmap_filename) {
531                 dbprintf(("create_split_buffer: munmap old file %s\n",
532                           mmap_filename));
533                 munmap(splitbuf, (size_t)mmap_splitsize);
534                 mmap_splitsize = 0;
535                 mmap_splitbuf = NULL;
536             }
537             nulls = alloc(1024); /* lame */
538             memset(nulls, 0, 1024);
539             for (c = offset; c < splitsize ; c += (off_t)1) {
540                 if (fullwrite(mmap_splitbuffer_fd, nulls, 1024) < 1024) {
541                     buff_err = newvstralloc(buff_err, "write to ",
542                                             splitbuffer_path,
543                                             "failed (", strerror(errno),
544                                             ")", NULL);
545                     c -= 1;
546                     if (c <= (off_t)fallback_splitsize) {
547                         goto fallback;
548                     }
549                     splitsize = c;
550                     break;
551                 }
552             }
553         }
554         amfree(nulls);
555
556         if (mmap_splitsize < splitsize*1024) {
557             mmap_splitsize = splitsize*1024;
558             mmap_filename = stralloc(splitbuffer_path);
559             dbprintf(("create_split_buffer: mmap file %s for " OFF_T_FMT "kb\n",
560                           mmap_filename,(OFF_T_FMT_TYPE)splitsize));
561             mmap_splitbuf = mmap(NULL, (size_t)mmap_splitsize,
562                                  PROT_READ|PROT_WRITE,
563                                  MAP_SHARED, mmap_splitbuffer_fd, (off_t)0);
564             if (mmap_splitbuf == (char*)-1) {
565                 buff_err = newvstralloc(buff_err, "mmap failed (",
566                                         strerror(errno), ")", NULL);
567                 aclose(mmap_splitbuffer_fd);
568                 amfree(mmap_filename);
569                 mmap_splitsize = 0;
570                 mmap_splitbuf = NULL;
571                 goto fallback;
572             }
573         }
574         quoted = quote_string(splitbuffer_path);
575         fprintf(stderr,
576                 "taper: r: buffering " OFF_T_FMT
577                 "kb split chunks in mmapped file %s\n",
578                 (OFF_T_FMT_TYPE)splitsize, quoted);
579         dbprintf(("taper: r: buffering " OFF_T_FMT
580                 "kb split chunks in mmapped file %s\n",
581                 (OFF_T_FMT_TYPE)splitsize, quoted));
582         amfree(splitbuffer_path);
583         amfree(quoted);
584         amfree(buff_err);
585         splitbuf = mmap_splitbuf;
586         splitbuf_wr_ptr = splitbuf;
587         return;
588     } else {
589         buff_err = stralloc("no split_diskbuffer specified");
590     }
591 #else
592     (void)split_diskbuffer;     /* Quite unused parameter warning */
593     buff_err = stralloc("mman.h not available");
594     goto fallback;
595 #endif
596 #else
597     (void)split_diskbuffer;     /* Quite unused parameter warning */
598     buff_err = stralloc("mmap not available");
599     goto fallback;
600 #endif
601
602     /*
603       Buffer split dumps in memory, if we can't use a file.
604     */
605     fallback:
606         amfree(splitbuffer_path);
607         splitsize = (off_t)fallback_splitsize;
608         dbprintf(("create_split_buffer: fallback size " OFF_T_FMT "\n",
609                   (OFF_T_FMT_TYPE)splitsize));
610         log_add(L_INFO,
611                 "%s: using fallback split size of " OFF_T_FMT "kb to buffer %s in-memory",
612                 buff_err, (OFF_T_FMT_TYPE)splitsize, id_string);
613         amfree(buff_err);
614         if (splitsize > mem_splitsize) {
615             amfree(mem_splitbuf);
616             mem_splitbuf = alloc(fallback_splitsize * 1024);
617             mem_splitsize = fallback_splitsize;
618             dbprintf(("create_split_buffer: alloc buffer size " OFF_T_FMT "\n",
619                           (OFF_T_FMT_TYPE)splitsize *1024));
620         }
621         splitbuf = mem_splitbuf;
622         splitbuf_wr_ptr = splitbuf;
623 }
624
625 /*
626  * Free up resources that create_split_buffer eats.
627  */
628 void
629 free_split_buffer(void)
630 {
631     if (mmap_splitbuffer_fd != -1) {
632 #ifdef HAVE_MMAP
633 #ifdef HAVE_SYS_MMAN_H
634         if (mmap_splitbuf != NULL) {
635             munmap(mmap_splitbuf, (size_t)mmap_splitsize);
636             mmap_splitbuf = NULL;
637         }
638 #endif
639 #endif
640         aclose(mmap_splitbuffer_fd);
641         amfree(mmap_filename);
642         mmap_splitsize = 0;
643     }
644     if (mem_splitbuf) {
645         amfree(mem_splitbuf);
646         mem_splitsize = 0;
647     }
648 }
649
650 void
651 put_syncpipe_fault_result(
652     char *      handle)
653 {
654     char *q;
655
656     if (handle == NULL)
657         handle = "<nohandle>";
658
659     q = squotef("[Taper syncpipe fault]");
660     putresult(TAPE_ERROR, "%s %s\n", handle, q);
661     log_add(L_ERROR, "tape-error %s %s", handle, q);
662     amfree(q);
663 }
664
665 void
666 file_reader_side(
667     int rdpipe,
668     int wrpipe)
669 {
670     cmd_t cmd;
671     struct cmdargs cmdargs;
672     char *handle = NULL;
673     char *filename = NULL;
674     char *qfilename = NULL;
675     char *hostname = NULL;
676     char *diskname = NULL;
677     char *qdiskname = NULL;
678     char *result = NULL;
679     char *datestamp = NULL;
680     char *split_diskbuffer = NULL;
681     char *id_string = NULL;
682     int tok;
683     char *q = NULL;
684     int level, fd;
685     in_port_t data_port;
686     int data_socket;
687     pid_t wpid;
688     char level_str[64];
689     struct stat stat_file;
690     int tape_started;
691     int a;
692     size_t fallback_splitsize = 0;
693     int tmpint;
694     char *c, *c1;
695
696     procname = "reader";
697     syncpipe_init(rdpipe, wrpipe);
698
699     /* must get START_TAPER before beginning */
700
701     startclock();
702     cmd = getcmd(&cmdargs);
703     total_wait = stopclock();
704
705     if (cmd != START_TAPER || cmdargs.argc != 2) {
706         error("error [file_reader_side cmd %d argc %d]", cmd, cmdargs.argc);
707         /*NOTREACHED*/
708     }
709
710     /* pass start command on to tape writer */
711
712     taper_timestamp = newstralloc(taper_timestamp, cmdargs.argv[2]);
713
714     if (tapedev == NULL) {
715         if (getconf_str(CNF_TPCHANGER) == NULL) {
716             putresult(TAPE_ERROR, "[No tapedev or tpchanger defined]\n");
717             log_add(L_ERROR, "No tapedev or tpchanger defined");
718             dbprintf(("taper: No tapedev or tpchanger defined\n"));
719             exit(1);
720         }
721     } else {
722         tapedev = stralloc(tapedev);
723     }
724
725     tape_started = 0;
726     if (syncpipe_put('S', 0) == -1) {
727         put_syncpipe_fault_result(NULL);
728     }
729
730     if (syncpipe_putstr(taper_timestamp) == -1) {
731         put_syncpipe_fault_result(NULL);
732     }
733
734     /* get result of start command */
735
736     tok = syncpipe_get(&tmpint);
737     switch(tok) {
738     case -1:
739         put_syncpipe_fault_result(NULL);
740         break;
741
742     case 'S':
743         putresult(TAPER_OK, "\n");
744         tape_started = 1;
745         /* start is logged in writer */
746         break;
747
748     case 'E':
749         /* no tape, bail out */
750         if ((result = syncpipe_getstr()) == NULL) {
751             put_syncpipe_fault_result(NULL);
752         } else {
753             q = squotef("[%s]", result);
754             putresult(TAPE_ERROR, "<nohandle> %s\n", q);
755             amfree(q);
756             log_add(L_ERROR,"no-tape [%s]", "No writable valid tape found");
757             c = c1 = result;
758             while (*c != '\0') {
759                 if (*c == '\n') {
760                     *c = '\0';
761                     log_add(L_WARNING,"%s", c1);
762                     c1 = c+1;
763                 }
764                 c++;
765             }
766             if (strlen(c1) > 1 )
767                 log_add(L_WARNING,"%s", c1);
768             amfree(result);
769             (void)syncpipe_put('e', 0);                 /* ACK error */
770         }
771         break;
772
773     case 'H': /* Syncpipe I/O error */
774         /* No ACK syncpipe is down just exit */
775         put_syncpipe_fault_result(handle);
776         break;
777
778     case 'X':
779         /*
780          * Pipe read error: Communications is severed at least
781          * back to us.  We send a blind 'Q' (quit) and we don't
782          * wait for a response...
783          */
784         syncpipe_put('Q', 0);                   /* ACK error */
785         error("error [communications pipe from writer severed]");
786         /*NOTREACHED*/
787
788     default:
789         q = squotef("[syncpipe sequence fault: Expected 'S' or 'E']");
790         putresult(TAPE_ERROR, "<nohandle> %s\n", q);
791         log_add(L_ERROR, "no-tape %s]", q);
792         amfree(q);
793     }
794
795     /* process further driver commands */
796     while (1) {
797         startclock();
798         cmd = getcmd(&cmdargs);
799         if (cmd != QUIT && !tape_started) {
800             error("error [file_reader_side cmd %d without tape ready]", cmd);
801             /*NOTREACHED*/
802         }
803         total_wait = timesadd(total_wait, stopclock());
804
805         switch(cmd) {
806         case PORT_WRITE:
807             /*
808              * PORT-WRITE
809              *   handle
810              *   hostname
811              *   features
812              *   diskname
813              *   level
814              *   datestamp
815              *   splitsize
816              *   split_diskbuffer
817              */
818             mode = MODE_PORT_WRITE;
819             cmdargs.argc++;                     /* true count of args */
820             a = 2;
821
822             if (a >= cmdargs.argc) {
823                 error("error [taper PORT-WRITE: not enough args: handle]");
824                 /*NOTREACHED*/
825             }
826             handle = newstralloc(handle, cmdargs.argv[a++]);
827
828             if (a >= cmdargs.argc) {
829                 error("error [taper PORT-WRITE: not enough args: hostname]");
830                 /*NOTREACHED*/
831             }
832             hostname = newstralloc(hostname, cmdargs.argv[a++]);
833
834             if (a >= cmdargs.argc) {
835                 error("error [taper PORT-WRITE: not enough args: features]");
836                 /*NOTREACHED*/
837             }
838             am_release_feature_set(their_features);
839             their_features = am_string_to_feature(cmdargs.argv[a++]);
840
841             if (a >= cmdargs.argc) {
842                 error("error [taper PORT-WRITE: not enough args: diskname]");
843                 /*NOTREACHED*/
844             }
845             qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
846             if (diskname != NULL)
847                 amfree(diskname);
848             diskname = unquote_string(qdiskname);
849
850             if (a >= cmdargs.argc) {
851                 error("error [taper PORT-WRITE: not enough args: level]");
852                 /*NOTREACHED*/
853             }
854             level = atoi(cmdargs.argv[a++]);
855
856             if (a >= cmdargs.argc) {
857                 error("error [taper PORT-WRITE: not enough args: datestamp]");
858                 /*NOTREACHED*/
859             }
860             datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
861
862             if (a >= cmdargs.argc) {
863                 error("error [taper PORT-WRITE: not enough args: splitsize]");
864                 /*NOTREACHED*/
865             }
866             splitsize = OFF_T_ATOI(cmdargs.argv[a++]);
867             if (SIZEOF_OFF_T == 4 && splitsize > 1048576) { /* 1G in 32 bits */
868                 splitsize = 1048576;
869             }
870
871             if (a >= cmdargs.argc) {
872                 error("error [taper PORT-WRITE: not enough args: split_diskbuffer]");
873                 /*NOTREACHED*/
874             }
875             split_diskbuffer = newstralloc(split_diskbuffer, cmdargs.argv[a++]);
876
877             if (a >= cmdargs.argc) {
878                 error("error [taper PORT-WRITE: not enough args: fallback_splitsize]");
879                 /*NOTREACHED*/
880             }
881             /* Must fit in memory... */
882             fallback_splitsize = (size_t)atoi(cmdargs.argv[a++]);
883             if (SIZEOF_OFF_T == 4 && fallback_splitsize > 1048576) { /* 1G */
884                 fallback_splitsize = 1048576;
885             }
886
887             if (a != cmdargs.argc) {
888                 error("error [taper file_reader_side PORT-WRITE: too many args: %d != %d]",
889                       cmdargs.argc, a);
890                 /*NOTREACHED*/
891             }
892
893             if (fallback_splitsize < 128 ||
894                 fallback_splitsize > 64 * 1024 * 1024) {
895                 error("error [bad value for fallback_splitsize]");
896                 /*NOTREACHED*/
897             }
898             snprintf(level_str, SIZEOF(level_str), "%d", level);
899             id_string = newvstralloc(id_string, hostname, ":", qdiskname, ".",
900                                      level_str, NULL);
901
902             create_split_buffer(split_diskbuffer, fallback_splitsize, id_string);
903             amfree(id_string);
904
905             data_port = 0;
906             data_socket = stream_server(&data_port, 0, STREAM_BUFSIZE, 0);      
907             if (data_socket < 0) {
908                 char *m;
909
910                 m = vstralloc("[port create failure: ",
911                               strerror(errno),
912                               "]",
913                               NULL);
914                 q = squote(m);
915                 putresult(TAPE_ERROR, "%s %s\n", handle, q);
916                 amfree(m);
917                 amfree(q);
918                 break;
919             }
920             putresult(PORT, "%d\n", data_port);
921
922             if ((fd = stream_accept(data_socket, CONNECT_TIMEOUT,
923                                    0, STREAM_BUFSIZE)) == -1) {
924                 q = squote("[port connect timeout]");
925                 putresult(TAPE_ERROR, "%s %s\n", handle, q);
926                 aclose(data_socket);
927                 amfree(q);
928                 break;
929             }
930             expected_splits = -1;
931
932             while(read_file(fd, handle, hostname, qdiskname, datestamp, level))
933                 (void)fd;  /* Quiet lint */
934
935             aclose(data_socket);
936             break;
937
938         case FILE_WRITE:
939             /*
940              * FILE-WRITE
941              *   handle
942              *   filename
943              *   hostname
944              *   features
945              *   diskname
946              *   level
947              *   datestamp
948              *   splitsize
949              */
950             mode = MODE_FILE_WRITE;
951             cmdargs.argc++;                     /* true count of args */
952             a = 2;
953
954             if (a >= cmdargs.argc) {
955                 error("error [taper FILE-WRITE: not enough args: handle]");
956                 /*NOTREACHED*/
957             }
958             handle = newstralloc(handle, cmdargs.argv[a++]);
959
960             if (a >= cmdargs.argc) {
961                 error("error [taper FILE-WRITE: not enough args: filename]");
962                 /*NOTREACHED*/
963             }
964             qfilename = newstralloc(qfilename, cmdargs.argv[a++]);
965             if (filename != NULL)
966                 amfree(filename);
967             filename = unquote_string(qfilename);
968
969             if (a >= cmdargs.argc) {
970                 error("error [taper FILE-WRITE: not enough args: hostname]");
971                 /*NOTREACHED*/
972             }
973             hostname = newstralloc(hostname, cmdargs.argv[a++]);
974
975             if (a >= cmdargs.argc) {
976                 error("error [taper FILE-WRITE: not enough args: features]");
977                 /*NOTREACHED*/
978             }
979             am_release_feature_set(their_features);
980             their_features = am_string_to_feature(cmdargs.argv[a++]);
981
982             if (a >= cmdargs.argc) {
983                 error("error [taper FILE-WRITE: not enough args: diskname]");
984                 /*NOTREACHED*/
985             }
986             qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
987             if (diskname != NULL)
988                 amfree(diskname);
989             diskname = unquote_string(qdiskname);
990
991             if (a >= cmdargs.argc) {
992                 error("error [taper FILE-WRITE: not enough args: level]");
993                 /*NOTREACHED*/
994             }
995             level = atoi(cmdargs.argv[a++]);
996
997             if (a >= cmdargs.argc) {
998                 error("error [taper FILE-WRITE: not enough args: datestamp]");
999                 /*NOTREACHED*/
1000             }
1001             datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
1002
1003             if (a >= cmdargs.argc) {
1004                 error("error [taper FILE-WRITE: not enough args: splitsize]");
1005                 /*NOTREACHED*/
1006             }
1007             splitsize = OFF_T_ATOI(cmdargs.argv[a++]);
1008
1009             if (a != cmdargs.argc) {
1010                 error("error [taper file_reader_side FILE-WRITE: too many args: %d != %d]",
1011                       cmdargs.argc, a);
1012                 /*NOTREACHED*/
1013             }
1014             if (holdfile_name != NULL) {
1015                 filename = newstralloc(filename, holdfile_name);
1016             }
1017
1018             if ((expected_splits = predict_splits(filename)) < 0) {
1019                 break;
1020             }
1021             if (stat(filename, &stat_file)!=0) {
1022                 q = squotef("[%s]", strerror(errno));
1023                 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1024                 amfree(q);
1025                 break;
1026             }
1027             if ((fd = open(filename, O_RDONLY)) == -1) {
1028                 q = squotef("[%s]", strerror(errno));
1029                 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1030                 amfree(q);
1031                 break;
1032             }
1033             holdfile_path = stralloc(filename);
1034             holdfile_path_thischunk = stralloc(filename);
1035             holdfile_offset_thischunk = (off_t)0;
1036
1037             while (read_file(fd,handle,hostname,qdiskname,datestamp,level)) {
1038                 if (splitsize > (off_t)0 && holdfile_path_thischunk)
1039                     filename = newstralloc(filename, holdfile_path_thischunk);
1040                 if ((fd = open(filename, O_RDONLY)) == -1) {
1041                     q = squotef("[%s]", strerror(errno));
1042                     putresult(TAPE_ERROR, "%s %s\n", handle, q);
1043                     amfree(q);
1044                     break;
1045                 }
1046             }
1047             break;
1048
1049         case QUIT:
1050             putresult(QUITTING, "\n");
1051             fprintf(stderr,"taper: DONE [idle wait: %s secs]\n",
1052                     walltime_str(total_wait));
1053             fflush(stderr);
1054             (void)syncpipe_put('Q', 0); /* tell writer we're exiting gracefully */
1055             aclose(wrpipe);
1056
1057             if ((wpid = wait(NULL)) != writerpid) {
1058                 dbprintf(("taper: writer wait returned %u instead of %u: %s\n",
1059                         (unsigned)wpid, (unsigned)writerpid, strerror(errno)));
1060                 fprintf(stderr,
1061                         "taper: writer wait returned %u instead of %u: %s\n",
1062                         (unsigned)wpid, (unsigned)writerpid, strerror(errno));
1063                 fflush(stderr);
1064             }
1065
1066             free_split_buffer();
1067             amfree(datestamp);
1068             clear_tapelist();
1069             amfree(taper_timestamp);
1070             amfree(label);
1071             amfree(errstr);
1072             amfree(changer_resultstr);
1073             amfree(tapedev);
1074             amfree(filename);
1075             amfree(conf_tapelist);
1076             amfree(config_dir);
1077             amfree(config_name);
1078             amfree(holdfile_name);
1079
1080             malloc_size_2 = malloc_inuse(&malloc_hist_2);
1081
1082             if (malloc_size_1 != malloc_size_2) {
1083                 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
1084             }
1085             exit(0);
1086             /*NOTREACHED*/
1087
1088         default:
1089             if (cmdargs.argc >= 1) {
1090                 q = squote(cmdargs.argv[1]);
1091             } else if (cmdargs.argc >= 0) {
1092                 q = squote(cmdargs.argv[0]);
1093             } else {
1094                 q = stralloc("(no input?)");
1095             }
1096             putresult(BAD_COMMAND, "%s\n", q);
1097             amfree(q);
1098             break;
1099         }
1100     }
1101     /* NOTREACHED */
1102 }
1103
1104 void
1105 dumpbufs(
1106     char *str1)
1107 {
1108     int i,j;
1109     long v;
1110
1111     fprintf(stderr, "%s: state", str1);
1112     for (i = j = 0; i < conf_tapebufs; i = j+1) {
1113         v = buftable[i].status;
1114         for(j = i; j < conf_tapebufs && buftable[j].status == v; j++)
1115             (void)j; /* Quiet lint */
1116         j--;
1117         if (i == j) {
1118             fprintf(stderr, " %d:", i);
1119         } else {
1120             fprintf(stderr, " %d-%d:", i, j);
1121         }
1122         switch(v) {
1123         case FULL:
1124             fputc('F', stderr);
1125             break;
1126
1127         case FILLING:
1128             fputc('f', stderr);
1129             break;
1130
1131         case EMPTY:
1132             fputc('E', stderr);
1133             break;
1134
1135         default:
1136             fprintf(stderr, "%ld", v);
1137             break;
1138         }
1139     }
1140     fputc('\n', stderr);
1141     fflush(stderr);
1142 }
1143
1144 void
1145 dumpstatus(
1146     buffer_t *bp)
1147 {
1148     char pn[2];
1149     char bt[NUM_STR_SIZE];
1150     char status[NUM_STR_SIZE + 1];
1151     char *str = NULL;
1152
1153     pn[0] = procname[0];
1154     pn[1] = '\0';
1155     snprintf(bt, SIZEOF(bt), "%d", (int)(bp-buftable));
1156
1157     switch(bp->status) {
1158     case FULL:
1159         snprintf(status, SIZEOF(status), "F" SIZE_T_FMT,
1160                 (SIZE_T_FMT_TYPE)bp->size);
1161         break;
1162
1163     case FILLING:
1164         snprintf(status, SIZEOF(status), "f");
1165         break;
1166
1167     case EMPTY:
1168         snprintf(status, SIZEOF(status), "E");
1169         break;
1170
1171     default:
1172         snprintf(status, SIZEOF(status), "%ld", bp->status);
1173         break;
1174     }
1175
1176     str = vstralloc("taper: ", pn, ": [buf ", bt, ":=", status, "]", NULL);
1177     dumpbufs(str);
1178     amfree(str);
1179 }
1180
1181 /*
1182   Handle moving to the next chunk of holding file, if any.  Returns -1 for
1183   errors, 0 if there's no more file, or a positive integer for the amount of
1184   stuff read that'll go into 'rc' (XXX That's fugly, maybe that should just
1185   be another global.  What is rc anyway, 'read count?' I keep thinking it
1186   should be 'return code')
1187 */
1188 ssize_t
1189 get_next_holding_file(
1190     int fd,
1191     buffer_t *bp,
1192     char **strclosing,
1193     size_t rc)
1194 {
1195     int save_fd;
1196     ssize_t rc1;
1197     struct stat stat_file;
1198     ssize_t ret = -1;
1199     
1200     save_fd = fd;
1201     close(fd);
1202     
1203     /* see if we're fresh out of file */
1204     if (file.cont_filename[0] == '\0') {
1205         err = 0;
1206         ret = 0;
1207     } else if (stat(file.cont_filename, &stat_file) != 0) {
1208         err = errno;
1209         ret = -1;
1210         *strclosing = newvstralloc(*strclosing, "can't stat: ",
1211                                    file.cont_filename, NULL);
1212     } else if ((fd = open(file.cont_filename,O_RDONLY)) == -1) {
1213         err = errno;
1214         ret = -1;
1215         *strclosing = newvstralloc(*strclosing, "can't open: ",
1216                                    file.cont_filename, NULL);
1217     } else if ((fd != save_fd) && dup2(fd, save_fd) == -1) {
1218         err = errno;
1219         ret = -1;
1220         *strclosing = newvstralloc(*strclosing, "can't dup2: ",
1221                                    file.cont_filename, NULL);
1222     } else {
1223         buffer_t bp1;
1224         char *quoted;
1225
1226         holdfile_path = stralloc(file.cont_filename);
1227         quoted = quote_string(holdfile_path);
1228         fprintf(stderr, "taper: r: switching to next holding chunk '%s'\n",
1229                 quoted); 
1230         amfree(quoted);
1231         num_holdfile_chunks++;
1232         
1233         bp1.status = EMPTY;
1234         bp1.size = DISK_BLOCK_BYTES;
1235         bp1.buffer = alloc(DISK_BLOCK_BYTES);
1236         
1237         if (fd != save_fd) {
1238             close(fd);
1239             fd = save_fd;
1240         }
1241         
1242         rc1 = taper_fill_buffer(fd, &bp1, DISK_BLOCK_BYTES);
1243         if (rc1 <= 0) {
1244             amfree(bp1.buffer);
1245             err = (rc1 < 0) ? errno : 0;
1246             ret = -1;
1247             *strclosing = newvstralloc(*strclosing,
1248                                        "Can't read header: ",
1249                                        file.cont_filename,
1250                                        NULL);
1251         } else {
1252             parse_file_header(bp1.buffer, &file, (size_t)rc1);
1253             
1254             amfree(bp1.buffer);
1255             bp1.buffer = bp->buffer + rc;
1256             
1257             rc1 = taper_fill_buffer(fd, &bp1, (size_t)tt_blocksize - rc);
1258             if (rc1 <= 0) {
1259                 err = (rc1 < 0) ? errno : 0;
1260                 ret = -1;
1261                 if (rc1 < 0) {
1262                     *strclosing = newvstralloc(*strclosing,
1263                                                "Can't read data: ",
1264                                                file.cont_filename,
1265                                                NULL);
1266                 }
1267             } else {
1268                 ret = rc1;
1269                 num_holdfiles++;
1270             }
1271         }
1272     }
1273
1274     return(ret);
1275 }
1276
1277
1278 int
1279 read_file(
1280     int         fd,
1281     char *      handle,
1282     char *      hostname,
1283     char *      qdiskname,
1284     char *      datestamp,
1285     int         level)
1286 {
1287     buffer_t *bp;
1288     int tok;
1289     ssize_t rc;
1290 #ifdef ASSERTIONS
1291     int opening;
1292 #endif
1293     int closing, bufnum, need_closing, nexting;
1294     off_t filesize;
1295     times_t runtime;
1296     char *strclosing = NULL;
1297     char seekerrstr[STR_SIZE];
1298     char *str;
1299     int header_written = 0;
1300     size_t buflen;
1301     dumpfile_t first_file;
1302     dumpfile_t cur_holdfile;
1303     off_t kbytesread = (off_t)0;
1304     int header_read = 0;
1305     char *cur_filename = NULL;
1306     int retry_from_splitbuf = 0;
1307     char *splitbuf_rd_ptr = NULL;
1308     char *q = NULL;
1309
1310 #ifdef HAVE_LIBVTBLC
1311     static char desc[45];
1312     static char vol_date[20];
1313     static char vol_label[45];
1314 #endif /* HAVE_LIBVTBLC */
1315
1316
1317     /* initialize */
1318     memset(&first_file, 0, SIZEOF(first_file));
1319     memset(&cur_holdfile, 0, SIZEOF(cur_holdfile));
1320
1321     filesize = (off_t)0;
1322     closing = 0;
1323     need_closing = 0;
1324     nexting = 0;
1325     err = 0;
1326
1327     /* don't break this if we're still on the same file as a previous init */
1328     if (cur_span_chunkstart <= (off_t)0) {
1329         fh_init(&file);
1330         header_read = 0;
1331     } else if(mode == MODE_FILE_WRITE){
1332         memcpy(&file, save_holdfile, SIZEOF(dumpfile_t));
1333         memcpy(&cur_holdfile, save_holdfile, SIZEOF(dumpfile_t));
1334     }
1335
1336     taper_debug(1, ("taper: r: start file\n"));
1337
1338     for (bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1339         bp->status = EMPTY;
1340     }
1341
1342     bp = buftable;
1343     if (interactive || debug_taper >= 1)
1344         dumpstatus(bp);
1345
1346     if ((cur_span_chunkstart >= (off_t)0) && (splitsize > (off_t)0)) {
1347         /* We're supposed to start at some later part of the file, not read the
1348            whole thing. "Seek" forward to where we want to be. */
1349         if (label)
1350             putresult(SPLIT_CONTINUE, "%s %s\n", handle, label);
1351         if ((mode == MODE_FILE_WRITE) && (cur_span_chunkstart > (off_t)0)) {
1352             char *quoted = quote_string(holdfile_path_thischunk);
1353             fprintf(stderr, "taper: r: seeking %s to " OFF_T_FMT " kb\n",
1354                             quoted,
1355                             (OFF_T_FMT_TYPE)holdfile_offset_thischunk);
1356             fflush(stderr);
1357
1358             if (holdfile_offset_thischunk > maxseek) {
1359                 snprintf(seekerrstr, SIZEOF(seekerrstr), "Can't seek by "
1360                         OFF_T_FMT " kb (compiled for %d-bit file offsets), "
1361                         "recompile with large file support or "
1362                         "set holdingdisk chunksize to <" OFF_T_FMT " Mb",
1363                         (OFF_T_FMT_TYPE)holdfile_offset_thischunk,
1364                         (int)(sizeof(off_t) * 8),
1365                         (OFF_T_FMT_TYPE)(maxseek/(off_t)1024));
1366                 log_add(L_ERROR, "%s", seekerrstr);
1367                 fprintf(stderr, "taper: r: FATAL: %s\n", seekerrstr);
1368                 fflush(stderr);
1369                 if (syncpipe_put('X', 0) == -1) {
1370                         put_syncpipe_fault_result(handle);
1371                 }
1372                 amfree(quoted);
1373                 return -1;
1374             }
1375             if (lseek(fd, holdfile_offset_thischunk*(off_t)1024, SEEK_SET) == (off_t)-1) {
1376                 fprintf(stderr, "taper: r: FATAL: seek_holdfile lseek error "
1377                         "while seeking into %s by "
1378                         OFF_T_FMT "kb: %s\n", quoted,
1379                         (OFF_T_FMT_TYPE)holdfile_offset_thischunk,
1380                         strerror(errno));
1381                 fflush(stderr);
1382                 if (syncpipe_put('X', 0) == -1) {
1383                         put_syncpipe_fault_result(handle);
1384                 }
1385                 amfree(quoted);
1386                 return -1;
1387             }
1388             amfree(quoted);
1389         } else if (mode == MODE_PORT_WRITE) {
1390             fprintf(stderr, "taper: r: re-reading split dump piece from buffer\n");
1391             fflush(stderr);
1392             retry_from_splitbuf = 1;
1393             splitbuf_rd_ptr = splitbuf;
1394             if (splitbuf_rd_ptr >= splitbuf_wr_ptr)
1395                 retry_from_splitbuf = 0;
1396         }
1397         if (cur_span_chunkstart > (off_t)0)
1398             header_read = 1; /* really initialized in prior run */
1399     }
1400
1401     /* tell writer to open tape */
1402
1403 #ifdef ASSERTIONS
1404     opening = 1;
1405 #endif
1406
1407     if (syncpipe_put('O', 0) == -1) {
1408         put_syncpipe_fault_result(handle);
1409         return -1;
1410     }
1411     if (syncpipe_putstr(datestamp) == -1) {
1412         put_syncpipe_fault_result(handle);
1413         return -1;
1414     }
1415     if (syncpipe_putstr(hostname) == -1) {
1416         put_syncpipe_fault_result(handle);
1417         return -1;
1418     }
1419     if (syncpipe_putstr(qdiskname) == -1) {
1420         put_syncpipe_fault_result(handle);
1421         return -1;
1422     }
1423     if (syncpipe_putint(level) == -1) {
1424         put_syncpipe_fault_result(handle);
1425         return -1;
1426     }
1427
1428     startclock();
1429     
1430     /* read file in loop */
1431     
1432     while (1) {
1433         if ((tok = syncpipe_get(&bufnum)) == -1) {
1434             put_syncpipe_fault_result(handle);
1435             return -1;
1436         }
1437
1438         switch(tok) {
1439         case 'O':
1440 #ifdef ASSERTIONS
1441             assert(opening);
1442             opening = 0;
1443 #endif
1444             err = 0;
1445             break;
1446             
1447         case 'R':
1448             taper_debug(1, ("taper: r: got R%d\n", bufnum));
1449             
1450             if (need_closing) {
1451                 if (syncpipe_put('C', 0) == -1) {
1452                     put_syncpipe_fault_result(handle);
1453                     return (-1);
1454                 }
1455                 closing = 1;
1456                 need_closing = 0;
1457                 break;
1458             }
1459             
1460             if (closing)
1461                 break;  /* ignore extra read tokens */
1462             
1463 #ifdef ASSERTIONS
1464             assert(!opening);
1465 #endif
1466             if(bp->status != EMPTY || bufnum != (int)(bp - buftable)) {
1467                 /* XXX this SHOULD NOT HAPPEN.  Famous last words. */
1468                 fprintf(stderr,"taper: panic: buffer mismatch at ofs "
1469                         OFF_T_FMT ":\n", (OFF_T_FMT_TYPE)filesize);
1470                 if(bufnum != (int)(bp - buftable)) {
1471                     fprintf(stderr, "    my buf %d but writer buf %d\n",
1472                             (int)(bp-buftable), bufnum);
1473                 } else {
1474                     fprintf(stderr,"buf %d state %s (%ld) instead of EMPTY\n",
1475                             (int)(bp-buftable),
1476                             bp->status == FILLING? "FILLING" :
1477                             bp->status == FULL? "FULL" : "EMPTY!?!?",
1478                             (long)bp->status);
1479                 }
1480                 dumpbufs("taper");
1481                 sleep(1);
1482                 dumpbufs("taper: after 1 sec");
1483                 if (bp->status == EMPTY)
1484                     fprintf(stderr, "taper: result now correct!\n");
1485                 fflush(stderr);
1486                 
1487                 errstr = newstralloc(errstr,
1488                                      "[fatal buffer mismanagement bug]");
1489                 q = squote(errstr);
1490                 putresult(TRYAGAIN, "%s %s\n", handle, q);
1491                 cur_span_chunkstart = (off_t)0;
1492                 amfree(q);
1493                 log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1494                         hostname, qdiskname, level, errstr);
1495                 closing = 1;
1496                 if (syncpipe_put('X', 0) == -1) {/* X == buffer snafu, bail */
1497                     put_syncpipe_fault_result(handle);
1498                     return (-1);
1499                 }
1500                 do {
1501                     if ((tok = syncpipe_get(&bufnum)) == -1) {
1502                         put_syncpipe_fault_result(handle);
1503                         return (-1);
1504                     }
1505                 } while (tok != 'x');
1506                 aclose(fd);
1507                 return -1;
1508             } /* end 'if (bf->status != EMPTY || bufnum != (int)(bp-buftable))' */
1509
1510             bp->status = FILLING;
1511             buflen = header_read ? (size_t)tt_blocksize : DISK_BLOCK_BYTES;
1512             if (interactive || debug_taper >= 1)
1513                 dumpstatus(bp);
1514             if (header_written == 0 &&
1515                         (header_read == 1 || cur_span_chunkstart > (off_t)0)) {
1516                 /* for split dumpfiles, modify headers for the second - nth
1517                    pieces that signify that they're continuations of the last
1518                    normal one */
1519                 char *cont_filename;
1520                 file.type = F_SPLIT_DUMPFILE;
1521                 file.partnum = num_splits + 1;
1522                 file.totalparts = expected_splits;
1523                 cont_filename = stralloc(file.cont_filename);
1524                 file.cont_filename[0] = '\0';
1525                 build_header(bp->buffer, &file, tt_blocksize);
1526   
1527                 if (cont_filename[0] != '\0') {
1528                   file.type = F_CONT_DUMPFILE;
1529                    strncpy(file.cont_filename, cont_filename,
1530                            SIZEOF(file.cont_filename));
1531                         }
1532                 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1533   
1534                 if (interactive || debug_taper >= 1)
1535                     dumpstatus(bp);
1536                 bp->size = (ssize_t)tt_blocksize;
1537                 rc = (ssize_t)tt_blocksize;
1538                 header_written = 1;
1539                 amfree(cont_filename);
1540             } else if (retry_from_splitbuf) {
1541                 /* quietly pull dump data from our in-memory cache, and the
1542                    writer side need never know the wiser */
1543                 memcpy(bp->buffer, splitbuf_rd_ptr, tt_blocksize);
1544                 bp->size = (ssize_t)tt_blocksize;
1545                 rc = (ssize_t)tt_blocksize;
1546  
1547                 splitbuf_rd_ptr += tt_blocksize;
1548                 if (splitbuf_rd_ptr >= splitbuf_wr_ptr)
1549                     retry_from_splitbuf = 0;
1550             } else if ((rc = taper_fill_buffer(fd, bp, buflen)) < 0) {
1551                 err = errno;
1552                 closing = 1;
1553                 strclosing = newvstralloc(strclosing,"Can't read data: ",
1554                                           NULL);
1555                 if (syncpipe_put('C', 0) == -1) {
1556                     put_syncpipe_fault_result(handle);
1557                     return (-1);
1558                 }
1559             }
1560   
1561             if (!closing) {
1562                 if (rc < (ssize_t)buflen) { /* switch to next holding file */
1563                     ssize_t ret;
1564
1565                     if (file.cont_filename[0] != '\0') {
1566                         cur_filename = newvstralloc(cur_filename, file.cont_filename, NULL);
1567                     }
1568                     ret = get_next_holding_file(fd, bp, &strclosing, (size_t)rc);
1569                     if (ret <= 0) {
1570                         need_closing = 1;
1571                     } else {
1572                         memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1573                         rc += ret;
1574                         bp->size = rc;
1575                     }
1576                 }
1577                 if (rc > 0) {
1578                     bp->status = FULL;
1579                     /* rebuild the header block, which might have CONT junk */
1580                     if (header_read == 0) {
1581                         char *cont_filename;
1582                         /* write the "real" filename if the holding-file
1583                            is a partial one */
1584                         parse_file_header(bp->buffer, &file, (size_t)rc);
1585                         parse_file_header(bp->buffer, &first_file, (size_t)rc);
1586                         cont_filename = stralloc(file.cont_filename);
1587                         file.cont_filename[0] = '\0';
1588                         if (splitsize > (off_t)0) {
1589                             file.type = F_SPLIT_DUMPFILE;
1590                             file.partnum = 1;
1591                             file.totalparts = expected_splits;
1592                         }
1593                         file.blocksize = tt_blocksize;
1594                         build_header(bp->buffer, &file, tt_blocksize);
1595  
1596                         file.type = F_CONT_DUMPFILE;
1597  
1598                         /* add CONT_FILENAME back to in-memory header */
1599                         strncpy(file.cont_filename, cont_filename, 
1600                                 SIZEOF(file.cont_filename));
1601                         if (interactive || debug_taper >= 1)
1602                             dumpstatus(bp);
1603                         bp->size = (ssize_t)tt_blocksize; /* output a full tape block */
1604                         /* save the header, we'll need it if we jump tapes */
1605                         memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1606                         header_read = 1;
1607                         header_written = 1;
1608                         amfree(cont_filename);
1609                     } else {
1610                         filesize = kbytesread;
1611                     }
1612
1613                     taper_debug(1, ("taper: r: put W%d\n",
1614                                     (int)(bp-buftable)));
1615                     if (syncpipe_put('W', (int)(bp-buftable)) == -1) {
1616                         put_syncpipe_fault_result(handle);
1617                         return (-1);
1618                     }
1619                     bp = nextbuf(bp);
1620                 }
1621
1622                 if (((kbytesread + (off_t)(DISK_BLOCK_BYTES/1024)) >= splitsize)
1623                         && (splitsize > (off_t)0) && !need_closing) {
1624
1625                     if (mode == MODE_PORT_WRITE) {
1626                         splitbuf_wr_ptr = splitbuf;
1627                         splitbuf_rd_ptr = splitbuf;
1628                         memset(splitbuf, 0, SIZEOF(splitbuf));
1629                         retry_from_splitbuf = 0;
1630                     }
1631
1632                     fprintf(stderr,"taper: r: end %s.%s.%s.%d part %d, "
1633                                 "splitting chunk that started at "
1634                                 OFF_T_FMT "kb after " OFF_T_FMT
1635                                 "kb (next chunk will start at "
1636                                 OFF_T_FMT "kb)\n",
1637                                 hostname, qdiskname, datestamp, level,
1638                                 num_splits+1,
1639                                 (OFF_T_FMT_TYPE)cur_span_chunkstart,
1640                                 (OFF_T_FMT_TYPE)kbytesread,
1641                                 (OFF_T_FMT_TYPE)(cur_span_chunkstart+kbytesread));
1642                     fflush(stderr);
1643
1644                     nexting = 1;
1645                     need_closing = 1;
1646                 } /* end '(kbytesread >= splitsize && splitsize > 0)' */
1647                 if (need_closing && rc <= 0) {
1648                     if (syncpipe_put('C', 0) == -1) {
1649                         put_syncpipe_fault_result(handle);
1650                         return (-1);
1651                     }
1652                     need_closing = 0;
1653                     closing = 1;
1654                 }
1655                 kbytesread += (off_t)(rc / 1024);
1656             } /* end the 'if (!closing)' (successful buffer fill) */
1657             break;
1658
1659         case 'T':
1660         case 'E':
1661         case 'H':
1662             if (syncpipe_put('e', 0) == -1) {   /* ACK error */
1663                 put_syncpipe_fault_result(handle);
1664                 return (-1);
1665             }
1666
1667             if ((str = syncpipe_getstr()) == NULL) {
1668                 put_syncpipe_fault_result(handle);
1669                 return (-1);
1670             }
1671             
1672             errstr = newvstralloc(errstr, "[", str, "]", NULL);
1673             amfree(str);
1674
1675             q = squote(errstr);
1676             if (tok == 'T') {
1677                 if (splitsize > (off_t)0) {
1678                     /* we'll be restarting this chunk on the next tape */
1679                     if (mode == MODE_FILE_WRITE) {
1680                       aclose(fd);
1681                     }
1682
1683                     putresult(SPLIT_NEEDNEXT, "%s " OFF_T_FMT "\n", handle,
1684                                 (OFF_T_FMT_TYPE)cur_span_chunkstart);
1685                     log_add(L_INFO, "continuing %s:%s.%d on new tape from "
1686                                 OFF_T_FMT "kb mark: %s",
1687                                 hostname, qdiskname, level,
1688                                 (OFF_T_FMT_TYPE)cur_span_chunkstart, errstr);
1689                     return 1;
1690                 } else {
1691                     /* restart the entire dump (failure propagates to driver) */
1692                     aclose(fd);
1693                     putresult(TRYAGAIN, "%s %s\n", handle, q);
1694                     cur_span_chunkstart = (off_t)0;
1695                     log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1696                             hostname, qdiskname, level, errstr);
1697                 }
1698             } else {
1699                 aclose(fd);
1700                 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1701                 log_add(L_FAIL, "%s %s %s %d [out of tape]",
1702                         hostname, qdiskname, datestamp, level);
1703                 log_add(L_ERROR,"no-tape [%s]", "No more writable valid tape found");
1704             }
1705             amfree(q);
1706             return 0;
1707
1708         case 'C':
1709 #ifdef ASSERTIONS
1710             assert(!opening);
1711 #endif
1712             assert(closing);
1713
1714             if (nexting) {
1715               cur_span_chunkstart += kbytesread; /* XXX possibly wrong */
1716               if (cur_filename)
1717                 holdfile_name = newvstralloc(holdfile_name, cur_filename,
1718                                              NULL);
1719               else
1720                 amfree(holdfile_name);
1721
1722               kbytesread = (off_t)0;
1723               amfree(cur_filename);
1724             }
1725
1726             if ((str = syncpipe_getstr()) == NULL) {
1727                 put_syncpipe_fault_result(handle);
1728                 return (-1);
1729             }
1730
1731             label = newstralloc(label, str ? str : "(null)");
1732             amfree(str);
1733             if ((str = syncpipe_getstr()) == NULL) {
1734                 put_syncpipe_fault_result(handle);
1735                 return (-1);
1736             }
1737
1738             filenum = atoi(str ? str : "-9876");        /* ??? */
1739             amfree(str);
1740             fprintf(stderr, "taper: reader-side: got label %s filenum %d\n",
1741                     label, filenum);
1742             fflush(stderr);
1743
1744             /* we'll need that file descriptor if we're gonna write more */
1745             if (!nexting) {
1746                 aclose(fd);
1747             }
1748
1749             runtime = stopclock();
1750             if (nexting)
1751                 startclock();
1752             if (err) {
1753                 if (strclosing) {
1754                     errstr = newvstralloc(errstr,
1755                                           "[input: ", strclosing, ": ",
1756                                           strerror(err), "]", NULL);
1757                     amfree(strclosing);
1758                 } else
1759                     errstr = newvstralloc(errstr,
1760                                           "[input: ", strerror(err), "]",
1761                                           NULL);
1762                 q = squote(errstr);
1763                 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1764
1765                 amfree(q);
1766                 if (splitsize != (off_t)0) {
1767                     log_add(L_FAIL, "%s %s %s.%d %d %s", hostname, qdiskname,
1768                                 datestamp, num_splits, level, errstr);
1769                 } else {
1770                     log_add(L_FAIL, "%s %s %s %d %s",
1771                                 hostname, qdiskname, datestamp, level, errstr);
1772                 }
1773                 if ((str = syncpipe_getstr()) == NULL) {        /* reap stats */
1774                     put_syncpipe_fault_result(handle);
1775                     return (-1);
1776                 }
1777                 amfree(str);
1778                 amfree(errstr);
1779             } else {
1780                 char kb_str[NUM_STR_SIZE];
1781                 char kps_str[NUM_STR_SIZE];
1782                 double rt;
1783
1784                 rt = (double)(runtime.r.tv_sec) +
1785                      ((double)(runtime.r.tv_usec) / 1000000.0);
1786                 curdump_rt = timesadd(runtime, curdump_rt);
1787                 snprintf(kb_str, SIZEOF(kb_str), OFF_T_FMT,
1788                         (OFF_T_FMT_TYPE)filesize);
1789                 snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
1790                                   (isnormal(rt) ? (double)filesize / rt : 0.0));
1791                 if ((str = syncpipe_getstr()) == NULL) {
1792                     put_syncpipe_fault_result(handle);
1793                     return (-1);
1794                 }
1795                 errstr = newvstralloc(errstr,
1796                                       "[sec ", walltime_str(runtime),
1797                                       " kb ", kb_str,
1798                                       " kps ", kps_str,
1799                                       " ", str,
1800                                       "]",
1801                                       NULL);
1802                 if (splitsize == (off_t)0) { /* Ordinary dump */
1803                     q = squote(errstr);
1804 /*@i@*/             if (first_file.is_partial) {
1805                         putresult(PARTIAL, "%s %s %d %s\n",
1806                                   handle, label, filenum, q);
1807                         log_add(L_PARTIAL, "%s %s %s %d %s",
1808                                 hostname, qdiskname, datestamp, level, errstr);
1809                     } else {
1810                         putresult(DONE, "%s %s %d %s\n",
1811                                   handle, label, filenum, q);
1812                         log_add(L_SUCCESS, "%s %s %s %d %s",
1813                                 hostname, qdiskname, datestamp, level, errstr);
1814                     }
1815                     amfree(q);
1816                 } else { /* Chunked dump */
1817                     num_splits++;
1818                     if (mode == MODE_FILE_WRITE) {
1819                         holdfile_path_thischunk = stralloc(holdfile_path);
1820                         holdfile_offset_thischunk = (lseek(fd, (off_t)0, SEEK_CUR))/(off_t)1024;
1821                         if(!save_holdfile){
1822                             save_holdfile = alloc(SIZEOF(dumpfile_t));
1823                         }
1824                         memcpy(save_holdfile, &cur_holdfile,SIZEOF(dumpfile_t));
1825                     }
1826                     log_add(L_CHUNK, "%s %s %s %d %d %s", hostname, qdiskname,
1827                             datestamp, num_splits, level, errstr);
1828                     if (!nexting) { /* split dump complete */
1829                         rt = (double)(curdump_rt.r.tv_sec) +
1830                              ((double)(curdump_rt.r.tv_usec) / 1000000.0);
1831                         snprintf(kb_str, SIZEOF(kb_str), OFF_T_FMT,
1832                                 (OFF_T_FMT_TYPE)(filesize + cur_span_chunkstart));
1833                         snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
1834                             isnormal(rt) ?
1835                             ((double)(filesize+cur_span_chunkstart)) / rt :
1836                             0.0);
1837                         amfree(errstr);
1838                         errstr = newvstralloc(errstr,
1839                                               "[sec ", walltime_str(curdump_rt),
1840                                               " kb ", kb_str,
1841                                               " kps ", kps_str,
1842                                               " ", str,
1843                                               "]",
1844                                               NULL);
1845                         q = squote(errstr);
1846                         putresult(DONE, "%s %s %d %s\n", handle, label,
1847                                   filenum, q);
1848                         log_add(L_CHUNKSUCCESS, "%s %s %s %d %s",
1849                                 hostname, qdiskname, datestamp, level, errstr);
1850                         amfree(save_holdfile);
1851                         amfree(holdfile_path_thischunk);
1852                         amfree(q);
1853                     }
1854                 }
1855                 amfree(str);
1856
1857                 if (!nexting) {
1858                     num_splits = 0;
1859                     expected_splits = 0;
1860                     amfree(holdfile_name);
1861                     num_holdfiles = 0;
1862                     cur_span_chunkstart = (off_t)0;
1863                     curdump_rt = times_zero;
1864                 }
1865                 amfree(errstr);
1866                 
1867 #ifdef HAVE_LIBVTBLC
1868                 /* 
1869                  *  We have 44 characters available for the label string:
1870                  *  use max 20 characters for hostname
1871                  *      max 20 characters for diskname 
1872                  *             (it could contain a samba share or dos path)
1873                  *           2 for level
1874                  */
1875                 memset(desc, '\0', 45);
1876
1877                 strncpy(desc, hostname, 20);
1878
1879                 if ((len = strlen(hostname)) <= 20) {
1880                     memset(desc + len, ' ', 1);
1881                     offset = len + 1;
1882                 } else {
1883                     memset(desc + 20, ' ', 1);
1884                     offset = 21;
1885                 }
1886
1887                 strncpy(desc + offset, qdiskname, 20);
1888
1889                 if ((len = strlen(qdiskname)) <= 20) {
1890                     memset(desc + offset + len, ' ', 1);
1891                     offset = offset + len + 1;
1892                 } else {
1893                     memset(desc + offset + 20, ' ', 1);
1894                     offset = offset + 21;
1895                 }
1896
1897                 sprintf(desc + offset, "%i", level);
1898
1899                 strncpy(vol_label, desc, 44);
1900                 fprintf(stderr, "taper: added vtbl label string %i: \"%s\"\n",
1901                         filenum, vol_label);
1902                 fflush(stderr);
1903
1904                 /* pass label string on to tape writer */
1905                 if (syncpipe_put('L', filenum) == -1) {
1906                     put_syncpipe_fault_result(handle);
1907                     return (-1);
1908                 }
1909                 if (syncpipe_putstr(vol_label) == -1) {
1910                     put_syncpipe_fault_result(handle);
1911                     return (-1);
1912                 }
1913
1914                 /* 
1915                  * reformat datestamp for later use with set_date from vtblc 
1916                  */
1917                 strptime(datestamp, "%Y%m%d", &backup_time);
1918                 strftime(vol_date, 20, "%T %D", &backup_time);
1919                 fprintf(stderr, 
1920                         "taper: reformatted vtbl date string: \"%s\"->\"%s\"\n",
1921                         datestamp,
1922                         vol_date);
1923
1924                 /* pass date string on to tape writer */                
1925                 if (syncpipe_put('D', filenum) == -1) {
1926                     put_syncpipe_fault_result(handle);
1927                     return (-1);
1928                 }
1929                 if (syncpipe_putstr(vol_date) == -1) {
1930                     put_syncpipe_fault_result(handle);
1931                     return (-1);
1932                 }
1933
1934 #endif /* HAVE_LIBVTBLC */
1935             }
1936             /* reset stuff that assumes we're on a new file */
1937
1938             if (!nexting)
1939                 return 0;
1940
1941 #ifdef ASSERTIONS
1942             opening = 1;
1943 #endif
1944             nexting = 0;
1945             closing = 0;
1946             filesize = (off_t)0;
1947             if (syncpipe_put('O', 0) == -1) {
1948                 put_syncpipe_fault_result(handle);
1949                 return -1;
1950             }
1951             if (syncpipe_putstr(datestamp) == -1) {
1952                 put_syncpipe_fault_result(handle);
1953                 return -1;
1954             }
1955             if (syncpipe_putstr(hostname) == -1) {
1956                 put_syncpipe_fault_result(handle);
1957                 return -1;
1958             }
1959             if (syncpipe_putstr(qdiskname) == -1) {
1960                 put_syncpipe_fault_result(handle);
1961                 return -1;
1962             }
1963             if (syncpipe_putint(level) == -1) {
1964                 put_syncpipe_fault_result(handle);
1965                 return -1;
1966             }
1967             for (bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1968                 bp->status = EMPTY;
1969             }
1970             bp = buftable;
1971             header_written = 0;
1972             break;
1973
1974         case 'X':
1975             /*
1976              * Pipe read error: Communications is severed at least
1977              * back to us.  We send a blind 'Q' (quit) and we don't
1978              * wait for a response...
1979              */
1980             syncpipe_put('Q', 0);                       /* ACK error */
1981             fprintf(stderr, "taper: communications pipe from reader severed\n");
1982             return -1;
1983
1984         default:
1985             q = squotef("[Taper syncpipe protocol error]");
1986             putresult(TAPE_ERROR, "%s %s\n", handle, q);
1987             log_add(L_ERROR, "tape-error %s %s", handle, q);
1988             amfree(q);
1989             return -1;
1990         }
1991     }
1992     return 0;
1993 }
1994
1995 ssize_t
1996 taper_fill_buffer(
1997     int fd,
1998     buffer_t *bp,
1999     size_t buflen)
2000 {
2001     char *curptr;
2002     ssize_t cnt;
2003
2004     curptr = bp->buffer;
2005
2006     cnt = fullread(fd, curptr, buflen);
2007     switch(cnt) {
2008     case 0:     /* eof */
2009         if (interactive)
2010             fputs("r0", stderr);
2011         bp->size = 0;
2012         return (ssize_t)0;
2013         /*NOTREACHED*/
2014
2015     case -1:    /* error on read, punt */
2016         if (interactive)
2017             fputs("rE", stderr);
2018         bp->size = 0;
2019         return -1;
2020         /*NOTREACHED*/
2021
2022     default:
2023         if ((mode == MODE_PORT_WRITE) && (splitsize > (off_t)0)) {
2024             memcpy(splitbuf_wr_ptr, curptr, (size_t)cnt);
2025             splitbuf_wr_ptr += cnt;
2026         }
2027         bp->size = cnt;
2028         break;
2029     }
2030
2031     if (interactive)
2032         fputs("R", stderr);
2033     return ((ssize_t)bp->size);
2034 }
2035
2036 /* Given a dumpfile in holding, determine its size and figure out how many
2037  * times we'd have to split it.
2038  */
2039 int
2040 predict_splits(
2041     char *filename)
2042 {
2043     int splits = 0;
2044     off_t total_kb = (off_t)0;
2045     off_t adj_splitsize = splitsize - (off_t)(DISK_BLOCK_BYTES / 1024);
2046
2047     if (splitsize <= (off_t)0)
2048         return(0);
2049
2050     if (adj_splitsize <= (off_t)0) {
2051         error("Split size must be > " OFF_T_FMT "k",
2052               (OFF_T_FMT_TYPE)(DISK_BLOCK_BYTES/1024));
2053       /*NOTREACHED*/
2054     }
2055
2056     /* should only calculuate this once, not on retries etc */
2057     if (expected_splits != 0)
2058         return(expected_splits);
2059
2060     total_kb = holding_file_size(filename, 1);
2061     
2062     if (total_kb <= (off_t)0) {
2063         fprintf(stderr, "taper: r: " OFF_T_FMT
2064                 " kb holding file makes no sense, setting splitsize to 0\n",
2065                 (OFF_T_FMT_TYPE)total_kb);
2066         fflush(stderr);
2067         splitsize = 0;  /* disabling split */
2068         return(0);
2069     }
2070
2071     fprintf(stderr, "taper: r: Total dump size should be " OFF_T_FMT
2072                 "kb, chunk size is " OFF_T_FMT "kb\n",
2073                 (OFF_T_FMT_TYPE)total_kb,
2074                 (OFF_T_FMT_TYPE)splitsize);
2075     fflush(stderr);
2076
2077     splits = (int)(total_kb / adj_splitsize);
2078     if ((splits == 0) || (total_kb % adj_splitsize))
2079         splits++;
2080
2081
2082     fprintf(stderr, "taper: r: Expecting to split into %d parts \n", splits);
2083     fflush(stderr);
2084
2085     return(splits);
2086 }
2087
2088 /*
2089  * ========================================================================
2090  * TAPE WRITER SIDE
2091  *
2092  */
2093 times_t idlewait, rdwait, wrwait, fmwait;
2094 unsigned long total_writes;
2095 off_t total_tape_used;
2096 int total_tape_fm;
2097
2098 void write_file(void);
2099 int write_buffer(buffer_t *bp);
2100
2101 void
2102 tape_writer_side(
2103     int getp,
2104     int putp)
2105 {
2106     int tok;
2107     int tape_started;
2108     char *str;
2109     char *hostname;
2110     char *diskname;
2111     char *datestamp;
2112     int level;
2113     int tmpint;
2114
2115 #ifdef HAVE_LIBVTBLC
2116     char *vol_label;
2117     char *vol_date;
2118 #endif /* HAVE_LIBVTBLC */
2119
2120     procname = "writer";
2121     syncpipe_init(getp, putp);
2122     tape_started = 0;
2123     idlewait = times_zero;
2124     if (tapedev != NULL) {
2125         tapedev = stralloc(tapedev);
2126     }
2127
2128     while (1) {
2129         startclock();
2130         if ((tok = syncpipe_get(&tmpint)) == -1) {
2131             error("writer: Syncpipe failure before start");
2132             /*NOTREACHED*/
2133         }
2134
2135         idlewait = timesadd(idlewait, stopclock());
2136         if (tok != 'S' && tok != 'Q' && !tape_started) {
2137             error("writer: token '%c' before start", tok);
2138             /*NOTREACHED*/
2139         }
2140
2141         switch(tok) {
2142         case 'H':               /* Reader read pipe side is down */
2143             dbprintf(("writer: Communications with reader is down"));
2144             error("writer: Communications with reader is down");
2145             /*NOTREACHED*/
2146             
2147         case 'S':               /* start-tape */
2148             if (tape_started) {
2149                 error("writer: multiple start requests");
2150                 /*NOTREACHED*/
2151             }
2152             if ((str = syncpipe_getstr()) == NULL) {
2153                 error("writer: Syncpipe failure");
2154                 /*NOTREACHED*/
2155             }
2156             if (!first_tape(str ? str : "bad-datestamp")) {
2157                 if (tape_fd >= 0) {
2158                     tapefd_close(tape_fd);
2159                     tape_fd = -1;
2160                 }
2161                 if (syncpipe_put('E', 0) == -1) {
2162                     error("writer: Syncpipe failure passing exit code");
2163                     /*NOTREACHED*/
2164                 }
2165                 if (syncpipe_putstr(errstr) == -1) {
2166                     error("writer: Syncpipe failure passing exit string");
2167                     /*NOTREACHED*/
2168                 }
2169                 /* wait for reader to acknowledge error */
2170                 do {
2171                     if ((tok = syncpipe_get(&tmpint)) == -1) {
2172                         error("writer: Syncpipe failure waiting for error ack");
2173                         /*NOTREACHED*/
2174                     }
2175                     if (tok != 'e') {
2176                         error("writer: got '%c' unexpectedly after error", tok);
2177                         /*NOTREACHED*/
2178                     }
2179                 } while (tok != 'e');
2180             } else {
2181                 if (syncpipe_put('S', 0) == -1) {
2182                     error("writer: syncpipe failure while starting tape");
2183                     /*NOTREACHED*/
2184                 }
2185                 tape_started = 1;
2186             }
2187             amfree(str);
2188             break;
2189
2190         case 'O':               /* open-output */
2191             if ((datestamp = syncpipe_getstr()) == NULL) {
2192                 error("writer: Syncpipe failure during open");
2193                 /*NOTREACHED*/
2194             }
2195             tapefd_setinfo_datestamp(tape_fd, datestamp);
2196             amfree(datestamp);
2197
2198             if ((hostname = syncpipe_getstr()) == NULL) {
2199                 error("writer: Syncpipe failure fetching hostname");
2200                 /*NOTREACHED*/
2201             }
2202             tapefd_setinfo_host(tape_fd, hostname);
2203             amfree(hostname);
2204
2205             if ((diskname = syncpipe_getstr()) == NULL) {
2206                 error("writer: Syncpipe failure fetching diskname");
2207                 /*NOTREACHED*/
2208             }
2209             tapefd_setinfo_disk(tape_fd, diskname);
2210             amfree(diskname);
2211             if ((level = syncpipe_getint()) == -1) {
2212                 error("writer: Syncpipe failure fetching level");
2213                 /*NOTREACHED*/
2214             }
2215             tapefd_setinfo_level(tape_fd, level);
2216             write_file();
2217             break;
2218
2219 #ifdef HAVE_LIBVTBLC
2220         case 'L':               /* read vtbl label */
2221             vtbl_no = tmpint;
2222             if ((vol_label = syncpipe_getstr()) == NULL) {
2223                 error("writer: Syncpipe failure fetching vrbl label");
2224                 /*NOTREACHED*/
2225             }
2226             fprintf(stderr, "taper: read label string \"%s\" from pipe\n", 
2227                     vol_label);
2228             strncpy(vtbl_entry[vtbl_no].label, vol_label, 45);
2229             break;
2230
2231         case 'D':               /* read vtbl date */
2232             vtbl_no = tmpint;
2233             if ((vol_date = syncpipe_getstr()) == NULL) {
2234                 error("writer: Syncpipe failure fetching vrbl date");
2235                 /*NOTREACHED*/
2236             }
2237             fprintf(stderr, "taper: read date string \"%s\" from pipe\n", 
2238                     vol_date);
2239             strncpy(vtbl_entry[vtbl_no].date, vol_date, 20);
2240             break;
2241 #endif /* HAVE_LIBVTBLC */
2242
2243         case 'Q':
2244             end_tape(0);        /* XXX check results of end tape ?? */
2245             clear_tapelist();
2246             amfree(taper_timestamp);
2247             amfree(label);
2248             amfree(errstr);
2249             amfree(changer_resultstr);
2250             amfree(tapedev);
2251             amfree(conf_tapelist);
2252             amfree(config_dir);
2253             amfree(config_name);
2254
2255             malloc_size_2 = malloc_inuse(&malloc_hist_2);
2256
2257             if (malloc_size_1 != malloc_size_2) {
2258                 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
2259             }
2260             exit(0);
2261             /*NOTREACHED*/
2262
2263         default:
2264             assert(0);
2265         }
2266     }
2267 }
2268
2269 void
2270 write_file(void)
2271 {
2272     buffer_t *bp;
2273     int full_buffers, i, bufnum;
2274     int tok;
2275     char number[NUM_STR_SIZE];
2276     char *rdwait_str, *wrwait_str, *fmwait_str;
2277     int tmpint;
2278
2279     rdwait = wrwait = times_zero;
2280     total_writes = 0;
2281
2282     bp = buftable;
2283     full_buffers = 0;
2284     tok = '?';
2285
2286     taper_debug(1, ("taper: w: start file\n"));
2287
2288     /*
2289      * Tell the reader that the tape is open, and give it all the buffers.
2290      */
2291     if (syncpipe_put('O', 0) == -1) {
2292         error("writer: Syncpipe failure starting write sequence");
2293         /*NOTREACHED*/
2294     }
2295     for (i = 0; i < conf_tapebufs; i++) {
2296         taper_debug(1, ("taper: w: put R%d\n", i));
2297         if (syncpipe_put('R', i) == -1) {
2298             error("writer: Syncpipe failure readying write buffers");
2299             /*NOTREACHED*/
2300         }
2301     }
2302
2303     /*
2304      * We write the filemark at the start of the file rather than at the end,
2305      * so that it can proceed in parallel with the reader's initial filling
2306      * up of the buffers.
2307      */
2308
2309     startclock();
2310     if (!write_filemark())
2311         goto tape_error;
2312     fmwait = stopclock();
2313
2314     filenum += 1;
2315
2316     do {
2317
2318         /*
2319          * STOPPED MODE
2320          *
2321          * At the start of the file, or if the input can't keep up with the
2322          * tape, we enter STOPPED mode, which waits for most of the buffers
2323          * to fill up before writing to tape.  This maximizes the amount of
2324          * data written in chunks to the tape drive, minimizing the number
2325          * of starts/stops, which in turn saves tape and time.
2326          */
2327
2328         if (interactive)
2329             fputs("[WS]", stderr);
2330         startclock();
2331         while (full_buffers < conf_tapebufs - THRESHOLD) {
2332             if ((tok = syncpipe_get(&bufnum)) == -1) {
2333                 error("writer: Syncpipe failure during buffer advance");
2334                 /*NOTREACHED*/
2335             }
2336             if (tok != 'W')
2337                 break;
2338             taper_debug(1, ("taper: w: got W%d\n",bufnum));
2339             full_buffers++;
2340         }
2341         rdwait = timesadd(rdwait, stopclock());
2342
2343         /*
2344          * STARTING MODE
2345          *
2346          * We start output when sufficient buffers have filled up, or at
2347          * end-of-file, whichever comes first.  Here we drain all the buffers
2348          * that were waited on in STOPPED mode.  If more full buffers come
2349          * in, then we will be STREAMING.
2350          */
2351
2352         while (full_buffers) {
2353             if (tt_file_pad && bp->size < (ssize_t)tt_blocksize) {
2354                 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
2355                 bp->size = (ssize_t)tt_blocksize;
2356             }
2357             if (!write_buffer(bp))
2358                 goto tape_error;
2359             full_buffers--;
2360             bp = nextbuf(bp);
2361         }
2362
2363         /*
2364          * STREAMING MODE
2365          *
2366          * With any luck, the input source is faster than the tape drive.  In
2367          * this case, full buffers will appear in the circular queue faster
2368          * than we can write them, so the next buffer in the queue will always
2369          * be marked FULL by the time we get to it.  If so, we'll stay in
2370          * STREAMING mode.
2371          *
2372          * On the other hand, if we catch up to the input and thus would have
2373          * to wait for buffers to fill, we are then STOPPED again.
2374          */
2375
2376         while (tok == 'W' && bp->status == FULL) {
2377             if ((tok = syncpipe_get(&bufnum)) == -1) {
2378                 error("writer: Syncpipe failure advancing buffer");
2379                 /*NOTREACHED*/
2380             }
2381
2382             if (tok == 'W') {
2383                 taper_debug(1, ("taper: w: got W%d\n",bufnum));
2384                 if(bufnum != (int)(bp - buftable)) {
2385                     fprintf(stderr,
2386                             "taper: tape-writer: my buf %d reader buf %d\n",
2387                             (int)(bp-buftable), bufnum);
2388                     fflush(stderr);
2389                     if (syncpipe_put('E', 0) == -1) { 
2390                         error("writer: Syncpipe failure putting error token");
2391                         /*NOTREACHED*/
2392                     }
2393                     if (syncpipe_putstr("writer-side buffer mismatch") == -1) {
2394                         error("writer: Syncpipe failure putting error messgae");
2395                         /*NOTREACHED*/
2396                     }
2397                     goto error_ack;
2398                 }
2399                 if (tt_file_pad && bp->size < (ssize_t)tt_blocksize) {
2400                     memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
2401                     bp->size = (ssize_t)tt_blocksize;
2402                 }
2403                 if (!write_buffer(bp))
2404                     goto tape_error;
2405                 bp = nextbuf(bp);
2406             } else if (tok == 'Q') {
2407                 return;
2408             } else if (tok == 'X') {
2409                 goto reader_buffer_snafu;
2410             } else {
2411                 error("writer-side not expecting token: %c", tok);
2412                 /*NOTREACHED*/
2413             }
2414         }
2415     } while (tok == 'W');
2416
2417     /* got close signal from reader, acknowledge it */
2418
2419     if (tok == 'X')
2420         goto reader_buffer_snafu;
2421
2422     assert(tok == 'C');
2423     if (syncpipe_put('C', 0) == -1) {
2424         error("writer: Syncpipe failure putting close");
2425         /*NOTREACHED*/
2426     }
2427
2428     /* tell reader the tape and file number */
2429
2430     if (syncpipe_putstr(label) == -1) {
2431         error("writer: Syncpipe failure putting label");
2432         /*NOTREACHED*/
2433     }
2434     snprintf(number, SIZEOF(number), "%d", filenum);
2435     if (syncpipe_putstr(number) == -1) {
2436         error("writer: Syncpipe failure putting filenum");
2437         /*NOTREACHED*/
2438     }
2439
2440     snprintf(number, SIZEOF(number), "%lu", total_writes);
2441     rdwait_str = stralloc(walltime_str(rdwait));
2442     wrwait_str = stralloc(walltime_str(wrwait));
2443     fmwait_str = stralloc(walltime_str(fmwait));
2444     errstr = newvstralloc(errstr,
2445                           "{wr:",
2446                           " writers ", number,
2447                           " rdwait ", rdwait_str,
2448                           " wrwait ", wrwait_str,
2449                           " filemark ", fmwait_str,
2450                           "}",
2451                           NULL);
2452     amfree(rdwait_str);
2453     amfree(wrwait_str);
2454     amfree(fmwait_str);
2455     if (syncpipe_putstr(errstr) == -1) {
2456         error("writer: Syncpipe failure putting '%s'", errstr);
2457         /*NOTREACHED*/
2458     }
2459
2460     /* XXX go to next tape if past tape size? */
2461
2462     return;
2463
2464  tape_error:
2465     if (errstr) 
2466         dbprintf(("tape_error: %s\n", errstr));
2467     /* got tape error */
2468     if (next_tape(1)) {
2469         if (syncpipe_put('T', 0) == -1) {   /* next tape in place, try again */
2470             error("writer: Syncpipe failure during tape advance");
2471             /*NOTREACHED*/
2472         }
2473     } else {
2474         if (syncpipe_put('E', 0) == -1) {   /* no more tapes, fail */
2475             error("writer: Syncpipe failure during tape error");
2476             /*NOTREACHED*/
2477         }
2478     }
2479     if (syncpipe_putstr(errstr) == -1) {
2480         error("writer: Syncpipe failure putting '%s'", errstr);
2481         /*NOTREACHED*/
2482     }
2483
2484  error_ack:
2485     /* wait for reader to acknowledge error */
2486     do {
2487         if ((tok = syncpipe_get(&tmpint)) == -1) {
2488             error("writer: syncpipe failure waiting for error ack");
2489             /*NOTREACHED*/
2490         }
2491
2492         if (tok != 'W' && tok != 'C' && tok != 'e') {
2493             error("writer: got '%c' unexpectedly after error", tok);
2494             /*NOTREACHED*/
2495         }
2496     } while (tok != 'e');
2497     return;
2498
2499  reader_buffer_snafu:
2500     if (syncpipe_put('x', 0) == -1) {
2501         error("writer: syncpipe failure putting buffer snafu");
2502         /*NOTREACHED*/
2503     }
2504     return;
2505 }
2506
2507 int
2508 write_buffer(
2509     buffer_t *bp)
2510 {
2511     ssize_t rc;
2512
2513     assert(bp->status == FULL);
2514
2515     startclock();
2516     rc = tapefd_write(tape_fd, bp->buffer, (size_t)bp->size);
2517     if (rc == (ssize_t)bp->size) {
2518 #if defined(NEED_RESETOFS)
2519         static double tape_used_modulus_2gb = 0;
2520
2521         /*
2522          * If the next write will go over the 2 GByte boundary, reset
2523          * the kernel concept of where we are to make sure it does not
2524          * go silly on us.
2525          */
2526         tape_used_modulus_2gb += (double)rc;
2527         if (tape_used_modulus_2gb + (double)rc > (double)0x7fffffff) {
2528             tape_used_modulus_2gb = 0;
2529             tapefd_resetofs(tape_fd);
2530         }
2531 #endif
2532         wrwait = timesadd(wrwait, stopclock());
2533         total_writes += 1;
2534         total_tape_used += (off_t)rc;
2535         bp->status = EMPTY;
2536         if (interactive || debug_taper >= 1)
2537             dumpstatus(bp);
2538         if (interactive)
2539             fputs("W", stderr);
2540
2541         taper_debug(1, ("taper: w: put R%d\n", (int)(bp-buftable)));
2542         if (syncpipe_put('R', (int)(bp-buftable)) == -1) {
2543             error("writer: Syncpipe failure during advancing write bufffer");
2544             /*NOTREACHED*/
2545         }
2546         return 1;
2547     } else {
2548         errstr = newvstralloc(errstr,
2549                               "writing file: ",
2550                               (rc != -1) ? "short write" : strerror(errno),
2551                               NULL);
2552         wrwait = timesadd(wrwait, stopclock());
2553         if (interactive)
2554             fputs("[WE]", stderr);
2555         return 0;
2556     }
2557 }
2558
2559
2560 static void 
2561 cleanup(void)
2562 {
2563     REMOVE_SHARED_MEMORY(); 
2564 }
2565
2566
2567 /*
2568  * Cleanup shared memory segments 
2569  */
2570 static void 
2571 signal_handler(
2572     int signum)
2573 {
2574     log_add(L_INFO, "Received signal %d", signum);
2575
2576     exit(1);
2577 }
2578
2579
2580 /*
2581  * Installing signal handlers for signal whose default action is 
2582  * process termination so that we can clean up shared memory
2583  * segments
2584  */
2585 static void
2586 install_signal_handlers(void)
2587 {
2588     struct sigaction act;
2589
2590     act.sa_handler = signal_handler;
2591     act.sa_flags = 0;
2592     sigemptyset(&act.sa_mask);
2593
2594     signal(SIGPIPE, SIG_IGN);
2595
2596     if (sigaction(SIGINT, &act, NULL) != 0) {
2597         error("taper: couldn't install SIGINT handler [%s]", strerror(errno));
2598         /*NOTREACHED*/
2599     }
2600
2601     if (sigaction(SIGHUP, &act, NULL) != 0) {
2602         error("taper: couldn't install SIGHUP handler [%s]", strerror(errno));
2603         /*NOTREACHED*/
2604     }
2605    
2606     if (sigaction(SIGTERM, &act, NULL) != 0) {
2607         error("taper: couldn't install SIGTERM handler [%s]", strerror(errno));
2608         /*NOTREACHED*/
2609     }
2610
2611     if (sigaction(SIGUSR1, &act, NULL) != 0) {
2612         error("taper: couldn't install SIGUSR1 handler [%s]", strerror(errno));
2613         /*NOTREACHED*/
2614     }
2615
2616     if (sigaction(SIGUSR2, &act, NULL) != 0) {
2617         error("taper: couldn't install SIGUSR2 handler [%s]", strerror(errno));
2618         /*NOTREACHED*/
2619     }
2620
2621     if (sigaction(SIGALRM, &act, NULL) != 0) {
2622         error("taper: couldn't install SIGALRM handler [%s]", strerror(errno));
2623         /*NOTREACHED*/
2624     }
2625 }
2626
2627
2628 /*
2629  * ========================================================================
2630  * SHARED-MEMORY BUFFER SUBSYSTEM
2631  *
2632  */
2633
2634 #ifdef HAVE_SYSVSHM
2635
2636 int shmid = -1;
2637
2638 char *
2639 attach_buffers(
2640     size_t size)
2641 {
2642     char *result;
2643
2644     shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0700);
2645     if (shmid == -1) {
2646         return NULL;
2647     }
2648
2649     result = (char *)shmat(shmid, (SHM_ARG_TYPE *)NULL, 0);
2650
2651     if (result == (char *)-1) {
2652         int save_errno = errno;
2653
2654         destroy_buffers();
2655         errno = save_errno;
2656         error("shmat: %s", strerror(errno));
2657         /*NOTREACHED*/
2658     }
2659
2660     return result;
2661 }
2662
2663
2664 void
2665 detach_buffers(
2666     char *bufp)
2667 {
2668     if ((bufp != NULL) &&
2669         (shmdt((SHM_ARG_TYPE *)bufp) == -1)) {
2670         error("shmdt: %s", strerror(errno));
2671         /*NOTREACHED*/
2672     }
2673 }
2674
2675 void
2676 destroy_buffers(void)
2677 {
2678     if (shmid == -1)
2679         return; /* nothing to destroy */
2680     if (shmctl(shmid, IPC_RMID, NULL) == -1) {
2681         error("shmctl: %s", strerror(errno));
2682         /*NOTREACHED*/
2683     }
2684 }
2685
2686 #else
2687 #ifdef HAVE_MMAP
2688
2689 #ifdef HAVE_SYS_MMAN_H
2690 #include <sys/mman.h>
2691 #endif
2692
2693 #ifndef MAP_ANON
2694 #  ifdef MAP_ANONYMOUS                  /* OSF/1-style */
2695 #    define MAP_ANON MAP_ANONYMOUS
2696 #  else                                 /* SunOS4-style */
2697 #    define MAP_ANON 0
2698 #    define ZERO_FILE "/dev/zero"
2699 #  endif
2700 #endif
2701
2702 int shmfd = -1;
2703 size_t saved_size;
2704
2705 char *
2706 attach_buffers(
2707     size_t size)
2708 {
2709     char *shmbuf;
2710
2711 #ifdef ZERO_FILE
2712     shmfd = open(ZERO_FILE, O_RDWR);
2713     if (shmfd == -1) {
2714         error("attach_buffers: could not open %s: %s",
2715               ZERO_FILE,
2716               strerror(errno));
2717         /*NOTREACHED*/
2718     }
2719 #endif
2720
2721     saved_size = size;
2722     shmbuf = (char *) mmap((void *) 0,
2723                            size,
2724                            PROT_READ|PROT_WRITE,
2725                            MAP_ANON|MAP_SHARED,
2726                            shmfd, 0);
2727
2728     return shmbuf;
2729 }
2730
2731 void
2732 detach_buffers(
2733     char *bufp)
2734 {
2735     if ((bufp != NULL) && 
2736         (munmap((void *)bufp, saved_size) == -1)) {
2737         error("detach_buffers: munmap: %s", strerror(errno));
2738         /*NOTREACHED*/
2739     }
2740
2741     if (shmfd != -1)
2742         aclose(shmfd);
2743 }
2744
2745 void
2746 destroy_buffers(void)
2747 {
2748 }
2749
2750 #else
2751 #error: must define either HAVE_SYSVSHM or HAVE_MMAP!
2752 #endif
2753 #endif
2754
2755
2756
2757 /*
2758  * ========================================================================
2759  * SYNC-PIPE SUBSYSTEM
2760  *
2761  */
2762
2763 int getpipe, putpipe;
2764
2765 void
2766 syncpipe_init(
2767     int rd,
2768     int wr)
2769 {
2770     getpipe = rd;
2771     putpipe = wr;
2772 }
2773
2774 void
2775 syncpipe_read_error(
2776     ssize_t     rc,
2777     ssize_t     expected)
2778 {
2779     char buf[sizeof(char) + sizeof(int)];
2780
2781     if (rc == 0) {
2782         dbprintf(("syncpipe_get %s halting: Unexpected read EOF\n", procname));
2783         fprintf(stderr, "syncpipe_get %s halting: Unexpected read EOF\n", procname);
2784     } else if (rc < 0) {
2785         dbprintf(("syncpipe_get %s halting: Read error - %s\n",
2786                         procname, strerror(errno)));
2787         fprintf(stderr, "syncpipe_get %s halting: Read error - %s\n",
2788                         procname, strerror(errno));
2789     } else {
2790         dbprintf(("syncpipe_get %s halting: Read "
2791                 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2792                 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2793                 (SSIZE_T_FMT_TYPE)expected));
2794         fprintf(stderr, "syncpipe_get %s halting: Read "
2795                 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2796                 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2797                 (SSIZE_T_FMT_TYPE)expected);
2798     }
2799     /* Halt the other side if it's still alive */
2800     buf[0] = 'H';
2801     memset(&buf[1], 0, SIZEOF(int));
2802     if (write(putpipe, buf, SIZEOF(buf)))
2803         return;
2804 }
2805
2806 void
2807 syncpipe_write_error(
2808     ssize_t     rc,
2809     ssize_t     expected)
2810 {
2811     char buf[sizeof(char) + sizeof(int)];
2812
2813     if (rc == 0) {              /* EOF */
2814         dbprintf(("syncpipe %s halting: Write EOF\n", procname));
2815         fprintf(stderr, "syncpipe %s halting: Write EOF\n", procname);
2816     } else if (rc < 0) {
2817         dbprintf(("syncpipe %s halting: Write error - %s\n",
2818                         procname, strerror(errno)));
2819         fprintf(stderr, "syncpipe %s halting: Write error - %s\n",
2820                         procname, strerror(errno));
2821     } else {
2822         dbprintf(("syncpipe %s halting: Write "
2823                         SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2824                         procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2825                         (SSIZE_T_FMT_TYPE)expected));
2826         fprintf(stderr, "syncpipe %s halting: Write "
2827                         SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2828                         procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2829                         (SSIZE_T_FMT_TYPE)expected);
2830     }
2831     /* Halt the other side if it's still alive */
2832     buf[0] = 'H';
2833     memset(&buf[1], 0, SIZEOF(int));
2834     if (write(putpipe, buf, SIZEOF(buf)))
2835         return;
2836 }
2837
2838 int
2839 syncpipe_get(
2840     int *intp)
2841 {
2842     ssize_t rc;
2843     char buf[SIZEOF(char) + SIZEOF(int)];
2844
2845     memset(buf, 0, sizeof(buf));
2846     rc = fullread(getpipe, buf, SIZEOF(buf));
2847     if (rc != (ssize_t)sizeof(buf)) {
2848         syncpipe_read_error(rc, (ssize_t)sizeof(buf));
2849         return (-1);
2850     }
2851
2852     if (debug_taper >= 1 && *buf != 'R' && *buf != 'W') {
2853         taper_debug(1, ("taper: %c: getc %c\n", *procname, *buf));
2854     }
2855
2856     memcpy(intp, &buf[1], SIZEOF(int));
2857     return (int)buf[0];
2858 }
2859
2860 int
2861 syncpipe_getint(void)
2862 {
2863     ssize_t rc;
2864     int i = 0;
2865
2866     rc = fullread(getpipe, &i, SIZEOF(i));
2867     if (rc != (ssize_t)sizeof(i)) {
2868         syncpipe_read_error(rc, (ssize_t)sizeof(i));
2869         return (-1);
2870     }
2871
2872     return (i);
2873 }
2874
2875
2876 char *
2877 syncpipe_getstr(void)
2878 {
2879     ssize_t rc;
2880     int len;
2881     char *str;
2882
2883     if ((len = syncpipe_getint()) <= 0) {
2884         fprintf(stderr, "syncpipe %s halting: Protocol error - "
2885                         "Invalid string length (%d)\n", procname, len);
2886         syncpipe_put('H', 0); /* Halt the other side */
2887         exit(1);
2888         /*NOTREACHED*/
2889     }
2890
2891     str = alloc((size_t)len);
2892
2893     rc = fullread(getpipe, str, (size_t)len);
2894     if (rc != (ssize_t)len) {
2895         syncpipe_read_error(rc, (ssize_t)len);
2896         return (NULL);
2897     }
2898     return (str);
2899 }
2900
2901
2902 int
2903 syncpipe_put(
2904     int chi,
2905     int intval)
2906 {
2907     char buf[sizeof(char) + sizeof(int)];
2908     ssize_t     rc;
2909
2910     buf[0] = (char)chi;
2911     memcpy(&buf[1], &intval, SIZEOF(int));
2912     if (debug_taper >= 1 && buf[0] != 'R' && buf[0] != 'W') {
2913         taper_debug(1, ("taper: %c: putc %c\n",*procname,buf[0]));
2914     }
2915
2916     rc = fullwrite(putpipe, buf, SIZEOF(buf));
2917     if (rc != (ssize_t)sizeof(buf)) {
2918         syncpipe_write_error(rc, (ssize_t)sizeof(buf));
2919         return (-1);
2920     }
2921     return (0);
2922 }
2923
2924 int
2925 syncpipe_putint(
2926     int i)
2927 {
2928     ssize_t     rc;
2929
2930     rc = fullwrite(putpipe, &i, SIZEOF(i));
2931     if (rc != (ssize_t)sizeof(i)) {
2932         syncpipe_write_error(rc, (ssize_t)sizeof(i));
2933         return (-1);
2934         /* NOTREACHED */
2935     }
2936     return (0);
2937 }
2938
2939 int
2940 syncpipe_putstr(
2941     const char *str)
2942 {
2943     ssize_t n, rc;
2944
2945     if(!str)
2946         str = "UNKNOWN syncpipe_putstr STRING";
2947
2948     n = (ssize_t)strlen(str) + 1;                       /* send '\0' as well */
2949     syncpipe_putint((int)n);
2950
2951     rc = fullwrite(putpipe, str, (size_t)n);
2952     if (rc != n) {
2953         syncpipe_write_error(rc, n);
2954         return (-1);
2955     }
2956     return (0);
2957 }
2958 \f
2959 /*
2960  * ========================================================================
2961  * TAPE MANIPULATION SUBSYSTEM
2962  *
2963  */
2964 int label_tape(void);
2965
2966 /* local functions */
2967
2968 /* return 0 on success              */
2969 /* return 1 on error and set errstr */
2970 int
2971 label_tape(void)
2972 {  
2973     char *conf_tapelist_old = NULL;
2974     char *result;
2975     static int first_call = 1;
2976     char *timestamp;
2977     char *error_msg = NULL;
2978     char *s, *r;
2979     int slot = -1;
2980     int scan_result;
2981
2982     amfree(label);
2983     amfree(tapedev);
2984     if ((scan_result = taper_scan(NULL, &label, &timestamp, &tapedev, CHAR_taperscan_output_callback, &error_msg)) < 0) {
2985         fprintf(stderr, "%s\n", error_msg);
2986         errstr = error_msg;
2987         error_msg = NULL;
2988         amfree(timestamp);
2989         return 0;
2990     }
2991     amfree(timestamp);
2992
2993     if(error_msg) {
2994         s = error_msg; r = NULL;
2995         while((s=strstr(s,"slot "))) { s += 5; r=s; };
2996         if(r) {
2997             slot = atoi(r);
2998         }
2999         amfree(error_msg);
3000     }
3001     if ((tape_fd = tape_open(tapedev, O_WRONLY)) == -1) {
3002         if (errno == EACCES) {
3003             errstr = newstralloc2(errstr,
3004                                  "writing label: tape is write protected or I don't have write permission on ", tapedev);
3005         } else {
3006             errstr = newstralloc2(errstr,
3007                                   "writing label: ", strerror(errno));
3008         }
3009         return 0;
3010     }
3011
3012     tapefd_setinfo_length(tape_fd, tapetype_get_length(tt));
3013
3014     tapefd_setinfo_datestamp(tape_fd, taper_timestamp);
3015     tapefd_setinfo_disk(tape_fd, label);
3016     result = tapefd_wrlabel(tape_fd, taper_timestamp, label, tt_blocksize);
3017     if (result != NULL) {
3018         errstr = newstralloc(errstr, result);
3019         return 0;
3020     }
3021
3022     /* Output a description of what we just did. A result of '3' from taper_scan
3023      * means that a new tape was found and will be labeled. */
3024     if (slot > -1) {
3025         fprintf(stderr, _("taper: slot: %d wrote label `%s' date `%s'\n"), slot, label, taper_timestamp);
3026         if (scan_result == 3)
3027             log_add(L_INFO, _("Wrote new label `%s' to new (non-amanda) tape in slot %d"), label, slot);
3028     } else {
3029         fprintf(stderr, _("taper: wrote label `%s' date `%s'\n"), label, taper_timestamp);
3030         if (scan_result == 3)
3031             log_add(L_INFO, _("Wrote new label `%s' to new (non-amanda) tape"), label);
3032     }
3033     fflush(stderr);
3034
3035 #ifdef HAVE_LIBVTBLC
3036     /* store time for the first volume entry */
3037     time(&raw_time);
3038     tape_timep = localtime(&raw_time);
3039     strftime(start_datestr, 20, "%T %D", tape_timep);
3040     fprintf(stderr, "taper: got vtbl start time: %s\n", start_datestr);
3041     fflush(stderr);
3042 #endif /* HAVE_LIBVTBLC */
3043
3044     if (strcmp(label, FAKE_LABEL) != 0) {
3045         if (cur_tape == 0) {
3046             conf_tapelist_old = stralloc2(conf_tapelist, ".yesterday");
3047         } else {
3048             char cur_str[NUM_STR_SIZE];
3049
3050             snprintf(cur_str, SIZEOF(cur_str), "%d", cur_tape - 1);
3051             conf_tapelist_old = vstralloc(conf_tapelist,
3052                                           ".today.", cur_str, NULL);
3053         }
3054
3055         if (write_tapelist(conf_tapelist_old)) {
3056             error("could not write tapelist: %s", strerror(errno));
3057             /*NOTREACHED*/
3058         }
3059         amfree(conf_tapelist_old);
3060
3061         remove_tapelabel(label);
3062         add_tapelabel(taper_timestamp, label);
3063         if (write_tapelist(conf_tapelist)) {
3064             error("could not write tapelist: %s", strerror(errno));
3065             /*NOTREACHED*/
3066         }
3067     }
3068
3069     log_add(L_START, "datestamp %s label %s tape %d",
3070             taper_timestamp, label, cur_tape);
3071     if (first_call && strcmp(label, FAKE_LABEL) == 0) {
3072         first_call = 0;
3073         log_add(L_WARNING, "tapedev is %s, dumps will be thrown away", tapedev);
3074     }
3075
3076     total_tape_used=(off_t)0;
3077     total_tape_fm = 0;
3078
3079     return 1;
3080 }
3081
3082 /* return 0 on error and set errstr */
3083 /* return 1 on success              */
3084 int
3085 first_tape(
3086     char *new_datestamp)
3087 {
3088     if ((have_changer = changer_init()) < 0) {
3089         error("changer initialization failed: %s", strerror(errno));
3090         /*NOTREACHED*/
3091     }
3092     changer_debug = 1;
3093
3094     taper_timestamp = newstralloc(taper_timestamp, new_datestamp);
3095
3096     if (!label_tape())
3097         return 0;
3098
3099     filenum = 0;
3100     return 1;
3101 }
3102
3103 int
3104 next_tape(
3105     int writerror)
3106 {
3107     end_tape(writerror);
3108
3109     if (++cur_tape >= runtapes)
3110         return 0;
3111
3112     if (!label_tape()) {
3113         return 0;
3114     }
3115
3116     filenum = 0;
3117     return 1;
3118 }
3119
3120
3121 int
3122 end_tape(
3123     int writerror)
3124 {
3125     char *result;
3126     int rc = 0;
3127
3128     if (tape_fd >= 0) {
3129         log_add(L_INFO, "tape %s kb " OFF_T_FMT " fm %d %s", 
3130                 label,
3131                 (OFF_T_FMT_TYPE)((total_tape_used+(off_t)1023) / (off_t)1024),
3132                 total_tape_fm,
3133                 writerror? errstr : "[OK]");
3134
3135         fprintf(stderr, "taper: writing end marker. [%s %s kb "
3136                 OFF_T_FMT " fm %d]\n", label,
3137                 writerror? "ERR" : "OK",
3138                 (OFF_T_FMT_TYPE)((total_tape_used+(off_t)1023) / (off_t)1024),
3139                 total_tape_fm);
3140         fflush(stderr);
3141         if (! writerror) {
3142             if (! write_filemark()) {
3143                 rc = 1;
3144                 goto common_exit;
3145             }
3146
3147             result = tapefd_wrendmark(tape_fd, taper_timestamp, tt_blocksize);
3148             if (result != NULL) {
3149                 errstr = newstralloc(errstr, result);
3150                 rc = 1;
3151                 goto common_exit;
3152             }
3153         }
3154     }
3155
3156 #ifdef HAVE_LINUX_ZFTAPE_H
3157     if (tape_fd >= 0 && is_zftape(tapedev) == 1) {
3158         /* rewind the tape */
3159
3160         if (tapefd_rewind(tape_fd) == -1 ) {
3161             errstr = newstralloc2(errstr, "rewinding tape: ", strerror(errno));
3162             rc = 1;
3163             goto common_exit;
3164         }
3165         /* close the tape */
3166
3167         if (tapefd_close(tape_fd) == -1) {
3168             errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
3169             rc = 1;
3170             goto common_exit;
3171         }
3172         tape_fd = -1;
3173
3174 #ifdef HAVE_LIBVTBLC
3175         /* update volume table */
3176         fprintf(stderr, "taper: updating volume table ...\n");
3177         fflush(stderr);
3178     
3179         if ((tape_fd = raw_tape_open(rawtapedev, O_RDWR)) == -1) {
3180             if (errno == EACCES) {
3181                 errstr = newstralloc(errstr,
3182                                      "updating volume table: tape is write protected");
3183             } else {
3184                 errstr = newstralloc2(errstr,
3185                                       "updating volume table: ", 
3186                                       strerror(errno));
3187             }
3188             rc = 1;
3189             goto common_exit;
3190         }
3191         /* read volume table */
3192         if ((num_volumes = read_vtbl(tape_fd, volumes, vtbl_buffer,
3193                                      &first_seg, &last_seg)) == -1 ) {
3194             errstr = newstralloc2(errstr,
3195                                   "reading volume table: ", 
3196                                   strerror(errno));
3197             rc = 1;
3198             goto common_exit;
3199         }
3200         /* set volume label and date for first entry */
3201         vtbl_no = 0;
3202         if (set_label(label, volumes, num_volumes, vtbl_no)) {
3203             errstr = newstralloc2(errstr,
3204                                   "setting label for entry 1: ",
3205                                   strerror(errno));
3206             rc = 1;
3207             goto common_exit;
3208         }
3209         /* date of start writing this tape */
3210         if (set_date(start_datestr, volumes, num_volumes, vtbl_no)) {
3211             errstr = newstralloc2(errstr,
3212                                   "setting date for entry 1: ", 
3213                                   strerror(errno));
3214             rc = 1;
3215             goto common_exit;
3216         }
3217         /* set volume labels and dates for backup files */
3218         for (vtbl_no = 1; vtbl_no <= num_volumes - 2; vtbl_no++) { 
3219             fprintf(stderr,"taper: label %i: %s, date %s\n", 
3220                     vtbl_no,
3221                     vtbl_entry[vtbl_no].label,
3222                     vtbl_entry[vtbl_no].date);
3223             fflush(stderr);
3224             if (set_label(vtbl_entry[vtbl_no].label, 
3225                          volumes, num_volumes, vtbl_no)) {
3226                 errstr = newstralloc2(errstr,
3227                                       "setting label for entry i: ", 
3228                                       strerror(errno));
3229                 rc = 1;
3230                 goto common_exit;
3231             }
3232             if (set_date(vtbl_entry[vtbl_no].date, 
3233                         volumes, num_volumes, vtbl_no)) {
3234                 errstr = newstralloc2(errstr,
3235                                       "setting date for entry i: ",
3236                                       strerror(errno));
3237                 rc = 1;
3238                 goto common_exit;
3239             }
3240         }
3241         /* set volume label and date for last entry */
3242         vtbl_no = num_volumes - 1;
3243         if (set_label("AMANDA Tape End", volumes, num_volumes, vtbl_no)) {
3244             errstr = newstralloc2(errstr,
3245                                   "setting label for last entry: ", 
3246                                   strerror(errno));
3247             rc = 1;
3248             goto common_exit;
3249         }
3250         datestr = NULL; /* take current time */ 
3251         if (set_date(datestr, volumes, num_volumes, vtbl_no)) {
3252             errstr = newstralloc2(errstr,
3253                                   "setting date for last entry 1: ", 
3254                                   strerror(errno));
3255             rc = 1;
3256             goto common_exit;
3257         }
3258         /* write volume table back */
3259         if (write_vtbl(tape_fd, volumes, vtbl_buffer, num_volumes, first_seg,
3260                        op_mode == trunc)) {
3261             errstr = newstralloc2(errstr,
3262                                   "writing volume table: ", 
3263                                   strerror(errno));
3264             rc = 1;
3265             goto common_exit;
3266         }  
3267
3268         fprintf(stderr, "taper: updating volume table: done.\n");
3269         fflush(stderr);
3270 #endif /* HAVE_LIBVTBLC */
3271     }
3272 #endif /* !HAVE_LINUX_ZFTAPE_H */
3273
3274     /* close the tape and let the OS write the final filemarks */
3275
3276 common_exit:
3277
3278     if (tape_fd >= 0 && tapefd_close(tape_fd) == -1 && ! writerror) {
3279         errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
3280         rc = 1;
3281     }
3282     tape_fd = -1;
3283     amfree(label);
3284
3285     return rc;
3286 }
3287
3288
3289 int
3290 write_filemark(void)
3291 {
3292     if (tapefd_weof(tape_fd, (off_t)1) == -1) {
3293         errstr = newstralloc2(errstr, "writing filemark: ", strerror(errno));
3294         return 0;
3295     }
3296     total_tape_fm++;
3297     return 1;
3298 }