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 * $P4: //depot/projects/trustedbsd/openbsm/compat/pidfile.h#1 $ 28243730Srwatson */ 29243730Srwatson 30243730Srwatson#include <sys/param.h> 31243730Srwatson#include <sys/file.h> 32243730Srwatson#include <sys/stat.h> 33243730Srwatson 34243730Srwatson#include <stdio.h> 35243730Srwatson#include <stdlib.h> 36243730Srwatson#include <unistd.h> 37243730Srwatson#include <fcntl.h> 38243730Srwatson#include <string.h> 39243730Srwatson#include <time.h> 40243730Srwatson#include <err.h> 41243730Srwatson#include <errno.h> 42243730Srwatson 43243730Srwatson#include "flopen.h" 44243730Srwatson 45243730Srwatsonstruct pidfh { 46243730Srwatson int pf_fd; 47243730Srwatson char pf_path[MAXPATHLEN + 1]; 48243730Srwatson dev_t pf_dev; 49243730Srwatson ino_t pf_ino; 50243730Srwatson}; 51243730Srwatson 52243730Srwatsonstatic int _pidfile_remove(struct pidfh *pfh, int freeit); 53243730Srwatson 54243730Srwatsonstatic int 55243730Srwatsonpidfile_verify(const struct pidfh *pfh) 56243730Srwatson{ 57243730Srwatson struct stat sb; 58243730Srwatson 59243730Srwatson if (pfh == NULL || pfh->pf_fd == -1) 60243730Srwatson return (EINVAL); 61243730Srwatson /* 62243730Srwatson * Check remembered descriptor. 63243730Srwatson */ 64243730Srwatson if (fstat(pfh->pf_fd, &sb) == -1) 65243730Srwatson return (errno); 66243730Srwatson if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino) 67243730Srwatson return (EINVAL); 68243730Srwatson return (0); 69243730Srwatson} 70243730Srwatson 71243730Srwatsonstatic int 72243730Srwatsonpidfile_read(const char *path, pid_t *pidptr) 73243730Srwatson{ 74243730Srwatson char buf[16], *endptr; 75243730Srwatson int error, fd, i; 76243730Srwatson 77243730Srwatson fd = open(path, O_RDONLY); 78243730Srwatson if (fd == -1) 79243730Srwatson return (errno); 80243730Srwatson 81243730Srwatson i = read(fd, buf, sizeof(buf) - 1); 82243730Srwatson error = errno; /* Remember errno in case close() wants to change it. */ 83243730Srwatson close(fd); 84243730Srwatson if (i == -1) 85243730Srwatson return (error); 86243730Srwatson else if (i == 0) 87243730Srwatson return (EAGAIN); 88243730Srwatson buf[i] = '\0'; 89243730Srwatson 90243730Srwatson *pidptr = strtol(buf, &endptr, 10); 91243730Srwatson if (endptr != &buf[i]) 92243730Srwatson return (EINVAL); 93243730Srwatson 94243730Srwatson return (0); 95243730Srwatson} 96243730Srwatson 97243730Srwatsonstatic struct pidfh * 98243730Srwatsonpidfile_open(const char *path, mode_t mode, pid_t *pidptr) 99243730Srwatson{ 100243730Srwatson struct pidfh *pfh; 101243730Srwatson struct stat sb; 102243730Srwatson int error, fd, len, count; 103243730Srwatson struct timespec rqtp; 104243730Srwatson 105243730Srwatson if (pidptr != NULL) 106243730Srwatson *pidptr = -1; 107243730Srwatson 108243730Srwatson if (path == NULL) 109243730Srwatson return (NULL); 110243730Srwatson 111243730Srwatson pfh = malloc(sizeof(*pfh)); 112243730Srwatson if (pfh == NULL) 113243730Srwatson return (NULL); 114243730Srwatson 115243730Srwatson len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 116243730Srwatson "%s", path); 117243730Srwatson if (len >= (int)sizeof(pfh->pf_path)) { 118243730Srwatson free(pfh); 119243730Srwatson errno = ENAMETOOLONG; 120243730Srwatson return (NULL); 121243730Srwatson } 122243730Srwatson 123243730Srwatson /* 124243730Srwatson * Open the PID file and obtain exclusive lock. 125243730Srwatson * We truncate PID file here only to remove old PID immediatelly, 126243730Srwatson * PID file will be truncated again in pidfile_write(), so 127243730Srwatson * pidfile_write() can be called multiple times. 128243730Srwatson */ 129243730Srwatson fd = flopen(pfh->pf_path, 130243730Srwatson#ifdef O_CLOEXEC 131243730Srwatson O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK | O_CLOEXEC, mode); 132243730Srwatson#else 133243730Srwatson O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode); 134243730Srwatson#endif 135243730Srwatson if (fd == -1) { 136243730Srwatson if (errno == EWOULDBLOCK && pidptr != NULL) { 137243730Srwatson count = 20; 138243730Srwatson rqtp.tv_sec = 0; 139243730Srwatson rqtp.tv_nsec = 5000000; 140243730Srwatson for (;;) { 141243730Srwatson errno = pidfile_read(pfh->pf_path, pidptr); 142243730Srwatson if (errno != EAGAIN || --count == 0) 143243730Srwatson break; 144243730Srwatson nanosleep(&rqtp, 0); 145243730Srwatson } 146243730Srwatson if (errno == EAGAIN) 147243730Srwatson *pidptr = -1; 148243730Srwatson if (errno == 0 || errno == EAGAIN) 149243730Srwatson errno = EEXIST; 150243730Srwatson } 151243730Srwatson free(pfh); 152243730Srwatson return (NULL); 153243730Srwatson } 154243730Srwatson 155243730Srwatson#ifndef O_CLOEXEC 156243730Srwatson if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { 157243730Srwatson error = errno; 158243730Srwatson unlink(pfh->pf_path); 159243730Srwatson close(fd); 160243730Srwatson free(pfh); 161243730Srwatson errno = error; 162243730Srwatson return (NULL); 163243730Srwatson } 164243730Srwatson#endif 165243730Srwatson 166243730Srwatson /* 167243730Srwatson * Remember file information, so in pidfile_write() we are sure we write 168243730Srwatson * to the proper descriptor. 169243730Srwatson */ 170243730Srwatson if (fstat(fd, &sb) == -1) { 171243730Srwatson error = errno; 172243730Srwatson unlink(pfh->pf_path); 173243730Srwatson close(fd); 174243730Srwatson free(pfh); 175243730Srwatson errno = error; 176243730Srwatson return (NULL); 177243730Srwatson } 178243730Srwatson 179243730Srwatson pfh->pf_fd = fd; 180243730Srwatson pfh->pf_dev = sb.st_dev; 181243730Srwatson pfh->pf_ino = sb.st_ino; 182243730Srwatson 183243730Srwatson return (pfh); 184243730Srwatson} 185243730Srwatson 186243730Srwatsonstatic int 187243730Srwatsonpidfile_write(struct pidfh *pfh) 188243730Srwatson{ 189243730Srwatson char pidstr[16]; 190243730Srwatson int error, fd; 191243730Srwatson 192243730Srwatson /* 193243730Srwatson * Check remembered descriptor, so we don't overwrite some other 194243730Srwatson * file if pidfile was closed and descriptor reused. 195243730Srwatson */ 196243730Srwatson errno = pidfile_verify(pfh); 197243730Srwatson if (errno != 0) { 198243730Srwatson /* 199243730Srwatson * Don't close descriptor, because we are not sure if it's ours. 200243730Srwatson */ 201243730Srwatson return (-1); 202243730Srwatson } 203243730Srwatson fd = pfh->pf_fd; 204243730Srwatson 205243730Srwatson /* 206243730Srwatson * Truncate PID file, so multiple calls of pidfile_write() are allowed. 207243730Srwatson */ 208243730Srwatson if (ftruncate(fd, 0) == -1) { 209243730Srwatson error = errno; 210243730Srwatson _pidfile_remove(pfh, 0); 211243730Srwatson errno = error; 212243730Srwatson return (-1); 213243730Srwatson } 214243730Srwatson 215243730Srwatson snprintf(pidstr, sizeof(pidstr), "%u", getpid()); 216243730Srwatson if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) { 217243730Srwatson error = errno; 218243730Srwatson _pidfile_remove(pfh, 0); 219243730Srwatson errno = error; 220243730Srwatson return (-1); 221243730Srwatson } 222243730Srwatson 223243730Srwatson return (0); 224243730Srwatson} 225243730Srwatson 226243730Srwatsonstatic int 227243730Srwatsonpidfile_close(struct pidfh *pfh) 228243730Srwatson{ 229243730Srwatson int error; 230243730Srwatson 231243730Srwatson error = pidfile_verify(pfh); 232243730Srwatson if (error != 0) { 233243730Srwatson errno = error; 234243730Srwatson return (-1); 235243730Srwatson } 236243730Srwatson 237243730Srwatson if (close(pfh->pf_fd) == -1) 238243730Srwatson error = errno; 239243730Srwatson free(pfh); 240243730Srwatson if (error != 0) { 241243730Srwatson errno = error; 242243730Srwatson return (-1); 243243730Srwatson } 244243730Srwatson return (0); 245243730Srwatson} 246243730Srwatson 247243730Srwatsonstatic int 248243730Srwatson_pidfile_remove(struct pidfh *pfh, int freeit) 249243730Srwatson{ 250243730Srwatson int error; 251243730Srwatson 252243730Srwatson error = pidfile_verify(pfh); 253243730Srwatson if (error != 0) { 254243730Srwatson errno = error; 255243730Srwatson return (-1); 256243730Srwatson } 257243730Srwatson 258243730Srwatson if (unlink(pfh->pf_path) == -1) 259243730Srwatson error = errno; 260243730Srwatson if (close(pfh->pf_fd) == -1) { 261243730Srwatson if (error == 0) 262243730Srwatson error = errno; 263243730Srwatson } 264243730Srwatson if (freeit) 265243730Srwatson free(pfh); 266243730Srwatson else 267243730Srwatson pfh->pf_fd = -1; 268243730Srwatson if (error != 0) { 269243730Srwatson errno = error; 270243730Srwatson return (-1); 271243730Srwatson } 272243730Srwatson return (0); 273243730Srwatson} 274243730Srwatson 275243730Srwatsonstatic int 276243730Srwatsonpidfile_remove(struct pidfh *pfh) 277243730Srwatson{ 278243730Srwatson 279243730Srwatson return (_pidfile_remove(pfh, 1)); 280243730Srwatson} 281243730Srwatson 282243730Srwatson#if 0 283243730Srwatsonstatic int 284243730Srwatsonpidfile_fileno(const struct pidfh *pfh) 285243730Srwatson{ 286243730Srwatson 287243730Srwatson if (pfh == NULL || pfh->pf_fd == -1) { 288243730Srwatson errno = EINVAL; 289243730Srwatson return (-1); 290243730Srwatson } 291243730Srwatson return (pfh->pf_fd); 292243730Srwatson} 293243730Srwatson#endif 294