1243730Srwatson/*- 2243730Srwatson * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3243730Srwatson * All rights reserved. 4243730Srwatson * 5243730Srwatson * Redistribution and use in source and binary forms, with or without 6243730Srwatson * modification, are permitted provided that the following conditions 7243730Srwatson * are met: 8243730Srwatson * 1. Redistributions of source code must retain the above copyright 9243730Srwatson * notice, this list of conditions and the following disclaimer. 10243730Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11243730Srwatson * notice, this list of conditions and the following disclaimer in the 12243730Srwatson * documentation and/or other materials provided with the distribution. 13243730Srwatson * 14243730Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15243730Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16243730Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17243730Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18243730Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19243730Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20243730Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21243730Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22243730Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23243730Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24243730Srwatson * SUCH DAMAGE. 25243730Srwatson * 26243730Srwatson * Derived from FreeBSD head/lib/libutil/pidfile.c r231938 27243730Srwatson */ 28243730Srwatson 29243730Srwatson#include <sys/param.h> 30243730Srwatson#include <sys/file.h> 31243730Srwatson#include <sys/stat.h> 32243730Srwatson 33243730Srwatson#include <stdio.h> 34243730Srwatson#include <stdlib.h> 35243730Srwatson#include <unistd.h> 36243730Srwatson#include <fcntl.h> 37243730Srwatson#include <string.h> 38243730Srwatson#include <time.h> 39243730Srwatson#include <err.h> 40243730Srwatson#include <errno.h> 41243730Srwatson 42243730Srwatson#include "flopen.h" 43243730Srwatson 44243730Srwatsonstruct pidfh { 45243730Srwatson int pf_fd; 46243730Srwatson char pf_path[MAXPATHLEN + 1]; 47243730Srwatson dev_t pf_dev; 48243730Srwatson ino_t pf_ino; 49243730Srwatson}; 50243730Srwatson 51243730Srwatsonstatic int _pidfile_remove(struct pidfh *pfh, int freeit); 52243730Srwatson 53243730Srwatsonstatic int 54243730Srwatsonpidfile_verify(const struct pidfh *pfh) 55243730Srwatson{ 56243730Srwatson struct stat sb; 57243730Srwatson 58243730Srwatson if (pfh == NULL || pfh->pf_fd == -1) 59243730Srwatson return (EINVAL); 60243730Srwatson /* 61243730Srwatson * Check remembered descriptor. 62243730Srwatson */ 63243730Srwatson if (fstat(pfh->pf_fd, &sb) == -1) 64243730Srwatson return (errno); 65243730Srwatson if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino) 66243730Srwatson return (EINVAL); 67243730Srwatson return (0); 68243730Srwatson} 69243730Srwatson 70243730Srwatsonstatic int 71243730Srwatsonpidfile_read(const char *path, pid_t *pidptr) 72243730Srwatson{ 73243730Srwatson char buf[16], *endptr; 74243730Srwatson int error, fd, i; 75243730Srwatson 76243730Srwatson fd = open(path, O_RDONLY); 77243730Srwatson if (fd == -1) 78243730Srwatson return (errno); 79243730Srwatson 80243730Srwatson i = read(fd, buf, sizeof(buf) - 1); 81243730Srwatson error = errno; /* Remember errno in case close() wants to change it. */ 82243730Srwatson close(fd); 83243730Srwatson if (i == -1) 84243730Srwatson return (error); 85243730Srwatson else if (i == 0) 86243730Srwatson return (EAGAIN); 87243730Srwatson buf[i] = '\0'; 88243730Srwatson 89243730Srwatson *pidptr = strtol(buf, &endptr, 10); 90243730Srwatson if (endptr != &buf[i]) 91243730Srwatson return (EINVAL); 92243730Srwatson 93243730Srwatson return (0); 94243730Srwatson} 95243730Srwatson 96243730Srwatsonstatic struct pidfh * 97243730Srwatsonpidfile_open(const char *path, mode_t mode, pid_t *pidptr) 98243730Srwatson{ 99243730Srwatson struct pidfh *pfh; 100243730Srwatson struct stat sb; 101243730Srwatson int error, fd, len, count; 102243730Srwatson struct timespec rqtp; 103243730Srwatson 104243730Srwatson if (pidptr != NULL) 105243730Srwatson *pidptr = -1; 106243730Srwatson 107243730Srwatson if (path == NULL) 108243730Srwatson return (NULL); 109243730Srwatson 110243730Srwatson pfh = malloc(sizeof(*pfh)); 111243730Srwatson if (pfh == NULL) 112243730Srwatson return (NULL); 113243730Srwatson 114243730Srwatson len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 115243730Srwatson "%s", path); 116243730Srwatson if (len >= (int)sizeof(pfh->pf_path)) { 117243730Srwatson free(pfh); 118243730Srwatson errno = ENAMETOOLONG; 119243730Srwatson return (NULL); 120243730Srwatson } 121243730Srwatson 122243730Srwatson /* 123243730Srwatson * Open the PID file and obtain exclusive lock. 124243730Srwatson * We truncate PID file here only to remove old PID immediatelly, 125243730Srwatson * PID file will be truncated again in pidfile_write(), so 126243730Srwatson * pidfile_write() can be called multiple times. 127243730Srwatson */ 128243730Srwatson fd = flopen(pfh->pf_path, 129243730Srwatson#ifdef O_CLOEXEC 130243730Srwatson O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK | O_CLOEXEC, mode); 131243730Srwatson#else 132243730Srwatson O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode); 133243730Srwatson#endif 134243730Srwatson if (fd == -1) { 135243730Srwatson if (errno == EWOULDBLOCK && pidptr != NULL) { 136243730Srwatson count = 20; 137243730Srwatson rqtp.tv_sec = 0; 138243730Srwatson rqtp.tv_nsec = 5000000; 139243730Srwatson for (;;) { 140243730Srwatson errno = pidfile_read(pfh->pf_path, pidptr); 141243730Srwatson if (errno != EAGAIN || --count == 0) 142243730Srwatson break; 143243730Srwatson nanosleep(&rqtp, 0); 144243730Srwatson } 145243730Srwatson if (errno == EAGAIN) 146243730Srwatson *pidptr = -1; 147243730Srwatson if (errno == 0 || errno == EAGAIN) 148243730Srwatson errno = EEXIST; 149243730Srwatson } 150243730Srwatson free(pfh); 151243730Srwatson return (NULL); 152243730Srwatson } 153243730Srwatson 154243730Srwatson#ifndef O_CLOEXEC 155243730Srwatson if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { 156243730Srwatson error = errno; 157243730Srwatson unlink(pfh->pf_path); 158243730Srwatson close(fd); 159243730Srwatson free(pfh); 160243730Srwatson errno = error; 161243730Srwatson return (NULL); 162243730Srwatson } 163243730Srwatson#endif 164243730Srwatson 165243730Srwatson /* 166243730Srwatson * Remember file information, so in pidfile_write() we are sure we write 167243730Srwatson * to the proper descriptor. 168243730Srwatson */ 169243730Srwatson if (fstat(fd, &sb) == -1) { 170243730Srwatson error = errno; 171243730Srwatson unlink(pfh->pf_path); 172243730Srwatson close(fd); 173243730Srwatson free(pfh); 174243730Srwatson errno = error; 175243730Srwatson return (NULL); 176243730Srwatson } 177243730Srwatson 178243730Srwatson pfh->pf_fd = fd; 179243730Srwatson pfh->pf_dev = sb.st_dev; 180243730Srwatson pfh->pf_ino = sb.st_ino; 181243730Srwatson 182243730Srwatson return (pfh); 183243730Srwatson} 184243730Srwatson 185243730Srwatsonstatic int 186243730Srwatsonpidfile_write(struct pidfh *pfh) 187243730Srwatson{ 188243730Srwatson char pidstr[16]; 189243730Srwatson int error, fd; 190243730Srwatson 191243730Srwatson /* 192243730Srwatson * Check remembered descriptor, so we don't overwrite some other 193243730Srwatson * file if pidfile was closed and descriptor reused. 194243730Srwatson */ 195243730Srwatson errno = pidfile_verify(pfh); 196243730Srwatson if (errno != 0) { 197243730Srwatson /* 198243730Srwatson * Don't close descriptor, because we are not sure if it's ours. 199243730Srwatson */ 200243730Srwatson return (-1); 201243730Srwatson } 202243730Srwatson fd = pfh->pf_fd; 203243730Srwatson 204243730Srwatson /* 205243730Srwatson * Truncate PID file, so multiple calls of pidfile_write() are allowed. 206243730Srwatson */ 207243730Srwatson if (ftruncate(fd, 0) == -1) { 208243730Srwatson error = errno; 209243730Srwatson _pidfile_remove(pfh, 0); 210243730Srwatson errno = error; 211243730Srwatson return (-1); 212243730Srwatson } 213243730Srwatson 214243730Srwatson snprintf(pidstr, sizeof(pidstr), "%u", getpid()); 215243730Srwatson if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) { 216243730Srwatson error = errno; 217243730Srwatson _pidfile_remove(pfh, 0); 218243730Srwatson errno = error; 219243730Srwatson return (-1); 220243730Srwatson } 221243730Srwatson 222243730Srwatson return (0); 223243730Srwatson} 224243730Srwatson 225243730Srwatsonstatic int 226243730Srwatsonpidfile_close(struct pidfh *pfh) 227243730Srwatson{ 228243730Srwatson int error; 229243730Srwatson 230243730Srwatson error = pidfile_verify(pfh); 231243730Srwatson if (error != 0) { 232243730Srwatson errno = error; 233243730Srwatson return (-1); 234243730Srwatson } 235243730Srwatson 236243730Srwatson if (close(pfh->pf_fd) == -1) 237243730Srwatson error = errno; 238243730Srwatson free(pfh); 239243730Srwatson if (error != 0) { 240243730Srwatson errno = error; 241243730Srwatson return (-1); 242243730Srwatson } 243243730Srwatson return (0); 244243730Srwatson} 245243730Srwatson 246243730Srwatsonstatic int 247243730Srwatson_pidfile_remove(struct pidfh *pfh, int freeit) 248243730Srwatson{ 249243730Srwatson int error; 250243730Srwatson 251243730Srwatson error = pidfile_verify(pfh); 252243730Srwatson if (error != 0) { 253243730Srwatson errno = error; 254243730Srwatson return (-1); 255243730Srwatson } 256243730Srwatson 257243730Srwatson if (unlink(pfh->pf_path) == -1) 258243730Srwatson error = errno; 259243730Srwatson if (close(pfh->pf_fd) == -1) { 260243730Srwatson if (error == 0) 261243730Srwatson error = errno; 262243730Srwatson } 263243730Srwatson if (freeit) 264243730Srwatson free(pfh); 265243730Srwatson else 266243730Srwatson pfh->pf_fd = -1; 267243730Srwatson if (error != 0) { 268243730Srwatson errno = error; 269243730Srwatson return (-1); 270243730Srwatson } 271243730Srwatson return (0); 272243730Srwatson} 273243730Srwatson 274243730Srwatsonstatic int 275243730Srwatsonpidfile_remove(struct pidfh *pfh) 276243730Srwatson{ 277243730Srwatson 278243730Srwatson return (_pidfile_remove(pfh, 1)); 279243730Srwatson} 280243730Srwatson 281243730Srwatson#if 0 282243730Srwatsonstatic int 283243730Srwatsonpidfile_fileno(const struct pidfh *pfh) 284243730Srwatson{ 285243730Srwatson 286243730Srwatson if (pfh == NULL || pfh->pf_fd == -1) { 287243730Srwatson errno = EINVAL; 288243730Srwatson return (-1); 289243730Srwatson } 290243730Srwatson return (pfh->pf_fd); 291243730Srwatson} 292243730Srwatson#endif 293