2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: tapefile.c,v 1.37 2006/07/21 00:25:52 martinea Exp $
30 * routines to read and write the amanda active tape list
37 static tape_t *tape_list = NULL;
40 static tape_t *parse_tapeline(int *status, char *line);
41 static tape_t *insert(tape_t *list, tape_t *tp);
42 static time_t stamp2time(char *datestamp);
55 if((tapef = fopen(tapefile,"r")) == NULL) {
56 if (errno == ENOENT) {
57 /* no tapelist is equivalent to an empty tapelist */
60 g_debug("Error opening '%s': %s", tapefile, strerror(errno));
65 while((line = agets(tapef)) != NULL) {
66 if (line[0] == '\0') {
70 tp = parse_tapeline(&status, line);
72 if(tp == NULL && status != 0)
75 tape_list = insert(tape_list, tp);
79 for(pos=1,tp=tape_list; tp != NULL; pos++,tp=tp->next) {
95 newtapefile = stralloc2(tapefile, ".new");
97 if((tapef = fopen(newtapefile,"w")) == NULL) {
102 for(tp = tape_list; tp != NULL; tp = tp->next) {
103 g_fprintf(tapef, "%s %s", tp->datestamp, tp->label);
104 if(tp->reuse) g_fprintf(tapef, " reuse");
105 else g_fprintf(tapef, " no-reuse");
107 g_fprintf(tapef, " BARCODE:%s", tp->barcode);
109 g_fprintf(tapef, " META:%s", tp->meta);
111 g_fprintf(tapef, " BLOCKSIZE:%jd", (intmax_t)tp->blocksize);
113 g_fprintf(tapef, " #%s", tp->comment);
114 g_fprintf(tapef, "\n");
117 if (fclose(tapef) == EOF) {
118 g_fprintf(stderr,_("error [closing %s: %s]"), newtapefile, strerror(errno));
122 rc = rename(newtapefile, tapefile);
133 for(tp = tape_list; tp; tp = next) {
135 amfree(tp->datestamp);
151 for(tp = tape_list; tp != NULL; tp = tp->next) {
152 if(strcmp(label, tp->label) == 0) return tp;
165 for(tp = tape_list; tp != NULL; tp = tp->next) {
166 if(tp->position == pos) return tp;
178 for(tp = tape_list; tp != NULL; tp = tp->next) {
179 if(strcmp(tp->datestamp, datestamp) == 0) return tp;
190 for(tp = tape_list; tp != NULL; tp = tp->next) {
198 get_last_reusable_tape_label(
201 tape_t *tp = lookup_last_reusable_tape(skip);
202 return (tp != NULL) ? tp->label : NULL;
206 lookup_last_reusable_tape(
209 tape_t *tp, **tpsave;
212 int tapecycle = getconf_int(CNF_TAPECYCLE);
213 char *labelstr = getconf_str (CNF_LABELSTR);
216 * The idea here is we keep the last "several" reusable tapes we
217 * find in a stack and then return the n-th oldest one to the
218 * caller. If skip is zero, the oldest is returned, if it is
219 * one, the next oldest, two, the next to next oldest and so on.
221 tpsave = alloc((skip + 1) * SIZEOF(*tpsave));
222 for(s = 0; s <= skip; s++) {
225 for(tp = tape_list; tp != NULL; tp = tp->next) {
226 if(tp->reuse == 1 && strcmp(tp->datestamp,"0") != 0 && match (labelstr, tp->label)) {
228 for(s = skip; s > 0; s--) {
229 tpsave[s] = tpsave[s - 1];
234 s = tapecycle - count;
236 if(count < tapecycle - skip) tp = NULL;
237 else tp = tpsave[skip - s];
248 if(tp == NULL) return 0;
249 if(tp->reuse == 0) return 0;
250 if( strcmp(tp->datestamp,"0") == 0) return 1;
252 if(tp->reuse == 1) count++;
255 return (count >= getconf_int(CNF_TAPECYCLE));
262 tape_t *tp, *prev, *next;
264 tp = lookup_tapelabel(label);
271 else /* begin of list */
276 while (next != NULL) {
280 amfree(tp->datestamp);
297 /* insert a new record to the front of the list */
299 new = g_new0(tape_t, 1);
301 new->datestamp = stralloc(datestamp);
304 new->label = stralloc(label);
305 new->comment = comment? stralloc(comment) : NULL;
308 if(tape_list != NULL) tape_list->prev = new;
309 new->next = tape_list;
312 /* scan list, updating positions */
323 guess_runs_from_tapelist(void)
326 int i, ntapes, tape_ndays, dumpcycle, runtapes, runs;
327 time_t tape_time, today;
330 dumpcycle = getconf_int(CNF_DUMPCYCLE);
331 runtapes = getconf_int(CNF_RUNTAPES);
332 if(runtapes == 0) runtapes = 1; /* just in case */
336 for(i = 1; i < getconf_int(CNF_TAPECYCLE); i++) {
337 if((tp = lookup_tapepos(i)) == NULL) break;
339 tape_time = stamp2time(tp->datestamp);
340 tape_ndays = (int)days_diff(tape_time, today);
342 if(tape_ndays < dumpcycle) ntapes++;
346 if(tape_ndays < dumpcycle) {
347 /* scale for best guess */
348 if(tape_ndays == 0) ntapes = dumpcycle * runtapes;
349 else ntapes = ntapes * dumpcycle / tape_ndays;
351 else if(ntapes == 0) {
352 /* no dumps within the last dumpcycle, guess as above */
353 ntapes = dumpcycle * runtapes;
356 runs = (ntapes + runtapes - 1) / runtapes;
377 skip_whitespace(s, ch);
382 cline = g_strdup(line);
383 tp = g_new0(tape_t, 1);
386 skip_non_whitespace(s, ch);
388 tp->datestamp = stralloc(s1);
390 skip_whitespace(s, ch);
392 skip_non_whitespace(s, ch);
394 tp->label = stralloc(s1);
396 skip_whitespace(s, ch);
398 if(strncmp_const(s - 1, "reuse") == 0) {
401 skip_non_whitespace(s, ch);
403 skip_whitespace(s, ch);
405 if(strncmp_const(s - 1, "no-reuse") == 0) {
408 skip_non_whitespace(s, ch);
410 skip_whitespace(s, ch);
413 if (strncmp_const(s - 1, "BARCODE:") == 0) {
415 skip_non_whitespace(s, ch);
417 skip_whitespace(s, ch);
418 tp->barcode = stralloc(s1);
421 if (strncmp_const(s - 1, "META:") == 0) {
423 skip_non_whitespace(s, ch);
425 skip_whitespace(s, ch);
426 tp->meta = stralloc(s1);
429 if (strncmp_const(s - 1, "BLOCKSIZE:") == 0) {
431 skip_non_whitespace(s, ch);
433 skip_whitespace(s, ch);
434 tp->blocksize = atol(s1);
436 if (*(s - 1) == '#') {
437 tp->comment = stralloc(s); /* skip leading '#' */
439 g_critical("Bogus line in the tapelist file: %s", cline);
446 /* insert in reversed datestamp order */
458 while(cur != NULL && strcmp(cur->datestamp, tp->datestamp) >= 0) {
479 * Converts datestamp (an char of the form YYYYMMDD or YYYYMMDDHHMMSS) into a real
481 * Since the datestamp contains no timezone or hh/mm/ss information, the
482 * value is approximate. This is ok for our purposes, since we round off
483 * scheduling calculations to the nearest day.
495 strncpy(date, datestamp, 8);
497 dateint = atoi(date);
499 tm = localtime(&now); /* initialize sec/min/hour & gmtoff */
502 tm = alloc(SIZEOF(struct tm));
512 tm->tm_year = ( dateint / 10000) - 1900;
513 tm->tm_mon = ((dateint % 10000) / 100) - 1;
514 tm->tm_mday = ((dateint % 100) );
523 tape_t *lasttp, *iter;
526 /* Find latest reusable new tape */
527 lasttp = lookup_tapepos(lookup_nb_tape());
528 while (lasttp && lasttp->reuse == 0)
529 lasttp = lasttp->prev;
531 if(lasttp && nb > 0 && strcmp(lasttp->datestamp,"0") == 0) {
534 /* count the number of tapes we *actually* used */
535 while(iter && nb > 0 && strcmp(iter->datestamp,"0") == 0) {
544 result = g_strdup_printf(
545 _("The next new tape already labelled is: %s."),
548 result = g_strdup_printf(
549 _("The next %d new tapes already labelled are: %s"),
553 while(iter && c > 0 && strcmp(iter->datestamp,"0") == 0) {
555 result = vstrextend(&result, ", ", iter->label, NULL);
570 char *result = list_new_tapes(nb);
573 g_fprintf(output,"%s\n", result);