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/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 *
test_flopen_create(void)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 *
test_flopen_open(void)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 *
test_flopen_lock_self(void)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 *
test_flopen_lock_other(void)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 *
test_flopen_lock_child(void)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
main(void)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