1/*-
2 * Copyright (c) 2007-2009 Dag-Erling Coïdan Smørgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/types.h>
32#include <sys/fcntl.h>
33
34#include <errno.h>
35#include <signal.h>
36#include <stdint.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include <libutil.h>
43
44/*
45 * Test that flopen() can create a file.
46 */
47const char *
48test_flopen_create(void)
49{
50	const char *fn = "test_flopen_create";
51	const char *result = NULL;
52	int fd;
53
54	unlink(fn);
55	fd = flopen(fn, O_RDWR|O_CREAT, 0640);
56	if (fd < 0) {
57		result = strerror(errno);
58	} else {
59		close(fd);
60	}
61	unlink(fn);
62	return (result);
63}
64
65/*
66 * Test that flopen() can open an existing file.
67 */
68const char *
69test_flopen_open(void)
70{
71	const char *fn = "test_flopen_open";
72	const char *result = NULL;
73	int fd;
74
75	fd = open(fn, O_RDWR|O_CREAT, 0640);
76	if (fd < 0) {
77		result = strerror(errno);
78	} else {
79		close(fd);
80		fd = flopen(fn, O_RDWR);
81		if (fd < 0) {
82			result = strerror(errno);
83		} else {
84			close(fd);
85		}
86	}
87	unlink(fn);
88	return (result);
89}
90
91/*
92 * Test that flopen() can lock against itself
93 */
94const char *
95test_flopen_lock_self(void)
96{
97	const char *fn = "test_flopen_lock_self";
98	const char *result = NULL;
99	int fd1, fd2;
100
101	unlink(fn);
102	fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
103	if (fd1 < 0) {
104		result = strerror(errno);
105	} else {
106		fd2 = flopen(fn, O_RDWR|O_NONBLOCK);
107		if (fd2 >= 0) {
108			result = "second open succeeded";
109			close(fd2);
110		}
111		close(fd1);
112	}
113	unlink(fn);
114	return (result);
115}
116
117/*
118 * Test that flopen() can lock against other processes
119 */
120const char *
121test_flopen_lock_other(void)
122{
123	const char *fn = "test_flopen_lock_other";
124	const char *result = NULL;
125	volatile int fd1, fd2;
126
127	unlink(fn);
128	fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
129	if (fd1 < 0) {
130		result = strerror(errno);
131	} else {
132		fd2 = -42;
133		if (vfork() == 0) {
134			fd2 = flopen(fn, O_RDWR|O_NONBLOCK);
135			close(fd2);
136			_exit(0);
137		}
138		if (fd2 == -42)
139			result = "vfork() doesn't work as expected";
140		if (fd2 >= 0)
141			result = "second open succeeded";
142		close(fd1);
143	}
144	unlink(fn);
145	return (result);
146}
147
148/*
149 * Test that child processes inherit the lock
150 */
151const char *
152test_flopen_lock_child(void)
153{
154	const char *fn = "test_flopen_lock_child";
155	const char *result = NULL;
156	pid_t pid;
157	volatile int fd1, fd2;
158
159	unlink(fn);
160	fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
161	if (fd1 < 0) {
162		result = strerror(errno);
163	} else {
164		pid = fork();
165		if (pid == -1) {
166			result = strerror(errno);
167		} else if (pid == 0) {
168			select(0, 0, 0, 0, 0);
169			_exit(0);
170		}
171		close(fd1);
172		if ((fd2 = flopen(fn, O_RDWR|O_NONBLOCK)) != -1) {
173			result = "second open succeeded";
174			close(fd2);
175		}
176		kill(pid, SIGINT);
177	}
178	unlink(fn);
179	return (result);
180}
181
182static struct test {
183	const char *name;
184	const char *(*func)(void);
185} t[] = {
186	{ "flopen_create", test_flopen_create },
187	{ "flopen_open", test_flopen_open },
188	{ "flopen_lock_self", test_flopen_lock_self },
189	{ "flopen_lock_other", test_flopen_lock_other },
190	{ "flopen_lock_child", test_flopen_lock_child },
191};
192
193int
194main(void)
195{
196	const char *result;
197	int i, nt;
198
199	nt = sizeof(t) / sizeof(*t);
200	printf("1..%d\n", nt);
201	for (i = 0; i < nt; ++i) {
202		if ((result = t[i].func()) != NULL)
203			printf("not ok %d - %s # %s\n", i + 1,
204			    t[i].name, result);
205		else
206			printf("ok %d - %s\n", i + 1,
207			    t[i].name);
208	}
209	exit(0);
210}
211