| /* |
| * 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., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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: sigrelse01.c,v 1.14 2009/08/28 14:10:16 vapier Exp $ */ |
| /***************************************************************************** |
| * OS Test - Silicon Graphics, Inc. Eagan, Minnesota |
| * |
| * TEST IDENTIFIER : sigrelse01 Releasing held signals. |
| * |
| * PARENT DOCUMENT : sgrtds01 sigrelse system call |
| * |
| * AUTHOR : Bob Clark |
| * : Rewrote 12/92 by Richard Logan |
| * |
| * CO-PILOT : Dave Baumgartner |
| * |
| * DATE STARTED : 10/08/86 |
| * |
| * TEST ITEMS |
| * |
| * 1. sigrelse turns on the receipt of signals held by sighold. |
| * |
| * SPECIAL PROCEDURAL REQUIRMENTS |
| * None |
| * |
| * DETAILED DESCRIPTION |
| * set up pipe for parent/child communications |
| * fork off a child process |
| * |
| * parent(): |
| * set up for unexpected signals |
| * wait for child to send ready message over pipe |
| * send all catchable signals to child process |
| * send alarm signal to speed up timeout |
| * wait for child to terminate and check exit value |
| * |
| * if exit value is EXIT_OK |
| * get message from pipe (contains array of signal counters) |
| * loop through array of signal counters and record any |
| * signals which were not caught once. |
| * record PASS or FAIL depending on what was found in the array. |
| * |
| * else if exit is SIG_CAUGHT then BROK (signal caught |
| * before released) |
| * else if exit is WRITE_BROK then BROK (write() to pipe failed) |
| * else if exit is HANDLE_ERR then BROK (error in child's |
| * signal handler) |
| * else unexpected exit value - BROK |
| * |
| * child(): |
| * phase 1: |
| * set up to catch all catchable signals (exit SIG_CAUGHT |
| * if caught) |
| * hold each signal with sighold() |
| * send parent ready message if setup went ok. |
| * wait for signals to arrive - timeout if they don't |
| * |
| * phase 2: |
| * release each signal and wait a second for the handler to |
| * catch it. |
| * (the handler will record each signal it catches in an array |
| * and exit HANDLE_ERR if an error occurs) |
| * |
| * send array of counters back to parent for processing. |
| * exit EXIT_OK |
| * NOTES |
| * since child is executing system calls under test, no |
| * system call times are printed. |
| * |
| ***************************************************************************/ |
| |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <signal.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include <unistd.h> |
| #include "test.h" |
| #include "usctest.h" |
| #include "safe_macros.h" |
| |
| #ifdef __linux__ |
| /* glibc2.2 definition needs -D_XOPEN_SOURCE, which breaks other things. */ |
| extern int sighold(int __sig); |
| extern int sigrelse(int __sig); |
| #endif |
| |
| /* Needed for NPTL */ |
| #define SIGCANCEL 32 |
| #define SIGTIMER 33 |
| |
| void setup(); |
| void cleanup(); |
| static void parent(); |
| static void child(); |
| static void timeout(); |
| static int setup_sigs(); |
| static void handler(); |
| static void wait_a_while(); |
| static char *read_pipe(); |
| static int write_pipe(); |
| static int set_timeout(); |
| static void clear_timeout(); |
| static void getout(); |
| int choose_sig(int sig); |
| |
| #define TRUE 1 |
| #define FALSE 0 |
| |
| #ifndef DEBUG |
| #define DEBUG 0 |
| #endif |
| |
| #define CHILD_EXIT(VAL) ((VAL >> 8) & 0377) /* exit value of child process */ |
| #define CHILD_SIG(VAL) (VAL & 0377) /* signal value of child proc */ |
| |
| #define MAXMESG 512 /* the size of the message string */ |
| |
| #define READY "ready" /* signal to parent that child is set up */ |
| |
| #define TIMEOUT 30 /* time (sec) used in the alarm calls */ |
| |
| /* child exit values */ |
| #define EXIT_OK 0 |
| #define SIG_CAUGHT 8 |
| #define WRITE_BROK 16 |
| #define HANDLE_ERR 32 |
| |
| int TST_TOTAL = 1; /* number of test items */ |
| |
| char *TCID = "sigrelse01"; /* test case identifier */ |
| static char mesg[MAXMESG]; /* message buffer for tst_res */ |
| static int pid; /* process id of child */ |
| static int pipe_fd[2]; /* file descriptors for pipe parent read */ |
| static int pipe_fd2[2]; /* file descriptors for pipe child read */ |
| static int phase; /* flag for phase1 or phase2 of */ |
| /* signal handler */ |
| static int sig_caught; /* flag TRUE if signal caught */ |
| /* (see wait_a_while ()) */ |
| |
| /* ensure that NUMSIGS is defined. */ |
| #ifndef NUMSIGS |
| #define NUMSIGS NSIG |
| #endif |
| |
| /* array of counters for signals caught by handler() */ |
| static int sig_array[NUMSIGS]; |
| |
| /*********************************************************************** |
| * M A I N |
| ***********************************************************************/ |
| int main(int argc, char **argv) |
| { |
| int lc; |
| char *msg; |
| |
| /* gcc -Wall complains about sig_caught not being ref'd because of the |
| external declarations. */ |
| sig_caught = FALSE; |
| |
| /* |
| * parse standard options |
| */ |
| if ((msg = parse_opts(argc, argv, NULL, NULL)) != NULL) { |
| tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); |
| |
| } |
| #ifdef UCLINUX |
| maybe_run_child(&child, "dd", &pipe_fd[1], &pipe_fd2[0]); |
| #endif |
| |
| /* |
| * perform global setup for test |
| */ |
| setup(); |
| |
| for (lc = 0; TEST_LOOPING(lc); lc++) { |
| |
| Tst_count = 0; |
| |
| /* |
| * fork off a child process |
| */ |
| if ((pid = FORK_OR_VFORK()) < 0) { |
| tst_brkm(TBROK | TERRNO, cleanup, "fork() failed"); |
| |
| } else if (pid > 0) { |
| parent(); |
| |
| } else { |
| #ifdef UCLINUX |
| if (self_exec(argv[0], "dd", pipe_fd[1], pipe_fd2[0]) < |
| 0) { |
| tst_brkm(TBROK | TERRNO, cleanup, |
| "self_exec() failed"); |
| } |
| #else |
| child(); |
| #endif |
| } |
| |
| } |
| |
| cleanup(); |
| tst_exit(); |
| |
| } /* end main */ |
| |
| /**************************************************************************** |
| * parent() : wait for "ready" from child, send signals to child, wait for |
| * child to exit and report what happened. |
| ***************************************************************************/ |
| static void parent() |
| { |
| int term_stat; /* child return status */ |
| int rv; /* function return value */ |
| int sig; /* current signal number */ |
| char *str; /* string returned from read_pipe() */ |
| int *array; /* pointer to sig_array returned from child */ |
| int fail = FALSE; /* flag indicating test item failure */ |
| char big_mesg[MAXMESG * 6]; /* storage for big failure message */ |
| int caught_sigs; |
| |
| /* wait for "ready" message from child */ |
| if ((str = read_pipe(pipe_fd[0])) == NULL) { |
| /* read_pipe() failed. */ |
| tst_brkm(TBROK, getout, "%s", mesg); |
| } |
| |
| if (strcmp(str, READY) != 0) { |
| /* child setup did not go well */ |
| tst_brkm(TBROK, getout, "%s", str); |
| } |
| |
| /* |
| * send signals to child and see if it holds them |
| */ |
| |
| for (sig = 1; sig < NUMSIGS; sig++) { |
| if (choose_sig(sig)) { |
| if (kill(pid, sig) < 0) { |
| if (errno == ESRCH) { |
| if (kill(pid, SIGTERM) < 0) |
| tst_brkm(TBROK | TERRNO, getout, |
| "kill(%d, %d) and kill(%d, SIGTERM) failed", |
| pid, sig, pid); |
| else |
| tst_brkm(TBROK | TERRNO, getout, |
| "kill(%d, %d) failed, but kill(%d, SIGTERM) worked", |
| pid, sig, pid); |
| } else |
| tst_brkm(TBROK | TERRNO, getout, |
| "kill(%d, %d) failed", pid, |
| sig); |
| } |
| } |
| } |
| |
| if (write_pipe(pipe_fd2[1], READY) < 0) { |
| tst_brkm(TBROK | TERRNO, getout, |
| "Unable to tell child to go, write to pipe failed"); |
| } |
| |
| /* |
| * child is now releasing signals, wait and check exit value |
| */ |
| if (wait(&term_stat) < 0) |
| tst_brkm(TBROK | TERRNO, getout, "wait() failed"); |
| |
| /* check child's signal exit value */ |
| if ((sig = CHILD_SIG(term_stat)) != 0) |
| /* the child was zapped by a signal */ |
| tst_brkm(TBROK, cleanup, "Unexpected signal %d killed child", |
| sig); |
| |
| /* get child exit value */ |
| |
| rv = CHILD_EXIT(term_stat); |
| |
| switch (rv) { |
| case EXIT_OK: |
| /* sig_array sent back on pipe, check it out */ |
| if ((array = (int *)read_pipe(pipe_fd[0])) == NULL) { |
| /* read_pipe() failed. */ |
| tst_resm(TBROK, "%s", mesg); |
| break; |
| } |
| #if DEBUG > 1 |
| for (sig = 1; sig < NUMSIGS; sig++) { |
| printf("array[%d] = %d\n", sig, array[sig]); |
| } |
| #endif |
| caught_sigs = 0; |
| for (sig = 1; sig < NUMSIGS; sig++) { |
| if (choose_sig(sig)) { |
| if (array[sig] != 1) { |
| /* sig was not caught or caught too many times */ |
| (void)sprintf(mesg, |
| "\tsignal %d caught %d times (expected 1).\n", |
| sig, array[sig]); |
| (void)strcat(big_mesg, mesg); |
| fail = TRUE; |
| } else { |
| caught_sigs++; |
| } |
| } |
| } /* endfor */ |
| |
| if (fail == TRUE) |
| tst_resm(TFAIL, "%s", big_mesg); |
| else |
| tst_resm(TPASS, |
| "sigrelse() released all %d signals under test.", |
| caught_sigs); |
| break; |
| |
| case TBROK: |
| /* get BROK message from pipe */ |
| if ((str = read_pipe(pipe_fd[0])) == NULL) { |
| /* read_pipe() failed. */ |
| tst_resm(TBROK, "%s", mesg); |
| break; |
| } |
| |
| /* call tst_res: str contains the message */ |
| tst_resm(TBROK, "%s", str); |
| break; |
| case SIG_CAUGHT: |
| /* a signal was caught before it was released */ |
| tst_resm(TBROK, "A signal was caught before being released."); |
| break; |
| case WRITE_BROK: |
| /* the write() call failed in child's write_pipe */ |
| tst_resm(TBROK, "write() pipe failed for child."); |
| break; |
| case HANDLE_ERR: |
| /* more than one signal tried to be handled at the same time */ |
| tst_resm(TBROK, "Error occured in signal handler."); |
| break; |
| default: |
| tst_resm(TBROK, "Unexpected exit code %d from child", rv); |
| break; |
| } |
| |
| } /* end of parent */ |
| |
| /**************************************************************************** |
| * child() : hold signals, notify parent and wait for parent to send signals. |
| * If none were caught (sighold worked), release the signals one at a time |
| * and wait for them to be caught. Send results back to parent |
| * for processing. |
| ***************************************************************************/ |
| static void child() |
| { |
| int rv; /* return value from sighold() and sigrelse() */ |
| int sig; /* signal value */ |
| int exit_val; /* exit value to send to parent */ |
| char note[MAXMESG]; /* message buffer for pipe */ |
| char *str; |
| |
| phase = 1; /* tell handler that we do not want to catch signals */ |
| |
| /* set note to READY and if an error occurs, overwrite it */ |
| (void)strcpy(note, READY); |
| |
| /* set alarm in case something hangs */ |
| if (set_timeout() < 0) { |
| /* an error occured - put mesg in note and send it back to parent */ |
| (void)strcpy(note, mesg); |
| |
| } else if (setup_sigs() < 0) { |
| /* an error occured - put mesg in note and send it back to parent */ |
| (void)strcpy(note, mesg); |
| |
| } else { |
| /* all set up to catch signals, now hold them */ |
| |
| for (sig = 1; sig < NUMSIGS; sig++) { |
| if (choose_sig(sig)) { |
| if ((rv = sighold(sig)) != 0) { |
| /* THEY say sighold ALWAYS returns 0 */ |
| (void)sprintf(note, |
| "sighold did not return 0. rv:%d", |
| rv); |
| break; |
| } |
| } |
| } |
| |
| } |
| |
| /* |
| * send note to parent (if not READY, parent will BROK) and |
| * wait for parent to send signals. The timeout clock is set so |
| * that we will not wait forever - if sighold() did its job, we |
| * will not receive the signals. If sighold() blew it we will |
| * catch a signal and the interrupt handler will exit with a |
| * value of SIG_CAUGHT. |
| */ |
| if (write_pipe(pipe_fd[1], note) < 0) { |
| /* |
| * write_pipe() failed. Set exit value to WRITE_BROK to let |
| * parent know what happened |
| */ |
| clear_timeout(); |
| exit(WRITE_BROK); |
| } |
| |
| /* |
| * if we get to this point, all signals have been held and the |
| * timer has expired. Now what we want to do is release each |
| * signal and see if we catch it. If we catch all signals, |
| * sigrelse passed, else it failed. |
| */ |
| |
| phase = 2; /* let handler know we are now expecting signals */ |
| |
| #if DEBUG > 0 |
| printf("child: PHASE II\n"); |
| #endif |
| |
| /* assume success and overwrite exit_val if an error occurs */ |
| exit_val = EXIT_OK; |
| |
| #if DEBUG > 0 |
| printf("child: pid=%d waiting for parent's ready...\n", getpid()); |
| #endif |
| |
| /* |
| * wait for parent to tell us that sigals were all sent |
| */ |
| |
| /* wait for "ready" message from parent */ |
| if ((str = read_pipe(pipe_fd2[0])) == NULL) { |
| /* read_pipe() failed. */ |
| printf(" child: read_pipe failed\n"); |
| exit(TBROK); |
| } |
| |
| if (strcmp(str, READY) != 0) { |
| /* parent/pipe problem */ |
| printf("child: didn't proper ready message\n"); |
| exit(TBROK); |
| } |
| |
| for (sig = 1; sig < NUMSIGS; sig++) { |
| if (choose_sig(sig)) { |
| |
| /* all set up, release and catch a signal */ |
| |
| sig_caught = FALSE; /* handler sets it to TRUE when caught */ |
| #if DEBUG > 1 |
| printf("child: releasing sig %d...\n", sig); |
| #endif |
| if ((rv = sigrelse(sig)) != 0) { |
| /* THEY say sigrelse ALWAYS returns 0 */ |
| (void)sprintf(note, |
| "sigrelse did not return 0. rv:%d", |
| rv); |
| exit_val = TBROK; |
| break; |
| } |
| |
| /* give signal handler some time to process signal */ |
| wait_a_while(); |
| } |
| |
| } /* endfor */ |
| |
| /* |
| * If we are error free so far... |
| * check the sig_array array for one occurence of |
| * each of the catchable signals. If this is true, |
| * then PASS, otherwise FAIL. |
| */ |
| |
| if (exit_val == EXIT_OK) { |
| (void)memcpy(note, (char *)sig_array, sizeof(sig_array)); |
| } |
| |
| /* send note to parent and exit */ |
| if (write_pipe(pipe_fd[1], note) < 0) { |
| /* |
| * write_pipe() failed. Set exit value to WRITE_BROK to let |
| * parent know what happened |
| */ |
| exit(WRITE_BROK); |
| } |
| |
| exit(exit_val); |
| |
| } /* end of child */ |
| |
| /***************************************************************************** |
| * setup_sigs() : set child up to catch all signals. If there is |
| * trouble, write message in mesg and return -1, else return 0. |
| * The signal handler has two functions depending on which phase |
| * of the test we are in. The first section is executed after the |
| * signals have been held (should not ever be used). The second |
| * section is executed after the signals have been released (should |
| * be executed for each signal). |
| ****************************************************************************/ |
| static int setup_sigs() |
| { |
| int sig; |
| |
| /* set up signal handler routine */ |
| for (sig = 1; sig < NUMSIGS; sig++) { |
| if (choose_sig(sig)) { |
| if (signal(sig, handler) == SIG_ERR) { |
| /* set up mesg to send back to parent */ |
| (void)sprintf(mesg, |
| "signal() failed for signal %d. error:%d %s.", |
| sig, errno, strerror(errno)); |
| return (-1); |
| } |
| } |
| } |
| return 0; |
| |
| } /* end of setup_sigs */ |
| |
| /***************************************************************************** |
| * handler() : child's interrupt handler for all signals. The phase variable |
| * is set in the child process indicating what action is to be taken. |
| * The phase 1 section will be run if the child process catches a signal |
| * after the signal has been held resulting in a test item BROK. |
| * The parent detects this situation by a child exit value of SIG_CAUGHT. |
| * The phase 2 section will be run if the child process catches a |
| * signal after the signal has been released. All signals must be |
| * caught in order for a PASS. |
| ****************************************************************************/ |
| static void handler(int sig) |
| { |
| static int s = 0; /* semaphore so that we don't handle 2 */ |
| /* sigs at once */ |
| #if DEBUG > 1 |
| printf("child: handler phase%d: caught signal %d.\n", phase, sig); |
| #endif |
| |
| if (phase == 1) { |
| /* exit the child process with a value of -1 */ |
| exit(SIG_CAUGHT); |
| |
| } else { |
| /* phase 2 (error if s gets incremented twice) */ |
| ++s; |
| |
| if (s > 1) { |
| exit(HANDLE_ERR); |
| } |
| |
| /* increment the array element for this signal */ |
| ++sig_array[sig]; |
| sig_caught = TRUE; /* flag for wait_a_while () */ |
| --s; |
| } |
| |
| return; |
| |
| } /* end of handler */ |
| |
| /***************************************************************************** |
| * read_pipe() : read data from pipe and return in buf. If an error occurs |
| * put message in mesg and return NULL. Note: this routine sets a |
| * timeout signal in case the pipe is blocked. |
| ****************************************************************************/ |
| static char *read_pipe(fd) |
| int fd; |
| { |
| static char buf[MAXMESG]; /* buffer for pipe read */ |
| int ret; |
| |
| #if DEBUG > 0 |
| printf("read_pipe: pid=%d waiting...\n", getpid()); |
| #endif |
| |
| /* set timeout alarm in case the pipe is blocked */ |
| if (set_timeout() < 0) { |
| /* an error occured, message in mesg */ |
| return NULL; |
| } |
| |
| ret = -1; |
| while (ret == -1) { /* while empty reads */ |
| if ((ret = read(fd, buf, MAXMESG)) == 0) { |
| (void)sprintf(mesg, "read() pipe failed. error:%d %s.", |
| errno, strerror(errno)); |
| |
| clear_timeout(); |
| return NULL; |
| } |
| } |
| clear_timeout(); |
| |
| #if DEBUG > 0 |
| printf("read_pipe: pid=%d received: %s.\n", getpid(), buf); |
| #endif |
| return (buf); |
| |
| } /* end of read_pipe */ |
| |
| /***************************************************************************** |
| * write_pipe(msg) : write msg to pipe. If it fails, put message in |
| * mesg and return -1, else return 0. |
| ****************************************************************************/ |
| static int write_pipe(int fd, char *msg) |
| { |
| |
| #if DEBUG > 0 |
| printf("write_pipe: pid=%d, sending %s.\n", getpid(), msg); |
| #endif |
| |
| if (write(fd, msg, MAXMESG) < 0) { |
| (void)sprintf(mesg, "write() pipe failed. error:%d %s.", |
| errno, strerror(errno)); |
| |
| return (-1); |
| } |
| return 0; |
| |
| } /* end of write_pipe */ |
| |
| /***************************************************************************** |
| * set_timeout() : set alarm to signal process after the period of time |
| * indicated by TIMEOUT. If the signal occurs, the routine timeout() |
| * will be executed. If all goes ok, return 0, else load message |
| * into mesg and return -1. |
| ****************************************************************************/ |
| static int set_timeout() |
| { |
| if (signal(SIGALRM, timeout) == SIG_ERR) { |
| (void)sprintf(mesg, |
| "signal() failed for signal %d. error:%d %s.", |
| SIGALRM, errno, strerror(errno)); |
| return (-1); |
| } |
| |
| (void)alarm(TIMEOUT); |
| return 0; |
| |
| } /* end of set_timeout */ |
| |
| /***************************************************************************** |
| * clear_timeout() : turn off the alarm so that SIGALRM will not get sent. |
| ****************************************************************************/ |
| static void clear_timeout() |
| { |
| (void)alarm(0); |
| |
| } /* end of clear_timeout */ |
| |
| /***************************************************************************** |
| * timeout() : this routine is executed when the SIGALRM signal is |
| * caught. It does nothing but return - the read() on the pipe |
| * will fail. |
| ****************************************************************************/ |
| static void timeout() |
| { |
| #if DEBUG > 0 |
| printf("timeout: pid=%d sigalrm caught.\n", getpid()); |
| #endif |
| } |
| |
| /***************************************************************************** |
| * wait_a_while () : wait a while before returning. |
| ****************************************************************************/ |
| static void wait_a_while() |
| { |
| long btime; |
| |
| btime = time((long *)0); |
| while (time((long *)0) - btime < (long)TIMEOUT) { |
| if (sig_caught == TRUE) |
| break; |
| } |
| } /* end of wait_a_while */ |
| |
| static void getout() |
| { |
| if (pid > 0 && kill(pid, SIGKILL) < 0) |
| tst_resm(TWARN, "kill(%d, SIGKILL) failed", pid); |
| cleanup(); |
| |
| } /* end of getout */ |
| |
| #ifdef VAX |
| static int sighold(int signo) |
| { |
| return 0; |
| } |
| |
| static int sigrelse(signo) |
| int signo; |
| { |
| return 0; |
| } |
| #endif |
| |
| int choose_sig(int sig) |
| { |
| switch (sig) { |
| |
| case SIGKILL: |
| case SIGSTOP: |
| case SIGTSTP: |
| case SIGCONT: |
| case SIGALRM: |
| case SIGCANCEL: |
| case SIGTIMER: |
| #ifdef SIGNOBDM |
| case SIGNOBDM: |
| #endif |
| #ifdef SIGTTIN |
| case SIGTTIN: |
| #endif |
| #ifdef SIGTTOU |
| case SIGTTOU: |
| #endif |
| #ifdef SIGPTINTR |
| case SIGPTINTR: |
| #endif |
| #ifdef SIGSWAP |
| case SIGSWAP: |
| #endif |
| return 0; |
| |
| } |
| |
| return 1; |
| |
| } |
| |
| void setup() |
| { |
| |
| tst_sig(FORK, DEF_HANDLER, cleanup); |
| |
| TEST_PAUSE; |
| |
| tst_tmpdir(); |
| |
| /* set up pipe for parent/child communications */ |
| SAFE_PIPE(cleanup, pipe_fd); |
| |
| /* |
| * Cause the read to return 0 once EOF is encountered and the |
| * read to return -1 if pipe is empty. |
| */ |
| if (fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK) == -1) |
| tst_brkm(TBROK | TERRNO, cleanup, |
| "fcntl(Fds[0], F_SETFL, O_NONBLOCK) failed"); |
| |
| /* set up pipe for parent/child communications */ |
| SAFE_PIPE(cleanup, pipe_fd2); |
| |
| /* |
| * Cause the read to return 0 once EOF is encountered and the |
| * read to return -1 if pipe is empty. |
| */ |
| if (fcntl(pipe_fd2[0], F_SETFL, O_NONBLOCK) == -1) |
| tst_brkm(TBROK | TERRNO, cleanup, |
| "fcntl(Fds[0], F_SETFL, O_NONBLOCK) failed"); |
| } |
| |
| void cleanup() |
| { |
| TEST_CLEANUP; |
| |
| tst_rmdir(); |
| |
| } |