blob: 4ec679c11e00dc9544a86de278d3590b37ac21eb [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * NAME
nstrazfa31d552002-05-14 16:50:06 +000022 * fcntl20.c
plars865695b2001-08-27 22:15:12 +000023 *
24 * DESCRIPTION
25 * Check locking of regions of a file
26 *
27 * ALGORITHM
28 * Test unlocking sections around a read lock
29 *
30 * USAGE
nstrazfa31d552002-05-14 16:50:06 +000031 * fcntl20
plars865695b2001-08-27 22:15:12 +000032 *
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>
robbiew5aab8a72003-03-26 18:05:30 +000043#include <sys/stat.h>
44#include <sys/types.h>
mridgedb639212005-01-04 21:04:11 +000045#include <sys/wait.h>
robbiew5aab8a72003-03-26 18:05:30 +000046#include "test.h"
47#include "usctest.h"
plars865695b2001-08-27 22:15:12 +000048
49#define STRINGSIZE 27
50#define STRING "abcdefghijklmnopqrstuvwxyz\n"
51#define STOP 0xFFF0
52
53int parent_pipe[2];
54int child_pipe[2];
55int fd;
plarsa1e518d2002-09-09 18:23:52 +000056pid_t parent_pid, child_pid;
plars865695b2001-08-27 22:15:12 +000057
58void parent_put();
59void parent_get();
60void child_put();
61void child_get();
62void stop_child();
plarsa1e518d2002-09-09 18:23:52 +000063void compare_lock(struct flock *, short, short, int, int, pid_t);
plars865695b2001-08-27 22:15:12 +000064void unlock_file();
65void do_test(struct flock *, short, short, int, int);
66void catch_child();
67char *str_type();
68int do_lock(int, short, short, int, int);
69
nstrazfa31d552002-05-14 16:50:06 +000070char *TCID = "fcntl20";
plars865695b2001-08-27 22:15:12 +000071int TST_TOTAL = 1;
72extern int Tst_count;
73
74void setup(void);
75void cleanup(void);
76
77int fail = 0;
78
plars865695b2001-08-27 22:15:12 +000079
80/*
81 * setup
82 * performs all ONE TIME setup for this test
83 */
84void
85setup()
86{
87 char *buf = STRING;
robbiewdad22712003-04-16 19:14:05 +000088 char template[PATH_MAX];
robbiew1e4cf0c2005-02-24 17:03:42 +000089 struct sigaction act;
plars865695b2001-08-27 22:15:12 +000090
91 /* capture signals */
92 tst_sig(FORK, DEF_HANDLER, cleanup);
93
94 umask(0);
95
96 /* Pause if that option was specified */
97 TEST_PAUSE;
98
99 pipe(parent_pipe);
100 pipe(child_pipe);
101 parent_pid = getpid();
robbiew54f7a712003-04-16 19:20:30 +0000102
103 tst_tmpdir();
robbiewdad22712003-04-16 19:14:05 +0000104 snprintf(template, PATH_MAX, "fcntl20XXXXXX");
plars865695b2001-08-27 22:15:12 +0000105
robbiewdad22712003-04-16 19:14:05 +0000106 if ((fd = mkstemp(template)) < 0) {
107 tst_resm(TFAIL, "Couldn't open temp file! errno = %d", errno);
108 }
plars865695b2001-08-27 22:15:12 +0000109
robbiewdad22712003-04-16 19:14:05 +0000110 if (write(fd, buf, STRINGSIZE) < 0) {
111 tst_resm(TFAIL, "Couldn't write to temp file! errno = %d", errno);
112 }
plars865695b2001-08-27 22:15:12 +0000113
robbiew1e4cf0c2005-02-24 17:03:42 +0000114 memset(&act, 0, sizeof(act));
115 act.sa_handler = catch_child;
116 sigemptyset(&act.sa_mask);
117 sigaddset(&act.sa_mask, SIGCLD);
118 if ((sigaction(SIGCLD, &act, NULL)) < 0) {
plars865695b2001-08-27 22:15:12 +0000119 tst_resm(TFAIL, "SIGCLD signal setup failed, errno: %d",
120 errno);
121 fail = 1;
122 }
123}
124
125/*
126 * cleanup()
127 * performs all ONE TIME cleanup for this test at completion or
128 * premature exit
129 */
130void
131cleanup()
132{
133 /*
134 * print timing stats if that option was specified
135 * print errno log if that option was specified
136 */
137 TEST_CLEANUP;
138
robbiew54f7a712003-04-16 19:20:30 +0000139 tst_rmdir();
plars865695b2001-08-27 22:15:12 +0000140 /* exit with return code appropriate for results */
141 tst_exit();
142}
143
robbiew5aab8a72003-03-26 18:05:30 +0000144void do_child()
plars865695b2001-08-27 22:15:12 +0000145{
146 struct flock fl;
147
148 close(parent_pipe[1]);
149 close(child_pipe[0]);
150 while(1) {
151 child_get(&fl);
152 if (fcntl(fd, F_GETLK, &fl) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000153 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
154 errno);
plars865695b2001-08-27 22:15:12 +0000155 fail = 1;
156 }
157 child_put(&fl);
158 }
159}
160
robbiew5aab8a72003-03-26 18:05:30 +0000161int do_lock(int cmd, short type, short whence, int start, int len)
plars865695b2001-08-27 22:15:12 +0000162{
163 struct flock fl;
164
165 fl.l_type = type;
166 fl.l_whence = whence;
167 fl.l_start = start;
168 fl.l_len = len;
169 return(fcntl(fd, cmd, &fl));
170}
171
172void
173do_test(struct flock *fl, short type, short whence, int start, int len)
174{
175 fl->l_type = type;
176 fl->l_whence = whence;
177 fl->l_start = start;
178 fl->l_len = len;
179 fl->l_pid = (short)0;
180
181 parent_put(fl);
182 parent_get(fl);
183}
184
185void
186compare_lock(struct flock *fl, short type, short whence, int start, int len,
plarsa1e518d2002-09-09 18:23:52 +0000187 pid_t pid)
plars865695b2001-08-27 22:15:12 +0000188{
189 if (fl->l_type != type) {
190 tst_resm(TFAIL, "lock type is wrong should be %s is %s",
191 str_type(type), str_type(fl->l_type));
192 fail = 1;
193 }
194
195 if (fl->l_whence != whence) {
196 tst_resm(TFAIL, "lock whence is wrong should be %d is %d",
197 whence, fl->l_whence);
198 fail = 1;
199 }
200
201 if (fl->l_start != start) {
202 tst_resm(TFAIL, "region starts in wrong place, should be"
203 "%d is %d", start, fl->l_start);
204 fail = 1;
205 }
206
207 if (fl->l_len != len) {
208 tst_resm(TFAIL, "region length is wrong, should be %d is %d",
209 len, fl->l_len);
210 fail = 1;
211 }
212
213 if (fl->l_pid != pid) {
214 tst_resm(TFAIL, "locking pid is wrong, should be %d is %d",
215 pid, fl->l_pid);
216 fail = 1;
217 }
218}
219
220void
221unlock_file()
222{
223 struct flock fl;
224
225 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 0, 0) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000226 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
plars865695b2001-08-27 22:15:12 +0000227 errno);
228 fail = 1;
229 }
230 do_test(&fl, F_WRLCK, 0, 0, 0);
plarsa1e518d2002-09-09 18:23:52 +0000231 compare_lock(&fl, (short)F_UNLCK, (short)0, 0, 0, (pid_t)0);
plars865695b2001-08-27 22:15:12 +0000232}
233
234char *
235str_type(int type)
236{
237 static char buf[20];
238
239 switch (type) {
240 case 1:
241 return("F_RDLCK");
242 case 2:
243 return("F_WRLCK");
244 case 3:
245 return("F_UNLCK");
246 default:
247 sprintf(buf, "BAD VALUE: %d", type);
248 return(buf);
249 }
250}
251
252void
253parent_put(struct flock *l)
254{
255 if (write(parent_pipe[1], l, sizeof(*l)) != sizeof(*l)) {
256 tst_resm(TFAIL, "couldn't send message to child");
257 fail = 1;
258 }
259}
260
261void
262parent_get(struct flock *l)
263{
264 if (read(child_pipe[0], l, sizeof(*l)) != sizeof(*l)) {
265 tst_resm(TFAIL, "couldn't get message from child");
266 fail = 1;
267 }
268}
269
270void
271child_put(struct flock *l)
272{
273 if (write(child_pipe[1], l, sizeof(*l)) != sizeof(*l)) {
274 tst_resm(TFAIL, "couldn't send message to parent");
275 fail = 1;
276 }
277}
278
279void
280child_get(struct flock *l)
281{
282 if (read(parent_pipe[0], l, sizeof(*l)) != sizeof(*l)) {
283 tst_resm(TFAIL, "couldn't get message from parent");
284 cleanup();
285 } else if (l->l_type == (short)STOP) {
286 exit(0);
287 }
288}
289
290void
291stop_child()
292{
293 struct flock fl;
294
295 (void) signal(SIGCLD, (void (*)())SIG_DFL);
296 fl.l_type = STOP;
297 parent_put(&fl);
298 wait(0);
299}
300
301void
302catch_child()
303{
304 tst_resm(TFAIL, "Unexpected death of child process");
305 cleanup();
306}
robbiew5aab8a72003-03-26 18:05:30 +0000307
308int main(int ac, char **av)
309{
310 struct flock tl;
311
312 int lc; /* loop counter */
313 char *msg; /* message returned from parse_opts */
314
315 /* parse standard options */
316 if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
317 tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
318 }
319
320 setup(); /* global setup */
321
322 /* Check for looping state if -i option is given */
323 for (lc = 0; TEST_LOOPING(lc); lc++) {
324 /* reset Tst_count in case we are looping */
325 Tst_count = 0;
326
327 if ((child_pid = fork()) == 0) {
328 do_child();
329 }
330
331 if (child_pid < 0) {
332 tst_resm(TFAIL, "Fork failed");
333 cleanup();
334 }
335
336 (void)close(parent_pipe[0]);
337 (void)close(child_pipe[1]);
338
mridgedb639212005-01-04 21:04:11 +0000339/* //block1: */
robbiew5aab8a72003-03-26 18:05:30 +0000340 tst_resm(TINFO, "Enter block 1");
341 /*
342 * Add a read lock to the middle of the file and unlock a
343 * section just before the lock
344 */
345 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000346 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
347 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000348 fail = 1;
349 }
350
351 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 5, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000352 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
353 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000354 fail = 1;
355 }
356
357 /*
358 * Test read lock
359 */
360 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
361 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 5, parent_pid);
362
363 /*
364 * Test that the rest of the file is unlocked
365 */
366 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
367 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, (pid_t)0);
368
369 /*
370 * remove all the locks set above
371 */
372 unlock_file();
373
374 if (fail) {
375 tst_resm(TINFO, "Test block 1: FAILED");
376 } else {
377 tst_resm(TINFO, "Test block 1: PASSED");
378 }
379 tst_resm(TINFO, "Exit block 1");
380
mridgedb639212005-01-04 21:04:11 +0000381/* //block2: */
robbiew5aab8a72003-03-26 18:05:30 +0000382 tst_resm(TINFO, "Enter block 2");
383 fail = 0;
384 /*
385 * Set a read lock in the middle and do an unlock that
386 * ends at the first byte of the read lock.
387 */
388 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000389 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
390 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000391 fail = 1;
392 }
393
394 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 5, 6) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000395 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
396 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000397 fail = 1;
398 }
399
400 /*
401 * Test read lock
402 */
403 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
404 compare_lock(&tl, (short)F_RDLCK, (short)0, 11, 4, parent_pid);
405
406 /*
407 * Test to make sure the rest of the file is unlocked
408 */
409 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
410 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, (pid_t)0);
411
412 /*
413 * remove all the locks set above
414 */
415 unlock_file();
416
417 if (fail) {
418 tst_resm(TINFO, "Test block 2: FAILED");
419 } else {
420 tst_resm(TINFO, "Test block 2: PASSED");
421 }
422 tst_resm(TINFO, "Exit block 2");
423
mridgedb639212005-01-04 21:04:11 +0000424/* //block3: */
robbiew5aab8a72003-03-26 18:05:30 +0000425 tst_resm(TINFO, "Enter block 3");
426 fail = 0;
427
428 /*
429 * Set a read lock on the middle of the file and do an
430 * unlock that overlaps the front of the read
431 */
432 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000433 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
434 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000435 fail = 1;
436 }
437
438 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 5, 8) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000439 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
440 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000441 fail = 1;
442 }
443
444 /*
445 * Test the read lock
446 */
447 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
448 compare_lock(&tl, (short)F_RDLCK, (short)0, 13, 2, parent_pid);
449
450 /*
451 * Test to make sure the rest of the file is unlocked
452 */
453 do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
454 compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, (pid_t)0);
455
456 /*
457 * remove all the locks set above
458 */
459 unlock_file();
460
461 if (fail) {
462 tst_resm(TINFO, "Test block 3: FAILED");
463 } else {
464 tst_resm(TINFO, "Test block 3: PASSED");
465 }
466 tst_resm(TINFO, "Exit block 3");
467
mridgedb639212005-01-04 21:04:11 +0000468/* //block4: */
robbiew5aab8a72003-03-26 18:05:30 +0000469 tst_resm(TINFO, "Enter blcok 4");
470 fail = 0;
471
472 /*
473 * Set a read lock in the middle of a file and unlock a
474 * section in the middle of it
475 */
476 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 10) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000477 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
478 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000479 fail = 1;
480 }
481
482 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 13, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000483 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
484 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000485 fail = 1;
486 }
487
488 /*
489 * Test the first read lock
490 */
491 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
492 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 3, parent_pid);
493
494 /*
495 * Test the second read lock
496 */
497 do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
498 compare_lock(&tl, (short)F_RDLCK, (short)0, 18, 2, parent_pid);
499
500 /*
501 * Test to make sure the rest of the file is unlocked
502 */
503 do_test(&tl, (short)F_WRLCK, (short)0, 20, 0);
504 compare_lock(&tl, (short)F_UNLCK, (short)0, 20, 0, (pid_t)0);
505
506 /*
507 * remove all the locks set above
508 */
509 unlock_file();
510
511 if (fail) {
512 tst_resm(TINFO, "Test block 4: FAILED");
513 } else {
514 tst_resm(TINFO, "Test block 4: PASSED");
515 }
516 tst_resm(TINFO, "Exit block 4");
517
mridgedb639212005-01-04 21:04:11 +0000518/* //block5: */
robbiew5aab8a72003-03-26 18:05:30 +0000519 tst_resm(TINFO, "Enter block 5");
520 fail = 0;
521
522 /*
523 * Set a read lock in the middle of the file and do a
524 * unlock that overlaps the end
525 */
526 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000527 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
528 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000529 fail = 1;
530 }
531
532 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 13, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000533 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
534 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000535 fail = 1;
536 }
537
538 /*
539 * Test the read lock
540 */
541 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
542 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 3, parent_pid);
543
544 /*
545 * Test to make sure the rest of the file is unlocked
546 */
547 do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
548 compare_lock(&tl, (short)F_UNLCK, (short)0, 13, 0, (pid_t)0);
549
550 /*
551 * remove all the locks set above
552 */
553 unlock_file();
554
555 if (fail) {
556 tst_resm(TINFO, "Test block 5: FAILED");
557 } else {
558 tst_resm(TINFO, "Test block 5: PASSED");
559 }
560 tst_resm(TINFO, "Exit block 5");
561
mridgedb639212005-01-04 21:04:11 +0000562/* //block6: */
robbiew5aab8a72003-03-26 18:05:30 +0000563 tst_resm(TINFO, "Enter block 6");
564 fail = 0;
565
566 /*
567 * Set read lock in the middle of the file and do an unlock
568 * starting at the last byte of the read lock
569 */
570 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000571 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
572 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000573 fail = 1;
574 }
575
576 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 14, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000577 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
578 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000579 fail = 1;
580 }
581
582 /*
583 * Test read lock
584 */
585 do_test(&tl, (short)F_WRLCK, (short)0, 10, 0);
586 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 4, parent_pid);
587
588 /*
589 * Test to make sure the end of the file is unlocked
590 */
591 do_test(&tl, (short)F_WRLCK, (short)0, 14, 0);
592 compare_lock(&tl, (short)F_UNLCK, (short)0, 14, 0, (pid_t)0);
593
594 /*
595 * remove all the locks set above
596 */
597 unlock_file();
598
599 if (fail) {
600 tst_resm(TINFO, "Test block 6: FAILED");
601 } else {
602 tst_resm(TINFO, "Test block 6: PASSED");
603 }
604 tst_resm(TINFO, "Exit block 6");
605
mridgedb639212005-01-04 21:04:11 +0000606/* //block7: */
robbiew5aab8a72003-03-26 18:05:30 +0000607 tst_resm(TINFO, "Enter block 7");
608 fail = 0;
609
610 /*
611 * Set a read lock at the middle of the file and do an
612 * unlock that starts at the byte past the end of the read
613 * lock
614 */
615 if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000616 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
617 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000618 fail = 1;
619 }
620
621 if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 16, 0) < 0) {
robbiewdad22712003-04-16 19:14:05 +0000622 tst_resm(TFAIL, "fcntl on file failed, errno =%d",
623 errno);
robbiew5aab8a72003-03-26 18:05:30 +0000624 fail = 1;
625 }
626
627 /*
628 * Test the read lock
629 */
630 do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
631 compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 5, parent_pid);
632
633 /*
634 * Test to make sure the rest of the file is unlocked
635 */
636 do_test(&tl, (short)F_WRLCK, (short)0, 16, 0);
637 compare_lock(&tl, (short)F_UNLCK, (short)0, 16, 0, (pid_t)0);
638
639 /*
640 * remove all the locks set above
641 */
642 unlock_file();
643
644 if (fail) {
645 tst_resm(TINFO, "Test block 7: FAILED");
646 } else {
647 tst_resm(TINFO, "Test block 7: PASSED");
648 }
649
650 tst_resm(TINFO, "Exit block 7");
651
652 stop_child();
653 close(fd);
robbiew5aab8a72003-03-26 18:05:30 +0000654 }
655 cleanup();
656 return(0);
657}