1 /*-
2 * Copyright (c) 2007-2009 Dag-Erling Smørgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 #include <sys/param.h>
30 #include <sys/wait.h>
31 #include <sys/event.h>
32
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <signal.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include <libutil.h>
43
44 /*
45 * We need a signal handler so kill(2) will interrupt the child
46 * instead of killing it.
47 */
48 static void
signal_handler(int sig)49 signal_handler(int sig)
50 {
51 (void)sig;
52 }
53
54 /*
55 * Test that pidfile_open() can create a pidfile and that pidfile_write()
56 * can write to it.
57 */
58 static const char *
test_pidfile_uncontested(void)59 test_pidfile_uncontested(void)
60 {
61 const char *fn = "test_pidfile_uncontested";
62 struct pidfh *pf;
63 pid_t other = 0;
64
65 unlink(fn);
66 pf = pidfile_open(fn, 0600, &other);
67 if (pf == NULL && other != 0)
68 return ("pidfile exists and is locked");
69 if (pf == NULL)
70 return (strerror(errno));
71 if (pidfile_write(pf) != 0) {
72 pidfile_close(pf);
73 unlink(fn);
74 return ("failed to write PID");
75 }
76 pidfile_close(pf);
77 unlink(fn);
78 return (NULL);
79 }
80
81 /*
82 * Test that pidfile_open() locks against self.
83 */
84 static const char *
test_pidfile_self(void)85 test_pidfile_self(void)
86 {
87 const char *fn = "test_pidfile_self";
88 struct pidfh *pf1, *pf2;
89 pid_t other = 0;
90 int serrno;
91
92 unlink(fn);
93 pf1 = pidfile_open(fn, 0600, &other);
94 if (pf1 == NULL && other != 0)
95 return ("pidfile exists and is locked");
96 if (pf1 == NULL)
97 return (strerror(errno));
98 if (pidfile_write(pf1) != 0) {
99 serrno = errno;
100 pidfile_close(pf1);
101 unlink(fn);
102 return (strerror(serrno));
103 }
104 // second open should fail
105 pf2 = pidfile_open(fn, 0600, &other);
106 if (pf2 != NULL) {
107 pidfile_close(pf1);
108 pidfile_close(pf2);
109 unlink(fn);
110 return ("managed to opened pidfile twice");
111 }
112 if (other != getpid()) {
113 pidfile_close(pf1);
114 unlink(fn);
115 return ("pidfile contained wrong PID");
116 }
117 pidfile_close(pf1);
118 unlink(fn);
119 return (NULL);
120 }
121
122 /*
123 * Common code for test_pidfile_{contested,inherited}.
124 */
125 static const char *
common_test_pidfile_child(const char * fn,int parent_open)126 common_test_pidfile_child(const char *fn, int parent_open)
127 {
128 struct pidfh *pf = NULL;
129 pid_t other = 0, pid = 0;
130 int fd[2], serrno, status;
131 struct kevent event, ke;
132 char ch;
133 int kq;
134
135 unlink(fn);
136 if (pipe(fd) != 0)
137 return (strerror(errno));
138
139 if (parent_open) {
140 pf = pidfile_open(fn, 0600, &other);
141 if (pf == NULL && other != 0)
142 return ("pidfile exists and is locked");
143 if (pf == NULL)
144 return (strerror(errno));
145 }
146
147 pid = fork();
148 if (pid == -1)
149 return (strerror(errno));
150 if (pid == 0) {
151 // child
152 close(fd[0]);
153 signal(SIGINT, signal_handler);
154 if (!parent_open) {
155 pf = pidfile_open(fn, 0600, &other);
156 if (pf == NULL && other != 0)
157 return ("pidfile exists and is locked");
158 if (pf == NULL)
159 return (strerror(errno));
160 }
161 if (pidfile_write(pf) != 0) {
162 serrno = errno;
163 pidfile_close(pf);
164 unlink(fn);
165 return (strerror(serrno));
166 }
167 if (pf == NULL)
168 _exit(1);
169 if (pidfile_write(pf) != 0)
170 _exit(2);
171 kq = kqueue();
172 if (kq == -1)
173 _exit(3);
174 EV_SET(&ke, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
175 /* Attach event to the kqueue. */
176 if (kevent(kq, &ke, 1, NULL, 0, NULL) != 0)
177 _exit(4);
178 /* Inform the parent we are ready to receive SIGINT */
179 if (write(fd[1], "*", 1) != 1)
180 _exit(5);
181 /* Wait for SIGINT received */
182 if (kevent(kq, NULL, 0, &event, 1, NULL) != 1)
183 _exit(6);
184 _exit(0);
185 }
186 // parent
187 close(fd[1]);
188 if (pf)
189 pidfile_close(pf);
190
191 // wait for the child to signal us
192 if (read(fd[0], &ch, 1) != 1) {
193 serrno = errno;
194 unlink(fn);
195 kill(pid, SIGTERM);
196 errno = serrno;
197 return (strerror(errno));
198 }
199
200 // We shouldn't be able to lock the same pidfile as our child
201 pf = pidfile_open(fn, 0600, &other);
202 if (pf != NULL) {
203 pidfile_close(pf);
204 unlink(fn);
205 return ("managed to lock contested pidfile");
206 }
207
208 // Failed to lock, but not because it was contested
209 if (other == 0) {
210 unlink(fn);
211 return (strerror(errno));
212 }
213
214 // Locked by the wrong process
215 if (other != pid) {
216 unlink(fn);
217 return ("pidfile contained wrong PID");
218 }
219
220 // check our child's fate
221 if (pf)
222 pidfile_close(pf);
223 unlink(fn);
224 if (kill(pid, SIGINT) != 0)
225 return (strerror(errno));
226 if (waitpid(pid, &status, 0) == -1)
227 return (strerror(errno));
228 if (WIFSIGNALED(status))
229 return ("child caught signal");
230 if (WEXITSTATUS(status) != 0)
231 return ("child returned non-zero status");
232
233 // success
234 return (NULL);
235 }
236
237 /*
238 * Test that pidfile_open() fails when attempting to open a pidfile that
239 * is already locked, and that it returns the correct PID.
240 */
241 static const char *
test_pidfile_contested(void)242 test_pidfile_contested(void)
243 {
244 const char *fn = "test_pidfile_contested";
245 const char *result;
246
247 result = common_test_pidfile_child(fn, 0);
248 return (result);
249 }
250
251 /*
252 * Test that the pidfile lock is inherited.
253 */
254 static const char *
test_pidfile_inherited(void)255 test_pidfile_inherited(void)
256 {
257 const char *fn = "test_pidfile_inherited";
258 const char *result;
259
260 result = common_test_pidfile_child(fn, 1);
261 return (result);
262 }
263
264 /*
265 * Make sure we handle relative pidfile paths correctly.
266 */
267 static const char *
test_pidfile_relative(void)268 test_pidfile_relative(void)
269 {
270 char path[PATH_MAX], pid[32], tmpdir[PATH_MAX];
271 struct pidfh *pfh;
272 int fd;
273
274 (void)snprintf(tmpdir, sizeof(tmpdir), "%s.XXXXXX", __func__);
275 if (mkdtemp(tmpdir) == NULL)
276 return (strerror(errno));
277 (void)snprintf(path, sizeof(path), "%s/pidfile", tmpdir);
278
279 pfh = pidfile_open(path, 0600, NULL);
280 if (pfh == NULL)
281 return (strerror(errno));
282 if (pidfile_write(pfh) != 0)
283 return (strerror(errno));
284 fd = open(path, O_RDONLY);
285 if (fd < 0)
286 return (strerror(errno));
287 memset(pid, 0, sizeof(pid));
288 if (read(fd, pid, sizeof(pid) - 1) < 0)
289 return (strerror(errno));
290 if (atoi(pid) != getpid())
291 return ("pid mismatch");
292 if (close(fd) != 0)
293 return (strerror(errno));
294 if (pidfile_close(pfh) != 0)
295 return (strerror(errno));
296 return (NULL);
297 }
298
299 static struct test {
300 const char *name;
301 const char *(*func)(void);
302 } t[] = {
303 { "pidfile_uncontested", test_pidfile_uncontested },
304 { "pidfile_self", test_pidfile_self },
305 { "pidfile_contested", test_pidfile_contested },
306 { "pidfile_inherited", test_pidfile_inherited },
307 { "pidfile_relative", test_pidfile_relative },
308 };
309
310 int
main(void)311 main(void)
312 {
313 const char *result;
314 int i, nt;
315
316 nt = sizeof(t) / sizeof(*t);
317 printf("1..%d\n", nt);
318 for (i = 0; i < nt; ++i) {
319 if ((result = t[i].func()) != NULL)
320 printf("not ok %d - %s # %s\n", i + 1,
321 t[i].name, result);
322 else
323 printf("ok %d - %s\n", i + 1,
324 t[i].name);
325 }
326 exit(0);
327 }
328