1 /*- 2 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 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 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * Derived from FreeBSD head/lib/libutil/pidfile.c r231938 27 * $P4: //depot/projects/trustedbsd/openbsm/compat/pidfile.h#1 $ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/file.h> 32 #include <sys/stat.h> 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <fcntl.h> 38 #include <string.h> 39 #include <time.h> 40 #include <err.h> 41 #include <errno.h> 42 43 #include "flopen.h" 44 45 struct pidfh { 46 int pf_fd; 47 char pf_path[MAXPATHLEN + 1]; 48 dev_t pf_dev; 49 ino_t pf_ino; 50 }; 51 52 static int _pidfile_remove(struct pidfh *pfh, int freeit); 53 54 static int 55 pidfile_verify(const struct pidfh *pfh) 56 { 57 struct stat sb; 58 59 if (pfh == NULL || pfh->pf_fd == -1) 60 return (EINVAL); 61 /* 62 * Check remembered descriptor. 63 */ 64 if (fstat(pfh->pf_fd, &sb) == -1) 65 return (errno); 66 if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino) 67 return (EINVAL); 68 return (0); 69 } 70 71 static int 72 pidfile_read(const char *path, pid_t *pidptr) 73 { 74 char buf[16], *endptr; 75 int error, fd, i; 76 77 fd = open(path, O_RDONLY); 78 if (fd == -1) 79 return (errno); 80 81 i = read(fd, buf, sizeof(buf) - 1); 82 error = errno; /* Remember errno in case close() wants to change it. */ 83 close(fd); 84 if (i == -1) 85 return (error); 86 else if (i == 0) 87 return (EAGAIN); 88 buf[i] = '\0'; 89 90 *pidptr = strtol(buf, &endptr, 10); 91 if (endptr != &buf[i]) 92 return (EINVAL); 93 94 return (0); 95 } 96 97 static struct pidfh * 98 pidfile_open(const char *path, mode_t mode, pid_t *pidptr) 99 { 100 struct pidfh *pfh; 101 struct stat sb; 102 int error, fd, len, count; 103 struct timespec rqtp; 104 105 if (pidptr != NULL) 106 *pidptr = -1; 107 108 if (path == NULL) 109 return (NULL); 110 111 pfh = malloc(sizeof(*pfh)); 112 if (pfh == NULL) 113 return (NULL); 114 115 len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 116 "%s", path); 117 if (len >= (int)sizeof(pfh->pf_path)) { 118 free(pfh); 119 errno = ENAMETOOLONG; 120 return (NULL); 121 } 122 123 /* 124 * Open the PID file and obtain exclusive lock. 125 * We truncate PID file here only to remove old PID immediatelly, 126 * PID file will be truncated again in pidfile_write(), so 127 * pidfile_write() can be called multiple times. 128 */ 129 fd = flopen(pfh->pf_path, 130 #ifdef O_CLOEXEC 131 O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK | O_CLOEXEC, mode); 132 #else 133 O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode); 134 #endif 135 if (fd == -1) { 136 if (errno == EWOULDBLOCK && pidptr != NULL) { 137 count = 20; 138 rqtp.tv_sec = 0; 139 rqtp.tv_nsec = 5000000; 140 for (;;) { 141 errno = pidfile_read(pfh->pf_path, pidptr); 142 if (errno != EAGAIN || --count == 0) 143 break; 144 nanosleep(&rqtp, 0); 145 } 146 if (errno == EAGAIN) 147 *pidptr = -1; 148 if (errno == 0 || errno == EAGAIN) 149 errno = EEXIST; 150 } 151 free(pfh); 152 return (NULL); 153 } 154 155 #ifndef O_CLOEXEC 156 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { 157 error = errno; 158 unlink(pfh->pf_path); 159 close(fd); 160 free(pfh); 161 errno = error; 162 return (NULL); 163 } 164 #endif 165 166 /* 167 * Remember file information, so in pidfile_write() we are sure we write 168 * to the proper descriptor. 169 */ 170 if (fstat(fd, &sb) == -1) { 171 error = errno; 172 unlink(pfh->pf_path); 173 close(fd); 174 free(pfh); 175 errno = error; 176 return (NULL); 177 } 178 179 pfh->pf_fd = fd; 180 pfh->pf_dev = sb.st_dev; 181 pfh->pf_ino = sb.st_ino; 182 183 return (pfh); 184 } 185 186 static int 187 pidfile_write(struct pidfh *pfh) 188 { 189 char pidstr[16]; 190 int error, fd; 191 192 /* 193 * Check remembered descriptor, so we don't overwrite some other 194 * file if pidfile was closed and descriptor reused. 195 */ 196 errno = pidfile_verify(pfh); 197 if (errno != 0) { 198 /* 199 * Don't close descriptor, because we are not sure if it's ours. 200 */ 201 return (-1); 202 } 203 fd = pfh->pf_fd; 204 205 /* 206 * Truncate PID file, so multiple calls of pidfile_write() are allowed. 207 */ 208 if (ftruncate(fd, 0) == -1) { 209 error = errno; 210 _pidfile_remove(pfh, 0); 211 errno = error; 212 return (-1); 213 } 214 215 snprintf(pidstr, sizeof(pidstr), "%u", getpid()); 216 if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) { 217 error = errno; 218 _pidfile_remove(pfh, 0); 219 errno = error; 220 return (-1); 221 } 222 223 return (0); 224 } 225 226 static int 227 pidfile_close(struct pidfh *pfh) 228 { 229 int error; 230 231 error = pidfile_verify(pfh); 232 if (error != 0) { 233 errno = error; 234 return (-1); 235 } 236 237 if (close(pfh->pf_fd) == -1) 238 error = errno; 239 free(pfh); 240 if (error != 0) { 241 errno = error; 242 return (-1); 243 } 244 return (0); 245 } 246 247 static int 248 _pidfile_remove(struct pidfh *pfh, int freeit) 249 { 250 int error; 251 252 error = pidfile_verify(pfh); 253 if (error != 0) { 254 errno = error; 255 return (-1); 256 } 257 258 if (unlink(pfh->pf_path) == -1) 259 error = errno; 260 if (close(pfh->pf_fd) == -1) { 261 if (error == 0) 262 error = errno; 263 } 264 if (freeit) 265 free(pfh); 266 else 267 pfh->pf_fd = -1; 268 if (error != 0) { 269 errno = error; 270 return (-1); 271 } 272 return (0); 273 } 274 275 static int 276 pidfile_remove(struct pidfh *pfh) 277 { 278 279 return (_pidfile_remove(pfh, 1)); 280 } 281 282 #if 0 283 static int 284 pidfile_fileno(const struct pidfh *pfh) 285 { 286 287 if (pfh == NULL || pfh->pf_fd == -1) { 288 errno = EINVAL; 289 return (-1); 290 } 291 return (pfh->pf_fd); 292 } 293 #endif 294