* Authors: the Amanda Development Team. Its members are listed in a
* file named AUTHORS, in the root directory of this distribution.
*/
-/* $Id: taper.c,v 1.47.2.14.4.8.2.18 2004/02/13 14:11:26 martinea Exp $
+/* $Id: taper.c 6512 2007-05-24 17:00:24Z ian $
*
* moves files from holding disk to tape, or from a socket to tape
*/
-#include "amanda.h"
-#include "conffile.h"
-#include "tapefile.h"
+/* FIXME: This file needs to use gettext. */
+
+#include <glib.h>
+#include "physmem.h"
+
+#include "changer.h"
#include "clock.h"
-#include "stream.h"
+#include "conffile.h"
+#include "device.h"
#include "logfile.h"
-#include "tapeio.h"
-#include "changer.h"
-#include "version.h"
-#include "arglist.h"
-#include "token.h"
-#include "amfeatures.h"
-#include "fileheader.h"
#include "server_util.h"
-#ifdef HAVE_LIBVTBLC
-#include <vtblc.h>
-#include <strings.h>
-
-static int vtbl_no = -1;
-static int len = 0;
-static int offset = 0;
-static char *datestr = NULL;
-static char start_datestr[20];
-time_t raw_time;
-struct tm tape_time;
-struct tm backup_time;
-struct tm *tape_timep = &tape_time;
-typedef struct vtbl_lbls {
- u_int8_t label[45];
- u_int8_t date[20];
-} vtbl_lbls;
-static vtbl_lbls vtbl_entry[MAX_VOLUMES];
-#endif /* HAVE_LIBVTBLC */
-/*
- * XXX update stat collection/printing
- * XXX advance to next tape first in next_tape
- * XXX label is being read twice?
- */
-
-/* NBUFS replaced by conf_tapebufs */
-/* #define NBUFS 20 */
-int conf_tapebufs;
-
-/* This is now the number of empties, not full bufs */
-#define THRESHOLD 1
-
-#define CONNECT_TIMEOUT 2*60
-
-
-
-#define EMPTY 1
-#define FILLING 2
-#define FULL 3
-
-typedef struct buffer_s {
- long status;
- unsigned int size;
- char *buffer;
-} buffer_t;
-
-#define nextbuf(p) ((p) == buftable+conf_tapebufs-1? buftable : (p)+1)
-#define prevbuf(p) ((p) == buftable? buftable+conf_tapebufs-1 : (p)-1)
-
-/* major modules */
-int main P((int main_argc, char **main_argv));
-void file_reader_side P((int rdpipe, int wrpipe));
-void tape_writer_side P((int rdpipe, int wrpipe));
-
-/* shared-memory routines */
-char *attach_buffers P((unsigned int size));
-void detach_buffers P((char *bufp));
-void destroy_buffers P((void));
-
-/* synchronization pipe routines */
-void syncpipe_init P((int rd, int wr));
-char syncpipe_get P((void));
-int syncpipe_getint P((void));
-char *syncpipe_getstr P((void));
-void syncpipe_put P((int ch));
-void syncpipe_putint P((int i));
-void syncpipe_putstr P((char *str));
-
-/* tape manipulation subsystem */
-int first_tape P((char *new_datestamp));
-int next_tape P((int writerr));
-int end_tape P((int writerr));
-int write_filemark P((void));
-
-/*
- * ========================================================================
- * GLOBAL STATE
- *
- */
-int interactive;
-int writerpid;
-times_t total_wait;
-#ifdef TAPER_DEBUG
-int bufdebug = 1;
-#else
-int bufdebug = 0;
-#endif
-
-char *buffers = NULL;
-buffer_t *buftable = NULL;
-
-char *procname = "parent";
-
-char *taper_datestamp = NULL;
-char *label = NULL;
-int filenum;
-char *errstr = NULL;
-int tape_fd = -1;
-char *tapedev = NULL;
-char *tapetype = NULL;
-tapetype_t *tt = NULL;
-long tt_blocksize;
-long tt_blocksize_kb;
-long buffer_size;
-int tt_file_pad;
-static unsigned long malloc_hist_1, malloc_size_1;
-static unsigned long malloc_hist_2, malloc_size_2;
-
-am_feature_t *their_features = NULL;
-
-int runtapes, cur_tape, have_changer, tapedays;
-char *labelstr, *conf_tapelist;
-#ifdef HAVE_LIBVTBLC
-char *rawtapedev;
-int first_seg, last_seg;
-#endif /* HAVE_LIBVTBLC */
+#include "stream.h"
+#include "tapefile.h"
+#include "taperscan.h"
+#include "taper-source.h"
+#include "timestamp.h"
+#include "util.h"
+#include "version.h"
+#include "queueing.h"
+#include "device-queueing.h"
+
+/* FIXME: This should not be here. */
+#define CONNECT_TIMEOUT (2*60)
+
+/* Use this instead of global variables, so that we are reentrant. */
+typedef struct {
+ Device * device;
+ char * driver_start_time;
+ int cur_tape;
+ char * next_tape_label;
+ char * next_tape_device;
+ taper_scan_tracker_t * taper_scan_tracker;
+ char * last_errmsg;
+ off_t total_bytes;
+ int have_changer;
+} taper_state_t;
+
+typedef struct {
+ char * handle;
+ char * hostname;
+ char * diskname;
+ int level;
+ char * timestamp;
+ char * id_string;
+ TaperSource * source;
+ int current_part;
+ GTimeVal total_time;
+ guint64 total_bytes;
+} dump_info_t;
+
+static gboolean label_new_tape(taper_state_t * state, dump_info_t * dump_info);
+
+static void init_taper_state(taper_state_t* state) {
+ state->device = NULL;
+ state->driver_start_time = NULL;
+ state->taper_scan_tracker = taper_scan_tracker_new();
+ state->last_errmsg = NULL;
+ state->total_bytes = 0;
+}
-/*
- * ========================================================================
- * MAIN PROGRAM
- *
- */
-int main(main_argc, main_argv)
-int main_argc;
-char **main_argv;
-{
- int p2c[2], c2p[2]; /* parent-to-child, child-to-parent pipes */
- char *conffile;
- int fd;
- unsigned int size;
- int i;
- int j;
- int page_size;
- char *first_buffer;
-
- for(fd = 3; fd < FD_SETSIZE; fd++) {
- /*
- * Make sure nobody spoofs us with a lot of extra open files
- * that would cause an open we do to get a very high file
- * descriptor, which in turn might be used as an index into
- * an array (e.g. an fd_set).
- */
- close(fd);
+static void cleanup(taper_state_t * state) {
+ amfree(state->driver_start_time);
+ amfree(state->next_tape_label);
+ amfree(state->next_tape_device);
+ amfree(state->last_errmsg);
+ taper_scan_tracker_free(state->taper_scan_tracker);
+ if (state->device != NULL) {
+ g_object_unref(state->device);
+ state->device = NULL;
}
+}
- set_pname("taper");
-
- malloc_size_1 = malloc_inuse(&malloc_hist_1);
-
- fprintf(stderr, "%s: pid %ld executable %s version %s\n",
- get_pname(), (long) getpid(), main_argv[0], version());
- fflush(stderr);
-
- if (main_argc > 1 && main_argv[1][0] != '-') {
- config_name = stralloc(main_argv[1]);
- config_dir = vstralloc(CONFIG_DIR, "/", main_argv[1], "/", NULL);
- main_argc--;
- main_argv++;
- } else {
- char my_cwd[STR_SIZE];
-
- if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
- error("cannot determine current working directory");
- }
- config_dir = stralloc2(my_cwd, "/");
- if ((config_name = strrchr(my_cwd, '/')) != NULL) {
- config_name = stralloc(config_name + 1);
- }
+static void free_dump_info(dump_info_t * info) {
+ amfree(info->handle);
+ amfree(info->hostname);
+ amfree(info->diskname);
+ amfree(info->timestamp);
+ amfree(info->id_string);
+ if (info->source != NULL) {
+ g_object_unref(info->source);
+ info->source = NULL;
}
+}
- safe_cd();
-
- /* print prompts and debug messages if running interactive */
+/* Validate that a command has the proper number of arguments, and
+ print a meaningful error message if not. It returns only if the
+ check is successful. */
+static void validate_args(struct cmdargs * cmdargs,
+ char ** argnames) {
+ int len = g_strv_length(argnames);
- interactive = (main_argc > 1 && strcmp(main_argv[1],"-t") == 0);
- if(interactive) {
- erroutput_type = ERR_INTERACTIVE;
- } else {
- erroutput_type = ERR_AMANDALOG;
- set_logerror(logerror);
+ if (len > cmdargs->argc) {
+ error("error [taper %s: not enough args; first missing arg is %s]",
+ cmdstr[cmdargs->cmd], argnames[cmdargs->argc]);
}
- conffile = stralloc2(config_dir, CONFFILE_NAME);
- if(read_conffile(conffile)) {
- error("errors processing config file \"%s\"", conffile);
+ if (len < cmdargs->argc) {
+ error("error [taper %s: Too many args: Got %d, expected %d.]",
+ cmdstr[cmdargs->cmd], cmdargs->argc, len);
}
- amfree(conffile);
+}
- conf_tapelist = getconf_str(CNF_TAPELIST);
- if (*conf_tapelist == '/') {
- conf_tapelist = stralloc(conf_tapelist);
- } else {
- conf_tapelist = stralloc2(config_dir, conf_tapelist);
- }
- if(read_tapelist(conf_tapelist)) {
- error("could not load tapelist \"%s\"", conf_tapelist);
- }
+/* Open a socket to the dumper. Returns TRUE if everything is happy, FALSE
+ otherwise. */
+static gboolean open_read_socket(dump_info_t * info, char * split_diskbuffer,
+ guint64 splitsize, guint64 fallback_splitsize) {
+ in_port_t port = 0;
+ int socket;
+ int fd;
+ int result;
+ struct addrinfo *res;
- tapedev = getconf_str(CNF_TAPEDEV);
- tapetype = getconf_str(CNF_TAPETYPE);
- tt = lookup_tapetype(tapetype);
-#ifdef HAVE_LIBVTBLC
- rawtapedev = getconf_str(CNF_RAWTAPEDEV);
-#endif /* HAVE_LIBVTBLC */
- tapedays = getconf_int(CNF_TAPECYCLE);
- labelstr = getconf_str(CNF_LABELSTR);
+ if ((result = resolve_hostname("localhost", 0, &res, NULL) != 0)) {
+ char *m;
+ char *q;
+ int save_errno = errno;
+ char *qdiskname = quote_string(info->diskname);
+
+ m = vstralloc("[localhost resolve failure: ",
+ strerror(save_errno),
+ "]",
+ NULL);
+ q = quote_string(m);
+ putresult(TAPE_ERROR, "%s %s\n", info->handle, q);
+ log_add(L_FAIL, "%s %s %s %d %s",
+ info->hostname, qdiskname, info->timestamp,
+ info->level, q);
+ amfree(qdiskname);
+ amfree(m);
+ amfree(q);
+ return FALSE;
+ }
- runtapes = getconf_int(CNF_RUNTAPES);
- cur_tape = 0;
+ socket = stream_server(res->ai_family, &port, 0, STREAM_BUFSIZE, 0);
+ freeaddrinfo(res);
- conf_tapebufs = getconf_int(CNF_TAPEBUFS);
+ if (socket < 0) {
+ char *m;
+ char *q;
+ int save_errno = errno;
+ char *qdiskname = quote_string(info->diskname);
+
+ m = vstralloc("[port create failure: ",
+ strerror(save_errno),
+ "]",
+ NULL);
+ q = quote_string(m);
+ putresult(TAPE_ERROR, "%s %s\n", info->handle, q);
+ log_add(L_FAIL, "%s %s %s %d %s",
+ info->hostname, qdiskname, info->timestamp,
+ info->level, q);
+ amfree(qdiskname);
+ amfree(m);
+ amfree(q);
+ return FALSE;
+ }
- tt_blocksize_kb = tt->blocksize;
- tt_blocksize = tt_blocksize_kb * 1024;
- tt_file_pad = tt->file_pad;
+ putresult(PORT, "%d\n", port);
- if(interactive) {
- fprintf(stderr,"taper: running in interactive test mode\n");
- fflush(stderr);
- }
+ fd = stream_accept(socket, CONNECT_TIMEOUT, 0, STREAM_BUFSIZE);
- /* create read/write syncronization pipes */
-
- if(pipe(p2c) || pipe(c2p))
- error("creating sync pipes: %s", strerror(errno));
-
- /* create shared memory segment */
-
-#if defined(HAVE_GETPAGESIZE)
- page_size = getpagesize();
- fprintf(stderr, "%s: page size is %d\n", get_pname(), page_size);
-#else
- page_size = 1024;
- fprintf(stderr, "%s: getpagesize() not available, using %d\n",
- get_pname(),
- page_size);
-#endif
- buffer_size = am_round(tt_blocksize, page_size);
- fprintf(stderr, "%s: buffer size is %ld\n", get_pname(), buffer_size);
- while(conf_tapebufs > 0) {
- size = page_size;
- size += conf_tapebufs * buffer_size;
- size += conf_tapebufs * sizeof(buffer_t);
- if((buffers = attach_buffers(size)) != NULL) {
- break;
- }
- log_add(L_INFO, "attach_buffers: (%d tapebuf%s: %d bytes) %s",
- conf_tapebufs,
- (conf_tapebufs == 1) ? "" : "s",
- size,
- strerror(errno));
- conf_tapebufs--;
- }
- if(buffers == NULL) {
- error("cannot allocate shared memory");
- }
- i = (buffers - (char *)0) & (page_size - 1); /* page boundary offset */
- if(i != 0) {
- first_buffer = buffers + page_size - i;
- fprintf(stderr, "%s: shared memory at %p, first buffer at %p\n",
- get_pname(),
- buffers,
- first_buffer);
- } else {
- first_buffer = buffers;
- }
- buftable = (buffer_t *)(first_buffer + conf_tapebufs * buffer_size);
- memset(buftable, 0, conf_tapebufs * sizeof(buffer_t));
- if(conf_tapebufs < 10) {
- j = 1;
- } else if(conf_tapebufs < 100) {
- j = 2;
+ if (fd < 0) {
+ char *m, *q;
+ int save_errno = errno;
+ char *qdiskname = quote_string(info->diskname);
+ m = vstralloc("[port connect failure: ",
+ strerror(save_errno),
+ "]",
+ NULL);
+ q = quote_string(m);
+ putresult(TAPE_ERROR, "%s %s\n", info->handle, q);
+ log_add(L_FAIL, "%s %s %s %d %s",
+ info->hostname, qdiskname, info->timestamp,
+ info->level, q);
+ amfree(qdiskname);
+ aclose(socket);
+ amfree(m);
+ amfree(q);
+ return FALSE;
} else {
- j = 3;
+ aclose(socket);
}
- for(i = 0; i < conf_tapebufs; i++) {
- buftable[i].buffer = first_buffer + i * buffer_size;
- fprintf(stderr, "%s: buffer[%0*d] at %p\n",
- get_pname(),
- j, i,
- buftable[i].buffer);
- }
- fprintf(stderr, "%s: buffer structures at %p for %d bytes\n",
- get_pname(),
- buftable,
- (int)(conf_tapebufs * sizeof(buffer_t)));
-
- /* fork off child writer process, parent becomes reader process */
-
- switch(writerpid = fork()) {
- case -1:
- error("fork: %s", strerror(errno));
- case 0: /* child */
- aclose(p2c[1]);
- aclose(c2p[0]);
+ info->source = taper_source_new(info->handle, PORT_WRITE, NULL, fd,
+ split_diskbuffer, splitsize,
+ fallback_splitsize);
+ /* FIXME: This should be handled properly. */
+ g_assert(info->source != NULL);
+ return TRUE;
+}
- tape_writer_side(p2c[0], c2p[1]);
- error("tape writer terminated unexpectedly");
+typedef struct {
+ ConsumerFunctor next_consumer;
+ gpointer next_consumer_data;
+ guint64 bytes_written;
+} CountingConsumerData;
- default: /* parent */
- aclose(p2c[0]);
- aclose(c2p[1]);
+/* A ConsumerFunctor. This consumer just passes its arguments on to a
+ second consumer, but counts the number of bytes successfully
+ written. */
+static ssize_t counting_consumer(gpointer user_data, queue_buffer_t * buffer) {
+ ssize_t result;
+ CountingConsumerData * data = user_data;
- file_reader_side(c2p[0], p2c[1]);
- error("file reader terminated unexpectedly");
+ result = data->next_consumer(data->next_consumer_data, buffer);
+
+ if (result > 0) {
+ data->bytes_written += result;
}
- /* NOTREACHED */
- return 0;
+ return result;
}
-
-/*
- * ========================================================================
- * FILE READER SIDE
- *
- */
-void read_file P((int fd, char *handle,
- char *host, char *disk, char *datestamp,
- int level, int port_flag));
-int taper_fill_buffer P((int fd, buffer_t *bp, int buflen));
-void dumpbufs P((char *str1));
-void dumpstatus P((buffer_t *bp));
-
-void file_reader_side(rdpipe, wrpipe)
-int rdpipe, wrpipe;
-{
- cmd_t cmd;
- struct cmdargs cmdargs;
- char *handle = NULL;
- char *filename = NULL;
- char *hostname = NULL;
- char *diskname = NULL;
- char *result = NULL;
- char *datestamp = NULL;
- char tok;
- char *q = NULL;
- int level, fd, data_port, data_socket, wpid;
- struct stat stat_file;
- int tape_started;
- int a;
-
- procname = "reader";
- syncpipe_init(rdpipe, wrpipe);
-
- /* must get START_TAPER before beginning */
-
- startclock();
- cmd = getcmd(&cmdargs);
- total_wait = stopclock();
-
- if(cmd != START_TAPER || cmdargs.argc != 2) {
- error("error [file_reader_side cmd %d argc %d]", cmd, cmdargs.argc);
- }
-
- /* pass start command on to tape writer */
-
- taper_datestamp = newstralloc(taper_datestamp, cmdargs.argv[2]);
-
- tape_started = 0;
- syncpipe_put('S');
- syncpipe_putstr(taper_datestamp);
-
- /* get result of start command */
-
- tok = syncpipe_get();
- switch(tok) {
- case 'S':
- putresult(TAPER_OK, "\n");
- tape_started = 1;
- /* start is logged in writer */
- break;
- case 'E':
- /* no tape, bail out */
- result = syncpipe_getstr();
- q = squotef("[%s]", result ? result : "(null)");
- putresult(TAPE_ERROR, "%s\n", q);
- amfree(q);
- log_add(L_ERROR,"no-tape [%s]", result);
- amfree(result);
- syncpipe_put('e'); /* ACK error */
- break;
- default:
- error("expected 'S' or 'E' for START-TAPER, got '%c'", tok);
+static gboolean boolean_prolong(void * data) {
+ if (data == NULL) {
+ return TRUE; /* Do not interrupt. */
+ } else {
+ return *(gboolean*)data;
}
+}
- /* process further commands */
-
- while(1) {
- startclock();
- cmd = getcmd(&cmdargs);
- if(cmd != QUIT && !tape_started) {
- error("error [file_reader_side cmd %d without tape ready]", cmd);
- }
- total_wait = timesadd(total_wait, stopclock());
-
- switch(cmd) {
- case PORT_WRITE:
- /*
- * PORT-WRITE
- * handle
- * hostname
- * features
- * diskname
- * level
- * datestamp
- */
- cmdargs.argc++; /* true count of args */
- a = 2;
-
- if(a >= cmdargs.argc) {
- error("error [taper PORT-WRITE: not enough args: handle]");
- }
- handle = newstralloc(handle, cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper PORT-WRITE: not enough args: hostname]");
- }
- hostname = newstralloc(hostname, cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper PORT-WRITE: not enough args: features]");
- }
- am_release_feature_set(their_features);
- their_features = am_string_to_feature(cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper PORT-WRITE: not enough args: diskname]");
- }
- diskname = newstralloc(diskname, cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper PORT-WRITE: not enough args: level]");
- }
- level = atoi(cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper PORT-WRITE: not enough args: datestamp]");
- }
- datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
-
- if(a != cmdargs.argc) {
- error("error [taper file_reader_side PORT-WRITE: too many args: %d != %d]",
- cmdargs.argc, a);
- }
-
- data_port = 0;
- data_socket = stream_server(&data_port,
- -1,
- STREAM_BUFSIZE);
- if(data_socket < 0) {
- char *m;
-
- m = vstralloc("[port create failure: ",
- strerror(errno),
- "]",
- NULL);
- q = squote(m);
- putresult(TAPE_ERROR, "%s %s\n", handle, q);
- amfree(m);
- break;
- }
- putresult(PORT, "%d\n", data_port);
-
- if((fd = stream_accept(data_socket, CONNECT_TIMEOUT,
- -1, NETWORK_BLOCK_BYTES)) == -1) {
- q = squote("[port connect timeout]");
- putresult(TAPE_ERROR, "%s %s\n", handle, q);
- aclose(data_socket);
- break;
- }
- read_file(fd, handle, hostname, diskname, datestamp, level, 1);
- aclose(data_socket);
- break;
-
- case FILE_WRITE:
- /*
- * FILE-WRITE
- * handle
- * filename
- * hostname
- * features
- * diskname
- * level
- * datestamp
- */
- cmdargs.argc++; /* true count of args */
- a = 2;
-
- if(a >= cmdargs.argc) {
- error("error [taper FILE-WRITE: not enough args: handle]");
- }
- handle = newstralloc(handle, cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper FILE-WRITE: not enough args: filename]");
- }
- filename = newstralloc(filename, cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper FILE-WRITE: not enough args: hostname]");
- }
- hostname = newstralloc(hostname, cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper FILE-WRITE: not enough args: features]");
- }
- am_release_feature_set(their_features);
- their_features = am_string_to_feature(cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper FILE-WRITE: not enough args: diskname]");
- }
- diskname = newstralloc(diskname, cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper FILE-WRITE: not enough args: level]");
- }
- level = atoi(cmdargs.argv[a++]);
-
- if(a >= cmdargs.argc) {
- error("error [taper FILE-WRITE: not enough args: datestamp]");
- }
- datestamp = newstralloc(datestamp, cmdargs.argv[a++]);
-
- if(a != cmdargs.argc) {
- error("error [taper file_reader_side FILE-WRITE: too many args: %d != %d]",
- cmdargs.argc, a);
- }
-
- if(stat(filename,&stat_file)!=0) {
- q = squotef("[%s]", strerror(errno));
- putresult(TAPE_ERROR, "%s %s\n", handle, q);
- break;
- }
- if((fd = open(filename, O_RDONLY)) == -1) {
- q = squotef("[%s]", strerror(errno));
- putresult(TAPE_ERROR, "%s %s\n", handle, q);
- break;
- }
- read_file(fd, handle, hostname, diskname, datestamp, level, 0);
- break;
-
- case QUIT:
- putresult(QUITTING, "\n");
- fprintf(stderr,"taper: DONE [idle wait: %s secs]\n",
- walltime_str(total_wait));
- fflush(stderr);
- syncpipe_put('Q'); /* tell writer we're exiting gracefully */
- aclose(wrpipe);
-
- if((wpid = wait(NULL)) != writerpid) {
- fprintf(stderr,
- "taper: writer wait returned %d instead of %d: %s\n",
- wpid, writerpid, strerror(errno));
- fflush(stderr);
- }
-
- detach_buffers(buffers);
- destroy_buffers();
- amfree(datestamp);
- amfree(label);
- amfree(errstr);
- amfree(changer_resultstr);
- amfree(tapedev);
- amfree(config_dir);
- amfree(config_name);
-
- malloc_size_2 = malloc_inuse(&malloc_hist_2);
-
- if(malloc_size_1 != malloc_size_2) {
- malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
- }
-
- exit(0);
+/* A (simpler) wrapper around taper_scan(). */
+static gboolean simple_taper_scan(taper_state_t * state,
+ gboolean* prolong, char ** error_message) {
+ char ** label = &(state->next_tape_label);
+ char ** device = &(state->next_tape_device);
+ char *timestamp = NULL;
+ int result;
+ result = taper_scan(NULL, label, ×tamp, device,
+ state->taper_scan_tracker,
+ CHAR_taperscan_output_callback,
+ error_message, boolean_prolong, prolong);
+ if (prolong != NULL && !*prolong) {
+ g_fprintf(stderr, _("Cancelled taper scan.\n"));
+ return FALSE;
+ } else if (result < 0) {
+ g_fprintf(stderr, _("Failed taper scan: %s\n"), (*error_message)?(*error_message):_("(no error message)"));
+ amfree(timestamp);
+ return FALSE;
+ } else {
+ g_fprintf(stderr, _("taper: using label `%s' date `%s'\n"), *label,
+ state->driver_start_time);
+ if (result == 3) {
+ log_add(L_INFO,
+ _("Will write new label `%s' to new tape"),
+ *label);
+ }
- default:
- if(cmdargs.argc >= 1) {
- q = squote(cmdargs.argv[1]);
- } else if(cmdargs.argc >= 0) {
- q = squote(cmdargs.argv[0]);
- } else {
- q = stralloc("(no input?)");
- }
- putresult(BAD_COMMAND, "%s\n", q);
- break;
- }
}
- amfree(q);
- amfree(handle);
- amfree(filename);
- amfree(hostname);
- amfree(diskname);
+ amfree(timestamp);
+ return TRUE;
}
-void dumpbufs(str1)
-char *str1;
-{
- int i,j;
- long v;
-
- fprintf(stderr, "%s: state", str1);
- for(i = j = 0; i < conf_tapebufs; i = j+1) {
- v = buftable[i].status;
- for(j = i; j < conf_tapebufs && buftable[j].status == v; j++);
- j--;
- if(i == j) fprintf(stderr, " %d:", i);
- else fprintf(stderr, " %d-%d:", i, j);
- switch(v) {
- case FULL: fputc('F', stderr); break;
- case FILLING: fputc('f', stderr); break;
- case EMPTY: fputc('E', stderr); break;
- default:
- fprintf(stderr, "%ld", v);
- break;
- }
+typedef struct {
+ taper_state_t * state;
+ gboolean prolong; /* scan stops when this is FALSE. */
+ char *errmsg;
+} tape_search_request_t;
- }
- fputc('\n', stderr);
- fflush(stderr);
-}
+/* A GThread that runs taper_scan. */
+static gpointer tape_search_thread(gpointer data) {
+ tape_search_request_t * request = data;
-void dumpstatus(bp)
-buffer_t *bp;
-{
- char pn[2];
- char bt[NUM_STR_SIZE];
- char status[NUM_STR_SIZE + 1];
- char *str = NULL;
-
- pn[0] = procname[0];
- pn[1] = '\0';
- ap_snprintf(bt, sizeof(bt), "%d", (int)(bp-buftable));
-
- switch(bp->status) {
- case FULL: ap_snprintf(status, sizeof(status), "F%d", bp->size);
- break;
- case FILLING: status[0] = 'f'; status[1] = '\0'; break;
- case EMPTY: status[0] = 'E'; status[1] = '\0'; break;
- default:
- ap_snprintf(status, sizeof(status), "%ld", bp->status);
- break;
+ if (request->state->next_tape_label != NULL &&
+ request->state->next_tape_device != NULL) {
+ return GINT_TO_POINTER(TRUE);
+ } else {
+ amfree(request->state->next_tape_label);
+ amfree(request->state->next_tape_device);
}
- str = vstralloc("taper: ", pn, ": [buf ", bt, ":=", status, "]", NULL);
- dumpbufs(str);
- amfree(str);
+ return GINT_TO_POINTER
+ (simple_taper_scan(request->state,
+ &(request->prolong),
+ &(request->errmsg)));
}
-
-void read_file(fd, handle, hostname, diskname, datestamp, level, port_flag)
- int fd, level, port_flag;
- char *handle, *hostname, *diskname, *datestamp;
-{
- buffer_t *bp;
- char tok;
- int rc, err, opening, closing, bufnum, need_closing;
- long filesize;
- times_t runtime;
- char *strclosing = NULL;
- char *str;
- int header_read = 0;
- int buflen;
- dumpfile_t file;
-
- char *q = NULL;
-
-#ifdef HAVE_LIBVTBLC
- static char desc[45];
- static char vol_date[20];
- static char vol_label[45];
-#endif /* HAVE_LIBVTBLC */
-
-
- /* initialize */
-
- filesize = 0;
- closing = 0;
- need_closing = 0;
- err = 0;
- fh_init(&file);
-
- if(bufdebug) {
- fprintf(stderr, "taper: r: start file\n");
- fflush(stderr);
- }
-
- for(bp = buftable; bp < buftable + conf_tapebufs; bp++) {
- bp->status = EMPTY;
+static void log_taper_scan_errmsg(char * errmsg) {
+ char *c, *c1;
+ if (errmsg == NULL)
+ return;
+
+ c = c1 = errmsg;
+ while (*c != '\0') {
+ if (*c == '\n') {
+ *c = '\0';
+ log_add(L_WARNING,"%s", c1);
+ c1 = c+1;
+ }
+ c++;
}
+ if (strlen(c1) > 1 )
+ log_add(L_WARNING,"%s", c1);
+ amfree(errmsg);
+}
- bp = buftable;
- if(interactive || bufdebug) dumpstatus(bp);
-
- /* tell writer to open tape */
-
- opening = 1;
- syncpipe_put('O');
- syncpipe_putstr(datestamp);
- syncpipe_putstr(hostname);
- syncpipe_putstr(diskname);
- syncpipe_putint(level);
-
- startclock();
-
- /* read file in loop */
-
- while(1) {
- tok = syncpipe_get();
- switch(tok) {
-
- case 'O':
- assert(opening);
- opening = 0;
- err = 0;
- break;
-
- case 'R':
- bufnum = syncpipe_getint();
-
- if(bufdebug) {
- fprintf(stderr, "taper: r: got R%d\n", bufnum);
- fflush(stderr);
- }
-
- if(need_closing) {
- syncpipe_put('C');
- closing = 1;
- need_closing = 0;
- break;
- }
-
- if(closing) break; /* ignore extra read tokens */
-
- assert(!opening);
- if(bp->status != EMPTY || bufnum != bp-buftable) {
- /* XXX this SHOULD NOT HAPPEN. Famous last words. */
- fprintf(stderr,"taper: panic: buffer mismatch at ofs %ld:\n",
- filesize);
- if(bufnum != bp-buftable) {
- fprintf(stderr, " my buf %d but writer buf %d\n",
- (int)(bp-buftable), bufnum);
- }
- else {
- fprintf(stderr,"buf %d state %s (%ld) instead of EMPTY\n",
- (int)(bp-buftable),
- bp->status == FILLING? "FILLING" :
- bp->status == FULL? "FULL" : "EMPTY!?!?",
- (long)bp->status);
- }
- dumpbufs("taper");
- sleep(1);
- dumpbufs("taper: after 1 sec");
- if(bp->status == EMPTY)
- fprintf(stderr, "taper: result now correct!\n");
- fflush(stderr);
-
- errstr = newstralloc(errstr,
- "[fatal buffer mismanagement bug]");
- q = squote(errstr);
- putresult(TRYAGAIN, "%s %s\n", handle, q);
- amfree(q);
- log_add(L_INFO, "retrying %s:%s.%d on new tape: %s",
- hostname, diskname, level, errstr);
- closing = 1;
- syncpipe_put('X'); /* X == buffer snafu, bail */
- do {
- tok = syncpipe_get();
- if(tok == 'R')
- bufnum = syncpipe_getint();
- } while(tok != 'x');
- aclose(fd);
- return;
- }
-
- bp->status = FILLING;
- buflen = header_read ? tt_blocksize : DISK_BLOCK_BYTES;
- if(interactive || bufdebug) dumpstatus(bp);
- if((rc = taper_fill_buffer(fd, bp, buflen)) < 0) {
- err = errno;
- closing = 1;
- strclosing = newvstralloc(strclosing,"Can't read data: ",NULL);
- syncpipe_put('C');
- } else {
- if(rc < buflen) { /* switch to next file */
- int save_fd;
- struct stat stat_file;
-
- save_fd = fd;
- close(fd);
- if(file.cont_filename[0] == '\0') { /* no more file */
- err = 0;
- need_closing = 1;
- } else if(stat(file.cont_filename, &stat_file) != 0) {
- err = errno;
- need_closing = 1;
- strclosing = newvstralloc(strclosing,"can't stat: ",file.cont_filename,NULL);
- } else if((fd = open(file.cont_filename,O_RDONLY)) == -1) {
- err = errno;
- need_closing = 1;
- strclosing = newvstralloc(strclosing,"can't open: ",file.cont_filename,NULL);
- } else if((fd != save_fd) && dup2(fd, save_fd) == -1) {
- err = errno;
- need_closing = 1;
- strclosing = newvstralloc(strclosing,"can't dup2: ",file.cont_filename,NULL);
- } else {
- buffer_t bp1;
- int rc1;
-
- bp1.status = EMPTY;
- bp1.size = DISK_BLOCK_BYTES;
- bp1.buffer = malloc(DISK_BLOCK_BYTES);
-
- if(fd != save_fd) {
- close(fd);
- fd = save_fd;
- }
-
- rc1 = taper_fill_buffer(fd, &bp1, DISK_BLOCK_BYTES);
- if(rc1 <= 0) {
- amfree(bp1.buffer);
- err = (rc1 < 0) ? errno : 0;
- need_closing = 1;
- strclosing = newvstralloc(strclosing,
- "Can't read header: ",
- file.cont_filename,
- NULL);
- } else {
- parse_file_header(bp1.buffer, &file, rc1);
-
- amfree(bp1.buffer);
- bp1.buffer = bp->buffer + rc;
-
- rc1 = taper_fill_buffer(fd, &bp1, tt_blocksize - rc);
- if(rc1 <= 0) {
- err = (rc1 < 0) ? errno : 0;
- need_closing = 1;
- if(rc1 < 0) {
- strclosing = newvstralloc(strclosing,
- "Can't read data: ",
- file.cont_filename,
- NULL);
- }
- }
- else {
- rc += rc1;
- bp->size = rc;
- }
- }
- }
- }
- if(rc > 0) {
- bp->status = FULL;
- if(header_read == 0) {
- char *cont_filename;
-
- parse_file_header(bp->buffer, &file, rc);
- cont_filename = stralloc(file.cont_filename);
- file.cont_filename[0] = '\0';
- file.blocksize = tt_blocksize;
- build_header(bp->buffer, &file, tt_blocksize);
-
- /* add CONT_FILENAME back to in-memory header */
- strncpy(file.cont_filename, cont_filename,
- sizeof(file.cont_filename));
- if(interactive || bufdebug) dumpstatus(bp);
- bp->size = tt_blocksize; /* output a full tape block */
- header_read = 1;
- amfree(cont_filename);
- }
- else {
- filesize += am_round(rc, 1024) / 1024;
- }
- if(interactive || bufdebug) dumpstatus(bp);
- if(bufdebug) {
- fprintf(stderr,"taper: r: put W%d\n",(int)(bp-buftable));
- fflush(stderr);
- }
- syncpipe_put('W');
- syncpipe_putint(bp-buftable);
- bp = nextbuf(bp);
- }
- if(need_closing && rc <= 0) {
- syncpipe_put('C');
- need_closing = 0;
- closing = 1;
- }
- }
- break;
-
- case 'T':
- case 'E':
- syncpipe_put('e'); /* ACK error */
-
- aclose(fd);
- str = syncpipe_getstr();
- errstr = newvstralloc(errstr, "[", str ? str : "(null)", "]", NULL);
- amfree(str);
-
- q = squote(errstr);
- if(tok == 'T') {
- putresult(TRYAGAIN, "%s %s\n", handle, q);
- log_add(L_INFO, "retrying %s:%s.%d on new tape: %s",
- hostname, diskname, level, errstr);
- } else {
- putresult(TAPE_ERROR, "%s %s\n", handle, q);
- log_add(L_FAIL, "%s %s %s %d [out of tape]",
- hostname, diskname, datestamp, level);
- log_add(L_ERROR,"no-tape [%s]", errstr);
- }
- amfree(q);
- return;
-
- case 'C':
- assert(!opening);
- assert(closing);
-
- str = syncpipe_getstr();
- label = newstralloc(label, str ? str : "(null)");
- amfree(str);
- str = syncpipe_getstr();
- filenum = atoi(str ? str : "-9876"); /* ??? */
- amfree(str);
- fprintf(stderr, "taper: reader-side: got label %s filenum %d\n",
- label, filenum);
- fflush(stderr);
-
- aclose(fd);
- runtime = stopclock();
- if(err) {
- if(strclosing) {
- errstr = newvstralloc(errstr,
- "[input: ", strclosing, ": ",
- strerror(err), "]", NULL);
- amfree(strclosing);
- }
- else
- errstr = newvstralloc(errstr,
- "[input: ", strerror(err), "]",
- NULL);
- q = squote(errstr);
- putresult(TAPE_ERROR, "%s %s\n", handle, q);
- amfree(q);
- log_add(L_FAIL, "%s %s %s %d %s",
- hostname, diskname, datestamp, level, errstr);
- str = syncpipe_getstr(); /* reap stats */
- amfree(str);
- } else {
- char kb_str[NUM_STR_SIZE];
- char kps_str[NUM_STR_SIZE];
- double rt;
-
- rt = runtime.r.tv_sec+runtime.r.tv_usec/1000000.0;
- ap_snprintf(kb_str, sizeof(kb_str), "%ld", filesize);
- ap_snprintf(kps_str, sizeof(kps_str), "%3.1f",
- rt ? filesize / rt : 0.0);
- str = syncpipe_getstr();
- errstr = newvstralloc(errstr,
- "[sec ", walltime_str(runtime),
- " kb ", kb_str,
- " kps ", kps_str,
- " ", str ? str : "(null)",
- "]",
- NULL);
- amfree(str);
- q = squote(errstr);
- putresult(DONE, "%s %s %d %s\n",
- handle, label, filenum, q);
- amfree(q);
- log_add(L_SUCCESS, "%s %s %s %d %s",
- hostname, diskname, datestamp, level, errstr);
-#ifdef HAVE_LIBVTBLC
- /*
- * We have 44 characters available for the label string:
- * use max 20 characters for hostname
- * max 20 characters for diskname
- * (it could contain a samba share or dos path)
- * 2 for level
- */
- memset(desc, '\0', 45);
-
- strncpy(desc, hostname, 20);
-
- if ((len = strlen(hostname)) <= 20) {
- memset(desc + len, ' ', 1);
- offset = len + 1;
- }
- else{
- memset(desc + 20, ' ', 1);
- offset = 21;
- }
+/* If handle is NULL, then this function assumes that we are in startup mode.
+ * In that case it will wait for a command from driver. If handle is not NULL,
+ * this this function will ask for permission with REQUEST-NEW-TAPE. */
+static gboolean find_new_tape(taper_state_t * state, dump_info_t * dump) {
+ GThread * tape_search = NULL;
+ tape_search_request_t search_request;
+ gboolean use_threads;
+ struct cmdargs *cmdargs;
+ cmd_t cmd;
- strncpy(desc + offset, diskname, 20);
+ if (state->device != NULL) {
+ return TRUE;
+ }
- if ((len = strlen(diskname)) <= 20) {
- memset(desc + offset + len, ' ', 1);
- offset = offset + len + 1;
- }
- else{
- memset(desc + offset + 20, ' ', 1);
- offset = offset + 21;
- }
+ /* We save the value here in case it changes while we're running. */
+ use_threads = g_thread_supported();
- sprintf(desc + offset, "%i", level);
-
- strncpy(vol_label, desc, 44);
- fprintf(stderr, "taper: added vtbl label string %i: \"%s\"\n",
- filenum, vol_label);
- fflush(stderr);
-
- /* pass label string on to tape writer */
- syncpipe_put('L');
- syncpipe_putint(filenum);
- syncpipe_putstr(vol_label);
-
- /*
- * reformat datestamp for later use with set_date from vtblc
- */
- strptime(datestamp, "%Y%m%d", &backup_time);
- strftime(vol_date, 20, "%T %D", &backup_time);
- fprintf(stderr,
- "taper: reformatted vtbl date string: \"%s\"->\"%s\"\n",
- datestamp,
- vol_date);
-
- /* pass date string on to tape writer */
- syncpipe_put('D');
- syncpipe_putint(filenum);
- syncpipe_putstr(vol_date);
-
-#endif /* HAVE_LIBVTBLC */
- }
- return;
+ search_request.state = state;
+ search_request.prolong = TRUE;
+ search_request.errmsg = NULL;
+ if (use_threads) {
+ tape_search = g_thread_create(tape_search_thread,
+ &search_request, TRUE, NULL);
+ }
+
+ putresult(REQUEST_NEW_TAPE, "%s\n", dump->handle);
+ cmdargs = getcmd();
+ cmd = cmdargs->cmd;
- default:
- assert(0);
- }
+ switch (cmd) {
+ default:
+ g_fprintf(stderr, "taper: Got odd message from driver, expected NEW-TAPE or NO-NEW-TAPE.\n");
+ /* FALLTHROUGH. */
+ case NEW_TAPE: {
+ gboolean search_result;
+ if (use_threads) {
+ search_result = GPOINTER_TO_INT(g_thread_join(tape_search));
+ } else {
+ search_result =
+ GPOINTER_TO_INT(tape_search_thread(&search_request));
+ }
+ if (search_result) {
+ /* We don't say NEW_TAPE until we actually write the label. */
+ amfree(search_request.errmsg);
+ free_cmdargs(cmdargs);
+ return TRUE;
+ } else {
+ putresult(NO_NEW_TAPE, "%s\n", dump->handle);
+ log_taper_scan_errmsg(search_request.errmsg);
+ log_add(L_ERROR, "no-tape [%s]", "No more writable valid tape found");
+ free_cmdargs(cmdargs);
+ return FALSE;
+ }
+ }
+ case NO_NEW_TAPE:
+ search_request.prolong = FALSE;
+ if (use_threads) {
+ g_thread_join(tape_search);
+ }
+ log_add(L_ERROR, "no-tape [%s]", cmdargs->argv[1]);
+ state->last_errmsg = stralloc(cmdargs->argv[1]);
+ free_cmdargs(cmdargs);
+ return FALSE;
}
+ /* NOTREACHED */
}
-int taper_fill_buffer(fd, bp, buflen)
-int fd;
-buffer_t *bp;
-int buflen;
-{
- char *curptr;
- int spaceleft, cnt;
-
- curptr = bp->buffer;
- bp->size = 0;
- spaceleft = buflen;
-
- do {
- cnt = read(fd, curptr, spaceleft);
- switch(cnt) {
- case 0: /* eof */
- if(interactive) fputs("r0", stderr);
- return bp->size;
- case -1: /* error on read, punt */
- if(interactive) fputs("rE", stderr);
- return -1;
- default:
- spaceleft -= cnt;
- curptr += cnt;
- bp->size += cnt;
- }
-
- } while(spaceleft > 0);
-
- if(interactive) fputs("R", stderr);
- return bp->size;
+/* Returns TRUE if the old volume details are not the same as the new ones. */
+static gboolean check_volume_changed(Device * device,
+ char * old_label, char * old_timestamp) {
+ /* If one is NULL and the other is not, something changed. */
+ if ((old_label == NULL) != (device->volume_label == NULL))
+ return TRUE;
+ if ((old_timestamp == NULL) != (device->volume_time == NULL))
+ return TRUE;
+ /* If details were not NULL and is now different, we have a difference. */
+ if (old_label != NULL && strcmp(old_label, device->volume_label) != 0)
+ return TRUE;
+ if (old_timestamp != NULL &&
+ strcmp(old_timestamp, device->volume_time) != 0)
+ return TRUE;
+
+ /* If we got here, everything is cool. */
+ return FALSE;
}
-
-
-/*
- * ========================================================================
- * TAPE WRITER SIDE
- *
- */
-times_t idlewait, rdwait, wrwait, fmwait;
-long total_writes;
-double total_tape_used;
-int total_tape_fm;
-
-void write_file P((void));
-int write_buffer P((buffer_t *bp));
-
-void tape_writer_side(getp, putp)
-int getp, putp;
+static void
+update_tapelist(
+ taper_state_t *state)
{
- char tok;
- int tape_started;
- char *str;
- char *hostname;
- char *diskname;
- char *datestamp;
- int level;
-
-#ifdef HAVE_LIBVTBLC
- char *vol_label;
- char *vol_date;
-#endif /* HAVE_LIBVTBLC */
-
- procname = "writer";
- syncpipe_init(getp, putp);
-
- tape_started = 0;
- idlewait = times_zero;
-
- while(1) {
- startclock();
- tok = syncpipe_get();
- idlewait = timesadd(idlewait, stopclock());
- if(tok != 'S' && tok != 'Q' && !tape_started) {
- error("writer: token '%c' before start", tok);
- }
-
- switch(tok) {
- case 'S': /* start-tape */
- if(tape_started) {
- error("writer: multiple start requests");
- }
- str = syncpipe_getstr();
- if(!first_tape(str ? str : "bad-datestamp")) {
- if(tape_fd >= 0) {
- tapefd_close(tape_fd);
- tape_fd = -1;
- }
- syncpipe_put('E');
- syncpipe_putstr(errstr);
- /* wait for reader to acknowledge error */
- do {
- tok = syncpipe_get();
- if(tok != 'e') {
- error("writer: got '%c' unexpectedly after error", tok);
- }
- } while(tok != 'e');
- } else {
- syncpipe_put('S');
- tape_started = 1;
- }
- amfree(str);
-
- break;
-
- case 'O': /* open-output */
- datestamp = syncpipe_getstr();
- tapefd_setinfo_datestamp(tape_fd, datestamp);
- amfree(datestamp);
- hostname = syncpipe_getstr();
- tapefd_setinfo_host(tape_fd, hostname);
- amfree(hostname);
- diskname = syncpipe_getstr();
- tapefd_setinfo_disk(tape_fd, diskname);
- amfree(diskname);
- level = syncpipe_getint();
- tapefd_setinfo_level(tape_fd, level);
- write_file();
- break;
-
-#ifdef HAVE_LIBVTBLC
- case 'L': /* read vtbl label */
- vtbl_no = syncpipe_getint();
- vol_label = syncpipe_getstr();
- fprintf(stderr, "taper: read label string \"%s\" from pipe\n",
- vol_label);
- strncpy(vtbl_entry[vtbl_no].label, vol_label, 45);
- break;
-
- case 'D': /* read vtbl date */
- vtbl_no = syncpipe_getint();
- vol_date = syncpipe_getstr();
- fprintf(stderr, "taper: read date string \"%s\" from pipe\n",
- vol_date);
- strncpy(vtbl_entry[vtbl_no].date, vol_date, 20);
- break;
-#endif /* HAVE_LIBVTBLC */
-
- case 'Q':
- end_tape(0); /* XXX check results of end tape ?? */
- clear_tapelist();
- amfree(taper_datestamp);
- amfree(label);
- amfree(errstr);
- amfree(changer_resultstr);
- amfree(tapedev);
- amfree(config_dir);
- amfree(config_name);
-
- malloc_size_2 = malloc_inuse(&malloc_hist_2);
-
- if(malloc_size_1 != malloc_size_2) {
- malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
- }
-
- exit(0);
+ char *tapelist_name = NULL;
+ char *tapelist_name_old = NULL;
+ tape_t *tp;
+ char *comment = NULL;
- default:
- assert(0);
- }
+ tapelist_name = config_dir_relative(getconf_str(CNF_TAPELIST));
+ if (state->cur_tape == 0) {
+ tapelist_name_old = stralloc2(tapelist_name, ".yesterday");
+ } else {
+ char cur_str[NUM_STR_SIZE];
+ g_snprintf(cur_str, SIZEOF(cur_str), "%d", state->cur_tape - 1);
+ tapelist_name_old = vstralloc(tapelist_name,
+ ".today.", cur_str, NULL);
}
-}
-void write_file()
-{
- buffer_t *bp;
- int full_buffers, i, bufnum;
- char tok;
- char number[NUM_STR_SIZE];
- char *rdwait_str, *wrwait_str, *fmwait_str;
-
- rdwait = wrwait = times_zero;
- total_writes = 0;
-
- bp = buftable;
- full_buffers = 0;
- tok = '?';
-
- if(bufdebug) {
- fprintf(stderr, "taper: w: start file\n");
- fflush(stderr);
+ if (read_tapelist(tapelist_name) != 0) {
+ log_add(L_INFO, "pid-done %ld", (long)getpid());
+ error("could not load tapelist \"%s\"", tapelist_name);
+ /*NOTREACHED*/
}
- /*
- * Tell the reader that the tape is open, and give it all the buffers.
- */
- syncpipe_put('O');
- for(i = 0; i < conf_tapebufs; i++) {
- if(bufdebug) {
- fprintf(stderr, "taper: w: put R%d\n", i);
- fflush(stderr);
- }
- syncpipe_put('R'); syncpipe_putint(i);
+ /* make a copy of the tapelist file */
+ if (write_tapelist(tapelist_name_old)) {
+ log_add(L_INFO, "pid-done %ld", (long)getpid());
+ error("could not write tapelist: %s", strerror(errno));
+ /*NOTREACHED*/
}
-
- /*
- * We write the filemark at the start of the file rather than at the end,
- * so that it can proceed in parallel with the reader's initial filling
- * up of the buffers.
- */
-
- startclock();
- if(!write_filemark())
- goto tape_error;
- fmwait = stopclock();
-
- filenum += 1;
-
- do {
-
- /*
- * STOPPED MODE
- *
- * At the start of the file, or if the input can't keep up with the
- * tape, we enter STOPPED mode, which waits for most of the buffers
- * to fill up before writing to tape. This maximizes the amount of
- * data written in chunks to the tape drive, minimizing the number
- * of starts/stops, which in turn saves tape and time.
- */
-
- if(interactive) fputs("[WS]", stderr);
- startclock();
- while(full_buffers < conf_tapebufs - THRESHOLD) {
- tok = syncpipe_get();
- if(tok != 'W') break;
- bufnum = syncpipe_getint();
- if(bufdebug) {
- fprintf(stderr,"taper: w: got W%d\n",bufnum);
- fflush(stderr);
- }
- full_buffers++;
- }
- rdwait = timesadd(rdwait, stopclock());
-
- /*
- * STARTING MODE
- *
- * We start output when sufficient buffers have filled up, or at
- * end-of-file, whichever comes first. Here we drain all the buffers
- * that were waited on in STOPPED mode. If more full buffers come
- * in, then we will be STREAMING.
- */
-
- while(full_buffers) {
- if(tt_file_pad && bp->size < tt_blocksize) {
- memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
- bp->size = tt_blocksize;
- }
- if(!write_buffer(bp)) goto tape_error;
- full_buffers--;
- bp = nextbuf(bp);
- }
-
- /*
- * STREAMING MODE
- *
- * With any luck, the input source is faster than the tape drive. In
- * this case, full buffers will appear in the circular queue faster
- * than we can write them, so the next buffer in the queue will always
- * be marked FULL by the time we get to it. If so, we'll stay in
- * STREAMING mode.
- *
- * On the other hand, if we catch up to the input and thus would have
- * to wait for buffers to fill, we are then STOPPED again.
- */
-
- while(tok == 'W' && bp->status == FULL) {
- tok = syncpipe_get();
- if(tok == 'W') {
- bufnum = syncpipe_getint();
- if(bufdebug) {
- fprintf(stderr,"taper: w: got W%d\n",bufnum);
- fflush(stderr);
- }
- if(bufnum != bp-buftable) {
- fprintf(stderr,
- "taper: tape-writer: my buf %d reader buf %d\n",
- (int)(bp-buftable), bufnum);
- fflush(stderr);
- syncpipe_put('E');
- syncpipe_putstr("writer-side buffer mismatch");
- goto error_ack;
- }
- if(tt_file_pad && bp->size < tt_blocksize) {
- memset(bp->buffer+bp->size, 0, tt_blocksize - bp->size);
- bp->size = tt_blocksize;
- }
- if(!write_buffer(bp)) goto tape_error;
- bp = nextbuf(bp);
- }
- else if(tok == 'Q')
- return;
- else if(tok == 'X')
- goto reader_buffer_snafu;
- else
- error("writer-side not expecting token: %c", tok);
- }
- } while(tok == 'W');
-
- /* got close signal from reader, acknowledge it */
-
- if(tok == 'X')
- goto reader_buffer_snafu;
-
- assert(tok == 'C');
- syncpipe_put('C');
-
- /* tell reader the tape and file number */
-
- syncpipe_putstr(label);
- ap_snprintf(number, sizeof(number), "%d", filenum);
- syncpipe_putstr(number);
-
- ap_snprintf(number, sizeof(number), "%ld", total_writes);
- rdwait_str = stralloc(walltime_str(rdwait));
- wrwait_str = stralloc(walltime_str(wrwait));
- fmwait_str = stralloc(walltime_str(fmwait));
- errstr = newvstralloc(errstr,
- "{wr:",
- " writers ", number,
- " rdwait ", rdwait_str,
- " wrwait ", wrwait_str,
- " filemark ", fmwait_str,
- "}",
- NULL);
- amfree(rdwait_str);
- amfree(wrwait_str);
- amfree(fmwait_str);
- syncpipe_putstr(errstr);
-
- /* XXX go to next tape if past tape size? */
-
- return;
-
- tape_error:
- /* got tape error */
- if(next_tape(1)) syncpipe_put('T'); /* next tape in place, try again */
- else syncpipe_put('E'); /* no more tapes, fail */
- syncpipe_putstr(errstr);
-
- error_ack:
- /* wait for reader to acknowledge error */
- do {
- tok = syncpipe_get();
- if(tok != 'W' && tok != 'C' && tok != 'e')
- error("writer: got '%c' unexpectedly after error", tok);
- if(tok == 'W')
- syncpipe_getint(); /* eat buffer number */
- } while(tok != 'e');
- return;
-
- reader_buffer_snafu:
- syncpipe_put('x');
- return;
+ amfree(tapelist_name_old);
+
+ /* get a copy of the comment, before freeing the old record */
+ tp = lookup_tapelabel(state->device->volume_label);
+ if (tp && tp->comment)
+ comment = stralloc(tp->comment);
+
+ /* edit the tapelist and rewrite it */
+ remove_tapelabel(state->device->volume_label);
+ add_tapelabel(state->driver_start_time,
+ state->device->volume_label,
+ comment);
+ if (write_tapelist(tapelist_name)) {
+ error("could not write tapelist: %s", strerror(errno));
+ /*NOTREACHED*/
+ }
+ amfree(tapelist_name);
+ amfree(comment);
}
-int write_buffer(bp)
-buffer_t *bp;
-{
- int rc;
-
- if(bp->status != FULL) {
- /* XXX buffer management snafu */
- assert(0);
+/* Find and label a new tape, if one is not already open. Returns TRUE
+ * if a tape could be written. */
+static gboolean find_and_label_new_tape(taper_state_t * state,
+ dump_info_t * dump_info) {
+ if (state->device != NULL) {
+ return TRUE;
}
-
- startclock();
- rc = tapefd_write(tape_fd, bp->buffer, bp->size);
- if(rc == bp->size) {
-#if defined(NEED_RESETOFS)
- static double tape_used_modulus_2gb = 0;
-
- /*
- * If the next write will go over the 2 GByte boundary, reset
- * the kernel concept of where we are to make sure it does not
- * go silly on us.
- */
- tape_used_modulus_2gb += (double)rc;
- if(tape_used_modulus_2gb + (double)rc > (double)0x7fffffff) {
- tape_used_modulus_2gb = 0;
- tapefd_resetofs(tape_fd);
- }
-#endif
- wrwait = timesadd(wrwait, stopclock());
- total_writes += 1;
- total_tape_used += (double)rc;
- bp->status = EMPTY;
- if(interactive || bufdebug) dumpstatus(bp);
- if(interactive) fputs("W", stderr);
-
- if(bufdebug) {
- fprintf(stderr, "taper: w: put R%d\n", (int)(bp-buftable));
- fflush(stderr);
- }
- syncpipe_put('R'); syncpipe_putint(bp-buftable);
- return 1;
- } else {
- errstr = newvstralloc(errstr,
- "writing file: ",
- (rc != -1) ? "short write" : strerror(errno),
- NULL);
- wrwait = timesadd(wrwait, stopclock());
- if(interactive) fputs("[WE]", stderr);
- return 0;
+ state->total_bytes = 0;
+
+ if (!find_new_tape(state, dump_info)) {
+ return FALSE;
}
-}
-
-
-/*
- * ========================================================================
- * SHARED-MEMORY BUFFER SUBSYSTEM
- *
- */
-#ifdef HAVE_SYSVSHM
-
-int shmid = -1;
-
-char *attach_buffers(size)
- unsigned int size;
-{
- char *result;
+ return label_new_tape(state, dump_info);
+}
- shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0700);
- if(shmid == -1) {
- return NULL;
+static gboolean label_new_tape(taper_state_t * state, dump_info_t * dump_info) {
+ char *old_volume_name = NULL;
+ char *old_volume_time = NULL;
+ tape_search_request_t request;
+ gboolean search_result;
+ DeviceStatusFlags status;
+
+ /* If we got here, it means that we have found a tape to label and
+ * have gotten permission from the driver to write it. But we
+ * still can say NO-NEW-TAPE if a problem shows up, and must still
+ * say NEW-TAPE if one doesn't. */
+
+ amfree(state->last_errmsg);
+ state->device = device_open(state->next_tape_device);
+ g_assert(state->device != NULL);
+ amfree(state->next_tape_device);
+
+ if (state->device->status != DEVICE_STATUS_SUCCESS)
+ goto skip_volume;
+
+ if (!device_configure(state->device, TRUE))
+ goto skip_volume;
+
+ /* if we have an error, and are sure it isn't just an unlabeled volume,
+ * then skip this volume */
+ status = device_read_label(state->device);
+ if ((status & ~DEVICE_STATUS_VOLUME_UNLABELED) &&
+ !(status & DEVICE_STATUS_VOLUME_UNLABELED))
+ goto skip_volume;
+
+ old_volume_name = g_strdup(state->device->volume_label);
+ old_volume_time = g_strdup(state->device->volume_time);
+
+ if (!device_start(state->device, ACCESS_WRITE, state->next_tape_label,
+ state->driver_start_time)) {
+ gboolean tape_used;
+
+ /* Something broke, see if we can tell if the volume was erased or
+ * not. */
+ g_fprintf(stderr, "taper: Error writing label %s to device %s: %s.\n",
+ state->next_tape_label, state->device->device_name,
+ device_error_or_status(state->device));
+
+ if (!device_finish(state->device))
+ goto request_new_volume;
+
+ /* This time, if we can't read the label, assume we've overwritten
+ * the volume or otherwise corrupted it */
+ status = device_read_label(state->device);
+ if ((status & ~DEVICE_STATUS_VOLUME_UNLABELED) &&
+ !(status & DEVICE_STATUS_VOLUME_UNLABELED))
+ goto request_new_volume;
+
+ tape_used = check_volume_changed(state->device, old_volume_name,
+ old_volume_time);
+
+ if (tape_used)
+ goto request_new_volume;
+ else
+ goto skip_volume;
}
- result = (char *)shmat(shmid, (SHM_ARG_TYPE *)NULL, 0);
+ amfree(old_volume_name);
+ amfree(old_volume_time);
+ amfree(state->next_tape_label);
- if(result == (char *)-1) {
- int save_errno = errno;
+ update_tapelist(state);
+ state->cur_tape++;
- destroy_buffers();
- errno = save_errno;
- error("shmat: %s", strerror(errno));
+ if (state->have_changer &&
+ changer_label("UNKNOWN", state->device->volume_label) != 0) {
+ error(_("couldn't update barcode database"));
+ /*NOTREACHED*/
}
- return result;
-}
-
-
-void detach_buffers(bufp)
- char *bufp;
-{
- if(shmdt((SHM_ARG_TYPE *)bufp) == -1) {
- error("shmdt: %s", strerror(errno));
+ log_add(L_START, "datestamp %s label %s tape %d",
+ state->driver_start_time, state->device->volume_label,
+ state->cur_tape);
+ putresult(NEW_TAPE, "%s %s\n", dump_info->handle,
+ state->device->volume_label);
+
+ return TRUE;
+
+request_new_volume:
+ /* Tell the driver we overwrote this volume, even if it was empty, and request
+ * a new volume. */
+ if (state->device)
+ state->last_errmsg = newstralloc(state->last_errmsg, device_error_or_status(state->device));
+ else
+ state->last_errmsg = newstralloc(state->last_errmsg, "(unknown)");
+
+ putresult(NEW_TAPE, "%s %s\n", dump_info->handle,
+ state->next_tape_label);
+ if (old_volume_name) {
+ log_add(L_WARNING, "Problem writing label '%s' to volume %s "
+ "(volume may be erased): %s\n",
+ state->next_tape_label, old_volume_name,
+ state->last_errmsg);
+ } else {
+ log_add(L_WARNING, "Problem writing label '%s' to new volume "
+ "(volume may be erased): %s\n", state->next_tape_label,
+ state->last_errmsg);
}
-}
-void destroy_buffers()
-{
- if(shmid == -1) return; /* nothing to destroy */
- if(shmctl(shmid, IPC_RMID, NULL) == -1) {
- error("shmctl: %s", strerror(errno));
+ if (state->device) {
+ g_object_unref(state->device);
+ state->device = NULL;
}
-}
-#else
-#ifdef HAVE_MMAP
+ amfree(state->next_tape_label);
+ amfree(old_volume_name);
+ amfree(old_volume_time);
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
+ return find_and_label_new_tape(state, dump_info);
-#ifndef MAP_ANON
-# ifdef MAP_ANONYMOUS /* OSF/1-style */
-# define MAP_ANON MAP_ANONYMOUS
-# else /* SunOS4-style */
-# define MAP_ANON 0
-# define ZERO_FILE "/dev/zero"
-# endif
-#endif
-
-int shmfd = -1;
-unsigned int saved_size;
+skip_volume:
+ /* grab a new volume without talking to the driver again -- we do this if we're
+ * confident we didn't overwrite the last tape we got. */
+ if (state->device)
+ state->last_errmsg = newstralloc(state->last_errmsg, device_error_or_status(state->device));
+ else
+ state->last_errmsg = newstralloc(state->last_errmsg, "(unknown)");
-char *attach_buffers(size)
- unsigned int size;
-{
- char *shmbuf;
-
-#ifdef ZERO_FILE
- shmfd = open(ZERO_FILE, O_RDWR);
- if(shmfd == -1) {
- error("attach_buffers: could not open %s: %s",
- ZERO_FILE,
- strerror(errno));
+ if (old_volume_name) {
+ log_add(L_WARNING, "Problem writing label '%s' to volume '%s' "
+ "(old volume data intact): %s\n",
+ state->next_tape_label, old_volume_name, state->last_errmsg);
+ } else {
+ log_add(L_WARNING, "Problem writing label '%s' to new volume "
+ "(old volume data intact): %s\n", state->next_tape_label,
+ state->last_errmsg);
}
-#endif
-
- saved_size = size;
- shmbuf = (char *) mmap((void *) 0,
- size,
- PROT_READ|PROT_WRITE,
- MAP_ANON|MAP_SHARED,
- shmfd, 0);
- return shmbuf;
-}
-
-void detach_buffers(bufp)
-char *bufp;
-{
- if(munmap((void *)bufp, saved_size) == -1) {
- error("detach_buffers: munmap: %s", strerror(errno));
+ if (state->device) {
+ g_object_unref(state->device);
+ state->device = NULL;
}
- aclose(shmfd);
-}
-
-void destroy_buffers()
-{
-}
-
-#else
-error: must define either HAVE_SYSVSHM or HAVE_MMAP!
-#endif
-#endif
-
-
-
-/*
- * ========================================================================
- * SYNC-PIPE SUBSYSTEM
- *
- */
-
-int getpipe, putpipe;
-
-void syncpipe_init(rd, wr)
-int rd, wr;
-{
- getpipe = rd;
- putpipe = wr;
+ amfree(state->next_tape_label);
+ amfree(old_volume_name);
+ amfree(old_volume_time);
+
+ request.state = state;
+ request.prolong = TRUE;
+ request.errmsg = NULL;
+ search_result = GPOINTER_TO_INT(tape_search_thread(&request));
+ if (search_result) {
+ amfree(request.errmsg);
+ return label_new_tape(state, dump_info);
+ } else {
+ /* Problem finding a new tape! */
+ log_taper_scan_errmsg(request.errmsg);
+ putresult(NO_NEW_TAPE, "%s\n", dump_info->handle);
+ return FALSE;
+ }
}
-char syncpipe_get()
-{
- int rc;
- char buf[1];
-
- rc = read(getpipe, buf, sizeof(buf));
- if(rc == 0) /* EOF */
- error("syncpipe_get: %c: unexpected EOF", *procname);
- else if(rc < 0)
- error("syncpipe_get: %c: %s", *procname, strerror(errno));
-
- if(bufdebug && *buf != 'R' && *buf != 'W') {
- fprintf(stderr,"taper: %c: getc %c\n",*procname,*buf);
- fflush(stderr);
+/* Find out if the dump is PARTIAL or not, and set the proper driver
+ and logfile tags for the dump. */
+static void find_completion_tags(dump_info_t * dump_info, /* IN */
+ cmd_t * result_cmd, /* OUT */
+ logtype_t * result_log /* OUT */) {
+ /* result_cmd is always DONE because the taper wrote all the input to
+ * the output. driver need to know if the taper completed its job.
+ * result_log is set to L_PARTIAL if the image is partial, the log
+ * must tell if the image is partial or complete.
+ */
+
+ if (taper_source_is_partial(dump_info->source)) {
+ *result_cmd = DONE;
+ *result_log = L_PARTIAL;
+ } else {
+ *result_cmd = DONE;
+ *result_log = L_DONE;
}
+}
- return buf[0];
+/* Put an L_PARTIAL message to the logfile. */
+static void put_partial_log(dump_info_t * dump_info, double dump_time,
+ guint64 dump_kbytes, char *errstr) {
+ char * qdiskname = quote_string(dump_info->diskname);
+
+ log_add(L_PARTIAL, "%s %s %s %d %d [sec %f kb %ju kps %f] %s",
+ dump_info->hostname, qdiskname, dump_info->timestamp,
+ dump_info->current_part, dump_info->level, dump_time,
+ (uintmax_t)dump_kbytes, dump_kbytes / dump_time,
+ errstr);
+ amfree(qdiskname);
}
-int syncpipe_getint()
-{
- int rc;
- int i;
- int len = sizeof(i);
- char *p;
-
- for(p = (char *)&i; len > 0; len -= rc, p += rc) {
- if ((rc = read(getpipe, p, len)) <= 0) {
- error("syncpipe_getint: %s",
- rc < 0 ? strerror(errno) : "short read");
+/* Figure out what to do after a part attempt. Returns TRUE if another
+ attempt should proceed for this dump; FALSE if we are done. */
+static gboolean finish_part_attempt(taper_state_t * taper_state,
+ dump_info_t * dump_info,
+ queue_result_flags queue_result,
+ GTimeVal run_time, guint64 run_bytes) {
+ double part_time = g_timeval_to_double(run_time);
+ guint64 part_kbytes = run_bytes / 1024;
+ double part_kbps = run_bytes / (1024 * part_time);
+
+ char * qdiskname = quote_string(dump_info->diskname);
+
+ if (queue_result == QUEUE_SUCCESS) {
+ dump_info->total_time = timesadd(run_time, dump_info->total_time);
+ dump_info->total_bytes += run_bytes;
+
+ log_add(L_PART, "%s %d %s %s %s %d/%d %d [sec %f kb %ju kps %f]",
+ taper_state->device->volume_label,
+ taper_state->device->file, dump_info->hostname, qdiskname,
+ dump_info->timestamp, dump_info->current_part,
+ taper_source_predict_parts(dump_info->source),
+ dump_info->level, part_time, (uintmax_t)part_kbytes, part_kbps);
+ putresult(PARTDONE, "%s %s %d %ju \"[sec %f kb %ju kps %f]\"\n",
+ dump_info->handle, taper_state->device->volume_label,
+ taper_state->device->file, (uintmax_t)part_kbytes, part_time,
+ (uintmax_t)part_kbytes, part_kbps);
+ taper_state->total_bytes += run_bytes;
+
+ if (taper_source_get_end_of_data(dump_info->source)) {
+ cmd_t result_cmd;
+ logtype_t result_log;
+ double dump_time = g_timeval_to_double(dump_info->total_time);
+ guint64 dump_kbytes = dump_info->total_bytes / 1024;
+ double dump_kbps = dump_info->total_bytes / (1024 * dump_time);
+
+ find_completion_tags(dump_info, &result_cmd, &result_log);
+
+ g_object_unref(dump_info->source);
+ dump_info->source = NULL;
+
+ log_add(result_log, "%s %s %s %d %d [sec %f kb %ju kps %f]",
+ dump_info->hostname, qdiskname, dump_info->timestamp,
+ dump_info->current_part, dump_info->level, dump_time,
+ (uintmax_t)dump_kbytes, dump_kbps);
+ putresult(result_cmd, "%s INPUT-GOOD TAPE-GOOD "
+ "\"[sec %f kb %ju kps %f]\" \"\" \"\"\n",
+ dump_info->handle, dump_time, (uintmax_t)dump_kbytes,
+ dump_kbps);
+
+ amfree(qdiskname);
+ return FALSE;
+ } else if (taper_source_get_end_of_part(dump_info->source)) {
+ taper_source_start_new_part(dump_info->source);
+ dump_info->current_part ++;
+ amfree(qdiskname);
+ return TRUE;
+ }
+ /* If we didn't read EOF or EOP, then an error
+ occured. But we read QUEUE_SUCCESS, so something is
+ b0rked. */
+ g_assert_not_reached();
+ } else {
+ char * volume_label = strdup(taper_state->device->volume_label);
+ int file_number = taper_state->device->file;
+ double dump_time, dump_kbps;
+ guint64 dump_kbytes;
+ char *producer_errstr = quote_string(
+ taper_source_get_errmsg(dump_info->source));
+ char *consumer_errstr = quote_string(
+ device_error(taper_state->device));
+
+ log_add(L_PARTPARTIAL,
+ "%s %d %s %s %s %d/%d %d [sec %f kb %ju kps %f] %s",
+ volume_label, file_number, dump_info->hostname, qdiskname,
+ dump_info->timestamp, dump_info->current_part,
+ taper_source_predict_parts(dump_info->source),
+ dump_info->level, part_time, (uintmax_t)part_kbytes, part_kbps,
+ consumer_errstr);
+ log_add(L_INFO, "tape %s kb %lld fm %d [OK]\n",
+ volume_label,
+ (long long)((taper_state->total_bytes+(off_t)1023) / (off_t)1024),
+ taper_state->device->file);
+
+ /* A problem occured. */
+ if (queue_result & QUEUE_CONSUMER_ERROR) {
+ /* Make a note if this was EOM (we treat EOM the same as any other error,
+ * so it's just for debugging purposes */
+ if (taper_state->device->is_eof)
+ g_debug("device %s ran out of space", taper_state->device->device_name);
+
+ /* Close the device. */
+ device_finish(taper_state->device);
+ g_object_unref(taper_state->device);
+ taper_state->device = NULL;
+ }
+
+ amfree(volume_label);
+
+ if ((queue_result & QUEUE_CONSUMER_ERROR) &&
+ (!(queue_result & QUEUE_PRODUCER_ERROR)) &&
+ taper_source_seek_to_part_start(dump_info->source)) {
+ /* It is recoverable. */
+ log_add(L_INFO, "Will request retry of failed split part.");
+ if (find_and_label_new_tape(taper_state, dump_info)) {
+ /* dump_info->current_part is unchanged. */
+ amfree(qdiskname);
+ return TRUE;
+ }
+ }
+
+ dump_info->total_time = timesadd(run_time, dump_info->total_time);
+ dump_info->total_bytes += run_bytes;
+ dump_time = g_timeval_to_double(dump_info->total_time);
+ dump_kbytes = dump_info->total_bytes / 1024;
+ dump_kbps = dump_info->total_bytes / (1024 * dump_time);
+
+ putresult(PARTIAL,
+ "%s INPUT-%s TAPE-%s "
+ "\"[sec %f kb %ju kps %f]\" %s %s\n",
+ dump_info->handle,
+ (queue_result & QUEUE_PRODUCER_ERROR) ? "ERROR" : "GOOD",
+ (queue_result & QUEUE_CONSUMER_ERROR) ? "ERROR" : "GOOD",
+ dump_time, (uintmax_t)dump_kbytes, dump_kbps,
+ producer_errstr, consumer_errstr);
+ if (queue_result & QUEUE_CONSUMER_ERROR) {
+ put_partial_log(dump_info, dump_time, dump_kbytes,
+ consumer_errstr);
+ } else {
+ put_partial_log(dump_info, dump_time, dump_kbytes,
+ producer_errstr);
}
+ amfree(producer_errstr);
+ amfree(consumer_errstr);
}
- return i;
+ amfree(qdiskname);
+ return FALSE;
}
+/* Generate the actual header structure to write to tape. This means dropping
+ * bits related to the holding disk, and adding bits for split dumps. */
+static dumpfile_t * munge_headers(dump_info_t * dump_info) {
+ dumpfile_t * rval;
+ int expected_splits;
+
+ rval = taper_source_get_first_header(dump_info->source);
-char *syncpipe_getstr()
-{
- int rc;
- int len;
- char *p;
- char *str;
-
- if((len = syncpipe_getint()) <= 0) {
- return NULL;
- }
-
- str = alloc(len);
-
- for(p = str; len > 0; len -= rc, p += rc) {
- if ((rc = read(getpipe, p, len)) <= 0) {
- error("syncpipe_getstr: %s",
- rc < 0 ? strerror(errno) : "short read");
- }
+ if (rval == NULL) {
+ return NULL;
}
- return str;
-}
-
+ rval->cont_filename[0] = '\0';
-void syncpipe_put(chi)
-int chi;
-{
- int l, n, s;
- char ch = chi;
- char *item = &ch;
+ expected_splits = taper_source_predict_parts(dump_info->source);
- if(bufdebug && chi != 'R' && chi != 'W') {
- fprintf(stderr,"taper: %c: putc %c\n",*procname,chi);
- fflush(stderr);
+ if (expected_splits != 1) {
+ rval->type = F_SPLIT_DUMPFILE;
+ rval->partnum = dump_info->current_part;
+ rval->totalparts = expected_splits;
}
- for(l = 0, n = sizeof(ch); l < n; l += s) {
- if((s = write(putpipe, item + l, n - l)) < 0) {
- error("syncpipe_put: %s", strerror(errno));
- }
- }
+ return rval;
}
-void syncpipe_putint(i)
-int i;
+/* We call this when we can't find a tape to write data to. This could
+ happen with the first (or only) part of a file, but it could also
+ happen with an intermediate part of a split dump. dump_bytes
+ is 0 if this is the first part of a dump. */
+static void bail_no_volume(
+ dump_info_t *dump_info,
+ char *errmsg)
{
- int l, n, s;
- char *item = (char *)&i;
-
- for(l = 0, n = sizeof(i); l < n; l += s) {
- if((s = write(putpipe, item + l, n - l)) < 0) {
- error("syncpipe_putint: %s", strerror(errno));
- }
+ char *errstr;
+ if (errmsg)
+ errstr = quote_string(errmsg);
+ else
+ errstr = quote_string("no new tape");
+ if (dump_info->total_bytes > 0) {
+ /* Second or later part of a split dump, so PARTIAL message. */
+ double dump_time = g_timeval_to_double(dump_info->total_time);
+ guint64 dump_kbytes = dump_info->total_bytes / 1024;
+ double dump_kbps = dump_kbytes / dump_time;
+ putresult(PARTIAL,
+ "%s INPUT-GOOD TAPE-ERROR "
+ "\"[sec %f kb %ju kps %f]\" \"\" %s\n",
+ dump_info->handle,
+ dump_time, (uintmax_t)dump_kbytes, dump_kbps, errstr);
+ put_partial_log(dump_info, dump_time, dump_kbytes, errstr);
+ } else {
+ char * qdiskname = quote_string(dump_info->diskname);
+ putresult(FAILED,
+ "%s INPUT-GOOD TAPE-ERROR \"\" %s\n",
+ dump_info->handle, errstr);
+ log_add(L_FAIL, "%s %s %s %d %s",
+ dump_info->hostname, qdiskname, dump_info->timestamp,
+ dump_info->level, errstr);
+ amfree(qdiskname);
}
+ amfree(errstr);
}
-void syncpipe_putstr(item)
-char *item;
-{
- int l, n, s;
-
- n = strlen(item)+1; /* send '\0' as well */
- syncpipe_putint(n);
- for(l = 0, n = strlen(item)+1; l < n; l += s) {
- if((s = write(putpipe, item + l, n - l)) < 0) {
- error("syncpipe_putstr: %s", strerror(errno));
- }
+/* Link up the TaperSource with the Device, including retries etc. */
+static void run_device_output(taper_state_t * taper_state,
+ dump_info_t * dump_info) {
+ GValue val;
+ guint file_number;
+ dump_info->current_part = 1;
+ dump_info->total_time.tv_sec = 0;
+ dump_info->total_time.tv_usec = 0;
+ dump_info->total_bytes = 0;
+
+ for (;;) {
+ GTimeVal start_time, end_time, run_time;
+ StreamingRequirement streaming_mode;
+ queue_result_flags queue_result;
+ CountingConsumerData consumer_data;
+ dumpfile_t *this_header;
+ size_t max_memory;
+
+ this_header = munge_headers(dump_info);
+ if (this_header == NULL) {
+ char * qdiskname = quote_string(dump_info->diskname);
+ char * errstr = taper_source_get_errmsg(dump_info->source);
+ if (!errstr)
+ errstr = "Failed reading dump header.";
+ errstr = quote_string(errstr);
+ putresult(FAILED,
+ "%s INPUT-ERROR TAPE-GOOD %s \"\"\n",
+ dump_info->handle, errstr);
+ log_add(L_FAIL, "%s %s %s %d %s",
+ dump_info->hostname, qdiskname, dump_info->timestamp,
+ dump_info->level, errstr);
+ amfree(qdiskname);
+ amfree(errstr);
+ return;
+ }
+
+ if (!find_and_label_new_tape(taper_state, dump_info)) {
+ bail_no_volume(dump_info, taper_state->last_errmsg);
+ dumpfile_free(this_header);
+ return;
+ }
+
+ while (!device_start_file(taper_state->device, this_header)) {
+ /* Close the device. */
+ device_finish(taper_state->device);
+ g_object_unref(taper_state->device);
+ taper_state->device = NULL;
+
+ if (!find_and_label_new_tape(taper_state, dump_info)) {
+ bail_no_volume(dump_info, taper_state->last_errmsg);
+ dumpfile_free(this_header);
+ return;
+ }
+ }
+ dumpfile_free(this_header);
+
+ bzero(&val, sizeof(val));
+ if (!device_property_get(taper_state->device, PROPERTY_STREAMING, &val)
+ || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
+ g_fprintf(stderr, "taper: Couldn't get streaming type!\n");
+ streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
+ } else {
+ streaming_mode = g_value_get_enum(&val);
+ }
+
+ file_number = taper_state->device->file;
+
+ consumer_data.next_consumer = device_write_consumer;
+ consumer_data.next_consumer_data = taper_state->device;
+ consumer_data.bytes_written = 0;
+
+ g_get_current_time(&start_time);
+
+ if (getconf_seen(CNF_DEVICE_OUTPUT_BUFFER_SIZE)) {
+ max_memory = getconf_size(CNF_DEVICE_OUTPUT_BUFFER_SIZE);
+ if (getconf_seen(CNF_TAPEBUFS)) {
+ g_fprintf(stderr,
+ "Configuration directives 'device_output_buffer_size' "
+ "and \n"
+ "'tapebufs' are incompatible; using former.\n");
+ }
+ } else if (getconf_seen(CNF_TAPEBUFS)) {
+ max_memory = getconf_int(CNF_TAPEBUFS) *
+ taper_state->device->block_size;
+ } else {
+ /* Use default. */
+ max_memory = getconf_size(CNF_DEVICE_OUTPUT_BUFFER_SIZE);
+ }
+
+ queue_result = do_consumer_producer_queue_full
+ (taper_source_producer,
+ dump_info->source,
+ counting_consumer,
+ &consumer_data,
+ taper_state->device->block_size, max_memory,
+ streaming_mode);
+
+ g_get_current_time(&end_time);
+ run_time = timesub(end_time, start_time);
+
+ /* The device_write_consumer leaves the file open, so close it now. */
+ if (!device_finish_file(taper_state->device)) {
+ queue_result = queue_result | QUEUE_CONSUMER_ERROR;
+ }
+
+ if (!finish_part_attempt(taper_state, dump_info, queue_result,
+ run_time, consumer_data.bytes_written)) {
+ break;
+ }
}
}
-\f
-/*
- * ========================================================================
- * TAPE MANIPULATION SUBSYSTEM
- *
- */
-
-/* local functions */
-int scan_init P((int rc, int ns, int bk));
-int taperscan_slot P((int rc, char *slotstr, char *device));
-char *taper_scan P((void));
-int label_tape P((void));
-
-int label_tape()
-{
- char *conf_tapelist_old = NULL;
- char *olddatestamp = NULL;
- char *result;
- tape_t *tp;
- static int first_call = 1;
-
- if(have_changer) {
- amfree(tapedev);
- if ((tapedev = taper_scan()) == NULL) {
- errstr = newstralloc(errstr, changer_resultstr);
- return 0;
- }
- }
-
-#ifdef HAVE_LINUX_ZFTAPE_H
- if (is_zftape(tapedev) == 1){
- if((tape_fd = tape_open(tapedev, O_RDONLY)) == -1) {
- errstr = newstralloc2(errstr, "taper: ",
- (errno == EACCES) ? "tape is write-protected"
- : strerror(errno));
- return 0;
- }
- if((result = tapefd_rdlabel(tape_fd, &olddatestamp, &label)) != NULL) {
- amfree(olddatestamp);
- errstr = newstralloc(errstr, result);
- return 0;
- }
- if(tapefd_rewind(tape_fd) == -1) {
- return 0;
- }
- tapefd_close(tape_fd);
- tape_fd = -1;
+/* Handle a PORT_WRITE command. */
+static void process_port_write(taper_state_t * state,
+ struct cmdargs * cmdargs) {
+ dump_info_t dump_state;
+ guint64 splitsize;
+ guint64 fallback_splitsize;
+ char * split_diskbuffer;
+ char * argnames[] = {"command", /* 0 */
+ "handle", /* 1 */
+ "hostname", /* 2 */
+ "diskname", /* 3 */
+ "level", /* 4 */
+ "datestamp", /* 5 */
+ "splitsize", /* 6 */
+ "split_diskbuffer", /* 7 */
+ "fallback_splitsize", /* 8 */
+ NULL };
+
+ validate_args(cmdargs, argnames);
+
+ dump_state.handle = g_strdup(cmdargs->argv[1]);
+ dump_state.hostname = g_strdup(cmdargs->argv[2]);
+ dump_state.diskname = g_strdup(cmdargs->argv[3]);
+
+ errno = 0;
+ dump_state.level = strtol(cmdargs->argv[4], NULL, 10);
+ if (errno != 0) {
+ error("error [taper PORT-WRITE: Invalid dump level %s]",
+ cmdargs->argv[4]);
+ g_assert_not_reached();
}
- else
-#endif /* !HAVE_LINUX_ZFTAPE_H */
- if((result = tape_rdlabel(tapedev, &olddatestamp, &label)) != NULL) {
- amfree(olddatestamp);
- errstr = newstralloc(errstr, result);
- return 0;
+
+ dump_state.timestamp = strdup(cmdargs->argv[5]);
+
+ errno = 0;
+ splitsize = g_ascii_strtoull(cmdargs->argv[6], NULL, 10);
+ if (errno != 0) {
+ error("error [taper PORT-WRITE: Invalid splitsize %s]",
+ cmdargs->argv[6]);
+ g_assert_not_reached();
}
-
- fprintf(stderr, "taper: read label `%s' date `%s'\n", label, olddatestamp);
- fflush(stderr);
- amfree(olddatestamp);
-
- /* check against tape list */
- if (strcmp(label, FAKE_LABEL) != 0) {
- tp = lookup_tapelabel(label);
- if(tp == NULL) {
- errstr = newvstralloc(errstr,
- "label ", label,
- " match labelstr but it not listed in the tapelist file",
- NULL);
- return 0;
- }
- else if(tp != NULL && !reusable_tape(tp)) {
- errstr = newvstralloc(errstr,
- "cannot overwrite active tape ", label,
- NULL);
- return 0;
- }
-
- if(!match(labelstr, label)) {
- errstr = newvstralloc(errstr,
- "label ", label,
- " doesn\'t match labelstr \"", labelstr, "\"",
- NULL);
- return 0;
- }
+
+ if (strcmp(cmdargs->argv[7], "NULL") == 0) {
+ split_diskbuffer = NULL;
+ } else {
+ split_diskbuffer = g_strdup(cmdargs->argv[7]);
}
-
- if((tape_fd = tape_open(tapedev, O_WRONLY)) == -1) {
- if(errno == EACCES) {
- errstr = newstralloc(errstr,
- "writing label: tape is write protected");
- } else {
- errstr = newstralloc2(errstr,
- "writing label: ", strerror(errno));
- }
- return 0;
+
+ errno = 0;
+ fallback_splitsize = g_ascii_strtoull(cmdargs->argv[8], NULL, 10);
+ if (errno != 0) {
+ error("error [taper PORT-WRITE: Invalid fallback_splitsize %s]",
+ cmdargs->argv[8]);
+ g_assert_not_reached();
}
- tapefd_setinfo_length(tape_fd, tt->length);
-
- tapefd_setinfo_datestamp(tape_fd, taper_datestamp);
- tapefd_setinfo_disk(tape_fd, label);
- result = tapefd_wrlabel(tape_fd, taper_datestamp, label, tt_blocksize);
- if(result != NULL) {
- errstr = newstralloc(errstr, result);
- return 0;
+ dump_state.id_string = g_strdup_printf("%s:%s.%d", dump_state.hostname,
+ dump_state.diskname,
+ dump_state.level);
+
+ if (!open_read_socket(&dump_state, split_diskbuffer, splitsize,
+ fallback_splitsize)) {
+ free(split_diskbuffer);
+ return;
}
+ free(split_diskbuffer);
- fprintf(stderr, "taper: wrote label `%s' date `%s'\n", label, taper_datestamp);
- fflush(stderr);
-
-#ifdef HAVE_LIBVTBLC
- /* store time for the first volume entry */
- time(&raw_time);
- tape_timep = localtime(&raw_time);
- strftime(start_datestr, 20, "%T %D", tape_timep);
- fprintf(stderr, "taper: got vtbl start time: %s\n", start_datestr);
- fflush(stderr);
-#endif /* HAVE_LIBVTBLC */
-
- /* write tape list */
-
- /* XXX add cur_tape number to tape list structure */
- if (strcmp(label, FAKE_LABEL) != 0) {
-
- if(cur_tape == 0) {
- conf_tapelist_old = stralloc2(conf_tapelist, ".yesterday");
- } else {
- char cur_str[NUM_STR_SIZE];
+ run_device_output(state, &dump_state);
- ap_snprintf(cur_str, sizeof(cur_str), "%d", cur_tape - 1);
- conf_tapelist_old = vstralloc(conf_tapelist,
- ".today.", cur_str, NULL);
- }
- if(write_tapelist(conf_tapelist_old)) {
- error("could not write tapelist: %s", strerror(errno));
- }
- amfree(conf_tapelist_old);
+ free_dump_info(&dump_state);
+}
- remove_tapelabel(label);
- add_tapelabel(atoi(taper_datestamp), label);
- if(write_tapelist(conf_tapelist)) {
- error("could not write tapelist: %s", strerror(errno));
- }
+/* Handle a FILE_WRITE command. */
+static void process_file_write(taper_state_t * state,
+ struct cmdargs * cmdargs) {
+ dump_info_t dump_state;
+ char * holding_disk_file;
+ guint64 splitsize;
+ char * argnames[] = {"command", /* 0 */
+ "handle", /* 1 */
+ "filename", /* 2 */
+ "hostname", /* 3 */
+ "diskname", /* 4 */
+ "level", /* 5 */
+ "datestamp", /* 6 */
+ "splitsize", /* 7 */
+ NULL };
+
+ validate_args(cmdargs, argnames);
+
+ dump_state.handle = g_strdup(cmdargs->argv[1]);
+ holding_disk_file = g_strdup(cmdargs->argv[2]);
+ dump_state.hostname = g_strdup(cmdargs->argv[3]);
+ dump_state.diskname = g_strdup(cmdargs->argv[4]);
+
+ errno = 0;
+ dump_state.level = strtol(cmdargs->argv[5], NULL, 10);
+ if (errno != 0) {
+ error("error [taper FILE-WRITE: Invalid dump level %s]",
+ cmdargs->argv[5]);
+ g_assert_not_reached();
}
-
- log_add(L_START, "datestamp %s label %s tape %d",
- taper_datestamp, label, cur_tape);
- if (first_call && strcmp(label, FAKE_LABEL) == 0) {
- first_call = 0;
- log_add(L_WARNING, "tapedev is %s, dumps will be thrown away", tapedev);
+
+ dump_state.timestamp = strdup(cmdargs->argv[6]);
+
+ errno = 0;
+ splitsize = g_ascii_strtoull(cmdargs->argv[7], NULL, 10);
+ if (errno != 0) {
+ error("error [taper FILE-WRITE: Invalid splitsize %s]",
+ cmdargs->argv[7]);
+ g_assert_not_reached();
}
- total_tape_used=0.0;
- total_tape_fm = 0;
-
- return 1;
-}
-
-int first_tape(new_datestamp)
-char *new_datestamp;
-{
- if((have_changer = changer_init()) < 0) {
- error("changer initialization failed: %s", strerror(errno));
- }
- changer_debug = 1;
+ dump_state.id_string = g_strdup_printf("%s:%s.%d", dump_state.hostname,
+ dump_state.diskname,
+ dump_state.level);
+
+ dump_state.source = taper_source_new(dump_state.handle, FILE_WRITE,
+ holding_disk_file, -1,
+ NULL, splitsize, -1);
+ /* FIXME: This should be handled properly. */
+ g_assert(dump_state.source != NULL);
- taper_datestamp = newstralloc(taper_datestamp, new_datestamp);
+ run_device_output(state, &dump_state);
- if(!label_tape())
- return 0;
+ free_dump_info(&dump_state);
+ amfree(holding_disk_file);
+}
- filenum = 0;
- return 1;
+/* Send QUITTING message to driver and associated logging. Always
+ returns false. */
+static gboolean send_quitting(taper_state_t * state) {
+ putresult(QUITTING, "\n");
+ g_fprintf(stderr,"taper: DONE\n");
+ cleanup(state);
+ return FALSE;
}
-int next_tape(writerror)
-int writerror;
-{
- end_tape(writerror);
+/* This function recieves the START_TAPER command from driver, and
+ returns the attached timestamp. */
+static gboolean find_first_tape(taper_state_t * state) {
+ struct cmdargs *cmdargs;
+ tape_search_request_t search_request;
+ GThread * tape_search = NULL;
+ gboolean use_threads;
- if(++cur_tape >= runtapes)
- return 0;
+ /* We save the value here in case it changes while we're running. */
+ use_threads = g_thread_supported();
- if(!label_tape()) {
- return 0;
+ search_request.state = state;
+ search_request.prolong = TRUE;
+ search_request.errmsg = NULL;
+
+ if (use_threads) {
+ tape_search = g_thread_create(tape_search_thread,
+ &search_request, TRUE, NULL);
}
- filenum = 0;
- return 1;
-}
-
-
-int end_tape(writerror)
-int writerror;
-{
- char *result;
- int rc = 0;
-
- if(tape_fd >= 0) {
- log_add(L_INFO, "tape %s kb %ld fm %d %s",
- label,
- (long) ((total_tape_used+1023.0) / 1024.0),
- total_tape_fm,
- writerror? errstr : "[OK]");
-
- fprintf(stderr, "taper: writing end marker. [%s %s kb %ld fm %d]\n",
- label,
- writerror? "ERR" : "OK",
- (long) ((total_tape_used+1023.0) / 1024.0),
- total_tape_fm);
- fflush(stderr);
- if(! writerror) {
- if(! write_filemark()) {
- rc = 1;
- goto common_exit;
- }
-
- result = tapefd_wrendmark(tape_fd, taper_datestamp, tt_blocksize);
- if(result != NULL) {
- errstr = newstralloc(errstr, result);
- rc = 1;
- goto common_exit;
+ cmdargs = getcmd();
+
+ switch (cmdargs->cmd) {
+ case START_TAPER: {
+ gboolean search_result;
+ state->driver_start_time = strdup(cmdargs->argv[1]);
+ if (use_threads) {
+ search_result = GPOINTER_TO_INT(g_thread_join(tape_search));
+ } else {
+ search_result =
+ GPOINTER_TO_INT(tape_search_thread(&search_request));
+ }
+ if (search_result) {
+ putresult(TAPER_OK, "\n");
+ } else {
+ putresult(TAPE_ERROR, "Could not find a tape to use.\n");
+ log_add(L_ERROR, "no-tape [%s]", "Could not find a tape to use");
+ if (search_request.errmsg != NULL) {
+ char *c, *c1;
+ c = c1 = search_request.errmsg;
+ while (*c != '\0') {
+ if (*c == '\n') {
+ *c = '\0';
+ log_add(L_WARNING,"%s", c1);
+ c1 = c+1;
+ }
+ c++;
+ }
+ if (strlen(c1) > 1 )
+ log_add(L_WARNING,"%s", c1);
}
- }
+ }
+ amfree(search_request.errmsg);
+ free_cmdargs(cmdargs);
+ return TRUE;
+ }
+ case QUIT:
+ search_request.prolong = FALSE;
+ if (use_threads) {
+ g_thread_join(tape_search);
+ }
+ free_cmdargs(cmdargs);
+ return send_quitting(state);
+ default:
+ error("error [file_reader_side cmd %d argc %d]", cmdargs->cmd, cmdargs->argc);
}
-#ifdef HAVE_LINUX_ZFTAPE_H
- if (tape_fd >= 0 && is_zftape(tapedev) == 1) {
- /* rewind the tape */
+ g_assert_not_reached();
+}
- if(tapefd_rewind(tape_fd) == -1 ) {
- errstr = newstralloc2(errstr, "rewinding tape: ", strerror(errno));
- rc = 1;
- goto common_exit;
+/* In running mode (not startup mode), get a command from driver and
+ deal with it. */
+static gboolean process_driver_command(taper_state_t * state) {
+ struct cmdargs *cmdargs;
+ char * q;
+
+ /* This will return QUIT if driver has died. */
+ cmdargs = getcmd();
+ switch (cmdargs->cmd) {
+ case PORT_WRITE:
+ /*
+ * PORT-WRITE
+ * handle
+ * hostname
+ * features
+ * diskname
+ * level
+ * datestamp
+ * splitsize
+ * split_diskbuffer
+ */
+ process_port_write(state, cmdargs);
+ break;
+
+ case FILE_WRITE:
+ /*
+ * FILE-WRITE
+ * handle
+ * filename
+ * hostname
+ * features
+ * diskname
+ * level
+ * datestamp
+ * splitsize
+ */
+ process_file_write(state, cmdargs);
+ break;
+
+ case QUIT:
+ free_cmdargs(cmdargs);
+ if (state->device && state->device->volume_label) {
+ log_add(L_INFO, "tape %s kb %lld fm %d [OK]\n",
+ state->device->volume_label,
+ (long long)((state->total_bytes+(off_t)1023) / (off_t)1024),
+ state->device->file);
}
- /* close the tape */
+ return send_quitting(state);
+ default:
+ if (cmdargs->argc >= 1) {
+ q = quote_string(cmdargs->argv[0]);
+ } else {
+ q = stralloc("(no input?)");
+ }
+ putresult(BAD_COMMAND, "%s\n", q);
+ amfree(q);
+ break;
+ }
+ free_cmdargs(cmdargs);
- if(tapefd_close(tape_fd) == -1) {
- errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
- rc = 1;
- goto common_exit;
- }
- tape_fd = -1;
+ return TRUE;
+}
-#ifdef HAVE_LIBVTBLC
- /* update volume table */
- fprintf(stderr, "taper: updating volume table ...\n");
- fflush(stderr);
-
- if ((tape_fd = raw_tape_open(rawtapedev, O_RDWR)) == -1) {
- if(errno == EACCES) {
- errstr = newstralloc(errstr,
- "updating volume table: tape is write protected");
- } else {
- errstr = newstralloc2(errstr,
- "updating volume table: ",
- strerror(errno));
- }
- rc = 1;
- goto common_exit;
- }
- /* read volume table */
- if ((num_volumes = read_vtbl(tape_fd, volumes, vtbl_buffer,
- &first_seg, &last_seg)) == -1 ) {
- errstr = newstralloc2(errstr,
- "reading volume table: ",
- strerror(errno));
- rc = 1;
- goto common_exit;
- }
- /* set volume label and date for first entry */
- vtbl_no = 0;
- if(set_label(label, volumes, num_volumes, vtbl_no)){
- errstr = newstralloc2(errstr,
- "setting label for entry 1: ",
- strerror(errno));
- rc = 1;
- goto common_exit;
- }
- /* date of start writing this tape */
- if (set_date(start_datestr, volumes, num_volumes, vtbl_no)){
- errstr = newstralloc2(errstr,
- "setting date for entry 1: ",
- strerror(errno));
- rc = 1;
- goto common_exit;
- }
- /* set volume labels and dates for backup files */
- for (vtbl_no = 1; vtbl_no <= num_volumes - 2; vtbl_no++){
- fprintf(stderr,"taper: label %i: %s, date %s\n",
- vtbl_no,
- vtbl_entry[vtbl_no].label,
- vtbl_entry[vtbl_no].date);
- fflush(stderr);
- if(set_label(vtbl_entry[vtbl_no].label,
- volumes, num_volumes, vtbl_no)){
- errstr = newstralloc2(errstr,
- "setting label for entry i: ",
- strerror(errno));
- rc = 1;
- goto common_exit;
- }
- if(set_date(vtbl_entry[vtbl_no].date,
- volumes, num_volumes, vtbl_no)){
- errstr = newstralloc2(errstr,
- "setting date for entry i: ",
- strerror(errno));
- rc = 1;
- goto common_exit;
- }
- }
- /* set volume label and date for last entry */
- vtbl_no = num_volumes - 1;
- if(set_label("AMANDA Tape End", volumes, num_volumes, vtbl_no)){
- errstr = newstralloc2(errstr,
- "setting label for last entry: ",
- strerror(errno));
- rc = 1;
- goto common_exit;
- }
- datestr = NULL; /* take current time */
- if (set_date(datestr, volumes, num_volumes, vtbl_no)){
- errstr = newstralloc2(errstr,
- "setting date for last entry 1: ",
- strerror(errno));
- rc = 1;
- goto common_exit;
- }
- /* write volume table back */
- if (write_vtbl(tape_fd, volumes, vtbl_buffer, num_volumes, first_seg,
- op_mode == trunc)) {
- errstr = newstralloc2(errstr,
- "writing volume table: ",
- strerror(errno));
- rc = 1;
- goto common_exit;
- }
-
- fprintf(stderr, "taper: updating volume table: done.\n");
- fflush(stderr);
-#endif /* HAVE_LIBVTBLC */
- }
-#endif /* !HAVE_LINUX_ZFTAPE_H */
+int main(int argc, char ** argv) {
+ char * tapelist_name;
+ taper_state_t state;
+ config_overwrites_t *cfg_ovr = NULL;
+ char *cfg_opt = NULL;
- /* close the tape and let the OS write the final filemarks */
+ /*
+ * Configure program for internationalization:
+ * 1) Only set the message locale for now.
+ * 2) Set textdomain for all amanda related programs to "amanda"
+ * We don't want to be forced to support dozens of message catalogs.
+ */
+ setlocale(LC_MESSAGES, "C");
+ textdomain("amanda");
+
+ safe_fd(-1, 0);
+ set_pname("taper");
-common_exit:
+ dbopen("server");
- if(tape_fd >= 0 && tapefd_close(tape_fd) == -1 && ! writerror) {
- errstr = newstralloc2(errstr, "closing tape: ", strerror(errno));
- rc = 1;
- }
- tape_fd = -1;
- amfree(label);
+ device_api_init();
+ init_taper_state(&state);
- return rc;
-}
+ /* Don't die when child closes pipe */
+ signal(SIGPIPE, SIG_IGN);
+ g_fprintf(stderr, _("%s: pid %ld executable %s version %s\n"),
+ get_pname(), (long) getpid(), argv[0], version());
+ dbprintf(_("%s: pid %ld executable %s version %s\n"),
+ get_pname(), (long) getpid(), argv[0], version());
-int write_filemark()
-{
- if(tapefd_weof(tape_fd, 1) == -1) {
- errstr = newstralloc2(errstr, "writing filemark: ", strerror(errno));
- return 0;
- }
- total_tape_fm++;
- return 1;
-}
+ /* Process options */
+ cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
-/*
- * ========================================================================
- * TAPE CHANGER SCAN
- *
- */
-int nslots, backwards, found, got_match, tapedays;
-char *first_match_label = NULL, *first_match = NULL, *found_device = NULL;
-char *searchlabel, *labelstr;
-tape_t *tp;
+ if(argc > 2) {
+ error("Too many arguments!\n");
+ g_assert_not_reached();
+ }
+ if (argc > 1)
+ cfg_opt = argv[1];
+ config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
+ apply_config_overwrites(cfg_ovr);
-int scan_init(rc, ns, bk)
-int rc, ns, bk;
-{
- if(rc) {
- fprintf(stderr, "%s: could not get changer info: %s\n",
- get_pname(), changer_resultstr);
- return rc;
+ if (config_errors(NULL) >= CFGERR_ERRORS) {
+ g_critical(_("errors processing config file"));
}
- nslots = ns;
- backwards = bk;
+ safe_cd();
- return 0;
-}
+ set_logerror(logerror);
-int taperscan_slot(rc, slotstr, device)
- int rc;
- char *slotstr;
- char *device;
-{
- char *t_errstr;
- char *scan_datestamp = NULL;
-
- if(rc == 2) {
- fprintf(stderr, "%s: fatal slot %s: %s\n",
- get_pname(), slotstr, changer_resultstr);
- fflush(stderr);
- return 1;
- }
- else if(rc == 1) {
- fprintf(stderr, "%s: slot %s: %s\n", get_pname(),
- slotstr, changer_resultstr);
- fflush(stderr);
- return 0;
- }
- else {
- if((t_errstr = tape_rdlabel(device, &scan_datestamp, &label)) != NULL) {
- amfree(scan_datestamp);
- fprintf(stderr, "%s: slot %s: %s\n",
- get_pname(), slotstr, t_errstr);
- fflush(stderr);
- }
- else {
- /* got an amanda tape */
- fprintf(stderr, "%s: slot %s: date %-8s label %s",
- get_pname(), slotstr, scan_datestamp, label);
- fflush(stderr);
- amfree(scan_datestamp);
- if(searchlabel != NULL
- && (strcmp(label, FAKE_LABEL) == 0
- || strcmp(label, searchlabel) == 0)) {
- /* it's the one we are looking for, stop here */
- fprintf(stderr, " (exact label match)\n");
- fflush(stderr);
- found_device = newstralloc(found_device, device);
- found = 1;
- return 1;
- }
- else if(!match(labelstr, label)) {
- fprintf(stderr, " (no match)\n");
- fflush(stderr);
- }
- else {
- /* not an exact label match, but a labelstr match */
- /* check against tape list */
- tp = lookup_tapelabel(label);
- if(tp == NULL) {
- fprintf(stderr, "(not in tapelist)\n");
- fflush(stderr);
- }
- else if(!reusable_tape(tp)) {
- fprintf(stderr, " (active tape)\n");
- fflush(stderr);
- }
- else if(got_match == 0 && tp->datestamp == 0) {
- got_match = 1;
- first_match = newstralloc(first_match, slotstr);
- first_match_label = newstralloc(first_match_label, label);
- fprintf(stderr, " (new tape)\n");
- fflush(stderr);
- found = 3;
- found_device = newstralloc(found_device, device);
- return 1;
- }
- else if(got_match) {
- fprintf(stderr, " (labelstr match)\n");
- fflush(stderr);
- }
- else {
- got_match = 1;
- first_match = newstralloc(first_match, slotstr);
- first_match_label = newstralloc(first_match_label, label);
- fprintf(stderr, " (first labelstr match)\n");
- fflush(stderr);
- if(!backwards || !searchlabel) {
- found = 2;
- found_device = newstralloc(found_device, device);
- return 1;
- }
- }
- }
- }
- }
- return 0;
-}
+ check_running_as(RUNNING_AS_DUMPUSER);
-char *taper_scan()
-{
- char *outslot = NULL;
+ dbrename(get_config_name(), DBG_SUBDIR_SERVER);
- if((tp = lookup_last_reusable_tape(0)) == NULL)
- searchlabel = NULL;
- else
- searchlabel = tp->label;
+ log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
- found = 0;
- got_match = 0;
+ tapelist_name = config_dir_relative(getconf_str(CNF_TAPELIST));
- if (searchlabel != NULL)
- changer_find(scan_init, taperscan_slot, searchlabel);
- else
- changer_scan(scan_init, taperscan_slot);
-
- if(found == 2 || found == 3)
- searchlabel = first_match_label;
- else if(!found && got_match) {
- searchlabel = first_match_label;
- amfree(found_device);
- if(changer_loadslot(first_match, &outslot, &found_device) == 0) {
- found = 1;
- }
- amfree(outslot);
+ if (read_tapelist(tapelist_name) != 0) {
+ log_add(L_INFO, "pid-done %ld", (long)getpid());
+ error("could not load tapelist \"%s\"", tapelist_name);
+ g_assert_not_reached();
}
- else if(!found) {
- if(searchlabel) {
- changer_resultstr = newvstralloc(changer_resultstr,
- "label ", searchlabel,
- " or new tape not found in rack",
- NULL);
- } else {
- changer_resultstr = newstralloc(changer_resultstr,
- "new tape not found in rack");
- }
+ amfree(tapelist_name);
+
+ state.have_changer = changer_init();
+ if (state.have_changer < 0) {
+ log_add(L_INFO, "pid-done %ld", (long)getpid());
+ error("changer initialization failed: %s", strerror(errno));
+ g_assert_not_reached();
}
- if(found) {
- outslot = found_device;
- found_device = NULL; /* forget about our copy */
- } else {
- outslot = NULL;
- amfree(found_device);
+ state.next_tape_label = NULL;
+ state.next_tape_device = NULL;
+ state.cur_tape = 0;
+
+ if (!find_first_tape(&state)) {
+ log_add(L_INFO, "pid-done %ld", (long)getpid());
+ return EXIT_SUCCESS;
}
- return outslot;
+
+ while (process_driver_command(&state));
+ log_add(L_INFO, "pid-done %ld", (long)getpid());
+ return EXIT_SUCCESS;
}