168723Sru/*
268723Sru * Copyright (c) 1996 John M. Vinopal
368723Sru * All rights reserved.
468723Sru *
568723Sru * Redistribution and use in source and binary forms, with or without
668723Sru * modification, are permitted provided that the following conditions
768723Sru * are met:
868723Sru * 1. Redistributions of source code must retain the above copyright
968723Sru *    notice, this list of conditions and the following disclaimer.
1068723Sru * 2. Redistributions in binary form must reproduce the above copyright
1168723Sru *    notice, this list of conditions and the following disclaimer in the
1268723Sru *    documentation and/or other materials provided with the distribution.
1368723Sru * 3. All advertising materials mentioning features or use of this software
1468723Sru *    must display the following acknowledgement:
1568723Sru *	This product includes software developed for the NetBSD Project
1668723Sru *	by John M. Vinopal.
1768723Sru * 4. The name of the author may not be used to endorse or promote products
1868723Sru *    derived from this software without specific prior written permission.
1968723Sru *
2068723Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2168723Sru * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2268723Sru * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2368723Sru * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2468723Sru * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2568723Sru * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2668723Sru * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2768723Sru * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2868723Sru * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2968723Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3068723Sru * SUCH DAMAGE.
3168723Sru */
3268723Sru
3368723Sru#include <sys/cdefs.h>
3468723Sru#ifndef lint
3568723Sru__RCSID("$FreeBSD$");
3668723Sru__RCSID("$NetBSD: lastlogin.c,v 1.4 1998/02/03 04:45:35 perry Exp $");
3768723Sru#endif
3868723Sru
3968723Sru#include <err.h>
4068723Sru#include <stdio.h>
4178719Sdd#include <stdlib.h>
42206471Sed#include <string.h>
4368723Sru#include <time.h>
4468723Sru#include <unistd.h>
45202205Sed#include <utmpx.h>
4668723Sru
4799800Salfred	int	main(int, char **);
48202205Sedstatic	void	output(struct utmpx *);
4999800Salfredstatic	void	usage(void);
50222767Sedstatic int	utcmp_user(const void *, const void *);
5168723Sru
52222767Sedstatic int	order = 1;
53222767Sedstatic const char *file = NULL;
54222767Sedstatic int	(*utcmp)(const void *, const void *) = utcmp_user;
55222767Sed
56206471Sedstatic int
57222767Sedutcmp_user(const void *u1, const void *u2)
58206471Sed{
59206471Sed
60222767Sed	return (order * strcmp(((const struct utmpx *)u1)->ut_user,
61206471Sed	    ((const struct utmpx *)u2)->ut_user));
62206471Sed}
63206471Sed
64222767Sedstatic int
65222767Sedutcmp_time(const void *u1, const void *u2)
66222767Sed{
67222767Sed	time_t t1, t2;
68222767Sed
69222767Sed	t1 = ((const struct utmpx *)u1)->ut_tv.tv_sec;
70222767Sed	t2 = ((const struct utmpx *)u2)->ut_tv.tv_sec;
71222767Sed	return (t1 < t2 ? order : t1 > t2 ? -order : 0);
72222767Sed}
73222767Sed
7468723Sruint
75201227Sedmain(int argc, char *argv[])
7668723Sru{
77206471Sed	int	ch, i, ulistsize;
78206471Sed	struct utmpx *u, *ulist;
7968723Sru
80222767Sed	while ((ch = getopt(argc, argv, "f:rt")) != -1) {
81222767Sed		switch (ch) {
82222767Sed		case 'f':
83222767Sed			file = optarg;
84222767Sed			break;
85222767Sed		case 'r':
86222767Sed			order = -1;
87222767Sed			break;
88222767Sed		case 't':
89222767Sed			utcmp = utcmp_time;
90222767Sed			break;
91222767Sed		default:
92222767Sed			usage();
93222767Sed		}
9468723Sru	}
95222767Sed	argc -= optind;
96222767Sed	argv += optind;
9768723Sru
98222767Sed	if (argc > 0) {
99222767Sed		/* Process usernames given on the command line. */
100222767Sed		for (i = 0; i < argc; i++) {
101222767Sed			if (setutxdb(UTXDB_LASTLOGIN, file) != 0)
102222767Sed				err(1, "failed to open lastlog database");
103202205Sed			if ((u = getutxuser(argv[i])) == NULL) {
10468723Sru				warnx("user '%s' not found", argv[i]);
10568723Sru				continue;
10668723Sru			}
107200303Sed			output(u);
108202205Sed			endutxent();
10968723Sru		}
110222767Sed	} else {
111222767Sed		/* Read all lastlog entries, looking for active ones. */
112222767Sed		if (setutxdb(UTXDB_LASTLOGIN, file) != 0)
113222767Sed			err(1, "failed to open lastlog database");
114206471Sed		ulist = NULL;
115206471Sed		ulistsize = 0;
116202205Sed		while ((u = getutxent()) != NULL) {
117200303Sed			if (u->ut_type != USER_PROCESS)
11868723Sru				continue;
119206472Sed			if ((ulistsize % 16) == 0) {
120206471Sed				ulist = realloc(ulist,
121206471Sed				    (ulistsize + 16) * sizeof(struct utmpx));
122206472Sed				if (ulist == NULL)
123206472Sed					err(1, "malloc");
124206472Sed			}
125206471Sed			ulist[ulistsize++] = *u;
12668723Sru		}
127202205Sed		endutxent();
128206471Sed
129206471Sed		qsort(ulist, ulistsize, sizeof(struct utmpx), utcmp);
130206471Sed		for (i = 0; i < ulistsize; i++)
131206471Sed			output(&ulist[i]);
13268723Sru	}
13368723Sru
13468723Sru	exit(0);
13568723Sru}
13668723Sru
13768723Sru/* Duplicate the output of last(1) */
13868723Srustatic void
139202205Sedoutput(struct utmpx *u)
14068723Sru{
141200303Sed	time_t t = u->ut_tv.tv_sec;
142200303Sed
143205365Sed	printf("%-10s %-8s %-22.22s %s",
144202205Sed		u->ut_user, u->ut_line, u->ut_host, ctime(&t));
14568723Sru}
14668723Sru
14768723Srustatic void
148201227Sedusage(void)
14968723Sru{
150222767Sed	fprintf(stderr, "usage: lastlogin [-f file] [-rt] [user ...]\n");
15168723Sru	exit(1);
15268723Sru}
153