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