No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / who / utmpentry.c
blobe88ccb411d7cd48594a63325245d17413f9cb26c
1 /* $NetBSD: utmpentry.c,v 1.16 2008/10/28 14:01:46 christos Exp $ */
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: utmpentry.c,v 1.16 2008/10/28 14:01:46 christos Exp $");
35 #endif
37 #include <sys/stat.h>
39 #include <time.h>
40 #include <string.h>
41 #include <err.h>
42 #include <stdlib.h>
44 #ifdef SUPPORT_UTMP
45 #include <utmp.h>
46 #endif
47 #ifdef SUPPORT_UTMPX
48 #include <utmpx.h>
49 #endif
51 #include "utmpentry.h"
54 /* Fail the compile if x is not true, by constructing an illegal type. */
55 #define COMPILE_ASSERT(x) /*LINTED null effect */ \
56 ((void)sizeof(struct { unsigned : ((x) ? 1 : -1); }))
59 #ifdef SUPPORT_UTMP
60 static void getentry(struct utmpentry *, struct utmp *);
61 static struct timespec utmptime = {0, 0};
62 #endif
63 #ifdef SUPPORT_UTMPX
64 static void getentryx(struct utmpentry *, struct utmpx *);
65 static struct timespec utmpxtime = {0, 0};
66 #endif
67 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
68 static int setup(const char *);
69 static void adjust_size(struct utmpentry *e);
70 #endif
72 int maxname = 8, maxline = 8, maxhost = 16;
73 int etype = 1 << USER_PROCESS;
74 static int numutmp = 0;
75 static struct utmpentry *ehead;
77 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
78 static void
79 adjust_size(struct utmpentry *e)
81 int max;
83 if ((max = strlen(e->name)) > maxname)
84 maxname = max;
85 if ((max = strlen(e->line)) > maxline)
86 maxline = max;
87 if ((max = strlen(e->host)) > maxhost)
88 maxhost = max;
91 static int
92 setup(const char *fname)
94 int what = 3;
95 struct stat st;
96 const char *sfname;
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 warnx("Cannot set utmpx file to `%s'",
114 fname);
115 #else
116 warnx("utmpx support not compiled in");
117 #endif
118 } else {
119 #ifdef SUPPORT_UTMP
120 if (utmpname(fname) == 0)
121 warnx("Cannot set utmp file to `%s'",
122 fname);
123 #else
124 warnx("utmp support not compiled in");
125 #endif
128 #ifdef SUPPORT_UTMPX
129 if (what & 1) {
130 sfname = fname ? fname : _PATH_UTMPX;
131 if (stat(sfname, &st) == -1) {
132 warn("Cannot stat `%s'", sfname);
133 what &= ~1;
134 } else {
135 if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
136 utmpxtime = st.st_mtimespec;
137 else
138 what &= ~1;
141 #endif
142 #ifdef SUPPORT_UTMP
143 if (what & 2) {
144 sfname = fname ? fname : _PATH_UTMP;
145 if (stat(sfname, &st) == -1) {
146 warn("Cannot stat `%s'", sfname);
147 what &= ~2;
148 } else {
149 if (timespeccmp(&st.st_mtimespec, &utmptime, >))
150 utmptime = st.st_mtimespec;
151 else
152 what &= ~2;
155 #endif
156 return what;
158 #endif
160 void
161 endutentries(void)
163 struct utmpentry *ep;
165 #ifdef SUPPORT_UTMP
166 timespecclear(&utmptime);
167 #endif
168 #ifdef SUPPORT_UTMPX
169 timespecclear(&utmpxtime);
170 #endif
171 ep = ehead;
172 while (ep) {
173 struct utmpentry *sep = ep;
174 ep = ep->next;
175 free(sep);
177 ehead = NULL;
178 numutmp = 0;
182 getutentries(const char *fname, struct utmpentry **epp)
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;
204 #endif
206 #ifdef SUPPORT_UTMPX
207 while ((what & 1) && (utx = getutxent()) != NULL) {
208 if (fname == NULL && ((1 << utx->ut_type) & etype) == 0)
209 continue;
210 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
211 warn(NULL);
212 return 0;
214 getentryx(ep, utx);
215 *nextp = ep;
216 nextp = &(ep->next);
218 #endif
220 #ifdef SUPPORT_UTMP
221 if ((etype & (1 << USER_PROCESS)) != 0) {
222 while ((what & 2) && (ut = getutent()) != NULL) {
223 if (fname == NULL && (*ut->ut_name == '\0' ||
224 *ut->ut_line == '\0'))
225 continue;
226 /* Don't process entries that we have utmpx for */
227 for (ep = ehead; ep != NULL; ep = ep->next) {
228 if (strncmp(ep->line, ut->ut_line,
229 sizeof(ut->ut_line)) == 0)
230 break;
232 if (ep != NULL)
233 continue;
234 if ((ep = calloc(1, sizeof(*ep))) == NULL) {
235 warn(NULL);
236 return 0;
238 getentry(ep, ut);
239 *nextp = ep;
240 nextp = &(ep->next);
243 #endif
244 numutmp = 0;
245 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
246 if (ehead != NULL) {
247 struct utmpentry *from = ehead, *save;
249 ehead = NULL;
250 while (from != NULL) {
251 for (nextp = &ehead;
252 (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
253 nextp = &(*nextp)->next)
254 continue;
255 save = from;
256 from = from->next;
257 save->next = *nextp;
258 *nextp = save;
259 numutmp++;
262 *epp = ehead;
263 return numutmp;
264 #else
265 *epp = NULL;
266 return 0;
267 #endif
270 #ifdef SUPPORT_UTMP
271 static void
272 getentry(struct utmpentry *e, struct utmp *up)
274 COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
275 COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
276 COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
279 * e has just been calloc'd. We don't need to clear it or
280 * append null-terminators, because its length is strictly
281 * greater than the source string. Use strncpy to _read_
282 * up->ut_* because they may not be terminated. For this
283 * reason we use the size of the _source_ as the length
284 * argument.
286 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
287 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
288 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
290 e->tv.tv_sec = up->ut_time;
291 e->tv.tv_usec = 0;
292 e->pid = 0;
293 e->term = 0;
294 e->exit = 0;
295 e->sess = 0;
296 e->type = USER_PROCESS;
297 adjust_size(e);
299 #endif
301 #ifdef SUPPORT_UTMPX
302 static void
303 getentryx(struct utmpentry *e, struct utmpx *up)
305 COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
306 COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
307 COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
310 * e has just been calloc'd. We don't need to clear it or
311 * append null-terminators, because its length is strictly
312 * greater than the source string. Use strncpy to _read_
313 * up->ut_* because they may not be terminated. For this
314 * reason we use the size of the _source_ as the length
315 * argument.
317 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
318 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
319 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
321 e->tv = up->ut_tv;
322 e->pid = up->ut_pid;
323 e->term = up->ut_exit.e_termination;
324 e->exit = up->ut_exit.e_exit;
325 e->sess = up->ut_session;
326 e->type = up->ut_type;
327 adjust_size(e);
329 #endif