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