diff options
author | Egor Duda <deo@logos-m.ru> | 2001-09-09 17:38:17 +0400 |
---|---|---|
committer | Egor Duda <deo@logos-m.ru> | 2001-09-09 17:38:17 +0400 |
commit | d961def403a334176adb4c79cb02385bfca230e7 (patch) | |
tree | 3863580db025e747aa1a5cf6f69fa0be5894e426 /winsup/testsuite/winsup.api/ltp/signal03.c | |
parent | 92ef5188af2deecd2054462bf940f6460d127fe9 (diff) |
* winsup.api/ltp/dup03.c: New test.
* winsup.api/ltp/lseek03.c: Ditto.
* winsup.api/ltp/mmap001.c: Ditto.
* winsup.api/ltp/read01.c: Ditto.
* winsup.api/ltp/readdir01.c: Ditto.
* winsup.api/ltp/rmdir05.c: Ditto.
* winsup.api/ltp/sbrk01.c: Ditto.
* winsup.api/ltp/select02.c: Ditto.
* winsup.api/ltp/select03.c: Ditto.
* winsup.api/ltp/signal03.c: Ditto.
* winsup.api/ltp/stat06.c: Ditto.
* winsup.api/ltp/unlink08.c: Ditto.
* winsup.api/known_bugs.tcl: Update to reflect new test's known
failures.
* winsup.api/winsup.exp: Don't delete executable in case of
unexpected pass, as well as in case of unexpected failure.
* README: Update paragraph about expected failures.
Diffstat (limited to 'winsup/testsuite/winsup.api/ltp/signal03.c')
-rw-r--r-- | winsup/testsuite/winsup.api/ltp/signal03.c | 665 |
1 files changed, 665 insertions, 0 deletions
diff --git a/winsup/testsuite/winsup.api/ltp/signal03.c b/winsup/testsuite/winsup.api/ltp/signal03.c new file mode 100644 index 000000000..38ba72b3c --- /dev/null +++ b/winsup/testsuite/winsup.api/ltp/signal03.c @@ -0,0 +1,665 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * + */ +/* $Id$ */ +/*********************************************************************************** + * + * OS Test - Silicon Graphics, Inc. Eagan, Minnesota + * + * TEST IDENTIFIER : signal03 Boundary value and other invalid value checking + * of signal setup and signal sending. + * + * PARENT DOCUMENT : sgntds01 Signal System Call + * + * AUTHOR : Dave Baumgartner + * : Rewrote 12/92 by Richard Logan + * + * CO-PILOT : Barrie Kletscher + * + * DATE STARTED : 10/17/85 + * + * TEST ITEMS + * + * 1. SIGKILL can not be set to be caught, errno:EINVAL (POSIX). + * 2. SIGKILL can not be caught. + * 3. SIGKILL can not be set to be ignored, errno:EINVAL (POSIX). + * 4. SIGKILL can not be ignored. + * 5. SIGKILL can not be reset to default, errno:EINVAL (POSIX. + * + * ENVIRONMENTAL NEEDS + * + * NONE + * + * SPECIAL PROCEDURAL REQUIREMENTS + * + * None + * + * INTERCASE DEPENDENCIES + * + * 2 depends on 1 and 4 on 3. + * + * DETAILED DESCRIPTION + * + * main() + * Call catch_test to test setup and catching of SIGKILL. + * + * + * Call ignore_test to test setup and ignoring of SIGKILL. + * + * + * Call sigdfl_test to test setting SIGKILL to default. + * + * * END OF MAIN * + * + * + * catch_test() + * + * fork a child + * if this is the parent + * sleep to let child start. + * send sig to child. + * wait for the child to terminate. + * + * if the termination status of the child equals the signal sent to it + * Test item 1 PASSED the child was killed. + * else if status equals the exit value of SIG_CAUGHT + * Test item 2 FAILED sig was caught. + * else + * Test item 2 FAILED because the child was not killed + * but sig was not caught either. + * + * else this the child + * set exit_val to SIG_NOT_CAUGHT. + * set to catch sig, where the interrupt routine just sets + * exit_val to SIG_CAUGHT. + * + * If the return value and errno, after trying to set to catch sig, + * do not indicate that an error has occurred. + * Test item 1 FAILED bad return, return value:X, errno:X. + * else + * Test item 1 PASSED sig was not set to be caught. + * + * pause until the parent sends a signal. + * The child should be killed by the signal but if not exit + * with exit_val. + * + * * End of catch_test. * + * + * + * ignore_test() + * + * fork a child + * if this is the parent + * sleep to let child start. + * send SIGKILL to child. + * wait for the child to terminate. + * + * if the termination status of the child equals SIGKILL + * Test item 4 PASSED the child was killed. + * else if the status equals the exit value of SIG_IGNORED + * Test item 4 FAILED SIGKILL was ignored. + * + * else this the child + * + * If the return value and errno, after trying to set to ignore SIGKILL, + * do not indicate that an error has occurred. + * Test item 3 FAILED bad return, return value:X, errno:X. + * else + * Test item 3 PASSED SIGKILL was not set to be ignored. + * + * pause until the parent sends SIGKILL. + * The child should be killed by the signal but if not exit + * with SIG_IGNORED. + * + * * End of ignore_test. * + * + * + * sigdfl_test() + * + * If the return value and errno, after trying to set to SIGKILL to default, + * do not indicate that an error has occurred. + * Test item 5 FAILED bad return, return value:X, errno:X. + * else + * Test item 5 PASSED SIGKILL was not set to default. + * + * * End of sigdfl_test. * + * + * BUGS/NOTES + * Since the system call under test is executed in the child, no + * timings on this system call will be reported. + * +***********************************************************************************/ + +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <sys/wait.h> + +#include "test.h" +#include "usctest.h" + +void setup(); +void cleanup(); +void do_test(); +void sigdfl_test(); +void update_timings(); + +#if defined(linux) +# define SIG_PF sig_t /* This might need to be sighandler_t on some systems */ +#elif defined(__CYGWIN__) +typedef void (*sighandler_t) (int); +#define SIG_PF sighandler_t +#endif + +#define SIG_CAUGHT 1 +#define SIG_NOT_CAUGHT 0 +#define SIG_IGNORED 5 +#define TIMED_OUT 99 + +#define TIMEOUT 20 + +#define GO_FLAG 1 +#define ERROR_FLAG 2 +#define PASS_FLAG 3 +#define FAIL_FLAG 4 + +#define IGNORE_TEST 1 +#define CATCH_TEST 2 + +#define MAXMESG 150 /* The Maximum message that can be created. */ + +int exit_val; /* Global variable, used to tell whether the */ + /* child exited instead of being killed. */ +extern int errno; /* errno holds the error value returned by */ + /* a system call. */ +char mesg[MAXMESG]; /* Holds messages to pass to tst_res. */ + +struct ipc_t { + int status; + char mesg[MAXMESG]; + struct tblock timings; +} Ipc_info; + +char *TCID = "signal03"; +int TST_TOTAL = 5; +extern int Tst_count; /* count of test items completed */ + +int Pid; /* Return value from fork. */ + +long Tret; + +/*********************************************************************** + * M A I N + ***********************************************************************/ +int +main(argc, argv) +int argc; +char **argv; +{ + int lc; + const char *msg; + + /*************************************************************** + * parse standard options + ***************************************************************/ + if ( (msg=parse_opts(argc, argv, (option_t *) NULL, NULL)) != (char *) NULL ) { + tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); + tst_exit(); + } + + /*************************************************************** + * perform global setup for test + ***************************************************************/ + setup(); + + /*************************************************************** + * check looping state if -c option given + ***************************************************************/ + for (lc=0; TEST_LOOPING(lc); lc++) { + + /* reset Tst_count in case we are looping. */ + Tst_count=0; + + errno=-4; + + /* + * Call catch_test to test setup and catching of SIGKILL. + */ + (void) do_test(CATCH_TEST, Tst_count); + + /* + * Call ignore_test to test setup and ignoring of SIGKILL. + */ + (void) do_test(IGNORE_TEST, Tst_count); + + /* + * Call sigdfl_test to test setting SIGKILL to default. + */ + (void) sigdfl_test(); + + } + + cleanup(); + + return 0; +} /*End of main*/ + +/*********************************************************************** + * + ***********************************************************************/ +void +do_test(test_case, tst_count) +int test_case; +int tst_count; +{ + int term_stat; /* Termination status of the child returned to */ + /* the parent. */ + char string[30]; + int fd1[2]; /* ipc */ + int rd_sz; /* size of read */ + void p_timeout_handler(); + void c_timeout_handler(); + void catchsig(); + + Tst_count = tst_count; + + /* + * Create a pipe of ipc + */ + if ( pipe(fd1) == -1 ) { + sprintf(mesg, + "pipe system call failed, Errno: %d, Error message: %s", + errno,strerror(errno)); + tst_resm(TBROK,mesg); + tst_resm(TBROK,mesg); + return; + } + + /* + * Cause the read to return 0 once EOF is encountered and the + * read to return -1 if pipe is empty. + */ + + if ( fcntl(fd1[0], F_SETFL, O_NONBLOCK) == -1 ) { + sprintf(mesg, "fcntl(fd1[0], F_SETFL, O_NONBLOCK) failed: errno=%d", + errno); + tst_resm(TBROK,mesg); + tst_resm(TBROK,mesg); + close(fd1[0]); + close(fd1[1]); + return; + } + + if ((Pid = fork()) > 0) { /* parent */ + + signal(SIGALRM, p_timeout_handler); + + alarm(TIMEOUT); + + close(fd1[1]); /* close write side */ + + /* + * Deal with child's messages. + * Only the GO_FLAG status will allow parent to + * go on. All pipe io will be in the ipc_t structure sizes + * to avoid reading part of next message. + */ + while ( 1 ) { + + while ( (rd_sz=read(fd1[0], (char *)&Ipc_info, sizeof(Ipc_info))) != 0 ) { + if ( rd_sz > 0 ) + break; /* read something */ + } + + if ( rd_sz == 0 ) { /* if EOF encountered */ + sprintf(mesg, "child's pipe is closed before 'go' message received"); + tst_resm(TBROK, Ipc_info.mesg); + tst_resm(TBROK, Ipc_info.mesg); + close(fd1[0]); + return; + } + + else if ( Ipc_info.status == GO_FLAG ) { + break; /* go on */ + } + else if ( Ipc_info.status == ERROR_FLAG ) { + tst_resm(TBROK, "From child: %s", Ipc_info.mesg); + tst_resm(TBROK, "From child: %s", Ipc_info.mesg); + close(fd1[0]); + return; + } + else if ( Ipc_info.status == PASS_FLAG ) { + + if ( STD_FUNCTIONAL_TEST ) + tst_resm(TPASS, "From child: %s", Ipc_info.mesg); + else + Tst_count++; + update_timings(Ipc_info.timings); + } + else if ( Ipc_info.status == FAIL_FLAG ) { + tst_resm(TFAIL, "From child: %s", Ipc_info.mesg); + update_timings(Ipc_info.timings); + } + else { + tst_resm(TINFO, "Unknown message from child: %s", mesg); + } + } + + /* + * Send the signal SIGKILL to the child. + */ + if (kill(Pid,SIGKILL) == -1) + { + /* + * The kill system call failed. + */ + sprintf(mesg, + "kill(Pid,SIGKILL) failed, Errno: %d, Error message: %s", + errno,strerror(errno)); + tst_resm(TBROK,mesg); + tst_resm(TBROK,mesg); + close(fd1[0]); + return; + } + + /* + * Wait for the child to terminate and check the termination status. + */ + if (wait(&term_stat) == -1) { + /* + * The wait system call failed. + */ + sprintf(mesg, + "Wait system call failed. Errno: %d, Error message: %s", + errno,strerror(errno)); + tst_resm(TBROK,mesg); + tst_resm(TBROK,mesg); + close(fd1[0]); + return; + } + else if ( STD_FUNCTIONAL_TEST ) { + if ((term_stat & 0377) == SIGKILL) { + /* + * The child was killed by the signal sent, + * which is correct. + */ + tst_resm(TPASS,"The child was killed by SIGKILL."); + } + else if ( (term_stat >> 8) == TIMED_OUT ) { + sprintf(mesg, "child exited with a timed out exit status"); + tst_resm(TBROK,mesg); + } + else { + if ((term_stat >> 8) == SIG_IGNORED && test_case == IGNORE_TEST ) { + sprintf(mesg, + "SIGKILL was ignored by child after sent by parent."); + } + else if ((term_stat >> 8) == SIG_CAUGHT && test_case == CATCH_TEST ) { + sprintf(mesg, + "SIGKILL was caught by child after sent by parent."); + } + else { + sprintf(mesg, + "Child's termination status is unexpected. Status: %d (%#o).", + term_stat, term_stat); + } + tst_resm(TFAIL, mesg); + } + } + else { + Tst_count++; /* increment test counter */ + } + close(fd1[0]); + + } /* End of parent. */ + else if (Pid == 0) { + /* + * This is the child. + * Set up to ignore/catch SIGKILL and check the return values. + */ + errno=0; + if ( test_case == IGNORE_TEST ) { + exit_val = SIG_IGNORED; + strcpy(string, "signal(SIGKILL, SIG_IGN)"); + + Tret=(long)signal(SIGKILL, SIG_IGN); + TEST_ERRNO=errno; + } + else { + exit_val = SIG_NOT_CAUGHT; + strcpy(string, "signal(SIGKILL, catchsig)"); + Tret=(long)signal(SIGKILL, catchsig); + TEST_ERRNO=errno; + } + Ipc_info.timings=tblock; + + if ( (SIG_PF)Tret == SIG_ERR ) { + if ( TEST_ERRNO == EINVAL ) { + sprintf(Ipc_info.mesg, "%s ret:%ld SIG_ERR (%ld) as expected", + string, Tret, (long)SIG_ERR); + Ipc_info.status = PASS_FLAG; + } + else { + sprintf(Ipc_info.mesg, + "%s ret:%ld, errno:%d expected ret:%ld, errno:%d", + string, Tret, TEST_ERRNO, (long)SIG_ERR, EINVAL); + Ipc_info.status = FAIL_FLAG; + } + + write(fd1[1], (char *)&Ipc_info, sizeof(Ipc_info)); + } + else { + /* + * The child was not allowed to set the signal to + * be ignored and errno was correct. + */ + sprintf(Ipc_info.mesg, + "%s ret:%ld, errno:%d expected ret:%ld, errno:%d", + string, Tret, TEST_ERRNO, (long)SIG_ERR, EINVAL); + Ipc_info.status = FAIL_FLAG; + write(fd1[1], (char *)&Ipc_info, sizeof(Ipc_info)); + } + + /* + * tell parent we are ready - setup by child is done + */ + Ipc_info.status = GO_FLAG; + write(fd1[1], (char *)&Ipc_info, sizeof(Ipc_info)); + + /* + * Set the alarm to wake up from the pause below if + * the parents signal is ignored. + */ + signal(SIGALRM, p_timeout_handler); + alarm(TIMEOUT); + + /* + * Pause until the parent sends a signal or until alarm is received. + */ + pause(); + + exit(exit_val); + + + } /* End of child. */ + else { + /* + * The fork system call failed. + */ + sprintf(mesg, + "Fork system call failed. Errno: %d, Error message: %s", + errno,strerror(errno)); + tst_resm(TBROK,mesg); + tst_resm(TBROK,mesg); + close(fd1[0]); + close(fd1[1]); + return; + } + +} /* End of do_test. */ + +/*********************************************************************** + * sigdfl_test - test for attempt to set SIGKILL to default + ***********************************************************************/ +void +sigdfl_test() +{ + /* + * Try to set SIGKILL to default and check the return values. + */ + errno=-4; + + Tret=(long)signal(SIGKILL,SIG_DFL); + TEST_RETURN=Tret; + TEST_ERRNO=errno; + + + if ( (SIG_PF)TEST_RETURN == SIG_ERR ) { + if ( STD_FUNCTIONAL_TEST ) { + if ( TEST_ERRNO != EINVAL ) { + sprintf(mesg, + "signal(SIGKILL,SIG_DFL) ret:%d, errno:%d expected ret:-1, errno:%d", + TEST_RETURN, TEST_ERRNO, EINVAL); + tst_resm(TFAIL, mesg); + } + else { + sprintf(mesg, + "signal(SIGKILL,SIG_DFL) ret:%d, errno:%d as expected.", + TEST_RETURN, TEST_ERRNO); + tst_resm(TPASS, mesg); + } + } + else + Tst_count++; + } + else { + sprintf(mesg, + "signal(SIGKILL,SIG_DFL) ret:%d, errno:%d expected ret:-1, errno:%d", + TEST_RETURN, TEST_ERRNO, EINVAL); + tst_resm(TFAIL, mesg); + } + +} /* End of sigdfl_test. */ + +/*************************************************************** + * setup() - performs all ONE TIME setup for this test. + ***************************************************************/ +void +setup() +{ + /* capture signals */ + tst_sig(FORK, DEF_HANDLER, cleanup); + + /* make and change to a temporary directory */ + tst_tmpdir(); + + /* Pause if that option was specified */ + TEST_PAUSE; + +} /* End setup() */ + +/*************************************************************** + * cleanup() - performs all ONE TIME cleanup for this test at + * completion or premature exit. + ***************************************************************/ +void +cleanup() +{ + + /* + * print timing stats if that option was specified. + * print errno log if that option was specified. + */ + + TEST_CLEANUP; + + /* + * remove the temporary directory and exit with + * return code appropriate for results + */ + + tst_rmdir(); + + tst_exit(); + +} /* End cleanup() */ + +/*********************************************************************** + * Signal handler routine that used by the parent to handler + * a time out situation. It will attempt to kill the child and + * call cleanup. + ***********************************************************************/ +void +p_timeout_handler() +{ + kill(Pid, SIGKILL); + cleanup(); +} + +/*********************************************************************** + * Signal handler routine that used by the child to handle + * a time out situation. It will set a global varaible and return + * if called. + ***********************************************************************/ +void +c_timeout_handler() +{ + exit_val = TIMED_OUT; + return; +} + +/*********************************************************************** + * This signal handling routine will set a global variable and return + * if called. + ***********************************************************************/ +void +catchsig() +{ + exit_val = SIG_CAUGHT; + return; +} + +/*********************************************************************** + * Update timing information + ***********************************************************************/ +void +update_timings(atblock) +struct tblock atblock; +{ + tblock.tb_max += atblock.tb_max; + tblock.tb_min += atblock.tb_min; + tblock.tb_total += atblock.tb_total; + tblock.tb_count += atblock.tb_count; +} |