1
/* dotlock.c - dotfile locking
2
* Copyright (C) 1998, 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
4
* This file is part of GnuPG.
6
* GnuPG is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* GnuPG is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
28
#if !defined (HAVE_DOSISH_SYSTEM)
29
#include <sys/utsname.h>
31
#include <sys/types.h>
42
struct dotlock_handle {
43
struct dotlock_handle *next;
44
char *tname; /* name of lockfile template */
45
char *lockname; /* name of the real lockfile */
46
int locked; /* lock status */
47
int disable; /* locking */
51
static volatile DOTLOCK all_lockfiles;
52
static int never_lock;
54
static int read_lockfile( const char *name );
63
* Create a lockfile with the given name and return an object of
64
* type DOTLOCK which may be used later to actually do the lock.
65
* A cleanup routine gets installed to cleanup left over locks
66
* or other files used together with the lockmechanism.
67
* Althoug the function is called dotlock, this does not necessarily
68
* mean that real lockfiles are used - the function may decide to
69
* use fcntl locking. Calling the function with NULL only install
70
* the atexit handler and maybe used to assure that the cleanup
71
* is called after all other atexit handlers.
73
* Notes: This function creates a lock file in the same directory
74
* as file_to_lock with the name "file_to_lock.lock"
75
* A temporary file ".#lk.<hostname>.pid[.threadid] is used.
76
* This function does nothing for Windoze.
79
create_dotlock( const char *file_to_lock )
81
static int initialized;
85
#if !defined (HAVE_DOSISH_SYSTEM)
86
struct utsname utsbuf;
93
atexit( remove_lockfiles );
99
h = m_alloc_clear( sizeof *h );
103
/* fixme: aquire mutex on all_lockfiles */
105
h->next = all_lockfiles;
111
#if !defined (HAVE_DOSISH_SYSTEM)
112
sprintf( pidstr, "%10d\n", (int)getpid() );
113
/* fixme: add the hostname to the second line (FQDN or IP addr?) */
115
/* create a temporary file */
116
if( uname( &utsbuf ) )
117
nodename = "unknown";
119
nodename = utsbuf.nodename;
123
char *iter = (char *) nodename;
124
for (; iter[0]; iter++)
128
#endif /* __riscos__ */
130
if( !(dirpart = strrchr( file_to_lock, DIRSEP_C )) ) {
135
dirpartlen = dirpart - file_to_lock;
136
dirpart = file_to_lock;
140
/* fixme: aquire mutex on all_lockfiles */
142
h->next = all_lockfiles;
145
h->tname = m_alloc( dirpartlen + 6+30+ strlen(nodename) + 11 );
147
sprintf( h->tname, "%.*s/.#lk%p.%s.%d",
148
dirpartlen, dirpart, h, nodename, (int)getpid() );
149
#else /* __riscos__ */
150
sprintf( h->tname, "%.*s.lk%p/%s/%d",
151
dirpartlen, dirpart, h, nodename, (int)getpid() );
152
#endif /* __riscos__ */
156
fd = open( h->tname, O_WRONLY|O_CREAT|O_EXCL,
157
S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
158
} while( fd == -1 && errno == EINTR );
160
all_lockfiles = h->next;
161
log_error( "failed to create temporary file `%s': %s\n",
162
h->tname, strerror(errno));
167
if( write(fd, pidstr, 11 ) != 11 ) {
168
all_lockfiles = h->next;
172
log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) );
180
all_lockfiles = h->next;
184
log_error( "error closing `%s': %s\n", h->tname, strerror(errno));
195
h->lockname = m_alloc( strlen(file_to_lock) + 6 );
196
strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
202
destroy_dotlock ( DOTLOCK h )
204
#if !defined (HAVE_DOSISH_SYSTEM)
209
/* First remove the handle from our global list of all locks. */
210
for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
214
hprev->next = htmp->next;
216
all_lockfiles = htmp->next;
221
/* Second destroy the lock. */
224
if (h->locked && h->lockname)
225
unlink (h->lockname);
229
m_free (h->lockname);
240
maybe_deadlock( DOTLOCK h )
244
for( r=all_lockfiles; r; r = r->next ) {
245
if( r != h && r->locked )
252
* Do a lock on H. A TIMEOUT of 0 returns immediately,
253
* -1 waits forever (hopefully not), other
254
* values are timeouts in milliseconds.
255
* Returns: 0 on success
258
make_dotlock( DOTLOCK h, long timeout )
260
#if defined (HAVE_DOSISH_SYSTEM)
264
const char *maybe_dead="";
273
log_debug("oops, `%s' is already locked\n", h->lockname );
274
#endif /* !__riscos__ */
280
if( !link(h->tname, h->lockname) ) {
281
/* fixme: better use stat to check the link count */
285
if( errno != EEXIST ) {
286
log_error( "lock not made: link() failed: %s\n", strerror(errno) );
289
#else /* __riscos__ */
290
if( !riscos_renamefile(h->tname, h->lockname) ) {
294
if( errno != EEXIST ) {
295
log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
298
#endif /* __riscos__ */
299
if( (pid = read_lockfile(h->lockname)) == -1 ) {
300
if( errno != ENOENT ) {
301
log_info("cannot read lockfile\n");
304
log_info( "lockfile disappeared\n");
307
else if( pid == getpid() ) {
308
log_info( "Oops: lock already held by us\n");
312
else if( kill(pid, 0) && errno == ESRCH ) {
314
maybe_dead = " - probably dead";
315
#if 0 /* we should not do this without checking the permissions */
316
/* and the hostname */
317
log_info( "removing stale lockfile (created by %d)", pid );
319
#else /* __riscos__ */
320
/* we are *pretty* sure that the other task is dead and therefore
321
we remove the other lock file */
322
maybe_dead = " - probably dead - removing lock";
324
#endif /* __riscos__ */
326
if( timeout == -1 ) {
328
log_info( "waiting for lock (held by %d%s) %s...\n",
329
pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":"");
332
/* can't use sleep, cause signals may be blocked */
333
tv.tv_sec = 1 + backoff;
335
select(0, NULL, NULL, NULL, &tv);
349
* Returns: 0 := success
352
release_dotlock( DOTLOCK h )
354
#if defined (HAVE_DOSISH_SYSTEM)
359
/* To avoid atexit race conditions we first check whether there
360
are any locks left. It might happen that another atexit
361
handler tries to release the lock while the atexit handler of
362
this module already ran and thus H is undefined. */
370
log_debug("oops, `%s' is not locked\n", h->lockname );
374
pid = read_lockfile( h->lockname );
376
log_error( "release_dotlock: lockfile error\n");
379
if( pid != getpid() ) {
380
log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
384
if( unlink( h->lockname ) ) {
385
log_error( "release_dotlock: error removing lockfile `%s'",
389
#else /* __riscos__ */
390
if( riscos_renamefile(h->lockname, h->tname) ) {
391
log_error( "release_dotlock: error renaming lockfile `%s' to `%s'",
392
h->lockname, h->tname);
395
#endif /* __riscos__ */
396
/* fixme: check that the link count is now 1 */
404
* Read the lock file and return the pid, returns -1 on error.
407
read_lockfile( const char *name )
409
#if defined (HAVE_DOSISH_SYSTEM)
415
if( (fd = open(name, O_RDONLY)) == -1 ) {
417
log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) );
421
if( read(fd, pidstr, 10 ) != 10 ) { /* Read 10 digits w/o newline */
422
log_debug("error reading lockfile `%s'", name );
427
pidstr[10] = 0; /* terminate pid string */
431
if( !pid || pid == -1 ) {
432
#else /* __riscos__ */
433
if( (!pid && riscos_getpid()) || pid == -1 ) {
434
#endif /* __riscos__ */
435
log_error("invalid pid %d in lockfile `%s'", pid, name );
447
#if !defined (HAVE_DOSISH_SYSTEM)
451
all_lockfiles = NULL;