1149423Spjd/*- 2149423Spjd * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3149423Spjd * All rights reserved. 4149423Spjd * 5149423Spjd * Redistribution and use in source and binary forms, with or without 6149423Spjd * modification, are permitted provided that the following conditions 7149423Spjd * are met: 8149423Spjd * 1. Redistributions of source code must retain the above copyright 9149423Spjd * notice, this list of conditions and the following disclaimer. 10149423Spjd * 2. Redistributions in binary form must reproduce the above copyright 11149423Spjd * notice, this list of conditions and the following disclaimer in the 12149423Spjd * documentation and/or other materials provided with the distribution. 13149423Spjd * 14149423Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15149423Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16149423Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17149423Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18149423Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19149423Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20149423Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21149423Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22149423Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23149423Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24149423Spjd * SUCH DAMAGE. 25149423Spjd */ 26149423Spjd 27149423Spjd#include <sys/cdefs.h> 28149423Spjd__FBSDID("$FreeBSD$"); 29149423Spjd 30149423Spjd#include <sys/param.h> 31149423Spjd#include <sys/file.h> 32149423Spjd#include <sys/stat.h> 33149423Spjd 34149423Spjd#include <stdio.h> 35149423Spjd#include <stdlib.h> 36149423Spjd#include <unistd.h> 37171706Sdes#include <fcntl.h> 38149423Spjd#include <string.h> 39172577Skib#include <time.h> 40171706Sdes#include <err.h> 41171706Sdes#include <errno.h> 42149423Spjd#include <libutil.h> 43149423Spjd 44233855Sghelmerstruct pidfh { 45233855Sghelmer int pf_fd; 46233855Sghelmer char pf_path[MAXPATHLEN + 1]; 47233855Sghelmer dev_t pf_dev; 48233855Sghelmer ino_t pf_ino; 49233855Sghelmer}; 50233855Sghelmer 51149423Spjdstatic int _pidfile_remove(struct pidfh *pfh, int freeit); 52149423Spjd 53149423Spjdstatic int 54233855Sghelmerpidfile_verify(const struct pidfh *pfh) 55149423Spjd{ 56149423Spjd struct stat sb; 57149423Spjd 58149423Spjd if (pfh == NULL || pfh->pf_fd == -1) 59149423Spjd return (EDOOFUS); 60149423Spjd /* 61149423Spjd * Check remembered descriptor. 62149423Spjd */ 63149423Spjd if (fstat(pfh->pf_fd, &sb) == -1) 64149423Spjd return (errno); 65149423Spjd if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino) 66149423Spjd return (EDOOFUS); 67149423Spjd return (0); 68149423Spjd} 69149423Spjd 70149423Spjdstatic int 71149423Spjdpidfile_read(const char *path, pid_t *pidptr) 72149423Spjd{ 73149423Spjd char buf[16], *endptr; 74149423Spjd int error, fd, i; 75149423Spjd 76149423Spjd fd = open(path, O_RDONLY); 77149423Spjd if (fd == -1) 78149423Spjd return (errno); 79149423Spjd 80149423Spjd i = read(fd, buf, sizeof(buf) - 1); 81149423Spjd error = errno; /* Remember errno in case close() wants to change it. */ 82149423Spjd close(fd); 83149423Spjd if (i == -1) 84149423Spjd return (error); 85172577Skib else if (i == 0) 86172577Skib return (EAGAIN); 87149423Spjd buf[i] = '\0'; 88149423Spjd 89149423Spjd *pidptr = strtol(buf, &endptr, 10); 90149423Spjd if (endptr != &buf[i]) 91149423Spjd return (EINVAL); 92149423Spjd 93149423Spjd return (0); 94149423Spjd} 95149423Spjd 96149423Spjdstruct pidfh * 97149423Spjdpidfile_open(const char *path, mode_t mode, pid_t *pidptr) 98149423Spjd{ 99149423Spjd struct pidfh *pfh; 100149423Spjd struct stat sb; 101172577Skib int error, fd, len, count; 102172577Skib struct timespec rqtp; 103149423Spjd 104149423Spjd pfh = malloc(sizeof(*pfh)); 105149423Spjd if (pfh == NULL) 106149423Spjd return (NULL); 107149423Spjd 108169468Sdes if (path == NULL) 109169468Sdes len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 110169468Sdes "/var/run/%s.pid", getprogname()); 111169468Sdes else 112169468Sdes len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 113169468Sdes "%s", path); 114169468Sdes if (len >= (int)sizeof(pfh->pf_path)) { 115149423Spjd free(pfh); 116149423Spjd errno = ENAMETOOLONG; 117149423Spjd return (NULL); 118149423Spjd } 119149423Spjd 120149423Spjd /* 121149423Spjd * Open the PID file and obtain exclusive lock. 122149423Spjd * We truncate PID file here only to remove old PID immediatelly, 123149423Spjd * PID file will be truncated again in pidfile_write(), so 124149423Spjd * pidfile_write() can be called multiple times. 125149423Spjd */ 126169448Sdes fd = flopen(pfh->pf_path, 127233856Sghelmer O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode); 128149423Spjd if (fd == -1) { 129172577Skib count = 0; 130172577Skib rqtp.tv_sec = 0; 131172577Skib rqtp.tv_nsec = 5000000; 132149423Spjd if (errno == EWOULDBLOCK && pidptr != NULL) { 133172577Skib again: 134149423Spjd errno = pidfile_read(pfh->pf_path, pidptr); 135149423Spjd if (errno == 0) 136149423Spjd errno = EEXIST; 137172577Skib else if (errno == EAGAIN) { 138172577Skib if (++count <= 3) { 139172577Skib nanosleep(&rqtp, 0); 140172577Skib goto again; 141172577Skib } 142172577Skib } 143149423Spjd } 144149423Spjd free(pfh); 145149423Spjd return (NULL); 146149423Spjd } 147149423Spjd /* 148149423Spjd * Remember file information, so in pidfile_write() we are sure we write 149149423Spjd * to the proper descriptor. 150149423Spjd */ 151149423Spjd if (fstat(fd, &sb) == -1) { 152149423Spjd error = errno; 153149423Spjd unlink(pfh->pf_path); 154149423Spjd close(fd); 155149423Spjd free(pfh); 156149423Spjd errno = error; 157149423Spjd return (NULL); 158149423Spjd } 159149423Spjd 160149423Spjd pfh->pf_fd = fd; 161149423Spjd pfh->pf_dev = sb.st_dev; 162149423Spjd pfh->pf_ino = sb.st_ino; 163149423Spjd 164149423Spjd return (pfh); 165149423Spjd} 166149423Spjd 167149423Spjdint 168149423Spjdpidfile_write(struct pidfh *pfh) 169149423Spjd{ 170149423Spjd char pidstr[16]; 171149423Spjd int error, fd; 172149423Spjd 173149423Spjd /* 174149423Spjd * Check remembered descriptor, so we don't overwrite some other 175149423Spjd * file if pidfile was closed and descriptor reused. 176149423Spjd */ 177149423Spjd errno = pidfile_verify(pfh); 178149423Spjd if (errno != 0) { 179149423Spjd /* 180149423Spjd * Don't close descriptor, because we are not sure if it's ours. 181149423Spjd */ 182149423Spjd return (-1); 183149423Spjd } 184149423Spjd fd = pfh->pf_fd; 185149423Spjd 186149423Spjd /* 187149423Spjd * Truncate PID file, so multiple calls of pidfile_write() are allowed. 188149423Spjd */ 189149423Spjd if (ftruncate(fd, 0) == -1) { 190149423Spjd error = errno; 191149423Spjd _pidfile_remove(pfh, 0); 192149423Spjd errno = error; 193149423Spjd return (-1); 194149423Spjd } 195149423Spjd 196149423Spjd snprintf(pidstr, sizeof(pidstr), "%u", getpid()); 197157671Sjmg if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) { 198149423Spjd error = errno; 199149423Spjd _pidfile_remove(pfh, 0); 200149423Spjd errno = error; 201149423Spjd return (-1); 202149423Spjd } 203149423Spjd 204149423Spjd return (0); 205149423Spjd} 206149423Spjd 207149423Spjdint 208149423Spjdpidfile_close(struct pidfh *pfh) 209149423Spjd{ 210149423Spjd int error; 211149423Spjd 212149423Spjd error = pidfile_verify(pfh); 213149423Spjd if (error != 0) { 214149423Spjd errno = error; 215149423Spjd return (-1); 216149423Spjd } 217149423Spjd 218149423Spjd if (close(pfh->pf_fd) == -1) 219149423Spjd error = errno; 220149423Spjd free(pfh); 221149423Spjd if (error != 0) { 222149423Spjd errno = error; 223149423Spjd return (-1); 224149423Spjd } 225149423Spjd return (0); 226149423Spjd} 227149423Spjd 228149423Spjdstatic int 229149423Spjd_pidfile_remove(struct pidfh *pfh, int freeit) 230149423Spjd{ 231149423Spjd int error; 232149423Spjd 233149423Spjd error = pidfile_verify(pfh); 234149423Spjd if (error != 0) { 235149423Spjd errno = error; 236149423Spjd return (-1); 237149423Spjd } 238149423Spjd 239149423Spjd if (unlink(pfh->pf_path) == -1) 240149423Spjd error = errno; 241149423Spjd if (close(pfh->pf_fd) == -1) { 242149423Spjd if (error == 0) 243149423Spjd error = errno; 244149423Spjd } 245149423Spjd if (freeit) 246149423Spjd free(pfh); 247149423Spjd else 248149423Spjd pfh->pf_fd = -1; 249149423Spjd if (error != 0) { 250149423Spjd errno = error; 251149423Spjd return (-1); 252149423Spjd } 253149423Spjd return (0); 254149423Spjd} 255149423Spjd 256149423Spjdint 257149423Spjdpidfile_remove(struct pidfh *pfh) 258149423Spjd{ 259149423Spjd 260149423Spjd return (_pidfile_remove(pfh, 1)); 261149423Spjd} 262233837Sghelmer 263233837Sghelmerint 264233855Sghelmerpidfile_fileno(const struct pidfh *pfh) 265233837Sghelmer{ 266233856Sghelmer 267233837Sghelmer if (pfh == NULL || pfh->pf_fd == -1) { 268233837Sghelmer errno = EDOOFUS; 269233837Sghelmer return (-1); 270233837Sghelmer } 271233837Sghelmer return (pfh->pf_fd); 272233837Sghelmer} 273