6d2b86453cf9667fd21e126deb50436256bf9f72
[debian/amanda] / server-src / tapefile.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
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.
15  *
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.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: tapefile.c,v 1.15.2.6.6.7 2003/10/24 13:44:49 martinea Exp $
28  *
29  * routines to read and write the amanda active tape list
30  */
31 #include "amanda.h"
32 #include "tapefile.h"
33 #include "conffile.h"
34
35 static tape_t *tape_list = NULL;
36
37 /* local functions */
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));
41
42
43
44 int read_tapelist(tapefile)
45 char *tapefile;
46 {
47     tape_t *tp;
48     FILE *tapef;
49     int pos;
50     char *line = NULL;
51     int status;
52
53     tape_list = NULL;
54     if((tapef = fopen(tapefile,"r")) == NULL) {
55         return 1;
56     }
57
58     while((line = agets(tapef)) != NULL) {
59         tp = parse_tapeline(&status, line);
60         amfree(line);
61         if(tp == NULL && status != 0) return 1;
62         if(tp != NULL) tape_list = insert(tape_list, tp);
63     }
64     afclose(tapef);
65
66     for(pos=1,tp=tape_list; tp != NULL; pos++,tp=tp->next) {
67         tp->position = pos;
68     }
69
70     return 0;
71 }
72
73 int write_tapelist(tapefile)
74 char *tapefile;
75 {
76     tape_t *tp;
77     FILE *tapef;
78     char *newtapefile;
79     int rc;
80
81     newtapefile = stralloc2(tapefile, ".new");
82
83     if((tapef = fopen(newtapefile,"w")) == NULL) {
84         amfree(newtapefile);
85         return 1;
86     }
87
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");
92         fprintf(tapef, "\n");
93     }
94
95     if (fclose(tapef) == EOF) {
96         fprintf(stderr,"error [closing %s: %s]", newtapefile, strerror(errno));
97         return 1;
98     }
99     rc = rename(newtapefile, tapefile);
100     amfree(newtapefile);
101
102     return(rc != 0);
103 }
104
105 void clear_tapelist()
106 {
107     tape_t *tp, *next;
108
109     for(tp = tape_list; tp; tp = next) {
110         amfree(tp->label);
111         next = tp->next;
112         amfree(tp);
113     }
114     tape_list = NULL;
115 }
116
117 tape_t *lookup_tapelabel(label)
118 char *label;
119 {
120     tape_t *tp;
121
122     for(tp = tape_list; tp != NULL; tp = tp->next) {
123         if(strcmp(label, tp->label) == 0) return tp;
124     }
125     return NULL;
126 }
127
128
129
130 tape_t *lookup_tapepos(pos)
131 int pos;
132 {
133     tape_t *tp;
134
135     for(tp = tape_list; tp != NULL; tp = tp->next) {
136         if(tp->position == pos) return tp;
137     }
138     return NULL;
139 }
140
141
142 tape_t *lookup_tapedate(datestamp)
143 int datestamp;
144 {
145     tape_t *tp;
146
147     for(tp = tape_list; tp != NULL; tp = tp->next) {
148         if(tp->datestamp == datestamp) return tp;
149     }
150     return NULL;
151 }
152
153 int lookup_nb_tape()
154 {
155     tape_t *tp;
156     int pos=0;
157
158     for(tp = tape_list; tp != NULL; tp = tp->next) {
159         pos=tp->position;
160     }
161     return pos;
162 }
163
164 tape_t *lookup_last_reusable_tape(skip)
165      int skip;
166 {
167     tape_t *tp, **tpsave;
168     int count=0;
169     int s;
170     int tapecycle = getconf_int(CNF_TAPECYCLE);
171     char *labelstr = getconf_str (CNF_LABELSTR);
172
173     /*
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.
178      */
179     tpsave = alloc((skip + 1) * sizeof (*tpsave));
180     for(s = 0; s <= skip; s++) {
181         tpsave[s] = NULL;
182     }
183     for(tp = tape_list; tp != NULL; tp = tp->next) {
184         if(tp->reuse == 1 && tp->datestamp > 0 && match (labelstr, tp->label)) {
185             count++;
186             for(s = skip; s > 0; s--) {
187                 tpsave[s] = tpsave[s - 1];
188             }
189             tpsave[0] = tp;
190         }
191     }
192     s = tapecycle - count;
193     if(s < 0) s = 0;
194     if(count < tapecycle - skip) tp = NULL;
195     else tp = tpsave[skip - s];
196     amfree(tpsave);
197     return tp;
198 }
199
200 int reusable_tape(tp)
201     tape_t *tp;
202 {
203     int count = 0;
204
205     if(tp == NULL) return 0;
206     if(tp->reuse == 0) return 0;
207     if(tp->datestamp == 0) return 1;
208     while(tp != NULL) {
209         if(tp->reuse == 1) count++;
210         tp = tp->prev;
211     }
212     return (count >= getconf_int(CNF_TAPECYCLE));
213 }
214
215 void remove_tapelabel(label)
216 char *label;
217 {
218     tape_t *tp, *prev, *next;
219
220     tp = lookup_tapelabel(label);
221     if(tp != NULL) {
222         prev = tp->prev;
223         next = tp->next;
224         if(prev != NULL)
225             prev->next = next;
226         else /* begin of list */
227             tape_list = next;
228         if(next != NULL)
229             next->prev = prev;
230         while (next != NULL) {
231             next->position--;
232             next = next->next;
233         }
234         amfree(tp->label);
235         amfree(tp);
236     }
237 }
238
239 tape_t *add_tapelabel(datestamp, label)
240 int datestamp;
241 char *label;
242 {
243     tape_t *cur, *new;
244
245     /* insert a new record to the front of the list */
246
247     new = (tape_t *) alloc(sizeof(tape_t));
248
249     new->datestamp = datestamp;
250     new->position = 0;
251     new->reuse = 1;
252     new->label = stralloc(label);
253
254     new->prev  = NULL;
255     if(tape_list != NULL) tape_list->prev = new;
256     new->next = tape_list;
257     tape_list = new;
258
259     /* scan list, updating positions */
260     cur = tape_list;
261     while(cur != NULL) {
262         cur->position++;
263         cur = cur->next;
264     }
265
266     return new;
267 }
268
269 int guess_runs_from_tapelist()
270 {
271     tape_t *tp;
272     int i, ntapes, tape_ndays, dumpcycle, runtapes, runs;
273     time_t tape_time, today;
274
275     today = time(0);
276     dumpcycle = getconf_int(CNF_DUMPCYCLE);
277     runtapes = getconf_int(CNF_RUNTAPES);
278     if(runtapes == 0) runtapes = 1;     /* just in case */
279
280     ntapes = 0;
281     tape_ndays = 0;
282     for(i = 1; i < getconf_int(CNF_TAPECYCLE); i++) {
283         if((tp = lookup_tapepos(i)) == NULL) break;
284
285         tape_time  = stamp2time(tp->datestamp);
286         tape_ndays = days_diff(tape_time, today);
287
288         if(tape_ndays < dumpcycle) ntapes++;
289         else break;
290     }
291
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;
296     }
297     else if(ntapes == 0) {
298         /* no dumps within the last dumpcycle, guess as above */
299         ntapes = dumpcycle * runtapes;
300     }
301
302     runs = (ntapes + runtapes - 1) / runtapes;
303     if (runs <= 0)
304       runs = 1;
305     return runs;
306 }
307
308 static tape_t *parse_tapeline(status, line)
309 int *status;
310 char *line;
311 {
312     tape_t *tp = NULL;
313     char *s, *s1;
314     int ch;
315
316     *status = 0;
317     tp = (tape_t *) alloc(sizeof(tape_t));
318
319     tp->prev = NULL;
320     tp->next = NULL;
321
322     s = line;
323     ch = *s++;
324
325     skip_whitespace(s, ch);
326     if(ch == '\0') {
327         amfree(tp);
328         return NULL;
329     }
330     if (sscanf(s - 1, "%d", &tp->datestamp) != 1) {
331         amfree(tp);
332         *status = 1;
333         return NULL;
334     }
335     skip_integer(s, ch);
336
337     skip_whitespace(s, ch);
338     s1 = s - 1;
339     skip_non_whitespace(s, ch);
340     s[-1] = '\0';
341     tp->label = stralloc(s1);
342     skip_whitespace(s, ch);
343     tp->reuse = 1;
344 #define sc "reuse"
345     if(strncmp(s - 1, sc, sizeof(sc)-1) == 0)
346         tp->reuse = 1;
347 #undef sc
348 #define sc "no-reuse"
349     if(strncmp(s - 1, sc, sizeof(sc)-1) == 0)
350         tp->reuse = 0;
351 #undef sc
352
353     return tp;
354 }
355
356
357 /* insert in reversed datestamp order */
358 static tape_t *insert(list, tp)
359 tape_t *list, *tp;
360 {
361     tape_t *prev, *cur;
362
363     prev = NULL;
364     cur = list;
365
366     while(cur != NULL && cur->datestamp >= tp->datestamp) {
367         prev = cur;
368         cur = cur->next;
369     }
370     tp->prev = prev;
371     tp->next = cur;
372     if(prev == NULL) list = tp;
373     else prev->next = tp;
374     if(cur !=NULL) cur->prev = tp;
375
376     return list;
377 }
378
379
380 static time_t stamp2time(datestamp)
381 int datestamp;
382 /*
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.
387  */
388 {
389     struct tm tm;
390     time_t now;
391
392     now = time(0);
393     tm = *localtime(&now);      /* initialize sec/min/hour & gmtoff */
394
395     tm.tm_year = ( datestamp          / 10000) - 1900;
396     tm.tm_mon  = ((datestamp % 10000) /   100) - 1;
397     tm.tm_mday = ((datestamp %   100)        );
398
399     return mktime(&tm);
400 }