Line data Source code
1 : /* dotlock.c - dotfile locking
2 : * Copyright (C) 1998, 2000, 2001, 2003, 2004,
3 : * 2005, 2006, 2008, 2010, 2011 Free Software Foundation, Inc.
4 : *
5 : * This file is part of JNLIB, which is a subsystem of GnuPG.
6 : *
7 : * JNLIB is free software; you can redistribute it and/or modify it
8 : * under the terms of either
9 : *
10 : * - the GNU Lesser General Public License as published by the Free
11 : * Software Foundation; either version 3 of the License, or (at
12 : * your option) any later version.
13 : *
14 : * or
15 : *
16 : * - the GNU General Public License as published by the Free
17 : * Software Foundation; either version 2 of the License, or (at
18 : * your option) any later version.
19 : *
20 : * or both in parallel, as here.
21 : *
22 : * JNLIB is distributed in the hope that it will be useful, but
23 : * WITHOUT ANY WARRANTY; without even the implied warranty of
24 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 : * General Public License for more details.
26 : *
27 : * You should have received a copies of the GNU General Public License
28 : * and the GNU Lesser General Public License along with this program;
29 : * if not, see <http://www.gnu.org/licenses/>.
30 : *
31 : * ALTERNATIVELY, this file may be distributed under the terms of the
32 : * following license, in which case the provisions of this license are
33 : * required INSTEAD OF the GNU Lesser General License or the GNU
34 : * General Public License. If you wish to allow use of your version of
35 : * this file only under the terms of the GNU Lesser General License or
36 : * the GNU General Public License, and not to allow others to use your
37 : * version of this file under the terms of the following license,
38 : * indicate your decision by deleting this paragraph and the license
39 : * below.
40 : *
41 : * Redistribution and use in source and binary forms, with or without
42 : * modification, are permitted provided that the following conditions
43 : * are met:
44 : *
45 : * 1. Redistributions of source code must retain the above copyright
46 : * notice, and the entire permission notice in its entirety,
47 : * including the disclaimer of warranties.
48 : * 2. Redistributions in binary form must reproduce the above copyright
49 : * notice, this list of conditions and the following disclaimer in the
50 : * documentation and/or other materials provided with the distribution.
51 : * 3. The name of the author may not be used to endorse or promote
52 : * products derived from this software without specific prior
53 : * written permission.
54 : *
55 : * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
56 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
57 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
58 : * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
59 : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
60 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
61 : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
63 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
65 : * OF THE POSSIBILITY OF SUCH DAMAGE.
66 : */
67 :
68 : /*
69 : Overview:
70 : =========
71 :
72 : This module implements advisory file locking in a portable way.
73 : Due to the problems with POSIX fcntl locking a separate lock file
74 : is used. It would be possible to use fcntl locking on this lock
75 : file and thus avoid the weird auto unlock bug of POSIX while still
76 : having an unproved better performance of fcntl locking. However
77 : there are still problems left, thus we resort to use a hardlink
78 : which has the well defined property that a link call will fail if
79 : the target file already exists.
80 :
81 : Given that hardlinks are also available on NTFS file systems since
82 : Windows XP; it will be possible to enhance this module to use
83 : hardlinks even on Windows and thus allow Windows and Posix clients
84 : to use locking on the same directory. This is not yet implemented;
85 : instead we use a lockfile on Windows along with W32 style file
86 : locking.
87 :
88 : On FAT file systems hardlinks are not supported. Thus this method
89 : does not work. Our solution is to use a O_EXCL locking instead.
90 : Querying the type of the file system is not easy to do in a
91 : portable way (e.g. Linux has a statfs, BSDs have a the same call
92 : but using different structures and constants). What we do instead
93 : is to check at runtime whether link(2) works for a specific lock
94 : file.
95 :
96 :
97 : How to use:
98 : ===========
99 :
100 : At program initialization time, the module should be explicitly
101 : initialized:
102 :
103 : dotlock_create (NULL, 0);
104 :
105 : This installs an atexit handler and may also initialize mutex etc.
106 : It is optional for non-threaded applications. Only the first call
107 : has an effect. This needs to be done before any extra threads are
108 : started.
109 :
110 : To create a lock file (which prepares it but does not take the
111 : lock) you do:
112 :
113 : dotlock_t h
114 :
115 : h = dotlock_create (fname, 0);
116 : if (!h)
117 : error ("error creating lock file: %s\n", strerror (errno));
118 :
119 : It is important to handle the error. For example on a read-only
120 : file system a lock can't be created (but is usually not needed).
121 : FNAME is the file you want to lock; the actual lockfile is that
122 : name with the suffix ".lock" appended. On success a handle to be
123 : used with the other functions is returned or NULL on error. Note
124 : that the handle shall only be used by one thread at a time. This
125 : function creates a unique file temporary file (".#lk*") in the same
126 : directory as FNAME and returns a handle for further operations.
127 : The module keeps track of theses unique files so that they will be
128 : unlinked using the atexit handler. If you don't need the lock file
129 : anymore, you may also explicitly remove it with a call to:
130 :
131 : dotlock_destroy (h);
132 :
133 : To actually lock the file, you use:
134 :
135 : if (dotlock_take (h, -1))
136 : error ("error taking lock: %s\n", strerror (errno));
137 :
138 : This function will wait until the lock is acquired. If an
139 : unexpected error occurs if will return non-zero and set ERRNO. If
140 : you pass (0) instead of (-1) the function does not wait in case the
141 : file is already locked but returns -1 and sets ERRNO to EACCES.
142 : Any other positive value for the second parameter is considered a
143 : timeout valuie in milliseconds.
144 :
145 : To release the lock you call:
146 :
147 : if (dotlock_release (h))
148 : error ("error releasing lock: %s\n", strerror (errno));
149 :
150 : or, if the lock file is not anymore needed, you may just call
151 : dotlock_destroy. However dotlock_release does some extra checks
152 : before releasing the lock and prints diagnostics to help detecting
153 : bugs.
154 :
155 : If you want to explicitly destroy all lock files you may call
156 :
157 : dotlock_remove_lockfiles ();
158 :
159 : which is the core of the installed atexit handler. In case your
160 : application wants to disable locking completely it may call
161 :
162 : disable_locking ()
163 :
164 : before any locks are created.
165 :
166 : There are two convenience functions to store an integer (e.g. a
167 : file descriptor) value with the handle:
168 :
169 : void dotlock_set_fd (dotlock_t h, int fd);
170 : int dotlock_get_fd (dotlock_t h);
171 :
172 : If nothing has been stored dotlock_get_fd returns -1.
173 :
174 :
175 :
176 : How to build:
177 : =============
178 :
179 : This module was originally developed for GnuPG but later changed to
180 : allow its use without any GnuPG dependency. If you want to use it
181 : with you application you may simply use it and it should figure out
182 : most things automagically.
183 :
184 : You may use the common config.h file to pass macros, but take care
185 : to pass -DHAVE_CONFIG_H to the compiler. Macros used by this
186 : module are:
187 :
188 : DOTLOCK_USE_PTHREAD - Define if POSIX threads are in use.
189 :
190 : DOTLOCK_GLIB_LOGGING - Define this to use Glib logging functions.
191 :
192 : DOTLOCK_EXT_SYM_PREFIX - Prefix all external symbols with the
193 : string to which this macro evaluates.
194 :
195 : GNUPG_MAJOR_VERSION - Defined when used by GnuPG.
196 :
197 : HAVE_DOSISH_SYSTEM - Defined for Windows etc. Will be
198 : automatically defined if a the target is
199 : Windows.
200 :
201 : HAVE_POSIX_SYSTEM - Internally defined to !HAVE_DOSISH_SYSTEM.
202 :
203 : HAVE_SIGNAL_H - Should be defined on Posix systems. If config.h
204 : is not used defaults to defined.
205 :
206 : DIRSEP_C - Separation character for file name parts.
207 : Usually not redefined.
208 :
209 : EXTSEP_S - Separation string for file name suffixes.
210 : Usually not redefined.
211 :
212 : HAVE_W32CE_SYSTEM - Currently only used by GnuPG.
213 :
214 : Note that there is a test program t-dotlock which has compile
215 : instructions at its end. At least for SMBFS and CIFS it is
216 : important that 64 bit versions of stat are used; most programming
217 : environments do this these days, just in case you want to compile
218 : it on the command line, remember to pass -D_FILE_OFFSET_BITS=64
219 :
220 :
221 : Bugs:
222 : =====
223 :
224 : On Windows this module is not yet thread-safe.
225 :
226 :
227 : Miscellaneous notes:
228 : ====================
229 :
230 : On hardlinks:
231 : - Hardlinks are supported under Windows with NTFS since XP/Server2003.
232 : - In Linux 2.6.33 both SMBFS and CIFS seem to support hardlinks.
233 : - NFS supports hard links. But there are solvable problems.
234 : - FAT does not support links
235 :
236 : On the file locking API:
237 : - CIFS on Linux 2.6.33 supports several locking methods.
238 : SMBFS seems not to support locking. No closer checks done.
239 : - NFS supports Posix locks. flock is emulated in the server.
240 : However there are a couple of problems; see below.
241 : - FAT does not support locks.
242 : - An advantage of fcntl locking is that R/W locks can be
243 : implemented which is not easy with a straight lock file.
244 :
245 : On O_EXCL:
246 : - Does not work reliable on NFS
247 : - Should work on CIFS and SMBFS but how can we delete lockfiles?
248 :
249 : On NFS problems:
250 : - Locks vanish if the server crashes and reboots.
251 : - Client crashes keep the lock in the server until the client
252 : re-connects.
253 : - Communication problems may return unreliable error codes. The
254 : MUA Postfix's workaround is to compare the link count after
255 : seeing an error for link. However that gives a race. If using a
256 : unique file to link to a lockfile and using stat to check the
257 : link count instead of looking at the error return of link(2) is
258 : the best solution.
259 : - O_EXCL seems to have a race and may re-create a file anyway.
260 :
261 : */
262 :
263 : #ifdef HAVE_CONFIG_H
264 : # include <config.h>
265 : #endif
266 :
267 : /* Some quick replacements for stuff we usually expect to be defined
268 : in config.h. Define HAVE_POSIX_SYSTEM for better readability. */
269 : #if !defined (HAVE_DOSISH_SYSTEM) && defined(_WIN32)
270 : # define HAVE_DOSISH_SYSTEM 1
271 : #endif
272 : #if !defined (HAVE_DOSISH_SYSTEM) && !defined (HAVE_POSIX_SYSTEM)
273 : # define HAVE_POSIX_SYSTEM 1
274 : #endif
275 :
276 : /* With no config.h assume that we have sitgnal.h. */
277 : #if !defined (HAVE_CONFIG_H) && defined (HAVE_POSIX_SYSTEM)
278 : # define HAVE_SIGNAL_H 1
279 : #endif
280 :
281 : /* Standard headers. */
282 : #include <stdlib.h>
283 : #include <stdio.h>
284 : #include <string.h>
285 : #include <errno.h>
286 : #include <ctype.h>
287 : #include <errno.h>
288 : #include <unistd.h>
289 : #ifdef HAVE_DOSISH_SYSTEM
290 : # define WIN32_LEAN_AND_MEAN /* We only need the OS core stuff. */
291 : # include <windows.h>
292 : #else
293 : # include <sys/types.h>
294 : # include <sys/stat.h>
295 : # include <sys/utsname.h>
296 : #endif
297 : #include <sys/types.h>
298 : #include <sys/time.h>
299 : #include <sys/stat.h>
300 : #include <fcntl.h>
301 : #ifdef HAVE_SIGNAL_H
302 : # include <signal.h>
303 : #endif
304 : #ifdef DOTLOCK_USE_PTHREAD
305 : # include <pthread.h>
306 : #endif
307 :
308 : #ifdef DOTLOCK_GLIB_LOGGING
309 : # include <glib.h>
310 : #endif
311 :
312 : #ifdef GNUPG_MAJOR_VERSION
313 : # include "libjnlib-config.h"
314 : #endif
315 : #ifdef HAVE_W32CE_SYSTEM
316 : # include "utf8conv.h" /* WindowsCE requires filename conversion. */
317 : #endif
318 :
319 : #include "dotlock.h"
320 :
321 :
322 : /* Define constants for file name construction. */
323 : #if !defined(DIRSEP_C) && !defined(EXTSEP_S)
324 : # ifdef HAVE_DOSISH_SYSTEM
325 : # define DIRSEP_C '\\'
326 : # define EXTSEP_S "."
327 : #else
328 : # define DIRSEP_C '/'
329 : # define EXTSEP_S "."
330 : # endif
331 : #endif
332 :
333 : /* In GnuPG we use wrappers around the malloc fucntions. If they are
334 : not defined we assume that this code is used outside of GnuPG and
335 : fall back to the regular malloc functions. */
336 : #ifndef jnlib_malloc
337 : # define jnlib_malloc(a) malloc ((a))
338 : # define jnlib_calloc(a,b) calloc ((a), (b))
339 : # define jnlib_free(a) free ((a))
340 : #endif
341 :
342 : /* Wrapper to set ERRNO. */
343 : #ifndef jnlib_set_errno
344 : # ifdef HAVE_W32CE_SYSTEM
345 : # define jnlib_set_errno(e) gpg_err_set_errno ((e))
346 : # else
347 : # define jnlib_set_errno(e) do { errno = (e); } while (0)
348 : # endif
349 : #endif
350 :
351 : /* Gettext macro replacement. */
352 : #ifndef _
353 : # define _(a) (a)
354 : #endif
355 :
356 : #ifdef GNUPG_MAJOR_VERSION
357 : # define my_info_0(a) log_info ((a))
358 : # define my_info_1(a,b) log_info ((a), (b))
359 : # define my_info_2(a,b,c) log_info ((a), (b), (c))
360 : # define my_info_3(a,b,c,d) log_info ((a), (b), (c), (d))
361 : # define my_error_0(a) log_error ((a))
362 : # define my_error_1(a,b) log_error ((a), (b))
363 : # define my_error_2(a,b,c) log_error ((a), (b), (c))
364 : # define my_debug_1(a,b) log_debug ((a), (b))
365 : # define my_fatal_0(a) log_fatal ((a))
366 : #elif defined (DOTLOCK_GLIB_LOGGING)
367 : # define my_info_0(a) g_message ((a))
368 : # define my_info_1(a,b) g_message ((a), (b))
369 : # define my_info_2(a,b,c) g_message ((a), (b), (c))
370 : # define my_info_3(a,b,c,d) g_message ((a), (b), (c), (d))
371 : # define my_error_0(a) g_warning ((a))
372 : # define my_error_1(a,b) g_warning ((a), (b))
373 : # define my_error_2(a,b,c) g_warning ((a), (b), (c))
374 : # define my_debug_1(a,b) g_debug ((a), (b))
375 : # define my_fatal_0(a) g_error ((a))
376 : #else
377 : # define my_info_0(a) fprintf (stderr, (a))
378 : # define my_info_1(a,b) fprintf (stderr, (a), (b))
379 : # define my_info_2(a,b,c) fprintf (stderr, (a), (b), (c))
380 : # define my_info_3(a,b,c,d) fprintf (stderr, (a), (b), (c), (d))
381 : # define my_error_0(a) fprintf (stderr, (a))
382 : # define my_error_1(a,b) fprintf (stderr, (a), (b))
383 : # define my_error_2(a,b,c) fprintf (stderr, (a), (b), (c))
384 : # define my_debug_1(a,b) fprintf (stderr, (a), (b))
385 : # define my_fatal_0(a) do { fprintf (stderr,(a)); fflush (stderr); \
386 : abort (); } while (0)
387 : #endif
388 :
389 :
390 :
391 :
392 :
393 : /* The object describing a lock. */
394 : struct dotlock_handle
395 : {
396 : struct dotlock_handle *next;
397 : char *lockname; /* Name of the actual lockfile. */
398 : unsigned int locked:1; /* Lock status. */
399 : unsigned int disable:1; /* If true, locking is disabled. */
400 : unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
401 :
402 : int extra_fd; /* A place for the caller to store an FD. */
403 :
404 : #ifdef HAVE_DOSISH_SYSTEM
405 : HANDLE lockhd; /* The W32 handle of the lock file. */
406 : #else /*!HAVE_DOSISH_SYSTEM */
407 : char *tname; /* Name of the lockfile template. */
408 : size_t nodename_off; /* Offset in TNAME of the nodename part. */
409 : size_t nodename_len; /* Length of the nodename part. */
410 : #endif /*!HAVE_DOSISH_SYSTEM */
411 : };
412 :
413 :
414 : /* A list of of all lock handles. The volatile attribute might help
415 : if used in an atexit handler. */
416 : static volatile dotlock_t all_lockfiles;
417 : #ifdef DOTLOCK_USE_PTHREAD
418 : static pthread_mutex_t all_lockfiles_mutex = PTHREAD_MUTEX_INITIALIZER;
419 : # define LOCK_all_lockfiles() do { \
420 : if (pthread_mutex_lock (&all_lockfiles_mutex)) \
421 : my_fatal_0 ("locking all_lockfiles_mutex failed\n"); \
422 : } while (0)
423 : # define UNLOCK_all_lockfiles() do { \
424 : if (pthread_mutex_unlock (&all_lockfiles_mutex)) \
425 : my_fatal_0 ("unlocking all_lockfiles_mutex failed\n"); \
426 : } while (0)
427 : #else /*!DOTLOCK_USE_PTHREAD*/
428 : # define LOCK_all_lockfiles() do { } while (0)
429 : # define UNLOCK_all_lockfiles() do { } while (0)
430 : #endif /*!DOTLOCK_USE_PTHREAD*/
431 :
432 : /* If this has the value true all locking is disabled. */
433 : static int never_lock;
434 :
435 :
436 :
437 :
438 :
439 : /* Entirely disable all locking. This function should be called
440 : before any locking is done. It may be called right at startup of
441 : the process as it only sets a global value. */
442 : void
443 0 : dotlock_disable (void)
444 : {
445 0 : never_lock = 1;
446 0 : }
447 :
448 :
449 : #ifdef HAVE_POSIX_SYSTEM
450 : static int
451 0 : maybe_deadlock (dotlock_t h)
452 : {
453 : dotlock_t r;
454 0 : int res = 0;
455 :
456 0 : LOCK_all_lockfiles ();
457 0 : for (r=all_lockfiles; r; r = r->next)
458 : {
459 0 : if ( r != h && r->locked )
460 : {
461 0 : res = 1;
462 0 : break;
463 : }
464 : }
465 0 : UNLOCK_all_lockfiles ();
466 0 : return res;
467 : }
468 : #endif /*HAVE_POSIX_SYSTEM*/
469 :
470 :
471 : /* Read the lock file and return the pid, returns -1 on error. True
472 : will be stored in the integer at address SAME_NODE if the lock file
473 : has been created on the same node. */
474 : #ifdef HAVE_POSIX_SYSTEM
475 : static int
476 32 : read_lockfile (dotlock_t h, int *same_node )
477 : {
478 : char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
479 : names are usually shorter. */
480 : int fd;
481 32 : int pid = -1;
482 : char *buffer, *p;
483 : size_t expected_len;
484 : int res, nread;
485 :
486 32 : *same_node = 0;
487 32 : expected_len = 10 + 1 + h->nodename_len + 1;
488 32 : if ( expected_len >= sizeof buffer_space)
489 : {
490 0 : buffer = jnlib_malloc (expected_len);
491 0 : if (!buffer)
492 0 : return -1;
493 : }
494 : else
495 32 : buffer = buffer_space;
496 :
497 32 : if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
498 : {
499 0 : int e = errno;
500 0 : my_info_2 ("error opening lockfile `%s': %s\n",
501 : h->lockname, strerror(errno) );
502 0 : if (buffer != buffer_space)
503 0 : jnlib_free (buffer);
504 0 : jnlib_set_errno (e); /* Need to return ERRNO here. */
505 0 : return -1;
506 : }
507 :
508 32 : p = buffer;
509 32 : nread = 0;
510 : do
511 : {
512 32 : res = read (fd, p, expected_len - nread);
513 32 : if (res == -1 && errno == EINTR)
514 0 : continue;
515 32 : if (res < 0)
516 : {
517 0 : my_info_1 ("error reading lockfile `%s'\n", h->lockname );
518 0 : close (fd);
519 0 : if (buffer != buffer_space)
520 0 : jnlib_free (buffer);
521 0 : jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */
522 0 : return -1;
523 : }
524 32 : p += res;
525 32 : nread += res;
526 : }
527 32 : while (res && nread != expected_len);
528 32 : close(fd);
529 :
530 32 : if (nread < 11)
531 : {
532 0 : my_info_1 ("invalid size of lockfile `%s'\n", h->lockname);
533 0 : if (buffer != buffer_space)
534 0 : jnlib_free (buffer);
535 0 : jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */
536 0 : return -1;
537 : }
538 :
539 32 : if (buffer[10] != '\n'
540 32 : || (buffer[10] = 0, pid = atoi (buffer)) == -1
541 32 : || !pid )
542 : {
543 0 : my_error_2 ("invalid pid %d in lockfile `%s'\n", pid, h->lockname);
544 0 : if (buffer != buffer_space)
545 0 : jnlib_free (buffer);
546 0 : jnlib_set_errno (0);
547 0 : return -1;
548 : }
549 :
550 32 : if (nread == expected_len
551 32 : && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
552 32 : && buffer[11+h->nodename_len] == '\n')
553 32 : *same_node = 1;
554 :
555 32 : if (buffer != buffer_space)
556 0 : jnlib_free (buffer);
557 32 : return pid;
558 : }
559 : #endif /*HAVE_POSIX_SYSTEM */
560 :
561 :
562 : /* Check whether the file system which stores TNAME supports
563 : hardlinks. Instead of using the non-portable statsfs call which
564 : differs between various Unix versions, we do a runtime test.
565 : Returns: 0 supports hardlinks; 1 no hardlink support, -1 unknown
566 : (test error). */
567 : #ifdef HAVE_POSIX_SYSTEM
568 : static int
569 32 : use_hardlinks_p (const char *tname)
570 : {
571 : char *lname;
572 : struct stat sb;
573 : unsigned int nlink;
574 : int res;
575 :
576 32 : if (stat (tname, &sb))
577 0 : return -1;
578 32 : nlink = (unsigned int)sb.st_nlink;
579 :
580 32 : lname = jnlib_malloc (strlen (tname) + 1 + 1);
581 32 : if (!lname)
582 0 : return -1;
583 32 : strcpy (lname, tname);
584 32 : strcat (lname, "x");
585 :
586 32 : link (tname, lname);
587 :
588 32 : if (stat (tname, &sb))
589 0 : res = -1; /* Ooops. */
590 32 : else if (sb.st_nlink == nlink + 1)
591 32 : res = 0; /* Yeah, hardlinks are supported. */
592 : else
593 0 : res = 1; /* No hardlink support. */
594 :
595 32 : unlink (lname);
596 32 : jnlib_free (lname);
597 32 : return res;
598 : }
599 : #endif /*HAVE_POSIX_SYSTEM */
600 :
601 :
602 :
603 : #ifdef HAVE_POSIX_SYSTEM
604 : /* Locking core for Unix. It used a temporary file and the link
605 : system call to make locking an atomic operation. */
606 : static dotlock_t
607 32 : dotlock_create_unix (dotlock_t h, const char *file_to_lock)
608 : {
609 32 : int fd = -1;
610 : char pidstr[16];
611 : const char *nodename;
612 : const char *dirpart;
613 : int dirpartlen;
614 : struct utsname utsbuf;
615 : size_t tnamelen;
616 :
617 32 : snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
618 :
619 : /* Create a temporary file. */
620 32 : if ( uname ( &utsbuf ) )
621 0 : nodename = "unknown";
622 : else
623 32 : nodename = utsbuf.nodename;
624 :
625 32 : if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
626 : {
627 0 : dirpart = EXTSEP_S;
628 0 : dirpartlen = 1;
629 : }
630 : else
631 : {
632 32 : dirpartlen = dirpart - file_to_lock;
633 32 : dirpart = file_to_lock;
634 : }
635 :
636 32 : LOCK_all_lockfiles ();
637 32 : h->next = all_lockfiles;
638 32 : all_lockfiles = h;
639 :
640 32 : tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
641 32 : h->tname = jnlib_malloc (tnamelen + 1);
642 32 : if (!h->tname)
643 : {
644 0 : all_lockfiles = h->next;
645 0 : UNLOCK_all_lockfiles ();
646 0 : jnlib_free (h);
647 0 : return NULL;
648 : }
649 32 : h->nodename_len = strlen (nodename);
650 :
651 32 : snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
652 32 : h->nodename_off = strlen (h->tname);
653 32 : snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
654 32 : "%s.%d", nodename, (int)getpid ());
655 :
656 : do
657 : {
658 32 : jnlib_set_errno (0);
659 32 : fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
660 : S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
661 : }
662 32 : while (fd == -1 && errno == EINTR);
663 :
664 32 : if ( fd == -1 )
665 : {
666 0 : all_lockfiles = h->next;
667 0 : UNLOCK_all_lockfiles ();
668 0 : my_error_2 (_("failed to create temporary file `%s': %s\n"),
669 : h->tname, strerror(errno));
670 0 : jnlib_free (h->tname);
671 0 : jnlib_free (h);
672 0 : return NULL;
673 : }
674 32 : if ( write (fd, pidstr, 11 ) != 11 )
675 0 : goto write_failed;
676 32 : if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
677 0 : goto write_failed;
678 32 : if ( write (fd, "\n", 1 ) != 1 )
679 0 : goto write_failed;
680 32 : if ( close (fd) )
681 0 : goto write_failed;
682 :
683 : /* Check whether we support hard links. */
684 32 : switch (use_hardlinks_p (h->tname))
685 : {
686 32 : case 0: /* Yes. */
687 32 : break;
688 0 : case 1: /* No. */
689 0 : unlink (h->tname);
690 0 : h->use_o_excl = 1;
691 0 : break;
692 0 : default:
693 0 : my_error_2 ("can't check whether hardlinks are supported for `%s': %s\n",
694 : h->tname, strerror(errno));
695 0 : goto write_failed;
696 : }
697 :
698 32 : h->lockname = jnlib_malloc (strlen (file_to_lock) + 6 );
699 32 : if (!h->lockname)
700 : {
701 0 : all_lockfiles = h->next;
702 0 : UNLOCK_all_lockfiles ();
703 0 : unlink (h->tname);
704 0 : jnlib_free (h->tname);
705 0 : jnlib_free (h);
706 0 : return NULL;
707 : }
708 32 : strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
709 32 : UNLOCK_all_lockfiles ();
710 32 : if (h->use_o_excl)
711 0 : my_debug_1 ("locking for `%s' done via O_EXCL\n", h->lockname);
712 :
713 32 : return h;
714 :
715 0 : write_failed:
716 0 : all_lockfiles = h->next;
717 0 : UNLOCK_all_lockfiles ();
718 0 : my_error_2 (_("error writing to `%s': %s\n"), h->tname, strerror (errno));
719 0 : close (fd);
720 0 : unlink (h->tname);
721 0 : jnlib_free (h->tname);
722 0 : jnlib_free (h);
723 0 : return NULL;
724 : }
725 : #endif /*HAVE_POSIX_SYSTEM*/
726 :
727 :
728 : #ifdef HAVE_DOSISH_SYSTEM
729 : /* Locking core for Windows. This version does not need a temporary
730 : file but uses the plain lock file along with record locking. We
731 : create this file here so that we later only need to do the file
732 : locking. For error reporting it is useful to keep the name of the
733 : file in the handle. */
734 : static dotlock_t
735 : dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
736 : {
737 : LOCK_all_lockfiles ();
738 : h->next = all_lockfiles;
739 : all_lockfiles = h;
740 :
741 : h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
742 : if (!h->lockname)
743 : {
744 : all_lockfiles = h->next;
745 : UNLOCK_all_lockfiles ();
746 : jnlib_free (h);
747 : return NULL;
748 : }
749 : strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
750 :
751 : /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
752 : along with FILE_SHARE_DELETE but that does not work due to a race
753 : condition: Despite the OPEN_ALWAYS flag CreateFile may return an
754 : error and we can't reliable create/open the lock file unless we
755 : would wait here until it works - however there are other valid
756 : reasons why a lock file can't be created and thus the process
757 : would not stop as expected but spin until Windows crashes. Our
758 : solution is to keep the lock file open; that does not harm. */
759 : {
760 : #ifdef HAVE_W32CE_SYSTEM
761 : wchar_t *wname = utf8_to_wchar (h->lockname);
762 :
763 : if (wname)
764 : h->lockhd = CreateFile (wname,
765 : GENERIC_READ|GENERIC_WRITE,
766 : FILE_SHARE_READ|FILE_SHARE_WRITE,
767 : NULL, OPEN_ALWAYS, 0, NULL);
768 : else
769 : h->lockhd = INVALID_HANDLE_VALUE;
770 : jnlib_free (wname);
771 : #else
772 : h->lockhd = CreateFile (h->lockname,
773 : GENERIC_READ|GENERIC_WRITE,
774 : FILE_SHARE_READ|FILE_SHARE_WRITE,
775 : NULL, OPEN_ALWAYS, 0, NULL);
776 : #endif
777 : }
778 : if (h->lockhd == INVALID_HANDLE_VALUE)
779 : {
780 : all_lockfiles = h->next;
781 : UNLOCK_all_lockfiles ();
782 : my_error_2 (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
783 : jnlib_free (h->lockname);
784 : jnlib_free (h);
785 : return NULL;
786 : }
787 : return h;
788 : }
789 : #endif /*HAVE_DOSISH_SYSTEM*/
790 :
791 :
792 : /* Create a lockfile for a file name FILE_TO_LOCK and returns an
793 : object of type dotlock_t which may be used later to actually acquire
794 : the lock. A cleanup routine gets installed to cleanup left over
795 : locks or other files used internally by the lock mechanism.
796 :
797 : Calling this function with NULL does only install the atexit
798 : handler and may thus be used to assure that the cleanup is called
799 : after all other atexit handlers.
800 :
801 : This function creates a lock file in the same directory as
802 : FILE_TO_LOCK using that name and a suffix of ".lock". Note that on
803 : POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
804 : used.
805 :
806 : FLAGS must be 0.
807 :
808 : The function returns an new handle which needs to be released using
809 : destroy_dotlock but gets also released at the termination of the
810 : process. On error NULL is returned.
811 : */
812 :
813 : dotlock_t
814 32 : dotlock_create (const char *file_to_lock, unsigned int flags)
815 : {
816 : static int initialized;
817 : dotlock_t h;
818 :
819 32 : if ( !initialized )
820 : {
821 6 : atexit (dotlock_remove_lockfiles);
822 6 : initialized = 1;
823 : }
824 :
825 32 : if ( !file_to_lock )
826 0 : return NULL; /* Only initialization was requested. */
827 :
828 32 : if (flags)
829 : {
830 0 : jnlib_set_errno (EINVAL);
831 0 : return NULL;
832 : }
833 :
834 32 : h = jnlib_calloc (1, sizeof *h);
835 32 : if (!h)
836 0 : return NULL;
837 32 : h->extra_fd = -1;
838 :
839 32 : if (never_lock)
840 : {
841 0 : h->disable = 1;
842 0 : LOCK_all_lockfiles ();
843 0 : h->next = all_lockfiles;
844 0 : all_lockfiles = h;
845 0 : UNLOCK_all_lockfiles ();
846 0 : return h;
847 : }
848 :
849 : #ifdef HAVE_DOSISH_SYSTEM
850 : return dotlock_create_w32 (h, file_to_lock);
851 : #else /*!HAVE_DOSISH_SYSTEM */
852 32 : return dotlock_create_unix (h, file_to_lock);
853 : #endif /*!HAVE_DOSISH_SYSTEM*/
854 : }
855 :
856 :
857 :
858 : /* Convenience function to store a file descriptor (or any any other
859 : integer value) in the context of handle H. */
860 : void
861 32 : dotlock_set_fd (dotlock_t h, int fd)
862 : {
863 32 : h->extra_fd = fd;
864 32 : }
865 :
866 : /* Convenience function to retrieve a file descriptor (or any any other
867 : integer value) stored in the context of handle H. */
868 : int
869 42 : dotlock_get_fd (dotlock_t h)
870 : {
871 42 : return h->extra_fd;
872 : }
873 :
874 :
875 :
876 : #ifdef HAVE_POSIX_SYSTEM
877 : /* Unix specific code of destroy_dotlock. */
878 : static void
879 32 : dotlock_destroy_unix (dotlock_t h)
880 : {
881 32 : if (h->locked && h->lockname)
882 0 : unlink (h->lockname);
883 32 : if (h->tname && !h->use_o_excl)
884 32 : unlink (h->tname);
885 32 : jnlib_free (h->tname);
886 32 : }
887 : #endif /*HAVE_POSIX_SYSTEM*/
888 :
889 :
890 : #ifdef HAVE_DOSISH_SYSTEM
891 : /* Windows specific code of destroy_dotlock. */
892 : static void
893 : dotlock_destroy_w32 (dotlock_t h)
894 : {
895 : if (h->locked)
896 : {
897 : OVERLAPPED ovl;
898 :
899 : memset (&ovl, 0, sizeof ovl);
900 : UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
901 : }
902 : CloseHandle (h->lockhd);
903 : }
904 : #endif /*HAVE_DOSISH_SYSTEM*/
905 :
906 :
907 : /* Destroy the locck handle H and release the lock. */
908 : void
909 32 : dotlock_destroy (dotlock_t h)
910 : {
911 : dotlock_t hprev, htmp;
912 :
913 32 : if ( !h )
914 0 : return;
915 :
916 : /* First remove the handle from our global list of all locks. */
917 32 : LOCK_all_lockfiles ();
918 32 : for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
919 32 : if (htmp == h)
920 : {
921 32 : if (hprev)
922 0 : hprev->next = htmp->next;
923 : else
924 32 : all_lockfiles = htmp->next;
925 32 : h->next = NULL;
926 32 : break;
927 : }
928 32 : UNLOCK_all_lockfiles ();
929 :
930 : /* Then destroy the lock. */
931 32 : if (!h->disable)
932 : {
933 : #ifdef HAVE_DOSISH_SYSTEM
934 : dotlock_destroy_w32 (h);
935 : #else /* !HAVE_DOSISH_SYSTEM */
936 32 : dotlock_destroy_unix (h);
937 : #endif /* HAVE_DOSISH_SYSTEM */
938 32 : jnlib_free (h->lockname);
939 : }
940 32 : jnlib_free(h);
941 : }
942 :
943 :
944 :
945 : #ifdef HAVE_POSIX_SYSTEM
946 : /* Unix specific code of make_dotlock. Returns 0 on success and -1 on
947 : error. */
948 : static int
949 32 : dotlock_take_unix (dotlock_t h, long timeout)
950 : {
951 32 : int wtime = 0;
952 32 : int sumtime = 0;
953 : int pid;
954 32 : int lastpid = -1;
955 : int ownerchanged;
956 32 : const char *maybe_dead="";
957 : int same_node;
958 :
959 0 : again:
960 32 : if (h->use_o_excl)
961 : {
962 : /* No hardlink support - use open(O_EXCL). */
963 : int fd;
964 :
965 : do
966 : {
967 0 : jnlib_set_errno (0);
968 0 : fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
969 : S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
970 : }
971 0 : while (fd == -1 && errno == EINTR);
972 :
973 0 : if (fd == -1 && errno == EEXIST)
974 : ; /* Lock held by another process. */
975 0 : else if (fd == -1)
976 : {
977 0 : my_error_2 ("lock not made: open(O_EXCL) of `%s' failed: %s\n",
978 : h->lockname, strerror (errno));
979 0 : return -1;
980 : }
981 : else
982 : {
983 : char pidstr[16];
984 :
985 0 : snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
986 0 : if (write (fd, pidstr, 11 ) == 11
987 0 : && write (fd, h->tname + h->nodename_off,h->nodename_len)
988 0 : == h->nodename_len
989 0 : && write (fd, "\n", 1) == 1
990 0 : && !close (fd))
991 : {
992 0 : h->locked = 1;
993 0 : return 0;
994 : }
995 : /* Write error. */
996 0 : my_error_2 ("lock not made: writing to `%s' failed: %s\n",
997 : h->lockname, strerror (errno));
998 0 : close (fd);
999 0 : unlink (h->lockname);
1000 0 : return -1;
1001 : }
1002 : }
1003 : else /* Standard method: Use hardlinks. */
1004 : {
1005 : struct stat sb;
1006 :
1007 32 : link (h->tname, h->lockname);
1008 :
1009 32 : if (stat (h->tname, &sb))
1010 : {
1011 0 : my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
1012 : strerror (errno));
1013 : /* In theory this might be a severe error: It is possible
1014 : that link succeeded but stat failed due to changed
1015 : permissions. We can't do anything about it, though. */
1016 32 : return -1;
1017 : }
1018 :
1019 32 : if (sb.st_nlink == 2)
1020 : {
1021 32 : h->locked = 1;
1022 32 : return 0; /* Okay. */
1023 : }
1024 : }
1025 :
1026 : /* Check for stale lock files. */
1027 0 : if ( (pid = read_lockfile (h, &same_node)) == -1 )
1028 : {
1029 0 : if ( errno != ENOENT )
1030 : {
1031 0 : my_info_0 ("cannot read lockfile\n");
1032 0 : return -1;
1033 : }
1034 0 : my_info_0 ("lockfile disappeared\n");
1035 0 : goto again;
1036 : }
1037 0 : else if ( pid == getpid() && same_node )
1038 : {
1039 0 : my_info_0 ("Oops: lock already held by us\n");
1040 0 : h->locked = 1;
1041 0 : return 0; /* okay */
1042 : }
1043 0 : else if ( same_node && kill (pid, 0) && errno == ESRCH )
1044 : {
1045 : /* Note: It is unlikley that we get a race here unless a pid is
1046 : reused too fast or a new process with the same pid as the one
1047 : of the stale file tries to lock right at the same time as we. */
1048 0 : my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
1049 0 : unlink (h->lockname);
1050 0 : goto again;
1051 : }
1052 :
1053 0 : if (lastpid == -1)
1054 0 : lastpid = pid;
1055 0 : ownerchanged = (pid != lastpid);
1056 :
1057 0 : if (timeout)
1058 : {
1059 : struct timeval tv;
1060 :
1061 : /* Wait until lock has been released. We use increasing retry
1062 : intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
1063 : but reset it if the lock owner meanwhile changed. */
1064 0 : if (!wtime || ownerchanged)
1065 0 : wtime = 50;
1066 0 : else if (wtime < 800)
1067 0 : wtime *= 2;
1068 0 : else if (wtime == 800)
1069 0 : wtime = 2000;
1070 0 : else if (wtime < 8000)
1071 0 : wtime *= 2;
1072 :
1073 0 : if (timeout > 0)
1074 : {
1075 0 : if (wtime > timeout)
1076 0 : wtime = timeout;
1077 0 : timeout -= wtime;
1078 : }
1079 :
1080 0 : sumtime += wtime;
1081 0 : if (sumtime >= 1500)
1082 : {
1083 0 : sumtime = 0;
1084 0 : my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
1085 : pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
1086 : }
1087 :
1088 :
1089 0 : tv.tv_sec = wtime / 1000;
1090 0 : tv.tv_usec = (wtime % 1000) * 1000;
1091 0 : select (0, NULL, NULL, NULL, &tv);
1092 0 : goto again;
1093 : }
1094 :
1095 0 : jnlib_set_errno (EACCES);
1096 0 : return -1;
1097 : }
1098 : #endif /*HAVE_POSIX_SYSTEM*/
1099 :
1100 :
1101 : #ifdef HAVE_DOSISH_SYSTEM
1102 : /* Windows specific code of make_dotlock. Returns 0 on success and -1 on
1103 : error. */
1104 : static int
1105 : dotlock_take_w32 (dotlock_t h, long timeout)
1106 : {
1107 : int wtime = 0;
1108 : int w32err;
1109 : OVERLAPPED ovl;
1110 :
1111 : again:
1112 : /* Lock one byte at offset 0. The offset is given by OVL. */
1113 : memset (&ovl, 0, sizeof ovl);
1114 : if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
1115 : | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
1116 : {
1117 : h->locked = 1;
1118 : return 0; /* okay */
1119 : }
1120 :
1121 : w32err = GetLastError ();
1122 : if (w32err != ERROR_LOCK_VIOLATION)
1123 : {
1124 : my_error_2 (_("lock `%s' not made: %s\n"),
1125 : h->lockname, w32_strerror (w32err));
1126 : return -1;
1127 : }
1128 :
1129 : if (timeout)
1130 : {
1131 : /* Wait until lock has been released. We use retry intervals of
1132 : 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s. */
1133 : if (!wtime)
1134 : wtime = 50;
1135 : else if (wtime < 800)
1136 : wtime *= 2;
1137 : else if (wtime == 800)
1138 : wtime = 2000;
1139 : else if (wtime < 8000)
1140 : wtime *= 2;
1141 :
1142 : if (timeout > 0)
1143 : {
1144 : if (wtime > timeout)
1145 : wtime = timeout;
1146 : timeout -= wtime;
1147 : }
1148 :
1149 : if (wtime >= 800)
1150 : my_info_1 (_("waiting for lock %s...\n"), h->lockname);
1151 :
1152 : Sleep (wtime);
1153 : goto again;
1154 : }
1155 :
1156 : return -1;
1157 : }
1158 : #endif /*HAVE_DOSISH_SYSTEM*/
1159 :
1160 :
1161 : /* Take a lock on H. A value of 0 for TIMEOUT returns immediately if
1162 : the lock can't be taked, -1 waits forever (hopefully not), other
1163 : values wait for TIMEOUT milliseconds. Returns: 0 on success */
1164 : int
1165 32 : dotlock_take (dotlock_t h, long timeout)
1166 : {
1167 : int ret;
1168 :
1169 32 : if ( h->disable )
1170 0 : return 0; /* Locks are completely disabled. Return success. */
1171 :
1172 32 : if ( h->locked )
1173 : {
1174 0 : my_debug_1 ("Oops, `%s' is already locked\n", h->lockname);
1175 0 : return 0;
1176 : }
1177 :
1178 : #ifdef HAVE_DOSISH_SYSTEM
1179 : ret = dotlock_take_w32 (h, timeout);
1180 : #else /*!HAVE_DOSISH_SYSTEM*/
1181 32 : ret = dotlock_take_unix (h, timeout);
1182 : #endif /*!HAVE_DOSISH_SYSTEM*/
1183 :
1184 32 : return ret;
1185 : }
1186 :
1187 :
1188 :
1189 : #ifdef HAVE_POSIX_SYSTEM
1190 : /* Unix specific code of release_dotlock. */
1191 : static int
1192 32 : dotlock_release_unix (dotlock_t h)
1193 : {
1194 : int pid, same_node;
1195 :
1196 32 : pid = read_lockfile (h, &same_node);
1197 32 : if ( pid == -1 )
1198 : {
1199 0 : my_error_0 ("release_dotlock: lockfile error\n");
1200 0 : return -1;
1201 : }
1202 32 : if ( pid != getpid() || !same_node )
1203 : {
1204 0 : my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
1205 0 : return -1;
1206 : }
1207 :
1208 32 : if ( unlink( h->lockname ) )
1209 : {
1210 0 : my_error_1 ("release_dotlock: error removing lockfile `%s'\n",
1211 : h->lockname);
1212 0 : return -1;
1213 : }
1214 : /* Fixme: As an extra check we could check whether the link count is
1215 : now really at 1. */
1216 32 : return 0;
1217 : }
1218 : #endif /*HAVE_POSIX_SYSTEM */
1219 :
1220 :
1221 : #ifdef HAVE_DOSISH_SYSTEM
1222 : /* Windows specific code of release_dotlock. */
1223 : static int
1224 : dotlock_release_w32 (dotlock_t h)
1225 : {
1226 : OVERLAPPED ovl;
1227 :
1228 : memset (&ovl, 0, sizeof ovl);
1229 : if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
1230 : {
1231 : my_error_2 ("release_dotlock: error removing lockfile `%s': %s\n",
1232 : h->lockname, w32_strerror (-1));
1233 : return -1;
1234 : }
1235 :
1236 : return 0;
1237 : }
1238 : #endif /*HAVE_DOSISH_SYSTEM */
1239 :
1240 :
1241 : /* Release a lock. Returns 0 on success. */
1242 : int
1243 32 : dotlock_release (dotlock_t h)
1244 : {
1245 : int ret;
1246 :
1247 : /* To avoid atexit race conditions we first check whether there are
1248 : any locks left. It might happen that another atexit handler
1249 : tries to release the lock while the atexit handler of this module
1250 : already ran and thus H is undefined. */
1251 32 : LOCK_all_lockfiles ();
1252 32 : ret = !all_lockfiles;
1253 32 : UNLOCK_all_lockfiles ();
1254 32 : if (ret)
1255 0 : return 0;
1256 :
1257 32 : if ( h->disable )
1258 0 : return 0;
1259 :
1260 32 : if ( !h->locked )
1261 : {
1262 0 : my_debug_1 ("Oops, `%s' is not locked\n", h->lockname);
1263 0 : return 0;
1264 : }
1265 :
1266 : #ifdef HAVE_DOSISH_SYSTEM
1267 : ret = dotlock_release_w32 (h);
1268 : #else
1269 32 : ret = dotlock_release_unix (h);
1270 : #endif
1271 :
1272 32 : if (!ret)
1273 32 : h->locked = 0;
1274 32 : return ret;
1275 : }
1276 :
1277 :
1278 :
1279 : /* Remove all lockfiles. This is called by the atexit handler
1280 : installed by this module but may also be called by other
1281 : termination handlers. */
1282 : void
1283 6 : dotlock_remove_lockfiles (void)
1284 : {
1285 : dotlock_t h, h2;
1286 :
1287 : /* First set the lockfiles list to NULL so that for example
1288 : dotlock_release is ware that this fucntion is currently
1289 : running. */
1290 6 : LOCK_all_lockfiles ();
1291 6 : h = all_lockfiles;
1292 6 : all_lockfiles = NULL;
1293 6 : UNLOCK_all_lockfiles ();
1294 :
1295 6 : while ( h )
1296 : {
1297 0 : h2 = h->next;
1298 0 : dotlock_destroy (h);
1299 0 : h = h2;
1300 : }
1301 6 : }
|