about summary refs log tree commit diff
path: root/login
diff options
context:
space:
mode:
Diffstat (limited to 'login')
-rw-r--r--login/Makefile13
-rw-r--r--login/getutent.c34
-rw-r--r--login/getutent_r.c211
-rw-r--r--login/getutid.c36
-rw-r--r--login/getutid_r.c118
-rw-r--r--login/getutline.c36
-rw-r--r--login/getutline_r.c91
-rw-r--r--login/login.c81
-rw-r--r--login/logout.c11
-rw-r--r--login/logwtmp.c28
-rw-r--r--login/utmp-private.h41
-rw-r--r--login/utmp.h43
-rw-r--r--login/utmp_db.c102
-rw-r--r--login/utmp_file.c385
14 files changed, 901 insertions, 329 deletions
diff --git a/login/Makefile b/login/Makefile
index 247ab958df..da47089b5a 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -12,9 +12,9 @@
 # Library General Public License for more details.
 
 # You should have received a copy of the GNU Library General Public
-# License along with the GNU C Library; see the file COPYING.LIB.  If
-# not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# License along with the GNU C Library; see the file COPYING.LIB.  If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
 
 #
 #	Sub-makefile for login portion of the library.
@@ -24,9 +24,10 @@ subdir	:= login
 
 headers	:= utmp.h utmpbits.h lastlog.h pty.h
 
-routines := setutent endutent getutent getutid getutline pututline	\
-	    setutent_r endutent_r getutent_r getutid_r getutline_r	\
-	    pututline_r
+routines := getutent getutent_r getutid getutline getutid_r getutline_r \
+	    utmp_file utmp_db
+
+distribtue := utmp-private.h
 
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
diff --git a/login/getutent.c b/login/getutent.c
index 03b49dbf7e..e9462db18d 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -1,27 +1,27 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <utmp.h>
 
 
-/* The global data defined in setutent.c.  */
-extern struct utmp_data __utmp_data;
+/* Local buffer to store the result.  */
+static struct utmp buffer;
 
 
 struct utmp *
