Updated FSF street address and preparations for a release candidate.
[gnupg.git] / util / dotlock.c
1 /* dotlock.c - dotfile locking
2  * Copyright (C) 1998, 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #if !defined (HAVE_DOSISH_SYSTEM)
30 #include <sys/utsname.h>
31 #endif
32 #include <sys/types.h>
33 #ifndef _WIN32
34 #include <sys/time.h>
35 #endif
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <signal.h>
39 #include "types.h"
40 #include "util.h"
41 #include "memory.h"
42
43 struct dotlock_handle {
44     struct dotlock_handle *next;
45     char *tname;    /* name of lockfile template */
46     char *lockname; /* name of the real lockfile */
47     int locked;     /* lock status */
48     int disable;    /* locking */
49 };
50
51
52 static volatile DOTLOCK all_lockfiles;
53 static int never_lock;
54
55 static int read_lockfile( const char *name );
56
57 void
58 disable_dotlock(void)
59 {
60     never_lock = 1;
61 }
62
63 /****************
64  * Create a lockfile with the given name and return an object of
65  * type DOTLOCK which may be used later to actually do the lock.
66  * A cleanup routine gets installed to cleanup left over locks
67  * or other files used together with the lockmechanism.
68  * Althoug the function is called dotlock, this does not necessarily
69  * mean that real lockfiles are used - the function may decide to
70  * use fcntl locking.  Calling the function with NULL only install
71  * the atexit handler and maybe used to assure that the cleanup
72  * is called after all other atexit handlers.
73  *
74  * Notes: This function creates a lock file in the same directory
75  *        as file_to_lock with the name "file_to_lock.lock"
76  *        A temporary file ".#lk.<hostname>.pid[.threadid] is used.
77  *        This function does nothing for Windoze.
78  */
79 DOTLOCK
80 create_dotlock( const char *file_to_lock )
81 {
82     static int initialized;
83     DOTLOCK h;
84     int  fd = -1;
85     char pidstr[16];
86 #if !defined (HAVE_DOSISH_SYSTEM)
87     struct utsname utsbuf;
88 #endif
89     const char *nodename;
90     const char *dirpart;
91     int dirpartlen;
92
93     if( !initialized ) {
94         atexit( remove_lockfiles );
95         initialized = 1;
96     }
97     if( !file_to_lock )
98         return NULL;
99
100     h = m_alloc_clear( sizeof *h );
101     if( never_lock ) {
102         h->disable = 1;
103 #ifdef _REENTRANT
104         /* fixme: aquire mutex on all_lockfiles */
105 #endif
106         h->next = all_lockfiles;
107         all_lockfiles = h;
108         return h;
109     }
110
111
112 #if !defined (HAVE_DOSISH_SYSTEM)
113     sprintf( pidstr, "%10d\n", (int)getpid() );
114     /* fixme: add the hostname to the second line (FQDN or IP addr?) */
115
116     /* create a temporary file */
117     if( uname( &utsbuf ) )
118         nodename = "unknown";
119     else
120         nodename = utsbuf.nodename;
121
122 #ifdef __riscos__
123     {
124         char *iter = (char *) nodename;
125         for (; iter[0]; iter++)
126             if (iter[0] == '.')
127                 iter[0] = '/';
128     }
129 #endif /* __riscos__ */
130
131     if( !(dirpart = strrchr( file_to_lock, DIRSEP_C )) ) {
132         dirpart = EXTSEP_S;
133         dirpartlen = 1;
134     }
135     else {
136         dirpartlen = dirpart - file_to_lock;
137         dirpart = file_to_lock;
138     }
139
140 #ifdef _REENTRANT
141     /* fixme: aquire mutex on all_lockfiles */
142 #endif
143     h->next = all_lockfiles;
144     all_lockfiles = h;
145
146     h->tname = m_alloc( dirpartlen + 6+30+ strlen(nodename) + 11 );
147 #ifndef __riscos__
148     sprintf( h->tname, "%.*s/.#lk%p.%s.%d",
149              dirpartlen, dirpart, h, nodename, (int)getpid() );
150 #else /* __riscos__ */
151     sprintf( h->tname, "%.*s.lk%p/%s/%d",
152              dirpartlen, dirpart, h, nodename, (int)getpid() );
153 #endif /* __riscos__ */
154
155     do {
156         errno = 0;
157         fd = open( h->tname, O_WRONLY|O_CREAT|O_EXCL,
158                           S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
159     } while( fd == -1 && errno == EINTR );
160     if( fd == -1 ) {
161         all_lockfiles = h->next;
162         log_error( "failed to create temporary file `%s': %s\n",
163                                             h->tname, strerror(errno));
164         m_free(h->tname);
165         m_free(h);
166         return NULL;
167     }
168     if( write(fd, pidstr, 11 ) != 11 ) {
169         all_lockfiles = h->next;
170 #ifdef _REENTRANT
171         /* release mutex */
172 #endif
173         log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) );
174         close(fd);
175         unlink(h->tname);
176         m_free(h->tname);
177         m_free(h);
178         return NULL;
179     }
180     if( close(fd) ) {
181         all_lockfiles = h->next;
182 #ifdef _REENTRANT
183         /* release mutex */
184 #endif
185         log_error( "error closing `%s': %s\n", h->tname, strerror(errno));
186         unlink(h->tname);
187         m_free(h->tname);
188         m_free(h);
189         return NULL;
190     }
191
192 #ifdef _REENTRANT
193     /* release mutex */
194 #endif
195 #endif
196     h->lockname = m_alloc( strlen(file_to_lock) + 6 );
197     strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
198     return h;
199 }
200
201
202 void
203 destroy_dotlock ( DOTLOCK h )
204 {
205 #if !defined (HAVE_DOSISH_SYSTEM)
206     if ( h )
207       {
208         DOTLOCK hprev, htmp;
209
210         /* First remove the handle from our global list of all locks. */
211         for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
212           if (htmp == h)
213             {
214               if (hprev)
215                 hprev->next = htmp->next;
216               else
217                 all_lockfiles = htmp->next;
218               h->next = NULL;
219               break;
220             }
221
222         /* Second destroy the lock. */
223         if (!h->disable)
224           {
225             if (h->locked && h->lockname)
226               unlink (h->lockname);
227             if (h->tname)
228               unlink (h->tname);
229             m_free (h->tname);
230             m_free (h->lockname);
231           }
232         m_free(h);
233
234       }
235 #endif
236 }
237
238
239
240 static int
241 maybe_deadlock( DOTLOCK h )
242 {
243     DOTLOCK r;
244
245     for( r=all_lockfiles; r; r = r->next ) {
246         if( r != h && r->locked )
247             return 1;
248     }
249     return 0;
250 }
251
252 /****************
253  * Do a lock on H. A TIMEOUT of 0 returns immediately,
254  * -1 waits forever (hopefully not), other
255  * values are timeouts in milliseconds.
256  * Returns: 0 on success
257  */
258 int
259 make_dotlock( DOTLOCK h, long timeout )
260 {
261 #if defined (HAVE_DOSISH_SYSTEM)
262     return 0;
263 #else
264     int  pid;
265     const char *maybe_dead="";
266     int backoff=0;
267
268     if( h->disable ) {
269         return 0;
270     }
271
272     if( h->locked ) {
273 #ifndef __riscos__
274         log_debug("oops, `%s' is already locked\n", h->lockname );
275 #endif /* !__riscos__ */
276         return 0;
277     }
278
279     for(;;) {
280 #ifndef __riscos__
281         if( !link(h->tname, h->lockname) ) {
282             /* fixme: better use stat to check the link count */
283             h->locked = 1;
284             return 0; /* okay */
285         }
286         if( errno != EEXIST ) {
287             log_error( "lock not made: link() failed: %s\n", strerror(errno) );
288             return -1;
289         }
290 #else /* __riscos__ */
291         if( !riscos_renamefile(h->tname, h->lockname) ) {
292             h->locked = 1;
293             return 0; /* okay */
294         }
295         if( errno != EEXIST ) {
296             log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
297             return -1;
298         }
299 #endif /* __riscos__ */
300         if( (pid = read_lockfile(h->lockname)) == -1 ) {
301             if( errno != ENOENT ) {
302                 log_info("cannot read lockfile\n");
303                 return -1;
304             }
305             log_info( "lockfile disappeared\n");
306             continue;
307         }
308         else if( pid == getpid() ) {
309             log_info( "Oops: lock already held by us\n");
310             h->locked = 1;
311             return 0; /* okay */
312         }
313         else if( kill(pid, 0) && errno == ESRCH ) {
314 #ifndef __riscos__
315             maybe_dead = " - probably dead";
316 #if 0 /* we should not do this without checking the permissions */
317                /* and the hostname */
318             log_info( "removing stale lockfile (created by %d)", pid );
319 #endif
320 #else /* __riscos__ */
321             /* we are *pretty* sure that the other task is dead and therefore
322                we remove the other lock file */
323             maybe_dead = " - probably dead - removing lock";
324             unlink(h->lockname);
325 #endif /* __riscos__ */
326         }
327         if( timeout == -1 ) {
328             struct timeval tv;
329             log_info( "waiting for lock (held by %d%s) %s...\n",
330                       pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":"");
331
332
333             /* can't use sleep, cause signals may be blocked */
334             tv.tv_sec = 1 + backoff;
335             tv.tv_usec = 0;
336             select(0, NULL, NULL, NULL, &tv);
337             if( backoff < 10 )
338                 backoff++ ;
339         }
340         else
341             return -1;
342     }
343     /*not reached */
344 #endif
345 }
346
347
348 /****************
349  * release a lock
350  * Returns: 0 := success
351  */
352 int
353 release_dotlock( DOTLOCK h )
354 {
355 #if defined (HAVE_DOSISH_SYSTEM)
356     return 0;
357 #else
358     int pid;
359
360     /* To avoid atexit race conditions we first check whether there
361        are any locks left.  It might happen that another atexit
362        handler tries to release the lock while the atexit handler of
363        this module already ran and thus H is undefined.  */
364     if(!all_lockfiles)
365         return 0;
366
367     if( h->disable ) 
368         return 0;
369
370     if( !h->locked ) {
371         log_debug("oops, `%s' is not locked\n", h->lockname );
372         return 0;
373     }
374
375     pid = read_lockfile( h->lockname );
376     if( pid == -1 ) {
377         log_error( "release_dotlock: lockfile error\n");
378         return -1;
379     }
380     if( pid != getpid() ) {
381         log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
382         return -1;
383     }
384 #ifndef __riscos__
385     if( unlink( h->lockname ) ) {
386         log_error( "release_dotlock: error removing lockfile `%s'",
387                                                         h->lockname);
388         return -1;
389     }
390 #else /* __riscos__ */
391     if( riscos_renamefile(h->lockname, h->tname) ) {
392         log_error( "release_dotlock: error renaming lockfile `%s' to `%s'",
393                                                         h->lockname, h->tname);
394         return -1;
395     }
396 #endif /* __riscos__ */
397     /* fixme: check that the link count is now 1 */
398     h->locked = 0;
399     return 0;
400 #endif
401 }
402
403
404 /****************
405  * Read the lock file and return the pid, returns -1 on error.
406  */
407 static int
408 read_lockfile( const char *name )
409 {
410 #if defined (HAVE_DOSISH_SYSTEM)
411     return 0;
412 #else
413     int fd, pid;
414     char pidstr[16];
415
416     if( (fd = open(name, O_RDONLY)) == -1 ) {
417         int e = errno;
418         log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) );
419         errno = e;
420         return -1;
421     }
422     if( read(fd, pidstr, 10 ) != 10 ) {  /* Read 10 digits w/o newline */
423         log_debug("error reading lockfile `%s'", name );
424         close(fd);
425         errno = 0;
426         return -1;
427     }
428     pidstr[10] = 0;  /* terminate pid string */
429     close(fd);
430     pid = atoi(pidstr);
431 #ifndef __riscos__
432     if( !pid || pid == -1 ) {
433 #else /* __riscos__ */
434     if( (!pid && riscos_getpid()) || pid == -1 ) {
435 #endif /* __riscos__ */
436         log_error("invalid pid %d in lockfile `%s'", pid, name );
437         errno = 0;
438         return -1;
439     }
440     return pid;
441 #endif
442 }
443
444
445 void
446 remove_lockfiles()
447 {
448 #if !defined (HAVE_DOSISH_SYSTEM)
449     DOTLOCK h, h2;
450
451     h = all_lockfiles;
452     all_lockfiles = NULL;
453
454     while( h ) {
455         h2 = h->next;
456         destroy_dotlock (h);
457         h = h2;
458     }
459 #endif
460 }