fcntl21.c revision fa31d55d3486830313bd044f7333697ce6124d22
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * NAME
22 * 	fcntl21.c
23 *
24 * DESCRIPTION
25 * 	Check locking of regions of a file
26 *
27 * ALGORITHM
28 * 	Test changing lock sections around a read lock
29 *
30 * USAGE
31 * 	fcntl21
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 <test.h>
44#include <usctest.h>
45
46#define STRINGSIZE	27
47#define STRING		"abcdefghijklmnopqrstuvwxyz\n"
48#define STOP		0xFFF0
49
50int parent_pipe[2];
51int child_pipe[2];
52int fd;
53int parent_pid, child_pid;
54char *file;
55
56void parent_put();
57void parent_get();
58void child_put();
59void child_get();
60void stop_child();
61void compare_lock(struct flock *, short, short, int, int, short);
62void unlock_file();
63void do_test(struct flock *, short, short, int, int);
64void catch_child();
65char *str_type();
66int do_lock(int, short, short, int, int);
67
68char *TCID = "fcntl21";
69int TST_TOTAL = 1;
70extern int Tst_count;
71
72void setup(void);
73void cleanup(void);
74int fail;
75
76main(int ac, char **av)
77{
78	struct flock tl;
79
80	int lc;				/* loop counter */
81	char *msg;			/* message returned from parse_opts */
82
83	/* parse standard options */
84	if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){
85		tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
86	}
87
88	setup();			/* global setup */
89
90	/* Check for looping state if -i option is given */
91	for (lc = 0; TEST_LOOPING(lc); lc++) {
92		/* reset Tst_count in case we are looping */
93		Tst_count = 0;
94
95		if ((child_pid = fork()) == 0) {
96			do_child();
97		}
98		if (child_pid < 0) {
99			tst_resm(TFAIL, "Fork failed");
100			cleanup();
101		}
102
103		(void)close(parent_pipe[0]);
104		(void)close(child_pipe[1]);
105
106block1:
107		tst_resm(TINFO, "Enter block 1");
108		fail = 0;
109		/*
110		 * Set a read lock on the whole file
111		 */
112		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 0, 0) < 0) {
113			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
114				 file, errno);
115			fail = 1;
116		}
117
118		/*
119		 * Test to make sure it's there.
120		 */
121		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
122		compare_lock(&tl, (short)F_RDLCK, (short)0, 0, 0, parent_pid);
123
124		/*
125		 * remove the lock set above
126		 */
127		unlock_file();
128
129		if (fail) {
130			tst_resm(TINFO, "Test block 1: FAILED");
131		} else {
132			tst_resm(TINFO, "Test block 1: PASSED");
133		}
134		tst_resm(TINFO, "Exit block 1");
135
136block2:
137		tst_resm(TINFO, "Enter block 2");
138		fail = 0;
139
140		/*
141		 * Set a write lock on the whole file
142		 */
143		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 0, 0) < 0) {
144			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
145				 file, errno);
146			fail = 1;
147		}
148
149		/*
150		 * Test to make sure its there
151		 */
152		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
153		compare_lock(&tl, (short)F_WRLCK, (short)0, 0, 0, parent_pid);
154
155		/*
156		 * remove the lock set above
157		 */
158		unlock_file();
159
160		if (fail) {
161			tst_resm(TINFO, "Test block 2: FAILED");
162		} else {
163			tst_resm(TINFO, "Test block 2: PASSED");
164		}
165
166		tst_resm(TINFO, "Exit block 2");
167
168block3:
169		tst_resm(TINFO, "Enter block 3");
170		fail = 0;
171
172		/*
173		 * Add a read lock to the middle of the file and a write
174		 * at the begining
175		 */
176		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
177			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
178				 file, errno);
179			fail = 1;
180		}
181
182		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 1, 5) < 0) {
183			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
184				 file, errno);
185			fail = 1;
186		}
187
188		/*
189		 * Test write lock
190		 */
191		do_test(&tl, F_WRLCK, 0, 0, 0);
192		compare_lock(&tl, (short)F_WRLCK, (short)0, 1, 5, parent_pid);
193
194		/*
195		 * Test read lock
196		 */
197		do_test(&tl, F_WRLCK, 0, 6, 0);
198		compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 5, parent_pid);
199
200		/*
201		 * Test that the rest of the file is unlocked
202		 */
203		do_test(&tl, F_WRLCK, 0, 15, 0);
204		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
205
206		/*
207		 * remove all the locks set above
208		 */
209		unlock_file();
210
211		if (fail) {
212			tst_resm(TINFO, "Test block 3: FAILED");
213		} else {
214			tst_resm(TINFO, "Test block 3 : PASSED");
215		}
216		tst_resm(TINFO, "Exit block 3");
217
218block4:
219		tst_resm(TINFO, "Enter block 4");
220		fail = 0;
221
222		/*
223		 * Set a read lock at the middle of the file and a
224		 * write lock just before
225		 */
226		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
227			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
228				 file, errno);
229			fail = 1;
230		}
231
232		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 5, 5) < 0) {
233			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
234				 file, errno);
235			fail = 1;
236		}
237
238		/*
239		 * Test the write lock
240		 */
241		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
242		compare_lock(&tl, (short)F_WRLCK, (short)0, 5, 5, parent_pid);
243
244		/*
245		 * Test the read lock.
246		 */
247		do_test(&tl, (short)F_WRLCK, (short)0, 10, 0);
248		compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 5, parent_pid);
249
250		/*
251		 * Test to make sure the rest of the file is unlocked.
252		 */
253		do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
254		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
255
256		/*
257		 * remove all the locks set above
258		 */
259		unlock_file();
260
261		if (fail) {
262			tst_resm(TINFO, "Test block 4: FAILED");
263		} else {
264			tst_resm(TINFO, "Test block 4: PASSED");
265		}
266		tst_resm(TINFO, "Exit block 4");
267
268block5:
269		tst_resm(TINFO, "Enter block 5");
270		fail = 0;
271
272		/*
273		 * Set a read lock in the middle and a write lock that
274		 * ends at the first byte of the read lock
275		 */
276		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
277			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
278				 file, errno);
279			fail = 1;
280		}
281
282		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 5, 6) < 0) {
283			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
284				 file, errno);
285			fail = 1;
286		}
287
288		/*
289		 * Test write lock
290		 */
291		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
292		compare_lock(&tl, (short)F_WRLCK, (short)0, 5, 6, parent_pid);
293
294		/*
295		 * Test read lock
296		 */
297		do_test(&tl, (short)F_WRLCK, (short)0, 11, 0);
298		compare_lock(&tl, (short)F_RDLCK, (short)0, 11, 4, parent_pid);
299
300		/*
301		 * Test to make sure the rest of the file is unlocked.
302		 */
303		do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
304		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
305
306		/*
307		 * remove all the locks set above
308		 */
309		unlock_file();
310
311		if (fail) {
312			tst_resm(TINFO, "Test block 5: FAILED");
313		} else {
314			tst_resm(TINFO, "Test block 5: PASSED");
315		}
316		tst_resm(TINFO, "Exit block 5");
317
318block6:
319		tst_resm(TINFO, "Enter block 6");
320		fail = 0;
321
322		/*
323		 * Set a read lock on the middle of the file and a write
324		 * lock that overlaps the front of the read.
325		 */
326		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
327			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
328				 file, errno);
329			fail = 1;
330		}
331
332		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 5, 8) < 0) {
333			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
334				 file, errno);
335			fail = 1;
336		}
337
338		/*
339		 * Test the write lock
340		 */
341		do_test(&tl, (short)F_WRLCK, (short)0, 5, 0);
342		compare_lock(&tl, (short)F_WRLCK, (short)0, 5, 8, parent_pid);
343
344		/*
345		 * Test the read lock
346		 */
347		do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
348		compare_lock(&tl, (short)F_RDLCK, (short)0, 13, 2, parent_pid);
349
350		/*
351		 * Test to make sure the rest of the file is unlocked.
352		 */
353		do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
354		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
355
356		/*
357		 * remove all the locks set above
358		 */
359		unlock_file();
360
361		if (fail) {
362			tst_resm(TINFO, "Test block 6 FAILED");
363		} else {
364			tst_resm(TINFO, "Test block 6 PASSED");
365		}
366		tst_resm(TINFO, "Exit block 6");
367
368block7:
369		tst_resm(TINFO, "Enter block 7");
370		fail = 0;
371
372		/*
373		 * Set a read lock in the middle of a file and a write
374		 * lock in the middle of it
375		 */
376		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 10) < 0) {
377			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
378				 file, errno);
379			fail = 1;
380		}
381
382		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 13, 5) < 0) {
383			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
384				 file, errno);
385			fail = 1;
386		}
387
388		/*
389		 * Test the first read lock
390		 */
391		do_test(&tl, (short)F_WRLCK, (short)0 , 0, 0);
392		compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 3, parent_pid);
393
394		/*
395		 * Test the write lock
396		 */
397		do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
398		compare_lock(&tl, (short)F_WRLCK, (short)0, 13, 5, parent_pid);
399
400		/*
401		 * Test the second read lock
402		 */
403		do_test(&tl, (short)F_WRLCK, (short)0, 18, 0);
404		compare_lock(&tl, (short)F_RDLCK, (short)0, 18, 2, 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, 20, 0);
410		compare_lock(&tl, (short)F_UNLCK, (short)0, 20, 0, 0);
411
412		/*
413		 * remove all the locks set above.
414		 */
415		unlock_file();
416		if (fail) {
417			tst_resm(TINFO, "Test block 7: FAILED");
418		} else {
419			tst_resm(TINFO, "Test block 7: PASSED");
420		}
421		tst_resm(TINFO, "Exit block 7");
422
423block8:
424		tst_resm(TINFO, "Enter block 8");
425		fail = 0;
426		/*
427		 * Set a read lock in the middle of the file and a write
428		 * lock that overlaps the end
429		 */
430		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
431			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
432				 file, errno);
433			fail = 1;
434		}
435
436		/*
437		 * Set a write lock on the whole file
438		 */
439		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 13, 5) < 0) {
440			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
441				 file, errno);
442			fail = 1;
443		}
444
445		/*
446		 * Test the read lock
447		 */
448		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
449		compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 3, parent_pid);
450
451		/*
452		 * Test the write lock
453		 */
454		do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
455		compare_lock(&tl, (short)F_WRLCK, (short)0, 13, 5, parent_pid);
456
457		/*
458		 * Test to make sure the rest of the file is unlocked
459		 */
460		do_test(&tl, (short)F_WRLCK, (short)0, 18, 0);
461		compare_lock(&tl, (short)F_UNLCK, (short)0, 18, 0, 0);
462
463		/*
464		 * remove all the locks set above
465		 */
466		unlock_file();
467
468		if (fail) {
469			tst_resm(TINFO, "Test block 8: FAILED");
470		} else {
471			tst_resm(TINFO, "Test block 8: PASSED");
472		}
473		tst_resm(TINFO, "Exit block 8");
474
475block9:
476		tst_resm(TINFO, "Enter block 9");
477		fail = 0;
478
479		/*
480		 * Set a read lock in the middle of the file and a write
481		 * lock starting at the last byte of the read lock
482		 */
483		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
484			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
485				 file, errno);
486			fail = 1;
487		}
488
489		/*
490		 * Set a write lock on the whole file.
491		 */
492		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 14, 5) < 0) {
493			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
494				 file, errno);
495			fail = 1;
496		}
497
498		/*
499		 * Test read lock
500		 */
501		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
502		compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 4, parent_pid);
503
504		/*
505		 * Test the write lock
506		 */
507		do_test(&tl, (short)F_WRLCK, (short)0, 14, 0);
508		compare_lock(&tl, (short)F_WRLCK, (short)0, 14, 5, parent_pid);
509
510		/*
511		 * Test to make sure the end of the file is unlocked
512		 */
513		do_test(&tl, (short)F_WRLCK, (short)0, 19, 0);
514		compare_lock(&tl, (short)F_UNLCK, (short)0, 19, 0, 0);
515
516		/*
517		 * remove all the locks set above
518		 */
519		unlock_file();
520
521		if (fail) {
522			tst_resm(TINFO, "Test block 9: FAILED");
523		} else {
524			tst_resm(TINFO, "Test block 9: PASSED");
525		}
526		tst_resm(TINFO, "Exit block 9");
527
528block10:
529		tst_resm(TINFO, "Enter block 10");
530		fail = 0;
531
532		/*
533		 * Set a read lock in the middle of the file and a write
534		 * lock that starts just after the last byte of the
535		 * read lock.
536		 */
537		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
538			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
539				 file, errno);
540			fail = 1;
541		}
542
543		/*
544		 * Set a write lock on the whole file
545		 */
546		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 15, 5) < 0) {
547			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
548				 file, errno);
549			fail = 1;
550		}
551
552		/*
553		 * Test the read lock
554		 */
555		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
556		compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 5, parent_pid);
557
558		/*
559		 * Test the write lock
560		 */
561		do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
562		compare_lock(&tl, (short)F_WRLCK, (short)0, 15, 5, parent_pid);
563
564		/*
565		 * Test to make sure the rest of the file is unlocked
566		 */
567		do_test(&tl, (short)F_WRLCK, (short)0, 20, 0);
568		compare_lock(&tl, (short)F_UNLCK, (short)0, 20, 0, 0);
569
570		/*
571		 * remove all the locks set above
572		 */
573		unlock_file();
574
575		if (fail) {
576			tst_resm(TINFO, "Test block 10: FAILED");
577		} else {
578			tst_resm(TINFO, "Test block 10: PASSED");
579		}
580		tst_resm(TINFO, "Exit block 10");
581
582block11:
583		tst_resm(TINFO, "Enter block 11");
584		fail = 0;
585
586		/*
587		 * Set a read lock at the middle of the file and a write
588		 * lock that starts past the end of the read lock.
589		 */
590		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 10, 5) < 0) {
591			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
592				 file, errno);
593			fail = 1;
594		}
595
596		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 16, 5) < 0) {
597			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
598				 file, errno);
599			fail = 1;
600		}
601
602		/*
603		 * Test the read lock
604		 */
605		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
606		compare_lock(&tl, (short)F_RDLCK, (short)0, 10, 5, parent_pid);
607
608		/*
609		 * Test that byte in between is unlocked
610		 */
611		do_test(&tl, (short)F_WRLCK, (short)0, 15, 1);
612		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 1, 0);
613
614		/*
615		 * Test the write lock
616		 */
617		do_test(&tl, (short)F_WRLCK, (short)0, 16, 0);
618		compare_lock(&tl, (short)F_WRLCK, (short)0, 16, 5, parent_pid);
619
620		/*
621		 * Test to make sure the rest of the file is unlocked
622		 */
623		do_test(&tl, (short)F_WRLCK, (short)0, 21, 0);
624		compare_lock(&tl, (short)F_UNLCK, (short)0, 21, 0, 0);
625
626		/*
627		 * remove all the locks set above
628		 */
629		unlock_file();
630
631		if (fail) {
632			tst_resm(TINFO, "Test block 11: FAILED");
633		} else {
634			tst_resm(TINFO, "Test block 11: PASSED");
635		}
636		tst_resm(TINFO, "Exit block 11");
637
638		stop_child();
639		close(fd);
640	}
641	cleanup();
642}
643
644/*
645 * setup
646 * 	performs all ONE TIME setup for this test
647 */
648void
649setup()
650{
651	char *buf = STRING;
652
653	/* capture signals */
654	tst_sig(FORK, DEF_HANDLER, cleanup);
655
656	umask(0);
657
658	/* Pause if that option was specified */
659	TEST_PAUSE;
660
661	pipe(parent_pipe);
662	pipe(child_pipe);
663	parent_pid = getpid();
664	file = tempnam(".", NULL);
665
666	if ((fd = open(file, O_RDWR|O_CREAT, 0777)) < 0) {
667		tst_resm(TFAIL, "Couldn't open %s! errno = %d", file, errno);
668		fail = 1;
669	}
670
671	if (write(fd, buf, STRINGSIZE) < 0) {
672		tst_resm(TFAIL, "Couldn't write %s! errno = %d", file, errno);
673		fail = 1;
674	}
675
676	if ((int)(signal(SIGCLD, catch_child)) < 0) {
677		tst_resm(TFAIL, "SIGCLD signal setup failed, errno: %d",
678			 errno);
679		fail = 1;
680	}
681}
682
683/*
684 * cleanup()
685 * 	performs all ONE TIME cleanup for this test at completion or
686 * 	premature exit
687 */
688void
689cleanup()
690{
691	/*
692	 * print timing stats if that option was specified
693	 * print errno log if that option was specified
694	 */
695	TEST_CLEANUP;
696
697	unlink(file);
698
699	/* exit with return code appropriate for results */
700	tst_exit();
701}
702
703do_child()
704{
705	struct flock fl;
706
707	close(parent_pipe[1]);
708	close(child_pipe[0]);
709	while(1) {
710		child_get(&fl);
711		if (fcntl(fd, F_GETLK, &fl) < 0) {
712			tst_resm(TFAIL, "fcntl on file %s failed, errno =%d",
713				 file, errno);
714			fail = 1;
715		}
716		child_put(&fl);
717	}
718}
719
720do_lock(int cmd, short type, short whence, int start, int len)
721{
722	struct flock fl;
723
724	fl.l_type = type;
725	fl.l_whence = whence;
726	fl.l_start = start;
727	fl.l_len = len;
728	return(fcntl(fd, cmd, &fl));
729}
730
731void
732do_test(struct flock *fl, short type, short whence, int start, int len)
733{
734	fl->l_type = type;
735	fl->l_whence = whence;
736	fl->l_start = start;
737	fl->l_len = len;
738	fl->l_pid = (short)0;
739
740	parent_put(fl);
741	parent_get(fl);
742}
743
744void
745compare_lock(struct flock *fl, short type, short whence, int start, int len,
746	     short pid)
747{
748	if (fl->l_type != type) {
749		tst_resm(TFAIL, "lock type is wrong should be %s is %s",
750			 str_type(type), str_type(fl->l_type));
751		fail = 1;
752	}
753
754	if (fl->l_whence != whence) {
755		tst_resm(TFAIL, "lock whence is wrong should be %d is %d",
756			 whence, fl->l_whence);
757		fail = 1;
758	}
759
760	if (fl->l_start != start) {
761		tst_resm(TFAIL, "region starts in wrong place, should be"
762			 "%d is %d", start, fl->l_start);
763		fail = 1;
764	}
765
766	if (fl->l_len != len) {
767		tst_resm(TFAIL, "region length is wrong, should be %d is %d",
768			 len, fl->l_len);
769		fail = 1;
770	}
771
772	if (fl->l_pid != pid) {
773		tst_resm(TFAIL, "locking pid is wrong, should be %d is %d",
774			 pid, fl->l_pid);
775		fail = 1;
776	}
777}
778
779void
780unlock_file()
781{
782	struct flock fl;
783
784	if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 0, 0) < 0) {
785		tst_resm(TFAIL, "fcntl on file %s failed, errno =%d", file,
786			 errno);
787		fail = 1;
788	}
789	do_test(&fl, F_WRLCK, 0, 0, 0);
790	compare_lock(&fl, (short)F_UNLCK, (short)0, 0, 0, (short)0);
791}
792
793char *
794str_type(int type)
795{
796	static char buf[20];
797
798	switch (type) {
799	case 1:
800		return("F_RDLCK");
801	case 2:
802		return("F_WRLCK");
803	case 3:
804		return("F_UNLCK");
805	default:
806		sprintf(buf, "BAD VALUE: %d", type);
807		return(buf);
808	}
809}
810
811void
812parent_put(struct flock *l)
813{
814	if (write(parent_pipe[1], l, sizeof(*l)) != sizeof(*l)) {
815		tst_resm(TFAIL, "couldn't send message to child");
816		fail = 1;
817	}
818}
819
820void
821parent_get(struct flock *l)
822{
823	if (read(child_pipe[0], l, sizeof(*l)) != sizeof(*l)) {
824		tst_resm(TFAIL, "couldn't get message from child");
825		fail = 1;
826	}
827}
828
829void
830child_put(struct flock *l)
831{
832	if (write(child_pipe[1], l, sizeof(*l)) != sizeof(*l)) {
833		tst_resm(TFAIL, "couldn't send message to parent");
834		fail = 1;
835	}
836}
837
838void
839child_get(struct flock *l)
840{
841	if (read(parent_pipe[0], l, sizeof(*l)) != sizeof(*l)) {
842		tst_resm(TFAIL, "couldn't get message from parent");
843		cleanup();
844	} else if (l->l_type == (short)STOP) {
845		exit(0);
846	}
847}
848
849void
850stop_child()
851{
852	struct flock fl;
853
854	(void) signal(SIGCLD, (void (*)())SIG_DFL);
855	fl.l_type = STOP;
856	parent_put(&fl);
857	wait(0);
858}
859
860void
861catch_child()
862{
863	tst_resm(TFAIL, "Unexpected death of child process");
864	cleanup();
865}
866