Imported Upstream version 2.5.1
[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.21 2006/07/25 18:35:21 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 #include "util.h"
36
37 #include "amandates.h"
38
39 static amandates_t *amandates_list = NULL;
40 static FILE *amdf = NULL;
41 static int updated, readonly;
42 static char *g_amandates_file = NULL;
43 static void import_dumpdates(amandates_t *);
44 static void enter_record(char *, int , time_t);
45 static amandates_t *lookup(char *name, int import);
46
47 int
48 start_amandates(
49     char *amandates_file,
50     int   open_readwrite)
51 {
52     int rc, level = 0;
53     long ldate = 0L;
54     char *line;
55     char *name;
56     char *s;
57     int ch;
58     char *qname;
59
60     if (amandates_file == NULL)
61         return 0;
62
63     /* clean up from previous invocation */
64
65     if(amdf != NULL)
66         finish_amandates();
67     if(amandates_list != NULL)
68         free_amandates();
69     amfree(g_amandates_file);
70
71     /* initialize state */
72
73     updated = 0;
74     readonly = !open_readwrite;
75     amdf = NULL;
76     amandates_list = NULL;
77     g_amandates_file = stralloc(amandates_file);
78     /* open the file */
79
80     if (access(amandates_file,F_OK))
81         /* not yet existing */
82         if ( (rc = open(amandates_file,(O_CREAT|O_RDWR),0644)) != -1 )
83             /* open/create successfull */
84             aclose(rc);
85
86     if(open_readwrite)
87         amdf = fopen(amandates_file, "r+");
88     else
89         amdf = fopen(amandates_file, "r");
90
91     /* create it if we need to */
92
93     if(amdf == NULL && (errno == EINTR || errno == ENOENT) && open_readwrite)
94         amdf = fopen(amandates_file, "w");
95
96     if(amdf == NULL)
97         return 0;
98
99     if(open_readwrite)
100         rc = amflock(fileno(amdf), amandates_file);
101     else
102         rc = amroflock(fileno(amdf), amandates_file);
103
104     if(rc == -1) {
105         error("could not lock %s: %s", amandates_file, strerror(errno));
106         /*NOTREACHED*/
107     }
108
109     for(; (line = agets(amdf)) != NULL; free(line)) {
110         if (line[0] == '\0')
111             continue;
112         s = line;
113         ch = *s++;
114
115         skip_whitespace(s, ch);
116         if(ch == '\0') {
117             continue;                           /* no name field */
118         }
119         qname = s - 1;
120         skip_quoted_string(s, ch);
121         s[-1] = '\0';                           /* terminate the name */
122         name = unquote_string(qname);
123
124         skip_whitespace(s, ch);
125         if(ch == '\0' || sscanf(s - 1, "%d %ld", &level, &ldate) != 2) {
126             amfree(name);
127             continue;                           /* no more fields */
128         }
129
130         if(level < 0 || level >= DUMP_LEVELS) {
131             amfree(name);
132             continue;
133         }
134
135         enter_record(name, level, (time_t) ldate);
136         amfree(name);
137     }
138
139     if(ferror(amdf)) {
140         error("reading %s: %s", amandates_file, strerror(errno));
141         /*NOTREACHED*/
142     }
143
144     updated = 0;        /* reset updated flag */
145     return 1;
146 }
147
148 void
149 finish_amandates(void)
150 {
151     amandates_t *amdp;
152     int level;
153     char *qname;
154
155     if(amdf == NULL)
156         return;
157
158     if(updated) {
159         if(readonly) {
160             error("updated amandates after opening readonly");
161             /*NOTREACHED*/
162         }
163
164         rewind(amdf);
165         for(amdp = amandates_list; amdp != NULL; amdp = amdp->next) {
166             for(level = 0; level < DUMP_LEVELS; level++) {
167                 if(amdp->dates[level] == EPOCH) continue;
168                 qname = quote_string(amdp->name);
169                 fprintf(amdf, "%s %d %ld\n",
170                         qname, level, (long) amdp->dates[level]);
171                 amfree(qname);
172             }
173         }
174     }
175
176     if(amfunlock(fileno(amdf), g_amandates_file) == -1) {
177         error("could not unlock %s: %s", g_amandates_file, strerror(errno));
178         /*NOTREACHED*/
179     }
180     if (fclose(amdf) == EOF) {
181         error("error [closing %s: %s]", g_amandates_file, strerror(errno));
182         /*NOTREACHED*/
183     }
184     amdf = NULL;
185 }
186
187 void
188 free_amandates(void)
189 {
190     amandates_t *amdp, *nextp;
191
192     for(amdp = amandates_list; amdp != NULL; amdp = nextp) {
193         nextp = amdp->next;
194         amfree(amdp->name);
195         amfree(amdp);
196     }
197     amandates_list = NULL;
198 }
199
200 static amandates_t *
201 lookup(
202     char *      name,
203     int         import)
204 {
205     amandates_t *prevp, *amdp;
206     int rc, level;
207
208     (void)import;       /* Quiet unused parameter warning */
209     rc = 0;
210
211     prevp = NULL;
212     amdp = amandates_list;
213     while (amdp != NULL) {
214         if ((rc = strcmp(name, amdp->name)) <= 0)
215             break;
216         prevp = amdp;
217         amdp = amdp->next;
218     }
219     if (!(amdp && (rc == 0))) {
220         amandates_t *newp = alloc(SIZEOF(amandates_t));
221         newp->name = stralloc(name);
222         for (level = 0; level < DUMP_LEVELS; level++)
223             newp->dates[level] = EPOCH;
224         newp->next = amdp;
225         if (prevp != NULL) {
226 #ifndef __lint  /* Remove complaint about NULL pointer assignment */
227             prevp->next = newp;
228 #else
229             (void)prevp;
230 #endif
231         } else {
232             amandates_list = newp;
233         }
234         import_dumpdates(newp);
235         return newp;
236     }
237     return amdp;
238 }
239
240 amandates_t *
241 amandates_lookup(
242     char *      name)
243 {
244     return lookup(name, 1);
245 }
246
247 static void
248 enter_record(
249     char *      name,
250     int         level,
251     time_t      dumpdate)
252 {
253     amandates_t *amdp;
254     char *qname;
255
256     amdp = lookup(name, 0);
257
258     if(level < 0 || level >= DUMP_LEVELS || dumpdate < amdp->dates[level]) {
259         qname = quote_string(name);
260         /* this is not allowed, but we can ignore it */
261         dbprintf(("amandates botch: %s lev %d: new dumpdate %ld old %ld\n",
262                   qname, level, (long) dumpdate, (long) amdp->dates[level]));
263         amfree(qname);
264         return;
265     }
266
267     amdp->dates[level] = dumpdate;
268 }
269
270
271 void
272 amandates_updateone(
273     char *      name,
274     int         level,
275     time_t      dumpdate)
276 {
277     amandates_t *amdp;
278     char *qname;
279
280     assert(!readonly);
281
282     amdp = lookup(name, 1);
283
284     if(level < 0 || level >= DUMP_LEVELS || dumpdate < amdp->dates[level]) {
285         /* this is not allowed, but we can ignore it */
286         qname = quote_string(name);
287         dbprintf(("amandates updateone: %s lev %d: new dumpdate %ld old %ld",
288                   name, level, (long) dumpdate, (long) amdp->dates[level]));
289         amfree(qname);
290         return;
291     }
292
293     amdp->dates[level] = dumpdate;
294     updated = 1;
295 }
296
297
298 /* -------------------------- */
299
300 static void
301 import_dumpdates(
302     amandates_t *       amdp)
303 {
304     char *devname;
305     char *line;
306     char *fname;
307     int level = 0;
308     time_t dumpdate;
309     FILE *dumpdf;
310     char *s;
311     int ch;
312
313     devname = amname_to_devname(amdp->name);
314
315     if((dumpdf = fopen("/etc/dumpdates", "r")) == NULL) {
316         amfree(devname);
317         return;
318     }
319
320     for(; (line = agets(dumpdf)) != NULL; free(line)) {
321         if (line[0] == '\0')
322             continue;
323         s = line;
324         ch = *s++;
325
326         skip_whitespace(s, ch);
327         if(ch == '\0') {
328             continue;                           /* no fname field */
329         }
330         fname = s - 1;
331         skip_non_whitespace(s, ch);
332         s[-1] = '\0';                           /* terminate fname */
333
334         skip_whitespace(s, ch);
335         if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
336             continue;                           /* no level field */
337         }
338         skip_integer(s, ch);
339
340         skip_whitespace(s, ch);
341         if(ch == '\0') {
342             continue;                           /* no dumpdate field */
343         }
344         dumpdate = unctime(s-1);
345
346         if(strcmp(fname, devname) != 0 || level < 0 || level >= DUMP_LEVELS) {
347             continue;
348         }
349
350         if(dumpdate != -1 && dumpdate > amdp->dates[level]) {
351             if(!readonly) updated = 1;
352             amdp->dates[level] = dumpdate;
353         }
354     }
355     afclose(dumpdf);
356     amfree(devname);
357 }