18fae3551SRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
48fae3551SRodney W. Grimes * Copyright (c) 1980, 1993
58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved.
68fae3551SRodney W. Grimes *
78fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
88fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions
98fae3551SRodney W. Grimes * are met:
108fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
128fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
138fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
148fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
168fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software
178fae3551SRodney W. Grimes * without specific prior written permission.
188fae3551SRodney W. Grimes *
198fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
208fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
238fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298fae3551SRodney W. Grimes * SUCH DAMAGE.
308fae3551SRodney W. Grimes */
318fae3551SRodney W. Grimes
328fae3551SRodney W. Grimes #include <sys/param.h>
33941ee632SPoul-Henning Kamp #include <sys/queue.h>
348fae3551SRodney W. Grimes
358fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h>
368fae3551SRodney W. Grimes
378fae3551SRodney W. Grimes #include <protocols/dumprestore.h>
388fae3551SRodney W. Grimes
398fae3551SRodney W. Grimes #include <errno.h>
408fae3551SRodney W. Grimes #include <fcntl.h>
4189fdc4e1SMike Barcroft #include <limits.h>
428fae3551SRodney W. Grimes #include <stdio.h>
438fae3551SRodney W. Grimes #include <stdlib.h>
448fae3551SRodney W. Grimes #include <string.h>
457649cb00SKirk McKusick #include <time.h>
46617dbd3cSIan Dowse #include <timeconv.h>
478fae3551SRodney W. Grimes
488fae3551SRodney W. Grimes #include "dump.h"
498fae3551SRodney W. Grimes
50941ee632SPoul-Henning Kamp struct dumptime {
51941ee632SPoul-Henning Kamp struct dumpdates dt_value;
52941ee632SPoul-Henning Kamp SLIST_ENTRY(dumptime) dt_list;
53941ee632SPoul-Henning Kamp };
54941ee632SPoul-Henning Kamp SLIST_HEAD(dthead, dumptime) dthead = SLIST_HEAD_INITIALIZER(dthead);
55*33ceb489SKirk McKusick int nddates = 0; /* number of records (might be zero) */
56*33ceb489SKirk McKusick struct dumpdates **ddatev; /* the arrayfied version */
57*33ceb489SKirk McKusick char *dumpdates; /* name of the file containing dump date info */
58*33ceb489SKirk McKusick int lastlevel; /* dump level of previous dump */
598fae3551SRodney W. Grimes
602db673abSWarner Losh static void dumprecout(FILE *, const struct dumpdates *);
612db673abSWarner Losh static int getrecord(FILE *, struct dumpdates *);
622db673abSWarner Losh static int makedumpdate(struct dumpdates *, const char *);
632db673abSWarner Losh static void readdumptimes(FILE *);
648fae3551SRodney W. Grimes
658fae3551SRodney W. Grimes void
initdumptimes(void)662db673abSWarner Losh initdumptimes(void)
678fae3551SRodney W. Grimes {
688fae3551SRodney W. Grimes FILE *df;
698fae3551SRodney W. Grimes
708fae3551SRodney W. Grimes if ((df = fopen(dumpdates, "r")) == NULL) {
718fae3551SRodney W. Grimes if (errno != ENOENT) {
72b2f6bdeeSDavid E. O'Brien msg("WARNING: cannot read %s: %s\n", dumpdates,
738fae3551SRodney W. Grimes strerror(errno));
748cc6e4d8SDavid E. O'Brien return;
758fae3551SRodney W. Grimes }
768fae3551SRodney W. Grimes /*
778fae3551SRodney W. Grimes * Dumpdates does not exist, make an empty one.
788fae3551SRodney W. Grimes */
798fae3551SRodney W. Grimes msg("WARNING: no file `%s', making an empty one\n", dumpdates);
808fae3551SRodney W. Grimes if ((df = fopen(dumpdates, "w")) == NULL) {
81b2f6bdeeSDavid E. O'Brien msg("WARNING: cannot create %s: %s\n", dumpdates,
828fae3551SRodney W. Grimes strerror(errno));
838cc6e4d8SDavid E. O'Brien return;
848fae3551SRodney W. Grimes }
858fae3551SRodney W. Grimes (void) fclose(df);
868fae3551SRodney W. Grimes if ((df = fopen(dumpdates, "r")) == NULL) {
878fae3551SRodney W. Grimes quit("cannot read %s even after creating it: %s\n",
888fae3551SRodney W. Grimes dumpdates, strerror(errno));
898fae3551SRodney W. Grimes /* NOTREACHED */
908fae3551SRodney W. Grimes }
918fae3551SRodney W. Grimes }
928fae3551SRodney W. Grimes (void) flock(fileno(df), LOCK_SH);
938fae3551SRodney W. Grimes readdumptimes(df);
948fae3551SRodney W. Grimes (void) fclose(df);
958fae3551SRodney W. Grimes }
968fae3551SRodney W. Grimes
978fae3551SRodney W. Grimes static void
readdumptimes(FILE * df)982db673abSWarner Losh readdumptimes(FILE *df)
998fae3551SRodney W. Grimes {
100d2334e27SIan Dowse int i;
101d2334e27SIan Dowse struct dumptime *dtwalk;
1028fae3551SRodney W. Grimes
1038fae3551SRodney W. Grimes for (;;) {
1048fae3551SRodney W. Grimes dtwalk = (struct dumptime *)calloc(1, sizeof (struct dumptime));
10580ca1f34SXin LI if (getrecord(df, &(dtwalk->dt_value)) < 0) {
10680ca1f34SXin LI free(dtwalk);
1078fae3551SRodney W. Grimes break;
10880ca1f34SXin LI }
1098fae3551SRodney W. Grimes nddates++;
110941ee632SPoul-Henning Kamp SLIST_INSERT_HEAD(&dthead, dtwalk, dt_list);
1118fae3551SRodney W. Grimes }
1128fae3551SRodney W. Grimes
1138fae3551SRodney W. Grimes /*
1148fae3551SRodney W. Grimes * arrayify the list, leaving enough room for the additional
1158fae3551SRodney W. Grimes * record that we may have to add to the ddate structure
1168fae3551SRodney W. Grimes */
1174c8762f0SPedro F. Giffuni ddatev = calloc((unsigned) (nddates + 1), sizeof (struct dumpdates *));
118941ee632SPoul-Henning Kamp dtwalk = SLIST_FIRST(&dthead);
119941ee632SPoul-Henning Kamp for (i = nddates - 1; i >= 0; i--, dtwalk = SLIST_NEXT(dtwalk, dt_list))
1208fae3551SRodney W. Grimes ddatev[i] = &dtwalk->dt_value;
1218fae3551SRodney W. Grimes }
1228fae3551SRodney W. Grimes
1238fae3551SRodney W. Grimes void
getdumptime(void)1242db673abSWarner Losh getdumptime(void)
1258fae3551SRodney W. Grimes {
126d2334e27SIan Dowse struct dumpdates *ddp;
127d2334e27SIan Dowse int i;
1288fae3551SRodney W. Grimes char *fname;
1298fae3551SRodney W. Grimes
1308fae3551SRodney W. Grimes fname = disk;
1318fae3551SRodney W. Grimes #ifdef FDEBUG
132f72ab793SKirk McKusick msg("Looking for name %s in dumpdates = %s for level = %d\n",
1338fae3551SRodney W. Grimes fname, dumpdates, level);
1348fae3551SRodney W. Grimes #endif
1358fae3551SRodney W. Grimes spcl.c_ddate = 0;
136f72ab793SKirk McKusick lastlevel = 0;
1378fae3551SRodney W. Grimes
1388fae3551SRodney W. Grimes initdumptimes();
1398fae3551SRodney W. Grimes /*
1408fae3551SRodney W. Grimes * Go find the entry with the same name for a lower increment
1418fae3551SRodney W. Grimes * and older date
1428fae3551SRodney W. Grimes */
1438fae3551SRodney W. Grimes ITITERATE(i, ddp) {
1448fae3551SRodney W. Grimes if (strncmp(fname, ddp->dd_name, sizeof (ddp->dd_name)) != 0)
1458fae3551SRodney W. Grimes continue;
1468fae3551SRodney W. Grimes if (ddp->dd_level >= level)
1478fae3551SRodney W. Grimes continue;
1481c85e6a3SKirk McKusick if (ddp->dd_ddate <= _time64_to_time(spcl.c_ddate))
1498fae3551SRodney W. Grimes continue;
1501c85e6a3SKirk McKusick spcl.c_ddate = _time_to_time64(ddp->dd_ddate);
1518fae3551SRodney W. Grimes lastlevel = ddp->dd_level;
1528fae3551SRodney W. Grimes }
1538fae3551SRodney W. Grimes }
1548fae3551SRodney W. Grimes
1558fae3551SRodney W. Grimes void
putdumptime(void)1562db673abSWarner Losh putdumptime(void)
1578fae3551SRodney W. Grimes {
1588fae3551SRodney W. Grimes FILE *df;
159d2334e27SIan Dowse struct dumpdates *dtwalk;
160d2334e27SIan Dowse int i;
1618fae3551SRodney W. Grimes int fd;
1628fae3551SRodney W. Grimes char *fname;
1635b3817c6SMatthew Dillon char *tmsg;
1648fae3551SRodney W. Grimes
1658fae3551SRodney W. Grimes if(uflag == 0)
1668fae3551SRodney W. Grimes return;
1678fae3551SRodney W. Grimes if ((df = fopen(dumpdates, "r+")) == NULL)
1688fae3551SRodney W. Grimes quit("cannot rewrite %s: %s\n", dumpdates, strerror(errno));
1698fae3551SRodney W. Grimes fd = fileno(df);
1708fae3551SRodney W. Grimes (void) flock(fd, LOCK_EX);
1718fae3551SRodney W. Grimes fname = disk;
1724c8762f0SPedro F. Giffuni free(ddatev);
1734c8762f0SPedro F. Giffuni ddatev = NULL;
1748fae3551SRodney W. Grimes nddates = 0;
1758fae3551SRodney W. Grimes readdumptimes(df);
1768fae3551SRodney W. Grimes if (fseek(df, 0L, 0) < 0)
1778fae3551SRodney W. Grimes quit("fseek: %s\n", strerror(errno));
1788fae3551SRodney W. Grimes spcl.c_ddate = 0;
1798fae3551SRodney W. Grimes ITITERATE(i, dtwalk) {
1808fae3551SRodney W. Grimes if (strncmp(fname, dtwalk->dd_name,
1818fae3551SRodney W. Grimes sizeof (dtwalk->dd_name)) != 0)
1828fae3551SRodney W. Grimes continue;
1838fae3551SRodney W. Grimes if (dtwalk->dd_level != level)
1848fae3551SRodney W. Grimes continue;
1858fae3551SRodney W. Grimes goto found;
1868fae3551SRodney W. Grimes }
1878fae3551SRodney W. Grimes /*
1888fae3551SRodney W. Grimes * construct the new upper bound;
1898fae3551SRodney W. Grimes * Enough room has been allocated.
1908fae3551SRodney W. Grimes */
1918fae3551SRodney W. Grimes dtwalk = ddatev[nddates] =
1928fae3551SRodney W. Grimes (struct dumpdates *)calloc(1, sizeof (struct dumpdates));
1938fae3551SRodney W. Grimes nddates += 1;
1948fae3551SRodney W. Grimes found:
1958fae3551SRodney W. Grimes (void) strncpy(dtwalk->dd_name, fname, sizeof (dtwalk->dd_name));
1968fae3551SRodney W. Grimes dtwalk->dd_level = level;
1971c85e6a3SKirk McKusick dtwalk->dd_ddate = _time64_to_time(spcl.c_date);
1988fae3551SRodney W. Grimes
1998fae3551SRodney W. Grimes ITITERATE(i, dtwalk) {
2008fae3551SRodney W. Grimes dumprecout(df, dtwalk);
2018fae3551SRodney W. Grimes }
2028fae3551SRodney W. Grimes if (fflush(df))
2038fae3551SRodney W. Grimes quit("%s: %s\n", dumpdates, strerror(errno));
2048fae3551SRodney W. Grimes if (ftruncate(fd, ftell(df)))
2058fae3551SRodney W. Grimes quit("ftruncate (%s): %s\n", dumpdates, strerror(errno));
2068fae3551SRodney W. Grimes (void) fclose(df);
2075b3817c6SMatthew Dillon if (spcl.c_date == 0) {
2085b3817c6SMatthew Dillon tmsg = "the epoch\n";
2095b3817c6SMatthew Dillon } else {
2101c85e6a3SKirk McKusick time_t t = _time64_to_time(spcl.c_date);
2115b3817c6SMatthew Dillon tmsg = ctime(&t);
2125b3817c6SMatthew Dillon }
213f72ab793SKirk McKusick msg("level %d dump on %s", level, tmsg);
2148fae3551SRodney W. Grimes }
2158fae3551SRodney W. Grimes
2168fae3551SRodney W. Grimes static void
dumprecout(FILE * file,const struct dumpdates * what)2172db673abSWarner Losh dumprecout(FILE *file, const struct dumpdates *what)
2188fae3551SRodney W. Grimes {
2198fae3551SRodney W. Grimes
22023ad9069SKirk McKusick if (strlen(what->dd_name) > DUMPFMTLEN)
22123ad9069SKirk McKusick quit("Name '%s' exceeds DUMPFMTLEN (%d) bytes\n",
22223ad9069SKirk McKusick what->dd_name, DUMPFMTLEN);
22323ad9069SKirk McKusick if (fprintf(file, DUMPOUTFMT, DUMPFMTLEN, what->dd_name,
2242db673abSWarner Losh what->dd_level, ctime(&what->dd_ddate)) < 0)
2258fae3551SRodney W. Grimes quit("%s: %s\n", dumpdates, strerror(errno));
2268fae3551SRodney W. Grimes }
2278fae3551SRodney W. Grimes
2288fae3551SRodney W. Grimes int recno;
2298fae3551SRodney W. Grimes
2308fae3551SRodney W. Grimes static int
getrecord(FILE * df,struct dumpdates * ddatep)2312db673abSWarner Losh getrecord(FILE *df, struct dumpdates *ddatep)
2328fae3551SRodney W. Grimes {
2338fae3551SRodney W. Grimes char tbuf[BUFSIZ];
2348fae3551SRodney W. Grimes
2358fae3551SRodney W. Grimes recno = 0;
2368fae3551SRodney W. Grimes if ( (fgets(tbuf, sizeof (tbuf), df)) != tbuf)
2378fae3551SRodney W. Grimes return(-1);
2388fae3551SRodney W. Grimes recno++;
2398fae3551SRodney W. Grimes if (makedumpdate(ddatep, tbuf) < 0)
2408fae3551SRodney W. Grimes msg("Unknown intermediate format in %s, line %d\n",
2418fae3551SRodney W. Grimes dumpdates, recno);
2428fae3551SRodney W. Grimes
2438fae3551SRodney W. Grimes #ifdef FDEBUG
244f72ab793SKirk McKusick msg("getrecord: %s %d %s", ddatep->dd_name, ddatep->dd_level,
2458fae3551SRodney W. Grimes ddatep->dd_ddate == 0 ? "the epoch\n" : ctime(&ddatep->dd_ddate));
2468fae3551SRodney W. Grimes #endif
2478fae3551SRodney W. Grimes return(0);
2488fae3551SRodney W. Grimes }
2498fae3551SRodney W. Grimes
2508fae3551SRodney W. Grimes static int
makedumpdate(struct dumpdates * ddp,const char * tbuf)2512db673abSWarner Losh makedumpdate(struct dumpdates *ddp, const char *tbuf)
2528fae3551SRodney W. Grimes {
2538fae3551SRodney W. Grimes char un_buf[128];
2548fae3551SRodney W. Grimes
2558fae3551SRodney W. Grimes (void) sscanf(tbuf, DUMPINFMT, ddp->dd_name, &ddp->dd_level, un_buf);
2568fae3551SRodney W. Grimes ddp->dd_ddate = unctime(un_buf);
2578fae3551SRodney W. Grimes if (ddp->dd_ddate < 0)
2588fae3551SRodney W. Grimes return(-1);
2598fae3551SRodney W. Grimes return(0);
2608fae3551SRodney W. Grimes }
261