utmpentry.c revision 1.10 1 /* $NetBSD: utmpentry.c,v 1.10 2006/09/20 19:43:33 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.10 2006/09/20 19:43:33 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 int etype = 1 << USER_PROCESS;
76 static int numutmp = 0;
77 static struct utmpentry *ehead;
78
79 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
80 static void
81 adjust_size(struct utmpentry *e)
82 {
83 int max;
84
85 if ((max = strlen(e->name)) > maxname)
86 maxname = max;
87 if ((max = strlen(e->line)) > maxline)
88 maxline = max;
89 if ((max = strlen(e->host)) > maxhost)
90 maxhost = max;
91 }
92
93 static int
94 setup(const char *fname)
95 {
96 int what = 3;
97 struct stat st;
98 const char *sfname;
99
100 if (fname == NULL) {
101 #ifdef SUPPORT_UTMPX
102 setutxent();
103 #endif
104 #ifdef SUPPORT_UTMP
105 setutent();
106 #endif
107 } else {
108 size_t len = strlen(fname);
109 if (len == 0)
110 errx(1, "Filename cannot be 0 length.");
111 what = fname[len - 1] == 'x' ? 1 : 2;
112 if (what == 1) {
113 #ifdef SUPPORT_UTMPX
114 if (utmpxname(fname) == 0)
115 warnx("Cannot set utmpx file to `%s'",
116 fname);
117 #else
118 warnx("utmpx support not compiled in");
119 #endif
120 } else {
121 #ifdef SUPPORT_UTMP
122 if (utmpname(fname) == 0)
123 warnx("Cannot set utmp file to `%s'",
124 fname);
125 #else
126 warnx("utmp support not compiled in");
127 #endif
128 }
129 }
130 #ifdef SUPPORT_UTMPX
131 if (what & 1) {
132 sfname = fname ? fname : _PATH_UTMPX;
133 if (stat(sfname, &st) == -1) {
134 warn("Cannot stat `%s'", sfname);
135 what &= ~1;
136 } else {
137 if (st.st_mtime > utmpxtime)
138 utmpxtime = st.st_mtime;
139 else
140 what &= ~1;
141 }
142 }
143 #endif
144 #ifdef SUPPORT_UTMP
145 if (what & 2) {
146 sfname = fname ? fname : _PATH_UTMP;
147 if (stat(sfname, &st) == -1) {
148 warn("Cannot stat `%s'", sfname);
149 what &= ~2;
150 } else {
151 if (st.st_mtime > utmptime)
152 utmptime = st.st_mtime;
153 else
154 what &= ~2;
155 }
156 }
157 #endif
158 return what;
159 }
160 #endif
161
162 void
163 freeutentries(struct utmpentry *ep)
164 {
165 #ifdef SUPPORT_UTMP
166 utmptime = 0;
167 #endif
168 #ifdef SUPPORT_UTMPX
169 utmpxtime = 0;
170 #endif
171 if (ep == ehead) {
172 ehead = NULL;
173 numutmp = 0;
174 }
175 while (ep) {
176 struct utmpentry *sep = ep;
177 ep = ep->next;
178 free(sep);
179 }
180 }
181
182 int
183 getutentries(const char *fname, struct utmpentry **epp)
184 {
185 #ifdef SUPPORT_UTMPX
186 struct utmpx *utx;
187 #endif
188 #ifdef SUPPORT_UTMP
189 struct utmp *ut;
190 #endif
191 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
192 struct utmpentry *ep;
193 int what = setup(fname);
194 struct utmpentry **nextp = &ehead;
195 switch (what) {
196 case 0:
197 /* No updates */
198 *epp = ehead;
199 return numutmp;
200 default:
201 /* Need to re-scan */
202 ehead = NULL;
203 numutmp = 0;
204 }
205 #endif
206
207 #ifdef SUPPORT_UTMPX
208 while ((what & 1) && (utx = getutxent()) != NULL) {
209 if (fname == NULL && ((1 << utx->ut_type) & etype) == 0)
210 continue;
211 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
212 warn(NULL);
213 return 0;
214 }
215 getentryx(ep, utx);
216 *nextp = ep;
217 nextp = &(ep->next);
218 }
219 #endif
220
221 #ifdef SUPPORT_UTMP
222 if ((etype & (1 << USER_PROCESS)) != 0) {
223 while ((what & 2) && (ut = getutent()) != NULL) {
224 if (fname == NULL && (*ut->ut_name == '\0' ||
225 *ut->ut_line == '\0'))
226 continue;
227 /* Don't process entries that we have utmpx for */
228 for (ep = ehead; ep != NULL; ep = ep->next) {
229 if (strncmp(ep->line, ut->ut_line,
230 sizeof(ut->ut_line)) == 0)
231 break;
232 }
233 if (ep != NULL)
234 continue;
235 if ((ep = calloc(1, sizeof(*ep))) == NULL) {
236 warn(NULL);
237 return 0;
238 }
239 getentry(ep, ut);
240 *nextp = ep;
241 nextp = &(ep->next);
242 }
243 }
244 #endif
245 numutmp = 0;
246 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX)
247 if (ehead != NULL) {
248 struct utmpentry *from = ehead, *save;
249
250 ehead = NULL;
251 while (from != NULL) {
252 for (nextp = &ehead;
253 (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
254 nextp = &(*nextp)->next)
255 continue;
256 save = from;
257 from = from->next;
258 save->next = *nextp;
259 *nextp = save;
260 numutmp++;
261 }
262 }
263 *epp = ehead;
264 return numutmp;
265 #else
266 *epp = NULL;
267 return 0;
268 #endif
269 }
270
271 #ifdef SUPPORT_UTMP
272 static void
273 getentry(struct utmpentry *e, struct utmp *up)
274 {
275 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
276 e->name[sizeof(e->name) - 1] = '\0';
277 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
278 e->line[sizeof(e->line) - 1] = '\0';
279 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
280 e->name[sizeof(e->name) - 1] = '\0';
281 e->tv.tv_sec = up->ut_time;
282 e->tv.tv_usec = 0;
283 e->pid = 0;
284 e->term = 0;
285 e->exit = 0;
286 e->sess = 0;
287 e->type = USER_PROCESS;
288 adjust_size(e);
289 }
290 #endif
291
292 #ifdef SUPPORT_UTMPX
293 static void
294 getentryx(struct utmpentry *e, struct utmpx *up)
295 {
296 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
297 e->name[sizeof(e->name) - 1] = '\0';
298 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
299 e->line[sizeof(e->line) - 1] = '\0';
300 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
301 e->name[sizeof(e->name) - 1] = '\0';
302 e->tv = up->ut_tv;
303 e->pid = up->ut_pid;
304 e->term = up->ut_exit.e_termination;
305 e->exit = up->ut_exit.e_exit;
306 e->sess = up->ut_session;
307 e->type = up->ut_type;
308 adjust_size(e);
309 }
310 #endif
311