summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ac/ac.c
diff options
context:
space:
mode:
authorgad <gad@FreeBSD.org>2004-03-08 20:02:23 +0000
committergad <gad@FreeBSD.org>2004-03-08 20:02:23 +0000
commited1fac1d1e69ddd592d995c02c0d042c199ced61 (patch)
tree45a0ec4843ed07ece88e3810f00def5ede45e169 /usr.sbin/ac/ac.c
parente7d237f567f13bd1c2a97b48e9d7dce0049b9a69 (diff)
downloadFreeBSD-src-ed1fac1d1e69ddd592d995c02c0d042c199ced61.zip
FreeBSD-src-ed1fac1d1e69ddd592d995c02c0d042c199ced61.tar.gz
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
Diffstat (limited to 'usr.sbin/ac/ac.c')
-rw-r--r--usr.sbin/ac/ac.c76
1 files changed, 64 insertions, 12 deletions
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;
}
OpenPOWER on IntegriCloud