X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=server-src%2Ftaperscan.c;h=8e513736bcd4bb3409f38b56df7eecf01e8344c6;hb=2627875b7d18858bc1f9f7652811e4d8c15a23eb;hp=3b5ba5518876f19fcc303d40290c0ab6964b6f59;hpb=1194fb66aa28d9929c3f2bef3cc6c1c3f40a60a4;p=debian%2Famanda diff --git a/server-src/taperscan.c b/server-src/taperscan.c index 3b5ba55..8e51373 100644 --- a/server-src/taperscan.c +++ b/server-src/taperscan.c @@ -1,10 +1,9 @@ /* - * Copyright (c) 2005 Zmanda Inc. All Rights Reserved. + * Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY @@ -15,29 +14,42 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120 - * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com + * Contact information: Zmanda Inc, 465 S Mathlida Ave, Suite 300 + * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com */ /* - * $Id: taperscan.c,v 1.9 2006/03/10 14:29:22 martinea Exp $ + * $Id: taperscan.c,v 1.17 2006/07/12 12:28:19 martinea Exp $ * * This contains the implementation of the taper-scan algorithm, as it is * used by taper, amcheck, and amtape. See the header file taperscan.h for * interface information. */ -#include -#include -#include +#include "amanda.h" +#include "conffile.h" #include "changer.h" #include "tapefile.h" +#include "device.h" +#include "timestamp.h" +#include "taperscan.h" -int scan_read_label P((char *dev, char *wantlabel, +struct taper_scan_tracker_s { + GHashTable * scanned_slots; +}; + +int scan_read_label (char *dev, char * slot, char *wantlabel, char** label, char** timestamp, - char**error_message)); -int changer_taper_scan P((char *wantlabel, char** gotlabel, char**timestamp, - char**error_message, char **tapedev)); -char *find_brand_new_tape_label(); + char**error_message); +int changer_taper_scan (char *wantlabel, char** gotlabel, char** timestamp, + char **tapedev, taper_scan_tracker_t * tracker, + TaperscanOutputFunctor output_functor, + void *output_data, + TaperscanProlongFunctor prolong_functor, + void *prolong_data); +int scan_slot (void *data, int rc, char *slotstr, char *device); +char *find_brand_new_tape_label (void); +void FILE_taperscan_output_callback (void *data, char *msg); +void CHAR_taperscan_output_callback (void *data, char *msg); /* NO GLOBALS PLEASE! */ @@ -53,82 +65,151 @@ char *find_brand_new_tape_label(); */ /* This function checks the label of a single tape, which may or may not - * have been loaded by the changer. With the addition of char *dev, it has - * the same interface as taper_scan. + * have been loaded by the changer. With the addition of char *dev, and *slot, + * it has the same interface as taper_scan. slot should be the slot where + * this tape is found, or NULL if no changer is in use. * Return value is the same as taper_scan. */ -int scan_read_label(char *dev, char *desired_label, - char** label, char** timestamp, char** error_message) { - char *result = NULL; - char *errstr = NULL; +int scan_read_label( + char *dev, + char *slot, + char *desired_label, + char** label, + char** timestamp, + char** error_message) +{ + Device * device; + char *labelstr; + DeviceStatusFlags device_status; + + g_return_val_if_fail(dev != NULL, -1); + + if (*error_message == NULL) + *error_message = stralloc(""); *label = *timestamp = NULL; - result = tape_rdlabel(dev, timestamp, label); - if (result != NULL) { - if (CHECK_NOT_AMANDA_TAPE_MSG(result) && - getconf_seen(CNF_LABEL_NEW_TAPES)) { - amfree(result); - - *label = find_brand_new_tape_label(); - if (*label != NULL) { - *timestamp = stralloc("X"); - vstrextend(error_message, - "Found a non-amanda tape, will label it `", - *label, "'.\n", NULL); - return 3; - } - vstrextend(error_message, - "Found a non-amanda tape, but have no labels left.\n", - NULL); - return -1; - } + device = device_open(dev); + g_assert(device != NULL); + + if (device->status != DEVICE_STATUS_SUCCESS ) { + *error_message = newvstrallocf(*error_message, + _("%sError opening device %s: %s.\n"), + *error_message, dev, + device_error_or_status(device)); + g_object_unref(device); + amfree(*timestamp); + amfree(*label); + return -1; + } + + if (!device_configure(device, TRUE)) { + *error_message = newvstrallocf(*error_message, + _("%sError configuring device %s: %s.\n"), + *error_message, dev, + device_error_or_status(device)); + g_object_unref(device); amfree(*timestamp); amfree(*label); - vstrextend(error_message, result, "\n", NULL); - amfree(result); return -1; } + + device_status = device_read_label(device); - if ((*label == NULL) || (*timestamp == NULL)) { - error("Invalid return from tape_rdlabel"); + if (device_status == DEVICE_STATUS_SUCCESS && device->volume_label != NULL) { + *label = g_strdup(device->volume_label); + *timestamp = strdup(device->volume_time); + } else if (device_status & DEVICE_STATUS_VOLUME_UNLABELED) { + if (!getconf_seen(CNF_LABEL_NEW_TAPES)) { + *error_message = newvstrallocf(*error_message, + _("%sFound an empty or non-amanda tape.\n"), + *error_message); + g_object_unref(device); + return -1; + } + + /* If we got a header, but the Device doesn't think it's labeled, then this + * tape probably has some data on it, so refuse to automatically label it */ + if (device->volume_header && device->volume_header->type != F_EMPTY) { + *error_message = newvstrallocf(*error_message, + _("%sFound a non-amanda tape; check and relabel it with 'amlabel -f'\n"), + *error_message); + g_object_unref(device); + return -1; + } + g_object_unref(device); + + *label = find_brand_new_tape_label(); + if (*label != NULL) { + *timestamp = stralloc("X"); + *error_message = newvstrallocf(*error_message, + _("%sFound an empty tape, will label it `%s'.\n"), + *error_message, *label); + + return 3; + } + *error_message = newvstrallocf(*error_message, + _("%sFound an empty tape, but have no labels left.\n"), + *error_message); + + return -1; + } else { + char * label_errstr; + label_errstr = g_strdup_printf(_("Error reading label: %s.\n"), + device_error_or_status(device)); + *error_message = newvstralloc(*error_message, *error_message, + label_errstr, NULL); + g_free(label_errstr); + return -1; } - vstrextend(error_message, "read label `", *label, "', date `", - *timestamp, "'\n", NULL); + g_assert(*label != NULL && *timestamp != NULL); + g_object_unref(device); + + *error_message = newvstrallocf(*error_message, + _("%sread label `%s', date `%s'.\n"), + *error_message, *label, *timestamp); + /* Register this with the barcode database, even if its not ours. */ + if (slot != NULL) { + changer_label(slot, *label); + } + if (desired_label != NULL && strcmp(*label, desired_label) == 0) { /* Got desired label. */ return 1; } /* Is this actually an acceptable tape? */ - if (strcmp(*label, FAKE_LABEL) != 0) { - char *labelstr; - labelstr = getconf_str(CNF_LABELSTR); - if(!match(labelstr, *label)) { - vstrextend(&errstr, "label ", *label, - " doesn\'t match labelstr \"", - labelstr, "\"\n", NULL); - return -1; - } else { - tape_t *tp; - if (strcmp(*timestamp, "X") == 0) { - /* new, labeled tape. */ - return 1; - } + labelstr = getconf_str(CNF_LABELSTR); + if(!match(labelstr, *label)) { + *error_message = newvstrallocf(*error_message, + _("%slabel \"%s\" doesn't match \"%s\".\n"), + *error_message, *label, labelstr); - tp = lookup_tapelabel(*label); - - if(tp == NULL) { - vstrextend(&errstr, "label ", *label, - " match labelstr but it not listed in the tapelist file.\n", - NULL); - return -1; - } else if(tp != NULL && !reusable_tape(tp)) { - vstrextend(&errstr, "cannot overwrite active tape ", *label, - "\n", NULL); - return -1; - } + return -1; + } else { + tape_t *tp; + if (strcmp(*timestamp, "X") == 0) { + /* new, labeled tape. */ + return 1; + } + + tp = lookup_tapelabel(*label); + + if(tp == NULL) { + *error_message = + newvstrallocf(*error_message, + _("%slabel \"%s\" matches labelstr but it is" + " not listed in the tapelist file.\n"), + *error_message, *label); + return -1; + } else if(tp != NULL && !reusable_tape(tp)) { + *error_message = + newvstrallocf(*error_message, + _("%sTape with label %s is still active" + " and cannot be overwritten.\n"), + *error_message, *label); + return -1; } } @@ -136,86 +217,188 @@ int scan_read_label(char *dev, char *desired_label, return 2; } -/* Interface is the same as taper_scan, with the addition of the tapedev - * output. */ +/* Interface is the same as taper_scan, with some additional bookkeeping. */ typedef struct { char *wantlabel; char **gotlabel; char **timestamp; char **error_message; char **tapedev; + char *slotstr; /* Best-choice slot number. */ char *first_labelstr_slot; int backwards; int tape_status; + TaperscanOutputFunctor output_callback; + void *output_data; + TaperscanProlongFunctor prolong_callback; + void * prolong_data; + taper_scan_tracker_t * persistent; } changertrack_t; -int scan_slot(void *data, int rc, char *slotstr, char *device) { +int +scan_slot( + void *data, + int rc, + char *slotstr, + char *device) +{ int label_result; changertrack_t *ct = ((changertrack_t*)data); + int result; + + if (ct->prolong_callback && + !ct->prolong_callback(ct->prolong_data)) { + return 1; + } + + if (ct->persistent != NULL) { + gpointer key; + gpointer value; + if (g_hash_table_lookup_extended(ct->persistent->scanned_slots, + slotstr, &key, &value)) { + /* We already returned this slot in a previous invocation, + skip it now. */ + return 0; + } + } + + if (*(ct->error_message) == NULL) + *(ct->error_message) = stralloc(""); switch (rc) { default: - newvstralloc(*(ct->error_message), *(ct->error_message), - "fatal changer error ", slotstr, ": ", - changer_resultstr, NULL); - return 1; + *(ct->error_message) = newvstrallocf(*(ct->error_message), + _("%sfatal changer error: slot %s: %s\n"), + *(ct->error_message), slotstr, changer_resultstr); + result = 1; + break; + case 1: - newvstralloc(*(ct->error_message), *(ct->error_message), - "changer error ", slotstr, ": ", changer_resultstr, NULL); - return 0; + *(ct->error_message) = newvstrallocf(*(ct->error_message), + _("%schanger error: slot %s: %s\n"), + *(ct->error_message), slotstr, changer_resultstr); + result = 0; + break; + case 0: - vstrextend(ct->error_message, "slot ", slotstr, ": ", NULL); - label_result = scan_read_label(device, ct->wantlabel, ct->gotlabel, + *(ct->error_message) = newvstrallocf(*(ct->error_message), + _("slot %s:"), slotstr); + amfree(*ct->gotlabel); + amfree(*ct->timestamp); + label_result = scan_read_label(device, slotstr, + ct->wantlabel, ct->gotlabel, ct->timestamp, ct->error_message); if (label_result == 1 || label_result == 3 || (label_result == 2 && !ct->backwards)) { *(ct->tapedev) = stralloc(device); ct->tape_status = label_result; - return 1; - } else if (label_result == 2) { - if (ct->first_labelstr_slot == NULL) - ct->first_labelstr_slot = stralloc(slotstr); - return 0; + amfree(ct->slotstr); + ct->slotstr = stralloc(slotstr); + result = 1; } else { - return 0; - } + if ((label_result == 2) && (ct->first_labelstr_slot == NULL)) + ct->first_labelstr_slot = stralloc(slotstr); + result = 0; + } + break; } - /* NOTREACHED */ - return 1; + ct->output_callback(ct->output_data, *(ct->error_message)); + amfree(*(ct->error_message)); + return result; } static int -scan_init(void *data, int rc, int nslots, int backwards, int searchable) { +scan_init( + void *data, + int rc, + G_GNUC_UNUSED int nslots, + int backwards, + G_GNUC_UNUSED int searchable) +{ changertrack_t *ct = ((changertrack_t*)data); - + if (rc) { - newvstralloc(*(ct->error_message), *(ct->error_message), - "could not get changer info: ", changer_resultstr, NULL); + *(ct->error_message) = newvstrallocf(*(ct->error_message), + _("%scould not get changer info: %s\n"), + *(ct->error_message), changer_resultstr); + ct->output_callback(ct->output_data, *(ct->error_message)); + amfree(*(ct->error_message)); } ct->backwards = backwards; return 0; } -int changer_taper_scan(char* wantlabel, - char** gotlabel, char** timestamp, - char** error_message, char **tapedev) { - changertrack_t local_data = {wantlabel, gotlabel, timestamp, - error_message, tapedev, NULL, 0, 0}; +int +changer_taper_scan( + char *wantlabel, + char **gotlabel, + char **timestamp, + char **tapedev, + taper_scan_tracker_t * tracker, + TaperscanOutputFunctor taperscan_output_callback, + void *output_data, + TaperscanProlongFunctor prolong_callback, + void * prolong_data) +{ + char *error_message = NULL; + changertrack_t local_data; + char *outslotstr = NULL; + int result; *gotlabel = *timestamp = *tapedev = NULL; - + local_data.wantlabel = wantlabel; + local_data.gotlabel = gotlabel; + local_data.timestamp = timestamp; + local_data.error_message = &error_message; + local_data.tapedev = tapedev; + local_data.first_labelstr_slot = NULL; + local_data.backwards = 0; + local_data.tape_status = 0; + local_data.output_callback = taperscan_output_callback; + local_data.output_data = output_data; + local_data.prolong_callback = prolong_callback; + local_data.prolong_data = prolong_data; + local_data.persistent = tracker; + local_data.slotstr = NULL; + changer_find(&local_data, scan_init, scan_slot, wantlabel); if (*(local_data.tapedev)) { /* We got it, and it's loaded. */ + if (local_data.persistent != NULL && local_data.slotstr != NULL) { + g_hash_table_insert(local_data.persistent->scanned_slots, + local_data.slotstr, NULL); + } else { + amfree(local_data.slotstr); + } + amfree(local_data.first_labelstr_slot); return local_data.tape_status; } else if (local_data.first_labelstr_slot) { /* Use plan B. */ - if (changer_loadslot(local_data.first_labelstr_slot, - NULL, tapedev) == 0) { - return scan_read_label(*tapedev, NULL, gotlabel, timestamp, - error_message); + if (prolong_callback && !prolong_callback(prolong_data)) { + return -1; + } + result = changer_loadslot(local_data.first_labelstr_slot, + &outslotstr, tapedev); + amfree(local_data.first_labelstr_slot); + amfree(outslotstr); + if (result == 0) { + amfree(*gotlabel); + amfree(*timestamp); + result = scan_read_label(*tapedev, NULL, NULL, + gotlabel, timestamp, + &error_message); + taperscan_output_callback(output_data, error_message); + amfree(error_message); + if (result > 0 && local_data.persistent != NULL && + local_data.slotstr != NULL) { + g_hash_table_insert(local_data.persistent->scanned_slots, + local_data.slotstr, NULL); + } else { + amfree(local_data.slotstr); + } + return result; } } @@ -225,11 +408,15 @@ int changer_taper_scan(char* wantlabel, } int taper_scan(char* wantlabel, - char** gotlabel, char** timestamp, char** error_message, - char** tapedev) { - - *gotlabel = *timestamp = *error_message = NULL; - *tapedev = getconf_str(CNF_TAPEDEV); + char** gotlabel, char** timestamp, char** tapedev, + taper_scan_tracker_t * tracker, + TaperscanOutputFunctor output_functor, + void *output_data, + TaperscanProlongFunctor prolong_functor, + void *prolong_data) { + char *error_message = NULL; + int result; + *gotlabel = *timestamp = NULL; if (wantlabel == NULL) { tape_t *tmp; @@ -240,36 +427,51 @@ int taper_scan(char* wantlabel, } if (changer_init()) { - return changer_taper_scan(wantlabel, gotlabel, timestamp, - error_message, tapedev); + result = changer_taper_scan(wantlabel, gotlabel, timestamp, + tapedev, tracker, + output_functor, output_data, + prolong_functor, prolong_data); + } else { + /* Note that the tracker is not used in this case. */ + *tapedev = stralloc(getconf_str(CNF_TAPEDEV)); + if (*tapedev == NULL) { + result = -1; + output_functor(output_data, _("No tapedev specified")); + } else { + result = scan_read_label(*tapedev, NULL, wantlabel, gotlabel, + timestamp, &error_message); + output_functor(output_data, error_message); + amfree(error_message); + } } - return scan_read_label(*tapedev, wantlabel, - gotlabel, timestamp, error_message); + return result; } #define AUTO_LABEL_MAX_LEN 1024 -char* find_brand_new_tape_label() { +char * +find_brand_new_tape_label(void) +{ char *format; char newlabel[AUTO_LABEL_MAX_LEN]; - char tmpnum[12]; + char tmpnum[30]; /* 64-bit integers can be 21 digists... */ char tmpfmt[16]; char *auto_pos = NULL; - int i, format_len, label_len, auto_len; + int i; + ssize_t label_len, auto_len; tape_t *tp; if (!getconf_seen(CNF_LABEL_NEW_TAPES)) { return NULL; } format = getconf_str(CNF_LABEL_NEW_TAPES); - format_len = strlen(format); memset(newlabel, 0, AUTO_LABEL_MAX_LEN); label_len = 0; auto_len = -1; /* Only find the first '%' */ while (*format != '\0') { if (label_len + 4 > AUTO_LABEL_MAX_LEN) { - fprintf(stderr, "Auto label format is too long!\n"); + g_fprintf(stderr, _("Auto label format is too long!\n")); return NULL; } @@ -298,26 +500,27 @@ char* find_brand_new_tape_label() { } if (auto_pos == NULL) { - fprintf(stderr, "Auto label template contains no '%%'!\n"); + g_fprintf(stderr, _("Auto label template contains no '%%'!\n")); return NULL; } - sprintf(tmpfmt, "%%0%dd", auto_len); + g_snprintf(tmpfmt, SIZEOF(tmpfmt), "%%0%zdd", + (size_t)auto_len); for (i = 1; i < INT_MAX; i ++) { - sprintf(tmpnum, tmpfmt, i); - if (strlen(tmpnum) != auto_len) { - fprintf(stderr, "All possible auto-labels used.\n"); + g_snprintf(tmpnum, SIZEOF(tmpnum), tmpfmt, i); + if (strlen(tmpnum) != (size_t)auto_len) { + g_fprintf(stderr, _("All possible auto-labels used.\n")); return NULL; } - strncpy(auto_pos, tmpnum, auto_len); + strncpy(auto_pos, tmpnum, (size_t)auto_len); tp = lookup_tapelabel(newlabel); if (tp == NULL) { /* Got it. Double-check that this is a labelstr match. */ if (!match(getconf_str(CNF_LABELSTR), newlabel)) { - fprintf(stderr, "New label %s does not match labelstr %s!\n", + g_fprintf(stderr, _("New label %s does not match labelstr %s from amanda.conf\n"), newlabel, getconf_str(CNF_LABELSTR)); return 0; } @@ -325,7 +528,55 @@ char* find_brand_new_tape_label() { } } - /* NOTREACHED. Unless you have over two billion tapes. */ - fprintf(stderr, "Taper internal error in find_brand_new_tape_label."); + /* Should not get here unless you have over two billion tapes. */ + g_fprintf(stderr, _("Taper internal error in find_brand_new_tape_label.")); return 0; } + +void +FILE_taperscan_output_callback( + void *data, + char *msg) +{ + if(!msg) return; + if(strlen(msg) == 0) return; + + if(data) + g_fprintf((FILE *)data, "%s", msg); + else + g_printf("%s", msg); +} + +void +CHAR_taperscan_output_callback( + /*@keep@*/ void *data, + char *msg) +{ + char **s = (char **)data; + + if(!msg) return; + if(strlen(msg) == 0) return; + + if(*s) + strappend(*s, msg); + else + *s = stralloc(msg); +} + +taper_scan_tracker_t * taper_scan_tracker_new(void) { + taper_scan_tracker_t * rval = malloc(sizeof(*rval)); + + rval->scanned_slots = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); + + return rval; +} + +void taper_scan_tracker_free(taper_scan_tracker_t * tracker) { + if (tracker->scanned_slots != NULL) { + g_hash_table_destroy(tracker->scanned_slots); + } + + free(tracker); +} +