Home | History | Annotate | Line # | Download | only in who
utmpentry.c revision 1.6
      1 /*	$NetBSD: utmpentry.c,v 1.6 2006/03/17 20:41:02 elad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Christos Zoulas.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 #ifndef lint
     41 __RCSID("$NetBSD: utmpentry.c,v 1.6 2006/03/17 20:41:02 elad Exp $");
     42 #endif
     43 
     44 #include <sys/stat.h>
     45 
     46 #include <time.h>
     47 #include <string.h>
     48 #include <err.h>
     49 #include <stdlib.h>
     50 
     51 #ifdef SUPPORT_UTMP
     52 #include <utmp.h>
     53 #endif
     54 #ifdef SUPPORT_UTMPX
     55 #include <utmpx.h>
     56 #endif
     57 
     58 #include "utmpentry.h"
     59 
     60 
     61 #ifdef SUPPORT_UTMP
     62 static void getentry(struct utmpentry *, struct utmp *);
     63 static time_t utmptime = 0;
     64 #endif
     65 #ifdef SUPPORT_UTMPX
     66 static void getentryx(struct utmpentry *, struct utmpx *);
     67 static time_t utmpxtime = 0;
     68 #endif
     69 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
     70 static int setup(const char *);
     71 static void adjust_size(struct utmpentry *e);
     72 #endif
     73 
     74 int maxname = 8, maxline = 8, maxhost = 16;
     75 static int numutmp = 0;
     76 static struct utmpentry *ehead;
     77 
     78 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
     79 static void
     80 adjust_size(struct utmpentry *e)
     81 {
     82 	int max;
     83 
     84 	if ((max = strlen(e->name)) > maxname)
     85 		maxname = max;
     86 	if ((max = strlen(e->line)) > maxline)
     87 		maxline = max;
     88 	if ((max = strlen(e->host)) > maxhost)
     89 		maxhost = max;
     90 }
     91 
     92 static int
     93 setup(const char *fname)
     94 {
     95 	int what = 3;
     96 	struct stat st;
     97 	const char *sfname;
     98 
     99 	if (fname == NULL) {
    100 #ifdef SUPPORT_UTMPX
    101 		setutxent();
    102 #endif
    103 #ifdef SUPPORT_UTMP
    104 		setutent();
    105 #endif
    106 	} else {
    107 		size_t len = strlen(fname);
    108 		if (len == 0)
    109 			errx(1, "Filename cannot be 0 length.");
    110 		what = fname[len - 1] == 'x' ? 1 : 2;
    111 		if (what == 1) {
    112 #ifdef SUPPORT_UTMPX
    113 			if (utmpxname(fname) == 0)
    114 				warnx("Cannot set utmpx file to `%s'",
    115 				    fname);
    116 #else
    117 			warnx("utmpx support not compiled in");
    118 #endif
    119 		} else {
    120 #ifdef SUPPORT_UTMP
    121 			if (utmpname(fname) == 0)
    122 				warnx("Cannot set utmp file to `%s'",
    123 				    fname);
    124 #else
    125 			warnx("utmp support not compiled in");
    126 #endif
    127 		}
    128 	}
    129 #ifdef SUPPORT_UTMPX
    130 	if (what & 1) {
    131 		sfname = fname ? fname : _PATH_UTMPX;
    132 		if (stat(sfname, &st) == -1) {
    133 			warn("Cannot stat `%s'", sfname);
    134 			what &= ~1;
    135 		} else {
    136 			if (st.st_mtime > utmpxtime)
    137 			    utmpxtime = st.st_mtime;
    138 			else
    139 			    what &= ~1;
    140 		}
    141 	}
    142 #endif
    143 #ifdef SUPPORT_UTMP
    144 	if (what & 2) {
    145 		sfname = fname ? fname : _PATH_UTMP;
    146 		if (stat(sfname, &st) == -1) {
    147 			warn("Cannot stat `%s'", sfname);
    148 			what &= ~2;
    149 		} else {
    150 			if (st.st_mtime > utmptime)
    151 				utmptime = st.st_mtime;
    152 			else
    153 				what &= ~2;
    154 		}
    155 	}
    156 #endif
    157 	return what;
    158 }
    159 #endif
    160 
    161 void
    162 freeutentries(struct utmpentry *ep)
    163 {
    164 #ifdef SUPPORT_UTMP
    165 	utmptime = 0;
    166 #endif
    167 #ifdef SUPPORT_UTMPX
    168 	utmpxtime = 0;
    169 #endif
    170 	if (ep == ehead) {
    171 		ehead = NULL;
    172 		numutmp = 0;
    173 	}
    174 	while (ep) {
    175 		struct utmpentry *sep = ep;
    176 		ep = ep->next;
    177 		free(sep);
    178 	}
    179 }
    180 
    181 int
    182 getutentries(const char *fname, struct utmpentry **epp)
    183 {
    184 #ifdef SUPPORT_UTMPX
    185 	struct utmpx *utx;
    186 #endif
    187 #ifdef SUPPORT_UTMP
    188 	struct utmp *ut;
    189 #endif
    190 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
    191 	struct utmpentry *ep;
    192 	int what = setup(fname);
    193 	struct utmpentry **nextp = &ehead;
    194 	switch (what) {
    195 	case 0:
    196 		/* No updates */
    197 		*epp = ehead;
    198 		return numutmp;
    199 	default:
    200 		/* Need to re-scan */
    201 		ehead = NULL;
    202 		numutmp = 0;
    203 	}
    204 #endif
    205 
    206 #ifdef SUPPORT_UTMPX
    207 	while ((what & 1) && (utx = getutxent()) != NULL) {
    208 		if (fname == NULL && utx->ut_type != USER_PROCESS)
    209 			continue;
    210 		if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
    211 			warn(NULL);
    212 			return 0;
    213 		}
    214 		getentryx(ep, utx);
    215 		*nextp = ep;
    216 		nextp = &(ep->next);
    217 	}
    218 #endif
    219 
    220 #ifdef SUPPORT_UTMP
    221 	while ((what & 2) && (ut = getutent()) != NULL) {
    222 		if (fname == NULL && (*ut->ut_name == '\0' ||
    223 		    *ut->ut_line == '\0'))
    224 			continue;
    225 		/* Don't process entries that we have utmpx for */
    226 		for (ep = ehead; ep != NULL; ep = ep->next) {
    227 			if (strncmp(ep->line, ut->ut_line,
    228 			    sizeof(ut->ut_line)) == 0)
    229 				break;
    230 		}
    231 		if (ep != NULL)
    232 			continue;
    233 		if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
    234 			warn(NULL);
    235 			return 0;
    236 		}
    237 		getentry(ep, ut);
    238 		*nextp = ep;
    239 		nextp = &(ep->next);
    240 	}
    241 #endif
    242 	numutmp = 0;
    243 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX)
    244 	if (ehead != NULL) {
    245 		struct utmpentry *from = ehead, *save;
    246 
    247 		ehead = NULL;
    248 		while (from != NULL) {
    249 			for (nextp = &ehead;
    250 			    (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
    251 			    nextp = &(*nextp)->next)
    252 				continue;
    253 			save = from;
    254 			from = from->next;
    255 			save->next = *nextp;
    256 			*nextp = save;
    257 			numutmp++;
    258 		}
    259 	}
    260 	*epp = ehead;
    261 	return numutmp;
    262 #else
    263 	*epp = NULL;
    264 	return 0;
    265 #endif
    266 }
    267 
    268 #ifdef SUPPORT_UTMP
    269 static void
    270 getentry(struct utmpentry *e, struct utmp *up)
    271 {
    272 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
    273 	e->name[sizeof(e->name) - 1] = '\0';
    274 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
    275 	e->line[sizeof(e->line) - 1] = '\0';
    276 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
    277 	e->name[sizeof(e->host) - 1] = '\0';
    278 	e->tv.tv_sec = up->ut_time;
    279 	e->tv.tv_usec = 0;
    280 	adjust_size(e);
    281 }
    282 #endif
    283 
    284 #ifdef SUPPORT_UTMPX
    285 static void
    286 getentryx(struct utmpentry *e, struct utmpx *up)
    287 {
    288 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
    289 	e->name[sizeof(e->name) - 1] = '\0';
    290 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
    291 	e->line[sizeof(e->line) - 1] = '\0';
    292 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
    293 	e->name[sizeof(e->name) - 1] = '\0';
    294 	e->tv = up->ut_tv;
    295 	adjust_size(e);
    296 }
    297 #endif
    298