about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--login/pututline_r.c60
1 files changed, 35 insertions, 25 deletions
diff --git a/login/pututline_r.c b/login/pututline_r.c
index 62fc83bd58..4fffbb7b38 100644
--- a/login/pututline_r.c
+++ b/login/pututline_r.c
@@ -60,7 +60,8 @@ pututline_r (const struct utmp *id, struct utmp_data *utmp_data)
 
 #if _HAVE_UT_TYPE - 0
   /* Seek position to write.  */
-  if (utmp_data->ubuf.ut_type != id->ut_type)
+  if (utmp_data->loc_utmp >= sizeof (utmp)
+      && utmp_data->ubuf.ut_type != id->ut_type)
     {
       /* We must not overwrite the data in UTMP_DATA.  */
       struct utmp_data *data_tmp = alloca (sizeof (*data_tmp));
@@ -82,16 +83,6 @@ pututline_r (const struct utmp *id, struct utmp_data *utmp_data)
     }
 #endif
 
-  /* Find out how large the file is.  */
-  if (fstat (utmp_data->ut_fd, &st) < 0)
-    return -1;
-
-  /* Position file correctly.  */
-  if (utmp_data->loc_utmp <= st.st_size
-      && lseek (utmp_data->ut_fd, utmp_data->loc_utmp - sizeof (struct utmp),
-		SEEK_SET) < 0)
-    return -1;
-
   /* Try to lock the file.  */
   if (flock (utmp_data->ut_fd, LOCK_EX | LOCK_NB) < 0 && errno != ENOSYS)
     {
@@ -102,20 +93,39 @@ pututline_r (const struct utmp *id, struct utmp_data *utmp_data)
       (void) flock (utmp_data->ut_fd, LOCK_EX | LOCK_NB);
     }
 
-  /* Write the new data.  */
-  if (write (utmp_data->ut_fd, id, sizeof (struct utmp))
-      != sizeof (struct utmp))
-    {
-      /* If we appended a new record this is only partially written.
-	 Remove it.  */
-      if (utmp_data->loc_utmp > st.st_size)
-	{
-	  (void) ftruncate (utmp_data->ut_fd, st.st_size);
-	  utmp_data->loc_utmp = st.st_size;
-	}
-
-      result = -1;
-    }
+  /* Find out how large the file is.  */
+  result = fstat (utmp_data->ut_fd, &st);
+
+  if (result == 0)
+    /* Position file correctly.  */
+    if (utmp_data->loc_utmp < sizeof (struct utmp))
+      /* Not located at any valid entry.  Add at the end.  */
+      {
+	result = lseek (utmp_data->ut_fd, 0L, SEEK_END);
+	if (result == 0)
+	  /* Where we'll be if the write succeeds.  */
+	  utmp_data->loc_utmp = st.st_size + sizeof (struct utmp);
+      }
+    else if (utmp_data->loc_utmp <= st.st_size)
+      result =
+	lseek (utmp_data->ut_fd, utmp_data->loc_utmp - sizeof (struct utmp),
+	       SEEK_SET);
+
+  if (result == 0)
+    /* Write the new data.  */
+    if (write (utmp_data->ut_fd, id, sizeof (struct utmp))
+	!= sizeof (struct utmp))
+      {
+	/* If we appended a new record this is only partially written.
+	   Remove it.  */
+	if (utmp_data->loc_utmp > st.st_size)
+	  {
+	    (void) ftruncate (utmp_data->ut_fd, st.st_size);
+	    utmp_data->loc_utmp = st.st_size;
+	  }
+
+	result = -1;
+      }
 
   /* And unlock the file.  */
   (void) flock (utmp_data->ut_fd, LOCK_UN);