e1aad269b5e464b3c7137337ec12bfc016dcc653
[debian/amanda] / client-src / amandates.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: amandates.c,v 1.16 2003/10/22 17:43:20 martinea Exp $
28  *
29  * manage amandates file, that mimics /etc/dumpdates, but stores
30  * GNUTAR dates
31  */
32
33 #include "amanda.h"
34 #include "getfsent.h"
35
36 #include "amandates.h"
37
38 static amandates_t *amandates_list = NULL;
39 static FILE *amdf = NULL;
40 static int updated, readonly;
41 static void import_dumpdates P((amandates_t *));
42 static void enter_record P((char *, int , time_t));
43 static amandates_t *lookup P((char *name, int import));
44
45 int start_amandates(open_readwrite)
46 int open_readwrite;
47 {
48     int rc, level;
49     long ldate;
50     char *line = NULL, *name = NULL;
51     char *s;
52     int ch;
53
54     /* clean up from previous invocation */
55
56     if(amdf != NULL)
57         finish_amandates();
58     if(amandates_list != NULL)
59         free_amandates();
60
61     /* initialize state */
62
63     updated = 0;
64     readonly = !open_readwrite;
65     amdf = NULL;
66     amandates_list = NULL;
67
68     /* open the file */
69
70     if (access(AMANDATES_FILE,F_OK))
71         /* not yet existing */
72         if ( (rc = open(AMANDATES_FILE,(O_CREAT|O_RDWR),0644)) != -1 )
73             /* open/create successfull */
74             aclose(rc);
75
76     if(open_readwrite)
77         amdf = fopen(AMANDATES_FILE, "r+");
78     else
79         amdf = fopen(AMANDATES_FILE, "r");
80
81     /* create it if we need to */
82
83     if(amdf == NULL && (errno == EINTR || errno == ENOENT) && open_readwrite)
84         amdf = fopen(AMANDATES_FILE, "w");
85
86     if(amdf == NULL)
87         return 0;
88
89     if(open_readwrite)
90         rc = amflock(fileno(amdf), "amandates");
91     else
92         rc = amroflock(fileno(amdf), "amandates");
93
94     if(rc == -1)
95         error("could not lock %s: %s", AMANDATES_FILE, strerror(errno));
96
97     for(; (line = agets(amdf)) != NULL; free(line)) {
98         s = line;
99         ch = *s++;
100
101         skip_whitespace(s, ch);
102         if(ch == '\0') {
103             continue;                           /* no name field */
104         }
105         name = s - 1;
106         skip_non_whitespace(s, ch);
107         s[-1] = '\0';                           /* terminate the name */
108
109         skip_whitespace(s, ch);
110         if(ch == '\0' || sscanf(s - 1, "%d %ld", &level, &ldate) != 2) {
111             continue;                           /* no more fields */
112         }
113
114         if(level < 0 || level >= DUMP_LEVELS) {
115             continue;
116         }
117
118         enter_record(name, level, (time_t) ldate);
119     }
120
121     if(ferror(amdf))
122         error("reading %s: %s", AMANDATES_FILE, strerror(errno));
123
124     updated = 0;        /* reset updated flag */
125     return 1;
126 }
127
128 void finish_amandates()
129 {
130     amandates_t *amdp;
131     int level;
132
133     if(amdf == NULL)
134         return;
135
136     if(updated) {
137         if(readonly)
138             error("updated amandates after opening readonly");
139
140         rewind(amdf);
141         for(amdp = amandates_list; amdp != NULL; amdp = amdp->next) {
142             for(level = 0; level < DUMP_LEVELS; level++) {
143                 if(amdp->dates[level] == EPOCH) continue;
144                 fprintf(amdf, "%s %d %ld\n",
145                         amdp->name, level, (long) amdp->dates[level]);
146             }
147         }
148     }
149
150     if(amfunlock(fileno(amdf), "amandates") == -1)
151         error("could not unlock %s: %s", AMANDATES_FILE, strerror(errno));
152     if (fclose(amdf) == EOF)
153         error("error [closing %s: %s]", AMANDATES_FILE, strerror(errno));
154     amdf = NULL;
155 }
156
157 void free_amandates()
158 {
159     amandates_t *amdp, *nextp;
160
161     for(amdp = amandates_list; amdp != NULL; amdp = nextp) {
162         nextp = amdp->next;
163         amfree(amdp->name);
164         amfree(amdp);
165     }
166     amandates_list = NULL;
167 }
168
169 static amandates_t *lookup(name, import)
170 char *name;
171 int import;
172 {
173     amandates_t *prevp, *amdp, *newp;
174     int rc, level;
175
176     rc = 0;
177
178     for(prevp=NULL,amdp=amandates_list;amdp!=NULL;prevp=amdp,amdp=amdp->next)
179         if((rc = strcmp(name, amdp->name)) <= 0)
180             break;
181
182     if(amdp && rc == 0)
183         return amdp;
184
185     newp = alloc(sizeof(amandates_t));
186     newp->name = stralloc(name);
187     for(level = 0; level < DUMP_LEVELS; level++)
188         newp->dates[level] = EPOCH;
189     newp->next = amdp;
190     if(prevp) prevp->next = newp;
191     else amandates_list = newp;
192
193     import_dumpdates(newp);
194
195     return newp;
196 }
197
198 amandates_t *amandates_lookup(name)
199 char *name;
200 {
201     return lookup(name, 1);
202 }
203
204 static void enter_record(name, level, dumpdate)
205 char *name;
206 int level;
207 time_t dumpdate;
208 {
209     amandates_t *amdp;
210
211     amdp = lookup(name, 0);
212
213     if(level < 0 || level >= DUMP_LEVELS || dumpdate < amdp->dates[level]) {
214         /* this is not allowed, but we can ignore it */
215         dbprintf(("amandates botch: %s lev %d: new dumpdate %ld old %ld\n",
216                   name, level, (long) dumpdate, (long) amdp->dates[level]));
217         return;
218     }
219
220     amdp->dates[level] = dumpdate;
221 }
222
223
224 void amandates_updateone(name, level, dumpdate)
225 char *name;
226 int level;
227 time_t dumpdate;
228 {
229     amandates_t *amdp;
230
231     assert(!readonly);
232
233     amdp = lookup(name, 1);
234
235     if(level < 0 || level >= DUMP_LEVELS || dumpdate < amdp->dates[level]) {
236         /* this is not allowed, but we can ignore it */
237         dbprintf(("amandates updateone: %s lev %d: new dumpdate %ld old %ld",
238                   name, level, (long) dumpdate, (long) amdp->dates[level]));
239         return;
240     }
241
242     amdp->dates[level] = dumpdate;
243     updated = 1;
244 }
245
246
247 /* -------------------------- */
248
249 static void import_dumpdates(amdp)
250 amandates_t *amdp;
251 {
252     char *devname = NULL, *line = NULL, *fname = NULL;
253     int level;
254     time_t dumpdate;
255     FILE *dumpdf;
256     char *s;
257     int ch;
258
259     devname = amname_to_devname(amdp->name);
260
261     if((dumpdf = fopen("/etc/dumpdates", "r")) == NULL) {
262         amfree(devname);
263         return;
264     }
265
266     for(; (line = agets(dumpdf)) != NULL; free(line)) {
267         s = line;
268         ch = *s++;
269
270         skip_whitespace(s, ch);
271         if(ch == '\0') {
272             continue;                           /* no fname field */
273         }
274         fname = s - 1;
275         skip_non_whitespace(s, ch);
276         s[-1] = '\0';                           /* terminate fname */
277
278         skip_whitespace(s, ch);
279         if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
280             continue;                           /* no level field */
281         }
282         skip_integer(s, ch);
283
284         skip_whitespace(s, ch);
285         if(ch == '\0') {
286             continue;                           /* no dumpdate field */
287         }
288         dumpdate = unctime(s-1);
289
290         if(strcmp(fname, devname) != 0 || level < 0 || level >= DUMP_LEVELS) {
291             continue;
292         }
293
294         if(dumpdate != -1 && dumpdate > amdp->dates[level]) {
295             if(!readonly) updated = 1;
296             amdp->dates[level] = dumpdate;
297         }
298     }
299     afclose(dumpdf);
300     amfree(devname);
301 }