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