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