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.47.2.14.4.8.2.17.2.1 2004/02/13 14:09:34 martinea Exp $
28 * moves files from holding disk to tape, or from a socket to tape
42 #include "amfeatures.h"
43 #include "fileheader.h"
44 #include "server_util.h"
49 static int vtbl_no = -1;
51 static int offset = 0;
52 static char *datestr = NULL;
53 static char start_datestr[20];
56 struct tm backup_time;
57 struct tm *tape_timep = &tape_time;
58 typedef struct vtbl_lbls {
62 static vtbl_lbls vtbl_entry[MAX_VOLUMES];
63 #endif /* HAVE_LIBVTBLC */
65 * XXX update stat collection/printing
66 * XXX advance to next tape first in next_tape
67 * XXX label is being read twice?
70 /* NBUFS replaced by conf_tapebufs */
71 /* #define NBUFS 20 */
74 /* This is now the number of empties, not full bufs */
77 #define CONNECT_TIMEOUT 2*60
85 typedef struct buffer_s {
91 #define nextbuf(p) ((p) == buftable+conf_tapebufs-1? buftable : (p)+1)
92 #define prevbuf(p) ((p) == buftable? buftable+conf_tapebufs-1 : (p)-1)
95 int main P((int main_argc, char **main_argv));
96 void file_reader_side P((int rdpipe, int wrpipe));
97 void tape_writer_side P((int rdpipe, int wrpipe));
99 /* shared-memory routines */
100 char *attach_buffers P((unsigned int size));
101 void detach_buffers P((char *bufp));
102 void destroy_buffers P((void));
104 /* synchronization pipe routines */
105 void syncpipe_init P((int rd, int wr));
106 char syncpipe_get P((void));
107 int syncpipe_getint P((void));
108 char *syncpipe_getstr P((void));
109 void syncpipe_put P((int ch));
110 void syncpipe_putint P((int i));
111 void syncpipe_putstr P((char *str));
113 /* tape manipulation subsystem */
114 int first_tape P((char *new_datestamp));
115 int next_tape P((int writerr));
116 int end_tape P((int writerr));
117 int write_filemark P((void));
120 * ========================================================================
133 char *buffers = NULL;
134 buffer_t *buftable = NULL;
136 char *procname = "parent";
138 char *taper_datestamp = NULL;
143 char *tapedev = NULL;
144 char *tapetype = NULL;
145 tapetype_t *tt = NULL;
147 long tt_blocksize_kb;
150 static unsigned long malloc_hist_1, malloc_size_1;
151 static unsigned long malloc_hist_2, malloc_size_2;
153 am_feature_t *their_features = NULL;
155 int runtapes, cur_tape, have_changer, tapedays;
156 char *labelstr, *conf_tapelist;
159 int first_seg, last_seg;
160 #endif /* HAVE_LIBVTBLC */
163 * ========================================================================
167 int main(main_argc, main_argv)
171 int p2c[2], c2p[2]; /* parent-to-child, child-to-parent pipes */
180 for(fd = 3; fd < FD_SETSIZE; fd++) {
182 * Make sure nobody spoofs us with a lot of extra open files
183 * that would cause an open we do to get a very high file
184 * descriptor, which in turn might be used as an index into
185 * an array (e.g. an fd_set).
192 malloc_size_1 = malloc_inuse(&malloc_hist_1);
194 fprintf(stderr, "%s: pid %ld executable %s version %s\n",
195 get_pname(), (long) getpid(), main_argv[0], version());
198 if (main_argc > 1 && main_argv[1][0] != '-') {
199 config_name = stralloc(main_argv[1]);
200 config_dir = vstralloc(CONFIG_DIR, "/", main_argv[1], "/", NULL);
204 char my_cwd[STR_SIZE];
206 if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
207 error("cannot determine current working directory");
209 config_dir = stralloc2(my_cwd, "/");
210 if ((config_name = strrchr(my_cwd, '/')) != NULL) {
211 config_name = stralloc(config_name + 1);
217 /* print prompts and debug messages if running interactive */
219 interactive = (main_argc > 1 && strcmp(main_argv[1],"-t") == 0);
221 erroutput_type = ERR_INTERACTIVE;
223 erroutput_type = ERR_AMANDALOG;
224 set_logerror(logerror);
227 conffile = stralloc2(config_dir, CONFFILE_NAME);
228 if(read_conffile(conffile)) {
229 error("errors processing config file \"%s\"", conffile);
233 conf_tapelist = getconf_str(CNF_TAPELIST);
234 if (*conf_tapelist == '/') {
235 conf_tapelist = stralloc(conf_tapelist);
237 conf_tapelist = stralloc2(config_dir, conf_tapelist);
239 if(read_tapelist(conf_tapelist)) {
240 error("could not load tapelist \"%s\"", conf_tapelist);
243 tapedev = getconf_str(CNF_TAPEDEV);
244 tapetype = getconf_str(CNF_TAPETYPE);
245 tt = lookup_tapetype(tapetype);
247 rawtapedev = getconf_str(CNF_RAWTAPEDEV);
248 #endif /* HAVE_LIBVTBLC */
249 tapedays = getconf_int(CNF_TAPECYCLE);
250 labelstr = getconf_str(CNF_LABELSTR);
252 runtapes = getconf_int(CNF_RUNTAPES);
255 conf_tapebufs = getconf_int(CNF_TAPEBUFS);
257 tt_blocksize_kb = tt->blocksize;
258 tt_blocksize = tt_blocksize_kb * 1024;
259 tt_file_pad = tt->file_pad;
262 fprintf(stderr,"taper: running in interactive test mode\n");
266 /* create read/write syncronization pipes */
268 if(pipe(p2c) || pipe(c2p))
269 error("creating sync pipes: %s", strerror(errno));
271 /* create shared memory segment */
273 #if defined(HAVE_GETPAGESIZE)
274 page_size = getpagesize();
275 fprintf(stderr, "%s: page size is %d\n", get_pname(), page_size);
278 fprintf(stderr, "%s: getpagesize() not available, using %d\n",
282 buffer_size = am_round(tt_blocksize, page_size);
283 fprintf(stderr, "%s: buffer size is %ld\n", get_pname(), buffer_size);
284 while(conf_tapebufs > 0) {
286 size += conf_tapebufs * buffer_size;
287 size += conf_tapebufs * sizeof(buffer_t);
288 if((buffers = attach_buffers(size)) != NULL) {
291 log_add(L_INFO, "attach_buffers: (%d tapebuf%s: %d bytes) %s",
293 (conf_tapebufs == 1) ? "" : "s",
298 if(buffers == NULL) {
299 error("cannot allocate shared memory");
301 i = (buffers - (char *)0) & (page_size - 1); /* page boundary offset */
303 first_buffer = buffers + page_size - i;
304 fprintf(stderr, "%s: shared memory at %p, first buffer at %p\n",
309 first_buffer = buffers;
311 buftable = (buffer_t *)(first_buffer + conf_tapebufs * buffer_size);
312 memset(buftable, 0, conf_tapebufs * sizeof(buffer_t));
313 if(conf_tapebufs < 10) {
315 } else if(conf_tapebufs < 100) {
320 for(i = 0; i < conf_tapebufs; i++) {
321 buftable[i].buffer = first_buffer + i * buffer_size;
322 fprintf(stderr, "%s: buffer[%0*d] at %p\n",
327 fprintf(stderr, "%s: buffer structures at %p for %d bytes\n",
330 (int)(conf_tapebufs * sizeof(buffer_t)));
332 /* fork off child writer process, parent becomes reader process */
334 switch(writerpid = fork()) {
336 error("fork: %s", strerror(errno));
342 tape_writer_side(p2c[0], c2p[1]);
343 error("tape writer terminated unexpectedly");
345 default: /* parent */
349 file_reader_side(c2p[0], p2c[1]);
350 error("file reader terminated unexpectedly");
359 * ========================================================================
363 void read_file P((int fd, char *handle,
364 char *host, char *disk, char *datestamp,
365 int level, int port_flag));
366 int taper_fill_buffer P((int fd, buffer_t *bp, int buflen));
367 void dumpbufs P((char *str1));
368 void dumpstatus P((buffer_t *bp));
370 void file_reader_side(rdpipe, wrpipe)
374 struct cmdargs cmdargs;
376 char *filename = NULL;
377 char *hostname = NULL;
378 char *diskname = NULL;
380 char *datestamp = NULL;
383 int level, fd, data_port, data_socket, wpid;
384 struct stat stat_file;
389 syncpipe_init(rdpipe, wrpipe);
391 /* must get START_TAPER before beginning */
394 cmd = getcmd(&cmdargs);
395 total_wait = stopclock();
397 if(cmd != START_TAPER || cmdargs.argc != 2) {
398 error("error [file_reader_side cmd %d argc %d]", cmd, cmdargs.argc);
401 /* pass start command on to tape writer */
403 taper_datestamp = newstralloc(taper_datestamp, cmdargs.argv[2]);
407 syncpipe_putstr(taper_datestamp);
409 /* get result of start command */
411 tok = syncpipe_get();
414 putresult(TAPER_OK, "\n");
416 /* start is logged in writer */
419 /* no tape, bail out */
420 result = syncpipe_getstr();
421 q = squotef("[%s]", result ? result : "(null)");
422 putresult(TAPE_ERROR, "%s\n", q);
424 log_add(L_ERROR,"no-tape [%s]", result);
426 syncpipe_put('e'); /* ACK error */
429 error("expected 'S' or 'E' for START-TAPER, got '%c'", tok);
432 /* process further commands */
436 cmd = getcmd(&cmdargs);
437 if(cmd != QUIT && !tape_started) {
438 error("error [file_reader_side cmd %d without tape ready]", cmd);
440 total_wait = timesadd(total_wait, stopclock());
453 cmdargs.argc++; /* true count of args */
456 if(a >= cmdargs.argc) {
457 error("error [taper PORT-WRITE: not enough args: handle]");
459 handle = newstralloc(handle, cmdargs.argv[a++]);
461 if(a >= cmdargs.argc) {
462 error("error [taper PORT-WRITE: not enough args: hostname]");
464 hostname = newstralloc(hostname, cmdargs.argv[a++]);
466 if(a >= cmdargs.argc) {
467 error("error [taper PORT-WRITE: not enough args: features]");
469 am_release_feature_set(their_features);
470 their_features = am_string_to_feature(cmdargs.argv[a++]);
472 if(a >= cmdargs.argc) {
473 error("error [taper PORT-WRITE: not enough args: diskname]");
475 diskname = newstralloc(diskname, cmdargs.argv[a++]);
477 if(a >= cmdargs.argc) {
478 error("error [taper PORT-WRITE: not enough args: level]");
480 level = atoi(cmdargs.argv[a++]);
482 if(a >= cmdargs.argc) {
483 error("error [taper PORT-WRITE: not enough args: datestamp]");
485 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
487 if(a != cmdargs.argc) {
488 error("error [taper file_reader_side PORT-WRITE: too many args: %d != %d]",
493 data_socket = stream_server(&data_port,
496 if(data_socket < 0) {
499 m = vstralloc("[port create failure: ",
504 putresult(TAPE_ERROR, "%s %s\n", handle, q);
508 putresult(PORT, "%d\n", data_port);
510 if((fd = stream_accept(data_socket, CONNECT_TIMEOUT,
511 -1, NETWORK_BLOCK_BYTES)) == -1) {
512 q = squote("[port connect timeout]");
513 putresult(TAPE_ERROR, "%s %s\n", handle, q);
517 read_file(fd, handle, hostname, diskname, datestamp, level, 1);
532 cmdargs.argc++; /* true count of args */
535 if(a >= cmdargs.argc) {
536 error("error [taper FILE-WRITE: not enough args: handle]");
538 handle = newstralloc(handle, cmdargs.argv[a++]);
540 if(a >= cmdargs.argc) {
541 error("error [taper FILE-WRITE: not enough args: filename]");
543 filename = newstralloc(filename, cmdargs.argv[a++]);
545 if(a >= cmdargs.argc) {
546 error("error [taper FILE-WRITE: not enough args: hostname]");
548 hostname = newstralloc(hostname, cmdargs.argv[a++]);
550 if(a >= cmdargs.argc) {
551 error("error [taper FILE-WRITE: not enough args: features]");
553 am_release_feature_set(their_features);
554 their_features = am_string_to_feature(cmdargs.argv[a++]);
556 if(a >= cmdargs.argc) {
557 error("error [taper FILE-WRITE: not enough args: diskname]");
559 diskname = newstralloc(diskname, cmdargs.argv[a++]);
561 if(a >= cmdargs.argc) {
562 error("error [taper FILE-WRITE: not enough args: level]");
564 level = atoi(cmdargs.argv[a++]);
566 if(a >= cmdargs.argc) {
567 error("error [taper FILE-WRITE: not enough args: datestamp]");
569 datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
571 if(a != cmdargs.argc) {
572 error("error [taper file_reader_side FILE-WRITE: too many args: %d != %d]",
576 if(stat(filename,&stat_file)!=0) {
577 q = squotef("[%s]", strerror(errno));
578 putresult(TAPE_ERROR, "%s %s\n", handle, q);
581 if((fd = open(filename, O_RDONLY)) == -1) {
582 q = squotef("[%s]", strerror(errno));
583 putresult(TAPE_ERROR, "%s %s\n", handle, q);
586 read_file(fd, handle, hostname, diskname, datestamp, level, 0);
590 putresult(QUITTING, "\n");
591 fprintf(stderr,"taper: DONE [idle wait: %s secs]\n",
592 walltime_str(total_wait));
594 syncpipe_put('Q'); /* tell writer we're exiting gracefully */
597 if((wpid = wait(NULL)) != writerpid) {
599 "taper: writer wait returned %d instead of %d: %s\n",
600 wpid, writerpid, strerror(errno));
604 detach_buffers(buffers);
609 amfree(changer_resultstr);
614 malloc_size_2 = malloc_inuse(&malloc_hist_2);
616 if(malloc_size_1 != malloc_size_2) {
617 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
623 if(cmdargs.argc >= 1) {
624 q = squote(cmdargs.argv[1]);
625 } else if(cmdargs.argc >= 0) {
626 q = squote(cmdargs.argv[0]);
628 q = stralloc("(no input?)");
630 putresult(BAD_COMMAND, "%s\n", q);
647 fprintf(stderr, "%s: state", str1);
648 for(i = j = 0; i < conf_tapebufs; i = j+1) {
649 v = buftable[i].status;
650 for(j = i; j < conf_tapebufs && buftable[j].status == v; j++);
652 if(i == j) fprintf(stderr, " %d:", i);
653 else fprintf(stderr, " %d-%d:", i, j);
655 case FULL: fputc('F', stderr); break;
656 case FILLING: fputc('f', stderr); break;
657 case EMPTY: fputc('E', stderr); break;
659 fprintf(stderr, "%ld", v);
672 char bt[NUM_STR_SIZE];
673 char status[NUM_STR_SIZE + 1];
678 ap_snprintf(bt, sizeof(bt), "%d", (int)(bp-buftable));
681 case FULL: ap_snprintf(status, sizeof(status), "F%d", bp->size);
683 case FILLING: status[0] = 'f'; status[1] = '\0'; break;
684 case EMPTY: status[0] = 'E'; status[1] = '\0'; break;
686 ap_snprintf(status, sizeof(status), "%ld", bp->status);
690 str = vstralloc("taper: ", pn, ": [buf ", bt, ":=", status, "]", NULL);
696 void read_file(fd, handle, hostname, diskname, datestamp, level, port_flag)
697 int fd, level, port_flag;
698 char *handle, *hostname, *diskname, *datestamp;
702 int rc, err, opening, closing, bufnum, need_closing;
705 char *strclosing = NULL;
714 static char desc[45];
715 static char vol_date[20];
716 static char vol_label[45];
717 #endif /* HAVE_LIBVTBLC */
729 fprintf(stderr, "taper: r: start file\n");
733 for(bp = buftable; bp < buftable + conf_tapebufs; bp++) {
738 if(interactive || bufdebug) dumpstatus(bp);
740 /* tell writer to open tape */
744 syncpipe_putstr(datestamp);
745 syncpipe_putstr(hostname);
746 syncpipe_putstr(diskname);
747 syncpipe_putint(level);
751 /* read file in loop */
754 tok = syncpipe_get();
764 bufnum = syncpipe_getint();
767 fprintf(stderr, "taper: r: got R%d\n", bufnum);
778 if(closing) break; /* ignore extra read tokens */
781 if(bp->status != EMPTY || bufnum != bp-buftable) {
782 /* XXX this SHOULD NOT HAPPEN. Famous last words. */
783 fprintf(stderr,"taper: panic: buffer mismatch at ofs %ld:\n",
785 if(bufnum != bp-buftable) {
786 fprintf(stderr, " my buf %d but writer buf %d\n",
787 (int)(bp-buftable), bufnum);
790 fprintf(stderr,"buf %d state %s (%ld) instead of EMPTY\n",
792 bp->status == FILLING? "FILLING" :
793 bp->status == FULL? "FULL" : "EMPTY!?!?",
798 dumpbufs("taper: after 1 sec");
799 if(bp->status == EMPTY)
800 fprintf(stderr, "taper: result now correct!\n");
803 errstr = newstralloc(errstr,
804 "[fatal buffer mismanagement bug]");
806 putresult(TRYAGAIN, "%s %s\n", handle, q);
808 log_add(L_INFO, "retrying %s:%s.%d on new tape: %s",
809 hostname, diskname, level, errstr);
811 syncpipe_put('X'); /* X == buffer snafu, bail */
813 tok = syncpipe_get();
815 bufnum = syncpipe_getint();
821 bp->status = FILLING;
822 buflen = header_read ? tt_blocksize : DISK_BLOCK_BYTES;
823 if(interactive || bufdebug) dumpstatus(bp);
824 if((rc = taper_fill_buffer(fd, bp, buflen)) < 0) {
827 strclosing = newvstralloc(strclosing,"Can't read data: ",NULL);
830 if(rc < buflen) { /* switch to next file */
832 struct stat stat_file;
836 if(file.cont_filename[0] == '\0') { /* no more file */
839 } else if(stat(file.cont_filename, &stat_file) != 0) {
842 strclosing = newvstralloc(strclosing,"can't stat: ",file.cont_filename,NULL);
843 } else if((fd = open(file.cont_filename,O_RDONLY)) == -1) {
846 strclosing = newvstralloc(strclosing,"can't open: ",file.cont_filename,NULL);
847 } else if((fd != save_fd) && dup2(fd, save_fd) == -1) {
850 strclosing = newvstralloc(strclosing,"can't dup2: ",file.cont_filename,NULL);
856 bp1.size = DISK_BLOCK_BYTES;
857 bp1.buffer = malloc(DISK_BLOCK_BYTES);
864 rc1 = taper_fill_buffer(fd, &bp1, DISK_BLOCK_BYTES);
867 err = (rc1 < 0) ? errno : 0;
869 strclosing = newvstralloc(strclosing,
870 "Can't read header: ",
874 parse_file_header(bp1.buffer, &file, rc1);
877 bp1.buffer = bp->buffer + rc;
879 rc1 = taper_fill_buffer(fd, &bp1, tt_blocksize - rc);
881 err = (rc1 < 0) ? errno : 0;
884 strclosing = newvstralloc(strclosing,
899 if(header_read == 0) {
902 parse_file_header(bp->buffer, &file, rc);
903 cont_filename = stralloc(file.cont_filename);
904 file.cont_filename[0] = '\0';
905 file.blocksize = tt_blocksize;
906 build_header(bp->buffer, &file, tt_blocksize);
908 /* add CONT_FILENAME back to in-memory header */
909 strncpy(file.cont_filename, cont_filename,
910 sizeof(file.cont_filename));
911 if(interactive || bufdebug) dumpstatus(bp);
912 bp->size = tt_blocksize; /* output a full tape block */
914 amfree(cont_filename);
917 filesize += am_round(rc, 1024) / 1024;
919 if(interactive || bufdebug) dumpstatus(bp);
921 fprintf(stderr,"taper: r: put W%d\n",(int)(bp-buftable));
925 syncpipe_putint(bp-buftable);
928 if(need_closing && rc <= 0) {
938 syncpipe_put('e'); /* ACK error */
941 str = syncpipe_getstr();
942 errstr = newvstralloc(errstr, "[", str ? str : "(null)", "]", NULL);
947 putresult(TRYAGAIN, "%s %s\n", handle, q);
948 log_add(L_INFO, "retrying %s:%s.%d on new tape: %s",
949 hostname, diskname, level, errstr);
951 putresult(TAPE_ERROR, "%s %s\n", handle, q);
952 log_add(L_FAIL, "%s %s %s %d [out of tape]",
953 hostname, diskname, datestamp, level);
954 log_add(L_ERROR,"no-tape [%s]", errstr);
963 str = syncpipe_getstr();
964 label = newstralloc(label, str ? str : "(null)");
966 str = syncpipe_getstr();
967 filenum = atoi(str ? str : "-9876"); /* ??? */
969 fprintf(stderr, "taper: reader-side: got label %s filenum %d\n",
974 runtime = stopclock();
977 errstr = newvstralloc(errstr,
978 "[input: ", strclosing, ": ",
979 strerror(err), "]", NULL);
983 errstr = newvstralloc(errstr,
984 "[input: ", strerror(err), "]",
987 putresult(TAPE_ERROR, "%s %s\n", handle, q);
989 log_add(L_FAIL, "%s %s %s %d %s",
990 hostname, diskname, datestamp, level, errstr);
991 str = syncpipe_getstr(); /* reap stats */
994 char kb_str[NUM_STR_SIZE];
995 char kps_str[NUM_STR_SIZE];
998 rt = runtime.r.tv_sec+runtime.r.tv_usec/1000000.0;
999 ap_snprintf(kb_str, sizeof(kb_str), "%ld", filesize);
1000 ap_snprintf(kps_str, sizeof(kps_str), "%3.1f",
1001 rt ? filesize / rt : 0.0);
1002 str = syncpipe_getstr();
1003 errstr = newvstralloc(errstr,
1004 "[sec ", walltime_str(runtime),
1007 " ", str ? str : "(null)",
1012 putresult(DONE, "%s %s %d %s\n",
1013 handle, label, filenum, q);
1015 log_add(L_SUCCESS, "%s %s %s %d %s",
1016 hostname, diskname, datestamp, level, errstr);
1017 #ifdef HAVE_LIBVTBLC
1019 * We have 44 characters available for the label string:
1020 * use max 20 characters for hostname
1021 * max 20 characters for diskname
1022 * (it could contain a samba share or dos path)
1025 memset(desc, '\0', 45);
1027 strncpy(desc, hostname, 20);
1029 if ((len = strlen(hostname)) <= 20) {
1030 memset(desc + len, ' ', 1);
1034 memset(desc + 20, ' ', 1);
1038 strncpy(desc + offset, diskname, 20);
1040 if ((len = strlen(diskname)) <= 20) {
1041 memset(desc + offset + len, ' ', 1);
1042 offset = offset + len + 1;
1045 memset(desc + offset + 20, ' ', 1);
1046 offset = offset + 21;
1049 sprintf(desc + offset, "%i", level);
1051 strncpy(vol_label, desc, 44);
1052 fprintf(stderr, "taper: added vtbl label string %i: \"%s\"\n",
1053 filenum, vol_label);
1056 /* pass label string on to tape writer */
1058 syncpipe_putint(filenum);
1059 syncpipe_putstr(vol_label);
1062 * reformat datestamp for later use with set_date from vtblc
1064 strptime(datestamp, "%Y%m%d", &backup_time);
1065 strftime(vol_date, 20, "%T %D", &backup_time);
1067 "taper: reformatted vtbl date string: \"%s\"->\"%s\"\n",
1071 /* pass date string on to tape writer */
1073 syncpipe_putint(filenum);
1074 syncpipe_putstr(vol_date);
1076 #endif /* HAVE_LIBVTBLC */
1086 int taper_fill_buffer(fd, bp, buflen)
1094 curptr = bp->buffer;
1099 cnt = read(fd, curptr, spaceleft);
1102 if(interactive) fputs("r0", stderr);
1104 case -1: /* error on read, punt */
1105 if(interactive) fputs("rE", stderr);
1113 } while(spaceleft > 0);
1115 if(interactive) fputs("R", stderr);
1122 * ========================================================================
1126 times_t idlewait, rdwait, wrwait, fmwait;
1128 double total_tape_used;
1131 void write_file P((void));
1132 int write_buffer P((buffer_t *bp));
1134 void tape_writer_side(getp, putp)
1145 #ifdef HAVE_LIBVTBLC
1148 #endif /* HAVE_LIBVTBLC */
1150 procname = "writer";
1151 syncpipe_init(getp, putp);
1154 idlewait = times_zero;
1158 tok = syncpipe_get();
1159 idlewait = timesadd(idlewait, stopclock());
1160 if(tok != 'S' && tok != 'Q' && !tape_started) {
1161 error("writer: token '%c' before start", tok);
1165 case 'S': /* start-tape */
1167 error("writer: multiple start requests");
1169 str = syncpipe_getstr();
1170 if(!first_tape(str ? str : "bad-datestamp")) {
1172 tapefd_close(tape_fd);
1176 syncpipe_putstr(errstr);
1177 /* wait for reader to acknowledge error */
1179 tok = syncpipe_get();
1181 error("writer: got '%c' unexpectedly after error", tok);
1183 } while(tok != 'e');
1192 case 'O': /* open-output */
1193 datestamp = syncpipe_getstr();
1194 tapefd_setinfo_datestamp(tape_fd, datestamp);
1196 hostname = syncpipe_getstr();
1197 tapefd_setinfo_host(tape_fd, hostname);
1199 diskname = syncpipe_getstr();
1200 tapefd_setinfo_disk(tape_fd, diskname);
1202 level = syncpipe_getint();
1203 tapefd_setinfo_level(tape_fd, level);
1207 #ifdef HAVE_LIBVTBLC
1208 case 'L': /* read vtbl label */
1209 vtbl_no = syncpipe_getint();
1210 vol_label = syncpipe_getstr();
1211 fprintf(stderr, "taper: read label string \"%s\" from pipe\n",
1213 strncpy(vtbl_entry[vtbl_no].label, vol_label, 45);
1216 case 'D': /* read vtbl date */
1217 vtbl_no = syncpipe_getint();
1218 vol_date = syncpipe_getstr();
1219 fprintf(stderr, "taper: read date string \"%s\" from pipe\n",
1221 strncpy(vtbl_entry[vtbl_no].date, vol_date, 20);
1223 #endif /* HAVE_LIBVTBLC */
1226 end_tape(0); /* XXX check results of end tape ?? */
1228 amfree(taper_datestamp);
1231 amfree(changer_resultstr);
1234 amfree(config_name);
1236 malloc_size_2 = malloc_inuse(&malloc_hist_2);
1238 if(malloc_size_1 != malloc_size_2) {
1239 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
1253 int full_buffers, i, bufnum;
1255 char number[NUM_STR_SIZE];
1256 char *rdwait_str, *wrwait_str, *fmwait_str;
1258 rdwait = wrwait = times_zero;
1266 fprintf(stderr, "taper: w: start file\n");
1271 * Tell the reader that the tape is open, and give it all the buffers.
1274 for(i = 0; i < conf_tapebufs; i++) {
1276 fprintf(stderr, "taper: w: put R%d\n", i);
1279 syncpipe_put('R'); syncpipe_putint(i);
1283 * We write the filemark at the start of the file rather than at the end,
1284 * so that it can proceed in parallel with the reader's initial filling
1285 * up of the buffers.
1289 if(!write_filemark())
1291 fmwait = stopclock();
1300 * At the start of the file, or if the input can't keep up with the
1301 * tape, we enter STOPPED mode, which waits for most of the buffers
1302 * to fill up before writing to tape. This maximizes the amount of
1303 * data written in chunks to the tape drive, minimizing the number
1304 * of starts/stops, which in turn saves tape and time.
1307 if(interactive) fputs("[WS]", stderr);
1309 while(full_buffers < conf_tapebufs - THRESHOLD) {
1310 tok = syncpipe_get();
1311 if(tok != 'W') break;
1312 bufnum = syncpipe_getint();
1314 fprintf(stderr,"taper: w: got W%d\n",bufnum);
1319 rdwait = timesadd(rdwait, stopclock());
1324 * We start output when sufficient buffers have filled up, or at
1325 * end-of-file, whichever comes first. Here we drain all the buffers
1326 * that were waited on in STOPPED mode. If more full buffers come
1327 * in, then we will be STREAMING.
1330 while(full_buffers) {
1331 if(tt_file_pad && bp->size < tt_blocksize) {
1332 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
1333 bp->size = tt_blocksize;
1335 if(!write_buffer(bp)) goto tape_error;
1343 * With any luck, the input source is faster than the tape drive. In
1344 * this case, full buffers will appear in the circular queue faster
1345 * than we can write them, so the next buffer in the queue will always
1346 * be marked FULL by the time we get to it. If so, we'll stay in
1349 * On the other hand, if we catch up to the input and thus would have
1350 * to wait for buffers to fill, we are then STOPPED again.
1353 while(tok == 'W' && bp->status == FULL) {
1354 tok = syncpipe_get();
1356 bufnum = syncpipe_getint();
1358 fprintf(stderr,"taper: w: got W%d\n",bufnum);
1361 if(bufnum != bp-buftable) {
1363 "taper: tape-writer: my buf %d reader buf %d\n",
1364 (int)(bp-buftable), bufnum);
1367 syncpipe_putstr("writer-side buffer mismatch");
1370 if(tt_file_pad && bp->size < tt_blocksize) {
1371 memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
1372 bp->size = tt_blocksize;
1374 if(!write_buffer(bp)) goto tape_error;
1380 goto reader_buffer_snafu;
1382 error("writer-side not expecting token: %c", tok);
1384 } while(tok == 'W');
1386 /* got close signal from reader, acknowledge it */
1389 goto reader_buffer_snafu;
1394 /* tell reader the tape and file number */
1396 syncpipe_putstr(label);
1397 ap_snprintf(number, sizeof(number), "%d", filenum);
1398 syncpipe_putstr(number);
1400 ap_snprintf(number, sizeof(number), "%ld", total_writes);
1401 rdwait_str = stralloc(walltime_str(rdwait));
1402 wrwait_str = stralloc(walltime_str(wrwait));
1403 fmwait_str = stralloc(walltime_str(fmwait));
1404 errstr = newvstralloc(errstr,
1406 " writers ", number,
1407 " rdwait ", rdwait_str,
1408 " wrwait ", wrwait_str,
1409 " filemark ", fmwait_str,
1415 syncpipe_putstr(errstr);
1417 /* XXX go to next tape if past tape size? */
1422 /* got tape error */
1423 if(next_tape(1)) syncpipe_put('T'); /* next tape in place, try again */
1424 else syncpipe_put('E'); /* no more tapes, fail */
1425 syncpipe_putstr(errstr);
1428 /* wait for reader to acknowledge error */
1430 tok = syncpipe_get();
1431 if(tok != 'W' && tok != 'C' && tok != 'e')
1432 error("writer: got '%c' unexpectedly after error", tok);
1434 syncpipe_getint(); /* eat buffer number */
1435 } while(tok != 'e');
1438 reader_buffer_snafu:
1443 int write_buffer(bp)
1448 if(bp->status != FULL) {
1449 /* XXX buffer management snafu */
1454 rc = tapefd_write(tape_fd, bp->buffer, bp->size);
1455 if(rc == bp->size) {
1456 #if defined(NEED_RESETOFS)
1457 static double tape_used_modulus_2gb = 0;
1460 * If the next write will go over the 2 GByte boundary, reset
1461 * the kernel concept of where we are to make sure it does not
1464 tape_used_modulus_2gb += (double)rc;
1465 if(tape_used_modulus_2gb + (double)rc > (double)0x7fffffff) {
1466 tape_used_modulus_2gb = 0;
1467 tapefd_resetofs(tape_fd);
1470 wrwait = timesadd(wrwait, stopclock());
1472 total_tape_used += (double)rc;
1474 if(interactive || bufdebug) dumpstatus(bp);
1475 if(interactive) fputs("W", stderr);
1478 fprintf(stderr, "taper: w: put R%d\n", (int)(bp-buftable));
1481 syncpipe_put('R'); syncpipe_putint(bp-buftable);
1484 errstr = newvstralloc(errstr,
1486 (rc != -1) ? "short write" : strerror(errno),
1488 wrwait = timesadd(wrwait, stopclock());
1489 if(interactive) fputs("[WE]", stderr);
1496 * ========================================================================
1497 * SHARED-MEMORY BUFFER SUBSYSTEM
1505 char *attach_buffers(size)
1510 shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0700);
1515 result = (char *)shmat(shmid, (SHM_ARG_TYPE *)NULL, 0);
1517 if(result == (char *)-1) {
1518 int save_errno = errno;
1522 error("shmat: %s", strerror(errno));
1529 void detach_buffers(bufp)
1532 if(shmdt((SHM_ARG_TYPE *)bufp) == -1) {
1533 error("shmdt: %s", strerror(errno));
1537 void destroy_buffers()
1539 if(shmid == -1) return; /* nothing to destroy */
1540 if(shmctl(shmid, IPC_RMID, NULL) == -1) {
1541 error("shmctl: %s", strerror(errno));
1548 #ifdef HAVE_SYS_MMAN_H
1549 #include <sys/mman.h>
1553 # ifdef MAP_ANONYMOUS /* OSF/1-style */
1554 # define MAP_ANON MAP_ANONYMOUS
1555 # else /* SunOS4-style */
1557 # define ZERO_FILE "/dev/zero"
1562 unsigned int saved_size;
1564 char *attach_buffers(size)
1570 shmfd = open(ZERO_FILE, O_RDWR);
1572 error("attach_buffers: could not open %s: %s",
1579 shmbuf = (char *) mmap((void *) 0,
1581 PROT_READ|PROT_WRITE,
1582 MAP_ANON|MAP_SHARED,
1588 void detach_buffers(bufp)
1591 if(munmap((void *)bufp, saved_size) == -1) {
1592 error("detach_buffers: munmap: %s", strerror(errno));
1598 void destroy_buffers()
1603 error: must define either HAVE_SYSVSHM or HAVE_MMAP!
1610 * ========================================================================
1611 * SYNC-PIPE SUBSYSTEM
1615 int getpipe, putpipe;
1617 void syncpipe_init(rd, wr)
1629 rc = read(getpipe, buf, sizeof(buf));
1630 if(rc == 0) /* EOF */
1631 error("syncpipe_get: %c: unexpected EOF", *procname);
1633 error("syncpipe_get: %c: %s", *procname, strerror(errno));
1635 if(bufdebug && *buf != 'R' && *buf != 'W') {
1636 fprintf(stderr,"taper: %c: getc %c\n",*procname,*buf);
1643 int syncpipe_getint()
1647 int len = sizeof(i);
1650 for(p = (char *)&i; len > 0; len -= rc, p += rc) {
1651 if ((rc = read(getpipe, p, len)) <= 0) {
1652 error("syncpipe_getint: %s",
1653 rc < 0 ? strerror(errno) : "short read");
1661 char *syncpipe_getstr()
1668 if((len = syncpipe_getint()) <= 0) {
1674 for(p = str; len > 0; len -= rc, p += rc) {
1675 if ((rc = read(getpipe, p, len)) <= 0) {
1676 error("syncpipe_getstr: %s",
1677 rc < 0 ? strerror(errno) : "short read");
1685 void syncpipe_put(chi)
1692 if(bufdebug && chi != 'R' && chi != 'W') {
1693 fprintf(stderr,"taper: %c: putc %c\n",*procname,chi);
1697 for(l = 0, n = sizeof(ch); l < n; l += s) {
1698 if((s = write(putpipe, item + l, n - l)) < 0) {
1699 error("syncpipe_put: %s", strerror(errno));
1704 void syncpipe_putint(i)
1708 char *item = (char *)&i;
1710 for(l = 0, n = sizeof(i); l < n; l += s) {
1711 if((s = write(putpipe, item + l, n - l)) < 0) {
1712 error("syncpipe_putint: %s", strerror(errno));
1717 void syncpipe_putstr(item)
1722 n = strlen(item)+1; /* send '\0' as well */
1724 for(l = 0, n = strlen(item)+1; l < n; l += s) {
1725 if((s = write(putpipe, item + l, n - l)) < 0) {
1726 error("syncpipe_putstr: %s", strerror(errno));
1733 * ========================================================================
1734 * TAPE MANIPULATION SUBSYSTEM
1738 /* local functions */
1739 int scan_init P((int rc, int ns, int bk));
1740 int taperscan_slot P((int rc, char *slotstr, char *device));
1741 char *taper_scan P((void));
1742 int label_tape P((void));
1746 char *conf_tapelist_old = NULL;
1747 char *olddatestamp = NULL;
1750 static int first_call = 1;
1754 if ((tapedev = taper_scan()) == NULL) {
1755 errstr = newstralloc(errstr, changer_resultstr);
1760 #ifdef HAVE_LINUX_ZFTAPE_H
1761 if (is_zftape(tapedev) == 1){
1762 if((tape_fd = tape_open(tapedev, O_RDONLY)) == -1) {
1763 errstr = newstralloc2(errstr, "taper: ",
1764 (errno == EACCES) ? "tape is write-protected"
1768 if((result = tapefd_rdlabel(tape_fd, &olddatestamp, &label)) != NULL) {
1769 amfree(olddatestamp);
1770 errstr = newstralloc(errstr, result);
1773 if(tapefd_rewind(tape_fd) == -1) {
1776 tapefd_close(tape_fd);
1780 #endif /* !HAVE_LINUX_ZFTAPE_H */
1781 if((result = tape_rdlabel(tapedev, &olddatestamp, &label)) != NULL) {
1782 amfree(olddatestamp);
1783 errstr = newstralloc(errstr, result);
1787 fprintf(stderr, "taper: read label `%s' date `%s'\n", label, olddatestamp);
1789 amfree(olddatestamp);
1791 /* check against tape list */
1792 if (strcmp(label, FAKE_LABEL) != 0) {
1793 tp = lookup_tapelabel(label);
1795 errstr = newvstralloc(errstr,
1797 " match labelstr but it not listed in the tapelist file",
1801 else if(tp != NULL && !reusable_tape(tp)) {
1802 errstr = newvstralloc(errstr,
1803 "cannot overwrite active tape ", label,
1808 if(!match(labelstr, label)) {
1809 errstr = newvstralloc(errstr,
1811 " doesn\'t match labelstr \"", labelstr, "\"",
1817 if((tape_fd = tape_open(tapedev, O_WRONLY)) == -1) {
1818 if(errno == EACCES) {
1819 errstr = newstralloc(errstr,
1820 "writing label: tape is write protected");
1822 errstr = newstralloc2(errstr,
1823 "writing label: ", strerror(errno));
1828 tapefd_setinfo_length(tape_fd, tt->length);
1830 tapefd_setinfo_datestamp(tape_fd, taper_datestamp);
1831 tapefd_setinfo_disk(tape_fd, label);
1832 result = tapefd_wrlabel(tape_fd, taper_datestamp, label, tt_blocksize);
1833 if(result != NULL) {
1834 errstr = newstralloc(errstr, result);
1838 fprintf(stderr, "taper: wrote label `%s' date `%s'\n", label, taper_datestamp);
1841 #ifdef HAVE_LIBVTBLC
1842 /* store time for the first volume entry */
1844 tape_timep = localtime(&raw_time);
1845 strftime(start_datestr, 20, "%T %D", tape_timep);
1846 fprintf(stderr, "taper: got vtbl start time: %s\n", start_datestr);
1848 #endif /* HAVE_LIBVTBLC */
1850 /* write tape list */
1852 /* XXX add cur_tape number to tape list structure */
1853 if (strcmp(label, FAKE_LABEL) != 0) {
1856 conf_tapelist_old = stralloc2(conf_tapelist, ".yesterday");
1858 char cur_str[NUM_STR_SIZE];
1860 ap_snprintf(cur_str, sizeof(cur_str), "%d", cur_tape - 1);
1861 conf_tapelist_old = vstralloc(conf_tapelist,
1862 ".today.", cur_str, NULL);
1864 if(write_tapelist(conf_tapelist_old)) {
1865 error("could not write tapelist: %s", strerror(errno));
1867 amfree(conf_tapelist_old);
1869 remove_tapelabel(label);
1870 add_tapelabel(atoi(taper_datestamp), label);
1871 if(write_tapelist(conf_tapelist)) {
1872 error("could not write tapelist: %s", strerror(errno));
1876 log_add(L_START, "datestamp %s label %s tape %d",
1877 taper_datestamp, label, cur_tape);
1878 if (first_call && strcmp(label, FAKE_LABEL) == 0) {
1880 log_add(L_WARNING, "tapedev is %s, dumps will be thrown away", tapedev);
1883 total_tape_used=0.0;
1889 int first_tape(new_datestamp)
1890 char *new_datestamp;
1892 if((have_changer = changer_init()) < 0) {
1893 error("changer initialization failed: %s", strerror(errno));
1897 taper_datestamp = newstralloc(taper_datestamp, new_datestamp);
1906 int next_tape(writerror)
1909 end_tape(writerror);
1911 if(++cur_tape >= runtapes)
1923 int end_tape(writerror)
1930 log_add(L_INFO, "tape %s kb %ld fm %d %s",
1932 (long) ((total_tape_used+1023.0) / 1024.0),
1934 writerror? errstr : "[OK]");
1936 fprintf(stderr, "taper: writing end marker. [%s %s kb %ld fm %d]\n",
1938 writerror? "ERR" : "OK",
1939 (long) ((total_tape_used+1023.0) / 1024.0),
1943 if(! write_filemark()) {
1948 result = tapefd_wrendmark(tape_fd, taper_datestamp, tt_blocksize);
1949 if(result != NULL) {
1950 errstr = newstralloc(errstr, result);
1957 #ifdef HAVE_LINUX_ZFTAPE_H
1958 if (tape_fd >= 0 && is_zftape(tapedev) == 1) {
1959 /* rewind the tape */
1961 if(tapefd_rewind(tape_fd) == -1 ) {
1962 errstr = newstralloc2(errstr, "rewinding tape: ", strerror(errno));
1966 /* close the tape */
1968 if(tapefd_close(tape_fd) == -1) {
1969 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
1975 #ifdef HAVE_LIBVTBLC
1976 /* update volume table */
1977 fprintf(stderr, "taper: updating volume table ...\n");
1980 if ((tape_fd = raw_tape_open(rawtapedev, O_RDWR)) == -1) {
1981 if(errno == EACCES) {
1982 errstr = newstralloc(errstr,
1983 "updating volume table: tape is write protected");
1985 errstr = newstralloc2(errstr,
1986 "updating volume table: ",
1992 /* read volume table */
1993 if ((num_volumes = read_vtbl(tape_fd, volumes, vtbl_buffer,
1994 &first_seg, &last_seg)) == -1 ) {
1995 errstr = newstralloc2(errstr,
1996 "reading volume table: ",
2001 /* set volume label and date for first entry */
2003 if(set_label(label, volumes, num_volumes, vtbl_no)){
2004 errstr = newstralloc2(errstr,
2005 "setting label for entry 1: ",
2010 /* date of start writing this tape */
2011 if (set_date(start_datestr, volumes, num_volumes, vtbl_no)){
2012 errstr = newstralloc2(errstr,
2013 "setting date for entry 1: ",
2018 /* set volume labels and dates for backup files */
2019 for (vtbl_no = 1; vtbl_no <= num_volumes - 2; vtbl_no++){
2020 fprintf(stderr,"taper: label %i: %s, date %s\n",
2022 vtbl_entry[vtbl_no].label,
2023 vtbl_entry[vtbl_no].date);
2025 if(set_label(vtbl_entry[vtbl_no].label,
2026 volumes, num_volumes, vtbl_no)){
2027 errstr = newstralloc2(errstr,
2028 "setting label for entry i: ",
2033 if(set_date(vtbl_entry[vtbl_no].date,
2034 volumes, num_volumes, vtbl_no)){
2035 errstr = newstralloc2(errstr,
2036 "setting date for entry i: ",
2042 /* set volume label and date for last entry */
2043 vtbl_no = num_volumes - 1;
2044 if(set_label("AMANDA Tape End", volumes, num_volumes, vtbl_no)){
2045 errstr = newstralloc2(errstr,
2046 "setting label for last entry: ",
2051 datestr = NULL; /* take current time */
2052 if (set_date(datestr, volumes, num_volumes, vtbl_no)){
2053 errstr = newstralloc2(errstr,
2054 "setting date for last entry 1: ",
2059 /* write volume table back */
2060 if (write_vtbl(tape_fd, volumes, vtbl_buffer, num_volumes, first_seg,
2061 op_mode == trunc)) {
2062 errstr = newstralloc2(errstr,
2063 "writing volume table: ",
2069 fprintf(stderr, "taper: updating volume table: done.\n");
2071 #endif /* HAVE_LIBVTBLC */
2073 #endif /* !HAVE_LINUX_ZFTAPE_H */
2075 /* close the tape and let the OS write the final filemarks */
2079 if(tape_fd >= 0 && tapefd_close(tape_fd) == -1 && ! writerror) {
2080 errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
2090 int write_filemark()
2092 if(tapefd_weof(tape_fd, 1) == -1) {
2093 errstr = newstralloc2(errstr, "writing filemark: ", strerror(errno));
2102 * ========================================================================
2106 int nslots, backwards, found, got_match, tapedays;
2107 char *first_match_label = NULL, *first_match = NULL, *found_device = NULL;
2108 char *searchlabel, *labelstr;
2111 int scan_init(rc, ns, bk)
2115 fprintf(stderr, "%s: could not get changer info: %s\n",
2116 get_pname(), changer_resultstr);
2126 int taperscan_slot(rc, slotstr, device)
2132 char *scan_datestamp = NULL;
2135 fprintf(stderr, "%s: fatal slot %s: %s\n",
2136 get_pname(), slotstr, changer_resultstr);
2141 fprintf(stderr, "%s: slot %s: %s\n", get_pname(),
2142 slotstr, changer_resultstr);
2147 if((t_errstr = tape_rdlabel(device, &scan_datestamp, &label)) != NULL) {
2148 amfree(scan_datestamp);
2149 fprintf(stderr, "%s: slot %s: %s\n",
2150 get_pname(), slotstr, t_errstr);
2154 /* got an amanda tape */
2155 fprintf(stderr, "%s: slot %s: date %-8s label %s",
2156 get_pname(), slotstr, scan_datestamp, label);
2158 amfree(scan_datestamp);
2159 if(searchlabel != NULL
2160 && (strcmp(label, FAKE_LABEL) == 0
2161 || strcmp(label, searchlabel) == 0)) {
2162 /* it's the one we are looking for, stop here */
2163 fprintf(stderr, " (exact label match)\n");
2165 found_device = newstralloc(found_device, device);
2169 else if(!match(labelstr, label)) {
2170 fprintf(stderr, " (no match)\n");
2174 /* not an exact label match, but a labelstr match */
2175 /* check against tape list */
2176 tp = lookup_tapelabel(label);
2178 fprintf(stderr, "(not in tapelist)\n");
2181 else if(!reusable_tape(tp)) {
2182 fprintf(stderr, " (active tape)\n");
2185 else if(got_match == 0 && tp->datestamp == 0) {
2187 first_match = newstralloc(first_match, slotstr);
2188 first_match_label = newstralloc(first_match_label, label);
2189 fprintf(stderr, " (new tape)\n");
2192 found_device = newstralloc(found_device, device);
2195 else if(got_match) {
2196 fprintf(stderr, " (labelstr match)\n");
2201 first_match = newstralloc(first_match, slotstr);
2202 first_match_label = newstralloc(first_match_label, label);
2203 fprintf(stderr, " (first labelstr match)\n");
2205 if(!backwards || !searchlabel) {
2207 found_device = newstralloc(found_device, device);
2219 char *outslot = NULL;
2221 if((tp = lookup_last_reusable_tape(0)) == NULL)
2224 searchlabel = tp->label;
2229 if (searchlabel != NULL)
2230 changer_find(scan_init, taperscan_slot, searchlabel);
2232 changer_scan(scan_init, taperscan_slot);
2234 if(found == 2 || found == 3)
2235 searchlabel = first_match_label;
2236 else if(!found && got_match) {
2237 searchlabel = first_match_label;
2238 amfree(found_device);
2239 if(changer_loadslot(first_match, &outslot, &found_device) == 0) {
2246 changer_resultstr = newvstralloc(changer_resultstr,
2247 "label ", searchlabel,
2248 " or new tape not found in rack",
2251 changer_resultstr = newstralloc(changer_resultstr,
2252 "new tape not found in rack");
2257 outslot = found_device;
2258 found_device = NULL; /* forget about our copy */
2261 amfree(found_device);