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 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 * 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 * 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 * 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 * 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 * 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 * 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 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