@@ -29,7 +29,7 @@ getutent (void)
 {
   struct utmp *result;
 
-  if (__getutent_r (&result, &__utmp_data) < 0)
+  if (__getutent_r (&buffer, &result) < 0)
     return NULL;
 
   return result;
diff --git a/login/getutent_r.c b/login/getutent_r.c
index e3550017f9..df9a7977ab 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -1,51 +1,196 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>
+   and Paul Janzen <pcj@primenet.com>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
-#include <unistd.h>
+#include <assert.h>
+#include <db.h>
+#include <fcntl.h>
+#include <libc-lock.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <utmp.h>
+#include <gnu/lib-names.h>
+#include <sys/stat.h>
 
+#include "utmp-private.h"
+#include "../elf/link.h"
 
-int
-__getutent_r (struct utmp **utmp, struct utmp_data *utmp_data)
+
+/* The various backends we have.  */
+static int __setutent_unknown (int reset);
+static int __getutent_r_unknown (struct utmp *buffer, struct utmp **result);
+static void __pututline_unknown (const struct utmp *data);
+static void __endutent_unknown (void);
+
+
+/* We have three jump tables: unknown, db, or file.  */
+static struct utfuncs unknown_functions =
+{
+  __setutent_unknown,
+  __getutent_r_unknown,
+  NULL,
+  NULL,
+  __pututline_unknown,
+  __endutent_unknown,
+  NULL
+};
+
+/* Currently selected backend.  */
+struct utfuncs *__libc_utmp_jump_table = &unknown_functions;
+
+/* The tables from the services.  */
+extern struct utfuncs __libc_utmp_db_functions;
+extern struct utfuncs __libc_utmp_file_functions;
+
+
+/* We need to protect the opening of the file.  */
+__libc_lock_define_initialized (, __libc_utmp_lock)
+
+void
+__setutent (void)
+{
+  __libc_lock_lock (__libc_utmp_lock);
+
+  (void) (*__libc_utmp_jump_table->setutent) (1);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+}
+weak_alias (__setutent, setutent)
+
+
+static int
+__setutent_unknown (int reset)
 {
-  /* Open utmp file if not already done.  */
-  if (utmp_data->ut_fd == -1)
+  /* We have to test whether it is still not decided which backend to use.  */
+  assert (__libc_utmp_jump_table == &unknown_functions);
+
+  /* See whether utmp db file exists.  */
+  if ((*__libc_utmp_db_functions.setutent) (reset))
+    __libc_utmp_jump_table = &__libc_utmp_db_functions;
+  else
     {
-      setutent_r (utmp_data);
-      if (utmp_data->ut_fd == -1)
-	return -1;
+      /* Either the db file does not exist or we have other
+	 problems.  So use the normal file.  */
+      (*__libc_utmp_file_functions.setutent) (reset);
+      __libc_utmp_jump_table = &__libc_utmp_file_functions;
     }
 
-  /* Position file correctly.  */
-  if (lseek (utmp_data->ut_fd, utmp_data->loc_utmp, SEEK_SET) == -1)
-    return -1;
+  return 0;
+}
+
 
-  /* Read the next entry.  */
-  if (read (utmp_data->ut_fd, &utmp_data->ubuf, sizeof (struct utmp))
-      != sizeof (struct utmp))
-    return -1;
+void
+__endutent (void)
+{
+  __libc_lock_lock (__libc_utmp_lock);
+
+  (*__libc_utmp_jump_table->endutent) ();
 
-  /* Update position pointer.  */
-  utmp_data->loc_utmp += sizeof (struct utmp);
+  __libc_lock_unlock (__libc_utmp_lock);
+}
+weak_alias (__endutent, endutent)
 
-  *utmp = &utmp_data->ubuf;
 
-  return 0;
+static void
+__endutent_unknown (void)
+{
+  /* Huh, how do we came here?  Nothing to do.  */
+}
+
+
+int
+__getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int retval;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  retval = (*__libc_utmp_jump_table->getutent_r) (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return retval;
 }
 weak_alias (__getutent_r, getutent_r)
+
+
+static int
+__getutent_r_unknown (struct utmp *buffer, struct utmp **result)
+{
+  /* It is not yet initialized.  */
+  __setutent_unknown (0);
+
+  return (*__libc_utmp_jump_table->getutent_r) (buffer, result);
+}
+
+
+void
+__pututline (const struct utmp *data)
+{
+  __libc_lock_lock (__libc_utmp_lock);
+
+  (*__libc_utmp_jump_table->pututline) (data);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+}
+
+
+static void
+__pututline_unknown (const struct utmp *data)
+{
+  /* It is not yet initialized.  */
+  __setutent_unknown (0);
+
+  (*__libc_utmp_jump_table->pututline) (data);
+}
+
+
+int
+__utmpname (const char *file)
+{
+  int result = -1;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  /* Close the old file.  */
+  (*__libc_utmp_jump_table->endutent) ();
+
+  /* Store new names.  */
+  if ((*__libc_utmp_file_functions.utmpname) (file) == 0
+      && !(*__libc_utmp_db_functions.utmpname) (file) == 0)
+    {
+      /* Try to find out whether we are supposed to work with a db
+	 file or not.  Do this by looking for the extension ".db".  */
+      const char *ext = strrchr (file, '.');
+
+      if (ext != NULL && strcmp (ext, ".db") == 0)
+	__libc_utmp_jump_table = &__libc_utmp_db_functions;
+      else
+	__libc_utmp_jump_table = &unknown_functions;
+
+      result = 0;
+    }
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return result;
+}
+weak_alias (__utmpname, utmpname)
diff --git a/login/getutid.c b/login/getutid.c
index 64ced6aeea..d3d3b5d068 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -1,27 +1,27 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <utmp.h>
 
 
-/* The global data defined in setutent.c.  */
-extern struct utmp_data __utmp_data;
+/* Local buffer to store the result.  */
+static struct utmp buffer;
 
 
 struct utmp *
@@ -29,8 +29,8 @@ getutid (const struct utmp *id)
 {
   struct utmp *result;
 
-  if (__getutid_r (id, &result, &__utmp_data) < 0)
+  if (__getutid_r (id, &buffer, &result) < 0)
     return NULL;
 
-  return (struct utmp *) result;
+  return result;
 }
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 81070157a4..52b83cd862 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -1,35 +1,45 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>
+   and Paul Janzen <pcj@primenet.com>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#include <libc-lock.h>
 #include <string.h>
 #include <unistd.h>
 #include <utmp.h>
 
+#include "utmp-private.h"
+
+
+/* We have to use the lock in getutent_r.c.  */
+__libc_lock_define (extern, __libc_utmp_lock)
+
+/* The jump table is also in getutent_r.c.  */
+extern struct utfuncs *__libc_utmp_jump_table;
+
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
 int
-__getutid_r (const struct utmp *id, struct utmp **utmp,
-	     struct utmp_data *utmp_data)
+__getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 {
 #if (_HAVE_UT_ID - 0) && (_HAVE_UT_TYPE - 0)
+  int retval = -1;
+
   /* Test whether ID has any of the legal types.  */
   if (id->ut_type != RUN_LVL && id->ut_type != BOOT_TIME
       && id->ut_type != OLD_TIME && id->ut_type != NEW_TIME
@@ -38,77 +48,21 @@ __getutid_r (const struct utmp *id, struct utmp **utmp,
     /* No, using '<' and '>' for the test is not possible.  */
     {
       __set_errno (EINVAL);
+      *result = NULL;
       return -1;
     }
 
-  /* Open utmp file if not already done.  */
-  if (utmp_data->ut_fd == -1)
-    {
-      setutent_r (utmp_data);
-      if (utmp_data->ut_fd == -1)
-	return -1;
-    }
-
-  /* Position file correctly.  */
-  if (lseek (utmp_data->ut_fd, utmp_data->loc_utmp, SEEK_SET) == -1)
-    return -1;
-
-  if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
-      || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
-    {
-      /* Search for next entry with type RUN_LVL, BOOT_TIME,
-	 OLD_TIME, or NEW_TIME.  */
-
-      while (1)
-	{
-	  /* Read the next entry.  */
-	  if (read (utmp_data->ut_fd, &utmp_data->ubuf, sizeof (struct utmp))
-	      != sizeof (struct utmp))
-	    {
-	      utmp_data->loc_utmp = 0; /* Mark loc_utmp invalid. */
-	      __set_errno (ESRCH);
-	      return -1;
-	    }
-
-	  /* Update position pointer.  */
-	  utmp_data->loc_utmp += sizeof (struct utmp);
+  __libc_lock_lock (__libc_utmp_lock);
 
-	  if (id->ut_type == utmp_data->ubuf.ut_type)
-	    break;
-	}
-    }
+  /* Not yet initialized.  */
+  if ((*__libc_utmp_jump_table->setutent) (0))
+    retval = (*__libc_utmp_jump_table->getutid_r) (id, buffer, result);
   else
-    {
-      /* Search for the next entry with the specified ID and with type
-	 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS.  */
-
-      while (1)
-	{
-	  /* Read the next entry.  */
-	  if (read (utmp_data->ut_fd, &utmp_data->ubuf, sizeof (struct utmp))
-	      != sizeof (struct utmp))
-	    {
-	      utmp_data->loc_utmp = 0; /* Mark loc_utmp invalid. */
-	      __set_errno (ESRCH);
-	      return -1;
-	    }
-
-	  /* Update position pointer.  */
-	  utmp_data->loc_utmp += sizeof (struct utmp);
-
-	  if ((   utmp_data->ubuf.ut_type == INIT_PROCESS
-	       || utmp_data->ubuf.ut_type == LOGIN_PROCESS
-	       || utmp_data->ubuf.ut_type == USER_PROCESS
-	       || utmp_data->ubuf.ut_type == DEAD_PROCESS)
-	      && (strncmp (utmp_data->ubuf.ut_id, id->ut_id, sizeof id->ut_id)
-		  == 0))
-	    break;
-	}
-    }
+    *result = NULL;
 
-  *utmp = &utmp_data->ubuf;
+  __libc_lock_unlock (__libc_utmp_lock);
 
-  return 0;
+  return retval;
 #else	/* !_HAVE_UT_ID && !_HAVE_UT_TYPE */
   __set_errno (ENOSYS);
   return -1;
diff --git a/login/getutline.c b/login/getutline.c
index c21f81745b..16a02f6e89 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -1,27 +1,27 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <utmp.h>
 
 
-/* The global data defined in setutent.c.  */
-extern struct utmp_data __utmp_data;
+/* Local buffer to store the result.  */
+static struct utmp buffer;
 
 
 struct utmp *
@@ -29,8 +29,8 @@ getutline (const struct utmp *line)
 {
   struct utmp *result;
 
-  if (__getutline_r (line, &result, &__utmp_data) < 0)
+  if (__getutline_r (line, &buffer, &result) < 0)
     return NULL;
 
-  return (struct utmp *) result;
+  return result;
 }
diff --git a/login/getutline_r.c b/login/getutline_r.c
index e88267decb..2285248ece 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -1,74 +1,55 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>
+   and Paul Janzen <pcj@primenet.com>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#include <libc-lock.h>
 #include <string.h>
 #include <unistd.h>
 #include <utmp.h>
 
+#include "utmp-private.h"
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__getutline_r (const struct utmp *line, struct utmp **utmp,
-	       struct utmp_data *utmp_data)
-{
-  /* Open utmp file if not already done.  */
-  if (utmp_data->ut_fd == -1)
-    {
-      __setutent_r (utmp_data);
-      if (utmp_data->ut_fd == -1)
-	return -1;
-    }
 
-  /* Position file correctly.  */
-  if (lseek (utmp_data->ut_fd, utmp_data->loc_utmp, SEEK_SET) == -1)
-    return -1;
+/* We have to use the lock in getutent_r.c.  */
+__libc_lock_define (extern, __libc_utmp_lock)
+
+/* The jump table is also in getutent_r.c.  */
+extern struct utfuncs *__libc_utmp_jump_table;
 
-  while (1)
-    {
-      /* Read the next entry.  */
-      if (read (utmp_data->ut_fd, &utmp_data->ubuf, sizeof (struct utmp))
-	  != sizeof (struct utmp))
-	{
-	  utmp_data->loc_utmp = 0; /* Mark UTMP_DATA->ubuf invalid.  */
-	  __set_errno (ESRCH);
-	  return -1;
-	}
 
-      /* Update position pointer.  */
-      utmp_data->loc_utmp += sizeof (struct utmp);
+int
+__getutline_r (const struct utmp *line, struct utmp *buffer,
+	       struct utmp **result)
+{
+  int retval = -1;
+
+  __libc_lock_lock (__libc_utmp_lock);
 
-      if (
-#if _HAVE_UT_TYPE - 0
-	  (utmp_data->ubuf.ut_type == USER_PROCESS
-	   || utmp_data->ubuf.ut_type == LOGIN_PROCESS)
-	  &&
-#endif
-	  ! strncmp (line->ut_line, utmp_data->ubuf.ut_line,
-		     sizeof line->ut_line))
-	/* Stop if we found a user or login entry.  */
-	break;
-    }
+  /* Not yet initialized.  */
+  if ((*__libc_utmp_jump_table->setutent) (0))
+    retval = (*__libc_utmp_jump_table->getutline_r) (line, buffer, result);
+  else
+    *result = NULL;
 
-  *utmp = &utmp_data->ubuf;
+  __libc_lock_unlock (__libc_utmp_lock);
 
-  return 0;
+  return retval;
 }
 weak_alias (__getutline_r, getutline_r)
diff --git a/login/login.c b/login/login.c
index 00b176a104..7cbe8b603e 100644
--- a/login/login.c
+++ b/login/login.c
@@ -1,21 +1,21 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
 #include <limits.h>
@@ -43,8 +43,8 @@ tty_name (int fd, char **tty, size_t buf_len)
 	  rv = ttyname_r (fd, buf, buf_len);
 
 	  if (rv < 0 || memchr (buf, '\0', buf_len))
-	    /* We either got an error, or we succeeded and the returned name fit
-	       in the buffer.  */
+	    /* We either got an error, or we succeeded and the
+	       returned name fit in the buffer.  */
 	    break;
 
 	  /* Try again with a longer buffer.  */
@@ -68,9 +68,9 @@ tty_name (int fd, char **tty, size_t buf_len)
     }
 
   if (rv == 0)
-    *tty = buf;			/* Return buffer to the user.  */
+    *tty = buf;		/* Return buffer to the user.  */
   else if (buf != *tty)
-    free (buf);			/* Free what we malloced when returning an error.  */
+    free (buf);		/* Free what we malloced when returning an error.  */
 
   return rv;
 }
@@ -86,8 +86,8 @@ login (const struct utmp *ut)
   char *tty = _tty;
   int found_tty;
   const char *ttyp;
-  struct utmp_data data = { -1 };
   struct utmp copy = *ut;
+  struct utmp utbuf;
 
   /* Fill in those fields we supply.  */
 #if _HAVE_UT_TYPE - 0
@@ -118,26 +118,16 @@ login (const struct utmp *ut)
 	  struct utmp *old;
 
 	  /* Open UTMP file.  */
-	  setutent_r (&data);
+	  setutent ();
 
 	  /* Read the record.  */
-	  if (getutline_r (&copy, &old, &data) >= 0)
-	    {
-#if _HAVE_UT_TYPE - 0
-	      /* We have to fake the old entry because this `login'
-		 function does not fit well into the UTMP file
-		 handling scheme.  */
-	      old->ut_type = copy.ut_type;
-#endif
-	      pututline_r (&copy, &data);
-	    }
-	  else if (errno == ESRCH)
-	    /* We didn't find anything.  pututline_r will add UT at the end
-	       of the file in this case.  */
-	    pututline_r (&copy, &data);
+	  getutline_r (&copy, &utbuf, &old);
+
+	  /* Write the entry.  */
+	  pututline (&copy);
 
 	  /* Close UTMP file.  */
-	  endutent_r (&data);
+	  endutent ();
 	}
 
       if (tty != _tty)
@@ -147,23 +137,18 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   if (utmpname (_PATH_WTMP) != 0)
     {
+      struct utmp *up;
+
       /* Open the WTMP file.  */
-      setutent_r (&data);
+      setutent ();
 
       /* Position at end of file.  */
-      data.loc_utmp = lseek (data.ut_fd, 0, SEEK_END);
-      if (data.loc_utmp != -1)
-	{
-#if _HAVE_UT_TYPE - 0
-	  /* We have to fake the old entry because this `login'
-	     function does not fit well into the UTMP file handling
-	     scheme.  */
-	  data.ubuf.ut_type = copy.ut_type;
-#endif
-	  pututline_r (&copy, &data);
-	}
+      while (! getutent_r (&utbuf, &up));
+
+      /* Write the new entry.  */
+      pututline (&copy);
 
       /* Close WTMP file.  */
-      endutent_r (&data);
+      endutent ();
     }
 }
diff --git a/login/logout.c b/login/logout.c
index 8575512e0e..3e625486f6 100644
--- a/login/logout.c
+++ b/login/logout.c
@@ -25,8 +25,7 @@ Boston, MA 02111-1307, USA.  */
 int
 logout (const char *line)
 {
-  struct utmp_data data = { ut_fd: -1 };
-  struct utmp tmp;
+  struct utmp tmp, utbuf;
   struct utmp *ut;
   int result = 0;
 
@@ -35,7 +34,7 @@ logout (const char *line)
     return 0;
 
   /* Open UTMP file.  */
-  setutent_r (&data);
+  setutent ();
 
   /* Fill in search information.  */
 #if _HAVE_UT_TYPE - 0
@@ -44,7 +43,7 @@ logout (const char *line)
   strncpy (tmp.ut_line, line, sizeof tmp.ut_line);
 
   /* Read the record.  */
-  if (getutline_r (&tmp, &ut, &data) >= 0)
+  if (getutline_r (&tmp, &utbuf, &ut) >= 0)
     {
       /* Clear information about who & from where.  */
       bzero (ut->ut_name, sizeof ut->ut_name);
@@ -57,12 +56,12 @@ logout (const char *line)
       time (&ut->ut_time);
 #endif
 
-      if (pututline_r (ut, &data) >= 0)
+      if (pututline (ut) >= 0)
 	result = 1;
     }
 
   /* Close UTMP file.  */
-  endutent_r (&data);
+  endutent ();
 
   return result;
 }
diff --git a/login/logwtmp.c b/login/logwtmp.c
index 17c900181f..0d5e48e51f 100644
--- a/login/logwtmp.c
+++ b/login/logwtmp.c
@@ -1,21 +1,21 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
 #include <string.h>
diff --git a/login/utmp-private.h b/login/utmp-private.h
new file mode 100644
index 0000000000..4825ae3f6d
--- /dev/null
+++ b/login/utmp-private.h
@@ -0,0 +1,41 @@
+/* Internal definitions and declarations for UTMP functions.
+   Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>
+   and Paul Janzen <pcj@primenet.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _UTMP_PRIVATE_H
+#define _UTMP_PRIVATE_H	1
+
+#include <utmp.h>
+
+/* The extra `int' argument for each function shows whether locking is
+   wanted or not.  */
+struct utfuncs
+{
+  int (*setutent) (int);
+  int (*getutent_r) (struct utmp *, struct utmp **);
+  int (*getutid_r) (const struct utmp *, struct utmp *, struct utmp **);
+  int (*getutline_r) (const struct utmp *, struct utmp *, struct utmp **);
+  struct utmp *(*pututline) (const struct utmp *);
+  void (*endutent) (void);
+  int (*utmpname) (const char *);
+
+};
+
+#endif /* utmp-private.h */
diff --git a/login/utmp.h b/login/utmp.h
index 6786190aad..87f822d9c3 100644
--- a/login/utmp.h
+++ b/login/utmp.h
@@ -58,9 +58,11 @@ extern int utmpname __P ((__const char *__file));
 extern struct utmp *getutent __P ((void));
 
 /* Rest the input stream to the beginning of the file.  */
+extern void __setutent __P ((void));
 extern void setutent __P ((void));
 
 /* Close the current open file.  */
+extern void __endutent __P ((void));
 extern void endutent __P ((void));
 
 /* Search forward from the current point in the utmp file until the
@@ -76,42 +78,19 @@ extern struct utmp *pututline __P ((__const struct utmp *__utmp_ptr));
 
 
 #ifdef	__USE_REENTRANT
-/* Define the data structure needed for the reentrant version.  */
-struct utmp_data
-{
-  int ut_fd;
-  off_t loc_utmp;
-  struct utmp ubuf;
-};
-
-
 /* Reentrant versions of the file for handling utmp files.  */
-extern int __getutent_r __P ((struct utmp **__utmp,
-			      struct utmp_data *__utmp_data));
-extern int getutent_r __P ((struct utmp **__utmp,
-			    struct utmp_data *__utmp_data));
-
-extern void __setutent_r __P ((struct utmp_data *__utmp_data));
-extern void setutent_r __P ((struct utmp_data *__utmp_data));
-
-extern void __endutent_r __P ((struct utmp_data *__utmp_data));
-extern void endutent_r __P ((struct utmp_data *__utmp_data));
+extern int __getutent_r __P ((struct utmp *__buffer, struct utmp **__result));
+extern int getutent_r __P ((struct utmp *__buffer, struct utmp **__result));
 
-extern int __getutid_r __P ((__const struct utmp *__id, struct utmp **__utmp,
-			     struct utmp_data *__utmp_data));
-extern int getutid_r __P ((__const struct utmp *__id, struct utmp **__utmp,
-			   struct utmp_data *__utmp_data));
+extern int __getutid_r __P ((__const struct utmp *__id, struct utmp *__buffer,
+			     struct utmp **__result));
+extern int getutid_r __P ((__const struct utmp *__id, struct utmp *__buffer,
+			   struct utmp **__result));
 
 extern int __getutline_r __P ((__const struct utmp *__line,
-			       struct utmp **__utmp,
-			       struct utmp_data *__utmp_data));
-extern int getutline_r __P ((__const struct utmp *__line, struct utmp **__utmp,
-			     struct utmp_data *__utmp_data));
-
-extern int __pututline_r __P ((__const struct utmp *__utmp_ptr,
-			       struct utmp_data *__utmp_data));
-extern int pututline_r __P ((__const struct utmp *__utmp_ptr,
-			     struct utmp_data *__utmp_data));
+			       struct utmp *__buffer, struct utmp **__result));
+extern int getutline_r __P ((__const struct utmp *__line,
+			     struct utmp *__buffer, struct utmp **__result));
 
 #endif	/* Use reentrant.  */
 
