2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998, 2000 University of Maryland at College Park
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.
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.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
26 /* $Id: taper.c,v 1.118.2.1 2006/05/04 21:31:15 martinea Exp $
28 * moves files from holding disk to tape, or from a socket to tape
44 #include "amfeatures.h"
45 #include "fileheader.h"
46 #include "server_util.h"
47 #include "taperscan.c"
49 #ifdef HAVE_SYS_MMAN_H
59 static int vtbl_no = -1;
61 static int offset = 0;
62 static char *datestr = NULL;
63 static char start_datestr[20];
66 struct tm backup_time;
67 struct tm *tape_timep = &tape_time;
68 typedef struct vtbl_lbls {
72 static vtbl_lbls vtbl_entry[MAX_VOLUMES];
73 #endif /* HAVE_LIBVTBLC */
75 * XXX update stat collection/printing
76 * XXX advance to next tape first in next_tape
77 * XXX label is being read twice?
79 long splitsize = 0; /* max size of dumpfile before split (Kb) */
80 char *splitbuf = NULL;
81 char *splitbuf_wr_ptr = NULL; /* the number of Kb we've written into splitbuf */
82 int orig_holdfile = -1;
84 /* NBUFS replaced by conf_tapebufs */
85 /* #define NBUFS 20 */
88 off_t maxseek = (off_t)1 << ((sizeof(off_t) * 8) - 11);
90 char *holdfile_path = NULL;
91 char *holdfile_path_thischunk = NULL;
92 int num_holdfile_chunks = 0;
93 dumpfile_t holdfile_hdr;
94 dumpfile_t holdfile_hdr_thischunk;
95 off_t holdfile_offset_thischunk = (off_t)0;
96 int splitbuffer_fd = -1;
97 char *splitbuffer_path = NULL;
100 #define MODE_FILE_WRITE 1
101 #define MODE_PORT_WRITE 2
103 int mode = MODE_NONE;
105 /* This is now the number of empties, not full bufs */
108 #define CONNECT_TIMEOUT 2*60
116 typedef struct buffer_s {
122 #define nextbuf(p) ((p) == buftable+conf_tapebufs-1? buftable : (p)+1)
123 #define prevbuf(p) ((p) == buftable? buftable+conf_tapebufs-1 : (p)-1)
126 int main P((int main_argc, char **main_argv));
127 void file_reader_side P((int rdpipe, int wrpipe));
128 void tape_writer_side P((int rdpipe, int wrpipe));
130 /* shared-memory routines */
131 char *attach_buffers P((unsigned int size));
132 void detach_buffers P((char *bufp));
133 void destroy_buffers P((void));
134 #define REMOVE_SHARED_MEMORY() \
135 detach_buffers(buffers); \
136 if (strcmp(procname, "reader") == 0) { \
140 /* synchronization pipe routines */
141 void syncpipe_init P((int rd, int wr));
142 char syncpipe_get P((int *intp));
143 int syncpipe_getint P((void));
144 char *syncpipe_getstr P((void));
145 void syncpipe_put P((int ch, int intval));
146 void syncpipe_putint P((int i));
147 void syncpipe_putstr P((const char *str));
149 /* tape manipulation subsystem */
150 int first_tape P((char *new_datestamp));
151 int next_tape P((int writerr));
152 int end_tape P((int writerr));
153 int write_filemark P((void));
156 int seek_holdfile P((int fd, buffer_t *bp, long kbytes));
158 /* signal handling */
159 static void install_signal_handlers P((void));
160 static void signal_handler P((int));
163 static void cleanup P((void));
166 * ========================================================================
179 char *buffers = NULL;
180 buffer_t *buftable = NULL;
183 char *procname = "parent";
185 char *taper_datestamp = NULL;
190 char *tapedev = NULL;
191 char *tapetype = NULL;
192 tapetype_t *tt = NULL;
194 long tt_blocksize_kb;
197 static unsigned long malloc_hist_1, malloc_size_1;
198 static unsigned long malloc_hist_2, malloc_size_2;
200 dumpfile_t *save_holdfile = NULL;
201 long cur_span_chunkstart = 0; /* start of current split dump chunk (Kb) */
204 int expected_splits = 0;
205 int num_holdfiles = 0;
208 am_feature_t *their_features = NULL;
210 int runtapes, cur_tape, have_changer, tapedays;
211 char *labelstr, *conf_tapelist;
214 int first_seg, last_seg;
215 #endif /* HAVE_LIBVTBLC */
218 * ========================================================================
222 int main(main_argc, main_argv)
226 int p2c[2], c2p[2]; /* parent-to-child, child-to-parent pipes */
238 /* Don't die when child closes pipe */
239 signal(SIGPIPE, SIG_IGN);
241 malloc_size_1 = malloc_inuse(&malloc_hist_1);
243 fprintf(stderr, "%s: pid %ld executable %s version %s\n",
244 get_pname(), (long) getpid(), main_argv[0], version());
247 if (main_argc > 1 && main_argv[1][0] != '-') {
248 config_name = stralloc(main_argv[1]);
249 config_dir = vstralloc(CONFIG_DIR, "/", main_argv[1], "/", NULL);
253 char my_cwd[STR_SIZE];
255 if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
256 error("cannot determine current working directory");
258 config_dir = stralloc2(my_cwd, "/");
259 if ((config_name = strrchr(my_cwd, '/')) != NULL) {
260 config_name = stralloc(config_name + 1);
266 install_signal_handlers();
269 /* print prompts and debug messages if running interactive */
271 interactive = (main_argc > 1 && strcmp(main_argv[1],"-t") == 0);
273 erroutput_type = ERR_INTERACTIVE;
275 erroutput_type = ERR_AMANDALOG;
276 set_logerror(logerror);
279 conffile = stralloc2(config_dir, CONFFILE_NAME);
280 if(read_conffile(conffile)) {
281 error("errors processing config file \"%s\"", conffile);
285 conf_tapelist = getconf_str(CNF_TAPELIST);
286 if (*conf_tapelist == '/') {
287 conf_tapelist = stralloc(conf_tapelist);
289 conf_tapelist = stralloc2(config_dir, conf_tapelist);
291 if(read_tapelist(conf_tapelist)) {
292 error("could not load tapelist \"%s\"", conf_tapelist);
295 tapedev = getconf_str(CNF_TAPEDEV);
296 tapetype = getconf_str(CNF_TAPETYPE);
297 tt = lookup_tapetype(tapetype);
299 rawtapedev = getconf_str(CNF_RAWTAPEDEV);
300 #endif /* HAVE_LIBVTBLC */
301 tapedays = getconf_int(CNF_TAPECYCLE);
302 labelstr = getconf_str(CNF_LABELSTR);
304 runtapes = getconf_int(CNF_RUNTAPES);
307 conf_tapebufs = getconf_int(CNF_TAPEBUFS);
309 tt_blocksize_kb = tt->blocksize;
310 tt_blocksize = tt_blocksize_kb * 1024;
311 tt_file_pad = tt->file_pad;
314 fprintf(stderr,"taper: running in interactive test mode\n");
318 /* create read/write syncronization pipes */
320 if(pipe(p2c) || pipe(c2p))
321 error("creating sync pipes: %s", strerror(errno));
323 /* create shared memory segment */
325 #if defined(HAVE_GETPAGESIZE)
326 page_size = getpagesize();
327 fprintf(stderr, "%s: page size is %d\n", get_pname(), page_size);
330 fprintf(stderr, "%s: getpagesize() not available, using %d\n",
334 buffer_size = am_round(tt_blocksize, page_size);
335 fprintf(stderr, "%s: buffer size is %ld\n", get_pname(), buffer_size);
336 while(conf_tapebufs > 0) {
338 size += conf_tapebufs * buffer_size;
339 size += conf_tapebufs * sizeof(buffer_t);
340 if((buffers = attach_buffers(size)) != NULL) {
343 log_add(L_INFO, "attach_buffers: (%d tapebuf%s: %d bytes) %s",
345 (conf_tapebufs == 1) ? "" : "s",
350 if(buffers == NULL) {
351 error("cannot allocate shared memory");
353 i = (buffers - (char *)0) & (page_size - 1); /* page boundary offset */
355 first_buffer = buffers + page_size - i;
356 fprintf(stderr, "%s: shared memory at %p, first buffer at %p\n",
361 first_buffer = buffers;
363 buftable = (buffer_t *)(first_buffer + conf_tapebufs * buffer_size);
364 memset(buftable, 0, conf_tapebufs * sizeof(buffer_t));
365 if(conf_tapebufs < 10) {
367 } else if(conf_tapebufs < 100) {
372 for(i = 0; i < conf_tapebufs; i++) {
373 buftable[i].buffer = first_buffer + i * buffer_size;
374 fprintf(stderr, "%s: buffer[%0*d] at %p\n",
379 fprintf(stderr, "%s: buffer structures at %p for %d bytes\n",
382 (int)(conf_tapebufs * sizeof(buffer_t)));
384 /* fork off child writer process, parent becomes reader process */
386 switch(writerpid = fork()) {
388 error("fork: %s", strerror(errno));
394 tape_writer_side(p2c[0], c2p[1]);
395 error("tape writer terminated unexpectedly");
397 default: /* parent */
401 file_reader_side(c2p[0], p2c[1]);
402 error("file reader terminated unexpectedly");
411 * ========================================================================
415 int read_file P((int fd, char *handle,
416 char *host, char *disk, char *datestamp,
418 int taper_fill_buffer P((int fd, buffer_t *bp, int buflen));
419 void dumpbufs P((char *str1));
420 void dumpstatus P((buffer_t *bp));
421 int get_next_holding_file P((int fd, buffer_t *bp, char *strclosing, int rc));
422 int predict_splits P((char *filename));
423 void create_split_buffer P((char *split_diskbuffer, long fallback_splitsize, char *id_string));
424 void free_split_buffer P(());
428 * Create a buffer, either in an mmapped file or in memory, where PORT-WRITE
429 * dumps can buffer the current split chunk in case of retry.
431 void create_split_buffer(split_diskbuffer, fallback_splitsize, id_string)
432 char *split_diskbuffer;
433 long fallback_splitsize;
436 char *buff_err = NULL;
440 /* don't bother if we're not actually splitting */
443 splitbuf_wr_ptr = NULL;
448 #ifdef HAVE_SYS_MMAN_H
449 if(strcmp(split_diskbuffer, "NULL")){
450 splitbuffer_path = vstralloc(split_diskbuffer,
451 "/splitdump_buffer_XXXXXX",
454 splitbuffer_fd = mkstemp(splitbuffer_path);
456 log_add(L_INFO, "mkstemp not available, using plain open() for split buffer- make sure %s has safe permissions", split_diskbuffer);
457 splitbuffer_fd = open(splitbuffer_path, O_RDWR|O_CREAT, 0600);
459 if(splitbuffer_fd == -1){
460 buff_err = newvstralloc(buff_err, "mkstemp/open of ",
461 splitbuffer_path, "failed (",
462 strerror(errno), ")", NULL);
465 nulls = alloc(1024); /* lame */
466 memset(nulls, 0, 1024);
467 for(c = 0; c < splitsize ; c++) {
468 if(fullwrite(splitbuffer_fd, nulls, 1024) < 1024){
469 buff_err = newvstralloc(buff_err, "write to ", splitbuffer_path,
470 "failed (", strerror(errno), ")", NULL);
477 splitbuf = mmap(NULL, (size_t)splitsize*1024, PROT_READ|PROT_WRITE,
478 MAP_SHARED, splitbuffer_fd, (off_t)0);
479 if(splitbuf == (char*)-1){
480 buff_err = newvstralloc(buff_err, "mmap failed (", strerror(errno),
486 "taper: r: buffering %ldkb split chunks in mmapped file %s\n",
487 splitsize, splitbuffer_path);
488 splitbuf_wr_ptr = splitbuf;
492 buff_err = stralloc("no split_diskbuffer specified");
495 buff_err = stralloc("mman.h not available");
499 buff_err = stralloc("mmap not available");
504 Buffer split dumps in memory, if we can't use a file.
507 splitsize = fallback_splitsize;
509 "%s: using fallback split size of %dkb to buffer %s in-memory",
510 buff_err, splitsize, id_string);
511 splitbuf = alloc(splitsize * 1024);
512 splitbuf_wr_ptr = splitbuf;
516 * Free up resources that create_split_buffer eats.
518 void free_split_buffer()
520 if(splitbuffer_fd != -1){
522 #ifdef HAVE_SYS_MMAN_H
523 if(splitbuf != NULL) munmap(splitbuf, splitsize);
526 aclose(splitbuffer_fd);
529 if(unlink(splitbuffer_path) == -1){
530 log_add(L_WARNING, "Failed to unlink %s: %s",
531 splitbuffer_path, strerror(errno));
533 amfree(splitbuffer_path);
534 splitbuffer_path = NULL;
543 void file_reader_side(rdpipe, wrpipe)
547 struct cmdargs cmdargs;
549 char *filename = NULL;
550 char *hostname = NULL;
551 char *diskname = NULL;
553 char *datestamp = NULL;
554 char *split_diskbuffer = NULL;
555 char *id_string = NULL;
558 int level, fd, data_port, data_socket, wpid;
560 struct stat stat_file;
563 long fallback_splitsize = 0;
567 syncpipe_init(rdpipe, wrpipe);
569 /* must get START_TAPER before beginning */
572 cmd = getcmd(&cmdargs);
573 total_wait = stopclock();
575 if(cmd != START_TAPER || cmdargs.argc != 2) {
576 error("error [file_reader_side cmd %d argc %d]", cmd, cmdargs.argc);
579 /* pass start command on to tape writer */
581 taper_datestamp = newstralloc(taper_datestamp, cmdargs.argv[2]);
584 syncpipe_put('S', 0);
585 syncpipe_putstr(taper_datestamp);
587 /* get result of start command */
589 tok = syncpipe_get(&tmpint);
592 putresult(TAPER_OK, "\n");
594 /* start is logged in writer */
597 /* no tape, bail out */
598 result = syncpipe_getstr();
599 q = squotef("[%s]", result ? result : "(null)");
600 putresult(TAPE_ERROR, "%s\n", q);
602 log_add(L_ERROR,"no-tape [%s]", "No writable valid tape found");
604 syncpipe_put('e', 0); /* ACK error */
607 error("expected 'S' or 'E' for START-TAPER, got '%c'", tok);
610 /* process further commands */
614 cmd = getcmd(&cmdargs);
615 if(cmd != QUIT && !tape_started) {
616 error("error [file_reader_side cmd %d without tape ready]", cmd);
618 total_wait = timesadd(total_wait, stopclock());
633 mode = MODE_PORT_WRITE;
634 cmdargs.argc++; /* true count of args */
637 if(a >= cmdargs.argc) {
638 error("error [taper PORT-WRITE: not enough args: handle]");
640 handle = newstralloc(handle, cmdargs.argv[a++]);
642 if(a >= cmdargs.argc) {
643 error("error [taper PORT-WRITE: not enough args: hostname]");
645 hostname = newstralloc(hostname, cmdargs.argv[a++]);
647 if(a >= cmdargs.argc) {
648 error("error [taper PORT-WRITE: not enough args: features]");
650 am_release_feature_set(their_features);
651 their_features = am_string_to_feature(cmdargs.argv[a++]);
653 if(a >= cmdargs.argc) {
654 error("error [taper PORT-WRITE: not enough args: diskname]");
656 diskname = newstralloc(diskname, cmdargs.argv[a++]);
658 if(a >= cmdargs.argc) {
659 error("error [taper PORT-WRITE: not enough args: level]");
661 level = atoi(cmdargs.argv[a++]);
663 if(a >= cmdargs.argc) {
664 error("error [taper PORT-WRITE: not enough args: datestamp]");
666 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
668 if(a >= cmdargs.argc) {
669 error("error [taper PORT-WRITE: not enough args: splitsize]");
671 splitsize = atoi(cmdargs.argv[a++]);
673 if(a >= cmdargs.argc) {
674 error("error [taper PORT-WRITE: not enough args: split_diskbuffer]");
676 split_diskbuffer = newstralloc(split_diskbuffer, cmdargs.argv[a++]);
678 if(a >= cmdargs.argc) {
679 error("error [taper PORT-WRITE: not enough args: fallback_splitsize]");
681 fallback_splitsize = atoi(cmdargs.argv[a++]);
683 if(a != cmdargs.argc) {
684 error("error [taper file_reader_side PORT-WRITE: too many args: %d != %d]",
688 snprintf(level_str, sizeof(level_str), "%d", level);
689 id_string = newvstralloc(id_string, hostname, ":", diskname, ".",
692 create_split_buffer(split_diskbuffer, fallback_splitsize, id_string);
696 data_socket = stream_server(&data_port, -1, STREAM_BUFSIZE);
697 if(data_socket < 0) {
700 m = vstralloc("[port create failure: ",
705 putresult(TAPE_ERROR, "%s %s\n", handle, q);
710 putresult(PORT, "%d\n", data_port);
712 if((fd = stream_accept(data_socket, CONNECT_TIMEOUT,
713 -1, NETWORK_BLOCK_BYTES)) == -1) {
714 q = squote("[port connect timeout]");
715 putresult(TAPE_ERROR, "%s %s\n", handle, q);
720 expected_splits = -1;
722 while(read_file(fd,handle,hostname,diskname,datestamp,level));
740 mode = MODE_FILE_WRITE;
741 cmdargs.argc++; /* true count of args */
744 if(a >= cmdargs.argc) {
745 error("error [taper FILE-WRITE: not enough args: handle]");
747 handle = newstralloc(handle, cmdargs.argv[a++]);
749 if(a >= cmdargs.argc) {
750 error("error [taper FILE-WRITE: not enough args: filename]");
752 filename = newstralloc(filename, cmdargs.argv[a++]);
754 if(a >= cmdargs.argc) {
755 error("error [taper FILE-WRITE: not enough args: hostname]");
757 hostname = newstralloc(hostname, cmdargs.argv[a++]);
759 if(a >= cmdargs.argc) {
760 error("error [taper FILE-WRITE: not enough args: features]");
762 am_release_feature_set(their_features);
763 their_features = am_string_to_feature(cmdargs.argv[a++]);
765 if(a >= cmdargs.argc) {
766 error("error [taper FILE-WRITE: not enough args: diskname]");
768 diskname = newstralloc(diskname, cmdargs.argv[a++]);
770 if(a >= cmdargs.argc) {
771 error("error [taper FILE-WRITE: not enough args: level]");
773 level = atoi(cmdargs.argv[a++]);
775 if(a >= cmdargs.argc) {
776 error("error [taper FILE-WRITE: not enough args: datestamp]");
778 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
780 if(a >= cmdargs.argc) {
781 error("error [taper FILE-WRITE: not enough args: splitsize]");
783 splitsize = atoi(cmdargs.argv[a++]);
785 if(a != cmdargs.argc) {
786 error("error [taper file_reader_side FILE-WRITE: too many args: %d != %d]",
789 if(holdfile_name != NULL) {
790 filename = newstralloc(filename, holdfile_name);
793 if((expected_splits = predict_splits(filename)) < 0) {
796 if(stat(filename, &stat_file)!=0) {
797 q = squotef("[%s]", strerror(errno));
798 putresult(TAPE_ERROR, "%s %s\n", handle, q);
802 if((fd = open(filename, O_RDONLY)) == -1) {
803 q = squotef("[%s]", strerror(errno));
804 putresult(TAPE_ERROR, "%s %s\n", handle, q);
808 holdfile_path = stralloc(filename);
809 holdfile_path_thischunk = stralloc(filename);
810 holdfile_offset_thischunk = (off_t)0;
812 while(read_file(fd,handle,hostname,diskname,datestamp,level)){
813 if(splitsize > 0 && holdfile_path_thischunk)
814 filename = newstralloc(filename, holdfile_path_thischunk);
815 if((fd = open(filename, O_RDONLY)) == -1) {
816 q = squotef("[%s]", strerror(errno));
817 putresult(TAPE_ERROR, "%s %s\n", handle, q);
826 putresult(QUITTING, "\n");
827 fprintf(stderr,"taper: DONE [idle wait: %s secs]\n",
828 walltime_str(total_wait));
830 syncpipe_put('Q', 0); /* tell writer we're exiting gracefully */
833 if((wpid = wait(NULL)) != writerpid) {
835 "taper: writer wait returned %d instead of %d: %s\n",
836 wpid, writerpid, strerror(errno));
840 if (datestamp != NULL)
844 amfree(changer_resultstr);
846 amfree(conf_tapelist);
850 if(holdfile_name != NULL) amfree(holdfile_name);
852 malloc_size_2 = malloc_inuse(&malloc_hist_2);
854 if(malloc_size_1 != malloc_size_2) {
855 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
861 if(cmdargs.argc >= 1) {
862 q = squote(cmdargs.argv[1]);
863 } else if(cmdargs.argc >= 0) {
864 q = squote(cmdargs.argv[0]);
866 q = stralloc("(no input?)");
868 putresult(BAD_COMMAND, "%s\n", q);
874 am_release_feature_set(their_features);
877 fprintf(stderr, "TAPER AT END OF READER SIDE\n");
886 fprintf(stderr, "%s: state", str1);
887 for(i = j = 0; i < conf_tapebufs; i = j+1) {
888 v = buftable[i].status;
889 for(j = i; j < conf_tapebufs && buftable[j].status == v; j++);
891 if(i == j) fprintf(stderr, " %d:", i);
892 else fprintf(stderr, " %d-%d:", i, j);
894 case FULL: fputc('F', stderr); break;
895 case FILLING: fputc('f', stderr); break;
896 case EMPTY: fputc('E', stderr); break;
898 fprintf(stderr, "%ld", v);
911 char bt[NUM_STR_SIZE];
912 char status[NUM_STR_SIZE + 1];
917 snprintf(bt, sizeof(bt), "%d", (int)(bp-buftable));
920 case FULL: snprintf(status, sizeof(status), "F%d", bp->size);
922 case FILLING: status[0] = 'f'; status[1] = '\0'; break;
923 case EMPTY: status[0] = 'E'; status[1] = '\0'; break;
925 snprintf(status, sizeof(status), "%ld", bp->status);
929 str = vstralloc("taper: ", pn, ": [buf ", bt, ":=", status, "]", NULL);
935 Handle moving to the next chunk of holding file, if any. Returns -1 for
936 errors, 0 if there's no more file, or a positive integer for the amount of
937 stuff read that'll go into 'rc' (XXX That's fugly, maybe that should just
938 be another global. What is rc anyway, 'read count?' I keep thinking it
939 should be 'return code')
941 int get_next_holding_file(fd, bp, strclosing, rc)
947 struct stat stat_file;
953 /* see if we're fresh out of file */
954 if(file.cont_filename[0] == '\0') {
957 } else if(stat(file.cont_filename, &stat_file) != 0) {
960 strclosing = newvstralloc(strclosing,"can't stat: ",file.cont_filename,NULL);
961 } else if((fd = open(file.cont_filename,O_RDONLY)) == -1) {
964 strclosing = newvstralloc(strclosing,"can't open: ",file.cont_filename,NULL);
965 } else if((fd != save_fd) && dup2(fd, save_fd) == -1) {
968 strclosing = newvstralloc(strclosing,"can't dup2: ",file.cont_filename,NULL);
971 holdfile_path = stralloc(file.cont_filename);
973 fprintf(stderr, "taper: r: switching to next holding chunk '%s'\n", file.cont_filename);
974 num_holdfile_chunks++;
977 bp1.size = DISK_BLOCK_BYTES;
978 bp1.buffer = malloc(DISK_BLOCK_BYTES);
985 rc1 = taper_fill_buffer(fd, &bp1, DISK_BLOCK_BYTES);
988 err = (rc1 < 0) ? errno : 0;
990 strclosing = newvstralloc(strclosing,
991 "Can't read header: ",
995 parse_file_header(bp1.buffer, &file, rc1);
998 bp1.buffer = bp->buffer + rc;
1000 rc1 = taper_fill_buffer(fd, &bp1, tt_blocksize - rc);
1002 err = (rc1 < 0) ? errno : 0;
1005 strclosing = newvstralloc(strclosing,
1006 "Can't read data: ",
1022 int read_file(fd, handle, hostname, diskname, datestamp, level)
1024 char *handle, *hostname, *diskname, *datestamp;
1028 int rc, opening, closing, bufnum, need_closing, nexting;
1031 char *strclosing = NULL;
1032 char seekerrstr[STR_SIZE];
1034 int header_written = 0;
1036 dumpfile_t first_file;
1037 dumpfile_t cur_holdfile;
1038 long kbytesread = 0;
1039 int header_read = 0;
1040 char *cur_filename = NULL;
1041 int retry_from_splitbuf = 0;
1042 char *splitbuf_rd_ptr = NULL;
1046 #ifdef HAVE_LIBVTBLC
1047 static char desc[45];
1048 static char vol_date[20];
1049 static char vol_label[45];
1050 #endif /* HAVE_LIBVTBLC */
1061 /* don't break this if we're still on the same file as a previous init */
1062 if(cur_span_chunkstart <= 0){
1066 else if(mode == MODE_FILE_WRITE){
1067 memcpy(&file, save_holdfile, sizeof(dumpfile_t));
1068 memcpy(&cur_holdfile, save_holdfile, sizeof(dumpfile_t));
1072 fprintf(stderr, "taper: r: start file\n");
1076 for(bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1081 if(interactive || bufdebug) dumpstatus(bp);
1083 if(cur_span_chunkstart >= 0 && splitsize > 0){
1084 /* We're supposed to start at some later part of the file, not read the
1085 whole thing. "Seek" forward to where we want to be. */
1086 if(label) putresult(SPLIT_CONTINUE, "%s %s\n", handle, label);
1087 if(mode == MODE_FILE_WRITE && cur_span_chunkstart > 0){
1088 fprintf(stderr, "taper: r: seeking %s to " OFF_T_FMT " kb\n",
1089 holdfile_path_thischunk, holdfile_offset_thischunk);
1092 if(holdfile_offset_thischunk > maxseek){
1093 snprintf(seekerrstr, sizeof(seekerrstr), "Can't seek by " OFF_T_FMT " kb (compiled for %d-bit file offsets), recompile with large file support or set holdingdisk chunksize to <%ld Mb", holdfile_offset_thischunk, (int)(sizeof(off_t) * 8), (long)(maxseek/1024));
1094 log_add(L_ERROR, "%s", seekerrstr);
1095 fprintf(stderr, "taper: r: FATAL: %s\n", seekerrstr);
1097 syncpipe_put('X', 0);
1100 if(lseek(fd, holdfile_offset_thischunk*1024, SEEK_SET) == (off_t)-1){
1101 fprintf(stderr, "taper: r: FATAL: seek_holdfile lseek error while seeking into %s by " OFF_T_FMT "kb: %s\n", holdfile_path_thischunk, holdfile_offset_thischunk, strerror(errno));
1103 syncpipe_put('X', 0);
1107 else if(mode == MODE_PORT_WRITE){
1108 fprintf(stderr, "taper: r: re-reading split dump piece from buffer\n");
1110 retry_from_splitbuf = 1;
1111 splitbuf_rd_ptr = splitbuf;
1112 if(splitbuf_rd_ptr >= splitbuf_wr_ptr) retry_from_splitbuf = 0;
1114 if(cur_span_chunkstart > 0) header_read = 1; /* really initialized in prior run */
1117 /* tell writer to open tape */
1120 syncpipe_put('O', 0);
1121 syncpipe_putstr(datestamp);
1122 syncpipe_putstr(hostname);
1123 syncpipe_putstr(diskname);
1124 syncpipe_putint(level);
1128 /* read file in loop */
1131 tok = syncpipe_get(&bufnum);
1142 fprintf(stderr, "taper: r: got R%d\n", bufnum);
1147 syncpipe_put('C', 0);
1153 if(closing) break; /* ignore extra read tokens */
1156 if(bp->status != EMPTY || bufnum != bp-buftable) {
1157 /* XXX this SHOULD NOT HAPPEN. Famous last words. */
1158 fprintf(stderr,"taper: panic: buffer mismatch at ofs %ld:\n",
1160 if(bufnum != bp-buftable) {
1161 fprintf(stderr, " my buf %d but writer buf %d\n",
1162 (int)(bp-buftable), bufnum);
1165 fprintf(stderr,"buf %d state %s (%ld) instead of EMPTY\n",
1167 bp->status == FILLING? "FILLING" :
1168 bp->status == FULL? "FULL" : "EMPTY!?!?",
1173 dumpbufs("taper: after 1 sec");
1174 if(bp->status == EMPTY)
1175 fprintf(stderr, "taper: result now correct!\n");
1178 errstr = newstralloc(errstr,
1179 "[fatal buffer mismanagement bug]");
1181 putresult(TRYAGAIN, "%s %s\n", handle, q);
1182 cur_span_chunkstart = 0;
1184 log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1185 hostname, diskname, level, errstr);
1187 syncpipe_put('X', 0); /* X == buffer snafu, bail */
1189 tok = syncpipe_get(&bufnum);
1190 } while(tok != 'x');
1193 } /* end 'if (bf->status != EMPTY || bufnum != bp-buftable)' */
1195 bp->status = FILLING;
1196 buflen = header_read ? tt_blocksize : DISK_BLOCK_BYTES;
1197 if(interactive || bufdebug) dumpstatus(bp);
1198 if(header_written == 0 && (header_read == 1 || cur_span_chunkstart > 0)){
1199 /* for split dumpfiles, modify headers for the second - nth
1200 pieces that signify that they're continuations of the last
1202 char *cont_filename;
1203 file.type = F_SPLIT_DUMPFILE;
1204 file.partnum = num_splits + 1;
1205 file.totalparts = expected_splits;
1206 cont_filename = stralloc(file.cont_filename);
1207 file.cont_filename[0] = '\0';
1208 build_header(bp->buffer, &file, tt_blocksize);
1210 if(cont_filename[0] != '\0') {
1211 file.type = F_CONT_DUMPFILE;
1212 strncpy(file.cont_filename, cont_filename,
1213 sizeof(file.cont_filename));
1215 memcpy(&cur_holdfile, &file, sizeof(dumpfile_t));
1217 if(interactive || bufdebug) dumpstatus(bp);
1218 bp->size = tt_blocksize;
1221 amfree(cont_filename);
1223 else if(retry_from_splitbuf){
1224 /* quietly pull dump data from our in-memory cache, and the
1225 writer side need never know the wiser */
1226 memcpy(bp->buffer, splitbuf_rd_ptr, tt_blocksize);
1227 bp->size = tt_blocksize;
1230 splitbuf_rd_ptr += tt_blocksize;
1231 if(splitbuf_rd_ptr >= splitbuf_wr_ptr) retry_from_splitbuf = 0;
1233 else if((rc = taper_fill_buffer(fd, bp, buflen)) < 0) {
1236 strclosing = newvstralloc(strclosing,"Can't read data: ",NULL);
1237 syncpipe_put('C', 0);
1241 if(rc < buflen) { /* switch to next holding file */
1243 if(file.cont_filename[0] != '\0'){
1244 cur_filename = newvstralloc(cur_filename, file.cont_filename, NULL);
1246 ret = get_next_holding_file(fd, bp, strclosing, rc);
1251 memcpy(&cur_holdfile, &file, sizeof(dumpfile_t));
1258 /* rebuild the header block, which might have CONT junk */
1259 if(header_read == 0) {
1260 char *cont_filename;
1261 /* write the "real" filename if the holding-file
1263 parse_file_header(bp->buffer, &file, rc);
1264 parse_file_header(bp->buffer, &first_file, rc);
1265 cont_filename = stralloc(file.cont_filename);
1266 file.cont_filename[0] = '\0';
1268 file.type = F_SPLIT_DUMPFILE;
1270 file.totalparts = expected_splits;
1272 file.blocksize = tt_blocksize;
1273 build_header(bp->buffer, &file, tt_blocksize);
1274 kbytesread += tt_blocksize/1024; /* XXX shady */
1276 file.type = F_CONT_DUMPFILE;
1278 /* add CONT_FILENAME back to in-memory header */
1279 strncpy(file.cont_filename, cont_filename,
1280 sizeof(file.cont_filename));
1281 if(interactive || bufdebug) dumpstatus(bp);
1282 bp->size = tt_blocksize; /* output a full tape block */
1283 /* save the header, we'll need it if we jump tapes */
1284 memcpy(&cur_holdfile, &file, sizeof(dumpfile_t));
1287 amfree(cont_filename);
1290 filesize = kbytesread;
1294 fprintf(stderr,"taper: r: put W%d\n",(int)(bp-buftable));
1297 syncpipe_put('W', bp-buftable);
1301 if(kbytesread + DISK_BLOCK_BYTES/1024 >= splitsize && splitsize > 0 && !need_closing){
1303 if(mode == MODE_PORT_WRITE){
1304 splitbuf_wr_ptr = splitbuf;
1305 splitbuf_rd_ptr = splitbuf;
1306 memset(splitbuf, 0, sizeof(splitbuf));
1307 retry_from_splitbuf = 0;
1310 fprintf(stderr,"taper: r: end %s.%s.%s.%d part %d, splitting chunk that started at %ldkb after %ldkb (next chunk will start at %ldkb)\n", hostname, diskname, datestamp, level, num_splits+1, cur_span_chunkstart, kbytesread, cur_span_chunkstart+kbytesread);
1315 } /* end '(kbytesread >= splitsize && splitsize > 0)' */
1316 if(need_closing && rc <= 0) {
1317 syncpipe_put('C', 0);
1321 kbytesread += rc/1024;
1322 } /* end the 'if(!closing)' (successful buffer fill) */
1327 syncpipe_put('e', 0); /* ACK error */
1329 str = syncpipe_getstr();
1330 errstr = newvstralloc(errstr, "[", str ? str : "(null)", "]", NULL);
1336 /* we'll be restarting this chunk on the next tape */
1337 if(mode == MODE_FILE_WRITE){
1341 putresult(SPLIT_NEEDNEXT, "%s %ld\n", handle, cur_span_chunkstart);
1342 log_add(L_INFO, "continuing %s:%s.%d on new tape from %ldkb mark: %s",
1343 hostname, diskname, level, cur_span_chunkstart, errstr);
1347 /* restart the entire dump (failure propagates to driver) */
1349 putresult(TRYAGAIN, "%s %s\n", handle, q);
1350 cur_span_chunkstart = 0;
1351 log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1352 hostname, diskname, level, errstr);
1356 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1357 log_add(L_FAIL, "%s %s %s %d [out of tape]",
1358 hostname, diskname, datestamp, level);
1359 log_add(L_ERROR,"no-tape [%s]", "No more writable valid tape found");
1370 cur_span_chunkstart += kbytesread; /* XXX possibly wrong */
1371 holdfile_name = newvstralloc(holdfile_name, cur_filename, NULL);
1374 if(cur_filename != NULL) amfree(cur_filename);
1378 str = syncpipe_getstr();
1379 label = newstralloc(label, str ? str : "(null)");
1381 str = syncpipe_getstr();
1382 filenum = atoi(str ? str : "-9876"); /* ??? */
1384 fprintf(stderr, "taper: reader-side: got label %s filenum %d\n",
1388 /* we'll need that file descriptor if we're gonna write more */
1393 runtime = stopclock();
1394 if(nexting) startclock();
1397 errstr = newvstralloc(errstr,
1398 "[input: ", strclosing, ": ",
1399 strerror(err), "]", NULL);
1403 errstr = newvstralloc(errstr,
1404 "[input: ", strerror(err), "]",
1407 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1411 log_add(L_FAIL, "%s %s %s.%d %d %s", hostname, diskname,
1412 datestamp, num_splits, level, errstr);
1415 log_add(L_FAIL, "%s %s %s %d %s",
1416 hostname, diskname, datestamp, level, errstr);
1418 str = syncpipe_getstr(); /* reap stats */
1422 char kb_str[NUM_STR_SIZE];
1423 char kps_str[NUM_STR_SIZE];
1426 rt = runtime.r.tv_sec+runtime.r.tv_usec/1000000.0;
1427 curdump_rt = timesadd(runtime, curdump_rt);
1428 snprintf(kb_str, sizeof(kb_str), "%ld", filesize);
1429 snprintf(kps_str, sizeof(kps_str), "%3.1f",
1430 rt ? filesize / rt : 0.0);
1431 str = syncpipe_getstr();
1432 errstr = newvstralloc(errstr,
1433 "[sec ", walltime_str(runtime),
1440 if (splitsize == 0) { /* Ordinary dump */
1441 if(first_file.is_partial) {
1442 putresult(PARTIAL, "%s %s %d %s\n",
1443 handle, label, filenum, q);
1444 log_add(L_PARTIAL, "%s %s %s %d %s",
1445 hostname, diskname, datestamp, level, errstr);
1448 putresult(DONE, "%s %s %d %s\n",
1449 handle, label, filenum, q);
1450 log_add(L_SUCCESS, "%s %s %s %d %s",
1451 hostname, diskname, datestamp, level, errstr);
1453 } else { /* Chunked dump */
1455 if(mode == MODE_FILE_WRITE){
1456 holdfile_path_thischunk = stralloc(holdfile_path);
1457 holdfile_offset_thischunk = (lseek(fd, (off_t)0, SEEK_CUR))/1024;
1459 save_holdfile = alloc(sizeof(dumpfile_t));
1461 memcpy(save_holdfile, &cur_holdfile,sizeof(dumpfile_t));
1463 log_add(L_CHUNK, "%s %s %s %d %d %s", hostname, diskname,
1464 datestamp, num_splits, level, errstr);
1465 if(!nexting){ /* split dump complete */
1466 rt =curdump_rt.r.tv_sec+curdump_rt.r.tv_usec/1000000.0;
1467 snprintf(kb_str, sizeof(kb_str), "%ld",
1468 filesize+cur_span_chunkstart);
1469 snprintf(kps_str, sizeof(kps_str), "%3.1f",
1470 rt ? (filesize+cur_span_chunkstart) / rt : 0.0);
1472 errstr = newvstralloc(errstr,
1473 "[sec ", walltime_str(curdump_rt),
1480 putresult(DONE, "%s %s %d %s\n", handle, label,
1482 log_add(L_CHUNKSUCCESS, "%s %s %s %d %s",
1483 hostname, diskname, datestamp, level, errstr);
1484 amfree(save_holdfile);
1485 amfree(holdfile_path_thischunk);
1493 expected_splits = 0;
1494 amfree(holdfile_name);
1496 cur_span_chunkstart = 0;
1497 curdump_rt = times_zero;
1502 #ifdef HAVE_LIBVTBLC
1504 * We have 44 characters available for the label string:
1505 * use max 20 characters for hostname
1506 * max 20 characters for diskname
1507 * (it could contain a samba share or dos path)
1510 memset(desc, '\0', 45);
1512 strncpy(desc, hostname, 20);
1514 if ((len = strlen(hostname)) <= 20) {
1515 memset(desc + len, ' ', 1);
1519 memset(desc + 20, ' ', 1);
1523 strncpy(desc + offset, diskname, 20);
1525 if ((len = strlen(diskname)) <= 20) {
1526 memset(desc + offset + len, ' ', 1);
1527 offset = offset + len + 1;
1530 memset(desc + offset + 20, ' ', 1);
1531 offset = offset + 21;
1534 sprintf(desc + offset, "%i", level);
1536 strncpy(vol_label, desc, 44);
1537 fprintf(stderr, "taper: added vtbl label string %i: \"%s\"\n",
1538 filenum, vol_label);
1541 /* pass label string on to tape writer */
1542 syncpipe_put('L', filenum);
1543 syncpipe_putstr(vol_label);
1546 * reformat datestamp for later use with set_date from vtblc
1548 strptime(datestamp, "%Y%m%d", &backup_time);
1549 strftime(vol_date, 20, "%T %D", &backup_time);
1551 "taper: reformatted vtbl date string: \"%s\"->\"%s\"\n",
1555 /* pass date string on to tape writer */
1556 syncpipe_put('D', filenum);
1557 syncpipe_putstr(vol_date);
1559 #endif /* HAVE_LIBVTBLC */
1561 /* reset stuff that assumes we're on a new file */
1568 syncpipe_put('O', 0);
1569 syncpipe_putstr(datestamp);
1570 syncpipe_putstr(hostname);
1571 syncpipe_putstr(diskname);
1572 syncpipe_putint(level);
1573 for(bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1590 int taper_fill_buffer(fd, bp, buflen)
1598 curptr = bp->buffer;
1602 cnt = fullread(fd, curptr, spaceleft);
1605 if(interactive) fputs("r0", stderr);
1607 case -1: /* error on read, punt */
1608 if(interactive) fputs("rE", stderr);
1611 if(mode == MODE_PORT_WRITE && splitsize > 0){
1612 memcpy(splitbuf_wr_ptr, curptr, (size_t)cnt);
1613 splitbuf_wr_ptr += cnt;
1620 if(interactive) fputs("R", stderr);
1624 /* Given a dumpfile in holding, determine its size and figure out how many
1625 * times we'd have to split it.
1627 int predict_splits(filename)
1632 long adj_splitsize = splitsize - DISK_BLOCK_BYTES/1024;
1634 if(splitsize <= 0) return(0);
1636 if(adj_splitsize <= 0){
1637 error("Split size must be > %ldk", DISK_BLOCK_BYTES/1024);
1640 /* should only calculuate this once, not on retries etc */
1641 if(expected_splits != 0) return(expected_splits);
1643 total_kb = size_holding_files(filename, 1);
1646 fprintf(stderr, "taper: r: %ld kb holding file makes no sense, not precalculating splits\n", total_kb);
1651 fprintf(stderr, "taper: r: Total dump size should be %ldkb, chunk size is %ldkb\n", total_kb, splitsize);
1654 splits = total_kb/adj_splitsize;
1655 if(total_kb % adj_splitsize) splits++;
1658 fprintf(stderr, "taper: r: Expecting to split into %d parts \n", splits);
1665 * ========================================================================
1669 times_t idlewait, rdwait, wrwait, fmwait;
1671 double total_tape_used;
1674 void write_file P((void));
1675 int write_buffer P((buffer_t *bp));
1677 void tape_writer_side(getp, putp)
1689 #ifdef HAVE_LIBVTBLC
1692 #endif /* HAVE_LIBVTBLC */
1694 procname = "writer";
1695 syncpipe_init(getp, putp);
1698 idlewait = times_zero;
1702 tok = syncpipe_get(&tmpint);
1703 idlewait = timesadd(idlewait, stopclock());
1704 if(tok != 'S' && tok != 'Q' && !tape_started) {
1705 error("writer: token '%c' before start", tok);
1709 case 'S': /* start-tape */
1711 error("writer: multiple start requests");
1713 str = syncpipe_getstr();
1714 if(!first_tape(str ? str : "bad-datestamp")) {
1716 tapefd_close(tape_fd);
1719 syncpipe_put('E', 0);
1720 syncpipe_putstr(errstr);
1721 /* wait for reader to acknowledge error */
1723 tok = syncpipe_get(&tmpint);
1725 error("writer: got '%c' unexpectedly after error", tok);
1727 } while(tok != 'e');
1729 syncpipe_put('S', 0);
1736 case 'O': /* open-output */
1737 datestamp = syncpipe_getstr();
1738 tapefd_setinfo_datestamp(tape_fd, datestamp);
1740 hostname = syncpipe_getstr();
1741 tapefd_setinfo_host(tape_fd, hostname);
1743 diskname = syncpipe_getstr();
1744 tapefd_setinfo_disk(tape_fd, diskname);
1746 level = syncpipe_getint();
1747 tapefd_setinfo_level(tape_fd, level);
1751 #ifdef HAVE_LIBVTBLC
1752 case 'L': /* read vtbl label */
1754 vol_label = syncpipe_getstr();
1755 fprintf(stderr, "taper: read label string \"%s\" from pipe\n",
1757 strncpy(vtbl_entry[vtbl_no].label, vol_label, 45);
1760 case 'D': /* read vtbl date */
1762 vol_date = syncpipe_getstr();
1763 fprintf(stderr, "taper: read date string \"%s\" from pipe\n",
1765 strncpy(vtbl_entry[vtbl_no].date, vol_date, 20);
1767 #endif /* HAVE_LIBVTBLC */
1770 end_tape(0); /* XXX check results of end tape ?? */
1772 amfree(taper_datestamp);
1775 amfree(changer_resultstr);
1777 amfree(conf_tapelist);
1779 amfree(config_name);
1781 malloc_size_2 = malloc_inuse(&malloc_hist_2);
1783 if(malloc_size_1 != malloc_size_2) {
1784 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
1798 int full_buffers, i, bufnum;
1800 char number[NUM_STR_SIZE];
1801 char *rdwait_str, *wrwait_str, *fmwait_str;
1804 rdwait = wrwait = times_zero;
1812 fprintf(stderr, "taper: w: start file\n");
1817 * Tell the reader that the tape is open, and give it all the buffers.
1819 syncpipe_put('O', 0);
1820 for(i = 0; i < conf_tapebufs; i++) {
1822 fprintf(stderr, "taper: w: put R%d\n", i);
1825 syncpipe_put('R', i);
1829 * We write the filemark at the start of the file rather than at the end,
1830 * so that it can proceed in parallel with the reader's initial filling
1831 * up of the buffers.
1835 if(!write_filemark())
1837 fmwait = stopclock();
1846 * At the start of the file, or if the input can't keep up with the
1847 * tape, we enter STOPPED mode, which waits for most of the buffers
1848 * to fill up before writing to tape. This maximizes the amount of
1849 * data written in chunks to the tape drive, minimizing the number
1850 * of starts/stops, which in turn saves tape and time.
1853 if(interactive) fputs("[WS]", stderr);
1855 while(full_buffers < conf_tapebufs - THRESHOLD) {
1856 tok = syncpipe_get(&bufnum);
1857 if(tok != 'W') break;
1859 fprintf(stderr,"taper: w: got W%d\n",bufnum);
1864 rdwait = timesadd(rdwait, stopclock());
1869 * We start output when sufficient buffers have filled up, or at
1870 * end-of-file, whichever comes first. Here we drain all the buffers
1871 * that were waited on in STOPPED mode. If more full buffers come
1872 * in, then we will be STREAMING.
1875 while(full_buffers) {
1876 if(tt_file_pad && bp->size < tt_blocksize) {
1877 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
1878 bp->size = tt_blocksize;
1880 if(!write_buffer(bp)) goto tape_error;
1888 * With any luck, the input source is faster than the tape drive. In
1889 * this case, full buffers will appear in the circular queue faster
1890 * than we can write them, so the next buffer in the queue will always
1891 * be marked FULL by the time we get to it. If so, we'll stay in
1894 * On the other hand, if we catch up to the input and thus would have
1895 * to wait for buffers to fill, we are then STOPPED again.
1898 while(tok == 'W' && bp->status == FULL) {
1899 tok = syncpipe_get(&bufnum);
1902 fprintf(stderr,"taper: w: got W%d\n",bufnum);
1905 if(bufnum != bp-buftable) {
1907 "taper: tape-writer: my buf %d reader buf %d\n",
1908 (int)(bp-buftable), bufnum);
1910 syncpipe_put('E', 0);
1911 syncpipe_putstr("writer-side buffer mismatch");
1914 if(tt_file_pad && bp->size < tt_blocksize) {
1915 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
1916 bp->size = tt_blocksize;
1918 if(!write_buffer(bp)) goto tape_error;
1924 goto reader_buffer_snafu;
1926 error("writer-side not expecting token: %c", tok);
1928 } while(tok == 'W');
1930 /* got close signal from reader, acknowledge it */
1933 goto reader_buffer_snafu;
1936 syncpipe_put('C', 0);
1938 /* tell reader the tape and file number */
1940 syncpipe_putstr(label);
1941 snprintf(number, sizeof(number), "%d", filenum);
1942 syncpipe_putstr(number);
1944 snprintf(number, sizeof(number), "%ld", total_writes);
1945 rdwait_str = stralloc(walltime_str(rdwait));
1946 wrwait_str = stralloc(walltime_str(wrwait));
1947 fmwait_str = stralloc(walltime_str(fmwait));
1948 errstr = newvstralloc(errstr,
1950 " writers ", number,
1951 " rdwait ", rdwait_str,
1952 " wrwait ", wrwait_str,
1953 " filemark ", fmwait_str,
1959 syncpipe_putstr(errstr);
1961 /* XXX go to next tape if past tape size? */
1966 /* got tape error */
1967 if(next_tape(1)) syncpipe_put('T', 0); /* next tape in place, try again */
1968 else syncpipe_put('E', 0); /* no more tapes, fail */
1969 syncpipe_putstr(errstr);
1972 /* wait for reader to acknowledge error */
1974 tok = syncpipe_get(&tmpint);
1975 if(tok != 'W' && tok != 'C' && tok != 'e')
1976 error("writer: got '%c' unexpectedly after error", tok);
1977 } while(tok != 'e');
1980 reader_buffer_snafu:
1981 syncpipe_put('x', 0);
1985 int write_buffer(bp)
1990 assert(bp->status == FULL);
1993 rc = tapefd_write(tape_fd, bp->buffer, bp->size);
1994 if(rc == bp->size) {
1995 #if defined(NEED_RESETOFS)
1996 static double tape_used_modulus_2gb = 0;
1999 * If the next write will go over the 2 GByte boundary, reset
2000 * the kernel concept of where we are to make sure it does not
2003 tape_used_modulus_2gb += (double)rc;
2004 if(tape_used_modulus_2gb + (double)rc > (double)0x7fffffff) {
2005 tape_used_modulus_2gb = 0;
2006 tapefd_resetofs(tape_fd);
2009 wrwait = timesadd(wrwait, stopclock());
2011 total_tape_used += (double)rc;
2013 if(interactive || bufdebug) dumpstatus(bp);
2014 if(interactive) fputs("W", stderr);
2017 fprintf(stderr, "taper: w: put R%d\n", (int)(bp-buftable));
2020 syncpipe_put('R', bp-buftable);
2023 errstr = newvstralloc(errstr,
2025 (rc != -1) ? "short write" : strerror(errno),
2027 wrwait = timesadd(wrwait, stopclock());
2028 if(interactive) fputs("[WE]", stderr);
2037 REMOVE_SHARED_MEMORY();
2042 * Cleanup shared memory segments
2045 signal_handler(int signum)
2047 log_add(L_INFO, "Received signal %d", signum);
2054 * Installing signal handlers for signal whose default action is
2055 * process termination so that we can clean up shared memory
2059 install_signal_handlers(void)
2061 struct sigaction act;
2063 act.sa_handler = signal_handler;
2065 sigemptyset(&act.sa_mask);
2067 signal(SIGPIPE, SIG_IGN);
2069 if (sigaction(SIGINT, &act, NULL) != 0) {
2070 error("taper: couldn't install SIGINT handler [%s]", strerror(errno));
2073 if (sigaction(SIGHUP, &act, NULL) != 0) {
2074 error("taper: couldn't install SIGHUP handler [%s]", strerror(errno));
2077 if (sigaction(SIGTERM, &act, NULL) != 0) {
2078 error("taper: couldn't install SIGTERM handler [%s]", strerror(errno));
2081 if (sigaction(SIGUSR1, &act, NULL) != 0) {
2082 error("taper: couldn't install SIGUSR1 handler [%s]", strerror(errno));
2085 if (sigaction(SIGUSR2, &act, NULL) != 0) {
2086 error("taper: couldn't install SIGUSR2 handler [%s]", strerror(errno));
2089 if (sigaction(SIGALRM, &act, NULL) != 0) {
2090 error("taper: couldn't install SIGALRM handler [%s]", strerror(errno));
2096 * ========================================================================
2097 * SHARED-MEMORY BUFFER SUBSYSTEM
2105 char *attach_buffers(size)
2110 shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0700);
2115 result = (char *)shmat(shmid, (SHM_ARG_TYPE *)NULL, 0);
2117 if(result == (char *)-1) {
2118 int save_errno = errno;
2122 error("shmat: %s", strerror(errno));
2129 void detach_buffers(bufp)
2132 if ((bufp != NULL) &&
2133 (shmdt((SHM_ARG_TYPE *)bufp) == -1)) {
2134 error("shmdt: %s", strerror(errno));
2138 void destroy_buffers()
2140 if(shmid == -1) return; /* nothing to destroy */
2141 if(shmctl(shmid, IPC_RMID, NULL) == -1) {
2142 error("shmctl: %s", strerror(errno));
2149 #ifdef HAVE_SYS_MMAN_H
2150 #include <sys/mman.h>
2154 # ifdef MAP_ANONYMOUS /* OSF/1-style */
2155 # define MAP_ANON MAP_ANONYMOUS
2156 # else /* SunOS4-style */
2158 # define ZERO_FILE "/dev/zero"
2163 unsigned int saved_size;
2165 char *attach_buffers(size)
2171 shmfd = open(ZERO_FILE, O_RDWR);
2173 error("attach_buffers: could not open %s: %s",
2180 shmbuf = (char *) mmap((void *) 0,
2182 PROT_READ|PROT_WRITE,
2183 MAP_ANON|MAP_SHARED,
2189 void detach_buffers(bufp)
2192 if ((bufp != NULL) &&
2193 (munmap((void *)bufp, saved_size) == -1)) {
2194 error("detach_buffers: munmap: %s", strerror(errno));
2201 void destroy_buffers()
2206 #error: must define either HAVE_SYSVSHM or HAVE_MMAP!
2213 * ========================================================================
2214 * SYNC-PIPE SUBSYSTEM
2218 int getpipe, putpipe;
2220 void syncpipe_init(rd, wr)
2227 char syncpipe_get(intp)
2231 char buf[sizeof(char) + sizeof(int)];
2233 rc = fullread(getpipe, buf, sizeof(buf));
2234 if(rc == 0) /* EOF */
2235 error("syncpipe_get: %c: unexpected EOF", *procname);
2237 error("syncpipe_get: %c: %s", *procname, strerror(errno));
2238 else if(rc != sizeof(buf))
2239 error("syncpipe_get: %s", "short read");
2241 if(bufdebug && *buf != 'R' && *buf != 'W') {
2242 fprintf(stderr,"taper: %c: getc %c\n",*procname,*buf);
2246 memcpy(intp, &buf[1], sizeof(int));
2250 int syncpipe_getint()
2254 if ((rc = fullread(getpipe, &i, sizeof(i))) != sizeof(i))
2255 error("syncpipe_getint: %s", rc < 0 ? strerror(errno) : "short read");
2261 char *syncpipe_getstr()
2266 if((len = syncpipe_getint()) <= 0) {
2267 error("syncpipe_getstr: Protocol error - Invalid length (%d)", len);
2273 if ((rc = fullread(getpipe, str, len)) != len) {
2274 error("syncpipe_getstr: %s", rc < 0 ? strerror(errno) : "short read");
2282 void syncpipe_put(chi, intval)
2286 char buf[sizeof(char) + sizeof(int)];
2289 memcpy(&buf[1], &intval, sizeof(int));
2290 if(bufdebug && buf[0] != 'R' && buf[0] != 'W') {
2291 fprintf(stderr,"taper: %c: putc %c\n",*procname,buf[0]);
2295 if (fullwrite(putpipe, buf, sizeof(buf)) < 0)
2296 error("syncpipe_put: %s", strerror(errno));
2299 void syncpipe_putint(i)
2303 if (fullwrite(putpipe, &i, sizeof(i)) < 0)
2304 error("syncpipe_putint: %s", strerror(errno));
2307 void syncpipe_putstr(str)
2312 n = strlen(str)+1; /* send '\0' as well */
2314 if (fullwrite(putpipe, str, n) < 0)
2315 error("syncpipe_putstr: %s", strerror(errno));
2320 * ========================================================================
2321 * TAPE MANIPULATION SUBSYSTEM
2325 /* local functions */
2326 int label_tape P((void));
2330 char *conf_tapelist_old = NULL;
2332 static int first_call = 1;
2338 if (taper_scan(NULL, &label, ×tamp, &error_msg, &tapedev) < 0) {
2339 fprintf(stderr, "%s\n", error_msg);
2340 errstr = newstralloc(errstr, error_msg);
2346 s = error_msg; r = NULL;
2347 while((s=strstr(s,"slot "))) { s += 5; r=s; };
2352 if((tape_fd = tape_open(tapedev, O_WRONLY)) == -1) {
2353 if(errno == EACCES) {
2354 errstr = newstralloc(errstr,
2355 "writing label: tape is write protected");
2357 errstr = newstralloc2(errstr,
2358 "writing label: ", strerror(errno));
2363 tapefd_setinfo_length(tape_fd, tt->length);
2365 tapefd_setinfo_datestamp(tape_fd, taper_datestamp);
2366 tapefd_setinfo_disk(tape_fd, label);
2367 result = tapefd_wrlabel(tape_fd, taper_datestamp, label, tt_blocksize);
2368 if(result != NULL) {
2369 errstr = newstralloc(errstr, result);
2374 fprintf(stderr, "taper: slot: %d wrote label `%s' date `%s'\n", slot,
2375 label, taper_datestamp);
2378 fprintf(stderr, "taper: wrote label `%s' date `%s'\n", label,
2383 #ifdef HAVE_LIBVTBLC
2384 /* store time for the first volume entry */
2386 tape_timep = localtime(&raw_time);
2387 strftime(start_datestr, 20, "%T %D", tape_timep);
2388 fprintf(stderr, "taper: got vtbl start time: %s\n", start_datestr);
2390 #endif /* HAVE_LIBVTBLC */
2392 if (strcmp(label, FAKE_LABEL) != 0) {
2395 conf_tapelist_old = stralloc2(conf_tapelist, ".yesterday");
2397 char cur_str[NUM_STR_SIZE];
2399 snprintf(cur_str, sizeof(cur_str), "%d", cur_tape - 1);
2400 conf_tapelist_old = vstralloc(conf_tapelist,
2401 ".today.", cur_str, NULL);
2403 if(write_tapelist(conf_tapelist_old)) {
2404 error("could not write tapelist: %s", strerror(errno));
2406 amfree(conf_tapelist_old);
2408 remove_tapelabel(label);
2409 add_tapelabel(atoi(taper_datestamp), label);
2410 if(write_tapelist(conf_tapelist)) {
2411 error("could not write tapelist: %s", strerror(errno));
2415 log_add(L_START, "datestamp %s label %s tape %d",
2416 taper_datestamp, label, cur_tape);
2417 if (first_call && strcmp(label, FAKE_LABEL) == 0) {
2419 log_add(L_WARNING, "tapedev is %s, dumps will be thrown away", tapedev);
2422 total_tape_used=0.0;
2428 int first_tape(new_datestamp)
2429 char *new_datestamp;
2431 if((have_changer = changer_init()) < 0) {
2432 error("changer initialization failed: %s", strerror(errno));
2436 taper_datestamp = newstralloc(taper_datestamp, new_datestamp);
2445 int next_tape(writerror)
2448 end_tape(writerror);
2450 if(++cur_tape >= runtapes)
2462 int end_tape(writerror)
2469 log_add(L_INFO, "tape %s kb %ld fm %d %s",
2471 (long) ((total_tape_used+1023.0) / 1024.0),
2473 writerror? errstr : "[OK]");
2475 fprintf(stderr, "taper: writing end marker. [%s %s kb %ld fm %d]\n",
2477 writerror? "ERR" : "OK",
2478 (long) ((total_tape_used+1023.0) / 1024.0),
2482 if(! write_filemark()) {
2487 result = tapefd_wrendmark(tape_fd, taper_datestamp, tt_blocksize);
2488 if(result != NULL) {
2489 errstr = newstralloc(errstr, result);
2496 #ifdef HAVE_LINUX_ZFTAPE_H
2497 if (tape_fd >= 0 && is_zftape(tapedev) == 1) {
2498 /* rewind the tape */
2500 if(tapefd_rewind(tape_fd) == -1 ) {
2501 errstr = newstralloc2(errstr, "rewinding tape: ", strerror(errno));
2505 /* close the tape */
2507 if(tapefd_close(tape_fd) == -1) {
2508 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
2514 #ifdef HAVE_LIBVTBLC
2515 /* update volume table */
2516 fprintf(stderr, "taper: updating volume table ...\n");
2519 if ((tape_fd = raw_tape_open(rawtapedev, O_RDWR)) == -1) {
2520 if(errno == EACCES) {
2521 errstr = newstralloc(errstr,
2522 "updating volume table: tape is write protected");
2524 errstr = newstralloc2(errstr,
2525 "updating volume table: ",
2531 /* read volume table */
2532 if ((num_volumes = read_vtbl(tape_fd, volumes, vtbl_buffer,
2533 &first_seg, &last_seg)) == -1 ) {
2534 errstr = newstralloc2(errstr,
2535 "reading volume table: ",
2540 /* set volume label and date for first entry */
2542 if(set_label(label, volumes, num_volumes, vtbl_no)){
2543 errstr = newstralloc2(errstr,
2544 "setting label for entry 1: ",
2549 /* date of start writing this tape */
2550 if (set_date(start_datestr, volumes, num_volumes, vtbl_no)){
2551 errstr = newstralloc2(errstr,
2552 "setting date for entry 1: ",
2557 /* set volume labels and dates for backup files */
2558 for (vtbl_no = 1; vtbl_no <= num_volumes - 2; vtbl_no++){
2559 fprintf(stderr,"taper: label %i: %s, date %s\n",
2561 vtbl_entry[vtbl_no].label,
2562 vtbl_entry[vtbl_no].date);
2564 if(set_label(vtbl_entry[vtbl_no].label,
2565 volumes, num_volumes, vtbl_no)){
2566 errstr = newstralloc2(errstr,
2567 "setting label for entry i: ",
2572 if(set_date(vtbl_entry[vtbl_no].date,
2573 volumes, num_volumes, vtbl_no)){
2574 errstr = newstralloc2(errstr,
2575 "setting date for entry i: ",
2581 /* set volume label and date for last entry */
2582 vtbl_no = num_volumes - 1;
2583 if(set_label("AMANDA Tape End", volumes, num_volumes, vtbl_no)){
2584 errstr = newstralloc2(errstr,
2585 "setting label for last entry: ",
2590 datestr = NULL; /* take current time */
2591 if (set_date(datestr, volumes, num_volumes, vtbl_no)){
2592 errstr = newstralloc2(errstr,
2593 "setting date for last entry 1: ",
2598 /* write volume table back */
2599 if (write_vtbl(tape_fd, volumes, vtbl_buffer, num_volumes, first_seg,
2600 op_mode == trunc)) {
2601 errstr = newstralloc2(errstr,
2602 "writing volume table: ",
2608 fprintf(stderr, "taper: updating volume table: done.\n");
2610 #endif /* HAVE_LIBVTBLC */
2612 #endif /* !HAVE_LINUX_ZFTAPE_H */
2614 /* close the tape and let the OS write the final filemarks */
2618 if(tape_fd >= 0 && tapefd_close(tape_fd) == -1 && ! writerror) {
2619 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
2629 int write_filemark()
2631 if(tapefd_weof(tape_fd, 1) == -1) {
2632 errstr = newstralloc2(errstr, "writing filemark: ", strerror(errno));