1272343Sngie/* Test case written by Bharat Joshi */ 2272343Sngie#include <sys/cdefs.h> 3272343Sngie__RCSID("$NetBSD: t_fifo.c,v 1.1 2011/12/21 00:17:07 christos Exp $"); 4272343Sngie 5272343Sngie#include <sys/types.h> 6272343Sngie#include <sys/wait.h> 7272343Sngie 8272343Sngie#include <stdio.h> 9272343Sngie#include <stdlib.h> 10272343Sngie#include <unistd.h> 11272343Sngie#include <fcntl.h> 12272343Sngie#include <errno.h> 13272343Sngie#include <string.h> 14272343Sngie#include <err.h> 15272343Sngie#include <signal.h> 16272343Sngie 17272343Sngie#ifndef STANDALONE 18272343Sngie#include <atf-c.h> 19272343Sngie#endif 20272343Sngie 21272343Sngie#define FIFO_FILE_PATH "./fifo_file" 22272343Sngie#define NUM_MESSAGES 20 23272343Sngie#define MSG_SIZE 240 24272343Sngie#define MESSAGE "I am fine" 25272343Sngie 26272343Sngiestatic int verbose = 0; 27272343Sngie 28272343Sngie/* 29272343Sngie * child_writer 30272343Sngie * 31272343Sngie * Function that runs in child context and opens and write to the FIFO. 32272343Sngie */ 33272343Sngiestatic void 34272343Sngiechild_writer(void) 35272343Sngie{ 36272343Sngie ssize_t rv; 37272343Sngie int fd; 38272343Sngie size_t count; 39272343Sngie char message[MSG_SIZE] = MESSAGE; 40272343Sngie static const struct timespec ts = { 0, 10000 }; 41272343Sngie 42272343Sngie /* Open the fifo in write-mode */ 43272343Sngie for (;;) { 44272343Sngie fd = open(FIFO_FILE_PATH, O_WRONLY, 0); 45272343Sngie if (fd == -1) { 46272343Sngie if (errno == EINTR) 47272343Sngie continue; 48272343Sngie err(1, "Child: can't open fifo in write mode"); 49272343Sngie } 50272343Sngie break; 51272343Sngie } 52272343Sngie 53272343Sngie for (count = 0; count < NUM_MESSAGES; count++) { 54272343Sngie rv = write(fd, message, MSG_SIZE); 55272343Sngie if (rv == -1) { 56272343Sngie warn("Child: Failed to write"); 57272343Sngie break; 58272343Sngie } 59272343Sngie if (rv != MSG_SIZE) 60272343Sngie warnx("Child: wrote only %zd", rv); 61272343Sngie nanosleep(&ts, NULL); 62272343Sngie } 63272343Sngie 64272343Sngie close(fd); 65272343Sngie if (verbose) { 66272343Sngie printf("Child: Closed the fifo file\n"); 67272343Sngie fflush(stdout); 68272343Sngie } 69272343Sngie} 70272343Sngie 71272343Sngie/* 72272343Sngie * _sigchild_handler 73272343Sngie * 74272343Sngie * Called when a sigchild is delivered 75272343Sngie */ 76272343Sngiestatic void 77272343Sngiesigchild_handler(int signo) 78272343Sngie{ 79272343Sngie if (verbose) { 80272343Sngie if (signo == SIGCHLD) { 81272343Sngie printf("Got sigchild\n"); 82272343Sngie } else { 83272343Sngie printf("Got %d signal\n", signo); 84272343Sngie } 85272343Sngie fflush(stdout); 86272343Sngie } 87272343Sngie 88272343Sngie} 89272343Sngie 90272343Sngiestatic int 91272343Sngierun(void) 92272343Sngie{ 93272343Sngie pid_t pid; 94272343Sngie ssize_t rv; 95272343Sngie int fd, status; 96272343Sngie size_t buf_size = MSG_SIZE; 97272343Sngie char buf[MSG_SIZE]; 98272343Sngie struct sigaction action; 99272343Sngie static const struct timespec ts = { 0, 500000000 }; 100272343Sngie 101272343Sngie /* Catch sigchild Signal */ 102272343Sngie memset(&action, 0, sizeof(action)); 103272343Sngie action.sa_handler = sigchild_handler; 104272343Sngie sigemptyset(&action.sa_mask); 105272343Sngie 106272343Sngie if (sigaction(SIGCHLD, &action, NULL) == -1) 107272343Sngie err(1, "sigaction"); 108272343Sngie 109272343Sngie (void)unlink(FIFO_FILE_PATH); 110272343Sngie /* First create a fifo */ 111272343Sngie if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1) 112272343Sngie err(1, "mkfifo"); 113272343Sngie 114272343Sngie switch ((pid = fork())) { 115272343Sngie case -1: 116272343Sngie err(1, "fork"); 117272343Sngie case 0: 118272343Sngie /* Open the file in write mode so that subsequent read 119272343Sngie * from parent side does not block the parent.. 120272343Sngie */ 121272343Sngie if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1) 122272343Sngie err(1, "failed to open fifo"); 123272343Sngie 124272343Sngie /* In child */ 125272343Sngie child_writer(); 126272343Sngie return 0; 127272343Sngie 128272343Sngie default: 129272343Sngie break; 130272343Sngie } 131272343Sngie 132272343Sngie if (verbose) { 133272343Sngie printf("Child pid is %d\n", pid ); 134272343Sngie fflush(stdout); 135272343Sngie } 136272343Sngie 137272343Sngie /* In parent */ 138272343Sngie for (;;) { 139272343Sngie if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) { 140272343Sngie if (errno == EINTR) 141272343Sngie continue; 142272343Sngie else 143272343Sngie err(1, "Failed to open the fifo in read mode"); 144272343Sngie } 145272343Sngie /* Read mode is opened */ 146272343Sngie break; 147272343Sngie 148272343Sngie } 149272343Sngie 150272343Sngie nanosleep(&ts, NULL); 151272343Sngie if (verbose) { 152272343Sngie printf("Was sleeping...\n"); 153272343Sngie fflush(stdout); 154272343Sngie } 155272343Sngie 156272343Sngie for (;;) { 157272343Sngie rv = read(fd, buf, buf_size); 158272343Sngie 159272343Sngie if (rv == -1) { 160272343Sngie warn("Failed to read"); 161272343Sngie if (errno == EINTR) { 162272343Sngie if (verbose) { 163272343Sngie printf("Parent interrupted, " 164272343Sngie "continuing...\n"); 165272343Sngie fflush(stdout); 166272343Sngie } 167272343Sngie continue; 168272343Sngie } 169272343Sngie 170272343Sngie break; 171272343Sngie } 172272343Sngie 173272343Sngie if (rv == 0) { 174272343Sngie if (verbose) { 175272343Sngie printf("Writers have closed, looks like we " 176272343Sngie "are done\n"); 177272343Sngie fflush(stdout); 178272343Sngie } 179272343Sngie break; 180272343Sngie } 181272343Sngie 182272343Sngie if (verbose) { 183272343Sngie printf("Received %zd bytes message '%s'\n", rv, buf); 184272343Sngie fflush(stdout); 185272343Sngie } 186272343Sngie } 187272343Sngie 188272343Sngie close(fd); 189272343Sngie 190272343Sngie if (verbose) { 191272343Sngie printf("We are done.. now reap the child"); 192272343Sngie fflush(stdout); 193272343Sngie } 194272343Sngie 195272343Sngie // Read the child... 196272343Sngie while (waitpid(pid, &status, 0) == -1) 197272343Sngie if (errno != EINTR) { 198272343Sngie warn("Failed to reap the child"); 199272343Sngie return 1; 200272343Sngie } 201272343Sngie 202272343Sngie if (verbose) { 203272343Sngie printf("We are done completely\n"); 204272343Sngie fflush(stdout); 205272343Sngie } 206272343Sngie return 0; 207272343Sngie} 208272343Sngie 209272343Sngie#ifndef STANDALONE 210272343SngieATF_TC(parent_child); 211272343Sngie 212272343SngieATF_TC_HEAD(parent_child, tc) 213272343Sngie{ 214272343Sngie atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared " 215272343Sngie "between a reader parent and a writer child, that read will " 216272343Sngie "return EOF, and not get stuck after the child exits"); 217272343Sngie} 218272343Sngie 219272343SngieATF_TC_BODY(parent_child, tc) 220272343Sngie{ 221272343Sngie ATF_REQUIRE(run() == 0); 222272343Sngie} 223272343Sngie 224272343SngieATF_TP_ADD_TCS(tp) 225272343Sngie{ 226272343Sngie ATF_TP_ADD_TC(tp, parent_child); 227272343Sngie 228272343Sngie return atf_no_error(); 229272343Sngie} 230272343Sngie#else 231272343Sngieint 232272343Sngiemain(void) 233272343Sngie{ 234272343Sngie verbose = 1; 235272343Sngie return run(); 236272343Sngie} 237272343Sngie#endif 238