diff options
author | ed <ed@FreeBSD.org> | 2012-08-30 16:45:27 +0000 |
---|---|---|
committer | ed <ed@FreeBSD.org> | 2012-08-30 16:45:27 +0000 |
commit | 88b1307252e748c6e3141597c928606a9a776df1 (patch) | |
tree | 69b360b84bc7b6c2a4c7473a7b81482d1979609e /usr.sbin | |
parent | d3cf18fd76410d0b05ef27bc3acf7efe9bb388a8 (diff) | |
download | FreeBSD-src-88b1307252e748c6e3141597c928606a9a776df1.zip FreeBSD-src-88b1307252e748c6e3141597c928606a9a776df1.tar.gz |
Massively refactor ac(8).
- Use queue(3) -- not some homegrown implementation of linked lists.
- Rename structures to _entry, as they are entries in the linked list --
not the lists themselves.
- Don't store entire copies of struct utmpx in utmpx_entry, but only the
members we're interested in. Large fields such as hostnames are not
needed during the execution of the program.
- Give structure members useful names, instead of `name'.
- While there, use struct timevals instead of time_t's internally. This
is not strictly useful, but while we're at it...
- Mark stuff static.
- Add missing const keywords.
- Remove unneeded prototypes.
- Remove workaround for sparc64-specific utmp problems. These don't
apply to utmpx.
- Don't discard entries when timestamps are not monotone. This shouldn't
ever happen with utmpx, but discarding them is a bit too harsh.
- Remove debug code. We nowadays have `getent utmpx', which can be used
to analyze logfiles in depth.
- Use proper uppercasing/periods in comments.
- Print output of `ac -p' sorted alphabetically, instead of first
occurrence.
- Properly check against pts/* instead of tty[PQRSpqrs]* to determine
whether a TTY is a pseudo-terminal.
MFC after: 1 month
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/ac/Makefile | 5 | ||||
-rw-r--r-- | usr.sbin/ac/ac.c | 500 |
2 files changed, 189 insertions, 316 deletions
diff --git a/usr.sbin/ac/Makefile b/usr.sbin/ac/Makefile index 576dbb3..0fac2fb 100644 --- a/usr.sbin/ac/Makefile +++ b/usr.sbin/ac/Makefile @@ -3,11 +3,6 @@ PROG= ac MAN= ac.8 -# Temporary, while tracking down problem wrt 64-bit time_t's on sparc64 -.if ${MACHINE_CPUARCH} == "sparc64" -CFLAGS+=-DDEBUG -.endif - # If "CONSOLE_TTY" is not defined, this program is compatible with the # traditional implementation (using SunOS 4.x as the sample traditional # implementation). This is the default. diff --git a/usr.sbin/ac/ac.c b/usr.sbin/ac/ac.c index bcbf534..1e2c54b 100644 --- a/usr.sbin/ac/ac.c +++ b/usr.sbin/ac/ac.c @@ -16,8 +16,9 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/types.h> +#include <sys/queue.h> #include <sys/time.h> + #include <err.h> #include <errno.h> #include <langinfo.h> @@ -32,43 +33,47 @@ __FBSDID("$FreeBSD$"); /* * this is for our list of currently logged in sessions */ -struct utmp_list { - struct utmp_list *next; - struct utmpx usr; +struct utmpx_entry { + SLIST_ENTRY(utmpx_entry) next; + char user[sizeof(((struct utmpx *)0)->ut_user)]; + char id[sizeof(((struct utmpx *)0)->ut_id)]; +#ifdef CONSOLE_TTY + char line[sizeof(((struct utmpx *)0)->ut_line)]; +#endif + struct timeval time; }; /* * this is for our list of users that are accumulating time. */ -struct user_list { - struct user_list *next; - char name[sizeof(((struct utmpx *)0)->ut_user)]; - time_t secs; +struct user_entry { + SLIST_ENTRY(user_entry) next; + char user[sizeof(((struct utmpx *)0)->ut_user)]; + struct timeval time; }; /* * this is for chosing whether to ignore a login */ -struct tty_list { - struct tty_list *next; - char name[sizeof(((struct utmpx *)0)->ut_host) + 2]; - size_t len; - int ret; +struct tty_entry { + SLIST_ENTRY(tty_entry) next; + char line[sizeof(((struct utmpx *)0)->ut_line) + 2]; + size_t len; + int ret; }; /* * globals - yes yuk */ #ifdef CONSOLE_TTY -static char *Console = CONSOLE_TTY; +static const char *Console = CONSOLE_TTY; #endif -static time_t Total = 0; -static time_t FirstTime = 0; +static struct timeval Total = { 0, 0 }; +static struct timeval FirstTime = { 0, 0 }; static int Flags = 0; -static struct user_list *Users = NULL; -static struct tty_list *Ttys = NULL; - -#define NEW(type) (type *)malloc(sizeof (type)) +static SLIST_HEAD(, utmpx_entry) CurUtmpx = SLIST_HEAD_INITIALIZER(CurUtmpx); +static SLIST_HEAD(, user_entry) Users = SLIST_HEAD_INITIALIZER(Users); +static SLIST_HEAD(, tty_entry) Ttys = SLIST_HEAD_INITIALIZER(Ttys); #define AC_W 1 /* not _PATH_WTMP */ #define AC_D 2 /* daily totals (ignore -p) */ @@ -76,182 +81,112 @@ static struct tty_list *Ttys = NULL; #define AC_U 8 /* specified users only */ #define AC_T 16 /* specified ttys only */ -#ifdef DEBUG -static int Debug = 0; -#endif +static void ac(const char *); +static void usage(void); -int main(int, char **); -int ac(const char *); -struct tty_list *add_tty(char *); -#ifdef DEBUG -const char *debug_pfx(const struct utmpx *, const struct utmpx *); -#endif -int do_tty(char *); -struct utmp_list *log_in(struct utmp_list *, struct utmpx *); -struct utmp_list *log_out(struct utmp_list *, struct utmpx *); -int on_console(struct utmp_list *); -void show(const char *, time_t); -void show_today(struct user_list *, struct utmp_list *, - time_t); -void show_users(struct user_list *); -struct user_list *update_user(struct user_list *, char *, time_t); -void usage(void); - -struct tty_list * -add_tty(char *name) +static void +add_tty(const char *line) { - struct tty_list *tp; + struct tty_entry *tp; char *rcp; Flags |= AC_T; - if ((tp = NEW(struct tty_list)) == NULL) + if ((tp = malloc(sizeof(*tp))) == NULL) errx(1, "malloc failed"); tp->len = 0; /* full match */ tp->ret = 1; /* do if match */ - if (*name == '!') { /* don't do if match */ + if (*line == '!') { /* don't do if match */ tp->ret = 0; - name++; + line++; } - strlcpy(tp->name, name, sizeof (tp->name)); - if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */ + strlcpy(tp->line, line, sizeof(tp->line)); + /* Wildcard. */ + if ((rcp = strchr(tp->line, '*')) != NULL) { *rcp = '\0'; - tp->len = strlen(tp->name); /* match len bytes only */ + /* Match len bytes only. */ + tp->len = strlen(tp->line); } - tp->next = Ttys; - Ttys = tp; - return Ttys; + SLIST_INSERT_HEAD(&Ttys, tp, next); } /* * should we process the named tty? */ -int -do_tty(char *name) +static int +do_tty(const char *line) { - struct tty_list *tp; + struct tty_entry *tp; int def_ret = 0; - for (tp = Ttys; tp != NULL; tp = tp->next) { + SLIST_FOREACH(tp, &Ttys, next) { if (tp->ret == 0) /* specific don't */ def_ret = 1; /* default do */ if (tp->len != 0) { - if (strncmp(name, tp->name, tp->len) == 0) + if (strncmp(line, tp->line, tp->len) == 0) return tp->ret; } else { - if (strncmp(name, tp->name, sizeof (tp->name)) == 0) + if (strncmp(line, tp->line, sizeof(tp->line)) == 0) return tp->ret; } } - return def_ret; + return (def_ret); } #ifdef CONSOLE_TTY /* * is someone logged in on Console? */ -int -on_console(struct utmp_list *head) +static int +on_console(void) { - struct utmp_list *up; + struct utmpx_entry *up; - for (up = head; up; up = up->next) { - if (strcmp(up->usr.ut_line, Console) == 0) - return 1; - } - return 0; + SLIST_FOREACH(up, &CurUtmpx, next) + if (strcmp(up->line, Console) == 0) + return (1); + return (0); } #endif /* - * update user's login time + * Update user's login time. + * If no entry for this user is found, a new entry is inserted into the + * list alphabetically. */ -struct user_list * -update_user(struct user_list *head, char *name, time_t secs) +static void +update_user(const char *user, struct timeval secs) { - struct user_list *up; + struct user_entry *up, *aup; + int c; - for (up = head; up != NULL; up = up->next) { - if (strcmp(up->name, name) == 0) { - up->secs += secs; - Total += secs; - return head; - } + aup = NULL; + SLIST_FOREACH(up, &Users, next) { + c = strcmp(up->user, user); + if (c == 0) { + timeradd(&up->time, &secs, &up->time); + timeradd(&Total, &secs, &Total); + return; + } else if (c > 0) + break; + aup = up; } /* * not found so add new user unless specified users only */ if (Flags & AC_U) - return head; + return; - if ((up = NEW(struct user_list)) == NULL) + if ((up = malloc(sizeof(*up))) == NULL) errx(1, "malloc failed"); - up->next = head; - strlcpy(up->name, name, sizeof (up->name)); - up->secs = secs; - Total += secs; - 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 utmpx *event_up, const struct utmpx *userinf_up) -{ - static char str_result[40 + sizeof(userinf_up->ut_line) + - sizeof(userinf_up->ut_user)]; - 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_tv.tv_sec == 0) - strlcpy(str_result, "*ZeroTime* --:--:-- ", sizeof(str_result)); - else { - ut_timecopy = event_up->ut_tv.tv_sec; - 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 (userinf_up->ut_line[0] == '\0') - strlcat(str_result, "NoDev", sizeof(str_result)); - else { - maxcopy = strlen(str_result) + sizeof(userinf_up->ut_line); - if (maxcopy > sizeof(str_result)) - maxcopy = sizeof(str_result); - strlcat(str_result, userinf_up->ut_line, maxcopy); - } - strlcat(str_result, ": ", sizeof(str_result)); - - if (userinf_up->ut_user[0] == '\0') - strlcat(str_result, "LogOff", sizeof(str_result)); - else { - maxcopy = strlen(str_result) + sizeof(userinf_up->ut_user); - if (maxcopy > sizeof(str_result)) - maxcopy = sizeof(str_result); - strlcat(str_result, userinf_up->ut_user, maxcopy); - } - - return (str_result); + if (aup == NULL) + SLIST_INSERT_HEAD(&Users, up, next); + else + SLIST_INSERT_AFTER(aup, up, next); + strlcpy(up->user, user, sizeof(up->user)); + up->time = secs; + timeradd(&Total, &secs, &Total); } -#endif int main(int argc, char *argv[]) @@ -261,13 +196,8 @@ main(int argc, char *argv[]) (void) setlocale(LC_TIME, ""); - while ((c = getopt(argc, argv, "Dc:dpt:w:")) != -1) { + while ((c = getopt(argc, argv, "c:dpt:w:")) != -1) { switch (c) { -#ifdef DEBUG - case 'D': - Debug++; - break; -#endif case 'c': #ifdef CONSOLE_TTY Console = optarg; @@ -299,7 +229,7 @@ main(int argc, char *argv[]) * initialize user list */ for (; optind < argc; optind++) { - Users = update_user(Users, argv[optind], (time_t)0); + update_user(argv[optind], (struct timeval){ 0, 0 }); } Flags |= AC_U; /* freeze user list */ } @@ -307,112 +237,108 @@ main(int argc, char *argv[]) Flags &= ~AC_P; ac(wtmpf); - return 0; + return (0); } /* * print login time in decimal hours */ -void -show(const char *name, time_t secs) +static void +show(const char *user, struct timeval secs) { (void)printf("\t%-*s %8.2f\n", - (int)sizeof(((struct utmpx *)0)->ut_user), name, - ((double)secs / 3600)); + (int)sizeof(((struct user_entry *)0)->user), user, + (double)secs.tv_sec / 3600); } -void -show_users(struct user_list *list) +static void +show_users(void) { - struct user_list *lp; + struct user_entry *lp; - for (lp = list; lp; lp = lp->next) - show(lp->name, lp->secs); + SLIST_FOREACH(lp, &Users, next) + show(lp->user, lp->time); } /* * print total login time for 24hr period in decimal hours */ -void -show_today(struct user_list *users, struct utmp_list *logins, time_t secs) +static void +show_today(struct timeval today) { - struct user_list *up; - struct utmp_list *lp; + struct user_entry *up; + struct utmpx_entry *lp; char date[64]; - time_t yesterday = secs - 1; + struct timeval usec = { 0, 1 }; + struct timeval yesterday; static int d_first = -1; if (d_first < 0) d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); - (void)strftime(date, sizeof (date), + timersub(&today, &usec, &yesterday); + (void)strftime(date, sizeof(date), d_first ? "%e %b total" : "%b %e total", - localtime(&yesterday)); + localtime(&yesterday.tv_sec)); /* restore the missing second */ - yesterday++; + timeradd(&today, &usec, &yesterday); - for (lp = logins; lp != NULL; lp = lp->next) { - secs = yesterday - lp->usr.ut_tv.tv_sec; - Users = update_user(Users, lp->usr.ut_user, secs); - lp->usr.ut_tv.tv_sec = yesterday; /* as if they just logged in */ + SLIST_FOREACH(lp, &CurUtmpx, next) { + timersub(&yesterday, &lp->time, &today); + update_user(lp->user, today); + /* As if they just logged in. */ + lp->time = yesterday; } - secs = 0; - for (up = users; up != NULL; up = up->next) { - secs += up->secs; - up->secs = 0; /* for next day */ + timerclear(&today); + SLIST_FOREACH(up, &Users, next) { + timeradd(&today, &up->time, &today); + /* For next day. */ + timerclear(&up->time); } - if (secs) - (void)printf("%s %11.2f\n", date, ((double)secs / 3600)); + if (timerisset(&today)) + (void)printf("%s %11.2f\n", date, (double)today.tv_sec / 3600); } /* - * log a user out and update their times. - * if ut_line is "~", we log all users out as the system has - * been shut down. + * Log a user out and update their times. + * If ut_type is BOOT_TIME or SHUTDOWN_TIME, we log all users out as the + * system has been shut down. */ -struct utmp_list * -log_out(struct utmp_list *head, struct utmpx *up) +static void +log_out(const struct utmpx *up) { - struct utmp_list *lp, *lp2, *tlp; - time_t secs; + struct utmpx_entry *lp, *lp2, *tlp; + struct timeval secs; - for (lp = head, lp2 = NULL; lp != NULL; ) + for (lp = SLIST_FIRST(&CurUtmpx), lp2 = NULL; lp != NULL;) if (up->ut_type == BOOT_TIME || up->ut_type == SHUTDOWN_TIME || (up->ut_type == DEAD_PROCESS && - memcmp(lp->usr.ut_id, up->ut_id, sizeof up->ut_id) == 0)) { - secs = up->ut_tv.tv_sec - lp->usr.ut_tv.tv_sec; - Users = update_user(Users, lp->usr.ut_user, secs); -#ifdef DEBUG - if (Debug) - printf("%s logged out (%2d:%02d:%02d)\n", - debug_pfx(up, &lp->usr), (int)(secs / 3600), - (int)((secs % 3600) / 60), - (int)(secs % 60)); -#endif + memcmp(lp->id, up->ut_id, sizeof(up->ut_id)) == 0)) { + timersub(&up->ut_tv, &lp->time, &secs); + update_user(lp->user, secs); /* * now lose it */ tlp = lp; - lp = lp->next; - if (tlp == head) - head = lp; - else if (lp2 != NULL) - lp2->next = lp; + lp = SLIST_NEXT(lp, next); + if (lp2 == NULL) + SLIST_REMOVE_HEAD(&CurUtmpx, next); + else + SLIST_REMOVE_AFTER(lp2, next); free(tlp); } else { lp2 = lp; - lp = lp->next; + lp = SLIST_NEXT(lp, next); } - return head; } /* * if do_tty says ok, login a user */ -struct utmp_list * -log_in(struct utmp_list *head, struct utmpx *up) +static void +log_in(struct utmpx *up) { - struct utmp_list *lp; + struct utmpx_entry *lp; /* * this could be a login. if we're not dealing with @@ -431,198 +357,150 @@ log_in(struct utmp_list *head, struct utmpx *up) * SunOS 4.0.2 does not treat ":0.0" as special but we * do. */ - if (on_console(head)) - return head; + if (on_console()) + return; /* * ok, no recorded login, so they were here when wtmp * started! Adjust ut_time! */ - up->ut_time = FirstTime; + up->ut_tv = FirstTime; /* * this allows us to pick the right logout */ - strlcpy(up->ut_line, Console, sizeof (up->ut_line)); + strlcpy(up->ut_line, Console, sizeof(up->ut_line)); } #endif /* * If we are doing specified ttys only, we ignore * anything else. */ - if (Flags & AC_T) - if (!do_tty(up->ut_line)) - return head; + if (Flags & AC_T && !do_tty(up->ut_line)) + return; /* * go ahead and log them in */ - if ((lp = NEW(struct utmp_list)) == NULL) + if ((lp = malloc(sizeof(*lp))) == NULL) errx(1, "malloc failed"); - lp->next = head; - head = lp; - memmove(&lp->usr, up, sizeof *up); -#ifdef DEBUG - if (Debug) { - printf("%s logged in", debug_pfx(&lp->usr, up)); - if (*up->ut_host) - printf(" (%-.*s)", (int)sizeof(up->ut_host), - up->ut_host); - putchar('\n'); - } + SLIST_INSERT_HEAD(&CurUtmpx, lp, next); + strlcpy(lp->user, up->ut_user, sizeof(lp->user)); + memcpy(lp->id, up->ut_id, sizeof(lp->id)); +#ifdef CONSOLE_TTY + memcpy(lp->line, up->ut_line, sizeof(lp->line)); #endif - return head; + lp->time = up->ut_tv; } -int +static void ac(const char *file) { - struct utmp_list *lp, *head = NULL; + struct utmpx_entry *lp; struct utmpx *usr, usht; struct tm *ltm; - time_t prev_secs, secs, ut_timecopy; - int day, rfound, tchanged, tskipped; + struct timeval prev_secs, ut_timecopy, secs, clock_shift, now; + int day, rfound; day = -1; - prev_secs = 1; /* Minimum acceptable date == 1970 */ - rfound = tchanged = tskipped = 0; - secs = 0; + timerclear(&prev_secs); /* Minimum acceptable date == 1970. */ + timerclear(&secs); + timerclear(&clock_shift); + rfound = 0; if (setutxdb(UTXDB_LOG, file) != 0) err(1, "%s", file); while ((usr = getutxent()) != NULL) { rfound++; - ut_timecopy = usr->ut_tv.tv_sec; - /* - * 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_tv.tv_sec = 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. */ - } + ut_timecopy = usr->ut_tv; + /* Don't let the time run backwards. */ + if (timercmp(&ut_timecopy, &prev_secs, <)) + ut_timecopy = prev_secs; prev_secs = ut_timecopy; - if (!FirstTime) + if (!timerisset(&FirstTime)) FirstTime = ut_timecopy; if (Flags & AC_D) { - ltm = localtime(&ut_timecopy); + ltm = localtime(&ut_timecopy.tv_sec); if (day >= 0 && day != ltm->tm_yday) { day = ltm->tm_yday; /* * print yesterday's total */ secs = ut_timecopy; - secs -= ltm->tm_sec; - secs -= 60 * ltm->tm_min; - secs -= 3600 * ltm->tm_hour; - show_today(Users, head, secs); + secs.tv_sec -= ltm->tm_sec; + secs.tv_sec -= 60 * ltm->tm_min; + secs.tv_sec -= 3600 * ltm->tm_hour; + secs.tv_usec = 0; + show_today(secs); } else day = ltm->tm_yday; } switch(usr->ut_type) { case OLD_TIME: - secs = ut_timecopy; + clock_shift = ut_timecopy; break; case NEW_TIME: - secs -= ut_timecopy; + timersub(&clock_shift, &ut_timecopy, &clock_shift); /* * adjust time for those logged in */ - for (lp = head; lp != NULL; lp = lp->next) - lp->usr.ut_tv.tv_sec -= secs; + SLIST_FOREACH(lp, &CurUtmpx, next) + timersub(&lp->time, &clock_shift, &lp->time); break; case BOOT_TIME: case SHUTDOWN_TIME: - head = log_out(head, usr); + log_out(usr); FirstTime = ut_timecopy; /* shouldn't be needed */ break; case USER_PROCESS: /* - * if they came in on tty[p-sP-S]*, then it is only - * a login session if the ut_host field is non-empty + * If they came in on pts/..., then it is only + * a login session if the ut_host field is non-empty. */ - if (strncmp(usr->ut_line, "tty", 3) != 0 || - strchr("pqrsPQRS", usr->ut_line[3]) == NULL || + if (strncmp(usr->ut_line, "pts/", 4) != 0 || *usr->ut_host != '\0') - head = log_in(head, usr); -#ifdef DEBUG - else if (Debug > 1) - /* Things such as 'screen' sessions. */ - printf("%s - record ignored\n", - debug_pfx(usr, usr)); -#endif + log_in(usr); break; case DEAD_PROCESS: - head = log_out(head, usr); + log_out(usr); break; } } endutxent(); - if (!(Flags & AC_W)) - usht.ut_tv.tv_sec = time(NULL); + (void)gettimeofday(&now, NULL); + if (Flags & AC_W) + usht.ut_tv = ut_timecopy; else - usht.ut_tv.tv_sec = ut_timecopy; + usht.ut_tv = now; usht.ut_type = SHUTDOWN_TIME; if (Flags & AC_D) { - ltm = localtime(&ut_timecopy); + ltm = localtime(&ut_timecopy.tv_sec); if (day >= 0 && day != ltm->tm_yday) { /* * print yesterday's total */ secs = ut_timecopy; - secs -= ltm->tm_sec; - secs -= 60 * ltm->tm_min; - secs -= 3600 * ltm->tm_hour; - show_today(Users, head, secs); + secs.tv_sec -= ltm->tm_sec; + secs.tv_sec -= 60 * ltm->tm_min; + secs.tv_sec -= 3600 * ltm->tm_hour; + secs.tv_usec = 0; + show_today(secs); } } /* * anyone still logged in gets time up to now */ - head = log_out(head, &usht); + log_out(&usht); if (Flags & AC_D) - show_today(Users, head, time((time_t *)0)); + show_today(now); else { if (Flags & AC_P) - show_users(Users); + show_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; } -void +static void usage(void) { (void)fprintf(stderr, |