2 * Copyright (c) 1996 Joerg Wunsch
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: src/tools/3.0-upgrade/cvt-wtmp.c,v 1.6 1999/08/28 00:54:20 peter Exp $
27 * $DragonFly: src/tools/3.0-upgrade/Attic/cvt-wtmp.c,v 1.2 2003/06/17 04:29:10 dillon Exp $
32 * Heuristics to convert old wtmp format to new one.
35 #include <sys/types.h>
49 #define OUT_NAMESIZE 8
50 #define OUT_LINESIZE 8
51 #define OUT_HOSTSIZE 16
55 char ll_line[OUT_LINESIZE];
56 char ll_host[OUT_HOSTSIZE];
60 char ut_line[OUT_LINESIZE];
61 char ut_name[OUT_NAMESIZE];
62 char ut_host[OUT_HOSTSIZE];
67 void convert(const char *, int, int);
70 * NB: We cannot convert lastlog yet, but we don't need either.
76 errx(EX_USAGE, "usage: cvt-wtmp [-f] [-n] /var/log/wtmp*");
81 main(int argc, char **argv)
83 int errs, i, nflag, forceflag, rv;
85 errs = nflag = forceflag = 0;
86 while ((i = getopt(argc, argv, "fn")) != -1)
103 if (argc <= 0 || errs)
106 for (;argc > 0; argc--, argv++)
107 convert(*argv, nflag, forceflag);
113 convert(const char *name, int nflag, int forceflag)
116 struct timeval tv[2];
117 char xname[1024], yname[1024];
118 unsigned char buf[128]; /* large enough to hold one wtmp record */
120 size_t off, shouldbe;
122 time_t now, early, *t;
126 enum { OLD, NEW } which = OLD; /* what we're defaulting to */
128 if (stat(name, &sb) == -1)
130 warn("Cannot stat file \"%s\", continuing.", name);
135 /* some point in time very early, before 386BSD 0.0 */
136 tm.tm_sec = 0; tm.tm_min = 0; tm.tm_hour = 0;
137 tm.tm_mday = 1; tm.tm_mon = 2; tm.tm_year = 92;
141 tv[0].tv_sec = sb.st_atimespec.tv_sec;
142 tv[0].tv_usec = sb.st_atimespec.tv_nsec / 1000;
143 tv[1].tv_sec = sb.st_mtimespec.tv_sec;
144 tv[1].tv_usec = sb.st_mtimespec.tv_nsec / 1000;
146 /* unzipping is handled best externally */
147 if (strlen(name) > 3 && memcmp(&name[strlen(name) - 3], ".gz", 3) == 0)
149 warnx("Cannot handle gzipped files, ignoring \"%s\".", name);
153 (void) snprintf(xname, sizeof xname, "%s.new", name);
154 if (!nflag && (fd1 = open(xname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
155 err(EX_CANTCREAT, "Can't create new wtmp file");
157 if ((fd2 = open(name, O_RDONLY, 0)) == -1)
158 err(EX_UNAVAILABLE, "input file magically disappeared, i'm confused");
160 old = new = 0; off = 0;
161 memset(buf, 0, sizeof buf);
163 while (read(fd2, &buf[off], sizeof(time_t)) == sizeof(time_t))
165 t = (time_t *)&buf[off];
166 off += sizeof(time_t);
167 if (off < sizeof(struct outmp))
170 if (*t < early || *t > now)
172 /* unreasonable, collect another entry */
173 if (off > sizeof buf)
177 (void) unlink(xname);
178 errx(EX_UNAVAILABLE, "I can't seem to make sense out of file \"%s\",\n"
179 "Could have forced using -f.",
184 warnx("Record # %d in file \"%s\" seems bogus\n"
185 "(time: %d, previous time: %d, now: %d),\n"
186 "continuing anyway.",
187 old + new + 1, name, *t, early, now);
190 (void)lseek(fd2, sizeof(struct utmp) - sizeof buf, SEEK_CUR);
195 (void)lseek(fd2, sizeof(struct outmp) - sizeof buf, SEEK_CUR);
202 /* time is reasonable, we seem to have collected a full entry */
203 if (off == sizeof(struct utmp))
205 /* new wtmp record */
211 if (write(fd1, buf, sizeof(struct utmp)) != sizeof(struct utmp))
212 err(EX_IOERR, "writing file \"%s\"", xname);
215 else if (off == sizeof(struct outmp))
223 ou = (struct outmp *)buf;
224 memset(&u, 0, sizeof u);
225 memcpy(&u.ut_line, ou->ut_line, OUT_LINESIZE);
226 memcpy(&u.ut_name, ou->ut_name, OUT_NAMESIZE);
227 memcpy(&u.ut_host, ou->ut_host, OUT_HOSTSIZE);
228 memcpy(&u.ut_time, &ou->ut_time, sizeof u.ut_time);
229 if (write(fd1, &u, sizeof(struct utmp)) != sizeof(struct utmp))
230 err(EX_IOERR, "writing file \"%s\"", xname);
237 warnx("Illegal record in file \"%s\", ignoring.", name);
243 warnx("Illegal record in file \"%s\", considering it %s one.",
244 name, (which == OLD? "an old": "a new"));
245 shouldbe = (which == OLD? sizeof(struct outmp): sizeof(struct utmp));
247 (void)read(fd2, &buf[off], shouldbe - off);
249 (void)lseek(fd2, shouldbe - off, SEEK_CUR);
258 * Since the wtmp file is in chronologically acsending order, we
259 * can move the `early' time as we go. Allow for one hour
260 * time-of-day adjustments.
263 memset(buf, 0, sizeof buf);
267 printf("File \"%s\": %d old and %d new records found.\n",
274 (void) snprintf(yname, sizeof yname, "%s.bak", name);
276 if (rename(name, yname) == -1)
277 err(EX_OSERR, "Cannot rename \"%s\" to \"%s\"", name, yname);
279 if (rename(xname, name) == -1)
280 err(EX_OSERR, "Cannot rename \"%s\" to \"%s\"", xname, name);
282 if (utimes(name, tv) == -1)
283 warn("Cannot adjust access and modification times for \"%s\"", name);