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