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