Index: ac.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/ac/ac.c,v retrieving revision 1.27 diff -u -r1.27 ac.c --- ac.c 3 Mar 2004 02:44:52 -0000 1.27 +++ ac.c 8 Mar 2004 07:36:23 -0000 @@ -83,6 +83,9 @@ int main(int, char **); int ac(FILE *); struct tty_list *add_tty(char *); +#ifdef DEBUG +const char *debug_pfx(const struct utmp *, const struct utmp *); +#endif int do_tty(char *); FILE *file(const char *); struct utmp_list *log_in(struct utmp_list *, struct utmp *); @@ -208,6 +211,72 @@ return up; } +#ifdef DEBUG +/* + * Create a string which is the standard prefix for a debug line. It + * includes a timestamp (perhaps with year), device-name, and user-name. + */ +const char * +debug_pfx(const struct utmp *event_up, const struct utmp *dev_up) +{ + static char str_result[40+UT_LINESIZE+UT_NAMESIZE]; + static char thisyear[5]; + size_t maxcopy; + time_t ut_timecopy; + + if (thisyear[0] == '\0') { + /* Figure out what "this year" is. */ + time(&ut_timecopy); + strlcpy(str_result, ctime(&ut_timecopy), sizeof(str_result)); + strlcpy(thisyear, &str_result[20], sizeof(thisyear)); + } + + if (event_up->ut_time == 0) + strlcpy(str_result, "*ZeroTime* --:--:-- ", sizeof(str_result)); + else { + /* + * 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) != sizeof(int32_t). + */ + ut_timecopy = _time32_to_time(event_up->ut_time); + strlcpy(str_result, ctime(&ut_timecopy), sizeof(str_result)); + /* + * Include the year, if it is not the same year as "now". + */ + if (strncmp(&str_result[20], thisyear, 4) == 0) + str_result[20] = '\0'; + else { + str_result[24] = ' '; /* Replace a '\n' */ + str_result[25] = '\0'; + } + } + + if (dev_up->ut_line[0] == '\0') + strlcat(str_result, "NoDev", sizeof(str_result)); + else { + /* ut_line is not necessarily null-terminated. */ + maxcopy = strlen(str_result) + UT_LINESIZE + 1; + if (maxcopy > sizeof(str_result)) + maxcopy = sizeof(str_result); + strlcat(str_result, dev_up->ut_line, maxcopy); + } + strlcat(str_result, ": ", sizeof(str_result)); + + if (dev_up->ut_name[0] == '\0') + strlcat(str_result, "LogOff", sizeof(str_result)); + else { + /* ut_name is not necessarily null-terminated. */ + maxcopy = strlen(str_result) + UT_NAMESIZE + 1; + if (maxcopy > sizeof(str_result)) + maxcopy = sizeof(str_result); + strlcat(str_result, dev_up->ut_name, maxcopy); + } + + return (str_result); +} +#endif + int main(int argc, char *argv[]) { @@ -346,11 +415,10 @@ Users = update_user(Users, lp->usr.ut_name, secs); #ifdef DEBUG if (Debug) - printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n", - 19, ctime(&up->ut_time), - sizeof (lp->usr.ut_line), lp->usr.ut_line, - sizeof (lp->usr.ut_name), lp->usr.ut_name, - secs / 3600, (secs % 3600) / 60, secs % 60); + printf("%s logged out (%2d:%02d:%02d)\n", + debug_pfx(up, &lp->usr), (int)(secs / 3600), + (int)((secs % 3600) / 60), + (int)(secs % 60)); #endif /* * now lose it @@ -426,11 +494,10 @@ memmove((char *)&lp->usr, (char *)up, sizeof (struct utmp)); #ifdef DEBUG if (Debug) { - printf("%-.*s %-.*s: %-.*s logged in", 19, - ctime(&lp->usr.ut_time), sizeof (up->ut_line), - up->ut_line, sizeof (up->ut_name), up->ut_name); + printf("%s logged in", debug_pfx(&lp->usr, up)); if (*up->ut_host) - printf(" (%-.*s)", sizeof (up->ut_host), up->ut_host); + printf(" (%-.*s)", (int)sizeof(up->ut_host), + up->ut_host); putchar('\n'); } #endif @@ -443,21 +510,66 @@ 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, + * 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); + /* + * When sparc64 went to 64-bit time_t's, there was some + * routine which saved ut_time==0 (the high-order word) + * instead of the real time. For those wtmp files, it + * was found to be "more-accurate" to substitute the + * most-recent time found, instead of throwing away + * the record. It is still just a guess, but it is a + * better guess than (for instance) throwing away some + * log-off record, and thus charging someone as if they + * remained logged on until the next reboot or the end + * of the month. + */ + 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; @@ -467,10 +579,10 @@ } 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 */ @@ -479,7 +591,7 @@ 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: /* @@ -491,6 +603,12 @@ strchr("pqrsPQRS", usr.ut_line[3]) != 0 || *usr.ut_host != '\0') head = log_in(head, &usr); +#ifdef DEBUG + else if (Debug > 1) + /* Things such as 'screen' sessions. */ + printf("%s ignored\n", + debug_pfx(&usr, &usr)); +#endif } else head = log_out(head, &usr); break; @@ -502,13 +620,13 @@ (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; @@ -527,6 +645,14 @@ 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; }