1 /* dotlock.c - dotfile locking
2 * Copyright (C) 1998, 2000, 2001, 2003, 2004,
3 * 2005, 2006, 2008 Free Software Foundation, Inc.
5 * This file is part of JNLIB.
7 * JNLIB is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 3 of
10 * the License, or (at your option) any later version.
12 * JNLIB is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
28 #ifdef HAVE_DOSISH_SYSTEM
29 # define WIN32_LEAN_AND_MEAN
32 # include <sys/utsname.h>
34 #include <sys/types.h>
40 #include "libjnlib-config.h"
41 #include "stringhelp.h"
44 #if !defined(DIRSEP_C) && !defined(EXTSEP_C) \
45 && !defined(DIRSEP_S) && !defined(EXTSEP_S)
46 #ifdef HAVE_DOSISH_SYSTEM
60 /* The object describing a lock. */
63 struct dotlock_handle
*next
;
64 char *lockname
; /* Name of the actual lockfile. */
65 int locked
; /* Lock status. */
66 int disable
; /* If true, locking is disabled. */
68 #ifdef HAVE_DOSISH_SYSTEM
69 HANDLE lockhd
; /* The W32 handle of the lock file. */
71 char *tname
; /* Name of the lockfile template. */
72 size_t nodename_off
; /* Offset in TNAME of the nodename part. */
73 size_t nodename_len
; /* Length of the nodename part. */
74 #endif /* HAVE_DOSISH_SYSTEM */
78 /* A list of of all lock handles. */
79 static volatile DOTLOCK all_lockfiles
;
81 /* If this has the value true all locking is disabled. */
82 static int never_lock
;
85 /* Local protototypes. */
86 #ifndef HAVE_DOSISH_SYSTEM
87 static int read_lockfile (DOTLOCK h
, int *same_node
);
88 #endif /*!HAVE_DOSISH_SYSTEM*/
93 /* Entirely disable all locking. This function should be called
94 before any locking is done. It may be called right at startup of
95 the process as it only sets a global value. */
104 /* Create a lockfile for a file name FILE_TO_LOCK and returns an
105 object of type DOTLOCK which may be used later to actually acquire
106 the lock. A cleanup routine gets installed to cleanup left over
107 locks or other files used internally by the lock mechanism.
109 Calling this function with NULL does only install the atexit
110 handler and may thus be used to assure that the cleanup is called
111 after all other atexit handlers.
113 This function creates a lock file in the same directory as
114 FILE_TO_LOCK using that name and a suffix of ".lock". Note that on
115 POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
118 The function returns an new handle which needs to be released using
119 destroy_dotlock but gets also released at the termination of the
120 process. On error NULL is returned.
123 create_dotlock (const char *file_to_lock
)
125 static int initialized
;
127 #ifndef HAVE_DOSISH_SYSTEM
130 const char *nodename
;
133 struct utsname utsbuf
;
139 atexit (dotlock_remove_lockfiles
);
144 return NULL
; /* Only initialization was requested. */
146 h
= jnlib_calloc (1, sizeof *h
);
154 /* fixme: aquire mutex on all_lockfiles */
156 h
->next
= all_lockfiles
;
161 #ifndef HAVE_DOSISH_SYSTEM
163 This is the POSIX version which uses a temporary file and the
164 link system call to make locking an atomic operation.
167 snprintf (pidstr
, sizeof pidstr
, "%10d\n", (int)getpid() );
168 /* fixme: add the hostname to the second line (FQDN or IP addr?) */
170 /* Create a temporary file. */
171 if ( uname ( &utsbuf
) )
172 nodename
= "unknown";
174 nodename
= utsbuf
.nodename
;
178 char *iter
= (char *) nodename
;
179 for (; iter
[0]; iter
++)
183 #endif /* __riscos__ */
185 if ( !(dirpart
= strrchr (file_to_lock
, DIRSEP_C
)) )
192 dirpartlen
= dirpart
- file_to_lock
;
193 dirpart
= file_to_lock
;
197 /* fixme: aquire mutex on all_lockfiles */
199 h
->next
= all_lockfiles
;
202 tnamelen
= dirpartlen
+ 6 + 30 + strlen(nodename
) + 10;
203 h
->tname
= jnlib_malloc (tnamelen
+ 1);
206 all_lockfiles
= h
->next
;
210 h
->nodename_len
= strlen (nodename
);
213 snprintf (h
->tname
, tnamelen
, "%.*s/.#lk%p.", dirpartlen
, dirpart
, h
);
214 h
->nodename_off
= strlen (h
->tname
);
215 snprintf (h
->tname
+h
->nodename_off
, tnamelen
- h
->nodename_off
,
216 "%s.%d", nodename
, (int)getpid ());
217 #else /* __riscos__ */
218 snprintf (h
->tname
, tnamelen
, "%.*s.lk%p/", dirpartlen
, dirpart
, h
);
219 h
->nodename_off
= strlen (h
->tname
);
220 snprintf (h
->tname
+h
->nodename_off
, tnamelen
- h
->modename_off
,
221 "%s/%d", nodename
, (int)getpid () );
222 #endif /* __riscos__ */
227 fd
= open (h
->tname
, O_WRONLY
|O_CREAT
|O_EXCL
,
228 S_IRUSR
|S_IRGRP
|S_IROTH
|S_IWUSR
);
230 while (fd
== -1 && errno
== EINTR
);
234 all_lockfiles
= h
->next
;
235 log_error (_("failed to create temporary file `%s': %s\n"),
236 h
->tname
, strerror(errno
));
237 jnlib_free (h
->tname
);
241 if ( write (fd
, pidstr
, 11 ) != 11 )
243 if ( write (fd
, nodename
, strlen (nodename
) ) != strlen (nodename
) )
245 if ( write (fd
, "\n", 1 ) != 1 )
253 h
->lockname
= jnlib_malloc ( strlen (file_to_lock
) + 6 );
256 all_lockfiles
= h
->next
;
258 jnlib_free (h
->tname
);
262 strcpy (stpcpy (h
->lockname
, file_to_lock
), EXTSEP_S
"lock");
266 all_lockfiles
= h
->next
;
268 /* fixme: release mutex */
270 log_error ( _("error writing to `%s': %s\n"), h
->tname
, strerror(errno
) );
273 jnlib_free (h
->tname
);
277 #else /* HAVE_DOSISH_SYSTEM */
279 /* The Windows version does not need a temporary file but uses the
280 plain lock file along with record locking. We create this file
281 here so that we later do only need to do the file locking. For
282 error reporting it is useful to keep the name of the file in the
284 h
->next
= all_lockfiles
;
287 h
->lockname
= jnlib_malloc ( strlen (file_to_lock
) + 6 );
290 all_lockfiles
= h
->next
;
294 strcpy (stpcpy(h
->lockname
, file_to_lock
), EXTSEP_S
"lock");
296 /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
297 along with FILE_SHARE_DELETE but that does not work due to a race
298 condition: Despite the OPEN_ALWAYS flag CreateFile may return an
299 error and we can't reliable create/open the lock file unless we
300 would wait here until it works - however there are other valid
301 reasons why a lock file can't be created and thus the process
302 would not stop as expected but spin til until Windows crashes.
303 Our solution is to keep the lock file open; that does not
305 h
->lockhd
= CreateFile (h
->lockname
,
306 GENERIC_READ
|GENERIC_WRITE
,
307 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
308 NULL
, OPEN_ALWAYS
, 0, NULL
);
309 if (h
->lockhd
== INVALID_HANDLE_VALUE
)
311 log_error (_("can't create `%s': %s\n"), h
->lockname
, w32_strerror (-1));
312 all_lockfiles
= h
->next
;
313 jnlib_free (h
->lockname
);
319 #endif /* HAVE_DOSISH_SYSTEM */
323 /* Destroy the local handle H and release the lock. */
325 destroy_dotlock ( DOTLOCK h
)
332 /* First remove the handle from our global list of all locks. */
333 for (hprev
=NULL
, htmp
=all_lockfiles
; htmp
; hprev
=htmp
, htmp
=htmp
->next
)
337 hprev
->next
= htmp
->next
;
339 all_lockfiles
= htmp
->next
;
344 /* Then destroy the lock. */
347 #ifdef HAVE_DOSISH_SYSTEM
350 UnlockFile (h
->lockhd
, 0, 0, 1, 0);
352 CloseHandle (h
->lockhd
);
353 #else /* !HAVE_DOSISH_SYSTEM */
354 if (h
->locked
&& h
->lockname
)
355 unlink (h
->lockname
);
358 jnlib_free (h
->tname
);
359 #endif /* HAVE_DOSISH_SYSTEM */
360 jnlib_free (h
->lockname
);
366 #ifndef HAVE_DOSISH_SYSTEM
368 maybe_deadlock( DOTLOCK h
)
372 for ( r
=all_lockfiles
; r
; r
= r
->next
)
374 if ( r
!= h
&& r
->locked
)
379 #endif /*!HAVE_DOSISH_SYSTEM*/
383 /* Do a lock on H. A TIMEOUT of 0 returns immediately, -1 waits
384 forever (hopefully not), other values are reserved (should then be
385 timeouts in milliseconds). Returns: 0 on success */
387 make_dotlock ( DOTLOCK h
, long timeout
)
390 #ifndef HAVE_DOSISH_SYSTEM
392 const char *maybe_dead
="";
394 #endif /*!HAVE_DOSISH_SYSTEM*/
397 return 0; /* Locks are completely disabled. Return success. */
402 log_debug ("Oops, `%s' is already locked\n", h
->lockname
);
403 #endif /* !__riscos__ */
409 #ifndef HAVE_DOSISH_SYSTEM
411 if ( !link(h
->tname
, h
->lockname
) )
413 /* fixme: better use stat to check the link count */
417 if ( errno
!= EEXIST
)
419 log_error ( "lock not made: link() failed: %s\n", strerror(errno
) );
422 # else /* __riscos__ */
423 if ( !renamefile(h
->tname
, h
->lockname
) )
428 if ( errno
!= EEXIST
)
430 log_error( "lock not made: rename() failed: %s\n", strerror(errno
) );
433 # endif /* __riscos__ */
435 if ( (pid
= read_lockfile (h
, &same_node
)) == -1 )
437 if ( errno
!= ENOENT
)
439 log_info ("cannot read lockfile\n");
442 log_info( "lockfile disappeared\n");
445 else if ( pid
== getpid() && same_node
)
447 log_info( "Oops: lock already held by us\n");
451 else if ( same_node
&& kill (pid
, 0) && errno
== ESRCH
)
454 log_info (_("removing stale lockfile (created by %d)\n"), pid
);
455 unlink (h
->lockname
);
457 # else /* __riscos__ */
458 /* Under RISCOS we are *pretty* sure that the other task
459 is dead and therefore we remove the stale lock file. */
460 maybe_dead
= _(" - probably dead - removing lock");
462 # endif /* __riscos__ */
467 /* Wait until lock has been released. */
470 log_info (_("waiting for lock (held by %d%s) %s...\n"),
471 pid
, maybe_dead
, maybe_deadlock(h
)? _("(deadlock?) "):"");
474 /* We can't use sleep, cause signals may be blocked. */
475 tv
.tv_sec
= 1 + backoff
;
477 select(0, NULL
, NULL
, NULL
, &tv
);
483 #else /*HAVE_DOSISH_SYSTEM*/
486 if (LockFile (h
->lockhd
, 0, 0, 1, 0))
491 w32err
= GetLastError ();
492 if (w32err
!= ERROR_LOCK_VIOLATION
)
494 log_error (_("lock `%s' not made: %s\n"),
495 h
->lockname
, w32_strerror (w32err
));
501 /* Wait until lock has been released. */
502 log_info (_("waiting for lock %s...\n"), h
->lockname
);
503 Sleep ((1 + backoff
)*1000);
509 #endif /*HAVE_DOSISH_SYSTEM*/
515 /* Release a lock. Returns 0 on success. */
517 release_dotlock( DOTLOCK h
)
519 #ifndef HAVE_DOSISH_SYSTEM
523 /* To avoid atexit race conditions we first check whether there are
524 any locks left. It might happen that another atexit handler
525 tries to release the lock while the atexit handler of this module
526 already ran and thus H is undefined. */
535 log_debug("Oops, `%s' is not locked\n", h
->lockname
);
539 #ifdef HAVE_DOSISH_SYSTEM
540 if (!UnlockFile (h
->lockhd
, 0, 0, 1, 0))
542 log_error ("release_dotlock: error removing lockfile `%s': %s\n",
543 h
->lockname
, w32_strerror (-1));
548 pid
= read_lockfile (h
, &same_node
);
551 log_error( "release_dotlock: lockfile error\n");
554 if ( pid
!= getpid() || !same_node
)
556 log_error( "release_dotlock: not our lock (pid=%d)\n", pid
);
561 if ( unlink( h
->lockname
) )
563 log_error ("release_dotlock: error removing lockfile `%s'\n",
567 /* Fixme: As an extra check we could check whether the link count is
569 #else /* __riscos__ */
570 if ( renamefile (h
->lockname
, h
->tname
) )
572 log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
573 h
->lockname
, h
->tname
);
576 #endif /* __riscos__ */
578 #endif /* !HAVE_DOSISH_SYSTEM */
584 /* Read the lock file and return the pid, returns -1 on error. True
585 will be stored in the integer at address SAME_NODE if the lock file
586 has been created on the same node. */
587 #ifndef HAVE_DOSISH_SYSTEM
589 read_lockfile (DOTLOCK h
, int *same_node
)
591 char buffer_space
[10+1+70+1]; /* 70 is just an estimated value; node
592 name are usually shorter. */
600 expected_len
= 10 + 1 + h
->nodename_len
+ 1;
601 if ( expected_len
>= sizeof buffer_space
)
602 buffer
= jnlib_xmalloc (expected_len
);
604 buffer
= buffer_space
;
606 if ( (fd
= open (h
->lockname
, O_RDONLY
)) == -1 )
609 log_info ("error opening lockfile `%s': %s\n",
610 h
->lockname
, strerror(errno
) );
611 if (buffer
!= buffer_space
)
613 errno
= e
; /* Need to return ERRNO here. */
621 res
= read (fd
, p
, expected_len
- nread
);
622 if (res
== -1 && errno
== EINTR
)
626 log_info ("error reading lockfile `%s'", h
->lockname
);
628 if (buffer
!= buffer_space
)
630 errno
= 0; /* Do not return an inappropriate ERRNO. */
636 while (res
&& nread
!= expected_len
);
641 log_info ("invalid size of lockfile `%s'", h
->lockname
);
642 if (buffer
!= buffer_space
)
644 errno
= 0; /* Better don't return an inappropriate ERRNO. */
648 if (buffer
[10] != '\n'
649 || (buffer
[10] = 0, pid
= atoi (buffer
)) == -1
652 #else /* __riscos__ */
653 || (!pid
&& riscos_getpid())
654 #endif /* __riscos__ */
657 log_error ("invalid pid %d in lockfile `%s'", pid
, h
->lockname
);
658 if (buffer
!= buffer_space
)
664 if (nread
== expected_len
665 && !memcmp (h
->tname
+h
->nodename_off
, buffer
+11, h
->nodename_len
)
666 && buffer
[11+h
->nodename_len
] == '\n')
669 if (buffer
!= buffer_space
)
673 #endif /* !HAVE_DOSISH_SYSTEM */
676 /* Remove all lockfiles. This is usually called by the atexit handler
677 installed by this module but may also be called by other
678 termination handlers. */
680 dotlock_remove_lockfiles()
685 all_lockfiles
= NULL
;