xref: /netbsd-src/usr.bin/who/utmpentry.c (revision de1dfb1250df962f1ff3a011772cf58e605aed11)
1 /*	$NetBSD: utmpentry.c,v 1.4 2003/02/12 17:39:36 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  * 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.4 2003/02/12 17:39:36 christos 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 
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 				err(1, "Cannot open `%s'", fname);
114 #else
115 			errx(1, "utmpx support not compiled in");
116 #endif
117 		} else {
118 #ifdef SUPPORT_UTMP
119 			if (utmpname(fname) == 0)
120 				err(1, "Cannot open `%s'", fname);
121 #else
122 			errx(1, "utmp support not compiled in");
123 #endif
124 		}
125 	}
126 #ifdef SUPPORT_UTMPX
127 	if (what & 1) {
128 		(void)stat(fname ? fname : _PATH_UTMPX, &st);
129 		if (st.st_mtime > utmpxtime)
130 			utmpxtime = st.st_mtime;
131 		else
132 			what &= ~1;
133 	}
134 #endif
135 #ifdef SUPPORT_UTMP
136 	if (what & 2) {
137 		(void)stat(fname ? fname : _PATH_UTMP, &st);
138 		if (st.st_mtime > utmptime)
139 			utmptime = st.st_mtime;
140 		else
141 			what &= ~2;
142 	}
143 #endif
144 
145 	return what;
146 }
147 #endif
148 
149 void
150 freeutentries(struct utmpentry *ep)
151 {
152 #ifdef SUPPORT_UTMP
153 	utmptime = 0;
154 #endif
155 #ifdef SUPPORT_UTMPX
156 	utmpxtime = 0;
157 #endif
158 	if (ep == ehead) {
159 		ehead = NULL;
160 		numutmp = 0;
161 	}
162 	while (ep) {
163 		struct utmpentry *sep = ep;
164 		ep = ep->next;
165 		free(sep);
166 	}
167 }
168 
169 int
170 getutentries(const char *fname, struct utmpentry **epp)
171 {
172 #ifdef SUPPORT_UTMPX
173 	struct utmpx *utx;
174 #endif
175 #ifdef SUPPORT_UTMP
176 	struct utmp *ut;
177 #endif
178 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
179 	struct utmpentry *ep;
180 	int what = setup(fname);
181 	struct utmpentry **nextp = &ehead;
182 	if (what == 0) {
183 		*epp = ehead;
184 		return numutmp;
185 	} else {
186 		ehead = NULL;
187 		numutmp = 0;
188 	}
189 #endif
190 
191 #ifdef SUPPORT_UTMPX
192 	while ((what & 1) && (utx = getutxent()) != NULL) {
193 		if (fname == NULL && utx->ut_type != USER_PROCESS)
194 			continue;
195 		if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL)
196 			err(1, NULL);
197 		getentryx(ep, utx);
198 		*nextp = ep;
199 		nextp = &(ep->next);
200 	}
201 #endif
202 
203 #ifdef SUPPORT_UTMP
204 	while ((what & 2) && (ut = getutent()) != NULL) {
205 		if (fname == NULL && (*ut->ut_name == '\0' ||
206 		    *ut->ut_line == '\0'))
207 			continue;
208 		/* Don't process entries that we have utmpx for */
209 		for (ep = ehead; ep != NULL; ep = ep->next) {
210 			if (strncmp(ep->line, ut->ut_line,
211 			    sizeof(ut->ut_line)) == 0)
212 				break;
213 		}
214 		if (ep != NULL)
215 			continue;
216 		if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL)
217 			err(1, NULL);
218 		getentry(ep, ut);
219 		*nextp = ep;
220 		nextp = &(ep->next);
221 	}
222 #endif
223 	numutmp = 0;
224 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX)
225 	if (ehead != NULL) {
226 		struct utmpentry *from = ehead, *save;
227 
228 		ehead = NULL;
229 		while (from != NULL) {
230 			for (nextp = &ehead;
231 			    (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
232 			    nextp = &(*nextp)->next)
233 				continue;
234 			save = from;
235 			from = from->next;
236 			save->next = *nextp;
237 			*nextp = save;
238 			numutmp++;
239 		}
240 	}
241 	*epp = ehead;
242 	return numutmp;
243 #else
244 	*epp = NULL;
245 	return 0;
246 #endif
247 }
248 
249 #ifdef SUPPORT_UTMP
250 static void
251 getentry(struct utmpentry *e, struct utmp *up)
252 {
253 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
254 	e->name[sizeof(e->name) - 1] = '\0';
255 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
256 	e->line[sizeof(e->line) - 1] = '\0';
257 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
258 	e->name[sizeof(e->host) - 1] = '\0';
259 	e->tv.tv_sec = up->ut_time;
260 	e->tv.tv_usec = 0;
261 	adjust_size(e);
262 }
263 #endif
264 
265 #ifdef SUPPORT_UTMPX
266 static void
267 getentryx(struct utmpentry *e, struct utmpx *up)
268 {
269 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
270 	e->name[sizeof(e->name) - 1] = '\0';
271 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
272 	e->line[sizeof(e->line) - 1] = '\0';
273 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
274 	e->name[sizeof(e->host) - 1] = '\0';
275 	e->tv = up->ut_tv;
276 	adjust_size(e);
277 }
278 #endif
279