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.2.7 2007/01/18 12:57:16 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 = 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: %zu 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 " OFF_T_FMT "kb to buffer %s in-memory",
609 buff_err, (OFF_T_FMT_TYPE)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 (mmap_splitbuf != NULL) {
632 munmap(mmap_splitbuf, (size_t)mmap_splitsize);
633 mmap_splitbuf = NULL;
637 aclose(mmap_splitbuffer_fd);
638 amfree(mmap_filename);
642 amfree(mem_splitbuf);
648 put_syncpipe_fault_result(
654 handle = "<nohandle>";
656 q = squotef("[Taper syncpipe fault]");
657 putresult(TAPE_ERROR, "%s %s\n", handle, q);
658 log_add(L_ERROR, "tape-error %s %s", handle, q);
668 struct cmdargs cmdargs;
670 char *filename = NULL;
671 char *qfilename = NULL;
672 char *hostname = NULL;
673 char *diskname = NULL;
674 char *qdiskname = NULL;
676 char *datestamp = NULL;
677 char *split_diskbuffer = NULL;
678 char *id_string = NULL;
686 struct stat stat_file;
689 size_t fallback_splitsize = 0;
694 syncpipe_init(rdpipe, wrpipe);
696 /* must get START_TAPER before beginning */
699 cmd = getcmd(&cmdargs);
700 total_wait = stopclock();
702 if (cmd != START_TAPER || cmdargs.argc != 2) {
703 error("error [file_reader_side cmd %d argc %d]", cmd, cmdargs.argc);
707 /* pass start command on to tape writer */
709 taper_timestamp = newstralloc(taper_timestamp, cmdargs.argv[2]);
711 if (tapedev == NULL) {
712 if (getconf_str(CNF_TPCHANGER) == NULL) {
713 putresult(TAPE_ERROR, "[No tapedev or tpchanger defined]\n");
714 log_add(L_ERROR, "No tapedev or tpchanger defined");
715 dbprintf(("taper: No tapedev or tpchanger defined\n"));
719 tapedev = stralloc(tapedev);
723 if (syncpipe_put('S', 0) == -1) {
724 put_syncpipe_fault_result(NULL);
727 if (syncpipe_putstr(taper_timestamp) == -1) {
728 put_syncpipe_fault_result(NULL);
731 /* get result of start command */
733 tok = syncpipe_get(&tmpint);
736 put_syncpipe_fault_result(NULL);
740 putresult(TAPER_OK, "\n");
742 /* start is logged in writer */
746 /* no tape, bail out */
747 if ((result = syncpipe_getstr()) == NULL) {
748 put_syncpipe_fault_result(NULL);
750 q = squotef("[%s]", result);
751 putresult(TAPE_ERROR, "<nohandle> %s\n", q);
753 log_add(L_ERROR,"no-tape [%s]", "No writable valid tape found");
758 log_add(L_WARNING,"%s", c1);
764 log_add(L_WARNING,"%s", c1);
766 (void)syncpipe_put('e', 0); /* ACK error */
770 case 'H': /* Syncpipe I/O error */
771 /* No ACK syncpipe is down just exit */
772 put_syncpipe_fault_result(handle);
777 * Pipe read error: Communications is severed at least
778 * back to us. We send a blind 'Q' (quit) and we don't
779 * wait for a response...
781 syncpipe_put('Q', 0); /* ACK error */
782 error("error [communications pipe from writer severed]");
786 q = squotef("[syncpipe sequence fault: Expected 'S' or 'E']");
787 putresult(TAPE_ERROR, "<nohandle> %s\n", q);
788 log_add(L_ERROR, "no-tape %s]", q);
792 /* process further driver commands */
795 cmd = getcmd(&cmdargs);
796 if (cmd != QUIT && !tape_started) {
797 error("error [file_reader_side cmd %d without tape ready]", cmd);
800 total_wait = timesadd(total_wait, stopclock());
815 mode = MODE_PORT_WRITE;
816 cmdargs.argc++; /* true count of args */
819 if (a >= cmdargs.argc) {
820 error("error [taper PORT-WRITE: not enough args: handle]");
823 handle = newstralloc(handle, cmdargs.argv[a++]);
825 if (a >= cmdargs.argc) {
826 error("error [taper PORT-WRITE: not enough args: hostname]");
829 hostname = newstralloc(hostname, cmdargs.argv[a++]);
831 if (a >= cmdargs.argc) {
832 error("error [taper PORT-WRITE: not enough args: features]");
835 am_release_feature_set(their_features);
836 their_features = am_string_to_feature(cmdargs.argv[a++]);
838 if (a >= cmdargs.argc) {
839 error("error [taper PORT-WRITE: not enough args: diskname]");
842 qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
843 if (diskname != NULL)
845 diskname = unquote_string(qdiskname);
847 if (a >= cmdargs.argc) {
848 error("error [taper PORT-WRITE: not enough args: level]");
851 level = atoi(cmdargs.argv[a++]);
853 if (a >= cmdargs.argc) {
854 error("error [taper PORT-WRITE: not enough args: datestamp]");
857 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
859 if (a >= cmdargs.argc) {
860 error("error [taper PORT-WRITE: not enough args: splitsize]");
863 splitsize = OFF_T_ATOI(cmdargs.argv[a++]);
865 if (a >= cmdargs.argc) {
866 error("error [taper PORT-WRITE: not enough args: split_diskbuffer]");
869 split_diskbuffer = newstralloc(split_diskbuffer, cmdargs.argv[a++]);
871 if (a >= cmdargs.argc) {
872 error("error [taper PORT-WRITE: not enough args: fallback_splitsize]");
875 /* Must fit in memory... */
876 fallback_splitsize = (size_t)atoi(cmdargs.argv[a++]);
878 if (a != cmdargs.argc) {
879 error("error [taper file_reader_side PORT-WRITE: too many args: %d != %d]",
884 if (fallback_splitsize < 128 ||
885 fallback_splitsize > 64 * 1024 * 1024) {
886 error("error [bad value for fallback_splitsize]");
889 snprintf(level_str, SIZEOF(level_str), "%d", level);
890 id_string = newvstralloc(id_string, hostname, ":", qdiskname, ".",
893 create_split_buffer(split_diskbuffer, fallback_splitsize, id_string);
897 data_socket = stream_server(&data_port, 0, STREAM_BUFSIZE, 0);
898 if (data_socket < 0) {
901 m = vstralloc("[port create failure: ",
906 putresult(TAPE_ERROR, "%s %s\n", handle, q);
911 putresult(PORT, "%d\n", data_port);
913 if ((fd = stream_accept(data_socket, CONNECT_TIMEOUT,
914 0, STREAM_BUFSIZE)) == -1) {
915 q = squote("[port connect timeout]");
916 putresult(TAPE_ERROR, "%s %s\n", handle, q);
921 expected_splits = -1;
923 while(read_file(fd, handle, hostname, qdiskname, datestamp, level))
924 (void)fd; /* Quiet lint */
941 mode = MODE_FILE_WRITE;
942 cmdargs.argc++; /* true count of args */
945 if (a >= cmdargs.argc) {
946 error("error [taper FILE-WRITE: not enough args: handle]");
949 handle = newstralloc(handle, cmdargs.argv[a++]);
951 if (a >= cmdargs.argc) {
952 error("error [taper FILE-WRITE: not enough args: filename]");
955 qfilename = newstralloc(qfilename, cmdargs.argv[a++]);
956 if (filename != NULL)
958 filename = unquote_string(qfilename);
960 if (a >= cmdargs.argc) {
961 error("error [taper FILE-WRITE: not enough args: hostname]");
964 hostname = newstralloc(hostname, cmdargs.argv[a++]);
966 if (a >= cmdargs.argc) {
967 error("error [taper FILE-WRITE: not enough args: features]");
970 am_release_feature_set(their_features);
971 their_features = am_string_to_feature(cmdargs.argv[a++]);
973 if (a >= cmdargs.argc) {
974 error("error [taper FILE-WRITE: not enough args: diskname]");
977 qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
978 if (diskname != NULL)
980 diskname = unquote_string(qdiskname);
982 if (a >= cmdargs.argc) {
983 error("error [taper FILE-WRITE: not enough args: level]");
986 level = atoi(cmdargs.argv[a++]);
988 if (a >= cmdargs.argc) {
989 error("error [taper FILE-WRITE: not enough args: datestamp]");
992 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
994 if (a >= cmdargs.argc) {
995 error("error [taper FILE-WRITE: not enough args: splitsize]");
998 splitsize = OFF_T_ATOI(cmdargs.argv[a++]);
1000 if (a != cmdargs.argc) {
1001 error("error [taper file_reader_side FILE-WRITE: too many args: %d != %d]",
1005 if (holdfile_name != NULL) {
1006 filename = newstralloc(filename, holdfile_name);
1009 if ((expected_splits = predict_splits(filename)) < 0) {
1012 if (stat(filename, &stat_file)!=0) {
1013 q = squotef("[%s]", strerror(errno));
1014 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1018 if ((fd = open(filename, O_RDONLY)) == -1) {
1019 q = squotef("[%s]", strerror(errno));
1020 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1024 holdfile_path = stralloc(filename);
1025 holdfile_path_thischunk = stralloc(filename);
1026 holdfile_offset_thischunk = (off_t)0;
1028 while (read_file(fd,handle,hostname,qdiskname,datestamp,level)) {
1029 if (splitsize > (off_t)0 && holdfile_path_thischunk)
1030 filename = newstralloc(filename, holdfile_path_thischunk);
1031 if ((fd = open(filename, O_RDONLY)) == -1) {
1032 q = squotef("[%s]", strerror(errno));
1033 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1041 putresult(QUITTING, "\n");
1042 fprintf(stderr,"taper: DONE [idle wait: %s secs]\n",
1043 walltime_str(total_wait));
1045 (void)syncpipe_put('Q', 0); /* tell writer we're exiting gracefully */
1048 if ((wpid = wait(NULL)) != writerpid) {
1049 dbprintf(("taper: writer wait returned %u instead of %u: %s\n",
1050 (unsigned)wpid, (unsigned)writerpid, strerror(errno)));
1052 "taper: writer wait returned %u instead of %u: %s\n",
1053 (unsigned)wpid, (unsigned)writerpid, strerror(errno));
1057 free_split_buffer();
1060 free_server_config();
1061 amfree(taper_timestamp);
1064 amfree(changer_resultstr);
1067 amfree(conf_tapelist);
1069 amfree(config_name);
1070 amfree(holdfile_name);
1072 malloc_size_2 = malloc_inuse(&malloc_hist_2);
1074 if (malloc_size_1 != malloc_size_2) {
1075 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
1081 if (cmdargs.argc >= 1) {
1082 q = squote(cmdargs.argv[1]);
1083 } else if (cmdargs.argc >= 0) {
1084 q = squote(cmdargs.argv[0]);
1086 q = stralloc("(no input?)");
1088 putresult(BAD_COMMAND, "%s\n", q);
1103 fprintf(stderr, "%s: state", str1);
1104 for (i = j = 0; i < conf_tapebufs; i = j+1) {
1105 v = buftable[i].status;
1106 for(j = i; j < conf_tapebufs && buftable[j].status == v; j++)
1107 (void)j; /* Quiet lint */
1110 fprintf(stderr, " %d:", i);
1112 fprintf(stderr, " %d-%d:", i, j);
1128 fprintf(stderr, "%ld", v);
1132 fputc('\n', stderr);
1141 char bt[NUM_STR_SIZE];
1142 char status[NUM_STR_SIZE + 1];
1145 pn[0] = procname[0];
1147 snprintf(bt, SIZEOF(bt), "%d", (int)(bp-buftable));
1149 switch(bp->status) {
1151 snprintf(status, SIZEOF(status), "F" SIZE_T_FMT,
1152 (SIZE_T_FMT_TYPE)bp->size);
1156 snprintf(status, SIZEOF(status), "f");
1160 snprintf(status, SIZEOF(status), "E");
1164 snprintf(status, SIZEOF(status), "%ld", bp->status);
1168 str = vstralloc("taper: ", pn, ": [buf ", bt, ":=", status, "]", NULL);
1174 Handle moving to the next chunk of holding file, if any. Returns -1 for
1175 errors, 0 if there's no more file, or a positive integer for the amount of
1176 stuff read that'll go into 'rc' (XXX That's fugly, maybe that should just
1177 be another global. What is rc anyway, 'read count?' I keep thinking it
1178 should be 'return code')
1181 get_next_holding_file(
1189 struct stat stat_file;
1195 /* see if we're fresh out of file */
1196 if (file.cont_filename[0] == '\0') {
1199 } else if (stat(file.cont_filename, &stat_file) != 0) {
1202 *strclosing = newvstralloc(*strclosing, "can't stat: ",
1203 file.cont_filename, NULL);
1204 } else if ((fd = open(file.cont_filename,O_RDONLY)) == -1) {
1207 *strclosing = newvstralloc(*strclosing, "can't open: ",
1208 file.cont_filename, NULL);
1209 } else if ((fd != save_fd) && dup2(fd, save_fd) == -1) {
1212 *strclosing = newvstralloc(*strclosing, "can't dup2: ",
1213 file.cont_filename, NULL);
1218 holdfile_path = stralloc(file.cont_filename);
1219 quoted = quote_string(holdfile_path);
1220 fprintf(stderr, "taper: r: switching to next holding chunk '%s'\n",
1223 num_holdfile_chunks++;
1226 bp1.size = DISK_BLOCK_BYTES;
1227 bp1.buffer = alloc(DISK_BLOCK_BYTES);
1229 if (fd != save_fd) {
1234 rc1 = taper_fill_buffer(fd, &bp1, DISK_BLOCK_BYTES);
1237 err = (rc1 < 0) ? errno : 0;
1239 *strclosing = newvstralloc(*strclosing,
1240 "Can't read header: ",
1244 parse_file_header(bp1.buffer, &file, (size_t)rc1);
1247 bp1.buffer = bp->buffer + rc;
1249 rc1 = taper_fill_buffer(fd, &bp1, (size_t)tt_blocksize - rc);
1251 err = (rc1 < 0) ? errno : 0;
1254 *strclosing = newvstralloc(*strclosing,
1255 "Can't read data: ",
1285 int closing, bufnum, need_closing, nexting;
1288 char *strclosing = NULL;
1289 char seekerrstr[STR_SIZE];
1291 int header_written = 0;
1293 dumpfile_t first_file;
1294 dumpfile_t cur_holdfile;
1295 off_t kbytesread = (off_t)0;
1296 int header_read = 0;
1297 char *cur_filename = NULL;
1298 int retry_from_splitbuf = 0;
1299 char *splitbuf_rd_ptr = NULL;
1302 #ifdef HAVE_LIBVTBLC
1303 static char desc[45];
1304 static char vol_date[20];
1305 static char vol_label[45];
1306 #endif /* HAVE_LIBVTBLC */
1310 memset(&first_file, 0, SIZEOF(first_file));
1311 memset(&cur_holdfile, 0, SIZEOF(cur_holdfile));
1313 filesize = (off_t)0;
1319 /* don't break this if we're still on the same file as a previous init */
1320 if (cur_span_chunkstart <= (off_t)0) {
1323 } else if(mode == MODE_FILE_WRITE){
1324 memcpy(&file, save_holdfile, SIZEOF(dumpfile_t));
1325 memcpy(&cur_holdfile, save_holdfile, SIZEOF(dumpfile_t));
1329 fprintf(stderr, "taper: r: start file\n");
1333 for (bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1338 if (interactive || bufdebug)
1341 if ((cur_span_chunkstart >= (off_t)0) && (splitsize > (off_t)0)) {
1342 /* We're supposed to start at some later part of the file, not read the
1343 whole thing. "Seek" forward to where we want to be. */
1345 putresult(SPLIT_CONTINUE, "%s %s\n", handle, label);
1346 if ((mode == MODE_FILE_WRITE) && (cur_span_chunkstart > (off_t)0)) {
1347 char *quoted = quote_string(holdfile_path_thischunk);
1348 fprintf(stderr, "taper: r: seeking %s to " OFF_T_FMT " kb\n",
1350 (OFF_T_FMT_TYPE)holdfile_offset_thischunk);
1353 if (holdfile_offset_thischunk > maxseek) {
1354 snprintf(seekerrstr, SIZEOF(seekerrstr), "Can't seek by "
1355 OFF_T_FMT " kb (compiled for %d-bit file offsets), "
1356 "recompile with large file support or "
1357 "set holdingdisk chunksize to <" OFF_T_FMT " Mb",
1358 (OFF_T_FMT_TYPE)holdfile_offset_thischunk,
1359 (int)(sizeof(off_t) * 8),
1360 (OFF_T_FMT_TYPE)(maxseek/(off_t)1024));
1361 log_add(L_ERROR, "%s", seekerrstr);
1362 fprintf(stderr, "taper: r: FATAL: %s\n", seekerrstr);
1364 if (syncpipe_put('X', 0) == -1) {
1365 put_syncpipe_fault_result(handle);
1370 if (lseek(fd, holdfile_offset_thischunk*(off_t)1024, SEEK_SET) == (off_t)-1) {
1371 fprintf(stderr, "taper: r: FATAL: seek_holdfile lseek error "
1372 "while seeking into %s by "
1373 OFF_T_FMT "kb: %s\n", quoted,
1374 (OFF_T_FMT_TYPE)holdfile_offset_thischunk,
1377 if (syncpipe_put('X', 0) == -1) {
1378 put_syncpipe_fault_result(handle);
1384 } else if (mode == MODE_PORT_WRITE) {
1385 fprintf(stderr, "taper: r: re-reading split dump piece from buffer\n");
1387 retry_from_splitbuf = 1;
1388 splitbuf_rd_ptr = splitbuf;
1389 if (splitbuf_rd_ptr >= splitbuf_wr_ptr)
1390 retry_from_splitbuf = 0;
1392 if (cur_span_chunkstart > (off_t)0)
1393 header_read = 1; /* really initialized in prior run */
1396 /* tell writer to open tape */
1402 if (syncpipe_put('O', 0) == -1) {
1403 put_syncpipe_fault_result(handle);
1406 if (syncpipe_putstr(datestamp) == -1) {
1407 put_syncpipe_fault_result(handle);
1410 if (syncpipe_putstr(hostname) == -1) {
1411 put_syncpipe_fault_result(handle);
1414 if (syncpipe_putstr(qdiskname) == -1) {
1415 put_syncpipe_fault_result(handle);
1418 if (syncpipe_putint(level) == -1) {
1419 put_syncpipe_fault_result(handle);
1425 /* read file in loop */
1428 if ((tok = syncpipe_get(&bufnum)) == -1) {
1429 put_syncpipe_fault_result(handle);
1444 fprintf(stderr, "taper: r: got R%d\n", bufnum);
1449 if (syncpipe_put('C', 0) == -1) {
1450 put_syncpipe_fault_result(handle);
1459 break; /* ignore extra read tokens */
1464 if(bp->status != EMPTY || bufnum != (int)(bp - buftable)) {
1465 /* XXX this SHOULD NOT HAPPEN. Famous last words. */
1466 fprintf(stderr,"taper: panic: buffer mismatch at ofs "
1467 OFF_T_FMT ":\n", (OFF_T_FMT_TYPE)filesize);
1468 if(bufnum != (int)(bp - buftable)) {
1469 fprintf(stderr, " my buf %d but writer buf %d\n",
1470 (int)(bp-buftable), bufnum);
1472 fprintf(stderr,"buf %d state %s (%ld) instead of EMPTY\n",
1474 bp->status == FILLING? "FILLING" :
1475 bp->status == FULL? "FULL" : "EMPTY!?!?",
1480 dumpbufs("taper: after 1 sec");
1481 if (bp->status == EMPTY)
1482 fprintf(stderr, "taper: result now correct!\n");
1485 errstr = newstralloc(errstr,
1486 "[fatal buffer mismanagement bug]");
1488 putresult(TRYAGAIN, "%s %s\n", handle, q);
1489 cur_span_chunkstart = (off_t)0;
1491 log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1492 hostname, qdiskname, level, errstr);
1494 if (syncpipe_put('X', 0) == -1) {/* X == buffer snafu, bail */
1495 put_syncpipe_fault_result(handle);
1499 if ((tok = syncpipe_get(&bufnum)) == -1) {
1500 put_syncpipe_fault_result(handle);
1503 } while (tok != 'x');
1506 } /* end 'if (bf->status != EMPTY || bufnum != (int)(bp-buftable))' */
1508 bp->status = FILLING;
1509 buflen = header_read ? (size_t)tt_blocksize : DISK_BLOCK_BYTES;
1510 if (interactive || bufdebug)
1512 if (header_written == 0 &&
1513 (header_read == 1 || cur_span_chunkstart > (off_t)0)) {
1514 /* for split dumpfiles, modify headers for the second - nth
1515 pieces that signify that they're continuations of the last
1517 char *cont_filename;
1518 file.type = F_SPLIT_DUMPFILE;
1519 file.partnum = num_splits + 1;
1520 file.totalparts = expected_splits;
1521 cont_filename = stralloc(file.cont_filename);
1522 file.cont_filename[0] = '\0';
1523 build_header(bp->buffer, &file, tt_blocksize);
1525 if (cont_filename[0] != '\0') {
1526 file.type = F_CONT_DUMPFILE;
1527 strncpy(file.cont_filename, cont_filename,
1528 SIZEOF(file.cont_filename));
1530 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1532 if (interactive || bufdebug)
1534 bp->size = (ssize_t)tt_blocksize;
1535 rc = (ssize_t)tt_blocksize;
1537 amfree(cont_filename);
1538 } else if (retry_from_splitbuf) {
1539 /* quietly pull dump data from our in-memory cache, and the
1540 writer side need never know the wiser */
1541 memcpy(bp->buffer, splitbuf_rd_ptr, tt_blocksize);
1542 bp->size = (ssize_t)tt_blocksize;
1543 rc = (ssize_t)tt_blocksize;
1545 splitbuf_rd_ptr += tt_blocksize;
1546 if (splitbuf_rd_ptr >= splitbuf_wr_ptr)
1547 retry_from_splitbuf = 0;
1548 } else if ((rc = taper_fill_buffer(fd, bp, buflen)) < 0) {
1551 strclosing = newvstralloc(strclosing,"Can't read data: ",
1553 if (syncpipe_put('C', 0) == -1) {
1554 put_syncpipe_fault_result(handle);
1560 if (rc < (ssize_t)buflen) { /* switch to next holding file */
1563 if (file.cont_filename[0] != '\0') {
1564 cur_filename = newvstralloc(cur_filename, file.cont_filename, NULL);
1566 ret = get_next_holding_file(fd, bp, &strclosing, (size_t)rc);
1570 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1577 /* rebuild the header block, which might have CONT junk */
1578 if (header_read == 0) {
1579 char *cont_filename;
1580 /* write the "real" filename if the holding-file
1582 parse_file_header(bp->buffer, &file, (size_t)rc);
1583 parse_file_header(bp->buffer, &first_file, (size_t)rc);
1584 cont_filename = stralloc(file.cont_filename);
1585 file.cont_filename[0] = '\0';
1586 if (splitsize > (off_t)0) {
1587 file.type = F_SPLIT_DUMPFILE;
1589 file.totalparts = expected_splits;
1591 file.blocksize = tt_blocksize;
1592 build_header(bp->buffer, &file, tt_blocksize);
1594 file.type = F_CONT_DUMPFILE;
1596 /* add CONT_FILENAME back to in-memory header */
1597 strncpy(file.cont_filename, cont_filename,
1598 SIZEOF(file.cont_filename));
1599 if (interactive || bufdebug)
1601 bp->size = (ssize_t)tt_blocksize; /* output a full tape block */
1602 /* save the header, we'll need it if we jump tapes */
1603 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1606 amfree(cont_filename);
1608 filesize = kbytesread;
1612 fprintf(stderr,"taper: r: put W%d\n",(int)(bp-buftable));
1615 if (syncpipe_put('W', (int)(bp-buftable)) == -1) {
1616 put_syncpipe_fault_result(handle);
1622 if (((kbytesread + (off_t)(DISK_BLOCK_BYTES/1024)) >= splitsize)
1623 && (splitsize > (off_t)0) && !need_closing) {
1625 if (mode == MODE_PORT_WRITE) {
1626 splitbuf_wr_ptr = splitbuf;
1627 splitbuf_rd_ptr = splitbuf;
1628 memset(splitbuf, 0, SIZEOF(splitbuf));
1629 retry_from_splitbuf = 0;
1632 fprintf(stderr,"taper: r: end %s.%s.%s.%d part %d, "
1633 "splitting chunk that started at "
1634 OFF_T_FMT "kb after " OFF_T_FMT
1635 "kb (next chunk will start at "
1637 hostname, qdiskname, datestamp, level,
1639 (OFF_T_FMT_TYPE)cur_span_chunkstart,
1640 (OFF_T_FMT_TYPE)kbytesread,
1641 (OFF_T_FMT_TYPE)(cur_span_chunkstart+kbytesread));
1646 } /* end '(kbytesread >= splitsize && splitsize > 0)' */
1647 if (need_closing && rc <= 0) {
1648 if (syncpipe_put('C', 0) == -1) {
1649 put_syncpipe_fault_result(handle);
1655 kbytesread += (off_t)(rc / 1024);
1656 } /* end the 'if (!closing)' (successful buffer fill) */
1662 if (syncpipe_put('e', 0) == -1) { /* ACK error */
1663 put_syncpipe_fault_result(handle);
1667 if ((str = syncpipe_getstr()) == NULL) {
1668 put_syncpipe_fault_result(handle);
1672 errstr = newvstralloc(errstr, "[", str, "]", NULL);
1677 if (splitsize > (off_t)0) {
1678 /* we'll be restarting this chunk on the next tape */
1679 if (mode == MODE_FILE_WRITE) {
1683 putresult(SPLIT_NEEDNEXT, "%s " OFF_T_FMT "\n", handle,
1684 (OFF_T_FMT_TYPE)cur_span_chunkstart);
1685 log_add(L_INFO, "continuing %s:%s.%d on new tape from "
1686 OFF_T_FMT "kb mark: %s",
1687 hostname, qdiskname, level,
1688 (OFF_T_FMT_TYPE)cur_span_chunkstart, errstr);
1691 /* restart the entire dump (failure propagates to driver) */
1693 putresult(TRYAGAIN, "%s %s\n", handle, q);
1694 cur_span_chunkstart = (off_t)0;
1695 log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1696 hostname, qdiskname, level, errstr);
1700 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1701 log_add(L_FAIL, "%s %s %s %d [out of tape]",
1702 hostname, qdiskname, datestamp, level);
1703 log_add(L_ERROR,"no-tape [%s]", "No more writable valid tape found");
1715 cur_span_chunkstart += kbytesread; /* XXX possibly wrong */
1717 holdfile_name = newvstralloc(holdfile_name, cur_filename,
1720 amfree(holdfile_name);
1722 kbytesread = (off_t)0;
1723 amfree(cur_filename);
1726 if ((str = syncpipe_getstr()) == NULL) {
1727 put_syncpipe_fault_result(handle);
1731 label = newstralloc(label, str ? str : "(null)");
1733 if ((str = syncpipe_getstr()) == NULL) {
1734 put_syncpipe_fault_result(handle);
1738 filenum = atoi(str ? str : "-9876"); /* ??? */
1740 fprintf(stderr, "taper: reader-side: got label %s filenum %d\n",
1744 /* we'll need that file descriptor if we're gonna write more */
1749 runtime = stopclock();
1754 errstr = newvstralloc(errstr,
1755 "[input: ", strclosing, ": ",
1756 strerror(err), "]", NULL);
1759 errstr = newvstralloc(errstr,
1760 "[input: ", strerror(err), "]",
1763 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1766 if (splitsize != (off_t)0) {
1767 log_add(L_FAIL, "%s %s %s.%d %d %s", hostname, qdiskname,
1768 datestamp, num_splits, level, errstr);
1770 log_add(L_FAIL, "%s %s %s %d %s",
1771 hostname, qdiskname, datestamp, level, errstr);
1773 if ((str = syncpipe_getstr()) == NULL) { /* reap stats */
1774 put_syncpipe_fault_result(handle);
1780 char kb_str[NUM_STR_SIZE];
1781 char kps_str[NUM_STR_SIZE];
1784 rt = (double)(runtime.r.tv_sec) +
1785 ((double)(runtime.r.tv_usec) / 1000000.0);
1786 curdump_rt = timesadd(runtime, curdump_rt);
1787 snprintf(kb_str, SIZEOF(kb_str), OFF_T_FMT,
1788 (OFF_T_FMT_TYPE)filesize);
1789 snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
1790 (isnormal(rt) ? (double)filesize / rt : 0.0));
1791 if ((str = syncpipe_getstr()) == NULL) {
1792 put_syncpipe_fault_result(handle);
1795 errstr = newvstralloc(errstr,
1796 "[sec ", walltime_str(runtime),
1802 if (splitsize == (off_t)0) { /* Ordinary dump */
1804 /*@i@*/ if (first_file.is_partial) {
1805 putresult(PARTIAL, "%s %s %d %s\n",
1806 handle, label, filenum, q);
1807 log_add(L_PARTIAL, "%s %s %s %d %s",
1808 hostname, qdiskname, datestamp, level, errstr);
1810 putresult(DONE, "%s %s %d %s\n",
1811 handle, label, filenum, q);
1812 log_add(L_SUCCESS, "%s %s %s %d %s",
1813 hostname, qdiskname, datestamp, level, errstr);
1816 } else { /* Chunked dump */
1818 if (mode == MODE_FILE_WRITE) {
1819 holdfile_path_thischunk = stralloc(holdfile_path);
1820 holdfile_offset_thischunk = (lseek(fd, (off_t)0, SEEK_CUR))/(off_t)1024;
1822 save_holdfile = alloc(SIZEOF(dumpfile_t));
1824 memcpy(save_holdfile, &cur_holdfile,SIZEOF(dumpfile_t));
1826 log_add(L_CHUNK, "%s %s %s %d %d %s", hostname, qdiskname,
1827 datestamp, num_splits, level, errstr);
1828 if (!nexting) { /* split dump complete */
1829 rt = (double)(curdump_rt.r.tv_sec) +
1830 ((double)(curdump_rt.r.tv_usec) / 1000000.0);
1831 snprintf(kb_str, SIZEOF(kb_str), OFF_T_FMT,
1832 (OFF_T_FMT_TYPE)(filesize + cur_span_chunkstart));
1833 snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
1835 ((double)(filesize+cur_span_chunkstart)) / rt :
1838 errstr = newvstralloc(errstr,
1839 "[sec ", walltime_str(curdump_rt),
1846 putresult(DONE, "%s %s %d %s\n", handle, label,
1848 log_add(L_CHUNKSUCCESS, "%s %s %s %d %s",
1849 hostname, qdiskname, datestamp, level, errstr);
1850 amfree(save_holdfile);
1851 amfree(holdfile_path_thischunk);
1859 expected_splits = 0;
1860 amfree(holdfile_name);
1862 cur_span_chunkstart = (off_t)0;
1863 curdump_rt = times_zero;
1867 #ifdef HAVE_LIBVTBLC
1869 * We have 44 characters available for the label string:
1870 * use max 20 characters for hostname
1871 * max 20 characters for diskname
1872 * (it could contain a samba share or dos path)
1875 memset(desc, '\0', 45);
1877 strncpy(desc, hostname, 20);
1879 if ((len = strlen(hostname)) <= 20) {
1880 memset(desc + len, ' ', 1);
1883 memset(desc + 20, ' ', 1);
1887 strncpy(desc + offset, qdiskname, 20);
1889 if ((len = strlen(qdiskname)) <= 20) {
1890 memset(desc + offset + len, ' ', 1);
1891 offset = offset + len + 1;
1893 memset(desc + offset + 20, ' ', 1);
1894 offset = offset + 21;
1897 sprintf(desc + offset, "%i", level);
1899 strncpy(vol_label, desc, 44);
1900 fprintf(stderr, "taper: added vtbl label string %i: \"%s\"\n",
1901 filenum, vol_label);
1904 /* pass label string on to tape writer */
1905 if (syncpipe_put('L', filenum) == -1) {
1906 put_syncpipe_fault_result(handle);
1909 if (syncpipe_putstr(vol_label) == -1) {
1910 put_syncpipe_fault_result(handle);
1915 * reformat datestamp for later use with set_date from vtblc
1917 strptime(datestamp, "%Y%m%d", &backup_time);
1918 strftime(vol_date, 20, "%T %D", &backup_time);
1920 "taper: reformatted vtbl date string: \"%s\"->\"%s\"\n",
1924 /* pass date string on to tape writer */
1925 if (syncpipe_put('D', filenum) == -1) {
1926 put_syncpipe_fault_result(handle);
1929 if (syncpipe_putstr(vol_date) == -1) {
1930 put_syncpipe_fault_result(handle);
1934 #endif /* HAVE_LIBVTBLC */
1936 /* reset stuff that assumes we're on a new file */
1946 filesize = (off_t)0;
1947 if (syncpipe_put('O', 0) == -1) {
1948 put_syncpipe_fault_result(handle);
1951 if (syncpipe_putstr(datestamp) == -1) {
1952 put_syncpipe_fault_result(handle);
1955 if (syncpipe_putstr(hostname) == -1) {
1956 put_syncpipe_fault_result(handle);
1959 if (syncpipe_putstr(qdiskname) == -1) {
1960 put_syncpipe_fault_result(handle);
1963 if (syncpipe_putint(level) == -1) {
1964 put_syncpipe_fault_result(handle);
1967 for (bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1976 * Pipe read error: Communications is severed at least
1977 * back to us. We send a blind 'Q' (quit) and we don't
1978 * wait for a response...
1980 syncpipe_put('Q', 0); /* ACK error */
1981 fprintf(stderr, "taper: communications pipe from reader severed\n");
1985 q = squotef("[Taper syncpipe protocol error]");
1986 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1987 log_add(L_ERROR, "tape-error %s %s", handle, q);
2004 curptr = bp->buffer;
2006 cnt = fullread(fd, curptr, buflen);
2010 fputs("r0", stderr);
2015 case -1: /* error on read, punt */
2017 fputs("rE", stderr);
2023 if ((mode == MODE_PORT_WRITE) && (splitsize > (off_t)0)) {
2024 memcpy(splitbuf_wr_ptr, curptr, (size_t)cnt);
2025 splitbuf_wr_ptr += cnt;
2033 return ((ssize_t)bp->size);
2036 /* Given a dumpfile in holding, determine its size and figure out how many
2037 * times we'd have to split it.
2044 off_t total_kb = (off_t)0;
2045 off_t adj_splitsize = splitsize - (off_t)(DISK_BLOCK_BYTES / 1024);
2047 if (splitsize <= (off_t)0)
2050 if (adj_splitsize <= (off_t)0) {
2051 error("Split size must be > " OFF_T_FMT "k",
2052 (OFF_T_FMT_TYPE)(DISK_BLOCK_BYTES/1024));
2056 /* should only calculuate this once, not on retries etc */
2057 if (expected_splits != 0)
2058 return(expected_splits);
2060 total_kb = size_holding_files(filename, 1);
2062 if (total_kb <= (off_t)0) {
2063 fprintf(stderr, "taper: r: " OFF_T_FMT
2064 " kb holding file makes no sense, not precalculating splits\n",
2065 (OFF_T_FMT_TYPE)total_kb);
2070 fprintf(stderr, "taper: r: Total dump size should be " OFF_T_FMT
2071 "kb, chunk size is " OFF_T_FMT "kb\n",
2072 (OFF_T_FMT_TYPE)total_kb,
2073 (OFF_T_FMT_TYPE)splitsize);
2076 splits = (int)(total_kb / adj_splitsize);
2077 if ((splits == 0) || (total_kb % adj_splitsize))
2081 fprintf(stderr, "taper: r: Expecting to split into %d parts \n", splits);
2088 * ========================================================================
2092 times_t idlewait, rdwait, wrwait, fmwait;
2093 unsigned long total_writes;
2094 off_t total_tape_used;
2097 void write_file(void);
2098 int write_buffer(buffer_t *bp);
2114 #ifdef HAVE_LIBVTBLC
2117 #endif /* HAVE_LIBVTBLC */
2119 procname = "writer";
2120 syncpipe_init(getp, putp);
2122 idlewait = times_zero;
2123 if (tapedev != NULL) {
2124 tapedev = stralloc(tapedev);
2129 if ((tok = syncpipe_get(&tmpint)) == -1) {
2130 error("writer: Syncpipe failure before start");
2134 idlewait = timesadd(idlewait, stopclock());
2135 if (tok != 'S' && tok != 'Q' && !tape_started) {
2136 error("writer: token '%c' before start", tok);
2141 case 'H': /* Reader read pipe side is down */
2142 dbprintf(("writer: Communications with reader is down"));
2143 error("writer: Communications with reader is down");
2146 case 'S': /* start-tape */
2148 error("writer: multiple start requests");
2151 if ((str = syncpipe_getstr()) == NULL) {
2152 error("writer: Syncpipe failure");
2155 if (!first_tape(str ? str : "bad-datestamp")) {
2157 tapefd_close(tape_fd);
2160 if (syncpipe_put('E', 0) == -1) {
2161 error("writer: Syncpipe failure passing exit code");
2164 if (syncpipe_putstr(errstr) == -1) {
2165 error("writer: Syncpipe failure passing exit string");
2168 /* wait for reader to acknowledge error */
2170 if ((tok = syncpipe_get(&tmpint)) == -1) {
2171 error("writer: Syncpipe failure waiting for error ack");
2175 error("writer: got '%c' unexpectedly after error", tok);
2178 } while (tok != 'e');
2180 if (syncpipe_put('S', 0) == -1) {
2181 error("writer: syncpipe failure while starting tape");
2189 case 'O': /* open-output */
2190 if ((datestamp = syncpipe_getstr()) == NULL) {
2191 error("writer: Syncpipe failure during open");
2194 tapefd_setinfo_datestamp(tape_fd, datestamp);
2197 if ((hostname = syncpipe_getstr()) == NULL) {
2198 error("writer: Syncpipe failure fetching hostname");
2201 tapefd_setinfo_host(tape_fd, hostname);
2204 if ((diskname = syncpipe_getstr()) == NULL) {
2205 error("writer: Syncpipe failure fetching diskname");
2208 tapefd_setinfo_disk(tape_fd, diskname);
2210 if ((level = syncpipe_getint()) == -1) {
2211 error("writer: Syncpipe failure fetching level");
2214 tapefd_setinfo_level(tape_fd, level);
2218 #ifdef HAVE_LIBVTBLC
2219 case 'L': /* read vtbl label */
2221 if ((vol_label = syncpipe_getstr()) == NULL) {
2222 error("writer: Syncpipe failure fetching vrbl label");
2225 fprintf(stderr, "taper: read label string \"%s\" from pipe\n",
2227 strncpy(vtbl_entry[vtbl_no].label, vol_label, 45);
2230 case 'D': /* read vtbl date */
2232 if ((vol_date = syncpipe_getstr()) == NULL) {
2233 error("writer: Syncpipe failure fetching vrbl date");
2236 fprintf(stderr, "taper: read date string \"%s\" from pipe\n",
2238 strncpy(vtbl_entry[vtbl_no].date, vol_date, 20);
2240 #endif /* HAVE_LIBVTBLC */
2243 end_tape(0); /* XXX check results of end tape ?? */
2245 free_server_config();
2246 amfree(taper_timestamp);
2249 amfree(changer_resultstr);
2251 amfree(conf_tapelist);
2253 amfree(config_name);
2255 malloc_size_2 = malloc_inuse(&malloc_hist_2);
2257 if (malloc_size_1 != malloc_size_2) {
2258 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
2273 int full_buffers, i, bufnum;
2275 char number[NUM_STR_SIZE];
2276 char *rdwait_str, *wrwait_str, *fmwait_str;
2279 rdwait = wrwait = times_zero;
2287 fprintf(stderr, "taper: w: start file\n");
2292 * Tell the reader that the tape is open, and give it all the buffers.
2294 if (syncpipe_put('O', 0) == -1) {
2295 error("writer: Syncpipe failure starting write sequence");
2298 for (i = 0; i < conf_tapebufs; i++) {
2300 fprintf(stderr, "taper: w: put R%d\n", i);
2303 if (syncpipe_put('R', i) == -1) {
2304 error("writer: Syncpipe failure readying write buffers");
2310 * We write the filemark at the start of the file rather than at the end,
2311 * so that it can proceed in parallel with the reader's initial filling
2312 * up of the buffers.
2316 if (!write_filemark())
2318 fmwait = stopclock();
2327 * At the start of the file, or if the input can't keep up with the
2328 * tape, we enter STOPPED mode, which waits for most of the buffers
2329 * to fill up before writing to tape. This maximizes the amount of
2330 * data written in chunks to the tape drive, minimizing the number
2331 * of starts/stops, which in turn saves tape and time.
2335 fputs("[WS]", stderr);
2337 while (full_buffers < conf_tapebufs - THRESHOLD) {
2338 if ((tok = syncpipe_get(&bufnum)) == -1) {
2339 error("writer: Syncpipe failure during buffer advance");
2345 fprintf(stderr,"taper: w: got W%d\n",bufnum);
2350 rdwait = timesadd(rdwait, stopclock());
2355 * We start output when sufficient buffers have filled up, or at
2356 * end-of-file, whichever comes first. Here we drain all the buffers
2357 * that were waited on in STOPPED mode. If more full buffers come
2358 * in, then we will be STREAMING.
2361 while (full_buffers) {
2362 if (tt_file_pad && bp->size < (ssize_t)tt_blocksize) {
2363 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
2364 bp->size = (ssize_t)tt_blocksize;
2366 if (!write_buffer(bp))
2375 * With any luck, the input source is faster than the tape drive. In
2376 * this case, full buffers will appear in the circular queue faster
2377 * than we can write them, so the next buffer in the queue will always
2378 * be marked FULL by the time we get to it. If so, we'll stay in
2381 * On the other hand, if we catch up to the input and thus would have
2382 * to wait for buffers to fill, we are then STOPPED again.
2385 while (tok == 'W' && bp->status == FULL) {
2386 if ((tok = syncpipe_get(&bufnum)) == -1) {
2387 error("writer: Syncpipe failure advancing buffer");
2393 fprintf(stderr,"taper: w: got W%d\n",bufnum);
2396 if(bufnum != (int)(bp - buftable)) {
2398 "taper: tape-writer: my buf %d reader buf %d\n",
2399 (int)(bp-buftable), bufnum);
2401 if (syncpipe_put('E', 0) == -1) {
2402 error("writer: Syncpipe failure putting error token");
2405 if (syncpipe_putstr("writer-side buffer mismatch") == -1) {
2406 error("writer: Syncpipe failure putting error messgae");
2411 if (tt_file_pad && bp->size < (ssize_t)tt_blocksize) {
2412 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
2413 bp->size = (ssize_t)tt_blocksize;
2415 if (!write_buffer(bp))
2418 } else if (tok == 'Q') {
2420 } else if (tok == 'X') {
2421 goto reader_buffer_snafu;
2423 error("writer-side not expecting token: %c", tok);
2427 } while (tok == 'W');
2429 /* got close signal from reader, acknowledge it */
2432 goto reader_buffer_snafu;
2435 if (syncpipe_put('C', 0) == -1) {
2436 error("writer: Syncpipe failure putting close");
2440 /* tell reader the tape and file number */
2442 if (syncpipe_putstr(label) == -1) {
2443 error("writer: Syncpipe failure putting label");
2446 snprintf(number, SIZEOF(number), "%d", filenum);
2447 if (syncpipe_putstr(number) == -1) {
2448 error("writer: Syncpipe failure putting filenum");
2452 snprintf(number, SIZEOF(number), "%lu", total_writes);
2453 rdwait_str = stralloc(walltime_str(rdwait));
2454 wrwait_str = stralloc(walltime_str(wrwait));
2455 fmwait_str = stralloc(walltime_str(fmwait));
2456 errstr = newvstralloc(errstr,
2458 " writers ", number,
2459 " rdwait ", rdwait_str,
2460 " wrwait ", wrwait_str,
2461 " filemark ", fmwait_str,
2467 if (syncpipe_putstr(errstr) == -1) {
2468 error("writer: Syncpipe failure putting '%s'", errstr);
2472 /* XXX go to next tape if past tape size? */
2477 /* got tape error */
2479 if (syncpipe_put('T', 0) == -1) { /* next tape in place, try again */
2480 error("writer: Syncpipe failure during tape advance");
2484 if (syncpipe_put('E', 0) == -1) { /* no more tapes, fail */
2485 error("writer: Syncpipe failure during tape error");
2489 if (syncpipe_putstr(errstr) == -1) {
2490 error("writer: Syncpipe failure putting '%s'", errstr);
2495 /* wait for reader to acknowledge error */
2497 if ((tok = syncpipe_get(&tmpint)) == -1) {
2498 error("writer: syncpipe failure waiting for error ack");
2502 if (tok != 'W' && tok != 'C' && tok != 'e') {
2503 error("writer: got '%c' unexpectedly after error", tok);
2506 } while (tok != 'e');
2509 reader_buffer_snafu:
2510 if (syncpipe_put('x', 0) == -1) {
2511 error("writer: syncpipe failure putting buffer snafu");
2523 assert(bp->status == FULL);
2526 rc = tapefd_write(tape_fd, bp->buffer, (size_t)bp->size);
2527 if (rc == (ssize_t)bp->size) {
2528 #if defined(NEED_RESETOFS)
2529 static double tape_used_modulus_2gb = 0;
2532 * If the next write will go over the 2 GByte boundary, reset
2533 * the kernel concept of where we are to make sure it does not
2536 tape_used_modulus_2gb += (double)rc;
2537 if (tape_used_modulus_2gb + (double)rc > (double)0x7fffffff) {
2538 tape_used_modulus_2gb = 0;
2539 tapefd_resetofs(tape_fd);
2542 wrwait = timesadd(wrwait, stopclock());
2544 total_tape_used += (off_t)rc;
2546 if (interactive || bufdebug)
2552 fprintf(stderr, "taper: w: put R%d\n", (int)(bp-buftable));
2555 if (syncpipe_put('R', (int)(bp-buftable)) == -1) {
2556 error("writer: Syncpipe failure during advancing write bufffer");
2561 errstr = newvstralloc(errstr,
2563 (rc != -1) ? "short write" : strerror(errno),
2565 wrwait = timesadd(wrwait, stopclock());
2567 fputs("[WE]", stderr);
2576 REMOVE_SHARED_MEMORY();
2581 * Cleanup shared memory segments
2587 log_add(L_INFO, "Received signal %d", signum);
2594 * Installing signal handlers for signal whose default action is
2595 * process termination so that we can clean up shared memory
2599 install_signal_handlers(void)
2601 struct sigaction act;
2603 act.sa_handler = signal_handler;
2605 sigemptyset(&act.sa_mask);
2607 signal(SIGPIPE, SIG_IGN);
2609 if (sigaction(SIGINT, &act, NULL) != 0) {
2610 error("taper: couldn't install SIGINT handler [%s]", strerror(errno));
2614 if (sigaction(SIGHUP, &act, NULL) != 0) {
2615 error("taper: couldn't install SIGHUP handler [%s]", strerror(errno));
2619 if (sigaction(SIGTERM, &act, NULL) != 0) {
2620 error("taper: couldn't install SIGTERM handler [%s]", strerror(errno));
2624 if (sigaction(SIGUSR1, &act, NULL) != 0) {
2625 error("taper: couldn't install SIGUSR1 handler [%s]", strerror(errno));
2629 if (sigaction(SIGUSR2, &act, NULL) != 0) {
2630 error("taper: couldn't install SIGUSR2 handler [%s]", strerror(errno));
2634 if (sigaction(SIGALRM, &act, NULL) != 0) {
2635 error("taper: couldn't install SIGALRM handler [%s]", strerror(errno));
2642 * ========================================================================
2643 * SHARED-MEMORY BUFFER SUBSYSTEM
2657 shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0700);
2662 result = (char *)shmat(shmid, (SHM_ARG_TYPE *)NULL, 0);
2664 if (result == (char *)-1) {
2665 int save_errno = errno;
2669 error("shmat: %s", strerror(errno));
2681 if ((bufp != NULL) &&
2682 (shmdt((SHM_ARG_TYPE *)bufp) == -1)) {
2683 error("shmdt: %s", strerror(errno));
2689 destroy_buffers(void)
2692 return; /* nothing to destroy */
2693 if (shmctl(shmid, IPC_RMID, NULL) == -1) {
2694 error("shmctl: %s", strerror(errno));
2702 #ifdef HAVE_SYS_MMAN_H
2703 #include <sys/mman.h>
2707 # ifdef MAP_ANONYMOUS /* OSF/1-style */
2708 # define MAP_ANON MAP_ANONYMOUS
2709 # else /* SunOS4-style */
2711 # define ZERO_FILE "/dev/zero"
2725 shmfd = open(ZERO_FILE, O_RDWR);
2727 error("attach_buffers: could not open %s: %s",
2735 shmbuf = (char *) mmap((void *) 0,
2737 PROT_READ|PROT_WRITE,
2738 MAP_ANON|MAP_SHARED,
2748 if ((bufp != NULL) &&
2749 (munmap((void *)bufp, saved_size) == -1)) {
2750 error("detach_buffers: munmap: %s", strerror(errno));
2759 destroy_buffers(void)
2764 #error: must define either HAVE_SYSVSHM or HAVE_MMAP!
2771 * ========================================================================
2772 * SYNC-PIPE SUBSYSTEM
2776 int getpipe, putpipe;
2788 syncpipe_read_error(
2792 char buf[sizeof(char) + sizeof(int)];
2795 dbprintf(("syncpipe_get %s halting: Unexpected read EOF\n", procname));
2796 fprintf(stderr, "syncpipe_get %s halting: Unexpected read EOF\n", procname);
2797 } else if (rc < 0) {
2798 dbprintf(("syncpipe_get %s halting: Read error - %s\n",
2799 procname, strerror(errno)));
2800 fprintf(stderr, "syncpipe_get %s halting: Read error - %s\n",
2801 procname, strerror(errno));
2803 dbprintf(("syncpipe_get %s halting: Read "
2804 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2805 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2806 (SSIZE_T_FMT_TYPE)expected));
2807 fprintf(stderr, "syncpipe_get %s halting: Read "
2808 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2809 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2810 (SSIZE_T_FMT_TYPE)expected);
2812 /* Halt the other side if it's still alive */
2814 memset(&buf[1], 0, SIZEOF(int));
2815 if (write(putpipe, buf, SIZEOF(buf)))
2820 syncpipe_write_error(
2824 char buf[sizeof(char) + sizeof(int)];
2826 if (rc == 0) { /* EOF */
2827 dbprintf(("syncpipe %s halting: Write EOF\n", procname));
2828 fprintf(stderr, "syncpipe %s halting: Write EOF\n", procname);
2829 } else if (rc < 0) {
2830 dbprintf(("syncpipe %s halting: Write error - %s\n",
2831 procname, strerror(errno)));
2832 fprintf(stderr, "syncpipe %s halting: Write error - %s\n",
2833 procname, strerror(errno));
2835 dbprintf(("syncpipe %s halting: Write "
2836 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2837 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2838 (SSIZE_T_FMT_TYPE)expected));
2839 fprintf(stderr, "syncpipe %s halting: Write "
2840 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2841 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2842 (SSIZE_T_FMT_TYPE)expected);
2844 /* Halt the other side if it's still alive */
2846 memset(&buf[1], 0, SIZEOF(int));
2847 if (write(putpipe, buf, SIZEOF(buf)))
2856 char buf[SIZEOF(char) + SIZEOF(int)];
2858 memset(buf, 0, sizeof(buf));
2859 rc = fullread(getpipe, buf, SIZEOF(buf));
2860 if (rc != (ssize_t)sizeof(buf)) {
2861 syncpipe_read_error(rc, (ssize_t)sizeof(buf));
2865 if (bufdebug && *buf != 'R' && *buf != 'W') {
2866 fprintf(stderr,"taper: %c: getc %c\n", *procname, *buf);
2870 memcpy(intp, &buf[1], SIZEOF(int));
2875 syncpipe_getint(void)
2880 rc = fullread(getpipe, &i, SIZEOF(i));
2881 if (rc != (ssize_t)sizeof(i)) {
2882 syncpipe_read_error(rc, (ssize_t)sizeof(i));
2891 syncpipe_getstr(void)
2897 if ((len = syncpipe_getint()) <= 0) {
2898 fprintf(stderr, "syncpipe %s halting: Protocol error - "
2899 "Invalid string length (%d)\n", procname, len);
2900 syncpipe_put('H', 0); /* Halt the other side */
2905 str = alloc((size_t)len);
2907 rc = fullread(getpipe, str, (size_t)len);
2908 if (rc != (ssize_t)len) {
2909 syncpipe_read_error(rc, (ssize_t)len);
2921 char buf[sizeof(char) + sizeof(int)];
2925 memcpy(&buf[1], &intval, SIZEOF(int));
2926 if (bufdebug && buf[0] != 'R' && buf[0] != 'W') {
2927 fprintf(stderr,"taper: %c: putc %c\n",*procname,buf[0]);
2931 rc = fullwrite(putpipe, buf, SIZEOF(buf));
2932 if (rc != (ssize_t)sizeof(buf)) {
2933 syncpipe_write_error(rc, (ssize_t)sizeof(buf));
2945 rc = fullwrite(putpipe, &i, SIZEOF(i));
2946 if (rc != (ssize_t)sizeof(i)) {
2947 syncpipe_write_error(rc, (ssize_t)sizeof(i));
2961 str = "UNKNOWN syncpipe_putstr STRING";
2963 n = (ssize_t)strlen(str) + 1; /* send '\0' as well */
2964 syncpipe_putint((int)n);
2966 rc = fullwrite(putpipe, str, (size_t)n);
2968 syncpipe_write_error(rc, n);
2975 * ========================================================================
2976 * TAPE MANIPULATION SUBSYSTEM
2979 int label_tape(void);
2981 /* local functions */
2983 /* return 0 on success */
2984 /* return 1 on error and set errstr */
2988 char *conf_tapelist_old = NULL;
2990 static int first_call = 1;
2992 char *error_msg = NULL;
2998 if (taper_scan(NULL, &label, ×tamp, &tapedev, CHAR_taperscan_output_callback, &error_msg) < 0) {
2999 fprintf(stderr, "%s\n", error_msg);
3007 s = error_msg; r = NULL;
3008 while((s=strstr(s,"slot "))) { s += 5; r=s; };
3014 if ((tape_fd = tape_open(tapedev, O_WRONLY)) == -1) {
3015 if (errno == EACCES) {
3016 errstr = newstralloc2(errstr,
3017 "writing label: tape is write protected or I don't have write permission on ", tapedev);
3019 errstr = newstralloc2(errstr,
3020 "writing label: ", strerror(errno));
3025 tapefd_setinfo_length(tape_fd, tapetype_get_length(tt));
3027 tapefd_setinfo_datestamp(tape_fd, taper_timestamp);
3028 tapefd_setinfo_disk(tape_fd, label);
3029 result = tapefd_wrlabel(tape_fd, taper_timestamp, label, tt_blocksize);
3030 if (result != NULL) {
3031 errstr = newstralloc(errstr, result);
3036 fprintf(stderr, "taper: slot: %d wrote label `%s' date `%s'\n", slot,
3037 label, taper_timestamp);
3040 fprintf(stderr, "taper: wrote label `%s' date `%s'\n", label,
3045 #ifdef HAVE_LIBVTBLC
3046 /* store time for the first volume entry */
3048 tape_timep = localtime(&raw_time);
3049 strftime(start_datestr, 20, "%T %D", tape_timep);
3050 fprintf(stderr, "taper: got vtbl start time: %s\n", start_datestr);
3052 #endif /* HAVE_LIBVTBLC */
3054 if (strcmp(label, FAKE_LABEL) != 0) {
3055 if (cur_tape == 0) {
3056 conf_tapelist_old = stralloc2(conf_tapelist, ".yesterday");
3058 char cur_str[NUM_STR_SIZE];
3060 snprintf(cur_str, SIZEOF(cur_str), "%d", cur_tape - 1);
3061 conf_tapelist_old = vstralloc(conf_tapelist,
3062 ".today.", cur_str, NULL);
3065 if (write_tapelist(conf_tapelist_old)) {
3066 error("could not write tapelist: %s", strerror(errno));
3069 amfree(conf_tapelist_old);
3071 remove_tapelabel(label);
3072 add_tapelabel(taper_timestamp, label);
3073 if (write_tapelist(conf_tapelist)) {
3074 error("could not write tapelist: %s", strerror(errno));
3079 log_add(L_START, "datestamp %s label %s tape %d",
3080 taper_timestamp, label, cur_tape);
3081 if (first_call && strcmp(label, FAKE_LABEL) == 0) {
3083 log_add(L_WARNING, "tapedev is %s, dumps will be thrown away", tapedev);
3086 total_tape_used=(off_t)0;
3092 /* return 0 on error and set errstr */
3093 /* return 1 on success */
3096 char *new_datestamp)
3098 if ((have_changer = changer_init()) < 0) {
3099 error("changer initialization failed: %s", strerror(errno));
3104 taper_timestamp = newstralloc(taper_timestamp, new_datestamp);
3117 end_tape(writerror);
3119 if (++cur_tape >= runtapes)
3122 if (!label_tape()) {
3139 log_add(L_INFO, "tape %s kb " OFF_T_FMT " fm %d %s",
3141 (OFF_T_FMT_TYPE)((total_tape_used+(off_t)1023) / (off_t)1024),
3143 writerror? errstr : "[OK]");
3145 fprintf(stderr, "taper: writing end marker. [%s %s kb "
3146 OFF_T_FMT " fm %d]\n", label,
3147 writerror? "ERR" : "OK",
3148 (OFF_T_FMT_TYPE)((total_tape_used+(off_t)1023) / (off_t)1024),
3152 if (! write_filemark()) {
3157 result = tapefd_wrendmark(tape_fd, taper_timestamp, tt_blocksize);
3158 if (result != NULL) {
3159 errstr = newstralloc(errstr, result);
3166 #ifdef HAVE_LINUX_ZFTAPE_H
3167 if (tape_fd >= 0 && is_zftape(tapedev) == 1) {
3168 /* rewind the tape */
3170 if (tapefd_rewind(tape_fd) == -1 ) {
3171 errstr = newstralloc2(errstr, "rewinding tape: ", strerror(errno));
3175 /* close the tape */
3177 if (tapefd_close(tape_fd) == -1) {
3178 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
3184 #ifdef HAVE_LIBVTBLC
3185 /* update volume table */
3186 fprintf(stderr, "taper: updating volume table ...\n");
3189 if ((tape_fd = raw_tape_open(rawtapedev, O_RDWR)) == -1) {
3190 if (errno == EACCES) {
3191 errstr = newstralloc(errstr,
3192 "updating volume table: tape is write protected");
3194 errstr = newstralloc2(errstr,
3195 "updating volume table: ",
3201 /* read volume table */
3202 if ((num_volumes = read_vtbl(tape_fd, volumes, vtbl_buffer,
3203 &first_seg, &last_seg)) == -1 ) {
3204 errstr = newstralloc2(errstr,
3205 "reading volume table: ",
3210 /* set volume label and date for first entry */
3212 if (set_label(label, volumes, num_volumes, vtbl_no)) {
3213 errstr = newstralloc2(errstr,
3214 "setting label for entry 1: ",
3219 /* date of start writing this tape */
3220 if (set_date(start_datestr, volumes, num_volumes, vtbl_no)) {
3221 errstr = newstralloc2(errstr,
3222 "setting date for entry 1: ",
3227 /* set volume labels and dates for backup files */
3228 for (vtbl_no = 1; vtbl_no <= num_volumes - 2; vtbl_no++) {
3229 fprintf(stderr,"taper: label %i: %s, date %s\n",
3231 vtbl_entry[vtbl_no].label,
3232 vtbl_entry[vtbl_no].date);
3234 if (set_label(vtbl_entry[vtbl_no].label,
3235 volumes, num_volumes, vtbl_no)) {
3236 errstr = newstralloc2(errstr,
3237 "setting label for entry i: ",
3242 if (set_date(vtbl_entry[vtbl_no].date,
3243 volumes, num_volumes, vtbl_no)) {
3244 errstr = newstralloc2(errstr,
3245 "setting date for entry i: ",
3251 /* set volume label and date for last entry */
3252 vtbl_no = num_volumes - 1;
3253 if (set_label("AMANDA Tape End", volumes, num_volumes, vtbl_no)) {
3254 errstr = newstralloc2(errstr,
3255 "setting label for last entry: ",
3260 datestr = NULL; /* take current time */
3261 if (set_date(datestr, volumes, num_volumes, vtbl_no)) {
3262 errstr = newstralloc2(errstr,
3263 "setting date for last entry 1: ",
3268 /* write volume table back */
3269 if (write_vtbl(tape_fd, volumes, vtbl_buffer, num_volumes, first_seg,
3270 op_mode == trunc)) {
3271 errstr = newstralloc2(errstr,
3272 "writing volume table: ",
3278 fprintf(stderr, "taper: updating volume table: done.\n");
3280 #endif /* HAVE_LIBVTBLC */
3282 #endif /* !HAVE_LINUX_ZFTAPE_H */
3284 /* close the tape and let the OS write the final filemarks */
3288 if (tape_fd >= 0 && tapefd_close(tape_fd) == -1 && ! writerror) {
3289 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
3300 write_filemark(void)
3302 if (tapefd_weof(tape_fd, (off_t)1) == -1) {
3303 errstr = newstralloc2(errstr, "writing filemark: ", strerror(errno));