⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 taper.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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, &timestamp, 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 + -