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