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.144 2006/08/24 11:23:32 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];
64 static time_t raw_time;
65 static struct tm tape_time;
66 static struct tm backup_time;
67 static 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 static off_t splitsize = (off_t)0; /* max size of dumpfile before split (Kb) */
80 static off_t mmap_splitsize = (off_t)0;
81 static char *mmap_filename = NULL;
82 static char *mmap_splitbuf = NULL;
83 static char *mem_splitbuf = NULL;
84 static char *splitbuf = NULL;
85 static off_t mem_splitsize = (off_t)0;
86 static char *splitbuf_wr_ptr = NULL; /* the number of Kb we've written into splitbuf */
87 int orig_holdfile = -1;
89 /* NBUFS replaced by conf_tapebufs */
90 /* #define NBUFS 20 */
91 static int conf_tapebufs;
93 static off_t maxseek = (off_t)1 << ((SIZEOF(off_t) * 8) - 11);
95 static char *holdfile_path = NULL;
96 static char *holdfile_path_thischunk = NULL;
97 static int num_holdfile_chunks = 0;
98 static off_t holdfile_offset_thischunk = (off_t)0;
99 static int mmap_splitbuffer_fd = -1;
102 #define MODE_FILE_WRITE 1
103 #define MODE_PORT_WRITE 2
105 static mode_t mode = MODE_NONE;
107 /* This is now the number of empties, not full bufs */
110 #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(int main_argc, char **main_argv);
127 void file_reader_side(int rdpipe, int wrpipe);
128 void tape_writer_side(int rdpipe, int wrpipe);
129 void put_syncpipe_fault_result(char *handle);
131 /* shared-memory routines */
132 char *attach_buffers(size_t size);
133 void detach_buffers(char *bufp);
134 void destroy_buffers(void);
135 #define REMOVE_SHARED_MEMORY() \
136 detach_buffers(buffers); \
137 if (strcmp(procname, "reader") == 0) { \
141 /* synchronization pipe routines */
142 void syncpipe_init(int rd, int wr);
143 void syncpipe_read_error(ssize_t rc, ssize_t expected);
144 void syncpipe_write_error(ssize_t rc, ssize_t expected);
145 int syncpipe_get(int *intp);
146 int syncpipe_getint(void);
147 char *syncpipe_getstr(void);
148 int syncpipe_put(int ch, int intval);
149 int syncpipe_putint(int i);
150 int syncpipe_putstr(const char *str);
152 /* tape manipulation subsystem */
153 int first_tape(char *new_datestamp);
154 int next_tape(int writerr);
155 int end_tape(int writerr);
156 int write_filemark(void);
159 int seek_holdfile(int fd, buffer_t *bp, off_t kbytes);
161 /* signal handling */
162 static void install_signal_handlers(void);
163 static void signal_handler(int);
166 static void cleanup(void);
169 * ========================================================================
182 char *buffers = NULL;
183 buffer_t *buftable = NULL;
186 char *procname = "parent";
188 char *taper_timestamp = NULL;
193 char *tapedev = NULL;
194 char *tapetype = NULL;
195 tapetype_t *tt = NULL;
197 size_t tt_blocksize_kb;
200 static unsigned long malloc_hist_1, malloc_size_1;
201 static unsigned long malloc_hist_2, malloc_size_2;
203 dumpfile_t *save_holdfile = NULL;
204 off_t cur_span_chunkstart = (off_t)0; /* start of current split dump chunk (Kb) */
207 int expected_splits = 0;
208 int num_holdfiles = 0;
211 am_feature_t *their_features = NULL;
213 int runtapes, cur_tape, have_changer, tapedays;
214 char *labelstr, *conf_tapelist;
217 int first_seg, last_seg;
218 #endif /* HAVE_LIBVTBLC */
221 * ========================================================================
230 int p2c[2], c2p[2]; /* parent-to-child, child-to-parent pipes */
237 int new_argc, my_argc;
238 char **new_argv, **my_argv;
246 /* Don't die when child closes pipe */
247 signal(SIGPIPE, SIG_IGN);
249 malloc_size_1 = malloc_inuse(&malloc_hist_1);
251 parse_server_conf(main_argc, main_argv, &new_argc, &new_argv);
255 fprintf(stderr, "%s: pid %ld executable %s version %s\n",
256 get_pname(), (long) getpid(), my_argv[0], version());
257 dbprintf(("%s: pid %ld executable %s version %s\n",
258 get_pname(), (long) getpid(), my_argv[0], version()));
261 if (my_argc > 1 && my_argv[1][0] != '-') {
262 config_name = stralloc(my_argv[1]);
263 config_dir = vstralloc(CONFIG_DIR, "/", my_argv[1], "/", NULL);
267 char my_cwd[STR_SIZE];
269 if (getcwd(my_cwd, SIZEOF(my_cwd)) == NULL) {
270 error("cannot determine current working directory");
273 config_dir = stralloc2(my_cwd, "/");
274 if ((config_name = strrchr(my_cwd, '/')) != NULL) {
275 config_name = stralloc(config_name + 1);
281 install_signal_handlers();
284 /* print prompts and debug messages if running interactive */
286 interactive = (my_argc > 1 && strcmp(my_argv[1],"-t") == 0);
288 erroutput_type = ERR_INTERACTIVE;
290 erroutput_type = ERR_AMANDALOG;
291 set_logerror(logerror);
294 free_new_argv(new_argc, new_argv);
296 conffile = stralloc2(config_dir, CONFFILE_NAME);
297 if (read_conffile(conffile)) {
298 error("errors processing config file \"%s\"", conffile);
303 dbrename(config_name, DBG_SUBDIR_SERVER);
305 report_bad_conf_arg();
307 conf_tapelist = getconf_str(CNF_TAPELIST);
308 if (*conf_tapelist == '/') {
309 conf_tapelist = stralloc(conf_tapelist);
311 conf_tapelist = stralloc2(config_dir, conf_tapelist);
313 if (read_tapelist(conf_tapelist)) {
314 error("could not load tapelist \"%s\"", conf_tapelist);
318 tapedev = stralloc(getconf_str(CNF_TAPEDEV));
319 tapetype = getconf_str(CNF_TAPETYPE);
320 tt = lookup_tapetype(tapetype);
322 rawtapedev = stralloc(getconf_str(CNF_RAWTAPEDEV));
323 #endif /* HAVE_LIBVTBLC */
324 tapedays = getconf_int(CNF_TAPECYCLE);
325 labelstr = getconf_str(CNF_LABELSTR);
327 runtapes = getconf_int(CNF_RUNTAPES);
330 conf_tapebufs = getconf_int(CNF_TAPEBUFS);
332 tt_blocksize_kb = (size_t)tapetype_get_blocksize(tt);
333 tt_blocksize = tt_blocksize_kb * 1024;
334 tt_file_pad = tapetype_get_file_pad(tt);
337 fprintf(stderr,"taper: running in interactive test mode\n");
338 dbprintf(("taper: running in interactive test mode\n"));
342 /* create read/write syncronization pipes */
345 error("creating sync pipes: %s", strerror(errno));
349 error("creating sync pipes: %s", strerror(errno));
353 /* create shared memory segment */
355 #if defined(HAVE_GETPAGESIZE)
356 page_size = (size_t)getpagesize();
357 fprintf(stderr, "%s: page size = " SIZE_T_FMT "\n",
358 get_pname(), (SIZE_T_FMT_TYPE)page_size);
359 dbprintf(("%s: page size = " SIZE_T_FMT "\n", get_pname(),
360 (SIZE_T_FMT_TYPE)page_size));
363 fprintf(stderr, "%s: getpagesize() not available, using " SIZE_T_FMT "\n",
364 get_pname(), page_size);
365 dbprintf((stderr, "%s: getpagesize() not available, using " SIZE_T_FMT "\n",
366 get_pname(), page_size));
368 buffer_size = am_round(tt_blocksize, page_size);
369 fprintf(stderr, "%s: buffer size is " SIZE_T_FMT "\n",
370 get_pname(), (SIZE_T_FMT_TYPE)buffer_size);
371 dbprintf(("%s: buffer size is " SIZE_T_FMT "\n",
372 get_pname(), (SIZE_T_FMT_TYPE)buffer_size));
373 while (conf_tapebufs > 0) {
375 size += conf_tapebufs * buffer_size;
376 size += conf_tapebufs * SIZEOF(buffer_t);
377 if ((buffers = attach_buffers(size)) != NULL) {
380 log_add(L_INFO, "attach_buffers: (%d tapebuf%s: %d bytes) %s",
382 (conf_tapebufs == 1) ? "" : "s",
387 if (buffers == NULL) {
388 error("cannot allocate shared memory");
392 /* page boundary offset */
393 i = (int)((buffers - (char *)0) & (page_size - 1));
395 first_buffer = buffers + page_size - i;
396 dbprintf(("%s: shared memory at %p, first buffer at %p\n",
399 (void *)first_buffer));
401 first_buffer = buffers;
404 /*LINTED first_buffer, conf_tapebufs and buffer size are all * pagesize */
405 buftable = (buffer_t *)(first_buffer + (conf_tapebufs * buffer_size));
406 memset(buftable, 0, conf_tapebufs * SIZEOF(buffer_t));
407 if (conf_tapebufs < 10) {
409 } else if (conf_tapebufs < 100) {
414 for (i = 0; i < conf_tapebufs; i++) {
415 buftable[i].buffer = first_buffer + i * buffer_size;
416 dbprintf(("%s: buffer[%0*d] at %p\n",
419 (void *)buftable[i].buffer));
421 dbprintf(("%s: buffer structures at %p for %d bytes\n",
424 (int)(conf_tapebufs * SIZEOF(buffer_t))));
426 /* fork off child writer process, parent becomes reader process */
427 switch(writerpid = fork()) {
429 error("fork: %s", strerror(errno));
436 tape_writer_side(p2c[0], c2p[1]);
437 error("tape writer terminated unexpectedly");
440 default: /* parent */
444 file_reader_side(c2p[0], p2c[1]);
445 error("file reader terminated unexpectedly");
455 * ========================================================================
459 int read_file(int fd, char *handle,
460 char *host, char *disk, char *datestamp,
462 ssize_t taper_fill_buffer(int fd, buffer_t *bp, size_t buflen);
463 void dumpbufs(char *str1);
464 void dumpstatus(buffer_t *bp);
465 ssize_t get_next_holding_file(int fd, buffer_t *bp, char **strclosing, size_t rc);
466 int predict_splits(char *filename);
467 void create_split_buffer(char *split_diskbuffer, size_t fallback_splitsize, char *id_string);
468 void free_split_buffer(void);
472 * Create a buffer, either in an mmapped file or in memory, where PORT-WRITE
473 * dumps can buffer the current split chunk in case of retry.
477 char *split_diskbuffer,
478 size_t fallback_splitsize,
481 char *buff_err = NULL;
483 char *splitbuffer_path = NULL;
485 /* don't bother if we're not actually splitting */
486 if (splitsize <= (off_t)0) {
488 splitbuf_wr_ptr = NULL;
493 #ifdef HAVE_SYS_MMAN_H
494 if (strcmp(split_diskbuffer, "NULL")) {
499 splitbuffer_path = vstralloc(split_diskbuffer,
502 /* different file, munmap the previous */
503 if (mmap_filename && strcmp(mmap_filename, splitbuffer_path) != 0) {
504 dbprintf(("create_split_buffer: new file %s\n", splitbuffer_path));
505 munmap(splitbuf, (size_t)mmap_splitsize);
506 aclose(mmap_splitbuffer_fd);
507 mmap_splitbuf = NULL;
508 amfree(mmap_filename);
511 if (!mmap_filename) {
512 dbprintf(("create_split_buffer: open file %s\n",
514 mmap_splitbuffer_fd = open(splitbuffer_path, O_RDWR|O_CREAT, 0600);
515 if (mmap_splitbuffer_fd == -1) {
516 buff_err = newvstralloc(buff_err, "open of ",
517 splitbuffer_path, "failed (",
518 strerror(errno), ")", NULL);
522 offset = lseek(mmap_splitbuffer_fd, (off_t)0, SEEK_END) / 1024;
523 if (offset < splitsize) { /* Increase file size */
524 dbprintf(("create_split_buffer: increase file size of %s to "
526 splitbuffer_path, (OFF_T_FMT_TYPE)splitsize));
528 dbprintf(("create_split_buffer: munmap old file %s\n",
530 munmap(splitbuf, (size_t)mmap_splitsize);
532 mmap_splitbuf = NULL;
534 nulls = alloc(1024); /* lame */
535 memset(nulls, 0, 1024);
536 for (c = offset; c < splitsize ; c += (off_t)1) {
537 if (fullwrite(mmap_splitbuffer_fd, nulls, 1024) < 1024) {
538 buff_err = newvstralloc(buff_err, "write to ",
540 "failed (", strerror(errno),
543 if (c <= (off_t)fallback_splitsize) {
553 if (mmap_splitsize < splitsize*1024) {
554 mmap_splitsize = splitsize*1024;
555 mmap_filename = stralloc(splitbuffer_path);
556 dbprintf(("create_split_buffer: mmap file %s for " OFF_T_FMT "kb\n",
557 mmap_filename,(OFF_T_FMT_TYPE)splitsize));
558 mmap_splitbuf = mmap(NULL, (size_t)mmap_splitsize,
559 PROT_READ|PROT_WRITE,
560 MAP_SHARED, mmap_splitbuffer_fd, (off_t)0);
561 if (mmap_splitbuf == (char*)-1) {
562 buff_err = newvstralloc(buff_err, "mmap failed (",
563 strerror(errno), ")", NULL);
564 aclose(mmap_splitbuffer_fd);
565 amfree(mmap_filename);
567 mmap_splitbuf = NULL;
571 quoted = quote_string(splitbuffer_path);
573 "taper: r: buffering " OFF_T_FMT
574 "kb split chunks in mmapped file %s\n",
575 (OFF_T_FMT_TYPE)splitsize, quoted);
576 dbprintf(("taper: r: buffering " OFF_T_FMT
577 "kb split chunks in mmapped file %s\n",
578 (OFF_T_FMT_TYPE)splitsize, quoted));
579 amfree(splitbuffer_path);
582 splitbuf = mmap_splitbuf;
583 splitbuf_wr_ptr = splitbuf;
586 buff_err = stralloc("no split_diskbuffer specified");
589 (void)split_diskbuffer; /* Quite unused parameter warning */
590 buff_err = stralloc("mman.h not available");
594 (void)split_diskbuffer; /* Quite unused parameter warning */
595 buff_err = stralloc("mmap not available");
600 Buffer split dumps in memory, if we can't use a file.
603 amfree(splitbuffer_path);
604 splitsize = (off_t)fallback_splitsize;
605 dbprintf(("create_split_buffer: fallback size " OFF_T_FMT "\n",
606 (OFF_T_FMT_TYPE)splitsize));
608 "%s: using fallback split size of %dkb to buffer %s in-memory",
609 buff_err, splitsize, id_string);
611 if (splitsize > mem_splitsize) {
612 amfree(mem_splitbuf);
613 mem_splitbuf = alloc(fallback_splitsize * 1024);
614 mem_splitsize = fallback_splitsize;
615 dbprintf(("create_split_buffer: alloc buffer size " OFF_T_FMT "\n",
616 (OFF_T_FMT_TYPE)splitsize *1024));
618 splitbuf = mem_splitbuf;
619 splitbuf_wr_ptr = splitbuf;
623 * Free up resources that create_split_buffer eats.
626 free_split_buffer(void)
628 if (mmap_splitbuffer_fd != -1) {
630 #ifdef HAVE_SYS_MMAN_H
631 if (splitbuf != NULL)
632 munmap(splitbuf, (size_t)mmap_splitsize);
635 aclose(mmap_splitbuffer_fd);
636 amfree(mmap_filename);
646 put_syncpipe_fault_result(
652 handle = "<nohandle>";
654 q = squotef("[Taper syncpipe fault]");
655 putresult(TAPE_ERROR, "%s %s\n", handle, q);
656 log_add(L_ERROR, "tape-error %s %s", handle, q);
666 struct cmdargs cmdargs;
668 char *filename = NULL;
669 char *qfilename = NULL;
670 char *hostname = NULL;
671 char *diskname = NULL;
672 char *qdiskname = NULL;
674 char *datestamp = NULL;
675 char *split_diskbuffer = NULL;
676 char *id_string = NULL;
684 struct stat stat_file;
687 size_t fallback_splitsize = 0;
692 syncpipe_init(rdpipe, wrpipe);
694 /* must get START_TAPER before beginning */
697 cmd = getcmd(&cmdargs);
698 total_wait = stopclock();
700 if (cmd != START_TAPER || cmdargs.argc != 2) {
701 error("error [file_reader_side cmd %d argc %d]", cmd, cmdargs.argc);
705 /* pass start command on to tape writer */
707 taper_timestamp = newstralloc(taper_timestamp, cmdargs.argv[2]);
710 if (syncpipe_put('S', 0) == -1) {
711 put_syncpipe_fault_result(NULL);
714 if (syncpipe_putstr(taper_timestamp) == -1) {
715 put_syncpipe_fault_result(NULL);
718 /* get result of start command */
720 tok = syncpipe_get(&tmpint);
723 put_syncpipe_fault_result(NULL);
727 putresult(TAPER_OK, "\n");
729 /* start is logged in writer */
733 /* no tape, bail out */
734 if ((result = syncpipe_getstr()) == NULL) {
735 put_syncpipe_fault_result(NULL);
737 q = squotef("[%s]", result);
738 putresult(TAPE_ERROR, "<nohandle> %s\n", q);
740 log_add(L_ERROR,"no-tape [%s]", "No writable valid tape found");
745 log_add(L_WARNING,"%s", c1);
751 log_add(L_WARNING,"%s", c1);
753 (void)syncpipe_put('e', 0); /* ACK error */
757 case 'H': /* Syncpipe I/O error */
758 /* No ACK syncpipe is down just exit */
759 put_syncpipe_fault_result(handle);
764 * Pipe read error: Communications is severed at least
765 * back to us. We send a blind 'Q' (quit) and we don't
766 * wait for a response...
768 syncpipe_put('Q', 0); /* ACK error */
769 error("error [communications pipe from writer severed]");
773 q = squotef("[syncpipe sequence fault: Expected 'S' or 'E']");
774 putresult(TAPE_ERROR, "<nohandle> %s\n", q);
775 log_add(L_ERROR, "no-tape %s]", q);
779 /* process further driver commands */
782 cmd = getcmd(&cmdargs);
783 if (cmd != QUIT && !tape_started) {
784 error("error [file_reader_side cmd %d without tape ready]", cmd);
787 total_wait = timesadd(total_wait, stopclock());
802 mode = MODE_PORT_WRITE;
803 cmdargs.argc++; /* true count of args */
806 if (a >= cmdargs.argc) {
807 error("error [taper PORT-WRITE: not enough args: handle]");
810 handle = newstralloc(handle, cmdargs.argv[a++]);
812 if (a >= cmdargs.argc) {
813 error("error [taper PORT-WRITE: not enough args: hostname]");
816 hostname = newstralloc(hostname, cmdargs.argv[a++]);
818 if (a >= cmdargs.argc) {
819 error("error [taper PORT-WRITE: not enough args: features]");
822 am_release_feature_set(their_features);
823 their_features = am_string_to_feature(cmdargs.argv[a++]);
825 if (a >= cmdargs.argc) {
826 error("error [taper PORT-WRITE: not enough args: diskname]");
829 qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
830 if (diskname != NULL)
832 diskname = unquote_string(qdiskname);
834 if (a >= cmdargs.argc) {
835 error("error [taper PORT-WRITE: not enough args: level]");
838 level = atoi(cmdargs.argv[a++]);
840 if (a >= cmdargs.argc) {
841 error("error [taper PORT-WRITE: not enough args: datestamp]");
844 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
846 if (a >= cmdargs.argc) {
847 error("error [taper PORT-WRITE: not enough args: splitsize]");
850 splitsize = OFF_T_ATOI(cmdargs.argv[a++]);
852 if (a >= cmdargs.argc) {
853 error("error [taper PORT-WRITE: not enough args: split_diskbuffer]");
856 split_diskbuffer = newstralloc(split_diskbuffer, cmdargs.argv[a++]);
858 if (a >= cmdargs.argc) {
859 error("error [taper PORT-WRITE: not enough args: fallback_splitsize]");
862 /* Must fit in memory... */
863 fallback_splitsize = (size_t)atoi(cmdargs.argv[a++]);
865 if (a != cmdargs.argc) {
866 error("error [taper file_reader_side PORT-WRITE: too many args: %d != %d]",
871 if (fallback_splitsize < 128 ||
872 fallback_splitsize > 64 * 1024 * 1024) {
873 error("error [bad value for fallback_splitsize]");
876 snprintf(level_str, SIZEOF(level_str), "%d", level);
877 id_string = newvstralloc(id_string, hostname, ":", qdiskname, ".",
880 create_split_buffer(split_diskbuffer, fallback_splitsize, id_string);
884 data_socket = stream_server(&data_port, 0, STREAM_BUFSIZE, 0);
885 if (data_socket < 0) {
888 m = vstralloc("[port create failure: ",
893 putresult(TAPE_ERROR, "%s %s\n", handle, q);
898 putresult(PORT, "%d\n", data_port);
900 if ((fd = stream_accept(data_socket, CONNECT_TIMEOUT,
901 0, STREAM_BUFSIZE)) == -1) {
902 q = squote("[port connect timeout]");
903 putresult(TAPE_ERROR, "%s %s\n", handle, q);
908 expected_splits = -1;
910 while(read_file(fd, handle, hostname, qdiskname, datestamp, level))
911 (void)fd; /* Quiet lint */
928 mode = MODE_FILE_WRITE;
929 cmdargs.argc++; /* true count of args */
932 if (a >= cmdargs.argc) {
933 error("error [taper FILE-WRITE: not enough args: handle]");
936 handle = newstralloc(handle, cmdargs.argv[a++]);
938 if (a >= cmdargs.argc) {
939 error("error [taper FILE-WRITE: not enough args: filename]");
942 qfilename = newstralloc(qfilename, cmdargs.argv[a++]);
943 if (filename != NULL)
945 filename = unquote_string(qfilename);
947 if (a >= cmdargs.argc) {
948 error("error [taper FILE-WRITE: not enough args: hostname]");
951 hostname = newstralloc(hostname, cmdargs.argv[a++]);
953 if (a >= cmdargs.argc) {
954 error("error [taper FILE-WRITE: not enough args: features]");
957 am_release_feature_set(their_features);
958 their_features = am_string_to_feature(cmdargs.argv[a++]);
960 if (a >= cmdargs.argc) {
961 error("error [taper FILE-WRITE: not enough args: diskname]");
964 qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
965 if (diskname != NULL)
967 diskname = unquote_string(qdiskname);
969 if (a >= cmdargs.argc) {
970 error("error [taper FILE-WRITE: not enough args: level]");
973 level = atoi(cmdargs.argv[a++]);
975 if (a >= cmdargs.argc) {
976 error("error [taper FILE-WRITE: not enough args: datestamp]");
979 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
981 if (a >= cmdargs.argc) {
982 error("error [taper FILE-WRITE: not enough args: splitsize]");
985 splitsize = OFF_T_ATOI(cmdargs.argv[a++]);
987 if (a != cmdargs.argc) {
988 error("error [taper file_reader_side FILE-WRITE: too many args: %d != %d]",
992 if (holdfile_name != NULL) {
993 filename = newstralloc(filename, holdfile_name);
996 if ((expected_splits = predict_splits(filename)) < 0) {
999 if (stat(filename, &stat_file)!=0) {
1000 q = squotef("[%s]", strerror(errno));
1001 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1005 if ((fd = open(filename, O_RDONLY)) == -1) {
1006 q = squotef("[%s]", strerror(errno));
1007 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1011 holdfile_path = stralloc(filename);
1012 holdfile_path_thischunk = stralloc(filename);
1013 holdfile_offset_thischunk = (off_t)0;
1015 while (read_file(fd,handle,hostname,qdiskname,datestamp,level)) {
1016 if (splitsize > (off_t)0 && holdfile_path_thischunk)
1017 filename = newstralloc(filename, holdfile_path_thischunk);
1018 if ((fd = open(filename, O_RDONLY)) == -1) {
1019 q = squotef("[%s]", strerror(errno));
1020 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1028 putresult(QUITTING, "\n");
1029 fprintf(stderr,"taper: DONE [idle wait: %s secs]\n",
1030 walltime_str(total_wait));
1032 (void)syncpipe_put('Q', 0); /* tell writer we're exiting gracefully */
1035 if ((wpid = wait(NULL)) != writerpid) {
1036 dbprintf(("taper: writer wait returned %u instead of %u: %s\n",
1037 (unsigned)wpid, (unsigned)writerpid, strerror(errno)));
1039 "taper: writer wait returned %u instead of %u: %s\n",
1040 (unsigned)wpid, (unsigned)writerpid, strerror(errno));
1044 free_split_buffer();
1047 free_server_config();
1048 amfree(taper_timestamp);
1051 amfree(changer_resultstr);
1054 amfree(conf_tapelist);
1056 amfree(config_name);
1057 amfree(holdfile_name);
1059 malloc_size_2 = malloc_inuse(&malloc_hist_2);
1061 if (malloc_size_1 != malloc_size_2) {
1062 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
1068 if (cmdargs.argc >= 1) {
1069 q = squote(cmdargs.argv[1]);
1070 } else if (cmdargs.argc >= 0) {
1071 q = squote(cmdargs.argv[0]);
1073 q = stralloc("(no input?)");
1075 putresult(BAD_COMMAND, "%s\n", q);
1090 fprintf(stderr, "%s: state", str1);
1091 for (i = j = 0; i < conf_tapebufs; i = j+1) {
1092 v = buftable[i].status;
1093 for(j = i; j < conf_tapebufs && buftable[j].status == v; j++)
1094 (void)j; /* Quiet lint */
1097 fprintf(stderr, " %d:", i);
1099 fprintf(stderr, " %d-%d:", i, j);
1115 fprintf(stderr, "%ld", v);
1119 fputc('\n', stderr);
1128 char bt[NUM_STR_SIZE];
1129 char status[NUM_STR_SIZE + 1];
1132 pn[0] = procname[0];
1134 snprintf(bt, SIZEOF(bt), "%d", (int)(bp-buftable));
1136 switch(bp->status) {
1138 snprintf(status, SIZEOF(status), "F" SIZE_T_FMT,
1139 (SIZE_T_FMT_TYPE)bp->size);
1143 snprintf(status, SIZEOF(status), "f");
1147 snprintf(status, SIZEOF(status), "E");
1151 snprintf(status, SIZEOF(status), "%ld", bp->status);
1155 str = vstralloc("taper: ", pn, ": [buf ", bt, ":=", status, "]", NULL);
1161 Handle moving to the next chunk of holding file, if any. Returns -1 for
1162 errors, 0 if there's no more file, or a positive integer for the amount of
1163 stuff read that'll go into 'rc' (XXX That's fugly, maybe that should just
1164 be another global. What is rc anyway, 'read count?' I keep thinking it
1165 should be 'return code')
1168 get_next_holding_file(
1176 struct stat stat_file;
1182 /* see if we're fresh out of file */
1183 if (file.cont_filename[0] == '\0') {
1186 } else if (stat(file.cont_filename, &stat_file) != 0) {
1189 *strclosing = newvstralloc(*strclosing, "can't stat: ",
1190 file.cont_filename, NULL);
1191 } else if ((fd = open(file.cont_filename,O_RDONLY)) == -1) {
1194 *strclosing = newvstralloc(*strclosing, "can't open: ",
1195 file.cont_filename, NULL);
1196 } else if ((fd != save_fd) && dup2(fd, save_fd) == -1) {
1199 *strclosing = newvstralloc(*strclosing, "can't dup2: ",
1200 file.cont_filename, NULL);
1205 holdfile_path = stralloc(file.cont_filename);
1206 quoted = quote_string(holdfile_path);
1207 fprintf(stderr, "taper: r: switching to next holding chunk '%s'\n",
1210 num_holdfile_chunks++;
1213 bp1.size = DISK_BLOCK_BYTES;
1214 bp1.buffer = alloc(DISK_BLOCK_BYTES);
1216 if (fd != save_fd) {
1221 rc1 = taper_fill_buffer(fd, &bp1, DISK_BLOCK_BYTES);
1224 err = (rc1 < 0) ? errno : 0;
1226 *strclosing = newvstralloc(*strclosing,
1227 "Can't read header: ",
1231 parse_file_header(bp1.buffer, &file, (size_t)rc1);
1234 bp1.buffer = bp->buffer + rc;
1236 rc1 = taper_fill_buffer(fd, &bp1, (size_t)tt_blocksize - rc);
1238 err = (rc1 < 0) ? errno : 0;
1241 *strclosing = newvstralloc(*strclosing,
1242 "Can't read data: ",
1272 int closing, bufnum, need_closing, nexting;
1275 char *strclosing = NULL;
1276 char seekerrstr[STR_SIZE];
1278 int header_written = 0;
1280 dumpfile_t first_file;
1281 dumpfile_t cur_holdfile;
1282 off_t kbytesread = (off_t)0;
1283 int header_read = 0;
1284 char *cur_filename = NULL;
1285 int retry_from_splitbuf = 0;
1286 char *splitbuf_rd_ptr = NULL;
1289 #ifdef HAVE_LIBVTBLC
1290 static char desc[45];
1291 static char vol_date[20];
1292 static char vol_label[45];
1293 #endif /* HAVE_LIBVTBLC */
1297 memset(&first_file, 0, SIZEOF(first_file));
1298 memset(&cur_holdfile, 0, SIZEOF(cur_holdfile));
1300 filesize = (off_t)0;
1306 /* don't break this if we're still on the same file as a previous init */
1307 if (cur_span_chunkstart <= (off_t)0) {
1310 } else if(mode == MODE_FILE_WRITE){
1311 memcpy(&file, save_holdfile, SIZEOF(dumpfile_t));
1312 memcpy(&cur_holdfile, save_holdfile, SIZEOF(dumpfile_t));
1316 fprintf(stderr, "taper: r: start file\n");
1320 for (bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1325 if (interactive || bufdebug)
1328 if ((cur_span_chunkstart >= (off_t)0) && (splitsize > (off_t)0)) {
1329 /* We're supposed to start at some later part of the file, not read the
1330 whole thing. "Seek" forward to where we want to be. */
1332 putresult(SPLIT_CONTINUE, "%s %s\n", handle, label);
1333 if ((mode == MODE_FILE_WRITE) && (cur_span_chunkstart > (off_t)0)) {
1334 char *quoted = quote_string(holdfile_path_thischunk);
1335 fprintf(stderr, "taper: r: seeking %s to " OFF_T_FMT " kb\n",
1337 (OFF_T_FMT_TYPE)holdfile_offset_thischunk);
1340 if (holdfile_offset_thischunk > maxseek) {
1341 snprintf(seekerrstr, SIZEOF(seekerrstr), "Can't seek by "
1342 OFF_T_FMT " kb (compiled for %d-bit file offsets), "
1343 "recompile with large file support or "
1344 "set holdingdisk chunksize to <" OFF_T_FMT " Mb",
1345 (OFF_T_FMT_TYPE)holdfile_offset_thischunk,
1346 (int)(sizeof(off_t) * 8),
1347 (OFF_T_FMT_TYPE)(maxseek/(off_t)1024));
1348 log_add(L_ERROR, "%s", seekerrstr);
1349 fprintf(stderr, "taper: r: FATAL: %s\n", seekerrstr);
1351 if (syncpipe_put('X', 0) == -1) {
1352 put_syncpipe_fault_result(handle);
1357 if (lseek(fd, holdfile_offset_thischunk*(off_t)1024, SEEK_SET) == (off_t)-1) {
1358 fprintf(stderr, "taper: r: FATAL: seek_holdfile lseek error "
1359 "while seeking into %s by "
1360 OFF_T_FMT "kb: %s\n", quoted,
1361 (OFF_T_FMT_TYPE)holdfile_offset_thischunk,
1364 if (syncpipe_put('X', 0) == -1) {
1365 put_syncpipe_fault_result(handle);
1371 } else if (mode == MODE_PORT_WRITE) {
1372 fprintf(stderr, "taper: r: re-reading split dump piece from buffer\n");
1374 retry_from_splitbuf = 1;
1375 splitbuf_rd_ptr = splitbuf;
1376 if (splitbuf_rd_ptr >= splitbuf_wr_ptr)
1377 retry_from_splitbuf = 0;
1379 if (cur_span_chunkstart > (off_t)0)
1380 header_read = 1; /* really initialized in prior run */
1383 /* tell writer to open tape */
1389 if (syncpipe_put('O', 0) == -1) {
1390 put_syncpipe_fault_result(handle);
1393 if (syncpipe_putstr(datestamp) == -1) {
1394 put_syncpipe_fault_result(handle);
1397 if (syncpipe_putstr(hostname) == -1) {
1398 put_syncpipe_fault_result(handle);
1401 if (syncpipe_putstr(qdiskname) == -1) {
1402 put_syncpipe_fault_result(handle);
1405 if (syncpipe_putint(level) == -1) {
1406 put_syncpipe_fault_result(handle);
1412 /* read file in loop */
1415 if ((tok = syncpipe_get(&bufnum)) == -1) {
1416 put_syncpipe_fault_result(handle);
1431 fprintf(stderr, "taper: r: got R%d\n", bufnum);
1436 if (syncpipe_put('C', 0) == -1) {
1437 put_syncpipe_fault_result(handle);
1446 break; /* ignore extra read tokens */
1451 if(bp->status != EMPTY || bufnum != (int)(bp - buftable)) {
1452 /* XXX this SHOULD NOT HAPPEN. Famous last words. */
1453 fprintf(stderr,"taper: panic: buffer mismatch at ofs "
1454 OFF_T_FMT ":\n", (OFF_T_FMT_TYPE)filesize);
1455 if(bufnum != (int)(bp - buftable)) {
1456 fprintf(stderr, " my buf %d but writer buf %d\n",
1457 (int)(bp-buftable), bufnum);
1459 fprintf(stderr,"buf %d state %s (%ld) instead of EMPTY\n",
1461 bp->status == FILLING? "FILLING" :
1462 bp->status == FULL? "FULL" : "EMPTY!?!?",
1467 dumpbufs("taper: after 1 sec");
1468 if (bp->status == EMPTY)
1469 fprintf(stderr, "taper: result now correct!\n");
1472 errstr = newstralloc(errstr,
1473 "[fatal buffer mismanagement bug]");
1475 putresult(TRYAGAIN, "%s %s\n", handle, q);
1476 cur_span_chunkstart = (off_t)0;
1478 log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1479 hostname, qdiskname, level, errstr);
1481 if (syncpipe_put('X', 0) == -1) {/* X == buffer snafu, bail */
1482 put_syncpipe_fault_result(handle);
1486 if ((tok = syncpipe_get(&bufnum)) == -1) {
1487 put_syncpipe_fault_result(handle);
1490 } while (tok != 'x');
1493 } /* end 'if (bf->status != EMPTY || bufnum != (int)(bp-buftable))' */
1495 bp->status = FILLING;
1496 buflen = header_read ? (size_t)tt_blocksize : DISK_BLOCK_BYTES;
1497 if (interactive || bufdebug)
1499 if (header_written == 0 &&
1500 (header_read == 1 || cur_span_chunkstart > (off_t)0)) {
1501 /* for split dumpfiles, modify headers for the second - nth
1502 pieces that signify that they're continuations of the last
1504 char *cont_filename;
1505 file.type = F_SPLIT_DUMPFILE;
1506 file.partnum = num_splits + 1;
1507 file.totalparts = expected_splits;
1508 cont_filename = stralloc(file.cont_filename);
1509 file.cont_filename[0] = '\0';
1510 build_header(bp->buffer, &file, tt_blocksize);
1512 if (cont_filename[0] != '\0') {
1513 file.type = F_CONT_DUMPFILE;
1514 strncpy(file.cont_filename, cont_filename,
1515 SIZEOF(file.cont_filename));
1517 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1519 if (interactive || bufdebug)
1521 bp->size = (ssize_t)tt_blocksize;
1522 rc = (ssize_t)tt_blocksize;
1524 amfree(cont_filename);
1525 } else if (retry_from_splitbuf) {
1526 /* quietly pull dump data from our in-memory cache, and the
1527 writer side need never know the wiser */
1528 memcpy(bp->buffer, splitbuf_rd_ptr, tt_blocksize);
1529 bp->size = (ssize_t)tt_blocksize;
1530 rc = (ssize_t)tt_blocksize;
1532 splitbuf_rd_ptr += tt_blocksize;
1533 if (splitbuf_rd_ptr >= splitbuf_wr_ptr)
1534 retry_from_splitbuf = 0;
1535 } else if ((rc = taper_fill_buffer(fd, bp, buflen)) < 0) {
1538 strclosing = newvstralloc(strclosing,"Can't read data: ",
1540 if (syncpipe_put('C', 0) == -1) {
1541 put_syncpipe_fault_result(handle);
1547 if (rc < (ssize_t)buflen) { /* switch to next holding file */
1550 if (file.cont_filename[0] != '\0') {
1551 cur_filename = newvstralloc(cur_filename, file.cont_filename, NULL);
1553 ret = get_next_holding_file(fd, bp, &strclosing, (size_t)rc);
1557 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1564 /* rebuild the header block, which might have CONT junk */
1565 if (header_read == 0) {
1566 char *cont_filename;
1567 /* write the "real" filename if the holding-file
1569 parse_file_header(bp->buffer, &file, (size_t)rc);
1570 parse_file_header(bp->buffer, &first_file, (size_t)rc);
1571 cont_filename = stralloc(file.cont_filename);
1572 file.cont_filename[0] = '\0';
1573 if (splitsize > (off_t)0) {
1574 file.type = F_SPLIT_DUMPFILE;
1576 file.totalparts = expected_splits;
1578 file.blocksize = tt_blocksize;
1579 build_header(bp->buffer, &file, tt_blocksize);
1580 kbytesread += (off_t)(tt_blocksize/1024); /* XXX shady */
1582 file.type = F_CONT_DUMPFILE;
1584 /* add CONT_FILENAME back to in-memory header */
1585 strncpy(file.cont_filename, cont_filename,
1586 SIZEOF(file.cont_filename));
1587 if (interactive || bufdebug)
1589 bp->size = (ssize_t)tt_blocksize; /* output a full tape block */
1590 /* save the header, we'll need it if we jump tapes */
1591 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1594 amfree(cont_filename);
1596 filesize = kbytesread;
1600 fprintf(stderr,"taper: r: put W%d\n",(int)(bp-buftable));
1603 if (syncpipe_put('W', (int)(bp-buftable)) == -1) {
1604 put_syncpipe_fault_result(handle);
1610 if (((kbytesread + (off_t)(DISK_BLOCK_BYTES/1024)) >= splitsize)
1611 && (splitsize > (off_t)0) && !need_closing) {
1613 if (mode == MODE_PORT_WRITE) {
1614 splitbuf_wr_ptr = splitbuf;
1615 splitbuf_rd_ptr = splitbuf;
1616 memset(splitbuf, 0, SIZEOF(splitbuf));
1617 retry_from_splitbuf = 0;
1620 fprintf(stderr,"taper: r: end %s.%s.%s.%d part %d, "
1621 "splitting chunk that started at "
1622 OFF_T_FMT "kb after " OFF_T_FMT
1623 "kb (next chunk will start at "
1625 hostname, qdiskname, datestamp, level,
1627 (OFF_T_FMT_TYPE)cur_span_chunkstart,
1628 (OFF_T_FMT_TYPE)kbytesread,
1629 (OFF_T_FMT_TYPE)(cur_span_chunkstart+kbytesread));
1634 } /* end '(kbytesread >= splitsize && splitsize > 0)' */
1635 if (need_closing && rc <= 0) {
1636 if (syncpipe_put('C', 0) == -1) {
1637 put_syncpipe_fault_result(handle);
1643 kbytesread += (off_t)(rc / 1024);
1644 } /* end the 'if (!closing)' (successful buffer fill) */
1650 if (syncpipe_put('e', 0) == -1) { /* ACK error */
1651 put_syncpipe_fault_result(handle);
1655 if ((str = syncpipe_getstr()) == NULL) {
1656 put_syncpipe_fault_result(handle);
1660 errstr = newvstralloc(errstr, "[", str, "]", NULL);
1665 if (splitsize > (off_t)0) {
1666 /* we'll be restarting this chunk on the next tape */
1667 if (mode == MODE_FILE_WRITE) {
1671 putresult(SPLIT_NEEDNEXT, "%s " OFF_T_FMT "\n", handle,
1672 (OFF_T_FMT_TYPE)cur_span_chunkstart);
1673 log_add(L_INFO, "continuing %s:%s.%d on new tape from "
1674 OFF_T_FMT "kb mark: %s",
1675 hostname, qdiskname, level,
1676 (OFF_T_FMT_TYPE)cur_span_chunkstart, errstr);
1679 /* restart the entire dump (failure propagates to driver) */
1681 putresult(TRYAGAIN, "%s %s\n", handle, q);
1682 cur_span_chunkstart = (off_t)0;
1683 log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1684 hostname, qdiskname, level, errstr);
1688 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1689 log_add(L_FAIL, "%s %s %s %d [out of tape]",
1690 hostname, qdiskname, datestamp, level);
1691 log_add(L_ERROR,"no-tape [%s]", "No more writable valid tape found");
1703 cur_span_chunkstart += kbytesread; /* XXX possibly wrong */
1705 holdfile_name = newvstralloc(holdfile_name, cur_filename,
1708 amfree(holdfile_name);
1710 kbytesread = (off_t)0;
1711 amfree(cur_filename);
1714 if ((str = syncpipe_getstr()) == NULL) {
1715 put_syncpipe_fault_result(handle);
1719 label = newstralloc(label, str ? str : "(null)");
1721 if ((str = syncpipe_getstr()) == NULL) {
1722 put_syncpipe_fault_result(handle);
1726 filenum = atoi(str ? str : "-9876"); /* ??? */
1728 fprintf(stderr, "taper: reader-side: got label %s filenum %d\n",
1732 /* we'll need that file descriptor if we're gonna write more */
1737 runtime = stopclock();
1742 errstr = newvstralloc(errstr,
1743 "[input: ", strclosing, ": ",
1744 strerror(err), "]", NULL);
1747 errstr = newvstralloc(errstr,
1748 "[input: ", strerror(err), "]",
1751 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1754 if (splitsize != (off_t)0) {
1755 log_add(L_FAIL, "%s %s %s.%d %d %s", hostname, qdiskname,
1756 datestamp, num_splits, level, errstr);
1758 log_add(L_FAIL, "%s %s %s %d %s",
1759 hostname, qdiskname, datestamp, level, errstr);
1761 if ((str = syncpipe_getstr()) == NULL) { /* reap stats */
1762 put_syncpipe_fault_result(handle);
1768 char kb_str[NUM_STR_SIZE];
1769 char kps_str[NUM_STR_SIZE];
1772 rt = (double)(runtime.r.tv_sec) +
1773 ((double)(runtime.r.tv_usec) / 1000000.0);
1774 curdump_rt = timesadd(runtime, curdump_rt);
1775 snprintf(kb_str, SIZEOF(kb_str), OFF_T_FMT,
1776 (OFF_T_FMT_TYPE)filesize);
1777 snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
1778 (isnormal(rt) ? (double)filesize / rt : 0.0));
1779 if ((str = syncpipe_getstr()) == NULL) {
1780 put_syncpipe_fault_result(handle);
1783 errstr = newvstralloc(errstr,
1784 "[sec ", walltime_str(runtime),
1790 if (splitsize == (off_t)0) { /* Ordinary dump */
1792 /*@i@*/ if (first_file.is_partial) {
1793 putresult(PARTIAL, "%s %s %d %s\n",
1794 handle, label, filenum, q);
1795 log_add(L_PARTIAL, "%s %s %s %d %s",
1796 hostname, qdiskname, datestamp, level, errstr);
1798 putresult(DONE, "%s %s %d %s\n",
1799 handle, label, filenum, q);
1800 log_add(L_SUCCESS, "%s %s %s %d %s",
1801 hostname, qdiskname, datestamp, level, errstr);
1804 } else { /* Chunked dump */
1806 if (mode == MODE_FILE_WRITE) {
1807 holdfile_path_thischunk = stralloc(holdfile_path);
1808 holdfile_offset_thischunk = (lseek(fd, (off_t)0, SEEK_CUR))/(off_t)1024;
1810 save_holdfile = alloc(SIZEOF(dumpfile_t));
1812 memcpy(save_holdfile, &cur_holdfile,SIZEOF(dumpfile_t));
1814 log_add(L_CHUNK, "%s %s %s %d %d %s", hostname, qdiskname,
1815 datestamp, num_splits, level, errstr);
1816 if (!nexting) { /* split dump complete */
1817 rt = (double)(curdump_rt.r.tv_sec) +
1818 ((double)(curdump_rt.r.tv_usec) / 1000000.0);
1819 snprintf(kb_str, SIZEOF(kb_str), OFF_T_FMT,
1820 (OFF_T_FMT_TYPE)(filesize + cur_span_chunkstart));
1821 snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
1823 ((double)(filesize+cur_span_chunkstart)) / rt :
1826 errstr = newvstralloc(errstr,
1827 "[sec ", walltime_str(curdump_rt),
1834 putresult(DONE, "%s %s %d %s\n", handle, label,
1836 log_add(L_CHUNKSUCCESS, "%s %s %s %d %s",
1837 hostname, qdiskname, datestamp, level, errstr);
1838 amfree(save_holdfile);
1839 amfree(holdfile_path_thischunk);
1847 expected_splits = 0;
1848 amfree(holdfile_name);
1850 cur_span_chunkstart = (off_t)0;
1851 curdump_rt = times_zero;
1855 #ifdef HAVE_LIBVTBLC
1857 * We have 44 characters available for the label string:
1858 * use max 20 characters for hostname
1859 * max 20 characters for diskname
1860 * (it could contain a samba share or dos path)
1863 memset(desc, '\0', 45);
1865 strncpy(desc, hostname, 20);
1867 if ((len = strlen(hostname)) <= 20) {
1868 memset(desc + len, ' ', 1);
1871 memset(desc + 20, ' ', 1);
1875 strncpy(desc + offset, qdiskname, 20);
1877 if ((len = strlen(qdiskname)) <= 20) {
1878 memset(desc + offset + len, ' ', 1);
1879 offset = offset + len + 1;
1881 memset(desc + offset + 20, ' ', 1);
1882 offset = offset + 21;
1885 sprintf(desc + offset, "%i", level);
1887 strncpy(vol_label, desc, 44);
1888 fprintf(stderr, "taper: added vtbl label string %i: \"%s\"\n",
1889 filenum, vol_label);
1892 /* pass label string on to tape writer */
1893 if (syncpipe_put('L', filenum) == -1) {
1894 put_syncpipe_fault_result(handle);
1897 if (syncpipe_putstr(vol_label) == -1) {
1898 put_syncpipe_fault_result(handle);
1903 * reformat datestamp for later use with set_date from vtblc
1905 strptime(datestamp, "%Y%m%d", &backup_time);
1906 strftime(vol_date, 20, "%T %D", &backup_time);
1908 "taper: reformatted vtbl date string: \"%s\"->\"%s\"\n",
1912 /* pass date string on to tape writer */
1913 if (syncpipe_put('D', filenum) == -1) {
1914 put_syncpipe_fault_result(handle);
1917 if (syncpipe_putstr(vol_date) == -1) {
1918 put_syncpipe_fault_result(handle);
1922 #endif /* HAVE_LIBVTBLC */
1924 /* reset stuff that assumes we're on a new file */
1934 filesize = (off_t)0;
1935 if (syncpipe_put('O', 0) == -1) {
1936 put_syncpipe_fault_result(handle);
1939 if (syncpipe_putstr(datestamp) == -1) {
1940 put_syncpipe_fault_result(handle);
1943 if (syncpipe_putstr(hostname) == -1) {
1944 put_syncpipe_fault_result(handle);
1947 if (syncpipe_putstr(qdiskname) == -1) {
1948 put_syncpipe_fault_result(handle);
1951 if (syncpipe_putint(level) == -1) {
1952 put_syncpipe_fault_result(handle);
1955 for (bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1964 * Pipe read error: Communications is severed at least
1965 * back to us. We send a blind 'Q' (quit) and we don't
1966 * wait for a response...
1968 syncpipe_put('Q', 0); /* ACK error */
1969 fprintf(stderr, "taper: communications pipe from reader severed\n");
1973 q = squotef("[Taper syncpipe protocol error]");
1974 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1975 log_add(L_ERROR, "tape-error %s %s", handle, q);
1992 curptr = bp->buffer;
1994 cnt = fullread(fd, curptr, buflen);
1998 fputs("r0", stderr);
2003 case -1: /* error on read, punt */
2005 fputs("rE", stderr);
2011 if ((mode == MODE_PORT_WRITE) && (splitsize > (off_t)0)) {
2012 memcpy(splitbuf_wr_ptr, curptr, (size_t)cnt);
2013 splitbuf_wr_ptr += cnt;
2021 return ((ssize_t)bp->size);
2024 /* Given a dumpfile in holding, determine its size and figure out how many
2025 * times we'd have to split it.
2032 off_t total_kb = (off_t)0;
2033 off_t adj_splitsize = splitsize - (off_t)(DISK_BLOCK_BYTES / 1024);
2035 if (splitsize <= (off_t)0)
2038 if (adj_splitsize <= (off_t)0) {
2039 error("Split size must be > " OFF_T_FMT "k",
2040 (OFF_T_FMT_TYPE)(DISK_BLOCK_BYTES/1024));
2044 /* should only calculuate this once, not on retries etc */
2045 if (expected_splits != 0)
2046 return(expected_splits);
2048 total_kb = size_holding_files(filename, 1);
2050 if (total_kb <= (off_t)0) {
2051 fprintf(stderr, "taper: r: " OFF_T_FMT
2052 " kb holding file makes no sense, not precalculating splits\n",
2053 (OFF_T_FMT_TYPE)total_kb);
2058 fprintf(stderr, "taper: r: Total dump size should be " OFF_T_FMT
2059 "kb, chunk size is " OFF_T_FMT "kb\n",
2060 (OFF_T_FMT_TYPE)total_kb,
2061 (OFF_T_FMT_TYPE)splitsize);
2064 splits = (int)(total_kb / adj_splitsize);
2065 if ((splits == 0) || (total_kb % adj_splitsize))
2069 fprintf(stderr, "taper: r: Expecting to split into %d parts \n", splits);
2076 * ========================================================================
2080 times_t idlewait, rdwait, wrwait, fmwait;
2081 unsigned long total_writes;
2082 off_t total_tape_used;
2085 void write_file(void);
2086 int write_buffer(buffer_t *bp);
2102 #ifdef HAVE_LIBVTBLC
2105 #endif /* HAVE_LIBVTBLC */
2107 procname = "writer";
2108 syncpipe_init(getp, putp);
2110 idlewait = times_zero;
2114 if ((tok = syncpipe_get(&tmpint)) == -1) {
2115 error("writer: Syncpipe failure before start");
2119 idlewait = timesadd(idlewait, stopclock());
2120 if (tok != 'S' && tok != 'Q' && !tape_started) {
2121 error("writer: token '%c' before start", tok);
2126 case 'H': /* Reader read pipe side is down */
2127 dbprintf(("writer: Communications with reader is down"));
2128 error("writer: Communications with reader is down");
2131 case 'S': /* start-tape */
2133 error("writer: multiple start requests");
2136 if ((str = syncpipe_getstr()) == NULL) {
2137 error("writer: Syncpipe failure");
2140 if (!first_tape(str ? str : "bad-datestamp")) {
2142 tapefd_close(tape_fd);
2145 if (syncpipe_put('E', 0) == -1) {
2146 error("writer: Syncpipe failure passing exit code");
2149 if (syncpipe_putstr(errstr) == -1) {
2150 error("writer: Syncpipe failure passing exit string");
2153 /* wait for reader to acknowledge error */
2155 if ((tok = syncpipe_get(&tmpint)) == -1) {
2156 error("writer: Syncpipe failure waiting for error ack");
2160 error("writer: got '%c' unexpectedly after error", tok);
2163 } while (tok != 'e');
2165 if (syncpipe_put('S', 0) == -1) {
2166 error("writer: syncpipe failure while starting tape");
2174 case 'O': /* open-output */
2175 if ((datestamp = syncpipe_getstr()) == NULL) {
2176 error("writer: Syncpipe failure during open");
2179 tapefd_setinfo_datestamp(tape_fd, datestamp);
2182 if ((hostname = syncpipe_getstr()) == NULL) {
2183 error("writer: Syncpipe failure fetching hostname");
2186 tapefd_setinfo_host(tape_fd, hostname);
2189 if ((diskname = syncpipe_getstr()) == NULL) {
2190 error("writer: Syncpipe failure fetching diskname");
2193 tapefd_setinfo_disk(tape_fd, diskname);
2195 if ((level = syncpipe_getint()) == -1) {
2196 error("writer: Syncpipe failure fetching level");
2199 tapefd_setinfo_level(tape_fd, level);
2203 #ifdef HAVE_LIBVTBLC
2204 case 'L': /* read vtbl label */
2206 if ((vol_label = syncpipe_getstr()) == NULL) {
2207 error("writer: Syncpipe failure fetching vrbl label");
2210 fprintf(stderr, "taper: read label string \"%s\" from pipe\n",
2212 strncpy(vtbl_entry[vtbl_no].label, vol_label, 45);
2215 case 'D': /* read vtbl date */
2217 if ((vol_date = syncpipe_getstr()) == NULL) {
2218 error("writer: Syncpipe failure fetching vrbl date");
2221 fprintf(stderr, "taper: read date string \"%s\" from pipe\n",
2223 strncpy(vtbl_entry[vtbl_no].date, vol_date, 20);
2225 #endif /* HAVE_LIBVTBLC */
2228 end_tape(0); /* XXX check results of end tape ?? */
2230 free_server_config();
2231 amfree(taper_timestamp);
2234 amfree(changer_resultstr);
2236 amfree(conf_tapelist);
2238 amfree(config_name);
2240 malloc_size_2 = malloc_inuse(&malloc_hist_2);
2242 if (malloc_size_1 != malloc_size_2) {
2243 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
2258 int full_buffers, i, bufnum;
2260 char number[NUM_STR_SIZE];
2261 char *rdwait_str, *wrwait_str, *fmwait_str;
2264 rdwait = wrwait = times_zero;
2272 fprintf(stderr, "taper: w: start file\n");
2277 * Tell the reader that the tape is open, and give it all the buffers.
2279 if (syncpipe_put('O', 0) == -1) {
2280 error("writer: Syncpipe failure starting write sequence");
2283 for (i = 0; i < conf_tapebufs; i++) {
2285 fprintf(stderr, "taper: w: put R%d\n", i);
2288 if (syncpipe_put('R', i) == -1) {
2289 error("writer: Syncpipe failure readying write buffers");
2295 * We write the filemark at the start of the file rather than at the end,
2296 * so that it can proceed in parallel with the reader's initial filling
2297 * up of the buffers.
2301 if (!write_filemark())
2303 fmwait = stopclock();
2312 * At the start of the file, or if the input can't keep up with the
2313 * tape, we enter STOPPED mode, which waits for most of the buffers
2314 * to fill up before writing to tape. This maximizes the amount of
2315 * data written in chunks to the tape drive, minimizing the number
2316 * of starts/stops, which in turn saves tape and time.
2320 fputs("[WS]", stderr);
2322 while (full_buffers < conf_tapebufs - THRESHOLD) {
2323 if ((tok = syncpipe_get(&bufnum)) == -1) {
2324 error("writer: Syncpipe failure during buffer advance");
2330 fprintf(stderr,"taper: w: got W%d\n",bufnum);
2335 rdwait = timesadd(rdwait, stopclock());
2340 * We start output when sufficient buffers have filled up, or at
2341 * end-of-file, whichever comes first. Here we drain all the buffers
2342 * that were waited on in STOPPED mode. If more full buffers come
2343 * in, then we will be STREAMING.
2346 while (full_buffers) {
2347 if (tt_file_pad && bp->size < (ssize_t)tt_blocksize) {
2348 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
2349 bp->size = (ssize_t)tt_blocksize;
2351 if (!write_buffer(bp))
2360 * With any luck, the input source is faster than the tape drive. In
2361 * this case, full buffers will appear in the circular queue faster
2362 * than we can write them, so the next buffer in the queue will always
2363 * be marked FULL by the time we get to it. If so, we'll stay in
2366 * On the other hand, if we catch up to the input and thus would have
2367 * to wait for buffers to fill, we are then STOPPED again.
2370 while (tok == 'W' && bp->status == FULL) {
2371 if ((tok = syncpipe_get(&bufnum)) == -1) {
2372 error("writer: Syncpipe failure advancing buffer");
2378 fprintf(stderr,"taper: w: got W%d\n",bufnum);
2381 if(bufnum != (int)(bp - buftable)) {
2383 "taper: tape-writer: my buf %d reader buf %d\n",
2384 (int)(bp-buftable), bufnum);
2386 if (syncpipe_put('E', 0) == -1) {
2387 error("writer: Syncpipe failure putting error token");
2390 if (syncpipe_putstr("writer-side buffer mismatch") == -1) {
2391 error("writer: Syncpipe failure putting error messgae");
2396 if (tt_file_pad && bp->size < (ssize_t)tt_blocksize) {
2397 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
2398 bp->size = (ssize_t)tt_blocksize;
2400 if (!write_buffer(bp))
2403 } else if (tok == 'Q') {
2405 } else if (tok == 'X') {
2406 goto reader_buffer_snafu;
2408 error("writer-side not expecting token: %c", tok);
2412 } while (tok == 'W');
2414 /* got close signal from reader, acknowledge it */
2417 goto reader_buffer_snafu;
2420 if (syncpipe_put('C', 0) == -1) {
2421 error("writer: Syncpipe failure putting close");
2425 /* tell reader the tape and file number */
2427 if (syncpipe_putstr(label) == -1) {
2428 error("writer: Syncpipe failure putting label");
2431 snprintf(number, SIZEOF(number), "%d", filenum);
2432 if (syncpipe_putstr(number) == -1) {
2433 error("writer: Syncpipe failure putting filenum");
2437 snprintf(number, SIZEOF(number), "%lu", total_writes);
2438 rdwait_str = stralloc(walltime_str(rdwait));
2439 wrwait_str = stralloc(walltime_str(wrwait));
2440 fmwait_str = stralloc(walltime_str(fmwait));
2441 errstr = newvstralloc(errstr,
2443 " writers ", number,
2444 " rdwait ", rdwait_str,
2445 " wrwait ", wrwait_str,
2446 " filemark ", fmwait_str,
2452 if (syncpipe_putstr(errstr) == -1) {
2453 error("writer: Syncpipe failure putting '%s'", errstr);
2457 /* XXX go to next tape if past tape size? */
2462 /* got tape error */
2464 if (syncpipe_put('T', 0) == -1) { /* next tape in place, try again */
2465 error("writer: Syncpipe failure during tape advance");
2469 if (syncpipe_put('E', 0) == -1) { /* no more tapes, fail */
2470 error("writer: Syncpipe failure during tape error");
2474 if (syncpipe_putstr(errstr) == -1) {
2475 error("writer: Syncpipe failure putting '%s'", errstr);
2480 /* wait for reader to acknowledge error */
2482 if ((tok = syncpipe_get(&tmpint)) == -1) {
2483 error("writer: syncpipe failure waiting for error ack");
2487 if (tok != 'W' && tok != 'C' && tok != 'e') {
2488 error("writer: got '%c' unexpectedly after error", tok);
2491 } while (tok != 'e');
2494 reader_buffer_snafu:
2495 if (syncpipe_put('x', 0) == -1) {
2496 error("writer: syncpipe failure putting buffer snafu");
2508 assert(bp->status == FULL);
2511 rc = tapefd_write(tape_fd, bp->buffer, (size_t)bp->size);
2512 if (rc == (ssize_t)bp->size) {
2513 #if defined(NEED_RESETOFS)
2514 static double tape_used_modulus_2gb = 0;
2517 * If the next write will go over the 2 GByte boundary, reset
2518 * the kernel concept of where we are to make sure it does not
2521 tape_used_modulus_2gb += (double)rc;
2522 if (tape_used_modulus_2gb + (double)rc > (double)0x7fffffff) {
2523 tape_used_modulus_2gb = 0;
2524 tapefd_resetofs(tape_fd);
2527 wrwait = timesadd(wrwait, stopclock());
2529 total_tape_used += (off_t)rc;
2531 if (interactive || bufdebug)
2537 fprintf(stderr, "taper: w: put R%d\n", (int)(bp-buftable));
2540 if (syncpipe_put('R', (int)(bp-buftable)) == -1) {
2541 error("writer: Syncpipe failure during advancing write bufffer");
2546 errstr = newvstralloc(errstr,
2548 (rc != -1) ? "short write" : strerror(errno),
2550 wrwait = timesadd(wrwait, stopclock());
2552 fputs("[WE]", stderr);
2561 REMOVE_SHARED_MEMORY();
2566 * Cleanup shared memory segments
2572 log_add(L_INFO, "Received signal %d", signum);
2579 * Installing signal handlers for signal whose default action is
2580 * process termination so that we can clean up shared memory
2584 install_signal_handlers(void)
2586 struct sigaction act;
2588 act.sa_handler = signal_handler;
2590 sigemptyset(&act.sa_mask);
2592 signal(SIGPIPE, SIG_IGN);
2594 if (sigaction(SIGINT, &act, NULL) != 0) {
2595 error("taper: couldn't install SIGINT handler [%s]", strerror(errno));
2599 if (sigaction(SIGHUP, &act, NULL) != 0) {
2600 error("taper: couldn't install SIGHUP handler [%s]", strerror(errno));
2604 if (sigaction(SIGTERM, &act, NULL) != 0) {
2605 error("taper: couldn't install SIGTERM handler [%s]", strerror(errno));
2609 if (sigaction(SIGUSR1, &act, NULL) != 0) {
2610 error("taper: couldn't install SIGUSR1 handler [%s]", strerror(errno));
2614 if (sigaction(SIGUSR2, &act, NULL) != 0) {
2615 error("taper: couldn't install SIGUSR2 handler [%s]", strerror(errno));
2619 if (sigaction(SIGALRM, &act, NULL) != 0) {
2620 error("taper: couldn't install SIGALRM handler [%s]", strerror(errno));
2627 * ========================================================================
2628 * SHARED-MEMORY BUFFER SUBSYSTEM
2642 shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0700);
2647 result = (char *)shmat(shmid, (SHM_ARG_TYPE *)NULL, 0);
2649 if (result == (char *)-1) {
2650 int save_errno = errno;
2654 error("shmat: %s", strerror(errno));
2666 if ((bufp != NULL) &&
2667 (shmdt((SHM_ARG_TYPE *)bufp) == -1)) {
2668 error("shmdt: %s", strerror(errno));
2674 destroy_buffers(void)
2677 return; /* nothing to destroy */
2678 if (shmctl(shmid, IPC_RMID, NULL) == -1) {
2679 error("shmctl: %s", strerror(errno));
2687 #ifdef HAVE_SYS_MMAN_H
2688 #include <sys/mman.h>
2692 # ifdef MAP_ANONYMOUS /* OSF/1-style */
2693 # define MAP_ANON MAP_ANONYMOUS
2694 # else /* SunOS4-style */
2696 # define ZERO_FILE "/dev/zero"
2710 shmfd = open(ZERO_FILE, O_RDWR);
2712 error("attach_buffers: could not open %s: %s",
2720 shmbuf = (char *) mmap((void *) 0,
2722 PROT_READ|PROT_WRITE,
2723 MAP_ANON|MAP_SHARED,
2733 if ((bufp != NULL) &&
2734 (munmap((void *)bufp, saved_size) == -1)) {
2735 error("detach_buffers: munmap: %s", strerror(errno));
2744 destroy_buffers(void)
2749 #error: must define either HAVE_SYSVSHM or HAVE_MMAP!
2756 * ========================================================================
2757 * SYNC-PIPE SUBSYSTEM
2761 int getpipe, putpipe;
2773 syncpipe_read_error(
2777 char buf[sizeof(char) + sizeof(int)];
2780 dbprintf(("syncpipe_get %s halting: Unexpected read EOF\n", procname));
2781 fprintf(stderr, "syncpipe_get %s halting: Unexpected read EOF\n", procname);
2782 } else if (rc < 0) {
2783 dbprintf(("syncpipe_get %s halting: Read error - %s\n",
2784 procname, strerror(errno)));
2785 fprintf(stderr, "syncpipe_get %s halting: Read error - %s\n",
2786 procname, strerror(errno));
2788 dbprintf(("syncpipe_get %s halting: Read "
2789 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2790 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2791 (SSIZE_T_FMT_TYPE)expected));
2792 fprintf(stderr, "syncpipe_get %s halting: Read "
2793 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2794 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2795 (SSIZE_T_FMT_TYPE)expected);
2797 /* Halt the other side if it's still alive */
2799 memset(&buf[1], 0, SIZEOF(int));
2800 if (write(putpipe, buf, SIZEOF(buf)))
2805 syncpipe_write_error(
2809 char buf[sizeof(char) + sizeof(int)];
2811 if (rc == 0) { /* EOF */
2812 dbprintf(("syncpipe %s halting: Write EOF\n", procname));
2813 fprintf(stderr, "syncpipe %s halting: Write EOF\n", procname);
2814 } else if (rc < 0) {
2815 dbprintf(("syncpipe %s halting: Write error - %s\n",
2816 procname, strerror(errno)));
2817 fprintf(stderr, "syncpipe %s halting: Write error - %s\n",
2818 procname, strerror(errno));
2820 dbprintf(("syncpipe %s halting: Write "
2821 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2822 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2823 (SSIZE_T_FMT_TYPE)expected));
2824 fprintf(stderr, "syncpipe %s halting: Write "
2825 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2826 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2827 (SSIZE_T_FMT_TYPE)expected);
2829 /* Halt the other side if it's still alive */
2831 memset(&buf[1], 0, SIZEOF(int));
2832 if (write(putpipe, buf, SIZEOF(buf)))
2841 char buf[SIZEOF(char) + SIZEOF(int)];
2843 memset(buf, 0, sizeof(buf));
2844 rc = fullread(getpipe, buf, SIZEOF(buf));
2845 if (rc != (ssize_t)sizeof(buf)) {
2846 syncpipe_read_error(rc, (ssize_t)sizeof(buf));
2850 if (bufdebug && *buf != 'R' && *buf != 'W') {
2851 fprintf(stderr,"taper: %c: getc %c\n", *procname, *buf);
2855 memcpy(intp, &buf[1], SIZEOF(int));
2860 syncpipe_getint(void)
2865 rc = fullread(getpipe, &i, SIZEOF(i));
2866 if (rc != (ssize_t)sizeof(i)) {
2867 syncpipe_read_error(rc, (ssize_t)sizeof(i));
2876 syncpipe_getstr(void)
2882 if ((len = syncpipe_getint()) <= 0) {
2883 fprintf(stderr, "syncpipe %s halting: Protocol error - "
2884 "Invalid string length (%d)\n", procname, len);
2885 syncpipe_put('H', 0); /* Halt the other side */
2890 str = alloc((size_t)len);
2892 rc = fullread(getpipe, str, (size_t)len);
2893 if (rc != (ssize_t)len) {
2894 syncpipe_read_error(rc, (ssize_t)len);
2906 char buf[sizeof(char) + sizeof(int)];
2910 memcpy(&buf[1], &intval, SIZEOF(int));
2911 if (bufdebug && buf[0] != 'R' && buf[0] != 'W') {
2912 fprintf(stderr,"taper: %c: putc %c\n",*procname,buf[0]);
2916 rc = fullwrite(putpipe, buf, SIZEOF(buf));
2917 if (rc != (ssize_t)sizeof(buf)) {
2918 syncpipe_write_error(rc, (ssize_t)sizeof(buf));
2930 rc = fullwrite(putpipe, &i, SIZEOF(i));
2931 if (rc != (ssize_t)sizeof(i)) {
2932 syncpipe_write_error(rc, (ssize_t)sizeof(i));
2946 str = "UNKNOWN syncpipe_putstr STRING";
2948 n = (ssize_t)strlen(str) + 1; /* send '\0' as well */
2949 syncpipe_putint((int)n);
2951 rc = fullwrite(putpipe, str, (size_t)n);
2953 syncpipe_write_error(rc, n);
2960 * ========================================================================
2961 * TAPE MANIPULATION SUBSYSTEM
2964 int label_tape(void);
2966 /* local functions */
2968 /* return 0 on success */
2969 /* return 1 on error and set errstr */
2973 char *conf_tapelist_old = NULL;
2975 static int first_call = 1;
2977 char *error_msg = NULL;
2983 if (taper_scan(NULL, &label, ×tamp, &tapedev, CHAR_taperscan_output_callback, &error_msg) < 0) {
2984 fprintf(stderr, "%s\n", error_msg);
2992 s = error_msg; r = NULL;
2993 while((s=strstr(s,"slot "))) { s += 5; r=s; };
2999 if ((tape_fd = tape_open(tapedev, O_WRONLY)) == -1) {
3000 if (errno == EACCES) {
3001 errstr = newstralloc(errstr,
3002 "writing label: tape is write protected");
3004 errstr = newstralloc2(errstr,
3005 "writing label: ", strerror(errno));
3010 tapefd_setinfo_length(tape_fd, tapetype_get_length(tt));
3012 tapefd_setinfo_datestamp(tape_fd, taper_timestamp);
3013 tapefd_setinfo_disk(tape_fd, label);
3014 result = tapefd_wrlabel(tape_fd, taper_timestamp, label, tt_blocksize);
3015 if (result != NULL) {
3016 errstr = newstralloc(errstr, result);
3021 fprintf(stderr, "taper: slot: %d wrote label `%s' date `%s'\n", slot,
3022 label, taper_timestamp);
3025 fprintf(stderr, "taper: wrote label `%s' date `%s'\n", label,
3030 #ifdef HAVE_LIBVTBLC
3031 /* store time for the first volume entry */
3033 tape_timep = localtime(&raw_time);
3034 strftime(start_datestr, 20, "%T %D", tape_timep);
3035 fprintf(stderr, "taper: got vtbl start time: %s\n", start_datestr);
3037 #endif /* HAVE_LIBVTBLC */
3039 if (strcmp(label, FAKE_LABEL) != 0) {
3040 if (cur_tape == 0) {
3041 conf_tapelist_old = stralloc2(conf_tapelist, ".yesterday");
3043 char cur_str[NUM_STR_SIZE];
3045 snprintf(cur_str, SIZEOF(cur_str), "%d", cur_tape - 1);
3046 conf_tapelist_old = vstralloc(conf_tapelist,
3047 ".today.", cur_str, NULL);
3050 if (write_tapelist(conf_tapelist_old)) {
3051 error("could not write tapelist: %s", strerror(errno));
3054 amfree(conf_tapelist_old);
3056 remove_tapelabel(label);
3057 add_tapelabel(taper_timestamp, label);
3058 if (write_tapelist(conf_tapelist)) {
3059 error("could not write tapelist: %s", strerror(errno));
3064 log_add(L_START, "datestamp %s label %s tape %d",
3065 taper_timestamp, label, cur_tape);
3066 if (first_call && strcmp(label, FAKE_LABEL) == 0) {
3068 log_add(L_WARNING, "tapedev is %s, dumps will be thrown away", tapedev);
3071 total_tape_used=(off_t)0;
3077 /* return 0 on error and set errstr */
3078 /* return 1 on success */
3081 char *new_datestamp)
3083 if ((have_changer = changer_init()) < 0) {
3084 error("changer initialization failed: %s", strerror(errno));
3089 taper_timestamp = newstralloc(taper_timestamp, new_datestamp);
3102 end_tape(writerror);
3104 if (++cur_tape >= runtapes)
3107 if (!label_tape()) {
3124 log_add(L_INFO, "tape %s kb " OFF_T_FMT " fm %d %s",
3126 (OFF_T_FMT_TYPE)((total_tape_used+(off_t)1023) / (off_t)1024),
3128 writerror? errstr : "[OK]");
3130 fprintf(stderr, "taper: writing end marker. [%s %s kb "
3131 OFF_T_FMT " fm %d]\n", label,
3132 writerror? "ERR" : "OK",
3133 (OFF_T_FMT_TYPE)((total_tape_used+(off_t)1023) / (off_t)1024),
3137 if (! write_filemark()) {
3142 result = tapefd_wrendmark(tape_fd, taper_timestamp, tt_blocksize);
3143 if (result != NULL) {
3144 errstr = newstralloc(errstr, result);
3151 #ifdef HAVE_LINUX_ZFTAPE_H
3152 if (tape_fd >= 0 && is_zftape(tapedev) == 1) {
3153 /* rewind the tape */
3155 if (tapefd_rewind(tape_fd) == -1 ) {
3156 errstr = newstralloc2(errstr, "rewinding tape: ", strerror(errno));
3160 /* close the tape */
3162 if (tapefd_close(tape_fd) == -1) {
3163 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
3169 #ifdef HAVE_LIBVTBLC
3170 /* update volume table */
3171 fprintf(stderr, "taper: updating volume table ...\n");
3174 if ((tape_fd = raw_tape_open(rawtapedev, O_RDWR)) == -1) {
3175 if (errno == EACCES) {
3176 errstr = newstralloc(errstr,
3177 "updating volume table: tape is write protected");
3179 errstr = newstralloc2(errstr,
3180 "updating volume table: ",
3186 /* read volume table */
3187 if ((num_volumes = read_vtbl(tape_fd, volumes, vtbl_buffer,
3188 &first_seg, &last_seg)) == -1 ) {
3189 errstr = newstralloc2(errstr,
3190 "reading volume table: ",
3195 /* set volume label and date for first entry */
3197 if (set_label(label, volumes, num_volumes, vtbl_no)) {
3198 errstr = newstralloc2(errstr,
3199 "setting label for entry 1: ",
3204 /* date of start writing this tape */
3205 if (set_date(start_datestr, volumes, num_volumes, vtbl_no)) {
3206 errstr = newstralloc2(errstr,
3207 "setting date for entry 1: ",
3212 /* set volume labels and dates for backup files */
3213 for (vtbl_no = 1; vtbl_no <= num_volumes - 2; vtbl_no++) {
3214 fprintf(stderr,"taper: label %i: %s, date %s\n",
3216 vtbl_entry[vtbl_no].label,
3217 vtbl_entry[vtbl_no].date);
3219 if (set_label(vtbl_entry[vtbl_no].label,
3220 volumes, num_volumes, vtbl_no)) {
3221 errstr = newstralloc2(errstr,
3222 "setting label for entry i: ",
3227 if (set_date(vtbl_entry[vtbl_no].date,
3228 volumes, num_volumes, vtbl_no)) {
3229 errstr = newstralloc2(errstr,
3230 "setting date for entry i: ",
3236 /* set volume label and date for last entry */
3237 vtbl_no = num_volumes - 1;
3238 if (set_label("AMANDA Tape End", volumes, num_volumes, vtbl_no)) {
3239 errstr = newstralloc2(errstr,
3240 "setting label for last entry: ",
3245 datestr = NULL; /* take current time */
3246 if (set_date(datestr, volumes, num_volumes, vtbl_no)) {
3247 errstr = newstralloc2(errstr,
3248 "setting date for last entry 1: ",
3253 /* write volume table back */
3254 if (write_vtbl(tape_fd, volumes, vtbl_buffer, num_volumes, first_seg,
3255 op_mode == trunc)) {
3256 errstr = newstralloc2(errstr,
3257 "writing volume table: ",
3263 fprintf(stderr, "taper: updating volume table: done.\n");
3265 #endif /* HAVE_LIBVTBLC */
3267 #endif /* !HAVE_LINUX_ZFTAPE_H */
3269 /* close the tape and let the OS write the final filemarks */
3273 if (tape_fd >= 0 && tapefd_close(tape_fd) == -1 && ! writerror) {
3274 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
3285 write_filemark(void)
3287 if (tapefd_weof(tape_fd, (off_t)1) == -1) {
3288 errstr = newstralloc2(errstr, "writing filemark: ", strerror(errno));