1 |
|
|
/* $OpenBSD: itime.c,v 1.23 2015/12/22 21:03:58 mmcc Exp $ */ |
2 |
|
|
/* $NetBSD: itime.c,v 1.4 1997/04/15 01:09:50 lukem Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (c) 1980, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <sys/param.h> /* MAXBSIZE */ |
34 |
|
|
#include <sys/time.h> |
35 |
|
|
#include <ufs/ufs/dinode.h> |
36 |
|
|
|
37 |
|
|
#include <protocols/dumprestore.h> |
38 |
|
|
|
39 |
|
|
#include <errno.h> |
40 |
|
|
#include <fcntl.h> |
41 |
|
|
#include <stdio.h> |
42 |
|
|
#include <time.h> |
43 |
|
|
#include <stdlib.h> |
44 |
|
|
#include <string.h> |
45 |
|
|
#include <unistd.h> |
46 |
|
|
#include <limits.h> |
47 |
|
|
|
48 |
|
|
#include "dump.h" |
49 |
|
|
|
50 |
|
|
struct dumpdates **ddatev = NULL; |
51 |
|
|
int nddates = 0; |
52 |
|
|
int ddates_in = 0; |
53 |
|
|
struct dumptime *dthead = NULL; |
54 |
|
|
|
55 |
|
|
static void dumprecout(FILE *, struct dumpdates *); |
56 |
|
|
static int getrecord(FILE *, struct dumpdates *); |
57 |
|
|
static int makedumpdate(struct dumpdates *, char *); |
58 |
|
|
static void readdumptimes(FILE *); |
59 |
|
|
|
60 |
|
|
void |
61 |
|
|
initdumptimes(void) |
62 |
|
|
{ |
63 |
|
|
FILE *df; |
64 |
|
|
|
65 |
✗✓ |
2 |
if ((df = fopen(dumpdates, "r")) == NULL) { |
66 |
|
|
if (errno != ENOENT) { |
67 |
|
|
quit("cannot read %s: %s\n", dumpdates, |
68 |
|
|
strerror(errno)); |
69 |
|
|
/* NOTREACHED */ |
70 |
|
|
} |
71 |
|
|
/* |
72 |
|
|
* Dumpdates does not exist, make an empty one. |
73 |
|
|
*/ |
74 |
|
|
msg("WARNING: no file `%s', making an empty one\n", dumpdates); |
75 |
|
|
if ((df = fopen(dumpdates, "w")) == NULL) { |
76 |
|
|
quit("cannot create %s: %s\n", dumpdates, |
77 |
|
|
strerror(errno)); |
78 |
|
|
/* NOTREACHED */ |
79 |
|
|
} |
80 |
|
|
(void) fclose(df); |
81 |
|
|
if ((df = fopen(dumpdates, "r")) == NULL) { |
82 |
|
|
quit("cannot read %s even after creating it: %s\n", |
83 |
|
|
dumpdates, strerror(errno)); |
84 |
|
|
/* NOTREACHED */ |
85 |
|
|
} |
86 |
|
|
} |
87 |
✓✗ |
3 |
(void) flock(fileno(df), LOCK_SH); |
88 |
|
1 |
readdumptimes(df); |
89 |
|
1 |
(void) fclose(df); |
90 |
|
1 |
} |
91 |
|
|
|
92 |
|
|
static void |
93 |
|
|
readdumptimes(FILE *df) |
94 |
|
|
{ |
95 |
|
|
int i; |
96 |
|
|
struct dumptime *dtwalk; |
97 |
|
|
|
98 |
|
2 |
for (;;) { |
99 |
|
1 |
dtwalk = calloc(1, sizeof(struct dumptime)); |
100 |
✓✗ |
1 |
if (getrecord(df, &(dtwalk->dt_value)) < 0) { |
101 |
|
1 |
free(dtwalk); |
102 |
|
|
break; |
103 |
|
|
} |
104 |
|
|
nddates++; |
105 |
|
|
dtwalk->dt_next = dthead; |
106 |
|
|
dthead = dtwalk; |
107 |
|
|
} |
108 |
|
|
|
109 |
|
1 |
ddates_in = 1; |
110 |
|
|
/* |
111 |
|
|
* arrayify the list, leaving enough room for the additional |
112 |
|
|
* record that we may have to add to the ddate structure |
113 |
|
|
*/ |
114 |
|
1 |
ddatev = calloc((unsigned) (nddates + 1), sizeof(struct dumpdates *)); |
115 |
|
1 |
dtwalk = dthead; |
116 |
✗✓ |
2 |
for (i = nddates - 1; i >= 0; i--, dtwalk = dtwalk->dt_next) |
117 |
|
|
ddatev[i] = &dtwalk->dt_value; |
118 |
|
1 |
} |
119 |
|
|
|
120 |
|
|
void |
121 |
|
|
getdumptime(void) |
122 |
|
|
{ |
123 |
|
|
struct dumpdates *ddp; |
124 |
|
|
int i; |
125 |
|
|
char *fname; |
126 |
|
|
|
127 |
|
|
fname = duid ? duid : disk; |
128 |
|
|
#ifdef FDEBUG |
129 |
|
|
msg("Looking for name %s in dumpdates = %s for level = %c\n", |
130 |
|
|
fname, dumpdates, level); |
131 |
|
|
#endif |
132 |
|
|
spcl.c_ddate = 0; |
133 |
|
|
lastlevel = '0'; |
134 |
|
|
|
135 |
|
|
initdumptimes(); |
136 |
|
|
/* |
137 |
|
|
* Go find the entry with the same name for a lower increment |
138 |
|
|
* and older date |
139 |
|
|
*/ |
140 |
|
|
ITITERATE(i, ddp) { |
141 |
|
|
if ((strncmp(fname, ddp->dd_name, sizeof(ddp->dd_name)) != 0) && |
142 |
|
|
(strncmp(disk, ddp->dd_name, sizeof(ddp->dd_name)) != 0)) |
143 |
|
|
continue; |
144 |
|
|
if (ddp->dd_level >= level) |
145 |
|
|
continue; |
146 |
|
|
if (ddp->dd_ddate <= (time_t)spcl.c_ddate) |
147 |
|
|
continue; |
148 |
|
|
spcl.c_ddate = (int64_t)ddp->dd_ddate; |
149 |
|
|
lastlevel = ddp->dd_level; |
150 |
|
|
} |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
void |
154 |
|
|
putdumptime(void) |
155 |
|
|
{ |
156 |
|
|
FILE *df; |
157 |
|
|
struct dumpdates *dtwalk; |
158 |
|
|
int fd, i; |
159 |
|
|
char *fname; |
160 |
|
|
time_t t; |
161 |
|
|
|
162 |
|
|
if(uflag == 0) |
163 |
|
|
return; |
164 |
|
|
if ((df = fopen(dumpdates, "r+")) == NULL) |
165 |
|
|
quit("cannot rewrite %s: %s\n", dumpdates, strerror(errno)); |
166 |
|
|
fd = fileno(df); |
167 |
|
|
(void) flock(fd, LOCK_EX); |
168 |
|
|
fname = duid ? duid : disk; |
169 |
|
|
free(ddatev); |
170 |
|
|
ddatev = NULL; |
171 |
|
|
nddates = 0; |
172 |
|
|
dthead = NULL; |
173 |
|
|
ddates_in = 0; |
174 |
|
|
readdumptimes(df); |
175 |
|
|
if (fseek(df, 0L, SEEK_SET) < 0) |
176 |
|
|
quit("fseek: %s\n", strerror(errno)); |
177 |
|
|
spcl.c_ddate = 0; |
178 |
|
|
ITITERATE(i, dtwalk) { |
179 |
|
|
if ((strncmp(fname, dtwalk->dd_name, |
180 |
|
|
sizeof(dtwalk->dd_name)) != 0) && |
181 |
|
|
(strncmp(disk, dtwalk->dd_name, |
182 |
|
|
sizeof(dtwalk->dd_name)) != 0)) |
183 |
|
|
continue; |
184 |
|
|
if (dtwalk->dd_level != level) |
185 |
|
|
continue; |
186 |
|
|
goto found; |
187 |
|
|
} |
188 |
|
|
/* |
189 |
|
|
* construct the new upper bound; |
190 |
|
|
* Enough room has been allocated. |
191 |
|
|
*/ |
192 |
|
|
dtwalk = ddatev[nddates] = calloc(1, sizeof(struct dumpdates)); |
193 |
|
|
nddates += 1; |
194 |
|
|
found: |
195 |
|
|
(void) strlcpy(dtwalk->dd_name, fname, sizeof(dtwalk->dd_name)); |
196 |
|
|
dtwalk->dd_level = level; |
197 |
|
|
dtwalk->dd_ddate = (time_t)spcl.c_date; |
198 |
|
|
|
199 |
|
|
ITITERATE(i, dtwalk) { |
200 |
|
|
dumprecout(df, dtwalk); |
201 |
|
|
} |
202 |
|
|
if (fflush(df)) |
203 |
|
|
quit("%s: %s\n", dumpdates, strerror(errno)); |
204 |
|
|
if (ftruncate(fd, ftello(df))) |
205 |
|
|
quit("ftruncate (%s): %s\n", dumpdates, strerror(errno)); |
206 |
|
|
(void) fclose(df); |
207 |
|
|
t = (time_t)spcl.c_date; |
208 |
|
|
msg("level %c dump on %s", level, t == 0 ? "the epoch\n" : ctime(&t)); |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
static void |
212 |
|
|
dumprecout(FILE *file, struct dumpdates *what) |
213 |
|
|
{ |
214 |
|
|
|
215 |
|
|
if (fprintf(file, DUMPOUTFMT, |
216 |
|
|
what->dd_name, |
217 |
|
|
what->dd_level, |
218 |
|
|
ctime(&what->dd_ddate)) < 0) |
219 |
|
|
quit("%s: %s\n", dumpdates, strerror(errno)); |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
int recno; |
223 |
|
|
|
224 |
|
|
static int |
225 |
|
|
getrecord(FILE *df, struct dumpdates *ddatep) |
226 |
|
|
{ |
227 |
|
2 |
char tbuf[BUFSIZ]; |
228 |
|
|
|
229 |
|
1 |
recno = 0; |
230 |
✓✗ |
1 |
if (fgets(tbuf, sizeof(tbuf), df) == NULL) |
231 |
|
1 |
return(-1); |
232 |
|
|
recno++; |
233 |
|
|
if (makedumpdate(ddatep, tbuf) < 0) |
234 |
|
|
msg("Unknown intermediate format in %s, line %d\n", |
235 |
|
|
dumpdates, recno); |
236 |
|
|
|
237 |
|
|
#ifdef FDEBUG |
238 |
|
|
msg("getrecord: %s %c %s", ddatep->dd_name, ddatep->dd_level, |
239 |
|
|
ddatep->dd_ddate == 0 ? "the epoch\n" : ctime(&ddatep->dd_ddate)); |
240 |
|
|
#endif |
241 |
|
|
return(0); |
242 |
|
1 |
} |
243 |
|
|
|
244 |
|
|
static int |
245 |
|
|
makedumpdate(struct dumpdates *ddp, char *tbuf) |
246 |
|
|
{ |
247 |
|
|
char un_buf[BUFSIZ], *str; |
248 |
|
|
struct tm then; |
249 |
|
|
|
250 |
|
|
if (sscanf(tbuf, DUMPINFMT, ddp->dd_name, &ddp->dd_level, un_buf) != 3) |
251 |
|
|
return(-1); |
252 |
|
|
str = getduid(ddp->dd_name); |
253 |
|
|
if (str != NULL) { |
254 |
|
|
strlcpy(ddp->dd_name, str, sizeof(ddp->dd_name)); |
255 |
|
|
free(str); |
256 |
|
|
} |
257 |
|
|
str = strptime(un_buf, "%a %b %e %H:%M:%S %Y", &then); |
258 |
|
|
then.tm_isdst = -1; |
259 |
|
|
if (str == NULL || (*str != '\n' && *str != '\0')) |
260 |
|
|
ddp->dd_ddate = (time_t) -1; |
261 |
|
|
else |
262 |
|
|
ddp->dd_ddate = mktime(&then); |
263 |
|
|
if (ddp->dd_ddate < 0) |
264 |
|
|
return(-1); |
265 |
|
|
return(0); |
266 |
|
|
} |