pidfile.c revision 172577
129088Smarkm/*- 229088Smarkm * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 329088Smarkm * All rights reserved. 429088Smarkm * 529088Smarkm * Redistribution and use in source and binary forms, with or without 629088Smarkm * modification, are permitted provided that the following conditions 729088Smarkm * are met: 829088Smarkm * 1. Redistributions of source code must retain the above copyright 929088Smarkm * notice, this list of conditions and the following disclaimer. 1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1129088Smarkm * notice, this list of conditions and the following disclaimer in the 1229088Smarkm * documentation and/or other materials provided with the distribution. 1329088Smarkm * 1429088Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1529088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1629088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1729088Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 1829088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1929088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2029088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2129088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2229088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2329088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2429088Smarkm * SUCH DAMAGE. 2529088Smarkm */ 2629088Smarkm 2729088Smarkm#include <sys/cdefs.h> 2829088Smarkm__FBSDID("$FreeBSD: head/lib/libutil/pidfile.c 172577 2007-10-12 10:38:05Z kib $"); 2929088Smarkm 3029088Smarkm#include <sys/param.h> 3129088Smarkm#include <sys/file.h> 3229088Smarkm#include <sys/stat.h> 3329088Smarkm 3463248Speter#include <stdio.h> 3529088Smarkm#include <stdlib.h> 3629088Smarkm#include <unistd.h> 3729181Smarkm#include <fcntl.h> 3829181Smarkm#include <string.h> 3929088Smarkm#include <time.h> 4029088Smarkm#include <err.h> 4129088Smarkm#include <errno.h> 4229088Smarkm#include <libutil.h> 4329088Smarkm 4429088Smarkmstatic int _pidfile_remove(struct pidfh *pfh, int freeit); 4529088Smarkm 4629088Smarkmstatic int 4729088Smarkmpidfile_verify(struct pidfh *pfh) 4829088Smarkm{ 4929088Smarkm struct stat sb; 5029088Smarkm 5129088Smarkm if (pfh == NULL || pfh->pf_fd == -1) 5229088Smarkm return (EDOOFUS); 5329088Smarkm /* 5429088Smarkm * Check remembered descriptor. 5529088Smarkm */ 5629088Smarkm if (fstat(pfh->pf_fd, &sb) == -1) 5729088Smarkm return (errno); 5829088Smarkm if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino) 5929088Smarkm return (EDOOFUS); 6029088Smarkm return (0); 6129088Smarkm} 6229088Smarkm 6329088Smarkmstatic int 6429088Smarkmpidfile_read(const char *path, pid_t *pidptr) 6529088Smarkm{ 6629088Smarkm char buf[16], *endptr; 6787139Smarkm int error, fd, i; 6829088Smarkm 6929088Smarkm fd = open(path, O_RDONLY); 7029181Smarkm if (fd == -1) 7129181Smarkm return (errno); 7229088Smarkm 7329088Smarkm i = read(fd, buf, sizeof(buf) - 1); 7429088Smarkm error = errno; /* Remember errno in case close() wants to change it. */ 7529088Smarkm close(fd); 7629088Smarkm if (i == -1) 7729088Smarkm return (error); 7829088Smarkm else if (i == 0) 7929088Smarkm return (EAGAIN); 8029088Smarkm buf[i] = '\0'; 8129088Smarkm 8229088Smarkm *pidptr = strtol(buf, &endptr, 10); 8329088Smarkm if (endptr != &buf[i]) 8429088Smarkm return (EINVAL); 8529088Smarkm 8629088Smarkm return (0); 8729088Smarkm} 8829088Smarkm 8929088Smarkmstruct pidfh * 9029088Smarkmpidfile_open(const char *path, mode_t mode, pid_t *pidptr) 9129088Smarkm{ 9229088Smarkm struct pidfh *pfh; 9329088Smarkm struct stat sb; 9429088Smarkm int error, fd, len, count; 9529088Smarkm struct timespec rqtp; 9629088Smarkm 9729088Smarkm pfh = malloc(sizeof(*pfh)); 9829088Smarkm if (pfh == NULL) 9929088Smarkm return (NULL); 10029088Smarkm 10129088Smarkm if (path == NULL) 10229088Smarkm len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 10329088Smarkm "/var/run/%s.pid", getprogname()); 10429088Smarkm else 10529088Smarkm len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), 10629088Smarkm "%s", path); 10729088Smarkm if (len >= (int)sizeof(pfh->pf_path)) { 10829088Smarkm free(pfh); 10929088Smarkm errno = ENAMETOOLONG; 11029088Smarkm return (NULL); 11129088Smarkm } 11229088Smarkm 11329088Smarkm /* 11429088Smarkm * Open the PID file and obtain exclusive lock. 11529088Smarkm * We truncate PID file here only to remove old PID immediatelly, 11629088Smarkm * PID file will be truncated again in pidfile_write(), so 11729088Smarkm * pidfile_write() can be called multiple times. 11829088Smarkm */ 11929088Smarkm fd = flopen(pfh->pf_path, 12029088Smarkm O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode); 12129088Smarkm if (fd == -1) { 12229088Smarkm count = 0; 12329088Smarkm rqtp.tv_sec = 0; 124109466Sbillf rqtp.tv_nsec = 5000000; 125109466Sbillf if (errno == EWOULDBLOCK && pidptr != NULL) { 126109466Sbillf again: 127109466Sbillf errno = pidfile_read(pfh->pf_path, pidptr); 12829088Smarkm if (errno == 0) 12929088Smarkm errno = EEXIST; 13029088Smarkm else if (errno == EAGAIN) { 131109466Sbillf if (++count <= 3) { 13229088Smarkm nanosleep(&rqtp, 0); 13387139Smarkm goto again; 13429088Smarkm } 13529088Smarkm } 13629088Smarkm } 13729088Smarkm free(pfh); 13829088Smarkm return (NULL); 13929088Smarkm } 14029088Smarkm /* 14129088Smarkm * Remember file information, so in pidfile_write() we are sure we write 14229088Smarkm * to the proper descriptor. 143183004Santoine */ 144183004Santoine if (fstat(fd, &sb) == -1) { 14529181Smarkm error = errno; 14629088Smarkm unlink(pfh->pf_path); 14729088Smarkm close(fd); 148109466Sbillf free(pfh); 14929088Smarkm errno = error; 15029088Smarkm return (NULL); 15129088Smarkm } 15229088Smarkm 15329088Smarkm pfh->pf_fd = fd; 15429088Smarkm pfh->pf_dev = sb.st_dev; 15529088Smarkm pfh->pf_ino = sb.st_ino; 15629088Smarkm 15729088Smarkm return (pfh); 15829088Smarkm} 15929088Smarkm 16029088Smarkmint 16129088Smarkmpidfile_write(struct pidfh *pfh) 16229088Smarkm{ 16329088Smarkm char pidstr[16]; 16429088Smarkm int error, fd; 16529088Smarkm 16629088Smarkm /* 16729088Smarkm * Check remembered descriptor, so we don't overwrite some other 16829088Smarkm * file if pidfile was closed and descriptor reused. 16929088Smarkm */ 17029088Smarkm errno = pidfile_verify(pfh); 17129088Smarkm if (errno != 0) { 17229088Smarkm /* 17329088Smarkm * Don't close descriptor, because we are not sure if it's ours. 17429088Smarkm */ 17529088Smarkm return (-1); 17629088Smarkm } 17729088Smarkm fd = pfh->pf_fd; 17829088Smarkm 17929088Smarkm /* 18029088Smarkm * Truncate PID file, so multiple calls of pidfile_write() are allowed. 18129088Smarkm */ 18229088Smarkm if (ftruncate(fd, 0) == -1) { 18329088Smarkm error = errno; 18429088Smarkm _pidfile_remove(pfh, 0); 18529088Smarkm errno = error; 18629088Smarkm return (-1); 18729088Smarkm } 18829088Smarkm 18929088Smarkm snprintf(pidstr, sizeof(pidstr), "%u", getpid()); 19029088Smarkm if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) { 19129088Smarkm error = errno; 19229088Smarkm _pidfile_remove(pfh, 0); 19329088Smarkm errno = error; 19429088Smarkm return (-1); 19529088Smarkm } 19629088Smarkm 19729088Smarkm return (0); 19829088Smarkm} 19929088Smarkm 20029088Smarkmint 20129088Smarkmpidfile_close(struct pidfh *pfh) 20229088Smarkm{ 20329088Smarkm int error; 20429088Smarkm 20529088Smarkm error = pidfile_verify(pfh); 20629181Smarkm if (error != 0) { 20729181Smarkm errno = error; 20829181Smarkm return (-1); 20929181Smarkm } 21029181Smarkm 21129181Smarkm if (close(pfh->pf_fd) == -1) 21229181Smarkm error = errno; 21329181Smarkm free(pfh); 21429181Smarkm if (error != 0) { 21529181Smarkm errno = error; 21629181Smarkm return (-1); 21729181Smarkm } 21829088Smarkm return (0); 21929181Smarkm} 22029088Smarkm 22129088Smarkmstatic int 22272093Sasmodai_pidfile_remove(struct pidfh *pfh, int freeit) 22329088Smarkm{ 22429088Smarkm int error; 22585600Smarkm 22685600Smarkm error = pidfile_verify(pfh); 22729181Smarkm if (error != 0) { 22829181Smarkm errno = error; 22929181Smarkm return (-1); 23029181Smarkm } 23129181Smarkm 23229181Smarkm if (unlink(pfh->pf_path) == -1) 23329088Smarkm error = errno; 23487139Smarkm if (flock(pfh->pf_fd, LOCK_UN) == -1) { 23529088Smarkm if (error == 0) 23629088Smarkm error = errno; 23729088Smarkm } 23829088Smarkm if (close(pfh->pf_fd) == -1) { 23929088Smarkm if (error == 0) 24029088Smarkm error = errno; 24129088Smarkm } 24229088Smarkm if (freeit) 24329088Smarkm free(pfh); 24429088Smarkm else 24529088Smarkm pfh->pf_fd = -1; 24629088Smarkm if (error != 0) { 24729088Smarkm errno = error; 24829088Smarkm return (-1); 24929088Smarkm } 25029088Smarkm return (0); 25129088Smarkm} 25229088Smarkm 25329088Smarkmint 25429088Smarkmpidfile_remove(struct pidfh *pfh) 25529088Smarkm{ 25629088Smarkm 25729088Smarkm return (_pidfile_remove(pfh, 1)); 25829088Smarkm} 25929088Smarkm