Blame login/utmp_file.c

Packit 6c4009
/* Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>
Packit 6c4009
   and Paul Janzen <pcj@primenet.com>, 1996.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <signal.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <utmp.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
#include <kernel-features.h>
Packit 6c4009
#include <sigsetops.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
Packit 6c4009
#include "utmp-private.h"
Packit 6c4009
#include "utmp-equal.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Descriptor for the file and position.  */
Packit 6c4009
static int file_fd = -1;
Packit 6c4009
static bool file_writable;
Packit 6c4009
static off64_t file_offset;
Packit 6c4009
Packit 6c4009
/* Cache for the last read entry.  */
Packit 6c4009
static struct utmp last_entry;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Locking timeout.  */
Packit 6c4009
#ifndef TIMEOUT
Packit 6c4009
# define TIMEOUT 10
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Do-nothing handler for locking timeout.  */
Packit 6c4009
static void timeout_handler (int signum) {};
Packit 6c4009
Packit Service c8bedb
Packit Service c8bedb
/* try_file_lock (LOCKING, FD, TYPE) returns true if the locking
Packit Service c8bedb
   operation failed and recovery needs to be performed.
Packit Service c8bedb
Packit Service c8bedb
   file_unlock (FD) removes the lock (which must have been
Packit Service 42127a
   successfully acquired). */
