1/* 2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Further, this software is distributed without any warranty that it is 13 * free of the rightful claim of any third person regarding infringement 14 * or the like. Any license provided herein, whether implied or 15 * otherwise, applies only to this software file. Patent licenses, if 16 * any, provided herein do not apply to combinations of this program with 17 * other software, or any other product whatsoever. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write the Free Software Foundation, Inc., 21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 24 * Mountain View, CA 94043, or: 25 * 26 * http://www.sgi.com 27 * 28 * For further information regarding this notice, see: 29 * 30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ 31 * 32 */ 33/* $Id: sigrelse01.c,v 1.14 2009/08/28 14:10:16 vapier Exp $ */ 34/***************************************************************************** 35 * OS Test - Silicon Graphics, Inc. Eagan, Minnesota 36 * 37 * TEST IDENTIFIER : sigrelse01 Releasing held signals. 38 * 39 * PARENT DOCUMENT : sgrtds01 sigrelse system call 40 * 41 * AUTHOR : Bob Clark 42 * : Rewrote 12/92 by Richard Logan 43 * 44 * CO-PILOT : Dave Baumgartner 45 * 46 * DATE STARTED : 10/08/86 47 * 48 * TEST ITEMS 49 * 50 * 1. sigrelse turns on the receipt of signals held by sighold. 51 * 52 * SPECIAL PROCEDURAL REQUIRMENTS 53 * None 54 * 55 * DETAILED DESCRIPTION 56 * set up pipe for parent/child communications 57 * fork off a child process 58 * 59 * parent(): 60 * set up for unexpected signals 61 * wait for child to send ready message over pipe 62 * send all catchable signals to child process 63 * send alarm signal to speed up timeout 64 * wait for child to terminate and check exit value 65 * 66 * if exit value is EXIT_OK 67 * get message from pipe (contains array of signal counters) 68 * loop through array of signal counters and record any 69 * signals which were not caught once. 70 * record PASS or FAIL depending on what was found in the array. 71 * 72 * else if exit is SIG_CAUGHT then BROK (signal caught 73 * before released) 74 * else if exit is WRITE_BROK then BROK (write() to pipe failed) 75 * else if exit is HANDLE_ERR then BROK (error in child's 76 * signal handler) 77 * else unexpected exit value - BROK 78 * 79 * child(): 80 * phase 1: 81 * set up to catch all catchable signals (exit SIG_CAUGHT 82 * if caught) 83 * hold each signal with sighold() 84 * send parent ready message if setup went ok. 85 * wait for signals to arrive - timeout if they don't 86 * 87 * phase 2: 88 * release each signal and wait a second for the handler to 89 * catch it. 90 * (the handler will record each signal it catches in an array 91 * and exit HANDLE_ERR if an error occurs) 92 * 93 * send array of counters back to parent for processing. 94 * exit EXIT_OK 95 * NOTES 96 * since child is executing system calls under test, no 97 * system call times are printed. 98 * 99***************************************************************************/ 100 101#include <sys/types.h> 102#include <sys/wait.h> 103#include <errno.h> 104#include <fcntl.h> 105#include <signal.h> 106#include <stdlib.h> 107#include <string.h> 108#include <time.h> 109#include <unistd.h> 110#include "test.h" 111#include "safe_macros.h" 112 113#ifdef __linux__ 114/* glibc2.2 definition needs -D_XOPEN_SOURCE, which breaks other things. */ 115extern int sighold(int __sig); 116extern int sigrelse(int __sig); 117#endif 118 119/* Needed for NPTL */ 120#define SIGCANCEL 32 121#define SIGTIMER 33 122 123void setup(void); 124void cleanup(void); 125static void parent(void); 126static void child(void); 127static void timeout(int sig); 128static int setup_sigs(void); 129static void handler(int sig); 130static void wait_a_while(void); 131static char *read_pipe(int fd); 132static int write_pipe(int fd, char *msg); 133static int set_timeout(void); 134static void clear_timeout(void); 135static void getout(void); 136int choose_sig(int sig); 137 138#define TRUE 1 139#define FALSE 0 140 141#ifndef DEBUG 142#define DEBUG 0 143#endif 144 145#define CHILD_EXIT(VAL) ((VAL >> 8) & 0377) /* exit value of child process */ 146#define CHILD_SIG(VAL) (VAL & 0377) /* signal value of child proc */ 147 148#define MAXMESG 512 /* the size of the message string */ 149 150#define READY "ready" /* signal to parent that child is set up */ 151 152#define TIMEOUT 30 /* time (sec) used in the alarm calls */ 153 154/* child exit values */ 155#define EXIT_OK 0 156#define SIG_CAUGHT 8 157#define WRITE_BROK 16 158#define HANDLE_ERR 32 159 160int TST_TOTAL = 1; /* number of test items */ 161 162char *TCID = "sigrelse01"; /* test case identifier */ 163static char mesg[MAXMESG]; /* message buffer for tst_res */ 164static int pid; /* process id of child */ 165static int pipe_fd[2]; /* file descriptors for pipe parent read */ 166static int pipe_fd2[2]; /* file descriptors for pipe child read */ 167static int phase; /* flag for phase1 or phase2 of */ 168 /* signal handler */ 169static int sig_caught; /* flag TRUE if signal caught */ 170 /* (see wait_a_while ()) */ 171 172/* ensure that NUMSIGS is defined. */ 173#ifndef NUMSIGS 174#define NUMSIGS NSIG 175#endif 176 177/* array of counters for signals caught by handler() */ 178static int sig_array[NUMSIGS]; 179 180/*********************************************************************** 181 * M A I N 182 ***********************************************************************/ 183int main(int argc, char **argv) 184{ 185 int lc; 186 187 /* gcc -Wall complains about sig_caught not being ref'd because of the 188 external declarations. */ 189 sig_caught = FALSE; 190 191 /* 192 * parse standard options 193 */ 194 tst_parse_opts(argc, argv, NULL, NULL); 195#ifdef UCLINUX 196 maybe_run_child(&child, "dd", &pipe_fd[1], &pipe_fd2[0]); 197#endif 198 199 /* 200 * perform global setup for test 201 */ 202 setup(); 203 204 for (lc = 0; TEST_LOOPING(lc); lc++) { 205 206 tst_count = 0; 207 208 /* 209 * fork off a child process 210 */ 211 if ((pid = FORK_OR_VFORK()) < 0) { 212 tst_brkm(TBROK | TERRNO, cleanup, "fork() failed"); 213 214 } else if (pid > 0) { 215 parent(); 216 217 } else { 218#ifdef UCLINUX 219 if (self_exec(argv[0], "dd", pipe_fd[1], pipe_fd2[0]) < 220 0) { 221 tst_brkm(TBROK | TERRNO, cleanup, 222 "self_exec() failed"); 223 } 224#else 225 child(); 226#endif 227 } 228 229 } 230 231 cleanup(); 232 tst_exit(); 233 234} /* end main */ 235 236/**************************************************************************** 237 * parent() : wait for "ready" from child, send signals to child, wait for 238 * child to exit and report what happened. 239 ***************************************************************************/ 240static void parent(void) 241{ 242 int term_stat; /* child return status */ 243 int rv; /* function return value */ 244 int sig; /* current signal number */ 245 char *str; /* string returned from read_pipe() */ 246 int *array; /* pointer to sig_array returned from child */ 247 int fail = FALSE; /* flag indicating test item failure */ 248 char big_mesg[MAXMESG * 6]; /* storage for big failure message */ 249 int caught_sigs; 250 251 /* wait for "ready" message from child */ 252 if ((str = read_pipe(pipe_fd[0])) == NULL) { 253 /* read_pipe() failed. */ 254 tst_brkm(TBROK, getout, "%s", mesg); 255 } 256 257 if (strcmp(str, READY) != 0) { 258 /* child setup did not go well */ 259 tst_brkm(TBROK, getout, "%s", str); 260 } 261 262 /* 263 * send signals to child and see if it holds them 264 */ 265 266 for (sig = 1; sig < NUMSIGS; sig++) { 267 if (choose_sig(sig)) { 268 if (kill(pid, sig) < 0) { 269 if (errno == ESRCH) { 270 if (kill(pid, SIGTERM) < 0) 271 tst_brkm(TBROK | TERRNO, getout, 272 "kill(%d, %d) and kill(%d, SIGTERM) failed", 273 pid, sig, pid); 274 else 275 tst_brkm(TBROK | TERRNO, getout, 276 "kill(%d, %d) failed, but kill(%d, SIGTERM) worked", 277 pid, sig, pid); 278 } else 279 tst_brkm(TBROK | TERRNO, getout, 280 "kill(%d, %d) failed", pid, 281 sig); 282 } 283 } 284 } 285 286 if (write_pipe(pipe_fd2[1], READY) < 0) { 287 tst_brkm(TBROK | TERRNO, getout, 288 "Unable to tell child to go, write to pipe failed"); 289 } 290 291 /* 292 * child is now releasing signals, wait and check exit value 293 */ 294 if (wait(&term_stat) < 0) 295 tst_brkm(TBROK | TERRNO, getout, "wait() failed"); 296 297 /* check child's signal exit value */ 298 if ((sig = CHILD_SIG(term_stat)) != 0) 299 /* the child was zapped by a signal */ 300 tst_brkm(TBROK, cleanup, "Unexpected signal %d killed child", 301 sig); 302 303 /* get child exit value */ 304 305 rv = CHILD_EXIT(term_stat); 306 307 switch (rv) { 308 case EXIT_OK: 309 /* sig_array sent back on pipe, check it out */ 310 if ((array = (int *)read_pipe(pipe_fd[0])) == NULL) { 311 /* read_pipe() failed. */ 312 tst_resm(TBROK, "%s", mesg); 313 break; 314 } 315#if DEBUG > 1 316 for (sig = 1; sig < NUMSIGS; sig++) { 317 printf("array[%d] = %d\n", sig, array[sig]); 318 } 319#endif 320 caught_sigs = 0; 321 for (sig = 1; sig < NUMSIGS; sig++) { 322 if (choose_sig(sig)) { 323 if (array[sig] != 1) { 324 /* sig was not caught or caught too many times */ 325 (void)sprintf(mesg, 326 "\tsignal %d caught %d times (expected 1).\n", 327 sig, array[sig]); 328 (void)strcat(big_mesg, mesg); 329 fail = TRUE; 330 } else { 331 caught_sigs++; 332 } 333 } 334 } /* endfor */ 335 336 if (fail == TRUE) 337 tst_resm(TFAIL, "%s", big_mesg); 338 else 339 tst_resm(TPASS, 340 "sigrelse() released all %d signals under test.", 341 caught_sigs); 342 break; 343 344 case TBROK: 345 /* get BROK message from pipe */ 346 if ((str = read_pipe(pipe_fd[0])) == NULL) { 347 /* read_pipe() failed. */ 348 tst_resm(TBROK, "%s", mesg); 349 break; 350 } 351 352 /* call tst_res: str contains the message */ 353 tst_resm(TBROK, "%s", str); 354 break; 355 case SIG_CAUGHT: 356 /* a signal was caught before it was released */ 357 tst_resm(TBROK, "A signal was caught before being released."); 358 break; 359 case WRITE_BROK: 360 /* the write() call failed in child's write_pipe */ 361 tst_resm(TBROK, "write() pipe failed for child."); 362 break; 363 case HANDLE_ERR: 364 /* more than one signal tried to be handled at the same time */ 365 tst_resm(TBROK, "Error occured in signal handler."); 366 break; 367 default: 368 tst_resm(TBROK, "Unexpected exit code %d from child", rv); 369 break; 370 } 371 372} /* end of parent */ 373 374/**************************************************************************** 375 * child() : hold signals, notify parent and wait for parent to send signals. 376 * If none were caught (sighold worked), release the signals one at a time 377 * and wait for them to be caught. Send results back to parent 378 * for processing. 379 ***************************************************************************/ 380static void child(void) 381{ 382 int rv; /* return value from sighold() and sigrelse() */ 383 int sig; /* signal value */ 384 int exit_val; /* exit value to send to parent */ 385 char note[MAXMESG]; /* message buffer for pipe */ 386 char *str; 387 388 phase = 1; /* tell handler that we do not want to catch signals */ 389 390 /* set note to READY and if an error occurs, overwrite it */ 391 (void)strcpy(note, READY); 392 393 /* set alarm in case something hangs */ 394 if (set_timeout() < 0) { 395 /* an error occured - put mesg in note and send it back to parent */ 396 (void)strcpy(note, mesg); 397 398 } else if (setup_sigs() < 0) { 399 /* an error occured - put mesg in note and send it back to parent */ 400 (void)strcpy(note, mesg); 401 402 } else { 403 /* all set up to catch signals, now hold them */ 404 405 for (sig = 1; sig < NUMSIGS; sig++) { 406 if (choose_sig(sig)) { 407 if ((rv = sighold(sig)) != 0) { 408 /* THEY say sighold ALWAYS returns 0 */ 409 (void)sprintf(note, 410 "sighold did not return 0. rv:%d", 411 rv); 412 break; 413 } 414 } 415 } 416 417 } 418 419 /* 420 * send note to parent (if not READY, parent will BROK) and 421 * wait for parent to send signals. The timeout clock is set so 422 * that we will not wait forever - if sighold() did its job, we 423 * will not receive the signals. If sighold() blew it we will 424 * catch a signal and the interrupt handler will exit with a 425 * value of SIG_CAUGHT. 426 */ 427 if (write_pipe(pipe_fd[1], note) < 0) { 428 /* 429 * write_pipe() failed. Set exit value to WRITE_BROK to let 430 * parent know what happened 431 */ 432 clear_timeout(); 433 exit(WRITE_BROK); 434 } 435 436 /* 437 * if we get to this point, all signals have been held and the 438 * timer has expired. Now what we want to do is release each 439 * signal and see if we catch it. If we catch all signals, 440 * sigrelse passed, else it failed. 441 */ 442 443 phase = 2; /* let handler know we are now expecting signals */ 444 445#if DEBUG > 0 446 printf("child: PHASE II\n"); 447#endif 448 449 /* assume success and overwrite exit_val if an error occurs */ 450 exit_val = EXIT_OK; 451 452#if DEBUG > 0 453 printf("child: pid=%d waiting for parent's ready...\n", getpid()); 454#endif 455 456 /* 457 * wait for parent to tell us that sigals were all sent 458 */ 459 460 /* wait for "ready" message from parent */ 461 if ((str = read_pipe(pipe_fd2[0])) == NULL) { 462 /* read_pipe() failed. */ 463 printf(" child: read_pipe failed\n"); 464 exit(TBROK); 465 } 466 467 if (strcmp(str, READY) != 0) { 468 /* parent/pipe problem */ 469 printf("child: didn't proper ready message\n"); 470 exit(TBROK); 471 } 472 473 for (sig = 1; sig < NUMSIGS; sig++) { 474 if (choose_sig(sig)) { 475 476 /* all set up, release and catch a signal */ 477 478 sig_caught = FALSE; /* handler sets it to TRUE when caught */ 479#if DEBUG > 1 480 printf("child: releasing sig %d...\n", sig); 481#endif 482 if ((rv = sigrelse(sig)) != 0) { 483 /* THEY say sigrelse ALWAYS returns 0 */ 484 (void)sprintf(note, 485 "sigrelse did not return 0. rv:%d", 486 rv); 487 exit_val = TBROK; 488 break; 489 } 490 491 /* give signal handler some time to process signal */ 492 wait_a_while(); 493 } 494 495 } /* endfor */ 496 497 /* 498 * If we are error free so far... 499 * check the sig_array array for one occurence of 500 * each of the catchable signals. If this is true, 501 * then PASS, otherwise FAIL. 502 */ 503 504 if (exit_val == EXIT_OK) { 505 (void)memcpy(note, (char *)sig_array, 506 sizeof(note) < sizeof(sig_array) ? 507 sizeof(note) : sizeof(sig_array)); 508 } 509 510 /* send note to parent and exit */ 511 if (write_pipe(pipe_fd[1], note) < 0) { 512 /* 513 * write_pipe() failed. Set exit value to WRITE_BROK to let 514 * parent know what happened 515 */ 516 exit(WRITE_BROK); 517 } 518 519 exit(exit_val); 520 521} /* end of child */ 522 523/***************************************************************************** 524 * setup_sigs() : set child up to catch all signals. If there is 525 * trouble, write message in mesg and return -1, else return 0. 526 * The signal handler has two functions depending on which phase 527 * of the test we are in. The first section is executed after the 528 * signals have been held (should not ever be used). The second 529 * section is executed after the signals have been released (should 530 * be executed for each signal). 531 ****************************************************************************/ 532static int setup_sigs(void) 533{ 534 int sig; 535 536 /* set up signal handler routine */ 537 for (sig = 1; sig < NUMSIGS; sig++) { 538 if (choose_sig(sig)) { 539 if (signal(sig, handler) == SIG_ERR) { 540 /* set up mesg to send back to parent */ 541 (void)sprintf(mesg, 542 "signal() failed for signal %d. error:%d %s.", 543 sig, errno, strerror(errno)); 544 return (-1); 545 } 546 } 547 } 548 return 0; 549 550} /* end of setup_sigs */ 551 552/***************************************************************************** 553 * handler() : child's interrupt handler for all signals. The phase variable 554 * is set in the child process indicating what action is to be taken. 555 * The phase 1 section will be run if the child process catches a signal 556 * after the signal has been held resulting in a test item BROK. 557 * The parent detects this situation by a child exit value of SIG_CAUGHT. 558 * The phase 2 section will be run if the child process catches a 559 * signal after the signal has been released. All signals must be 560 * caught in order for a PASS. 561 ****************************************************************************/ 562static void handler(int sig) 563{ 564 static int s = 0; /* semaphore so that we don't handle 2 */ 565 /* sigs at once */ 566#if DEBUG > 1 567 printf("child: handler phase%d: caught signal %d.\n", phase, sig); 568#endif 569 570 if (phase == 1) { 571 /* exit the child process with a value of -1 */ 572 exit(SIG_CAUGHT); 573 574 } else { 575 /* phase 2 (error if s gets incremented twice) */ 576 ++s; 577 578 if (s > 1) { 579 exit(HANDLE_ERR); 580 } 581 582 /* increment the array element for this signal */ 583 ++sig_array[sig]; 584 sig_caught = TRUE; /* flag for wait_a_while () */ 585 --s; 586 } 587 588 return; 589 590} /* end of handler */ 591 592/***************************************************************************** 593 * read_pipe() : read data from pipe and return in buf. If an error occurs 594 * put message in mesg and return NULL. Note: this routine sets a 595 * timeout signal in case the pipe is blocked. 596 ****************************************************************************/ 597static char *read_pipe(int fd) 598{ 599 static char buf[MAXMESG]; /* buffer for pipe read */ 600 int ret; 601 602#if DEBUG > 0 603 printf("read_pipe: pid=%d waiting...\n", getpid()); 604#endif 605 606 /* set timeout alarm in case the pipe is blocked */ 607 if (set_timeout() < 0) { 608 /* an error occured, message in mesg */ 609 return NULL; 610 } 611 612 ret = -1; 613 while (ret == -1) { /* while empty reads */ 614 if ((ret = read(fd, buf, MAXMESG)) == 0) { 615 (void)sprintf(mesg, "read() pipe failed. error:%d %s.", 616 errno, strerror(errno)); 617 618 clear_timeout(); 619 return NULL; 620 } 621 } 622 clear_timeout(); 623 624#if DEBUG > 0 625 printf("read_pipe: pid=%d received: %s.\n", getpid(), buf); 626#endif 627 return (buf); 628 629} /* end of read_pipe */ 630 631/***************************************************************************** 632 * write_pipe(msg) : write msg to pipe. If it fails, put message in 633 * mesg and return -1, else return 0. 634 ****************************************************************************/ 635static int write_pipe(int fd, char *msg) 636{ 637 638#if DEBUG > 0 639 printf("write_pipe: pid=%d, sending %s.\n", getpid(), msg); 640#endif 641 642 if (write(fd, msg, MAXMESG) < 0) { 643 (void)sprintf(mesg, "write() pipe failed. error:%d %s.", 644 errno, strerror(errno)); 645 646 return (-1); 647 } 648 return 0; 649 650} /* end of write_pipe */ 651 652/***************************************************************************** 653 * set_timeout() : set alarm to signal process after the period of time 654 * indicated by TIMEOUT. If the signal occurs, the routine timeout() 655 * will be executed. If all goes ok, return 0, else load message 656 * into mesg and return -1. 657 ****************************************************************************/ 658static int set_timeout(void) 659{ 660 if (signal(SIGALRM, timeout) == SIG_ERR) { 661 (void)sprintf(mesg, 662 "signal() failed for signal %d. error:%d %s.", 663 SIGALRM, errno, strerror(errno)); 664 return (-1); 665 } 666 667 (void)alarm(TIMEOUT); 668 return 0; 669 670} /* end of set_timeout */ 671 672/***************************************************************************** 673 * clear_timeout() : turn off the alarm so that SIGALRM will not get sent. 674 ****************************************************************************/ 675static void clear_timeout(void) 676{ 677 (void)alarm(0); 678 679} /* end of clear_timeout */ 680 681/***************************************************************************** 682 * timeout() : this routine is executed when the SIGALRM signal is 683 * caught. It does nothing but return - the read() on the pipe 684 * will fail. 685 ****************************************************************************/ 686static void timeout(int sig) 687{ 688#if DEBUG > 0 689 printf("timeout: pid=%d sigalrm caught.\n", getpid()); 690#endif 691} 692 693/***************************************************************************** 694 * wait_a_while () : wait a while before returning. 695 ****************************************************************************/ 696static void wait_a_while(void) 697{ 698 long btime; 699 700 btime = time(NULL); 701 while (time(NULL) - btime < TIMEOUT) { 702 if (sig_caught == TRUE) 703 break; 704 } 705} /* end of wait_a_while */ 706 707static void getout(void) 708{ 709 if (pid > 0 && kill(pid, SIGKILL) < 0) 710 tst_resm(TWARN, "kill(%d, SIGKILL) failed", pid); 711 cleanup(); 712 713} /* end of getout */ 714 715#ifdef VAX 716static int sighold(int signo) 717{ 718 return 0; 719} 720 721static int sigrelse(signo) 722int signo; 723{ 724 return 0; 725} 726#endif 727 728int choose_sig(int sig) 729{ 730 switch (sig) { 731 732 case SIGKILL: 733 case SIGSTOP: 734 case SIGTSTP: 735 case SIGCONT: 736 case SIGALRM: 737 case SIGCANCEL: 738 case SIGTIMER: 739#ifdef SIGNOBDM 740 case SIGNOBDM: 741#endif 742#ifdef SIGTTIN 743 case SIGTTIN: 744#endif 745#ifdef SIGTTOU 746 case SIGTTOU: 747#endif 748#ifdef SIGPTINTR 749 case SIGPTINTR: 750#endif 751#ifdef SIGSWAP 752 case SIGSWAP: 753#endif 754 return 0; 755 756 } 757 758 return 1; 759 760} 761 762void setup(void) 763{ 764 765 tst_sig(FORK, DEF_HANDLER, cleanup); 766 767 TEST_PAUSE; 768 769 tst_tmpdir(); 770 771 /* set up pipe for parent/child communications */ 772 SAFE_PIPE(cleanup, pipe_fd); 773 774 /* 775 * Cause the read to return 0 once EOF is encountered and the 776 * read to return -1 if pipe is empty. 777 */ 778 if (fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK) == -1) 779 tst_brkm(TBROK | TERRNO, cleanup, 780 "fcntl(Fds[0], F_SETFL, O_NONBLOCK) failed"); 781 782 /* set up pipe for parent/child communications */ 783 SAFE_PIPE(cleanup, pipe_fd2); 784 785 /* 786 * Cause the read to return 0 once EOF is encountered and the 787 * read to return -1 if pipe is empty. 788 */ 789 if (fcntl(pipe_fd2[0], F_SETFL, O_NONBLOCK) == -1) 790 tst_brkm(TBROK | TERRNO, cleanup, 791 "fcntl(Fds[0], F_SETFL, O_NONBLOCK) failed"); 792} 793 794void cleanup(void) 795{ 796 tst_rmdir(); 797 798} 799