xref: /freebsd/lib/libutil/tests/flopen_test.c (revision 1d386b48)
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 #include <sys/types.h>
30 #include <sys/fcntl.h>
31 
32 #include <errno.h>
33 #include <signal.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 
40 #include <libutil.h>
41 
42 /*
43  * Test that flopen() can create a file.
44  */
45 const char *
46 test_flopen_create(void)
47 {
48 	const char *fn = "test_flopen_create";
49 	const char *result = NULL;
50 	int fd;
51 
52 	unlink(fn);
53 	fd = flopen(fn, O_RDWR|O_CREAT, 0640);
54 	if (fd < 0) {
55 		result = strerror(errno);
56 	} else {
57 		close(fd);
58 	}
59 	unlink(fn);
60 	return (result);
61 }
62 
63 /*
64  * Test that flopen() can open an existing file.
65  */
66 const char *
67 test_flopen_open(void)
68 {
69 	const char *fn = "test_flopen_open";
70 	const char *result = NULL;
71 	int fd;
72 
73 	fd = open(fn, O_RDWR|O_CREAT, 0640);
74 	if (fd < 0) {
75 		result = strerror(errno);
76 	} else {
77 		close(fd);
78 		fd = flopen(fn, O_RDWR);
79 		if (fd < 0) {
80 			result = strerror(errno);
81 		} else {
82 			close(fd);
83 		}
84 	}
85 	unlink(fn);
86 	return (result);
87 }
88 
89 /*
90  * Test that flopen() can lock against itself
91  */
92 const char *
93 test_flopen_lock_self(void)
94 {
95 	const char *fn = "test_flopen_lock_self";
96 	const char *result = NULL;
97 	int fd1, fd2;
98 
99 	unlink(fn);
100 	fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
101 	if (fd1 < 0) {
102 		result = strerror(errno);
103 	} else {
104 		fd2 = flopen(fn, O_RDWR|O_NONBLOCK);
105 		if (fd2 >= 0) {
106 			result = "second open succeeded";
107 			close(fd2);
108 		}
109 		close(fd1);
110 	}
111 	unlink(fn);
112 	return (result);
113 }
114 
115 /*
116  * Test that flopen() can lock against other processes
117  */
118 const char *
119 test_flopen_lock_other(void)
120 {
121 	const char *fn = "test_flopen_lock_other";
122 	const char *result = NULL;
123 	volatile int fd1, fd2;
124 
125 	unlink(fn);
126 	fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
127 	if (fd1 < 0) {
128 		result = strerror(errno);
129 	} else {
130 		fd2 = -42;
131 		if (vfork() == 0) {
132 			fd2 = flopen(fn, O_RDWR|O_NONBLOCK);
133 			close(fd2);
134 			_exit(0);
135 		}
136 		if (fd2 == -42)
137 			result = "vfork() doesn't work as expected";
138 		if (fd2 >= 0)
139 			result = "second open succeeded";
140 		close(fd1);
141 	}
142 	unlink(fn);
143 	return (result);
144 }
145 
146 /*
147  * Test that child processes inherit the lock
148  */
149 const char *
150 test_flopen_lock_child(void)
151 {
152 	const char *fn = "test_flopen_lock_child";
153 	const char *result = NULL;
154 	pid_t pid;
155 	volatile int fd1, fd2;
156 
157 	unlink(fn);
158 	fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
159 	if (fd1 < 0) {
160 		result = strerror(errno);
161 	} else {
162 		pid = fork();
163 		if (pid == -1) {
164 			result = strerror(errno);
165 		} else if (pid == 0) {
166 			select(0, 0, 0, 0, 0);
167 			_exit(0);
168 		}
169 		close(fd1);
170 		if ((fd2 = flopen(fn, O_RDWR|O_NONBLOCK)) != -1) {
171 			result = "second open succeeded";
172 			close(fd2);
173 		}
174 		kill(pid, SIGINT);
175 	}
176 	unlink(fn);
177 	return (result);
178 }
179 
180 static struct test {
181 	const char *name;
182 	const char *(*func)(void);
183 } t[] = {
184 	{ "flopen_create", test_flopen_create },
185 	{ "flopen_open", test_flopen_open },
186 	{ "flopen_lock_self", test_flopen_lock_self },
187 	{ "flopen_lock_other", test_flopen_lock_other },
188 	{ "flopen_lock_child", test_flopen_lock_child },
189 };
190 
191 int
192 main(void)
193 {
194 	const char *result;
195 	int i, nt;
196 
197 	nt = sizeof(t) / sizeof(*t);
198 	printf("1..%d\n", nt);
199 	for (i = 0; i < nt; ++i) {
200 		if ((result = t[i].func()) != NULL)
201 			printf("not ok %d - %s # %s\n", i + 1,
202 			    t[i].name, result);
203 		else
204 			printf("ok %d - %s\n", i + 1,
205 			    t[i].name);
206 	}
207 	exit(0);
208 }
209