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