1*eeb96f8cSmanu /* $NetBSD: itime.c,v 1.22 2019/03/25 02:13:01 manu Exp $ */
20114e805Scgd
3108d8947Scgd /*-
4ccfa3742Smycroft * Copyright (c) 1980, 1993
5ccfa3742Smycroft * The Regents of the University of California. All rights reserved.
6108d8947Scgd *
7108d8947Scgd * Redistribution and use in source and binary forms, with or without
8108d8947Scgd * modification, are permitted provided that the following conditions
9108d8947Scgd * are met:
10108d8947Scgd * 1. Redistributions of source code must retain the above copyright
11108d8947Scgd * notice, this list of conditions and the following disclaimer.
12108d8947Scgd * 2. Redistributions in binary form must reproduce the above copyright
13108d8947Scgd * notice, this list of conditions and the following disclaimer in the
14108d8947Scgd * documentation and/or other materials provided with the distribution.
15bf07c871Sagc * 3. Neither the name of the University nor the names of its contributors
16108d8947Scgd * may be used to endorse or promote products derived from this software
17108d8947Scgd * without specific prior written permission.
18108d8947Scgd *
19108d8947Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20108d8947Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21108d8947Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22108d8947Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23108d8947Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24108d8947Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25108d8947Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26108d8947Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27108d8947Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28108d8947Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29108d8947Scgd * SUCH DAMAGE.
30108d8947Scgd */
31108d8947Scgd
32a84bab53Slukem #include <sys/cdefs.h>
33108d8947Scgd #ifndef lint
340114e805Scgd #if 0
350114e805Scgd static char sccsid[] = "@(#)itime.c 8.1 (Berkeley) 6/5/93";
360114e805Scgd #else
37*eeb96f8cSmanu __RCSID("$NetBSD: itime.c,v 1.22 2019/03/25 02:13:01 manu Exp $");
380114e805Scgd #endif
39108d8947Scgd #endif /* not lint */
40108d8947Scgd
41108d8947Scgd #include <sys/param.h>
428975510aSlukem #include <sys/queue.h>
43108d8947Scgd #include <sys/time.h>
44ccfa3742Smycroft
45108d8947Scgd #include <errno.h>
46ccfa3742Smycroft #include <fcntl.h>
47108d8947Scgd #include <stdio.h>
48108d8947Scgd #include <stdlib.h>
49108d8947Scgd #include <string.h>
5022821b35Skleink #include <time.h>
51ccfa3742Smycroft #include <unistd.h>
52ccfa3742Smycroft
53108d8947Scgd #include "dump.h"
54108d8947Scgd
558975510aSlukem struct dumptime {
568975510aSlukem struct dumpdates dt_value;
578975510aSlukem SLIST_ENTRY(dumptime) dt_list;
588975510aSlukem };
598975510aSlukem SLIST_HEAD(dthead, dumptime) dthead = SLIST_HEAD_INITIALIZER(dthead);
60108d8947Scgd struct dumpdates **ddatev = 0;
61108d8947Scgd int nddates = 0;
62108d8947Scgd
6399feaf5bSlukem static void dumprecout(FILE *, struct dumpdates *);
6499feaf5bSlukem static int getrecord(FILE *, struct dumpdates *);
659c53e91bSdholland static int makedumpdate(struct dumpdates *, const char *);
6699feaf5bSlukem static void readdumptimes(FILE *);
67108d8947Scgd
68108d8947Scgd void
initdumptimes(void)6999feaf5bSlukem initdumptimes(void)
70108d8947Scgd {
71108d8947Scgd FILE *df;
72108d8947Scgd
73108d8947Scgd if ((df = fopen(dumpdates, "r")) == NULL) {
74108d8947Scgd if (errno != ENOENT) {
758975510aSlukem msg("WARNING: cannot read %s: %s\n", dumpdates,
76108d8947Scgd strerror(errno));
778975510aSlukem return;
78108d8947Scgd }
79108d8947Scgd /*
80108d8947Scgd * Dumpdates does not exist, make an empty one.
81108d8947Scgd */
82108d8947Scgd msg("WARNING: no file `%s', making an empty one\n", dumpdates);
83108d8947Scgd if ((df = fopen(dumpdates, "w")) == NULL) {
848975510aSlukem msg("WARNING: cannot create %s: %s\n", dumpdates,
85108d8947Scgd strerror(errno));
868975510aSlukem return;
87108d8947Scgd }
88108d8947Scgd (void) fclose(df);
89108d8947Scgd if ((df = fopen(dumpdates, "r")) == NULL) {
90c8d11eb8Schristos quite(errno, "cannot read %s even after creating it",
91c8d11eb8Schristos dumpdates);
92108d8947Scgd /* NOTREACHED */
93108d8947Scgd }
94108d8947Scgd }
95108d8947Scgd (void) flock(fileno(df), LOCK_SH);
96108d8947Scgd readdumptimes(df);
97108d8947Scgd (void) fclose(df);
98108d8947Scgd }
99108d8947Scgd
100ccfa3742Smycroft static void
readdumptimes(FILE * df)10199feaf5bSlukem readdumptimes(FILE *df)
102108d8947Scgd {
10393da79deSlukem int i;
10493da79deSlukem struct dumptime *dtwalk;
105108d8947Scgd
106108d8947Scgd for (;;) {
1079af1692eSlukem dtwalk = (struct dumptime *)xcalloc(1, sizeof(struct dumptime));
108326dc9f0Schristos if (getrecord(df, &(dtwalk->dt_value)) < 0) {
109326dc9f0Schristos free(dtwalk);
110108d8947Scgd break;
111326dc9f0Schristos }
112108d8947Scgd nddates++;
1138975510aSlukem SLIST_INSERT_HEAD(&dthead, dtwalk, dt_list);
114108d8947Scgd }
115108d8947Scgd
116108d8947Scgd /*
117108d8947Scgd * arrayify the list, leaving enough room for the additional
118108d8947Scgd * record that we may have to add to the ddate structure
119108d8947Scgd */
120108d8947Scgd ddatev = (struct dumpdates **)
1219af1692eSlukem xcalloc((unsigned) (nddates + 1), sizeof(struct dumpdates *));
1228975510aSlukem dtwalk = SLIST_FIRST(&dthead);
1238975510aSlukem for (i = nddates - 1; i >= 0; i--, dtwalk = SLIST_NEXT(dtwalk, dt_list))
124108d8947Scgd ddatev[i] = &dtwalk->dt_value;
125108d8947Scgd }
126108d8947Scgd
127108d8947Scgd void
getdumptime(void)12899feaf5bSlukem getdumptime(void)
129108d8947Scgd {
13093da79deSlukem struct dumpdates *ddp;
13193da79deSlukem int i;
132*eeb96f8cSmanu const char *fname;
133108d8947Scgd
134*eeb96f8cSmanu fname = dumpdev ? dumpdev : disk;
135108d8947Scgd #ifdef FDEBUG
136108d8947Scgd msg("Looking for name %s in dumpdates = %s for level = %c\n",
137108d8947Scgd fname, dumpdates, level);
138108d8947Scgd #endif
139108d8947Scgd spcl.c_ddate = 0;
140108d8947Scgd lastlevel = '0';
141108d8947Scgd
142108d8947Scgd initdumptimes();
143108d8947Scgd /*
144108d8947Scgd * Go find the entry with the same name for a lower increment
145c40eb1e7Schristos * and older date. If we are doing a true incremental, then
14620ebd2a4Schristos * we can use any level as a ref point.
147108d8947Scgd */
148108d8947Scgd ITITERATE(i, ddp) {
149108d8947Scgd if (strncmp(fname, ddp->dd_name, sizeof (ddp->dd_name)) != 0)
150108d8947Scgd continue;
15120ebd2a4Schristos /* trueinc: ostensibly could omit the second clause
15220ebd2a4Schristos * since if trueinc is set, we don't care about the level
15320ebd2a4Schristos * at all.
15420ebd2a4Schristos */
15520ebd2a4Schristos /* if ((!trueinc && (ddp->dd_level >= level)) ||
15620ebd2a4Schristos (trueinc && (ddp->dd_level > level))) */
15720ebd2a4Schristos if (!trueinc && (ddp->dd_level >= level))
158108d8947Scgd continue;
15934ccbd43Sbouyer if (ddp->dd_ddate <= iswap32(spcl.c_ddate))
160108d8947Scgd continue;
16134ccbd43Sbouyer spcl.c_ddate = iswap32(ddp->dd_ddate);
162108d8947Scgd lastlevel = ddp->dd_level;
163108d8947Scgd }
164108d8947Scgd }
165108d8947Scgd
166108d8947Scgd void
putdumptime(void)16799feaf5bSlukem putdumptime(void)
168108d8947Scgd {
169108d8947Scgd FILE *df;
170d90a3686Sbouyer struct dumpdates *dtwalk, *dtfound;
17193da79deSlukem int i;
172108d8947Scgd int fd;
173*eeb96f8cSmanu const char *fname;
174108d8947Scgd
175*eeb96f8cSmanu if (uflag == 0 && dumpdev == NULL)
176108d8947Scgd return;
177108d8947Scgd if ((df = fopen(dumpdates, "r+")) == NULL)
178c8d11eb8Schristos quite(errno, "cannot rewrite %s", dumpdates);
179108d8947Scgd fd = fileno(df);
180108d8947Scgd (void) flock(fd, LOCK_EX);
181*eeb96f8cSmanu fname = dumpdev ? dumpdev : disk;
182108d8947Scgd free((char *)ddatev);
183108d8947Scgd ddatev = 0;
184108d8947Scgd nddates = 0;
185108d8947Scgd readdumptimes(df);
186108d8947Scgd if (fseek(df, 0L, 0) < 0)
187c8d11eb8Schristos quite(errno, "can't fseek %s", dumpdates);
188108d8947Scgd spcl.c_ddate = 0;
189108d8947Scgd ITITERATE(i, dtwalk) {
190108d8947Scgd if (strncmp(fname, dtwalk->dd_name,
191108d8947Scgd sizeof (dtwalk->dd_name)) != 0)
192108d8947Scgd continue;
193108d8947Scgd if (dtwalk->dd_level != level)
194108d8947Scgd continue;
195108d8947Scgd goto found;
196108d8947Scgd }
197108d8947Scgd /*
198108d8947Scgd * construct the new upper bound;
199108d8947Scgd * Enough room has been allocated.
200108d8947Scgd */
201108d8947Scgd dtwalk = ddatev[nddates] =
2029af1692eSlukem (struct dumpdates *)xcalloc(1, sizeof (struct dumpdates));
203108d8947Scgd nddates += 1;
204108d8947Scgd found:
20594ccb14aSitojun (void) strlcpy(dtwalk->dd_name, fname, sizeof(dtwalk->dd_name));
206108d8947Scgd dtwalk->dd_level = level;
20734ccbd43Sbouyer dtwalk->dd_ddate = iswap32(spcl.c_date);
208d90a3686Sbouyer dtfound = dtwalk;
209108d8947Scgd
210108d8947Scgd ITITERATE(i, dtwalk) {
211108d8947Scgd dumprecout(df, dtwalk);
212108d8947Scgd }
213108d8947Scgd if (fflush(df))
214c8d11eb8Schristos quite(errno, "can't flush %s", dumpdates);
215108d8947Scgd if (ftruncate(fd, ftell(df)))
216c8d11eb8Schristos quite(errno, "can't ftruncate %s", dumpdates);
217108d8947Scgd (void) fclose(df);
218108d8947Scgd msg("level %c dump on %s", level,
219d90a3686Sbouyer spcl.c_date == 0 ? "the epoch\n" : ctime(&dtfound->dd_ddate));
220108d8947Scgd }
221108d8947Scgd
222108d8947Scgd static void
dumprecout(FILE * file,struct dumpdates * what)22399feaf5bSlukem dumprecout(FILE *file, struct dumpdates *what)
224108d8947Scgd {
225108d8947Scgd
226108d8947Scgd if (fprintf(file, DUMPOUTFMT,
227108d8947Scgd what->dd_name,
228108d8947Scgd what->dd_level,
229108d8947Scgd ctime(&what->dd_ddate)) < 0)
230c8d11eb8Schristos quite(errno, "can't write %s", dumpdates);
231108d8947Scgd }
232108d8947Scgd
233108d8947Scgd int recno;
234ccfa3742Smycroft
235ccfa3742Smycroft static int
getrecord(FILE * df,struct dumpdates * ddatep)23699feaf5bSlukem getrecord(FILE *df, struct dumpdates *ddatep)
237108d8947Scgd {
238108d8947Scgd char tbuf[BUFSIZ];
239108d8947Scgd
240108d8947Scgd recno = 0;
241108d8947Scgd if ( (fgets(tbuf, sizeof (tbuf), df)) != tbuf)
242108d8947Scgd return(-1);
243108d8947Scgd recno++;
244108d8947Scgd if (makedumpdate(ddatep, tbuf) < 0)
245108d8947Scgd msg("Unknown intermediate format in %s, line %d\n",
246108d8947Scgd dumpdates, recno);
247108d8947Scgd
248108d8947Scgd #ifdef FDEBUG
249108d8947Scgd msg("getrecord: %s %c %s", ddatep->dd_name, ddatep->dd_level,
250108d8947Scgd ddatep->dd_ddate == 0 ? "the epoch\n" : ctime(&ddatep->dd_ddate));
251108d8947Scgd #endif
252108d8947Scgd return(0);
253108d8947Scgd }
254108d8947Scgd
255ccfa3742Smycroft static int
makedumpdate(struct dumpdates * ddp,const char * tbuf)2569c53e91bSdholland makedumpdate(struct dumpdates *ddp, const char *tbuf)
257108d8947Scgd {
258ccfa3742Smycroft char un_buf[128];
259108d8947Scgd
260108d8947Scgd (void) sscanf(tbuf, DUMPINFMT, ddp->dd_name, &ddp->dd_level, un_buf);
261108d8947Scgd ddp->dd_ddate = unctime(un_buf);
262108d8947Scgd if (ddp->dd_ddate < 0)
263108d8947Scgd return(-1);
264108d8947Scgd return(0);
265108d8947Scgd }
266