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