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