fcntl16.c revision 8c200cb8e843724afb49fa6617fceec09ac826a5
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 *	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;
290
291#ifdef UCLINUX
292static char *argv0;
293#endif
294
295/*
296 * cleanup - performs all the ONE TIME cleanup for this test at completion or
297 *	premature exit
298 */
299void cleanup(void)
300{
301	TEST_CLEANUP;
302
303	tst_rmdir();
304
305}
306
307void dochild(int kid)
308{
309	/* child process */
310	struct sigaction sact;
311	sact.sa_flags = 0;
312	sact.sa_handler = catch_int;
313	sigemptyset(&sact.sa_mask);
314	(void)sigaction(SIGUSR1, &sact, NULL);
315
316	/* Lock should succeed after blocking and parent releases lock */
317	if (kid) {
318		if ((kill(parent, SIGUSR2)) < 0) {
319			tst_resm(TFAIL, "Attempt to send signal to parent "
320				 "failed");
321			tst_resm(TFAIL, "Test case %d, child %d, errno = %d",
322				 test + 1, kid, errno);
323			exit(1);
324		}
325	} else {
326		if ((kill(parent, SIGUSR1)) < 0) {
327			tst_resm(TFAIL, "Attempt to send signal to parent "
328				 "failed");
329			tst_resm(TFAIL, "Test case %d, child %d, errno = %d",
330				 test + 1, kid, errno);
331			exit(1);
332		}
333	}
334
335	if ((fcntl(fd, F_SETLKW, thislock)) < 0) {
336		if (errno == EINTR && parent_flag) {
337			/*
338			 * signal received is waiting for lock to clear,
339			 * this is expected if flag = WILLBLOCK
340			 */
341			exit(1);
342		} else {
343			tst_resm(TFAIL, "Attempt to set child BLOCKING lock "
344				 "failed");
345			tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
346				 errno);
347			exit(2);
348		}
349	}
350	exit(0);
351}				/* end of child process */
352
353#ifdef UCLINUX
354static int kid_uc;
355
356void dochild_uc()
357{
358	dochild(kid_uc);
359}
360#endif
361
362void catch_alarm()
363{
364	alarm_flag = 1;
365}
366
367void catch_usr1()
368{				/* invoked on catching SIGUSR1 */
369	/*
370	 * Set flag to let parent know that child #1 is ready to have the
371	 * lock removed
372	 */
373	child_flag1 = 1;
374}
375
376void catch_usr2()
377{				/* invoked on catching SIGUSR2 */
378	/*
379	 * Set flag to let parent know that child #2 is ready to have the
380	 * lock removed
381	 */
382	child_flag2 = 1;
383}
384
385void catch_int()
386{				/* invoked on child catching SIGUSR1 */
387	/*
388	 * Set flag to interrupt fcntl call in child and force a controlled
389	 * exit
390	 */
391	parent_flag = 1;
392}
393
394void child_sig(int sig, int nkids)
395{
396	int i;
397
398	for (i = 0; i < nkids; i++) {
399		if (kill(child_pid[i], 0) == 0) {
400			if ((kill(child_pid[i], sig)) < 0) {
401				tst_resm(TFAIL, "Attempt to signal child %d, "
402					 "failed", i + 1);
403			}
404		}
405	}
406}
407
408/*
409 * setup - performs all ONE TIME steup for this test
410 */
411void setup(void)
412{
413	struct sigaction sact;
414
415	tst_sig(FORK, DEF_HANDLER, cleanup);
416
417	umask(0);
418
419	/* Pause if option was specified */
420	TEST_PAUSE;
421
422	parent = getpid();
423
424	tst_tmpdir();
425
426	/* set up temp filename */
427	sprintf(tmpname, "fcntl4.%d", parent);
428
429	/*
430	 * Set up signal handling functions
431	 */
432	memset(&sact, 0, sizeof(sact));
433	sact.sa_handler = catch_usr1;
434	sigemptyset(&sact.sa_mask);
435	sigaddset(&sact.sa_mask, SIGUSR1);
436	sigaction(SIGUSR1, &sact, NULL);
437
438	memset(&sact, 0, sizeof(sact));
439	sact.sa_handler = catch_usr2;
440	sigemptyset(&sact.sa_mask);
441	sigaddset(&sact.sa_mask, SIGUSR2);
442	sigaction(SIGUSR2, &sact, NULL);
443
444	memset(&sact, 0, sizeof(sact));
445	sact.sa_handler = catch_alarm;
446	sigemptyset(&sact.sa_mask);
447	sigaddset(&sact.sa_mask, SIGALRM);
448	sigaction(SIGALRM, &sact, NULL);
449}
450
451int run_test(int file_flag, int file_mode, int start, int end)
452{
453	int child_count;
454	int child;
455	int nexited;
456	int status, expect_stat;
457	int i, fail = 0;
458
459	/* loop through all test cases */
460	for (test = start; test < end; test++) {
461		/* open a temp file to lock */
462		fd = open(tmpname, file_flag, file_mode);
463		if (fd < 0) {
464			tst_brkm(TBROK, cleanup, "open failed");
465		}
466
467		/* write some dummy data to the file */
468		(void)write(fd, FILEDATA, 10);
469
470		/* Initialize first parent lock structure */
471		thiscase = &testcases[test];
472		thislock = &thiscase->parent_a;
473
474		/* set the initial parent lock on the file */
475		if ((fcntl(fd, F_SETLK, thislock)) < 0) {
476			tst_resm(TFAIL, "First parent lock failed");
477			tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
478				 errno);
479			close(fd);
480			unlink(tmpname);
481			return 1;
482		}
483
484		/* Initialize second parent lock structure */
485		thislock = &thiscase->parent_b;
486
487		if ((thislock->type) != IGNORED) {	/*SKIPVAL */
488			/* set the second parent lock */
489			if ((fcntl(fd, F_SETLK, thislock)) < 0) {
490				tst_resm(TFAIL, "Second parent lock failed");
491				tst_resm(TFAIL, "Test case %d, errno = %d",
492					 test + 1, errno);
493				close(fd);
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			close(fd);
565			unlink(tmpname);
566			return 1;
567		}
568
569		/* Initialize fourth parent lock structure */
570		thislock = &thiscase->parent_d;
571
572		if ((thislock->type) != IGNORED) {	/*SKIPVAL */
573			/* set the fourth parent lock */
574			if ((fcntl(fd, F_SETLK, thislock)) < 0) {
575				tst_resm(TINFO, "Fourth parent lock failed");
576				tst_resm(TINFO, "Test case %d, errno = %d",
577					 test + 1, errno);
578				close(fd);
579				unlink(tmpname);
580				return 1;
581			}
582		}
583
584		/*
585		 * Wait for children to exit, or for timeout to occur.
586		 * Timeouts are expected for testcases where kids are
587		 * 'WILLBLOCK', In that case, send kids a wakeup interrupt
588		 * and wait again for them. If a second timeout occurs, then
589		 * something is wrong.
590		 */
591		alarm_flag = nexited = 0;
592		while (nexited < child_count) {
593			alarm(TIME_OUT);
594			child = wait(&status);
595			alarm(0);
596
597			if (child == -1) {
598				if (errno != EINTR || alarm_flag != 1) {
599					/*
600					 * Some error other than a timeout,
601					 * or else this is the second
602					 * timeout. Both cases are errors.
603					 */
604					break;
605				}
606
607				/*
608				 * Expected timeout case. Signal kids then
609				 * go back and wait again
610				 */
611				child_sig(SIGUSR1, child_count);
612				continue;
613			}
614
615			for (i = 0; i < child_count; i++)
616				if (child == child_pid[i])
617					break;
618			if (i == child_count) {
619				/*
620				 * Ignore unexpected kid, it could be a
621				 * leftover from a previous iteration that
622				 * timed out.
623				 */
624				continue;
625			}
626
627			/* Found the right kid, check his status */
628			nexited++;
629
630			expect_stat = (flag[i] == NOBLOCK) ? 0 : 1;
631
632			if (!WIFEXITED(status)
633			    || WEXITSTATUS(status) != expect_stat) {
634				/* got unexpected exit status from kid */
635				tst_resm(TFAIL, "Test case %d: child %d %s "
636					 "or got bad status (x%x)", test + 1,
637					 i, (flag[i] == NOBLOCK) ?
638					 "BLOCKED unexpectedly" :
639					 "failed to BLOCK", status);
640				fail = 1;
641			}
642		}
643
644		if (nexited != child_count) {
645			tst_resm(TFAIL, "Test case %d, caught %d expected %d "
646				 "children", test + 1, nexited, child_count);
647			child_sig(SIGKILL, nexited);
648			fail = 1;
649		}
650		close(fd);
651	}
652	unlink(tmpname);
653	if (fail) {
654		return 1;
655	} else {
656		return 0;
657	}
658	return 0;
659}
660
661int main(int ac, char **av)
662{
663
664	int lc;
665	char *msg;
666
667	if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) {
668		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
669	}
670#ifdef UCLINUX
671	maybe_run_child(dochild_uc, "ddddd", &kid_uc, &parent, &test,
672			&thislock, &fd);
673	argv0 = av[0];
674#endif
675
676	setup();		/* global setup */
677
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	tst_exit();
731}
732