• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * NAME
22  *	fcntl14.c
23  *
24  * DESCRIPTION
25  *	File locking test cases for fcntl. In Linux, S_ENFMT is not implemented
26  *	in the kernel. However all standard Unix kernels define S_ENFMT as
27  *	S_ISGID. So this test defines S_ENFMT as S_ISGID.
28  *
29  * ALGORITHM
30  *	Various test cases are used to lock a file opened without mandatory
31  *	locking, with mandatory locking and mandatory locking with NOBLOCK
32  *
33  * USAGE
34  *	fcntl14
35  *
36  * HISTORY
37  *	07/2001 Ported by Wayne Boyer
38  *
39  * RESTRICTIONS
40  *	None
41  */
42 #define _GNU_SOURCE 1
43 #include <fcntl.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <signal.h>
47 #include <errno.h>
48 #include <sys/wait.h>
49 #include <inttypes.h>
50 #include "test.h"
51 #include "safe_macros.h"
52 
53 #define SKIP 0x0c00
54 #if SKIP == F_RDLCK || SKIP== F_WRLCK
55 #error invalid value for SKIP, must be distinct from F_RDLCK and F_WRLCK
56 #endif
57 #ifndef S_ENFMT
58 #define S_ENFMT S_ISGID
59 #endif
60 
61 /* NOBLOCK - immediate success */
62 #define NOBLOCK 2
63 
64 /* WILLBLOCK - blocks, then succeeds (parent must unlock records) */
65 #define WILLBLOCK 3
66 
67 #define TIME_OUT 60
68 
69 typedef struct {
70 	short a_type;
71 	short a_whence;
72 	long a_start;
73 	long a_len;
74 	short b_type;		/* SKIP means suppress fcntl call */
75 	short b_whence;
76 	long b_start;
77 	long b_len;
78 	short c_type;
79 	int c_whence;
80 	long c_start;
81 	long c_len;
82 	short c_flag;
83 } testcase;
84 
85 static testcase testcases[] = {
86 	/* Test cases: entire boundary */
87 	/* #1 Parent making a write lock on entire file */
88 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
89 	 /* Child attempting a read lock on entire file */
90 	 F_RDLCK, 0, 0L, 0L, WILLBLOCK},
91 
92 	/* #2 Parent making a write lock on entire file */
93 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
94 	 /* Child attempting a write lock on entire file */
95 	 F_WRLCK, 0, 0L, 0L, WILLBLOCK},
96 
97 	/* #3 Parent making a read lock on entire file */
98 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
99 	 /* Child attempting a read lock on entire file */
100 	 F_RDLCK, 0, 0L, 0L, NOBLOCK},
101 
102 	/* #4 Parent making a read lock on entire file */
103 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
104 	 /* Child attempting a write lock on entire file */
105 	 F_WRLCK, 0, 0L, 0L, WILLBLOCK},
106 
107 	/* Test case: start boundary */
108 	/* #5 Parent making a write lock on entire file */
109 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
110 	 /*
111 	  * Child attempting a read lock from beginning of
112 	  * file for 5 bytes
113 	  */
114 	 F_RDLCK, 0, 0L, 5L, WILLBLOCK},
115 
116 	/* #6 Parent making a write lock on entire file */
117 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
118 	 /*
119 	  * Child attempting a write lock from beginning of
120 	  * file for 5 bytes
121 	  */
122 	 F_WRLCK, 0, 0L, 5L, WILLBLOCK},
123 
124 	/* #7 Parent making a read lock on entire file */
125 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
126 	 /*
127 	  * Child attempting a read lock from beginning of
128 	  * file for 5 bytes
129 	  */
130 	 F_RDLCK, 0, 0L, 5L, NOBLOCK},
131 
132 	/* #8 Parent making a read lock on entire file */
133 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
134 	 /*
135 	  * Child attempting a write lock from beginning of
136 	  * file for 5 bytes
137 	  */
138 	 F_WRLCK, 0, 0L, 5L, WILLBLOCK},
139 
140 	/* Test cases: end boundary */
141 	/* #9 Parent making a write lock on entire file */
142 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
143 	 /* Child attempting a read lock from byte 7 to end of file */
144 	 F_RDLCK, 0, 7L, 0L, WILLBLOCK},
145 
146 	/* #10 Parent making a write lock on entire file */
147 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
148 	 /* Child attempting a write lock from byte 7 to end of file */
149 	 F_WRLCK, 0, 7L, 0L, WILLBLOCK},
150 
151 	/* #11 Parent making a read lock on entire file */
152 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
153 	 /* Child attempting a read lock from byte 7 to end of file */
154 	 F_RDLCK, 0, 7L, 0L, NOBLOCK},
155 
156 	/* #12 Parent making a read lock on entire file */
157 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
158 	 /* Child attempting a write lock from byte 7 to end of file */
159 	 F_WRLCK, 0, 7L, 0L, WILLBLOCK},
160 
161 	/* Test cases: entire boundary ( less than entire file) */
162 	/*
163 	 * #13 Parent making a write lock from beginning of
164 	 * file for 5 bytes
165 	 */
166 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
167 	 /*
168 	  * Child attempting a read lock from beginning of
169 	  * file for 5 bytes
170 	  */
171 	 F_RDLCK, 0, 0L, 5L, WILLBLOCK},
172 
173 	/*
174 	 * #14 Parent making a write lock from beginning of file
175 	 * for 5 bytes
176 	 */
177 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
178 	 /*
179 	  * Child attempting a write lock from beginning of
180 	  * file for 5 bytes
181 	  */
182 	 F_WRLCK, 0, 0L, 5L, WILLBLOCK},
183 
184 	/*
185 	 * #15 Parent making a read lock from beginning of
186 	 * file for 5 bytes
187 	 */
188 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
189 	 /*
190 	  * Child attempting a read lock from beginning of
191 	  * file for 5 bytes
192 	  */
193 	 F_RDLCK, 0, 0L, 5L, NOBLOCK},
194 
195 	/*
196 	 * #16 Parent making a read lock from beginning of
197 	 * file for 5 bytes
198 	 */
199 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
200 	 /*
201 	  * Child attempting a write lock from beginning
202 	  * of file for 5 bytes
203 	  */
204 	 F_WRLCK, 0, 0L, 5L, WILLBLOCK},
205 
206 	/* Test cases: inside boundary */
207 	/*
208 	 * #17 Parent making a write lock from beginning
209 	 * of file for 5 bytes
210 	 */
211 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
212 	 /* Child attempting a read lock from byte 2 to byte 4 */
213 	 F_RDLCK, 0, 1L, 3L, WILLBLOCK},
214 
215 	/*
216 	 * #18 Parent making a write lock from beginning of
217 	 * file for 5 bytes
218 	 */
219 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
220 	 /* Child attempting a write lock from byte 2 to byte 4 */
221 	 F_WRLCK, 0, 1L, 3L, WILLBLOCK},
222 
223 	/*
224 	 * #19 Parent making a read lock from beginning of
225 	 * file for 5 bytes
226 	 */
227 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
228 	 /* Child attempting a read lock from byte 2 to byte 4 */
229 	 F_RDLCK, 0, 1L, 3L, NOBLOCK},
230 
231 	/*
232 	 * #20 Parent making a read lock from beginning of
233 	 * file for 5 bytes
234 	 */
235 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
236 	 /* Child attempting a write lock from byte 2 to byte 4 */
237 	 F_WRLCK, 0, 1L, 3L, WILLBLOCK},
238 
239 	/* Test cases: cross boundary (inside to after) */
240 	/*
241 	 * #21 Parent making a write lock from beginning of
242 	 * file for 5 bytes
243 	 */
244 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
245 	 /* Child attempting a read lock from byte 3 to byte 7 */
246 	 F_RDLCK, 0, 2L, 5L, WILLBLOCK},
247 
248 	/*
249 	 * #22 Parent making a write lock from beginning
250 	 * of file for 5 bytes
251 	 */
252 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
253 	 /* Child attempting a write lock from byte 3 to byte 7 */
254 	 F_WRLCK, 0, 2L, 5L, WILLBLOCK},
255 
256 	/*
257 	 * #23 Parent making a read lock from beginning of
258 	 * file for 5 bytes
259 	 */
260 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
261 	 /* Child attempting a read lock from byte 3 to byte 7 */
262 	 F_RDLCK, 0, 2L, 5L, NOBLOCK},
263 
264 	/*
265 	 * #24 Parent making a read lock from beginning of
266 	 * file for 5 bytes
267 	 */
268 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
269 	 /* Child attempting a write lock from byte 3 to byte 7 */
270 	 F_WRLCK, 0, 2L, 5L, WILLBLOCK},
271 
272 	/* Test cases: outside boundary (after) */
273 
274 	/*
275 	 * #25 Parent making a write lock from beginning of
276 	 * file for 5 bytes
277 	 */
278 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
279 	 /*  Child attempting a read lock from byte 7 to end of file */
280 	 F_RDLCK, 0, 6L, 0L, NOBLOCK},
281 
282 	/*
283 	 * #26 Parent making a write lock from beginning of
284 	 * file for 5 bytes
285 	 */
286 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
287 	 /* Child attempting a write lock from byte 7 to end of file */
288 	 F_WRLCK, 0, 6L, 0L, NOBLOCK},
289 
290 	/*
291 	 * #27 Parent making a read lock from beginning of
292 	 * file for 5 bytes
293 	 */
294 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
295 	 /* Child attempting a read lock from byte 7 to end of file */
296 	 F_RDLCK, 0, 6L, 0L, NOBLOCK},
297 
298 	/*
299 	 * #28 Parent making a read lock from beginning of
300 	 * file for 5 bytes
301 	 */
302 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
303 	 /* Child attempting a write lock from byte 7 to end of file */
304 	 F_WRLCK, 0, 6L, 0L, NOBLOCK},
305 
306 	/* Test cases: outside boundary (before) */
307 
308 	/* #29 Parent making a write lock from byte 3 to byte 7 */
309 	{F_WRLCK, 0, 2L, 5L, SKIP, 0, 0L, 0L,
310 	 /* Child attempting a read lock from beginning of file to byte 2 */
311 	 F_RDLCK, 0, 0L, 2L, NOBLOCK},
312 
313 	/* #30 Parent making a write lock from byte 3 to byte 7 */
314 	{F_WRLCK, 0, 2L, 5L, SKIP, 0, 0L, 0L,
315 	 /* Child attempting a write lock from beginning of file to byte 2 */
316 	 F_WRLCK, 0, 0L, 2L, NOBLOCK},
317 
318 	/* #31 Parent making a write lock from byte 3 to byte 7 */
319 	{F_RDLCK, 0, 2L, 5L, SKIP, 0, 0L, 0L,
320 	 /* Child attempting a read lock from beginning of file to byte 2 */
321 	 F_RDLCK, 0, 0L, 2L, NOBLOCK},
322 
323 	/* #32 Parent making a write lock from byte 3 to byte 7 */
324 	{F_RDLCK, 0, 2L, 5L, SKIP, 0, 0L, 0L,
325 	 /* Child attempting a write lock from beginning of file to byte 2 */
326 	 F_WRLCK, 0, 0L, 2L, NOBLOCK},
327 
328 	/* Test cases: cross boundary (before to inside) */
329 	/* #33 Parent making a write lock from byte 5 to end of file */
330 	{F_WRLCK, 0, 4L, 0L, SKIP, 0, 0L, 0L,
331 	 /* Child attempting a read lock from byte 3 to byte 7 */
332 	 F_RDLCK, 0, 2L, 5L, WILLBLOCK},
333 
334 	/* #34 Parent making a write lock from byte 5 to end of file */
335 	{F_WRLCK, 0, 4L, 0L, SKIP, 0, 0L, 0L,
336 	 /* Child attempting a write lock from byte 3 to byte 7 */
337 	 F_WRLCK, 0, 2L, 5L, WILLBLOCK},
338 
339 	/* #35 Parent making a read lock from byte 5 to end of file */
340 	{F_RDLCK, 0, 4L, 0L, SKIP, 0, 0L, 0L,
341 	 /* Child attempting a read lock from byte 3 to byte 7 */
342 	 F_RDLCK, 0, 2L, 5L, NOBLOCK},
343 
344 	/* #36 Parent making a read lock from byte 5 to end of file */
345 	{F_RDLCK, 0, 4L, 0L, SKIP, 0, 0L, 0L,
346 	 /* Child attempting a write lock from byte 3 to byte 7 */
347 	 F_WRLCK, 0, 2L, 5L, WILLBLOCK},
348 
349 	/* Start of negative L_start and L_len test cases */
350 	/*
351 	 * #37 Parent making write lock from byte 2 to byte 3
352 	 * with L_start = -3
353 	 */
354 	{F_WRLCK, 1, -3L, 2L, SKIP, 0, 0L, 0L,
355 	 /* Child attempting write lock on byte 1 */
356 	 F_WRLCK, 0, 1L, 1L, NOBLOCK},
357 
358 	/*
359 	 * #38 Parent making write lock from byte 2 to byte 3
360 	 * with L_start = -3
361 	 */
362 	{F_WRLCK, 1, -3L, 2L, SKIP, 0, 0L, 0L,
363 	 /* Child attempting write lock on byte 4 */
364 	 F_WRLCK, 0, 4L, 1L, NOBLOCK},
365 
366 	/*
367 	 * #39 Parent making write lock from byte 2 to byte 3
368 	 * with L_start = -3
369 	 */
370 	{F_WRLCK, 1, -3L, 2L, SKIP, 0, 0L, 0L,
371 	 /* Child attempting write lock on byte 2 */
372 	 F_WRLCK, 0, 2L, 1L, WILLBLOCK},
373 
374 	/*
375 	 * #40 Parent making write lock from byte 2 to byte 3
376 	 * with L_start = -3
377 	 */
378 	{F_WRLCK, 1, -3L, 2L, SKIP, 0, 0L, 0L,
379 	 /* Child attempting write lock on byte 3 */
380 	 F_WRLCK, 0, 3L, 1L, WILLBLOCK},
381 
382 	/*
383 	 * #41 Parent making write lock from byte 2 to byte 6
384 	 * with L_start = -3
385 	 */
386 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
387 	 /* Child attempting write lock on byte 1 */
388 	 F_WRLCK, 0, 1L, 1L, NOBLOCK},
389 
390 	/*
391 	 * #42 Parent making write lock from byte 2 to byte 6
392 	 * with L_start = -3
393 	 */
394 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
395 	 /* Child attempting write lock on byte 7 */
396 	 F_WRLCK, 0, 1L, 1L, NOBLOCK},
397 
398 	/*
399 	 * #43 Parent making write lock from byte 2 to byte 6
400 	 * with L_start = -3
401 	 */
402 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
403 	 /* Child attempting write lock on byte 2 */
404 	 F_WRLCK, 0, 2L, 1L, WILLBLOCK},
405 
406 	/*
407 	 * #44 Parent making write lock from byte 2 to byte 6
408 	 * with L_start = -3
409 	 */
410 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
411 	 /* Child attempting write lock on byte 5 */
412 	 F_WRLCK, 0, 5L, 1L, WILLBLOCK},
413 
414 	/*
415 	 * #45 Parent making write lock from byte 2 to byte 6
416 	 * with L_start = -3
417 	 */
418 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
419 	 /* Child attempting write lock on byte 6 */
420 	 F_WRLCK, 0, 6L, 1L, WILLBLOCK},
421 
422 	/*
423 	 * #46 Parent making write lock from byte 2 to byte 3 with
424 	 * L_start = -2 and L_len = -2
425 	 */
426 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
427 	 /* Child attempting write lock on byte 1 */
428 	 F_WRLCK, 0, 1L, 1L, NOBLOCK},
429 
430 	/*
431 	 * #47 Parent making write lock from byte 2 to byte 3 with
432 	 * L_start = -2 and L_len = -2
433 	 */
434 	{F_WRLCK, 1, -2L, -2L, SKIP, 0, 0L, 0L,
435 	 /* Child attempting write lock on byte 4 */
436 	 F_WRLCK, 0, 4L, 1L, NOBLOCK},
437 
438 	/*
439 	 * #48 Parent making write lock from byte 2 to byte 3 with
440 	 * L_start = -2 and L_len = -2
441 	 */
442 	{F_WRLCK, 1, -2L, -2L, SKIP, 0, 0L, 0L,
443 	 /* Child attempting write lock on byte 2 */
444 	 F_WRLCK, 0, 2L, 1L, WILLBLOCK},
445 
446 	/*
447 	 * #49 Parent making write lock from byte 2 to byte 3 with
448 	 * L_start = -2 and L_len = -2
449 	 */
450 	{F_WRLCK, 1, -2L, -2L, SKIP, 0, 0L, 0L,
451 	 /* Child attempting write lock on byte 3 */
452 	 F_WRLCK, 0, 3L, 1L, WILLBLOCK},
453 
454 	/*
455 	 * #50 Parent making write lock from byte 6 to byte 7 with
456 	 * L_start = 2 and L_len = -2
457 	 */
458 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
459 	 /* Child attempting write lock on byte 5 */
460 	 F_WRLCK, 0, 5L, 1L, NOBLOCK},
461 
462 	/*
463 	 * #51 Parent making write lock from byte 6 to byte 7 with
464 	 * L_start = 2 and L_len = -2
465 	 */
466 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
467 	 /* Child attempting write lock on byte 8 */
468 	 F_WRLCK, 0, 8L, 1L, NOBLOCK},
469 
470 	/*
471 	 * #52 Parent making write lock from byte 6 to byte 7 with
472 	 * L_start = 2 and L_len = -2
473 	 */
474 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
475 	 /* Child attempting write lock on byte 6 */
476 	 F_WRLCK, 0, 6L, 1L, WILLBLOCK},
477 
478 	/*
479 	 * #53 Parent making write lock from byte 6 to byte 7 with
480 	 * L_start = 2 and L_len = -2
481 	 */
482 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
483 	 /* Child attempting write lock on byte 7 */
484 	 F_WRLCK, 0, 7L, 1L, WILLBLOCK},
485 
486 	/*
487 	 * #54 Parent making write lock from byte 3 to byte 7 with
488 	 * L_start = 2 and L_len = -5
489 	 */
490 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
491 	 /* Child attempting write lock on byte 2 */
492 	 F_WRLCK, 0, 2L, 1L, NOBLOCK},
493 
494 	/*
495 	 * #55 Parent making write lock from byte 3 to byte 7 with
496 	 * L_start = 2 and L_len = -5
497 	 */
498 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
499 	 /* Child attempting write lock on byte 8 */
500 	 F_WRLCK, 0, 8L, 1L, NOBLOCK},
501 
502 	/*
503 	 * #56 Parent making write lock from byte 3 to byte 7 with
504 	 * L_start = 2 and L_len = -5
505 	 */
506 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
507 	 /* Child attempting write lock on byte 3 */
508 	 F_WRLCK, 0, 3L, 1L, WILLBLOCK},
509 
510 	/*
511 	 * #57 Parent making write lock from byte 3 to byte 7 with
512 	 * L_start = 2 and L_len = -5
513 	 */
514 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
515 	 /* Child attempting write lock on byte 5 */
516 	 F_WRLCK, 0, 5L, 1L, WILLBLOCK},
517 
518 	/*
519 	 * #58 Parent making write lock from byte 3 to byte 7 with
520 	 * L_start = 2 and L_len = -5
521 	 */
522 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
523 	 /* Child attempting write lock on byte 7 */
524 	 F_WRLCK, 0, 7L, 1L, WILLBLOCK},
525 
526 	/* Test case for block 4 */
527 	/* #59 Parent making write lock on entire file */
528 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
529 	 /* Child attempting write lock on byte 15 to end of file */
530 	 F_WRLCK, 0, 15L, 0L, WILLBLOCK},
531 };
532 
533 static testcase *thiscase;
534 static struct flock flock;
535 static int parent, child, status, fail = 0;
536 static int got1 = 0;
537 static int fd;
538 static int test;
539 static char tmpname[40];
540 
541 #define FILEDATA	"ten bytes!"
542 
543 void catch1(int sig);
544 void catch_alarm(int sig);
545 
546 char *TCID = "fcntl14";
547 int TST_TOTAL = 1;
548 int NO_NFS = 1;
549 
550 #ifdef UCLINUX
551 static char *argv0;
552 #endif
553 
cleanup(void)554 void cleanup(void)
555 {
556 	tst_rmdir();
557 }
558 
setup(void)559 void setup(void)
560 {
561 	struct sigaction act;
562 
563 	tst_sig(FORK, DEF_HANDLER, cleanup);
564 	signal(SIGHUP, SIG_IGN);
565 	umask(0);
566 	TEST_PAUSE;
567 	tst_tmpdir();
568 	parent = getpid();
569 
570 	sprintf(tmpname, "fcntl2.%d", parent);
571 
572 	/* setup signal handler for signal from child */
573 	memset(&act, 0, sizeof(act));
574 	act.sa_handler = catch1;
575 	sigemptyset(&act.sa_mask);
576 	sigaddset(&act.sa_mask, SIGUSR1);
577 	if ((sigaction(SIGUSR1, &act, NULL)) < 0) {
578 		tst_resm(TFAIL, "SIGUSR1 signal setup failed, errno = %d",
579 			 errno);
580 		cleanup();
581 	}
582 
583 	memset(&act, 0, sizeof(act));
584 	act.sa_handler = catch_alarm;
585 	sigemptyset(&act.sa_mask);
586 	sigaddset(&act.sa_mask, SIGALRM);
587 	if ((sigaction(SIGALRM, &act, NULL)) < 0) {
588 		tst_resm(TFAIL, "SIGALRM signal setup failed");
589 		cleanup();
590 	}
591 }
592 
wake_parent(void)593 void wake_parent(void)
594 {
595 	if ((kill(parent, SIGUSR1)) < 0) {
596 		tst_resm(TFAIL, "Attempt to send signal to parent " "failed");
597 		tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, errno);
598 		fail = 1;
599 	}
600 }
601 
do_usleep_child(void)602 void do_usleep_child(void)
603 {
604 	usleep(100000);		/* XXX how long is long enough? */
605 	wake_parent();
606 	exit(0);
607 }
608 
dochild(void)609 void dochild(void)
610 {
611 	int rc;
612 	pid_t pid;
613 
614 	flock.l_type = thiscase->c_type;
615 	flock.l_whence = thiscase->c_whence;
616 	flock.l_start = thiscase->c_start;
617 	flock.l_len = thiscase->c_len;
618 	flock.l_pid = 0;
619 	fail = 0;
620 
621 	/*
622 	 * Check to see if child lock will succeed. If it will, FLOCK
623 	 * structure will return with l_type changed to F_UNLCK. If it will
624 	 * not, the parent pid will be returned in l_pid and the type of
625 	 * lock that will block it in l_type.
626 	 */
627 	if ((rc = fcntl(fd, F_GETLK, &flock)) < 0) {
628 		tst_resm(TFAIL, "Attempt to check lock status failed");
629 		tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, errno);
630 		fail = 1;
631 	} else {
632 
633 		if ((thiscase->c_flag) == NOBLOCK) {
634 			if (flock.l_type != F_UNLCK) {
635 				tst_resm(TFAIL,
636 					 "Test case %d, GETLK: type = %d, "
637 					 "%d was expected", test + 1,
638 					 flock.l_type, F_UNLCK);
639 				fail = 1;
640 			}
641 
642 			if (flock.l_whence != thiscase->c_whence) {
643 				tst_resm(TFAIL,
644 					 "Test case %d, GETLK: whence = %d, "
645 					 "should have remained %d", test + 1,
646 					 flock.l_whence, thiscase->c_whence);
647 				fail = 1;
648 			}
649 
650 			if (flock.l_start != thiscase->c_start) {
651 				tst_resm(TFAIL,
652 					 "Test case %d, GETLK: start = %" PRId64
653 					 ", " "should have remained %" PRId64,
654 					 test + 1, (int64_t) flock.l_start,
655 					 (int64_t) thiscase->c_start);
656 				fail = 1;
657 			}
658 
659 			if (flock.l_len != thiscase->c_len) {
660 				tst_resm(TFAIL,
661 					 "Test case %d, GETLK: len = %" PRId64
662 					 ", " "should have remained %" PRId64,
663 					 test + 1, (int64_t) flock.l_len,
664 					 (int64_t) thiscase->c_len);
665 				fail = 1;
666 			}
667 
668 			if (flock.l_pid != 0) {
669 				tst_resm(TFAIL,
670 					 "Test case %d, GETLK: pid = %d, "
671 					 "should have remained 0", test + 1,
672 					 flock.l_pid);
673 				fail = 1;
674 			}
675 		} else {
676 			if (flock.l_pid != parent) {
677 				tst_resm(TFAIL,
678 					 "Test case %d, GETLK: pid = %d, "
679 					 "should be parent's id of %d",
680 					 test + 1, flock.l_pid, parent);
681 				fail = 1;
682 			}
683 
684 			if (flock.l_type != thiscase->a_type) {
685 				tst_resm(TFAIL,
686 					 "Test case %d, GETLK: type = %d, "
687 					 "should be parent's first lock type of %d",
688 					 test + 1, flock.l_type,
689 					 thiscase->a_type);
690 				fail = 1;
691 			}
692 		}
693 	}
694 
695 	/*
696 	 * now try to set the lock, nonblocking
697 	 * This will succeed for NOBLOCK,
698 	 * fail for WILLBLOCK
699 	 */
700 	flock.l_type = thiscase->c_type;
701 	flock.l_whence = thiscase->c_whence;
702 	flock.l_start = thiscase->c_start;
703 	flock.l_len = thiscase->c_len;
704 	flock.l_pid = 0;
705 
706 	if ((rc = fcntl(fd, F_SETLK, &flock)) < 0) {
707 		if ((thiscase->c_flag) == NOBLOCK) {
708 			tst_resm(TFAIL, "Attempt to set child NONBLOCKING "
709 				 "lock failed");
710 			tst_resm(TFAIL, "Test case %d, errno = %d",
711 				 test + 1, errno);
712 			fail = 1;
713 		}
714 	}
715 
716 	if ((thiscase->c_flag) == WILLBLOCK) {
717 		if (rc != -1 || (errno != EACCES && errno != EAGAIN)) {
718 			tst_resm(TFAIL,
719 				 "SETLK: rc = %d, errno = %d, -1/EAGAIN or EACCES "
720 				 "was expected", rc, errno);
721 			fail = 1;
722 		}
723 		if (rc == 0) {
724 			/* accidentally got the lock */
725 			/* XXX how to clean up? */
726 			(void)fcntl(fd, F_UNLCK, &flock);
727 		}
728 		/*
729 		 * Lock should succeed after blocking and parent releases
730 		 * lock, tell the parent to release the locks.
731 		 * Do the lock in this process, send the signal in a child
732 		 * process, so that the SETLKW actually uses the blocking
733 		 * mechanism in the kernel.
734 		 *
735 		 * XXX inherent race: we want to wait until the
736 		 * F_SETLKW has started, but we don't have a way to
737 		 * check that reliably in the child.  (We'd
738 		 * need some way to have fcntl() atomically unblock a
739 		 * signal and wait for the lock.)
740 		 */
741 		pid = FORK_OR_VFORK();
742 		switch (pid) {
743 		case -1:
744 			tst_resm(TFAIL, "Fork failed");
745 			fail = 1;
746 			break;
747 		case 0:
748 #ifdef UCLINUX
749 			if (self_exec(argv0, "nd", 1, parent) < 0) {
750 				tst_resm(TFAIL, "self_exec failed");
751 				break;
752 			}
753 #else
754 			do_usleep_child();
755 #endif
756 			break;
757 
758 		default:
759 			if ((rc = fcntl(fd, F_SETLKW, &flock)) < 0) {
760 				tst_resm(TFAIL, "Attempt to set child BLOCKING "
761 					 "lock failed");
762 				tst_resm(TFAIL, "Test case %d, errno = %d",
763 					 test + 1, errno);
764 				fail = 1;
765 			}
766 			waitpid(pid, &status, 0);
767 			break;
768 		}
769 	}
770 	if (fail) {
771 		exit(1);
772 	} else {
773 		exit(0);
774 	}
775 }
776 
run_test(int file_flag,int file_mode,int seek,int start,int end)777 void run_test(int file_flag, int file_mode, int seek, int start, int end)
778 {
779 	fail = 0;
780 
781 	for (test = start; test < end; test++) {
782 		fd = SAFE_OPEN(cleanup, tmpname, file_flag, file_mode);
783 
784 		if (write(fd, FILEDATA, 10) < 0)
785 			tst_brkm(TBROK, cleanup, "write() failed");
786 
787 		if (seek) {
788 			SAFE_LSEEK(cleanup, fd, seek, 0);
789 		}
790 
791 		thiscase = &testcases[test];
792 		flock.l_type = thiscase->a_type;
793 		flock.l_whence = thiscase->a_whence;
794 		flock.l_start = thiscase->a_start;
795 		flock.l_len = thiscase->a_len;
796 
797 		/* set the initial parent lock on the file */
798 		if ((fcntl(fd, F_SETLK, &flock)) < 0) {
799 			tst_resm(TFAIL, "First parent lock failed");
800 			tst_resm(TFAIL, "Test case %d, errno = %d",
801 				 test + 1, errno);
802 			fail = 1;
803 		}
804 
805 		if ((thiscase->b_type) != SKIP) {
806 			flock.l_type = thiscase->b_type;
807 			flock.l_whence = thiscase->b_whence;
808 			flock.l_start = thiscase->b_start;
809 			flock.l_len = thiscase->b_len;
810 
811 			/* set the second parent lock */
812 			if ((fcntl(fd, F_SETLK, &flock)) < 0) {
813 				tst_resm(TFAIL, "Second parent lock failed");
814 				tst_resm(TFAIL, "Test case %d, errno = %d",
815 					 test + 1, errno);
816 				fail = 1;
817 			}
818 		}
819 		if ((thiscase->c_type) == SKIP) {
820 			close(fd);
821 			tst_resm(TINFO, "skipping test %d", test + 1);
822 			continue;
823 		}
824 
825 		/* Mask SIG_USR1 before forking child, to avoid race */
826 		(void)sighold(SIGUSR1);
827 
828 		/* flush the stdout to avoid garbled output */
829 		fflush(stdout);
830 
831 		if ((child = FORK_OR_VFORK()) == 0) {
832 #ifdef UCLINUX
833 			if (self_exec(argv0, "nddddddddd", 2, thiscase->c_type,
834 				      thiscase->c_whence, thiscase->c_start,
835 				      thiscase->c_len, thiscase->c_flag,
836 				      thiscase->a_type, fd, test, parent) < 0) {
837 				tst_resm(TFAIL, "self_exec failed");
838 				cleanup();
839 			}
840 #else
841 			dochild();
842 #endif
843 		}
844 		if (child < 0)
845 			tst_brkm(TBROK|TERRNO, cleanup, "Fork failed");
846 
847 		if ((thiscase->c_flag) == WILLBLOCK) {
848 			/*
849 			 * Wait for a signal from the child then remove
850 			 * blocking lock. Set a 60 second alarm to break the
851 			 * pause just in case the child never signals us.
852 			 */
853 			alarm(TIME_OUT);
854 			sigpause(SIGUSR1);
855 
856 			/* turn off the alarm timer */
857 			alarm((unsigned)0);
858 			if (got1 != 1)
859 				tst_resm(TINFO, "Pause terminated without "
860 					 "signal SIGUSR1 from child");
861 			got1 = 0;
862 
863 			/*
864 			 * setup lock structure for parent to delete
865 			 * blocking lock then wait for child to exit
866 			 */
867 			flock.l_type = F_UNLCK;
868 			flock.l_whence = 0;
869 			flock.l_start = 0L;
870 			flock.l_len = 0L;
871 			if ((fcntl(fd, F_SETLK, &flock)) < 0) {
872 				tst_resm(TFAIL, "Attempt to release parent "
873 					 "lock failed");
874 				tst_resm(TFAIL, "Test case %d, errno = %d",
875 					 test + 1, errno);
876 				fail = 1;
877 			}
878 		}
879 		/*
880 		 * set a 60 second alarm to break the wait just in case the
881 		 * child doesn't terminate on its own accord
882 		 */
883 		alarm(TIME_OUT);
884 
885 		/* wait for the child to terminate and close the file */
886 		waitpid(child, &status, 0);
887 		/* turn off the alarm clock */
888 		alarm((unsigned)0);
889 		if (status != 0) {
890 			tst_resm(TFAIL, "tchild returned status 0x%x", status);
891 			fail = 1;
892 		}
893 		close(fd);
894 		if (fail)
895 			tst_resm(TFAIL, "testcase:%d FAILED", test + 1);
896 		else
897 			tst_resm(TPASS, "testcase:%d PASSED", test + 1);
898 	}
899 	unlink(tmpname);
900 }
901 
catch_alarm(int sig)902 void catch_alarm(int sig)
903 {
904 	/*
905 	 * Timer has runout and child has not signaled, need
906 	 * to kill off the child as it appears it will not
907 	 * on its own accord. Check that it is still around
908 	 * as it may have terminated abnormally while parent
909 	 * was waiting for SIGUSR1 signal from it.
910 	 */
911 	if (kill(child, 0) == 0) {
912 		kill(child, SIGKILL);
913 		perror("The child didnot terminate on its own accord");
914 	}
915 }
916 
catch1(int sig)917 void catch1(int sig)
918 {
919 	struct sigaction act;
920 
921 	/*
922 	 * Set flag to let parent know that child is ready to have lock
923 	 * removed
924 	 */
925 	memset(&act, 0, sizeof(act));
926 	act.sa_handler = catch1;
927 	sigemptyset(&act.sa_mask);
928 	sigaddset(&act.sa_mask, SIGUSR1);
929 	sigaction(SIGUSR1, &act, NULL);
930 	got1++;
931 }
932 
testcheck_end(int check_fail,char * msg)933 static void testcheck_end(int check_fail, char *msg)
934 {
935 	if (check_fail)
936 		tst_resm(TFAIL, "%s FAILED", msg);
937 	else
938 		tst_resm(TPASS, "%s PASSED", msg);
939 }
940 
main(int ac,char ** av)941 int main(int ac, char **av)
942 {
943 	int lc;
944 
945 	tst_parse_opts(ac, av, NULL, NULL);
946 #ifdef UCLINUX
947 	argv0 = av[0];
948 
949 	maybe_run_child(&do_usleep_child, "nd", 1, &parent);
950 	thiscase = malloc(sizeof(testcase));
951 
952 	maybe_run_child(&dochild, "nddddddddd", 2, &thiscase->c_type,
953 			&thiscase->c_whence, &thiscase->c_start,
954 			&thiscase->c_len, &thiscase->c_flag, &thiscase->a_type,
955 			&fd, &test, &parent);
956 #endif
957 
958 	setup();
959 
960 	if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC)
961 		NO_NFS = 0;
962 
963 	for (lc = 0; TEST_LOOPING(lc); lc++) {
964 		tst_count = 0;
965 
966 /* //block1: */
967 		tst_resm(TINFO, "Enter block 1: without mandatory locking");
968 		fail = 0;
969 		/*
970 		 * try various file locks on an ordinary file without
971 		 * mandatory locking
972 		 */
973 		(void)run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 0, 0, 36);
974 		testcheck_end(fail, "Block 1, test 1");
975 
976 		/* Now try with negative values for L_start and L_len */
977 		(void)run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 5, 36, 45);
978 		testcheck_end(fail, "Block 1, test 2");
979 
980 		tst_resm(TINFO, "Exit block 1");
981 
982 /* //block2: */
983 		/*
984 		 * Skip block2 if test on NFS, since NFS does not support
985 		 * mandatory locking
986 		 */
987 		tst_resm(TINFO, "Enter block 2: with mandatory locking");
988 		if (NO_NFS) {
989 			fail = 0;
990 			/*
991 			 * Try various locks on a file with mandatory
992 			 * record locking this should behave the same
993 			 * as an ordinary file
994 			 */
995 			(void)run_test(O_CREAT | O_RDWR | O_TRUNC,
996 				S_ENFMT | S_IRUSR | S_IWUSR, 0, 0, 36);
997 			testcheck_end(fail, "Block 2, test 1");
998 
999 			/* Now try negative values for L_start and L_len */
1000 			(void)run_test(O_CREAT | O_RDWR | O_TRUNC,
1001 				S_ENFMT | S_IRUSR | S_IWUSR, 5, 36, 45);
1002 			testcheck_end(fail, "Block 2, test 2");
1003 		} else {
1004 			tst_resm(TCONF, "Skip block 2 as NFS does not"
1005 				" support mandatory locking");
1006 		}
1007 
1008 		tst_resm(TINFO, "Exit block 2");
1009 
1010 /* //block3: */
1011 		tst_resm(TINFO, "Enter block 3");
1012 		fail = 0;
1013 		/*
1014 		 * Check that proper error status is returned when invalid
1015 		 * argument used for WHENCE (negative value)
1016 		 */
1017 
1018 		fd = SAFE_OPEN(cleanup, tmpname, O_CREAT | O_RDWR | O_TRUNC,
1019 			       0777);
1020 
1021 		if (write(fd, FILEDATA, 10) < 0)
1022 			tst_brkm(TBROK, cleanup, "write failed");
1023 
1024 		flock.l_type = F_WRLCK;
1025 		flock.l_whence = -1;
1026 		flock.l_start = 0L;
1027 		flock.l_len = 0L;
1028 
1029 		if ((fcntl(fd, F_SETLK, &flock)) < 0) {
1030 			if (errno != EINVAL) {
1031 				tst_resm(TFAIL, "Expected %d got %d",
1032 					 EINVAL, errno);
1033 				fail = 1;
1034 			}
1035 		} else {
1036 			tst_resm(TFAIL, "Lock succeeded when it should have "
1037 				 "failed");
1038 			fail = 1;
1039 		}
1040 
1041 		close(fd);
1042 		unlink(tmpname);
1043 
1044 		testcheck_end(fail, "Test with negative whence locking");
1045 		tst_resm(TINFO, "Exit block 3");
1046 
1047 /* //block4: */
1048 		tst_resm(TINFO, "Enter block 4");
1049 		fail = 0;
1050 		/*
1051 		 * Check that a lock on end of file is still valid when
1052 		 * additional data is appended to end of file and a new
1053 		 * process attempts to lock new data
1054 		 */
1055 		fd = SAFE_OPEN(cleanup, tmpname, O_CREAT | O_RDWR | O_TRUNC,
1056 			       0777);
1057 
1058 		if (write(fd, FILEDATA, 10) < 0)
1059 			tst_brkm(TBROK, cleanup, "write failed");
1060 
1061 		thiscase = &testcases[58];
1062 		flock.l_type = thiscase->a_type;
1063 		flock.l_whence = thiscase->a_whence;
1064 		flock.l_start = thiscase->a_start;
1065 		flock.l_len = thiscase->a_len;
1066 
1067 		/* Set the initial parent lock on the file */
1068 		if ((fcntl(fd, F_SETLK, &flock)) < 0) {
1069 			tst_resm(TFAIL, "First parent lock failed");
1070 			tst_resm(TFAIL, "Test case %d, errno = %d", 58, errno);
1071 			fail = 1;
1072 		}
1073 
1074 		/* Write some additional data to end of file */
1075 		if (write(fd, FILEDATA, 10) < 0)
1076 			tst_brkm(TBROK, cleanup, "write failed");
1077 
1078 		/* Mask signal to avoid race */
1079 		if (sighold(SIGUSR1) < 0)
1080 			tst_brkm(TBROK, cleanup, "sighold failed");
1081 
1082 		if ((child = FORK_OR_VFORK()) == 0) {
1083 #ifdef UCLINUX
1084 			if (self_exec(argv0, "nddddddddd", 2, thiscase->c_type,
1085 				      thiscase->c_whence, thiscase->c_start,
1086 				      thiscase->c_len, thiscase->c_flag,
1087 				      thiscase->a_type, fd, test, parent) < 0) {
1088 				tst_resm(TFAIL, "self_exec failed");
1089 				cleanup();
1090 			}
1091 #else
1092 			dochild();
1093 #endif
1094 		}
1095 		if (child < 0)
1096 			tst_brkm(TBROK|TERRNO, cleanup, "Fork failed");
1097 
1098 		/*
1099 		 * Wait for a signal from the child then remove blocking lock.
1100 		 * Set a 60 sec alarm to break the pause just in case the
1101 		 * child doesn't terminate on its own accord
1102 		 */
1103 		(void)alarm(TIME_OUT);
1104 
1105 		(void)sigpause(SIGUSR1);
1106 
1107 		/* turn off the alarm timer */
1108 		(void)alarm((unsigned)0);
1109 		if (got1 != 1) {
1110 			tst_resm(TINFO, "Pause terminated without signal "
1111 				 "SIGUSR1 from child");
1112 		}
1113 		got1 = 0;
1114 
1115 		/*
1116 		 * Set up lock structure for parent to delete
1117 		 * blocking lock then wait for child to exit
1118 		 */
1119 		flock.l_type = F_UNLCK;
1120 		flock.l_whence = 0;
1121 		flock.l_start = 0L;
1122 		flock.l_len = 0L;
1123 		if ((fcntl(fd, F_SETLK, &flock)) < 0) {
1124 			tst_resm(TFAIL, "Attempt to release parent lock "
1125 				 "failed");
1126 			tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
1127 				 errno);
1128 			fail = 1;
1129 		}
1130 
1131 		/*
1132 		 * set a 60 sec alarm to break the wait just in case the
1133 		 * child doesn't terminate on its own accord
1134 		 */
1135 		(void)alarm(TIME_OUT);
1136 
1137 		waitpid(child, &status, 0);
1138 		if (WEXITSTATUS(status) != 0) {
1139 			fail = 1;
1140 			tst_resm(TFAIL, "child returned bad exit status");
1141 		}
1142 
1143 		/* turn off the alarm clock */
1144 		(void)alarm((unsigned)0);
1145 		if (status != 0) {
1146 			tst_resm(TFAIL, "child returned status 0x%x", status);
1147 			fail = 1;
1148 		}
1149 		close(fd);
1150 		unlink(tmpname);
1151 
1152 		testcheck_end(fail, "Test of locks on file");
1153 		tst_resm(TINFO, "Exit block 4");
1154 	}
1155 	cleanup();
1156 	tst_exit();
1157 }
1158