1199213Sdes/*-
2199213Sdes * Copyright (c) 2007-2009 Dag-Erling Co��dan Sm��rgrav
3199213Sdes * All rights reserved.
4199213Sdes *
5199213Sdes * Redistribution and use in source and binary forms, with or without
6199213Sdes * modification, are permitted provided that the following conditions
7199213Sdes * are met:
8199213Sdes * 1. Redistributions of source code must retain the above copyright
9199213Sdes *    notice, this list of conditions and the following disclaimer
10199213Sdes *    in this position and unchanged.
11199213Sdes * 2. Redistributions in binary form must reproduce the above copyright
12199213Sdes *    notice, this list of conditions and the following disclaimer in the
13199213Sdes *    documentation and/or other materials provided with the distribution.
14199213Sdes *
15199213Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16199213Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17199213Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18199213Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19199213Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20199213Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21199213Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22199213Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23199213Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24199213Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25199213Sdes * SUCH DAMAGE.
26199213Sdes */
27199213Sdes
28199213Sdes#include <sys/cdefs.h>
29199213Sdes__FBSDID("$FreeBSD$");
30199213Sdes
31199213Sdes#include <sys/param.h>
32199213Sdes#include <sys/wait.h>
33199213Sdes
34199213Sdes#include <fcntl.h>
35199213Sdes#include <errno.h>
36199213Sdes#include <signal.h>
37199213Sdes#include <stdint.h>
38199213Sdes#include <stdio.h>
39199213Sdes#include <stdlib.h>
40199213Sdes#include <string.h>
41199213Sdes#include <unistd.h>
42199213Sdes
43199213Sdes#include <libutil.h>
44199213Sdes
45199213Sdes/*
46199213Sdes * We need a signal handler so kill(2) will interrupt our child's
47199213Sdes * select(2) instead of killing it.
48199213Sdes */
49199213Sdesstatic void
50199213Sdessignal_handler(int sig)
51199213Sdes{
52199213Sdes	(void)sig;
53199213Sdes}
54199213Sdes
55199213Sdes/*
56199213Sdes * Test that pidfile_open() can create a pidfile and that pidfile_write()
57199213Sdes * can write to it.
58199213Sdes */
59199213Sdesstatic const char *
60199213Sdestest_pidfile_uncontested(void)
61199213Sdes{
62199213Sdes	const char *fn = "test_pidfile_uncontested";
63199213Sdes	struct pidfh *pf;
64199213Sdes	pid_t other = 0;
65199213Sdes
66199213Sdes	unlink(fn);
67199213Sdes	pf = pidfile_open(fn, 0600, &other);
68199213Sdes	if (pf == NULL && other != 0)
69199213Sdes		return ("pidfile exists and is locked");
70199213Sdes	if (pf == NULL)
71199213Sdes		return (strerror(errno));
72199213Sdes	if (pidfile_write(pf) != 0) {
73199213Sdes		pidfile_close(pf);
74199213Sdes		unlink(fn);
75199213Sdes		return ("failed to write PID");
76199213Sdes	}
77199213Sdes	pidfile_close(pf);
78199213Sdes	unlink(fn);
79199213Sdes	return (NULL);
80199213Sdes}
81199213Sdes
82199213Sdes/*
83199213Sdes * Test that pidfile_open() locks against self.
84199213Sdes */
85199213Sdesstatic const char *
86199213Sdestest_pidfile_self(void)
87199213Sdes{
88199213Sdes	const char *fn = "test_pidfile_self";
89199213Sdes	struct pidfh *pf1, *pf2;
90199213Sdes	pid_t other = 0;
91199213Sdes	int serrno;
92199213Sdes
93199213Sdes	unlink(fn);
94199213Sdes	pf1 = pidfile_open(fn, 0600, &other);
95199213Sdes	if (pf1 == NULL && other != 0)
96199213Sdes		return ("pidfile exists and is locked");
97199213Sdes	if (pf1 == NULL)
98199213Sdes		return (strerror(errno));
99199213Sdes	if (pidfile_write(pf1) != 0) {
100199213Sdes		serrno = errno;
101199213Sdes		pidfile_close(pf1);
102199213Sdes		unlink(fn);
103199213Sdes		return (strerror(serrno));
104199213Sdes	}
105199213Sdes	// second open should fail
106199213Sdes	pf2 = pidfile_open(fn, 0600, &other);
107199213Sdes	if (pf2 != NULL) {
108199213Sdes		pidfile_close(pf1);
109199213Sdes		pidfile_close(pf2);
110199213Sdes		unlink(fn);
111199213Sdes		return ("managed to opened pidfile twice");
112199213Sdes	}
113199213Sdes	if (other != getpid()) {
114199213Sdes		pidfile_close(pf1);
115199213Sdes		unlink(fn);
116199213Sdes		return ("pidfile contained wrong PID");
117199213Sdes	}
118199213Sdes	pidfile_close(pf1);
119199213Sdes	unlink(fn);
120199213Sdes	return (NULL);
121199213Sdes}
122199213Sdes
123199213Sdes/*
124199213Sdes * Common code for test_pidfile_{contested,inherited}.
125199213Sdes */
126199213Sdesstatic const char *
127199213Sdescommon_test_pidfile_child(const char *fn, int parent_open)
128199213Sdes{
129199213Sdes	struct pidfh *pf = NULL;
130199213Sdes	pid_t other = 0, pid = 0;
131199213Sdes	int fd[2], serrno, status;
132199213Sdes	char ch;
133199213Sdes
134199213Sdes	unlink(fn);
135199213Sdes	if (pipe(fd) != 0)
136199213Sdes		return (strerror(errno));
137199213Sdes
138199213Sdes	if (parent_open) {
139199213Sdes		pf = pidfile_open(fn, 0600, &other);
140199213Sdes		if (pf == NULL && other != 0)
141199213Sdes			return ("pidfile exists and is locked");
142199213Sdes		if (pf == NULL)
143199213Sdes			return (strerror(errno));
144199213Sdes	}
145199213Sdes
146199213Sdes	pid = fork();
147199213Sdes	if (pid == -1)
148199213Sdes		return (strerror(errno));
149199213Sdes	if (pid == 0) {
150199213Sdes		// child
151199213Sdes		close(fd[0]);
152199213Sdes		signal(SIGINT, signal_handler);
153199213Sdes		if (!parent_open) {
154199213Sdes			pf = pidfile_open(fn, 0600, &other);
155199213Sdes			if (pf == NULL && other != 0)
156199213Sdes				return ("pidfile exists and is locked");
157199213Sdes			if (pf == NULL)
158199213Sdes				return (strerror(errno));
159199213Sdes		}
160199213Sdes		if (pidfile_write(pf) != 0) {
161199213Sdes			serrno = errno;
162199213Sdes			pidfile_close(pf);
163199213Sdes			unlink(fn);
164199213Sdes			return (strerror(serrno));
165199213Sdes		}
166199213Sdes		if (pf == NULL)
167199213Sdes			_exit(1);
168199213Sdes		if (pidfile_write(pf) != 0)
169199213Sdes			_exit(1);
170199213Sdes		if (write(fd[1], "*", 1) != 1)
171199213Sdes			_exit(1);
172199213Sdes		select(0, 0, 0, 0, 0);
173199213Sdes		_exit(0);
174199213Sdes	}
175199213Sdes	// parent
176199213Sdes	close(fd[1]);
177199213Sdes	if (pf)
178199213Sdes		pidfile_close(pf);
179199213Sdes
180199213Sdes	// wait for the child to signal us
181199213Sdes	if (read(fd[0], &ch, 1) != 1) {
182199213Sdes		serrno = errno;
183199213Sdes		unlink(fn);
184199213Sdes		kill(pid, SIGTERM);
185199213Sdes		errno = serrno;
186199213Sdes		return (strerror(errno));
187199213Sdes	}
188199213Sdes
189199213Sdes	// We shouldn't be able to lock the same pidfile as our child
190199213Sdes	pf = pidfile_open(fn, 0600, &other);
191199213Sdes	if (pf != NULL) {
192199213Sdes		pidfile_close(pf);
193199213Sdes		unlink(fn);
194199213Sdes		return ("managed to lock contested pidfile");
195199213Sdes	}
196199213Sdes
197199213Sdes	// Failed to lock, but not because it was contested
198199213Sdes	if (other == 0) {
199199213Sdes		unlink(fn);
200199213Sdes		return (strerror(errno));
201199213Sdes	}
202199213Sdes
203199213Sdes	// Locked by the wrong process
204199213Sdes	if (other != pid) {
205199213Sdes		unlink(fn);
206199213Sdes		return ("pidfile contained wrong PID");
207199213Sdes	}
208199213Sdes
209199213Sdes	// check our child's fate
210199213Sdes	if (pf)
211199213Sdes		pidfile_close(pf);
212199213Sdes	unlink(fn);
213199213Sdes	if (kill(pid, SIGINT) != 0)
214199213Sdes		return (strerror(errno));
215199213Sdes	if (waitpid(pid, &status, 0) == -1)
216199213Sdes		return (strerror(errno));
217199213Sdes	if (WIFSIGNALED(status))
218199213Sdes		return ("child caught signal");
219199213Sdes	if (WEXITSTATUS(status) != 0)
220199213Sdes		return ("child returned non-zero status");
221199213Sdes
222199213Sdes	// success
223199213Sdes	return (NULL);
224199213Sdes}
225199213Sdes
226199213Sdes/*
227199213Sdes * Test that pidfile_open() fails when attempting to open a pidfile that
228199213Sdes * is already locked, and that it returns the correct PID.
229199213Sdes */
230199213Sdesstatic const char *
231199213Sdestest_pidfile_contested(void)
232199213Sdes{
233199213Sdes	const char *fn = "test_pidfile_contested";
234199213Sdes	const char *result;
235199213Sdes
236199213Sdes	result = common_test_pidfile_child(fn, 0);
237199213Sdes	return (result);
238199213Sdes}
239199213Sdes
240199213Sdes/*
241199213Sdes * Test that the pidfile lock is inherited.
242199213Sdes */
243199213Sdesstatic const char *
244199213Sdestest_pidfile_inherited(void)
245199213Sdes{
246199213Sdes	const char *fn = "test_pidfile_inherited";
247199213Sdes	const char *result;
248199213Sdes
249199213Sdes	result = common_test_pidfile_child(fn, 1);
250199213Sdes	return (result);
251199213Sdes}
252199213Sdes
253199213Sdesstatic struct test {
254199213Sdes	const char *name;
255199213Sdes	const char *(*func)(void);
256199213Sdes} t[] = {
257199213Sdes	{ "pidfile_uncontested", test_pidfile_uncontested },
258199213Sdes	{ "pidfile_self", test_pidfile_self },
259199213Sdes	{ "pidfile_contested", test_pidfile_contested },
260199213Sdes	{ "pidfile_inherited", test_pidfile_inherited },
261199213Sdes};
262199213Sdes
263199213Sdesint
264199213Sdesmain(void)
265199213Sdes{
266199213Sdes	const char *result;
267199213Sdes	int i, nt;
268199213Sdes
269199213Sdes	nt = sizeof(t) / sizeof(*t);
270199213Sdes	printf("1..%d\n", nt);
271199213Sdes	for (i = 0; i < nt; ++i) {
272199213Sdes		if ((result = t[i].func()) != NULL)
273199213Sdes			printf("not ok %d - %s # %s\n", i + 1,
274199213Sdes			    t[i].name, result);
275199213Sdes		else
276199213Sdes			printf("ok %d - %s\n", i + 1,
277199213Sdes			    t[i].name);
278199213Sdes	}
279199213Sdes	exit(0);
280199213Sdes}
281