Replace a call to BUG by an error return.
[gnupg.git] / jnlib / dotlock.c
blob53a43244dc11171ff8a8a6a44c0c5311d0c376ac
1 /* dotlock.c - dotfile locking
2 * Copyright (C) 1998, 2000, 2001, 2003, 2004,
3 * 2005, 2006, 2008 Free Software Foundation, Inc.
5 * This file is part of JNLIB.
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.
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.
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/>.
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>
40 #include "libjnlib-config.h"
41 #include "stringhelp.h"
42 #include "dotlock.h"
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
60 /* The object describing a lock. */
61 struct dotlock_handle
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. */
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 */
78 /* A list of of all lock handles. */
79 static volatile DOTLOCK all_lockfiles;
81 /* If this has the value true all locking is disabled. */
82 static int never_lock;
85 /* Local protototypes. */
86 #ifndef HAVE_DOSISH_SYSTEM
87 static int read_lockfile (DOTLOCK h, int *same_node);
88 #endif /*!HAVE_DOSISH_SYSTEM*/
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)
99 never_lock = 1;
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.
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.
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.
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.
122 DOTLOCK
123 create_dotlock (const char *file_to_lock)
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
137 if ( !initialized )
139 atexit (dotlock_remove_lockfiles);
140 initialized = 1;
143 if ( !file_to_lock )
144 return NULL; /* Only initialization was requested. */
146 h = jnlib_calloc (1, sizeof *h);
147 if (!h)
148 return NULL;
150 if (never_lock)
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;
161 #ifndef HAVE_DOSISH_SYSTEM
163 This is the POSIX version which uses a temporary file and the
164 link system call to make locking an atomic operation.
167 snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
168 /* fixme: add the hostname to the second line (FQDN or IP addr?) */
170 /* Create a temporary file. */
171 if ( uname ( &utsbuf ) )
172 nodename = "unknown";
173 else
174 nodename = utsbuf.nodename;
176 #ifdef __riscos__
178 char *iter = (char *) nodename;
179 for (; iter[0]; iter++)
180 if (iter[0] == '.')
181 iter[0] = '/';
183 #endif /* __riscos__ */
185 if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
187 dirpart = EXTSEP_S;
188 dirpartlen = 1;
190 else
192 dirpartlen = dirpart - file_to_lock;
193 dirpart = file_to_lock;
196 #ifdef _REENTRANT
197 /* fixme: aquire mutex on all_lockfiles */
198 #endif
199 h->next = all_lockfiles;
200 all_lockfiles = h;
202 tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10;
203 h->tname = jnlib_malloc (tnamelen + 1);
204 if (!h->tname)
206 all_lockfiles = h->next;
207 jnlib_free (h);
208 return NULL;
210 h->nodename_len = strlen (nodename);
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__ */
226 errno = 0;
227 fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
228 S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
230 while (fd == -1 && errno == EINTR);
232 if ( fd == -1 )
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;
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;
250 # ifdef _REENTRANT
251 /* release mutex */
252 # endif
253 h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
254 if (!h->lockname)
256 all_lockfiles = h->next;
257 unlink (h->tname);
258 jnlib_free (h->tname);
259 jnlib_free (h);
260 return NULL;
262 strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
263 return h;
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;
277 #else /* HAVE_DOSISH_SYSTEM */
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;
287 h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
288 if (!h->lockname)
290 all_lockfiles = h->next;
291 jnlib_free (h);
292 return NULL;
294 strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
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)
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;
317 return h;
319 #endif /* HAVE_DOSISH_SYSTEM */
323 /* Destroy the local handle H and release the lock. */
324 void
325 destroy_dotlock ( DOTLOCK h )
327 DOTLOCK hprev, htmp;
329 if ( !h )
330 return;
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)
336 if (hprev)
337 hprev->next = htmp->next;
338 else
339 all_lockfiles = htmp->next;
340 h->next = NULL;
341 break;
344 /* Then destroy the lock. */
345 if (!h->disable)
347 #ifdef HAVE_DOSISH_SYSTEM
348 if (h->locked)
350 UnlockFile (h->lockhd, 0, 0, 1, 0);
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);
362 jnlib_free(h);
366 #ifndef HAVE_DOSISH_SYSTEM
367 static int
368 maybe_deadlock( DOTLOCK h )
370 DOTLOCK r;
372 for ( r=all_lockfiles; r; r = r->next )
374 if ( r != h && r->locked )
375 return 1;
377 return 0;
379 #endif /*!HAVE_DOSISH_SYSTEM*/
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 */
387 make_dotlock ( DOTLOCK h, long timeout )
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*/
396 if ( h->disable )
397 return 0; /* Locks are completely disabled. Return success. */
399 if ( h->locked )
401 #ifndef __riscos__
402 log_debug ("Oops, `%s' is already locked\n", h->lockname);
403 #endif /* !__riscos__ */
404 return 0;
407 for (;;)
409 #ifndef HAVE_DOSISH_SYSTEM
410 # ifndef __riscos__
411 if ( !link(h->tname, h->lockname) )
413 /* fixme: better use stat to check the link count */
414 h->locked = 1;
415 return 0; /* okay */
417 if ( errno != EEXIST )
419 log_error ( "lock not made: link() failed: %s\n", strerror(errno) );
420 return -1;
422 # else /* __riscos__ */
423 if ( !renamefile(h->tname, h->lockname) )
425 h->locked = 1;
426 return 0; /* okay */
428 if ( errno != EEXIST )
430 log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
431 return -1;
433 # endif /* __riscos__ */
435 if ( (pid = read_lockfile (h, &same_node)) == -1 )
437 if ( errno != ENOENT )
439 log_info ("cannot read lockfile\n");
440 return -1;
442 log_info( "lockfile disappeared\n");
443 continue;
445 else if ( pid == getpid() && same_node )
447 log_info( "Oops: lock already held by us\n");
448 h->locked = 1;
449 return 0; /* okay */
451 else if ( same_node && kill (pid, 0) && errno == ESRCH )
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__ */
465 if ( timeout == -1 )
467 /* Wait until lock has been released. */
468 struct timeval tv;
470 log_info (_("waiting for lock (held by %d%s) %s...\n"),
471 pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
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++ ;
481 else
482 return -1;
483 #else /*HAVE_DOSISH_SYSTEM*/
484 int w32err;
486 if (LockFile (h->lockhd, 0, 0, 1, 0))
488 h->locked = 1;
489 return 0; /* okay */
491 w32err = GetLastError ();
492 if (w32err != ERROR_LOCK_VIOLATION)
494 log_error (_("lock `%s' not made: %s\n"),
495 h->lockname, w32_strerror (w32err));
496 return -1;
499 if ( timeout == -1 )
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++ ;
507 else
508 return -1;
509 #endif /*HAVE_DOSISH_SYSTEM*/
511 /*NOTREACHED*/
515 /* Release a lock. Returns 0 on success. */
517 release_dotlock( DOTLOCK h )
519 #ifndef HAVE_DOSISH_SYSTEM
520 int pid, same_node;
521 #endif
523 /* To avoid atexit race conditions we first check whether there are
524 any locks left. It might happen that another atexit handler
525 tries to release the lock while the atexit handler of this module
526 already ran and thus H is undefined. */
527 if (!all_lockfiles)
528 return 0;
530 if ( h->disable )
531 return 0;
533 if ( !h->locked )
535 log_debug("Oops, `%s' is not locked\n", h->lockname);
536 return 0;
539 #ifdef HAVE_DOSISH_SYSTEM
540 if (!UnlockFile (h->lockhd, 0, 0, 1, 0))
542 log_error ("release_dotlock: error removing lockfile `%s': %s\n",
543 h->lockname, w32_strerror (-1));
544 return -1;
546 #else
548 pid = read_lockfile (h, &same_node);
549 if ( pid == -1 )
551 log_error( "release_dotlock: lockfile error\n");
552 return -1;
554 if ( pid != getpid() || !same_node )
556 log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
557 return -1;
560 #ifndef __riscos__
561 if ( unlink( h->lockname ) )
563 log_error ("release_dotlock: error removing lockfile `%s'\n",
564 h->lockname);
565 return -1;
567 /* Fixme: As an extra check we could check whether the link count is
568 now really at 1. */
569 #else /* __riscos__ */
570 if ( renamefile (h->lockname, h->tname) )
572 log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
573 h->lockname, h->tname);
574 return -1;
576 #endif /* __riscos__ */
578 #endif /* !HAVE_DOSISH_SYSTEM */
579 h->locked = 0;
580 return 0;
584 /* Read the lock file and return the pid, returns -1 on error. True
585 will be stored in the integer at address SAME_NODE if the lock file
586 has been created on the same node. */
587 #ifndef HAVE_DOSISH_SYSTEM
588 static int
589 read_lockfile (DOTLOCK h, int *same_node )
591 char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
592 name are usually shorter. */
593 int fd;
594 int pid = -1;
595 char *buffer, *p;
596 size_t expected_len;
597 int res, nread;
599 *same_node = 0;
600 expected_len = 10 + 1 + h->nodename_len + 1;
601 if ( expected_len >= sizeof buffer_space)
602 buffer = jnlib_xmalloc (expected_len);
603 else
604 buffer = buffer_space;
606 if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
608 int e = errno;
609 log_info ("error opening lockfile `%s': %s\n",
610 h->lockname, strerror(errno) );
611 if (buffer != buffer_space)
612 jnlib_free (buffer);
613 errno = e; /* Need to return ERRNO here. */
614 return -1;
617 p = buffer;
618 nread = 0;
621 res = read (fd, p, expected_len - nread);
622 if (res == -1 && errno == EINTR)
623 continue;
624 if (res < 0)
626 log_info ("error reading lockfile `%s'", h->lockname );
627 close (fd);
628 if (buffer != buffer_space)
629 jnlib_free (buffer);
630 errno = 0; /* Do not return an inappropriate ERRNO. */
631 return -1;
633 p += res;
634 nread += res;
636 while (res && nread != expected_len);
637 close(fd);
639 if (nread < 11)
641 log_info ("invalid size of lockfile `%s'", h->lockname );
642 if (buffer != buffer_space)
643 jnlib_free (buffer);
644 errno = 0; /* Better don't return an inappropriate ERRNO. */
645 return -1;
648 if (buffer[10] != '\n'
649 || (buffer[10] = 0, pid = atoi (buffer)) == -1
650 #ifndef __riscos__
651 || !pid
652 #else /* __riscos__ */
653 || (!pid && riscos_getpid())
654 #endif /* __riscos__ */
657 log_error ("invalid pid %d in lockfile `%s'", pid, h->lockname );
658 if (buffer != buffer_space)
659 jnlib_free (buffer);
660 errno = 0;
661 return -1;
664 if (nread == expected_len
665 && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
666 && buffer[11+h->nodename_len] == '\n')
667 *same_node = 1;
669 if (buffer != buffer_space)
670 jnlib_free (buffer);
671 return pid;
673 #endif /* !HAVE_DOSISH_SYSTEM */
676 /* Remove all lockfiles. This is usually called by the atexit handler
677 installed by this module but may also be called by other
678 termination handlers. */
679 void
680 dotlock_remove_lockfiles()
682 DOTLOCK h, h2;
684 h = all_lockfiles;
685 all_lockfiles = NULL;
687 while ( h )
689 h2 = h->next;
690 destroy_dotlock (h);
691 h = h2;