xref: /netbsd/usr.bin/who/utmpentry.c (revision c4a72b64)
1 /*	$NetBSD: utmpentry.c,v 1.3 2002/08/01 23:51:42 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.3 2002/08/01 23:51:42 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 	if (ep == ehead) {
153 		ehead = NULL;
154 		numutmp = 0;
155 	}
156 	while (ep) {
157 		struct utmpentry *sep = ep;
158 		ep = ep->next;
159 		free(sep);
160 	}
161 }
162 
163 int
164 getutentries(const char *fname, struct utmpentry **epp)
165 {
166 #ifdef SUPPORT_UTMPX
167 	struct utmpx *utx;
168 #endif
169 #ifdef SUPPORT_UTMP
170 	struct utmp *ut;
171 #endif
172 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
173 	struct utmpentry *ep;
174 	int what = setup(fname);
175 	struct utmpentry **nextp = &ehead;
176 	if (what == 0) {
177 		*epp = ehead;
178 		return numutmp;
179 	} else {
180 		ehead = NULL;
181 		numutmp = 0;
182 	}
183 #endif
184 
185 #ifdef SUPPORT_UTMPX
186 	while ((what & 1) && (utx = getutxent()) != NULL) {
187 		if (fname == NULL && utx->ut_type != USER_PROCESS)
188 			continue;
189 		if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL)
190 			err(1, NULL);
191 		getentryx(ep, utx);
192 		*nextp = ep;
193 		nextp = &(ep->next);
194 	}
195 #endif
196 
197 #ifdef SUPPORT_UTMP
198 	while ((what & 2) && (ut = getutent()) != NULL) {
199 		if (fname == NULL && (*ut->ut_name == '\0' ||
200 		    *ut->ut_line == '\0'))
201 			continue;
202 		/* Don't process entries that we have utmpx for */
203 		for (ep = ehead; ep != NULL; ep = ep->next) {
204 			if (strncmp(ep->line, ut->ut_line,
205 			    sizeof(ut->ut_line)) == 0)
206 				break;
207 		}
208 		if (ep != NULL)
209 			continue;
210 		if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL)
211 			err(1, NULL);
212 		getentry(ep, ut);
213 		*nextp = ep;
214 		nextp = &(ep->next);
215 	}
216 #endif
217 	numutmp = 0;
218 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX)
219 	if (ehead != NULL) {
220 		struct utmpentry *from = ehead, *save;
221 
222 		ehead = NULL;
223 		while (from != NULL) {
224 			for (nextp = &ehead;
225 			    (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
226 			    nextp = &(*nextp)->next)
227 				continue;
228 			save = from;
229 			from = from->next;
230 			save->next = *nextp;
231 			*nextp = save;
232 			numutmp++;
233 		}
234 	}
235 	*epp = ehead;
236 	return numutmp;
237 #else
238 	*epp = NULL;
239 	return 0;
240 #endif
241 }
242 
243 #ifdef SUPPORT_UTMP
244 static void
245 getentry(struct utmpentry *e, struct utmp *up)
246 {
247 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
248 	e->name[sizeof(e->name) - 1] = '\0';
249 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
250 	e->line[sizeof(e->line) - 1] = '\0';
251 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
252 	e->name[sizeof(e->host) - 1] = '\0';
253 	e->tv.tv_sec = up->ut_time;
254 	e->tv.tv_usec = 0;
255 	adjust_size(e);
256 }
257 #endif
258 
259 #ifdef SUPPORT_UTMPX
260 static void
261 getentryx(struct utmpentry *e, struct utmpx *up)
262 {
263 	(void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
264 	e->name[sizeof(e->name) - 1] = '\0';
265 	(void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
266 	e->line[sizeof(e->line) - 1] = '\0';
267 	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
268 	e->name[sizeof(e->host) - 1] = '\0';
269 	e->tv = up->ut_tv;
270 	adjust_size(e);
271 }
272 #endif
273