]>
git.saurik.com Git - apple/system_cmds.git/blob - ac.tproj/ac.c
2 * Copyright (c) 1999-2016 Apple 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));
131 if ((tp
= NEW(struct tty_list
)) == NULL
)
133 tp
->len
= 0; /* full match */
134 tp
->ret
= 1; /* do if match */
135 if (*name
== '!') { /* don't do if match */
139 (void)strncpy(tp
->name
, name
, sizeof (tp
->name
) - 1);
140 tp
->name
[sizeof (tp
->name
) - 1] = '\0';
141 if ((rcp
= strchr(tp
->name
, '*')) != NULL
) { /* wild card */
143 tp
->len
= (int)strlen(tp
->name
); /* match len bytes only */
151 * should we process the named tty?
159 for (tp
= Ttys
; tp
!= NULL
; tp
= tp
->next
) {
160 if (tp
->ret
== 0) /* specific don't */
161 def_ret
= 1; /* default do */
163 if (strncmp(name
, tp
->name
, tp
->len
) == 0)
166 if (strncmp(name
, tp
->name
, sizeof (tp
->name
)) == 0)
175 * is someone logged in on Console?
178 on_console(struct utmp_list
*head
)
180 struct utmp_list
*up
;
182 for (up
= head
; up
; up
= up
->next
) {
183 if (strncmp(up
->usr
.ut_line
, Console
,
184 sizeof (up
->usr
.ut_line
)) == 0)
192 * update user's login time
195 update_user(struct user_list
*head
, char *name
, time_t secs
)
197 struct user_list
*up
;
199 for (up
= head
; up
!= NULL
; up
= up
->next
) {
200 if (strncmp(up
->name
, name
, sizeof (up
->name
)) == 0) {
207 * not found so add new user unless specified users only
212 if ((up
= NEW(struct user_list
)) == NULL
)
215 (void)strncpy(up
->name
, name
, sizeof (up
->name
) - 1);
216 up
->name
[sizeof (up
->name
) - 1] = '\0'; /* paranoid! */
223 main(int argc
, char **argv
)
229 while ((c
= getopt(argc
, argv
, "Dc:dpt:w:")) != EOF
) {
249 case 't': /* only do specified ttys */
263 * initialize user list
265 for (; optind
< argc
; optind
++) {
266 Users
= update_user(Users
, argv
[optind
], 0L);
268 Flags
|= AC_U
; /* freeze user list */
278 * print login time in decimal hours
281 show(char *name
, time_t secs
)
283 (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE
, name
,
284 ((double)secs
/ 3600));
288 show_users(struct user_list
*list
)
290 struct user_list
*lp
;
292 for (lp
= list
; lp
; lp
= lp
->next
)
293 show(lp
->name
, lp
->secs
);
297 * print total login time for 24hr period in decimal hours
300 show_today(struct user_list
*users
, struct utmp_list
*logins
, time_t secs
)
302 struct user_list
*up
;
303 struct utmp_list
*lp
;
305 time_t yesterday
= secs
- 1;
307 (void)strftime(date
, sizeof (date
), "%b %e total",
308 localtime(&yesterday
));
310 /* restore the missing second */
313 for (lp
= logins
; lp
!= NULL
; lp
= lp
->next
) {
314 secs
= yesterday
- lp
->usr
.ut_tv
.tv_sec
;
315 Users
= update_user(Users
, lp
->usr
.ut_user
, secs
);
316 lp
->usr
.ut_tv
.tv_sec
= yesterday
; /* as if they just logged in */
319 for (up
= users
; up
!= NULL
; up
= up
->next
) {
321 up
->secs
= 0; /* for next day */
324 (void)printf("%s %11.2f\n", date
, ((double)secs
/ 3600));
328 * log a user out and update their times.
329 * if ut_line is "~", we log all users out as the system has
333 log_out(struct utmp_list
*head
, struct utmpx
*up
)
335 struct utmp_list
*lp
, *lp2
, *tlp
;
338 for (lp
= head
, lp2
= NULL
; lp
!= NULL
; )
339 if (up
->ut_type
== BOOT_TIME
|| up
->ut_type
== SHUTDOWN_TIME
|| strncmp(lp
->usr
.ut_line
, up
->ut_line
,
340 sizeof (up
->ut_line
)) == 0) {
341 secs
= up
->ut_tv
.tv_sec
- lp
->usr
.ut_tv
.tv_sec
;
342 Users
= update_user(Users
, lp
->usr
.ut_user
, secs
);
345 printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
346 19, ctime(&up
->ut_tv
.tv_sec
),
347 (int)sizeof (lp
->usr
.ut_line
), lp
->usr
.ut_line
,
348 (int)sizeof (lp
->usr
.ut_user
), lp
->usr
.ut_user
,
349 secs
/ 3600, (secs
% 3600) / 60, secs
% 60);
358 else if (lp2
!= NULL
)
370 * if do_tty says ok, login a user
373 log_in(struct utmp_list
*head
, struct utmpx
*up
)
375 struct utmp_list
*lp
;
378 * this could be a login. if we're not dealing with
379 * the console name, say it is.
381 * If we are, and if ut_host==":0.0" we know that it
382 * isn't a real login. _But_ if we have not yet recorded
383 * someone being logged in on Console - due to the wtmp
384 * file starting after they logged in, we'll pretend they
385 * logged in, at the start of the wtmp file.
389 if (up
->ut_host
[0] == ':') {
391 * SunOS 4.0.2 does not treat ":0.0" as special but we
394 if (on_console(head
))
397 * ok, no recorded login, so they were here when wtmp
398 * started! Adjust ut_tv.tv_sec!
400 up
->ut_tv
.tv_sec
= FirstTime
;
402 * this allows us to pick the right logout
404 (void)strncpy(up
->ut_line
, Console
, sizeof (up
->ut_line
) - 1);
405 up
->ut_line
[sizeof (up
->ut_line
) - 1] = '\0'; /* paranoid! */
409 * If we are doing specified ttys only, we ignore
413 if (!do_tty(up
->ut_line
))
417 * go ahead and log them in
419 if ((lp
= NEW(struct utmp_list
)) == NULL
)
423 memmove((char *)&lp
->usr
, (char *)up
, sizeof (struct utmpx
));
426 printf("%-.*s %-.*s: %-.*s logged in", 19,
427 ctime(&lp
->usr
.ut_tv
.tv_sec
), (int)sizeof (up
->ut_line
),
428 up
->ut_line
, (int)sizeof (up
->ut_user
), up
->ut_user
);
430 printf(" (%-.*s)", (int)sizeof (up
->ut_host
), up
->ut_host
);
440 struct utmp_list
*lp
, *head
= NULL
;
441 struct utmpx
*u
, end
;
446 setutxent_wtmp(1); /* read in forward direction */
447 while ((u
= getutxent_wtmp()) != NULL
) {
449 FirstTime
= u
->ut_tv
.tv_sec
;
451 ltm
= localtime(&u
->ut_tv
.tv_sec
);
452 if (day
>= 0 && day
!= ltm
->tm_yday
) {
455 * print yesterday's total
457 secs
= u
->ut_tv
.tv_sec
;
459 secs
-= 60 * ltm
->tm_min
;
460 secs
-= 3600 * ltm
->tm_hour
;
461 show_today(Users
, head
, secs
);
467 secs
= u
->ut_tv
.tv_sec
;
470 secs
-= u
->ut_tv
.tv_sec
;
472 * adjust time for those logged in
474 for (lp
= head
; lp
!= NULL
; lp
= lp
->next
)
475 lp
->usr
.ut_tv
.tv_sec
-= secs
;
477 case BOOT_TIME
: /* reboot or shutdown */
479 head
= log_out(head
, u
);
480 FirstTime
= u
->ut_tv
.tv_sec
; /* shouldn't be needed */
484 * if they came in on tty[p-y]*, then it is only
485 * a login session if the ut_host field is non-empty
487 if (strncmp(u
->ut_line
, "tty", 3) != 0 ||
488 strchr("pqrstuvwxy", u
->ut_line
[3]) == 0 ||
490 head
= log_in(head
, u
);
493 head
= log_out(head
, u
);
498 bzero(&end
, sizeof(end
));
499 end
.ut_tv
.tv_sec
= time((time_t *)0);
500 end
.ut_type
= SHUTDOWN_TIME
;
503 ltm
= localtime(&end
.ut_tv
.tv_sec
);
504 if (day
>= 0 && day
!= ltm
->tm_yday
) {
506 * print yesterday's total
508 secs
= end
.ut_tv
.tv_sec
;
510 secs
-= 60 * ltm
->tm_min
;
511 secs
-= 3600 * ltm
->tm_hour
;
512 show_today(Users
, head
, secs
);
516 * anyone still logged in gets time up to now
518 head
= log_out(head
, &end
);
521 show_today(Users
, head
, time((time_t *)0));
525 show("total", Total
);
533 (void)fprintf(stderr
,
535 "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n");
537 "ac [-dp] [-t tty] [-w wtmp] [users ...]\n");