fcntl16.c revision 45e285d46ab47b0ff76c88acb5ba97b0bd5f753d
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 *	fcntl16.c
23 *
24 * DESCRIPTION
25 *	Additional file locking test cases for checking proper notifictaion
26 *	of processes on lock change
27 *
28 * ALGORITHM
29 *	Various test cases are used to lock a file opened without mandatory
30 *	locking, with madatory locking and mandatory locking with NOBLOCK.
31 *	Checking that processes waiting on lock boundaries are notified
32 *	properly when boundaries change
33 *
34 * USAGE
35 *	fcntl16
36 *
37 * HISTORY
38 *	07/2001 Ported by Wayne Boyer
39 *	04/2002 wjhuie sigset cleanups
40 *
41 * RESTRICTIONS
42 *	None
43 */
44
45#include <fcntl.h>
46#include <signal.h>
47#include <errno.h>
48#include <test.h>
49#include <usctest.h>
50#include <sys/stat.h>
51#include <sys/types.h>
52#include <sys/wait.h>
53
54#define SKIPVAL 0x0f00
55//#define       SKIP    SKIPVAL, 0, 0L, 0L, IGNORED
56#define SKIP 0,0,0L,0L,0
57#if (SKIPVAL == F_RDLCK) || (SKIPVAL == F_WRLCK)
58#error invalid SKIP, must not be F_RDLCK or F_WRLCK
59#endif
60
61#define	IGNORED		0
62#define	NOBLOCK		2	/* immediate success */
63#define	WILLBLOCK	3	/* blocks, succeeds, parent unlocks records */
64#define	TIME_OUT	10
65
66typedef struct {
67	short type;
68	short whence;
69	long start;
70	long len;
71	short flag;
72} lock;
73
74typedef struct {
75	lock parent_a;
76	lock parent_b;
77	lock child_a;
78	lock child_b;
79	lock parent_c;
80	lock parent_d;
81} testcase;
82
83static testcase testcases[] = {
84	/* #1 Parent_a making a write lock on entire file */
85	{{F_WRLCK, 0, 0L, 0L, IGNORED},
86	 /* Parent_b skipped */
87	 {SKIP},
88	 /* Child_a read lock on byte 1 to byte 5 */
89	 {F_RDLCK, 0, 0L, 5L, NOBLOCK},
90	 /* Child_b read lock on byte 6 to byte 10 */
91	 {F_RDLCK, 0, 6L, 5L, NOBLOCK},
92	 /*
93	  * Parent_c read lock on entire file
94	  */
95	 {F_RDLCK, 0, 0L, 0L, IGNORED},
96	 /* Parent_d skipped */
97	 {SKIP},},
98
99	/* #2 Parent_a making a write lock on entire file */
100	{{F_WRLCK, 0, 0L, 0L, IGNORED},
101	 /* Parent_b skipped */
102	 {SKIP},
103	 /* Child_a read lock on byte 1 to byte 5 */
104	 {F_RDLCK, 0, 0L, 5L, WILLBLOCK},
105	 /* Child_b read lock on byte 6 to byte 10 */
106	 {F_RDLCK, 0, 6L, 5L, WILLBLOCK},
107	 /*
108	  * Parent_c write lock on entire
109	  * file
110	  */
111	 {F_WRLCK, 0, 0L, 0L, IGNORED},
112	 /* Parent_d skipped */
113	 {SKIP},},
114
115	/* #3 Parent_a making a write lock on entire file */
116	{{F_WRLCK, 0, 0L, 0L, IGNORED},
117	 /* Parent_b skipped */
118	 {SKIP},
119	 /* Child_a read lock on byte 2 to byte 4 */
120	 {F_RDLCK, 0, 2L, 3L, WILLBLOCK},
121	 /* Child_b read lock on byte 6 to byte 8 */
122	 {F_RDLCK, 0, 6L, 3L, WILLBLOCK},
123	 /*
124	  * Parent_c read lock on byte 3 to
125	  * byte 7
126	  */
127	 {F_RDLCK, 0, 3L, 5L, IGNORED},
128	 /* Parent_d skipped */
129	 {SKIP},},
130
131	/* #4 Parent_a making a write lock on entire file */
132	{{F_WRLCK, 0, 0L, 0L, IGNORED},
133	 /* Parent_b skipped */
134	 {SKIP},
135	 /* Child_a read lock on byte 2 to byte 4 */
136	 {F_RDLCK, 0, 2L, 3L, WILLBLOCK},
137	 /* Child_b read lock on byte 6 to byte 8 */
138	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
139	 /*
140	  * Parent_c read lock on byte 5 to
141	  * byte 9
142	  */
143	 {F_RDLCK, 0, 5L, 5L, IGNORED},
144	 /* Parent_d skipped */
145	 {SKIP},},
146
147	/* #5 Parent_a making a write lock on entire file */
148	{{F_WRLCK, 0, 0L, 0L, IGNORED},
149	 /* Parent_b skipped */
150	 {SKIP},
151	 /* Child_a read lock on byte 3 to byte 7 */
152	 {F_RDLCK, 0, 3L, 5L, NOBLOCK},
153	 /* Child_b read lock on byte 5 to byte 10 */
154	 {F_RDLCK, 0, 5L, 6L, WILLBLOCK},
155	 /*
156	  * Parent_c read lock on byte 2 to
157	  * byte 8
158	  */
159	 {F_RDLCK, 0, 2L, 7L, IGNORED},
160	 /* Parent_d skipped */
161	 {SKIP},},
162
163	/* #6 Parent_a making a write lock on entire file */
164	{{F_WRLCK, 0, 0L, 0L, IGNORED},
165	 /* Parent_b skipped */
166	 {SKIP},
167	 /* Child_a read lock on byte 2 to byte 4 */
168	 {F_RDLCK, 0, 2L, 3L, WILLBLOCK},
169	 /* Child_b write lock on byte 6 to byte 8 */
170	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
171	 /* Parent_c no lock on byte 3 to 9 */
172	 {F_UNLCK, 0, 3L, 7L, IGNORED},
173	 /* Parent_d skipped */
174	 {SKIP},},
175
176	/* #7 Parent_a making a write lock on entire file */
177	{{F_WRLCK, 0, 0L, 0L, IGNORED},
178	 /* Parent_b read lock on byte 3 to byte 7 */
179	 {F_RDLCK, 0, 3L, 5L, IGNORED},
180	 /* Child_a read lock on byte 2 to byte 4 */
181	 {F_RDLCK, 0, 2L, 3L, NOBLOCK},
182	 /* Child_b read lock on byte 6 to byte 8 */
183	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
184	 /*
185	  * Parent_c read lock on byte 1 to
186	  * byte 9
187	  */
188	 {F_RDLCK, 0, 1L, 9L, IGNORED},
189	 /* Parent_d skipped */
190	 {SKIP},},
191
192	/* #8 Parent_a making a write lock on byte 2 to byte 4 */
193	{{F_WRLCK, 0, 2L, 3L, IGNORED},
194	 /* Parent_b write lock on byte 6 to byte 8 */
195	 {F_WRLCK, 0, 6L, 3L, IGNORED},
196	 /* Child_a read lock on byte 3 to byte 7 */
197	 {F_RDLCK, 0, 3L, 5L, NOBLOCK},
198	 /* Child_b skipped */
199	 {SKIP},
200	 /*
201	  * Parent_c read lock on byte 1 to
202	  * byte 5
203	  */
204	 {F_RDLCK, 0, 1L, 5L, IGNORED},
205	 /*
206	  * Parent_d read lock on
207	  * byte 5 to byte 9
208	  */
209	 {F_RDLCK, 0, 5L, 5L,
210	  IGNORED},},
211
212	/* #9 Parent_a making a write lock on entire file */
213	{{F_WRLCK, 0, 0L, 0L, IGNORED},
214	 /* Parent_b read lock on byte 3 to byte 7 */
215	 {F_RDLCK, 0, 3L, 5L, IGNORED},
216	 /* Child_a read lock on byte 2 to byte 4 */
217	 {F_RDLCK, 0, 2L, 3L, NOBLOCK},
218	 /* Child_b read lock on byte 6 to byte 8 */
219	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
220	 /*
221	  * Parent_c read lock on byte 1 to
222	  * byte 3
223	  */
224	 {F_RDLCK, 0, 1L, 3L, IGNORED},
225	 /*
226	  * Parent_d read lock on
227	  * byte 7 to byte 9
228	  */
229	 {F_RDLCK, 0, 7L, 3L,
230	  IGNORED},},
231
232	/* #10 Parent_a making a write lock on entire file */
233	{{F_WRLCK, 0, 0L, 0L, IGNORED},
234	 /* Parent_b skipped */
235	 {SKIP},
236	 /* Child_a read lock on byte 2 to byte 4 */
237	 {F_RDLCK, 0, 2L, 3L, NOBLOCK},
238	 /* Child_b read lock on byte 6 to byte 8 */
239	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
240	 /*
241	  * Parent_c read lock on byte 1 to
242	  * byte 7
243	  */
244	 {F_RDLCK, 0, 1L, 7L, IGNORED},
245	 /*
246	  * Parent_d read lock on
247	  * byte 3 to byte 9
248	  */
249	 {F_RDLCK, 0, 3L, 7L,
250	  IGNORED},},
251
252	/* #11 Parent_a making a write lock on entire file */
253	{{F_WRLCK, 0, 0L, 0L, IGNORED},
254	 /* Parent_b skipped */
255	 {SKIP},
256	 /* Child_a read lock on byte 3 to byte 7 */
257	 {F_RDLCK, 0, 3L, 5L, NOBLOCK},
258	 /* Child_b read lock on byte 3 to byte 7 */
259	 {F_RDLCK, 0, 3L, 5L, NOBLOCK},
260	 /*
261	  * Parent_c read lock on byte 3 to
262	  * byte 7
263	  */
264	 {F_RDLCK, 0, 3L, 5L, IGNORED},
265	 /* Parent_d skipped */
266	 {SKIP},},
267};
268
269static testcase *thiscase;
270static lock *thislock;
271static int parent;
272static int child_flag1 = 0;
273static int child_flag2 = 0;
274static int parent_flag = 0;
275static int alarm_flag = 0;
276static int child_pid[2], flag[2];
277static int fd;
278static int test;
279static char tmpname[40];
280
281#define	FILEDATA	"tenbytes!"
282
283extern void catch_usr1();	/* signal catching subroutine */
284extern void catch_usr2();	/* signal catching subroutine */
285extern void catch_int();	/* signal catching subroutine */
286extern void catch_alarm();	/* signal catching subroutine */
287
288char *TCID = "fcntl16";
289int TST_TOTAL = 1;
290extern int Tst_count;
291
292#ifdef UCLINUX
293static char *argv0;
294#endif
295
296/*
297 * cleanup - performs all the ONE TIME cleanup for this test at completion or
298 *	premature exit
299 */
300void cleanup(void)
301{
302	TEST_CLEANUP;
303
304	tst_rmdir();
305
306	tst_exit();
307}
308
309void dochild(int kid)
310{
311	/* child process */
312	struct sigaction sact;
313	sact.sa_flags = 0;
314	sact.sa_handler = catch_int;
315	(void)sigaction(SIGUSR1, &sact, NULL);
316
317	/* Lock should succeed after blocking and parent releases lock */
318	if (kid) {
319		if ((kill(parent, SIGUSR2)) < 0) {
320			tst_resm(TFAIL, "Attempt to send signal to parent "
321				 "failed");
322			tst_resm(TFAIL, "Test case %d, child %d, errno = %d",
323				 test + 1, kid, errno);
324			exit(1);
325		}
326	} else {
327		if ((kill(parent, SIGUSR1)) < 0) {
328			tst_resm(TFAIL, "Attempt to send signal to parent "
329				 "failed");
330			tst_resm(TFAIL, "Test case %d, child %d, errno = %d",
331				 test + 1, kid, errno);
332			exit(1);
333		}
334	}
335
336	if ((fcntl(fd, F_SETLKW, thislock)) < 0) {
337		if (errno == EINTR && parent_flag) {
338			/*
339			 * signal received is waiting for lock to clear,
340			 * this is expected if flag = WILLBLOCK
341			 */
342			exit(1);
343		} else {
344			tst_resm(TFAIL, "Attempt to set child BLOCKING lock "
345				 "failed");
346			tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
347				 errno);
348			exit(2);
349		}
350	}
351	exit(0);
352}				/* end of child process */
353
354#ifdef UCLINUX
355static int kid_uc;
356
357void dochild_uc()
358{
359	dochild(kid_uc);
360}
361#endif
362
363void catch_alarm()
364{
365	alarm_flag = 1;
366}
367
368void catch_usr1()
369{				/* invoked on catching SIGUSR1 */
370	/*
371	 * Set flag to let parent know that child #1 is ready to have the
372	 * lock removed
373	 */
374	child_flag1 = 1;
375}
376
377void catch_usr2()
378{				/* invoked on catching SIGUSR2 */
379	/*
380	 * Set flag to let parent know that child #2 is ready to have the
381	 * lock removed
382	 */
383	child_flag2 = 1;
384}
385
386void catch_int()
387{				/* invoked on child catching SIGUSR1 */
388	/*
389	 * Set flag to interrupt fcntl call in child and force a controlled
390	 * exit
391	 */
392	parent_flag = 1;
393}
394
395void child_sig(int sig, int nkids)
396{
397	int i;
398
399	for (i = 0; i < nkids; i++) {
400		if (kill(child_pid[i], 0) == 0) {
401			if ((kill(child_pid[i], sig)) < 0) {
402				tst_resm(TFAIL, "Attempt to signal child %d, "
403					 "failed", i + 1);
404			}
405		}
406	}
407}
408
409/*
410 * setup - performs all ONE TIME steup for this test
411 */
412void setup(void)
413{
414	struct sigaction sact;
415
416	/* capture signals */
417	tst_sig(FORK, DEF_HANDLER, cleanup);
418
419	umask(0);
420
421	/* Pause if option was specified */
422	TEST_PAUSE;
423
424	parent = getpid();
425
426	tst_tmpdir();
427
428	/* set up temp filename */
429	sprintf(tmpname, "fcntl4.%d", parent);
430
431	/*
432	 * Set up signal handling functions
433	 */
434	memset(&sact, 0, sizeof(sact));
435	sact.sa_handler = catch_usr1;
436	sigemptyset(&sact.sa_mask);
437	sigaddset(&sact.sa_mask, SIGUSR1);
438	sigaction(SIGUSR1, &sact, NULL);
439
440	memset(&sact, 0, sizeof(sact));
441	sact.sa_handler = catch_usr2;
442	sigemptyset(&sact.sa_mask);
443	sigaddset(&sact.sa_mask, SIGUSR2);
444	sigaction(SIGUSR2, &sact, NULL);
445
446	memset(&sact, 0, sizeof(sact));
447	sact.sa_handler = catch_alarm;
448	sigemptyset(&sact.sa_mask);
449	sigaddset(&sact.sa_mask, SIGALRM);
450	sigaction(SIGALRM, &sact, NULL);
451}
452
453int run_test(int file_flag, int file_mode, int start, int end)
454{
455	int child_count;
456	int child;
457	int nexited;
458	int status, expect_stat;
459	int i, fail = 0;
460
461	/* loop through all test cases */
462	for (test = start; test < end; test++) {
463		/* open a temp file to lock */
464		fd = open(tmpname, file_flag, file_mode);
465		if (fd < 0) {
466			tst_brkm(TBROK, cleanup, "open failed");
467		 /*NOTREACHED*/}
468
469		/* write some dummy data to the file */
470		(void)write(fd, FILEDATA, 10);
471
472		/* Initialize first parent lock structure */
473		thiscase = &testcases[test];
474		thislock = &thiscase->parent_a;
475
476		/* set the initial parent lock on the file */
477		if ((fcntl(fd, F_SETLK, thislock)) < 0) {
478			tst_resm(TFAIL, "First parent lock failed");
479			tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
480				 errno);
481			unlink(tmpname);
482			return 1;
483		}
484
485		/* Initialize second parent lock structure */
486		thislock = &thiscase->parent_b;
487
488		if ((thislock->type) != IGNORED) {	/*SKIPVAL */
489			/* set the second parent lock */
490			if ((fcntl(fd, F_SETLK, thislock)) < 0) {
491				tst_resm(TFAIL, "Second parent lock failed");
492				tst_resm(TFAIL, "Test case %d, errno = %d",
493					 test + 1, errno);
494				unlink(tmpname);
495				return 1;
496			}
497		}
498
499		/* Initialize first child lock structure */
500		thislock = &thiscase->child_a;
501
502		/* Initialize child counter and flags */
503		alarm_flag = parent_flag = 0;
504		child_flag1 = child_flag2 = 0;
505		child_count = 0;
506
507		/* spawn child processes */
508		for (i = 0; i < 2; i++) {
509			if (thislock->type != IGNORED) {
510				if ((child = FORK_OR_VFORK()) == 0) {
511#ifdef UCLINUX
512					if (self_exec(argv0, "ddddd", i, parent,
513						      test, thislock, fd) < 0) {
514						perror("self_exec failed");
515						return 1;
516					}
517#else
518					dochild(i);
519#endif
520				}
521				if (child < 0) {
522					perror("Fork failed");
523					return 1;
524				}
525				child_count++;
526				child_pid[i] = child;
527				flag[i] = thislock->flag;
528			}
529			/* Initialize second child lock structure */
530			thislock = &thiscase->child_b;
531		}
532		/* parent process */
533
534		/*
535		 * Wait for children to signal they are ready. Set a timeout
536		 * just in case they don't signal at all.
537		 */
538		alarm(TIME_OUT);
539
540		while (!alarm_flag
541		       && (child_flag1 + child_flag2 != child_count)) {
542			pause();
543		}
544
545		/*
546		 * Turn off alarm and unmask signals
547		 */
548		alarm((unsigned)0);
549
550		if (child_flag1 + child_flag2 != child_count) {
551			tst_resm(TFAIL, "Test case %d: kids didn't signal",
552				 test + 1);
553			fail = 1;
554		}
555		child_flag1 = child_flag2 = alarm_flag = 0;
556
557		thislock = &thiscase->parent_c;
558
559		/* set the third parent lock on the file */
560		if ((fcntl(fd, F_SETLK, thislock)) < 0) {
561			tst_resm(TFAIL, "Third parent lock failed");
562			tst_resm(TFAIL, "Test case %d, errno = %d",
563				 test + 1, errno);
564			unlink(tmpname);
565			return 1;
566		}
567
568		/* Initialize fourth parent lock structure */
569		thislock = &thiscase->parent_d;
570
571		if ((thislock->type) != IGNORED) {	/*SKIPVAL */
572			/* set the fourth parent lock */
573			if ((fcntl(fd, F_SETLK, thislock)) < 0) {
574				tst_resm(TINFO, "Fourth parent lock failed");
575				tst_resm(TINFO, "Test case %d, errno = %d",
576					 test + 1, errno);
577				unlink(tmpname);
578				return 1;
579			}
580		}
581
582		/*
583		 * Wait for children to exit, or for timeout to occur.
584		 * Timeouts are expected for testcases where kids are
585		 * 'WILLBLOCK', In that case, send kids a wakeup interrupt
586		 * and wait again for them. If a second timeout occurs, then
587		 * something is wrong.
588		 */
589		alarm_flag = nexited = 0;
590		while (nexited < child_count) {
591			alarm(TIME_OUT);
592			child = wait(&status);
593			alarm(0);
594
595			if (child == -1) {
596				if (errno != EINTR || alarm_flag != 1) {
597					/*
598					 * Some error other than a timeout,
599					 * or else this is the second
600					 * timeout. Both cases are errors.
601					 */
602					break;
603				}
604
605				/*
606				 * Expected timeout case. Signal kids then
607				 * go back and wait again
608				 */
609				child_sig(SIGUSR1, child_count);
610				continue;
611			}
612
613			for (i = 0; i < child_count; i++)
614				if (child == child_pid[i])
615					break;
616			if (i == child_count) {
617				/*
618				 * Ignore unexpected kid, it could be a
619				 * leftover from a previous iteration that
620				 * timed out.
621				 */
622				continue;
623			}
624
625			/* Found the right kid, check his status */
626			nexited++;
627
628			expect_stat = (flag[i] == NOBLOCK) ? 0 : 1;
629
630			if (!WIFEXITED(status)
631			    || WEXITSTATUS(status) != expect_stat) {
632				/* got unexpected exit status from kid */
633				tst_resm(TFAIL, "Test case %d: child %d %s "
634					 "or got bad status (x%x)", test + 1,
635					 i, (flag[i] == NOBLOCK) ?
636					 "BLOCKED unexpectedly" :
637					 "failed to BLOCK", status);
638				fail = 1;
639			}
640		}
641
642		if (nexited != child_count) {
643			tst_resm(TFAIL, "Test case %d, caught %d expected %d "
644				 "children", test + 1, nexited, child_count);
645			child_sig(SIGKILL, nexited);
646			fail = 1;
647		}
648		close(fd);
649	}
650	unlink(tmpname);
651	if (fail) {
652		return 1;
653	} else {
654		return 0;
655	}
656	return 0;
657}
658
659int main(int ac, char **av)
660{
661
662	int lc;			/* loop counter */
663	char *msg;		/* message returned from parse_opts */
664
665	/* parse standard options */
666	if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) {
667		tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
668	}
669#ifdef UCLINUX
670	maybe_run_child(dochild_uc, "ddddd", &kid_uc, &parent, &test,
671			&thislock, &fd);
672	argv0 = av[0];
673#endif
674
675	setup();		/* global setup */
676
677	/* check looping state if -i option given */
678	for (lc = 0; TEST_LOOPING(lc); lc++) {
679		/* reset Tst_count in case we are looping */
680		Tst_count = 0;
681
682/* //block1: */
683		/*
684		 * Check file locks on an ordinary file without
685		 * mandatory locking
686		 */
687		tst_resm(TINFO, "Entering block 1");
688		if (run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 0, 11)) {
689			tst_resm(TINFO, "Test case 1: without mandatory "
690				 "locking FAILED");
691		} else {
692			tst_resm(TINFO, "Test case 1: without manadatory "
693				 "locking PASSED");
694		}
695		tst_resm(TINFO, "Exiting block 1");
696
697/* //block2: */
698		/*
699		 * Check the file locks on a file with mandatory record
700		 * locking
701		 */
702		tst_resm(TINFO, "Entering block 2");
703		if (run_test(O_CREAT | O_RDWR | O_TRUNC, S_ISGID |
704			     S_IRUSR | S_IWUSR, 0, 11)) {
705			tst_resm(TINFO, "Test case 2: with mandatory record "
706				 "locking FAILED");
707		} else {
708			tst_resm(TINFO, "Test case 2: with mandatory record "
709				 "locking PASSED");
710		}
711		tst_resm(TINFO, "Exiting block 2");
712
713/* //block3: */
714		/*
715		 * Check file locks on a file with mandatory record locking
716		 * and no delay
717		 */
718		tst_resm(TINFO, "Entering block 3");
719		if (run_test(O_CREAT | O_RDWR | O_TRUNC | O_NDELAY,
720			     S_ISGID | S_IRUSR | S_IWUSR, 0, 11)) {
721			tst_resm(TINFO, "Test case 3: mandatory locking with "
722				 "NODELAY FAILED");
723		} else {
724			tst_resm(TINFO, "Test case 3: mandatory locking with "
725				 "NODELAY PASSED");
726		}
727		tst_resm(TINFO, "Exiting block 3");
728	}
729	cleanup();
730	return 0;
731}
732