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