]>
git.saurik.com Git - apple/system_cmds.git/blob - ac.tproj/ac.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1994 Christopher G. Demetriou.
26 * @(#)Copyright (c) 1994, Simon J. Gerraty.
28 * This is free software. It comes with NO WARRANTY.
29 * Permission to use, modify and distribute this source code
30 * is granted subject to the following conditions.
31 * 1/ that the above copyright notice and this notice
32 * are preserved in all copies and that due credit be given
34 * 2/ that any changes to this code are clearly commented
35 * as such so that the author does not get blamed for bugs
40 #include <sys/cdefs.h>
41 __unused
static char rcsid
[] = "$Id: ac.c,v 1.2 2006/02/07 05:51:22 lindak Exp $";
44 #include <sys/types.h>
56 #define UT_NAMESIZE 8 /* from utmp.h; only for formatting */
59 * this is for our list of currently logged in sessions
62 struct utmp_list
*next
;
67 * this is for our list of users that are accumulating time.
70 struct user_list
*next
;
71 char name
[_UTX_USERSIZE
+1];
76 * this is for chosing whether to ignore a login
79 struct tty_list
*next
;
80 char name
[_UTX_USERSIZE
+3];
89 static char *Console
= CONSOLE_TTY
;
91 static time_t Total
= 0;
92 static time_t FirstTime
= 0;
94 static struct user_list
*Users
= NULL
;
95 static struct tty_list
*Ttys
= NULL
;
97 #define NEW(type) (type *)malloc(sizeof (type))
99 #define AC_W 1 /* not _PATH_WTMP */
100 #define AC_D 2 /* daily totals (ignore -p) */
101 #define AC_P 4 /* per-user totals */
102 #define AC_U 8 /* specified users only */
103 #define AC_T 16 /* specified ttys only */
106 static int Debug
= 0;
109 int main
__P((int, char **));
111 struct tty_list
*add_tty
__P((char *));
112 int do_tty
__P((char *));
113 struct utmp_list
*log_in
__P((struct utmp_list
*, struct utmpx
*));
114 struct utmp_list
*log_out
__P((struct utmp_list
*, struct utmpx
*));
115 int on_console
__P((struct utmp_list
*));
116 void show
__P((char *, time_t));
117 void show_today
__P((struct user_list
*, struct utmp_list
*,
119 void show_users
__P((struct user_list
*));
120 struct user_list
*update_user
__P((struct user_list
*, char *, time_t));
121 void usage
__P((void));
132 if ((tp
= NEW(struct tty_list
)) == NULL
)
134 tp
->len
= 0; /* full match */
135 tp
->ret
= 1; /* do if match */
136 if (*name
== '!') { /* don't do if match */
140 (void)strncpy(tp
->name
, name
, sizeof (tp
->name
) - 1);
141 tp
->name
[sizeof (tp
->name
) - 1] = '\0';
142 if ((rcp
= strchr(tp
->name
, '*')) != NULL
) { /* wild card */
144 tp
->len
= (int)strlen(tp
->name
); /* match len bytes only */
152 * should we process the named tty?
161 for (tp
= Ttys
; tp
!= NULL
; tp
= tp
->next
) {
162 if (tp
->ret
== 0) /* specific don't */
163 def_ret
= 1; /* default do */
165 if (strncmp(name
, tp
->name
, tp
->len
) == 0)
168 if (strncmp(name
, tp
->name
, sizeof (tp
->name
)) == 0)
177 * is someone logged in on Console?
181 struct utmp_list
*head
;
183 struct utmp_list
*up
;
185 for (up
= head
; up
; up
= up
->next
) {
186 if (strncmp(up
->usr
.ut_line
, Console
,
187 sizeof (up
->usr
.ut_line
)) == 0)
195 * update user's login time
198 update_user(head
, name
, secs
)
199 struct user_list
*head
;
203 struct user_list
*up
;
205 for (up
= head
; up
!= NULL
; up
= up
->next
) {
206 if (strncmp(up
->name
, name
, sizeof (up
->name
)) == 0) {
213 * not found so add new user unless specified users only
218 if ((up
= NEW(struct user_list
)) == NULL
)
221 (void)strncpy(up
->name
, name
, sizeof (up
->name
) - 1);
222 up
->name
[sizeof (up
->name
) - 1] = '\0'; /* paranoid! */
237 while ((c
= getopt(argc
, argv
, "Dc:dpt:w:")) != EOF
) {
257 case 't': /* only do specified ttys */
271 * initialize user list
273 for (; optind
< argc
; optind
++) {
274 Users
= update_user(Users
, argv
[optind
], 0L);
276 Flags
|= AC_U
; /* freeze user list */
286 * print login time in decimal hours
293 (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE
, name
,
294 ((double)secs
/ 3600));
299 struct user_list
*list
;
301 struct user_list
*lp
;
303 for (lp
= list
; lp
; lp
= lp
->next
)
304 show(lp
->name
, lp
->secs
);
308 * print total login time for 24hr period in decimal hours
311 show_today(users
, logins
, secs
)
312 struct user_list
*users
;
313 struct utmp_list
*logins
;
316 struct user_list
*up
;
317 struct utmp_list
*lp
;
319 time_t yesterday
= secs
- 1;
321 (void)strftime(date
, sizeof (date
), "%b %e total",
322 localtime(&yesterday
));
324 /* restore the missing second */
327 for (lp
= logins
; lp
!= NULL
; lp
= lp
->next
) {
328 secs
= yesterday
- lp
->usr
.ut_tv
.tv_sec
;
329 Users
= update_user(Users
, lp
->usr
.ut_user
, secs
);
330 lp
->usr
.ut_tv
.tv_sec
= yesterday
; /* as if they just logged in */
333 for (up
= users
; up
!= NULL
; up
= up
->next
) {
335 up
->secs
= 0; /* for next day */
338 (void)printf("%s %11.2f\n", date
, ((double)secs
/ 3600));
342 * log a user out and update their times.
343 * if ut_line is "~", we log all users out as the system has
348 struct utmp_list
*head
;
351 struct utmp_list
*lp
, *lp2
, *tlp
;
354 for (lp
= head
, lp2
= NULL
; lp
!= NULL
; )
355 if (up
->ut_type
== BOOT_TIME
|| up
->ut_type
== SHUTDOWN_TIME
|| strncmp(lp
->usr
.ut_line
, up
->ut_line
,
356 sizeof (up
->ut_line
)) == 0) {
357 secs
= up
->ut_tv
.tv_sec
- lp
->usr
.ut_tv
.tv_sec
;
358 Users
= update_user(Users
, lp
->usr
.ut_user
, secs
);
361 printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
362 19, ctime(&up
->ut_tv
.tv_sec
),
363 (int)sizeof (lp
->usr
.ut_line
), lp
->usr
.ut_line
,
364 (int)sizeof (lp
->usr
.ut_user
), lp
->usr
.ut_user
,
365 secs
/ 3600, (secs
% 3600) / 60, secs
% 60);
374 else if (lp2
!= NULL
)
386 * if do_tty says ok, login a user
390 struct utmp_list
*head
;
393 struct utmp_list
*lp
;
396 * this could be a login. if we're not dealing with
397 * the console name, say it is.
399 * If we are, and if ut_host==":0.0" we know that it
400 * isn't a real login. _But_ if we have not yet recorded
401 * someone being logged in on Console - due to the wtmp
402 * file starting after they logged in, we'll pretend they
403 * logged in, at the start of the wtmp file.
407 if (up
->ut_host
[0] == ':') {
409 * SunOS 4.0.2 does not treat ":0.0" as special but we
412 if (on_console(head
))
415 * ok, no recorded login, so they were here when wtmp
416 * started! Adjust ut_tv.tv_sec!
418 up
->ut_tv
.tv_sec
= FirstTime
;
420 * this allows us to pick the right logout
422 (void)strncpy(up
->ut_line
, Console
, sizeof (up
->ut_line
) - 1);
423 up
->ut_line
[sizeof (up
->ut_line
) - 1] = '\0'; /* paranoid! */
427 * If we are doing specified ttys only, we ignore
431 if (!do_tty(up
->ut_line
))
435 * go ahead and log them in
437 if ((lp
= NEW(struct utmp_list
)) == NULL
)
441 memmove((char *)&lp
->usr
, (char *)up
, sizeof (struct utmpx
));
444 printf("%-.*s %-.*s: %-.*s logged in", 19,
445 ctime(&lp
->usr
.ut_tv
.tv_sec
), (int)sizeof (up
->ut_line
),
446 up
->ut_line
, (int)sizeof (up
->ut_user
), up
->ut_user
);
448 printf(" (%-.*s)", (int)sizeof (up
->ut_host
), up
->ut_host
);
458 struct utmp_list
*lp
, *head
= NULL
;
459 struct utmpx
*u
, end
;
464 setutxent_wtmp(1); /* read in forward direction */
465 while ((u
= getutxent_wtmp()) != NULL
) {
467 FirstTime
= u
->ut_tv
.tv_sec
;
469 ltm
= localtime(&u
->ut_tv
.tv_sec
);
470 if (day
>= 0 && day
!= ltm
->tm_yday
) {
473 * print yesterday's total
475 secs
= u
->ut_tv
.tv_sec
;
477 secs
-= 60 * ltm
->tm_min
;
478 secs
-= 3600 * ltm
->tm_hour
;
479 show_today(Users
, head
, secs
);
485 secs
= u
->ut_tv
.tv_sec
;
488 secs
-= u
->ut_tv
.tv_sec
;
490 * adjust time for those logged in
492 for (lp
= head
; lp
!= NULL
; lp
= lp
->next
)
493 lp
->usr
.ut_tv
.tv_sec
-= secs
;
495 case BOOT_TIME
: /* reboot or shutdown */
497 head
= log_out(head
, u
);
498 FirstTime
= u
->ut_tv
.tv_sec
; /* shouldn't be needed */
502 * if they came in on tty[p-y]*, then it is only
503 * a login session if the ut_host field is non-empty
505 if (strncmp(u
->ut_line
, "tty", 3) != 0 ||
506 strchr("pqrstuvwxy", u
->ut_line
[3]) == 0 ||
508 head
= log_in(head
, u
);
511 head
= log_out(head
, u
);
516 bzero(&end
, sizeof(end
));
517 end
.ut_tv
.tv_sec
= time((time_t *)0);
518 end
.ut_type
= SHUTDOWN_TIME
;
521 ltm
= localtime(&end
.ut_tv
.tv_sec
);
522 if (day
>= 0 && day
!= ltm
->tm_yday
) {
524 * print yesterday's total
526 secs
= end
.ut_tv
.tv_sec
;
528 secs
-= 60 * ltm
->tm_min
;
529 secs
-= 3600 * ltm
->tm_hour
;
530 show_today(Users
, head
, secs
);
534 * anyone still logged in gets time up to now
536 head
= log_out(head
, &end
);
539 show_today(Users
, head
, time((time_t *)0));
543 show("total", Total
);
551 (void)fprintf(stderr
,
553 "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n");
555 "ac [-dp] [-t tty] [-w wtmp] [users ...]\n");