Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / dot_lockfile.c
blobaec7a245365bcec25b2aba8841d9af9aa3358353
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* dot_lockfile 3
6 /* SUMMARY
7 /* dotlock file management
8 /* SYNOPSIS
9 /* #include <dot_lockfile.h>
11 /* int dot_lockfile(path, why)
12 /* const char *path;
13 /* VSTRING *why;
15 /* void dot_unlockfile(path)
16 /* const char *path;
17 /* DESCRIPTION
18 /* dot_lockfile() constructs a lock file name by appending ".lock" to
19 /* \fIpath\fR and creates the named file exclusively. It tries several
20 /* times and attempts to break stale locks. A negative result value
21 /* means no lock file could be created.
23 /* dot_unlockfile() attempts to remove the lock file created by
24 /* dot_lockfile(). The operation always succeeds, and therefore
25 /* it preserves the errno value.
27 /* Arguments:
28 /* .IP path
29 /* Name of the file to be locked or unlocked.
30 /* .IP why
31 /* A null pointer, or storage for the reason why a lock file could
32 /* not be created.
33 /* DIAGNOSTICS
34 /* dot_lockfile() returns 0 upon success. In case of failure, the
35 /* result is -1, and the errno variable is set appropriately:
36 /* EEXIST when a "fresh" lock file already exists; other values as
37 /* appropriate.
38 /* CONFIGURATION PARAMETERS
39 /* deliver_lock_attempts, how many times to try to create a lock
40 /* deliver_lock_delay, how long to wait between attempts
41 /* stale_lock_time, when to break a stale lock
42 /* LICENSE
43 /* .ad
44 /* .fi
45 /* The Secure Mailer license must be distributed with this software.
46 /* AUTHOR(S)
47 /* Wietse Venema
48 /* IBM T.J. Watson Research
49 /* P.O. Box 704
50 /* Yorktown Heights, NY 10598, USA
51 /*--*/
53 /* System library. */
55 #include "sys_defs.h"
56 #include <sys/stat.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <fcntl.h>
60 #include <errno.h>
61 #include <time.h>
63 /* Utility library. */
65 #include <vstring.h>
66 #include <stringops.h>
67 #include <mymalloc.h>
68 #include <iostuff.h>
70 /* Global library. */
72 #include "mail_params.h"
73 #include "dot_lockfile.h"
75 /* Application-specific. */
77 #define MILLION 1000000
79 /* dot_lockfile - create user.lock file */
81 int dot_lockfile(const char *path, VSTRING *why)
83 char *lock_file;
84 int count;
85 struct stat st;
86 int fd;
87 int status = -1;
89 lock_file = concatenate(path, ".lock", (char *) 0);
91 for (count = 1; /* void */ ; count++) {
94 * Attempt to create the lock. This code relies on O_EXCL | O_CREAT
95 * to not follow symlinks. With NFS file systems this operation can
96 * at the same time succeed and fail with errno of EEXIST.
98 if ((fd = open(lock_file, O_WRONLY | O_EXCL | O_CREAT, 0)) >= 0) {
99 close(fd);
100 status = 0;
101 break;
103 if (count >= var_flock_tries)
104 break;
107 * We can deal only with "file exists" errors. Any other error means
108 * we better give up trying.
110 if (errno != EEXIST)
111 break;
114 * Break the lock when it is too old. Give up when we are unable to
115 * remove a stale lock.
117 if (stat(lock_file, &st) == 0)
118 if (time((time_t *) 0) > st.st_ctime + var_flock_stale)
119 if (unlink(lock_file) < 0)
120 if (errno != ENOENT)
121 break;
123 rand_sleep(var_flock_delay * MILLION, var_flock_delay * MILLION / 2);
125 if (status && why)
126 vstring_sprintf(why, "unable to create lock file %s: %m", lock_file);
128 myfree(lock_file);
129 return (status);
132 /* dot_unlockfile - remove .lock file */
134 void dot_unlockfile(const char *path)
136 char *lock_file;
137 int saved_errno = errno;
139 lock_file = concatenate(path, ".lock", (char *) 0);
140 (void) unlink(lock_file);
141 myfree(lock_file);
142 errno = saved_errno;
145 #ifdef TEST
148 * Test program for setting a .lock file.
150 * Usage: dot_lockfile filename
152 * Creates filename.lock and removes it.
154 #include <msg.h>
155 #include <vstream.h>
156 #include <msg_vstream.h>
157 #include <mail_conf.h>
159 int main(int argc, char **argv)
161 VSTRING *why = vstring_alloc(100);
163 msg_vstream_init(argv[0], VSTREAM_ERR);
164 if (argc != 2)
165 msg_fatal("usage: %s file-to-be-locked", argv[0]);
166 mail_conf_read();
167 if (dot_lockfile(argv[1], why) < 0)
168 msg_fatal("%s", vstring_str(why));
169 dot_unlockfile(argv[1]);
170 vstring_free(why);
171 return (0);
174 #endif