1ff9c3a32SDavid Greenman /* 2ff9c3a32SDavid Greenman * Copyright (c) 1994 Christopher G. Demetriou. 3ff9c3a32SDavid Greenman * @(#)Copyright (c) 1994, Simon J. Gerraty. 4ff9c3a32SDavid Greenman * 5ff9c3a32SDavid Greenman * This is free software. It comes with NO WARRANTY. 6ff9c3a32SDavid Greenman * Permission to use, modify and distribute this source code 7ff9c3a32SDavid Greenman * is granted subject to the following conditions. 8ff9c3a32SDavid Greenman * 1/ that the above copyright notice and this notice 9ff9c3a32SDavid Greenman * are preserved in all copies and that due credit be given 10ff9c3a32SDavid Greenman * to the author. 11ff9c3a32SDavid Greenman * 2/ that any changes to this code are clearly commented 12ff9c3a32SDavid Greenman * as such so that the author does not get blamed for bugs 13ff9c3a32SDavid Greenman * other than his own. 14ff9c3a32SDavid Greenman */ 15ff9c3a32SDavid Greenman 16ff9c3a32SDavid Greenman #ifndef lint 175877948cSAndrey A. Chernov static char rcsid[] = "$Id: ac.c,v 1.3 1995/05/30 03:45:34 rgrimes Exp $"; 18ff9c3a32SDavid Greenman #endif 19ff9c3a32SDavid Greenman 20ff9c3a32SDavid Greenman #include <sys/types.h> 21ff9c3a32SDavid Greenman #include <sys/file.h> 22ff9c3a32SDavid Greenman #include <sys/time.h> 23ff9c3a32SDavid Greenman #include <err.h> 24ff9c3a32SDavid Greenman #include <errno.h> 25ff9c3a32SDavid Greenman #include <pwd.h> 26ff9c3a32SDavid Greenman #include <stdio.h> 27ff9c3a32SDavid Greenman #include <stdlib.h> 28ff9c3a32SDavid Greenman #include <string.h> 29ff9c3a32SDavid Greenman #include <utmp.h> 30ff9c3a32SDavid Greenman #include <unistd.h> 315877948cSAndrey A. Chernov #include <locale.h> 32ff9c3a32SDavid Greenman 33ff9c3a32SDavid Greenman /* 34ff9c3a32SDavid Greenman * this is for our list of currently logged in sessions 35ff9c3a32SDavid Greenman */ 36ff9c3a32SDavid Greenman struct utmp_list { 37ff9c3a32SDavid Greenman struct utmp_list *next; 38ff9c3a32SDavid Greenman struct utmp usr; 39ff9c3a32SDavid Greenman }; 40ff9c3a32SDavid Greenman 41ff9c3a32SDavid Greenman /* 42ff9c3a32SDavid Greenman * this is for our list of users that are accumulating time. 43ff9c3a32SDavid Greenman */ 44ff9c3a32SDavid Greenman struct user_list { 45ff9c3a32SDavid Greenman struct user_list *next; 46ff9c3a32SDavid Greenman char name[UT_NAMESIZE+1]; 47ff9c3a32SDavid Greenman time_t secs; 48ff9c3a32SDavid Greenman }; 49ff9c3a32SDavid Greenman 50ff9c3a32SDavid Greenman /* 51ff9c3a32SDavid Greenman * this is for chosing whether to ignore a login 52ff9c3a32SDavid Greenman */ 53ff9c3a32SDavid Greenman struct tty_list { 54ff9c3a32SDavid Greenman struct tty_list *next; 55ff9c3a32SDavid Greenman char name[UT_LINESIZE+3]; 56ff9c3a32SDavid Greenman int len; 57ff9c3a32SDavid Greenman int ret; 58ff9c3a32SDavid Greenman }; 59ff9c3a32SDavid Greenman 60ff9c3a32SDavid Greenman /* 61ff9c3a32SDavid Greenman * globals - yes yuk 62ff9c3a32SDavid Greenman */ 63ff9c3a32SDavid Greenman #ifdef CONSOLE_TTY 64ff9c3a32SDavid Greenman static char *Console = CONSOLE_TTY; 65ff9c3a32SDavid Greenman #endif 66ff9c3a32SDavid Greenman static time_t Total = 0; 67ff9c3a32SDavid Greenman static time_t FirstTime = 0; 68ff9c3a32SDavid Greenman static int Flags = 0; 69ff9c3a32SDavid Greenman static struct user_list *Users = NULL; 70ff9c3a32SDavid Greenman static struct tty_list *Ttys = NULL; 71ff9c3a32SDavid Greenman 72ff9c3a32SDavid Greenman #define NEW(type) (type *)malloc(sizeof (type)) 73ff9c3a32SDavid Greenman 74ff9c3a32SDavid Greenman #define AC_W 1 /* not _PATH_WTMP */ 75ff9c3a32SDavid Greenman #define AC_D 2 /* daily totals (ignore -p) */ 76ff9c3a32SDavid Greenman #define AC_P 4 /* per-user totals */ 77ff9c3a32SDavid Greenman #define AC_U 8 /* specified users only */ 78ff9c3a32SDavid Greenman #define AC_T 16 /* specified ttys only */ 79ff9c3a32SDavid Greenman 80ff9c3a32SDavid Greenman #ifdef DEBUG 81ff9c3a32SDavid Greenman static int Debug = 0; 82ff9c3a32SDavid Greenman #endif 83ff9c3a32SDavid Greenman 84ff9c3a32SDavid Greenman int main __P((int, char **)); 85ff9c3a32SDavid Greenman int ac __P((FILE *)); 86ff9c3a32SDavid Greenman struct tty_list *add_tty __P((char *)); 87ff9c3a32SDavid Greenman int do_tty __P((char *)); 88ff9c3a32SDavid Greenman FILE *file __P((char *)); 89ff9c3a32SDavid Greenman struct utmp_list *log_in __P((struct utmp_list *, struct utmp *)); 90ff9c3a32SDavid Greenman struct utmp_list *log_out __P((struct utmp_list *, struct utmp *)); 91ff9c3a32SDavid Greenman int on_console __P((struct utmp_list *)); 92ff9c3a32SDavid Greenman void show __P((char *, time_t)); 93ff9c3a32SDavid Greenman void show_today __P((struct user_list *, struct utmp_list *, 94ff9c3a32SDavid Greenman time_t)); 95ff9c3a32SDavid Greenman void show_users __P((struct user_list *)); 96ff9c3a32SDavid Greenman struct user_list *update_user __P((struct user_list *, char *, time_t)); 97ff9c3a32SDavid Greenman void usage __P((void)); 98ff9c3a32SDavid Greenman 99ff9c3a32SDavid Greenman /* 100ff9c3a32SDavid Greenman * open wtmp or die 101ff9c3a32SDavid Greenman */ 102ff9c3a32SDavid Greenman FILE * 103ff9c3a32SDavid Greenman file(name) 104ff9c3a32SDavid Greenman char *name; 105ff9c3a32SDavid Greenman { 106ff9c3a32SDavid Greenman FILE *fp; 107ff9c3a32SDavid Greenman 108ff9c3a32SDavid Greenman if ((fp = fopen(name, "r")) == NULL) 109ff9c3a32SDavid Greenman err(1, "%s", name); 110ff9c3a32SDavid Greenman /* in case we want to discriminate */ 111ff9c3a32SDavid Greenman if (strcmp(_PATH_WTMP, name)) 112ff9c3a32SDavid Greenman Flags |= AC_W; 113ff9c3a32SDavid Greenman return fp; 114ff9c3a32SDavid Greenman } 115ff9c3a32SDavid Greenman 116ff9c3a32SDavid Greenman struct tty_list * 117ff9c3a32SDavid Greenman add_tty(name) 118ff9c3a32SDavid Greenman char *name; 119ff9c3a32SDavid Greenman { 120ff9c3a32SDavid Greenman struct tty_list *tp; 121ff9c3a32SDavid Greenman register char *rcp; 122ff9c3a32SDavid Greenman 123ff9c3a32SDavid Greenman Flags |= AC_T; 124ff9c3a32SDavid Greenman 125ff9c3a32SDavid Greenman if ((tp = NEW(struct tty_list)) == NULL) 126ff9c3a32SDavid Greenman err(1, "malloc"); 127ff9c3a32SDavid Greenman tp->len = 0; /* full match */ 128ff9c3a32SDavid Greenman tp->ret = 1; /* do if match */ 129ff9c3a32SDavid Greenman if (*name == '!') { /* don't do if match */ 130ff9c3a32SDavid Greenman tp->ret = 0; 131ff9c3a32SDavid Greenman name++; 132ff9c3a32SDavid Greenman } 133ff9c3a32SDavid Greenman (void)strncpy(tp->name, name, sizeof (tp->name) - 1); 134ff9c3a32SDavid Greenman tp->name[sizeof (tp->name) - 1] = '\0'; 135ff9c3a32SDavid Greenman if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */ 136ff9c3a32SDavid Greenman *rcp = '\0'; 137ff9c3a32SDavid Greenman tp->len = strlen(tp->name); /* match len bytes only */ 138ff9c3a32SDavid Greenman } 139ff9c3a32SDavid Greenman tp->next = Ttys; 140ff9c3a32SDavid Greenman Ttys = tp; 141ff9c3a32SDavid Greenman return Ttys; 142ff9c3a32SDavid Greenman } 143ff9c3a32SDavid Greenman 144ff9c3a32SDavid Greenman /* 145ff9c3a32SDavid Greenman * should we process the named tty? 146ff9c3a32SDavid Greenman */ 147ff9c3a32SDavid Greenman int 148ff9c3a32SDavid Greenman do_tty(name) 149ff9c3a32SDavid Greenman char *name; 150ff9c3a32SDavid Greenman { 151ff9c3a32SDavid Greenman struct tty_list *tp; 152ff9c3a32SDavid Greenman int def_ret = 0; 153ff9c3a32SDavid Greenman 154ff9c3a32SDavid Greenman for (tp = Ttys; tp != NULL; tp = tp->next) { 155ff9c3a32SDavid Greenman if (tp->ret == 0) /* specific don't */ 156ff9c3a32SDavid Greenman def_ret = 1; /* default do */ 157ff9c3a32SDavid Greenman if (tp->len != 0) { 158ff9c3a32SDavid Greenman if (strncmp(name, tp->name, tp->len) == 0) 159ff9c3a32SDavid Greenman return tp->ret; 160ff9c3a32SDavid Greenman } else { 161ff9c3a32SDavid Greenman if (strncmp(name, tp->name, sizeof (tp->name)) == 0) 162ff9c3a32SDavid Greenman return tp->ret; 163ff9c3a32SDavid Greenman } 164ff9c3a32SDavid Greenman } 165ff9c3a32SDavid Greenman return def_ret; 166ff9c3a32SDavid Greenman } 167ff9c3a32SDavid Greenman 168ff9c3a32SDavid Greenman #ifdef CONSOLE_TTY 169ff9c3a32SDavid Greenman /* 170ff9c3a32SDavid Greenman * is someone logged in on Console? 171ff9c3a32SDavid Greenman */ 172ff9c3a32SDavid Greenman int 173ff9c3a32SDavid Greenman on_console(head) 174ff9c3a32SDavid Greenman struct utmp_list *head; 175ff9c3a32SDavid Greenman { 176ff9c3a32SDavid Greenman struct utmp_list *up; 177ff9c3a32SDavid Greenman 178ff9c3a32SDavid Greenman for (up = head; up; up = up->next) { 179ff9c3a32SDavid Greenman if (strncmp(up->usr.ut_line, Console, 180ff9c3a32SDavid Greenman sizeof (up->usr.ut_line)) == 0) 181ff9c3a32SDavid Greenman return 1; 182ff9c3a32SDavid Greenman } 183ff9c3a32SDavid Greenman return 0; 184ff9c3a32SDavid Greenman } 185ff9c3a32SDavid Greenman #endif 186ff9c3a32SDavid Greenman 187ff9c3a32SDavid Greenman /* 188ff9c3a32SDavid Greenman * update user's login time 189ff9c3a32SDavid Greenman */ 190ff9c3a32SDavid Greenman struct user_list * 191ff9c3a32SDavid Greenman update_user(head, name, secs) 192ff9c3a32SDavid Greenman struct user_list *head; 193ff9c3a32SDavid Greenman char *name; 194ff9c3a32SDavid Greenman time_t secs; 195ff9c3a32SDavid Greenman { 196ff9c3a32SDavid Greenman struct user_list *up; 197ff9c3a32SDavid Greenman 198ff9c3a32SDavid Greenman for (up = head; up != NULL; up = up->next) { 1993f6dabb2SAndrey A. Chernov if (strncmp(up->name, name, UT_NAMESIZE) == 0) { 200ff9c3a32SDavid Greenman up->secs += secs; 201ff9c3a32SDavid Greenman Total += secs; 202ff9c3a32SDavid Greenman return head; 203ff9c3a32SDavid Greenman } 204ff9c3a32SDavid Greenman } 205ff9c3a32SDavid Greenman /* 206ff9c3a32SDavid Greenman * not found so add new user unless specified users only 207ff9c3a32SDavid Greenman */ 208ff9c3a32SDavid Greenman if (Flags & AC_U) 209ff9c3a32SDavid Greenman return head; 210ff9c3a32SDavid Greenman 211ff9c3a32SDavid Greenman if ((up = NEW(struct user_list)) == NULL) 212ff9c3a32SDavid Greenman err(1, "malloc"); 213ff9c3a32SDavid Greenman up->next = head; 214ff9c3a32SDavid Greenman (void)strncpy(up->name, name, sizeof (up->name) - 1); 215ff9c3a32SDavid Greenman up->name[sizeof (up->name) - 1] = '\0'; /* paranoid! */ 216ff9c3a32SDavid Greenman up->secs = secs; 217ff9c3a32SDavid Greenman Total += secs; 218ff9c3a32SDavid Greenman return up; 219ff9c3a32SDavid Greenman } 220ff9c3a32SDavid Greenman 221ff9c3a32SDavid Greenman int 222ff9c3a32SDavid Greenman main(argc, argv) 223ff9c3a32SDavid Greenman int argc; 224ff9c3a32SDavid Greenman char **argv; 225ff9c3a32SDavid Greenman { 226ff9c3a32SDavid Greenman FILE *fp; 227ff9c3a32SDavid Greenman int c; 228ff9c3a32SDavid Greenman 2295877948cSAndrey A. Chernov (void) setlocale(LC_TIME, ""); 2305877948cSAndrey A. Chernov 231ff9c3a32SDavid Greenman fp = NULL; 232ff9c3a32SDavid Greenman while ((c = getopt(argc, argv, "Dc:dpt:w:")) != EOF) { 233ff9c3a32SDavid Greenman switch (c) { 234ff9c3a32SDavid Greenman #ifdef DEBUG 235ff9c3a32SDavid Greenman case 'D': 236ff9c3a32SDavid Greenman Debug++; 237ff9c3a32SDavid Greenman break; 238ff9c3a32SDavid Greenman #endif 239ff9c3a32SDavid Greenman case 'c': 240ff9c3a32SDavid Greenman #ifdef CONSOLE_TTY 241ff9c3a32SDavid Greenman Console = optarg; 242ff9c3a32SDavid Greenman #else 243ff9c3a32SDavid Greenman usage(); /* XXX */ 244ff9c3a32SDavid Greenman #endif 245ff9c3a32SDavid Greenman break; 246ff9c3a32SDavid Greenman case 'd': 247ff9c3a32SDavid Greenman Flags |= AC_D; 248ff9c3a32SDavid Greenman break; 249ff9c3a32SDavid Greenman case 'p': 250ff9c3a32SDavid Greenman Flags |= AC_P; 251ff9c3a32SDavid Greenman break; 252ff9c3a32SDavid Greenman case 't': /* only do specified ttys */ 253ff9c3a32SDavid Greenman add_tty(optarg); 254ff9c3a32SDavid Greenman break; 255ff9c3a32SDavid Greenman case 'w': 256ff9c3a32SDavid Greenman fp = file(optarg); 257ff9c3a32SDavid Greenman break; 258ff9c3a32SDavid Greenman case '?': 259ff9c3a32SDavid Greenman default: 260ff9c3a32SDavid Greenman usage(); 261ff9c3a32SDavid Greenman break; 262ff9c3a32SDavid Greenman } 263ff9c3a32SDavid Greenman } 264ff9c3a32SDavid Greenman if (optind < argc) { 265ff9c3a32SDavid Greenman /* 266ff9c3a32SDavid Greenman * initialize user list 267ff9c3a32SDavid Greenman */ 268ff9c3a32SDavid Greenman for (; optind < argc; optind++) { 269ff9c3a32SDavid Greenman Users = update_user(Users, argv[optind], 0L); 270ff9c3a32SDavid Greenman } 271ff9c3a32SDavid Greenman Flags |= AC_U; /* freeze user list */ 272ff9c3a32SDavid Greenman } 273ff9c3a32SDavid Greenman if (Flags & AC_D) 274ff9c3a32SDavid Greenman Flags &= ~AC_P; 275ff9c3a32SDavid Greenman if (fp == NULL) { 276ff9c3a32SDavid Greenman /* 277ff9c3a32SDavid Greenman * if _PATH_WTMP does not exist, exit quietly 278ff9c3a32SDavid Greenman */ 279ff9c3a32SDavid Greenman if (access(_PATH_WTMP, 0) != 0 && errno == ENOENT) 280ff9c3a32SDavid Greenman return 0; 281ff9c3a32SDavid Greenman 282ff9c3a32SDavid Greenman fp = file(_PATH_WTMP); 283ff9c3a32SDavid Greenman } 284ff9c3a32SDavid Greenman ac(fp); 285ff9c3a32SDavid Greenman 286ff9c3a32SDavid Greenman return 0; 287ff9c3a32SDavid Greenman } 288ff9c3a32SDavid Greenman 289ff9c3a32SDavid Greenman /* 290ff9c3a32SDavid Greenman * print login time in decimal hours 291ff9c3a32SDavid Greenman */ 292ff9c3a32SDavid Greenman void 293ff9c3a32SDavid Greenman show(name, secs) 294ff9c3a32SDavid Greenman char *name; 295ff9c3a32SDavid Greenman time_t secs; 296ff9c3a32SDavid Greenman { 297ff9c3a32SDavid Greenman (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name, 298ff9c3a32SDavid Greenman ((double)secs / 3600)); 299ff9c3a32SDavid Greenman } 300ff9c3a32SDavid Greenman 301ff9c3a32SDavid Greenman void 302ff9c3a32SDavid Greenman show_users(list) 303ff9c3a32SDavid Greenman struct user_list *list; 304ff9c3a32SDavid Greenman { 305ff9c3a32SDavid Greenman struct user_list *lp; 306ff9c3a32SDavid Greenman 307ff9c3a32SDavid Greenman for (lp = list; lp; lp = lp->next) 308ff9c3a32SDavid Greenman show(lp->name, lp->secs); 309ff9c3a32SDavid Greenman } 310ff9c3a32SDavid Greenman 311ff9c3a32SDavid Greenman /* 312ff9c3a32SDavid Greenman * print total login time for 24hr period in decimal hours 313ff9c3a32SDavid Greenman */ 314ff9c3a32SDavid Greenman void 315ff9c3a32SDavid Greenman show_today(users, logins, secs) 316ff9c3a32SDavid Greenman struct user_list *users; 317ff9c3a32SDavid Greenman struct utmp_list *logins; 318ff9c3a32SDavid Greenman time_t secs; 319ff9c3a32SDavid Greenman { 320ff9c3a32SDavid Greenman struct user_list *up; 321ff9c3a32SDavid Greenman struct utmp_list *lp; 322ff9c3a32SDavid Greenman char date[64]; 323ff9c3a32SDavid Greenman time_t yesterday = secs - 1; 324ff9c3a32SDavid Greenman 325ff9c3a32SDavid Greenman (void)strftime(date, sizeof (date), "%b %e total", 326ff9c3a32SDavid Greenman localtime(&yesterday)); 327ff9c3a32SDavid Greenman 328ff9c3a32SDavid Greenman /* restore the missing second */ 329ff9c3a32SDavid Greenman yesterday++; 330ff9c3a32SDavid Greenman 331ff9c3a32SDavid Greenman for (lp = logins; lp != NULL; lp = lp->next) { 332ff9c3a32SDavid Greenman secs = yesterday - lp->usr.ut_time; 333ff9c3a32SDavid Greenman Users = update_user(Users, lp->usr.ut_name, secs); 334ff9c3a32SDavid Greenman lp->usr.ut_time = yesterday; /* as if they just logged in */ 335ff9c3a32SDavid Greenman } 336ff9c3a32SDavid Greenman secs = 0; 337ff9c3a32SDavid Greenman for (up = users; up != NULL; up = up->next) { 338ff9c3a32SDavid Greenman secs += up->secs; 339ff9c3a32SDavid Greenman up->secs = 0; /* for next day */ 340ff9c3a32SDavid Greenman } 341ff9c3a32SDavid Greenman if (secs) 342ff9c3a32SDavid Greenman (void)printf("%s %11.2f\n", date, ((double)secs / 3600)); 343ff9c3a32SDavid Greenman } 344ff9c3a32SDavid Greenman 345ff9c3a32SDavid Greenman /* 346ff9c3a32SDavid Greenman * log a user out and update their times. 347ff9c3a32SDavid Greenman * if ut_line is "~", we log all users out as the system has 348ff9c3a32SDavid Greenman * been shut down. 349ff9c3a32SDavid Greenman */ 350ff9c3a32SDavid Greenman struct utmp_list * 351ff9c3a32SDavid Greenman log_out(head, up) 352ff9c3a32SDavid Greenman struct utmp_list *head; 353ff9c3a32SDavid Greenman struct utmp *up; 354ff9c3a32SDavid Greenman { 355ff9c3a32SDavid Greenman struct utmp_list *lp, *lp2, *tlp; 356ff9c3a32SDavid Greenman time_t secs; 357ff9c3a32SDavid Greenman 358ff9c3a32SDavid Greenman for (lp = head, lp2 = NULL; lp != NULL; ) 359ff9c3a32SDavid Greenman if (*up->ut_line == '~' || strncmp(lp->usr.ut_line, up->ut_line, 360ff9c3a32SDavid Greenman sizeof (up->ut_line)) == 0) { 361ff9c3a32SDavid Greenman secs = up->ut_time - lp->usr.ut_time; 362ff9c3a32SDavid Greenman Users = update_user(Users, lp->usr.ut_name, secs); 363ff9c3a32SDavid Greenman #ifdef DEBUG 364ff9c3a32SDavid Greenman if (Debug) 365ff9c3a32SDavid Greenman printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n", 366ff9c3a32SDavid Greenman 19, ctime(&up->ut_time), 367ff9c3a32SDavid Greenman sizeof (lp->usr.ut_line), lp->usr.ut_line, 368ff9c3a32SDavid Greenman sizeof (lp->usr.ut_name), lp->usr.ut_name, 369ff9c3a32SDavid Greenman secs / 3600, (secs % 3600) / 60, secs % 60); 370ff9c3a32SDavid Greenman #endif 371ff9c3a32SDavid Greenman /* 372ff9c3a32SDavid Greenman * now lose it 373ff9c3a32SDavid Greenman */ 374ff9c3a32SDavid Greenman tlp = lp; 375ff9c3a32SDavid Greenman lp = lp->next; 376ff9c3a32SDavid Greenman if (tlp == head) 377ff9c3a32SDavid Greenman head = lp; 378ff9c3a32SDavid Greenman else if (lp2 != NULL) 379ff9c3a32SDavid Greenman lp2->next = lp; 380ff9c3a32SDavid Greenman free(tlp); 381ff9c3a32SDavid Greenman } else { 382ff9c3a32SDavid Greenman lp2 = lp; 383ff9c3a32SDavid Greenman lp = lp->next; 384ff9c3a32SDavid Greenman } 385ff9c3a32SDavid Greenman return head; 386ff9c3a32SDavid Greenman } 387ff9c3a32SDavid Greenman 388ff9c3a32SDavid Greenman 389ff9c3a32SDavid Greenman /* 390ff9c3a32SDavid Greenman * if do_tty says ok, login a user 391ff9c3a32SDavid Greenman */ 392ff9c3a32SDavid Greenman struct utmp_list * 393ff9c3a32SDavid Greenman log_in(head, up) 394ff9c3a32SDavid Greenman struct utmp_list *head; 395ff9c3a32SDavid Greenman struct utmp *up; 396ff9c3a32SDavid Greenman { 397ff9c3a32SDavid Greenman struct utmp_list *lp; 398ff9c3a32SDavid Greenman 399ff9c3a32SDavid Greenman /* 400ff9c3a32SDavid Greenman * this could be a login. if we're not dealing with 401ff9c3a32SDavid Greenman * the console name, say it is. 402ff9c3a32SDavid Greenman * 403ff9c3a32SDavid Greenman * If we are, and if ut_host==":0.0" we know that it 404ff9c3a32SDavid Greenman * isn't a real login. _But_ if we have not yet recorded 405ff9c3a32SDavid Greenman * someone being logged in on Console - due to the wtmp 406ff9c3a32SDavid Greenman * file starting after they logged in, we'll pretend they 407ff9c3a32SDavid Greenman * logged in, at the start of the wtmp file. 408ff9c3a32SDavid Greenman */ 409ff9c3a32SDavid Greenman 410ff9c3a32SDavid Greenman #ifdef CONSOLE_TTY 411ff9c3a32SDavid Greenman if (up->ut_host[0] == ':') { 412ff9c3a32SDavid Greenman /* 413ff9c3a32SDavid Greenman * SunOS 4.0.2 does not treat ":0.0" as special but we 414ff9c3a32SDavid Greenman * do. 415ff9c3a32SDavid Greenman */ 416ff9c3a32SDavid Greenman if (on_console(head)) 417ff9c3a32SDavid Greenman return head; 418ff9c3a32SDavid Greenman /* 419ff9c3a32SDavid Greenman * ok, no recorded login, so they were here when wtmp 420ff9c3a32SDavid Greenman * started! Adjust ut_time! 421ff9c3a32SDavid Greenman */ 422ff9c3a32SDavid Greenman up->ut_time = FirstTime; 423ff9c3a32SDavid Greenman /* 424ff9c3a32SDavid Greenman * this allows us to pick the right logout 425ff9c3a32SDavid Greenman */ 426ff9c3a32SDavid Greenman (void)strncpy(up->ut_line, Console, sizeof (up->ut_line) - 1); 427ff9c3a32SDavid Greenman up->ut_line[sizeof (up->ut_line) - 1] = '\0'; /* paranoid! */ 428ff9c3a32SDavid Greenman } 429ff9c3a32SDavid Greenman #endif 430ff9c3a32SDavid Greenman /* 431ff9c3a32SDavid Greenman * If we are doing specified ttys only, we ignore 432ff9c3a32SDavid Greenman * anything else. 433ff9c3a32SDavid Greenman */ 434ff9c3a32SDavid Greenman if (Flags & AC_T) 435ff9c3a32SDavid Greenman if (!do_tty(up->ut_line)) 436ff9c3a32SDavid Greenman return head; 437ff9c3a32SDavid Greenman 438ff9c3a32SDavid Greenman /* 439ff9c3a32SDavid Greenman * go ahead and log them in 440ff9c3a32SDavid Greenman */ 441ff9c3a32SDavid Greenman if ((lp = NEW(struct utmp_list)) == NULL) 442ff9c3a32SDavid Greenman err(1, "malloc"); 443ff9c3a32SDavid Greenman lp->next = head; 444ff9c3a32SDavid Greenman head = lp; 445ff9c3a32SDavid Greenman memmove((char *)&lp->usr, (char *)up, sizeof (struct utmp)); 446ff9c3a32SDavid Greenman #ifdef DEBUG 447ff9c3a32SDavid Greenman if (Debug) { 448ff9c3a32SDavid Greenman printf("%-.*s %-.*s: %-.*s logged in", 19, 449ff9c3a32SDavid Greenman ctime(&lp->usr.ut_time), sizeof (up->ut_line), 450ff9c3a32SDavid Greenman up->ut_line, sizeof (up->ut_name), up->ut_name); 451ff9c3a32SDavid Greenman if (*up->ut_host) 452ff9c3a32SDavid Greenman printf(" (%-.*s)", sizeof (up->ut_host), up->ut_host); 453ff9c3a32SDavid Greenman putchar('\n'); 454ff9c3a32SDavid Greenman } 455ff9c3a32SDavid Greenman #endif 456ff9c3a32SDavid Greenman return head; 457ff9c3a32SDavid Greenman } 458ff9c3a32SDavid Greenman 459ff9c3a32SDavid Greenman int 460ff9c3a32SDavid Greenman ac(fp) 461ff9c3a32SDavid Greenman FILE *fp; 462ff9c3a32SDavid Greenman { 463ff9c3a32SDavid Greenman struct utmp_list *lp, *head = NULL; 464ff9c3a32SDavid Greenman struct utmp usr; 465ff9c3a32SDavid Greenman struct tm *ltm; 466ff9c3a32SDavid Greenman time_t secs; 467ff9c3a32SDavid Greenman int day = -1; 468ff9c3a32SDavid Greenman 469ff9c3a32SDavid Greenman while (fread((char *)&usr, sizeof(usr), 1, fp) == 1) { 470ff9c3a32SDavid Greenman if (!FirstTime) 471ff9c3a32SDavid Greenman FirstTime = usr.ut_time; 472ff9c3a32SDavid Greenman if (Flags & AC_D) { 473ff9c3a32SDavid Greenman ltm = localtime(&usr.ut_time); 474ff9c3a32SDavid Greenman if (day >= 0 && day != ltm->tm_yday) { 475ff9c3a32SDavid Greenman day = ltm->tm_yday; 476ff9c3a32SDavid Greenman /* 477ff9c3a32SDavid Greenman * print yesterday's total 478ff9c3a32SDavid Greenman */ 479ff9c3a32SDavid Greenman secs = usr.ut_time; 480ff9c3a32SDavid Greenman secs -= ltm->tm_sec; 481ff9c3a32SDavid Greenman secs -= 60 * ltm->tm_min; 482ff9c3a32SDavid Greenman secs -= 3600 * ltm->tm_hour; 483ff9c3a32SDavid Greenman show_today(Users, head, secs); 484ff9c3a32SDavid Greenman } else 485ff9c3a32SDavid Greenman day = ltm->tm_yday; 486ff9c3a32SDavid Greenman } 487ff9c3a32SDavid Greenman switch(*usr.ut_line) { 488ff9c3a32SDavid Greenman case '|': 489ff9c3a32SDavid Greenman secs = usr.ut_time; 490ff9c3a32SDavid Greenman break; 491ff9c3a32SDavid Greenman case '{': 492ff9c3a32SDavid Greenman secs -= usr.ut_time; 493ff9c3a32SDavid Greenman /* 494ff9c3a32SDavid Greenman * adjust time for those logged in 495ff9c3a32SDavid Greenman */ 496ff9c3a32SDavid Greenman for (lp = head; lp != NULL; lp = lp->next) 497ff9c3a32SDavid Greenman lp->usr.ut_time -= secs; 498ff9c3a32SDavid Greenman break; 499ff9c3a32SDavid Greenman case '~': /* reboot or shutdown */ 500ff9c3a32SDavid Greenman head = log_out(head, &usr); 501ff9c3a32SDavid Greenman FirstTime = usr.ut_time; /* shouldn't be needed */ 502ff9c3a32SDavid Greenman break; 503ff9c3a32SDavid Greenman default: 504ff9c3a32SDavid Greenman /* 505ff9c3a32SDavid Greenman * if they came in on tty[p-y]*, then it is only 506ff9c3a32SDavid Greenman * a login session if the ut_host field is non-empty 507ff9c3a32SDavid Greenman */ 508ff9c3a32SDavid Greenman if (*usr.ut_name) { 509ff9c3a32SDavid Greenman if (strncmp(usr.ut_line, "tty", 3) != 0 || 510ff9c3a32SDavid Greenman strchr("pqrstuvwxy", usr.ut_line[3]) == 0 || 511ff9c3a32SDavid Greenman *usr.ut_host != '\0') 512ff9c3a32SDavid Greenman head = log_in(head, &usr); 513ff9c3a32SDavid Greenman } else 514ff9c3a32SDavid Greenman head = log_out(head, &usr); 515ff9c3a32SDavid Greenman break; 516ff9c3a32SDavid Greenman } 517ff9c3a32SDavid Greenman } 518ff9c3a32SDavid Greenman (void)fclose(fp); 519ff9c3a32SDavid Greenman usr.ut_time = time((time_t *)0); 520ff9c3a32SDavid Greenman (void)strcpy(usr.ut_line, "~"); 521ff9c3a32SDavid Greenman 522ff9c3a32SDavid Greenman if (Flags & AC_D) { 523ff9c3a32SDavid Greenman ltm = localtime(&usr.ut_time); 524ff9c3a32SDavid Greenman if (day >= 0 && day != ltm->tm_yday) { 525ff9c3a32SDavid Greenman /* 526ff9c3a32SDavid Greenman * print yesterday's total 527ff9c3a32SDavid Greenman */ 528ff9c3a32SDavid Greenman secs = usr.ut_time; 529ff9c3a32SDavid Greenman secs -= ltm->tm_sec; 530ff9c3a32SDavid Greenman secs -= 60 * ltm->tm_min; 531ff9c3a32SDavid Greenman secs -= 3600 * ltm->tm_hour; 532ff9c3a32SDavid Greenman show_today(Users, head, secs); 533ff9c3a32SDavid Greenman } 534ff9c3a32SDavid Greenman } 535ff9c3a32SDavid Greenman /* 536ff9c3a32SDavid Greenman * anyone still logged in gets time up to now 537ff9c3a32SDavid Greenman */ 538ff9c3a32SDavid Greenman head = log_out(head, &usr); 539ff9c3a32SDavid Greenman 540ff9c3a32SDavid Greenman if (Flags & AC_D) 541ff9c3a32SDavid Greenman show_today(Users, head, time((time_t *)0)); 542ff9c3a32SDavid Greenman else { 543ff9c3a32SDavid Greenman if (Flags & AC_P) 544ff9c3a32SDavid Greenman show_users(Users); 545ff9c3a32SDavid Greenman show("total", Total); 546ff9c3a32SDavid Greenman } 547ff9c3a32SDavid Greenman return 0; 548ff9c3a32SDavid Greenman } 549ff9c3a32SDavid Greenman 550ff9c3a32SDavid Greenman void 551ff9c3a32SDavid Greenman usage() 552ff9c3a32SDavid Greenman { 553ff9c3a32SDavid Greenman (void)fprintf(stderr, 554ff9c3a32SDavid Greenman #ifdef CONSOLE_TTY 555ff9c3a32SDavid Greenman "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n"); 556ff9c3a32SDavid Greenman #else 557ff9c3a32SDavid Greenman "ac [-dp] [-t tty] [-w wtmp] [users ...]\n"); 558ff9c3a32SDavid Greenman #endif 559ff9c3a32SDavid Greenman exit(1); 560ff9c3a32SDavid Greenman } 561