From ed1fac1d1e69ddd592d995c02c0d042c199ced61 Mon Sep 17 00:00:00 2001 From: gad Date: Mon, 8 Mar 2004 20:02:23 +0000 Subject: Add a check for wtmp records which have invalid values for ut_time. Wtmp records with time==0 get "the time of the last valid record", while records where time goes backwards (compared to the previous record) are skipped. Also prints a message saying how many records were changed or skipped due to these checks. Check was inspired by a simpler check in OpenBSD's version. This is all meant to sidestep problems that Tillman Hodgson noticed with 'ac' when running sparc64 with 64-bit time_t's. The real problem is whatever is creating wtmp records with ut_time==0, of course, but I have not yet figured out what is doing that. Reviewed by: no screams from freebsd-sparc64 or bde MFC after: 2 weeks --- usr.sbin/ac/ac.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 12 deletions(-) (limited to 'usr.sbin/ac/ac.c') diff --git a/usr.sbin/ac/ac.c b/usr.sbin/ac/ac.c index c562e4f..031099a 100644 --- a/usr.sbin/ac/ac.c +++ b/usr.sbin/ac/ac.c @@ -510,21 +510,65 @@ ac(FILE *fp) struct utmp_list *lp, *head = NULL; struct utmp usr; struct tm *ltm; - time_t secs; - int day = -1; + time_t prev_secs, secs, ut_timecopy; + int day, rfound, tchanged, tskipped; + day = -1; + prev_secs = 1; /* Minimum acceptable date == 1970 */ + rfound = tchanged = tskipped = 0; + secs = 0; while (fread((char *)&usr, sizeof(usr), 1, fp) == 1) { + rfound++; + /* + * The type of utmp.ut_time is not necessary type time_t, as + * it is explicitly defined as type int32_t. Copy the value + * for platforms where sizeof(time_t) != size(int32_t). + */ + ut_timecopy = _time32_to_time(usr.ut_time); + /* + * With sparc64 using 64-bit time_t's, there is some system + * routine which sets ut_time==0 (the high-order word of a + * 64-bit time) instead of a 32-bit time value. For those + * wtmp files, it is "more-accurate" to substitute the most- + * recent time found, instead of throwing away the entire + * record. While it is still just a guess, it is a better + * guess than throwing away a log-off record and therefore + * counting a session as if it continued to the end of the + * month, or the next system-reboot. + */ + if (ut_timecopy == 0 && prev_secs > 1) { +#ifdef DEBUG + if (Debug) + printf("%s - date changed to: %s", + debug_pfx(&usr, &usr), ctime(&prev_secs)); +#endif + tchanged++; + usr.ut_time = ut_timecopy = prev_secs; + } + /* + * Skip records where the time goes backwards. + */ + if (ut_timecopy < prev_secs) { +#ifdef DEBUG + if (Debug) + printf("%s - bad date, record skipped\n", + debug_pfx(&usr, &usr)); +#endif + tskipped++; + continue; /* Skip this invalid record. */ + } + prev_secs = ut_timecopy; + if (!FirstTime) - FirstTime = usr.ut_time; + FirstTime = ut_timecopy; if (Flags & AC_D) { - time_t t = _int_to_time(usr.ut_time); - ltm = localtime(&t); + ltm = localtime(&ut_timecopy); if (day >= 0 && day != ltm->tm_yday) { day = ltm->tm_yday; /* * print yesterday's total */ - secs = usr.ut_time; + secs = ut_timecopy; secs -= ltm->tm_sec; secs -= 60 * ltm->tm_min; secs -= 3600 * ltm->tm_hour; @@ -534,10 +578,10 @@ ac(FILE *fp) } switch(*usr.ut_line) { case '|': - secs = usr.ut_time; + secs = ut_timecopy; break; case '{': - secs -= usr.ut_time; + secs -= ut_timecopy; /* * adjust time for those logged in */ @@ -546,7 +590,7 @@ ac(FILE *fp) break; case '~': /* reboot or shutdown */ head = log_out(head, &usr); - FirstTime = usr.ut_time; /* shouldn't be needed */ + FirstTime = ut_timecopy; /* shouldn't be needed */ break; default: /* @@ -575,13 +619,13 @@ ac(FILE *fp) (void)strcpy(usr.ut_line, "~"); if (Flags & AC_D) { - time_t t = _int_to_time(usr.ut_time); - ltm = localtime(&t); + ut_timecopy = _time32_to_time(usr.ut_time); + ltm = localtime(&ut_timecopy); if (day >= 0 && day != ltm->tm_yday) { /* * print yesterday's total */ - secs = usr.ut_time; + secs = ut_timecopy; secs -= ltm->tm_sec; secs -= 60 * ltm->tm_min; secs -= 3600 * ltm->tm_hour; @@ -600,6 +644,14 @@ ac(FILE *fp) show_users(Users); show("total", Total); } + + if (tskipped > 0) + printf("(Skipped %d of %d records due to invalid time values)\n", + tskipped, rfound); + if (tchanged > 0) + printf("(Changed %d of %d records to have a more likely time value)\n", + tchanged, rfound); + return 0; } -- cgit v1.1