Move program code in subdir programs to avoid clash of directory name of program...
authordrepper <drepper>
Mon, 2 Jun 1997 02:33:58 +0000 (02:33 +0000)
committerdrepper <drepper>
Mon, 2 Jun 1997 02:33:58 +0000 (02:33 +0000)
21 files changed:
login/Makefile
login/programs/connection.c [new file with mode: 0644]
login/programs/database.c [new file with mode: 0644]
login/programs/error.c [new file with mode: 0644]
login/programs/request.c [new file with mode: 0644]
login/programs/utmpd-private.h [new file with mode: 0644]
login/programs/utmpd.c [new file with mode: 0644]
login/programs/utmpd.h [new file with mode: 0644]
login/programs/utmpdump.c [new file with mode: 0644]
login/programs/xtmp.c [new file with mode: 0644]
login/programs/xtmp.h [new file with mode: 0644]
login/utmpd/connection.c [deleted file]
login/utmpd/database.c [deleted file]
login/utmpd/error.c [deleted file]
login/utmpd/request.c [deleted file]
login/utmpd/utmpd-private.h [deleted file]
login/utmpd/utmpd.c [deleted file]
login/utmpd/utmpd.h [deleted file]
login/utmpd/xtmp.c [deleted file]
login/utmpd/xtmp.h [deleted file]
login/utmpdump.c [deleted file]

index 832b1ca..406b5cc 100644 (file)
@@ -31,9 +31,10 @@ others = utmpd
 install-sbin = utmpd
 utmpd-routines := connection database error request xtmp
 
-distribute := utmp-private.h utmpd/xtmp.h utmpd/utmpd.h utmpd/utmpd-private.h
+distribute := utmp-private.h programs/xtmp.h programs/utmpd.h \
+             programs/utmpd-private.h
 
