xref: /netbsd-src/usr.bin/who/utmpentry.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: utmpentry.c,v 1.5 2004/10/22 15:50:47 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.5 2004/10/22 15:50:47 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 	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->host) - 1] = '\0';
294 	e->tv = up->ut_tv;
295 	adjust_size(e);
296 }
297 #endif
298