xref: /openbsd/usr.sbin/ac/ac.c (revision ce7279d8)
1e48d0af3Smillert /*-
2e48d0af3Smillert  * Copyright (c) 1994 Christopher G. Demetriou
3e48d0af3Smillert  * Copyright (c) 1994 Simon J. Gerraty
4e48d0af3Smillert  * All rights reserved.
5df930be7Sderaadt  *
6e48d0af3Smillert  * Redistribution and use in source and binary forms, with or without
7e48d0af3Smillert  * modification, are permitted provided that the following conditions
8e48d0af3Smillert  * are met:
9e48d0af3Smillert  * 1. Redistributions of source code must retain the above copyright
10e48d0af3Smillert  *    notice, this list of conditions and the following disclaimer.
11e48d0af3Smillert  * 2. Redistributions in binary form must reproduce the above copyright
12e48d0af3Smillert  *    notice, this list of conditions and the following disclaimer in the
13e48d0af3Smillert  *    documentation and/or other materials provided with the distribution.
14e48d0af3Smillert  *
15e48d0af3Smillert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e48d0af3Smillert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e48d0af3Smillert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e48d0af3Smillert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e48d0af3Smillert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e48d0af3Smillert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e48d0af3Smillert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e48d0af3Smillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e48d0af3Smillert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e48d0af3Smillert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e48d0af3Smillert  * SUCH DAMAGE.
26df930be7Sderaadt  */
27df930be7Sderaadt 
28df930be7Sderaadt #include <sys/time.h>
29f4147939Sguenther 
30df930be7Sderaadt #include <err.h>
31df930be7Sderaadt #include <errno.h>
32df930be7Sderaadt #include <pwd.h>
33df930be7Sderaadt #include <stdio.h>
34df930be7Sderaadt #include <stdlib.h>
35df930be7Sderaadt #include <string.h>
36df930be7Sderaadt #include <utmp.h>
37df930be7Sderaadt #include <unistd.h>
38df930be7Sderaadt 
39df930be7Sderaadt /*
40df930be7Sderaadt  * this is for our list of currently logged in sessions
41df930be7Sderaadt  */
42df930be7Sderaadt struct utmp_list {
43df930be7Sderaadt 	struct utmp_list *next;
44df930be7Sderaadt 	struct utmp usr;
45df930be7Sderaadt };
46df930be7Sderaadt 
47df930be7Sderaadt /*
48df930be7Sderaadt  * this is for our list of users that are accumulating time.
49df930be7Sderaadt  */
50df930be7Sderaadt struct user_list {
51df930be7Sderaadt 	struct user_list *next;
52df930be7Sderaadt 	char	name[UT_NAMESIZE+1];
53df930be7Sderaadt 	time_t	secs;
54df930be7Sderaadt };
55df930be7Sderaadt 
56df930be7Sderaadt /*
57*3a50f0a9Sjmc  * this is for choosing whether to ignore a login
58df930be7Sderaadt  */
59df930be7Sderaadt struct tty_list {
60df930be7Sderaadt 	struct tty_list *next;
61df930be7Sderaadt 	char	name[UT_LINESIZE+3];
629f305af3Sdhill 	size_t	len;
63df930be7Sderaadt 	int	ret;
64df930be7Sderaadt };
65df930be7Sderaadt 
66df930be7Sderaadt /*
67df930be7Sderaadt  * globals - yes yuk
68df930be7Sderaadt  */
69df930be7Sderaadt static time_t	Total = 0;
70df930be7Sderaadt static time_t	FirstTime = 0;
71df930be7Sderaadt static int	Flags = 0;
72df930be7Sderaadt static struct user_list *Users = NULL;
73df930be7Sderaadt static struct tty_list *Ttys = NULL;
74df930be7Sderaadt 
75df930be7Sderaadt #define	AC_W	1				/* not _PATH_WTMP */
76df930be7Sderaadt #define	AC_D	2				/* daily totals (ignore -p) */
77df930be7Sderaadt #define	AC_P	4				/* per-user totals */
78df930be7Sderaadt #define	AC_U	8				/* specified users only */
79df930be7Sderaadt #define	AC_T	16				/* specified ttys only */
80df930be7Sderaadt 
81df930be7Sderaadt #ifdef DEBUG
82df930be7Sderaadt static int Debug = 0;
83df930be7Sderaadt #endif
84df930be7Sderaadt 
85c72b5b24Smillert int			main(int, char **);
86c72b5b24Smillert int			ac(FILE *);
879f305af3Sdhill void			add_tty(char *);
88c72b5b24Smillert int			do_tty(char *);
89c72b5b24Smillert FILE			*file(char *);
90c72b5b24Smillert struct utmp_list	*log_in(struct utmp_list *, struct utmp *);
91c72b5b24Smillert struct utmp_list	*log_out(struct utmp_list *, struct utmp *);
92c72b5b24Smillert void			show(char *, time_t);
93f3c3a9c6Smillert void			show_today(struct user_list *, struct utmp_list *,
94f3c3a9c6Smillert 			    time_t);
95c72b5b24Smillert void			show_users(struct user_list *);
96c72b5b24Smillert struct user_list	*update_user(struct user_list *, char *, time_t);
97c72b5b24Smillert void			usage(void);
98df930be7Sderaadt 
99df930be7Sderaadt /*
100df930be7Sderaadt  * open wtmp or die
101df930be7Sderaadt  */
102df930be7Sderaadt FILE *
file(char * name)1034b6e8b27Sderaadt file(char *name)
104df930be7Sderaadt {
105df930be7Sderaadt 	FILE *fp;
106df930be7Sderaadt 
107559b49b0Spvalchev 	if (strcmp(name, "-") == 0)
108559b49b0Spvalchev 		fp = stdin;
109559b49b0Spvalchev 	else if ((fp = fopen(name, "r")) == NULL)
110df930be7Sderaadt 		err(1, "%s", name);
111df930be7Sderaadt 	/* in case we want to discriminate */
112df930be7Sderaadt 	if (strcmp(_PATH_WTMP, name))
113df930be7Sderaadt 		Flags |= AC_W;
114df930be7Sderaadt 	return fp;
115df930be7Sderaadt }
116df930be7Sderaadt 
1179f305af3Sdhill void
add_tty(char * name)1184b6e8b27Sderaadt add_tty(char *name)
119df930be7Sderaadt {
120df930be7Sderaadt 	struct tty_list *tp;
1214b6e8b27Sderaadt 	char *rcp;
122df930be7Sderaadt 
123df930be7Sderaadt 	Flags |= AC_T;
124df930be7Sderaadt 
1259f305af3Sdhill 	if ((tp = malloc(sizeof(struct tty_list))) == NULL)
126df930be7Sderaadt 		err(1, "malloc");
127df930be7Sderaadt 	tp->len = 0;				/* full match */
128df930be7Sderaadt 	tp->ret = 1;				/* do if match */
129df930be7Sderaadt 	if (*name == '!') {			/* don't do if match */
130df930be7Sderaadt 		tp->ret = 0;
131df930be7Sderaadt 		name++;
132df930be7Sderaadt 	}
1334f77c0acSmickey 	strlcpy(tp->name, name, sizeof (tp->name));
134df930be7Sderaadt 	if ((rcp = strchr(tp->name, '*')) != NULL) {	/* wild card */
135df930be7Sderaadt 		*rcp = '\0';
136df930be7Sderaadt 		tp->len = strlen(tp->name);	/* match len bytes only */
137df930be7Sderaadt 	}
138df930be7Sderaadt 	tp->next = Ttys;
139df930be7Sderaadt 	Ttys = tp;
140df930be7Sderaadt }
141df930be7Sderaadt 
142df930be7Sderaadt /*
143df930be7Sderaadt  * should we process the named tty?
144df930be7Sderaadt  */
145df930be7Sderaadt int
do_tty(char * name)1464b6e8b27Sderaadt do_tty(char *name)
147df930be7Sderaadt {
148df930be7Sderaadt 	struct tty_list *tp;
149df930be7Sderaadt 	int def_ret = 0;
150df930be7Sderaadt 
151df930be7Sderaadt 	for (tp = Ttys; tp != NULL; tp = tp->next) {
152df930be7Sderaadt 		if (tp->ret == 0)		/* specific don't */
153df930be7Sderaadt 			def_ret = 1;		/* default do */
154df930be7Sderaadt 		if (tp->len != 0) {
155df930be7Sderaadt 			if (strncmp(name, tp->name, tp->len) == 0)
156df930be7Sderaadt 				return tp->ret;
157df930be7Sderaadt 		} else {
158df930be7Sderaadt 			if (strncmp(name, tp->name, sizeof (tp->name)) == 0)
159df930be7Sderaadt 				return tp->ret;
160df930be7Sderaadt 		}
161df930be7Sderaadt 	}
162df930be7Sderaadt 	return def_ret;
163df930be7Sderaadt }
164df930be7Sderaadt 
165df930be7Sderaadt /*
166df930be7Sderaadt  * update user's login time
167df930be7Sderaadt  */
168df930be7Sderaadt struct user_list *
update_user(struct user_list * head,char * name,time_t secs)1694b6e8b27Sderaadt update_user(struct user_list *head, char *name, time_t secs)
170df930be7Sderaadt {
171df930be7Sderaadt 	struct user_list *up;
172df930be7Sderaadt 
173df930be7Sderaadt 	for (up = head; up != NULL; up = up->next) {
17465ed1f83Sderaadt 		if (strncmp(up->name, name, sizeof (up->name) - 1) == 0) {
175df930be7Sderaadt 			up->secs += secs;
176df930be7Sderaadt 			Total += secs;
177df930be7Sderaadt 			return head;
178df930be7Sderaadt 		}
179df930be7Sderaadt 	}
180df930be7Sderaadt 	/*
181df930be7Sderaadt 	 * not found so add new user unless specified users only
182df930be7Sderaadt 	 */
183df930be7Sderaadt 	if (Flags & AC_U)
184df930be7Sderaadt 		return head;
185df930be7Sderaadt 
1869f305af3Sdhill 	if ((up = malloc(sizeof(struct user_list))) == NULL)
187df930be7Sderaadt 		err(1, "malloc");
188df930be7Sderaadt 	up->next = head;
1893b868ddaSmestre 	strncpy(up->name, name, sizeof(up->name) - 1);
1903b868ddaSmestre 	up->name[sizeof(up->name) - 1] = '\0';
191df930be7Sderaadt 	up->secs = secs;
192df930be7Sderaadt 	Total += secs;
193df930be7Sderaadt 	return up;
194df930be7Sderaadt }
195df930be7Sderaadt 
196df930be7Sderaadt int
main(int argc,char * argv[])1974b6e8b27Sderaadt main(int argc, char *argv[])
198df930be7Sderaadt {
199df930be7Sderaadt 	FILE *fp;
200df930be7Sderaadt 	int c;
201df930be7Sderaadt 
2024823dc0dSderaadt 	if (pledge("stdio rpath", NULL) == -1)
2034823dc0dSderaadt 		err(1, "pledge");
2044823dc0dSderaadt 
205df930be7Sderaadt 	fp = NULL;
2068ac7991eSmillert 	while ((c = getopt(argc, argv, "Ddpt:w:")) != -1) {
207df930be7Sderaadt 		switch (c) {
208df930be7Sderaadt #ifdef DEBUG
209df930be7Sderaadt 		case 'D':
21028056f30Sderaadt 			Debug = 1;
211df930be7Sderaadt 			break;
212df930be7Sderaadt #endif
213df930be7Sderaadt 		case 'd':
214df930be7Sderaadt 			Flags |= AC_D;
215df930be7Sderaadt 			break;
216df930be7Sderaadt 		case 'p':
217df930be7Sderaadt 			Flags |= AC_P;
218df930be7Sderaadt 			break;
219df930be7Sderaadt 		case 't':			/* only do specified ttys */
220df930be7Sderaadt 			add_tty(optarg);
221df930be7Sderaadt 			break;
222df930be7Sderaadt 		case 'w':
223df930be7Sderaadt 			fp = file(optarg);
224df930be7Sderaadt 			break;
225df930be7Sderaadt 		default:
226df930be7Sderaadt 			usage();
227df930be7Sderaadt 			break;
228df930be7Sderaadt 		}
229df930be7Sderaadt 	}
230df930be7Sderaadt 	if (optind < argc) {
231df930be7Sderaadt 		/*
232df930be7Sderaadt 		 * initialize user list
233df930be7Sderaadt 		 */
234df930be7Sderaadt 		for (; optind < argc; optind++) {
235df930be7Sderaadt 			Users = update_user(Users, argv[optind], 0L);
236df930be7Sderaadt 		}
237df930be7Sderaadt 		Flags |= AC_U;			/* freeze user list */
238df930be7Sderaadt 	}
239df930be7Sderaadt 	if (Flags & AC_D)
240df930be7Sderaadt 		Flags &= ~AC_P;
241df930be7Sderaadt 	if (fp == NULL) {
242df930be7Sderaadt 		/*
243df930be7Sderaadt 		 * if _PATH_WTMP does not exist, exit quietly
244df930be7Sderaadt 		 */
245df930be7Sderaadt 		if (access(_PATH_WTMP, 0) != 0 && errno == ENOENT)
246df930be7Sderaadt 			return 0;
247df930be7Sderaadt 
248df930be7Sderaadt 		fp = file(_PATH_WTMP);
249df930be7Sderaadt 	}
250df930be7Sderaadt 	ac(fp);
251df930be7Sderaadt 
252df930be7Sderaadt 	return 0;
253df930be7Sderaadt }
254df930be7Sderaadt 
255df930be7Sderaadt /*
256df930be7Sderaadt  * print login time in decimal hours
257df930be7Sderaadt  */
258df930be7Sderaadt void
show(char * name,time_t secs)2594b6e8b27Sderaadt show(char *name, time_t secs)
260df930be7Sderaadt {
261df930be7Sderaadt 	(void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name,
262df930be7Sderaadt 	    ((double)secs / 3600));
263df930be7Sderaadt }
264df930be7Sderaadt 
265df930be7Sderaadt void
show_users(struct user_list * list)2664b6e8b27Sderaadt show_users(struct user_list *list)
267df930be7Sderaadt {
268df930be7Sderaadt 	struct user_list *lp;
269df930be7Sderaadt 
270df930be7Sderaadt 	for (lp = list; lp; lp = lp->next)
271df930be7Sderaadt 		show(lp->name, lp->secs);
272df930be7Sderaadt }
273df930be7Sderaadt 
274df930be7Sderaadt /*
275df930be7Sderaadt  * print total login time for 24hr period in decimal hours
276df930be7Sderaadt  */
277df930be7Sderaadt void
show_today(struct user_list * users,struct utmp_list * logins,time_t secs)2784b6e8b27Sderaadt show_today(struct user_list *users, struct utmp_list *logins, time_t secs)
279df930be7Sderaadt {
280df930be7Sderaadt 	struct user_list *up;
281df930be7Sderaadt 	struct utmp_list *lp;
282df930be7Sderaadt 	char date[64];
283df930be7Sderaadt 	time_t yesterday = secs - 1;
284df930be7Sderaadt 
285df930be7Sderaadt 	(void)strftime(date, sizeof (date), "%b %e  total",
286df930be7Sderaadt 	    localtime(&yesterday));
287df930be7Sderaadt 
288df930be7Sderaadt 	/* restore the missing second */
289df930be7Sderaadt 	yesterday++;
290df930be7Sderaadt 
291df930be7Sderaadt 	for (lp = logins; lp != NULL; lp = lp->next) {
292df930be7Sderaadt 		secs = yesterday - lp->usr.ut_time;
293df930be7Sderaadt 		Users = update_user(Users, lp->usr.ut_name, secs);
294df930be7Sderaadt 		lp->usr.ut_time = yesterday;	/* as if they just logged in */
295df930be7Sderaadt 	}
296df930be7Sderaadt 	secs = 0;
297df930be7Sderaadt 	for (up = users; up != NULL; up = up->next) {
298df930be7Sderaadt 		secs += up->secs;
299df930be7Sderaadt 		up->secs = 0;			/* for next day */
300df930be7Sderaadt 	}
301df930be7Sderaadt 	if (secs)
302df930be7Sderaadt 		(void)printf("%s %11.2f\n", date, ((double)secs / 3600));
303df930be7Sderaadt }
304df930be7Sderaadt 
305df930be7Sderaadt /*
306df930be7Sderaadt  * log a user out and update their times.
307df930be7Sderaadt  * if ut_line is "~", we log all users out as the system has
308df930be7Sderaadt  * been shut down.
309df930be7Sderaadt  */
310df930be7Sderaadt struct utmp_list *
log_out(struct utmp_list * head,struct utmp * up)3114b6e8b27Sderaadt log_out(struct utmp_list *head, struct utmp *up)
312df930be7Sderaadt {
313df930be7Sderaadt 	struct utmp_list *lp, *lp2, *tlp;
314df930be7Sderaadt 	time_t secs;
315df930be7Sderaadt 
316df930be7Sderaadt 	for (lp = head, lp2 = NULL; lp != NULL; )
317df930be7Sderaadt 		if (*up->ut_line == '~' || strncmp(lp->usr.ut_line, up->ut_line,
318df930be7Sderaadt 		    sizeof (up->ut_line)) == 0) {
319df930be7Sderaadt 			secs = up->ut_time - lp->usr.ut_time;
320df930be7Sderaadt 			Users = update_user(Users, lp->usr.ut_name, secs);
321df930be7Sderaadt #ifdef DEBUG
322df930be7Sderaadt 			if (Debug)
323df930be7Sderaadt 				printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
324df930be7Sderaadt 				    19, ctime(&up->ut_time),
325df930be7Sderaadt 				    sizeof (lp->usr.ut_line), lp->usr.ut_line,
326df930be7Sderaadt 				    sizeof (lp->usr.ut_name), lp->usr.ut_name,
327df930be7Sderaadt 				    secs / 3600, (secs % 3600) / 60, secs % 60);
328df930be7Sderaadt #endif
329df930be7Sderaadt 			/*
330df930be7Sderaadt 			 * now lose it
331df930be7Sderaadt 			 */
332df930be7Sderaadt 			tlp = lp;
333df930be7Sderaadt 			lp = lp->next;
334df930be7Sderaadt 			if (tlp == head)
335df930be7Sderaadt 				head = lp;
336df930be7Sderaadt 			else if (lp2 != NULL)
337df930be7Sderaadt 				lp2->next = lp;
338df930be7Sderaadt 			free(tlp);
339df930be7Sderaadt 		} else {
340df930be7Sderaadt 			lp2 = lp;
341df930be7Sderaadt 			lp = lp->next;
342df930be7Sderaadt 		}
343df930be7Sderaadt 	return head;
344df930be7Sderaadt }
345df930be7Sderaadt 
346df930be7Sderaadt 
347df930be7Sderaadt /*
348df930be7Sderaadt  * if do_tty says ok, login a user
349df930be7Sderaadt  */
350df930be7Sderaadt struct utmp_list *
log_in(struct utmp_list * head,struct utmp * up)3514b6e8b27Sderaadt log_in(struct utmp_list *head, struct utmp *up)
352df930be7Sderaadt {
353df930be7Sderaadt 	struct utmp_list *lp;
354df930be7Sderaadt 
355df930be7Sderaadt 	/*
356df930be7Sderaadt 	 * this could be a login. if we're not dealing with
357df930be7Sderaadt 	 * the console name, say it is.
358df930be7Sderaadt 	 *
359df930be7Sderaadt 	 * If we are, and if ut_host==":0.0" we know that it
360df930be7Sderaadt 	 * isn't a real login. _But_ if we have not yet recorded
361df930be7Sderaadt 	 * someone being logged in on Console - due to the wtmp
362df930be7Sderaadt 	 * file starting after they logged in, we'll pretend they
363df930be7Sderaadt 	 * logged in, at the start of the wtmp file.
364df930be7Sderaadt 	 */
365df930be7Sderaadt 
366df930be7Sderaadt 	/*
367df930be7Sderaadt 	 * If we are doing specified ttys only, we ignore
368df930be7Sderaadt 	 * anything else.
369df930be7Sderaadt 	 */
370df930be7Sderaadt 	if (Flags & AC_T)
371df930be7Sderaadt 		if (!do_tty(up->ut_line))
372df930be7Sderaadt 			return head;
373df930be7Sderaadt 
374df930be7Sderaadt 	/*
375df930be7Sderaadt 	 * go ahead and log them in
376df930be7Sderaadt 	 */
3779f305af3Sdhill 	if ((lp = malloc(sizeof(struct utmp_list))) == NULL)
378df930be7Sderaadt 		err(1, "malloc");
379df930be7Sderaadt 	lp->next = head;
380df930be7Sderaadt 	head = lp;
381df930be7Sderaadt 	memmove((char *)&lp->usr, (char *)up, sizeof (struct utmp));
382df930be7Sderaadt #ifdef DEBUG
383df930be7Sderaadt 	if (Debug) {
384df930be7Sderaadt 		printf("%-.*s %-.*s: %-.*s logged in", 19,
385df930be7Sderaadt 		    ctime(&lp->usr.ut_time), sizeof (up->ut_line),
386df930be7Sderaadt 		    up->ut_line, sizeof (up->ut_name), up->ut_name);
387df930be7Sderaadt 		if (*up->ut_host)
388df930be7Sderaadt 			printf(" (%-.*s)", sizeof (up->ut_host), up->ut_host);
389df930be7Sderaadt 		putchar('\n');
390df930be7Sderaadt 	}
391df930be7Sderaadt #endif
392df930be7Sderaadt 	return head;
393df930be7Sderaadt }
394df930be7Sderaadt 
395df930be7Sderaadt int
ac(FILE * fp)3964b6e8b27Sderaadt ac(FILE	*fp)
397df930be7Sderaadt {
398df930be7Sderaadt 	struct utmp_list *lp, *head = NULL;
399df930be7Sderaadt 	struct utmp usr;
400df930be7Sderaadt 	struct tm *ltm;
4013a88dae6Smickey 	time_t secs = 0, prev = 0;
402df930be7Sderaadt 	int day = -1;
403df930be7Sderaadt 
404df930be7Sderaadt 	while (fread((char *)&usr, sizeof(usr), 1, fp) == 1) {
405df930be7Sderaadt 		if (!FirstTime)
406df930be7Sderaadt 			FirstTime = usr.ut_time;
4073a88dae6Smickey 		if (usr.ut_time < prev)
4083a88dae6Smickey 			continue;	/* broken record */
4093a88dae6Smickey 		prev = usr.ut_time;
410df930be7Sderaadt 		if (Flags & AC_D) {
411df930be7Sderaadt 			ltm = localtime(&usr.ut_time);
412134d3d08Smestre 			if (ltm == NULL)
413134d3d08Smestre 				err(1, "localtime");
414df930be7Sderaadt 			if (day >= 0 && day != ltm->tm_yday) {
415df930be7Sderaadt 				day = ltm->tm_yday;
416df930be7Sderaadt 				/*
417df930be7Sderaadt 				 * print yesterday's total
418df930be7Sderaadt 				 */
419df930be7Sderaadt 				secs = usr.ut_time;
420df930be7Sderaadt 				secs -= ltm->tm_sec;
421df930be7Sderaadt 				secs -= 60 * ltm->tm_min;
422df930be7Sderaadt 				secs -= 3600 * ltm->tm_hour;
423df930be7Sderaadt 				show_today(Users, head, secs);
424df930be7Sderaadt 			} else
425df930be7Sderaadt 				day = ltm->tm_yday;
426df930be7Sderaadt 		}
427df930be7Sderaadt 		switch(*usr.ut_line) {
428df930be7Sderaadt 		case '|':
429df930be7Sderaadt 			secs = usr.ut_time;
430df930be7Sderaadt 			break;
431df930be7Sderaadt 		case '{':
432df930be7Sderaadt 			secs -= usr.ut_time;
433df930be7Sderaadt 			/*
434df930be7Sderaadt 			 * adjust time for those logged in
435df930be7Sderaadt 			 */
436df930be7Sderaadt 			for (lp = head; lp != NULL; lp = lp->next)
437df930be7Sderaadt 				lp->usr.ut_time -= secs;
438df930be7Sderaadt 			break;
439df930be7Sderaadt 		case '~':			/* reboot or shutdown */
440df930be7Sderaadt 			head = log_out(head, &usr);
441df930be7Sderaadt 			FirstTime = usr.ut_time; /* shouldn't be needed */
442df930be7Sderaadt 			break;
443df930be7Sderaadt 		default:
444df930be7Sderaadt 			/*
4454ecde836Sderaadt 			 * if they came in on a pseudo-tty, then it is only
446df930be7Sderaadt 			 * a login session if the ut_host field is non-empty
447df930be7Sderaadt 			 */
448df930be7Sderaadt 			if (*usr.ut_name) {
449df930be7Sderaadt 				if (strncmp(usr.ut_line, "tty", 3) != 0 ||
45054208c2cStedu 				    strchr("pqrstuvwxyzPQRST", usr.ut_line[3]) != NULL ||
451df930be7Sderaadt 				    *usr.ut_host != '\0')
452df930be7Sderaadt 					head = log_in(head, &usr);
453df930be7Sderaadt 			} else
454df930be7Sderaadt 				head = log_out(head, &usr);
455df930be7Sderaadt 			break;
456df930be7Sderaadt 		}
457df930be7Sderaadt 	}
458df930be7Sderaadt 	(void)fclose(fp);
459f470cc8cSderaadt 	if (!(Flags & AC_W))
46054208c2cStedu 		usr.ut_time = time(NULL);
461334e018bSderaadt 	(void)strlcpy(usr.ut_line, "~", sizeof usr.ut_line);
462df930be7Sderaadt 
463df930be7Sderaadt 	if (Flags & AC_D) {
464df930be7Sderaadt 		ltm = localtime(&usr.ut_time);
465134d3d08Smestre 		if (ltm == NULL)
466134d3d08Smestre 			err(1, "localtime");
467df930be7Sderaadt 		if (day >= 0 && day != ltm->tm_yday) {
468df930be7Sderaadt 			/*
469df930be7Sderaadt 			 * print yesterday's total
470df930be7Sderaadt 			 */
471df930be7Sderaadt 			secs = usr.ut_time;
472df930be7Sderaadt 			secs -= ltm->tm_sec;
473df930be7Sderaadt 			secs -= 60 * ltm->tm_min;
474df930be7Sderaadt 			secs -= 3600 * ltm->tm_hour;
475df930be7Sderaadt 			show_today(Users, head, secs);
476df930be7Sderaadt 		}
477df930be7Sderaadt 	}
478df930be7Sderaadt 	/*
479df930be7Sderaadt 	 * anyone still logged in gets time up to now
480df930be7Sderaadt 	 */
481df930be7Sderaadt 	head = log_out(head, &usr);
482df930be7Sderaadt 
483df930be7Sderaadt 	if (Flags & AC_D)
48454208c2cStedu 		show_today(Users, head, time(NULL));
485df930be7Sderaadt 	else {
486df930be7Sderaadt 		if (Flags & AC_P)
487df930be7Sderaadt 			show_users(Users);
488df930be7Sderaadt 		show("total", Total);
489df930be7Sderaadt 	}
490df930be7Sderaadt 	return 0;
491df930be7Sderaadt }
492df930be7Sderaadt 
493df930be7Sderaadt void
usage(void)4944b6e8b27Sderaadt usage(void)
495df930be7Sderaadt {
496559b49b0Spvalchev 	extern char *__progname;
4970d5c87f9Ssobrado 	(void)fprintf(stderr, "usage: "
4980d5c87f9Ssobrado 	    "%s [-dp] [-t tty] [-w wtmp] [user ...]\n", __progname);
499df930be7Sderaadt 	exit(1);
500df930be7Sderaadt }
501