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 * fcntl11.c
23 *
24 * DESCRIPTION
25 * Testcase to check locking of regions of a file
26 *
27 * ALGORITHM
28 * Test changing lock sections around a write lock
29 *
30 * USAGE
31 * fcntl11
32 *
33 * HISTORY
34 * 07/2001 Ported by Wayne Boyer
35 *
36 * RESTRICTIONS
37 * None
38 */
39
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <signal.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/wait.h>
46 #include <inttypes.h>
47 #include "test.h"
48 #include "safe_macros.h"
49
50 #define STRINGSIZE 27
51 #define STRING "abcdefghijklmnopqrstuvwxyz\n"
52 #define STOP 0xFFF0
53
54 int parent_pipe[2];
55 int child_pipe[2];
56 int fd;
57 pid_t parent_pid, child_pid;
58
59 void parent_put();
60 void parent_get();
61 void child_put();
62 void child_get();
63 void stop_child();
64 void compare_lock(struct flock *, short, short, int, int, pid_t);
65 void unlock_file();
66 void do_test(struct flock *, short, short, int, int);
67 void catch_child();
68 char *str_type();
69 int do_lock(int, short, short, int, int);
70
71 char *TCID = "fcntl11";
72 int TST_TOTAL = 1;
73
74 int fail;
75
cleanup(void)76 void cleanup(void)
77 {
78 tst_rmdir();
79
80 }
81
setup(void)82 void setup(void)
83 {
84 char *buf = STRING;
85 char template[PATH_MAX];
86 struct sigaction act;
87
88 tst_sig(FORK, DEF_HANDLER, cleanup);
89 tst_tmpdir();
90
91 umask(0);
92
93 TEST_PAUSE;
94
95 SAFE_PIPE(cleanup, parent_pipe);
96 SAFE_PIPE(cleanup, child_pipe);
97 parent_pid = getpid();
98 snprintf(template, PATH_MAX, "fcntl11XXXXXX");
99
100 if ((fd = mkstemp(template)) < 0)
101 tst_resm(TFAIL, "Couldn't open temp file! errno = %d", errno);
102
103 SAFE_WRITE(cleanup, 0, fd, buf, STRINGSIZE);
104
105 memset(&act, 0, sizeof(act));
106 act.sa_handler = catch_child;
107 sigemptyset(&act.sa_mask);
108 sigaddset(&act.sa_mask, SIGCHLD);
109 if ((sigaction(SIGCHLD, &act, NULL)) < 0)
110 tst_brkm(TBROK | TERRNO, cleanup,
111 "sigaction(SIGCHLD, ..) failed");
112 }
113
do_child(void)114 void do_child(void)
115 {
116 struct flock fl;
117
118 close(parent_pipe[1]);
119 close(child_pipe[0]);
120 while (1) {
121 child_get(&fl);
122 if (fcntl(fd, F_GETLK, &fl) < 0)
123 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
124 child_put(&fl);
125 }
126 }
127
do_lock(int cmd,short type,short whence,int start,int len)128 int do_lock(int cmd, short type, short whence, int start, int len)
129 {
130 struct flock fl;
131
132 fl.l_type = type;
133 fl.l_whence = whence;
134 fl.l_start = start;
135 fl.l_len = len;
136 return (fcntl(fd, cmd, &fl));
137 }
138
do_test(struct flock * fl,short type,short whence,int start,int len)139 void do_test(struct flock *fl, short type, short whence, int start, int len)
140 {
141 fl->l_type = type;
142 fl->l_whence = whence;
143 fl->l_start = start;
144 fl->l_len = len;
145 fl->l_pid = (short)0;
146
147 parent_put(fl);
148 parent_get(fl);
149 }
150
151 void
compare_lock(struct flock * fl,short type,short whence,int start,int len,pid_t pid)152 compare_lock(struct flock *fl, short type, short whence, int start, int len,
153 pid_t pid)
154 {
155 if (fl->l_type != type)
156 tst_resm(TFAIL, "lock type is wrong should be %s is %s",
157 str_type(type), str_type(fl->l_type));
158
159 if (fl->l_whence != whence)
160 tst_resm(TFAIL, "lock whence is wrong should be %d is %d",
161 whence, fl->l_whence);
162
163 if (fl->l_start != start)
164 tst_resm(TFAIL, "region starts in wrong place, should be "
165 "%d is %" PRId64, start, (int64_t) fl->l_start);
166
167 if (fl->l_len != len)
168 tst_resm(TFAIL,
169 "region length is wrong, should be %d is %" PRId64,
170 len, (int64_t) fl->l_len);
171
172 if (fl->l_pid != pid)
173 tst_resm(TFAIL, "locking pid is wrong, should be %d is %d",
174 pid, fl->l_pid);
175 }
176
unlock_file(void)177 void unlock_file(void)
178 {
179 struct flock fl;
180
181 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 0, 0) < 0)
182 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
183 do_test(&fl, F_WRLCK, 0, 0, 0);
184 compare_lock(&fl, (short)F_UNLCK, (short)0, 0, 0, (pid_t) 0);
185 }
186
str_type(int type)187 char *str_type(int type)
188 {
189 static char buf[20];
190
191 switch (type) {
192 case 0:
193 return ("F_RDLCK");
194 case 1:
195 return ("F_WRLCK");
196 case 2:
197 return ("F_UNLCK");
198 default:
199 sprintf(buf, "BAD VALUE: %d", type);
200 return (buf);
201 }
202 }
203
parent_put(struct flock * l)204 void parent_put(struct flock *l)
205 {
206 SAFE_WRITE(cleanup, 1, parent_pipe[1], l, sizeof(*l));
207 }
208
parent_get(struct flock * l)209 void parent_get(struct flock *l)
210 {
211 SAFE_READ(cleanup, 1, child_pipe[0], l, sizeof(*l));
212 }
213
child_put(struct flock * l)214 void child_put(struct flock *l)
215 {
216 SAFE_WRITE(NULL, 1, child_pipe[1], l, sizeof(*l));
217 }
218
child_get(struct flock * l)219 void child_get(struct flock *l)
220 {
221 SAFE_READ(NULL, 1, parent_pipe[0], l, sizeof(*l));
222 if (l->l_type == (short)STOP)
223 exit(0);
224 }
225
stop_child(void)226 void stop_child(void)
227 {
228 struct flock fl;
229
230 signal(SIGCHLD, SIG_DFL);
231 fl.l_type = STOP;
232 parent_put(&fl);
233 wait(0);
234 }
235
catch_child(void)236 void catch_child(void)
237 {
238 tst_brkm(TFAIL, cleanup, "Unexpected death of child process");
239 }
240
main(int ac,char ** av)241 int main(int ac, char **av)
242 {
243 struct flock tl;
244
245 int lc;
246
247 tst_parse_opts(ac, av, NULL, NULL);
248 #ifdef UCLINUX
249 maybe_run_child(&do_child, "ddddd", &parent_pipe[0],
250 &parent_pipe[1], &child_pipe[0], &child_pipe[1], &fd);
251 #endif
252
253 setup(); /* global setup */
254
255 /* Check for looping state if -i option is given */
256 for (lc = 0; TEST_LOOPING(lc); lc++) {
257 /* reset tst_count in case we are looping */
258 tst_count = 0;
259
260 if ((child_pid = FORK_OR_VFORK()) == 0) { /* parent */
261 #ifdef UCLINUX
262 if (self_exec(av[0], "ddddd", parent_pipe[0],
263 parent_pipe[1], child_pipe[0],
264 child_pipe[1], fd) < 0)
265 tst_brkm(TBROK | TERRNO, cleanup,
266 "self_exec failed");
267 #else
268 do_child();
269 #endif
270 } else if (child_pid == -1)
271 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
272
273 SAFE_CLOSE(cleanup, parent_pipe[0]);
274 SAFE_CLOSE(cleanup, child_pipe[1]);
275
276 /* //block1: */
277 tst_resm(TINFO, "Enter block 1");
278
279 /*
280 * Add a write lock to the middle of the file and a read
281 * at the begining
282 */
283 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
284 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
285
286 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 1, 5) < 0)
287 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
288
289 /*
290 * Test read lock
291 */
292 do_test(&tl, F_WRLCK, 0, 0, 0);
293 compare_lock(&tl, (short)F_RDLCK, (short)0, 1, 5, parent_pid);
294
295 /*
296 * Test write lock
297 */
298 do_test(&tl, F_WRLCK, 0, 6, 0);
299 compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 5, parent_pid);
300
301 /*
302 * Test that the rest of the file is unlocked
303 */
304 do_test(&tl, F_WRLCK, 0, 15, 0);
305 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
306
307 /*
308 * remove all the locks set above
309 */
310 unlock_file();
311
312 tst_resm(TINFO, "Exit block 1");
313
314 /* //block2: */
315 tst_resm(TINFO, "Enter block 2");
316
317 /*
318 * Set a write lock at the middle of the file and a
319 * read lock just before
320 */
321 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
322 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
323
324 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 5, 5) < 0)
325 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
326
327 /*
328 * Test the read lock
329 */
330 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
331 compare_lock(&tl, (short)F_RDLCK, (short)0, 5, 5, parent_pid);
332
333 /*
334 * Test the write lock.
335 */
336 do_test(&tl, (short)F_WRLCK, (short)0, 10, 0);
337 compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 5, parent_pid);
338
339 /*
340 * Test to make sure the rest of the file is unlocked.
341 */
342 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
343 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
344
345 /*
346 * remove all the locks set above
347 */
348 unlock_file();
349
350 tst_resm(TINFO, "Exit block 2");
351
352 /* //block3: */
353 tst_resm(TINFO, "Enter block 3");
354
355 /*
356 * Set a write lock in the middle and a read lock that
357 * ends at the first byte of the write lock
358 */
359 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
360 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
361
362 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 5, 6) < 0)
363 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
364
365 /*
366 * Test read lock
367 */
368 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
369 compare_lock(&tl, (short)F_RDLCK, (short)0, 5, 6, parent_pid);
370
371 /*
372 * Test write lock
373 */
374 do_test(&tl, (short)F_WRLCK, (short)0, 11, 0);
375 compare_lock(&tl, (short)F_WRLCK, (short)0, 11, 4, parent_pid);
376
377 /*
378 * Test to make sure the rest of the file is unlocked.
379 */
380 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
381 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
382
383 /*
384 * remove all the locks set above
385 */
386 unlock_file();
387
388 tst_resm(TINFO, "Exit block 3");
389
390 /* //block4: */
391 tst_resm(TINFO, "Enter block 4");
392
393 /*
394 * Set a write lock on the middle of the file and a read
395 * lock that overlaps the front of the write.
396 */
397 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
398 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
399
400 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 5, 8) < 0)
401 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
402
403 /*
404 * Test the read lock
405 */
406 do_test(&tl, (short)F_WRLCK, (short)0, 5, 0);
407 compare_lock(&tl, (short)F_RDLCK, (short)0, 5, 8, parent_pid);
408
409 /*
410 * Test the write lock
411 */
412 do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
413 compare_lock(&tl, (short)F_WRLCK, (short)0, 13, 2, parent_pid);
414
415 /*
416 * Test to make sure the rest of the file is unlocked.
417 */
418 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
419 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
420
421 /*
422 * remove all the locks set above
423 */
424 unlock_file();
425
426 tst_resm(TINFO, "Exit block 4");
427
428 /* //block5: */
429 tst_resm(TINFO, "Enter block 5");
430
431 /*
432 * Set a write lock in the middle of a file and a read
433 * lock in the middle of it
434 */
435 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 10) < 0)
436 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
437
438 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 13, 5) < 0)
439 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
440
441 /*
442 * Test the first write lock
443 */
444 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
445 compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 3, parent_pid);
446
447 /*
448 * Test the read lock
449 */
450 do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
451 compare_lock(&tl, (short)F_RDLCK, (short)0, 13, 5, parent_pid);
452
453 /*
454 * Test the second write lock
455 */
456 do_test(&tl, (short)F_WRLCK, (short)0, 18, 0);
457 compare_lock(&tl, (short)F_WRLCK, (short)0, 18, 2, parent_pid);
458
459 /*
460 * Test to make sure the rest of the file is unlocked
461 */
462 do_test(&tl, (short)F_WRLCK, (short)0, 20, 0);
463 compare_lock(&tl, (short)F_UNLCK, (short)0, 20, 0, 0);
464
465 /*
466 * remove all the locks set above.
467 */
468 unlock_file();
469 tst_resm(TINFO, "Exit block 5");
470
471 /* //block6: */
472 tst_resm(TINFO, "Enter block 6");
473 /*
474 * Set a write lock in the middle of the file and a read
475 * lock that overlaps the end
476 */
477 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
478 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
479
480 /*
481 * Set a read lock on the whole file
482 */
483 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 13, 5) < 0)
484 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
485
486 /*
487 * Test the write lock
488 */
489 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
490 compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 3, parent_pid);
491
492 /*
493 * Test the read lock
494 */
495 do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
496 compare_lock(&tl, (short)F_RDLCK, (short)0, 13, 5, parent_pid);
497
498 /*
499 * Test to make sure the rest of the file is unlocked
500 */
501 do_test(&tl, (short)F_WRLCK, (short)0, 18, 0);
502 compare_lock(&tl, (short)F_UNLCK, (short)0, 18, 0, 0);
503
504 /*
505 * remove all the locks set above
506 */
507 unlock_file();
508
509 tst_resm(TINFO, "Exit block 6");
510
511 /* //block7: */
512 tst_resm(TINFO, "Enter block 7");
513
514 /*
515 * Set a write lock in the middle of the file and a read
516 * lock starting at the last byte of the write lock
517 */
518 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
519 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
520
521 /*
522 * Set a read lock on the whole file.
523 */
524 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 14, 5) < 0)
525 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
526
527 /*
528 * Test write lock
529 */
530 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
531 compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 4, parent_pid);
532
533 /*
534 * Test the read lock
535 */
536 do_test(&tl, (short)F_WRLCK, (short)0, 14, 0);
537 compare_lock(&tl, (short)F_RDLCK, (short)0, 14, 5, parent_pid);
538
539 /*
540 * Test to make sure the end of the file is unlocked
541 */
542 do_test(&tl, (short)F_WRLCK, (short)0, 19, 0);
543 compare_lock(&tl, (short)F_UNLCK, (short)0, 19, 0, 0);
544
545 /*
546 * remove all the locks set above
547 */
548 unlock_file();
549
550 tst_resm(TINFO, "Exit block 7");
551
552 /* //block8: */
553 tst_resm(TINFO, "Enter block 8");
554
555 /*
556 * Set a write lock in the middle of the file and a read
557 * lock that starts just after the last byte of the
558 * write lock.
559 */
560 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
561 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
562
563 /*
564 * Set a read lock on the whole file
565 */
566 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 15, 5) < 0)
567 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
568
569 /*
570 * Test the write lock
571 */
572 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
573 compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 5, parent_pid);
574
575 /*
576 * Test the read lock
577 */
578 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
579 compare_lock(&tl, (short)F_RDLCK, (short)0, 15, 5, parent_pid);
580
581 /*
582 * Test to make sure the rest of the file is unlocked
583 */
584 do_test(&tl, (short)F_WRLCK, (short)0, 20, 0);
585 compare_lock(&tl, (short)F_UNLCK, (short)0, 20, 0, 0);
586
587 /*
588 * remove all the locks set above
589 */
590 unlock_file();
591
592 tst_resm(TINFO, "Exit block 8");
593
594 /* //block9: */
595 tst_resm(TINFO, "Enter block 9");
596
597 /*
598 * Set a write lock at the middle of the file and a read
599 * lock that starts past the end of the write lock.
600 */
601 if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
602 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
603
604 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 16, 5) < 0)
605 tst_resm(TFAIL | TERRNO, "fcntl on file failed");
606
607 /*
608 * Test the write lock
609 */
610 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
611 compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 5, parent_pid);
612
613 /*
614 * Test that byte in between is unlocked
615 */
616 do_test(&tl, (short)F_WRLCK, (short)0, 15, 1);
617 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 1, 0);
618
619 /*
620 * Test the read lock
621 */
622 do_test(&tl, (short)F_WRLCK, (short)0, 16, 0);
623 compare_lock(&tl, (short)F_RDLCK, (short)0, 16, 5, parent_pid);
624
625 /*
626 * Test to make sure the rest of the file is unlocked
627 */
628 do_test(&tl, (short)F_WRLCK, (short)0, 21, 0);
629 compare_lock(&tl, (short)F_UNLCK, (short)0, 21, 0, 0);
630
631 /*
632 * remove all the locks set above
633 */
634 unlock_file();
635
636 tst_resm(TINFO, "Exit block 9");
637
638 stop_child();
639 SAFE_CLOSE(cleanup, fd);
640 }
641 cleanup();
642 tst_exit();
643 }
644