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