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() );
169 /* Create a temporary file. */
170 if ( uname ( &utsbuf
) )
171 nodename
= "unknown";
173 nodename
= utsbuf
.nodename
;
177 char *iter
= (char *) nodename
;
178 for (; iter
[0]; iter
++)
182 #endif /* __riscos__ */
184 if ( !(dirpart
= strrchr (file_to_lock
, DIRSEP_C
)) )
191 dirpartlen
= dirpart
- file_to_lock
;
192 dirpart
= file_to_lock
;
196 /* fixme: aquire mutex on all_lockfiles */
198 h
->next
= all_lockfiles
;
201 tnamelen
= dirpartlen
+ 6 + 30 + strlen(nodename
) + 10;
202 h
->tname
= jnlib_malloc (tnamelen
+ 1);
205 all_lockfiles
= h
->next
;
209 h
->nodename_len
= strlen (nodename
);
212 snprintf (h
->tname
, tnamelen
, "%.*s/.#lk%p.", dirpartlen
, dirpart
, h
);
213 h
->nodename_off
= strlen (h
->tname
);
214 snprintf (h
->tname
+h
->nodename_off
, tnamelen
- h
->nodename_off
,
215 "%s.%d", nodename
, (int)getpid ());
216 #else /* __riscos__ */
217 snprintf (h
->tname
, tnamelen
, "%.*s.lk%p/", dirpartlen
, dirpart
, h
);
218 h
->nodename_off
= strlen (h
->tname
);
219 snprintf (h
->tname
+h
->nodename_off
, tnamelen
- h
->modename_off
,
220 "%s/%d", nodename
, (int)getpid () );
221 #endif /* __riscos__ */
226 fd
= open (h
->tname
, O_WRONLY
|O_CREAT
|O_EXCL
,
227 S_IRUSR
|S_IRGRP
|S_IROTH
|S_IWUSR
);
229 while (fd
== -1 && errno
== EINTR
);
233 all_lockfiles
= h
->next
;
234 log_error (_("failed to create temporary file `%s': %s\n"),
235 h
->tname
, strerror(errno
));
236 jnlib_free (h
->tname
);
240 if ( write (fd
, pidstr
, 11 ) != 11 )
242 if ( write (fd
, nodename
, strlen (nodename
) ) != strlen (nodename
) )
244 if ( write (fd
, "\n", 1 ) != 1 )
252 h
->lockname
= jnlib_malloc ( strlen (file_to_lock
) + 6 );
255 all_lockfiles
= h
->next
;
257 jnlib_free (h
->tname
);
261 strcpy (stpcpy (h
->lockname
, file_to_lock
), EXTSEP_S
"lock");
265 all_lockfiles
= h
->next
;
267 /* fixme: release mutex */
269 log_error ( _("error writing to `%s': %s\n"), h
->tname
, strerror(errno
) );
272 jnlib_free (h
->tname
);
276 #else /* HAVE_DOSISH_SYSTEM */
278 /* The Windows version does not need a temporary file but uses the
279 plain lock file along with record locking. We create this file
280 here so that we later do only need to do the file locking. For
281 error reporting it is useful to keep the name of the file in the
283 h
->next
= all_lockfiles
;
286 h
->lockname
= jnlib_malloc ( strlen (file_to_lock
) + 6 );
289 all_lockfiles
= h
->next
;
293 strcpy (stpcpy(h
->lockname
, file_to_lock
), EXTSEP_S
"lock");
295 /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
296 along with FILE_SHARE_DELETE but that does not work due to a race
297 condition: Despite the OPEN_ALWAYS flag CreateFile may return an
298 error and we can't reliable create/open the lock file unless we
299 would wait here until it works - however there are other valid
300 reasons why a lock file can't be created and thus the process
301 would not stop as expected but spin til until Windows crashes.
302 Our solution is to keep the lock file open; that does not
304 h
->lockhd
= CreateFile (h
->lockname
,
305 GENERIC_READ
|GENERIC_WRITE
,
306 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
307 NULL
, OPEN_ALWAYS
, 0, NULL
);
308 if (h
->lockhd
== INVALID_HANDLE_VALUE
)
310 log_error (_("can't create `%s': %s\n"), h
->lockname
, w32_strerror (-1));
311 all_lockfiles
= h
->next
;
312 jnlib_free (h
->lockname
);
318 #endif /* HAVE_DOSISH_SYSTEM */
322 /* Destroy the local handle H and release the lock. */
324 destroy_dotlock ( DOTLOCK h
)
331 /* First remove the handle from our global list of all locks. */
332 for (hprev
=NULL
, htmp
=all_lockfiles
; htmp
; hprev
=htmp
, htmp
=htmp
->next
)
336 hprev
->next
= htmp
->next
;
338 all_lockfiles
= htmp
->next
;
343 /* Then destroy the lock. */
346 #ifdef HAVE_DOSISH_SYSTEM
349 UnlockFile (h
->lockhd
, 0, 0, 1, 0);
351 CloseHandle (h
->lockhd
);
352 #else /* !HAVE_DOSISH_SYSTEM */
353 if (h
->locked
&& h
->lockname
)
354 unlink (h
->lockname
);
357 jnlib_free (h
->tname
);
358 #endif /* HAVE_DOSISH_SYSTEM */
359 jnlib_free (h
->lockname
);
365 #ifndef HAVE_DOSISH_SYSTEM
367 maybe_deadlock( DOTLOCK h
)
371 for ( r
=all_lockfiles
; r
; r
= r
->next
)
373 if ( r
!= h
&& r
->locked
)
378 #endif /*!HAVE_DOSISH_SYSTEM*/
382 /* Do a lock on H. A TIMEOUT of 0 returns immediately, -1 waits
383 forever (hopefully not), other values are reserved (should then be
384 timeouts in milliseconds). Returns: 0 on success */
386 make_dotlock ( DOTLOCK h
, long timeout
)
389 #ifndef HAVE_DOSISH_SYSTEM
391 const char *maybe_dead
="";
393 #endif /*!HAVE_DOSISH_SYSTEM*/
396 return 0; /* Locks are completely disabled. Return success. */
401 log_debug ("Oops, `%s' is already locked\n", h
->lockname
);
402 #endif /* !__riscos__ */
408 #ifndef HAVE_DOSISH_SYSTEM
410 if ( !link(h
->tname
, h
->lockname
) )
412 /* fixme: better use stat to check the link count */
416 if ( errno
!= EEXIST
)
418 log_error ( "lock not made: link() failed: %s\n", strerror(errno
) );
421 # else /* __riscos__ */
422 if ( !renamefile(h
->tname
, h
->lockname
) )
427 if ( errno
!= EEXIST
)
429 log_error( "lock not made: rename() failed: %s\n", strerror(errno
) );
432 # endif /* __riscos__ */
434 if ( (pid
= read_lockfile (h
, &same_node
)) == -1 )
436 if ( errno
!= ENOENT
)
438 log_info ("cannot read lockfile\n");
441 log_info( "lockfile disappeared\n");
444 else if ( pid
== getpid() && same_node
)
446 log_info( "Oops: lock already held by us\n");
450 else if ( same_node
&& kill (pid
, 0) && errno
== ESRCH
)
453 log_info (_("removing stale lockfile (created by %d)\n"), pid
);
454 unlink (h
->lockname
);
456 # else /* __riscos__ */
457 /* Under RISCOS we are *pretty* sure that the other task
458 is dead and therefore we remove the stale lock file. */
459 maybe_dead
= _(" - probably dead - removing lock");
461 # endif /* __riscos__ */
466 /* Wait until lock has been released. */
469 log_info (_("waiting for lock (held by %d%s) %s...\n"),
470 pid
, maybe_dead
, maybe_deadlock(h
)? _("(deadlock?) "):"");
473 /* We can't use sleep, cause signals may be blocked. */
474 tv
.tv_sec
= 1 + backoff
;
476 select(0, NULL
, NULL
, NULL
, &tv
);
482 #else /*HAVE_DOSISH_SYSTEM*/
485 if (LockFile (h
->lockhd
, 0, 0, 1, 0))
490 w32err
= GetLastError ();
491 if (w32err
!= ERROR_LOCK_VIOLATION
)
493 log_error (_("lock `%s' not made: %s\n"),
494 h
->lockname
, w32_strerror (w32err
));
500 /* Wait until lock has been released. */
501 log_info (_("waiting for lock %s...\n"), h
->lockname
);
502 Sleep ((1 + backoff
)*1000);
508 #endif /*HAVE_DOSISH_SYSTEM*/
514 /* Release a lock. Returns 0 on success. */
516 release_dotlock( DOTLOCK h
)
518 #ifndef HAVE_DOSISH_SYSTEM
522 /* To avoid atexit race conditions we first check whether there are
523 any locks left. It might happen that another atexit handler
524 tries to release the lock while the atexit handler of this module
525 already ran and thus H is undefined. */
534 log_debug("Oops, `%s' is not locked\n", h
->lockname
);
538 #ifdef HAVE_DOSISH_SYSTEM
539 if (!UnlockFile (h
->lockhd
, 0, 0, 1, 0))
541 log_error ("release_dotlock: error removing lockfile `%s': %s\n",
542 h
->lockname
, w32_strerror (-1));
547 pid
= read_lockfile (h
, &same_node
);
550 log_error( "release_dotlock: lockfile error\n");
553 if ( pid
!= getpid() || !same_node
)
555 log_error( "release_dotlock: not our lock (pid=%d)\n", pid
);
560 if ( unlink( h
->lockname
) )
562 log_error ("release_dotlock: error removing lockfile `%s'\n",
566 /* Fixme: As an extra check we could check whether the link count is
568 #else /* __riscos__ */
569 if ( renamefile (h
->lockname
, h
->tname
) )
571 log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
572 h
->lockname
, h
->tname
);
575 #endif /* __riscos__ */
577 #endif /* !HAVE_DOSISH_SYSTEM */
583 /* Read the lock file and return the pid, returns -1 on error. True
584 will be stored in the integer at address SAME_NODE if the lock file
585 has been created on the same node. */
586 #ifndef HAVE_DOSISH_SYSTEM
588 read_lockfile (DOTLOCK h
, int *same_node
)
590 char buffer_space
[10+1+70+1]; /* 70 is just an estimated value; node
591 name are usually shorter. */
599 expected_len
= 10 + 1 + h
->nodename_len
+ 1;
600 if ( expected_len
>= sizeof buffer_space
)
601 buffer
= jnlib_xmalloc (expected_len
);
603 buffer
= buffer_space
;
605 if ( (fd
= open (h
->lockname
, O_RDONLY
)) == -1 )
608 log_info ("error opening lockfile `%s': %s\n",
609 h
->lockname
, strerror(errno
) );
610 if (buffer
!= buffer_space
)
612 errno
= e
; /* Need to return ERRNO here. */
620 res
= read (fd
, p
, expected_len
- nread
);
621 if (res
== -1 && errno
== EINTR
)
625 log_info ("error reading lockfile `%s'", h
->lockname
);
627 if (buffer
!= buffer_space
)
629 errno
= 0; /* Do not return an inappropriate ERRNO. */
635 while (res
&& nread
!= expected_len
);
640 log_info ("invalid size of lockfile `%s'", h
->lockname
);
641 if (buffer
!= buffer_space
)
643 errno
= 0; /* Better don't return an inappropriate ERRNO. */
647 if (buffer
[10] != '\n'
648 || (buffer
[10] = 0, pid
= atoi (buffer
)) == -1
651 #else /* __riscos__ */
652 || (!pid
&& riscos_getpid())
653 #endif /* __riscos__ */
656 log_error ("invalid pid %d in lockfile `%s'", pid
, h
->lockname
);
657 if (buffer
!= buffer_space
)
663 if (nread
== expected_len
664 && !memcmp (h
->tname
+h
->nodename_off
, buffer
+11, h
->nodename_len
)
665 && buffer
[11+h
->nodename_len
] == '\n')
668 if (buffer
!= buffer_space
)
672 #endif /* !HAVE_DOSISH_SYSTEM */
675 /* Remove all lockfiles. This is usually called by the atexit handler
676 installed by this module but may also be called by other
677 termination handlers. */
679 dotlock_remove_lockfiles()
684 all_lockfiles
= NULL
;