Doc fixes.
[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
169   /* Create a temporary file. */
170   if ( uname ( &utsbuf ) )
171     nodename = "unknown";
172   else
173     nodename = utsbuf.nodename;
174   
175 #ifdef __riscos__
176   {
177     char *iter = (char *) nodename;
178     for (; iter[0]; iter++)
179       if (iter[0] == '.')
180         iter[0] = '/';
181   }
182 #endif /* __riscos__ */
183
184   if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
185     {
186       dirpart = EXTSEP_S;
187       dirpartlen = 1;
188     }
189   else
190     {
191       dirpartlen = dirpart - file_to_lock;
192       dirpart = file_to_lock;
193     }
194
195 #ifdef _REENTRANT
196     /* fixme: aquire mutex on all_lockfiles */
197 #endif
198   h->next = all_lockfiles;
199   all_lockfiles = h;
200
201   tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10;
202   h->tname = jnlib_malloc (tnamelen + 1);
203   if (!h->tname)
204     {
205       all_lockfiles = h->next;
206       jnlib_free (h);
207       return NULL;
208     }
209   h->nodename_len = strlen (nodename);
210
211 #ifndef __riscos__
212   snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
213   h->nodename_off = strlen (h->tname);
214   snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
215            "%s.%d", nodename, (int)getpid ());
216 #else /* __riscos__ */
217   snprintf (h->tname, tnamelen, "%.*s.lk%p/", dirpartlen, dirpart, h );
218   h->nodename_off = strlen (h->tname);
219   snprintf (h->tname+h->nodename_off, tnamelen - h->modename_off,
220             "%s/%d", nodename, (int)getpid () );
221 #endif /* __riscos__ */
222
223   do 
224     {
225       errno = 0;
226       fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
227                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
228     } 
229   while (fd == -1 && errno == EINTR);
230
231   if ( fd == -1 ) 
232     {
233       all_lockfiles = h->next;
234       log_error (_("failed to create temporary file `%s': %s\n"),
235                   h->tname, strerror(errno));
236       jnlib_free (h->tname);
237       jnlib_free (h);
238       return NULL;
239     }
240   if ( write (fd, pidstr, 11 ) != 11 )
241     goto write_failed;
242   if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
243     goto write_failed;
244   if ( write (fd, "\n", 1 ) != 1 )
245     goto write_failed;
246   if ( close (fd) )
247     goto write_failed;
248
249 # ifdef _REENTRANT
250   /* release mutex */
251 # endif
252   h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
253   if (!h->lockname)
254     {
255       all_lockfiles = h->next;
256       unlink (h->tname);
257       jnlib_free (h->tname);
258       jnlib_free (h);
259       return NULL;
260     }
261   strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
262   return h;
263
264  write_failed:
265   all_lockfiles = h->next;
266 # ifdef _REENTRANT
267   /* fixme: release mutex */
268 # endif
269   log_error ( _("error writing to `%s': %s\n"), h->tname, strerror(errno) );
270   close (fd);
271   unlink (h->tname);
272   jnlib_free (h->tname);
273   jnlib_free (h);
274   return NULL;
275
276 #else /* HAVE_DOSISH_SYSTEM */
277
278   /* The Windows version does not need a temporary file but uses the
279      plain lock file along with record locking.  We create this file
280      here so that we later do only need to do the file locking.  For
281      error reporting it is useful to keep the name of the file in the
282      handle.  */
283   h->next = all_lockfiles;
284   all_lockfiles = h;
285
286   h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
287   if (!h->lockname)
288     {
289       all_lockfiles = h->next;
290       jnlib_free (h);
291       return NULL;
292     }
293   strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
294
295   /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
296      along with FILE_SHARE_DELETE but that does not work due to a race
297      condition: Despite the OPEN_ALWAYS flag CreateFile may return an
298      error and we can't reliable create/open the lock file unless we
299      would wait here until it works - however there are other valid
300      reasons why a lock file can't be created and thus the process
301      would not stop as expected but spin til until Windows crashes.
302      Our solution is to keep the lock file open; that does not
303      harm. */ 
304   h->lockhd = CreateFile (h->lockname,
305                           GENERIC_READ|GENERIC_WRITE,
306                           FILE_SHARE_READ|FILE_SHARE_WRITE,
307                           NULL, OPEN_ALWAYS, 0, NULL);
308   if (h->lockhd == INVALID_HANDLE_VALUE)
309     {
310       log_error (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
311       all_lockfiles = h->next;
312       jnlib_free (h->lockname);
313       jnlib_free (h);
314       return NULL;
315     }
316   return h;
317
318 #endif /* HAVE_DOSISH_SYSTEM */
319 }
320
321
322 /* Destroy the local handle H and release the lock. */
323 void
324 destroy_dotlock ( DOTLOCK h )
325 {
326   DOTLOCK hprev, htmp;
327
328   if ( !h )
329     return;
330
331   /* First remove the handle from our global list of all locks. */
332   for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
333     if (htmp == h)
334       {
335         if (hprev)
336           hprev->next = htmp->next;
337         else
338           all_lockfiles = htmp->next;
339         h->next = NULL;
340         break;
341       }
342   
343   /* Then destroy the lock. */
344   if (!h->disable)
345     {
346 #ifdef HAVE_DOSISH_SYSTEM
347       if (h->locked)
348         {
349           UnlockFile (h->lockhd, 0, 0, 1, 0);
350         }
351       CloseHandle (h->lockhd);
352 #else /* !HAVE_DOSISH_SYSTEM */
353       if (h->locked && h->lockname)
354         unlink (h->lockname);
355       if (h->tname)
356         unlink (h->tname);
357       jnlib_free (h->tname);
358 #endif /* HAVE_DOSISH_SYSTEM */
359       jnlib_free (h->lockname);
360     }
361   jnlib_free(h);
362 }
363
364
365 #ifndef HAVE_DOSISH_SYSTEM
366 static int
367 maybe_deadlock( DOTLOCK h )
368 {
369   DOTLOCK r;
370
371   for ( r=all_lockfiles; r; r = r->next )
372     {
373       if ( r != h && r->locked )
374         return 1;
375     }
376   return 0;
377 }
378 #endif /*!HAVE_DOSISH_SYSTEM*/
379
380
381
382 /* Do a lock on H. A TIMEOUT of 0 returns immediately, -1 waits
383    forever (hopefully not), other values are reserved (should then be
384    timeouts in milliseconds).  Returns: 0 on success  */
385 int
386 make_dotlock ( DOTLOCK h, long timeout )
387 {
388   int backoff = 0;
389 #ifndef HAVE_DOSISH_SYSTEM
390   int  pid;
391   const char *maybe_dead="";
392   int same_node;
393 #endif /*!HAVE_DOSISH_SYSTEM*/
394
395   if ( h->disable )
396     return 0; /* Locks are completely disabled.  Return success. */
397
398   if ( h->locked ) 
399     {
400 #ifndef __riscos__
401       log_debug ("Oops, `%s' is already locked\n", h->lockname);
402 #endif /* !__riscos__ */
403       return 0;
404     }
405
406   for (;;)
407     {
408 #ifndef HAVE_DOSISH_SYSTEM
409 # ifndef __riscos__
410       if ( !link(h->tname, h->lockname) )
411         {
412           /* fixme: better use stat to check the link count */
413           h->locked = 1;
414           return 0; /* okay */
415         }
416       if ( errno != EEXIST )
417         {
418           log_error ( "lock not made: link() failed: %s\n", strerror(errno) );
419           return -1;
420         }
421 # else /* __riscos__ */
422       if ( !renamefile(h->tname, h->lockname) ) 
423         {
424           h->locked = 1;
425           return 0; /* okay */
426         }
427       if ( errno != EEXIST ) 
428         {
429           log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
430           return -1;
431         }
432 # endif /* __riscos__ */
433
434       if ( (pid = read_lockfile (h, &same_node)) == -1 ) 
435         {
436           if ( errno != ENOENT )
437             {
438               log_info ("cannot read lockfile\n");
439               return -1;
440             }
441           log_info( "lockfile disappeared\n");
442           continue;
443         }
444       else if ( pid == getpid() && same_node )
445         {
446           log_info( "Oops: lock already held by us\n");
447           h->locked = 1;
448           return 0; /* okay */
449         }
450       else if ( same_node && kill (pid, 0) && errno == ESRCH )
451         {
452 # ifndef __riscos__
453           log_info (_("removing stale lockfile (created by %d)\n"), pid );
454           unlink (h->lockname);
455           continue;
456 # else /* __riscos__ */
457           /* Under RISCOS we are *pretty* sure that the other task
458              is dead and therefore we remove the stale lock file. */
459           maybe_dead = _(" - probably dead - removing lock");
460           unlink(h->lockname);
461 # endif /* __riscos__ */
462         }
463
464       if ( timeout == -1 ) 
465         {
466           /* Wait until lock has been released. */
467           struct timeval tv;
468           
469           log_info (_("waiting for lock (held by %d%s) %s...\n"),
470                     pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
471
472
473           /* We can't use sleep, cause signals may be blocked. */
474           tv.tv_sec = 1 + backoff;
475           tv.tv_usec = 0;
476           select(0, NULL, NULL, NULL, &tv);
477           if ( backoff < 10 )
478             backoff++ ;
479         }
480       else
481         return -1;
482 #else /*HAVE_DOSISH_SYSTEM*/
483       int w32err;
484
485       if (LockFile (h->lockhd, 0, 0, 1, 0))
486         {
487           h->locked = 1;
488           return 0; /* okay */
489         }
490       w32err = GetLastError ();
491       if (w32err != ERROR_LOCK_VIOLATION)
492         {
493           log_error (_("lock `%s' not made: %s\n"),
494                      h->lockname, w32_strerror (w32err));
495           return -1;
496         }
497
498       if ( timeout == -1 ) 
499         {
500           /* Wait until lock has been released. */
501           log_info (_("waiting for lock %s...\n"), h->lockname);
502           Sleep ((1 + backoff)*1000);
503           if ( backoff < 10 )
504             backoff++ ;
505         }
506       else
507         return -1;
508 #endif /*HAVE_DOSISH_SYSTEM*/
509     }
510   /*NOTREACHED*/
511 }
512
513
514 /* Release a lock.  Returns 0 on success.  */
515 int
516 release_dotlock( DOTLOCK h )
517 {
518 #ifndef HAVE_DOSISH_SYSTEM
519   int pid, same_node;
520 #endif
521
522   /* To avoid atexit race conditions we first check whether there are
523      any locks left.  It might happen that another atexit handler
524      tries to release the lock while the atexit handler of this module
525      already ran and thus H is undefined.  */
526   if (!all_lockfiles)
527     return 0;
528
529   if ( h->disable )
530     return 0;
531
532   if ( !h->locked )
533     {
534       log_debug("Oops, `%s' is not locked\n", h->lockname);
535       return 0;
536     }
537
538 #ifdef HAVE_DOSISH_SYSTEM
539   if (!UnlockFile (h->lockhd, 0, 0, 1, 0))
540     {
541       log_error ("release_dotlock: error removing lockfile `%s': %s\n",
542                  h->lockname, w32_strerror (-1));
543       return -1;
544     }
545 #else
546
547   pid = read_lockfile (h, &same_node);
548   if ( pid == -1 ) 
549     {
550       log_error( "release_dotlock: lockfile error\n");
551       return -1;
552     }
553   if ( pid != getpid() || !same_node )
554     {
555       log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
556       return -1;
557     }
558
559 #ifndef __riscos__
560   if ( unlink( h->lockname ) )
561     {
562       log_error ("release_dotlock: error removing lockfile `%s'\n",
563                  h->lockname);
564       return -1;
565     }
566   /* Fixme: As an extra check we could check whether the link count is
567      now really at 1. */
568 #else /* __riscos__ */
569   if ( renamefile (h->lockname, h->tname) ) 
570     {
571       log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
572                  h->lockname, h->tname);
573       return -1;
574     }
575 #endif /* __riscos__ */
576
577 #endif /* !HAVE_DOSISH_SYSTEM */
578   h->locked = 0;
579   return 0;
580 }
581
582
583 /* Read the lock file and return the pid, returns -1 on error.  True
584    will be stored in the integer at address SAME_NODE if the lock file
585    has been created on the same node. */
586 #ifndef HAVE_DOSISH_SYSTEM
587 static int
588 read_lockfile (DOTLOCK h, int *same_node )
589 {
590   char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
591                                    name are usually shorter. */
592   int fd;
593   int pid = -1;
594   char *buffer, *p;
595   size_t expected_len;
596   int res, nread;
597   
598   *same_node = 0;
599   expected_len = 10 + 1 + h->nodename_len + 1;
600   if ( expected_len >= sizeof buffer_space)
601     buffer = jnlib_xmalloc (expected_len);
602   else
603     buffer = buffer_space;
604
605   if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
606     {
607       int e = errno;
608       log_info ("error opening lockfile `%s': %s\n",
609                 h->lockname, strerror(errno) );
610       if (buffer != buffer_space)
611         jnlib_free (buffer);
612       errno = e; /* Need to return ERRNO here. */
613       return -1;
614     }
615
616   p = buffer;
617   nread = 0;
618   do
619     {
620       res = read (fd, p, expected_len - nread);
621       if (res == -1 && errno == EINTR)
622         continue;
623       if (res < 0)
624         {
625           log_info ("error reading lockfile `%s'", h->lockname );
626           close (fd); 
627           if (buffer != buffer_space)
628             jnlib_free (buffer);
629           errno = 0; /* Do not return an inappropriate ERRNO. */
630           return -1;
631         }
632       p += res;
633       nread += res;
634     }
635   while (res && nread != expected_len);
636   close(fd);
637
638   if (nread < 11)
639     {
640       log_info ("invalid size of lockfile `%s'", h->lockname );
641       if (buffer != buffer_space)
642         jnlib_free (buffer);
643       errno = 0; /* Better don't return an inappropriate ERRNO. */
644       return -1;
645     }
646
647   if (buffer[10] != '\n'
648       || (buffer[10] = 0, pid = atoi (buffer)) == -1
649 #ifndef __riscos__
650       || !pid 
651 #else /* __riscos__ */
652       || (!pid && riscos_getpid())
653 #endif /* __riscos__ */
654       )
655     {
656       log_error ("invalid pid %d in lockfile `%s'", pid, h->lockname );
657       if (buffer != buffer_space)
658         jnlib_free (buffer);
659       errno = 0;
660       return -1;
661     }
662
663   if (nread == expected_len
664       && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len) 
665       && buffer[11+h->nodename_len] == '\n')
666     *same_node = 1;
667
668   if (buffer != buffer_space)
669     jnlib_free (buffer);
670   return pid;
671 }
672 #endif /* !HAVE_DOSISH_SYSTEM */
673
674
675 /* Remove all lockfiles.  This is usually called by the atexit handler
676    installed by this module but may also be called by other
677    termination handlers.  */
678 void
679 dotlock_remove_lockfiles()
680 {
681   DOTLOCK h, h2;
682   
683   h = all_lockfiles;
684   all_lockfiles = NULL;
685     
686   while ( h )
687     {
688       h2 = h->next;
689       destroy_dotlock (h);
690       h = h2;
691     }
692 }
693