Home | History | Annotate | Line # | Download | only in who
utmpentry.c revision 1.16
      1 /*	$NetBSD: utmpentry.c,v 1.16 2008/10/28 14:01:46 christos 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  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 __RCSID("$NetBSD: utmpentry.c,v 1.16 2008/10/28 14:01:46 christos Exp $");
     35 #endif
     36 
     37 #include <sys/stat.h>
     38 
     39 #include <time.h>
     40 #include <string.h>
     41 #include <err.h>
     42 #include <stdlib.h>
     43 
     44 #ifdef SUPPORT_UTMP
     45 #include <utmp.h>
     46 #endif
     47 #ifdef SUPPORT_UTMPX
     48 #include <utmpx.h>
     49 #endif
     50 
     51 #include "utmpentry.h"
     52 
     53 
     54 /* Fail the compile if x is not true, by constructing an illegal type. */
     55 #define COMPILE_ASSERT(x) /*LINTED null effect */ \
     56 	((void)sizeof(struct { unsigned : ((x) ? 1 : -1); }))
     57 
     58 
     59 #ifdef SUPPORT_UTMP
     60 static void getentry(struct utmpentry *, struct utmp *);
     61 static struct timespec utmptime = {0, 0};
     62 #endif
     63 #ifdef SUPPORT_UTMPX
     64 static void getentryx(struct utmpentry *, struct utmpx *);
     65 static struct timespec utmpxtime = {0, 0};
     66 #endif
     67 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
     68 static int setup(const char *);
     69 static void adjust_size(struct utmpentry *e);
     70 #endif
     71 
     72 int maxname = 8, maxline = 8, maxhost = 16;
     73 int etype = 1 << USER_PROCESS;
     74 static int numutmp = 0;
     75 static struct utmpentry *ehead;
     76 
     77 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
     78 static void
     79 adjust_size(struct utmpentry *e)
     80 {
     81 	int max;
     82 
     83 	if ((max = strlen(e->name)) > maxname)
     84 		maxname = max;
     85 	if ((max = strlen(e->line)) > maxline)
     86 		maxline = max;
     87 	if ((max = strlen(e->host)) > maxhost)
     88 		maxhost = max;
     89 }
     90 
     91 static int
     92 setup(const char *fname)
     93 {
     94 	int what = 3;
     95 	struct stat st;
     96 	const char *sfname;
     97 
     98 	if (fname == NULL) {
     99 #ifdef SUPPORT_UTMPX
    100 		setutxent();
    101 #endif
    102 #ifdef SUPPORT_UTMP
    103 		setutent();
    104 #endif
    105 	} else {
    106 		size_t len = strlen(fname);
    107 		if (len == 0)
    108 			errx(1, "Filename cannot be 0 length.");
    109 		what = fname[len - 1] == 'x' ? 1 : 2;
    110 		if (what == 1) {
    111 #ifdef SUPPORT_UTMPX
    112 			if (utmpxname(fname) == 0)
    113 				warnx("Cannot set utmpx file to `%s'",
    114 				    fname);
    115 #else
    116 			warnx("utmpx support not compiled in");
    117 #endif
    118 		} else {
    119 #ifdef SUPPORT_UTMP
    120 			if (utmpname(fname) == 0)
    121 				warnx("Cannot set utmp file to `%s'",
    122 				    fname);
    123 #else
    124 			warnx("utmp support not compiled in");
    125 #endif
    126 		}
    127 	}
    128 #ifdef SUPPORT_UTMPX
    129 	if (what & 1) {
    130 		sfname = fname ? fname : _PATH_UTMPX;
    131 		if (stat(sfname, &st) == -1) {
    132 			warn("Cannot stat `%s'", sfname);
    133 			what &= ~1;
    134 		} else {
    135 			if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
    136 			    utmpxtime = st.st_mtimespec;
    137 			else
    138 			    what &= ~1;
    139 		}
    140 	}
    141 #endif
    142 #ifdef SUPPORT_UTMP
    143 	if (what & 2) {
    144 		sfname = fname ? fname : _PATH_UTMP;
    145 		if (stat(sfname, &st) == -1) {
    146 			warn("Cannot stat `%s'", sfname);
    147 			what &= ~2;
    148 		} else {
    149 			if (timespeccmp(&st.st_mtimespec, &utmptime, >))
    150 				utmptime = st.st_mtimespec;
    151 			else
    152 				what &= ~2;
    153 		}
    154 	}
    155 #endif
    156 	return what;
    157 }
    158 #endif
    159 
    160 void
    161 endutentries(void)
    162 {
    163 	struct utmpentry *ep;
    164 
    165 #ifdef SUPPORT_UTMP
    166 	timespecclear(&utmptime);
    167 #endif
    168 #ifdef SUPPORT_UTMPX
    169 	timespecclear(&utmpxtime);
    170 #endif
    171 	ep = ehead;
    172 	while (ep) {
    173 		struct utmpentry *sep = ep;
    174 		ep = ep->next;
    175 		free(sep);
    176 	}
    177 	ehead = NULL;
    178 	numutmp = 0;
    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 && ((1 << utx->ut_type) & etype) == 0)
    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 	if ((etype & (1 << USER_PROCESS)) != 0) {
    222 		while ((what & 2) && (ut = getutent()) != NULL) {
    223 			if (fname == NULL && (*ut->ut_name == '\0' ||
    224 			    *ut->ut_line == '\0'))
    225 				continue;
    226 			/* Don't process entries that we have utmpx for */
    227 			for (ep = ehead; ep != NULL; ep = ep->next) {
    228 				if (strncmp(ep->line, ut->ut_line,
    229 				    sizeof(ut->ut_line)) == 0)
    230 					break;
    231 			}
    232 			if (ep != NULL)
    233 				continue;
    234 			if ((ep = calloc(1, sizeof(*ep))) == NULL) {
    235 				warn(NULL);
    236 				return 0;
    237 			}
    238 			getentry(ep, ut);
    239 			*nextp = ep;
    240 			nextp = &(ep->next);
    241 		}
    242 	}
    243 #endif
    244 	numutmp = 0;
    245 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX)
    246 	if (ehead != NULL) {
    247 		struct utmpentry *from = ehead, *save;
    248 
    249 		ehead = NULL;
    250 		while (from != NULL) {
    251 			for (nextp = &ehead;
    252 			    (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
    253 			    nextp = &(*nextp)->next)
    254 				continue;
    255 			save = from;
    256 			from = from->next;
    257 			save->next = *nextp;
    258 			*nextp = save;
    259 			numutmp++;
    260 		}
    261 	}
    262 	*epp = ehead;
    263 	return numutmp;
    264 #else
    265 	*epp = NULL;
    266 	return 0;
    267 #endif
    268 }
    269 
    270 #ifdef SUPPORT_UTMP
    271 static void
    272 getentry(struct utmpentry *e, struct utmp *up)
    273 {
    274 	COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
    275 	COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
    276 	COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
    277 
    278 	/*
    279 	 * e has just been calloc'd. We don't need to clear it or
    280 	 * append null-terminators, because its length is strictly
    281 	 * greater than the source string. Use strncpy to _read_
    282 	 * up->ut_* because they may not be terminated. For this
    283 	 * reason we use the size of the _source_ as the length
    284 	 * argument.
    285 	 */
    286 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
    287 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
    288 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
    289 
    290 	e->tv.tv_sec = up->ut_time;
    291 	e->tv.tv_usec = 0;
    292 	e->pid = 0;
    293 	e->term = 0;
    294 	e->exit = 0;
    295 	e->sess = 0;
    296 	e->type = USER_PROCESS;
    297 	adjust_size(e);
    298 }
    299 #endif
    300 
    301 #ifdef SUPPORT_UTMPX
    302 static void
    303 getentryx(struct utmpentry *e, struct utmpx *up)
    304 {
    305 	COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
    306 	COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
    307 	COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
    308 
    309 	/*
    310 	 * e has just been calloc'd. We don't need to clear it or
    311 	 * append null-terminators, because its length is strictly
    312 	 * greater than the source string. Use strncpy to _read_
    313 	 * up->ut_* because they may not be terminated. For this
    314 	 * reason we use the size of the _source_ as the length
    315 	 * argument.
    316 	 */
    317 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
    318 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
    319 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
    320 
    321 	e->tv = up->ut_tv;
    322 	e->pid = up->ut_pid;
    323 	e->term = up->ut_exit.e_termination;
    324 	e->exit = up->ut_exit.e_exit;
    325 	e->sess = up->ut_session;
    326 	e->type = up->ut_type;
    327 	adjust_size(e);
    328 }
    329 #endif
    330