]> git.saurik.com Git - apple/shell_cmds.git/blame - who/utmpentry.c
shell_cmds-207.11.1.tar.gz
[apple/shell_cmds.git] / who / utmpentry.c
CommitLineData
ddb4a88b
A
1/* $NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland 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 *
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.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34__RCSID("$NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland Exp $");
35#endif
36
37#include <sys/stat.h>
38
39#include <time.h>
40#include <string.h>
41#include <err.h>
42#include <stdlib.h>
43#ifdef __APPLE__
44#include <stdint.h>
45#endif /* __APPLE__ */
46
47#ifdef SUPPORT_UTMP
48#include <utmp.h>
49#endif
50#ifdef SUPPORT_UTMPX
51#include <utmpx.h>
52#endif
53
54#include "utmpentry.h"
55
56#ifdef __APPLE__
57#define timespecclear(tsp) (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
58#define timespeccmp(tsp, usp, cmp) \
59 (((tsp)->tv_sec == (usp)->tv_sec) ? \
60 ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
61 ((tsp)->tv_sec cmp (usp)->tv_sec))
62#endif /* __APPLE__ */
63
64/* Fail the compile if x is not true, by constructing an illegal type. */
65#define COMPILE_ASSERT(x) ((void)sizeof(struct { unsigned : ((x) ? 1 : -1); }))
66
67
68#ifdef SUPPORT_UTMP
69static void getentry(struct utmpentry *, struct utmp *);
70static struct timespec utmptime = {0, 0};
71#endif
72#ifdef SUPPORT_UTMPX
73static void getentryx(struct utmpentry *, struct utmpx *);
74static struct timespec utmpxtime = {0, 0};
75#endif
76#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
77static int setup(const char *);
78static void adjust_size(struct utmpentry *e);
79#endif
80
81int maxname = 8, maxline = 8, maxhost = 16;
82int etype = 1 << USER_PROCESS;
83static int numutmp = 0;
84static struct utmpentry *ehead;
85
86#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
87static void
88adjust_size(struct utmpentry *e)
89{
90 int max;
91
92 if ((max = strlen(e->name)) > maxname)
93 maxname = max;
94 if ((max = strlen(e->line)) > maxline)
95 maxline = max;
96 if ((max = strlen(e->host)) > maxhost)
97 maxhost = max;
98}
99
100static int
101setup(const char *fname)
102{
103 int what = 3;
104 struct stat st;
105 const char *sfname;
106
107 if (fname == NULL) {
108#ifdef SUPPORT_UTMPX
109 setutxent();
110#endif
111#ifdef SUPPORT_UTMP
112 setutent();
113#endif
114 } else {
115 size_t len = strlen(fname);
116 if (len == 0)
117 errx(1, "Filename cannot be 0 length.");
118#ifdef __APPLE__
119 what = 1;
120#else /* !__APPLE__ */
121 what = fname[len - 1] == 'x' ? 1 : 2;
122#endif /* __APPLE__ */
123 if (what == 1) {
124#ifdef SUPPORT_UTMPX
125 if (utmpxname(fname) == 0)
126 warnx("Cannot set utmpx file to `%s'",
127 fname);
128#else
129 warnx("utmpx support not compiled in");
130#endif
131 } else {
132#ifdef SUPPORT_UTMP
133 if (utmpname(fname) == 0)
134 warnx("Cannot set utmp file to `%s'",
135 fname);
136#else
137 warnx("utmp support not compiled in");
138#endif
139 }
140 }
141#ifdef SUPPORT_UTMPX
142 if (what & 1) {
143 sfname = fname ? fname : _PATH_UTMPX;
144 if (stat(sfname, &st) == -1) {
145 warn("Cannot stat `%s'", sfname);
146 what &= ~1;
147 } else {
148 if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
149 utmpxtime = st.st_mtimespec;
150 else
151 what &= ~1;
152 }
153 }
154#endif
155#ifdef SUPPORT_UTMP
156 if (what & 2) {
157 sfname = fname ? fname : _PATH_UTMP;
158 if (stat(sfname, &st) == -1) {
159 warn("Cannot stat `%s'", sfname);
160 what &= ~2;
161 } else {
162 if (timespeccmp(&st.st_mtimespec, &utmptime, >))
163 utmptime = st.st_mtimespec;
164 else
165 what &= ~2;
166 }
167 }
168#endif
169 return what;
170}
171#endif
172
173void
174endutentries(void)
175{
176 struct utmpentry *ep;
177
178#ifdef SUPPORT_UTMP
179 timespecclear(&utmptime);
180#endif
181#ifdef SUPPORT_UTMPX
182 timespecclear(&utmpxtime);
183#endif
184 ep = ehead;
185 while (ep) {
186 struct utmpentry *sep = ep;
187 ep = ep->next;
188 free(sep);
189 }
190 ehead = NULL;
191 numutmp = 0;
192}
193
194int
195getutentries(const char *fname, struct utmpentry **epp)
196{
197#ifdef SUPPORT_UTMPX
198 struct utmpx *utx;
199#endif
200#ifdef SUPPORT_UTMP
201 struct utmp *ut;
202#endif
203#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
204 struct utmpentry *ep;
205 int what = setup(fname);
206 struct utmpentry **nextp = &ehead;
207 switch (what) {
208 case 0:
209 /* No updates */
210 *epp = ehead;
211 return numutmp;
212 default:
213 /* Need to re-scan */
214 ehead = NULL;
215 numutmp = 0;
216 }
217#endif
218
219#ifdef SUPPORT_UTMPX
220 while ((what & 1) && (utx = getutxent()) != NULL) {
221#ifdef __APPLE__
222 if (((1 << utx->ut_type) & etype) == 0)
223#else /* !__APPLE__ */
224 if (fname == NULL && ((1 << utx->ut_type) & etype) == 0)
225#endif /* __APPLE__ */
226 continue;
227 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
228 warn(NULL);
229 return 0;
230 }
231 getentryx(ep, utx);
232 *nextp = ep;
233 nextp = &(ep->next);
234 }
235#endif
236
237#ifdef SUPPORT_UTMP
238 if ((etype & (1 << USER_PROCESS)) != 0) {
239 while ((what & 2) && (ut = getutent()) != NULL) {
240 if (fname == NULL && (*ut->ut_name == '\0' ||
241 *ut->ut_line == '\0'))
242 continue;
243 /* Don't process entries that we have utmpx for */
244 for (ep = ehead; ep != NULL; ep = ep->next) {
245 if (strncmp(ep->line, ut->ut_line,
246 sizeof(ut->ut_line)) == 0)
247 break;
248 }
249 if (ep != NULL)
250 continue;
251 if ((ep = calloc(1, sizeof(*ep))) == NULL) {
252 warn(NULL);
253 return 0;
254 }
255 getentry(ep, ut);
256 *nextp = ep;
257 nextp = &(ep->next);
258 }
259 }
260#endif
261 numutmp = 0;
262#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
263 if (ehead != NULL) {
264 struct utmpentry *from = ehead, *save;
265
266 ehead = NULL;
267 while (from != NULL) {
268 for (nextp = &ehead;
269 (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
270 nextp = &(*nextp)->next)
271 continue;
272 save = from;
273 from = from->next;
274 save->next = *nextp;
275 *nextp = save;
276 numutmp++;
277 }
278 }
279 *epp = ehead;
280 return numutmp;
281#else
282 *epp = NULL;
283 return 0;
284#endif
285}
286
287#ifdef SUPPORT_UTMP
288static void
289getentry(struct utmpentry *e, struct utmp *up)
290{
291 COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
292 COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
293 COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
294
295 /*
296 * e has just been calloc'd. We don't need to clear it or
297 * append null-terminators, because its length is strictly
298 * greater than the source string. Use strncpy to _read_
299 * up->ut_* because they may not be terminated. For this
300 * reason we use the size of the _source_ as the length
301 * argument.
302 */
303 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
304 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
305 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
306
307 e->tv.tv_sec = up->ut_time;
308 e->tv.tv_usec = 0;
309 e->pid = 0;
310 e->term = 0;
311 e->exit = 0;
312 e->sess = 0;
313 e->type = USER_PROCESS;
314 adjust_size(e);
315}
316#endif
317
318#ifdef SUPPORT_UTMPX
319static void
320getentryx(struct utmpentry *e, struct utmpx *up)
321{
322 COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
323 COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
324 COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
325
326 /*
327 * e has just been calloc'd. We don't need to clear it or
328 * append null-terminators, because its length is strictly
329 * greater than the source string. Use strncpy to _read_
330 * up->ut_* because they may not be terminated. For this
331 * reason we use the size of the _source_ as the length
332 * argument.
333 */
334 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
335 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
336 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
337
338 e->tv = up->ut_tv;
339 e->pid = up->ut_pid;
340#ifndef __APPLE__
341 e->term = up->ut_exit.e_termination;
342 e->exit = up->ut_exit.e_exit;
343 e->sess = up->ut_session;
344#endif /* !__APPLE__ */
345 e->type = up->ut_type;
346 adjust_size(e);
347}
348#endif