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 GnuPG.
6 : *
7 : * GnuPG 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 : * GnuPG 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 "util.h"
314 : # include "common-defs.h"
315 : # include "stringhelp.h" /* For stpcpy and w32_strerror. */
316 : #endif
317 : #ifdef HAVE_W32CE_SYSTEM
318 : # include "utf8conv.h" /* WindowsCE requires filename conversion. */
319 : #endif
320 :
321 : #include "dotlock.h"
322 :
323 :
324 : /* Define constants for file name construction. */
325 : #if !defined(DIRSEP_C) && !defined(EXTSEP_S)
326 : # ifdef HAVE_DOSISH_SYSTEM
327 : # define DIRSEP_C '\\'
328 : # define EXTSEP_S "."
329 : #else
330 : # define DIRSEP_C '/'
331 : # define EXTSEP_S "."
332 : # endif
333 : #endif
334 :
335 : /* In GnuPG we use wrappers around the malloc fucntions. If they are
336 : not defined we assume that this code is used outside of GnuPG and
337 : fall back to the regular malloc functions. */
338 : #ifndef xtrymalloc
339 : # define xtrymalloc(a) malloc ((a))
340 : # define xtrycalloc(a,b) calloc ((a), (b))
341 : # define xfree(a) free ((a))
342 : #endif
343 :
344 : /* Wrapper to set ERRNO (required for W32CE). */
345 : #ifdef GPG_ERROR_VERSION
346 : # define my_set_errno(e) gpg_err_set_errno ((e))
347 : #else
348 : # define my_set_errno(e) do { errno = (e); } while (0)
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 : 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 : 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 12 : 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 12 : int pid = -1;
482 : char *buffer, *p;
483 : size_t expected_len;
484 : int res, nread;
485 :
486 12 : *same_node = 0;
487 12 : expected_len = 10 + 1 + h->nodename_len + 1;
488 12 : if ( expected_len >= sizeof buffer_space)
489 : {
490 0 : buffer = xtrymalloc (expected_len);
491 0 : if (!buffer)
492 0 : return -1;
493 : }
494 : else
495 12 : buffer = buffer_space;
496 :
497 12 : 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 : xfree (buffer);
504 0 : my_set_errno (e); /* Need to return ERRNO here. */
505 0 : return -1;
506 : }
507 :
508 12 : p = buffer;
509 12 : nread = 0;
510 : do
511 : {
512 12 : res = read (fd, p, expected_len - nread);
513 12 : if (res == -1 && errno == EINTR)
514 0 : continue;
515 12 : 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 : xfree (buffer);
521 0 : my_set_errno (0); /* Do not return an inappropriate ERRNO. */
522 0 : return -1;
523 : }
524 12 : p += res;
525 12 : nread += res;
526 : }
527 12 : while (res && nread != expected_len);
528 12 : close(fd);
529 :
530 12 : 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 : xfree (buffer);
535 0 : my_set_errno (0); /* Better don't return an inappropriate ERRNO. */
536 0 : return -1;
537 : }
538 :
539 12 : if (buffer[10] != '\n'
540 12 : || (buffer[10] = 0, pid = atoi (buffer)) == -1
541 12 : || !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 : xfree (buffer);
546 0 : my_set_errno (0);
547 0 : return -1;
548 : }
549 :
550 12 : if (nread == expected_len
551 12 : && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
552 12 : && buffer[11+h->nodename_len] == '\n')
553 12 : *same_node = 1;
554 :
555 12 : if (buffer != buffer_space)
556 0 : xfree (buffer);
557 12 : 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 9 : use_hardlinks_p (const char *tname)
570 : {
571 : char *lname;
572 : struct stat sb;
573 : unsigned int nlink;
574 : int res;
575 :
576 9 : if (stat (tname, &sb))
577 0 : return -1;
578 9 : nlink = (unsigned int)sb.st_nlink;
579 :
580 9 : lname = xtrymalloc (strlen (tname) + 1 + 1);
581 9 : if (!lname)
582 0 : return -1;
583 9 : strcpy (lname, tname);
584 9 : strcat (lname, "x");
585 :
586 : /* We ignore the return value of link() because it is unreliable. */
587 9 : (void) link (tname, lname);
588 :
589 9 : if (stat (tname, &sb))
590 0 : res = -1; /* Ooops. */
591 9 : else if (sb.st_nlink == nlink + 1)
592 9 : res = 0; /* Yeah, hardlinks are supported. */
593 : else
594 0 : res = 1; /* No hardlink support. */
595 :
596 9 : unlink (lname);
597 9 : xfree (lname);
598 9 : return res;
599 : }
600 : #endif /*HAVE_POSIX_SYSTEM */
601 :
602 :
603 :
604 : #ifdef HAVE_POSIX_SYSTEM
605 : /* Locking core for Unix. It used a temporary file and the link
606 : system call to make locking an atomic operation. */
607 : static dotlock_t
608 9 : dotlock_create_unix (dotlock_t h, const char *file_to_lock)
609 : {
610 9 : int fd = -1;
611 : char pidstr[16];
612 : const char *nodename;
613 : const char *dirpart;
614 : int dirpartlen;
615 : struct utsname utsbuf;
616 : size_t tnamelen;
617 :
618 9 : snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
619 :
620 : /* Create a temporary file. */
621 9 : if ( uname ( &utsbuf ) )
622 0 : nodename = "unknown";
623 : else
624 9 : nodename = utsbuf.nodename;
625 :
626 9 : if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
627 : {
628 0 : dirpart = EXTSEP_S;
629 0 : dirpartlen = 1;
630 : }
631 : else
632 : {
633 9 : dirpartlen = dirpart - file_to_lock;
634 9 : dirpart = file_to_lock;
635 : }
636 :
637 : LOCK_all_lockfiles ();
638 9 : h->next = all_lockfiles;
639 9 : all_lockfiles = h;
640 :
641 9 : tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
642 9 : h->tname = xtrymalloc (tnamelen + 1);
643 9 : if (!h->tname)
644 : {
645 0 : all_lockfiles = h->next;
646 : UNLOCK_all_lockfiles ();
647 0 : xfree (h);
648 0 : return NULL;
649 : }
650 9 : h->nodename_len = strlen (nodename);
651 :
652 9 : snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
653 9 : h->nodename_off = strlen (h->tname);
654 9 : snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
655 : "%s.%d", nodename, (int)getpid ());
656 :
657 : do
658 : {
659 9 : my_set_errno (0);
660 9 : fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
661 : S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
662 : }
663 9 : while (fd == -1 && errno == EINTR);
664 :
665 9 : if ( fd == -1 )
666 : {
667 0 : all_lockfiles = h->next;
668 : UNLOCK_all_lockfiles ();
669 0 : my_error_2 (_("failed to create temporary file '%s': %s\n"),
670 : h->tname, strerror(errno));
671 0 : xfree (h->tname);
672 0 : xfree (h);
673 0 : return NULL;
674 : }
675 9 : if ( write (fd, pidstr, 11 ) != 11 )
676 0 : goto write_failed;
677 9 : if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
678 0 : goto write_failed;
679 9 : if ( write (fd, "\n", 1 ) != 1 )
680 0 : goto write_failed;
681 9 : if ( close (fd) )
682 : {
683 0 : if ( errno == EINTR )
684 0 : fd = -1;
685 0 : goto write_failed;
686 : }
687 9 : fd = -1;
688 :
689 : /* Check whether we support hard links. */
690 9 : switch (use_hardlinks_p (h->tname))
691 : {
692 : case 0: /* Yes. */
693 9 : break;
694 : case 1: /* No. */
695 0 : unlink (h->tname);
696 0 : h->use_o_excl = 1;
697 0 : break;
698 : default:
699 0 : my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n",
700 : h->tname, strerror(errno));
701 0 : goto write_failed;
702 : }
703 :
704 9 : h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
705 9 : if (!h->lockname)
706 : {
707 0 : all_lockfiles = h->next;
708 : UNLOCK_all_lockfiles ();
709 0 : unlink (h->tname);
710 0 : xfree (h->tname);
711 0 : xfree (h);
712 0 : return NULL;
713 : }
714 9 : strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
715 : UNLOCK_all_lockfiles ();
716 9 : if (h->use_o_excl)
717 0 : my_debug_1 ("locking for '%s' done via O_EXCL\n", h->lockname);
718 :
719 9 : return h;
720 :
721 : write_failed:
722 0 : all_lockfiles = h->next;
723 : UNLOCK_all_lockfiles ();
724 0 : my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
725 0 : if ( fd != -1 )
726 0 : close (fd);
727 0 : unlink (h->tname);
728 0 : xfree (h->tname);
729 0 : xfree (h);
730 0 : return NULL;
731 : }
732 : #endif /*HAVE_POSIX_SYSTEM*/
733 :
734 :
735 : #ifdef HAVE_DOSISH_SYSTEM
736 : /* Locking core for Windows. This version does not need a temporary
737 : file but uses the plain lock file along with record locking. We
738 : create this file here so that we later only need to do the file
739 : locking. For error reporting it is useful to keep the name of the
740 : file in the handle. */
741 : static dotlock_t
742 : dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
743 : {
744 : LOCK_all_lockfiles ();
745 : h->next = all_lockfiles;
746 : all_lockfiles = h;
747 :
748 : h->lockname = xtrymalloc ( strlen (file_to_lock) + 6 );
749 : if (!h->lockname)
750 : {
751 : all_lockfiles = h->next;
752 : UNLOCK_all_lockfiles ();
753 : xfree (h);
754 : return NULL;
755 : }
756 : strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
757 :
758 : /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
759 : along with FILE_SHARE_DELETE but that does not work due to a race
760 : condition: Despite the OPEN_ALWAYS flag CreateFile may return an
761 : error and we can't reliable create/open the lock file unless we
762 : would wait here until it works - however there are other valid
763 : reasons why a lock file can't be created and thus the process
764 : would not stop as expected but spin until Windows crashes. Our
765 : solution is to keep the lock file open; that does not harm. */
766 : {
767 : #ifdef HAVE_W32CE_SYSTEM
768 : wchar_t *wname = utf8_to_wchar (h->lockname);
769 :
770 : if (wname)
771 : h->lockhd = CreateFile (wname,
772 : GENERIC_READ|GENERIC_WRITE,
773 : FILE_SHARE_READ|FILE_SHARE_WRITE,
774 : NULL, OPEN_ALWAYS, 0, NULL);
775 : else
776 : h->lockhd = INVALID_HANDLE_VALUE;
777 : xfree (wname);
778 : #else
779 : h->lockhd = CreateFile (h->lockname,
780 : GENERIC_READ|GENERIC_WRITE,
781 : FILE_SHARE_READ|FILE_SHARE_WRITE,
782 : NULL, OPEN_ALWAYS, 0, NULL);
783 : #endif
784 : }
785 : if (h->lockhd == INVALID_HANDLE_VALUE)
786 : {
787 : all_lockfiles = h->next;
788 : UNLOCK_all_lockfiles ();
789 : my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
790 : xfree (h->lockname);
791 : xfree (h);
792 : return NULL;
793 : }
794 : return h;
795 : }
796 : #endif /*HAVE_DOSISH_SYSTEM*/
797 :
798 :
799 : /* Create a lockfile for a file name FILE_TO_LOCK and returns an
800 : object of type dotlock_t which may be used later to actually acquire
801 : the lock. A cleanup routine gets installed to cleanup left over
802 : locks or other files used internally by the lock mechanism.
803 :
804 : Calling this function with NULL does only install the atexit
805 : handler and may thus be used to assure that the cleanup is called
806 : after all other atexit handlers.
807 :
808 : This function creates a lock file in the same directory as
809 : FILE_TO_LOCK using that name and a suffix of ".lock". Note that on
810 : POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
811 : used.
812 :
813 : FLAGS must be 0.
814 :
815 : The function returns an new handle which needs to be released using
816 : destroy_dotlock but gets also released at the termination of the
817 : process. On error NULL is returned.
818 : */
819 :
820 : dotlock_t
821 1343 : dotlock_create (const char *file_to_lock, unsigned int flags)
822 : {
823 : static int initialized;
824 : dotlock_t h;
825 :
826 1343 : if ( !initialized )
827 : {
828 1335 : atexit (dotlock_remove_lockfiles);
829 1335 : initialized = 1;
830 : }
831 :
832 1343 : if ( !file_to_lock )
833 1334 : return NULL; /* Only initialization was requested. */
834 :
835 9 : if (flags)
836 : {
837 0 : my_set_errno (EINVAL);
838 0 : return NULL;
839 : }
840 :
841 9 : h = xtrycalloc (1, sizeof *h);
842 9 : if (!h)
843 0 : return NULL;
844 9 : h->extra_fd = -1;
845 :
846 9 : if (never_lock)
847 : {
848 0 : h->disable = 1;
849 : LOCK_all_lockfiles ();
850 0 : h->next = all_lockfiles;
851 0 : all_lockfiles = h;
852 : UNLOCK_all_lockfiles ();
853 0 : return h;
854 : }
855 :
856 : #ifdef HAVE_DOSISH_SYSTEM
857 : return dotlock_create_w32 (h, file_to_lock);
858 : #else /*!HAVE_DOSISH_SYSTEM */
859 9 : return dotlock_create_unix (h, file_to_lock);
860 : #endif /*!HAVE_DOSISH_SYSTEM*/
861 : }
862 :
863 :
864 :
865 : /* Convenience function to store a file descriptor (or any any other
866 : integer value) in the context of handle H. */
867 : void
868 0 : dotlock_set_fd (dotlock_t h, int fd)
869 : {
870 0 : h->extra_fd = fd;
871 0 : }
872 :
873 : /* Convenience function to retrieve a file descriptor (or any any other
874 : integer value) stored in the context of handle H. */
875 : int
876 0 : dotlock_get_fd (dotlock_t h)
877 : {
878 0 : return h->extra_fd;
879 : }
880 :
881 :
882 :
883 : #ifdef HAVE_POSIX_SYSTEM
884 : /* Unix specific code of destroy_dotlock. */
885 : static void
886 9 : dotlock_destroy_unix (dotlock_t h)
887 : {
888 9 : if (h->locked && h->lockname)
889 1 : unlink (h->lockname);
890 9 : if (h->tname && !h->use_o_excl)
891 9 : unlink (h->tname);
892 9 : xfree (h->tname);
893 9 : }
894 : #endif /*HAVE_POSIX_SYSTEM*/
895 :
896 :
897 : #ifdef HAVE_DOSISH_SYSTEM
898 : /* Windows specific code of destroy_dotlock. */
899 : static void
900 : dotlock_destroy_w32 (dotlock_t h)
901 : {
902 : if (h->locked)
903 : {
904 : OVERLAPPED ovl;
905 :
906 : memset (&ovl, 0, sizeof ovl);
907 : UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
908 : }
909 : CloseHandle (h->lockhd);
910 : }
911 : #endif /*HAVE_DOSISH_SYSTEM*/
912 :
913 :
914 : /* Destroy the locck handle H and release the lock. */
915 : void
916 9 : dotlock_destroy (dotlock_t h)
917 : {
918 : dotlock_t hprev, htmp;
919 :
920 9 : if ( !h )
921 9 : return;
922 :
923 : /* First remove the handle from our global list of all locks. */
924 : LOCK_all_lockfiles ();
925 9 : for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
926 3 : if (htmp == h)
927 : {
928 3 : if (hprev)
929 0 : hprev->next = htmp->next;
930 : else
931 3 : all_lockfiles = htmp->next;
932 3 : h->next = NULL;
933 3 : break;
934 : }
935 : UNLOCK_all_lockfiles ();
936 :
937 : /* Then destroy the lock. */
938 9 : if (!h->disable)
939 : {
940 : #ifdef HAVE_DOSISH_SYSTEM
941 : dotlock_destroy_w32 (h);
942 : #else /* !HAVE_DOSISH_SYSTEM */
943 9 : dotlock_destroy_unix (h);
944 : #endif /* HAVE_DOSISH_SYSTEM */
945 9 : xfree (h->lockname);
946 : }
947 9 : xfree(h);
948 : }
949 :
950 :
951 :
952 : #ifdef HAVE_POSIX_SYSTEM
953 : /* Unix specific code of make_dotlock. Returns 0 on success and -1 on
954 : error. */
955 : static int
956 13 : dotlock_take_unix (dotlock_t h, long timeout)
957 : {
958 13 : int wtime = 0;
959 13 : int sumtime = 0;
960 : int pid;
961 13 : int lastpid = -1;
962 : int ownerchanged;
963 13 : const char *maybe_dead="";
964 : int same_node;
965 :
966 : again:
967 13 : if (h->use_o_excl)
968 : {
969 : /* No hardlink support - use open(O_EXCL). */
970 : int fd;
971 :
972 : do
973 : {
974 0 : my_set_errno (0);
975 0 : fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
976 : S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
977 : }
978 0 : while (fd == -1 && errno == EINTR);
979 :
980 0 : if (fd == -1 && errno == EEXIST)
981 : ; /* Lock held by another process. */
982 0 : else if (fd == -1)
983 : {
984 0 : my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
985 : h->lockname, strerror (errno));
986 0 : return -1;
987 : }
988 : else
989 : {
990 : char pidstr[16];
991 :
992 0 : snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
993 0 : if (write (fd, pidstr, 11 ) == 11
994 0 : && write (fd, h->tname + h->nodename_off,h->nodename_len)
995 0 : == h->nodename_len
996 0 : && write (fd, "\n", 1) == 1
997 0 : && !close (fd))
998 : {
999 0 : h->locked = 1;
1000 0 : return 0;
1001 : }
1002 : /* Write error. */
1003 0 : my_error_2 ("lock not made: writing to '%s' failed: %s\n",
1004 : h->lockname, strerror (errno));
1005 0 : close (fd);
1006 0 : unlink (h->lockname);
1007 0 : return -1;
1008 : }
1009 : }
1010 : else /* Standard method: Use hardlinks. */
1011 : {
1012 : struct stat sb;
1013 :
1014 : /* We ignore the return value of link() because it is unreliable. */
1015 13 : (void) link (h->tname, h->lockname);
1016 :
1017 13 : if (stat (h->tname, &sb))
1018 : {
1019 0 : my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
1020 : strerror (errno));
1021 : /* In theory this might be a severe error: It is possible
1022 : that link succeeded but stat failed due to changed
1023 : permissions. We can't do anything about it, though. */
1024 13 : return -1;
1025 : }
1026 :
1027 13 : if (sb.st_nlink == 2)
1028 : {
1029 13 : h->locked = 1;
1030 13 : return 0; /* Okay. */
1031 : }
1032 : }
1033 :
1034 : /* Check for stale lock files. */
1035 0 : if ( (pid = read_lockfile (h, &same_node)) == -1 )
1036 : {
1037 0 : if ( errno != ENOENT )
1038 : {
1039 0 : my_info_0 ("cannot read lockfile\n");
1040 0 : return -1;
1041 : }
1042 0 : my_info_0 ("lockfile disappeared\n");
1043 0 : goto again;
1044 : }
1045 0 : else if ( pid == getpid() && same_node )
1046 : {
1047 0 : my_info_0 ("Oops: lock already held by us\n");
1048 0 : h->locked = 1;
1049 0 : return 0; /* okay */
1050 : }
1051 0 : else if ( same_node && kill (pid, 0) && errno == ESRCH )
1052 : {
1053 : /* Note: It is unlikley that we get a race here unless a pid is
1054 : reused too fast or a new process with the same pid as the one
1055 : of the stale file tries to lock right at the same time as we. */
1056 0 : my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
1057 0 : unlink (h->lockname);
1058 0 : goto again;
1059 : }
1060 :
1061 0 : if (lastpid == -1)
1062 0 : lastpid = pid;
1063 0 : ownerchanged = (pid != lastpid);
1064 :
1065 0 : if (timeout)
1066 : {
1067 : struct timeval tv;
1068 :
1069 : /* Wait until lock has been released. We use increasing retry
1070 : intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
1071 : but reset it if the lock owner meanwhile changed. */
1072 0 : if (!wtime || ownerchanged)
1073 0 : wtime = 50;
1074 0 : else if (wtime < 800)
1075 0 : wtime *= 2;
1076 0 : else if (wtime == 800)
1077 0 : wtime = 2000;
1078 0 : else if (wtime < 8000)
1079 0 : wtime *= 2;
1080 :
1081 0 : if (timeout > 0)
1082 : {
1083 0 : if (wtime > timeout)
1084 0 : wtime = timeout;
1085 0 : timeout -= wtime;
1086 : }
1087 :
1088 0 : sumtime += wtime;
1089 0 : if (sumtime >= 1500)
1090 : {
1091 0 : sumtime = 0;
1092 0 : my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
1093 : pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
1094 : }
1095 :
1096 :
1097 0 : tv.tv_sec = wtime / 1000;
1098 0 : tv.tv_usec = (wtime % 1000) * 1000;
1099 0 : select (0, NULL, NULL, NULL, &tv);
1100 0 : goto again;
1101 : }
1102 :
1103 0 : my_set_errno (EACCES);
1104 0 : return -1;
1105 : }
1106 : #endif /*HAVE_POSIX_SYSTEM*/
1107 :
1108 :
1109 : #ifdef HAVE_DOSISH_SYSTEM
1110 : /* Windows specific code of make_dotlock. Returns 0 on success and -1 on
1111 : error. */
1112 : static int
1113 : dotlock_take_w32 (dotlock_t h, long timeout)
1114 : {
1115 : int wtime = 0;
1116 : int w32err;
1117 : OVERLAPPED ovl;
1118 :
1119 : again:
1120 : /* Lock one byte at offset 0. The offset is given by OVL. */
1121 : memset (&ovl, 0, sizeof ovl);
1122 : if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
1123 : | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
1124 : {
1125 : h->locked = 1;
1126 : return 0; /* okay */
1127 : }
1128 :
1129 : w32err = GetLastError ();
1130 : if (w32err != ERROR_LOCK_VIOLATION)
1131 : {
1132 : my_error_2 (_("lock '%s' not made: %s\n"),
1133 : h->lockname, w32_strerror (w32err));
1134 : return -1;
1135 : }
1136 :
1137 : if (timeout)
1138 : {
1139 : /* Wait until lock has been released. We use retry intervals of
1140 : 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s. */
1141 : if (!wtime)
1142 : wtime = 50;
1143 : else if (wtime < 800)
1144 : wtime *= 2;
1145 : else if (wtime == 800)
1146 : wtime = 2000;
1147 : else if (wtime < 8000)
1148 : wtime *= 2;
1149 :
1150 : if (timeout > 0)
1151 : {
1152 : if (wtime > timeout)
1153 : wtime = timeout;
1154 : timeout -= wtime;
1155 : }
1156 :
1157 : if (wtime >= 800)
1158 : my_info_1 (_("waiting for lock %s...\n"), h->lockname);
1159 :
1160 : Sleep (wtime);
1161 : goto again;
1162 : }
1163 :
1164 : return -1;
1165 : }
1166 : #endif /*HAVE_DOSISH_SYSTEM*/
1167 :
1168 :
1169 : /* Take a lock on H. A value of 0 for TIMEOUT returns immediately if
1170 : the lock can't be taked, -1 waits forever (hopefully not), other
1171 : values wait for TIMEOUT milliseconds. Returns: 0 on success */
1172 : int
1173 13 : dotlock_take (dotlock_t h, long timeout)
1174 : {
1175 : int ret;
1176 :
1177 13 : if ( h->disable )
1178 0 : return 0; /* Locks are completely disabled. Return success. */
1179 :
1180 13 : if ( h->locked )
1181 : {
1182 0 : my_debug_1 ("Oops, '%s' is already locked\n", h->lockname);
1183 0 : return 0;
1184 : }
1185 :
1186 : #ifdef HAVE_DOSISH_SYSTEM
1187 : ret = dotlock_take_w32 (h, timeout);
1188 : #else /*!HAVE_DOSISH_SYSTEM*/
1189 13 : ret = dotlock_take_unix (h, timeout);
1190 : #endif /*!HAVE_DOSISH_SYSTEM*/
1191 :
1192 13 : return ret;
1193 : }
1194 :
1195 :
1196 :
1197 : #ifdef HAVE_POSIX_SYSTEM
1198 : /* Unix specific code of release_dotlock. */
1199 : static int
1200 12 : dotlock_release_unix (dotlock_t h)
1201 : {
1202 : int pid, same_node;
1203 :
1204 12 : pid = read_lockfile (h, &same_node);
1205 12 : if ( pid == -1 )
1206 : {
1207 0 : my_error_0 ("release_dotlock: lockfile error\n");
1208 0 : return -1;
1209 : }
1210 12 : if ( pid != getpid() || !same_node )
1211 : {
1212 0 : my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
1213 0 : return -1;
1214 : }
1215 :
1216 12 : if ( unlink( h->lockname ) )
1217 : {
1218 0 : my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
1219 : h->lockname);
1220 0 : return -1;
1221 : }
1222 : /* Fixme: As an extra check we could check whether the link count is
1223 : now really at 1. */
1224 12 : return 0;
1225 : }
1226 : #endif /*HAVE_POSIX_SYSTEM */
1227 :
1228 :
1229 : #ifdef HAVE_DOSISH_SYSTEM
1230 : /* Windows specific code of release_dotlock. */
1231 : static int
1232 : dotlock_release_w32 (dotlock_t h)
1233 : {
1234 : OVERLAPPED ovl;
1235 :
1236 : memset (&ovl, 0, sizeof ovl);
1237 : if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
1238 : {
1239 : my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
1240 : h->lockname, w32_strerror (-1));
1241 : return -1;
1242 : }
1243 :
1244 : return 0;
1245 : }
1246 : #endif /*HAVE_DOSISH_SYSTEM */
1247 :
1248 :
1249 : /* Release a lock. Returns 0 on success. */
1250 : int
1251 12 : dotlock_release (dotlock_t h)
1252 : {
1253 : int ret;
1254 :
1255 : /* To avoid atexit race conditions we first check whether there are
1256 : any locks left. It might happen that another atexit handler
1257 : tries to release the lock while the atexit handler of this module
1258 : already ran and thus H is undefined. */
1259 : LOCK_all_lockfiles ();
1260 12 : ret = !all_lockfiles;
1261 : UNLOCK_all_lockfiles ();
1262 12 : if (ret)
1263 0 : return 0;
1264 :
1265 12 : if ( h->disable )
1266 0 : return 0;
1267 :
1268 12 : if ( !h->locked )
1269 : {
1270 0 : my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
1271 0 : return 0;
1272 : }
1273 :
1274 : #ifdef HAVE_DOSISH_SYSTEM
1275 : ret = dotlock_release_w32 (h);
1276 : #else
1277 12 : ret = dotlock_release_unix (h);
1278 : #endif
1279 :
1280 12 : if (!ret)
1281 12 : h->locked = 0;
1282 12 : return ret;
1283 : }
1284 :
1285 :
1286 :
1287 : /* Remove all lockfiles. This is called by the atexit handler
1288 : installed by this module but may also be called by other
1289 : termination handlers. */
1290 : void
1291 1335 : dotlock_remove_lockfiles (void)
1292 : {
1293 : dotlock_t h, h2;
1294 :
1295 : /* First set the lockfiles list to NULL so that for example
1296 : dotlock_release is ware that this fucntion is currently
1297 : running. */
1298 : LOCK_all_lockfiles ();
1299 1335 : h = all_lockfiles;
1300 1335 : all_lockfiles = NULL;
1301 : UNLOCK_all_lockfiles ();
1302 :
1303 2676 : while ( h )
1304 : {
1305 6 : h2 = h->next;
1306 6 : dotlock_destroy (h);
1307 6 : h = h2;
1308 : }
1309 1335 : }
|