Re-implemented GPG's --passwd command and improved it.
[gnupg.git] / common / dotlock.c
1 /* dotlock.c - dotfile locking
2  * Copyright (C) 1998, 2000, 2001, 2003, 2004, 
3  *               2005, 2006, 2008, 2010 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           OVERLAPPED ovl;
366
367           memset (&ovl, 0, sizeof ovl); 
368           UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
369         }
370       CloseHandle (h->lockhd);
371 #else /* !HAVE_DOSISH_SYSTEM */
372       if (h->locked && h->lockname)
373         unlink (h->lockname);
374       if (h->tname)
375         unlink (h->tname);
376       jnlib_free (h->tname);
377 #endif /* HAVE_DOSISH_SYSTEM */
378       jnlib_free (h->lockname);
379     }
380   jnlib_free(h);
381 }
382
383
384 #ifndef HAVE_DOSISH_SYSTEM
385 static int
386 maybe_deadlock (dotlock_t h)
387 {
388   dotlock_t r;
389
390   for ( r=all_lockfiles; r; r = r->next )
391     {
392       if ( r != h && r->locked )
393         return 1;
394     }
395   return 0;
396 }
397 #endif /*!HAVE_DOSISH_SYSTEM*/
398
399
400
401 /* Do a lock on H. A TIMEOUT of 0 returns immediately, -1 waits
402    forever (hopefully not), other values are reserved (should then be
403    timeouts in milliseconds).  Returns: 0 on success  */
404 int
405 make_dotlock (dotlock_t h, long timeout)
406 {
407   int backoff = 0;
408 #ifndef HAVE_DOSISH_SYSTEM
409   int  pid;
410   const char *maybe_dead="";
411   int same_node;
412 #endif /*!HAVE_DOSISH_SYSTEM*/
413
414   if ( h->disable )
415     return 0; /* Locks are completely disabled.  Return success. */
416
417   if ( h->locked ) 
418     {
419 #ifndef __riscos__
420       log_debug ("Oops, `%s' is already locked\n", h->lockname);
421 #endif /* !__riscos__ */
422       return 0;
423     }
424
425   for (;;)
426     {
427 #ifndef HAVE_DOSISH_SYSTEM
428 # ifndef __riscos__
429       if ( !link(h->tname, h->lockname) )
430         {
431           /* fixme: better use stat to check the link count */
432           h->locked = 1;
433           return 0; /* okay */
434         }
435       if ( errno != EEXIST )
436         {
437           log_error ( "lock not made: link() failed: %s\n", strerror(errno) );
438           return -1;
439         }
440 # else /* __riscos__ */
441       if ( !renamefile(h->tname, h->lockname) ) 
442         {
443           h->locked = 1;
444           return 0; /* okay */
445         }
446       if ( errno != EEXIST ) 
447         {
448           log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
449           return -1;
450         }
451 # endif /* __riscos__ */
452
453       if ( (pid = read_lockfile (h, &same_node)) == -1 ) 
454         {
455           if ( errno != ENOENT )
456             {
457               log_info ("cannot read lockfile\n");
458               return -1;
459             }
460           log_info( "lockfile disappeared\n");
461           continue;
462         }
463       else if ( pid == getpid() && same_node )
464         {
465           log_info( "Oops: lock already held by us\n");
466           h->locked = 1;
467           return 0; /* okay */
468         }
469       else if ( same_node && kill (pid, 0) && errno == ESRCH )
470         {
471 # ifndef __riscos__
472           log_info (_("removing stale lockfile (created by %d)\n"), pid );
473           unlink (h->lockname);
474           continue;
475 # else /* __riscos__ */
476           /* Under RISCOS we are *pretty* sure that the other task
477              is dead and therefore we remove the stale lock file. */
478           maybe_dead = _(" - probably dead - removing lock");
479           unlink(h->lockname);
480 # endif /* __riscos__ */
481         }
482
483       if ( timeout == -1 ) 
484         {
485           /* Wait until lock has been released. */
486           struct timeval tv;
487           
488           log_info (_("waiting for lock (held by %d%s) %s...\n"),
489                     pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
490
491
492           /* We can't use sleep, cause signals may be blocked. */
493           tv.tv_sec = 1 + backoff;
494           tv.tv_usec = 0;
495           select(0, NULL, NULL, NULL, &tv);
496           if ( backoff < 10 )
497             backoff++ ;
498         }
499       else
500         return -1;
501 #else /*HAVE_DOSISH_SYSTEM*/
502       int w32err;
503       OVERLAPPED ovl;
504
505       /* Lock one byte at offset 0.  The offset is given by OVL.  */
506       memset (&ovl, 0, sizeof ovl); 
507       if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
508                                   | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
509         {
510           h->locked = 1;
511           return 0; /* okay */
512         }
513       w32err = GetLastError ();
514       if (w32err != ERROR_LOCK_VIOLATION)
515         {
516           log_error (_("lock `%s' not made: %s\n"),
517                      h->lockname, w32_strerror (w32err));
518           return -1;
519         }
520
521       if ( timeout == -1 ) 
522         {
523           /* Wait until lock has been released. */
524           log_info (_("waiting for lock %s...\n"), h->lockname);
525           Sleep ((1 + backoff)*1000);
526           if ( backoff < 10 )
527             backoff++ ;
528         }
529       else
530         return -1;
531 #endif /*HAVE_DOSISH_SYSTEM*/
532     }
533   /*NOTREACHED*/
534 }
535
536
537 /* Release a lock.  Returns 0 on success.  */
538 int
539 release_dotlock (dotlock_t h)
540 {
541 #ifndef HAVE_DOSISH_SYSTEM
542   int pid, same_node;
543 #endif
544
545   /* To avoid atexit race conditions we first check whether there are
546      any locks left.  It might happen that another atexit handler
547      tries to release the lock while the atexit handler of this module
548      already ran and thus H is undefined.  */
549   if (!all_lockfiles)
550     return 0;
551
552   if ( h->disable )
553     return 0;
554
555   if ( !h->locked )
556     {
557       log_debug("Oops, `%s' is not locked\n", h->lockname);
558       return 0;
559     }
560
561 #ifdef HAVE_DOSISH_SYSTEM
562   {
563     OVERLAPPED ovl;
564     
565     memset (&ovl, 0, sizeof ovl); 
566     if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
567       {
568         log_error ("release_dotlock: error removing lockfile `%s': %s\n",
569                    h->lockname, w32_strerror (-1));
570         return -1;
571       }
572   }
573 #else
574
575   pid = read_lockfile (h, &same_node);
576   if ( pid == -1 ) 
577     {
578       log_error( "release_dotlock: lockfile error\n");
579       return -1;
580     }
581   if ( pid != getpid() || !same_node )
582     {
583       log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
584       return -1;
585     }
586
587 #ifndef __riscos__
588   if ( unlink( h->lockname ) )
589     {
590       log_error ("release_dotlock: error removing lockfile `%s'\n",
591                  h->lockname);
592       return -1;
593     }
594   /* Fixme: As an extra check we could check whether the link count is
595      now really at 1. */
596 #else /* __riscos__ */
597   if ( renamefile (h->lockname, h->tname) ) 
598     {
599       log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
600                  h->lockname, h->tname);
601       return -1;
602     }
603 #endif /* __riscos__ */
604
605 #endif /* !HAVE_DOSISH_SYSTEM */
606   h->locked = 0;
607   return 0;
608 }
609
610
611 /* Read the lock file and return the pid, returns -1 on error.  True
612    will be stored in the integer at address SAME_NODE if the lock file
613    has been created on the same node. */
614 #ifndef HAVE_DOSISH_SYSTEM
615 static int
616 read_lockfile (dotlock_t h, int *same_node )
617 {
618   char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
619                                    name are usually shorter. */
620   int fd;
621   int pid = -1;
622   char *buffer, *p;
623   size_t expected_len;
624   int res, nread;
625   
626   *same_node = 0;
627   expected_len = 10 + 1 + h->nodename_len + 1;
628   if ( expected_len >= sizeof buffer_space)
629     {
630       buffer = jnlib_malloc (expected_len);
631       if (!buffer)
632         return -1;
633     }
634   else
635     buffer = buffer_space;
636
637   if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
638     {
639       int e = errno;
640       log_info ("error opening lockfile `%s': %s\n",
641                 h->lockname, strerror(errno) );
642       if (buffer != buffer_space)
643         jnlib_free (buffer);
644       jnlib_set_errno (e); /* Need to return ERRNO here. */
645       return -1;
646     }
647
648   p = buffer;
649   nread = 0;
650   do
651     {
652       res = read (fd, p, expected_len - nread);
653       if (res == -1 && errno == EINTR)
654         continue;
655       if (res < 0)
656         {
657           log_info ("error reading lockfile `%s'", h->lockname );
658           close (fd); 
659           if (buffer != buffer_space)
660             jnlib_free (buffer);
661           jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */
662           return -1;
663         }
664       p += res;
665       nread += res;
666     }
667   while (res && nread != expected_len);
668   close(fd);
669
670   if (nread < 11)
671     {
672       log_info ("invalid size of lockfile `%s'", h->lockname );
673       if (buffer != buffer_space)
674         jnlib_free (buffer);
675       jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */
676       return -1;
677     }
678
679   if (buffer[10] != '\n'
680       || (buffer[10] = 0, pid = atoi (buffer)) == -1
681 #ifndef __riscos__
682       || !pid 
683 #else /* __riscos__ */
684       || (!pid && riscos_getpid())
685 #endif /* __riscos__ */
686       )
687     {
688       log_error ("invalid pid %d in lockfile `%s'", pid, h->lockname );
689       if (buffer != buffer_space)
690         jnlib_free (buffer);
691       jnlib_set_errno (0);
692       return -1;
693     }
694
695   if (nread == expected_len
696       && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len) 
697       && buffer[11+h->nodename_len] == '\n')
698     *same_node = 1;
699
700   if (buffer != buffer_space)
701     jnlib_free (buffer);
702   return pid;
703 }
704 #endif /* !HAVE_DOSISH_SYSTEM */
705
706
707 /* Remove all lockfiles.  This is usually called by the atexit handler
708    installed by this module but may also be called by other
709    termination handlers.  */
710 void
711 dotlock_remove_lockfiles (void)
712 {
713   dotlock_t h, h2;
714   
715   h = all_lockfiles;
716   all_lockfiles = NULL;
717     
718   while ( h )
719     {
720       h2 = h->next;
721       destroy_dotlock (h);
722       h = h2;
723     }
724 }
725