2 * Copyright (c) 1994 Christopher G. Demetriou.
3 * @(#)Copyright (c) 1994, Simon J. Gerraty.
5 * This is free software. It comes with NO WARRANTY.
6 * Permission to use, modify and distribute this source code
7 * is granted subject to the following conditions.
8 * 1/ that the above copyright notice and this notice
9 * are preserved in all copies and that due credit be given
11 * 2/ that any changes to this code are clearly commented
12 * as such so that the author does not get blamed for bugs
15 * $FreeBSD: src/usr.sbin/ac/ac.c,v 1.14.2.2 2002/03/12 19:55:04 phantom Exp $
18 #include <sys/types.h>
33 * this is for our list of currently logged in sessions
36 struct utmp_list
*next
;
41 * this is for our list of users that are accumulating time.
44 struct user_list
*next
;
45 char name
[UT_NAMESIZE
+1];
50 * this is for chosing whether to ignore a login
53 struct tty_list
*next
;
54 char name
[UT_LINESIZE
+3];
63 static char *Console
= CONSOLE_TTY
;
65 static time_t Total
= 0;
66 static time_t FirstTime
= 0;
68 static struct user_list
*Users
= NULL
;
69 static struct tty_list
*Ttys
= NULL
;
71 #define NEW(type) (type *)malloc(sizeof(type))
73 #define AC_W 1 /* not _PATH_WTMP */
74 #define AC_D 2 /* daily totals (ignore -p) */
75 #define AC_P 4 /* per-user totals */
76 #define AC_U 8 /* specified users only */
77 #define AC_T 16 /* specified ttys only */
84 struct tty_list
*add_tty(char *);
87 struct utmp_list
*log_in(struct utmp_list
*, struct utmp
*);
88 struct utmp_list
*log_out(struct utmp_list
*, struct utmp
*);
89 int on_console(struct utmp_list
*);
90 void show(char *, time_t);
91 void show_today(struct user_list
*, struct utmp_list
*,
93 void show_users(struct user_list
*);
94 struct user_list
*update_user(struct user_list
*, char *, time_t);
105 if ((fp
= fopen(name
, "r")) == NULL
)
107 /* in case we want to discriminate */
108 if (strcmp(_PATH_WTMP
, name
))
121 if ((tp
= NEW(struct tty_list
)) == NULL
)
122 errx(1, "malloc failed");
123 tp
->len
= 0; /* full match */
124 tp
->ret
= 1; /* do if match */
125 if (*name
== '!') { /* don't do if match */
129 strncpy(tp
->name
, name
, sizeof(tp
->name
) - 1);
130 tp
->name
[sizeof(tp
->name
) - 1] = '\0';
131 if ((rcp
= strchr(tp
->name
, '*')) != NULL
) { /* wild card */
133 tp
->len
= strlen(tp
->name
); /* match len bytes only */
141 * should we process the named tty?
149 for (tp
= Ttys
; tp
!= NULL
; tp
= tp
->next
) {
150 if (tp
->ret
== 0) /* specific don't */
151 def_ret
= 1; /* default do */
153 if (strncmp(name
, tp
->name
, tp
->len
) == 0)
156 if (strncmp(name
, tp
->name
, sizeof(tp
->name
)) == 0)
165 * is someone logged in on Console?
168 on_console(struct utmp_list
*head
)
170 struct utmp_list
*up
;
172 for (up
= head
; up
; up
= up
->next
) {
173 if (strncmp(up
->usr
.ut_line
, Console
,
174 sizeof(up
->usr
.ut_line
)) == 0)
182 * update user's login time
185 update_user(struct user_list
*head
, char *name
, time_t secs
)
187 struct user_list
*up
;
189 for (up
= head
; up
!= NULL
; up
= up
->next
) {
190 if (strncmp(up
->name
, name
, UT_NAMESIZE
) == 0) {
197 * not found so add new user unless specified users only
202 if ((up
= NEW(struct user_list
)) == NULL
)
203 errx(1, "malloc failed");
205 strncpy(up
->name
, name
, sizeof(up
->name
) - 1);
206 up
->name
[sizeof(up
->name
) - 1] = '\0'; /* paranoid! */
213 main(int argc
, char **argv
)
218 setlocale(LC_TIME
, "");
221 while ((c
= getopt(argc
, argv
, "Dc:dpt:w:")) != -1) {
241 case 't': /* only do specified ttys */
255 * initialize user list
257 for (; optind
< argc
; optind
++) {
258 Users
= update_user(Users
, argv
[optind
], 0L);
260 Flags
|= AC_U
; /* freeze user list */
266 * if _PATH_WTMP does not exist, exit quietly
268 if (access(_PATH_WTMP
, 0) != 0 && errno
== ENOENT
)
271 fp
= file(_PATH_WTMP
);
279 * print login time in decimal hours
282 show(char *name
, time_t secs
)
284 printf("\t%-*s %8.2f\n", UT_NAMESIZE
, name
,
285 ((double)secs
/ 3600));
289 show_users(struct user_list
*list
)
291 struct user_list
*lp
;
293 for (lp
= list
; lp
; lp
= lp
->next
)
294 show(lp
->name
, lp
->secs
);
298 * print total login time for 24hr period in decimal hours
301 show_today(struct user_list
*users
, struct utmp_list
*logins
, time_t secs
)
303 struct user_list
*up
;
304 struct utmp_list
*lp
;
306 time_t yesterday
= secs
- 1;
307 static int d_first
= -1;
310 d_first
= (*nl_langinfo(D_MD_ORDER
) == 'd');
311 strftime(date
, sizeof(date
),
312 d_first
? "%e %b total" : "%b %e total",
313 localtime(&yesterday
));
315 /* restore the missing second */
318 for (lp
= logins
; lp
!= NULL
; lp
= lp
->next
) {
319 secs
= yesterday
- lp
->usr
.ut_time
;
320 Users
= update_user(Users
, lp
->usr
.ut_name
, secs
);
321 lp
->usr
.ut_time
= yesterday
; /* as if they just logged in */
324 for (up
= users
; up
!= NULL
; up
= up
->next
) {
326 up
->secs
= 0; /* for next day */
329 printf("%s %11.2f\n", date
, ((double)secs
/ 3600));
333 * log a user out and update their times.
334 * if ut_line is "~", we log all users out as the system has
338 log_out(struct utmp_list
*head
, struct utmp
*up
)
340 struct utmp_list
*lp
, *lp2
, *tlp
;
343 for (lp
= head
, lp2
= NULL
; lp
!= NULL
; )
344 if (*up
->ut_line
== '~' || strncmp(lp
->usr
.ut_line
, up
->ut_line
,
345 sizeof(up
->ut_line
)) == 0) {
346 secs
= up
->ut_time
- lp
->usr
.ut_time
;
347 Users
= update_user(Users
, lp
->usr
.ut_name
, secs
);
350 printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
351 19, ctime(&up
->ut_time
),
352 sizeof(lp
->usr
.ut_line
), lp
->usr
.ut_line
,
353 sizeof(lp
->usr
.ut_name
), lp
->usr
.ut_name
,
354 secs
/ 3600, (secs
% 3600) / 60, secs
% 60);
363 else if (lp2
!= NULL
)
375 * if do_tty says ok, login a user
378 log_in(struct utmp_list
*head
, struct utmp
*up
)
380 struct utmp_list
*lp
;
383 * this could be a login. if we're not dealing with
384 * the console name, say it is.
386 * If we are, and if ut_host==":0.0" we know that it
387 * isn't a real login. _But_ if we have not yet recorded
388 * someone being logged in on Console - due to the wtmp
389 * file starting after they logged in, we'll pretend they
390 * logged in, at the start of the wtmp file.
394 if (up
->ut_host
[0] == ':') {
396 * SunOS 4.0.2 does not treat ":0.0" as special but we
399 if (on_console(head
))
402 * ok, no recorded login, so they were here when wtmp
403 * started! Adjust ut_time!
405 up
->ut_time
= FirstTime
;
407 * this allows us to pick the right logout
409 strncpy(up
->ut_line
, Console
, sizeof(up
->ut_line
) - 1);
410 up
->ut_line
[sizeof(up
->ut_line
) - 1] = '\0'; /* paranoid! */
414 * If we are doing specified ttys only, we ignore
418 if (!do_tty(up
->ut_line
))
422 * go ahead and log them in
424 if ((lp
= NEW(struct utmp_list
)) == NULL
)
425 errx(1, "malloc failed");
428 memmove((char *)&lp
->usr
, (char *)up
, sizeof(struct utmp
));
431 printf("%-.*s %-.*s: %-.*s logged in", 19,
432 ctime(&lp
->usr
.ut_time
), sizeof(up
->ut_line
),
433 up
->ut_line
, sizeof(up
->ut_name
), up
->ut_name
);
435 printf(" (%-.*s)", sizeof(up
->ut_host
), up
->ut_host
);
445 struct utmp_list
*lp
, *head
= NULL
;
451 while (fread((char *)&usr
, sizeof(usr
), 1, fp
) == 1) {
453 FirstTime
= usr
.ut_time
;
455 ltm
= localtime(&usr
.ut_time
);
456 if (day
>= 0 && day
!= ltm
->tm_yday
) {
459 * print yesterday's total
463 secs
-= 60 * ltm
->tm_min
;
464 secs
-= 3600 * ltm
->tm_hour
;
465 show_today(Users
, head
, secs
);
469 switch(*usr
.ut_line
) {
476 * adjust time for those logged in
478 for (lp
= head
; lp
!= NULL
; lp
= lp
->next
)
479 lp
->usr
.ut_time
-= secs
;
481 case '~': /* reboot or shutdown */
482 head
= log_out(head
, &usr
);
483 FirstTime
= usr
.ut_time
; /* shouldn't be needed */
487 * if they came in on tty[p-sP-S]*, then it is only
488 * a login session if the ut_host field is non-empty
491 if (strncmp(usr
.ut_line
, "tty", 3) != 0 ||
492 strchr("pqrsPQRS", usr
.ut_line
[3]) == 0 ||
493 *usr
.ut_host
!= '\0')
494 head
= log_in(head
, &usr
);
496 head
= log_out(head
, &usr
);
502 usr
.ut_time
= time(NULL
);
503 strcpy(usr
.ut_line
, "~");
506 ltm
= localtime(&usr
.ut_time
);
507 if (day
>= 0 && day
!= ltm
->tm_yday
) {
509 * print yesterday's total
513 secs
-= 60 * ltm
->tm_min
;
514 secs
-= 3600 * ltm
->tm_hour
;
515 show_today(Users
, head
, secs
);
519 * anyone still logged in gets time up to now
521 head
= log_out(head
, &usr
);
524 show_today(Users
, head
, time(NULL
));
528 show("total", Total
);
538 "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n");
540 "ac [-dp] [-t tty] [-w wtmp] [users ...]\n");