xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/dot_lockfile.c (revision a30b880ed60a24c405edba78187a04247f4d9d33)
1 /*	$NetBSD: dot_lockfile.c,v 1.1.1.2 2013/01/02 18:58:57 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	dot_lockfile 3
6 /* SUMMARY
7 /*	dotlock file management
8 /* SYNOPSIS
9 /*	#include <dot_lockfile.h>
10 /*
11 /*	int	dot_lockfile(path, why)
12 /*	const char *path;
13 /*	VSTRING	*why;
14 /*
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.
22 /*
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.
26 /*
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 /*--*/
52 
53 /* System library. */
54 
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>
62 
63 /* Utility library. */
64 
65 #include <vstring.h>
66 #include <stringops.h>
67 #include <mymalloc.h>
68 #include <iostuff.h>
69 #include <warn_stat.h>
70 
71 /* Global library. */
72 
73 #include "mail_params.h"
74 #include "dot_lockfile.h"
75 
76 /* Application-specific. */
77 
78 #define MILLION	1000000
79 
80 /* dot_lockfile - create user.lock file */
81 
dot_lockfile(const char * path,VSTRING * why)82 int     dot_lockfile(const char *path, VSTRING *why)
83 {
84     char   *lock_file;
85     int     count;
86     struct stat st;
87     int     fd;
88     int     status = -1;
89 
90     lock_file = concatenate(path, ".lock", (char *) 0);
91 
92     for (count = 1; /* void */ ; count++) {
93 
94 	/*
95 	 * Attempt to create the lock. This code relies on O_EXCL | O_CREAT
96 	 * to not follow symlinks. With NFS file systems this operation can
97 	 * at the same time succeed and fail with errno of EEXIST.
98 	 */
99 	if ((fd = open(lock_file, O_WRONLY | O_EXCL | O_CREAT, 0)) >= 0) {
100 	    close(fd);
101 	    status = 0;
102 	    break;
103 	}
104 	if (count >= var_flock_tries)
105 	    break;
106 
107 	/*
108 	 * We can deal only with "file exists" errors. Any other error means
109 	 * we better give up trying.
110 	 */
111 	if (errno != EEXIST)
112 	    break;
113 
114 	/*
115 	 * Break the lock when it is too old. Give up when we are unable to
116 	 * remove a stale lock.
117 	 */
118 	if (stat(lock_file, &st) == 0)
119 	    if (time((time_t *) 0) > st.st_ctime + var_flock_stale)
120 		if (unlink(lock_file) < 0)
121 		    if (errno != ENOENT)
122 			break;
123 
124 	rand_sleep(var_flock_delay * MILLION, var_flock_delay * MILLION / 2);
125     }
126     if (status && why)
127 	vstring_sprintf(why, "unable to create lock file %s: %m", lock_file);
128 
129     myfree(lock_file);
130     return (status);
131 }
132 
133 /* dot_unlockfile - remove .lock file */
134 
dot_unlockfile(const char * path)135 void    dot_unlockfile(const char *path)
136 {
137     char   *lock_file;
138     int     saved_errno = errno;
139 
140     lock_file = concatenate(path, ".lock", (char *) 0);
141     (void) unlink(lock_file);
142     myfree(lock_file);
143     errno = saved_errno;
144 }
145 
146 #ifdef TEST
147 
148  /*
149   * Test program for setting a .lock file.
150   *
151   * Usage: dot_lockfile filename
152   *
153   * Creates filename.lock and removes it.
154   */
155 #include <msg.h>
156 #include <vstream.h>
157 #include <msg_vstream.h>
158 #include <mail_conf.h>
159 
main(int argc,char ** argv)160 int     main(int argc, char **argv)
161 {
162     VSTRING *why = vstring_alloc(100);
163 
164     msg_vstream_init(argv[0], VSTREAM_ERR);
165     if (argc != 2)
166 	msg_fatal("usage: %s file-to-be-locked", argv[0]);
167     mail_conf_read();
168     if (dot_lockfile(argv[1], why) < 0)
169 	msg_fatal("%s", vstring_str(why));
170     dot_unlockfile(argv[1]);
171     vstring_free(why);
172     return (0);
173 }
174 
175 #endif
176