chiark / gitweb /
asshelp.c: add a lot of debug logging
[gnupg2.git] / common / dotlock.c
1 /* dotlock.c - dotfile locking
2  * Copyright (C) 1998, 2000, 2001, 2003, 2004,
3  *               2005, 2006, 2008, 2010, 2011 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify it
8  * under the terms of either
9  *
10  *   - the GNU Lesser General Public License as published by the Free
11  *     Software Foundation; either version 3 of the License, or (at
12  *     your option) any later version.
13  *
14  * or
15  *
16  *   - the GNU General Public License as published by the Free
17  *     Software Foundation; either version 2 of the License, or (at
18  *     your option) any later version.
19  *
20  * or both in parallel, as here.
21  *
22  * GnuPG is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * General Public License for more details.
26  *
27  * You should have received a copies of the GNU General Public License
28  * and the GNU Lesser General Public License along with this program;
29  * if not, see <https://www.gnu.org/licenses/>.
30  *
31  * ALTERNATIVELY, this file may be distributed under the terms of the
32  * following license, in which case the provisions of this license are
33  * required INSTEAD OF the GNU Lesser General License or the GNU
34  * General Public License. If you wish to allow use of your version of
35  * this file only under the terms of the GNU Lesser General License or
36  * the GNU General Public License, and not to allow others to use your
37  * version of this file under the terms of the following license,
38  * indicate your decision by deleting this paragraph and the license
39  * below.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  *
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, and the entire permission notice in its entirety,
47  *    including the disclaimer of warranties.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. The name of the author may not be used to endorse or promote
52  *    products derived from this software without specific prior
53  *    written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
56  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
57  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
58  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
59  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
60  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
61  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
63  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
65  * OF THE POSSIBILITY OF SUCH DAMAGE.
66  */
67
68 /*
69    Overview:
70    =========
71
72    This module implements advisory file locking in a portable way.
73    Due to the problems with POSIX fcntl locking a separate lock file
74    is used.  It would be possible to use fcntl locking on this lock
75    file and thus avoid the weird auto unlock bug of POSIX while still
76    having an unproved better performance of fcntl locking.  However
77    there are still problems left, thus we resort to use a hardlink
78    which has the well defined property that a link call will fail if
79    the target file already exists.
80
81    Given that hardlinks are also available on NTFS file systems since
82    Windows XP; it will be possible to enhance this module to use
83    hardlinks even on Windows and thus allow Windows and Posix clients
84    to use locking on the same directory.  This is not yet implemented;
85    instead we use a lockfile on Windows along with W32 style file
86    locking.
87
88    On FAT file systems hardlinks are not supported.  Thus this method
89    does not work.  Our solution is to use a O_EXCL locking instead.
90    Querying the type of the file system is not easy to do in a
91    portable way (e.g. Linux has a statfs, BSDs have a the same call
92    but using different structures and constants).  What we do instead
93    is to check at runtime whether link(2) works for a specific lock
94    file.
95
96
97    How to use:
98    ===========
99
100    At program initialization time, the module should be explicitly
101    initialized:
102
103       dotlock_create (NULL, 0);
104
105    This installs an atexit handler and may also initialize mutex etc.
106    It is optional for non-threaded applications.  Only the first call
107    has an effect.  This needs to be done before any extra threads are
108    started.
109
110    To create a lock file (which  prepares it but does not take the
111    lock) you do:
112
113      dotlock_t h
114
115      h = dotlock_create (fname, 0);
116      if (!h)
117        error ("error creating lock file: %s\n", strerror (errno));
118
119    It is important to handle the error.  For example on a read-only
120    file system a lock can't be created (but is usually not needed).
121    FNAME is the file you want to lock; the actual lockfile is that
122    name with the suffix ".lock" appended.  On success a handle to be
123    used with the other functions is returned or NULL on error.  Note
124    that the handle shall only be used by one thread at a time.  This
125    function creates a unique file temporary file (".#lk*") in the same
126    directory as FNAME and returns a handle for further operations.
127    The module keeps track of theses unique files so that they will be
128    unlinked using the atexit handler.  If you don't need the lock file
129    anymore, you may also explicitly remove it with a call to:
130
131      dotlock_destroy (h);
132
133    To actually lock the file, you use:
134
135      if (dotlock_take (h, -1))
136        error ("error taking lock: %s\n", strerror (errno));
137
138    This function will wait until the lock is acquired.  If an
139    unexpected error occurs if will return non-zero and set ERRNO.  If
140    you pass (0) instead of (-1) the function does not wait in case the
141    file is already locked but returns -1 and sets ERRNO to EACCES.
142    Any other positive value for the second parameter is considered a
143    timeout valuie in milliseconds.
144
145    To release the lock you call:
146
147      if (dotlock_release (h))
148        error ("error releasing lock: %s\n", strerror (errno));
149
150    or, if the lock file is not anymore needed, you may just call
151    dotlock_destroy.  However dotlock_release does some extra checks
152    before releasing the lock and prints diagnostics to help detecting
153    bugs.
154
155    If you want to explicitly destroy all lock files you may call
156
157      dotlock_remove_lockfiles ();
158
159    which is the core of the installed atexit handler.  In case your
160    application wants to disable locking completely it may call
161
162      disable_locking ()
163
164    before any locks are created.
165
166    There are two convenience functions to store an integer (e.g. a
167    file descriptor) value with the handle:
168
169      void dotlock_set_fd (dotlock_t h, int fd);
170      int  dotlock_get_fd (dotlock_t h);
171
172    If nothing has been stored dotlock_get_fd returns -1.
173
174
175
176    How to build:
177    =============
178
179    This module was originally developed for GnuPG but later changed to
180    allow its use without any GnuPG dependency.  If you want to use it
181    with you application you may simply use it and it should figure out
182    most things automagically.
183
184    You may use the common config.h file to pass macros, but take care
185    to pass -DHAVE_CONFIG_H to the compiler.  Macros used by this
186    module are:
187
188      DOTLOCK_USE_PTHREAD  - Define if POSIX threads are in use.
189
190      DOTLOCK_GLIB_LOGGING - Define this to use Glib logging functions.
191
192      DOTLOCK_EXT_SYM_PREFIX - Prefix all external symbols with the
193                               string to which this macro evaluates.
194
195      GNUPG_MAJOR_VERSION - Defined when used by GnuPG.
196
197      HAVE_DOSISH_SYSTEM  - Defined for Windows etc.  Will be
198                            automatically defined if a the target is
199                            Windows.
200
201      HAVE_POSIX_SYSTEM   - Internally defined to !HAVE_DOSISH_SYSTEM.
202
203      HAVE_SIGNAL_H       - Should be defined on Posix systems.  If config.h
204                            is not used defaults to defined.
205
206      DIRSEP_C            - Separation character for file name parts.
207                            Usually not redefined.
208
209      EXTSEP_S            - Separation string for file name suffixes.
210                            Usually not redefined.
211
212      HAVE_W32CE_SYSTEM   - Currently only used by GnuPG.
213
214    Note that there is a test program t-dotlock which has compile
215    instructions at its end.  At least for SMBFS and CIFS it is
216    important that 64 bit versions of stat are used; most programming
217    environments do this these days, just in case you want to compile
218    it on the command line, remember to pass -D_FILE_OFFSET_BITS=64
219
220
221    Bugs:
222    =====
223
224    On Windows this module is not yet thread-safe.
225
226
227    Miscellaneous notes:
228    ====================
229
230    On hardlinks:
231    - Hardlinks are supported under Windows with NTFS since XP/Server2003.
232    - In Linux 2.6.33 both SMBFS and CIFS seem to support hardlinks.
233    - NFS supports hard links.  But there are solvable problems.
234    - FAT does not support links
235
236    On the file locking API:
237    - CIFS on Linux 2.6.33 supports several locking methods.
238      SMBFS seems not to support locking.  No closer checks done.
239    - NFS supports Posix locks.  flock is emulated in the server.
240      However there are a couple of problems; see below.
241    - FAT does not support locks.
242    - An advantage of fcntl locking is that R/W locks can be
243      implemented which is not easy with a straight lock file.
244
245    On O_EXCL:
246    - Does not work reliable on NFS
247    - Should work on CIFS and SMBFS but how can we delete lockfiles?
248
249    On NFS problems:
250    - Locks vanish if the server crashes and reboots.
251    - Client crashes keep the lock in the server until the client
252      re-connects.
253    - Communication problems may return unreliable error codes.  The
254      MUA Postfix's workaround is to compare the link count after
255      seeing an error for link.  However that gives a race.  If using a
256      unique file to link to a lockfile and using stat to check the
257      link count instead of looking at the error return of link(2) is
258      the best solution.
259    - O_EXCL seems to have a race and may re-create a file anyway.
260
261 */
262
263 #ifdef HAVE_CONFIG_H
264 # include <config.h>
265 #endif
266
267 /* Some quick replacements for stuff we usually expect to be defined
268    in config.h.  Define HAVE_POSIX_SYSTEM for better readability. */
269 #if !defined (HAVE_DOSISH_SYSTEM) && defined(_WIN32)
270 # define HAVE_DOSISH_SYSTEM 1
271 #endif
272 #if !defined (HAVE_DOSISH_SYSTEM) && !defined (HAVE_POSIX_SYSTEM)
273 # define HAVE_POSIX_SYSTEM 1
274 #endif
275
276 /* With no config.h assume that we have sitgnal.h.  */
277 #if !defined (HAVE_CONFIG_H) && defined (HAVE_POSIX_SYSTEM)
278 # define HAVE_SIGNAL_H 1
279 #endif
280
281 /* Standard headers.  */
282 #include <stdlib.h>
283 #include <stdio.h>
284 #include <string.h>
285 #include <errno.h>
286 #include <ctype.h>
287 #include <errno.h>
288 #include <unistd.h>
289 #ifdef  HAVE_DOSISH_SYSTEM
290 # define WIN32_LEAN_AND_MEAN  /* We only need the OS core stuff.  */
291 # include <windows.h>
292 #else
293 # include <sys/types.h>
294 # include <sys/stat.h>
295 # include <sys/utsname.h>
296 #endif
297 #include <sys/types.h>
298 #include <sys/time.h>
299 #include <sys/stat.h>
300 #include <fcntl.h>
301 #ifdef HAVE_SIGNAL_H
302 # include <signal.h>
303 #endif
304 #ifdef DOTLOCK_USE_PTHREAD
305 # include <pthread.h>
306 #endif
307
308 #ifdef DOTLOCK_GLIB_LOGGING
309 # include <glib.h>
310 #endif
311
312 #ifdef GNUPG_MAJOR_VERSION
313 # include "util.h"
314 # include "common-defs.h"
315 # include "stringhelp.h"  /* For stpcpy and w32_strerror. */
316 #endif
317 #ifdef HAVE_W32CE_SYSTEM
318 # include "utf8conv.h"  /* WindowsCE requires filename conversion.  */
319 #endif
320
321 #include "dotlock.h"
322
323
324 /* Define constants for file name construction.  */
325 #if !defined(DIRSEP_C) && !defined(EXTSEP_S)
326 # ifdef HAVE_DOSISH_SYSTEM
327 #  define DIRSEP_C '\\'
328 #  define EXTSEP_S "."
329 #else
330 #  define DIRSEP_C '/'
331 #  define EXTSEP_S "."
332 # endif
333 #endif
334
335 /* In GnuPG we use wrappers around the malloc fucntions.  If they are
336    not defined we assume that this code is used outside of GnuPG and
337    fall back to the regular malloc functions.  */
338 #ifndef xtrymalloc
339 # define xtrymalloc(a)     malloc ((a))
340 # define xtrycalloc(a,b)   calloc ((a), (b))
341 # define xfree(a)          free ((a))
342 #endif
343
344 /* Wrapper to set ERRNO (required for W32CE).  */
345 #ifdef GPG_ERROR_VERSION
346 #  define my_set_errno(e)  gpg_err_set_errno ((e))
347 #else
348 #  define my_set_errno(e)  do { errno = (e); } while (0)
349 #endif
350
351 /* Gettext macro replacement.  */
352 #ifndef _
353 # define _(a) (a)
354 #endif
355
356 #ifdef GNUPG_MAJOR_VERSION
357 # define my_info_0(a)       log_info ((a))
358 # define my_info_1(a,b)     log_info ((a), (b))
359 # define my_info_2(a,b,c)   log_info ((a), (b), (c))
360 # define my_info_3(a,b,c,d) log_info ((a), (b), (c), (d))
361 # define my_error_0(a)      log_error ((a))
362 # define my_error_1(a,b)    log_error ((a), (b))
363 # define my_error_2(a,b,c)  log_error ((a), (b), (c))
364 # define my_debug_1(a,b)    log_debug ((a), (b))
365 # define my_fatal_0(a)      log_fatal ((a))
366 #elif defined (DOTLOCK_GLIB_LOGGING)
367 # define my_info_0(a)       g_message ((a))
368 # define my_info_1(a,b)     g_message ((a), (b))
369 # define my_info_2(a,b,c)   g_message ((a), (b), (c))
370 # define my_info_3(a,b,c,d) g_message ((a), (b), (c), (d))
371 # define my_error_0(a)      g_warning ((a))
372 # define my_error_1(a,b)    g_warning ((a), (b))
373 # define my_error_2(a,b,c)  g_warning ((a), (b), (c))
374 # define my_debug_1(a,b)    g_debug ((a), (b))
375 # define my_fatal_0(a)      g_error ((a))
376 #else
377 # define my_info_0(a)       fprintf (stderr, (a))
378 # define my_info_1(a,b)     fprintf (stderr, (a), (b))
379 # define my_info_2(a,b,c)   fprintf (stderr, (a), (b), (c))
380 # define my_info_3(a,b,c,d) fprintf (stderr, (a), (b), (c), (d))
381 # define my_error_0(a)      fprintf (stderr, (a))
382 # define my_error_1(a,b)    fprintf (stderr, (a), (b))
383 # define my_error_2(a,b,c)  fprintf (stderr, (a), (b), (c))
384 # define my_debug_1(a,b)    fprintf (stderr, (a), (b))
385 # define my_fatal_0(a)      do { fprintf (stderr,(a)); fflush (stderr); \
386                                  abort (); } while (0)
387 #endif
388
389
390
391
392 \f
393 /* The object describing a lock.  */
394 struct dotlock_handle
395 {
396   struct dotlock_handle *next;
397   char *lockname;            /* Name of the actual lockfile.          */
398   unsigned int locked:1;     /* Lock status.                          */
399   unsigned int disable:1;    /* If true, locking is disabled.         */
400   unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking.        */
401
402   int extra_fd;              /* A place for the caller to store an FD.  */
403
404 #ifdef HAVE_DOSISH_SYSTEM
405   HANDLE lockhd;       /* The W32 handle of the lock file.      */
406 #else /*!HAVE_DOSISH_SYSTEM */
407   char *tname;         /* Name of the lockfile template.        */
408   size_t nodename_off; /* Offset in TNAME of the nodename part. */
409   size_t nodename_len; /* Length of the nodename part.          */
410 #endif /*!HAVE_DOSISH_SYSTEM */
411 };
412
413
414 /* A list of of all lock handles.  The volatile attribute might help
415    if used in an atexit handler.  Note that [UN]LOCK_all_lockfiles
416    must not change ERRNO. */
417 static volatile dotlock_t all_lockfiles;
418 #ifdef DOTLOCK_USE_PTHREAD
419 static pthread_mutex_t all_lockfiles_mutex = PTHREAD_MUTEX_INITIALIZER;
420 # define LOCK_all_lockfiles() do {                               \
421         if (pthread_mutex_lock (&all_lockfiles_mutex))           \
422           my_fatal_0 ("locking all_lockfiles_mutex failed\n");   \
423       } while (0)
424 # define UNLOCK_all_lockfiles() do {                             \
425         if (pthread_mutex_unlock (&all_lockfiles_mutex))         \
426           my_fatal_0 ("unlocking all_lockfiles_mutex failed\n"); \
427       } while (0)
428 #else  /*!DOTLOCK_USE_PTHREAD*/
429 # define LOCK_all_lockfiles()   do { } while (0)
430 # define UNLOCK_all_lockfiles() do { } while (0)
431 #endif /*!DOTLOCK_USE_PTHREAD*/
432
433 /* If this has the value true all locking is disabled.  */
434 static int never_lock;
435
436
437
438 \f
439 #ifdef HAVE_DOSISH_SYSTEM
440 static int
441 map_w32_to_errno (DWORD w32_err)
442 {
443   switch (w32_err)
444     {
445     case 0:
446       return 0;
447
448     case ERROR_FILE_NOT_FOUND:
449       return ENOENT;
450
451     case ERROR_PATH_NOT_FOUND:
452       return ENOENT;
453
454     case ERROR_ACCESS_DENIED:
455       return EPERM;
456
457     case ERROR_INVALID_HANDLE:
458     case ERROR_INVALID_BLOCK:
459       return EINVAL;
460
461     case ERROR_NOT_ENOUGH_MEMORY:
462       return ENOMEM;
463
464     case ERROR_NO_DATA:
465     case ERROR_BROKEN_PIPE:
466       return EPIPE;
467
468     default:
469       return EIO;
470     }
471 }
472 #endif /*HAVE_DOSISH_SYSTEM*/
473
474 #define DLOG(h, m, ...) do{                             \
475     dotlock_t DLOG_h = (h);                             \
476     int DLOG_se = errno;                                \
477     if (/*DBG_IPC*/ 0)                                  \
478       log_debug("dotlock %p %s " m, (DLOG_h),           \
479                 !(DLOG_h)           ? "(none)" :        \
480                 !(DLOG_h)->lockname ? "(null)" :        \
481                  (DLOG_h)->lockname,                    \
482                 ##__VA_ARGS__);                         \
483     errno = DLOG_se;                                    \
484   }while(0)
485
486 \f
487 /* Entirely disable all locking.  This function should be called
488    before any locking is done.  It may be called right at startup of
489    the process as it only sets a global value.  */
490 void
491 dotlock_disable (void)
492 {
493   DLOG(0, "dotlock_disable\n");
494   never_lock = 1;
495 }
496
497
498 #ifdef HAVE_POSIX_SYSTEM
499 static int
500 maybe_deadlock (dotlock_t h)
501 {
502   dotlock_t r;
503   int res = 0;
504
505   DLOG(h, "maybe_deadlock\n");
506
507   LOCK_all_lockfiles ();
508   for (r=all_lockfiles; r; r = r->next)
509     {
510       if ( r != h && r->locked )
511         {
512           res = 1;
513           break;
514         }
515     }
516   UNLOCK_all_lockfiles ();
517   return res;
518 }
519 #endif /*HAVE_POSIX_SYSTEM*/
520
521
522 /* Read the lock file and return the pid, returns -1 on error.  True
523    will be stored in the integer at address SAME_NODE if the lock file
524    has been created on the same node. */
525 #ifdef HAVE_POSIX_SYSTEM
526 static int
527 read_lockfile (dotlock_t h, int *same_node )
528 {
529   char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
530                                    names are usually shorter. */
531   int fd;
532   int pid = -1;
533   char *buffer, *p;
534   size_t expected_len;
535   int res, nread;
536
537   DLOG(h, "read_lockfile()\n");
538
539   *same_node = 0;
540   expected_len = 10 + 1 + h->nodename_len + 1;
541   if ( expected_len >= sizeof buffer_space)
542     {
543       buffer = xtrymalloc (expected_len);
544       if (!buffer)
545         return -1;
546     }
547   else
548     buffer = buffer_space;
549
550   if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
551     {
552       int e = errno;
553       my_info_2 ("error opening lockfile '%s': %s\n",
554                  h->lockname, strerror(errno) );
555       if (buffer != buffer_space)
556         xfree (buffer);
557       my_set_errno (e); /* Need to return ERRNO here. */
558       return -1;
559     }
560
561   p = buffer;
562   nread = 0;
563   do
564     {
565       res = read (fd, p, expected_len - nread);
566       if (res == -1 && errno == EINTR)
567         continue;
568       if (res < 0)
569         {
570           int e = errno;
571           my_info_1 ("error reading lockfile '%s'\n", h->lockname );
572           close (fd);
573           if (buffer != buffer_space)
574             xfree (buffer);
575           my_set_errno (e);
576           return -1;
577         }
578       p += res;
579       nread += res;
580     }
581   while (res && nread != expected_len);
582   close(fd);
583
584   if (nread < 11)
585     {
586       my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
587       if (buffer != buffer_space)
588         xfree (buffer);
589       my_set_errno (EINVAL);
590       return -1;
591     }
592
593   if (buffer[10] != '\n'
594       || (buffer[10] = 0, pid = atoi (buffer)) == -1
595       || !pid )
596     {
597       my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
598       if (buffer != buffer_space)
599         xfree (buffer);
600       my_set_errno (EINVAL);
601       return -1;
602     }
603
604   if (nread == expected_len
605       && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
606       && buffer[11+h->nodename_len] == '\n')
607     *same_node = 1;
608
609   if (buffer != buffer_space)
610     xfree (buffer);
611   DLOG(h, "read_lockfile(%d) = %ld\n", *same_node, (long)pid);
612   return pid;
613 }
614 #endif /*HAVE_POSIX_SYSTEM */
615
616
617 /* Check whether the file system which stores TNAME supports
618    hardlinks.  Instead of using the non-portable statsfs call which
619    differs between various Unix versions, we do a runtime test.
620    Returns: 0 supports hardlinks; 1 no hardlink support, -1 unknown
621    (test error).  */
622 #ifdef HAVE_POSIX_SYSTEM
623 static int
624 use_hardlinks_p (const char *tname)
625 {
626   char *lname;
627   struct stat sb;
628   unsigned int nlink;
629   int res;
630
631   DLOG(0, "use_hardlinks_p(%s)\n", tname);
632
633   if (stat (tname, &sb))
634     return -1;
635   nlink = (unsigned int)sb.st_nlink;
636
637   lname = xtrymalloc (strlen (tname) + 1 + 1);
638   if (!lname)
639     return -1;
640   strcpy (lname, tname);
641   strcat (lname, "x");
642
643   /* We ignore the return value of link() because it is unreliable.  */
644   (void) link (tname, lname);
645
646   if (stat (tname, &sb))
647     res = -1;  /* Ooops.  */
648   else if (sb.st_nlink == nlink + 1)
649     res = 0;   /* Yeah, hardlinks are supported.  */
650   else
651     res = 1;   /* No hardlink support.  */
652
653   unlink (lname);
654   xfree (lname);
655
656   DLOG(0, "use_hardlinks_p(%s) = %d\n", tname, res);
657   return res;
658 }
659 #endif /*HAVE_POSIX_SYSTEM */
660
661
662 \f
663 #ifdef  HAVE_POSIX_SYSTEM
664 /* Locking core for Unix.  It used a temporary file and the link
665    system call to make locking an atomic operation. */
666 static dotlock_t
667 dotlock_create_unix (dotlock_t h, const char *file_to_lock)
668 {
669   int  fd = -1;
670   char pidstr[16];
671   const char *nodename;
672   const char *dirpart;
673   int dirpartlen;
674   struct utsname utsbuf;
675   size_t tnamelen;
676
677   DLOG(h, "dotlock_create_unix(%s)...\n", file_to_lock);
678
679   snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
680
681   /* Create a temporary file. */
682   if ( uname ( &utsbuf ) )
683     nodename = "unknown";
684   else
685     nodename = utsbuf.nodename;
686
687   if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
688     {
689       dirpart = EXTSEP_S;
690       dirpartlen = 1;
691     }
692   else
693     {
694       dirpartlen = dirpart - file_to_lock;
695       dirpart = file_to_lock;
696     }
697
698   LOCK_all_lockfiles ();
699   h->next = all_lockfiles;
700   all_lockfiles = h;
701
702   tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
703   h->tname = xtrymalloc (tnamelen + 1);
704   if (!h->tname)
705     {
706       all_lockfiles = h->next;
707       UNLOCK_all_lockfiles ();
708       xfree (h);
709       DLOG(h, "dotlock_create_unix()=0 (!xtrymalloc)\n");
710       return NULL;
711     }
712   h->nodename_len = strlen (nodename);
713
714   snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
715   h->nodename_off = strlen (h->tname);
716   snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
717            "%s.%d", nodename, (int)getpid ());
718
719   DLOG(h, "dotlock_create_unix() open...\n");
720   do
721     {
722       my_set_errno (0);
723       fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
724                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
725     }
726   while (fd == -1 && errno == EINTR);
727   DLOG(h, "dotlock_create_unix() open=%d...\n", fd);
728
729   if ( fd == -1 )
730     {
731       int saveerrno = errno;
732       all_lockfiles = h->next;
733       UNLOCK_all_lockfiles ();
734       my_error_2 (_("failed to create temporary file '%s': %s\n"),
735                   h->tname, strerror (errno));
736       xfree (h->tname);
737       xfree (h);
738       my_set_errno (saveerrno);
739       DLOG(h, "dotlock_create_unix()=0 (fd=-1) E=%d\n",errno);
740       return NULL;
741     }
742   if ( write (fd, pidstr, 11 ) != 11 )
743     goto write_failed;
744   if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
745     goto write_failed;
746   if ( write (fd, "\n", 1 ) != 1 )
747     goto write_failed;
748   if ( close (fd) )
749     {
750       if ( errno == EINTR )
751         fd = -1;
752       goto write_failed;
753     }
754   fd = -1;
755
756   /* Check whether we support hard links.  */
757   switch (use_hardlinks_p (h->tname))
758     {
759     case 0: /* Yes.  */
760       break;
761     case 1: /* No.  */
762       unlink (h->tname);
763       h->use_o_excl = 1;
764       break;
765     default:
766       {
767         int saveerrno = errno;
768         my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
769                     , h->tname, strerror (saveerrno));
770         my_set_errno (saveerrno);
771       }
772       goto write_failed;
773     }
774
775   h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
776   if (!h->lockname)
777     {
778       int saveerrno = errno;
779       all_lockfiles = h->next;
780       UNLOCK_all_lockfiles ();
781       unlink (h->tname);
782       xfree (h->tname);
783       xfree (h);
784       my_set_errno (saveerrno);
785       DLOG(h, "dotlock_create_unix()=0 (!lockname) E=%d\n",errno);
786       return NULL;
787     }
788   strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
789   UNLOCK_all_lockfiles ();
790   if (h->use_o_excl)
791     my_debug_1 ("locking for '%s' done via O_EXCL\n", h->lockname);
792
793   DLOG(h, "dotlock_create_unix()=%p\n", h);
794   return h;
795
796  write_failed:
797   {
798     int saveerrno = errno;
799     all_lockfiles = h->next;
800     UNLOCK_all_lockfiles ();
801     my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
802     if ( fd != -1 )
803       close (fd);
804     unlink (h->tname);
805     xfree (h->tname);
806     xfree (h);
807     my_set_errno (saveerrno);
808   }
809   DLOG(h, "dotlock_create_unix()=0 (write_failed) E=%d\n",errno);
810   return NULL;
811 }
812 #endif /*HAVE_POSIX_SYSTEM*/
813
814
815 #ifdef HAVE_DOSISH_SYSTEM
816 /* Locking core for Windows.  This version does not need a temporary
817    file but uses the plain lock file along with record locking.  We
818    create this file here so that we later only need to do the file
819    locking.  For error reporting it is useful to keep the name of the
820    file in the handle.  */
821 static dotlock_t
822 dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
823 {
824   LOCK_all_lockfiles ();
825   h->next = all_lockfiles;
826   all_lockfiles = h;
827
828   h->lockname = xtrymalloc ( strlen (file_to_lock) + 6 );
829   if (!h->lockname)
830     {
831       all_lockfiles = h->next;
832       UNLOCK_all_lockfiles ();
833       xfree (h);
834       return NULL;
835     }
836   strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
837
838   /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
839      along with FILE_SHARE_DELETE but that does not work due to a race
840      condition: Despite the OPEN_ALWAYS flag CreateFile may return an
841      error and we can't reliable create/open the lock file unless we
842      would wait here until it works - however there are other valid
843      reasons why a lock file can't be created and thus the process
844      would not stop as expected but spin until Windows crashes.  Our
845      solution is to keep the lock file open; that does not harm. */
846   {
847 #ifdef HAVE_W32CE_SYSTEM
848     wchar_t *wname = utf8_to_wchar (h->lockname);
849
850     if (wname)
851       h->lockhd = CreateFile (wname,
852                               GENERIC_READ|GENERIC_WRITE,
853                               FILE_SHARE_READ|FILE_SHARE_WRITE,
854                               NULL, OPEN_ALWAYS, 0, NULL);
855     else
856       h->lockhd = INVALID_HANDLE_VALUE;
857     xfree (wname);
858 #else
859     h->lockhd = CreateFile (h->lockname,
860                             GENERIC_READ|GENERIC_WRITE,
861                             FILE_SHARE_READ|FILE_SHARE_WRITE,
862                             NULL, OPEN_ALWAYS, 0, NULL);
863 #endif
864   }
865   if (h->lockhd == INVALID_HANDLE_VALUE)
866     {
867       int saveerrno = map_w32_to_errno (GetLastError ());
868       all_lockfiles = h->next;
869       UNLOCK_all_lockfiles ();
870       my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
871       xfree (h->lockname);
872       xfree (h);
873       my_set_errno (saveerrno);
874       return NULL;
875     }
876   return h;
877 }
878 #endif /*HAVE_DOSISH_SYSTEM*/
879
880
881 /* Create a lockfile for a file name FILE_TO_LOCK and returns an
882    object of type dotlock_t which may be used later to actually acquire
883    the lock.  A cleanup routine gets installed to cleanup left over
884    locks or other files used internally by the lock mechanism.
885
886    Calling this function with NULL does only install the atexit
887    handler and may thus be used to assure that the cleanup is called
888    after all other atexit handlers.
889
890    This function creates a lock file in the same directory as
891    FILE_TO_LOCK using that name and a suffix of ".lock".  Note that on
892    POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
893    used.
894
895    FLAGS must be 0.
896
897    The function returns an new handle which needs to be released using
898    destroy_dotlock but gets also released at the termination of the
899    process.  On error NULL is returned.
900  */
901
902 dotlock_t
903 dotlock_create (const char *file_to_lock, unsigned int flags)
904 {
905   static int initialized;
906   dotlock_t h;
907
908   if ( !initialized )
909     {
910       atexit (dotlock_remove_lockfiles);
911       initialized = 1;
912     }
913
914   if ( !file_to_lock )
915     return NULL;  /* Only initialization was requested.  */
916
917   if (flags)
918     {
919       my_set_errno (EINVAL);
920       return NULL;
921     }
922
923   h = xtrycalloc (1, sizeof *h);
924   if (!h)
925     return NULL;
926   h->extra_fd = -1;
927
928   if (never_lock)
929     {
930       h->disable = 1;
931       LOCK_all_lockfiles ();
932       h->next = all_lockfiles;
933       all_lockfiles = h;
934       UNLOCK_all_lockfiles ();
935       return h;
936     }
937
938 #ifdef HAVE_DOSISH_SYSTEM
939   return dotlock_create_w32 (h, file_to_lock);
940 #else /*!HAVE_DOSISH_SYSTEM */
941   return dotlock_create_unix (h, file_to_lock);
942 #endif /*!HAVE_DOSISH_SYSTEM*/
943 }
944
945
946 \f
947 /* Convenience function to store a file descriptor (or any any other
948    integer value) in the context of handle H.  */
949 void
950 dotlock_set_fd (dotlock_t h, int fd)
951 {
952   h->extra_fd = fd;
953 }
954
955 /* Convenience function to retrieve a file descriptor (or any any other
956    integer value) stored in the context of handle H.  */
957 int
958 dotlock_get_fd (dotlock_t h)
959 {
960   return h->extra_fd;
961 }
962
963
964 \f
965 #ifdef HAVE_POSIX_SYSTEM
966 /* Unix specific code of destroy_dotlock.  */
967 static void
968 dotlock_destroy_unix (dotlock_t h)
969 {
970   DLOG(h, "dotlock_destroy_unix() locked=%d lockname=%s tname=%s\n",
971        h->locked,
972        h->lockname ? h->lockname : "(null)",
973        h->tname ? h->tname : "(null)");
974   if (h->locked && h->lockname)
975     unlink (h->lockname);
976   if (h->tname && !h->use_o_excl)
977     unlink (h->tname);
978   xfree (h->tname);
979 }
980 #endif /*HAVE_POSIX_SYSTEM*/
981
982
983 #ifdef HAVE_DOSISH_SYSTEM
984 /* Windows specific code of destroy_dotlock.  */
985 static void
986 dotlock_destroy_w32 (dotlock_t h)
987 {
988   if (h->locked)
989     {
990       OVERLAPPED ovl;
991
992       memset (&ovl, 0, sizeof ovl);
993       UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
994     }
995   CloseHandle (h->lockhd);
996 }
997 #endif /*HAVE_DOSISH_SYSTEM*/
998
999
1000 /* Destroy the lock handle H and release the lock.  */
1001 void
1002 dotlock_destroy (dotlock_t h)
1003 {
1004   dotlock_t hprev, htmp;
1005
1006   DLOG(h, "dotlock_destroy()\n");
1007   if ( !h )
1008     return;
1009
1010   /* First remove the handle from our global list of all locks. */
1011   LOCK_all_lockfiles ();
1012   for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
1013     if (htmp == h)
1014       {
1015         if (hprev)
1016           hprev->next = htmp->next;
1017         else
1018           all_lockfiles = htmp->next;
1019         h->next = NULL;
1020         break;
1021       }
1022   UNLOCK_all_lockfiles ();
1023
1024   /* Then destroy the lock. */
1025   if (!h->disable)
1026     {
1027 #ifdef HAVE_DOSISH_SYSTEM
1028       dotlock_destroy_w32 (h);
1029 #else /* !HAVE_DOSISH_SYSTEM */
1030       dotlock_destroy_unix (h);
1031 #endif /* HAVE_DOSISH_SYSTEM */
1032       xfree (h->lockname);
1033     }
1034   xfree(h);
1035 }
1036
1037
1038 \f
1039 #ifdef HAVE_POSIX_SYSTEM
1040 /* Unix specific code of make_dotlock.  Returns 0 on success and -1 on
1041    error.  */
1042 static int
1043 dotlock_take_unix (dotlock_t h, long timeout)
1044 {
1045   int wtime = 0;
1046   int sumtime = 0;
1047   int pid;
1048   int lastpid = -1;
1049   int ownerchanged;
1050   const char *maybe_dead="";
1051   int same_node;
1052   int saveerrno;
1053
1054   DLOG(h, "dotlock_create_unix(timeout=%ld) ...\n", timeout);
1055
1056  again:
1057   if (h->use_o_excl)
1058     {
1059       /* No hardlink support - use open(O_EXCL).  */
1060       int fd;
1061
1062       DLOG(h, "dotlock_take_unix() open...\n");
1063       do
1064         {
1065           my_set_errno (0);
1066           fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
1067                      S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
1068         }
1069       while (fd == -1 && errno == EINTR);
1070       DLOG(h, "dotlock_take_unix() open=%d E=%d...\n",fd,errno);
1071
1072       if (fd == -1 && errno == EEXIST)
1073         ; /* Lock held by another process.  */
1074       else if (fd == -1)
1075         {
1076           saveerrno = errno;
1077           my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
1078                       h->lockname, strerror (saveerrno));
1079           my_set_errno (saveerrno);
1080           DLOG(h, "dotlock_take_unix()=-1 (fd=-1) E=%d\n",errno);
1081           return -1;
1082         }
1083       else
1084         {
1085           char pidstr[16];
1086
1087           snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
1088           if (write (fd, pidstr, 11 ) == 11
1089               && write (fd, h->tname + h->nodename_off,h->nodename_len)
1090               == h->nodename_len
1091               && write (fd, "\n", 1) == 1
1092               && !close (fd))
1093             {
1094               h->locked = 1;
1095               DLOG(h, "dotlock_take_unix()=0 (write)\n");
1096               return 0;
1097             }
1098           /* Write error.  */
1099           saveerrno = errno;
1100           my_error_2 ("lock not made: writing to '%s' failed: %s\n",
1101                       h->lockname, strerror (errno));
1102           close (fd);
1103           unlink (h->lockname);
1104           my_set_errno (saveerrno);
1105           DLOG(h, "dotlock_take_unix()=-1 (write) E=%d\n",errno);
1106           return -1;
1107         }
1108     }
1109   else /* Standard method:  Use hardlinks.  */
1110     {
1111       struct stat sb;
1112
1113       /* We ignore the return value of link() because it is unreliable.  */
1114       (void) link (h->tname, h->lockname);
1115
1116       if (stat (h->tname, &sb))
1117         {
1118           saveerrno = errno;
1119           my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
1120                       strerror (errno));
1121           /* In theory this might be a severe error: It is possible
1122              that link succeeded but stat failed due to changed
1123              permissions.  We can't do anything about it, though.  */
1124           my_set_errno (saveerrno);
1125           DLOG(h, "dotlock_take_unix()=-1 (stat) E=%d\n",errno);
1126           return -1;
1127         }
1128
1129       if (sb.st_nlink == 2)
1130         {
1131           h->locked = 1;
1132           DLOG(h, "dotlock_take_unix()=0 (nlink)\n");
1133           return 0; /* Okay.  */
1134         }
1135     }
1136
1137   /* Check for stale lock files.  */
1138   if ( (pid = read_lockfile (h, &same_node)) == -1 )
1139     {
1140       if ( errno != ENOENT )
1141         {
1142           saveerrno = errno;
1143           my_info_0 ("cannot read lockfile\n");
1144           my_set_errno (saveerrno);
1145           DLOG(h, "dotlock_take_unix()=-1 (read) E=%d\n",errno);
1146           return -1;
1147         }
1148       my_info_0 ("lockfile disappeared\n");
1149       goto again;
1150     }
1151   else if ( pid == getpid() && same_node )
1152     {
1153       my_info_0 ("Oops: lock already held by us\n");
1154       h->locked = 1;
1155       DLOG(h, "dotlock_take_unix()=0 (oops)\n");
1156       return 0; /* okay */
1157     }
1158   else if ( same_node && kill (pid, 0) && errno == ESRCH )
1159     {
1160       /* Note: It is unlikley that we get a race here unless a pid is
1161          reused too fast or a new process with the same pid as the one
1162          of the stale file tries to lock right at the same time as we.  */
1163       my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
1164       unlink (h->lockname);
1165       DLOG(h, "dotlock_take_unix() again...\n");
1166       goto again;
1167     }
1168
1169   if (lastpid == -1)
1170     lastpid = pid;
1171   ownerchanged = (pid != lastpid);
1172
1173   if (timeout)
1174     {
1175       struct timeval tv;
1176
1177       /* Wait until lock has been released.  We use increasing retry
1178          intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
1179          but reset it if the lock owner meanwhile changed.  */
1180       if (!wtime || ownerchanged)
1181         wtime = 50;
1182       else if (wtime < 800)
1183         wtime *= 2;
1184       else if (wtime == 800)
1185         wtime = 2000;
1186       else if (wtime < 8000)
1187         wtime *= 2;
1188
1189       if (timeout > 0)
1190         {
1191           if (wtime > timeout)
1192             wtime = timeout;
1193           timeout -= wtime;
1194         }
1195
1196       sumtime += wtime;
1197       if (sumtime >= 1500)
1198         {
1199           sumtime = 0;
1200           my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
1201                      pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
1202         }
1203
1204
1205       tv.tv_sec = wtime / 1000;
1206       tv.tv_usec = (wtime % 1000) * 1000;
1207       select (0, NULL, NULL, NULL, &tv);
1208       goto again;
1209     }
1210
1211   my_set_errno (EACCES);
1212   DLOG(h, "dotlock_take_unix()=-1 (EACCES) E=%d\n",errno);
1213   return -1;
1214 }
1215 #endif /*HAVE_POSIX_SYSTEM*/
1216
1217
1218 #ifdef HAVE_DOSISH_SYSTEM
1219 /* Windows specific code of make_dotlock.  Returns 0 on success and -1 on
1220    error.  */
1221 static int
1222 dotlock_take_w32 (dotlock_t h, long timeout)
1223 {
1224   int wtime = 0;
1225   int w32err;
1226   OVERLAPPED ovl;
1227
1228  again:
1229   /* Lock one byte at offset 0.  The offset is given by OVL.  */
1230   memset (&ovl, 0, sizeof ovl);
1231   if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
1232                               | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
1233     {
1234       h->locked = 1;
1235       return 0; /* okay */
1236     }
1237
1238   w32err = GetLastError ();
1239   if (w32err != ERROR_LOCK_VIOLATION)
1240     {
1241       my_error_2 (_("lock '%s' not made: %s\n"),
1242                   h->lockname, w32_strerror (w32err));
1243       my_set_errno (map_w32_to_errno (w32err));
1244       return -1;
1245     }
1246
1247   if (timeout)
1248     {
1249       /* Wait until lock has been released.  We use retry intervals of
1250          50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s.  */
1251       if (!wtime)
1252         wtime = 50;
1253       else if (wtime < 800)
1254         wtime *= 2;
1255       else if (wtime == 800)
1256         wtime = 2000;
1257       else if (wtime < 8000)
1258         wtime *= 2;
1259
1260       if (timeout > 0)
1261         {
1262           if (wtime > timeout)
1263             wtime = timeout;
1264           timeout -= wtime;
1265         }
1266
1267       if (wtime >= 800)
1268         my_info_1 (_("waiting for lock %s...\n"), h->lockname);
1269
1270       Sleep (wtime);
1271       goto again;
1272     }
1273
1274   my_set_errno (EACCES);
1275   return -1;
1276 }
1277 #endif /*HAVE_DOSISH_SYSTEM*/
1278
1279
1280 /* Take a lock on H.  A value of 0 for TIMEOUT returns immediately if
1281    the lock can't be taked, -1 waits forever (hopefully not), other
1282    values wait for TIMEOUT milliseconds.  Returns: 0 on success  */
1283 int
1284 dotlock_take (dotlock_t h, long timeout)
1285 {
1286   int ret;
1287
1288   if ( h->disable )
1289     return 0; /* Locks are completely disabled.  Return success. */
1290
1291   if ( h->locked )
1292     {
1293       my_debug_1 ("Oops, '%s' is already locked\n", h->lockname);
1294       return 0;
1295     }
1296
1297 #ifdef HAVE_DOSISH_SYSTEM
1298   ret = dotlock_take_w32 (h, timeout);
1299 #else /*!HAVE_DOSISH_SYSTEM*/
1300   ret = dotlock_take_unix (h, timeout);
1301 #endif /*!HAVE_DOSISH_SYSTEM*/
1302
1303   return ret;
1304 }
1305
1306
1307 \f
1308 #ifdef HAVE_POSIX_SYSTEM
1309 /* Unix specific code of release_dotlock.  */
1310 static int
1311 dotlock_release_unix (dotlock_t h)
1312 {
1313   int pid, same_node;
1314   int saveerrno;
1315
1316   DLOG(h, "dotlock_release_unix...\n");
1317
1318   pid = read_lockfile (h, &same_node);
1319   if ( pid == -1 )
1320     {
1321       saveerrno = errno;
1322       my_error_0 ("release_dotlock: lockfile error\n");
1323       my_set_errno (saveerrno);
1324       DLOG(h, "dotlock_release_unix()=-1 (read) E=%d\n",errno);
1325       return -1;
1326     }
1327   if ( pid != getpid() || !same_node )
1328     {
1329       my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
1330       my_set_errno (EACCES);
1331       DLOG(h, "dotlock_release_unix()=-1 (not ours) E=%d\n",errno);
1332       return -1;
1333     }
1334
1335   if ( unlink( h->lockname ) )
1336     {
1337       saveerrno = errno;
1338       my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
1339                   h->lockname);
1340       my_set_errno (saveerrno);
1341       DLOG(h, "dotlock_release_unix()=-1 (unlink) E=%d\n",errno);
1342       return -1;
1343     }
1344   /* Fixme: As an extra check we could check whether the link count is
1345      now really at 1. */
1346   DLOG(h, "dotlock_release_unix()=0\n");
1347   return 0;
1348 }
1349 #endif /*HAVE_POSIX_SYSTEM */
1350
1351
1352 #ifdef HAVE_DOSISH_SYSTEM
1353 /* Windows specific code of release_dotlock.  */
1354 static int
1355 dotlock_release_w32 (dotlock_t h)
1356 {
1357   OVERLAPPED ovl;
1358
1359   memset (&ovl, 0, sizeof ovl);
1360   if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
1361     {
1362       int saveerrno = map_w32_to_errno (GetLastError ());
1363       my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
1364                   h->lockname, w32_strerror (-1));
1365       my_set_errno (saveerrno);
1366       return -1;
1367     }
1368
1369   return 0;
1370 }
1371 #endif /*HAVE_DOSISH_SYSTEM */
1372
1373
1374 /* Release a lock.  Returns 0 on success.  */
1375 int
1376 dotlock_release (dotlock_t h)
1377 {
1378   int ret;
1379   DLOG(h, "dotlock_release\n");
1380
1381   /* To avoid atexit race conditions we first check whether there are
1382      any locks left.  It might happen that another atexit handler
1383      tries to release the lock while the atexit handler of this module
1384      already ran and thus H is undefined.  */
1385   LOCK_all_lockfiles ();
1386   ret = !all_lockfiles;
1387   UNLOCK_all_lockfiles ();
1388   if (ret)
1389     return 0;
1390
1391   if ( h->disable )
1392     return 0;
1393
1394   if ( !h->locked )
1395     {
1396       my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
1397       return 0;
1398     }
1399
1400 #ifdef HAVE_DOSISH_SYSTEM
1401   ret = dotlock_release_w32 (h);
1402 #else
1403   ret = dotlock_release_unix (h);
1404 #endif
1405
1406   if (!ret)
1407     h->locked = 0;
1408   return ret;
1409 }
1410
1411
1412 \f
1413 /* Remove all lockfiles.  This is called by the atexit handler
1414    installed by this module but may also be called by other
1415    termination handlers.  */
1416 void
1417 dotlock_remove_lockfiles (void)
1418 {
1419   dotlock_t h, h2;
1420   DLOG(0, "dotlock_remove_lockfiles\n");
1421
1422   /* First set the lockfiles list to NULL so that for example
1423      dotlock_release is aware that this function is currently
1424      running.  */
1425
1426   LOCK_all_lockfiles ();
1427   h = all_lockfiles;
1428   all_lockfiles = NULL;
1429   UNLOCK_all_lockfiles ();
1430
1431   while ( h )
1432     {
1433       h2 = h->next;
1434       dotlock_destroy (h);
1435       h = h2;
1436     }
1437 }