Subject: bin/35135: timespec patches for utmpentry.c
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <dholland@eecs.harvard.edu>
List: netbsd-bugs
Date: 11/26/2006 21:55:00
>Number: 35135
>Category: bin
>Synopsis: timespec patches for utmpentry.c
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sun Nov 26 21:55:00 +0000 2006
>Originator: David A. Holland <dholland@eecs.harvard.edu>
>Release: NetBSD 4.99.3 (-20061125)
>Organization:
Harvard EECS
>Environment:
System: NetBSD weatherwax 4.99.3 NetBSD 4.99.3 (WEATHERWAX) #2: Wed Oct 18 18:55:11 EDT 2006 dholland@weatherwax:/usr/src/sys/arch/i386/compile/WEATHERWAX i386
Architecture: i386
Machine: i386
>Description:
This morning I ran into an odd situation where talkd let me issue a
talk request to a user who had just logged out, after logout, and
repeatedly so until the currently running talkd process timed out,
exited, and was replaced with a new one by inetd.
The symptoms indicate some kind of problem with the utmp entry caching
code, but I can't find one; the only explanation I have is that the
logout code raced with the utmp reload: because the utmpx updating
code uses stdio, updating a utmp entry is not necessarily atomic.
The theory is that part of the entry was written, updating utmpx's
mtime and causing talkd to begin a reload, but the rest wasn't written
until talkd had read past the entry involved in the logout, and all of
this happened within one second so a subsequent check by talkd would
cause it to think its cached utmp data was still current.
Arguably, the utmpx code should be writing entries atomically;
however, the same thing could happen if two users logged out within
one second of each other and talkd looked at utmp in between.
So here's a patch to the utmp monitoring code used by talkd to have it
check the whole timespec instead of just the time in seconds.
>How-To-Repeat:
good luck.
>Fix:
(tested but not extensively so)
Index: usr.bin/who/utmpentry.c
===================================================================
RCS file: /cvsroot/src/usr.bin/who/utmpentry.c,v
retrieving revision 1.10
diff -u -r1.10 utmpentry.c
--- usr.bin/who/utmpentry.c 20 Sep 2006 19:43:33 -0000 1.10
+++ usr.bin/who/utmpentry.c 26 Nov 2006 19:38:35 -0000
@@ -60,11 +60,11 @@
#ifdef SUPPORT_UTMP
static void getentry(struct utmpentry *, struct utmp *);
-static time_t utmptime = 0;
+static struct timespec utmptime = {0, 0};
#endif
#ifdef SUPPORT_UTMPX
static void getentryx(struct utmpentry *, struct utmpx *);
-static time_t utmpxtime = 0;
+static struct timespec utmpxtime = {0, 0};
#endif
#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
static int setup(const char *);
@@ -134,8 +134,8 @@
warn("Cannot stat `%s'", sfname);
what &= ~1;
} else {
- if (st.st_mtime > utmpxtime)
- utmpxtime = st.st_mtime;
+ if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
+ utmpxtime = st.st_mtimespec;
else
what &= ~1;
}
@@ -148,8 +148,8 @@
warn("Cannot stat `%s'", sfname);
what &= ~2;
} else {
- if (st.st_mtime > utmptime)
- utmptime = st.st_mtime;
+ if (timespeccmp(&st.st_mtimespec, &utmptime, >))
+ utmptime = st.st_mtimespec;
else
what &= ~2;
}
@@ -163,10 +163,10 @@
freeutentries(struct utmpentry *ep)
{
#ifdef SUPPORT_UTMP
- utmptime = 0;
+ timespecclear(&utmptime);
#endif
#ifdef SUPPORT_UTMPX
- utmpxtime = 0;
+ timespecclear(&utmpxtime);
#endif
if (ep == ehead) {
ehead = NULL;