]> git.saurik.com Git - apple/shell_cmds.git/blob - who/utmpentry.c
shell_cmds-207.11.1.tar.gz
[apple/shell_cmds.git] / who / utmpentry.c
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
69 static void getentry(struct utmpentry *, struct utmp *);
70 static struct timespec utmptime = {0, 0};
71 #endif
72 #ifdef SUPPORT_UTMPX
73 static void getentryx(struct utmpentry *, struct utmpx *);
74 static struct timespec utmpxtime = {0, 0};
75 #endif
76 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
77 static int setup(const char *);
78 static void adjust_size(struct utmpentry *e);
79 #endif
80
81 int maxname = 8, maxline = 8, maxhost = 16;
82 int etype = 1 << USER_PROCESS;
83 static int numutmp = 0;
84 static struct utmpentry *ehead;
85
86 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
87 static void
88 adjust_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
100 static int
101 setup(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
173 void
174 endutentries(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
194 int
195 getutentries(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
288 static void
289 getentry(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
319 static void
320 getentryx(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