2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: tapefile.c,v 1.15.2.6.6.7 2003/10/24 13:44:49 martinea Exp $
29 * routines to read and write the amanda active tape list
35 static tape_t *tape_list = NULL;
38 static tape_t *parse_tapeline P((int *status, char *line));
39 static tape_t *insert P((tape_t *list, tape_t *tp));
40 static time_t stamp2time P((int datestamp));
44 int read_tapelist(tapefile)
54 if((tapef = fopen(tapefile,"r")) == NULL) {
58 while((line = agets(tapef)) != NULL) {
59 tp = parse_tapeline(&status, line);
61 if(tp == NULL && status != 0) return 1;
62 if(tp != NULL) tape_list = insert(tape_list, tp);
66 for(pos=1,tp=tape_list; tp != NULL; pos++,tp=tp->next) {
73 int write_tapelist(tapefile)
81 newtapefile = stralloc2(tapefile, ".new");
83 if((tapef = fopen(newtapefile,"w")) == NULL) {
88 for(tp = tape_list; tp != NULL; tp = tp->next) {
89 fprintf(tapef, "%d %s", tp->datestamp, tp->label);
90 if(tp->reuse) fprintf(tapef, " reuse");
91 else fprintf(tapef, " no-reuse");
95 if (fclose(tapef) == EOF) {
96 fprintf(stderr,"error [closing %s: %s]", newtapefile, strerror(errno));
99 rc = rename(newtapefile, tapefile);
105 void clear_tapelist()
109 for(tp = tape_list; tp; tp = next) {
117 tape_t *lookup_tapelabel(label)
122 for(tp = tape_list; tp != NULL; tp = tp->next) {
123 if(strcmp(label, tp->label) == 0) return tp;
130 tape_t *lookup_tapepos(pos)
135 for(tp = tape_list; tp != NULL; tp = tp->next) {
136 if(tp->position == pos) return tp;
142 tape_t *lookup_tapedate(datestamp)
147 for(tp = tape_list; tp != NULL; tp = tp->next) {
148 if(tp->datestamp == datestamp) return tp;
158 for(tp = tape_list; tp != NULL; tp = tp->next) {
164 tape_t *lookup_last_reusable_tape(skip)
167 tape_t *tp, **tpsave;
170 int tapecycle = getconf_int(CNF_TAPECYCLE);
171 char *labelstr = getconf_str (CNF_LABELSTR);
174 * The idea here is we keep the last "several" reusable tapes we
175 * find in a stack and then return the n-th oldest one to the
176 * caller. If skip is zero, the oldest is returned, if it is
177 * one, the next oldest, two, the next to next oldest and so on.
179 tpsave = alloc((skip + 1) * sizeof (*tpsave));
180 for(s = 0; s <= skip; s++) {
183 for(tp = tape_list; tp != NULL; tp = tp->next) {
184 if(tp->reuse == 1 && tp->datestamp > 0 && match (labelstr, tp->label)) {
186 for(s = skip; s > 0; s--) {
187 tpsave[s] = tpsave[s - 1];
192 s = tapecycle - count;
194 if(count < tapecycle - skip) tp = NULL;
195 else tp = tpsave[skip - s];
200 int reusable_tape(tp)
205 if(tp == NULL) return 0;
206 if(tp->reuse == 0) return 0;
207 if(tp->datestamp == 0) return 1;
209 if(tp->reuse == 1) count++;
212 return (count >= getconf_int(CNF_TAPECYCLE));
215 void remove_tapelabel(label)
218 tape_t *tp, *prev, *next;
220 tp = lookup_tapelabel(label);
226 else /* begin of list */
230 while (next != NULL) {
239 tape_t *add_tapelabel(datestamp, label)
245 /* insert a new record to the front of the list */
247 new = (tape_t *) alloc(sizeof(tape_t));
249 new->datestamp = datestamp;
252 new->label = stralloc(label);
255 if(tape_list != NULL) tape_list->prev = new;
256 new->next = tape_list;
259 /* scan list, updating positions */
269 int guess_runs_from_tapelist()
272 int i, ntapes, tape_ndays, dumpcycle, runtapes, runs;
273 time_t tape_time, today;
276 dumpcycle = getconf_int(CNF_DUMPCYCLE);
277 runtapes = getconf_int(CNF_RUNTAPES);
278 if(runtapes == 0) runtapes = 1; /* just in case */
282 for(i = 1; i < getconf_int(CNF_TAPECYCLE); i++) {
283 if((tp = lookup_tapepos(i)) == NULL) break;
285 tape_time = stamp2time(tp->datestamp);
286 tape_ndays = days_diff(tape_time, today);
288 if(tape_ndays < dumpcycle) ntapes++;
292 if(tape_ndays < dumpcycle) {
293 /* scale for best guess */
294 if(tape_ndays == 0) ntapes = dumpcycle * runtapes;
295 else ntapes = ntapes * dumpcycle / tape_ndays;
297 else if(ntapes == 0) {
298 /* no dumps within the last dumpcycle, guess as above */
299 ntapes = dumpcycle * runtapes;
302 runs = (ntapes + runtapes - 1) / runtapes;
308 static tape_t *parse_tapeline(status, line)
317 tp = (tape_t *) alloc(sizeof(tape_t));
325 skip_whitespace(s, ch);
330 if (sscanf(s - 1, "%d", &tp->datestamp) != 1) {
337 skip_whitespace(s, ch);
339 skip_non_whitespace(s, ch);
341 tp->label = stralloc(s1);
342 skip_whitespace(s, ch);
345 if(strncmp(s - 1, sc, sizeof(sc)-1) == 0)
348 #define sc "no-reuse"
349 if(strncmp(s - 1, sc, sizeof(sc)-1) == 0)
357 /* insert in reversed datestamp order */
358 static tape_t *insert(list, tp)
366 while(cur != NULL && cur->datestamp >= tp->datestamp) {
372 if(prev == NULL) list = tp;
373 else prev->next = tp;
374 if(cur !=NULL) cur->prev = tp;
380 static time_t stamp2time(datestamp)
383 * Converts datestamp (an int of the form YYYYMMDD) into a real time_t value.
384 * Since the datestamp contains no timezone or hh/mm/ss information, the
385 * value is approximate. This is ok for our purposes, since we round off
386 * scheduling calculations to the nearest day.
393 tm = *localtime(&now); /* initialize sec/min/hour & gmtoff */
395 tm.tm_year = ( datestamp / 10000) - 1900;
396 tm.tm_mon = ((datestamp % 10000) / 100) - 1;
397 tm.tm_mday = ((datestamp % 100) );