* card-util.c (card_status): Use isotimestamp and not the
[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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
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 #if !defined (HAVE_DOSISH_SYSTEM)
29 #include <sys/utsname.h>
30 #endif
31 #include <sys/types.h>
32 #ifndef _WIN32
33 #include <sys/time.h>
34 #endif
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include "types.h"
39 #include "util.h"
40 #include "memory.h"
41
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 */
48 };
49
50
51 static volatile DOTLOCK all_lockfiles;
52 static int never_lock;
53
54 static int read_lockfile( const char *name );
55
56 void
57 disable_dotlock(void)
58 {
59     never_lock = 1;
60 }
61
62 /****************
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.
72  *
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.
77  */
78 DOTLOCK
79 create_dotlock( const char *file_to_lock )
80 {
81     static int initialized;
82     DOTLOCK h;
83     int  fd = -1;
84     char pidstr[16];
85 #if !defined (HAVE_DOSISH_SYSTEM)
86     struct utsname utsbuf;
87 #endif
88     const char *nodename;
89     const char *dirpart;
90     int dirpartlen;
91
92     if( !initialized ) {
93         atexit( remove_lockfiles );
94         initialized = 1;
95     }
96     if( !file_to_lock )
97         return NULL;
98
99     h = m_alloc_clear( sizeof *h );
100     if( never_lock ) {
101         h->disable = 1;
102 #ifdef _REENTRANT
103         /* fixme: aquire mutex on all_lockfiles */
104 #endif
105         h->next = all_lockfiles;
106         all_lockfiles = h;
107         return h;
108     }
109
110
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?) */
114
115     /* create a temporary file */
116     if( uname( &utsbuf ) )
117         nodename = "unknown";
118     else
119         nodename = utsbuf.nodename;
120
121 #ifdef __riscos__
122     {
123         char *iter = (char *) nodename;
124         for (; iter[0]; iter++)
125             if (iter[0] == '.')
126                 iter[0] = '/';
127     }
128 #endif /* __riscos__ */
129
130     if( !(dirpart = strrchr( file_to_lock, DIRSEP_C )) ) {
131         dirpart = EXTSEP_S;
132         dirpartlen = 1;
133     }
134     else {
135         dirpartlen = dirpart - file_to_lock;
136         dirpart = file_to_lock;
137     }
138
139 #ifdef _REENTRANT
140     /* fixme: aquire mutex on all_lockfiles */
141 #endif
142     h->next = all_lockfiles;
143     all_lockfiles = h;
144
145     h->tname = m_alloc( dirpartlen + 6+30+ strlen(nodename) + 11 );
146 #ifndef __riscos__
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__ */
153
154     do {
155         errno = 0;
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 );
159     if( fd == -1 ) {
160         all_lockfiles = h->next;
161         log_error( "failed to create temporary file `%s': %s\n",
162                                             h->tname, strerror(errno));
163         m_free(h->tname);
164         m_free(h);
165         return NULL;
166     }
167     if( write(fd, pidstr, 11 ) != 11 ) {
168         all_lockfiles = h->next;
169 #ifdef _REENTRANT
170         /* release mutex */
171 #endif
172         log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) );
173         close(fd);
174         unlink(h->tname);
175         m_free(h->tname);
176         m_free(h);
177         return NULL;
178     }
179     if( close(fd) ) {
180         all_lockfiles = h->next;
181 #ifdef _REENTRANT
182         /* release mutex */
183 #endif
184         log_error( "error closing `%s': %s\n", h->tname, strerror(errno));
185         unlink(h->tname);
186         m_free(h->tname);
187         m_free(h);
188         return NULL;
189     }
190
191 #ifdef _REENTRANT
192     /* release mutex */
193 #endif
194 #endif
195     h->lockname = m_alloc( strlen(file_to_lock) + 6 );
196     strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
197     return h;
198 }
199
200
201 void
202 destroy_dotlock ( DOTLOCK h )
203 {
204 #if !defined (HAVE_DOSISH_SYSTEM)
205     if ( h )
206       {
207         DOTLOCK hprev, htmp;
208
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)
211           if (htmp == h)
212             {
213               if (hprev)
214                 hprev->next = htmp->next;
215               else
216                 all_lockfiles = htmp->next;
217               h->next = NULL;
218               break;
219             }
220
221         /* Second destroy the lock. */
222         if (!h->disable)
223           {
224             if (h->locked && h->lockname)
225               unlink (h->lockname);
226             if (h->tname)
227               unlink (h->tname);
228             m_free (h->tname);
229             m_free (h->lockname);
230           }
231         m_free(h);
232
233       }
234 #endif
235 }
236
237
238
239 static int
240 maybe_deadlock( DOTLOCK h )
241 {
242     DOTLOCK r;
243
244     for( r=all_lockfiles; r; r = r->next ) {
245         if( r != h && r->locked )
246             return 1;
247     }
248     return 0;
249 }
250
251 /****************
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
256  */
257 int
258 make_dotlock( DOTLOCK h, long timeout )
259 {
260 #if defined (HAVE_DOSISH_SYSTEM)
261     return 0;
262 #else
263     int  pid;
264     const char *maybe_dead="";
265     int backoff=0;
266
267     if( h->disable ) {
268         return 0;
269     }
270
271     if( h->locked ) {
272 #ifndef __riscos__
273         log_debug("oops, `%s' is already locked\n", h->lockname );
274 #endif /* !__riscos__ */
275         return 0;
276     }
277
278     for(;;) {
279 #ifndef __riscos__
280         if( !link(h->tname, h->lockname) ) {
281             /* fixme: better use stat to check the link count */
282             h->locked = 1;
283             return 0; /* okay */
284         }
285         if( errno != EEXIST ) {
286             log_error( "lock not made: link() failed: %s\n", strerror(errno) );
287             return -1;
288         }
289 #else /* __riscos__ */
290         if( !riscos_renamefile(h->tname, h->lockname) ) {
291             h->locked = 1;
292             return 0; /* okay */
293         }
294         if( errno != EEXIST ) {
295             log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
296             return -1;
297         }
298 #endif /* __riscos__ */
299         if( (pid = read_lockfile(h->lockname)) == -1 ) {
300             if( errno != ENOENT ) {
301                 log_info("cannot read lockfile\n");
302                 return -1;
303             }
304             log_info( "lockfile disappeared\n");
305             continue;
306         }
307         else if( pid == getpid() ) {
308             log_info( "Oops: lock already held by us\n");
309             h->locked = 1;
310             return 0; /* okay */
311         }
312         else if( kill(pid, 0) && errno == ESRCH ) {
313 #ifndef __riscos__
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 );
318 #endif
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";
323             unlink(h->lockname);
324 #endif /* __riscos__ */
325         }
326         if( timeout == -1 ) {
327             struct timeval tv;
328             log_info( "waiting for lock (held by %d%s) %s...\n",
329                       pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":"");
330
331
332             /* can't use sleep, cause signals may be blocked */
333             tv.tv_sec = 1 + backoff;
334             tv.tv_usec = 0;
335             select(0, NULL, NULL, NULL, &tv);
336             if( backoff < 10 )
337                 backoff++ ;
338         }
339         else
340             return -1;
341     }
342     /*not reached */
343 #endif
344 }
345
346
347 /****************
348  * release a lock
349  * Returns: 0 := success
350  */
351 int
352 release_dotlock( DOTLOCK h )
353 {
354 #if defined (HAVE_DOSISH_SYSTEM)
355     return 0;
356 #else
357     int pid;
358
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.  */
363     if(!all_lockfiles)
364         return 0;
365
366     if( h->disable ) 
367         return 0;
368
369     if( !h->locked ) {
370         log_debug("oops, `%s' is not locked\n", h->lockname );
371         return 0;
372     }
373
374     pid = read_lockfile( h->lockname );
375     if( pid == -1 ) {
376         log_error( "release_dotlock: lockfile error\n");
377         return -1;
378     }
379     if( pid != getpid() ) {
380         log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
381         return -1;
382     }
383 #ifndef __riscos__
384     if( unlink( h->lockname ) ) {
385         log_error( "release_dotlock: error removing lockfile `%s'",
386                                                         h->lockname);
387         return -1;
388     }
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);
393         return -1;
394     }
395 #endif /* __riscos__ */
396     /* fixme: check that the link count is now 1 */
397     h->locked = 0;
398     return 0;
399 #endif
400 }
401
402
403 /****************
404  * Read the lock file and return the pid, returns -1 on error.
405  */
406 static int
407 read_lockfile( const char *name )
408 {
409 #if defined (HAVE_DOSISH_SYSTEM)
410     return 0;
411 #else
412     int fd, pid;
413     char pidstr[16];
414
415     if( (fd = open(name, O_RDONLY)) == -1 ) {
416         int e = errno;
417         log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) );
418         errno = e;
419         return -1;
420     }
421     if( read(fd, pidstr, 10 ) != 10 ) {  /* Read 10 digits w/o newline */
422         log_debug("error reading lockfile `%s'", name );
423         close(fd);
424         errno = 0;
425         return -1;
426     }
427     pidstr[10] = 0;  /* terminate pid string */
428     close(fd);
429     pid = atoi(pidstr);
430 #ifndef __riscos__
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 );
436         errno = 0;
437         return -1;
438     }
439     return pid;
440 #endif
441 }
442
443
444 void
445 remove_lockfiles()
446 {
447 #if !defined (HAVE_DOSISH_SYSTEM)
448     DOTLOCK h, h2;
449
450     h = all_lockfiles;
451     all_lockfiles = NULL;
452
453     while( h ) {
454         h2 = h->next;
455         destroy_dotlock (h);
456         h = h2;
457     }
458 #endif
459 }