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