Add a flag parameter to dotlock_create.
[gnupg.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 JNLIB, which is a subsystem of GnuPG.
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 /*
22    Overview:
23    =========
24
25    This module implements advisory file locking in a portable way.
26    Due to the problems with POSIX fcntl locking a separate lock file
27    is used.  It would be possible to use fcntl locking on this lock
28    file and thus avoid the weird auto unlock bug of POSIX while still
29    having an unproved better performance of fcntl locking.  However
30    there are still problems left, thus we resort to use a hardlink
31    which has the well defined property that a link call will fail if
32    the target file already exists.
33
34    Given that hardlinks are also available on NTFS file systems since
35    Windows XP; it will be possible to enhance this module to use
36    hardlinks even on Windows and thus allow Windows and Posix clients
37    to use locking on the same directory.  This is not yet implemented;
38    instead we use a lockfile on Windows along with W32 style file
39    locking.
40
41    On FAT file systems hardlinks are not supported.  Thus this method
42    does not work.  Our solution is to use a O_EXCL locking instead.
43    Querying the type of the file system is not easy to do in a
44    portable way (e.g. Linux has a statfs, BSDs have a the same call
45    but using different structures and constants).  What we do instead
46    is to check at runtime whether link(2) works for a specific lock
47    file.
48
49
50    How to use:
51    ===========
52
53    At program initialization time, the module should be explicitly
54    initialized:
55
56       dotlock_create (NULL, 0);
57
58    This installs an atexit handler and may also initialize mutex etc.
59    It is optional for non-threaded applications.  Only the first call
60    has an effect.
61
62    To create a lock file (which  prepares it but does not take the
63    lock) you do:
64
65      dotlock_t h
66
67      h = dotlock_create (fname, 0);
68      if (!h)
69        error ("error creating lock file: %s\n", strerror (errno));
70
71    It is important to handle the error.  For example on a read-only
72    file system a lock can't be created (but is usually not needed).
73    FNAME is the file you want to lock; the actual lockfile is that
74    name with the suffix ".lock" appended.  This call creates a unique
75    file temporary file (".#lk*") in the same directory as FNAME and
76    returns a handle for further operations.  The module keeps track of
77    theses unique files so that they will be unlinked using the atexit
78    handler.  If you don't need the lock file anymore, you may also
79    explicitly remove it with a call to:
80
81      dotlock_destroy (h);
82
83    To actually lock the file, you use:
84
85      if (dotlock_take (h, -1))
86        error ("error taking lock: %s\n", strerror (errno));
87
88    This function will wait until the lock is acquired.  If an
89    unexpected error occurs if will return non-zero and set ERRNO.  If
90    you pass (0) instead of (-1) the function does not wait in case the
91    file is already locked but returns -1 and sets ERRNO to EACCES.
92    Any other positive value for the second parameter is considered a
93    timeout valuie in milliseconds.
94
95    To release the lock you call:
96
97      if (dotlock_release (h))
98        error ("error releasing lock: %s\n", strerror (errno));
99
100    or, if the lock file is not anymore needed, you may call
101    dotlock_destroy.
102
103    If you want to explicitly destroy all lock files you may call
104
105      dotlock_remove_lockfiles ();
106
107    which is the core of the installed atexit handler.  In case your
108    application wants to disable locking completely it may call
109
110      disable_locking ()
111
112    before any locks are created.
113
114
115    How to build:
116    =============
117
118    This module was originally developed for GnuPG but later changed to
119    allow its use without any GnuPG dependency.  If you want to use it
120    with you application you may simply use it and it should figure out
121    most things automagically.
122
123    You may use the common config.h file to pass macros, but take care
124    to pass -DHAVE_CONFIG_H to the compiler.  Macros used by this
125    module are:
126
127      DOTLOCK_GLIB_LOGGING - Define this to use Glib logging functions.
128
129      GNUPG_MAJOR_VERSION - Defined when used by GnuPG.
130
131      HAVE_DOSISH_SYSTEM   - Defined for Windows etc.  Will be
132                             automatically defined if a the target is
133                             Windows.
134      HAVE_POSIX_SYSTEM    - Internally defined to !HAVE_DOSISH_SYSTEM.
135
136      HAVE_SIGNAL_H        - Should be defined on Posix systems.  If config.h
137                             is not used defaults to defined.
138
139      DIRSEP_C            - Separation character for file name parts.
140                            Usually not redefined.
141      EXTSEP_S "."        - Separation string for file name suffixes.
142                            Usually not redefined.
143
144      HAVE_W32CE_SYSTEM   - Currently only used by GnuPG.
145
146    Note that there is a test program t-dotlock which has compile
147    instructions at its end.  At least for SMBFS and CIFS it is
148    important that 64 bit versions of stat are used; most programming
149    environments do this these days, just in case you want to compile
150    it on the command line, remember to pass -D_FILE_OFFSET_BITS=64
151
152
153    Miscellaneous notes:
154    ====================
155
156    On hardlinks:
157    - Hardlinks are supported under Windows with NTFS since XP/Server2003.
158    - In Linux 2.6.33 both SMBFS and CIFS seem to support hardlinks.
159    - NFS supports hard links.  But there are solvable problems.
160    - FAT does not support links
161
162    On the file locking API:
163    - CIFS on Linux 2.6.33 supports several locking methods.
164      SMBFS seems not to support locking.  No closer checks done.
165    - NFS supports Posix locks.  flock is emulated in the server.
166      However there are a couple of problems; see below.
167    - FAT does not support locks.
168    - An advantage of fcntl locking is that R/W locks can be
169      implemented which is not easy with a straight lock file.
170
171    On O_EXCL:
172    - Does not work reliable on NFS
173    - Should work on CIFS and SMBFS but how can we delete lockfiles?
174
175    On NFS problems:
176    - Locks vanish if the server crashes and reboots.
177    - Client crashes keep the lock in the server until the client
178      re-connects.
179    - Communication problems may return unreliable error codes.  The
180      MUA Postfix's workaround is to compare the link count after
181      seeing an error for link.  However that gives a race.  If using a
182      unique file to link to a lockfile and using stat to check the
183      link count instead of looking at the error return of link(2) is
184      the best solution.
185    - O_EXCL seems to have a race and may re-create a file anyway.
186
187 */
188
189 #ifdef HAVE_CONFIG_H
190 # include <config.h>
191 #endif
192
193 /* Some quick replacements for stuff we usually expect to be defined
194    in config.h.  Define HAVE_POSIX_SYSTEM for better readability. */
195 #if !defined (HAVE_DOSISH_SYSTEM) && defined(_WIN32)
196 # define HAVE_DOSISH_SYSTEM 1
197 #endif
198 #if !defined (HAVE_DOSISH_SYSTEM) && !defined (HAVE_POSIX_SYSTEM)
199 # define HAVE_POSIX_SYSTEM 1
200 #endif
201
202 /* With no config.h assume that we have sitgnal.h.  */
203 #if !defined (HAVE_CONFIG_H) && defined (HAVE_POSIX_SYSTEM)
204 # define HAVE_SIGNAL_H 1
205 #endif
206
207 /* Standard headers.  */
208 #include <stdlib.h>
209 #include <stdio.h>
210 #include <string.h>
211 #include <errno.h>
212 #include <ctype.h>
213 #include <errno.h>
214 #include <unistd.h>
215 #ifdef  HAVE_DOSISH_SYSTEM
216 # define WIN32_LEAN_AND_MEAN  /* We only need the OS core stuff.  */
217 # include <windows.h>
218 #else
219 # include <sys/types.h>
220 # include <sys/stat.h>
221 # include <sys/utsname.h>
222 #endif
223 #include <sys/types.h>
224 #include <sys/time.h>
225 #include <sys/stat.h>
226 #include <fcntl.h>
227 #ifdef HAVE_SIGNAL_H
228 # include <signal.h>
229 #endif
230
231 #ifdef DOTLOCK_GLIB_LOGGING
232 # include <glib.h>
233 #endif
234
235 #ifdef GNUPG_MAJOR_VERSION
236 # include "libjnlib-config.h"
237 #endif
238 #ifdef HAVE_W32CE_SYSTEM
239 # include "utf8conv.h"  /* WindowsCE requires filename conversion.  */
240 #endif
241
242 #include "dotlock.h"
243
244
245 /* Define constants for file name construction.  */
246 #if !defined(DIRSEP_C) && !defined(EXTSEP_S)
247 # ifdef HAVE_DOSISH_SYSTEM
248 #  define DIRSEP_C '\\'
249 #  define EXTSEP_S "."
250 #else
251 #  define DIRSEP_C '/'
252 #  define EXTSEP_S "."
253 # endif
254 #endif
255
256 /* In GnuPG we use wrappers around the malloc fucntions.  If they are
257    not defined we assume that this code is used outside of GnuPG and
258    fall back to the regular malloc functions.  */
259 #ifndef jnlib_malloc
260 # define jnlib_malloc(a)     malloc ((a))
261 # define jnlib_calloc(a,b)   calloc ((a), (b))
262 # define jnlib_free(a)       free ((a))
263 #endif
264
265 /* Wrapper to set ERRNO.  */
266 #ifndef jnlib_set_errno
267 # ifdef HAVE_W32CE_SYSTEM
268 #  define jnlib_set_errno(e)  gpg_err_set_errno ((e))
269 # else
270 #  define jnlib_set_errno(e)  do { errno = (e); } while (0)
271 # endif
272 #endif
273
274 /* Gettext macro replacement.  */
275 #ifndef _
276 # define _(a) (a)
277 #endif
278
279 #ifdef GNUPG_MAJOR_VERSION
280 # define my_info_0(a)       log_info ((a))
281 # define my_info_1(a,b)     log_info ((a), (b))
282 # define my_info_2(a,b,c)   log_info ((a), (b), (c))
283 # define my_info_3(a,b,c,d) log_info ((a), (b), (c), (d))
284 # define my_error_0(a)      log_error ((a))
285 # define my_error_1(a,b)    log_error ((a), (b))
286 # define my_error_2(a,b,c)  log_error ((a), (b), (c))
287 # define my_debug_1(a,b)    log_debug ((a), (b))
288 #elif defined (DOTLOCK_GLIB_LOGGING)
289 # define my_info_0(a)       g_message ((a))
290 # define my_info_1(a,b)     g_message ((a), (b))
291 # define my_info_2(a,b,c)   g_message ((a), (b), (c))
292 # define my_info_3(a,b,c,d) g_message ((a), (b), (c), (d))
293 # define my_error_0(a)      g_warning ((a))
294 # define my_error_1(a,b)    g_warning ((a), (b))
295 # define my_error_2(a,b,c   g_warning ((a), (b), (c))
296 # define my_debug_1(a,b)    g_debug ((a), (b))
297 #else
298 # define my_info_0(a)       fprintf (stderr, (a))
299 # define my_info_1(a,b)     fprintf (stderr, (a), (b))
300 # define my_info_2(a,b,c)   fprintf (stderr, (a), (b), (c))
301 # define my_info_3(a,b,c,d) fprintf (stderr, (a), (b), (c), (d))
302 # define my_error_0(a)      fprintf (stderr, (a))
303 # define my_error_1(a,b)    fprintf (stderr, (a), (b))
304 # define my_error_2(a,b,c)  fprintf (stderr, (a), (b), (c))
305 # define my_debug_1(a,b)    fprintf (stderr, (a), (b))
306 #endif
307
308
309
310
311 \f
312 /* The object describing a lock.  */
313 struct dotlock_handle
314 {
315   struct dotlock_handle *next;
316   char *lockname;            /* Name of the actual lockfile.          */
317   unsigned int locked:1;     /* Lock status.                          */
318   unsigned int disable:1;    /* If true, locking is disabled.         */
319   unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking.        */
320
321 #ifdef HAVE_DOSISH_SYSTEM
322   HANDLE lockhd;       /* The W32 handle of the lock file.      */
323 #else /*!HAVE_DOSISH_SYSTEM */
324   char *tname;         /* Name of the lockfile template.        */
325   size_t nodename_off; /* Offset in TNAME of the nodename part. */
326   size_t nodename_len; /* Length of the nodename part.          */
327 #endif /*!HAVE_DOSISH_SYSTEM */
328 };
329
330
331 /* A list of of all lock handles.  The volatile attribute might help
332    if used in an atexit handler.  */
333 static volatile dotlock_t all_lockfiles;
334
335 /* If this has the value true all locking is disabled.  */
336 static int never_lock;
337
338
339 \f
340 /* Entirely disable all locking.  This function should be called
341    before any locking is done.  It may be called right at startup of
342    the process as it only sets a global value.  */
343 void
344 dotlock_disable (void)
345 {
346   never_lock = 1;
347 }
348
349
350 #ifdef HAVE_POSIX_SYSTEM
351 static int
352 maybe_deadlock (dotlock_t h)
353 {
354   dotlock_t r;
355
356   for ( r=all_lockfiles; r; r = r->next )
357     {
358       if ( r != h && r->locked )
359         return 1;
360     }
361   return 0;
362 }
363 #endif /*HAVE_POSIX_SYSTEM*/
364
365
366 /* Read the lock file and return the pid, returns -1 on error.  True
367    will be stored in the integer at address SAME_NODE if the lock file
368    has been created on the same node. */
369 #ifdef HAVE_POSIX_SYSTEM
370 static int
371 read_lockfile (dotlock_t h, int *same_node )
372 {
373   char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
374                                    names are usually shorter. */
375   int fd;
376   int pid = -1;
377   char *buffer, *p;
378   size_t expected_len;
379   int res, nread;
380
381   *same_node = 0;
382   expected_len = 10 + 1 + h->nodename_len + 1;
383   if ( expected_len >= sizeof buffer_space)
384     {
385       buffer = jnlib_malloc (expected_len);
386       if (!buffer)
387         return -1;
388     }
389   else
390     buffer = buffer_space;
391
392   if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
393     {
394       int e = errno;
395       my_info_2 ("error opening lockfile `%s': %s\n",
396                  h->lockname, strerror(errno) );
397       if (buffer != buffer_space)
398         jnlib_free (buffer);
399       jnlib_set_errno (e); /* Need to return ERRNO here. */
400       return -1;
401     }
402
403   p = buffer;
404   nread = 0;
405   do
406     {
407       res = read (fd, p, expected_len - nread);
408       if (res == -1 && errno == EINTR)
409         continue;
410       if (res < 0)
411         {
412           my_info_1 ("error reading lockfile `%s'\n", h->lockname );
413           close (fd);
414           if (buffer != buffer_space)
415             jnlib_free (buffer);
416           jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */
417           return -1;
418         }
419       p += res;
420       nread += res;
421     }
422   while (res && nread != expected_len);
423   close(fd);
424
425   if (nread < 11)
426     {
427       my_info_1 ("invalid size of lockfile `%s'\n", h->lockname);
428       if (buffer != buffer_space)
429         jnlib_free (buffer);
430       jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */
431       return -1;
432     }
433
434   if (buffer[10] != '\n'
435       || (buffer[10] = 0, pid = atoi (buffer)) == -1
436       || !pid )
437     {
438       my_error_2 ("invalid pid %d in lockfile `%s'\n", pid, h->lockname);
439       if (buffer != buffer_space)
440         jnlib_free (buffer);
441       jnlib_set_errno (0);
442       return -1;
443     }
444
445   if (nread == expected_len
446       && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
447       && buffer[11+h->nodename_len] == '\n')
448     *same_node = 1;
449
450   if (buffer != buffer_space)
451     jnlib_free (buffer);
452   return pid;
453 }
454 #endif /*HAVE_POSIX_SYSTEM */
455
456
457 /* Check whether the file system which stores TNAME supports
458    hardlinks.  Instead of using the non-portable statsfs call which
459    differs between various Unix versions, we do a runtime test.
460    Returns: 0 supports hardlinks; 1 no hardlink support, -1 unknown
461    (test error).  */
462 #ifdef HAVE_POSIX_SYSTEM
463 static int
464 use_hardlinks_p (const char *tname)
465 {
466   char *lname;
467   struct stat sb;
468   unsigned int nlink;
469   int res;
470
471   if (stat (tname, &sb))
472     return -1;
473   nlink = (unsigned int)sb.st_nlink;
474
475   lname = jnlib_malloc (strlen (tname) + 1 + 1);
476   if (!lname)
477     return -1;
478   strcpy (lname, tname);
479   strcat (lname, "x");
480
481   link (tname, lname);
482
483   if (stat (tname, &sb))
484     res = -1;  /* Ooops.  */
485   else if (sb.st_nlink == nlink + 1)
486     res = 0;   /* Yeah, hardlinks are supported.  */
487   else
488     res = 1;   /* No hardlink support.  */
489
490   unlink (lname);
491   jnlib_free (lname);
492   return res;
493 }
494 #endif /*HAVE_POSIX_SYSTEM */
495
496
497 \f
498 #ifdef  HAVE_POSIX_SYSTEM
499 /* Locking core for Unix.  It used a temporary file and the link
500    system call to make locking an atomic operation. */
501 static dotlock_t
502 dotlock_create_unix (dotlock_t h, const char *file_to_lock)
503 {
504   int  fd = -1;
505   char pidstr[16];
506   const char *nodename;
507   const char *dirpart;
508   int dirpartlen;
509   struct utsname utsbuf;
510   size_t tnamelen;
511
512   snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
513
514   /* Create a temporary file. */
515   if ( uname ( &utsbuf ) )
516     nodename = "unknown";
517   else
518     nodename = utsbuf.nodename;
519
520   if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
521     {
522       dirpart = EXTSEP_S;
523       dirpartlen = 1;
524     }
525   else
526     {
527       dirpartlen = dirpart - file_to_lock;
528       dirpart = file_to_lock;
529     }
530
531 #ifdef _REENTRANT
532     /* fixme: aquire mutex on all_lockfiles */
533 #endif
534   h->next = all_lockfiles;
535   all_lockfiles = h;
536
537   tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
538   h->tname = jnlib_malloc (tnamelen + 1);
539   if (!h->tname)
540     {
541       all_lockfiles = h->next;
542       jnlib_free (h);
543       return NULL;
544     }
545   h->nodename_len = strlen (nodename);
546
547   snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
548   h->nodename_off = strlen (h->tname);
549   snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
550            "%s.%d", nodename, (int)getpid ());
551
552   do
553     {
554       jnlib_set_errno (0);
555       fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
556                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
557     }
558   while (fd == -1 && errno == EINTR);
559
560   if ( fd == -1 )
561     {
562       all_lockfiles = h->next;
563       my_error_2 (_("failed to create temporary file `%s': %s\n"),
564                   h->tname, strerror(errno));
565       jnlib_free (h->tname);
566       jnlib_free (h);
567       return NULL;
568     }
569   if ( write (fd, pidstr, 11 ) != 11 )
570     goto write_failed;
571   if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
572     goto write_failed;
573   if ( write (fd, "\n", 1 ) != 1 )
574     goto write_failed;
575   if ( close (fd) )
576     goto write_failed;
577
578   /* Check whether we support hard links.  */
579   switch (use_hardlinks_p (h->tname))
580     {
581     case 0: /* Yes.  */
582       break;
583     case 1: /* No.  */
584       unlink (h->tname);
585       h->use_o_excl = 1;
586       break;
587     default:
588       my_error_2 ("can't check whether hardlinks are supported for `%s': %s\n",
589                   h->tname, strerror(errno));
590       goto write_failed;
591     }
592
593 # ifdef _REENTRANT
594   /* release mutex */
595 # endif
596   h->lockname = jnlib_malloc (strlen (file_to_lock) + 6 );
597   if (!h->lockname)
598     {
599       all_lockfiles = h->next;
600       unlink (h->tname);
601       jnlib_free (h->tname);
602       jnlib_free (h);
603       return NULL;
604     }
605   strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
606   if (h->use_o_excl)
607     my_debug_1 ("locking for `%s' done via O_EXCL\n", h->lockname);
608
609   return h;
610
611  write_failed:
612   all_lockfiles = h->next;
613 # ifdef _REENTRANT
614   /* fixme: release mutex */
615 # endif
616   my_error_2 (_("error writing to `%s': %s\n"), h->tname, strerror (errno));
617   close (fd);
618   unlink (h->tname);
619   jnlib_free (h->tname);
620   jnlib_free (h);
621   return NULL;
622 }
623 #endif /*HAVE_POSIX_SYSTEM*/
624
625
626 #ifdef HAVE_DOSISH_SYSTEM
627 /* Locking core for Windows.  This version does not need a temporary
628    file but uses the plain lock file along with record locking.  We
629    create this file here so that we later only need to do the file
630    locking.  For error reporting it is useful to keep the name of the
631    file in the handle.  */
632 static dotlock_t
633 dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
634 {
635   h->next = all_lockfiles;
636   all_lockfiles = h;
637
638   h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
639   if (!h->lockname)
640     {
641       all_lockfiles = h->next;
642       jnlib_free (h);
643       return NULL;
644     }
645   strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
646
647   /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
648      along with FILE_SHARE_DELETE but that does not work due to a race
649      condition: Despite the OPEN_ALWAYS flag CreateFile may return an
650      error and we can't reliable create/open the lock file unless we
651      would wait here until it works - however there are other valid
652      reasons why a lock file can't be created and thus the process
653      would not stop as expected but spin until Windows crashes.  Our
654      solution is to keep the lock file open; that does not harm. */
655   {
656 #ifdef HAVE_W32CE_SYSTEM
657     wchar_t *wname = utf8_to_wchar (h->lockname);
658
659     if (wname)
660       h->lockhd = CreateFile (wname,
661                               GENERIC_READ|GENERIC_WRITE,
662                               FILE_SHARE_READ|FILE_SHARE_WRITE,
663                               NULL, OPEN_ALWAYS, 0, NULL);
664     else
665       h->lockhd = INVALID_HANDLE_VALUE;
666     jnlib_free (wname);
667 #else
668     h->lockhd = CreateFile (h->lockname,
669                             GENERIC_READ|GENERIC_WRITE,
670                             FILE_SHARE_READ|FILE_SHARE_WRITE,
671                             NULL, OPEN_ALWAYS, 0, NULL);
672 #endif
673   }
674   if (h->lockhd == INVALID_HANDLE_VALUE)
675     {
676       my_error_2 (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
677       all_lockfiles = h->next;
678       jnlib_free (h->lockname);
679       jnlib_free (h);
680       return NULL;
681     }
682   return h;
683 }
684 #endif /*HAVE_DOSISH_SYSTEM*/
685
686
687 /* Create a lockfile for a file name FILE_TO_LOCK and returns an
688    object of type dotlock_t which may be used later to actually acquire
689    the lock.  A cleanup routine gets installed to cleanup left over
690    locks or other files used internally by the lock mechanism.
691
692    Calling this function with NULL does only install the atexit
693    handler and may thus be used to assure that the cleanup is called
694    after all other atexit handlers.
695
696    This function creates a lock file in the same directory as
697    FILE_TO_LOCK using that name and a suffix of ".lock".  Note that on
698    POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
699    used.
700
701    FLAGS must be 0.
702
703    The function returns an new handle which needs to be released using
704    destroy_dotlock but gets also released at the termination of the
705    process.  On error NULL is returned.
706  */
707
708 dotlock_t
709 dotlock_create (const char *file_to_lock, unsigned int flags)
710 {
711   static int initialized;
712   dotlock_t h;
713
714   if ( !initialized )
715     {
716       atexit (dotlock_remove_lockfiles);
717       initialized = 1;
718     }
719
720   if ( !file_to_lock )
721     return NULL;  /* Only initialization was requested.  */
722
723   if (flags)
724     {
725       jnlib_set_errno (EINVAL);
726       return NULL;
727     }
728
729   h = jnlib_calloc (1, sizeof *h);
730   if (!h)
731     return NULL;
732
733   if (never_lock)
734     {
735       h->disable = 1;
736 #ifdef _REENTRANT
737       /* fixme: aquire mutex on all_lockfiles */
738 #endif
739       h->next = all_lockfiles;
740       all_lockfiles = h;
741       return h;
742     }
743
744 #ifdef HAVE_DOSISH_SYSTEM
745   return dotlock_create_w32 (h, file_to_lock);
746 #else /*!HAVE_DOSISH_SYSTEM */
747   return dotlock_create_unix (h, file_to_lock);
748 #endif /*!HAVE_DOSISH_SYSTEM*/
749 }
750
751
752 \f
753 #ifdef HAVE_POSIX_SYSTEM
754 /* Unix specific code of destroy_dotlock.  */
755 static void
756 dotlock_destroy_unix (dotlock_t h)
757 {
758   if (h->locked && h->lockname)
759     unlink (h->lockname);
760   if (h->tname && !h->use_o_excl)
761     unlink (h->tname);
762   jnlib_free (h->tname);
763 }
764 #endif /*HAVE_POSIX_SYSTEM*/
765
766
767 #ifdef HAVE_DOSISH_SYSTEM
768 /* Windows specific code of destroy_dotlock.  */
769 static void
770 dotlock_destroy_w32 (dotlock_t h)
771 {
772   if (h->locked)
773     {
774       OVERLAPPED ovl;
775
776       memset (&ovl, 0, sizeof ovl);
777       UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
778     }
779   CloseHandle (h->lockhd);
780 }
781 #endif /*HAVE_DOSISH_SYSTEM*/
782
783
784 /* Destroy the locck handle H and release the lock.  */
785 void
786 dotlock_destroy (dotlock_t h)
787 {
788   dotlock_t hprev, htmp;
789
790   if ( !h )
791     return;
792
793   /* First remove the handle from our global list of all locks. */
794   for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
795     if (htmp == h)
796       {
797         if (hprev)
798           hprev->next = htmp->next;
799         else
800           all_lockfiles = htmp->next;
801         h->next = NULL;
802         break;
803       }
804
805   /* Then destroy the lock. */
806   if (!h->disable)
807     {
808 #ifdef HAVE_DOSISH_SYSTEM
809       dotlock_destroy_w32 (h);
810 #else /* !HAVE_DOSISH_SYSTEM */
811       dotlock_destroy_unix (h);
812 #endif /* HAVE_DOSISH_SYSTEM */
813       jnlib_free (h->lockname);
814     }
815   jnlib_free(h);
816 }
817
818
819 \f
820 #ifdef HAVE_POSIX_SYSTEM
821 /* Unix specific code of make_dotlock.  Returns 0 on success and -1 on
822    error.  */
823 static int
824 dotlock_take_unix (dotlock_t h, long timeout)
825 {
826   int wtime = 0;
827   int sumtime = 0;
828   int pid;
829   int lastpid = -1;
830   int ownerchanged;
831   const char *maybe_dead="";
832   int same_node;
833
834  again:
835   if (h->use_o_excl)
836     {
837       /* No hardlink support - use open(O_EXCL).  */
838       int fd;
839
840       do
841         {
842           jnlib_set_errno (0);
843           fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
844                      S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
845         }
846       while (fd == -1 && errno == EINTR);
847
848       if (fd == -1 && errno == EEXIST)
849         ; /* Lock held by another process.  */
850       else if (fd == -1)
851         {
852           my_error_2 ("lock not made: open(O_EXCL) of `%s' failed: %s\n",
853                       h->lockname, strerror (errno));
854           return -1;
855         }
856       else
857         {
858           char pidstr[16];
859
860           snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
861           if (write (fd, pidstr, 11 ) == 11
862               && write (fd, h->tname + h->nodename_off,h->nodename_len)
863               == h->nodename_len
864               && write (fd, "\n", 1) == 1
865               && !close (fd))
866             {
867               h->locked = 1;
868               return 0;
869             }
870           /* Write error.  */
871           my_error_2 ("lock not made: writing to `%s' failed: %s\n",
872                       h->lockname, strerror (errno));
873           close (fd);
874           unlink (h->lockname);
875           return -1;
876         }
877     }
878   else /* Standard method:  Use hardlinks.  */
879     {
880       struct stat sb;
881
882       link (h->tname, h->lockname);
883
884       if (stat (h->tname, &sb))
885         {
886           my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
887                       strerror (errno));
888           /* In theory this might be a severe error: It is possible
889              that link succeeded but stat failed due to changed
890              permissions.  We can't do anything about it, though.  */
891           return -1;
892         }
893
894       if (sb.st_nlink == 2)
895         {
896           h->locked = 1;
897           return 0; /* Okay.  */
898         }
899     }
900
901   /* Check for stale lock files.  */
902   if ( (pid = read_lockfile (h, &same_node)) == -1 )
903     {
904       if ( errno != ENOENT )
905         {
906           my_info_0 ("cannot read lockfile\n");
907           return -1;
908         }
909       my_info_0 ("lockfile disappeared\n");
910       goto again;
911     }
912   else if ( pid == getpid() && same_node )
913     {
914       my_info_0 ("Oops: lock already held by us\n");
915       h->locked = 1;
916       return 0; /* okay */
917     }
918   else if ( same_node && kill (pid, 0) && errno == ESRCH )
919     {
920       /* Note: It is unlikley that we get a race here unless a pid is
921          reused too fast or a new process with the same pid as the one
922          of the stale file tries to lock right at the same time as we.  */
923       my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
924       unlink (h->lockname);
925       goto again;
926     }
927
928   if (lastpid == -1)
929     lastpid = pid;
930   ownerchanged = (pid != lastpid);
931
932   if (timeout)
933     {
934       struct timeval tv;
935
936       /* Wait until lock has been released.  We use increasing retry
937          intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
938          but reset it if the lock owner meanwhile changed.  */
939       if (!wtime || ownerchanged)
940         wtime = 50;
941       else if (wtime < 800)
942         wtime *= 2;
943       else if (wtime == 800)
944         wtime = 2000;
945       else if (wtime < 8000)
946         wtime *= 2;
947
948       if (timeout > 0)
949         {
950           if (wtime > timeout)
951             wtime = timeout;
952           timeout -= wtime;
953         }
954
955       sumtime += wtime;
956       if (sumtime >= 1500)
957         {
958           sumtime = 0;
959           my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
960                      pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
961         }
962
963
964       tv.tv_sec = wtime / 1000;
965       tv.tv_usec = (wtime % 1000) * 1000;
966       select (0, NULL, NULL, NULL, &tv);
967       goto again;
968     }
969
970   jnlib_set_errno (EACCES);
971   return -1;
972 }
973 #endif /*HAVE_POSIX_SYSTEM*/
974
975
976 #ifdef HAVE_DOSISH_SYSTEM
977 /* Windows specific code of make_dotlock.  Returns 0 on success and -1 on
978    error.  */
979 static int
980 dotlock_take_w32 (dotlock_t h, long timeout)
981 {
982   int wtime = 0;
983   int w32err;
984   OVERLAPPED ovl;
985
986  again:
987   /* Lock one byte at offset 0.  The offset is given by OVL.  */
988   memset (&ovl, 0, sizeof ovl);
989   if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
990                               | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
991     {
992       h->locked = 1;
993       return 0; /* okay */
994     }
995
996   w32err = GetLastError ();
997   if (w32err != ERROR_LOCK_VIOLATION)
998     {
999       my_error_2 (_("lock `%s' not made: %s\n"),
1000                   h->lockname, w32_strerror (w32err));
1001       return -1;
1002     }
1003
1004   if (timeout)
1005     {
1006       /* Wait until lock has been released.  We use retry intervals of
1007          50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s.  */
1008       if (!wtime)
1009         wtime = 50;
1010       else if (wtime < 800)
1011         wtime *= 2;
1012       else if (wtime == 800)
1013         wtime = 2000;
1014       else if (wtime < 8000)
1015         wtime *= 2;
1016
1017       if (timeout > 0)
1018         {
1019           if (wtime > timeout)
1020             wtime = timeout;
1021           timeout -= wtime;
1022         }
1023
1024       if (wtime >= 800)
1025         my_info_1 (_("waiting for lock %s...\n"), h->lockname);
1026
1027       Sleep (wtime);
1028       goto again;
1029     }
1030
1031   return -1;
1032 }
1033 #endif /*HAVE_DOSISH_SYSTEM*/
1034
1035
1036 /* Take a lock on H.  A value of 0 for TIMEOUT returns immediately if
1037    the lock can't be taked, -1 waits forever (hopefully not), other
1038    values wait for TIMEOUT milliseconds.  Returns: 0 on success  */
1039 int
1040 dotlock_take (dotlock_t h, long timeout)
1041 {
1042   int ret;
1043
1044   if ( h->disable )
1045     return 0; /* Locks are completely disabled.  Return success. */
1046
1047   if ( h->locked )
1048     {
1049       my_debug_1 ("Oops, `%s' is already locked\n", h->lockname);
1050       return 0;
1051     }
1052
1053 #ifdef HAVE_DOSISH_SYSTEM
1054   ret = dotlock_take_w32 (h, timeout);
1055 #else /*!HAVE_DOSISH_SYSTEM*/
1056   ret = dotlock_take_unix (h, timeout);
1057 #endif /*!HAVE_DOSISH_SYSTEM*/
1058
1059   return ret;
1060 }
1061
1062
1063 \f
1064 #ifdef HAVE_POSIX_SYSTEM
1065 /* Unix specific code of release_dotlock.  */
1066 static int
1067 dotlock_release_unix (dotlock_t h)
1068 {
1069   int pid, same_node;
1070
1071   pid = read_lockfile (h, &same_node);
1072   if ( pid == -1 )
1073     {
1074       my_error_0 ("release_dotlock: lockfile error\n");
1075       return -1;
1076     }
1077   if ( pid != getpid() || !same_node )
1078     {
1079       my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
1080       return -1;
1081     }
1082
1083   if ( unlink( h->lockname ) )
1084     {
1085       my_error_1 ("release_dotlock: error removing lockfile `%s'\n",
1086                   h->lockname);
1087       return -1;
1088     }
1089   /* Fixme: As an extra check we could check whether the link count is
1090      now really at 1. */
1091   return 0;
1092 }
1093 #endif /*HAVE_POSIX_SYSTEM */
1094
1095
1096 #ifdef HAVE_DOSISH_SYSTEM
1097 /* Windows specific code of release_dotlock.  */
1098 static int
1099 dotlock_release_w32 (dotlock_t h)
1100 {
1101   OVERLAPPED ovl;
1102
1103   memset (&ovl, 0, sizeof ovl);
1104   if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
1105     {
1106       my_error_2 ("release_dotlock: error removing lockfile `%s': %s\n",
1107                   h->lockname, w32_strerror (-1));
1108       return -1;
1109     }
1110
1111   return 0;
1112 }
1113 #endif /*HAVE_DOSISH_SYSTEM */
1114
1115
1116 /* Release a lock.  Returns 0 on success.  */
1117 int
1118 dotlock_release (dotlock_t h)
1119 {
1120   int ret;
1121
1122   /* To avoid atexit race conditions we first check whether there are
1123      any locks left.  It might happen that another atexit handler
1124      tries to release the lock while the atexit handler of this module
1125      already ran and thus H is undefined.  */
1126   if (!all_lockfiles)
1127     return 0;
1128
1129   if ( h->disable )
1130     return 0;
1131
1132   if ( !h->locked )
1133     {
1134       my_debug_1 ("Oops, `%s' is not locked\n", h->lockname);
1135       return 0;
1136     }
1137
1138 #ifdef HAVE_DOSISH_SYSTEM
1139   ret = dotlock_release_w32 (h);
1140 #else
1141   ret = dotlock_release_unix (h);
1142 #endif
1143
1144   if (!ret)
1145     h->locked = 0;
1146   return ret;
1147 }
1148
1149
1150 \f
1151 /* Remove all lockfiles.  This is usually called by the atexit handler
1152    installed by this module but may also be called by other
1153    termination handlers.  */
1154 void
1155 dotlock_remove_lockfiles (void)
1156 {
1157   dotlock_t h, h2;
1158
1159   h = all_lockfiles;
1160   all_lockfiles = NULL;
1161
1162   while ( h )
1163     {
1164       h2 = h->next;
1165       dotlock_destroy (h);
1166       h = h2;
1167     }
1168 }