📄 taper.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998, 2000 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: the Amanda Development Team. Its members are listed in a * file named AUTHORS, in the root directory of this distribution. *//* $Id: taper.c 6512 2007-05-24 17:00:24Z ian $ * * moves files from holding disk to tape, or from a socket to tape *//* FIXME: This file needs to use gettext. */#include <glib.h>#include "physmem.h"#include "changer.h"#include "clock.h"#include "conffile.h"#include "device.h"#include "logfile.h"#include "server_util.h"#include "stream.h"#include "tapefile.h"#include "taperscan.h"#include "taper-source.h"#include "timestamp.h"#include "token.h"#include "version.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;} 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();}static void cleanup(taper_state_t * state) { amfree(state->driver_start_time); amfree(state->next_tape_label); amfree(state->next_tape_device); taper_scan_tracker_free(state->taper_scan_tracker); if (state->device != NULL) { g_object_unref(state->device); state->device = NULL; }}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; }}/* 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(cmd_t cmd, struct cmdargs * args, char ** argnames) { int i; for (i = 0; argnames[i] != NULL; i ++) { if (i > args->argc) { error("error [taper %s: not enough args: %s]", cmdstr[cmd], argnames[i]); } } if (i < args->argc) { error("error [taper %s: Too many args: Got %d, expected %d.]", cmdstr[cmd], args->argc, i); }}/* 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; 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 = squote(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; } socket = stream_server(res->ai_family, &port, 0, STREAM_BUFSIZE, 0); freeaddrinfo(res); 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 = squote(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; } putresult(PORT, "%d\n", port); fd = stream_accept(socket, CONNECT_TIMEOUT, 0, STREAM_BUFSIZE); 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 = squote(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 { aclose(socket); } 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;}typedef struct { ConsumerFunctor next_consumer; gpointer next_consumer_data; guint64 bytes_written;} CountingConsumerData;/* A ConsumerFunctor. This consumer just passes its arguments on to a second consumer, but counts the number of bytes successfully written. */static int counting_consumer(gpointer user_data, queue_buffer_t * buffer) { int result; CountingConsumerData * data = user_data; result = data->next_consumer(data->next_consumer_data, buffer); if (result > 0) { data->bytes_written += result; } return result;}static gboolean boolean_prolong(void * data) { if (data == NULL) { return TRUE; /* Do not interrupt. */ } else { return *(gboolean*)data; }}/* 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 (previously non-amanda) tape"), *label); } } amfree(timestamp); return TRUE;}typedef struct { taper_state_t * state; gboolean prolong; /* scan stops when this is FALSE. */ char *errmsg;} tape_search_request_t;/* A GThread that runs taper_scan. */static gpointer tape_search_thread(gpointer data) { tape_search_request_t * request = data; 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); } return GINT_TO_POINTER (simple_taper_scan(request->state, &(request->prolong), &(request->errmsg)));}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);}/* 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; cmd_t cmd; struct cmdargs args; if (state->device != NULL) { return TRUE; } /* We save the value here in case it changes while we're running. */ use_threads = g_thread_supported(); 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); cmd = getcmd(&args); 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); return TRUE; } else { putresult(NO_NEW_TAPE, "%s\n", dump->handle); log_taper_scan_errmsg(search_request.errmsg); return FALSE; } } case NO_NEW_TAPE: search_request.prolong = FALSE; if (use_threads) { g_thread_join(tape_search); } return FALSE; }}/* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -