1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-02-23 20:08:04 +01:00

Avoid double-close in unusual dotlock situations.

* jnlib/dotlock.c (create_dotlock): Avoid double close due to EINTR.
--

close(2) says:

  close() should not be retried after an EINTR since this may cause a
  reused descriptor from another thread to be closed.

(backported from commit 628b111fa679612e23c0d46505b1ecbbf091897d)

Debian-Bug-Id: 773423
Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2015-02-12 18:26:58 +01:00
parent b2359db21c
commit f256bab03e

View File

@ -1,5 +1,5 @@
/* dotlock.c - dotfile locking /* dotlock.c - dotfile locking
* Copyright (C) 1998, 2000, 2001, 2003, 2004, * Copyright (C) 1998, 2000, 2001, 2003, 2004,
* 2005, 2006, 2008 Free Software Foundation, Inc. * 2005, 2006, 2008 Free Software Foundation, Inc.
* *
* This file is part of JNLIB. * This file is part of JNLIB.
@ -58,7 +58,7 @@
/* The object describing a lock. */ /* The object describing a lock. */
struct dotlock_handle struct dotlock_handle
{ {
struct dotlock_handle *next; struct dotlock_handle *next;
char *lockname; /* Name of the actual lockfile. */ char *lockname; /* Name of the actual lockfile. */
@ -109,7 +109,7 @@ disable_dotlock(void)
Calling this function with NULL does only install the atexit Calling this function with NULL does only install the atexit
handler and may thus be used to assure that the cleanup is called handler and may thus be used to assure that the cleanup is called
after all other atexit handlers. after all other atexit handlers.
This function creates a lock file in the same directory as This function creates a lock file in the same directory as
FILE_TO_LOCK using that name and a suffix of ".lock". Note that on FILE_TO_LOCK using that name and a suffix of ".lock". Note that on
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
@ -171,7 +171,7 @@ create_dotlock (const char *file_to_lock)
nodename = "unknown"; nodename = "unknown";
else else
nodename = utsbuf.nodename; nodename = utsbuf.nodename;
#ifdef __riscos__ #ifdef __riscos__
{ {
char *iter = (char *) nodename; char *iter = (char *) nodename;
@ -220,15 +220,15 @@ create_dotlock (const char *file_to_lock)
"%s/%d", nodename, (int)getpid () ); "%s/%d", nodename, (int)getpid () );
#endif /* __riscos__ */ #endif /* __riscos__ */
do do
{ {
errno = 0; errno = 0;
fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL, fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR ); S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
} }
while (fd == -1 && errno == EINTR); while (fd == -1 && errno == EINTR);
if ( fd == -1 ) if ( fd == -1 )
{ {
all_lockfiles = h->next; all_lockfiles = h->next;
log_error (_("failed to create temporary file `%s': %s\n"), log_error (_("failed to create temporary file `%s': %s\n"),
@ -244,7 +244,12 @@ create_dotlock (const char *file_to_lock)
if ( write (fd, "\n", 1 ) != 1 ) if ( write (fd, "\n", 1 ) != 1 )
goto write_failed; goto write_failed;
if ( close (fd) ) if ( close (fd) )
goto write_failed; {
if ( errno == EINTR )
fd = -1;
goto write_failed;
}
fd = -1;
# ifdef _REENTRANT # ifdef _REENTRANT
/* release mutex */ /* release mutex */
@ -267,7 +272,8 @@ create_dotlock (const char *file_to_lock)
/* fixme: release mutex */ /* fixme: release mutex */
# endif # endif
log_error ( _("error writing to `%s': %s\n"), h->tname, strerror(errno) ); log_error ( _("error writing to `%s': %s\n"), h->tname, strerror(errno) );
close (fd); if (fd != -1)
close (fd);
unlink (h->tname); unlink (h->tname);
jnlib_free (h->tname); jnlib_free (h->tname);
jnlib_free (h); jnlib_free (h);
@ -300,7 +306,7 @@ create_dotlock (const char *file_to_lock)
reasons why a lock file can't be created and thus the process reasons why a lock file can't be created and thus the process
would not stop as expected but spin til until Windows crashes. would not stop as expected but spin til until Windows crashes.
Our solution is to keep the lock file open; that does not Our solution is to keep the lock file open; that does not
harm. */ harm. */
h->lockhd = CreateFile (h->lockname, h->lockhd = CreateFile (h->lockname,
GENERIC_READ|GENERIC_WRITE, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
@ -339,7 +345,7 @@ destroy_dotlock ( DOTLOCK h )
h->next = NULL; h->next = NULL;
break; break;
} }
/* Then destroy the lock. */ /* Then destroy the lock. */
if (!h->disable) if (!h->disable)
{ {
@ -395,7 +401,7 @@ make_dotlock ( DOTLOCK h, long timeout )
if ( h->disable ) if ( h->disable )
return 0; /* Locks are completely disabled. Return success. */ return 0; /* Locks are completely disabled. Return success. */
if ( h->locked ) if ( h->locked )
{ {
#ifndef __riscos__ #ifndef __riscos__
log_debug ("Oops, `%s' is already locked\n", h->lockname); log_debug ("Oops, `%s' is already locked\n", h->lockname);
@ -419,19 +425,19 @@ make_dotlock ( DOTLOCK h, long timeout )
return -1; return -1;
} }
# else /* __riscos__ */ # else /* __riscos__ */
if ( !renamefile(h->tname, h->lockname) ) if ( !renamefile(h->tname, h->lockname) )
{ {
h->locked = 1; h->locked = 1;
return 0; /* okay */ return 0; /* okay */
} }
if ( errno != EEXIST ) if ( errno != EEXIST )
{ {
log_error( "lock not made: rename() failed: %s\n", strerror(errno) ); log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
return -1; return -1;
} }
# endif /* __riscos__ */ # endif /* __riscos__ */
if ( (pid = read_lockfile (h, &same_node)) == -1 ) if ( (pid = read_lockfile (h, &same_node)) == -1 )
{ {
if ( errno != ENOENT ) if ( errno != ENOENT )
{ {
@ -461,11 +467,11 @@ make_dotlock ( DOTLOCK h, long timeout )
# endif /* __riscos__ */ # endif /* __riscos__ */
} }
if ( timeout == -1 ) if ( timeout == -1 )
{ {
/* Wait until lock has been released. */ /* Wait until lock has been released. */
struct timeval tv; struct timeval tv;
log_info (_("waiting for lock (held by %d%s) %s...\n"), log_info (_("waiting for lock (held by %d%s) %s...\n"),
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):""); pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
@ -495,7 +501,7 @@ make_dotlock ( DOTLOCK h, long timeout )
return -1; return -1;
} }
if ( timeout == -1 ) if ( timeout == -1 )
{ {
/* Wait until lock has been released. */ /* Wait until lock has been released. */
log_info (_("waiting for lock %s...\n"), h->lockname); log_info (_("waiting for lock %s...\n"), h->lockname);
@ -545,7 +551,7 @@ release_dotlock( DOTLOCK h )
#else #else
pid = read_lockfile (h, &same_node); pid = read_lockfile (h, &same_node);
if ( pid == -1 ) if ( pid == -1 )
{ {
log_error( "release_dotlock: lockfile error\n"); log_error( "release_dotlock: lockfile error\n");
return -1; return -1;
@ -566,7 +572,7 @@ release_dotlock( DOTLOCK h )
/* Fixme: As an extra check we could check whether the link count is /* Fixme: As an extra check we could check whether the link count is
now really at 1. */ now really at 1. */
#else /* __riscos__ */ #else /* __riscos__ */
if ( renamefile (h->lockname, h->tname) ) if ( renamefile (h->lockname, h->tname) )
{ {
log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n", log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
h->lockname, h->tname); h->lockname, h->tname);
@ -594,7 +600,7 @@ read_lockfile (DOTLOCK h, int *same_node )
char *buffer, *p; char *buffer, *p;
size_t expected_len; size_t expected_len;
int res, nread; int res, nread;
*same_node = 0; *same_node = 0;
expected_len = 10 + 1 + h->nodename_len + 1; expected_len = 10 + 1 + h->nodename_len + 1;
if ( expected_len >= sizeof buffer_space) if ( expected_len >= sizeof buffer_space)
@ -627,7 +633,7 @@ read_lockfile (DOTLOCK h, int *same_node )
if (res < 0) if (res < 0)
{ {
log_info ("error reading lockfile `%s'", h->lockname ); log_info ("error reading lockfile `%s'", h->lockname );
close (fd); close (fd);
if (buffer != buffer_space) if (buffer != buffer_space)
jnlib_free (buffer); jnlib_free (buffer);
errno = 0; /* Do not return an inappropriate ERRNO. */ errno = 0; /* Do not return an inappropriate ERRNO. */
@ -651,7 +657,7 @@ read_lockfile (DOTLOCK h, int *same_node )
if (buffer[10] != '\n' if (buffer[10] != '\n'
|| (buffer[10] = 0, pid = atoi (buffer)) == -1 || (buffer[10] = 0, pid = atoi (buffer)) == -1
#ifndef __riscos__ #ifndef __riscos__
|| !pid || !pid
#else /* __riscos__ */ #else /* __riscos__ */
|| (!pid && riscos_getpid()) || (!pid && riscos_getpid())
#endif /* __riscos__ */ #endif /* __riscos__ */
@ -665,7 +671,7 @@ read_lockfile (DOTLOCK h, int *same_node )
} }
if (nread == expected_len if (nread == expected_len
&& !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len) && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
&& buffer[11+h->nodename_len] == '\n') && buffer[11+h->nodename_len] == '\n')
*same_node = 1; *same_node = 1;
@ -683,10 +689,10 @@ void
dotlock_remove_lockfiles() dotlock_remove_lockfiles()
{ {
DOTLOCK h, h2; DOTLOCK h, h2;
h = all_lockfiles; h = all_lockfiles;
all_lockfiles = NULL; all_lockfiles = NULL;
while ( h ) while ( h )
{ {
h2 = h->next; h2 = h->next;