]>
Commit | Line | Data |
---|---|---|
1f2f436a | 1 | /* $NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $ */ |
3d9156a7 A |
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. | |
3d9156a7 A |
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 | #include <sys/cdefs.h> | |
32 | ||
33 | #if defined(LIBC_SCCS) && !defined(lint) | |
1f2f436a | 34 | __RCSID("$NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $"); |
3d9156a7 A |
35 | #endif /* LIBC_SCCS and not lint */ |
36 | ||
37 | #include "namespace.h" | |
38 | #include <sys/types.h> | |
39 | #include <sys/param.h> | |
40 | #include <sys/socket.h> | |
41 | #include <sys/stat.h> | |
42 | #include <sys/time.h> | |
43 | #include <sys/wait.h> | |
44 | ||
3d9156a7 A |
45 | #include <fcntl.h> |
46 | #include <stdio.h> | |
47 | #include <stdlib.h> | |
48 | #include <string.h> | |
49 | #include <unistd.h> | |
ad3c9f2a | 50 | #ifdef UNIFDEF_LEGACY_UTMP_APIS |
3d9156a7 | 51 | #include <utmp.h> |
ad3c9f2a | 52 | #endif /* UNIFDEF_LEGACY_UTMP_APIS */ |
3d9156a7 | 53 | #include <utmpx.h> |
ad3c9f2a A |
54 | #include <utmpx-darwin.h> |
55 | #include <errno.h> | |
3d9156a7 | 56 | #include <vis.h> |
ad3c9f2a A |
57 | #include <notify.h> |
58 | ||
6465356a A |
59 | static struct _utmpx *__utx__ = NULL; |
60 | ||
61 | static void | |
62 | __default_utx_init(void) | |
63 | { | |
64 | __utx__ = calloc(1, sizeof(struct _utmpx)); | |
65 | const char magic[] = __UTX_MAGIC__; | |
66 | memcpy(&__utx__->magic, magic, UTMPX_MAGIC); | |
67 | pthread_mutex_init(&__utx__->utmpx_mutex, NULL); | |
68 | __utx__->utfile = _PATH_UTMPX; | |
69 | __utx__->utfile_system = 1; | |
70 | } | |
71 | ||
72 | struct _utmpx * | |
73 | __default_utx(void) | |
74 | { | |
75 | static pthread_once_t once = PTHREAD_ONCE_INIT; | |
76 | pthread_once(&once, &__default_utx_init); | |
77 | return __utx__; | |
78 | } | |
ad3c9f2a A |
79 | |
80 | static struct utmpx *__getutxid(struct _utmpx *, const struct utmpx *); | |
81 | ||
82 | __private_extern__ const char _utmpx_vers[] = "utmpx-1.00"; | |
83 | ||
84 | __private_extern__ void | |
85 | __setutxent(struct _utmpx *U) | |
86 | { | |
3d9156a7 | 87 | |
ad3c9f2a A |
88 | (void)memset(&U->ut, 0, sizeof(U->ut)); |
89 | if (U->fp == NULL) | |
90 | return; | |
91 | #ifdef __LP64__ | |
92 | (void)fseeko(U->fp, (off_t)sizeof(struct utmpx32), SEEK_SET); | |
93 | #else /* __LP64__ */ | |
94 | (void)fseeko(U->fp, (off_t)sizeof(U->ut), SEEK_SET); | |
95 | #endif /* __LP64__ */ | |
96 | } | |
3d9156a7 | 97 | |
ad3c9f2a A |
98 | void |
99 | _setutxent(struct _utmpx *U) | |
100 | { | |
101 | ||
102 | TEST_UTMPX_T("_setutxent", U); | |
103 | UTMPX_LOCK(U); | |
104 | __setutxent(U); | |
105 | UTMPX_UNLOCK(U); | |
106 | } | |
3d9156a7 | 107 | |
3d9156a7 A |
108 | |
109 | void | |
6465356a | 110 | setutxent(void) |
3d9156a7 | 111 | { |
6465356a | 112 | _setutxent(__default_utx()); |
ad3c9f2a | 113 | } |
3d9156a7 | 114 | |
ad3c9f2a A |
115 | |
116 | __private_extern__ void | |
117 | __endutxent(struct _utmpx *U) | |
118 | { | |
119 | (void)memset(&U->ut, 0, sizeof(U->ut)); | |
120 | if (U->fp != NULL) { | |
121 | int saveerrno = errno; | |
122 | (void)fclose(U->fp); | |
123 | errno = saveerrno; | |
124 | U->fp = NULL; | |
125 | U->readonly = 0; | |
126 | } | |
3d9156a7 A |
127 | } |
128 | ||
129 | ||
130 | void | |
ad3c9f2a | 131 | _endutxent(struct _utmpx *U) |
3d9156a7 | 132 | { |
ad3c9f2a A |
133 | TEST_UTMPX_T("_endutxent", U); |
134 | UTMPX_LOCK(U); | |
135 | __endutxent(U); | |
136 | UTMPX_UNLOCK(U); | |
137 | } | |
3d9156a7 | 138 | |
ad3c9f2a A |
139 | |
140 | void | |
6465356a | 141 | endutxent(void) |
ad3c9f2a | 142 | { |
6465356a | 143 | _endutxent(__default_utx()); |
3d9156a7 A |
144 | } |
145 | ||
146 | ||
ad3c9f2a A |
147 | __private_extern__ struct utmpx * |
148 | __getutxent(struct _utmpx *U) | |
3d9156a7 | 149 | { |
ad3c9f2a A |
150 | int saveerrno; |
151 | #ifdef __LP64__ | |
152 | struct utmpx32 ut32; | |
153 | #endif /* __LP64__ */ | |
3d9156a7 | 154 | |
ad3c9f2a | 155 | if (U->fp == NULL) { |
3d9156a7 A |
156 | struct stat st; |
157 | ||
ad3c9f2a A |
158 | if ((U->fp = fopen(U->utfile, "r+")) == NULL) |
159 | if ((U->fp = fopen(U->utfile, "w+")) == NULL) { | |
160 | if ((U->fp = fopen(U->utfile, "r")) == NULL) | |
3d9156a7 A |
161 | goto fail; |
162 | else | |
ad3c9f2a | 163 | U->readonly = 1; |
3d9156a7 | 164 | } |
ad3c9f2a A |
165 | |
166 | fcntl(fileno(U->fp), F_SETFD, 1); /* set close-on-exec flag */ | |
3d9156a7 A |
167 | |
168 | /* get file size in order to check if new file */ | |
ad3c9f2a | 169 | if (fstat(fileno(U->fp), &st) == -1) |
3d9156a7 A |
170 | goto failclose; |
171 | ||
172 | if (st.st_size == 0) { | |
173 | /* new file, add signature record */ | |
ad3c9f2a A |
174 | #ifdef __LP64__ |
175 | (void)memset(&ut32, 0, sizeof(ut32)); | |
176 | ut32.ut_type = SIGNATURE; | |
177 | (void)memcpy(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers)); | |
178 | if (fwrite(&ut32, sizeof(ut32), 1, U->fp) != 1) | |
179 | #else /* __LP64__ */ | |
180 | (void)memset(&U->ut, 0, sizeof(U->ut)); | |
181 | U->ut.ut_type = SIGNATURE; | |
182 | (void)memcpy(U->ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers)); | |
183 | if (fwrite(&U->ut, sizeof(U->ut), 1, U->fp) != 1) | |
184 | #endif /* __LP64__ */ | |
3d9156a7 A |
185 | goto failclose; |
186 | } else { | |
187 | /* old file, read signature record */ | |
ad3c9f2a A |
188 | #ifdef __LP64__ |
189 | if (fread(&ut32, sizeof(ut32), 1, U->fp) != 1) | |
190 | #else /* __LP64__ */ | |
191 | if (fread(&U->ut, sizeof(U->ut), 1, U->fp) != 1) | |
192 | #endif /* __LP64__ */ | |
3d9156a7 | 193 | goto failclose; |
ad3c9f2a A |
194 | #ifdef __LP64__ |
195 | if (memcmp(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 || | |
196 | ut32.ut_type != SIGNATURE) | |
197 | #else /* __LP64__ */ | |
198 | if (memcmp(U->ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 || | |
199 | U->ut.ut_type != SIGNATURE) | |
200 | #endif /* __LP64__ */ | |
201 | { | |
202 | errno = EINVAL; | |
3d9156a7 | 203 | goto failclose; |
ad3c9f2a | 204 | } |
3d9156a7 A |
205 | } |
206 | } | |
207 | ||
ad3c9f2a A |
208 | #ifdef __LP64__ |
209 | if (fread(&ut32, sizeof(ut32), 1, U->fp) != 1) | |
210 | #else /* __LP64__ */ | |
211 | if (fread(&U->ut, sizeof(U->ut), 1, U->fp) != 1) | |
212 | #endif /* __LP64__ */ | |
3d9156a7 A |
213 | goto fail; |
214 | ||
ad3c9f2a A |
215 | #ifdef __LP64__ |
216 | _utmpx32_64(&ut32, &U->ut); | |
217 | #endif /* __LP64__ */ | |
218 | return &U->ut; | |
3d9156a7 | 219 | failclose: |
ad3c9f2a A |
220 | saveerrno = errno; |
221 | (void)fclose(U->fp); | |
222 | errno = saveerrno; | |
223 | U->fp = NULL; | |
3d9156a7 | 224 | fail: |
ad3c9f2a | 225 | (void)memset(&U->ut, 0, sizeof(U->ut)); |
3d9156a7 A |
226 | return NULL; |
227 | } | |
228 | ||
229 | ||
230 | struct utmpx * | |
ad3c9f2a | 231 | _getutxent(struct _utmpx *U) |
3d9156a7 | 232 | { |
ad3c9f2a A |
233 | struct utmpx *ret; |
234 | ||
235 | TEST_UTMPX_T("_getutxent", U); | |
236 | UTMPX_LOCK(U); | |
237 | ret = __getutxent(U); | |
238 | UTMPX_UNLOCK(U); | |
239 | return ret; | |
240 | } | |
241 | ||
242 | ||
243 | struct utmpx * | |
6465356a | 244 | getutxent(void) |
ad3c9f2a | 245 | { |
6465356a | 246 | return _getutxent(__default_utx()); |
ad3c9f2a A |
247 | } |
248 | ||
3d9156a7 | 249 | |
ad3c9f2a A |
250 | struct utmpx * |
251 | _getutxid(struct _utmpx *U, const struct utmpx *utx) | |
252 | { | |
253 | struct utmpx temp; | |
254 | const struct utmpx *ux; | |
255 | struct utmpx *ret; | |
3d9156a7 A |
256 | |
257 | if (utx->ut_type == EMPTY) | |
258 | return NULL; | |
259 | ||
ad3c9f2a A |
260 | TEST_UTMPX_T("_getutxid", U); |
261 | UTMPX_LOCK(U); | |
262 | /* make a copy as needed, and auto-fill if requested */ | |
263 | ux = _utmpx_working_copy(utx, &temp, 1); | |
264 | if (!ux) { | |
265 | UTMPX_UNLOCK(U); | |
266 | return NULL; | |
267 | } | |
268 | ||
269 | ret = __getutxid(U, ux); | |
270 | UTMPX_UNLOCK(U); | |
271 | return ret; | |
272 | } | |
273 | ||
274 | ||
275 | struct utmpx * | |
276 | getutxid(const struct utmpx *utx) | |
277 | { | |
6465356a | 278 | return _getutxid(__default_utx(), utx); |
ad3c9f2a A |
279 | } |
280 | ||
281 | ||
282 | static struct utmpx * | |
283 | __getutxid(struct _utmpx *U, const struct utmpx *utx) | |
284 | { | |
285 | ||
3d9156a7 | 286 | do { |
ad3c9f2a | 287 | if (U->ut.ut_type == EMPTY) |
3d9156a7 A |
288 | continue; |
289 | switch (utx->ut_type) { | |
290 | case EMPTY: | |
291 | return NULL; | |
292 | case RUN_LVL: | |
293 | case BOOT_TIME: | |
294 | case OLD_TIME: | |
295 | case NEW_TIME: | |
ad3c9f2a A |
296 | if (U->ut.ut_type == utx->ut_type) |
297 | return &U->ut; | |
3d9156a7 A |
298 | break; |
299 | case INIT_PROCESS: | |
300 | case LOGIN_PROCESS: | |
301 | case USER_PROCESS: | |
302 | case DEAD_PROCESS: | |
ad3c9f2a | 303 | switch (U->ut.ut_type) { |
3d9156a7 A |
304 | case INIT_PROCESS: |
305 | case LOGIN_PROCESS: | |
306 | case USER_PROCESS: | |
307 | case DEAD_PROCESS: | |
ad3c9f2a A |
308 | if (memcmp(U->ut.ut_id, utx->ut_id, |
309 | sizeof(U->ut.ut_id)) == 0) | |
310 | return &U->ut; | |
3d9156a7 A |
311 | break; |
312 | default: | |
313 | break; | |
314 | } | |
315 | break; | |
316 | default: | |
317 | return NULL; | |
318 | } | |
ad3c9f2a | 319 | } while (__getutxent(U) != NULL); |
3d9156a7 A |
320 | return NULL; |
321 | } | |
322 | ||
323 | ||
ad3c9f2a A |
324 | static struct utmpx * |
325 | __getutxline(struct _utmpx *U, const struct utmpx *utx) | |
3d9156a7 | 326 | { |
3d9156a7 | 327 | do { |
ad3c9f2a | 328 | switch (U->ut.ut_type) { |
3d9156a7 A |
329 | case EMPTY: |
330 | break; | |
331 | case LOGIN_PROCESS: | |
332 | case USER_PROCESS: | |
ad3c9f2a A |
333 | if (strncmp(U->ut.ut_line, utx->ut_line, |
334 | sizeof(U->ut.ut_line)) == 0) | |
335 | return &U->ut; | |
3d9156a7 A |
336 | break; |
337 | default: | |
338 | break; | |
339 | } | |
ad3c9f2a | 340 | } while (__getutxent(U) != NULL); |
3d9156a7 A |
341 | return NULL; |
342 | } | |
343 | ||
344 | ||
345 | struct utmpx * | |
ad3c9f2a | 346 | _getutxline(struct _utmpx *U, const struct utmpx *utx) |
3d9156a7 | 347 | { |
ad3c9f2a A |
348 | struct utmpx *ret; |
349 | ||
350 | TEST_UTMPX_T("_getutxline", U); | |
351 | UTMPX_LOCK(U); | |
352 | ret = __getutxline(U, utx); | |
353 | UTMPX_UNLOCK(U); | |
354 | return ret; | |
355 | } | |
3d9156a7 | 356 | |
3d9156a7 | 357 | |
ad3c9f2a A |
358 | struct utmpx * |
359 | getutxline(const struct utmpx *utx) | |
360 | { | |
6465356a | 361 | return _getutxline(__default_utx(), utx); |
ad3c9f2a A |
362 | } |
363 | ||
364 | ||
365 | struct utmpx * | |
366 | _pututxline(struct _utmpx *U, const struct utmpx *utx) | |
367 | { | |
368 | struct utmpx *ux; | |
369 | ||
370 | if (utx == NULL) { | |
371 | errno = EINVAL; | |
3d9156a7 | 372 | return NULL; |
ad3c9f2a | 373 | } |
3d9156a7 | 374 | |
ad3c9f2a A |
375 | TEST_UTMPX_T("_pututxline", U); |
376 | UTMPX_LOCK(U); | |
6465356a | 377 | if ((ux = __pututxline(__default_utx(), utx)) != NULL && __default_utx()->utfile_system) { |
ad3c9f2a A |
378 | _utmpx_asl(ux); /* the equivalent of wtmpx and lastlogx */ |
379 | #ifdef UTMP_COMPAT | |
380 | _write_utmp_compat(ux); | |
381 | #endif /* UTMP_COMPAT */ | |
382 | } | |
383 | UTMPX_UNLOCK(U); | |
384 | return ux; | |
385 | } | |
3d9156a7 A |
386 | |
387 | ||
ad3c9f2a A |
388 | struct utmpx * |
389 | pututxline(const struct utmpx *utx) | |
390 | { | |
6465356a | 391 | return _pututxline(__default_utx(), utx); |
ad3c9f2a A |
392 | } |
393 | ||
394 | __private_extern__ struct utmpx * | |
395 | __pututxline(struct _utmpx *U, const struct utmpx *utx) | |
396 | { | |
397 | struct utmpx temp, *u = NULL, *x; | |
398 | const struct utmpx *ux; | |
399 | #ifdef __LP64__ | |
400 | struct utmpx32 ut32; | |
401 | #endif /* __LP64__ */ | |
402 | struct flock fl; | |
403 | #define gotlock (fl.l_start >= 0) | |
404 | ||
405 | fl.l_start = -1; /* also means we haven't locked */ | |
406 | if (U->utfile_system) | |
407 | if ((U->fp != NULL && U->readonly) || (U->fp == NULL && geteuid() != 0)) { | |
408 | errno = EPERM; | |
409 | return NULL; | |
410 | } | |
3d9156a7 | 411 | |
ad3c9f2a A |
412 | if (U->fp == NULL) { |
413 | (void)__getutxent(U); | |
414 | if (U->fp == NULL || U->readonly) { | |
415 | errno = EPERM; | |
3d9156a7 | 416 | return NULL; |
ad3c9f2a | 417 | } |
3d9156a7 A |
418 | } |
419 | ||
ad3c9f2a A |
420 | /* make a copy as needed, and auto-fill if requested */ |
421 | ux = _utmpx_working_copy(utx, &temp, 0); | |
422 | if (!ux) | |
423 | return NULL; | |
424 | ||
425 | if ((x = __getutxid(U, ux)) == NULL) { | |
426 | __setutxent(U); | |
427 | if ((x = __getutxid(U, ux)) == NULL) { | |
428 | /* | |
429 | * utx->ut_type has any original mask bits, while | |
430 | * ux->ut_type has those mask bits removed. If we | |
431 | * are trying to record a dead process, and | |
432 | * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, then since | |
433 | * there is no matching entry, we return NULL. | |
434 | */ | |
435 | if (ux->ut_type == DEAD_PROCESS && | |
436 | (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK)) { | |
437 | errno = EINVAL; | |
3d9156a7 | 438 | return NULL; |
ad3c9f2a A |
439 | } |
440 | /* | |
441 | * Replace lockf() with fcntl() and a fixed start | |
442 | * value. We should already be at EOF. | |
443 | */ | |
444 | if ((fl.l_start = lseek(fileno(U->fp), 0, SEEK_CUR)) < 0) | |
445 | return NULL; | |
446 | fl.l_len = 0; | |
447 | fl.l_whence = SEEK_SET; | |
448 | fl.l_type = F_WRLCK; | |
449 | if (fcntl(fileno(U->fp), F_SETLKW, &fl) == -1) | |
450 | return NULL; | |
451 | if (fseeko(U->fp, (off_t)0, SEEK_END) == -1) | |
3d9156a7 A |
452 | goto fail; |
453 | } | |
454 | } | |
455 | ||
456 | if (!gotlock) { | |
ad3c9f2a A |
457 | /* |
458 | * utx->ut_type has any original mask bits, while | |
459 | * ux->ut_type has those mask bits removed. If we | |
460 | * are trying to record a dead process, if | |
461 | * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, but the found | |
462 | * entry is not a (matching) USER_PROCESS, then return NULL. | |
463 | */ | |
464 | if (ux->ut_type == DEAD_PROCESS && | |
465 | (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK) && | |
466 | x->ut_type != USER_PROCESS) { | |
467 | errno = EINVAL; | |
468 | return NULL; | |
469 | } | |
3d9156a7 | 470 | /* we are not appending */ |
ad3c9f2a A |
471 | #ifdef __LP64__ |
472 | if (fseeko(U->fp, -(off_t)sizeof(ut32), SEEK_CUR) == -1) | |
473 | #else /* __LP64__ */ | |
474 | if (fseeko(U->fp, -(off_t)sizeof(U->ut), SEEK_CUR) == -1) | |
475 | #endif /* __LP64__ */ | |
3d9156a7 A |
476 | return NULL; |
477 | } | |
478 | ||
ad3c9f2a A |
479 | #ifdef __LP64__ |
480 | _utmpx64_32(ux, &ut32); | |
481 | if (fwrite(&ut32, sizeof (ut32), 1, U->fp) != 1) | |
482 | #else /* __LP64__ */ | |
483 | if (fwrite(ux, sizeof (*ux), 1, U->fp) != 1) | |
484 | #endif /* __LP64__ */ | |
3d9156a7 A |
485 | goto fail; |
486 | ||
ad3c9f2a | 487 | if (fflush(U->fp) == -1) |
3d9156a7 A |
488 | goto fail; |
489 | ||
ad3c9f2a A |
490 | u = memcpy(&U->ut, ux, sizeof(U->ut)); |
491 | notify_post(UTMPX_CHANGE_NOTIFICATION); | |
3d9156a7 A |
492 | fail: |
493 | if (gotlock) { | |
ad3c9f2a A |
494 | int save = errno; |
495 | fl.l_type = F_UNLCK; | |
496 | if (fcntl(fileno(U->fp), F_SETLK, &fl) == -1) | |
3d9156a7 | 497 | return NULL; |
ad3c9f2a | 498 | errno = save; |
3d9156a7 A |
499 | } |
500 | return u; | |
501 | } | |
502 | ||
503 | ||
3d9156a7 A |
504 | /* |
505 | * The following are extensions and not part of the X/Open spec. | |
506 | */ | |
ad3c9f2a A |
507 | __private_extern__ int |
508 | __utmpxname(struct _utmpx *U, const char *fname) | |
3d9156a7 A |
509 | { |
510 | size_t len; | |
511 | ||
ad3c9f2a A |
512 | if (fname == NULL) { |
513 | if(!U->utfile_system) | |
514 | free(U->utfile); | |
515 | U->utfile = _PATH_UTMPX; | |
516 | U->utfile_system = 1; | |
517 | __endutxent(U); | |
518 | return 1; | |
519 | } | |
3d9156a7 A |
520 | |
521 | len = strlen(fname); | |
522 | ||
ad3c9f2a | 523 | if (len >= MAXPATHLEN) |
3d9156a7 A |
524 | return 0; |
525 | ||
526 | /* must end in x! */ | |
527 | if (fname[len - 1] != 'x') | |
528 | return 0; | |
529 | ||
ad3c9f2a A |
530 | if (U->utfile_system) |
531 | U->utfile = NULL; | |
532 | U->utfile_system = 0; | |
533 | if ((U->utfile = reallocf(U->utfile, len + 1)) == NULL) | |
534 | return 0; | |
535 | ||
536 | (void)strcpy(U->utfile, fname); | |
537 | __endutxent(U); | |
3d9156a7 A |
538 | return 1; |
539 | } | |
540 | ||
ad3c9f2a A |
541 | int |
542 | _utmpxname(struct _utmpx *U, const char *fname) | |
543 | { | |
544 | int ret; | |
545 | ||
546 | TEST_UTMPX_T("_utmpxname", U); | |
547 | UTMPX_LOCK(U); | |
548 | ret = __utmpxname(U, fname); | |
549 | UTMPX_UNLOCK(U); | |
550 | return ret; | |
551 | } | |
552 | ||
553 | int | |
554 | utmpxname(const char *fname) | |
555 | { | |
6465356a | 556 | return _utmpxname(__default_utx(), fname); |
ad3c9f2a | 557 | } |
3d9156a7 | 558 | |
ad3c9f2a | 559 | #ifdef UNIFDEF_LEGACY_UTMP_APIS |
3d9156a7 A |
560 | void |
561 | getutmp(const struct utmpx *ux, struct utmp *u) | |
562 | { | |
563 | ||
ad3c9f2a A |
564 | bzero(u, sizeof(*u)); |
565 | (void)memcpy(u->ut_name, ux->ut_user, sizeof(u->ut_name)); | |
3d9156a7 A |
566 | (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line)); |
567 | (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host)); | |
568 | u->ut_time = ux->ut_tv.tv_sec; | |
569 | } | |
570 | ||
571 | void | |
572 | getutmpx(const struct utmp *u, struct utmpx *ux) | |
573 | { | |
574 | ||
ad3c9f2a A |
575 | bzero(ux, sizeof(*ux)); |
576 | (void)memcpy(ux->ut_user, u->ut_name, sizeof(u->ut_name)); | |
577 | ux->ut_user[sizeof(u->ut_name)] = 0; | |
3d9156a7 | 578 | (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line)); |
ad3c9f2a | 579 | ux->ut_line[sizeof(u->ut_line)] = 0; |
3d9156a7 | 580 | (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host)); |
ad3c9f2a | 581 | ux->ut_host[sizeof(u->ut_host)] = 0; |
3d9156a7 A |
582 | ux->ut_tv.tv_sec = u->ut_time; |
583 | ux->ut_tv.tv_usec = 0; | |
ad3c9f2a | 584 | ux->ut_pid = getpid(); |
3d9156a7 | 585 | ux->ut_type = USER_PROCESS; |
3d9156a7 | 586 | } |
ad3c9f2a | 587 | #endif /* UNIFDEF_LEGACY_UTMP_APIS */ |