1 1.27 andvar /* $NetBSD: ac.c,v 1.27 2022/05/24 06:28:02 andvar Exp $ */ 2 1.4 christos 3 1.25 wiz /*- 4 1.11 cgd * Copyright (c) 1994 Christopher G. Demetriou 5 1.25 wiz * Copyright (c) 1994 Simon J. Gerraty 6 1.11 cgd * All rights reserved. 7 1.25 wiz * 8 1.11 cgd * Redistribution and use in source and binary forms, with or without 9 1.11 cgd * modification, are permitted provided that the following conditions 10 1.11 cgd * are met: 11 1.11 cgd * 1. Redistributions of source code must retain the above copyright 12 1.11 cgd * notice, this list of conditions and the following disclaimer. 13 1.11 cgd * 2. Redistributions in binary form must reproduce the above copyright 14 1.11 cgd * notice, this list of conditions and the following disclaimer in the 15 1.11 cgd * documentation and/or other materials provided with the distribution. 16 1.11 cgd * 17 1.25 wiz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 1.25 wiz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 1.25 wiz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 1.25 wiz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 1.25 wiz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.25 wiz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 1.25 wiz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 1.25 wiz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 1.25 wiz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 1.25 wiz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 1.25 wiz * SUCH DAMAGE. 28 1.1 cgd */ 29 1.1 cgd 30 1.6 lukem #include <sys/cdefs.h> 31 1.1 cgd #ifndef lint 32 1.27 andvar __RCSID("$NetBSD: ac.c,v 1.27 2022/05/24 06:28:02 andvar Exp $"); 33 1.1 cgd #endif 34 1.1 cgd 35 1.1 cgd #include <sys/types.h> 36 1.8 kleink 37 1.1 cgd #include <err.h> 38 1.1 cgd #include <errno.h> 39 1.1 cgd #include <pwd.h> 40 1.1 cgd #include <stdio.h> 41 1.4 christos #include <string.h> 42 1.1 cgd #include <stdlib.h> 43 1.4 christos #include <unistd.h> 44 1.8 kleink #include <time.h> 45 1.1 cgd #include <utmp.h> 46 1.4 christos #include <ttyent.h> 47 1.1 cgd 48 1.1 cgd /* 49 1.1 cgd * this is for our list of currently logged in sessions 50 1.1 cgd */ 51 1.1 cgd struct utmp_list { 52 1.1 cgd struct utmp_list *next; 53 1.1 cgd struct utmp usr; 54 1.1 cgd }; 55 1.1 cgd 56 1.1 cgd /* 57 1.1 cgd * this is for our list of users that are accumulating time. 58 1.1 cgd */ 59 1.1 cgd struct user_list { 60 1.1 cgd struct user_list *next; 61 1.2 cgd char name[UT_NAMESIZE+1]; 62 1.1 cgd time_t secs; 63 1.1 cgd }; 64 1.1 cgd 65 1.1 cgd /* 66 1.27 andvar * this is for choosing whether to ignore a login 67 1.1 cgd */ 68 1.1 cgd struct tty_list { 69 1.1 cgd struct tty_list *next; 70 1.3 cgd char name[UT_LINESIZE+3]; 71 1.1 cgd int len; 72 1.1 cgd int ret; 73 1.1 cgd }; 74 1.1 cgd 75 1.1 cgd /* 76 1.1 cgd * globals - yes yuk 77 1.1 cgd */ 78 1.1 cgd static time_t Total = 0; 79 1.1 cgd static time_t FirstTime = 0; 80 1.1 cgd static int Flags = 0; 81 1.1 cgd static struct user_list *Users = NULL; 82 1.1 cgd static struct tty_list *Ttys = NULL; 83 1.4 christos static int Maxcon = 0, Ncon = 0; 84 1.4 christos static char (*Con)[UT_LINESIZE] = NULL; 85 1.1 cgd 86 1.1 cgd #define NEW(type) (type *)malloc(sizeof (type)) 87 1.1 cgd 88 1.4 christos #define is_login_tty(line) \ 89 1.4 christos (bsearch(line, Con, Ncon, sizeof(Con[0]), compare) != NULL) 90 1.4 christos 91 1.1 cgd #define AC_W 1 /* not _PATH_WTMP */ 92 1.1 cgd #define AC_D 2 /* daily totals (ignore -p) */ 93 1.1 cgd #define AC_P 4 /* per-user totals */ 94 1.1 cgd #define AC_U 8 /* specified users only */ 95 1.1 cgd #define AC_T 16 /* specified ttys only */ 96 1.1 cgd 97 1.1 cgd #ifdef DEBUG 98 1.1 cgd static int Debug = 0; 99 1.1 cgd #endif 100 1.1 cgd 101 1.21 xtraeme static int ac(FILE *); 102 1.21 xtraeme static struct tty_list *add_tty(char *); 103 1.21 xtraeme static int do_tty(char *); 104 1.21 xtraeme static FILE *file(const char *); 105 1.21 xtraeme static struct utmp_list *log_in(struct utmp_list *, struct utmp *); 106 1.21 xtraeme static struct utmp_list *log_out(struct utmp_list *, struct utmp *); 107 1.4 christos #ifdef notdef 108 1.21 xtraeme static int on_console(struct utmp_list *); 109 1.4 christos #endif 110 1.21 xtraeme static void find_login_ttys(void); 111 1.21 xtraeme static void show(const char *, time_t); 112 1.21 xtraeme static void show_today(struct user_list *, struct utmp_list *, 113 1.21 xtraeme time_t); 114 1.21 xtraeme static void show_users(struct user_list *); 115 1.21 xtraeme static struct user_list *update_user(struct user_list *, char *, time_t); 116 1.21 xtraeme static int compare(const void *, const void *); 117 1.24 joerg __dead static void usage(void); 118 1.1 cgd 119 1.1 cgd /* 120 1.1 cgd * open wtmp or die 121 1.1 cgd */ 122 1.4 christos static FILE * 123 1.21 xtraeme file(const char *name) 124 1.1 cgd { 125 1.1 cgd FILE *fp; 126 1.1 cgd 127 1.12 ad if (strcmp(name, "-") == 0) 128 1.12 ad fp = stdin; 129 1.12 ad else if ((fp = fopen(name, "r")) == NULL) 130 1.1 cgd err(1, "%s", name); 131 1.1 cgd /* in case we want to discriminate */ 132 1.1 cgd if (strcmp(_PATH_WTMP, name)) 133 1.1 cgd Flags |= AC_W; 134 1.1 cgd return fp; 135 1.1 cgd } 136 1.1 cgd 137 1.4 christos static struct tty_list * 138 1.21 xtraeme add_tty(char *name) 139 1.1 cgd { 140 1.1 cgd struct tty_list *tp; 141 1.7 lukem char *rcp; 142 1.1 cgd 143 1.1 cgd Flags |= AC_T; 144 1.1 cgd 145 1.1 cgd if ((tp = NEW(struct tty_list)) == NULL) 146 1.1 cgd err(1, "malloc"); 147 1.1 cgd tp->len = 0; /* full match */ 148 1.1 cgd tp->ret = 1; /* do if match */ 149 1.1 cgd if (*name == '!') { /* don't do if match */ 150 1.1 cgd tp->ret = 0; 151 1.1 cgd name++; 152 1.1 cgd } 153 1.15 itojun (void)strlcpy(tp->name, name, sizeof (tp->name)); 154 1.1 cgd if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */ 155 1.1 cgd *rcp = '\0'; 156 1.1 cgd tp->len = strlen(tp->name); /* match len bytes only */ 157 1.1 cgd } 158 1.1 cgd tp->next = Ttys; 159 1.1 cgd Ttys = tp; 160 1.1 cgd return Ttys; 161 1.1 cgd } 162 1.1 cgd 163 1.1 cgd /* 164 1.1 cgd * should we process the named tty? 165 1.1 cgd */ 166 1.4 christos static int 167 1.21 xtraeme do_tty(char *name) 168 1.1 cgd { 169 1.1 cgd struct tty_list *tp; 170 1.1 cgd int def_ret = 0; 171 1.1 cgd 172 1.1 cgd for (tp = Ttys; tp != NULL; tp = tp->next) { 173 1.1 cgd if (tp->ret == 0) /* specific don't */ 174 1.1 cgd def_ret = 1; /* default do */ 175 1.1 cgd if (tp->len != 0) { 176 1.1 cgd if (strncmp(name, tp->name, tp->len) == 0) 177 1.1 cgd return tp->ret; 178 1.1 cgd } else { 179 1.3 cgd if (strncmp(name, tp->name, sizeof (tp->name)) == 0) 180 1.1 cgd return tp->ret; 181 1.1 cgd } 182 1.1 cgd } 183 1.1 cgd return def_ret; 184 1.1 cgd } 185 1.1 cgd 186 1.4 christos static int 187 1.21 xtraeme compare(const void *a, const void *b) 188 1.4 christos { 189 1.4 christos return strncmp(a, b, UT_LINESIZE); 190 1.4 christos } 191 1.4 christos 192 1.1 cgd /* 193 1.4 christos * Deal correctly with multiple virtual consoles/login ttys. 194 1.4 christos * We read the ttyent's from /etc/ttys and classify as login 195 1.4 christos * ttys ones that are running getty and they are turned on. 196 1.1 cgd */ 197 1.4 christos static void 198 1.21 xtraeme find_login_ttys(void) 199 1.4 christos { 200 1.4 christos struct ttyent *tty; 201 1.16 itojun char (*nCon)[UT_LINESIZE]; 202 1.4 christos 203 1.4 christos if ((Con = malloc((Maxcon = 10) * sizeof(Con[0]))) == NULL) 204 1.4 christos err(1, "malloc"); 205 1.4 christos 206 1.4 christos setttyent(); 207 1.4 christos while ((tty = getttyent()) != NULL) 208 1.4 christos if ((tty->ty_status & TTY_ON) != 0 && 209 1.4 christos strstr(tty->ty_getty, "getty") != NULL) { 210 1.16 itojun if (Ncon == Maxcon) { 211 1.16 itojun if ((nCon = realloc(Con, (Maxcon + 10) * 212 1.4 christos sizeof(Con[0]))) == NULL) 213 1.4 christos err(1, "malloc"); 214 1.16 itojun Con = nCon; 215 1.16 itojun Maxcon += 10; 216 1.16 itojun } 217 1.26 mrg strlcpy(Con[Ncon++], tty->ty_name, UT_LINESIZE); 218 1.4 christos } 219 1.4 christos endttyent(); 220 1.4 christos qsort(Con, Ncon, sizeof(Con[0]), compare); 221 1.4 christos } 222 1.4 christos 223 1.4 christos #ifdef notdef 224 1.4 christos /* 225 1.4 christos * is someone logged in on Console/login tty? 226 1.4 christos */ 227 1.4 christos static int 228 1.21 xtraeme on_console(struct utmp_list *head) 229 1.1 cgd { 230 1.1 cgd struct utmp_list *up; 231 1.1 cgd 232 1.4 christos for (up = head; up; up = up->next) 233 1.4 christos if (is_login_tty(up->usr.ut_line)) 234 1.1 cgd return 1; 235 1.4 christos 236 1.1 cgd return 0; 237 1.1 cgd } 238 1.1 cgd #endif 239 1.1 cgd 240 1.1 cgd /* 241 1.1 cgd * update user's login time 242 1.1 cgd */ 243 1.4 christos static struct user_list * 244 1.21 xtraeme update_user(struct user_list *head, char *name, time_t secs) 245 1.1 cgd { 246 1.1 cgd struct user_list *up; 247 1.1 cgd 248 1.1 cgd for (up = head; up != NULL; up = up->next) { 249 1.5 hubertf if (strncmp(up->name, name, sizeof (up->name) - 1) == 0) { 250 1.1 cgd up->secs += secs; 251 1.1 cgd Total += secs; 252 1.1 cgd return head; 253 1.1 cgd } 254 1.1 cgd } 255 1.1 cgd /* 256 1.1 cgd * not found so add new user unless specified users only 257 1.1 cgd */ 258 1.1 cgd if (Flags & AC_U) 259 1.1 cgd return head; 260 1.1 cgd 261 1.1 cgd if ((up = NEW(struct user_list)) == NULL) 262 1.1 cgd err(1, "malloc"); 263 1.1 cgd up->next = head; 264 1.15 itojun (void)strlcpy(up->name, name, sizeof (up->name)); 265 1.1 cgd up->secs = secs; 266 1.1 cgd Total += secs; 267 1.1 cgd return up; 268 1.1 cgd } 269 1.1 cgd 270 1.1 cgd int 271 1.21 xtraeme main(int argc, char **argv) 272 1.1 cgd { 273 1.1 cgd FILE *fp; 274 1.1 cgd int c; 275 1.1 cgd 276 1.1 cgd fp = NULL; 277 1.19 wiz while ((c = getopt(argc, argv, "Ddpt:w:")) != -1) { 278 1.1 cgd switch (c) { 279 1.1 cgd #ifdef DEBUG 280 1.1 cgd case 'D': 281 1.1 cgd Debug++; 282 1.1 cgd break; 283 1.1 cgd #endif 284 1.1 cgd case 'd': 285 1.1 cgd Flags |= AC_D; 286 1.1 cgd break; 287 1.1 cgd case 'p': 288 1.1 cgd Flags |= AC_P; 289 1.1 cgd break; 290 1.1 cgd case 't': /* only do specified ttys */ 291 1.1 cgd add_tty(optarg); 292 1.1 cgd break; 293 1.1 cgd case 'w': 294 1.1 cgd fp = file(optarg); 295 1.1 cgd break; 296 1.1 cgd case '?': 297 1.1 cgd default: 298 1.1 cgd usage(); 299 1.1 cgd } 300 1.1 cgd } 301 1.4 christos 302 1.4 christos find_login_ttys(); 303 1.4 christos 304 1.1 cgd if (optind < argc) { 305 1.1 cgd /* 306 1.1 cgd * initialize user list 307 1.1 cgd */ 308 1.1 cgd for (; optind < argc; optind++) { 309 1.1 cgd Users = update_user(Users, argv[optind], 0L); 310 1.1 cgd } 311 1.1 cgd Flags |= AC_U; /* freeze user list */ 312 1.1 cgd } 313 1.1 cgd if (Flags & AC_D) 314 1.1 cgd Flags &= ~AC_P; 315 1.1 cgd if (fp == NULL) { 316 1.1 cgd /* 317 1.1 cgd * if _PATH_WTMP does not exist, exit quietly 318 1.1 cgd */ 319 1.1 cgd if (access(_PATH_WTMP, 0) != 0 && errno == ENOENT) 320 1.1 cgd return 0; 321 1.1 cgd 322 1.1 cgd fp = file(_PATH_WTMP); 323 1.1 cgd } 324 1.1 cgd ac(fp); 325 1.1 cgd 326 1.1 cgd return 0; 327 1.1 cgd } 328 1.1 cgd 329 1.1 cgd /* 330 1.1 cgd * print login time in decimal hours 331 1.1 cgd */ 332 1.4 christos static void 333 1.21 xtraeme show(const char *name, time_t secs) 334 1.1 cgd { 335 1.1 cgd (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name, 336 1.1 cgd ((double)secs / 3600)); 337 1.1 cgd } 338 1.1 cgd 339 1.4 christos static void 340 1.21 xtraeme show_users(struct user_list *list) 341 1.1 cgd { 342 1.1 cgd struct user_list *lp; 343 1.1 cgd 344 1.1 cgd for (lp = list; lp; lp = lp->next) 345 1.1 cgd show(lp->name, lp->secs); 346 1.1 cgd } 347 1.1 cgd 348 1.1 cgd /* 349 1.1 cgd * print total login time for 24hr period in decimal hours 350 1.1 cgd */ 351 1.4 christos static void 352 1.21 xtraeme show_today(struct user_list *users, struct utmp_list *logins, time_t secs) 353 1.1 cgd { 354 1.1 cgd struct user_list *up; 355 1.1 cgd struct utmp_list *lp; 356 1.1 cgd char date[64]; 357 1.1 cgd time_t yesterday = secs - 1; 358 1.1 cgd 359 1.1 cgd (void)strftime(date, sizeof (date), "%b %e total", 360 1.1 cgd localtime(&yesterday)); 361 1.1 cgd 362 1.1 cgd /* restore the missing second */ 363 1.1 cgd yesterday++; 364 1.1 cgd 365 1.1 cgd for (lp = logins; lp != NULL; lp = lp->next) { 366 1.1 cgd secs = yesterday - lp->usr.ut_time; 367 1.1 cgd Users = update_user(Users, lp->usr.ut_name, secs); 368 1.1 cgd lp->usr.ut_time = yesterday; /* as if they just logged in */ 369 1.1 cgd } 370 1.1 cgd secs = 0; 371 1.1 cgd for (up = users; up != NULL; up = up->next) { 372 1.1 cgd secs += up->secs; 373 1.1 cgd up->secs = 0; /* for next day */ 374 1.1 cgd } 375 1.1 cgd if (secs) 376 1.1 cgd (void)printf("%s %11.2f\n", date, ((double)secs / 3600)); 377 1.1 cgd } 378 1.1 cgd 379 1.1 cgd /* 380 1.1 cgd * log a user out and update their times. 381 1.1 cgd * if ut_line is "~", we log all users out as the system has 382 1.1 cgd * been shut down. 383 1.1 cgd */ 384 1.4 christos static struct utmp_list * 385 1.21 xtraeme log_out(struct utmp_list *head, struct utmp *up) 386 1.1 cgd { 387 1.1 cgd struct utmp_list *lp, *lp2, *tlp; 388 1.1 cgd time_t secs; 389 1.1 cgd 390 1.1 cgd for (lp = head, lp2 = NULL; lp != NULL; ) 391 1.3 cgd if (*up->ut_line == '~' || strncmp(lp->usr.ut_line, up->ut_line, 392 1.3 cgd sizeof (up->ut_line)) == 0) { 393 1.1 cgd secs = up->ut_time - lp->usr.ut_time; 394 1.1 cgd Users = update_user(Users, lp->usr.ut_name, secs); 395 1.1 cgd #ifdef DEBUG 396 1.1 cgd if (Debug) 397 1.3 cgd printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n", 398 1.3 cgd 19, ctime(&up->ut_time), 399 1.3 cgd sizeof (lp->usr.ut_line), lp->usr.ut_line, 400 1.3 cgd sizeof (lp->usr.ut_name), lp->usr.ut_name, 401 1.3 cgd secs / 3600, (secs % 3600) / 60, secs % 60); 402 1.1 cgd #endif 403 1.1 cgd /* 404 1.1 cgd * now lose it 405 1.1 cgd */ 406 1.1 cgd tlp = lp; 407 1.1 cgd lp = lp->next; 408 1.22 christos if (tlp == head) { 409 1.1 cgd head = lp; 410 1.23 jnemeth } else if (lp2 != NULL) 411 1.1 cgd lp2->next = lp; 412 1.1 cgd free(tlp); 413 1.1 cgd } else { 414 1.1 cgd lp2 = lp; 415 1.1 cgd lp = lp->next; 416 1.1 cgd } 417 1.1 cgd return head; 418 1.1 cgd } 419 1.1 cgd 420 1.1 cgd 421 1.1 cgd /* 422 1.1 cgd * if do_tty says ok, login a user 423 1.1 cgd */ 424 1.1 cgd struct utmp_list * 425 1.21 xtraeme log_in(struct utmp_list *head, struct utmp *up) 426 1.1 cgd { 427 1.1 cgd struct utmp_list *lp; 428 1.1 cgd 429 1.1 cgd /* 430 1.1 cgd * If we are doing specified ttys only, we ignore 431 1.1 cgd * anything else. 432 1.1 cgd */ 433 1.1 cgd if (Flags & AC_T) 434 1.1 cgd if (!do_tty(up->ut_line)) 435 1.1 cgd return head; 436 1.1 cgd 437 1.1 cgd /* 438 1.1 cgd * go ahead and log them in 439 1.1 cgd */ 440 1.1 cgd if ((lp = NEW(struct utmp_list)) == NULL) 441 1.1 cgd err(1, "malloc"); 442 1.1 cgd lp->next = head; 443 1.1 cgd head = lp; 444 1.1 cgd memmove((char *)&lp->usr, (char *)up, sizeof (struct utmp)); 445 1.1 cgd #ifdef DEBUG 446 1.1 cgd if (Debug) { 447 1.3 cgd printf("%-.*s %-.*s: %-.*s logged in", 19, 448 1.3 cgd ctime(&lp->usr.ut_time), sizeof (up->ut_line), 449 1.3 cgd up->ut_line, sizeof (up->ut_name), up->ut_name); 450 1.1 cgd if (*up->ut_host) 451 1.3 cgd printf(" (%-.*s)", sizeof (up->ut_host), up->ut_host); 452 1.1 cgd putchar('\n'); 453 1.1 cgd } 454 1.1 cgd #endif 455 1.1 cgd return head; 456 1.1 cgd } 457 1.1 cgd 458 1.4 christos static int 459 1.21 xtraeme ac(FILE *fp) 460 1.1 cgd { 461 1.1 cgd struct utmp_list *lp, *head = NULL; 462 1.1 cgd struct utmp usr; 463 1.1 cgd struct tm *ltm; 464 1.4 christos time_t secs = 0; 465 1.1 cgd int day = -1; 466 1.1 cgd 467 1.1 cgd while (fread((char *)&usr, sizeof(usr), 1, fp) == 1) { 468 1.1 cgd if (!FirstTime) 469 1.1 cgd FirstTime = usr.ut_time; 470 1.1 cgd if (Flags & AC_D) { 471 1.1 cgd ltm = localtime(&usr.ut_time); 472 1.1 cgd if (day >= 0 && day != ltm->tm_yday) { 473 1.1 cgd day = ltm->tm_yday; 474 1.1 cgd /* 475 1.1 cgd * print yesterday's total 476 1.1 cgd */ 477 1.1 cgd secs = usr.ut_time; 478 1.1 cgd secs -= ltm->tm_sec; 479 1.1 cgd secs -= 60 * ltm->tm_min; 480 1.1 cgd secs -= 3600 * ltm->tm_hour; 481 1.1 cgd show_today(Users, head, secs); 482 1.1 cgd } else 483 1.1 cgd day = ltm->tm_yday; 484 1.1 cgd } 485 1.1 cgd switch(*usr.ut_line) { 486 1.1 cgd case '|': 487 1.1 cgd secs = usr.ut_time; 488 1.1 cgd break; 489 1.1 cgd case '{': 490 1.1 cgd secs -= usr.ut_time; 491 1.1 cgd /* 492 1.1 cgd * adjust time for those logged in 493 1.1 cgd */ 494 1.1 cgd for (lp = head; lp != NULL; lp = lp->next) 495 1.1 cgd lp->usr.ut_time -= secs; 496 1.1 cgd break; 497 1.1 cgd case '~': /* reboot or shutdown */ 498 1.1 cgd head = log_out(head, &usr); 499 1.3 cgd FirstTime = usr.ut_time; /* shouldn't be needed */ 500 1.1 cgd break; 501 1.1 cgd default: 502 1.1 cgd /* 503 1.1 cgd * if they came in on tty[p-y]*, then it is only 504 1.4 christos * a login session if the ut_host field is non-empty, 505 1.4 christos * or this tty is a login tty [eg. a console] 506 1.1 cgd */ 507 1.1 cgd if (*usr.ut_name) { 508 1.9 mrg if ((strncmp(usr.ut_line, "tty", 3) != 0 && 509 1.9 mrg strncmp(usr.ut_line, "dty", 3) != 0) || 510 1.4 christos strchr("pqrstuvwxyzPQRST", usr.ut_line[3]) == 0 || 511 1.4 christos *usr.ut_host != '\0' || 512 1.4 christos is_login_tty(usr.ut_line)) 513 1.1 cgd head = log_in(head, &usr); 514 1.4 christos #ifdef DEBUG 515 1.4 christos else if (Debug) 516 1.4 christos printf("%-.*s %-.*s: %-.*s ignored\n", 517 1.4 christos 19, ctime(&usr.ut_time), 518 1.4 christos sizeof (usr.ut_line), usr.ut_line, 519 1.4 christos sizeof (usr.ut_name), usr.ut_name); 520 1.4 christos #endif 521 1.1 cgd } else 522 1.1 cgd head = log_out(head, &usr); 523 1.1 cgd break; 524 1.1 cgd } 525 1.1 cgd } 526 1.1 cgd (void)fclose(fp); 527 1.1 cgd usr.ut_time = time((time_t *)0); 528 1.1 cgd (void)strcpy(usr.ut_line, "~"); 529 1.1 cgd 530 1.1 cgd if (Flags & AC_D) { 531 1.1 cgd ltm = localtime(&usr.ut_time); 532 1.1 cgd if (day >= 0 && day != ltm->tm_yday) { 533 1.1 cgd /* 534 1.1 cgd * print yesterday's total 535 1.1 cgd */ 536 1.1 cgd secs = usr.ut_time; 537 1.1 cgd secs -= ltm->tm_sec; 538 1.1 cgd secs -= 60 * ltm->tm_min; 539 1.1 cgd secs -= 3600 * ltm->tm_hour; 540 1.1 cgd show_today(Users, head, secs); 541 1.1 cgd } 542 1.1 cgd } 543 1.1 cgd /* 544 1.1 cgd * anyone still logged in gets time up to now 545 1.1 cgd */ 546 1.1 cgd head = log_out(head, &usr); 547 1.1 cgd 548 1.1 cgd if (Flags & AC_D) 549 1.1 cgd show_today(Users, head, time((time_t *)0)); 550 1.1 cgd else { 551 1.1 cgd if (Flags & AC_P) 552 1.1 cgd show_users(Users); 553 1.1 cgd show("total", Total); 554 1.1 cgd } 555 1.1 cgd return 0; 556 1.1 cgd } 557 1.1 cgd 558 1.4 christos static void 559 1.21 xtraeme usage(void) 560 1.1 cgd { 561 1.4 christos 562 1.1 cgd (void)fprintf(stderr, 563 1.18 jmmv "usage: %s [-d | -p] [-t tty] [-w wtmp] [users ...]\n", 564 1.14 cgd getprogname()); 565 1.1 cgd exit(1); 566 1.1 cgd } 567