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