1 /* $NetBSD: utmpx.c,v 1.25.8.3 2008/11/23 22:54:47 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.25.8.3 2008/11/23 22:54:47 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
);
339 fd
= open(file
, O_WRONLY
|O_APPEND
|O_SHLOCK
);
342 if ((fd
= open(file
, O_CREAT
|O_WRONLY
|O_EXLOCK
, 0644)) == -1)
344 (void)memset(&ut
, 0, sizeof(ut
));
345 ut
.ut_type
= SIGNATURE
;
346 (void)memcpy(ut
.ut_user
, vers
, sizeof(vers
));
347 if (write(fd
, &ut
, sizeof(ut
)) == -1)
350 if (write(fd
, utx
, sizeof(*utx
)) == -1)
365 utmpxname(const char *fname
)
369 _DIAGASSERT(fname
!= NULL
);
373 if (len
>= sizeof(utfile
))
377 if (fname
[len
- 1] != 'x')
380 (void)strlcpy(utfile
, fname
, sizeof(utfile
));
387 getutmp(const struct utmpx
*ux
, struct utmp
*u
)
390 _DIAGASSERT(ux
!= NULL
);
391 _DIAGASSERT(u
!= NULL
);
393 (void)memcpy(u
->ut_name
, ux
->ut_name
, sizeof(u
->ut_name
));
394 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
395 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
396 u
->ut_time
= ux
->ut_tv
.tv_sec
;
400 getutmpx(const struct utmp
*u
, struct utmpx
*ux
)
403 _DIAGASSERT(ux
!= NULL
);
404 _DIAGASSERT(u
!= NULL
);
406 (void)memcpy(ux
->ut_name
, u
->ut_name
, sizeof(u
->ut_name
));
407 (void)memcpy(ux
->ut_line
, u
->ut_line
, sizeof(u
->ut_line
));
408 (void)memcpy(ux
->ut_host
, u
->ut_host
, sizeof(u
->ut_host
));
409 ux
->ut_tv
.tv_sec
= u
->ut_time
;
410 ux
->ut_tv
.tv_usec
= 0;
411 (void)memset(&ux
->ut_ss
, 0, sizeof(ux
->ut_ss
));
413 ux
->ut_type
= USER_PROCESS
;
415 ux
->ut_exit
.e_termination
= 0;
416 ux
->ut_exit
.e_exit
= 0;
420 getlastlogx(const char *fname
, uid_t uid
, struct lastlogx
*ll
)
425 _DIAGASSERT(fname
!= NULL
);
426 _DIAGASSERT(ll
!= NULL
);
428 db
= dbopen(fname
, O_RDONLY
|O_SHLOCK
, 0, DB_HASH
, NULL
);
434 key
.size
= sizeof(uid
);
436 if ((db
->get
)(db
, &key
, &data
, 0) != 0)
439 if (data
.size
!= sizeof(*ll
)) {
445 if ((ll
= malloc(sizeof(*ll
))) == NULL
)
448 (void)memcpy(ll
, data
.data
, sizeof(*ll
));
458 updlastlogx(const char *fname
, uid_t uid
, struct lastlogx
*ll
)
464 _DIAGASSERT(fname
!= NULL
);
465 _DIAGASSERT(ll
!= NULL
);
467 db
= dbopen(fname
, O_RDWR
|O_CREAT
|O_EXLOCK
, 0644, DB_HASH
, NULL
);
473 key
.size
= sizeof(uid
);
475 data
.size
= sizeof(*ll
);
476 if ((db
->put
)(db
, &key
, &data
, 0) != 0)