about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-11-30 06:56:27 +0000
committerUlrich Drepper <drepper@redhat.com>2008-11-30 06:56:27 +0000
commit37a6a271bf72e247047f1e4e9cf457e895d57dce (patch)
tree68bd421a535118a080c8b893ca5624dcfed6b556
parentbe4607eba89e85e3fd825e97e203f02cc3f31688 (diff)
downloadglibc-37a6a271bf72e247047f1e4e9cf457e895d57dce.tar.gz
glibc-37a6a271bf72e247047f1e4e9cf457e895d57dce.tar.xz
glibc-37a6a271bf72e247047f1e4e9cf457e895d57dce.zip
* login/utmp_file.c (file_writable): New variable.
	(setutent_file): Don't try to open file for writing.
	(pututline_file): Before writing, make descriptor writable if
	necessary.
-rw-r--r--ChangeLog7
-rw-r--r--login/utmp_file.c60
2 files changed, 58 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 4a6fc004d2..0aa3a5756b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2008-11-29  Ulrich Drepper  <drepper@redhat.com>
+
+	* login/utmp_file.c (file_writable): New variable.
+	(setutent_file): Don't try to open file for writing.
+	(pututline_file): Before writing, make descriptor writable if
+	necessary.
+
 2008-11-26  Ulrich Drepper  <drepper@redhat.com>
 
 	* sysdeps/posix/getaddrinfo.c (getaddrinfo): Only restrict search
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 9033f72a4e..fb5840242e 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -36,6 +36,7 @@
 
 /* Descriptor for the file and position.  */
 static int file_fd = -1;
+static bool file_writable;
 static off64_t file_offset;
 
 /* Cache for the last read entry.  */
@@ -138,7 +139,6 @@ setutent_file (void)
   if (file_fd < 0)
     {
       const char *file_name;
-      int result;
 
       file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name);
 
@@ -147,14 +147,10 @@ setutent_file (void)
 #else
 # define O_flags O_LARGEFILE
 #endif
-      file_fd = open_not_cancel_2 (file_name, O_RDWR | O_flags);
+      file_writable = false;
+      file_fd = open_not_cancel_2 (file_name, O_RDONLY | O_flags);
       if (file_fd == -1)
-	{
-	  /* Hhm, read-write access did not work.  Try read-only.  */
-	  file_fd = open_not_cancel_2 (file_name, O_RDONLY | O_flags);
-	  if (file_fd == -1)
-	    return 0;
-	}
+	return 0;
 
 #ifndef __ASSUME_O_CLOEXEC
 # ifdef O_CLOEXEC
@@ -162,7 +158,7 @@ setutent_file (void)
 # endif
 	{
 	  /* We have to make sure the file is `closed on exec'.  */
-	  result = fcntl_not_cancel (file_fd, F_GETFD, 0);
+	  int result = fcntl_not_cancel (file_fd, F_GETFD, 0);
 	  if (result >= 0)
 	    {
 # ifdef O_CLOEXEC
@@ -404,6 +400,52 @@ pututline_file (const struct utmp *data)
 
   assert (file_fd >= 0);
 
+  if (! file_writable)
+    {
+      /* We must make the file descriptor writable before going on.  */
+      const char *file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name);
+
+      int new_fd = open_not_cancel_2 (file_name, O_RDWR | O_flags);
+      if (new_fd == -1)
+	return NULL;
+
+#ifndef __ASSUME_O_CLOEXEC
+# ifdef O_CLOEXEC
+      if (__have_o_cloexec <= 0)
+# endif
+	{
+	  /* We have to make sure the file is `closed on exec'.  */
+	  int result = fcntl_not_cancel (file_fd, F_GETFD, 0);
+	  if (result >= 0)
+	    {
+# ifdef O_CLOEXEC
+	      if (__have_o_cloexec == 0)
+		__have_o_cloexec = (result & FD_CLOEXEC) ? 1 : -1;
+
+	      if (__have_o_cloexec < 0)
+# endif
+		result = fcntl_not_cancel (file_fd, F_SETFD,
+					   result | FD_CLOEXEC);
+	    }
+
+	  if (result == -1)
+	    {
+	      close_not_cancel_no_status (file_fd);
+	      return NULL;
+	    }
+	}
+#endif
+
+      if (__lseek64 (new_fd, __lseek64 (file_fd, 0, SEEK_CUR), SEEK_SET) == -1
+	  || dup2 (new_fd, file_fd) < 0)
+	{
+	  close_not_cancel_no_status (new_fd);
+	  return NULL;
+	}
+      close_not_cancel_no_status (new_fd);
+      file_writable = true;
+    }
+
   /* Find the correct place to insert the data.  */
   if (file_offset > 0
       && (