xref: /dflybsd-src/usr.bin/who/utmpentry.c (revision 944cd60c7b4392d637be82be7baafe9ac12a3061)
159a92d18SAlex Hornung /*	$NetBSD: utmpentry.c,v 1.16 2008/10/28 14:01:46 christos Exp $	*/
259a92d18SAlex Hornung 
359a92d18SAlex Hornung /*-
459a92d18SAlex Hornung  * Copyright (c) 2002 The NetBSD Foundation, Inc.
559a92d18SAlex Hornung  * All rights reserved.
659a92d18SAlex Hornung  *
759a92d18SAlex Hornung  * This code is derived from software contributed to The NetBSD Foundation
859a92d18SAlex Hornung  * by Christos Zoulas.
959a92d18SAlex Hornung  *
1059a92d18SAlex Hornung  * Redistribution and use in source and binary forms, with or without
1159a92d18SAlex Hornung  * modification, are permitted provided that the following conditions
1259a92d18SAlex Hornung  * are met:
1359a92d18SAlex Hornung  * 1. Redistributions of source code must retain the above copyright
1459a92d18SAlex Hornung  *    notice, this list of conditions and the following disclaimer.
1559a92d18SAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
1659a92d18SAlex Hornung  *    notice, this list of conditions and the following disclaimer in the
1759a92d18SAlex Hornung  *    documentation and/or other materials provided with the distribution.
1859a92d18SAlex Hornung  *
1959a92d18SAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2059a92d18SAlex Hornung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2159a92d18SAlex Hornung  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2259a92d18SAlex Hornung  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2359a92d18SAlex Hornung  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2459a92d18SAlex Hornung  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2559a92d18SAlex Hornung  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2659a92d18SAlex Hornung  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2759a92d18SAlex Hornung  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2859a92d18SAlex Hornung  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2959a92d18SAlex Hornung  * POSSIBILITY OF SUCH DAMAGE.
3059a92d18SAlex Hornung  */
3159a92d18SAlex Hornung 
3259a92d18SAlex Hornung #include <sys/cdefs.h>
3359a92d18SAlex Hornung #include <sys/stat.h>
3459a92d18SAlex Hornung 
3559a92d18SAlex Hornung #include <err.h>
360d92c45cSMatthew Dillon #include <stdio.h>
3759a92d18SAlex Hornung #include <stdlib.h>
380d92c45cSMatthew Dillon #include <string.h>
394ade5d60SSascha Wildner #include <time.h>
4059a92d18SAlex Hornung #include <utmpx.h>
4159a92d18SAlex Hornung 
4259a92d18SAlex Hornung #include "utmpentry.h"
4359a92d18SAlex Hornung 
4459a92d18SAlex Hornung /* Operations on timespecs. */
4559a92d18SAlex Hornung #define timespec2ns(x) (((uint64_t)(x)->tv_sec) * 1000000000L + (x)->tv_nsec)
4659a92d18SAlex Hornung 
4759a92d18SAlex Hornung 
48*adc29575SSascha Wildner #define	COMPILE_ASSERT(x)	_Static_assert(x, "assertion failed")
4959a92d18SAlex Hornung 
5059a92d18SAlex Hornung 
5159a92d18SAlex Hornung static void getentryx(struct utmpentry *, struct utmpx *);
5259a92d18SAlex Hornung static struct timespec utmpxtime = {0, 0};
5359a92d18SAlex Hornung static int setup(const char *);
5459a92d18SAlex Hornung static void adjust_size(struct utmpentry *e);
5559a92d18SAlex Hornung 
5659a92d18SAlex Hornung int maxname = 8, maxline = 8, maxhost = 16;
5759a92d18SAlex Hornung int etype = 1 << USER_PROCESS;
5859a92d18SAlex Hornung static int numutmp = 0;
5959a92d18SAlex Hornung static struct utmpentry *ehead;
6059a92d18SAlex Hornung 
6159a92d18SAlex Hornung static void
adjust_size(struct utmpentry * e)6259a92d18SAlex Hornung adjust_size(struct utmpentry *e)
6359a92d18SAlex Hornung {
6459a92d18SAlex Hornung 	int max;
6559a92d18SAlex Hornung 
6659a92d18SAlex Hornung 	if ((max = strlen(e->name)) > maxname)
6759a92d18SAlex Hornung 		maxname = max;
6859a92d18SAlex Hornung 	if ((max = strlen(e->line)) > maxline)
6959a92d18SAlex Hornung 		maxline = max;
7059a92d18SAlex Hornung 	if ((max = strlen(e->host)) > maxhost)
7159a92d18SAlex Hornung 		maxhost = max;
7259a92d18SAlex Hornung }
7359a92d18SAlex Hornung 
7459a92d18SAlex Hornung static int
setup(const char * fname)7559a92d18SAlex Hornung setup(const char *fname)
7659a92d18SAlex Hornung {
7759a92d18SAlex Hornung 	int what = 3;
7859a92d18SAlex Hornung 	struct stat st;
7959a92d18SAlex Hornung 	const char *sfname;
8059a92d18SAlex Hornung 
8159a92d18SAlex Hornung 	if (fname == NULL) {
8259a92d18SAlex Hornung 		setutxent();
8359a92d18SAlex Hornung 	} else {
8459a92d18SAlex Hornung 		size_t len = strlen(fname);
8559a92d18SAlex Hornung 		if (len == 0)
8659a92d18SAlex Hornung 			errx(1, "Filename cannot be 0 length.");
8759a92d18SAlex Hornung 		what = fname[len - 1] == 'x' ? 1 : 2;
8859a92d18SAlex Hornung 		if (what == 1) {
8959a92d18SAlex Hornung 			if (utmpxname(fname) == 0)
9059a92d18SAlex Hornung 				warnx("Cannot set utmpx file to `%s'",
9159a92d18SAlex Hornung 				    fname);
9259a92d18SAlex Hornung 		}
9359a92d18SAlex Hornung 	}
9459a92d18SAlex Hornung 	if (what & 1) {
9559a92d18SAlex Hornung 		sfname = fname ? fname : _PATH_UTMPX;
9659a92d18SAlex Hornung 		if (stat(sfname, &st) == -1) {
9759a92d18SAlex Hornung 			warn("Cannot stat `%s'", sfname);
9859a92d18SAlex Hornung 			what &= ~1;
9959a92d18SAlex Hornung 		} else {
10059a92d18SAlex Hornung 			if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
10159a92d18SAlex Hornung 			    utmpxtime = st.st_mtimespec;
10259a92d18SAlex Hornung 			else
10359a92d18SAlex Hornung 			    what &= ~1;
10459a92d18SAlex Hornung 		}
10559a92d18SAlex Hornung 	}
10659a92d18SAlex Hornung 	return what;
10759a92d18SAlex Hornung }
10859a92d18SAlex Hornung 
10959a92d18SAlex Hornung void
endutentries(void)11059a92d18SAlex Hornung endutentries(void)
11159a92d18SAlex Hornung {
11259a92d18SAlex Hornung 	struct utmpentry *ep;
11359a92d18SAlex Hornung 
11459a92d18SAlex Hornung 	timespecclear(&utmpxtime);
11559a92d18SAlex Hornung 	ep = ehead;
11659a92d18SAlex Hornung 	while (ep) {
11759a92d18SAlex Hornung 		struct utmpentry *sep = ep;
11859a92d18SAlex Hornung 		ep = ep->next;
11959a92d18SAlex Hornung 		free(sep);
12059a92d18SAlex Hornung 	}
12159a92d18SAlex Hornung 	ehead = NULL;
12259a92d18SAlex Hornung 	numutmp = 0;
12359a92d18SAlex Hornung }
12459a92d18SAlex Hornung 
12559a92d18SAlex Hornung int
getutentries(const char * fname,struct utmpentry ** epp)12659a92d18SAlex Hornung getutentries(const char *fname, struct utmpentry **epp)
12759a92d18SAlex Hornung {
12859a92d18SAlex Hornung 	struct utmpx *utx;
12959a92d18SAlex Hornung 	struct utmpentry *ep;
13059a92d18SAlex Hornung 	int what = setup(fname);
13159a92d18SAlex Hornung 	struct utmpentry **nextp = &ehead;
13259a92d18SAlex Hornung 	switch (what) {
13359a92d18SAlex Hornung 	case 0:
13459a92d18SAlex Hornung 		/* No updates */
13559a92d18SAlex Hornung 		*epp = ehead;
13659a92d18SAlex Hornung 		return numutmp;
13759a92d18SAlex Hornung 	default:
13859a92d18SAlex Hornung 		/* Need to re-scan */
13959a92d18SAlex Hornung 		ehead = NULL;
14059a92d18SAlex Hornung 		numutmp = 0;
14159a92d18SAlex Hornung 	}
14259a92d18SAlex Hornung 
14359a92d18SAlex Hornung 	while ((what & 1) && (utx = getutxent()) != NULL) {
14459a92d18SAlex Hornung 		if (fname == NULL && ((1 << utx->ut_type) & etype) == 0) {
14559a92d18SAlex Hornung 			continue;
14659a92d18SAlex Hornung 		}
14759a92d18SAlex Hornung 		if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
14859a92d18SAlex Hornung 			warn(NULL);
14959a92d18SAlex Hornung 			return 0;
15059a92d18SAlex Hornung 		}
15159a92d18SAlex Hornung 		getentryx(ep, utx);
15259a92d18SAlex Hornung 		*nextp = ep;
15359a92d18SAlex Hornung 		nextp = &(ep->next);
15459a92d18SAlex Hornung 	}
15559a92d18SAlex Hornung 
15659a92d18SAlex Hornung 	numutmp = 0;
15759a92d18SAlex Hornung 	if (ehead != NULL) {
15859a92d18SAlex Hornung 		struct utmpentry *from = ehead, *save;
15959a92d18SAlex Hornung 
16059a92d18SAlex Hornung 		ehead = NULL;
16159a92d18SAlex Hornung 		while (from != NULL) {
16259a92d18SAlex Hornung 			for (nextp = &ehead;
16359a92d18SAlex Hornung 			    (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
16459a92d18SAlex Hornung 			    nextp = &(*nextp)->next)
16559a92d18SAlex Hornung 				continue;
16659a92d18SAlex Hornung 			save = from;
16759a92d18SAlex Hornung 			from = from->next;
16859a92d18SAlex Hornung 			save->next = *nextp;
16959a92d18SAlex Hornung 			*nextp = save;
17059a92d18SAlex Hornung 			numutmp++;
17159a92d18SAlex Hornung 		}
17259a92d18SAlex Hornung 	}
17359a92d18SAlex Hornung 	*epp = ehead;
17459a92d18SAlex Hornung 	return numutmp;
17559a92d18SAlex Hornung }
17659a92d18SAlex Hornung 
17759a92d18SAlex Hornung static void
getentryx(struct utmpentry * e,struct utmpx * up)17859a92d18SAlex Hornung getentryx(struct utmpentry *e, struct utmpx *up)
17959a92d18SAlex Hornung {
18059a92d18SAlex Hornung 	COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
18159a92d18SAlex Hornung 	COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
18259a92d18SAlex Hornung 	COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
18359a92d18SAlex Hornung 
18459a92d18SAlex Hornung 	/*
18559a92d18SAlex Hornung 	 * e has just been calloc'd. We don't need to clear it or
18659a92d18SAlex Hornung 	 * append null-terminators, because its length is strictly
18759a92d18SAlex Hornung 	 * greater than the source string. Use strncpy to _read_
18859a92d18SAlex Hornung 	 * up->ut_* because they may not be terminated. For this
18959a92d18SAlex Hornung 	 * reason we use the size of the _source_ as the length
19059a92d18SAlex Hornung 	 * argument.
19159a92d18SAlex Hornung 	 */
1920d92c45cSMatthew Dillon 	snprintf(e->name, sizeof(e->name), "%.*s",
1930d92c45cSMatthew Dillon 		 (int)sizeof(up->ut_name), up->ut_name);
1940d92c45cSMatthew Dillon 	snprintf(e->line, sizeof(e->line), "%.*s",
1950d92c45cSMatthew Dillon 		 (int)sizeof(up->ut_line), up->ut_line);
1960d92c45cSMatthew Dillon 	snprintf(e->host, sizeof(e->host), "%.*s",
1970d92c45cSMatthew Dillon 		 (int)sizeof(up->ut_host), up->ut_host);
19859a92d18SAlex Hornung 
19959a92d18SAlex Hornung 	e->tv = up->ut_tv;
20059a92d18SAlex Hornung 	e->pid = up->ut_pid;
20159a92d18SAlex Hornung 	e->term = up->ut_exit.e_termination;
20259a92d18SAlex Hornung 	e->exit = up->ut_exit.e_exit;
20359a92d18SAlex Hornung 	e->sess = up->ut_session;
20459a92d18SAlex Hornung 	e->type = up->ut_type;
20559a92d18SAlex Hornung 	adjust_size(e);
20659a92d18SAlex Hornung }
207