]> git.wh0rd.org - dump.git/blob - dump/itime.c
Store dumpdates with timezone
[dump.git] / dump / itime.c
1 /*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <stelian@popies.net>, 1999-2000
6 * Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
7 */
8
9 /*-
10 * Copyright (c) 1980, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41
42 #ifndef lint
43 static const char rcsid[] =
44 "$Id: itime.c,v 1.24 2003/03/06 14:35:51 stelian Exp $";
45 #endif /* not lint */
46
47 #include <config.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <stdio.h>
51 #ifdef __STDC__
52 #include <stdlib.h>
53 #include <string.h>
54 #endif
55
56 #include <sys/param.h>
57 #include <sys/time.h>
58 #include <time.h>
59 #include <fcntl.h>
60 #ifdef __linux__
61 #ifdef HAVE_EXT2FS_EXT2_FS_H
62 #include <ext2fs/ext2_fs.h>
63 #else
64 #include <linux/ext2_fs.h>
65 #endif
66 #include <ext2fs/ext2fs.h>
67 #include <bsdcompat.h>
68 #include <sys/file.h>
69 #include <unistd.h>
70 #elif defined sunos
71 #include <sys/vnode.h>
72
73 #include <ufs/fsdir.h>
74 #include <ufs/inode.h>
75 #include <ufs/fs.h>
76 #else
77 #include <ufs/ufs/dinode.h>
78 #endif
79
80 #include <protocols/dumprestore.h>
81
82 #include "dump.h"
83
84 struct dumpdates **ddatev;
85 int nddates;
86 int ddates_in;
87 struct dumptime *dthead;
88
89 static void dumprecout __P((FILE *, struct dumpdates *));
90 static int getrecord __P((FILE *, struct dumpdates *));
91 static int makedumpdate __P((struct dumpdates *, char *));
92 static void readdumptimes __P((FILE *));
93
94 void
95 initdumptimes(int createdumpdates)
96 {
97 FILE *df;
98 struct flock lock;
99
100 if ((df = fopen(dumpdates, "r")) == NULL) {
101 if (errno != ENOENT) {
102 quit("cannot read %s: %s\n", dumpdates,
103 strerror(errno));
104 /* NOTREACHED */
105 }
106 if (createdumpdates) {
107 /*
108 * Dumpdates does not exist, make an empty one.
109 */
110 msg("WARNING: no file `%s', making an empty one\n", dumpdates);
111 if ((df = fopen(dumpdates, "w")) == NULL) {
112 quit("cannot create %s: %s\n", dumpdates,
113 strerror(errno));
114 /* NOTREACHED */
115 }
116 (void) fclose(df);
117 if ((df = fopen(dumpdates, "r")) == NULL) {
118 quit("cannot read %s even after creating it: %s\n",
119 dumpdates, strerror(errno));
120 /* NOTREACHED */
121 }
122 }
123 else
124 msg("WARNING: no file `%s'\n", dumpdates);
125 }
126 if (df != NULL) {
127 memset(&lock, 0, sizeof(lock));
128 lock.l_type = F_RDLCK;
129 if (fcntl(fileno(df), F_SETLKW, &lock) < 0)
130 quit("cannot set read lock on %s: %s\n",
131 dumpdates, strerror(errno));
132 readdumptimes(df);
133 (void) fclose(df);
134 }
135 }
136
137 static void
138 readdumptimes(FILE *df)
139 {
140 int i;
141 struct dumptime *dtwalk;
142
143 for (;;) {
144 dtwalk = (struct dumptime *)calloc(1, sizeof (struct dumptime));
145 if (getrecord(df, &(dtwalk->dt_value)) < 0)
146 break;
147 nddates++;
148 dtwalk->dt_next = dthead;
149 dthead = dtwalk;
150 }
151
152 ddates_in = 1;
153 /*
154 * arrayify the list, leaving enough room for the additional
155 * record that we may have to add to the ddate structure
156 */
157 ddatev = (struct dumpdates **)
158 calloc((unsigned) (nddates + 1), sizeof (struct dumpdates *));
159 dtwalk = dthead;
160 for (i = nddates - 1; i >= 0; i--, dtwalk = dtwalk->dt_next)
161 ddatev[i] = &dtwalk->dt_value;
162 }
163
164 void
165 getdumptime(int createdumpdates)
166 {
167 struct dumpdates *ddp;
168 int i;
169
170 #ifdef FDEBUG
171 msg("Looking for name %s in dumpdates = %s for level = %c\n",
172 disk, dumpdates, level);
173 #endif
174 spcl.c_ddate = 0;
175 lastlevel = '0';
176
177 /* If this is a level 0 dump, and we're not updating
178 dumpdates, there's no point in trying to read
179 dumpdates. It may not exist yet, or may not be mounted. For
180 incrementals, we *must* read dumpdates (fail if it's not there!) */
181 if ( (level == lastlevel) && !createdumpdates)
182 return;
183 initdumptimes(createdumpdates);
184 if (ddatev == NULL)
185 return;
186 /*
187 * Go find the entry with the same name for a lower increment
188 * and older date
189 */
190 ITITERATE(i, ddp) {
191 if (strncmp(disk, ddp->dd_name, sizeof (ddp->dd_name)) != 0)
192 continue;
193 if (ddp->dd_level >= level)
194 continue;
195 if (ddp->dd_ddate <= (time_t)spcl.c_ddate)
196 continue;
197 spcl.c_ddate = ddp->dd_ddate;
198 lastlevel = ddp->dd_level;
199 }
200 }
201
202 void
203 putdumptime(void)
204 {
205 FILE *df;
206 struct dumpdates *dtwalk;
207 int i;
208 int fd;
209 struct flock lock;
210
211 if(uflag == 0)
212 return;
213 if ((df = fopen(dumpdates, "r+")) == NULL)
214 quit("cannot rewrite %s: %s\n", dumpdates, strerror(errno));
215 fd = fileno(df);
216 memset(&lock, 0, sizeof(lock));
217 lock.l_type = F_WRLCK;
218 if (fcntl(fd, F_SETLKW, &lock) < 0)
219 quit("cannot set write lock on %s: %s\n", dumpdates, strerror(errno));
220 free((char *)ddatev);
221 ddatev = 0;
222 nddates = 0;
223 dthead = 0;
224 ddates_in = 0;
225 readdumptimes(df);
226 if (fseek(df, 0L, 0) < 0)
227 quit("fseek: %s\n", strerror(errno));
228 spcl.c_ddate = 0;
229 ITITERATE(i, dtwalk) {
230 if (strncmp(disk, dtwalk->dd_name,
231 sizeof (dtwalk->dd_name)) != 0)
232 continue;
233 if (dtwalk->dd_level != level)
234 continue;
235 goto found;
236 }
237 /*
238 * construct the new upper bound;
239 * Enough room has been allocated.
240 */
241 dtwalk = ddatev[nddates] =
242 (struct dumpdates *)calloc(1, sizeof (struct dumpdates));
243 nddates += 1;
244 found:
245 (void) strncpy(dtwalk->dd_name, disk, sizeof (dtwalk->dd_name));
246 dtwalk->dd_level = level;
247 dtwalk->dd_ddate = spcl.c_date;
248
249 ITITERATE(i, dtwalk) {
250 dumprecout(df, dtwalk);
251 }
252 if (fflush(df))
253 quit("%s: %s\n", dumpdates, strerror(errno));
254 if (ftruncate(fd, ftell(df)))
255 quit("ftruncate (%s): %s\n", dumpdates, strerror(errno));
256 (void) fclose(df);
257 }
258
259 static void
260 dumprecout(FILE *file, struct dumpdates *what)
261 {
262 char buf[26];
263 struct tm *tms;
264
265 tms = localtime(&what->dd_ddate);
266 strncpy(buf, asctime(tms), sizeof(buf));
267 if (buf[24] != '\n' || buf[25] != '\0')
268 quit("asctime returned an unexpected string\n");
269 buf[24] = 0;
270 if (fprintf(file, "%s %c %s %c%2.2d%2.2d\n",
271 what->dd_name,
272 what->dd_level,
273 buf,
274 (tms->tm_gmtoff < 0 ? '-' : '+'),
275 abs(tms->tm_gmtoff) / 3600,
276 abs(tms->tm_gmtoff) % 3600 / 60) < 0)
277 quit("%s: %s\n", dumpdates, strerror(errno));
278 }
279
280 int recno;
281
282 static int
283 getrecord(FILE *df, struct dumpdates *ddatep)
284 {
285 char tbuf[BUFSIZ];
286
287 recno = 0;
288 if (fgets(tbuf, sizeof (tbuf), df) == NULL)
289 return(-1);
290 recno++;
291 if (makedumpdate(ddatep, tbuf) < 0)
292 msg("Unknown intermediate format in %s, line %d\n",
293 dumpdates, recno);
294
295 #ifdef FDEBUG
296 msg("getrecord: %s %c %s", ddatep->dd_name, ddatep->dd_level,
297 ddatep->dd_ddate == 0 ? "the epoch\n" : ctime(&ddatep->dd_ddate));
298 #endif
299 return(0);
300 }
301
302 static int
303 makedumpdate(struct dumpdates *ddp, char *tbuf)
304 {
305 char *tok;
306
307 /* device name */
308 if ( NULL == (tok = strsep( &tbuf, " ")) )
309 return(-1);
310 if ( strlen(tok) > MAXPATHLEN )
311 return(-1);
312 strcpy(ddp->dd_name, tok);
313
314 /* eat whitespace */
315 for( ; *tbuf == ' ' ; tbuf++);
316
317 /* dump level */
318 ddp->dd_level = *tbuf;
319 ++tbuf;
320
321 /* eat whitespace */
322 for( ; *tbuf == ' ' ; tbuf++);
323
324 /* dump date */
325 ddp->dd_ddate = unctime(tbuf);
326 if (ddp->dd_ddate < 0)
327 return(-1);
328 /* fstab entry */
329 ddp->dd_fstab = fstabsearch(ddp->dd_name);
330 return(0);
331 }