-vpath %.c utmpd
+vpath %.c programs
 
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
diff --git a/login/programs/connection.c b/login/programs/connection.c
new file mode 100644 (file)
index 0000000..4e16631
--- /dev/null
@@ -0,0 +1,180 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "utmpd-private.h"
+
+
+/* Prototypes for the local functions.  */
+static client_connection *alloc_connection (void);
+static void free_connection (client_connection *connection);
+static int set_nonblock_flag (int desc, int value);
+
+
+/* The head of the connection list.  */
+static client_connection *connection_list = NULL;
+
+
+/* Accept connection on SOCK, with access permissions given by ACCESS.
+   Returns a pointer to a newly allocated client_connection if
+   successful, NULL if not.  */
+client_connection *
+accept_connection (int sock, int access)
+{
+  client_connection *connection;
+
+  connection = alloc_connection ();
+  if (connection == NULL)
+    return NULL;
+
+  connection->sock = accept (sock, NULL, NULL);
+  connection->access = access;
+  if (connection->sock < 0)
+    {
+      free_connection (connection);
+      return NULL;
+    }
+  
+  if (set_nonblock_flag (connection->sock, 1) < 0)
+    {
+      close_connection (connection);
+      return NULL;
+    }
+
+  return connection;  
+}
+
+
+/* Close CONNECTION.  */
+void
+close_connection (client_connection *connection)
+{
+  close (connection->sock);
+  free_connection (connection);
+}
+
+
+/* Return the connection for SOCK.  */
+client_connection *
+find_connection (int sock)
+{
+  client_connection *connection;
+
+  for (connection = connection_list; connection;
+       connection = connection->next)
+    {
+      if (connection->sock == sock)
+       return connection;
+    }
+
+  return NULL;
+}
+
+
+static client_connection *
+alloc_connection (void)
+{
+  client_connection *connection;
+  size_t read_bufsize = 1024;
+  size_t write_bufsize = 1024;
+
+  connection = (client_connection *)malloc (sizeof (client_connection));
+  if (connection == NULL)
+    return NULL;
+
+  memset (connection, 0, sizeof (client_connection));
+
+  /* Allocate read buffer.  */
+  connection->read_base = malloc (read_bufsize);
+  connection->read_ptr = connection->read_base;
+  connection->read_end = connection->read_base + read_bufsize;
+  if (connection->read_base == NULL)
+    {
+      free (connection);
+      return NULL;
+    }
+
+  /* Allocate write buffer.  */
+  connection->write_base = malloc (write_bufsize);
+  connection->write_ptr = connection->write_base;
+  connection->write_end = connection->write_base + write_bufsize;
+  if (connection->write_base == NULL)
+    {
+      free (connection->read_base);
+      free (connection);
+      return NULL;
+    }
+
+  /* Link connection.  */
+  connection->next = connection_list;
+  connection_list = connection;
+  if (connection->next)
+    connection->next->prev = connection;
+  
+  return connection;
+}
+
+
+static void
+free_connection (client_connection *connection)
+{
+  /* Unlink connection.  */
+  if (connection->next)
+    connection->next->prev = connection->prev;
+  if (connection->prev)
+    connection->prev->next = connection->next;
+
+  /* Take care of the head of the list.  */
+  if (connection == connection_list)
+    connection_list = connection->next;
+  
+  /* Free buffers.  */
+  if (connection->read_base)
+    free (connection->read_base);
+  if (connection->write_base)
+    free (connection->write_base);
+
+  free (connection);
+}
+
+
+/* Set the `O_NONBLOCK' flag of DESC if VALUE is nonzero,
+   or clear the flag if VALUE is 0.
+   Return 0 on success, or -1 on error with `errno' set. */
+static int
+set_nonblock_flag (int desc, int value)
+{
+  int oldflags = fcntl (desc, F_GETFL, 0);
+  /* If reading the flags failed, return error indication now. */
+  if (oldflags == -1)
+    return -1;
+  /* Set just the flag we want to set. */
+  if (value != 0)
+    oldflags |= O_NONBLOCK;
+  else
+    oldflags &= ~O_NONBLOCK;
+  /* Store modified flag word in the descriptor. */
+  return fcntl (desc, F_SETFL, oldflags);
+}
diff --git a/login/programs/database.c b/login/programs/database.c
new file mode 100644 (file)
index 0000000..e31e0d9
--- /dev/null
@@ -0,0 +1,516 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmp.h>
+
+
+#include "utmpd-private.h"
+#include "xtmp.h"
+
+
+/* Prototypes for the local functions.  */
+static int initialize_database (utmp_database *database);
+static int store_state_entry (utmp_database *database, int old_position,
+                             const struct utmp *old_entry);
+static int store_process_entry (utmp_database *database, int old_position,
+                               const struct utmp *old_entry);
+static int replace_entry (utmp_database *database, int old_position,
+                         int new_position, const struct utmp *entry);
+static int store_entry (utmp_database *database, int position,
+                       const struct utmp *entry);
+static int proc_utmp_eq (const struct utmp *entry, const struct utmp *match);
+static int get_mtime (const char *file, time_t *timer);
+
+
+/* Open the database specified by FILE and merge it with the
+   contents of the old format file specified by OLD_FILE.  Returns a
+   pointer to a newly allocated structure describing the database, or
+   NULL on error.  */
+utmp_database *
+open_database (const char *file, const char *old_file)
+{
+  utmp_database *database;
+
+  /* Allocate memory.  */
+  database = (utmp_database *) malloc (sizeof (utmp_database));
+  if (database == NULL)
+    return NULL;
+
+  memset (database, 0, sizeof (utmp_database));
+
+  /* Open database.  */
+  database->fd = open (file, O_RDWR);
+  if (database->fd < 0)
+    goto fail;
+
+  database->old_fd = open (old_file, O_RDWR);
+  if (database->old_fd < 0)
+    goto fail;
+  
+  if ((file && !(database->file = strdup (file)))
+      || (old_file && !(database->old_file = strdup (old_file))))
+    goto fail;
+
+  if (initialize_database (database) < 0
+      || synchronize_database (database) < 0)
+    goto fail;
+  
+  return database;
+
+fail:
+  close_database (database);
+  return NULL;
+}
+
+/* Synchronize DATABASE.  */
+int
+synchronize_database (utmp_database *database)
+{
+  assert (database);
+
+  /* Check if there is a file in the old format, that we have to
+     synchronize with.  */
+  if (database->old_file)
+    {
+      time_t curtime;
+      time_t mtime;
+      
+      curtime = time (NULL);
+      
+      if (get_mtime (database->old_file, &mtime) < 0)
+       return -1;
+      
+      if (mtime >= database->mtime)
+       {
+         int position = 0;
+         struct utmp entry;
+         struct utmp old_entry;
+
+         while (1)
+           {
+             if (read_old_entry (database, position, &old_entry) < 0)
+               break;
+             
+             if (read_entry (database, position, &entry) < 0
+                 || !compare_entry (&old_entry, &entry))
+               {
+                 if (write_entry (database, position, &old_entry) < 0)
+                   return -1;
+               }
+
+             position++;
+           }
+
+         database->mtime = curtime;
+       }
+      
+    }
+
+  return 0;
+}
+
+
+/* Close DATABASE.  */
+void
+close_database (utmp_database *database)
+{
+  assert (database);
+
+  if (database->fd >= 0)
+    close (database->fd);
+
+  if (database->old_fd >= 0)
+    close (database->old_fd);
+  
+  /* Free allocated memory.  */
+  if (database->file)
+    free (database->file);
+  if (database->old_file)
+    free (database->old_file);
+  free (database);
+}
+
+
+/* Read the entry at POSITION in DATABASE and store the result in
+   ENTRY.  Returns 0 if successful, -1 if not.  */
+int
+read_entry (utmp_database *database, int position, struct utmp *entry)
+{
+  ssize_t nbytes;
+  off_t offset;
+
+  offset = position * sizeof (struct utmp);
+  if (lseek (database->fd, offset, SEEK_SET) < 0)
+    return -1;
+
+  nbytes = read (database->fd, entry, sizeof (struct utmp));
+  if (nbytes != sizeof (struct utmp))
+    return -1;
+  
+  return 0;
+}
+
+
+/* Write ENTRY at POSITION in DATABASE.  Returns 0 if successful, -1
+   on error.  */
+int
+write_entry (utmp_database *database, int position,
+            const struct utmp *entry)
+{
+  int result = -1;
+  struct flock fl;
+  ssize_t nbytes;
+  off_t offset;
+
+  /* Try to lock the file.  */
+  memset (&fl, 0, sizeof (struct flock));
+  fl.l_type = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+  fcntl (database->fd, F_SETLKW, &fl);
+  
+  offset = position * sizeof (struct utmp);
+  if (lseek (database->fd, offset, SEEK_SET) < 0)
+    goto fail;
+
+  nbytes = write (database->fd, entry, sizeof (struct utmp));
+  if (nbytes != sizeof (struct utmp))
+    {
+      ftruncate (database->fd, offset);
+      goto fail;
+    }
+
+  result = 0;
+
+fail:
+  /* And unlock the file.  */
+  fl.l_type = F_UNLCK;
+  fcntl (database->fd, F_SETLKW, &fl);
+
+  return result;
+}
+
+
+/* Append ENTRY to DATABASE.  Returns the position of the appended
+   entry if successful, or -1 on error.  */
+int
+append_entry (utmp_database *database, const struct utmp *entry)
+{
+  int result = -1;
+  struct flock fl;
+  ssize_t nbytes;
+  off_t offset;
+
+  /* Try to lock the file.  */
+  memset (&fl, 0, sizeof (struct flock));
+  fl.l_type = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+  fcntl (database->fd, F_SETLKW, &fl);
+  
+  offset = lseek (database->fd, 0, SEEK_END);
+  if (offset % sizeof (struct utmp) != 0)
+    {
+      offset -= offset % sizeof (struct utmp);
+      ftruncate (database->fd, offset);
+
+      if (lseek (database->fd, 0, SEEK_END) < 0)
+       goto fail;
+    }
+
+  nbytes = write (database->fd, entry, sizeof (struct utmp));
+  if (nbytes != sizeof (struct utmp))
+    {
+      ftruncate (database->fd, offset);
+      goto fail;
+    }
+
+  result = offset / sizeof (struct utmp);
+  
+fail:
+  /* And unlock the file.  */
+  fl.l_type = F_UNLCK;
+  fcntl (database->fd, F_SETLKW, &fl);
+
+  return result;
+}
+
+
+int
+read_old_entry (utmp_database *database, int position,
+               struct utmp *entry)
+{
+  struct xtmp old_entry;
+  ssize_t nbytes;
+  off_t offset;
+
+  offset = position * sizeof (struct xtmp);
+  if (lseek (database->old_fd, offset, SEEK_SET) < 0)
+    return -1;
+
+  nbytes = read (database->old_fd, &old_entry, sizeof (struct xtmp));
+  if (nbytes != sizeof (struct xtmp))
+    return -1;
+  
+  xtmp_to_utmp (&old_entry, entry);
+  return 0;
+}
+
+
+int
+write_old_entry (utmp_database *database, int position,
+                const struct utmp *entry)
+{
+  struct xtmp old_entry;
+  ssize_t nbytes;
+  off_t offset;
+
+  utmp_to_xtmp (entry, &old_entry);
+  
+  offset = position * sizeof (struct xtmp);
+  if (lseek (database->old_fd, offset, SEEK_SET) < 0)
+    return -1;
+
+  nbytes = write (database->old_fd, &old_entry, sizeof (struct xtmp));
+  if (nbytes != sizeof (struct xtmp))
+    return -1;
+
+  return 0;
+}
+
+
+/* Initialize DATABASE.  */
+static int
+initialize_database (utmp_database *database)
+{
+  struct utmp entry;
+  int position = 0;
+  
+  assert (database);
+
+  /* Check if there is a file in the old format to read.  */
+  if (database->old_file)
+    {
+      while (1)
+       {
+         if (read_old_entry (database, position, &entry) < 0)
+           break;
+
+#if _HAVE_UT_TYPE - 0
+         /* If the login type is one of RUN_LVL, BOOT_TIME, OLD_TIME or
+            NEW_TIME, search for an entry of the same type in the
+            database, and replace it if the entry in the file is newer.  */
+         if (entry.ut_type == RUN_LVL || entry.ut_type == BOOT_TIME
+             || entry.ut_type == OLD_TIME || entry.ut_type == NEW_TIME)
+           {
+             if (store_state_entry (database, position, &entry) < 0)
+               return -1;
+           }
+         else
+#endif
+           {
+             if (store_process_entry (database, position, &entry) < 0)
+               return -1;
+           }
+
+         /* Update position.  */
+         position++;
+       }
+
+      while (1)
+       {
+         if (read_entry (database, position, &entry) < 0)
+           break;
+
+         if (write_old_entry (database, position, &entry) < 0)
+           return -1;
+
+         /* Update position.  */
+         position++;
+       }
+    }
+
+  return 0;
+}
+
+
+static int
+store_state_entry (utmp_database *database, int old_position,
+                  const struct utmp *old_entry)
+{
+  struct utmp new_entry;
+  int new_position = 0;
+  int found = 0;
+
+  assert (old_entry->ut_type == RUN_LVL
+         || old_entry->ut_type == BOOT_TIME
+         || old_entry->ut_type == OLD_TIME
+         || old_entry->ut_type == NEW_TIME);
+
+  while (!found)
+    {
+      /* Read the next entry.  */
+      if (read_entry (database, new_position, &new_entry) < 0)
+       break;
+      
+      if (old_entry->ut_type == new_entry.ut_type)
+       {
+         found = 1;
+         continue;
+       }
+
+      /* Update position.  */
+      new_position++;
+    }
+
+  if (found)
+    {
+      const struct utmp *entry;
+
+      if (old_entry->ut_time > new_entry.ut_time)
+       entry = old_entry;
+      else
+       entry = &new_entry;
+      
+      return replace_entry (database, old_position, new_position, entry);
+    }
+
+  return store_entry (database, old_position, old_entry);
+}
+
+
+static int
+store_process_entry (utmp_database *database, int old_position,
+                    const struct utmp *old_entry)
+{
+  struct utmp new_entry;
+  int new_position = 0;
+  int found = 0;
+
+  while (!found)
+    {
+      /* Read the next entry.  */
+      if (read_entry (database, new_position, &new_entry) < 0)
+       break;
+
+      if (proc_utmp_eq (old_entry, &new_entry))
+       {
+         found = 1;
+         continue;
+       }
+
+      /* Update position.  */
+      new_position++;
+    }
+
+  if (found)
+    {
+      const struct utmp *entry;
+
+      if (old_entry->ut_time > new_entry.ut_time)
+       entry = old_entry;
+      else
+       entry = &new_entry;
+      
+      return replace_entry (database, old_position, new_position, entry);
+    }
+
+  return store_entry (database, old_position, old_entry);
+}
+
+
+static int
+replace_entry (utmp_database *database, int old_position, int new_position,
+              const struct utmp *entry)
+{
+  struct utmp tmp;
+  
+  if (read_entry (database, old_position, &tmp) < 0
+      || write_entry (database, old_position, entry) < 0
+      || write_entry (database, new_position, &tmp) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+static int
+store_entry (utmp_database *database, int position,
+            const struct utmp *entry)
+{
+  struct utmp tmp;
+
+  if (read_entry (database, position, &tmp) < 0)
+    return write_entry (database, position, entry);
+
+  if (write_entry (database, position, entry) < 0
+      || append_entry (database, &tmp) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/* This function is identical to the one in login/utmp_file.c.  */
+static int
+proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
+{
+  return
+    (
+#if _HAVE_UT_TYPE - 0
+     (entry->ut_type == INIT_PROCESS
+      || entry->ut_type == LOGIN_PROCESS
+      || entry->ut_type == USER_PROCESS
+      || entry->ut_type == DEAD_PROCESS)
+     &&
+     (match->ut_type == INIT_PROCESS
+      || match->ut_type == LOGIN_PROCESS
+      || match->ut_type == USER_PROCESS
+      || match->ut_type == DEAD_PROCESS)
+     &&
+#endif
+#if _HAVE_UT_ID - 0
+     strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
+#else
+     strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
+#endif
+     );
+}
+
+
+/* Get modification time of FILE and put it in TIMER.  returns 0 if
+   successful, -1 if not.  */
+static int
+get_mtime (const char *file, time_t *timer)
+{
+  struct stat st;
+  
+  if (stat (file, &st) < 0)
+    return -1;
+
+  *timer = st.st_mtime;
+
+  return 0;
+}
diff --git a/login/programs/error.c b/login/programs/error.c
new file mode 100644 (file)
index 0000000..e651144
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "utmpd-private.h"
+
+
+/* This variable indicates if we have forked.  If set, we log messages
+   via the system logger.  Otherwise we simply print the program name
+   and the message to standard error.  */
+int forked = 0;
+
+
+/* Log error message MESSAGE, which is a printf-style format string
+   with optional args.
+   If ERRNUM is nonzero, also log its corresponding system error message.
+   Exit with status STATUS if it is nonzero.  */
+void
+error (int status, int errnum, const char *message, ...)
+{
+  va_list ap;
+  char *buffer = NULL;
+
+  va_start (ap, message);
+  vasprintf (&buffer, message, ap);
+  va_end (ap);
+
+  if (forked)
+    {
+      if (errnum == 0)
+       syslog (LOG_ERR, "%s", buffer);
+      else
+       syslog (LOG_ERR, "%s: %s", buffer, strerror (errnum));
+    }
+  else
+    {
+      if (errnum == 0)
+       fprintf (stderr, "%s: %s\n", program_invocation_name, buffer);
+      else
+       fprintf (stderr, "%s: %s: %s\n", program_invocation_name, buffer,
+                strerror (errnum));
+    }
+
+  if (buffer)
+    free (buffer);
+
+  if (status)
+    exit (status);
+}
+
+/* Log warning message MESSAGE, which is a printf-style format string
+   with optional args.
+   If ERRNUM is nonzero, also log its corresponding system error message. */
+void
+warning (int errnum, const char *message, ...)
+{
+  va_list ap;
+  char *buffer = NULL;
+
+  va_start (ap, message);
+  vasprintf (&buffer, message, ap);
+  va_end (ap);
+
+  if (forked)
+    {
+      if (errnum == 0)
+       syslog (LOG_WARNING, "%s", buffer);
+      else
+       syslog (LOG_WARNING, "%s: %s", buffer, strerror (errnum));
+    }
+  else
+    {
+      if (errnum == 0)
+       printf ("%s: %s\n", program_invocation_name, buffer);
+      else
+       printf ("%s: %s: %s\n", program_invocation_name, buffer,
+               strerror (errnum));
+    }
+
+  if (buffer)
+    free (buffer);
+}
diff --git a/login/programs/request.c b/login/programs/request.c
new file mode 100644 (file)
index 0000000..0f68b8a
--- /dev/null
@@ -0,0 +1,650 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#include "utmpd.h"
+#include "utmpd-private.h"
+
+
+/* Prototypes for the local functions.  */
+static int process_request (client_connection *connection);
+static int send_reply (client_connection *connect, const reply_header *reply);
+
+static int do_setutent (client_connection *connection);
+static int do_getutent (client_connection *connection);
+static int do_endutent (client_connection *connection);
+static int do_getutline (client_connection *connection);
+static int do_getutid (client_connection *connection);
+static int do_pututline (client_connection *connection);
+static int do_updwtmp (client_connection *connection);
+
+static int proc_utmp_eq (const struct utmp *entry, const struct utmp *match);
+static int internal_getut_r (client_connection *connection,
+                            const struct utmp *id, struct utmp *buffer);
+
+
+/* Read data from the client on CONNECTION.  */
+int
+read_data (client_connection *connection)
+{
+  ssize_t nbytes;
+
+  assert (connection);
+  assert ((connection->read_end - connection->read_ptr) > 0);
+
+  /* Read data.  */
+  nbytes = read (connection->sock, connection->read_ptr,
+                connection->read_end - connection->read_ptr);
+  if (nbytes > 0)
+    {
+      size_t total_bytes;
+
+      /* Update read pointer.  */
+      connection->read_ptr += nbytes;
+
+      /* Check if we have a complete request header.  */
+      total_bytes = connection->read_ptr - connection->read_base;
+      if (total_bytes >= sizeof (request_header))
+       {
+         request_header *header;
+
+         /* Check if we have a complete request.  */
+         header = (request_header *)connection->read_base;
+         if (total_bytes >= header->size)
+           {
+             /* Process the request.  */
+             if (process_request (connection) < 0)
+               return -1;
+
+             /* Adjust read pointer, and flush buffer.  */
+             connection->read_ptr -= header->size;
+             memmove (connection->read_base,
+                      connection->read_base + header->size,
+                      connection->read_ptr - connection->read_base);
+           }
+       }
+
+      return 0;
+    }
+
+  if (nbytes < 0)
+    error (0, errno, "cannot read from client");
+
+  return -1;
+}
+
+
+/* Write data to the client on CONNECTION.  */
+int
+write_data (client_connection *connection)
+{
+  ssize_t nbytes;
+
+  assert (connection);
+  assert ((connection->write_ptr - connection->write_base) > 0);
+
+  /* Write data.  */
+  nbytes = write (connection->sock, connection->write_base,
+                 connection->write_ptr - connection->write_base);
+  if (nbytes > 0)
+    {
+      /* Adjust write pointer and flush buffer.  */
+      connection->write_ptr -= nbytes;
+      memmove (connection->write_base, connection->write_base + nbytes,
+              connection->write_ptr - connection->write_base);
+
+      return 0;
+    }
+
+  if (nbytes < 0)
+    error (0, errno, "cannot write to client");
+
+  return -1;
+}
+
+
+/* Process the request received on CONNECTION.  Returns 0 if
+   successful, -1 if not.  */
+static int
+process_request (client_connection *connection)
+{
+  request_header *header;
+
+  assert (connection);
+  assert (connection->read_base);
+
+  header = (request_header *)connection->read_base;
+  if (header->version != UTMPD_VERSION)
+    {
+      warning (EINVAL, "invalid protocol version");
+      return -1;
+    }
+
+  switch (header->type)
+    {
+    case UTMPD_REQ_SETUTENT:   return do_setutent (connection);
+    case UTMPD_REQ_GETUTENT:   return do_getutent (connection);
+    case UTMPD_REQ_ENDUTENT:   return do_endutent (connection);
+    case UTMPD_REQ_GETUTLINE:  return do_getutline (connection);
+    case UTMPD_REQ_GETUTID:    return do_getutid (connection);
+    case UTMPD_REQ_PUTUTLINE:  return do_pututline (connection);
+    case UTMPD_REQ_UPDWTMP:    return do_updwtmp (connection);
+    default:
+      warning (EINVAL, "invalid request type");
+      return -1;
+    }
+}
+
+
+/* Send the reply specified by HEADER to the client on CONNECTION.
+   Returns 0 if successful, -1 if not.  */
+static int
+send_reply (client_connection *connection, const reply_header *reply)
+{
+  /* Check if the reply fits in the buffer.  */
+  if ((size_t) (connection->write_end - connection->write_ptr) < reply->size)
+    {
+      error (0, 0, "buffer overflow");
+      return -1;
+    }
+
+  /* Copy reply to buffer, and adjust write pointer.  */
+  memcpy (connection->write_ptr, reply, reply->size);
+  connection->write_ptr += reply->size;
+
+  return 0;
+}
+
+
+static int
+do_setutent (client_connection *connection)
+{
+  setutent_request *request;
+  setutent_reply reply;
+
+  request = (setutent_request *)connection->read_base;
+  if (request->header.size != sizeof (setutent_request))
+    {
+      warning (EINVAL, "invalid request size");
+      return -1;
+    }
+
+  /* Initialize reply.  */
+  reply.header.version = UTMPD_VERSION;
+  reply.header.size = sizeof (setutent_reply);
+  reply.header.type = UTMPD_REQ_SETUTENT;
+
+  /* Select database.  */
+  if (!strncmp (request->file, _PATH_UTMP, sizeof request->file))
+    connection->database = utmp_db;
+  else
+    {
+      errno = EINVAL;
+      goto return_error;
+    }
+
+  /* Initialize position pointer.  */
+  connection->position = 0;
+
+#if _HAVE_UT_TYPE - 0
+  /* Make sure the entry won't match.  */
+  connection->last_entry.ut_type = -1;
+#endif
+
+  reply.errnum = 0;
+  reply.result = 0;
+  return send_reply (connection, &reply.header);
+
+return_error:
+  reply.errnum = errno;
+  reply.result = -1;
+  return send_reply (connection, &reply.header);
+}
+
+
+static int
+do_getutent (client_connection *connection)
+{
+  getutent_request *request;
+  getutent_reply reply;
+
+  request = (getutent_request *)connection->read_base;
+  if (request->header.size != sizeof (getutent_request))
+    {
+      warning (EINVAL, "invalid request size");
+      return -1;
+    }
+
+  /* Initialize reply.  */
+  reply.header.version = UTMPD_VERSION;
+  reply.header.size = sizeof (getutent_reply);
+  reply.header.type = UTMPD_REQ_GETUTENT;
+
+  if (connection->database == NULL || connection->position == -1)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  /* Make sure we're in synch with the ordinary file.  */
+  if (synchronize_database (connection->database) < 0)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  /* Read the next entry from the database.  */
+  if (read_entry (connection->database, connection->position,
+                 &connection->last_entry) < 0)
+    {
+      connection->position = -1;
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  /* Update position pointer.  */
+  connection->position++;
+
+  memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
+  reply.errnum = 0;
+  reply.result = 0;
+  return send_reply (connection, (reply_header *)&reply);
+
+return_error:
+  memset (&reply.entry, 0, sizeof (struct utmp));
+  reply.errnum = errno;
+  reply.result = -1;
+  return send_reply (connection, &reply.header);
+}
+
+
+static int
+do_endutent (client_connection *connection)
+{
+  endutent_request *request;
+  endutent_reply reply;
+
+  request = (endutent_request *)connection->read_base;
+  if (request->header.size != sizeof (endutent_request))
+    {
+      warning (EINVAL, "invalid request size");
+      return -1;
+    }
+
+  /* Deselect database.  */
+  connection->database = NULL;
+
+  /* Formulate reply.  */
+  reply.header.version = UTMPD_VERSION;
+  reply.header.size = sizeof (endutent_reply);
+  reply.header.type = UTMPD_REQ_ENDUTENT;
+  reply.errnum = 0;
+  reply.result = 0;
+
+  return send_reply (connection, &reply.header);
+}
+
+
+static int
+do_getutline (client_connection *connection)
+{
+  getutline_request *request;
+  getutline_reply reply;
+
+  request = (getutline_request *)connection->read_base;
+  if (request->header.size != sizeof (getutline_request))
+    {
+      warning (EINVAL, "invalid request size");
+      return -1;
+    }
+
+  /* Initialize reply.  */
+  reply.header.version = UTMPD_VERSION;
+  reply.header.size = sizeof (getutline_reply);
+  reply.header.type = UTMPD_REQ_GETUTLINE;
+
+  if (connection->database == NULL || connection->position == -1)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  /* Make sure we're in synch with the ordinary file.  */
+  if (synchronize_database (connection->database) < 0)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  while (1)
+    {
+      /* Read the next entry.  */
+      if (read_entry (connection->database, connection->position,
+                     &connection->last_entry) < 0)
+       {
+         connection->position = -1;
+         errno = ESRCH;
+         goto return_error;
+       }
+      connection->position++;
+
+      /* Stop if we found a user or login entry.  */
+      if (
+#if _HAVE_UT_TYPE - 0
+         (connection->last_entry.ut_type == USER_PROCESS
+          || connection->last_entry.ut_type == LOGIN_PROCESS)
+         &&
+#endif
+         !strncmp (request->line.ut_line, connection->last_entry.ut_line,
+                   sizeof request->line.ut_line))
+       break;
+    }
+
+  memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
+  reply.errnum = 0;
+  reply.result = 0;
+  return send_reply (connection, &reply.header);
+
+return_error:
+  memset (&reply.entry, 0, sizeof (struct utmp));
+  reply.errnum = errno;
+  reply.result = -1;
+  return send_reply (connection, &reply.header);
+}
+
+
+static int
+do_getutid (client_connection *connection)
+{
+  getutid_request *request;
+  getutid_reply reply;
+
+  request = (getutid_request *)connection->read_base;
+  if (request->header.size != sizeof (getutid_request))
+    {
+      warning (EINVAL, "invalid request size");
+      return -1;
+    }
+
+  /* Initialize reply.  */
+  reply.header.version = UTMPD_VERSION;
+  reply.header.size = sizeof (getutid_reply);
+  reply.header.type = UTMPD_REQ_GETUTID;
+
+  if (connection->database == NULL || connection->position == -1)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  /* Make sure we're in synch with the ordinary file.  */
+  if (synchronize_database (connection->database) < 0)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  if (internal_getut_r (connection, &request->id,
+                       &connection->last_entry) < 0)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  reply.errnum = 0;
+  reply.result = 0;
+  memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
+  return send_reply (connection, &reply.header);
+
+return_error:
+  memset (&reply.entry, 0, sizeof (struct utmp));
+  reply.errnum = errno;
+  reply.result = -1;
+  return send_reply (connection, &reply.header);
+}
+
+
+static int
+do_pututline (client_connection *connection)
+{
+  pututline_request *request;
+  pututline_reply reply;
+  struct utmp buffer;
+  int found;
+
+  request = (pututline_request *)connection->read_base;
+  if (request->header.size != sizeof (pututline_request))
+    {
+      warning (EINVAL, "invalid request size");
+      return -1;
+    }
+
+  /* Initialize reply.  */
+  reply.header.version = UTMPD_VERSION;
+  reply.header.size = sizeof (pututline_reply);
+  reply.header.type = UTMPD_REQ_PUTUTLINE;
+
+  if (!(connection->access & W_OK))
+    {
+      errno = EPERM;
+      goto return_error;
+    }
+
+  if (connection->database == NULL || connection->position == -1)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  /* Make sure we're in synch with the ordinary file.  */
+  if (synchronize_database (connection->database) < 0)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  /* Find the correct place to insert the data.  */
+  if (connection->position > 0
+    && (
+#if _HAVE_UT_TYPE - 0
+       (connection->last_entry.ut_type == request->utmp.ut_type
+        && (connection->last_entry.ut_type == RUN_LVL
+            || connection->last_entry.ut_type == BOOT_TIME
+            || connection->last_entry.ut_type == OLD_TIME
+            || connection->last_entry.ut_type == NEW_TIME))
+       ||
+#endif
+       proc_utmp_eq (&connection->last_entry, &request->utmp)))
+    found = 1;
+  else
+    found = internal_getut_r (connection, &request->utmp, &buffer);
+
+  if (found < 0)
+    {
+      /* We append the next entry.  */
+      connection->position =
+       append_entry (connection->database, &request->utmp);
+      if (connection->position < 0)
+       goto return_error;
+    }
+  else
+    {
+      /* We replace the just read entry.  */
+      connection->position--;
+      if (write_entry (connection->database, connection->position,
+                      &request->utmp) < 0)
+       goto return_error;
+    }
+
+  /* Write the entry to the compatibility file.  */
+  write_old_entry (connection->database, connection->position, &request->utmp);
+
+  /* Update position pointer.  */
+  connection->position++;
+
+  reply.errnum = 0;
+  reply.result = 0;
+  return send_reply (connection, &reply.header);
+
+return_error:
+  reply.errnum = errno;
+  reply.result = -1;
+  return send_reply (connection, &reply.header);
+}
+
+
+static int
+do_updwtmp (client_connection *connection)
+{
+  updwtmp_request *request;
+  updwtmp_reply reply;
+  utmp_database *database;
+
+  request = (updwtmp_request *)connection->read_base;
+  if (request->header.size != sizeof (updwtmp_request))
+    {
+      warning (EINVAL, "invalid request size");
+      return -1;
+    }
+
+  /* Initialize reply.  */
+  reply.header.version = UTMPD_VERSION;
+  reply.header.size = sizeof (updwtmp_reply);
+  reply.header.type = UTMPD_REQ_UPDWTMP;
+
+  if (!(connection->access & W_OK))
+    {
+      errno = EPERM;
+      goto return_error;
+    }
+
+  /* Select database.  */
+  if (!strncmp (request->file, _PATH_UTMP, sizeof request->file))
+    database = utmp_db;
+  else
+    {
+      errno = EINVAL;
+      goto return_error;
+    }
+
+  /* Make sure we're in synch with the ordinary file.  */
+  if (synchronize_database (database) < 0)
+    {
+      errno = ESRCH;
+      goto return_error;
+    }
+
+  /* Append the entry.  */
+  if (append_entry (database, &request->utmp) < 0)
+    goto return_error;
+
+  reply.errnum = 0;
+  reply.result = 0;
+  return send_reply (connection, &reply.header);
+
+return_error:
+  reply.errnum = errno;
+  reply.result = -1;
+  return send_reply (connection, &reply.header);
+}
+
+
+/* This function is identical to the one in login/utmp_file.c.  */
+static int
+proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
+{
+  return
+    (
+#if _HAVE_UT_TYPE - 0
+     (entry->ut_type == INIT_PROCESS
+      || entry->ut_type == LOGIN_PROCESS
+      || entry->ut_type == USER_PROCESS
+      || entry->ut_type == DEAD_PROCESS)
+     &&
+     (match->ut_type == INIT_PROCESS
+      || match->ut_type == LOGIN_PROCESS
+      || match->ut_type == USER_PROCESS
+      || match->ut_type == DEAD_PROCESS)
+     &&
+#endif
+#if _HAVE_UT_ID - 0
+     strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
+#else
+     strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
+#endif
+     );
+}
+
+
+/* This function is derived from the one in login/utmp_file.c.  */
+static int
+internal_getut_r (client_connection *connection,
+                 const struct utmp *id, struct utmp *buffer)
+{
+#if _HAVE_UT_TYPE - 0
+  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_entry (connection->database, connection->position,
+                         buffer) < 0)
+           {
+             connection->position = -1;
+             return -1;
+           }
+         connection->position++;
+
+         if (id->ut_type == buffer->ut_type)
+           break;
+       }
+    }
+  else
+#endif /* _HAVE_UT_TYPE */
+    {
+      /* 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_entry (connection->database, connection->position,
+                         buffer) < 0)
+           {
+             connection->position = -1;
+             return -1;
+           }
+         connection->position++;
+
+         if (proc_utmp_eq (buffer, id))
+           break;
+       }
+    }
+
+  return 0;
+}
diff --git a/login/programs/utmpd-private.h b/login/programs/utmpd-private.h
new file mode 100644 (file)
index 0000000..4a9cdb9
--- /dev/null
@@ -0,0 +1,107 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 _UTMPD_PRIVATE_H
+#define _UTMPD_PRIVATE_H       1
+
+#include <time.h>
+#include <utmp.h>
+
+
+/* The number of connections we allow.  */
+#ifndef MAX_CONNECTIONS
+#define MAX_CONNECTIONS        16
+#endif
+
+
+typedef struct utmp_database
+{
+  int fd;
+  int old_fd;
+  char *file;
+  char *old_file;
+  time_t mtime;
+} utmp_database;
+
+
+/* The databases we handle.  */
+extern utmp_database *utmp_db;
+extern utmp_database *wtmp_db;
+
+
+typedef struct client_connection
+{
+  int sock;
+  /* Access permissions.  */
+  int access;
+
+  /* Read pointer.  */
+  void *read_base;
+  void *read_ptr;
+  void *read_end;
+
+  /* Write buffer.  */
+  void *write_base;
+  void *write_ptr;
+  void *write_end;
+
+  /* Database to use for this connection.  */
+  utmp_database *database;
+  /* Position pointer.  */
+  int position;
+  
+  /* Last read entry.  */
+  struct utmp last_entry;
+
+  /* Pointers to the next and previous connections in the list.  */
+  struct client_connection *next;
+  struct client_connection *prev;
+} client_connection;
+
+
+/* This variable indicates if we have forked.  If set, we log messages
+   via the system logger.  Otherwise we simply print the program name
+   and the message to standard error.  */
+extern int forked;
+
+
+/* Database functions.  */
+utmp_database *open_database (const char *file, const char *old_file);
+int synchronize_database (utmp_database *database);
+void close_database (utmp_database *database);
+int read_entry (utmp_database *database, int position, struct utmp *entry);
+int write_entry (utmp_database *database, int position,
+                const struct utmp *entry);
+int append_entry (utmp_database *database, const struct utmp *entry);
+int read_old_entry (utmp_database *database, int position, struct utmp *entry);
+int write_old_entry (utmp_database *database, int position,
+                    const struct utmp *entry);
+
+/* Connection oriented functions.  */
+client_connection *accept_connection (int sock, int access);
+client_connection *find_connection (int sock);
+void close_connection (client_connection *connection);
+int read_data (client_connection *connection);
+int write_data (client_connection *connection);
+
+void error (int status, int errnum, const char *message, ...);
+void warning (int errnum, const char *message, ...);
+
+#endif /* utmpd-private.h  */
+
diff --git a/login/programs/utmpd.c b/login/programs/utmpd.c
new file mode 100644 (file)
index 0000000..e112181
--- /dev/null
@@ -0,0 +1,384 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 <getopt.h>
+#include <libintl.h>
+#include <pwd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "utmpd.h"
+#include "utmpd-private.h"
+
+/* Get libc version number.  */
+#include "../../version.h"
+
+#define PACKAGE "libc"
+
+/* Long options.  */
+static const struct option long_options[] =
+{
+  { "debug", no_argument, NULL, 'd' },
+  { "help", no_argument, NULL, 'h' },
+  { "version", no_argument, NULL, 'V' },
+  { NULL, 0, NULL, 0}
+};
+
+/* The UTMP database.  */
+utmp_database *utmp_db;
+
+/* The socket for read only requests.  */
+int ro_sock = -1;
+
+/* The socket for read/write requests.  */
+int rw_sock = -1;
+
+
+/* Prototypes for the local functions.  */
+static void usage (int status) __attribute__ ((noreturn));
+static void drop_priviliges (void);
+static int make_socket (const char *name);
+static void handle_requests (void) __attribute__ ((noreturn));
+static void termination_handler (int signum);
+static int check_pid (const char *file);
+static int write_pid (const char *file);
+
+
+int
+main (int argc, char *argv[])
+{
+  mode_t mask;
+  int debug;
+  int do_help;
+  int do_version;
+  int opt;
+
+  /* Initialize local variables.  */
+  debug = 0;
+  do_help = 0;
+  do_version = 0;
+  
+  while ((opt = getopt_long (argc, argv, "dhV", long_options, NULL)) != -1)
+    switch (opt)
+      {
+      case '\0':               /* Long option.  */
+       break;
+      case 'h':
+       do_help = 1;
+       break;
+      case 'd':
+       debug = 1;
+       break;
+      case 'V':
+       do_version = 1;
+       break;
+      default:
+       usage (EXIT_FAILURE);
+      }
+
+  /* Version information is reequested.  */
+  if (do_version)
+    {
+      printf ("utmpd (GNU %s) %s\n", PACKAGE, VERSION);
+      printf (gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions.  There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "1997");
+      printf (gettext ("Written by %s.\n"), "Mark Kettenis");
+
+      exit (EXIT_SUCCESS);
+    }
+
+  /* Help is requested.  */
+  if (do_help)
+    usage (EXIT_SUCCESS);
+
+  signal (SIGINT, termination_handler);
+  signal (SIGTERM, termination_handler);
+
+  /* Check if we are already running.  */
+  if (check_pid (_PATH_UTMPDPID))
+    error (EXIT_FAILURE, 0, "already running");
+
+  /* Open UTMP database.  */
+  utmp_db = open_database (_PATH_UTMP "x", _PATH_UTMP);
+  if (utmp_db == NULL)
+    error (EXIT_FAILURE, errno, "%s", _PATH_UTMP);
+
+  /* Create sockets, with the right permissions.  */
+  mask = umask (S_IXUSR | S_IXGRP | S_IXOTH);
+  ro_sock = make_socket (_PATH_UTMPD_RO);
+  umask (S_IXUSR | S_IRWXG | S_IRWXO);
+  rw_sock = make_socket (_PATH_UTMPD_RW);
+  umask (mask);
+
+  /* Set the sockets up to accept connections.  */
+  if (listen (ro_sock, MAX_CONNECTIONS) < 0
+      || listen (rw_sock, MAX_CONNECTIONS) < 0)
+    error (EXIT_FAILURE, errno, "cannot enable socket to accept connections");
+
+  /* Behave like a daemon.  */
+  if (!debug)
+    {
+      openlog ("utmpd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
+      
+      if (daemon (0, 0) < 0)
+       error (EXIT_FAILURE, errno, "cannot auto-background");
+      forked = 1;
+
+      if (write_pid (_PATH_UTMPDPID) < 0)
+       warning (errno, "%s", _PATH_UTMPDPID);
+    }
+
+  /* Drop priviliges.  */
+  drop_priviliges ();
+  
+  /* Handle incoming requests.  */
+  handle_requests ();
+}
+
+
+/* Display usage information and exit.  */
+static void
+usage (int status)
+{
+  if (status != EXIT_SUCCESS)
+    fprintf (stderr, gettext ("Try `%s --help' for more information.\n"),
+            program_invocation_name);
+  else
+    {
+      printf (gettext ("\
+Usage: %s [OPTION]...\n\
+  -d, --debug           do not fork and display messages on the current tty\n\
+  -h, --help           display this help and exit\n\
+  -V, --version         output version information and exit\n"),
+             program_invocation_name);
+      fputs (gettext ("\
+Report bugs to <kettenis@phys.uva.nl>.\n"),
+            stdout);
+    }
+  
+  exit (status);
+}
+
+
+/* Drop priviliges.  */
+static void
+drop_priviliges (void)
+{
+  struct passwd *pw;
+
+  pw = getpwnam ("daemon");
+  if (pw)
+    {
+      seteuid (pw->pw_uid);
+      setegid (pw->pw_gid);
+    }
+}
+
+
+/* Make a socket in the file namespace using the filename NAME as the
+   socket's address.  */
+static int
+make_socket (const char *name)
+{
+  struct sockaddr_un addr;
+  size_t size;
+  int sock;
+
+  /* Create the socket.  */
+  sock = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    error (EXIT_FAILURE, errno, "cannot create socket");
+
+  /* Bind a name to the socket.  */
+  addr.sun_family = AF_UNIX;
+  strcpy (addr.sun_path, name);
+
+  /* The size of the address is the offset of the start
+     of the filename, plus its length, plus one for the
+     terminating null byte. */
+  size = (offsetof (struct sockaddr_un, sun_path)
+         + strlen (addr.sun_path));
+     
+  if (bind (sock, (struct sockaddr *) &addr, size) < 0)
+    error (EXIT_FAILURE, errno, "%s", name);
+     
+  return sock;
+}
+
+
+/* Hanlde incoming requests.  */
+static
+void handle_requests (void)
+{
+  client_connection *connection;
+  fd_set active_read_fd_set;
+  fd_set active_write_fd_set;
+  fd_set read_fd_set;
+  fd_set write_fd_set;
+  int fd;
+  
+  /* Initialize the set of active sockets.  */
+  FD_ZERO (&active_read_fd_set);
+  FD_ZERO (&active_write_fd_set);
+  FD_SET (rw_sock, &active_read_fd_set);
+  FD_SET (ro_sock, &active_read_fd_set);
+
+  while (1)
+    {
+      /* Block until input arrives on one or more active sockets.  */
+      read_fd_set = active_read_fd_set;
+      write_fd_set = active_write_fd_set;
+      if (select (FD_SETSIZE, &read_fd_set, &write_fd_set, NULL, NULL) < 0)
+       error (EXIT_FAILURE, errno, "cannot get input on sockets");
+
+      /* Service all the sockets with input pending.  */
+      for (fd = 0; fd < FD_SETSIZE; fd++)
+       {
+         if (FD_ISSET (fd, &read_fd_set))
+           {
+             if (fd == ro_sock || fd == rw_sock)
+               {
+                 int access = ((fd == rw_sock) ? (R_OK | W_OK) : R_OK);
+
+                 connection = accept_connection (fd, access);
+                 if (connection == NULL)
+                   error (0, errno, "cannot accept connection");
+
+                 FD_SET (connection->sock, &active_read_fd_set);
+               }
+             else
+               {
+                 connection = find_connection (fd);
+                 if (connection == NULL)
+                   error (EXIT_FAILURE, 0, "cannot find connection");
+
+                 if (read_data (connection) < 0)
+                   {
+                     close_connection (connection);
+                     FD_CLR (fd, &active_read_fd_set);
+                     FD_CLR (fd, &active_write_fd_set);
+                   }
+
+                 if (connection->write_ptr > connection->write_base)
+                     FD_SET (fd, &active_write_fd_set);
+               }
+           }
+         if (FD_ISSET (fd, &write_fd_set) &&
+             fd != rw_sock && fd != ro_sock)
+           {
+             connection = find_connection (fd);
+             if (connection == NULL)
+               error (EXIT_FAILURE, 0, "cannot find connection");
+
+             if (write_data (connection) < 0)
+               {
+                 close_connection (connection);
+                 FD_CLR (fd, &active_read_fd_set);
+                 FD_CLR (fd, &active_write_fd_set);
+               }
+
+             if (connection->write_ptr == connection->write_base)
+               FD_CLR (fd, &active_write_fd_set);
+           }
+       }       
+    }
+}
+
+
+/* Cleanup.  */
+static void
+termination_handler (int signum)
+{
+  /* Close sockets.  */
+  close (ro_sock);
+  close (rw_sock);
+
+  /* Restore user id.  */
+  seteuid (getuid ());
+  
+  /* Clean up the files created by `bind'.  */
+  unlink (_PATH_UTMPD_RO);
+  unlink (_PATH_UTMPD_RW);
+
+  if (utmp_db)
+    close_database (utmp_db);
+
+  /* Clean up pid file.  */
+  unlink (_PATH_UTMPDPID);
+  
+  exit (EXIT_SUCCESS);
+}
+
+
+/* Returns 1 if the process in pid file FILE is running, 0 if not.  */
+static int
+check_pid (const char *file)
+{
+  FILE *fp;
+  
+  fp = fopen (_PATH_UTMPDPID, "r");
+  if (fp)
+    {
+      pid_t pid;
+      
+      fscanf (fp, "%d", &pid);
+      fclose (fp);
+
+      if (kill (pid, 0) == 0)
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Write the current process id to the file FILE.  Returns 0 if
+   successful, -1 if not.  */
+static int
+write_pid (const char *file)
+{
+  FILE *fp;
+  
+  fp = fopen (_PATH_UTMPDPID, "w");
+  if (fp == NULL)
+    return -1;
+  
+  fprintf (fp, "%d\n", getpid ());
+  if (ferror (fp))
+    return -1;
+  
+  fclose (fp);
+
+  return 0;
+}
+
diff --git a/login/programs/utmpd.h b/login/programs/utmpd.h
new file mode 100644 (file)
index 0000000..8fbc33c
--- /dev/null
@@ -0,0 +1,141 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 _UTMPD_H
+#define _UTMPD_H               1
+
+/* This is an *internal* header.  */
+
+#include <limits.h>
+#include <stddef.h>
+#include <utmp.h>
+
+
+/* Paths to daemon sockets.  */
+#define _PATH_UTMPD_RO "/var/run/utmpd.ro"
+#define _PATH_UTMPD_RW "/var/run/utmpd.rw"
+
+
+/* Path to PID file.  */
+#define _PATH_UTMPDPID "/var/run/utmpd.pid"
+
+
+/* Version number of the daemon interface.  */
+#define UTMPD_VERSION  1
+
+
+/* Services provided.  */
+typedef enum
+{
+  UTMPD_REQ_SETUTENT,
+  UTMPD_REQ_GETUTENT,
+  UTMPD_REQ_ENDUTENT,
+  UTMPD_REQ_GETUTLINE,
+  UTMPD_REQ_GETUTID,
+  UTMPD_REQ_PUTUTLINE,
+  UTMPD_REQ_UPDWTMP
+} request_type;
+
+
+/* Header common to all requests.  */
+typedef struct
+{
+  /* Version number of the daemon interface.  */
+  int version;
+  /* Number of bytes in this request.  */
+  size_t size;
+  /* Service requested.  */
+  request_type type;
+} request_header;
+
+typedef struct
+{
+  request_header header;
+  /* File to use.  */
+  char file[_POSIX_PATH_MAX + 1];
+} setutent_request;
+
+typedef struct
+{
+  request_header header;
+} getutent_request, endutent_request;
+
+typedef struct
+{
+  request_header header;
+  /* Entry to match.  */
+  struct utmp line;
+} getutline_request;
+
+typedef struct
+{
+  request_header header;
+  /* Entry to match.  */
+  struct utmp id;
+} getutid_request;
+
+typedef struct
+{
+  request_header header;
+  /* Entry to write.  */
+  struct utmp utmp;
+} pututline_request;
+
+typedef struct
+{
+  request_header header;
+  /* File to use.  */
+  char file[_POSIX_PATH_MAX + 1];
+  /* Entry to write.  */
+  struct utmp utmp;
+} updwtmp_request;
+
+
+/* Header common to all replies.  */
+typedef struct
+{
+  /* Version number of the daemon interface.  */
+  int version;
+  /* Number of bytes in this reply.  */
+  size_t size;
+  /* Answer to the request.  */
+  request_type type;
+} reply_header;
+
+typedef struct
+{
+  reply_header header;
+  /* Error code.  */
+  int errnum;
+  /* Return value.  */
+  int result;
+} setutent_reply, endutent_reply, pututline_reply, updwtmp_reply;
+
+typedef struct
+{
+  reply_header header;
+  /* Found entry.  */
+  struct utmp entry;
+  /* Error code.  */
+  int errnum;
+  /* Return value.  */
+  int result;
+} getutent_reply, getutline_reply, getutid_reply;
+
+#endif /* utmpd.h  */
diff --git a/login/programs/utmpdump.c b/login/programs/utmpdump.c
new file mode 100644 (file)
index 0000000..e1422b5
--- /dev/null
@@ -0,0 +1,53 @@
+/* utmpdump - dump utmp-like files.
+   Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmp.h>
+
+void
+print_entry (struct utmp *up)
+{
+  printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-15.15s] [%ld]\n",
+         up->ut_type, up->ut_pid, up->ut_id, up->ut_user,
+         up->ut_line, 4 + ctime (&up->ut_time), up->ut_tv.tv_usec);
+}
+
+int
+main (int argc, char *argv[])
+{
+  struct utmp *up;
+
+  if (argc > 1)
+    utmpname (argv[1]);
+  
+  setutent ();
+
+  while ((up = getutent ()))
+    print_entry (up);
+
+  endutent ();
+  
+  return EXIT_SUCCESS;
+}
diff --git a/login/programs/xtmp.c b/login/programs/xtmp.c
new file mode 100644 (file)
index 0000000..d2d5fee
--- /dev/null
@@ -0,0 +1,102 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#include "xtmp.h"
+
+/* Convert the entry XT to the new utmp format and store it in UT.
+   Fields in UT that were not present in the old utmp format are
+   initialized to zero.  */
+void
+xtmp_to_utmp (const struct xtmp *xtmp, struct utmp *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmp));
+#if _HAVE_XT_TYPE - 0
+  utmp->ut_type = xtmp->xt_type;
+#endif
+#if _HAVE_XT_PID - 0
+  utmp->ut_pid = xtmp->xt_pid;
+#endif
+  strncpy (utmp->ut_line, xtmp->xt_line, XT_LINESIZE);
+#if _HAVE_XT_ID - 0
+  strncpy (utmp->ut_id, xtmp->xt_id, sizeof xtmp->xt_id);
+#endif
+  utmp->ut_time = xtmp->xt_time;
+  strncpy (utmp->ut_user, xtmp->xt_user, XT_NAMESIZE);
+#if _HAVE_XT_HOST - 0
+  strncpy (utmp->ut_host, xtmp->xt_host, XT_HOSTSIZE);
+#endif
+  utmp->ut_addr = xtmp->xt_addr;
+}
+
+/* Convert the entry UTMP to the old utmp format and store it in XTMP.  */
+void
+utmp_to_xtmp (const struct utmp *utmp, struct xtmp *xtmp)
+{
+  memset (xtmp, 0, sizeof (struct xtmp));
+#if _HAVE_XT_TYPE - 0
+  xtmp->xt_type = utmp->ut_type;
+#endif
+#if _HAVE_XT_PID - 0
+  xtmp->xt_pid = utmp->ut_pid;
+#endif
+  strncpy (xtmp->xt_line, utmp->ut_line, XT_LINESIZE);
+  xtmp->xt_line[XT_LINESIZE] = '\0';
+#if _HAVE_XT_ID - 0
+  strncpy (xtmp->xt_id, utmp->ut_id, sizeof xtmp->xt_id);
+#endif
+  xtmp->xt_time = utmp->ut_time;
+  strncpy (xtmp->xt_user, utmp->ut_user, XT_NAMESIZE);
+#if _HAVE_XT_HOST - 0
+  strncpy (xtmp->xt_host, utmp->ut_host, XT_HOSTSIZE);
+  xtmp->xt_host[XT_HOSTSIZE] = '\0';
+#endif
+  xtmp->xt_addr = utmp->ut_addr;
+}
+
+/* Compare an old style entry XTMP with a new style entry UTMP.  The
+   function returns 1 if the information that is in both old and new
+   style entries is identical.  Otherwise this function returns 0.  */
+int
+compare_entry (const struct utmp *xtmp, const struct utmp *utmp)
+{
+  return
+    (
+#if _HAVE_XT_TYPE - 0
+     xtmp->ut_type == utmp->ut_type
+#endif
+#if _HAVE_XT_PID - 0
+     && xtmp->ut_pid == utmp->ut_pid
+#endif
+     && !strncmp (xtmp->ut_line, utmp->ut_line, XT_LINESIZE - 1)
+#if _HAVE_XT_ID - 0
+     && !strncmp (xtmp->ut_id, utmp->ut_id, sizeof utmp->ut_id)
+#endif
+     && xtmp->ut_time == utmp->ut_time
+     && !strncmp (xtmp->ut_user, utmp->ut_user, XT_NAMESIZE)
+#if _HAVE_XT_HOST - 0
+     && !strncmp (xtmp->ut_host, utmp->ut_host, XT_HOSTSIZE - 1)
+#endif
+     && xtmp->ut_addr == utmp->ut_addr);
+}
diff --git a/login/programs/xtmp.h b/login/programs/xtmp.h
new file mode 100644 (file)
index 0000000..8fa982e
--- /dev/null
@@ -0,0 +1,56 @@
+/* The `struct xtmp' type, describing the old linux utmp format.
+   Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+   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 _XTMP_H
+#define _XTMP_H                1
+#include <features.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+
+#define XT_LINESIZE    12
+#define XT_NAMESIZE    8
+#define XT_HOSTSIZE    16
+
+struct xtmp
+{
+  short        int xt_type;            /* Type of login.  */
+  pid_t        xt_pid;                 /* Pid of login process.  */
+  char xt_line[XT_LINESIZE];   /* NUL-terminated devicename of tty.  */
+  char xt_id[4];               /* Inittab id.  */
+  time_t xt_time;              /* Time entry was made.  */
+  char xt_user[XT_NAMESIZE];   /* Username (not NUL terminated).  */
+  char xt_host[XT_HOSTSIZE];   /* Hostname for remote login.  */
+  long xt_addr;                /* Internet adress of remote host.  */
+};
+
+#define _HAVE_XT_TYPE  1
+#define _HAVE_XT_PID   1
+#define _HAVE_XT_ID    1
+#define _HAVE_XT_HOST  1
+
+
+extern void xtmp_to_utmp (const struct xtmp *xtmp, struct utmp *utmp);
+extern void utmp_to_xtmp (const struct utmp *utmp, struct xtmp *xtmp);
+extern int compare_entry (const struct utmp *xtmp,
+                         const struct utmp *utmp);
+
+#endif /* xtmp.h  */
diff --git a/login/utmpd/connection.c b/login/utmpd/connection.c
deleted file mode 100644 (file)
index 4e16631..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include "utmpd-private.h"
-
-
-/* Prototypes for the local functions.  */
-static client_connection *alloc_connection (void);
-static void free_connection (client_connection *connection);
-static int set_nonblock_flag (int desc, int value);
-
-
-/* The head of the connection list.  */
-static client_connection *connection_list = NULL;
-
-
-/* Accept connection on SOCK, with access permissions given by ACCESS.
-   Returns a pointer to a newly allocated client_connection if
-   successful, NULL if not.  */
-client_connection *
-accept_connection (int sock, int access)
-{
-  client_connection *connection;
-
-  connection = alloc_connection ();
-  if (connection == NULL)
-    return NULL;
-
-  connection->sock = accept (sock, NULL, NULL);
-  connection->access = access;
-  if (connection->sock < 0)
-    {
-      free_connection (connection);
-      return NULL;
-    }
-  
-  if (set_nonblock_flag (connection->sock, 1) < 0)
-    {
-      close_connection (connection);
-      return NULL;
-    }
-
-  return connection;  
-}
-
-
-/* Close CONNECTION.  */
-void
-close_connection (client_connection *connection)
-{
-  close (connection->sock);
-  free_connection (connection);
-}
-
-
-/* Return the connection for SOCK.  */
-client_connection *
-find_connection (int sock)
-{
-  client_connection *connection;
-
-  for (connection = connection_list; connection;
-       connection = connection->next)
-    {
-      if (connection->sock == sock)
-       return connection;
-    }
-
-  return NULL;
-}
-
-
-static client_connection *
-alloc_connection (void)
-{
-  client_connection *connection;
-  size_t read_bufsize = 1024;
-  size_t write_bufsize = 1024;
-
-  connection = (client_connection *)malloc (sizeof (client_connection));
-  if (connection == NULL)
-    return NULL;
-
-  memset (connection, 0, sizeof (client_connection));
-
-  /* Allocate read buffer.  */
-  connection->read_base = malloc (read_bufsize);
-  connection->read_ptr = connection->read_base;
-  connection->read_end = connection->read_base + read_bufsize;
-  if (connection->read_base == NULL)
-    {
-      free (connection);
-      return NULL;
-    }
-
-  /* Allocate write buffer.  */
-  connection->write_base = malloc (write_bufsize);
-  connection->write_ptr = connection->write_base;
-  connection->write_end = connection->write_base + write_bufsize;
-  if (connection->write_base == NULL)
-    {
-      free (connection->read_base);
-      free (connection);
-      return NULL;
-    }
-
-  /* Link connection.  */
-  connection->next = connection_list;
-  connection_list = connection;
-  if (connection->next)
-    connection->next->prev = connection;
-  
-  return connection;
-}
-
-
-static void
-free_connection (client_connection *connection)
-{
-  /* Unlink connection.  */
-  if (connection->next)
-    connection->next->prev = connection->prev;
-  if (connection->prev)
-    connection->prev->next = connection->next;
-
-  /* Take care of the head of the list.  */
-  if (connection == connection_list)
-    connection_list = connection->next;
-  
-  /* Free buffers.  */
-  if (connection->read_base)
-    free (connection->read_base);
-  if (connection->write_base)
-    free (connection->write_base);
-
-  free (connection);
-}
-
-
-/* Set the `O_NONBLOCK' flag of DESC if VALUE is nonzero,
-   or clear the flag if VALUE is 0.
-   Return 0 on success, or -1 on error with `errno' set. */
-static int
-set_nonblock_flag (int desc, int value)
-{
-  int oldflags = fcntl (desc, F_GETFL, 0);
-  /* If reading the flags failed, return error indication now. */
-  if (oldflags == -1)
-    return -1;
-  /* Set just the flag we want to set. */
-  if (value != 0)
-    oldflags |= O_NONBLOCK;
-  else
-    oldflags &= ~O_NONBLOCK;
-  /* Store modified flag word in the descriptor. */
-  return fcntl (desc, F_SETFL, oldflags);
-}
diff --git a/login/utmpd/database.c b/login/utmpd/database.c
deleted file mode 100644 (file)
index e31e0d9..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <unistd.h>
-#include <utmp.h>
-
-
-#include "utmpd-private.h"
-#include "xtmp.h"
-
-
-/* Prototypes for the local functions.  */
-static int initialize_database (utmp_database *database);
-static int store_state_entry (utmp_database *database, int old_position,
-                             const struct utmp *old_entry);
-static int store_process_entry (utmp_database *database, int old_position,
-                               const struct utmp *old_entry);
-static int replace_entry (utmp_database *database, int old_position,
-                         int new_position, const struct utmp *entry);
-static int store_entry (utmp_database *database, int position,
-                       const struct utmp *entry);
-static int proc_utmp_eq (const struct utmp *entry, const struct utmp *match);
-static int get_mtime (const char *file, time_t *timer);
-
-
-/* Open the database specified by FILE and merge it with the
-   contents of the old format file specified by OLD_FILE.  Returns a
-   pointer to a newly allocated structure describing the database, or
-   NULL on error.  */
-utmp_database *
-open_database (const char *file, const char *old_file)
-{
-  utmp_database *database;
-
-  /* Allocate memory.  */
-  database = (utmp_database *) malloc (sizeof (utmp_database));
-  if (database == NULL)
-    return NULL;
-
-  memset (database, 0, sizeof (utmp_database));
-
-  /* Open database.  */
-  database->fd = open (file, O_RDWR);
-  if (database->fd < 0)
-    goto fail;
-
-  database->old_fd = open (old_file, O_RDWR);
-  if (database->old_fd < 0)
-    goto fail;
-  
-  if ((file && !(database->file = strdup (file)))
-      || (old_file && !(database->old_file = strdup (old_file))))
-    goto fail;
-
-  if (initialize_database (database) < 0
-      || synchronize_database (database) < 0)
-    goto fail;
-  
-  return database;
-
-fail:
-  close_database (database);
-  return NULL;
-}
-
-/* Synchronize DATABASE.  */
-int
-synchronize_database (utmp_database *database)
-{
-  assert (database);
-
-  /* Check if there is a file in the old format, that we have to
-     synchronize with.  */
-  if (database->old_file)
-    {
-      time_t curtime;
-      time_t mtime;
-      
-      curtime = time (NULL);
-      
-      if (get_mtime (database->old_file, &mtime) < 0)
-       return -1;
-      
-      if (mtime >= database->mtime)
-       {
-         int position = 0;
-         struct utmp entry;
-         struct utmp old_entry;
-
-         while (1)
-           {
-             if (read_old_entry (database, position, &old_entry) < 0)
-               break;
-             
-             if (read_entry (database, position, &entry) < 0
-                 || !compare_entry (&old_entry, &entry))
-               {
-                 if (write_entry (database, position, &old_entry) < 0)
-                   return -1;
-               }
-
-             position++;
-           }
-
-         database->mtime = curtime;
-       }
-      
-    }
-
-  return 0;
-}
-
-
-/* Close DATABASE.  */
-void
-close_database (utmp_database *database)
-{
-  assert (database);
-
-  if (database->fd >= 0)
-    close (database->fd);
-
-  if (database->old_fd >= 0)
-    close (database->old_fd);
-  
-  /* Free allocated memory.  */
-  if (database->file)
-    free (database->file);
-  if (database->old_file)
-    free (database->old_file);
-  free (database);
-}
-
-
-/* Read the entry at POSITION in DATABASE and store the result in
-   ENTRY.  Returns 0 if successful, -1 if not.  */
-int
-read_entry (utmp_database *database, int position, struct utmp *entry)
-{
-  ssize_t nbytes;
-  off_t offset;
-
-  offset = position * sizeof (struct utmp);
-  if (lseek (database->fd, offset, SEEK_SET) < 0)
-    return -1;
-
-  nbytes = read (database->fd, entry, sizeof (struct utmp));
-  if (nbytes != sizeof (struct utmp))
-    return -1;
-  
-  return 0;
-}
-
-
-/* Write ENTRY at POSITION in DATABASE.  Returns 0 if successful, -1
-   on error.  */
-int
-write_entry (utmp_database *database, int position,
-            const struct utmp *entry)
-{
-  int result = -1;
-  struct flock fl;
-  ssize_t nbytes;
-  off_t offset;
-
-  /* Try to lock the file.  */
-  memset (&fl, 0, sizeof (struct flock));
-  fl.l_type = F_WRLCK;
-  fl.l_whence = SEEK_SET;
-  fcntl (database->fd, F_SETLKW, &fl);
-  
-  offset = position * sizeof (struct utmp);
-  if (lseek (database->fd, offset, SEEK_SET) < 0)
-    goto fail;
-
-  nbytes = write (database->fd, entry, sizeof (struct utmp));
-  if (nbytes != sizeof (struct utmp))
-    {
-      ftruncate (database->fd, offset);
-      goto fail;
-    }
-
-  result = 0;
-
-fail:
-  /* And unlock the file.  */
-  fl.l_type = F_UNLCK;
-  fcntl (database->fd, F_SETLKW, &fl);
-
-  return result;
-}
-
-
-/* Append ENTRY to DATABASE.  Returns the position of the appended
-   entry if successful, or -1 on error.  */
-int
-append_entry (utmp_database *database, const struct utmp *entry)
-{
-  int result = -1;
-  struct flock fl;
-  ssize_t nbytes;
-  off_t offset;
-
-  /* Try to lock the file.  */
-  memset (&fl, 0, sizeof (struct flock));
-  fl.l_type = F_WRLCK;
-  fl.l_whence = SEEK_SET;
-  fcntl (database->fd, F_SETLKW, &fl);
-  
-  offset = lseek (database->fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
-    {
-      offset -= offset % sizeof (struct utmp);
-      ftruncate (database->fd, offset);
-
-      if (lseek (database->fd, 0, SEEK_END) < 0)
-       goto fail;
-    }
-
-  nbytes = write (database->fd, entry, sizeof (struct utmp));
-  if (nbytes != sizeof (struct utmp))
-    {
-      ftruncate (database->fd, offset);
-      goto fail;
-    }
-
-  result = offset / sizeof (struct utmp);
-  
-fail:
-  /* And unlock the file.  */
-  fl.l_type = F_UNLCK;
-  fcntl (database->fd, F_SETLKW, &fl);
-
-  return result;
-}
-
-
-int
-read_old_entry (utmp_database *database, int position,
-               struct utmp *entry)
-{
-  struct xtmp old_entry;
-  ssize_t nbytes;
-  off_t offset;
-
-  offset = position * sizeof (struct xtmp);
-  if (lseek (database->old_fd, offset, SEEK_SET) < 0)
-    return -1;
-
-  nbytes = read (database->old_fd, &old_entry, sizeof (struct xtmp));
-  if (nbytes != sizeof (struct xtmp))
-    return -1;
-  
-  xtmp_to_utmp (&old_entry, entry);
-  return 0;
-}
-
-
-int
-write_old_entry (utmp_database *database, int position,
-                const struct utmp *entry)
-{
-  struct xtmp old_entry;
-  ssize_t nbytes;
-  off_t offset;
-
-  utmp_to_xtmp (entry, &old_entry);
-  
-  offset = position * sizeof (struct xtmp);
-  if (lseek (database->old_fd, offset, SEEK_SET) < 0)
-    return -1;
-
-  nbytes = write (database->old_fd, &old_entry, sizeof (struct xtmp));
-  if (nbytes != sizeof (struct xtmp))
-    return -1;
-
-  return 0;
-}
-
-
-/* Initialize DATABASE.  */
-static int
-initialize_database (utmp_database *database)
-{
-  struct utmp entry;
-  int position = 0;
-  
-  assert (database);
-
-  /* Check if there is a file in the old format to read.  */
-  if (database->old_file)
-    {
-      while (1)
-       {
-         if (read_old_entry (database, position, &entry) < 0)
-           break;
-
-#if _HAVE_UT_TYPE - 0
-         /* If the login type is one of RUN_LVL, BOOT_TIME, OLD_TIME or
-            NEW_TIME, search for an entry of the same type in the
-            database, and replace it if the entry in the file is newer.  */
-         if (entry.ut_type == RUN_LVL || entry.ut_type == BOOT_TIME
-             || entry.ut_type == OLD_TIME || entry.ut_type == NEW_TIME)
-           {
-             if (store_state_entry (database, position, &entry) < 0)
-               return -1;
-           }
-         else
-#endif
-           {
-             if (store_process_entry (database, position, &entry) < 0)
-               return -1;
-           }
-
-         /* Update position.  */
-         position++;
-       }
-
-      while (1)
-       {
-         if (read_entry (database, position, &entry) < 0)
-           break;
-
-         if (write_old_entry (database, position, &entry) < 0)
-           return -1;
-
-         /* Update position.  */
-         position++;
-       }
-    }
-
-  return 0;
-}
-
-
-static int
-store_state_entry (utmp_database *database, int old_position,
-                  const struct utmp *old_entry)
-{
-  struct utmp new_entry;
-  int new_position = 0;
-  int found = 0;
-
-  assert (old_entry->ut_type == RUN_LVL
-         || old_entry->ut_type == BOOT_TIME
-         || old_entry->ut_type == OLD_TIME
-         || old_entry->ut_type == NEW_TIME);
-
-  while (!found)
-    {
-      /* Read the next entry.  */
-      if (read_entry (database, new_position, &new_entry) < 0)
-       break;
-      
-      if (old_entry->ut_type == new_entry.ut_type)
-       {
-         found = 1;
-         continue;
-       }
-
-      /* Update position.  */
-      new_position++;
-    }
-
-  if (found)
-    {
-      const struct utmp *entry;
-
-      if (old_entry->ut_time > new_entry.ut_time)
-       entry = old_entry;
-      else
-       entry = &new_entry;
-      
-      return replace_entry (database, old_position, new_position, entry);
-    }
-
-  return store_entry (database, old_position, old_entry);
-}
-
-
-static int
-store_process_entry (utmp_database *database, int old_position,
-                    const struct utmp *old_entry)
-{
-  struct utmp new_entry;
-  int new_position = 0;
-  int found = 0;
-
-  while (!found)
-    {
-      /* Read the next entry.  */
-      if (read_entry (database, new_position, &new_entry) < 0)
-       break;
-
-      if (proc_utmp_eq (old_entry, &new_entry))
-       {
-         found = 1;
-         continue;
-       }
-
-      /* Update position.  */
-      new_position++;
-    }
-
-  if (found)
-    {
-      const struct utmp *entry;
-
-      if (old_entry->ut_time > new_entry.ut_time)
-       entry = old_entry;
-      else
-       entry = &new_entry;
-      
-      return replace_entry (database, old_position, new_position, entry);
-    }
-
-  return store_entry (database, old_position, old_entry);
-}
-
-
-static int
-replace_entry (utmp_database *database, int old_position, int new_position,
-              const struct utmp *entry)
-{
-  struct utmp tmp;
-  
-  if (read_entry (database, old_position, &tmp) < 0
-      || write_entry (database, old_position, entry) < 0
-      || write_entry (database, new_position, &tmp) < 0)
-    return -1;
-
-  return 0;
-}
-
-
-static int
-store_entry (utmp_database *database, int position,
-            const struct utmp *entry)
-{
-  struct utmp tmp;
-
-  if (read_entry (database, position, &tmp) < 0)
-    return write_entry (database, position, entry);
-
-  if (write_entry (database, position, entry) < 0
-      || append_entry (database, &tmp) < 0)
-    return -1;
-
-  return 0;
-}
-
-
-/* This function is identical to the one in login/utmp_file.c.  */
-static int
-proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
-{
-  return
-    (
-#if _HAVE_UT_TYPE - 0
-     (entry->ut_type == INIT_PROCESS
-      || entry->ut_type == LOGIN_PROCESS
-      || entry->ut_type == USER_PROCESS
-      || entry->ut_type == DEAD_PROCESS)
-     &&
-     (match->ut_type == INIT_PROCESS
-      || match->ut_type == LOGIN_PROCESS
-      || match->ut_type == USER_PROCESS
-      || match->ut_type == DEAD_PROCESS)
-     &&
-#endif
-#if _HAVE_UT_ID - 0
-     strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
-#else
-     strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
-#endif
-     );
-}
-
-
-/* Get modification time of FILE and put it in TIMER.  returns 0 if
-   successful, -1 if not.  */
-static int
-get_mtime (const char *file, time_t *timer)
-{
-  struct stat st;
-  
-  if (stat (file, &st) < 0)
-    return -1;
-
-  *timer = st.st_mtime;
-
-  return 0;
-}
diff --git a/login/utmpd/error.c b/login/utmpd/error.c
deleted file mode 100644 (file)
index e651144..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-
-#include "utmpd-private.h"
-
-
-/* This variable indicates if we have forked.  If set, we log messages
-   via the system logger.  Otherwise we simply print the program name
-   and the message to standard error.  */
-int forked = 0;
-
-
-/* Log error message MESSAGE, which is a printf-style format string
-   with optional args.
-   If ERRNUM is nonzero, also log its corresponding system error message.
-   Exit with status STATUS if it is nonzero.  */
-void
-error (int status, int errnum, const char *message, ...)
-{
-  va_list ap;
-  char *buffer = NULL;
-
-  va_start (ap, message);
-  vasprintf (&buffer, message, ap);
-  va_end (ap);
-
-  if (forked)
-    {
-      if (errnum == 0)
-       syslog (LOG_ERR, "%s", buffer);
-      else
-       syslog (LOG_ERR, "%s: %s", buffer, strerror (errnum));
-    }
-  else
-    {
-      if (errnum == 0)
-       fprintf (stderr, "%s: %s\n", program_invocation_name, buffer);
-      else
-       fprintf (stderr, "%s: %s: %s\n", program_invocation_name, buffer,
-                strerror (errnum));
-    }
-
-  if (buffer)
-    free (buffer);
-
-  if (status)
-    exit (status);
-}
-
-/* Log warning message MESSAGE, which is a printf-style format string
-   with optional args.
-   If ERRNUM is nonzero, also log its corresponding system error message. */
-void
-warning (int errnum, const char *message, ...)
-{
-  va_list ap;
-  char *buffer = NULL;
-
-  va_start (ap, message);
-  vasprintf (&buffer, message, ap);
-  va_end (ap);
-
-  if (forked)
-    {
-      if (errnum == 0)
-       syslog (LOG_WARNING, "%s", buffer);
-      else
-       syslog (LOG_WARNING, "%s: %s", buffer, strerror (errnum));
-    }
-  else
-    {
-      if (errnum == 0)
-       printf ("%s: %s\n", program_invocation_name, buffer);
-      else
-       printf ("%s: %s: %s\n", program_invocation_name, buffer,
-               strerror (errnum));
-    }
-
-  if (buffer)
-    free (buffer);
-}
diff --git a/login/utmpd/request.c b/login/utmpd/request.c
deleted file mode 100644 (file)
index 0f68b8a..0000000
+++ /dev/null
@@ -1,650 +0,0 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-
-#include "utmpd.h"
-#include "utmpd-private.h"
-
-
-/* Prototypes for the local functions.  */
-static int process_request (client_connection *connection);
-static int send_reply (client_connection *connect, const reply_header *reply);
-
-static int do_setutent (client_connection *connection);
-static int do_getutent (client_connection *connection);
-static int do_endutent (client_connection *connection);
-static int do_getutline (client_connection *connection);
-static int do_getutid (client_connection *connection);
-static int do_pututline (client_connection *connection);
-static int do_updwtmp (client_connection *connection);
-
-static int proc_utmp_eq (const struct utmp *entry, const struct utmp *match);
-static int internal_getut_r (client_connection *connection,
-                            const struct utmp *id, struct utmp *buffer);
-
-
-/* Read data from the client on CONNECTION.  */
-int
-read_data (client_connection *connection)
-{
-  ssize_t nbytes;
-
-  assert (connection);
-  assert ((connection->read_end - connection->read_ptr) > 0);
-
-  /* Read data.  */
-  nbytes = read (connection->sock, connection->read_ptr,
-                connection->read_end - connection->read_ptr);
-  if (nbytes > 0)
-    {
-      size_t total_bytes;
-
-      /* Update read pointer.  */
-      connection->read_ptr += nbytes;
-
-      /* Check if we have a complete request header.  */
-      total_bytes = connection->read_ptr - connection->read_base;
-      if (total_bytes >= sizeof (request_header))
-       {
-         request_header *header;
-
-         /* Check if we have a complete request.  */
-         header = (request_header *)connection->read_base;
-         if (total_bytes >= header->size)
-           {
-             /* Process the request.  */
-             if (process_request (connection) < 0)
-               return -1;
-
-             /* Adjust read pointer, and flush buffer.  */
-             connection->read_ptr -= header->size;
-             memmove (connection->read_base,
-                      connection->read_base + header->size,
-                      connection->read_ptr - connection->read_base);
-           }
-       }
-
-      return 0;
-    }
-
-  if (nbytes < 0)
-    error (0, errno, "cannot read from client");
-
-  return -1;
-}
-
-
-/* Write data to the client on CONNECTION.  */
-int
-write_data (client_connection *connection)
-{
-  ssize_t nbytes;
-
-  assert (connection);
-  assert ((connection->write_ptr - connection->write_base) > 0);
-
-  /* Write data.  */
-  nbytes = write (connection->sock, connection->write_base,
-                 connection->write_ptr - connection->write_base);
-  if (nbytes > 0)
-    {
-      /* Adjust write pointer and flush buffer.  */
-      connection->write_ptr -= nbytes;
-      memmove (connection->write_base, connection->write_base + nbytes,
-              connection->write_ptr - connection->write_base);
-
-      return 0;
-    }
-
-  if (nbytes < 0)
-    error (0, errno, "cannot write to client");
-
-  return -1;
-}
-
-
-/* Process the request received on CONNECTION.  Returns 0 if
-   successful, -1 if not.  */
-static int
-process_request (client_connection *connection)
-{
-  request_header *header;
-
-  assert (connection);
-  assert (connection->read_base);
-
-  header = (request_header *)connection->read_base;
-  if (header->version != UTMPD_VERSION)
-    {
-      warning (EINVAL, "invalid protocol version");
-      return -1;
-    }
-
-  switch (header->type)
-    {
-    case UTMPD_REQ_SETUTENT:   return do_setutent (connection);
-    case UTMPD_REQ_GETUTENT:   return do_getutent (connection);
-    case UTMPD_REQ_ENDUTENT:   return do_endutent (connection);
-    case UTMPD_REQ_GETUTLINE:  return do_getutline (connection);
-    case UTMPD_REQ_GETUTID:    return do_getutid (connection);
-    case UTMPD_REQ_PUTUTLINE:  return do_pututline (connection);
-    case UTMPD_REQ_UPDWTMP:    return do_updwtmp (connection);
-    default:
-      warning (EINVAL, "invalid request type");
-      return -1;
-    }
-}
-
-
-/* Send the reply specified by HEADER to the client on CONNECTION.
-   Returns 0 if successful, -1 if not.  */
-static int
-send_reply (client_connection *connection, const reply_header *reply)
-{
-  /* Check if the reply fits in the buffer.  */
-  if ((size_t) (connection->write_end - connection->write_ptr) < reply->size)
-    {
-      error (0, 0, "buffer overflow");
-      return -1;
-    }
-
-  /* Copy reply to buffer, and adjust write pointer.  */
-  memcpy (connection->write_ptr, reply, reply->size);
-  connection->write_ptr += reply->size;
-
-  return 0;
-}
-
-
-static int
-do_setutent (client_connection *connection)
-{
-  setutent_request *request;
-  setutent_reply reply;
-
-  request = (setutent_request *)connection->read_base;
-  if (request->header.size != sizeof (setutent_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
-
-  /* Initialize reply.  */
-  reply.header.version = UTMPD_VERSION;
-  reply.header.size = sizeof (setutent_reply);
-  reply.header.type = UTMPD_REQ_SETUTENT;
-
-  /* Select database.  */
-  if (!strncmp (request->file, _PATH_UTMP, sizeof request->file))
-    connection->database = utmp_db;
-  else
-    {
-      errno = EINVAL;
-      goto return_error;
-    }
-
-  /* Initialize position pointer.  */
-  connection->position = 0;
-
-#if _HAVE_UT_TYPE - 0
-  /* Make sure the entry won't match.  */
-  connection->last_entry.ut_type = -1;
-#endif
-
-  reply.errnum = 0;
-  reply.result = 0;
-  return send_reply (connection, &reply.header);
-
-return_error:
-  reply.errnum = errno;
-  reply.result = -1;
-  return send_reply (connection, &reply.header);
-}
-
-
-static int
-do_getutent (client_connection *connection)
-{
-  getutent_request *request;
-  getutent_reply reply;
-
-  request = (getutent_request *)connection->read_base;
-  if (request->header.size != sizeof (getutent_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
-
-  /* Initialize reply.  */
-  reply.header.version = UTMPD_VERSION;
-  reply.header.size = sizeof (getutent_reply);
-  reply.header.type = UTMPD_REQ_GETUTENT;
-
-  if (connection->database == NULL || connection->position == -1)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  /* Make sure we're in synch with the ordinary file.  */
-  if (synchronize_database (connection->database) < 0)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  /* Read the next entry from the database.  */
-  if (read_entry (connection->database, connection->position,
-                 &connection->last_entry) < 0)
-    {
-      connection->position = -1;
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  /* Update position pointer.  */
-  connection->position++;
-
-  memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
-  reply.errnum = 0;
-  reply.result = 0;
-  return send_reply (connection, (reply_header *)&reply);
-
-return_error:
-  memset (&reply.entry, 0, sizeof (struct utmp));
-  reply.errnum = errno;
-  reply.result = -1;
-  return send_reply (connection, &reply.header);
-}
-
-
-static int
-do_endutent (client_connection *connection)
-{
-  endutent_request *request;
-  endutent_reply reply;
-
-  request = (endutent_request *)connection->read_base;
-  if (request->header.size != sizeof (endutent_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
-
-  /* Deselect database.  */
-  connection->database = NULL;
-
-  /* Formulate reply.  */
-  reply.header.version = UTMPD_VERSION;
-  reply.header.size = sizeof (endutent_reply);
-  reply.header.type = UTMPD_REQ_ENDUTENT;
-  reply.errnum = 0;
-  reply.result = 0;
-
-  return send_reply (connection, &reply.header);
-}
-
-
-static int
-do_getutline (client_connection *connection)
-{
-  getutline_request *request;
-  getutline_reply reply;
-
-  request = (getutline_request *)connection->read_base;
-  if (request->header.size != sizeof (getutline_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
-
-  /* Initialize reply.  */
-  reply.header.version = UTMPD_VERSION;
-  reply.header.size = sizeof (getutline_reply);
-  reply.header.type = UTMPD_REQ_GETUTLINE;
-
-  if (connection->database == NULL || connection->position == -1)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  /* Make sure we're in synch with the ordinary file.  */
-  if (synchronize_database (connection->database) < 0)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  while (1)
-    {
-      /* Read the next entry.  */
-      if (read_entry (connection->database, connection->position,
-                     &connection->last_entry) < 0)
-       {
-         connection->position = -1;
-         errno = ESRCH;
-         goto return_error;
-       }
-      connection->position++;
-
-      /* Stop if we found a user or login entry.  */
-      if (
-#if _HAVE_UT_TYPE - 0
-         (connection->last_entry.ut_type == USER_PROCESS
-          || connection->last_entry.ut_type == LOGIN_PROCESS)
-         &&
-#endif
-         !strncmp (request->line.ut_line, connection->last_entry.ut_line,
-                   sizeof request->line.ut_line))
-       break;
-    }
-
-  memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
-  reply.errnum = 0;
-  reply.result = 0;
-  return send_reply (connection, &reply.header);
-
-return_error:
-  memset (&reply.entry, 0, sizeof (struct utmp));
-  reply.errnum = errno;
-  reply.result = -1;
-  return send_reply (connection, &reply.header);
-}
-
-
-static int
-do_getutid (client_connection *connection)
-{
-  getutid_request *request;
-  getutid_reply reply;
-
-  request = (getutid_request *)connection->read_base;
-  if (request->header.size != sizeof (getutid_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
-
-  /* Initialize reply.  */
-  reply.header.version = UTMPD_VERSION;
-  reply.header.size = sizeof (getutid_reply);
-  reply.header.type = UTMPD_REQ_GETUTID;
-
-  if (connection->database == NULL || connection->position == -1)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  /* Make sure we're in synch with the ordinary file.  */
-  if (synchronize_database (connection->database) < 0)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  if (internal_getut_r (connection, &request->id,
-                       &connection->last_entry) < 0)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  reply.errnum = 0;
-  reply.result = 0;
-  memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
-  return send_reply (connection, &reply.header);
-
-return_error:
-  memset (&reply.entry, 0, sizeof (struct utmp));
-  reply.errnum = errno;
-  reply.result = -1;
-  return send_reply (connection, &reply.header);
-}
-
-
-static int
-do_pututline (client_connection *connection)
-{
-  pututline_request *request;
-  pututline_reply reply;
-  struct utmp buffer;
-  int found;
-
-  request = (pututline_request *)connection->read_base;
-  if (request->header.size != sizeof (pututline_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
-
-  /* Initialize reply.  */
-  reply.header.version = UTMPD_VERSION;
-  reply.header.size = sizeof (pututline_reply);
-  reply.header.type = UTMPD_REQ_PUTUTLINE;
-
-  if (!(connection->access & W_OK))
-    {
-      errno = EPERM;
-      goto return_error;
-    }
-
-  if (connection->database == NULL || connection->position == -1)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  /* Make sure we're in synch with the ordinary file.  */
-  if (synchronize_database (connection->database) < 0)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  /* Find the correct place to insert the data.  */
-  if (connection->position > 0
-    && (
-#if _HAVE_UT_TYPE - 0
-       (connection->last_entry.ut_type == request->utmp.ut_type
-        && (connection->last_entry.ut_type == RUN_LVL
-            || connection->last_entry.ut_type == BOOT_TIME
-            || connection->last_entry.ut_type == OLD_TIME
-            || connection->last_entry.ut_type == NEW_TIME))
-       ||
-#endif
-       proc_utmp_eq (&connection->last_entry, &request->utmp)))
-    found = 1;
-  else
-    found = internal_getut_r (connection, &request->utmp, &buffer);
-
-  if (found < 0)
-    {
-      /* We append the next entry.  */
-      connection->position =
-       append_entry (connection->database, &request->utmp);
-      if (connection->position < 0)
-       goto return_error;
-    }
-  else
-    {
-      /* We replace the just read entry.  */
-      connection->position--;
-      if (write_entry (connection->database, connection->position,
-                      &request->utmp) < 0)
-       goto return_error;
-    }
-
-  /* Write the entry to the compatibility file.  */
-  write_old_entry (connection->database, connection->position, &request->utmp);
-
-  /* Update position pointer.  */
-  connection->position++;
-
-  reply.errnum = 0;
-  reply.result = 0;
-  return send_reply (connection, &reply.header);
-
-return_error:
-  reply.errnum = errno;
-  reply.result = -1;
-  return send_reply (connection, &reply.header);
-}
-
-
-static int
-do_updwtmp (client_connection *connection)
-{
-  updwtmp_request *request;
-  updwtmp_reply reply;
-  utmp_database *database;
-
-  request = (updwtmp_request *)connection->read_base;
-  if (request->header.size != sizeof (updwtmp_request))
-    {
-      warning (EINVAL, "invalid request size");
-      return -1;
-    }
-
-  /* Initialize reply.  */
-  reply.header.version = UTMPD_VERSION;
-  reply.header.size = sizeof (updwtmp_reply);
-  reply.header.type = UTMPD_REQ_UPDWTMP;
-
-  if (!(connection->access & W_OK))
-    {
-      errno = EPERM;
-      goto return_error;
-    }
-
-  /* Select database.  */
-  if (!strncmp (request->file, _PATH_UTMP, sizeof request->file))
-    database = utmp_db;
-  else
-    {
-      errno = EINVAL;
-      goto return_error;
-    }
-
-  /* Make sure we're in synch with the ordinary file.  */
-  if (synchronize_database (database) < 0)
-    {
-      errno = ESRCH;
-      goto return_error;
-    }
-
-  /* Append the entry.  */
-  if (append_entry (database, &request->utmp) < 0)
-    goto return_error;
-
-  reply.errnum = 0;
-  reply.result = 0;
-  return send_reply (connection, &reply.header);
-
-return_error:
-  reply.errnum = errno;
-  reply.result = -1;
-  return send_reply (connection, &reply.header);
-}
-
-
-/* This function is identical to the one in login/utmp_file.c.  */
-static int
-proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
-{
-  return
-    (
-#if _HAVE_UT_TYPE - 0
-     (entry->ut_type == INIT_PROCESS
-      || entry->ut_type == LOGIN_PROCESS
-      || entry->ut_type == USER_PROCESS
-      || entry->ut_type == DEAD_PROCESS)
-     &&
-     (match->ut_type == INIT_PROCESS
-      || match->ut_type == LOGIN_PROCESS
-      || match->ut_type == USER_PROCESS
-      || match->ut_type == DEAD_PROCESS)
-     &&
-#endif
-#if _HAVE_UT_ID - 0
-     strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
-#else
-     strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
-#endif
-     );
-}
-
-
-/* This function is derived from the one in login/utmp_file.c.  */
-static int
-internal_getut_r (client_connection *connection,
-                 const struct utmp *id, struct utmp *buffer)
-{
-#if _HAVE_UT_TYPE - 0
-  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_entry (connection->database, connection->position,
-                         buffer) < 0)
-           {
-             connection->position = -1;
-             return -1;
-           }
-         connection->position++;
-
-         if (id->ut_type == buffer->ut_type)
-           break;
-       }
-    }
-  else
-#endif /* _HAVE_UT_TYPE */
-    {
-      /* 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_entry (connection->database, connection->position,
-                         buffer) < 0)
-           {
-             connection->position = -1;
-             return -1;
-           }
-         connection->position++;
-
-         if (proc_utmp_eq (buffer, id))
-           break;
-       }
-    }
-
-  return 0;
-}
diff --git a/login/utmpd/utmpd-private.h b/login/utmpd/utmpd-private.h
deleted file mode 100644 (file)
index 4a9cdb9..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 _UTMPD_PRIVATE_H
-#define _UTMPD_PRIVATE_H       1
-
-#include <time.h>
-#include <utmp.h>
-
-
-/* The number of connections we allow.  */
-#ifndef MAX_CONNECTIONS
-#define MAX_CONNECTIONS        16
-#endif
-
-
-typedef struct utmp_database
-{
-  int fd;
-  int old_fd;
-  char *file;
-  char *old_file;
-  time_t mtime;
-} utmp_database;
-
-
-/* The databases we handle.  */
-extern utmp_database *utmp_db;
-extern utmp_database *wtmp_db;
-
-
-typedef struct client_connection
-{
-  int sock;
-  /* Access permissions.  */
-  int access;
-
-  /* Read pointer.  */
-  void *read_base;
-  void *read_ptr;
-  void *read_end;
-
-  /* Write buffer.  */
-  void *write_base;
-  void *write_ptr;
-  void *write_end;
-
-  /* Database to use for this connection.  */
-  utmp_database *database;
-  /* Position pointer.  */
-  int position;
-  
-  /* Last read entry.  */
-  struct utmp last_entry;
-
-  /* Pointers to the next and previous connections in the list.  */
-  struct client_connection *next;
-  struct client_connection *prev;
-} client_connection;
-
-
-/* This variable indicates if we have forked.  If set, we log messages
-   via the system logger.  Otherwise we simply print the program name
-   and the message to standard error.  */
-extern int forked;
-
-
-/* Database functions.  */
-utmp_database *open_database (const char *file, const char *old_file);
-int synchronize_database (utmp_database *database);
-void close_database (utmp_database *database);
-int read_entry (utmp_database *database, int position, struct utmp *entry);
-int write_entry (utmp_database *database, int position,
-                const struct utmp *entry);
-int append_entry (utmp_database *database, const struct utmp *entry);
-int read_old_entry (utmp_database *database, int position, struct utmp *entry);
-int write_old_entry (utmp_database *database, int position,
-                    const struct utmp *entry);
-
-/* Connection oriented functions.  */
-client_connection *accept_connection (int sock, int access);
-client_connection *find_connection (int sock);
-void close_connection (client_connection *connection);
-int read_data (client_connection *connection);
-int write_data (client_connection *connection);
-
-void error (int status, int errnum, const char *message, ...);
-void warning (int errnum, const char *message, ...);
-
-#endif /* utmpd-private.h  */
-
diff --git a/login/utmpd/utmpd.c b/login/utmpd/utmpd.c
deleted file mode 100644 (file)
index e112181..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 <getopt.h>
-#include <libintl.h>
-#include <pwd.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "utmpd.h"
-#include "utmpd-private.h"
-
-/* Get libc version number.  */
-#include "../../version.h"
-
-#define PACKAGE "libc"
-
-/* Long options.  */
-static const struct option long_options[] =
-{
-  { "debug", no_argument, NULL, 'd' },
-  { "help", no_argument, NULL, 'h' },
-  { "version", no_argument, NULL, 'V' },
-  { NULL, 0, NULL, 0}
-};
-
-/* The UTMP database.  */
-utmp_database *utmp_db;
-
-/* The socket for read only requests.  */
-int ro_sock = -1;
-
-/* The socket for read/write requests.  */
-int rw_sock = -1;
-
-
-/* Prototypes for the local functions.  */
-static void usage (int status) __attribute__ ((noreturn));
-static void drop_priviliges (void);
-static int make_socket (const char *name);
-static void handle_requests (void) __attribute__ ((noreturn));
-static void termination_handler (int signum);
-static int check_pid (const char *file);
-static int write_pid (const char *file);
-
-
-int
-main (int argc, char *argv[])
-{
-  mode_t mask;
-  int debug;
-  int do_help;
-  int do_version;
-  int opt;
-
-  /* Initialize local variables.  */
-  debug = 0;
-  do_help = 0;
-  do_version = 0;
-  
-  while ((opt = getopt_long (argc, argv, "dhV", long_options, NULL)) != -1)
-    switch (opt)
-      {
-      case '\0':               /* Long option.  */
-       break;
-      case 'h':
-       do_help = 1;
-       break;
-      case 'd':
-       debug = 1;
-       break;
-      case 'V':
-       do_version = 1;
-       break;
-      default:
-       usage (EXIT_FAILURE);
-      }
-
-  /* Version information is reequested.  */
-  if (do_version)
-    {
-      printf ("utmpd (GNU %s) %s\n", PACKAGE, VERSION);
-      printf (gettext ("\
-Copyright (C) %s Free Software Foundation, Inc.\n\
-This is free software; see the source for copying conditions.  There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "1997");
-      printf (gettext ("Written by %s.\n"), "Mark Kettenis");
-
-      exit (EXIT_SUCCESS);
-    }
-
-  /* Help is requested.  */
-  if (do_help)
-    usage (EXIT_SUCCESS);
-
-  signal (SIGINT, termination_handler);
-  signal (SIGTERM, termination_handler);
-
-  /* Check if we are already running.  */
-  if (check_pid (_PATH_UTMPDPID))
-    error (EXIT_FAILURE, 0, "already running");
-
-  /* Open UTMP database.  */
-  utmp_db = open_database (_PATH_UTMP "x", _PATH_UTMP);
-  if (utmp_db == NULL)
-    error (EXIT_FAILURE, errno, "%s", _PATH_UTMP);
-
-  /* Create sockets, with the right permissions.  */
-  mask = umask (S_IXUSR | S_IXGRP | S_IXOTH);
-  ro_sock = make_socket (_PATH_UTMPD_RO);
-  umask (S_IXUSR | S_IRWXG | S_IRWXO);
-  rw_sock = make_socket (_PATH_UTMPD_RW);
-  umask (mask);
-
-  /* Set the sockets up to accept connections.  */
-  if (listen (ro_sock, MAX_CONNECTIONS) < 0
-      || listen (rw_sock, MAX_CONNECTIONS) < 0)
-    error (EXIT_FAILURE, errno, "cannot enable socket to accept connections");
-
-  /* Behave like a daemon.  */
-  if (!debug)
-    {
-      openlog ("utmpd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
-      
-      if (daemon (0, 0) < 0)
-       error (EXIT_FAILURE, errno, "cannot auto-background");
-      forked = 1;
-
-      if (write_pid (_PATH_UTMPDPID) < 0)
-       warning (errno, "%s", _PATH_UTMPDPID);
-    }
-
-  /* Drop priviliges.  */
-  drop_priviliges ();
-  
-  /* Handle incoming requests.  */
-  handle_requests ();
-}
-
-
-/* Display usage information and exit.  */
-static void
-usage (int status)
-{
-  if (status != EXIT_SUCCESS)
-    fprintf (stderr, gettext ("Try `%s --help' for more information.\n"),
-            program_invocation_name);
-  else
-    {
-      printf (gettext ("\
-Usage: %s [OPTION]...\n\
-  -d, --debug           do not fork and display messages on the current tty\n\
-  -h, --help           display this help and exit\n\
-  -V, --version         output version information and exit\n"),
-             program_invocation_name);
-      fputs (gettext ("\
-Report bugs to <kettenis@phys.uva.nl>.\n"),
-            stdout);
-    }
-  
-  exit (status);
-}
-
-
-/* Drop priviliges.  */
-static void
-drop_priviliges (void)
-{
-  struct passwd *pw;
-
-  pw = getpwnam ("daemon");
-  if (pw)
-    {
-      seteuid (pw->pw_uid);
-      setegid (pw->pw_gid);
-    }
-}
-
-
-/* Make a socket in the file namespace using the filename NAME as the
-   socket's address.  */
-static int
-make_socket (const char *name)
-{
-  struct sockaddr_un addr;
-  size_t size;
-  int sock;
-
-  /* Create the socket.  */
-  sock = socket (PF_UNIX, SOCK_STREAM, 0);
-  if (sock < 0)
-    error (EXIT_FAILURE, errno, "cannot create socket");
-
-  /* Bind a name to the socket.  */
-  addr.sun_family = AF_UNIX;
-  strcpy (addr.sun_path, name);
-
-  /* The size of the address is the offset of the start
-     of the filename, plus its length, plus one for the
-     terminating null byte. */
-  size = (offsetof (struct sockaddr_un, sun_path)
-         + strlen (addr.sun_path));
-     
-  if (bind (sock, (struct sockaddr *) &addr, size) < 0)
-    error (EXIT_FAILURE, errno, "%s", name);
-     
-  return sock;
-}
-
-
-/* Hanlde incoming requests.  */
-static
-void handle_requests (void)
-{
-  client_connection *connection;
-  fd_set active_read_fd_set;
-  fd_set active_write_fd_set;
-  fd_set read_fd_set;
-  fd_set write_fd_set;
-  int fd;
-  
-  /* Initialize the set of active sockets.  */
-  FD_ZERO (&active_read_fd_set);
-  FD_ZERO (&active_write_fd_set);
-  FD_SET (rw_sock, &active_read_fd_set);
-  FD_SET (ro_sock, &active_read_fd_set);
-
-  while (1)
-    {
-      /* Block until input arrives on one or more active sockets.  */
-      read_fd_set = active_read_fd_set;
-      write_fd_set = active_write_fd_set;
-      if (select (FD_SETSIZE, &read_fd_set, &write_fd_set, NULL, NULL) < 0)
-       error (EXIT_FAILURE, errno, "cannot get input on sockets");
-
-      /* Service all the sockets with input pending.  */
-      for (fd = 0; fd < FD_SETSIZE; fd++)
-       {
-         if (FD_ISSET (fd, &read_fd_set))
-           {
-             if (fd == ro_sock || fd == rw_sock)
-               {
-                 int access = ((fd == rw_sock) ? (R_OK | W_OK) : R_OK);
-
-                 connection = accept_connection (fd, access);
-                 if (connection == NULL)
-                   error (0, errno, "cannot accept connection");
-
-                 FD_SET (connection->sock, &active_read_fd_set);
-               }
-             else
-               {
-                 connection = find_connection (fd);
-                 if (connection == NULL)
-                   error (EXIT_FAILURE, 0, "cannot find connection");
-
-                 if (read_data (connection) < 0)
-                   {
-                     close_connection (connection);
-                     FD_CLR (fd, &active_read_fd_set);
-                     FD_CLR (fd, &active_write_fd_set);
-                   }
-
-                 if (connection->write_ptr > connection->write_base)
-                     FD_SET (fd, &active_write_fd_set);
-               }
-           }
-         if (FD_ISSET (fd, &write_fd_set) &&
-             fd != rw_sock && fd != ro_sock)
-           {
-             connection = find_connection (fd);
-             if (connection == NULL)
-               error (EXIT_FAILURE, 0, "cannot find connection");
-
-             if (write_data (connection) < 0)
-               {
-                 close_connection (connection);
-                 FD_CLR (fd, &active_read_fd_set);
-                 FD_CLR (fd, &active_write_fd_set);
-               }
-
-             if (connection->write_ptr == connection->write_base)
-               FD_CLR (fd, &active_write_fd_set);
-           }
-       }       
-    }
-}
-
-
-/* Cleanup.  */
-static void
-termination_handler (int signum)
-{
-  /* Close sockets.  */
-  close (ro_sock);
-  close (rw_sock);
-
-  /* Restore user id.  */
-  seteuid (getuid ());
-  
-  /* Clean up the files created by `bind'.  */
-  unlink (_PATH_UTMPD_RO);
-  unlink (_PATH_UTMPD_RW);
-
-  if (utmp_db)
-    close_database (utmp_db);
-
-  /* Clean up pid file.  */
-  unlink (_PATH_UTMPDPID);
-  
-  exit (EXIT_SUCCESS);
-}
-
-
-/* Returns 1 if the process in pid file FILE is running, 0 if not.  */
-static int
-check_pid (const char *file)
-{
-  FILE *fp;
-  
-  fp = fopen (_PATH_UTMPDPID, "r");
-  if (fp)
-    {
-      pid_t pid;
-      
-      fscanf (fp, "%d", &pid);
-      fclose (fp);
-
-      if (kill (pid, 0) == 0)
-       return 1;
-    }
-
-  return 0;
-}
-
-/* Write the current process id to the file FILE.  Returns 0 if
-   successful, -1 if not.  */
-static int
-write_pid (const char *file)
-{
-  FILE *fp;
-  
-  fp = fopen (_PATH_UTMPDPID, "w");
-  if (fp == NULL)
-    return -1;
-  
-  fprintf (fp, "%d\n", getpid ());
-  if (ferror (fp))
-    return -1;
-  
-  fclose (fp);
-
-  return 0;
-}
-
diff --git a/login/utmpd/utmpd.h b/login/utmpd/utmpd.h
deleted file mode 100644 (file)
index 8fbc33c..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 _UTMPD_H
-#define _UTMPD_H               1
-
-/* This is an *internal* header.  */
-
-#include <limits.h>
-#include <stddef.h>
-#include <utmp.h>
-
-
-/* Paths to daemon sockets.  */
-#define _PATH_UTMPD_RO "/var/run/utmpd.ro"
-#define _PATH_UTMPD_RW "/var/run/utmpd.rw"
-
-
-/* Path to PID file.  */
-#define _PATH_UTMPDPID "/var/run/utmpd.pid"
-
-
-/* Version number of the daemon interface.  */
-#define UTMPD_VERSION  1
-
-
-/* Services provided.  */
-typedef enum
-{
-  UTMPD_REQ_SETUTENT,
-  UTMPD_REQ_GETUTENT,
-  UTMPD_REQ_ENDUTENT,
-  UTMPD_REQ_GETUTLINE,
-  UTMPD_REQ_GETUTID,
-  UTMPD_REQ_PUTUTLINE,
-  UTMPD_REQ_UPDWTMP
-} request_type;
-
-
-/* Header common to all requests.  */
-typedef struct
-{
-  /* Version number of the daemon interface.  */
-  int version;
-  /* Number of bytes in this request.  */
-  size_t size;
-  /* Service requested.  */
-  request_type type;
-} request_header;
-
-typedef struct
-{
-  request_header header;
-  /* File to use.  */
-  char file[_POSIX_PATH_MAX + 1];
-} setutent_request;
-
-typedef struct
-{
-  request_header header;
-} getutent_request, endutent_request;
-
-typedef struct
-{
-  request_header header;
-  /* Entry to match.  */
-  struct utmp line;
-} getutline_request;
-
-typedef struct
-{
-  request_header header;
-  /* Entry to match.  */
-  struct utmp id;
-} getutid_request;
-
-typedef struct
-{
-  request_header header;
-  /* Entry to write.  */
-  struct utmp utmp;
-} pututline_request;
-
-typedef struct
-{
-  request_header header;
-  /* File to use.  */
-  char file[_POSIX_PATH_MAX + 1];
-  /* Entry to write.  */
-  struct utmp utmp;
-} updwtmp_request;
-
-
-/* Header common to all replies.  */
-typedef struct
-{
-  /* Version number of the daemon interface.  */
-  int version;
-  /* Number of bytes in this reply.  */
-  size_t size;
-  /* Answer to the request.  */
-  request_type type;
-} reply_header;
-
-typedef struct
-{
-  reply_header header;
-  /* Error code.  */
-  int errnum;
-  /* Return value.  */
-  int result;
-} setutent_reply, endutent_reply, pututline_reply, updwtmp_reply;
-
-typedef struct
-{
-  reply_header header;
-  /* Found entry.  */
-  struct utmp entry;
-  /* Error code.  */
-  int errnum;
-  /* Return value.  */
-  int result;
-} getutent_reply, getutline_reply, getutid_reply;
-
-#endif /* utmpd.h  */
diff --git a/login/utmpd/xtmp.c b/login/utmpd/xtmp.c
deleted file mode 100644 (file)
index d2d5fee..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-
-#include "xtmp.h"
-
-/* Convert the entry XT to the new utmp format and store it in UT.
-   Fields in UT that were not present in the old utmp format are
-   initialized to zero.  */
-void
-xtmp_to_utmp (const struct xtmp *xtmp, struct utmp *utmp)
-{
-  memset (utmp, 0, sizeof (struct utmp));
-#if _HAVE_XT_TYPE - 0
-  utmp->ut_type = xtmp->xt_type;
-#endif
-#if _HAVE_XT_PID - 0
-  utmp->ut_pid = xtmp->xt_pid;
-#endif
-  strncpy (utmp->ut_line, xtmp->xt_line, XT_LINESIZE);
-#if _HAVE_XT_ID - 0
-  strncpy (utmp->ut_id, xtmp->xt_id, sizeof xtmp->xt_id);
-#endif
-  utmp->ut_time = xtmp->xt_time;
-  strncpy (utmp->ut_user, xtmp->xt_user, XT_NAMESIZE);
-#if _HAVE_XT_HOST - 0
-  strncpy (utmp->ut_host, xtmp->xt_host, XT_HOSTSIZE);
-#endif
-  utmp->ut_addr = xtmp->xt_addr;
-}
-
-/* Convert the entry UTMP to the old utmp format and store it in XTMP.  */
-void
-utmp_to_xtmp (const struct utmp *utmp, struct xtmp *xtmp)
-{
-  memset (xtmp, 0, sizeof (struct xtmp));
-#if _HAVE_XT_TYPE - 0
-  xtmp->xt_type = utmp->ut_type;
-#endif
-#if _HAVE_XT_PID - 0
-  xtmp->xt_pid = utmp->ut_pid;
-#endif
-  strncpy (xtmp->xt_line, utmp->ut_line, XT_LINESIZE);
-  xtmp->xt_line[XT_LINESIZE] = '\0';
-#if _HAVE_XT_ID - 0
-  strncpy (xtmp->xt_id, utmp->ut_id, sizeof xtmp->xt_id);
-#endif
-  xtmp->xt_time = utmp->ut_time;
-  strncpy (xtmp->xt_user, utmp->ut_user, XT_NAMESIZE);
-#if _HAVE_XT_HOST - 0
-  strncpy (xtmp->xt_host, utmp->ut_host, XT_HOSTSIZE);
-  xtmp->xt_host[XT_HOSTSIZE] = '\0';
-#endif
-  xtmp->xt_addr = utmp->ut_addr;
-}
-
-/* Compare an old style entry XTMP with a new style entry UTMP.  The
-   function returns 1 if the information that is in both old and new
-   style entries is identical.  Otherwise this function returns 0.  */
-int
-compare_entry (const struct utmp *xtmp, const struct utmp *utmp)
-{
-  return
-    (
-#if _HAVE_XT_TYPE - 0
-     xtmp->ut_type == utmp->ut_type
-#endif
-#if _HAVE_XT_PID - 0
-     && xtmp->ut_pid == utmp->ut_pid
-#endif
-     && !strncmp (xtmp->ut_line, utmp->ut_line, XT_LINESIZE - 1)
-#if _HAVE_XT_ID - 0
-     && !strncmp (xtmp->ut_id, utmp->ut_id, sizeof utmp->ut_id)
-#endif
-     && xtmp->ut_time == utmp->ut_time
-     && !strncmp (xtmp->ut_user, utmp->ut_user, XT_NAMESIZE)
-#if _HAVE_XT_HOST - 0
-     && !strncmp (xtmp->ut_host, utmp->ut_host, XT_HOSTSIZE - 1)
-#endif
-     && xtmp->ut_addr == utmp->ut_addr);
-}
diff --git a/login/utmpd/xtmp.h b/login/utmpd/xtmp.h
deleted file mode 100644 (file)
index 8fa982e..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* The `struct xtmp' type, describing the old linux utmp format.
-   Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 _XTMP_H
-#define _XTMP_H                1
-#include <features.h>
-
-#include <sys/time.h>
-#include <sys/types.h>
-
-
-#define XT_LINESIZE    12
-#define XT_NAMESIZE    8
-#define XT_HOSTSIZE    16
-
-struct xtmp
-{
-  short        int xt_type;            /* Type of login.  */
-  pid_t        xt_pid;                 /* Pid of login process.  */
-  char xt_line[XT_LINESIZE];   /* NUL-terminated devicename of tty.  */
-  char xt_id[4];               /* Inittab id.  */
-  time_t xt_time;              /* Time entry was made.  */
-  char xt_user[XT_NAMESIZE];   /* Username (not NUL terminated).  */
-  char xt_host[XT_HOSTSIZE];   /* Hostname for remote login.  */
-  long xt_addr;                /* Internet adress of remote host.  */
-};
-
-#define _HAVE_XT_TYPE  1
-#define _HAVE_XT_PID   1
-#define _HAVE_XT_ID    1
-#define _HAVE_XT_HOST  1
-
-
-extern void xtmp_to_utmp (const struct xtmp *xtmp, struct utmp *utmp);
-extern void utmp_to_xtmp (const struct utmp *utmp, struct xtmp *xtmp);
-extern int compare_entry (const struct utmp *xtmp,
-                         const struct utmp *utmp);
-
-#endif /* xtmp.h  */
diff --git a/login/utmpdump.c b/login/utmpdump.c
deleted file mode 100644 (file)
index e1422b5..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* utmpdump - dump utmp-like files.
-   Copyright (C) 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
-
-   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 <error.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-#include <utmp.h>
-
-void
-print_entry (struct utmp *up)
-{
-  printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-15.15s] [%ld]\n",
-         up->ut_type, up->ut_pid, up->ut_id, up->ut_user,
-         up->ut_line, 4 + ctime (&up->ut_time), up->ut_tv.tv_usec);
-}
-
-int
-main (int argc, char *argv[])
-{
-  struct utmp *up;
-
-  if (argc > 1)
-    utmpname (argv[1]);
-  
-  setutent ();
-
-  while ((up = getutent ()))
-    print_entry (up);
-
-  endutent ();
-  
-  return EXIT_SUCCESS;
-}