1/* 2 * Copyright (c) 1996 John M. Vinopal 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed for the NetBSD Project 16 * by John M. Vinopal. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34#ifndef lint 35__RCSID("$FreeBSD$"); 36__RCSID("$NetBSD: lastlogin.c,v 1.4 1998/02/03 04:45:35 perry Exp $"); 37#endif 38 39#include <err.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <time.h> 44#include <unistd.h> 45#include <utmpx.h> 46 47 int main(int, char **); 48static void output(struct utmpx *); 49static void usage(void); 50static int utcmp_user(const void *, const void *); 51 52static int order = 1; 53static const char *file = NULL; 54static int (*utcmp)(const void *, const void *) = utcmp_user; 55 56static int 57utcmp_user(const void *u1, const void *u2) 58{ 59 60 return (order * strcmp(((const struct utmpx *)u1)->ut_user, 61 ((const struct utmpx *)u2)->ut_user)); 62} 63 64static int 65utcmp_time(const void *u1, const void *u2) 66{ 67 time_t t1, t2; 68 69 t1 = ((const struct utmpx *)u1)->ut_tv.tv_sec; 70 t2 = ((const struct utmpx *)u2)->ut_tv.tv_sec; 71 return (t1 < t2 ? order : t1 > t2 ? -order : 0); 72} 73 74int 75main(int argc, char *argv[]) 76{ 77 int ch, i, ulistsize; 78 struct utmpx *u, *ulist; 79 80 while ((ch = getopt(argc, argv, "f:rt")) != -1) { 81 switch (ch) { 82 case 'f': 83 file = optarg; 84 break; 85 case 'r': 86 order = -1; 87 break; 88 case 't': 89 utcmp = utcmp_time; 90 break; 91 default: 92 usage(); 93 } 94 } 95 argc -= optind; 96 argv += optind; 97 98 if (argc > 0) { 99 /* Process usernames given on the command line. */ 100 for (i = 0; i < argc; i++) { 101 if (setutxdb(UTXDB_LASTLOGIN, file) != 0) 102 err(1, "failed to open lastlog database"); 103 if ((u = getutxuser(argv[i])) == NULL) { 104 warnx("user '%s' not found", argv[i]); 105 continue; 106 } 107 output(u); 108 endutxent(); 109 } 110 } else { 111 /* Read all lastlog entries, looking for active ones. */ 112 if (setutxdb(UTXDB_LASTLOGIN, file) != 0) 113 err(1, "failed to open lastlog database"); 114 ulist = NULL; 115 ulistsize = 0; 116 while ((u = getutxent()) != NULL) { 117 if (u->ut_type != USER_PROCESS) 118 continue; 119 if ((ulistsize % 16) == 0) { 120 ulist = realloc(ulist, 121 (ulistsize + 16) * sizeof(struct utmpx)); 122 if (ulist == NULL) 123 err(1, "malloc"); 124 } 125 ulist[ulistsize++] = *u; 126 } 127 endutxent(); 128 129 qsort(ulist, ulistsize, sizeof(struct utmpx), utcmp); 130 for (i = 0; i < ulistsize; i++) 131 output(&ulist[i]); 132 } 133 134 exit(0); 135} 136 137/* Duplicate the output of last(1) */ 138static void 139output(struct utmpx *u) 140{ 141 time_t t = u->ut_tv.tv_sec; 142 143 printf("%-10s %-8s %-22.22s %s", 144 u->ut_user, u->ut_line, u->ut_host, ctime(&t)); 145} 146 147static void 148usage(void) 149{ 150 fprintf(stderr, "usage: lastlogin [-f file] [-rt] [user ...]\n"); 151 exit(1); 152} 153