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