Packit Service c8bedb
Packit Service c8bedb
static bool
Packit Service 42127a
try_file_lock (int fd, int type)
Packit Service c8bedb
{
Packit Service c8bedb
  /* Cancel any existing alarm.  */
Packit Service 42127a
  int old_timeout = alarm (0);
Packit Service c8bedb
Packit Service c8bedb
  /* Establish signal handler.  */
Packit Service 42127a
  struct sigaction old_action;
Packit Service c8bedb
  struct sigaction action;
Packit Service c8bedb
  action.sa_handler = timeout_handler;
Packit Service c8bedb
  __sigemptyset (&action.sa_mask);
Packit Service c8bedb
  action.sa_flags = 0;
Packit Service 42127a
  __sigaction (SIGALRM, &action, &old_action);
Packit Service c8bedb
Packit Service c8bedb
  alarm (TIMEOUT);
Packit Service c8bedb
Packit Service c8bedb
  /* Try to get the lock.  */
Packit Service 9d49ce
 struct flock64 fl =
Packit Service c8bedb
   {
Packit Service c8bedb
    .l_type = type,
Packit Service c8ab11
    .l_whence = SEEK_SET,
Packit Service c8bedb
   };
Packit Service 42127a
Packit Service 42127a
 bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
Packit Service 42127a
 int saved_errno = errno;
Packit Service 42127a
Packit Service 42127a
 /* Reset the signal handler and alarm.  We must reset the alarm
Packit Service 42127a
    before resetting the handler so our alarm does not generate a
Packit Service 42127a
    spurious SIGALRM seen by the user.  However, we cannot just set
Packit Service 42127a
    the user's old alarm before restoring the handler, because then
Packit Service 42127a
    it's possible our handler could catch the user alarm's SIGARLM and
Packit Service 42127a
    then the user would never see the signal he expected.  */
Packit Service 42127a
  alarm (0);
Packit Service 42127a
  __sigaction (SIGALRM, &old_action, NULL);
Packit Service 42127a
  if (old_timeout != 0)
Packit Service 42127a
    alarm (old_timeout);
Packit Service 42127a
Packit Service 42127a
  __set_errno (saved_errno);
Packit Service 42127a
  return status;
Packit Service c8bedb
}
Packit Service c8bedb
Packit Service c8bedb
static void
Packit Service c8bedb
file_unlock (int fd)
Packit Service c8bedb
{
Packit Service 9d49ce
  struct flock64 fl =
Packit Service c8bedb
    {
Packit Service c8bedb
      .l_type = F_UNLCK,
Packit Service c8bedb
    };
Packit Service c8bedb
  __fcntl64_nocancel (fd, F_SETLKW, &fl);
Packit Service c8bedb
}
Packit Service c8bedb
Packit 6c4009
#ifndef TRANSFORM_UTMP_FILE_NAME
Packit 6c4009
# define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
Packit 6c4009
#endif
Packit 6c4009
Packit Service 9c1ddb
int
Packit Service 9c1ddb
__libc_setutent (void)
Packit 6c4009
{
Packit 6c4009
  if (file_fd < 0)
Packit 6c4009
    {
Packit 6c4009
      const char *file_name;
Packit 6c4009
Packit 6c4009
      file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name);
Packit 6c4009
Packit 6c4009
      file_writable = false;
Packit 6c4009
      file_fd = __open_nocancel
Packit 6c4009
	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
Packit 6c4009
      if (file_fd == -1)
Packit 6c4009
	return 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __lseek64 (file_fd, 0, SEEK_SET);
Packit 6c4009
  file_offset = 0;
Packit 6c4009
Packit Service 93dc7a
  /* Make sure the entry won't match.  */
Packit Service 93dc7a
  last_entry.ut_type = -1;
Packit Service 93dc7a
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit Service 9c1ddb
/* Preform initialization if necessary.  */
Packit Service 9c1ddb
static bool
Packit Service 9c1ddb
maybe_setutent (void)
Packit Service 9c1ddb
{
Packit Service 9c1ddb
  return file_fd >= 0 || __libc_setutent ();
Packit Service 9c1ddb
}
Packit 6c4009
Packit Service 9c1ddb
int
Packit Service 9c1ddb
__libc_getutent_r (struct utmp *buffer, struct utmp **result)
Packit a1b262
{
Packit Service 93dc7a
  ssize_t nbytes;
Packit a1b262
Packit Service 9c1ddb
  if (!maybe_setutent () || file_offset == -1l)
Packit 6c4009
    {
Packit 6c4009
      /* Not available.  */
Packit 6c4009
      *result = NULL;
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit Service 42127a
  if (try_file_lock (file_fd, F_RDLCK))
Packit Service c8bedb
    nbytes = 0;
Packit Service c8bedb
  else
Packit Service 93dc7a
    {
Packit Service c8bedb
      /* Read the next entry.  */
Packit Service c8bedb
      nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp));
Packit Service c8bedb
      file_unlock (file_fd);
Packit Service 93dc7a
    }
Packit Service 93dc7a
Packit Service 93dc7a
  if (nbytes != sizeof (struct utmp))
Packit 6c4009
    {
Packit Service 93dc7a
      if (nbytes != 0)
Packit Service 93dc7a
	file_offset = -1l;
Packit 6c4009
      *result = NULL;
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit Service 93dc7a
  /* Update position pointer.  */
Packit Service 93dc7a
  file_offset += sizeof (struct utmp);
Packit Service 93dc7a
Packit 6c4009
  memcpy (buffer, &last_entry, sizeof (struct utmp));
Packit 6c4009
  *result = buffer;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit Service 1e51d9
/* Search for *ID, updating last_entry and file_offset.  Return 0 on
Packit Service 4b3385
   success and -1 on failure.  Does not perform locking; for that see
Packit Service 4b3385
   internal_getut_r below.  */
Packit 6c4009
static int
Packit Service 4b3385
internal_getut_nolock (const struct utmp *id)
Packit 6c4009
{
Packit Service 93dc7a
  if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
Packit Service 93dc7a
      || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
Packit 6c4009
    {
Packit Service 93dc7a
      /* Search for next entry with type RUN_LVL, BOOT_TIME,
Packit Service 93dc7a
	 OLD_TIME, or NEW_TIME.  */
Packit Service 93dc7a
Packit Service 93dc7a
      while (1)
Packit 6c4009
	{
Packit Service 93dc7a
	  /* Read the next entry.  */
Packit Service 1e51d9
	  if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
Packit Service 93dc7a
	      != sizeof (struct utmp))
Packit Service 93dc7a
	    {
Packit Service 93dc7a
	      __set_errno (ESRCH);
Packit Service 93dc7a
	      file_offset = -1l;
Packit Service 4b3385
	      return -1;
Packit Service 93dc7a
	    }
Packit Service 93dc7a
	  file_offset += sizeof (struct utmp);
Packit Service 93dc7a
Packit Service 1e51d9
	  if (id->ut_type == last_entry.ut_type)
Packit Service 93dc7a
	    break;
Packit 6c4009
	}
Packit Service 93dc7a
    }
Packit Service 93dc7a
  else
Packit Service 93dc7a
    {
Packit Service 93dc7a
      /* Search for the next entry with the specified ID and with type
Packit Service 93dc7a
	 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS.  */
Packit 6c4009
Packit Service 93dc7a
      while (1)
Packit Service 93dc7a
	{
Packit Service 93dc7a
	  /* Read the next entry.  */
Packit Service 1e51d9
	  if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
Packit Service 93dc7a
	      != sizeof (struct utmp))
Packit Service 93dc7a
	    {
Packit Service 93dc7a
	      __set_errno (ESRCH);
Packit Service 93dc7a
	      file_offset = -1l;
Packit Service 4b3385
	      return -1;
Packit Service 93dc7a
	    }
Packit Service 93dc7a
	  file_offset += sizeof (struct utmp);
Packit Service 93dc7a
Packit Service 1e51d9
	  if (__utmp_equal (&last_entry, id))
Packit Service 93dc7a
	    break;
Packit Service 93dc7a
	}
Packit 6c4009
    }
Packit 6c4009
Packit Service 4b3385
  return 0;
Packit Service 4b3385
}
Packit 6c4009
Packit Service 4b3385
/* Search for *ID, updating last_entry and file_offset.  Return 0 on
Packit Service 4b3385
   success and -1 on failure.  If the locking operation failed, write
Packit Service 4b3385
   true to *LOCK_FAILED.  */
