/* Test case written by Bharat Joshi */ #include __RCSID("$NetBSD: t_fifo.c,v 1.2 2017/01/10 22:36:29 christos Exp $"); #include #include #include #include #include #include #include #include #include #include #include #ifndef STANDALONE #include #endif #define FIFO_FILE_PATH "./fifo_file" #define NUM_MESSAGES 20 #define MSG_SIZE 240 #define MESSAGE "I am fine" static int verbose = 0; /* * child_writer * * Function that runs in child context and opens and write to the FIFO. */ static void child_writer(void) { ssize_t rv; int fd; size_t count; char message[MSG_SIZE] = MESSAGE; static const struct timespec ts = { 0, 10000 }; /* Open the fifo in write-mode */ for (;;) { fd = open(FIFO_FILE_PATH, O_WRONLY, 0); if (fd == -1) { if (errno == EINTR) continue; err(1, "Child: can't open fifo in write mode"); } break; } for (count = 0; count < NUM_MESSAGES; count++) { rv = write(fd, message, MSG_SIZE); if (rv == -1) { warn("Child: Failed to write"); break; } if (rv != MSG_SIZE) warnx("Child: wrote only %zd", rv); nanosleep(&ts, NULL); } close(fd); if (verbose) { printf("Child: Closed the fifo file\n"); fflush(stdout); } } /* * _sigchild_handler * * Called when a sigchild is delivered */ static void sigchild_handler(int signo) { if (verbose) { if (signo == SIGCHLD) { printf("Got sigchild\n"); } else { printf("Got %d signal\n", signo); } fflush(stdout); } } static int run(void) { pid_t pid; ssize_t rv; int fd, status; size_t buf_size = MSG_SIZE; char buf[MSG_SIZE]; struct sigaction action; static const struct timespec ts = { 0, 500000000 }; /* Catch sigchild Signal */ memset(&action, 0, sizeof(action)); action.sa_handler = sigchild_handler; sigemptyset(&action.sa_mask); if (sigaction(SIGCHLD, &action, NULL) == -1) err(1, "sigaction"); (void)unlink(FIFO_FILE_PATH); /* First create a fifo */ if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1) err(1, "mkfifo"); switch ((pid = fork())) { case -1: err(1, "fork"); case 0: /* Open the file in write mode so that subsequent read * from parent side does not block the parent.. */ if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1) err(1, "failed to open fifo"); /* In child */ child_writer(); return 0; default: break; } if (verbose) { printf("Child pid is %d\n", pid ); fflush(stdout); } /* In parent */ for (;;) { if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) { if (errno == EINTR) continue; else err(1, "Failed to open the fifo in read mode"); } /* Read mode is opened */ break; } nanosleep(&ts, NULL); if (verbose) { printf("Was sleeping...\n"); fflush(stdout); } for (;;) { rv = read(fd, buf, buf_size); if (rv == -1) { warn("Failed to read"); if (errno == EINTR) { if (verbose) { printf("Parent interrupted, " "continuing...\n"); fflush(stdout); } continue; } break; } if (rv == 0) { if (verbose) { printf("Writers have closed, looks like we " "are done\n"); fflush(stdout); } break; } if (verbose) { printf("Received %zd bytes message '%s'\n", rv, buf); fflush(stdout); } } close(fd); if (verbose) { printf("We are done.. now reap the child"); fflush(stdout); } // Read the child... while (waitpid(pid, &status, 0) == -1) if (errno != EINTR) { warn("Failed to reap the child"); return 1; } if (verbose) { printf("We are done completely\n"); fflush(stdout); } return 0; } #ifndef STANDALONE ATF_TC(parent_child); ATF_TC_HEAD(parent_child, tc) { atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared " "between a reader parent and a writer child, that read will " "return EOF, and not get stuck after the child exits"); } ATF_TC_BODY(parent_child, tc) { ATF_REQUIRE(run() == 0); } ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, parent_child); return atf_no_error(); } #else int main(void) { verbose = 1; return run(); } #endif