Home | History | Annotate | Line # | Download | only in lastlogin
lastlogin.c revision 1.8
      1 /*	$NetBSD: lastlogin.c,v 1.8 2003/12/16 15:40:29 wulf Exp $	*/
      2 /*
      3  * Copyright (c) 1996 John M. Vinopal
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *	This product includes software developed for the NetBSD Project
     17  *	by John M. Vinopal.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 #ifndef lint
     36 __RCSID("$NetBSD: lastlogin.c,v 1.8 2003/12/16 15:40:29 wulf Exp $");
     37 #endif
     38 
     39 #include <sys/types.h>
     40 #include <err.h>
     41 #include <errno.h>
     42 #include <pwd.h>
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <string.h>
     46 #include <time.h>
     47 #include <utmp.h>
     48 #include <unistd.h>
     49 
     50 struct output {
     51 	char		 o_name[UT_NAMESIZE];
     52 	char		 o_line[UT_LINESIZE];
     53 	char		 o_host[UT_HOSTSIZE];
     54 	time_t		 o_time;
     55 	struct output	*next;
     56 };
     57 
     58 static	char *logfile = _PATH_LASTLOG;
     59 
     60 #define SORT_NONE	0x0000
     61 #define SORT_REVERSE	0x0001
     62 #define SORT_TIME	0x0002
     63 #define DOSORT(x)	((x) & (SORT_TIME))
     64 static	int sortlog = SORT_NONE;
     65 static	struct output *outstack = NULL;
     66 
     67 	int	main __P((int, char **));
     68 static	int	comparelog __P((const void *, const void *));
     69 static	void	output __P((struct output *));
     70 static	void	process_entry __P((struct passwd *, struct lastlog *));
     71 static	void	push __P((struct output *));
     72 static	void	sortoutput __P((struct output *));
     73 static	void	usage __P((void));
     74 
     75 int
     76 main(argc, argv)
     77 	int argc;
     78 	char *argv[];
     79 {
     80 	int	ch, i;
     81 	FILE	*fp;
     82 	struct passwd	*passwd;
     83 	struct lastlog	last;
     84 
     85 	while ((ch = getopt(argc, argv, "rt")) != -1) {
     86 		switch (ch) {
     87 		case 'r':
     88 			sortlog |= SORT_REVERSE;
     89 			break;
     90 		case 't':
     91 			sortlog |= SORT_TIME;
     92 			break;
     93 		default:
     94 			usage();
     95 		}
     96 	}
     97 	argc -= optind;
     98 	argv += optind;
     99 
    100 	fp = fopen(logfile, "r");
    101 	if (fp == NULL)
    102 		err(1, "%s", logfile);
    103 
    104 	setpassent(1);	/* Keep passwd file pointers open */
    105 
    106 	/* Process usernames given on the command line. */
    107 	if (argc > 0) {
    108 		long offset;
    109 		for (i = 0; i < argc; i++) {
    110 			if ((passwd = getpwnam(argv[i])) == NULL) {
    111 				warnx("user '%s' not found", argv[i]);
    112 				continue;
    113 			}
    114 			/* Calculate the offset into the lastlog file. */
    115 			offset = (long)(passwd->pw_uid * sizeof(last));
    116 			if (fseek(fp, offset, SEEK_SET)) {
    117 				warn("fseek error");
    118 				continue;
    119 			}
    120 			if (fread(&last, sizeof(last), 1, fp) != 1) {
    121 				warnx("fread error on '%s'", passwd->pw_name);
    122 				clearerr(fp);
    123 				continue;
    124 			}
    125 			process_entry(passwd, &last);
    126 		}
    127 	}
    128 	/* Read all lastlog entries, looking for active ones */
    129 	else {
    130 		for (i = 0; fread(&last, sizeof(last), 1, fp) == 1; i++) {
    131 			if (last.ll_time == 0)
    132 				continue;
    133 			if ((passwd = getpwuid(i)) != NULL)
    134 				process_entry(passwd, &last);
    135 		}
    136 		if (ferror(fp))
    137 			warnx("fread error");
    138 	}
    139 
    140 	setpassent(0);	/* Close passwd file pointers */
    141 
    142 	if (DOSORT(sortlog))
    143 		sortoutput(outstack);
    144 
    145 	fclose(fp);
    146 	exit(0);
    147 }
    148 
    149 static void
    150 process_entry(struct passwd *p, struct lastlog *l)
    151 {
    152 	struct output	o;
    153 
    154 	strncpy(o.o_name, p->pw_name, UT_NAMESIZE);
    155 	strncpy(o.o_line, l->ll_line, UT_LINESIZE);
    156 	strncpy(o.o_host, l->ll_host, UT_HOSTSIZE);
    157 	o.o_time = l->ll_time;
    158 	o.next = NULL;
    159 
    160 	/*
    161 	 * If we are sorting it, we need all the entries in memory so
    162 	 * push the current entry onto a stack.  Otherwise, we can just
    163 	 * output it.
    164 	 */
    165 	if (DOSORT(sortlog))
    166 		push(&o);
    167 	else
    168 		output(&o);
    169 }
    170 
    171 static void
    172 push(struct output *o)
    173 {
    174 	struct output	*out;
    175 
    176 	out = malloc(sizeof(*out));
    177 	if (!out)
    178 		err(EXIT_FAILURE, "malloc failed");
    179 	memcpy(out, o, sizeof(*out));
    180 	out->next = NULL;
    181 
    182 	if (outstack) {
    183 		out->next = outstack;
    184 		outstack = out;
    185 	} else {
    186 		outstack = out;
    187 	}
    188 }
    189 
    190 static void
    191 sortoutput(struct output *o)
    192 {
    193 	struct	output **outs;
    194 	struct	output *tmpo;
    195 	int	num;
    196 	int	i;
    197 
    198 	/* count the number of entries to display */
    199 	for (num=0, tmpo = o; tmpo; tmpo=tmpo->next, num++)
    200 		;
    201 
    202 	outs = malloc(sizeof(*outs) * num);
    203 	if (!outs)
    204 		err(EXIT_FAILURE, "malloc failed");
    205 	for (i=0, tmpo = o; i < num; tmpo=tmpo->next, i++)
    206 		outs[i] = tmpo;
    207 
    208 	mergesort(outs, num, sizeof(*outs), comparelog);
    209 
    210 	for (i=0; i < num; i++)
    211 		output(outs[i]);
    212 }
    213 
    214 static int
    215 comparelog(const void *left, const void *right)
    216 {
    217 	struct output *l = *(struct output **)left;
    218 	struct output *r = *(struct output **)right;
    219 	int order = (sortlog&SORT_REVERSE)?-1:1;
    220 
    221 	if (l->o_time < r->o_time)
    222 		return 1 * order;
    223 	if (l->o_time == r->o_time)
    224 		return 0;
    225 	return -1 * order;
    226 }
    227 
    228 /* Duplicate the output of last(1) */
    229 static void
    230 output(struct output *o)
    231 {
    232 
    233 	printf("%-*.*s  %-*.*s %-*.*s   %s",
    234 		UT_NAMESIZE, UT_NAMESIZE, o->o_name,
    235 		UT_LINESIZE, UT_LINESIZE, o->o_line,
    236 		UT_HOSTSIZE, UT_HOSTSIZE, o->o_host,
    237 		(o->o_time) ? ctime(&(o->o_time)) : "Never logged in\n");
    238 }
    239 
    240 static void
    241 usage()
    242 {
    243 	fprintf(stderr, "usage: %s [-rt] [user ...]\n", getprogname());
    244 	exit(1);
    245 }
    246