Packit Service 4b3385
static int
Packit Service 4b3385
internal_getut_r (const struct utmp *id, bool *lock_failed)
Packit Service 4b3385
{
Packit Service 4b3385
  if (try_file_lock (file_fd, F_RDLCK))
Packit Service 4b3385
    {
Packit Service 4b3385
      *lock_failed = true;
Packit Service 4b3385
      return -1;
Packit Service 4b3385
    }
Packit 6c4009
Packit Service 4b3385
  int result = internal_getut_nolock (id);
Packit Service 4b3385
  file_unlock (file_fd);
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* For implementing this function we don't use the getutent_r function
Packit 6c4009
   because we can avoid the reposition on every new entry this way.  */
Packit Service 9c1ddb
int
Packit Service 9c1ddb
__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
Packit Service 9c1ddb
		  struct utmp **result)
Packit 6c4009
{
Packit Service 9c1ddb
  if (!maybe_setutent () || file_offset == -1l)
Packit 6c4009
    {
Packit 6c4009
      *result = NULL;
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We don't have to distinguish whether we can lock the file or
Packit 6c4009
     whether there is no entry.  */
Packit 6c4009
  bool lock_failed = false;
Packit Service 1e51d9
  if (internal_getut_r (id, &lock_failed) < 0)
Packit 6c4009
    {
Packit 6c4009
      *result = NULL;
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  memcpy (buffer, &last_entry, sizeof (struct utmp));
Packit 6c4009
  *result = buffer;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* For implementing this function we don't use the getutent_r function
Packit 6c4009
   because we can avoid the reposition on every new entry this way.  */
Packit Service 9c1ddb
int
Packit Service 9c1ddb
__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
Packit Service 9c1ddb
		    struct utmp **result)
Packit 6c4009
{
Packit Service 9c1ddb
  if (!maybe_setutent () || file_offset == -1l)
Packit 6c4009
    {
Packit 6c4009
      *result = NULL;
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit Service 42127a
  if (try_file_lock (file_fd, F_RDLCK))
Packit 6c4009
    {
Packit 6c4009
      *result = NULL;
Packit Service c8bedb
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit Service 93dc7a
      /* Read the next entry.  */
Packit Service 93dc7a
      if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
Packit Service 93dc7a
	  != sizeof (struct utmp))
Packit 6c4009
	{
Packit 6c4009
	  __set_errno (ESRCH);
Packit Service 93dc7a
	  file_offset = -1l;
Packit 6c4009
	  *result = NULL;
Packit Service 93dc7a
	  goto unlock_return;
Packit 6c4009
	}
Packit Service 93dc7a
      file_offset += sizeof (struct utmp);
Packit 6c4009
Packit 6c4009
      /* Stop if we found a user or login entry.  */
Packit Service 2df192
      if ((last_entry.ut_type == USER_PROCESS
Packit 6c4009
	   || last_entry.ut_type == LOGIN_PROCESS)
Packit Service 2df192
	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
Packit Service 2df192
	      == 0))
Packit 6c4009
	break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  memcpy (buffer, &last_entry, sizeof (struct utmp));
Packit 6c4009
  *result = buffer;
Packit 6c4009
Packit Service 93dc7a
unlock_return:
Packit Service c8bedb
  file_unlock (file_fd);
Packit Service 93dc7a
Packit Service 93dc7a
  return ((*result == NULL) ? -1 : 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit Service 9c1ddb
struct utmp *
Packit Service 9c1ddb
__libc_pututline (const struct utmp *data)
Packit 6c4009
{
Packit Service 1e51d9
  if (!maybe_setutent () || file_offset == -1l)
Packit Service 9c1ddb
    return NULL;
Packit Service 9c1ddb
Packit 6c4009
  struct utmp *pbuf;
Packit Service 93dc7a
Packit 6c4009
  if (! file_writable)
Packit 6c4009
    {
Packit 6c4009
      /* We must make the file descriptor writable before going on.  */
Packit 6c4009
      const char *file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name);
Packit 6c4009
Packit 6c4009
      int new_fd = __open_nocancel
Packit 6c4009
	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
Packit 6c4009
      if (new_fd == -1)
Packit 6c4009
	return NULL;
Packit 6c4009
Packit Service 93dc7a
      if (__lseek64 (new_fd, __lseek64 (file_fd, 0, SEEK_CUR), SEEK_SET) == -1
Packit Service 93dc7a
	  || __dup2 (new_fd, file_fd) < 0)
Packit 6c4009
	{
Packit 6c4009
	  __close_nocancel_nostatus (new_fd);
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
      __close_nocancel_nostatus (new_fd);
Packit 6c4009
      file_writable = true;
Packit 6c4009
    }
Packit 6c4009
Packit Service 4b3385
  /* Exclude other writers before validating the cache.  */
Packit Service 4b3385
  if (try_file_lock (file_fd, F_WRLCK))
Packit Service 4b3385
    return NULL;
Packit Service 4b3385
Packit 6c4009
  /* Find the correct place to insert the data.  */
Packit Service 4b3385
  bool found = false;
Packit Service 93dc7a
  if (file_offset > 0
Packit Service 2df192
      && ((last_entry.ut_type == data->ut_type
Packit Service 93dc7a
	   && (last_entry.ut_type == RUN_LVL
Packit Service 93dc7a
	       || last_entry.ut_type == BOOT_TIME
Packit Service 93dc7a
	       || last_entry.ut_type == OLD_TIME
Packit Service 93dc7a
	       || last_entry.ut_type == NEW_TIME))
Packit Service 2df192
	  || __utmp_equal (&last_entry, data)))
Packit 6c4009
    {
Packit Service 4b3385
      if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0)
Packit 6c4009
	{
Packit Service 4b3385
	  file_unlock (file_fd);
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit Service 4b3385
      if (__read_nocancel (file_fd, &last_entry, sizeof (last_entry))
Packit Service 4b3385
	  != sizeof (last_entry))
Packit Service 4b3385
	{
Packit Service 4b3385
	  if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0)
Packit Service 4b3385
	    {
Packit Service 4b3385
	      file_unlock (file_fd);
Packit Service 4b3385
	      return NULL;
Packit Service 4b3385
	    }
Packit Service 4b3385
	  found = false;
Packit Service 4b3385
	}
Packit Service 4b3385
      else
Packit Service 4b3385
	found = __utmp_equal (&last_entry, data);
Packit 6c4009
    }
Packit 6c4009
Packit Service 4b3385
  if (!found)
Packit Service 4b3385
    found = internal_getut_nolock (data) >= 0;
Packit 6c4009
Packit Service 4b3385
  if (!found)
Packit 6c4009
    {
Packit 6c4009
      /* We append the next entry.  */
Packit Service 93dc7a
      file_offset = __lseek64 (file_fd, 0, SEEK_END);
Packit Service 93dc7a
      if (file_offset % sizeof (struct utmp) != 0)
Packit Service 93dc7a
	{
Packit Service 93dc7a
	  file_offset -= file_offset % sizeof (struct utmp);
Packit Service 93dc7a
	  __ftruncate64 (file_fd, file_offset);
Packit Service 93dc7a
Packit Service 93dc7a
	  if (__lseek64 (file_fd, 0, SEEK_END) < 0)
Packit Service 93dc7a
	    {
Packit Service 93dc7a
	      pbuf = NULL;
Packit Service 93dc7a
	      goto unlock_return;
Packit Service 93dc7a
	    }
Packit Service 93dc7a
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit Service 93dc7a
      /* We replace the just read entry.  */
Packit Service 93dc7a
      file_offset -= sizeof (struct utmp);
Packit Service 93dc7a
      __lseek64 (file_fd, file_offset, SEEK_SET);
Packit 6c4009
    }
Packit 6c4009
Packit Service 93dc7a
  /* Write the new data.  */
Packit Service 93dc7a
  if (__write_nocancel (file_fd, data, sizeof (struct utmp))
Packit Service 93dc7a
      != sizeof (struct utmp))
Packit 6c4009
    {
Packit 6c4009
      /* If we appended a new record this is only partially written.
Packit 6c4009
	 Remove it.  */
Packit Service 4b3385
      if (!found)
Packit Service 93dc7a
	(void) __ftruncate64 (file_fd, file_offset);
Packit Service 93dc7a
      pbuf = NULL;
Packit Service 93dc7a
    }
Packit Service 93dc7a
  else
Packit Service 93dc7a
    {
Packit Service 93dc7a
      file_offset += sizeof (struct utmp);
Packit Service 93dc7a
      pbuf = (struct utmp *) data;
Packit 6c4009
    }
Packit 6c4009
Packit Service 93dc7a
 unlock_return:
Packit Service c8bedb
  file_unlock (file_fd);
Packit 6c4009
Packit 6c4009
  return pbuf;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit Service 9c1ddb
void
Packit Service 9c1ddb
__libc_endutent (void)
Packit 6c4009
{
Packit Service 9c1ddb
  if (file_fd >= 0)
Packit Service 9c1ddb
    {
Packit Service 9c1ddb
      __close_nocancel_nostatus (file_fd);
Packit Service 9c1ddb
      file_fd = -1;
Packit Service 9c1ddb
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit Service 9c1ddb
int
Packit Service 9c1ddb
__libc_updwtmp (const char *file, const struct utmp *utmp)
Packit 6c4009
{
Packit 6c4009
  int result = -1;
Packit 6c4009
  off64_t offset;
Packit 6c4009
  int fd;
Packit 6c4009
Packit 6c4009
  /* Open WTMP file.  */
Packit 6c4009
  fd = __open_nocancel (file, O_WRONLY | O_LARGEFILE);
Packit 6c4009
  if (fd < 0)
Packit 6c4009
    return -1;
Packit 6c4009
Packit Service 42127a
  if (try_file_lock (fd, F_WRLCK))
Packit Service c8bedb
    {
Packit Service c8bedb
      __close_nocancel_nostatus (fd);
Packit Service c8bedb
      return -1;
Packit Service c8bedb
    }
Packit 6c4009
Packit 6c4009
  /* Remember original size of log file.  */
Packit 6c4009
  offset = __lseek64 (fd, 0, SEEK_END);
Packit 6c4009
  if (offset % sizeof (struct utmp) != 0)
Packit 6c4009
    {
Packit 6c4009
      offset -= offset % sizeof (struct utmp);
Packit 6c4009
      __ftruncate64 (fd, offset);
Packit 6c4009
Packit 6c4009
      if (__lseek64 (fd, 0, SEEK_END) < 0)
Packit 6c4009
	goto unlock_return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Write the entry.  If we can't write all the bytes, reset the file
Packit 6c4009
     size back to the original size.  That way, no partial entries
Packit 6c4009
     will remain.  */
Packit 6c4009
  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
Packit 6c4009
      != sizeof (struct utmp))
Packit 6c4009
    {
Packit 6c4009
      __ftruncate64 (fd, offset);
Packit 6c4009
      goto unlock_return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  result = 0;
Packit 6c4009
Packit 6c4009
unlock_return:
Packit Service 94eefb
  file_unlock (fd);
Packit 6c4009
Packit 6c4009
  /* Close WTMP file.  */
Packit 6c4009
  __close_nocancel_nostatus (fd);
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}