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 44230037Sghelmerstruct pidfh { 45230037Sghelmer int pf_fd; 46230037Sghelmer char pf_path[MAXPATHLEN + 1]; 47230037Sghelmer dev_t pf_dev; 48230037Sghelmer ino_t pf_ino; 49230037Sghelmer}; 50230037Sghelmer 51149423Spjdstatic int _pidfile_remove(struct pidfh *pfh, int freeit); 52149423Spjd 53149423Spjdstatic int 54229951Spjdpidfile_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 76255007Sjilles fd = open(path, O_RDONLY | O_CLOEXEC); 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, 127231938Sghelmer O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode); 128149423Spjd if (fd == -1) { 129248281Spjd if (errno == EWOULDBLOCK) { 130248281Spjd if (pidptr == NULL) { 131248281Spjd errno = EEXIST; 132248281Spjd } else { 133248281Spjd count = 20; 134248281Spjd rqtp.tv_sec = 0; 135248281Spjd rqtp.tv_nsec = 5000000; 136248281Spjd for (;;) { 137248281Spjd errno = pidfile_read(pfh->pf_path, 138248281Spjd pidptr); 139248281Spjd if (errno != EAGAIN || --count == 0) 140248281Spjd break; 141248281Spjd nanosleep(&rqtp, 0); 142248281Spjd } 143248281Spjd if (errno == EAGAIN) 144248281Spjd *pidptr = -1; 145248281Spjd if (errno == 0 || errno == EAGAIN) 146248281Spjd errno = EEXIST; 147226450Spjd } 148149423Spjd } 149149423Spjd free(pfh); 150149423Spjd return (NULL); 151149423Spjd } 152229936Sghelmer 153149423Spjd /* 154149423Spjd * Remember file information, so in pidfile_write() we are sure we write 155149423Spjd * to the proper descriptor. 156149423Spjd */ 157149423Spjd if (fstat(fd, &sb) == -1) { 158149423Spjd error = errno; 159149423Spjd unlink(pfh->pf_path); 160149423Spjd close(fd); 161149423Spjd free(pfh); 162149423Spjd errno = error; 163149423Spjd return (NULL); 164149423Spjd } 165149423Spjd 166149423Spjd pfh->pf_fd = fd; 167149423Spjd pfh->pf_dev = sb.st_dev; 168149423Spjd pfh->pf_ino = sb.st_ino; 169149423Spjd 170149423Spjd return (pfh); 171149423Spjd} 172149423Spjd 173149423Spjdint 174149423Spjdpidfile_write(struct pidfh *pfh) 175149423Spjd{ 176149423Spjd char pidstr[16]; 177149423Spjd int error, fd; 178149423Spjd 179149423Spjd /* 180149423Spjd * Check remembered descriptor, so we don't overwrite some other 181149423Spjd * file if pidfile was closed and descriptor reused. 182149423Spjd */ 183149423Spjd errno = pidfile_verify(pfh); 184149423Spjd if (errno != 0) { 185149423Spjd /* 186149423Spjd * Don't close descriptor, because we are not sure if it's ours. 187149423Spjd */ 188149423Spjd return (-1); 189149423Spjd } 190149423Spjd fd = pfh->pf_fd; 191149423Spjd 192149423Spjd /* 193149423Spjd * Truncate PID file, so multiple calls of pidfile_write() are allowed. 194149423Spjd */ 195149423Spjd if (ftruncate(fd, 0) == -1) { 196149423Spjd error = errno; 197149423Spjd _pidfile_remove(pfh, 0); 198149423Spjd errno = error; 199149423Spjd return (-1); 200149423Spjd } 201149423Spjd 202149423Spjd snprintf(pidstr, sizeof(pidstr), "%u", getpid()); 203157671Sjmg if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) { 204149423Spjd error = errno; 205149423Spjd _pidfile_remove(pfh, 0); 206149423Spjd errno = error; 207149423Spjd return (-1); 208149423Spjd } 209149423Spjd 210149423Spjd return (0); 211149423Spjd} 212149423Spjd 213149423Spjdint 214149423Spjdpidfile_close(struct pidfh *pfh) 215149423Spjd{ 216149423Spjd int error; 217149423Spjd 218149423Spjd error = pidfile_verify(pfh); 219149423Spjd if (error != 0) { 220149423Spjd errno = error; 221149423Spjd return (-1); 222149423Spjd } 223149423Spjd 224149423Spjd if (close(pfh->pf_fd) == -1) 225149423Spjd error = errno; 226149423Spjd free(pfh); 227149423Spjd if (error != 0) { 228149423Spjd errno = error; 229149423Spjd return (-1); 230149423Spjd } 231149423Spjd return (0); 232149423Spjd} 233149423Spjd 234149423Spjdstatic int 235149423Spjd_pidfile_remove(struct pidfh *pfh, int freeit) 236149423Spjd{ 237149423Spjd int error; 238149423Spjd 239149423Spjd error = pidfile_verify(pfh); 240149423Spjd if (error != 0) { 241149423Spjd errno = error; 242149423Spjd return (-1); 243149423Spjd } 244149423Spjd 245149423Spjd if (unlink(pfh->pf_path) == -1) 246149423Spjd error = errno; 247149423Spjd if (close(pfh->pf_fd) == -1) { 248149423Spjd if (error == 0) 249149423Spjd error = errno; 250149423Spjd } 251149423Spjd if (freeit) 252149423Spjd free(pfh); 253149423Spjd else 254149423Spjd pfh->pf_fd = -1; 255149423Spjd if (error != 0) { 256149423Spjd errno = error; 257149423Spjd return (-1); 258149423Spjd } 259149423Spjd return (0); 260149423Spjd} 261149423Spjd 262149423Spjdint 263149423Spjdpidfile_remove(struct pidfh *pfh) 264149423Spjd{ 265149423Spjd 266149423Spjd return (_pidfile_remove(pfh, 1)); 267149423Spjd} 268229937Sghelmer 269229937Sghelmerint 270229951Spjdpidfile_fileno(const struct pidfh *pfh) 271229937Sghelmer{ 272229942Sghelmer 273229937Sghelmer if (pfh == NULL || pfh->pf_fd == -1) { 274229937Sghelmer errno = EDOOFUS; 275229937Sghelmer return (-1); 276229937Sghelmer } 277229937Sghelmer return (pfh->pf_fd); 278229937Sghelmer} 279