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
53 #define taper_debug(i,x) do { \
54 if ((i) <= debug_taper) { \
64 static int vtbl_no = -1;
66 static int offset = 0;
67 static char *datestr = NULL;
68 static char start_datestr[20];
69 static time_t raw_time;
70 static struct tm tape_time;
71 static struct tm backup_time;
72 static struct tm *tape_timep = &tape_time;
73 typedef struct vtbl_lbls {
77 static vtbl_lbls vtbl_entry[MAX_VOLUMES];
78 #endif /* HAVE_LIBVTBLC */
81 * XXX update stat collection/printing
82 * XXX advance to next tape first in next_tape
83 * XXX label is being read twice?
85 static off_t splitsize = (off_t)0; /* max size of dumpfile before split (Kb) */
86 static off_t mmap_splitsize = (off_t)0;
87 static char *mmap_filename = NULL;
88 static char *mmap_splitbuf = NULL;
89 static char *mem_splitbuf = NULL;
90 static char *splitbuf = NULL;
91 static off_t mem_splitsize = (off_t)0;
92 static char *splitbuf_wr_ptr = NULL; /* the number of Kb we've written into splitbuf */
93 int orig_holdfile = -1;
95 /* NBUFS replaced by conf_tapebufs */
96 /* #define NBUFS 20 */
97 static int conf_tapebufs;
99 static off_t maxseek = (off_t)1 << ((SIZEOF(off_t) * 8) - 11);
101 static char *holdfile_path = NULL;
102 static char *holdfile_path_thischunk = NULL;
103 static int num_holdfile_chunks = 0;
104 static off_t holdfile_offset_thischunk = (off_t)0;
105 static int mmap_splitbuffer_fd = -1;
108 #define MODE_FILE_WRITE 1
109 #define MODE_PORT_WRITE 2
111 static mode_t mode = MODE_NONE;
113 /* This is now the number of empties, not full bufs */
116 #define CONNECT_TIMEOUT 2*60
122 typedef struct buffer_s {
128 #define nextbuf(p) ((p) == buftable+conf_tapebufs-1? buftable : (p)+1)
129 #define prevbuf(p) ((p) == buftable? buftable+conf_tapebufs-1 : (p)-1)
132 int main(int main_argc, char **main_argv);
133 void file_reader_side(int rdpipe, int wrpipe);
134 void tape_writer_side(int rdpipe, int wrpipe);
135 void put_syncpipe_fault_result(char *handle);
137 /* shared-memory routines */
138 char *attach_buffers(size_t size);
139 void detach_buffers(char *bufp);
140 void destroy_buffers(void);
141 #define REMOVE_SHARED_MEMORY() \
142 detach_buffers(buffers); \
143 if (strcmp(procname, "reader") == 0) { \
147 /* synchronization pipe routines */
148 void syncpipe_init(int rd, int wr);
149 void syncpipe_read_error(ssize_t rc, ssize_t expected);
150 void syncpipe_write_error(ssize_t rc, ssize_t expected);
151 int syncpipe_get(int *intp);
152 int syncpipe_getint(void);
153 char *syncpipe_getstr(void);
154 int syncpipe_put(int ch, int intval);
155 int syncpipe_putint(int i);
156 int syncpipe_putstr(const char *str);
158 /* tape manipulation subsystem */
159 int first_tape(char *new_datestamp);
160 int next_tape(int writerr);
161 int end_tape(int writerr);
162 int write_filemark(void);
165 int seek_holdfile(int fd, buffer_t *bp, off_t kbytes);
167 /* signal handling */
168 static void install_signal_handlers(void);
169 static void signal_handler(int);
172 static void cleanup(void);
175 * ========================================================================
183 char *buffers = NULL;
184 buffer_t *buftable = NULL;
187 char *procname = "parent";
189 char *taper_timestamp = NULL;
194 char *tapedev = NULL;
195 char *tapetype = NULL;
196 tapetype_t *tt = NULL;
198 size_t tt_blocksize_kb;
201 static unsigned long malloc_hist_1, malloc_size_1;
202 static unsigned long malloc_hist_2, malloc_size_2;
204 dumpfile_t *save_holdfile = NULL;
205 off_t cur_span_chunkstart = (off_t)0; /* start of current split dump chunk (Kb) */
208 int expected_splits = 0;
209 int num_holdfiles = 0;
212 am_feature_t *their_features = NULL;
214 int runtapes, cur_tape, have_changer, tapedays;
215 char *labelstr, *conf_tapelist;
218 int first_seg, last_seg;
219 #endif /* HAVE_LIBVTBLC */
222 * ========================================================================
231 int p2c[2], c2p[2]; /* parent-to-child, child-to-parent pipes */
238 int new_argc, my_argc;
239 char **new_argv, **my_argv;
247 /* Don't die when child closes pipe */
248 signal(SIGPIPE, SIG_IGN);
250 malloc_size_1 = malloc_inuse(&malloc_hist_1);
252 parse_conf(main_argc, main_argv, &new_argc, &new_argv);
256 fprintf(stderr, "%s: pid %ld executable %s version %s\n",
257 get_pname(), (long) getpid(), my_argv[0], version());
258 dbprintf(("%s: pid %ld executable %s version %s\n",
259 get_pname(), (long) getpid(), my_argv[0], version()));
262 if (my_argc > 1 && my_argv[1][0] != '-') {
263 config_name = stralloc(my_argv[1]);
264 config_dir = vstralloc(CONFIG_DIR, "/", my_argv[1], "/", NULL);
268 char my_cwd[STR_SIZE];
270 if (getcwd(my_cwd, SIZEOF(my_cwd)) == NULL) {
271 error("cannot determine current working directory");
274 config_dir = stralloc2(my_cwd, "/");
275 if ((config_name = strrchr(my_cwd, '/')) != NULL) {
276 config_name = stralloc(config_name + 1);
282 install_signal_handlers();
285 /* print prompts and debug messages if running interactive */
287 interactive = (my_argc > 1 && strcmp(my_argv[1],"-t") == 0);
289 erroutput_type = ERR_INTERACTIVE;
291 erroutput_type = ERR_AMANDALOG;
292 set_logerror(logerror);
295 free_new_argv(new_argc, new_argv);
297 conffile = stralloc2(config_dir, CONFFILE_NAME);
298 if (read_conffile(conffile)) {
299 error("errors processing config file \"%s\"", conffile);
304 dbrename(config_name, DBG_SUBDIR_SERVER);
306 report_bad_conf_arg();
308 conf_tapelist = getconf_str(CNF_TAPELIST);
309 if (*conf_tapelist == '/') {
310 conf_tapelist = stralloc(conf_tapelist);
312 conf_tapelist = stralloc2(config_dir, conf_tapelist);
314 if (read_tapelist(conf_tapelist)) {
315 error("could not load tapelist \"%s\"", conf_tapelist);
319 tapedev = getconf_str(CNF_TAPEDEV);
321 tapedev = stralloc(tapedev);
322 tapetype = getconf_str(CNF_TAPETYPE);
323 tt = lookup_tapetype(tapetype);
325 rawtapedev = stralloc(getconf_str(CNF_RAWTAPEDEV));
326 #endif /* HAVE_LIBVTBLC */
327 tapedays = getconf_int(CNF_TAPECYCLE);
328 labelstr = getconf_str(CNF_LABELSTR);
330 runtapes = getconf_int(CNF_RUNTAPES);
333 conf_tapebufs = getconf_int(CNF_TAPEBUFS);
335 tt_blocksize_kb = (size_t)tapetype_get_blocksize(tt);
336 tt_blocksize = tt_blocksize_kb * 1024;
337 tt_file_pad = tapetype_get_file_pad(tt);
340 fprintf(stderr,"taper: running in interactive test mode\n");
341 dbprintf(("taper: running in interactive test mode\n"));
345 /* create read/write syncronization pipes */
348 error("creating sync pipes: %s", strerror(errno));
352 error("creating sync pipes: %s", strerror(errno));
356 /* create shared memory segment */
358 #if defined(HAVE_GETPAGESIZE)
359 page_size = (size_t)getpagesize();
360 fprintf(stderr, "%s: page size = " SIZE_T_FMT "\n",
361 get_pname(), (SIZE_T_FMT_TYPE)page_size);
362 dbprintf(("%s: page size = " SIZE_T_FMT "\n", get_pname(),
363 (SIZE_T_FMT_TYPE)page_size));
366 fprintf(stderr, "%s: getpagesize() not available, using " SIZE_T_FMT "\n",
367 get_pname(), page_size);
368 dbprintf((stderr, "%s: getpagesize() not available, using " SIZE_T_FMT "\n",
369 get_pname(), page_size));
371 buffer_size = am_round(tt_blocksize, page_size);
372 fprintf(stderr, "%s: buffer size is " SIZE_T_FMT "\n",
373 get_pname(), (SIZE_T_FMT_TYPE)buffer_size);
374 dbprintf(("%s: buffer size is " SIZE_T_FMT "\n",
375 get_pname(), (SIZE_T_FMT_TYPE)buffer_size));
376 while (conf_tapebufs > 0) {
378 size += conf_tapebufs * buffer_size;
379 size += conf_tapebufs * SIZEOF(buffer_t);
380 if ((buffers = attach_buffers(size)) != NULL) {
383 log_add(L_INFO, "attach_buffers: (%d tapebuf%s: " SIZE_T_FMT " bytes) %s",
385 (conf_tapebufs == 1) ? "" : "s",
390 if (buffers == NULL) {
391 error("cannot allocate shared memory");
395 /* page boundary offset */
396 i = (int)((buffers - (char *)0) & (page_size - 1));
398 first_buffer = buffers + page_size - i;
399 dbprintf(("%s: shared memory at %p, first buffer at %p\n",
402 (void *)first_buffer));
404 first_buffer = buffers;
407 /*LINTED first_buffer, conf_tapebufs and buffer size are all * pagesize */
408 buftable = (buffer_t *)(first_buffer + (conf_tapebufs * buffer_size));
409 memset(buftable, 0, conf_tapebufs * SIZEOF(buffer_t));
410 if (conf_tapebufs < 10) {
412 } else if (conf_tapebufs < 100) {
417 for (i = 0; i < conf_tapebufs; i++) {
418 buftable[i].buffer = first_buffer + i * buffer_size;
419 dbprintf(("%s: buffer[%0*d] at %p\n",
422 (void *)buftable[i].buffer));
424 dbprintf(("%s: buffer structures at %p for %d bytes\n",
427 (int)(conf_tapebufs * SIZEOF(buffer_t))));
429 /* fork off child writer process, parent becomes reader process */
430 switch(writerpid = fork()) {
432 error("fork: %s", strerror(errno));
439 tape_writer_side(p2c[0], c2p[1]);
440 error("tape writer terminated unexpectedly");
443 default: /* parent */
447 file_reader_side(c2p[0], p2c[1]);
448 error("file reader terminated unexpectedly");
458 * ========================================================================
462 int read_file(int fd, char *handle,
463 char *host, char *disk, char *datestamp,
465 ssize_t taper_fill_buffer(int fd, buffer_t *bp, size_t buflen);
466 void dumpbufs(char *str1);
467 void dumpstatus(buffer_t *bp);
468 ssize_t get_next_holding_file(int fd, buffer_t *bp, char **strclosing, size_t rc);
469 int predict_splits(char *filename);
470 void create_split_buffer(char *split_diskbuffer, size_t fallback_splitsize, char *id_string);
471 void free_split_buffer(void);
475 * Create a buffer, either in an mmapped file or in memory, where PORT-WRITE
476 * dumps can buffer the current split chunk in case of retry.
480 char *split_diskbuffer,
481 size_t fallback_splitsize,
484 char *buff_err = NULL;
486 char *splitbuffer_path = NULL;
488 /* don't bother if we're not actually splitting */
489 if (splitsize <= (off_t)0) {
491 splitbuf_wr_ptr = NULL;
496 #ifdef HAVE_SYS_MMAN_H
497 if (strcmp(split_diskbuffer, "NULL")) {
502 splitbuffer_path = vstralloc(split_diskbuffer,
505 /* different file, munmap the previous */
506 if (mmap_filename && strcmp(mmap_filename, splitbuffer_path) != 0) {
507 dbprintf(("create_split_buffer: new file %s\n", splitbuffer_path));
508 munmap(splitbuf, (size_t)mmap_splitsize);
509 aclose(mmap_splitbuffer_fd);
510 mmap_splitbuf = NULL;
511 amfree(mmap_filename);
514 if (!mmap_filename) {
515 dbprintf(("create_split_buffer: open file %s\n",
517 mmap_splitbuffer_fd = open(splitbuffer_path, O_RDWR|O_CREAT, 0600);
518 if (mmap_splitbuffer_fd == -1) {
519 buff_err = newvstralloc(buff_err, "open of ",
520 splitbuffer_path, "failed (",
521 strerror(errno), ")", NULL);
525 offset = lseek(mmap_splitbuffer_fd, (off_t)0, SEEK_END) / 1024;
526 if (offset < splitsize) { /* Increase file size */
527 dbprintf(("create_split_buffer: increase file size of %s to "
529 splitbuffer_path, (OFF_T_FMT_TYPE)splitsize));
531 dbprintf(("create_split_buffer: munmap old file %s\n",
533 munmap(splitbuf, (size_t)mmap_splitsize);
535 mmap_splitbuf = NULL;
537 nulls = alloc(1024); /* lame */
538 memset(nulls, 0, 1024);
539 for (c = offset; c < splitsize ; c += (off_t)1) {
540 if (fullwrite(mmap_splitbuffer_fd, nulls, 1024) < 1024) {
541 buff_err = newvstralloc(buff_err, "write to ",
543 "failed (", strerror(errno),
546 if (c <= (off_t)fallback_splitsize) {
556 if (mmap_splitsize < splitsize*1024) {
557 mmap_splitsize = splitsize*1024;
558 mmap_filename = stralloc(splitbuffer_path);
559 dbprintf(("create_split_buffer: mmap file %s for " OFF_T_FMT "kb\n",
560 mmap_filename,(OFF_T_FMT_TYPE)splitsize));
561 mmap_splitbuf = mmap(NULL, (size_t)mmap_splitsize,
562 PROT_READ|PROT_WRITE,
563 MAP_SHARED, mmap_splitbuffer_fd, (off_t)0);
564 if (mmap_splitbuf == (char*)-1) {
565 buff_err = newvstralloc(buff_err, "mmap failed (",
566 strerror(errno), ")", NULL);
567 aclose(mmap_splitbuffer_fd);
568 amfree(mmap_filename);
570 mmap_splitbuf = NULL;
574 quoted = quote_string(splitbuffer_path);
576 "taper: r: buffering " OFF_T_FMT
577 "kb split chunks in mmapped file %s\n",
578 (OFF_T_FMT_TYPE)splitsize, quoted);
579 dbprintf(("taper: r: buffering " OFF_T_FMT
580 "kb split chunks in mmapped file %s\n",
581 (OFF_T_FMT_TYPE)splitsize, quoted));
582 amfree(splitbuffer_path);
585 splitbuf = mmap_splitbuf;
586 splitbuf_wr_ptr = splitbuf;
589 buff_err = stralloc("no split_diskbuffer specified");
592 (void)split_diskbuffer; /* Quite unused parameter warning */
593 buff_err = stralloc("mman.h not available");
597 (void)split_diskbuffer; /* Quite unused parameter warning */
598 buff_err = stralloc("mmap not available");
603 Buffer split dumps in memory, if we can't use a file.
606 amfree(splitbuffer_path);
607 splitsize = (off_t)fallback_splitsize;
608 dbprintf(("create_split_buffer: fallback size " OFF_T_FMT "\n",
609 (OFF_T_FMT_TYPE)splitsize));
611 "%s: using fallback split size of " OFF_T_FMT "kb to buffer %s in-memory",
612 buff_err, (OFF_T_FMT_TYPE)splitsize, id_string);
614 if (splitsize > mem_splitsize) {
615 amfree(mem_splitbuf);
616 mem_splitbuf = alloc(fallback_splitsize * 1024);
617 mem_splitsize = fallback_splitsize;
618 dbprintf(("create_split_buffer: alloc buffer size " OFF_T_FMT "\n",
619 (OFF_T_FMT_TYPE)splitsize *1024));
621 splitbuf = mem_splitbuf;
622 splitbuf_wr_ptr = splitbuf;
626 * Free up resources that create_split_buffer eats.
629 free_split_buffer(void)
631 if (mmap_splitbuffer_fd != -1) {
633 #ifdef HAVE_SYS_MMAN_H
634 if (mmap_splitbuf != NULL) {
635 munmap(mmap_splitbuf, (size_t)mmap_splitsize);
636 mmap_splitbuf = NULL;
640 aclose(mmap_splitbuffer_fd);
641 amfree(mmap_filename);
645 amfree(mem_splitbuf);
651 put_syncpipe_fault_result(
657 handle = "<nohandle>";
659 q = squotef("[Taper syncpipe fault]");
660 putresult(TAPE_ERROR, "%s %s\n", handle, q);
661 log_add(L_ERROR, "tape-error %s %s", handle, q);
671 struct cmdargs cmdargs;
673 char *filename = NULL;
674 char *qfilename = NULL;
675 char *hostname = NULL;
676 char *diskname = NULL;
677 char *qdiskname = NULL;
679 char *datestamp = NULL;
680 char *split_diskbuffer = NULL;
681 char *id_string = NULL;
689 struct stat stat_file;
692 size_t fallback_splitsize = 0;
697 syncpipe_init(rdpipe, wrpipe);
699 /* must get START_TAPER before beginning */
702 cmd = getcmd(&cmdargs);
703 total_wait = stopclock();
705 if (cmd != START_TAPER || cmdargs.argc != 2) {
706 error("error [file_reader_side cmd %d argc %d]", cmd, cmdargs.argc);
710 /* pass start command on to tape writer */
712 taper_timestamp = newstralloc(taper_timestamp, cmdargs.argv[2]);
714 if (tapedev == NULL) {
715 if (getconf_str(CNF_TPCHANGER) == NULL) {
716 putresult(TAPE_ERROR, "[No tapedev or tpchanger defined]\n");
717 log_add(L_ERROR, "No tapedev or tpchanger defined");
718 dbprintf(("taper: No tapedev or tpchanger defined\n"));
722 tapedev = stralloc(tapedev);
726 if (syncpipe_put('S', 0) == -1) {
727 put_syncpipe_fault_result(NULL);
730 if (syncpipe_putstr(taper_timestamp) == -1) {
731 put_syncpipe_fault_result(NULL);
734 /* get result of start command */
736 tok = syncpipe_get(&tmpint);
739 put_syncpipe_fault_result(NULL);
743 putresult(TAPER_OK, "\n");
745 /* start is logged in writer */
749 /* no tape, bail out */
750 if ((result = syncpipe_getstr()) == NULL) {
751 put_syncpipe_fault_result(NULL);
753 q = squotef("[%s]", result);
754 putresult(TAPE_ERROR, "<nohandle> %s\n", q);
756 log_add(L_ERROR,"no-tape [%s]", "No writable valid tape found");
761 log_add(L_WARNING,"%s", c1);
767 log_add(L_WARNING,"%s", c1);
769 (void)syncpipe_put('e', 0); /* ACK error */
773 case 'H': /* Syncpipe I/O error */
774 /* No ACK syncpipe is down just exit */
775 put_syncpipe_fault_result(handle);
780 * Pipe read error: Communications is severed at least
781 * back to us. We send a blind 'Q' (quit) and we don't
782 * wait for a response...
784 syncpipe_put('Q', 0); /* ACK error */
785 error("error [communications pipe from writer severed]");
789 q = squotef("[syncpipe sequence fault: Expected 'S' or 'E']");
790 putresult(TAPE_ERROR, "<nohandle> %s\n", q);
791 log_add(L_ERROR, "no-tape %s]", q);
795 /* process further driver commands */
798 cmd = getcmd(&cmdargs);
799 if (cmd != QUIT && !tape_started) {
800 error("error [file_reader_side cmd %d without tape ready]", cmd);
803 total_wait = timesadd(total_wait, stopclock());
818 mode = MODE_PORT_WRITE;
819 cmdargs.argc++; /* true count of args */
822 if (a >= cmdargs.argc) {
823 error("error [taper PORT-WRITE: not enough args: handle]");
826 handle = newstralloc(handle, cmdargs.argv[a++]);
828 if (a >= cmdargs.argc) {
829 error("error [taper PORT-WRITE: not enough args: hostname]");
832 hostname = newstralloc(hostname, cmdargs.argv[a++]);
834 if (a >= cmdargs.argc) {
835 error("error [taper PORT-WRITE: not enough args: features]");
838 am_release_feature_set(their_features);
839 their_features = am_string_to_feature(cmdargs.argv[a++]);
841 if (a >= cmdargs.argc) {
842 error("error [taper PORT-WRITE: not enough args: diskname]");
845 qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
846 if (diskname != NULL)
848 diskname = unquote_string(qdiskname);
850 if (a >= cmdargs.argc) {
851 error("error [taper PORT-WRITE: not enough args: level]");
854 level = atoi(cmdargs.argv[a++]);
856 if (a >= cmdargs.argc) {
857 error("error [taper PORT-WRITE: not enough args: datestamp]");
860 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
862 if (a >= cmdargs.argc) {
863 error("error [taper PORT-WRITE: not enough args: splitsize]");
866 splitsize = OFF_T_ATOI(cmdargs.argv[a++]);
867 if (SIZEOF_OFF_T == 4 && splitsize > 1048576) { /* 1G in 32 bits */
871 if (a >= cmdargs.argc) {
872 error("error [taper PORT-WRITE: not enough args: split_diskbuffer]");
875 split_diskbuffer = newstralloc(split_diskbuffer, cmdargs.argv[a++]);
877 if (a >= cmdargs.argc) {
878 error("error [taper PORT-WRITE: not enough args: fallback_splitsize]");
881 /* Must fit in memory... */
882 fallback_splitsize = (size_t)atoi(cmdargs.argv[a++]);
883 if (SIZEOF_OFF_T == 4 && fallback_splitsize > 1048576) { /* 1G */
884 fallback_splitsize = 1048576;
887 if (a != cmdargs.argc) {
888 error("error [taper file_reader_side PORT-WRITE: too many args: %d != %d]",
893 if (fallback_splitsize < 128 ||
894 fallback_splitsize > 64 * 1024 * 1024) {
895 error("error [bad value for fallback_splitsize]");
898 snprintf(level_str, SIZEOF(level_str), "%d", level);
899 id_string = newvstralloc(id_string, hostname, ":", qdiskname, ".",
902 create_split_buffer(split_diskbuffer, fallback_splitsize, id_string);
906 data_socket = stream_server(&data_port, 0, STREAM_BUFSIZE, 0);
907 if (data_socket < 0) {
910 m = vstralloc("[port create failure: ",
915 putresult(TAPE_ERROR, "%s %s\n", handle, q);
920 putresult(PORT, "%d\n", data_port);
922 if ((fd = stream_accept(data_socket, CONNECT_TIMEOUT,
923 0, STREAM_BUFSIZE)) == -1) {
924 q = squote("[port connect timeout]");
925 putresult(TAPE_ERROR, "%s %s\n", handle, q);
930 expected_splits = -1;
932 while(read_file(fd, handle, hostname, qdiskname, datestamp, level))
933 (void)fd; /* Quiet lint */
950 mode = MODE_FILE_WRITE;
951 cmdargs.argc++; /* true count of args */
954 if (a >= cmdargs.argc) {
955 error("error [taper FILE-WRITE: not enough args: handle]");
958 handle = newstralloc(handle, cmdargs.argv[a++]);
960 if (a >= cmdargs.argc) {
961 error("error [taper FILE-WRITE: not enough args: filename]");
964 qfilename = newstralloc(qfilename, cmdargs.argv[a++]);
965 if (filename != NULL)
967 filename = unquote_string(qfilename);
969 if (a >= cmdargs.argc) {
970 error("error [taper FILE-WRITE: not enough args: hostname]");
973 hostname = newstralloc(hostname, cmdargs.argv[a++]);
975 if (a >= cmdargs.argc) {
976 error("error [taper FILE-WRITE: not enough args: features]");
979 am_release_feature_set(their_features);
980 their_features = am_string_to_feature(cmdargs.argv[a++]);
982 if (a >= cmdargs.argc) {
983 error("error [taper FILE-WRITE: not enough args: diskname]");
986 qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
987 if (diskname != NULL)
989 diskname = unquote_string(qdiskname);
991 if (a >= cmdargs.argc) {
992 error("error [taper FILE-WRITE: not enough args: level]");
995 level = atoi(cmdargs.argv[a++]);
997 if (a >= cmdargs.argc) {
998 error("error [taper FILE-WRITE: not enough args: datestamp]");
1001 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
1003 if (a >= cmdargs.argc) {
1004 error("error [taper FILE-WRITE: not enough args: splitsize]");
1007 splitsize = OFF_T_ATOI(cmdargs.argv[a++]);
1009 if (a != cmdargs.argc) {
1010 error("error [taper file_reader_side FILE-WRITE: too many args: %d != %d]",
1014 if (holdfile_name != NULL) {
1015 filename = newstralloc(filename, holdfile_name);
1018 if ((expected_splits = predict_splits(filename)) < 0) {
1021 if (stat(filename, &stat_file)!=0) {
1022 q = squotef("[%s]", strerror(errno));
1023 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1027 if ((fd = open(filename, O_RDONLY)) == -1) {
1028 q = squotef("[%s]", strerror(errno));
1029 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1033 holdfile_path = stralloc(filename);
1034 holdfile_path_thischunk = stralloc(filename);
1035 holdfile_offset_thischunk = (off_t)0;
1037 while (read_file(fd,handle,hostname,qdiskname,datestamp,level)) {
1038 if (splitsize > (off_t)0 && holdfile_path_thischunk)
1039 filename = newstralloc(filename, holdfile_path_thischunk);
1040 if ((fd = open(filename, O_RDONLY)) == -1) {
1041 q = squotef("[%s]", strerror(errno));
1042 putresult(TAPE_ERROR, "%s %s\n", handle, q);
1050 putresult(QUITTING, "\n");
1051 fprintf(stderr,"taper: DONE [idle wait: %s secs]\n",
1052 walltime_str(total_wait));
1054 (void)syncpipe_put('Q', 0); /* tell writer we're exiting gracefully */
1057 if ((wpid = wait(NULL)) != writerpid) {
1058 dbprintf(("taper: writer wait returned %u instead of %u: %s\n",
1059 (unsigned)wpid, (unsigned)writerpid, strerror(errno)));
1061 "taper: writer wait returned %u instead of %u: %s\n",
1062 (unsigned)wpid, (unsigned)writerpid, strerror(errno));
1066 free_split_buffer();
1069 amfree(taper_timestamp);
1072 amfree(changer_resultstr);
1075 amfree(conf_tapelist);
1077 amfree(config_name);
1078 amfree(holdfile_name);
1080 malloc_size_2 = malloc_inuse(&malloc_hist_2);
1082 if (malloc_size_1 != malloc_size_2) {
1083 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
1089 if (cmdargs.argc >= 1) {
1090 q = squote(cmdargs.argv[1]);
1091 } else if (cmdargs.argc >= 0) {
1092 q = squote(cmdargs.argv[0]);
1094 q = stralloc("(no input?)");
1096 putresult(BAD_COMMAND, "%s\n", q);
1111 fprintf(stderr, "%s: state", str1);
1112 for (i = j = 0; i < conf_tapebufs; i = j+1) {
1113 v = buftable[i].status;
1114 for(j = i; j < conf_tapebufs && buftable[j].status == v; j++)
1115 (void)j; /* Quiet lint */
1118 fprintf(stderr, " %d:", i);
1120 fprintf(stderr, " %d-%d:", i, j);
1136 fprintf(stderr, "%ld", v);
1140 fputc('\n', stderr);
1149 char bt[NUM_STR_SIZE];
1150 char status[NUM_STR_SIZE + 1];
1153 pn[0] = procname[0];
1155 snprintf(bt, SIZEOF(bt), "%d", (int)(bp-buftable));
1157 switch(bp->status) {
1159 snprintf(status, SIZEOF(status), "F" SIZE_T_FMT,
1160 (SIZE_T_FMT_TYPE)bp->size);
1164 snprintf(status, SIZEOF(status), "f");
1168 snprintf(status, SIZEOF(status), "E");
1172 snprintf(status, SIZEOF(status), "%ld", bp->status);
1176 str = vstralloc("taper: ", pn, ": [buf ", bt, ":=", status, "]", NULL);
1182 Handle moving to the next chunk of holding file, if any. Returns -1 for
1183 errors, 0 if there's no more file, or a positive integer for the amount of
1184 stuff read that'll go into 'rc' (XXX That's fugly, maybe that should just
1185 be another global. What is rc anyway, 'read count?' I keep thinking it
1186 should be 'return code')
1189 get_next_holding_file(
1197 struct stat stat_file;
1203 /* see if we're fresh out of file */
1204 if (file.cont_filename[0] == '\0') {
1207 } else if (stat(file.cont_filename, &stat_file) != 0) {
1210 *strclosing = newvstralloc(*strclosing, "can't stat: ",
1211 file.cont_filename, NULL);
1212 } else if ((fd = open(file.cont_filename,O_RDONLY)) == -1) {
1215 *strclosing = newvstralloc(*strclosing, "can't open: ",
1216 file.cont_filename, NULL);
1217 } else if ((fd != save_fd) && dup2(fd, save_fd) == -1) {
1220 *strclosing = newvstralloc(*strclosing, "can't dup2: ",
1221 file.cont_filename, NULL);
1226 holdfile_path = stralloc(file.cont_filename);
1227 quoted = quote_string(holdfile_path);
1228 fprintf(stderr, "taper: r: switching to next holding chunk '%s'\n",
1231 num_holdfile_chunks++;
1234 bp1.size = DISK_BLOCK_BYTES;
1235 bp1.buffer = alloc(DISK_BLOCK_BYTES);
1237 if (fd != save_fd) {
1242 rc1 = taper_fill_buffer(fd, &bp1, DISK_BLOCK_BYTES);
1245 err = (rc1 < 0) ? errno : 0;
1247 *strclosing = newvstralloc(*strclosing,
1248 "Can't read header: ",
1252 parse_file_header(bp1.buffer, &file, (size_t)rc1);
1255 bp1.buffer = bp->buffer + rc;
1257 rc1 = taper_fill_buffer(fd, &bp1, (size_t)tt_blocksize - rc);
1259 err = (rc1 < 0) ? errno : 0;
1262 *strclosing = newvstralloc(*strclosing,
1263 "Can't read data: ",
1293 int closing, bufnum, need_closing, nexting;
1296 char *strclosing = NULL;
1297 char seekerrstr[STR_SIZE];
1299 int header_written = 0;
1301 dumpfile_t first_file;
1302 dumpfile_t cur_holdfile;
1303 off_t kbytesread = (off_t)0;
1304 int header_read = 0;
1305 char *cur_filename = NULL;
1306 int retry_from_splitbuf = 0;
1307 char *splitbuf_rd_ptr = NULL;
1310 #ifdef HAVE_LIBVTBLC
1311 static char desc[45];
1312 static char vol_date[20];
1313 static char vol_label[45];
1314 #endif /* HAVE_LIBVTBLC */
1318 memset(&first_file, 0, SIZEOF(first_file));
1319 memset(&cur_holdfile, 0, SIZEOF(cur_holdfile));
1321 filesize = (off_t)0;
1327 /* don't break this if we're still on the same file as a previous init */
1328 if (cur_span_chunkstart <= (off_t)0) {
1331 } else if(mode == MODE_FILE_WRITE){
1332 memcpy(&file, save_holdfile, SIZEOF(dumpfile_t));
1333 memcpy(&cur_holdfile, save_holdfile, SIZEOF(dumpfile_t));
1336 taper_debug(1, ("taper: r: start file\n"));
1338 for (bp = buftable; bp < buftable + conf_tapebufs; bp++) {
1343 if (interactive || debug_taper >= 1)
1346 if ((cur_span_chunkstart >= (off_t)0) && (splitsize > (off_t)0)) {
1347 /* We're supposed to start at some later part of the file, not read the
1348 whole thing. "Seek" forward to where we want to be. */
1350 putresult(SPLIT_CONTINUE, "%s %s\n", handle, label);
1351 if ((mode == MODE_FILE_WRITE) && (cur_span_chunkstart > (off_t)0)) {
1352 char *quoted = quote_string(holdfile_path_thischunk);
1353 fprintf(stderr, "taper: r: seeking %s to " OFF_T_FMT " kb\n",
1355 (OFF_T_FMT_TYPE)holdfile_offset_thischunk);
1358 if (holdfile_offset_thischunk > maxseek) {
1359 snprintf(seekerrstr, SIZEOF(seekerrstr), "Can't seek by "
1360 OFF_T_FMT " kb (compiled for %d-bit file offsets), "
1361 "recompile with large file support or "
1362 "set holdingdisk chunksize to <" OFF_T_FMT " Mb",
1363 (OFF_T_FMT_TYPE)holdfile_offset_thischunk,
1364 (int)(sizeof(off_t) * 8),
1365 (OFF_T_FMT_TYPE)(maxseek/(off_t)1024));
1366 log_add(L_ERROR, "%s", seekerrstr);
1367 fprintf(stderr, "taper: r: FATAL: %s\n", seekerrstr);
1369 if (syncpipe_put('X', 0) == -1) {
1370 put_syncpipe_fault_result(handle);
1375 if (lseek(fd, holdfile_offset_thischunk*(off_t)1024, SEEK_SET) == (off_t)-1) {
1376 fprintf(stderr, "taper: r: FATAL: seek_holdfile lseek error "
1377 "while seeking into %s by "
1378 OFF_T_FMT "kb: %s\n", quoted,
1379 (OFF_T_FMT_TYPE)holdfile_offset_thischunk,
1382 if (syncpipe_put('X', 0) == -1) {
1383 put_syncpipe_fault_result(handle);
1389 } else if (mode == MODE_PORT_WRITE) {
1390 fprintf(stderr, "taper: r: re-reading split dump piece from buffer\n");
1392 retry_from_splitbuf = 1;
1393 splitbuf_rd_ptr = splitbuf;
1394 if (splitbuf_rd_ptr >= splitbuf_wr_ptr)
1395 retry_from_splitbuf = 0;
1397 if (cur_span_chunkstart > (off_t)0)
1398 header_read = 1; /* really initialized in prior run */
1401 /* tell writer to open tape */
1407 if (syncpipe_put('O', 0) == -1) {
1408 put_syncpipe_fault_result(handle);
1411 if (syncpipe_putstr(datestamp) == -1) {
1412 put_syncpipe_fault_result(handle);
1415 if (syncpipe_putstr(hostname) == -1) {
1416 put_syncpipe_fault_result(handle);
1419 if (syncpipe_putstr(qdiskname) == -1) {
1420 put_syncpipe_fault_result(handle);
1423 if (syncpipe_putint(level) == -1) {
1424 put_syncpipe_fault_result(handle);
1430 /* read file in loop */
1433 if ((tok = syncpipe_get(&bufnum)) == -1) {
1434 put_syncpipe_fault_result(handle);
1448 taper_debug(1, ("taper: r: got R%d\n", bufnum));
1451 if (syncpipe_put('C', 0) == -1) {
1452 put_syncpipe_fault_result(handle);
1461 break; /* ignore extra read tokens */
1466 if(bp->status != EMPTY || bufnum != (int)(bp - buftable)) {
1467 /* XXX this SHOULD NOT HAPPEN. Famous last words. */
1468 fprintf(stderr,"taper: panic: buffer mismatch at ofs "
1469 OFF_T_FMT ":\n", (OFF_T_FMT_TYPE)filesize);
1470 if(bufnum != (int)(bp - buftable)) {
1471 fprintf(stderr, " my buf %d but writer buf %d\n",
1472 (int)(bp-buftable), bufnum);
1474 fprintf(stderr,"buf %d state %s (%ld) instead of EMPTY\n",
1476 bp->status == FILLING? "FILLING" :
1477 bp->status == FULL? "FULL" : "EMPTY!?!?",
1482 dumpbufs("taper: after 1 sec");
1483 if (bp->status == EMPTY)
1484 fprintf(stderr, "taper: result now correct!\n");
1487 errstr = newstralloc(errstr,
1488 "[fatal buffer mismanagement bug]");
1490 putresult(TRYAGAIN, "%s %s\n", handle, q);
1491 cur_span_chunkstart = (off_t)0;
1493 log_add(L_INFO, "retrying %s:%s.%d on new tape due to: %s",
1494 hostname, qdiskname, level, errstr);
1496 if (syncpipe_put('X', 0) == -1) {/* X == buffer snafu, bail */
1497 put_syncpipe_fault_result(handle);
1501 if ((tok = syncpipe_get(&bufnum)) == -1) {
1502 put_syncpipe_fault_result(handle);
1505 } while (tok != 'x');
1508 } /* end 'if (bf->status != EMPTY || bufnum != (int)(bp-buftable))' */
1510 bp->status = FILLING;
1511 buflen = header_read ? (size_t)tt_blocksize : DISK_BLOCK_BYTES;
1512 if (interactive || debug_taper >= 1)
1514 if (header_written == 0 &&
1515 (header_read == 1 || cur_span_chunkstart > (off_t)0)) {
1516 /* for split dumpfiles, modify headers for the second - nth
1517 pieces that signify that they're continuations of the last
1519 char *cont_filename;
1520 file.type = F_SPLIT_DUMPFILE;
1521 file.partnum = num_splits + 1;
1522 file.totalparts = expected_splits;
1523 cont_filename = stralloc(file.cont_filename);
1524 file.cont_filename[0] = '\0';
1525 build_header(bp->buffer, &file, tt_blocksize);
1527 if (cont_filename[0] != '\0') {
1528 file.type = F_CONT_DUMPFILE;
1529 strncpy(file.cont_filename, cont_filename,
1530 SIZEOF(file.cont_filename));
1532 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1534 if (interactive || debug_taper >= 1)
1536 bp->size = (ssize_t)tt_blocksize;
1537 rc = (ssize_t)tt_blocksize;
1539 amfree(cont_filename);
1540 } else if (retry_from_splitbuf) {
1541 /* quietly pull dump data from our in-memory cache, and the
1542 writer side need never know the wiser */
1543 memcpy(bp->buffer, splitbuf_rd_ptr, tt_blocksize);
1544 bp->size = (ssize_t)tt_blocksize;
1545 rc = (ssize_t)tt_blocksize;
1547 splitbuf_rd_ptr += tt_blocksize;
1548 if (splitbuf_rd_ptr >= splitbuf_wr_ptr)
1549 retry_from_splitbuf = 0;
1550 } else if ((rc = taper_fill_buffer(fd, bp, buflen)) < 0) {
1553 strclosing = newvstralloc(strclosing,"Can't read data: ",
1555 if (syncpipe_put('C', 0) == -1) {
1556 put_syncpipe_fault_result(handle);
1562 if (rc < (ssize_t)buflen) { /* switch to next holding file */
1565 if (file.cont_filename[0] != '\0') {
1566 cur_filename = newvstralloc(cur_filename, file.cont_filename, NULL);
1568 ret = get_next_holding_file(fd, bp, &strclosing, (size_t)rc);
1572 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1579 /* rebuild the header block, which might have CONT junk */
1580 if (header_read == 0) {
1581 char *cont_filename;
1582 /* write the "real" filename if the holding-file
1584 parse_file_header(bp->buffer, &file, (size_t)rc);
1585 parse_file_header(bp->buffer, &first_file, (size_t)rc);
1586 cont_filename = stralloc(file.cont_filename);
1587 file.cont_filename[0] = '\0';
1588 if (splitsize > (off_t)0) {
1589 file.type = F_SPLIT_DUMPFILE;
1591 file.totalparts = expected_splits;
1593 file.blocksize = tt_blocksize;
1594 build_header(bp->buffer, &file, tt_blocksize);
1596 file.type = F_CONT_DUMPFILE;
1598 /* add CONT_FILENAME back to in-memory header */
1599 strncpy(file.cont_filename, cont_filename,
1600 SIZEOF(file.cont_filename));
1601 if (interactive || debug_taper >= 1)
1603 bp->size = (ssize_t)tt_blocksize; /* output a full tape block */
1604 /* save the header, we'll need it if we jump tapes */
1605 memcpy(&cur_holdfile, &file, SIZEOF(dumpfile_t));
1608 amfree(cont_filename);
1610 filesize = kbytesread;
1613 taper_debug(1, ("taper: r: put W%d\n",
1614 (int)(bp-buftable)));
1615 if (syncpipe_put('W', (int)(bp-buftable)) == -1) {
1616 put_syncpipe_fault_result(handle);
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 = holding_file_size(filename, 1);
2062 if (total_kb <= (off_t)0) {
2063 fprintf(stderr, "taper: r: " OFF_T_FMT
2064 " kb holding file makes no sense, setting splitsize to 0\n",
2065 (OFF_T_FMT_TYPE)total_kb);
2067 splitsize = 0; /* disabling split */
2071 fprintf(stderr, "taper: r: Total dump size should be " OFF_T_FMT
2072 "kb, chunk size is " OFF_T_FMT "kb\n",
2073 (OFF_T_FMT_TYPE)total_kb,
2074 (OFF_T_FMT_TYPE)splitsize);
2077 splits = (int)(total_kb / adj_splitsize);
2078 if ((splits == 0) || (total_kb % adj_splitsize))
2082 fprintf(stderr, "taper: r: Expecting to split into %d parts \n", splits);
2089 * ========================================================================
2093 times_t idlewait, rdwait, wrwait, fmwait;
2094 unsigned long total_writes;
2095 off_t total_tape_used;
2098 void write_file(void);
2099 int write_buffer(buffer_t *bp);
2115 #ifdef HAVE_LIBVTBLC
2118 #endif /* HAVE_LIBVTBLC */
2120 procname = "writer";
2121 syncpipe_init(getp, putp);
2123 idlewait = times_zero;
2124 if (tapedev != NULL) {
2125 tapedev = stralloc(tapedev);
2130 if ((tok = syncpipe_get(&tmpint)) == -1) {
2131 error("writer: Syncpipe failure before start");
2135 idlewait = timesadd(idlewait, stopclock());
2136 if (tok != 'S' && tok != 'Q' && !tape_started) {
2137 error("writer: token '%c' before start", tok);
2142 case 'H': /* Reader read pipe side is down */
2143 dbprintf(("writer: Communications with reader is down"));
2144 error("writer: Communications with reader is down");
2147 case 'S': /* start-tape */
2149 error("writer: multiple start requests");
2152 if ((str = syncpipe_getstr()) == NULL) {
2153 error("writer: Syncpipe failure");
2156 if (!first_tape(str ? str : "bad-datestamp")) {
2158 tapefd_close(tape_fd);
2161 if (syncpipe_put('E', 0) == -1) {
2162 error("writer: Syncpipe failure passing exit code");
2165 if (syncpipe_putstr(errstr) == -1) {
2166 error("writer: Syncpipe failure passing exit string");
2169 /* wait for reader to acknowledge error */
2171 if ((tok = syncpipe_get(&tmpint)) == -1) {
2172 error("writer: Syncpipe failure waiting for error ack");
2176 error("writer: got '%c' unexpectedly after error", tok);
2179 } while (tok != 'e');
2181 if (syncpipe_put('S', 0) == -1) {
2182 error("writer: syncpipe failure while starting tape");
2190 case 'O': /* open-output */
2191 if ((datestamp = syncpipe_getstr()) == NULL) {
2192 error("writer: Syncpipe failure during open");
2195 tapefd_setinfo_datestamp(tape_fd, datestamp);
2198 if ((hostname = syncpipe_getstr()) == NULL) {
2199 error("writer: Syncpipe failure fetching hostname");
2202 tapefd_setinfo_host(tape_fd, hostname);
2205 if ((diskname = syncpipe_getstr()) == NULL) {
2206 error("writer: Syncpipe failure fetching diskname");
2209 tapefd_setinfo_disk(tape_fd, diskname);
2211 if ((level = syncpipe_getint()) == -1) {
2212 error("writer: Syncpipe failure fetching level");
2215 tapefd_setinfo_level(tape_fd, level);
2219 #ifdef HAVE_LIBVTBLC
2220 case 'L': /* read vtbl label */
2222 if ((vol_label = syncpipe_getstr()) == NULL) {
2223 error("writer: Syncpipe failure fetching vrbl label");
2226 fprintf(stderr, "taper: read label string \"%s\" from pipe\n",
2228 strncpy(vtbl_entry[vtbl_no].label, vol_label, 45);
2231 case 'D': /* read vtbl date */
2233 if ((vol_date = syncpipe_getstr()) == NULL) {
2234 error("writer: Syncpipe failure fetching vrbl date");
2237 fprintf(stderr, "taper: read date string \"%s\" from pipe\n",
2239 strncpy(vtbl_entry[vtbl_no].date, vol_date, 20);
2241 #endif /* HAVE_LIBVTBLC */
2244 end_tape(0); /* XXX check results of end tape ?? */
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;
2286 taper_debug(1, ("taper: w: start file\n"));
2289 * Tell the reader that the tape is open, and give it all the buffers.
2291 if (syncpipe_put('O', 0) == -1) {
2292 error("writer: Syncpipe failure starting write sequence");
2295 for (i = 0; i < conf_tapebufs; i++) {
2296 taper_debug(1, ("taper: w: put R%d\n", i));
2297 if (syncpipe_put('R', i) == -1) {
2298 error("writer: Syncpipe failure readying write buffers");
2304 * We write the filemark at the start of the file rather than at the end,
2305 * so that it can proceed in parallel with the reader's initial filling
2306 * up of the buffers.
2310 if (!write_filemark())
2312 fmwait = stopclock();
2321 * At the start of the file, or if the input can't keep up with the
2322 * tape, we enter STOPPED mode, which waits for most of the buffers
2323 * to fill up before writing to tape. This maximizes the amount of
2324 * data written in chunks to the tape drive, minimizing the number
2325 * of starts/stops, which in turn saves tape and time.
2329 fputs("[WS]", stderr);
2331 while (full_buffers < conf_tapebufs - THRESHOLD) {
2332 if ((tok = syncpipe_get(&bufnum)) == -1) {
2333 error("writer: Syncpipe failure during buffer advance");
2338 taper_debug(1, ("taper: w: got W%d\n",bufnum));
2341 rdwait = timesadd(rdwait, stopclock());
2346 * We start output when sufficient buffers have filled up, or at
2347 * end-of-file, whichever comes first. Here we drain all the buffers
2348 * that were waited on in STOPPED mode. If more full buffers come
2349 * in, then we will be STREAMING.
2352 while (full_buffers) {
2353 if (tt_file_pad && bp->size < (ssize_t)tt_blocksize) {
2354 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
2355 bp->size = (ssize_t)tt_blocksize;
2357 if (!write_buffer(bp))
2366 * With any luck, the input source is faster than the tape drive. In
2367 * this case, full buffers will appear in the circular queue faster
2368 * than we can write them, so the next buffer in the queue will always
2369 * be marked FULL by the time we get to it. If so, we'll stay in
2372 * On the other hand, if we catch up to the input and thus would have
2373 * to wait for buffers to fill, we are then STOPPED again.
2376 while (tok == 'W' && bp->status == FULL) {
2377 if ((tok = syncpipe_get(&bufnum)) == -1) {
2378 error("writer: Syncpipe failure advancing buffer");
2383 taper_debug(1, ("taper: w: got W%d\n",bufnum));
2384 if(bufnum != (int)(bp - buftable)) {
2386 "taper: tape-writer: my buf %d reader buf %d\n",
2387 (int)(bp-buftable), bufnum);
2389 if (syncpipe_put('E', 0) == -1) {
2390 error("writer: Syncpipe failure putting error token");
2393 if (syncpipe_putstr("writer-side buffer mismatch") == -1) {
2394 error("writer: Syncpipe failure putting error messgae");
2399 if (tt_file_pad && bp->size < (ssize_t)tt_blocksize) {
2400 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
2401 bp->size = (ssize_t)tt_blocksize;
2403 if (!write_buffer(bp))
2406 } else if (tok == 'Q') {
2408 } else if (tok == 'X') {
2409 goto reader_buffer_snafu;
2411 error("writer-side not expecting token: %c", tok);
2415 } while (tok == 'W');
2417 /* got close signal from reader, acknowledge it */
2420 goto reader_buffer_snafu;
2423 if (syncpipe_put('C', 0) == -1) {
2424 error("writer: Syncpipe failure putting close");
2428 /* tell reader the tape and file number */
2430 if (syncpipe_putstr(label) == -1) {
2431 error("writer: Syncpipe failure putting label");
2434 snprintf(number, SIZEOF(number), "%d", filenum);
2435 if (syncpipe_putstr(number) == -1) {
2436 error("writer: Syncpipe failure putting filenum");
2440 snprintf(number, SIZEOF(number), "%lu", total_writes);
2441 rdwait_str = stralloc(walltime_str(rdwait));
2442 wrwait_str = stralloc(walltime_str(wrwait));
2443 fmwait_str = stralloc(walltime_str(fmwait));
2444 errstr = newvstralloc(errstr,
2446 " writers ", number,
2447 " rdwait ", rdwait_str,
2448 " wrwait ", wrwait_str,
2449 " filemark ", fmwait_str,
2455 if (syncpipe_putstr(errstr) == -1) {
2456 error("writer: Syncpipe failure putting '%s'", errstr);
2460 /* XXX go to next tape if past tape size? */
2466 dbprintf(("tape_error: %s\n", errstr));
2467 /* got tape error */
2469 if (syncpipe_put('T', 0) == -1) { /* next tape in place, try again */
2470 error("writer: Syncpipe failure during tape advance");
2474 if (syncpipe_put('E', 0) == -1) { /* no more tapes, fail */
2475 error("writer: Syncpipe failure during tape error");
2479 if (syncpipe_putstr(errstr) == -1) {
2480 error("writer: Syncpipe failure putting '%s'", errstr);
2485 /* wait for reader to acknowledge error */
2487 if ((tok = syncpipe_get(&tmpint)) == -1) {
2488 error("writer: syncpipe failure waiting for error ack");
2492 if (tok != 'W' && tok != 'C' && tok != 'e') {
2493 error("writer: got '%c' unexpectedly after error", tok);
2496 } while (tok != 'e');
2499 reader_buffer_snafu:
2500 if (syncpipe_put('x', 0) == -1) {
2501 error("writer: syncpipe failure putting buffer snafu");
2513 assert(bp->status == FULL);
2516 rc = tapefd_write(tape_fd, bp->buffer, (size_t)bp->size);
2517 if (rc == (ssize_t)bp->size) {
2518 #if defined(NEED_RESETOFS)
2519 static double tape_used_modulus_2gb = 0;
2522 * If the next write will go over the 2 GByte boundary, reset
2523 * the kernel concept of where we are to make sure it does not
2526 tape_used_modulus_2gb += (double)rc;
2527 if (tape_used_modulus_2gb + (double)rc > (double)0x7fffffff) {
2528 tape_used_modulus_2gb = 0;
2529 tapefd_resetofs(tape_fd);
2532 wrwait = timesadd(wrwait, stopclock());
2534 total_tape_used += (off_t)rc;
2536 if (interactive || debug_taper >= 1)
2541 taper_debug(1, ("taper: w: put R%d\n", (int)(bp-buftable)));
2542 if (syncpipe_put('R', (int)(bp-buftable)) == -1) {
2543 error("writer: Syncpipe failure during advancing write bufffer");
2548 errstr = newvstralloc(errstr,
2550 (rc != -1) ? "short write" : strerror(errno),
2552 wrwait = timesadd(wrwait, stopclock());
2554 fputs("[WE]", stderr);
2563 REMOVE_SHARED_MEMORY();
2568 * Cleanup shared memory segments
2574 log_add(L_INFO, "Received signal %d", signum);
2581 * Installing signal handlers for signal whose default action is
2582 * process termination so that we can clean up shared memory
2586 install_signal_handlers(void)
2588 struct sigaction act;
2590 act.sa_handler = signal_handler;
2592 sigemptyset(&act.sa_mask);
2594 signal(SIGPIPE, SIG_IGN);
2596 if (sigaction(SIGINT, &act, NULL) != 0) {
2597 error("taper: couldn't install SIGINT handler [%s]", strerror(errno));
2601 if (sigaction(SIGHUP, &act, NULL) != 0) {
2602 error("taper: couldn't install SIGHUP handler [%s]", strerror(errno));
2606 if (sigaction(SIGTERM, &act, NULL) != 0) {
2607 error("taper: couldn't install SIGTERM handler [%s]", strerror(errno));
2611 if (sigaction(SIGUSR1, &act, NULL) != 0) {
2612 error("taper: couldn't install SIGUSR1 handler [%s]", strerror(errno));
2616 if (sigaction(SIGUSR2, &act, NULL) != 0) {
2617 error("taper: couldn't install SIGUSR2 handler [%s]", strerror(errno));
2621 if (sigaction(SIGALRM, &act, NULL) != 0) {
2622 error("taper: couldn't install SIGALRM handler [%s]", strerror(errno));
2629 * ========================================================================
2630 * SHARED-MEMORY BUFFER SUBSYSTEM
2644 shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0700);
2649 result = (char *)shmat(shmid, (SHM_ARG_TYPE *)NULL, 0);
2651 if (result == (char *)-1) {
2652 int save_errno = errno;
2656 error("shmat: %s", strerror(errno));
2668 if ((bufp != NULL) &&
2669 (shmdt((SHM_ARG_TYPE *)bufp) == -1)) {
2670 error("shmdt: %s", strerror(errno));
2676 destroy_buffers(void)
2679 return; /* nothing to destroy */
2680 if (shmctl(shmid, IPC_RMID, NULL) == -1) {
2681 error("shmctl: %s", strerror(errno));
2689 #ifdef HAVE_SYS_MMAN_H
2690 #include <sys/mman.h>
2694 # ifdef MAP_ANONYMOUS /* OSF/1-style */
2695 # define MAP_ANON MAP_ANONYMOUS
2696 # else /* SunOS4-style */
2698 # define ZERO_FILE "/dev/zero"
2712 shmfd = open(ZERO_FILE, O_RDWR);
2714 error("attach_buffers: could not open %s: %s",
2722 shmbuf = (char *) mmap((void *) 0,
2724 PROT_READ|PROT_WRITE,
2725 MAP_ANON|MAP_SHARED,
2735 if ((bufp != NULL) &&
2736 (munmap((void *)bufp, saved_size) == -1)) {
2737 error("detach_buffers: munmap: %s", strerror(errno));
2746 destroy_buffers(void)
2751 #error: must define either HAVE_SYSVSHM or HAVE_MMAP!
2758 * ========================================================================
2759 * SYNC-PIPE SUBSYSTEM
2763 int getpipe, putpipe;
2775 syncpipe_read_error(
2779 char buf[sizeof(char) + sizeof(int)];
2782 dbprintf(("syncpipe_get %s halting: Unexpected read EOF\n", procname));
2783 fprintf(stderr, "syncpipe_get %s halting: Unexpected read EOF\n", procname);
2784 } else if (rc < 0) {
2785 dbprintf(("syncpipe_get %s halting: Read error - %s\n",
2786 procname, strerror(errno)));
2787 fprintf(stderr, "syncpipe_get %s halting: Read error - %s\n",
2788 procname, strerror(errno));
2790 dbprintf(("syncpipe_get %s halting: Read "
2791 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2792 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2793 (SSIZE_T_FMT_TYPE)expected));
2794 fprintf(stderr, "syncpipe_get %s halting: Read "
2795 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2796 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2797 (SSIZE_T_FMT_TYPE)expected);
2799 /* Halt the other side if it's still alive */
2801 memset(&buf[1], 0, SIZEOF(int));
2802 if (write(putpipe, buf, SIZEOF(buf)))
2807 syncpipe_write_error(
2811 char buf[sizeof(char) + sizeof(int)];
2813 if (rc == 0) { /* EOF */
2814 dbprintf(("syncpipe %s halting: Write EOF\n", procname));
2815 fprintf(stderr, "syncpipe %s halting: Write EOF\n", procname);
2816 } else if (rc < 0) {
2817 dbprintf(("syncpipe %s halting: Write error - %s\n",
2818 procname, strerror(errno)));
2819 fprintf(stderr, "syncpipe %s halting: Write error - %s\n",
2820 procname, strerror(errno));
2822 dbprintf(("syncpipe %s halting: Write "
2823 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2824 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2825 (SSIZE_T_FMT_TYPE)expected));
2826 fprintf(stderr, "syncpipe %s halting: Write "
2827 SSIZE_T_FMT " bytes short of " SSIZE_T_FMT "\n",
2828 procname, (SSIZE_T_FMT_TYPE)(rc - expected),
2829 (SSIZE_T_FMT_TYPE)expected);
2831 /* Halt the other side if it's still alive */
2833 memset(&buf[1], 0, SIZEOF(int));
2834 if (write(putpipe, buf, SIZEOF(buf)))
2843 char buf[SIZEOF(char) + SIZEOF(int)];
2845 memset(buf, 0, sizeof(buf));
2846 rc = fullread(getpipe, buf, SIZEOF(buf));
2847 if (rc != (ssize_t)sizeof(buf)) {
2848 syncpipe_read_error(rc, (ssize_t)sizeof(buf));
2852 if (debug_taper >= 1 && *buf != 'R' && *buf != 'W') {
2853 taper_debug(1, ("taper: %c: getc %c\n", *procname, *buf));
2856 memcpy(intp, &buf[1], SIZEOF(int));
2861 syncpipe_getint(void)
2866 rc = fullread(getpipe, &i, SIZEOF(i));
2867 if (rc != (ssize_t)sizeof(i)) {
2868 syncpipe_read_error(rc, (ssize_t)sizeof(i));
2877 syncpipe_getstr(void)
2883 if ((len = syncpipe_getint()) <= 0) {
2884 fprintf(stderr, "syncpipe %s halting: Protocol error - "
2885 "Invalid string length (%d)\n", procname, len);
2886 syncpipe_put('H', 0); /* Halt the other side */
2891 str = alloc((size_t)len);
2893 rc = fullread(getpipe, str, (size_t)len);
2894 if (rc != (ssize_t)len) {
2895 syncpipe_read_error(rc, (ssize_t)len);
2907 char buf[sizeof(char) + sizeof(int)];
2911 memcpy(&buf[1], &intval, SIZEOF(int));
2912 if (debug_taper >= 1 && buf[0] != 'R' && buf[0] != 'W') {
2913 taper_debug(1, ("taper: %c: putc %c\n",*procname,buf[0]));
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;
2984 if ((scan_result = taper_scan(NULL, &label, ×tamp, &tapedev, CHAR_taperscan_output_callback, &error_msg)) < 0) {
2985 fprintf(stderr, "%s\n", error_msg);
2994 s = error_msg; r = NULL;
2995 while((s=strstr(s,"slot "))) { s += 5; r=s; };
3001 if ((tape_fd = tape_open(tapedev, O_WRONLY)) == -1) {
3002 if (errno == EACCES) {
3003 errstr = newstralloc2(errstr,
3004 "writing label: tape is write protected or I don't have write permission on ", tapedev);
3006 errstr = newstralloc2(errstr,
3007 "writing label: ", strerror(errno));
3012 tapefd_setinfo_length(tape_fd, tapetype_get_length(tt));
3014 tapefd_setinfo_datestamp(tape_fd, taper_timestamp);
3015 tapefd_setinfo_disk(tape_fd, label);
3016 result = tapefd_wrlabel(tape_fd, taper_timestamp, label, tt_blocksize);
3017 if (result != NULL) {
3018 errstr = newstralloc(errstr, result);
3022 /* Output a description of what we just did. A result of '3' from taper_scan
3023 * means that a new tape was found and will be labeled. */
3025 fprintf(stderr, _("taper: slot: %d wrote label `%s' date `%s'\n"), slot, label, taper_timestamp);
3026 if (scan_result == 3)
3027 log_add(L_INFO, _("Wrote new label `%s' to new (non-amanda) tape in slot %d"), label, slot);
3029 fprintf(stderr, _("taper: wrote label `%s' date `%s'\n"), label, taper_timestamp);
3030 if (scan_result == 3)
3031 log_add(L_INFO, _("Wrote new label `%s' to new (non-amanda) tape"), label);
3035 #ifdef HAVE_LIBVTBLC
3036 /* store time for the first volume entry */
3038 tape_timep = localtime(&raw_time);
3039 strftime(start_datestr, 20, "%T %D", tape_timep);
3040 fprintf(stderr, "taper: got vtbl start time: %s\n", start_datestr);
3042 #endif /* HAVE_LIBVTBLC */
3044 if (strcmp(label, FAKE_LABEL) != 0) {
3045 if (cur_tape == 0) {
3046 conf_tapelist_old = stralloc2(conf_tapelist, ".yesterday");
3048 char cur_str[NUM_STR_SIZE];
3050 snprintf(cur_str, SIZEOF(cur_str), "%d", cur_tape - 1);
3051 conf_tapelist_old = vstralloc(conf_tapelist,
3052 ".today.", cur_str, NULL);
3055 if (write_tapelist(conf_tapelist_old)) {
3056 error("could not write tapelist: %s", strerror(errno));
3059 amfree(conf_tapelist_old);
3061 remove_tapelabel(label);
3062 add_tapelabel(taper_timestamp, label);
3063 if (write_tapelist(conf_tapelist)) {
3064 error("could not write tapelist: %s", strerror(errno));
3069 log_add(L_START, "datestamp %s label %s tape %d",
3070 taper_timestamp, label, cur_tape);
3071 if (first_call && strcmp(label, FAKE_LABEL) == 0) {
3073 log_add(L_WARNING, "tapedev is %s, dumps will be thrown away", tapedev);
3076 total_tape_used=(off_t)0;
3082 /* return 0 on error and set errstr */
3083 /* return 1 on success */
3086 char *new_datestamp)
3088 if ((have_changer = changer_init()) < 0) {
3089 error("changer initialization failed: %s", strerror(errno));
3094 taper_timestamp = newstralloc(taper_timestamp, new_datestamp);
3107 end_tape(writerror);
3109 if (++cur_tape >= runtapes)
3112 if (!label_tape()) {
3129 log_add(L_INFO, "tape %s kb " OFF_T_FMT " fm %d %s",
3131 (OFF_T_FMT_TYPE)((total_tape_used+(off_t)1023) / (off_t)1024),
3133 writerror? errstr : "[OK]");
3135 fprintf(stderr, "taper: writing end marker. [%s %s kb "
3136 OFF_T_FMT " fm %d]\n", label,
3137 writerror? "ERR" : "OK",
3138 (OFF_T_FMT_TYPE)((total_tape_used+(off_t)1023) / (off_t)1024),
3142 if (! write_filemark()) {
3147 result = tapefd_wrendmark(tape_fd, taper_timestamp, tt_blocksize);
3148 if (result != NULL) {
3149 errstr = newstralloc(errstr, result);
3156 #ifdef HAVE_LINUX_ZFTAPE_H
3157 if (tape_fd >= 0 && is_zftape(tapedev) == 1) {
3158 /* rewind the tape */
3160 if (tapefd_rewind(tape_fd) == -1 ) {
3161 errstr = newstralloc2(errstr, "rewinding tape: ", strerror(errno));
3165 /* close the tape */
3167 if (tapefd_close(tape_fd) == -1) {
3168 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
3174 #ifdef HAVE_LIBVTBLC
3175 /* update volume table */
3176 fprintf(stderr, "taper: updating volume table ...\n");
3179 if ((tape_fd = raw_tape_open(rawtapedev, O_RDWR)) == -1) {
3180 if (errno == EACCES) {
3181 errstr = newstralloc(errstr,
3182 "updating volume table: tape is write protected");
3184 errstr = newstralloc2(errstr,
3185 "updating volume table: ",
3191 /* read volume table */
3192 if ((num_volumes = read_vtbl(tape_fd, volumes, vtbl_buffer,
3193 &first_seg, &last_seg)) == -1 ) {
3194 errstr = newstralloc2(errstr,
3195 "reading volume table: ",
3200 /* set volume label and date for first entry */
3202 if (set_label(label, volumes, num_volumes, vtbl_no)) {
3203 errstr = newstralloc2(errstr,
3204 "setting label for entry 1: ",
3209 /* date of start writing this tape */
3210 if (set_date(start_datestr, volumes, num_volumes, vtbl_no)) {
3211 errstr = newstralloc2(errstr,
3212 "setting date for entry 1: ",
3217 /* set volume labels and dates for backup files */
3218 for (vtbl_no = 1; vtbl_no <= num_volumes - 2; vtbl_no++) {
3219 fprintf(stderr,"taper: label %i: %s, date %s\n",
3221 vtbl_entry[vtbl_no].label,
3222 vtbl_entry[vtbl_no].date);
3224 if (set_label(vtbl_entry[vtbl_no].label,
3225 volumes, num_volumes, vtbl_no)) {
3226 errstr = newstralloc2(errstr,
3227 "setting label for entry i: ",
3232 if (set_date(vtbl_entry[vtbl_no].date,
3233 volumes, num_volumes, vtbl_no)) {
3234 errstr = newstralloc2(errstr,
3235 "setting date for entry i: ",
3241 /* set volume label and date for last entry */
3242 vtbl_no = num_volumes - 1;
3243 if (set_label("AMANDA Tape End", volumes, num_volumes, vtbl_no)) {
3244 errstr = newstralloc2(errstr,
3245 "setting label for last entry: ",
3250 datestr = NULL; /* take current time */
3251 if (set_date(datestr, volumes, num_volumes, vtbl_no)) {
3252 errstr = newstralloc2(errstr,
3253 "setting date for last entry 1: ",
3258 /* write volume table back */
3259 if (write_vtbl(tape_fd, volumes, vtbl_buffer, num_volumes, first_seg,
3260 op_mode == trunc)) {
3261 errstr = newstralloc2(errstr,
3262 "writing volume table: ",
3268 fprintf(stderr, "taper: updating volume table: done.\n");
3270 #endif /* HAVE_LIBVTBLC */
3272 #endif /* !HAVE_LINUX_ZFTAPE_H */
3274 /* close the tape and let the OS write the final filemarks */
3278 if (tape_fd >= 0 && tapefd_close(tape_fd) == -1 && ! writerror) {
3279 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
3290 write_filemark(void)
3292 if (tapefd_weof(tape_fd, (off_t)1) == -1) {
3293 errstr = newstralloc2(errstr, "writing filemark: ", strerror(errno));