diff --git a/login/utmp_db.c b/login/utmp_db.c
new file mode 100644
index 0000000000..2c5baf6592
--- /dev/null
+++ b/login/utmp_db.c
@@ -0,0 +1,102 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>
+   and Paul Janzen <pcj@primenet.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <assert.h>
+#include <db.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+#include <sys/stat.h>
+
+#include "utmp-private.h"
+
+
+/* This is the default name.  */
+static const char default_file_name[] = _PATH_UTMP_DB;
+
+/* Current file name.  */
+static const char *file_name = (const char *) default_file_name;
+
+/* Descriptor for database.  */
+static DB *db_fd;
+static char last_date[16];
+
+
+/* Our local functions.  */
+static int setutent_db (int reset);
+static void endutent_db (void);
+static int utmpname_db (const char *name);
+
+
+/* The jump table for the local functions.  */
+struct utfuncs __libc_utmp_db_functions =
+{
+  setutent_db,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  endutent_db,
+  utmpname_db
+};
+
+
+static int
+setutent_db (int reset)
+{
+  return 0;
+}
+
+
+static void
+endutent_db (void)
+{
+}
+
+
+static int
+utmpname_db (const char *name)
+{
+  if (strcmp (name, file_name) != 0)
+    {
+      if (strcmp (name, default_file_name) == 0)
+	{
+	  if (file_name != default_file_name)
+	    free ((char *) file_name);
+
+	  file_name = default_file_name;
+	}
+      else
+	{
+	  char *new_name = __strdup (name);
+	  if (new_name == NULL)
+	    /* Out of memory.  */
+	    return -1;
+
+	  if (file_name != default_file_name)
+	    free ((char *) file_name);
+
+	  file_name = new_name;
+	}
+    }
+  return 0;
+}
diff --git a/login/utmp_file.c b/login/utmp_file.c
new file mode 100644
index 0000000000..fff487a0a3
--- /dev/null
+++ b/login/utmp_file.c
@@ -0,0 +1,385 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>
+   and Paul Janzen <pcj@primenet.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include "utmp-private.h"
+
+
+/* This is the default name.  */
+static const char default_file_name[] = _PATH_UTMP;
+
+/* Current file name.  */
+static const char *file_name = (const char *) default_file_name;
+
+/* Descriptor for the file and position.  */
+static int file_fd = INT_MIN;
+static off_t file_offset;
+
+static struct utmp last_entry;
+
+/* Functions defined here.  */
+static int setutent_file (int reset);
+static int getutent_r_file (struct utmp *buffer, struct utmp **result);
+static int getutid_r_file (const struct utmp *key, struct utmp *buffer,
+			   struct utmp **result);
+static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
+			     struct utmp **result);
+static struct utmp *pututline_file (const struct utmp *data);
+static void endutent_file (void);
+static int utmpname_file (const char *name);
+
+
+/* Jump table for file functions.  */
+struct utfuncs __libc_utmp_file_functions =
+{
+  setutent_file,
+  getutent_r_file,
+  getutid_r_file,
+  getutline_r_file,
+  pututline_file,
+  endutent_file,
+  utmpname_file
+};
+
+
+static int
+setutent_file (int reset)
+{
+  if (file_fd == INT_MIN)
+    {
+      file_fd = open (file_name, O_RDWR);
+      if (file_fd == -1)
+	{
+	  /* Hhm, read-write access did not work.  Try read-only.  */
+	  file_fd = open (file_name, O_RDONLY);
+	  if (file_fd == -1)
+	    {
+	      perror (_("while opening UTMP file"));
+	      return 0;
+	    }
+	}
+      file_offset = 0;
+
+      /* Make sure the entry won't match.  */
+      last_entry.ut_type = -1;
+    }
+  else if (reset)
+    {
+      /* Remember we are at beginning of file.  */
+      file_offset = 0;
+
+      /* Make sure the entry won't match.  */
+      last_entry.ut_type = -1;
+    }
+
+  return 1;
+}
+
+
+static void
+endutent_file (void)
+{
+  if (file_fd >= 0)
+    close (file_fd);
+
+  file_fd = INT_MIN;
+}
+
+
+static int
+getutent_r_file (struct utmp *buffer, struct utmp **result)
+{
+  int nbytes;
+
+  /* Open utmp file if not already done.  */
+  if (file_fd == INT_MIN)
+    setutent_file (1);
+
+  if (file_fd == -1 || file_offset == -1l)
+    {
+      /* Not available.  */
+      *result = NULL;
+      return -1;
+    }
+
+  /* Read the next entry.  */
+  flock (file_fd, LOCK_SH);
+  nbytes = read (file_fd, &last_entry, sizeof (struct utmp));
+  flock (file_fd, LOCK_UN);
+
+  if (nbytes!= sizeof (struct utmp))
+    {
+      file_offset = -1l;
+      *result = NULL;
+      return -1;
+    }
+
+  /* Update position pointer.  */
+  file_offset += sizeof (struct utmp);
+
+  memcpy (buffer, &last_entry, sizeof (struct utmp));
+  *result = buffer;
+
+  return 0;
+}
+
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+static int
+getutline_r_file (const struct utmp *line, struct utmp *buffer,
+		  struct utmp **result)
+{
+  if (file_fd < 0 || file_offset == -1l)
+    {
+      *result = NULL;
+      return -1;
+    }
+
+  while (1)
+    {
+      /* Read the next entry.  */
+      if (read (file_fd, &last_entry, sizeof (struct utmp))
+	  != sizeof (struct utmp))
+	{
+	  __set_errno (ESRCH);
+	  file_offset = -1l;
+	  *result = NULL;
+	  return -1;
+	}
+
+      /* Stop if we found a user or login entry.  */
+      if (
+#if _HAVE_UT_TYPE - 0
+	  (last_entry.ut_type == USER_PROCESS
+	   || last_entry.ut_type == LOGIN_PROCESS)
+	  &&
+#endif
+	  !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
+	break;
+
+      file_offset += sizeof (struct utmp);
+    }
+
+  memcpy (buffer, &last_entry, sizeof (struct utmp));
+  *result = buffer;
+
+  return 0;
+}
+
+
+static int
+internal_getutid_r (const struct utmp *id, struct utmp *buffer)
+{
+  if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
+      || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
+    {
+      /* Search for next entry with type RUN_LVL, BOOT_TIME,
+	 OLD_TIME, or NEW_TIME.  */
+
+      while (1)
+	{
+	  /* Read the next entry.  */
+	  if (read (file_fd, buffer, sizeof (struct utmp))
+	      != sizeof (struct utmp))
+	    {
+	      __set_errno (ESRCH);
+	      file_offset = -1l;
+	      return -1;
+	    }
+
+	  if (id->ut_type == buffer->ut_type)
+	    break;
+
+	  file_offset += sizeof (struct utmp);
+	}
+    }
+  else
+    {
+      /* Search for the next entry with the specified ID and with type
+	 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS.  */
+
+      while (1)
+	{
+	  /* Read the next entry.  */
+	  if (read (file_fd, buffer, sizeof (struct utmp))
+	      != sizeof (struct utmp))
+	    {
+	      __set_errno (ESRCH);
+	      file_offset = -1l;
+	      return -1;
+	    }
+	  if ((   buffer->ut_type == INIT_PROCESS
+	       || buffer->ut_type == LOGIN_PROCESS
+	       || buffer->ut_type == USER_PROCESS
+	       || buffer->ut_type == DEAD_PROCESS)
+	      && strncmp (buffer->ut_id, id->ut_id, sizeof id->ut_id) == 0)
+	    break;
+
+	  file_offset += sizeof (struct utmp);
+	}
+    }
+
+  return 0;
+}
+
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+static int
+getutid_r_file (const struct utmp *id, struct utmp *buffer,
+		struct utmp **result)
+{
+  if (file_fd < 0 || file_offset == -1l)
+    {
+      *result = NULL;
+      return -1;
+    }
+
+  if (internal_getutid_r (id, &last_entry) < 0)
+    {
+      *result = NULL;
+      return -1;
+    }
+
+  memcpy (buffer, &last_entry, sizeof (struct utmp));
+  *result = buffer;
+
+  return 0;
+}
+
+
+static struct utmp *
+pututline_file (const struct utmp *data)
+{
+  struct utmp buffer;
+  struct utmp *pbuf;
+  int found;
+
+  if (file_fd < 0)
+    /* Something went wrong.  */
+    return NULL;
+
+  /* Find the correct place to insert the data.  */
+  if (file_offset > 0)
+    found = 0;
+  else
+    if (   last_entry.ut_type == RUN_LVL
+	|| last_entry.ut_type == BOOT_TIME
+	|| last_entry.ut_type == OLD_TIME
+	|| last_entry.ut_type == NEW_TIME
+	|| ((   last_entry.ut_type == INIT_PROCESS
+	     || last_entry.ut_type == LOGIN_PROCESS
+	     || last_entry.ut_type == USER_PROCESS
+	     || last_entry.ut_type == DEAD_PROCESS)
+	    && !strncmp (last_entry.ut_id, data->ut_id, sizeof data->ut_id)))
+      found = 1;
+    else
+      found = internal_getutid_r (data, &buffer);
+
+  /* Try to lock the file.  */
+  if (flock (file_fd, LOCK_EX | LOCK_NB) < 0 && errno != ENOSYS)
+    {
+      /* Oh, oh.  The file is already locked.  Wait a bit and try again.  */
+      sleep (1);
+
+      /* This time we ignore the error.  */
+      (void) flock (file_fd, LOCK_EX | LOCK_NB);
+    }
+
+  if (found < 0)
+    {
+      /* We append the next entry.  */
+      file_offset = lseek (file_fd, 0, SEEK_END);
+      if (file_offset % sizeof (struct utmp) != 0)
+	{
+	  file_offset -= file_offset % sizeof (struct utmp);
+	  ftruncate (file_fd, file_offset);
+
+	  if (lseek (file_fd, 0, SEEK_END) < 0)
+	    {
+	      (void) flock (file_fd, LOCK_UN);
+	      return NULL;
+	    }
+	}
+    }
+  else
+    {
+      /* We replace the just read entry.  */
+      file_offset -= sizeof (struct utmp);
+      lseek (file_fd, file_offset, SEEK_SET);
+    }
+
+  /* Write the new data.  */
+  if (write (file_fd, data, sizeof (struct utmp)) != sizeof (struct utmp)
+      /* If we appended a new record this is only partially written.
+	 Remove it.  */
+      && found < 0)
+    {
+      (void) ftruncate (file_fd, file_offset);
+      pbuf = NULL;
+    }
+  else
+    pbuf = (struct utmp *) data;
+
+   /* And unlock the file.  */
+  (void) flock (file_fd, LOCK_UN);
+
+  return pbuf;
+}
+
+
+static int
+utmpname_file (const char *name)
+{
+  if (strcmp (name, file_name) != 0)
+    {
+      if (strcmp (name, default_file_name) == 0)
+	{
+	  if (file_name != default_file_name)
+	    free ((char *) file_name);
+
+	  file_name = default_file_name;
+	}
+      else
+	{
+	  char *new_name = __strdup (name);
+	  if (new_name == NULL)
+	    /* Out of memory.  */
+	    return -1;
+
+	  if (file_name != default_file_name)
+	    free ((char *) file_name);
+
+	  file_name = new_name;
+	}
+    }
+  return 0;
+}