1 /* $NetBSD: utmpx.c,v 1.26 2009/01/11 02:46:27 christos Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
31 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
34 __RCSID("$NetBSD: utmpx.c,v 1.26 2009/01/11 02:46:27 christos Exp $");
35 #endif /* LIBC_SCCS and not lint */
37 #include "namespace.h"
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
58 static int readonly
= 0;
59 static int version
= 1;
60 static struct utmpx ut
;
61 static char utfile
[MAXPATHLEN
] = _PATH_UTMPX
;
63 static struct utmpx
*utmp_update(const struct utmpx
*);
65 static const char vers
[] = "utmpx-2.00";
73 old2new(struct utmpx
*utx
)
76 struct timeval
*tv
= &utx
->ut_tv
;
77 (void)memcpy(&otv
, tv
, sizeof(otv
));
78 tv
->tv_sec
= otv
.tv_sec
;
79 tv
->tv_usec
= otv
.tv_usec
;
83 new2old(struct utmpx
*utx
)
86 struct otimeval
*otv
= (void *)&utx
->ut_tv
;
87 (void)memcpy(&tv
, otv
, sizeof(tv
));
88 otv
->tv_sec
= (long)tv
.tv_sec
;
89 otv
->tv_usec
= (long)tv
.tv_usec
;
96 (void)memset(&ut
, 0, sizeof(ut
));
99 (void)fseeko(fp
, (off_t
)sizeof(ut
), SEEK_SET
);
107 (void)memset(&ut
, 0, sizeof(ut
));
123 if ((fp
= fopen(utfile
, "r+")) == NULL
)
124 if ((fp
= fopen(utfile
, "w+")) == NULL
) {
125 if ((fp
= fopen(utfile
, "r")) == NULL
)
132 /* get file size in order to check if new file */
133 if (fstat(fileno(fp
), &st
) == -1)
136 if (st
.st_size
== 0) {
137 /* new file, add signature record */
138 (void)memset(&ut
, 0, sizeof(ut
));
139 ut
.ut_type
= SIGNATURE
;
140 (void)memcpy(ut
.ut_user
, vers
, sizeof(vers
));
141 if (fwrite(&ut
, sizeof(ut
), 1, fp
) != 1)
144 /* old file, read signature record */
145 if (fread(&ut
, sizeof(ut
), 1, fp
) != 1)
147 if (memcmp(ut
.ut_user
, vers
, 5) != 0 ||
148 ut
.ut_type
!= SIGNATURE
)
151 version
= ut
.ut_user
[6] - '0';
154 if (fread(&ut
, sizeof(ut
), 1, fp
) != 1)
163 (void)memset(&ut
, 0, sizeof(ut
));
169 getutxid(const struct utmpx
*utx
)
172 _DIAGASSERT(utx
!= NULL
);
174 if (utx
->ut_type
== EMPTY
)
178 if (ut
.ut_type
== EMPTY
)
180 switch (utx
->ut_type
) {
187 if (ut
.ut_type
== utx
->ut_type
)
194 switch (ut
.ut_type
) {
199 if (memcmp(ut
.ut_id
, utx
->ut_id
,
200 sizeof(ut
.ut_id
)) == 0)
210 } while (getutxent() != NULL
);
216 getutxline(const struct utmpx
*utx
)
219 _DIAGASSERT(utx
!= NULL
);
222 switch (ut
.ut_type
) {
227 if (strncmp(ut
.ut_line
, utx
->ut_line
,
228 sizeof(ut
.ut_line
)) == 0)
234 } while (getutxent() != NULL
);
240 pututxline(const struct utmpx
*utx
)
242 struct utmpx temp
, *u
= NULL
;
245 _DIAGASSERT(utx
!= NULL
);
250 if (strcmp(_PATH_UTMPX
, utfile
) == 0)
251 if ((fp
!= NULL
&& readonly
) || (fp
== NULL
&& geteuid() != 0))
252 return utmp_update(utx
);
255 (void)memcpy(&temp
, utx
, sizeof(temp
));
259 if (fp
== NULL
|| readonly
)
263 if (getutxid(&temp
) == NULL
) {
265 if (getutxid(&temp
) == NULL
) {
266 if (lockf(fileno(fp
), F_LOCK
, (off_t
)0) == -1)
269 if (fseeko(fp
, (off_t
)0, SEEK_END
) == -1)
275 /* we are not appending */
276 if (fseeko(fp
, -(off_t
)sizeof(ut
), SEEK_CUR
) == -1)
282 if (fwrite(&temp
, sizeof (temp
), 1, fp
) != 1)
285 if (fflush(fp
) == -1)
288 u
= memcpy(&ut
, &temp
, sizeof(ut
));
291 if (lockf(fileno(fp
), F_ULOCK
, (off_t
)0) == -1)
298 static struct utmpx
*
299 utmp_update(const struct utmpx
*utx
)
301 char buf
[sizeof(*utx
) * 4 + 1];
305 _DIAGASSERT(utx
!= NULL
);
307 (void)strvisx(buf
, (const char *)(const void *)utx
, sizeof(*utx
),
309 switch (pid
= fork()) {
311 (void)execl(_PATH_UTMP_UPDATE
,
312 strrchr(_PATH_UTMP_UPDATE
, '/') + 1, buf
, NULL
);
318 if (waitpid(pid
, &status
, 0) == -1)
320 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 0)
321 return memcpy(&ut
, utx
, sizeof(ut
));
328 * The following are extensions and not part of the X/Open spec.
331 updwtmpx(const char *file
, const struct utmpx
*utx
)
336 _DIAGASSERT(file
!= NULL
);
337 _DIAGASSERT(utx
!= NULL
);
340 fd
= open(file
, O_WRONLY
|O_APPEND
|O_SHLOCK
);
342 fd
= open(file
, O_WRONLY
|O_APPEND
);
347 if ((fd
= open(file
, O_CREAT
|O_WRONLY
|O_EXLOCK
, 0644)) == -1)
350 if ((fd
= open(file
, O_CREAT
|O_WRONLY
, 0644)) < 0)
352 if (flock(fd
, LOCK_EX
) < 0)
355 (void)memset(&ut
, 0, sizeof(ut
));
356 ut
.ut_type
= SIGNATURE
;
357 (void)memcpy(ut
.ut_user
, vers
, sizeof(vers
));
358 if (write(fd
, &ut
, sizeof(ut
)) == -1)
362 if (flock(fd
, LOCK_SH
) < 0 )
366 if (write(fd
, utx
, sizeof(*utx
)) == -1)
381 utmpxname(const char *fname
)
385 _DIAGASSERT(fname
!= NULL
);
389 if (len
>= sizeof(utfile
))
393 if (fname
[len
- 1] != 'x')
396 (void)strlcpy(utfile
, fname
, sizeof(utfile
));
403 getutmp(const struct utmpx
*ux
, struct utmp
*u
)
406 _DIAGASSERT(ux
!= NULL
);
407 _DIAGASSERT(u
!= NULL
);
409 (void)memcpy(u
->ut_name
, ux
->ut_name
, sizeof(u
->ut_name
));
410 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
411 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
412 u
->ut_time
= ux
->ut_tv
.tv_sec
;
416 getutmpx(const struct utmp
*u
, struct utmpx
*ux
)
419 _DIAGASSERT(ux
!= NULL
);
420 _DIAGASSERT(u
!= NULL
);
422 (void)memcpy(ux
->ut_name
, u
->ut_name
, sizeof(u
->ut_name
));
423 (void)memcpy(ux
->ut_line
, u
->ut_line
, sizeof(u
->ut_line
));
424 (void)memcpy(ux
->ut_host
, u
->ut_host
, sizeof(u
->ut_host
));
425 ux
->ut_tv
.tv_sec
= u
->ut_time
;
426 ux
->ut_tv
.tv_usec
= 0;
427 (void)memset(&ux
->ut_ss
, 0, sizeof(ux
->ut_ss
));
429 ux
->ut_type
= USER_PROCESS
;
431 ux
->ut_exit
.e_termination
= 0;
432 ux
->ut_exit
.e_exit
= 0;
436 getlastlogx(const char *fname
, uid_t uid
, struct lastlogx
*ll
)
441 _DIAGASSERT(fname
!= NULL
);
442 _DIAGASSERT(ll
!= NULL
);
445 db
= dbopen(fname
, O_RDONLY
, 0, DB_HASH
, NULL
);
447 db
= dbopen(fname
, O_RDONLY
|O_SHLOCK
, 0, DB_HASH
, NULL
);
453 if (flock(db
->fd(db
), LOCK_SH
) < 0)
458 key
.size
= sizeof(uid
);
460 if ((db
->get
)(db
, &key
, &data
, 0) != 0)
463 if (data
.size
!= sizeof(*ll
)) {
469 if ((ll
= malloc(sizeof(*ll
))) == NULL
)
472 (void)memcpy(ll
, data
.data
, sizeof(*ll
));
482 updlastlogx(const char *fname
, uid_t uid
, struct lastlogx
*ll
)
488 _DIAGASSERT(fname
!= NULL
);
489 _DIAGASSERT(ll
!= NULL
);
492 db
= dbopen(fname
, O_RDWR
|O_CREAT
|O_EXLOCK
, 0644, DB_HASH
, NULL
);
494 db
= dbopen(fname
, O_RDWR
|O_CREAT
, 0644, DB_HASH
, NULL
);
501 if (flock(db
->fd(db
), LOCK_EX
) < 0)
505 key
.size
= sizeof(uid
);
507 data
.size
= sizeof(*ll
);
508 if ((db
->put
)(db
, &key
, &data
, 0) != 0)