Use cancel button in confirmation only if requested.
[gnupg.git] / jnlib / dotlock.c
blob96041c0ce113611b872e3b55b93b9d0c3cf77179
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() );
169 /* Create a temporary file. */
170 if ( uname ( &utsbuf ) )
171 nodename = "unknown";
172 else
173 nodename = utsbuf.nodename;
175 #ifdef __riscos__
177 char *iter = (char *) nodename;
178 for (; iter[0]; iter++)
179 if (iter[0] == '.')
180 iter[0] = '/';
182 #endif /* __riscos__ */
184 if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
186 dirpart = EXTSEP_S;
187 dirpartlen = 1;
189 else
191 dirpartlen = dirpart - file_to_lock;
192 dirpart = file_to_lock;
195 #ifdef _REENTRANT
196 /* fixme: aquire mutex on all_lockfiles */
197 #endif
198 h->next = all_lockfiles;
199 all_lockfiles = h;
201 tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10;
202 h->tname = jnlib_malloc (tnamelen + 1);
203 if (!h->tname)
205 all_lockfiles = h->next;
206 jnlib_free (h);
207 return NULL;
209 h->nodename_len = strlen (nodename);
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__ */
225 errno = 0;
226 fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
227 S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
229 while (fd == -1 && errno == EINTR);
231 if ( fd == -1 )
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;
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;
249 # ifdef _REENTRANT
250 /* release mutex */
251 # endif
252 h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
253 if (!h->lockname)
255 all_lockfiles = h->next;
256 unlink (h->tname);
257 jnlib_free (h->tname);
258 jnlib_free (h);
259 return NULL;
261 strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
262 return h;
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;
276 #else /* HAVE_DOSISH_SYSTEM */
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;
286 h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
287 if (!h->lockname)
289 all_lockfiles = h->next;
290 jnlib_free (h);
291 return NULL;
293 strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
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)
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;
316 return h;
318 #endif /* HAVE_DOSISH_SYSTEM */
322 /* Destroy the local handle H and release the lock. */
323 void
324 destroy_dotlock ( DOTLOCK h )
326 DOTLOCK hprev, htmp;
328 if ( !h )
329 return;
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)
335 if (hprev)
336 hprev->next = htmp->next;
337 else
338 all_lockfiles = htmp->next;
339 h->next = NULL;
340 break;
343 /* Then destroy the lock. */
344 if (!h->disable)
346 #ifdef HAVE_DOSISH_SYSTEM
347 if (h->locked)
349 UnlockFile (h->lockhd, 0, 0, 1, 0);
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);
361 jnlib_free(h);
365 #ifndef HAVE_DOSISH_SYSTEM
366 static int
367 maybe_deadlock( DOTLOCK h )
369 DOTLOCK r;
371 for ( r=all_lockfiles; r; r = r->next )
373 if ( r != h && r->locked )
374 return 1;
376 return 0;
378 #endif /*!HAVE_DOSISH_SYSTEM*/
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 */
386 make_dotlock ( DOTLOCK h, long timeout )
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*/
395 if ( h->disable )
396 return 0; /* Locks are completely disabled. Return success. */
398 if ( h->locked )
400 #ifndef __riscos__
401 log_debug ("Oops, `%s' is already locked\n", h->lockname);
402 #endif /* !__riscos__ */
403 return 0;
406 for (;;)
408 #ifndef HAVE_DOSISH_SYSTEM
409 # ifndef __riscos__
410 if ( !link(h->tname, h->lockname) )
412 /* fixme: better use stat to check the link count */
413 h->locked = 1;
414 return 0; /* okay */
416 if ( errno != EEXIST )
418 log_error ( "lock not made: link() failed: %s\n", strerror(errno) );
419 return -1;
421 # else /* __riscos__ */
422 if ( !renamefile(h->tname, h->lockname) )
424 h->locked = 1;
425 return 0; /* okay */
427 if ( errno != EEXIST )
429 log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
430 return -1;
432 # endif /* __riscos__ */
434 if ( (pid = read_lockfile (h, &same_node)) == -1 )
436 if ( errno != ENOENT )
438 log_info ("cannot read lockfile\n");
439 return -1;
441 log_info( "lockfile disappeared\n");
442 continue;
444 else if ( pid == getpid() && same_node )
446 log_info( "Oops: lock already held by us\n");
447 h->locked = 1;
448 return 0; /* okay */
450 else if ( same_node && kill (pid, 0) && errno == ESRCH )
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__ */
464 if ( timeout == -1 )
466 /* Wait until lock has been released. */
467 struct timeval tv;
469 log_info (_("waiting for lock (held by %d%s) %s...\n"),
470 pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
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++ ;
480 else
481 return -1;
482 #else /*HAVE_DOSISH_SYSTEM*/
483 int w32err;
485 if (LockFile (h->lockhd, 0, 0, 1, 0))
487 h->locked = 1;
488 return 0; /* okay */
490 w32err = GetLastError ();
491 if (w32err != ERROR_LOCK_VIOLATION)
493 log_error (_("lock `%s' not made: %s\n"),
494 h->lockname, w32_strerror (w32err));
495 return -1;
498 if ( timeout == -1 )
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++ ;
506 else
507 return -1;
508 #endif /*HAVE_DOSISH_SYSTEM*/
510 /*NOTREACHED*/
514 /* Release a lock. Returns 0 on success. */
516 release_dotlock( DOTLOCK h )
518 #ifndef HAVE_DOSISH_SYSTEM
519 int pid, same_node;
520 #endif
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;
529 if ( h->disable )
530 return 0;
532 if ( !h->locked )
534 log_debug("Oops, `%s' is not locked\n", h->lockname);
535 return 0;
538 #ifdef HAVE_DOSISH_SYSTEM
539 if (!UnlockFile (h->lockhd, 0, 0, 1, 0))
541 log_error ("release_dotlock: error removing lockfile `%s': %s\n",
542 h->lockname, w32_strerror (-1));
543 return -1;
545 #else
547 pid = read_lockfile (h, &same_node);
548 if ( pid == -1 )
550 log_error( "release_dotlock: lockfile error\n");
551 return -1;
553 if ( pid != getpid() || !same_node )
555 log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
556 return -1;
559 #ifndef __riscos__
560 if ( unlink( h->lockname ) )
562 log_error ("release_dotlock: error removing lockfile `%s'\n",
563 h->lockname);
564 return -1;
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) )
571 log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
572 h->lockname, h->tname);
573 return -1;
575 #endif /* __riscos__ */
577 #endif /* !HAVE_DOSISH_SYSTEM */
578 h->locked = 0;
579 return 0;
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 )
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;
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;
605 if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
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;
616 p = buffer;
617 nread = 0;
620 res = read (fd, p, expected_len - nread);
621 if (res == -1 && errno == EINTR)
622 continue;
623 if (res < 0)
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;
632 p += res;
633 nread += res;
635 while (res && nread != expected_len);
636 close(fd);
638 if (nread < 11)
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;
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__ */
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;
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;
668 if (buffer != buffer_space)
669 jnlib_free (buffer);
670 return pid;
672 #endif /* !HAVE_DOSISH_SYSTEM */
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()
681 DOTLOCK h, h2;
683 h = all_lockfiles;
684 all_lockfiles = NULL;
686 while ( h )
688 h2 = h->next;
689 destroy_dotlock (h);
690 h = h2;