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: stable/10/lib/libutil/tests/pidfile_test.c 335965 2018-07-04 18:03:19Z emaste $");
30199213Sdes
31199213Sdes#include <sys/param.h>
32199213Sdes#include <sys/wait.h>
33335965Semaste#include <sys/event.h>
34199213Sdes
35199213Sdes#include <fcntl.h>
36199213Sdes#include <errno.h>
37199213Sdes#include <signal.h>
38199213Sdes#include <stdint.h>
39199213Sdes#include <stdio.h>
40199213Sdes#include <stdlib.h>
41199213Sdes#include <string.h>
42199213Sdes#include <unistd.h>
43199213Sdes
44199213Sdes#include <libutil.h>
45199213Sdes
46199213Sdes/*
47335965Semaste * We need a signal handler so kill(2) will interrupt the child
48335965Semaste * instead of killing it.
49199213Sdes */
50199213Sdesstatic void
51199213Sdessignal_handler(int sig)
52199213Sdes{
53199213Sdes	(void)sig;
54199213Sdes}
55199213Sdes
56199213Sdes/*
57199213Sdes * Test that pidfile_open() can create a pidfile and that pidfile_write()
58199213Sdes * can write to it.
59199213Sdes */
60199213Sdesstatic const char *
61199213Sdestest_pidfile_uncontested(void)
62199213Sdes{
63199213Sdes	const char *fn = "test_pidfile_uncontested";
64199213Sdes	struct pidfh *pf;
65199213Sdes	pid_t other = 0;
66199213Sdes
67199213Sdes	unlink(fn);
68199213Sdes	pf = pidfile_open(fn, 0600, &other);
69199213Sdes	if (pf == NULL && other != 0)
70199213Sdes		return ("pidfile exists and is locked");
71199213Sdes	if (pf == NULL)
72199213Sdes		return (strerror(errno));
73199213Sdes	if (pidfile_write(pf) != 0) {
74199213Sdes		pidfile_close(pf);
75199213Sdes		unlink(fn);
76199213Sdes		return ("failed to write PID");
77199213Sdes	}
78199213Sdes	pidfile_close(pf);
79199213Sdes	unlink(fn);
80199213Sdes	return (NULL);
81199213Sdes}
82199213Sdes
83199213Sdes/*
84199213Sdes * Test that pidfile_open() locks against self.
85199213Sdes */
86199213Sdesstatic const char *
87199213Sdestest_pidfile_self(void)
88199213Sdes{
89199213Sdes	const char *fn = "test_pidfile_self";
90199213Sdes	struct pidfh *pf1, *pf2;
91199213Sdes	pid_t other = 0;
92199213Sdes	int serrno;
93199213Sdes
94199213Sdes	unlink(fn);
95199213Sdes	pf1 = pidfile_open(fn, 0600, &other);
96199213Sdes	if (pf1 == NULL && other != 0)
97199213Sdes		return ("pidfile exists and is locked");
98199213Sdes	if (pf1 == NULL)
99199213Sdes		return (strerror(errno));
100199213Sdes	if (pidfile_write(pf1) != 0) {
101199213Sdes		serrno = errno;
102199213Sdes		pidfile_close(pf1);
103199213Sdes		unlink(fn);
104199213Sdes		return (strerror(serrno));
105199213Sdes	}
106199213Sdes	// second open should fail
107199213Sdes	pf2 = pidfile_open(fn, 0600, &other);
108199213Sdes	if (pf2 != NULL) {
109199213Sdes		pidfile_close(pf1);
110199213Sdes		pidfile_close(pf2);
111199213Sdes		unlink(fn);
112199213Sdes		return ("managed to opened pidfile twice");
113199213Sdes	}
114199213Sdes	if (other != getpid()) {
115199213Sdes		pidfile_close(pf1);
116199213Sdes		unlink(fn);
117199213Sdes		return ("pidfile contained wrong PID");
118199213Sdes	}
119199213Sdes	pidfile_close(pf1);
120199213Sdes	unlink(fn);
121199213Sdes	return (NULL);
122199213Sdes}
123199213Sdes
124199213Sdes/*
125199213Sdes * Common code for test_pidfile_{contested,inherited}.
126199213Sdes */
127199213Sdesstatic const char *
128199213Sdescommon_test_pidfile_child(const char *fn, int parent_open)
129199213Sdes{
130199213Sdes	struct pidfh *pf = NULL;
131199213Sdes	pid_t other = 0, pid = 0;
132199213Sdes	int fd[2], serrno, status;
133335965Semaste	struct kevent event, ke;
134199213Sdes	char ch;
135335965Semaste	int kq;
136199213Sdes
137199213Sdes	unlink(fn);
138199213Sdes	if (pipe(fd) != 0)
139199213Sdes		return (strerror(errno));
140199213Sdes
141199213Sdes	if (parent_open) {
142199213Sdes		pf = pidfile_open(fn, 0600, &other);
143199213Sdes		if (pf == NULL && other != 0)
144199213Sdes			return ("pidfile exists and is locked");
145199213Sdes		if (pf == NULL)
146199213Sdes			return (strerror(errno));
147199213Sdes	}
148199213Sdes
149199213Sdes	pid = fork();
150199213Sdes	if (pid == -1)
151199213Sdes		return (strerror(errno));
152199213Sdes	if (pid == 0) {
153199213Sdes		// child
154199213Sdes		close(fd[0]);
155199213Sdes		signal(SIGINT, signal_handler);
156199213Sdes		if (!parent_open) {
157199213Sdes			pf = pidfile_open(fn, 0600, &other);
158199213Sdes			if (pf == NULL && other != 0)
159199213Sdes				return ("pidfile exists and is locked");
160199213Sdes			if (pf == NULL)
161199213Sdes				return (strerror(errno));
162199213Sdes		}
163199213Sdes		if (pidfile_write(pf) != 0) {
164199213Sdes			serrno = errno;
165199213Sdes			pidfile_close(pf);
166199213Sdes			unlink(fn);
167199213Sdes			return (strerror(serrno));
168199213Sdes		}
169199213Sdes		if (pf == NULL)
170199213Sdes			_exit(1);
171199213Sdes		if (pidfile_write(pf) != 0)
172335965Semaste			_exit(2);
173335965Semaste		kq = kqueue();
174335965Semaste		if (kq == -1)
175335965Semaste			_exit(3);
176335965Semaste		EV_SET(&ke, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
177335965Semaste		/* Attach event to the kqueue. */
178335965Semaste		if (kevent(kq, &ke, 1, NULL, 0, NULL) != 0)
179335965Semaste			_exit(4);
180335965Semaste		/* Inform the parent we are ready to receive SIGINT */
181199213Sdes		if (write(fd[1], "*", 1) != 1)
182335965Semaste			_exit(5);
183335965Semaste		/* Wait for SIGINT received */
184335965Semaste		if (kevent(kq, NULL, 0, &event, 1, NULL) != 1)
185335965Semaste			_exit(6);
186199213Sdes		_exit(0);
187199213Sdes	}
188199213Sdes	// parent
189199213Sdes	close(fd[1]);
190199213Sdes	if (pf)
191199213Sdes		pidfile_close(pf);
192199213Sdes
193199213Sdes	// wait for the child to signal us
194199213Sdes	if (read(fd[0], &ch, 1) != 1) {
195199213Sdes		serrno = errno;
196199213Sdes		unlink(fn);
197199213Sdes		kill(pid, SIGTERM);
198199213Sdes		errno = serrno;
199199213Sdes		return (strerror(errno));
200199213Sdes	}
201199213Sdes
202199213Sdes	// We shouldn't be able to lock the same pidfile as our child
203199213Sdes	pf = pidfile_open(fn, 0600, &other);
204199213Sdes	if (pf != NULL) {
205199213Sdes		pidfile_close(pf);
206199213Sdes		unlink(fn);
207199213Sdes		return ("managed to lock contested pidfile");
208199213Sdes	}
209199213Sdes
210199213Sdes	// Failed to lock, but not because it was contested
211199213Sdes	if (other == 0) {
212199213Sdes		unlink(fn);
213199213Sdes		return (strerror(errno));
214199213Sdes	}
215199213Sdes
216199213Sdes	// Locked by the wrong process
217199213Sdes	if (other != pid) {
218199213Sdes		unlink(fn);
219199213Sdes		return ("pidfile contained wrong PID");
220199213Sdes	}
221199213Sdes
222199213Sdes	// check our child's fate
223199213Sdes	if (pf)
224199213Sdes		pidfile_close(pf);
225199213Sdes	unlink(fn);
226199213Sdes	if (kill(pid, SIGINT) != 0)
227199213Sdes		return (strerror(errno));
228199213Sdes	if (waitpid(pid, &status, 0) == -1)
229199213Sdes		return (strerror(errno));
230199213Sdes	if (WIFSIGNALED(status))
231199213Sdes		return ("child caught signal");
232199213Sdes	if (WEXITSTATUS(status) != 0)
233199213Sdes		return ("child returned non-zero status");
234199213Sdes
235199213Sdes	// success
236199213Sdes	return (NULL);
237199213Sdes}
238199213Sdes
239199213Sdes/*
240199213Sdes * Test that pidfile_open() fails when attempting to open a pidfile that
241199213Sdes * is already locked, and that it returns the correct PID.
242199213Sdes */
243199213Sdesstatic const char *
244199213Sdestest_pidfile_contested(void)
245199213Sdes{
246199213Sdes	const char *fn = "test_pidfile_contested";
247199213Sdes	const char *result;
248199213Sdes
249199213Sdes	result = common_test_pidfile_child(fn, 0);
250199213Sdes	return (result);
251199213Sdes}
252199213Sdes
253199213Sdes/*
254199213Sdes * Test that the pidfile lock is inherited.
255199213Sdes */
256199213Sdesstatic const char *
257199213Sdestest_pidfile_inherited(void)
258199213Sdes{
259199213Sdes	const char *fn = "test_pidfile_inherited";
260199213Sdes	const char *result;
261199213Sdes
262199213Sdes	result = common_test_pidfile_child(fn, 1);
263199213Sdes	return (result);
264199213Sdes}
265199213Sdes
266199213Sdesstatic struct test {
267199213Sdes	const char *name;
268199213Sdes	const char *(*func)(void);
269199213Sdes} t[] = {
270199213Sdes	{ "pidfile_uncontested", test_pidfile_uncontested },
271199213Sdes	{ "pidfile_self", test_pidfile_self },
272199213Sdes	{ "pidfile_contested", test_pidfile_contested },
273199213Sdes	{ "pidfile_inherited", test_pidfile_inherited },
274199213Sdes};
275199213Sdes
276199213Sdesint
277199213Sdesmain(void)
278199213Sdes{
279199213Sdes	const char *result;
280199213Sdes	int i, nt;
281199213Sdes
282199213Sdes	nt = sizeof(t) / sizeof(*t);
283199213Sdes	printf("1..%d\n", nt);
284199213Sdes	for (i = 0; i < nt; ++i) {
285199213Sdes		if ((result = t[i].func()) != NULL)
286199213Sdes			printf("not ok %d - %s # %s\n", i + 1,
287199213Sdes			    t[i].name, result);
288199213Sdes		else
289199213Sdes			printf("ok %d - %s\n", i + 1,
290199213Sdes			    t[i].name);
291199213Sdes	}
292199213Sdes	exit(0);
293199213Sdes}
294