Implement dotlocking for W32.
[gnupg.git] / jnlib / dotlock.c
1 /* dotlock.c - dotfile locking
2  * Copyright (C) 1998, 2000, 2001, 2003, 2004, 
3  *               2005, 2006, 2008 Free Software Foundation, Inc.
4  *
5  * This file is part of JNLIB.
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 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #ifdef  HAVE_DOSISH_SYSTEM
29 # define WIN32_LEAN_AND_MEAN
30 # include <windows.h>
31 #else
32 # include <sys/utsname.h>
33 #endif
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <signal.h>
39
40 #include "libjnlib-config.h"
41 #include "stringhelp.h"
42 #include "dotlock.h"
43
44 #if !defined(DIRSEP_C) && !defined(EXTSEP_C) \
45     && !defined(DIRSEP_S) && !defined(EXTSEP_S)
46 #ifdef HAVE_DOSISH_SYSTEM
47 #define DIRSEP_C '\\'
48 #define EXTSEP_C '.'
49 #define DIRSEP_S "\\"
50 #define EXTSEP_S "."
51 #else
52 #define DIRSEP_C '/'
53 #define EXTSEP_C '.'
54 #define DIRSEP_S "/"
55 #define EXTSEP_S "."
56 #endif
57 #endif
58
59
60 /* The object describing a lock.  */
61 struct dotlock_handle 
62 {
63   struct dotlock_handle *next;
64   char *lockname;      /* Name of the actual lockfile.          */
65   int locked;          /* Lock status.                          */
66   int disable;         /* If true, locking is disabled.         */
67
68 #ifdef HAVE_DOSISH_SYSTEM
69   HANDLE lockhd;       /* The W32 handle of the lock file.      */
70 #else
71   char *tname;         /* Name of the lockfile template.        */
72   size_t nodename_off; /* Offset in TNAME of the nodename part. */
73   size_t nodename_len; /* Length of the nodename part.          */
74 #endif /* HAVE_DOSISH_SYSTEM */
75 };
76
77
78 /* A list of of all lock handles. */
79 static volatile DOTLOCK all_lockfiles;
80
81 /* If this has the value true all locking is disabled.  */
82 static int never_lock;
83
84
85 /* Local protototypes.  */
86 #ifndef HAVE_DOSISH_SYSTEM
87 static int read_lockfile (DOTLOCK h, int *same_node);
88 #endif /*!HAVE_DOSISH_SYSTEM*/
89
90
91
92 \f
93 /* Entirely disable all locking.  This function should be called
94    before any locking is done.  It may be called right at startup of
95    the process as it only sets a global value.  */
96 void
97 disable_dotlock(void)
98 {
99   never_lock = 1;
100 }
101
102
103
104 /* Create a lockfile for a file name FILE_TO_LOCK and returns an
105    object of type DOTLOCK which may be used later to actually acquire
106    the lock.  A cleanup routine gets installed to cleanup left over
107    locks or other files used internally by the lock mechanism.
108
109    Calling this function with NULL does only install the atexit
110    handler and may thus be used to assure that the cleanup is called
111    after all other atexit handlers.
112   
113    This function creates a lock file in the same directory as
114    FILE_TO_LOCK using that name and a suffix of ".lock".  Note that on
115    POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
116    used.
117
118    The function returns an new handle which needs to be released using
119    destroy_dotlock but gets also released at the termination of the
120    process.  On error NULL is returned.
121  */
122 DOTLOCK
123 create_dotlock (const char *file_to_lock)
124 {
125   static int initialized;
126   DOTLOCK h;
127 #ifndef  HAVE_DOSISH_SYSTEM
128   int  fd = -1;
129   char pidstr[16];
130   const char *nodename;
131   const char *dirpart;
132   int dirpartlen;
133   struct utsname utsbuf;
134   size_t tnamelen;
135 #endif
136
137   if ( !initialized )
138     {
139       atexit (dotlock_remove_lockfiles);
140       initialized = 1;
141     }
142
143   if ( !file_to_lock )
144     return NULL;  /* Only initialization was requested.  */
145
146   h = jnlib_calloc (1, sizeof *h);
147   if (!h)
148     return NULL;
149
150   if (never_lock)
151     {
152       h->disable = 1;
153 #ifdef _REENTRANT
154       /* fixme: aquire mutex on all_lockfiles */
155 #endif
156       h->next = all_lockfiles;
157       all_lockfiles = h;
158       return h;
159     }
160
161 #ifndef HAVE_DOSISH_SYSTEM
162   /*
163      This is the POSIX version which uses a temporary file and the
164      link system call to make locking an atomic operation.
165    */
166
167   snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
168   /* fixme: add the hostname to the second line (FQDN or IP addr?) */
169
170   /* Create a temporary file. */
171   if ( uname ( &utsbuf ) )
172     nodename = "unknown";
173   else
174     nodename = utsbuf.nodename;
175   
176 #ifdef __riscos__
177   {
178     char *iter = (char *) nodename;
179     for (; iter[0]; iter++)
180       if (iter[0] == '.')
181         iter[0] = '/';
182   }
183 #endif /* __riscos__ */
184
185   if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
186     {
187       dirpart = EXTSEP_S;
188       dirpartlen = 1;
189     }
190   else
191     {
192       dirpartlen = dirpart - file_to_lock;
193       dirpart = file_to_lock;
194     }
195
196 #ifdef _REENTRANT
197     /* fixme: aquire mutex on all_lockfiles */
198 #endif
199   h->next = all_lockfiles;
200   all_lockfiles = h;
201
202   tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10;
203   h->tname = jnlib_malloc (tnamelen + 1);
204   if (!h->tname)
205     {
206       all_lockfiles = h->next;
207       jnlib_free (h);
208       return NULL;
209     }
210   h->nodename_len = strlen (nodename);
211
212 #ifndef __riscos__
213   snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
214   h->nodename_off = strlen (h->tname);
215   snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
216            "%s.%d", nodename, (int)getpid ());
217 #else /* __riscos__ */
218   snprintf (h->tname, tnamelen, "%.*s.lk%p/", dirpartlen, dirpart, h );
219   h->nodename_off = strlen (h->tname);
220   snprintf (h->tname+h->nodename_off, tnamelen - h->modename_off,
221             "%s/%d", nodename, (int)getpid () );
222 #endif /* __riscos__ */
223
224   do 
225     {
226       errno = 0;
227       fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
228                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
229     } 
230   while (fd == -1 && errno == EINTR);
231
232   if ( fd == -1 ) 
233     {
234       all_lockfiles = h->next;
235       log_error (_("failed to create temporary file `%s': %s\n"),
236                   h->tname, strerror(errno));
237       jnlib_free (h->tname);
238       jnlib_free (h);
239       return NULL;
240     }
241   if ( write (fd, pidstr, 11 ) != 11 )
242     goto write_failed;
243   if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
244     goto write_failed;
245   if ( write (fd, "\n", 1 ) != 1 )
246     goto write_failed;
247   if ( close (fd) )
248     goto write_failed;
249
250 # ifdef _REENTRANT
251   /* release mutex */
252 # endif
253   h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
254   if (!h->lockname)
255     {
256       all_lockfiles = h->next;
257       unlink (h->tname);
258       jnlib_free (h->tname);
259       jnlib_free (h);
260       return NULL;
261     }
262   strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
263   return h;
264
265  write_failed:
266   all_lockfiles = h->next;
267 # ifdef _REENTRANT
268   /* fixme: release mutex */
269 # endif
270   log_error ( _("error writing to `%s': %s\n"), h->tname, strerror(errno) );
271   close (fd);
272   unlink (h->tname);
273   jnlib_free (h->tname);
274   jnlib_free (h);
275   return NULL;
276
277 #else /* HAVE_DOSISH_SYSTEM */
278
279   /* The Windows version does not need a temporary file but uses the
280      plain lock file along with record locking.  We create this file
281      here so that we later do only need to do the file locking.  For
282      error reporting it is useful to keep the name of the file in the
283      handle.  */
284   h->next = all_lockfiles;
285   all_lockfiles = h;
286
287   h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
288   if (!h->lockname)
289     {
290       all_lockfiles = h->next;
291       jnlib_free (h);
292       return NULL;
293     }
294   strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
295
296   /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
297      along with FILE_SHARE_DELETE but that does not work due to a race
298      condition: Despite the OPEN_ALWAYS flag CreateFile may return an
299      error and we can't reliable create/open the lock file unless we
300      would wait here until it works - however there are other valid
301      reasons why a lock file can't be created and thus the process
302      would not stop as expected but spin til until Windows crashes.
303      Our solution is to keep the lock file open; that does not
304      harm. */ 
305   h->lockhd = CreateFile (h->lockname,
306                           GENERIC_READ|GENERIC_WRITE,
307                           FILE_SHARE_READ|FILE_SHARE_WRITE,
308                           NULL, OPEN_ALWAYS, 0, NULL);
309   if (h->lockhd == INVALID_HANDLE_VALUE)
310     {
311       log_error (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
312       all_lockfiles = h->next;
313       jnlib_free (h->lockname);
314       jnlib_free (h);
315       return NULL;
316     }
317   return h;
318
319 #endif /* HAVE_DOSISH_SYSTEM */
320 }
321
322
323 /* Destroy the local handle H and release the lock. */
324 void
325 destroy_dotlock ( DOTLOCK h )
326 {
327   DOTLOCK hprev, htmp;
328
329   if ( !h )
330     return;
331
332   /* First remove the handle from our global list of all locks. */
333   for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
334     if (htmp == h)
335       {
336         if (hprev)
337           hprev->next = htmp->next;
338         else
339           all_lockfiles = htmp->next;
340         h->next = NULL;
341         break;
342       }
343   
344   /* Then destroy the lock. */
345   if (!h->disable)
346     {
347 #ifdef HAVE_DOSISH_SYSTEM
348       if (h->locked)
349         {
350           UnlockFile (h->lockhd, 0, 0, 1, 0);
351         }
352       CloseHandle (h->lockhd);
353 #else /* !HAVE_DOSISH_SYSTEM */
354       if (h->locked && h->lockname)
355         unlink (h->lockname);
356       if (h->tname)
357         unlink (h->tname);
358       jnlib_free (h->tname);
359 #endif /* HAVE_DOSISH_SYSTEM */
360       jnlib_free (h->lockname);
361     }
362   jnlib_free(h);
363 }
364
365
366 #ifndef HAVE_DOSISH_SYSTEM
367 static int
368 maybe_deadlock( DOTLOCK h )
369 {
370   DOTLOCK r;
371
372   for ( r=all_lockfiles; r; r = r->next )
373     {
374       if ( r != h && r->locked )
375         return 1;
376     }
377   return 0;
378 }
379 #endif /*!HAVE_DOSISH_SYSTEM*/
380
381
382
383 /* Do a lock on H. A TIMEOUT of 0 returns immediately, -1 waits
384    forever (hopefully not), other values are reserved (should then be
385    timeouts in milliseconds).  Returns: 0 on success  */
386 int
387 make_dotlock ( DOTLOCK h, long timeout )
388 {
389   int backoff = 0;
390 #ifndef HAVE_DOSISH_SYSTEM
391   int  pid;
392   const char *maybe_dead="";
393   int same_node;
394 #endif /*!HAVE_DOSISH_SYSTEM*/
395
396   if ( h->disable )
397     return 0; /* Locks are completely disabled.  Return success. */
398
399   if ( h->locked ) 
400     {
401 #ifndef __riscos__
402       log_debug ("Oops, `%s' is already locked\n", h->lockname);
403 #endif /* !__riscos__ */
404       return 0;
405     }
406
407   for (;;)
408     {
409 #ifndef HAVE_DOSISH_SYSTEM
410 # ifndef __riscos__
411       if ( !link(h->tname, h->lockname) )
412         {
413           /* fixme: better use stat to check the link count */
414           h->locked = 1;
415           return 0; /* okay */
416         }
417       if ( errno != EEXIST )
418         {
419           log_error ( "lock not made: link() failed: %s\n", strerror(errno) );
420           return -1;
421         }
422 # else /* __riscos__ */
423       if ( !renamefile(h->tname, h->lockname) ) 
424         {
425           h->locked = 1;
426           return 0; /* okay */
427         }
428       if ( errno != EEXIST ) 
429         {
430           log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
431           return -1;
432         }
433 # endif /* __riscos__ */
434
435       if ( (pid = read_lockfile (h, &same_node)) == -1 ) 
436         {
437           if ( errno != ENOENT )
438             {
439               log_info ("cannot read lockfile\n");
440               return -1;
441             }
442           log_info( "lockfile disappeared\n");
443           continue;
444         }
445       else if ( pid == getpid() && same_node )
446         {
447           log_info( "Oops: lock already held by us\n");
448           h->locked = 1;
449           return 0; /* okay */
450         }
451       else if ( same_node && kill (pid, 0) && errno == ESRCH )
452         {
453 # ifndef __riscos__
454           log_info (_("removing stale lockfile (created by %d)\n"), pid );
455           unlink (h->lockname);
456           continue;
457 # else /* __riscos__ */
458           /* Under RISCOS we are *pretty* sure that the other task
459              is dead and therefore we remove the stale lock file. */
460           maybe_dead = _(" - probably dead - removing lock");
461           unlink(h->lockname);
462 # endif /* __riscos__ */
463         }
464
465       if ( timeout == -1 ) 
466         {
467           /* Wait until lock has been released. */
468           struct timeval tv;
469           
470           log_info (_("waiting for lock (held by %d%s) %s...\n"),
471                     pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
472
473
474           /* We can't use sleep, cause signals may be blocked. */
475           tv.tv_sec = 1 + backoff;
476           tv.tv_usec = 0;
477           select(0, NULL, NULL, NULL, &tv);
478           if ( backoff < 10 )
479             backoff++ ;
480         }
481       else
482         return -1;
483 #else /*HAVE_DOSISH_SYSTEM*/
484       int w32err;
485
486       if (LockFile (h->lockhd, 0, 0, 1, 0))
487         {
488           h->locked = 1;
489           return 0; /* okay */
490         }
491       w32err = GetLastError ();
492       if (w32err != ERROR_LOCK_VIOLATION)
493         {
494           log_error (_("lock `%s' not made: %s\n"),
495                      h->lockname, w32_strerror (w32err));
496           return -1;
497         }
498
499       if ( timeout == -1 ) 
500         {
501           /* Wait until lock has been released. */
502           log_info (_("waiting for lock %s...\n"), h->lockname);
503           Sleep ((1 + backoff)*1000);
504           if ( backoff < 10 )
505             backoff++ ;
506         }
507       else
508         return -1;
509 #endif /*HAVE_DOSISH_SYSTEM*/
510     }
511   /*NOTREACHED*/
512 }
513
514
515 /* Release a lock.  Returns 0 on success.  */
516 int
517 release_dotlock( DOTLOCK h )
518 {
519   /* To avoid atexit race conditions we first check whether there are
520      any locks left.  It might happen that another atexit handler
521      tries to release the lock while the atexit handler of this module
522      already ran and thus H is undefined.  */
523   if (!all_lockfiles)
524     return 0;
525
526   if ( h->disable )
527     return 0;
528
529   if ( !h->locked )
530     {
531       log_debug("Oops, `%s' is not locked\n", h->lockname);
532       return 0;
533     }
534
535 #ifdef HAVE_DOSISH_SYSTEM
536   if (!UnlockFile (h->lockhd, 0, 0, 1, 0))
537     {
538       log_error ("release_dotlock: error removing lockfile `%s': %s\n",
539                  h->lockname, w32_strerror (-1));
540       return -1;
541     }
542 #else
543   int pid, same_node;
544
545   pid = read_lockfile (h, &same_node);
546   if ( pid == -1 ) 
547     {
548       log_error( "release_dotlock: lockfile error\n");
549       return -1;
550     }
551   if ( pid != getpid() || !same_node )
552     {
553       log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
554       return -1;
555     }
556
557 #ifndef __riscos__
558   if ( unlink( h->lockname ) )
559     {
560       log_error ("release_dotlock: error removing lockfile `%s'\n",
561                  h->lockname);
562       return -1;
563     }
564   /* Fixme: As an extra check we could check whether the link count is
565      now really at 1. */
566 #else /* __riscos__ */
567   if ( renamefile (h->lockname, h->tname) ) 
568     {
569       log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
570                  h->lockname, h->tname);
571       return -1;
572     }
573 #endif /* __riscos__ */
574
575 #endif /* !HAVE_DOSISH_SYSTEM */
576   h->locked = 0;
577   return 0;
578 }
579
580
581 /* Read the lock file and return the pid, returns -1 on error.  True
582    will be stored in the integer at address SAME_NODE if the lock file
583    has been created on the same node. */
584 #ifndef HAVE_DOSISH_SYSTEM
585 static int
586 read_lockfile (DOTLOCK h, int *same_node )
587 {
588   char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
589                                    name are usually shorter. */
590   int fd;
591   int pid = -1;
592   char *buffer, *p;
593   size_t expected_len;
594   int res, nread;
595   
596   *same_node = 0;
597   expected_len = 10 + 1 + h->nodename_len + 1;
598   if ( expected_len >= sizeof buffer_space)
599     buffer = jnlib_xmalloc (expected_len);
600   else
601     buffer = buffer_space;
602
603   if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
604     {
605       int e = errno;
606       log_info ("error opening lockfile `%s': %s\n",
607                 h->lockname, strerror(errno) );
608       if (buffer != buffer_space)
609         jnlib_free (buffer);
610       errno = e; /* Need to return ERRNO here. */
611       return -1;
612     }
613
614   p = buffer;
615   nread = 0;
616   do
617     {
618       res = read (fd, p, expected_len - nread);
619       if (res == -1 && errno == EINTR)
620         continue;
621       if (res < 0)
622         {
623           log_info ("error reading lockfile `%s'", h->lockname );
624           close (fd); 
625           if (buffer != buffer_space)
626             jnlib_free (buffer);
627           errno = 0; /* Do not return an inappropriate ERRNO. */
628           return -1;
629         }
630       p += res;
631       nread += res;
632     }
633   while (res && nread != expected_len);
634   close(fd);
635
636   if (nread < 11)
637     {
638       log_info ("invalid size of lockfile `%s'", h->lockname );
639       if (buffer != buffer_space)
640         jnlib_free (buffer);
641       errno = 0; /* Better don't return an inappropriate ERRNO. */
642       return -1;
643     }
644
645   if (buffer[10] != '\n'
646       || (buffer[10] = 0, pid = atoi (buffer)) == -1
647 #ifndef __riscos__
648       || !pid 
649 #else /* __riscos__ */
650       || (!pid && riscos_getpid())
651 #endif /* __riscos__ */
652       )
653     {
654       log_error ("invalid pid %d in lockfile `%s'", pid, h->lockname );
655       if (buffer != buffer_space)
656         jnlib_free (buffer);
657       errno = 0;
658       return -1;
659     }
660
661   if (nread == expected_len
662       && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len) 
663       && buffer[11+h->nodename_len] == '\n')
664     *same_node = 1;
665
666   if (buffer != buffer_space)
667     jnlib_free (buffer);
668   return pid;
669 }
670 #endif /* !HAVE_DOSISH_SYSTEM */
671
672
673 /* Remove all lockfiles.  This is usually called by the atexit handler
674    installed by this module but may also be called by other
675    termination handlers.  */
676 void
677 dotlock_remove_lockfiles()
678 {
679   DOTLOCK h, h2;
680   
681   h = all_lockfiles;
682   all_lockfiles = NULL;
683     
684   while ( h )
685     {
686       h2 = h->next;
687       destroy_dotlock (h);
688       h = h2;
689     }
690 }
691