1 /* $OpenBSD: itime.c,v 1.27 2024/05/09 08:35:40 florian 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 int nddates = 0;
51 struct dumpdates **ddatev = NULL;
52 char *dumpdates = NULL;
53 char lastlevel = 0;
54 int ddates_in = 0;
55 struct dumptime *dthead = NULL;
56
57 static void dumprecout(FILE *, struct dumpdates *);
58 static int getrecord(FILE *, struct dumpdates *);
59 static int makedumpdate(struct dumpdates *, char *);
60 static void readdumptimes(FILE *);
61
62 void
initdumptimes(void)63 initdumptimes(void)
64 {
65 FILE *df;
66
67 if ((df = fopen(dumpdates, "r")) == NULL) {
68 if (errno != ENOENT) {
69 quit("cannot read %s: %s\n", dumpdates,
70 strerror(errno));
71 /* NOTREACHED */
72 }
73 /*
74 * Dumpdates does not exist, make an empty one.
75 */
76 msg("WARNING: no file `%s', making an empty one\n", dumpdates);
77 if ((df = fopen(dumpdates, "w")) == NULL) {
78 quit("cannot create %s: %s\n", dumpdates,
79 strerror(errno));
80 /* NOTREACHED */
81 }
82 (void) fclose(df);
83 if ((df = fopen(dumpdates, "r")) == NULL) {
84 quit("cannot read %s even after creating it: %s\n",
85 dumpdates, strerror(errno));
86 /* NOTREACHED */
87 }
88 }
89 (void) flock(fileno(df), LOCK_SH);
90 readdumptimes(df);
91 (void) fclose(df);
92 }
93
94 static void
readdumptimes(FILE * df)95 readdumptimes(FILE *df)
96 {
97 int i;
98 struct dumptime *dtwalk;
99
100 for (;;) {
101 dtwalk = calloc(1, sizeof(struct dumptime));
102 if (dtwalk == NULL)
103 quit("allocation failed");
104 if (getrecord(df, &(dtwalk->dt_value)) < 0) {
105 free(dtwalk);
106 break;
107 }
108 nddates++;
109 dtwalk->dt_next = dthead;
110 dthead = dtwalk;
111 }
112
113 ddates_in = 1;
114 /*
115 * arrayify the list, leaving enough room for the additional
116 * record that we may have to add to the ddate structure
117 */
118 ddatev = calloc((unsigned) (nddates + 1), sizeof(struct dumpdates *));
119 if (ddatev == NULL)
120 quit("allocation failed");
121 dtwalk = dthead;
122 for (i = nddates - 1; i >= 0; i--, dtwalk = dtwalk->dt_next)
123 ddatev[i] = &dtwalk->dt_value;
124 }
125
126 void
getdumptime(void)127 getdumptime(void)
128 {
129 struct dumpdates *ddp;
130 int i;
131 char *fname;
132
133 fname = duid ? duid : disk;
134 #ifdef FDEBUG
135 msg("Looking for name %s in dumpdates = %s for level = %c\n",
136 fname, dumpdates, level);
137 #endif
138 spcl.c_ddate = 0;
139 lastlevel = '0';
140
141 initdumptimes();
142 /*
143 * Go find the entry with the same name for a lower increment
144 * and older date
145 */
146 ITITERATE(i, ddp) {
147 if ((strncmp(fname, ddp->dd_name, sizeof(ddp->dd_name)) != 0) &&
148 (strncmp(disk, ddp->dd_name, sizeof(ddp->dd_name)) != 0))
149 continue;
150 if (ddp->dd_level >= level)
151 continue;
152 if (ddp->dd_ddate <= (time_t)spcl.c_ddate)
153 continue;
154 spcl.c_ddate = (int64_t)ddp->dd_ddate;
155 lastlevel = ddp->dd_level;
156 }
157 }
158
159 void
putdumptime(void)160 putdumptime(void)
161 {
162 FILE *df;
163 struct dumpdates *dtwalk;
164 int fd, i;
165 char *fname, *ct;
166 time_t t;
167
168 if(uflag == 0)
169 return;
170 if ((df = fopen(dumpdates, "r+")) == NULL)
171 quit("cannot rewrite %s: %s\n", dumpdates, strerror(errno));
172 fd = fileno(df);
173 (void) flock(fd, LOCK_EX);
174 fname = duid ? duid : disk;
175 free(ddatev);
176 ddatev = NULL;
177 nddates = 0;
178 dthead = NULL;
179 ddates_in = 0;
180 readdumptimes(df);
181 if (fseek(df, 0L, SEEK_SET) == -1)
182 quit("fseek: %s\n", strerror(errno));
183 spcl.c_ddate = 0;
184 ITITERATE(i, dtwalk) {
185 if ((strncmp(fname, dtwalk->dd_name,
186 sizeof(dtwalk->dd_name)) != 0) &&
187 (strncmp(disk, dtwalk->dd_name,
188 sizeof(dtwalk->dd_name)) != 0))
189 continue;
190 if (dtwalk->dd_level != level)
191 continue;
192 goto found;
193 }
194 /*
195 * construct the new upper bound;
196 * Enough room has been allocated.
197 */
198 dtwalk = ddatev[nddates] = calloc(1, sizeof(struct dumpdates));
199 if (dtwalk == NULL)
200 quit("allocation failed");
201 nddates += 1;
202 found:
203 (void) strlcpy(dtwalk->dd_name, fname, sizeof(dtwalk->dd_name));
204 dtwalk->dd_level = level;
205 dtwalk->dd_ddate = (time_t)spcl.c_date;
206
207 ITITERATE(i, dtwalk) {
208 dumprecout(df, dtwalk);
209 }
210 if (fflush(df))
211 quit("%s: %s\n", dumpdates, strerror(errno));
212 if (ftruncate(fd, ftello(df)))
213 quit("ftruncate (%s): %s\n", dumpdates, strerror(errno));
214 (void) fclose(df);
215 t = (time_t)spcl.c_date;
216 if (t == 0)
217 ct = "the epoch\n";
218 else if ((ct = ctime(&t)) == NULL)
219 ct = "?\n";
220 msg("level %c dump on %s", level, ct);
221 }
222
223 static void
dumprecout(FILE * file,struct dumpdates * what)224 dumprecout(FILE *file, struct dumpdates *what)
225 {
226 char *ct;
227
228 ct = ctime(&what->dd_ddate);
229 if (ct == NULL)
230 quit("Cannot convert date\n");
231
232 if (fprintf(file, DUMPOUTFMT,
233 what->dd_name,
234 what->dd_level,
235 ctime(&what->dd_ddate)) < 0)
236 quit("%s: %s\n", dumpdates, strerror(errno));
237 }
238
239 int recno;
240
241 static int
getrecord(FILE * df,struct dumpdates * ddatep)242 getrecord(FILE *df, struct dumpdates *ddatep)
243 {
244 char tbuf[BUFSIZ];
245
246 recno = 0;
247 if (fgets(tbuf, sizeof(tbuf), df) == NULL)
248 return(-1);
249 recno++;
250 if (makedumpdate(ddatep, tbuf) < 0)
251 msg("Unknown intermediate format in %s, line %d\n",
252 dumpdates, recno);
253
254 #ifdef FDEBUG
255 {
256 char *ct;
257
258 if (ddatep->dd_ddate == 0)
259 ct = "the epoch\n";
260 else
261 ct = ctime(&ddatep->dd_ddate);
262
263 if (ct)
264 msg("getrecord: %s %c %s", ddatep->dd_name,
265 ddatep->dd_level, ct);
266 else
267 msg("getrecord: %s %c %lld seconds after the epoch\n",
268 ddatep->dd_name, ddatep->dd_level,
269 ddatep->dd_ddate);
270 }
271 #endif
272 return(0);
273 }
274
275 static int
makedumpdate(struct dumpdates * ddp,char * tbuf)276 makedumpdate(struct dumpdates *ddp, char *tbuf)
277 {
278 char un_buf[BUFSIZ], *str;
279 struct tm then;
280
281 if (sscanf(tbuf, DUMPINFMT, ddp->dd_name, &ddp->dd_level, un_buf) != 3)
282 return(-1);
283 str = getduid(ddp->dd_name);
284 if (str != NULL) {
285 strlcpy(ddp->dd_name, str, sizeof(ddp->dd_name));
286 free(str);
287 }
288 str = strptime(un_buf, "%a %b %e %H:%M:%S %Y", &then);
289 then.tm_isdst = -1;
290 if (str == NULL || (*str != '\n' && *str != '\0'))
291 ddp->dd_ddate = (time_t) -1;
292 else
293 ddp->dd_ddate = mktime(&then);
294 if (ddp->dd_ddate < 0)
295 return(-1);
296 return(0);
297 }
298