157718be8SEnji Cooper /* Test case written by Bharat Joshi */
257718be8SEnji Cooper #include <sys/cdefs.h>
3*cdebaff8SEnji Cooper __RCSID("$NetBSD: t_fifo.c,v 1.2 2017/01/10 22:36:29 christos Exp $");
457718be8SEnji Cooper
557718be8SEnji Cooper #include <sys/types.h>
657718be8SEnji Cooper #include <sys/wait.h>
7*cdebaff8SEnji Cooper #include <sys/stat.h>
857718be8SEnji Cooper
957718be8SEnji Cooper #include <stdio.h>
1057718be8SEnji Cooper #include <stdlib.h>
1157718be8SEnji Cooper #include <unistd.h>
1257718be8SEnji Cooper #include <fcntl.h>
1357718be8SEnji Cooper #include <errno.h>
1457718be8SEnji Cooper #include <string.h>
1557718be8SEnji Cooper #include <err.h>
1657718be8SEnji Cooper #include <signal.h>
1757718be8SEnji Cooper
1857718be8SEnji Cooper #ifndef STANDALONE
1957718be8SEnji Cooper #include <atf-c.h>
2057718be8SEnji Cooper #endif
2157718be8SEnji Cooper
2257718be8SEnji Cooper #define FIFO_FILE_PATH "./fifo_file"
2357718be8SEnji Cooper #define NUM_MESSAGES 20
2457718be8SEnji Cooper #define MSG_SIZE 240
2557718be8SEnji Cooper #define MESSAGE "I am fine"
2657718be8SEnji Cooper
2757718be8SEnji Cooper static int verbose = 0;
2857718be8SEnji Cooper
2957718be8SEnji Cooper /*
3057718be8SEnji Cooper * child_writer
3157718be8SEnji Cooper *
3257718be8SEnji Cooper * Function that runs in child context and opens and write to the FIFO.
3357718be8SEnji Cooper */
3457718be8SEnji Cooper static void
child_writer(void)3557718be8SEnji Cooper child_writer(void)
3657718be8SEnji Cooper {
3757718be8SEnji Cooper ssize_t rv;
3857718be8SEnji Cooper int fd;
3957718be8SEnji Cooper size_t count;
4057718be8SEnji Cooper char message[MSG_SIZE] = MESSAGE;
4157718be8SEnji Cooper static const struct timespec ts = { 0, 10000 };
4257718be8SEnji Cooper
4357718be8SEnji Cooper /* Open the fifo in write-mode */
4457718be8SEnji Cooper for (;;) {
4557718be8SEnji Cooper fd = open(FIFO_FILE_PATH, O_WRONLY, 0);
4657718be8SEnji Cooper if (fd == -1) {
4757718be8SEnji Cooper if (errno == EINTR)
4857718be8SEnji Cooper continue;
4957718be8SEnji Cooper err(1, "Child: can't open fifo in write mode");
5057718be8SEnji Cooper }
5157718be8SEnji Cooper break;
5257718be8SEnji Cooper }
5357718be8SEnji Cooper
5457718be8SEnji Cooper for (count = 0; count < NUM_MESSAGES; count++) {
5557718be8SEnji Cooper rv = write(fd, message, MSG_SIZE);
5657718be8SEnji Cooper if (rv == -1) {
5757718be8SEnji Cooper warn("Child: Failed to write");
5857718be8SEnji Cooper break;
5957718be8SEnji Cooper }
6057718be8SEnji Cooper if (rv != MSG_SIZE)
6157718be8SEnji Cooper warnx("Child: wrote only %zd", rv);
6257718be8SEnji Cooper nanosleep(&ts, NULL);
6357718be8SEnji Cooper }
6457718be8SEnji Cooper
6557718be8SEnji Cooper close(fd);
6657718be8SEnji Cooper if (verbose) {
6757718be8SEnji Cooper printf("Child: Closed the fifo file\n");
6857718be8SEnji Cooper fflush(stdout);
6957718be8SEnji Cooper }
7057718be8SEnji Cooper }
7157718be8SEnji Cooper
7257718be8SEnji Cooper /*
7357718be8SEnji Cooper * _sigchild_handler
7457718be8SEnji Cooper *
7557718be8SEnji Cooper * Called when a sigchild is delivered
7657718be8SEnji Cooper */
7757718be8SEnji Cooper static void
sigchild_handler(int signo)7857718be8SEnji Cooper sigchild_handler(int signo)
7957718be8SEnji Cooper {
8057718be8SEnji Cooper if (verbose) {
8157718be8SEnji Cooper if (signo == SIGCHLD) {
8257718be8SEnji Cooper printf("Got sigchild\n");
8357718be8SEnji Cooper } else {
8457718be8SEnji Cooper printf("Got %d signal\n", signo);
8557718be8SEnji Cooper }
8657718be8SEnji Cooper fflush(stdout);
8757718be8SEnji Cooper }
8857718be8SEnji Cooper
8957718be8SEnji Cooper }
9057718be8SEnji Cooper
9157718be8SEnji Cooper static int
run(void)9257718be8SEnji Cooper run(void)
9357718be8SEnji Cooper {
9457718be8SEnji Cooper pid_t pid;
9557718be8SEnji Cooper ssize_t rv;
9657718be8SEnji Cooper int fd, status;
9757718be8SEnji Cooper size_t buf_size = MSG_SIZE;
9857718be8SEnji Cooper char buf[MSG_SIZE];
9957718be8SEnji Cooper struct sigaction action;
10057718be8SEnji Cooper static const struct timespec ts = { 0, 500000000 };
10157718be8SEnji Cooper
10257718be8SEnji Cooper /* Catch sigchild Signal */
10357718be8SEnji Cooper memset(&action, 0, sizeof(action));
10457718be8SEnji Cooper action.sa_handler = sigchild_handler;
10557718be8SEnji Cooper sigemptyset(&action.sa_mask);
10657718be8SEnji Cooper
10757718be8SEnji Cooper if (sigaction(SIGCHLD, &action, NULL) == -1)
10857718be8SEnji Cooper err(1, "sigaction");
10957718be8SEnji Cooper
11057718be8SEnji Cooper (void)unlink(FIFO_FILE_PATH);
11157718be8SEnji Cooper /* First create a fifo */
11257718be8SEnji Cooper if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1)
11357718be8SEnji Cooper err(1, "mkfifo");
11457718be8SEnji Cooper
11557718be8SEnji Cooper switch ((pid = fork())) {
11657718be8SEnji Cooper case -1:
11757718be8SEnji Cooper err(1, "fork");
11857718be8SEnji Cooper case 0:
11957718be8SEnji Cooper /* Open the file in write mode so that subsequent read
12057718be8SEnji Cooper * from parent side does not block the parent..
12157718be8SEnji Cooper */
12257718be8SEnji Cooper if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1)
12357718be8SEnji Cooper err(1, "failed to open fifo");
12457718be8SEnji Cooper
12557718be8SEnji Cooper /* In child */
12657718be8SEnji Cooper child_writer();
12757718be8SEnji Cooper return 0;
12857718be8SEnji Cooper
12957718be8SEnji Cooper default:
13057718be8SEnji Cooper break;
13157718be8SEnji Cooper }
13257718be8SEnji Cooper
13357718be8SEnji Cooper if (verbose) {
13457718be8SEnji Cooper printf("Child pid is %d\n", pid );
13557718be8SEnji Cooper fflush(stdout);
13657718be8SEnji Cooper }
13757718be8SEnji Cooper
13857718be8SEnji Cooper /* In parent */
13957718be8SEnji Cooper for (;;) {
14057718be8SEnji Cooper if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) {
14157718be8SEnji Cooper if (errno == EINTR)
14257718be8SEnji Cooper continue;
14357718be8SEnji Cooper else
14457718be8SEnji Cooper err(1, "Failed to open the fifo in read mode");
14557718be8SEnji Cooper }
14657718be8SEnji Cooper /* Read mode is opened */
14757718be8SEnji Cooper break;
14857718be8SEnji Cooper
14957718be8SEnji Cooper }
15057718be8SEnji Cooper
15157718be8SEnji Cooper nanosleep(&ts, NULL);
15257718be8SEnji Cooper if (verbose) {
15357718be8SEnji Cooper printf("Was sleeping...\n");
15457718be8SEnji Cooper fflush(stdout);
15557718be8SEnji Cooper }
15657718be8SEnji Cooper
15757718be8SEnji Cooper for (;;) {
15857718be8SEnji Cooper rv = read(fd, buf, buf_size);
15957718be8SEnji Cooper
16057718be8SEnji Cooper if (rv == -1) {
16157718be8SEnji Cooper warn("Failed to read");
16257718be8SEnji Cooper if (errno == EINTR) {
16357718be8SEnji Cooper if (verbose) {
16457718be8SEnji Cooper printf("Parent interrupted, "
16557718be8SEnji Cooper "continuing...\n");
16657718be8SEnji Cooper fflush(stdout);
16757718be8SEnji Cooper }
16857718be8SEnji Cooper continue;
16957718be8SEnji Cooper }
17057718be8SEnji Cooper
17157718be8SEnji Cooper break;
17257718be8SEnji Cooper }
17357718be8SEnji Cooper
17457718be8SEnji Cooper if (rv == 0) {
17557718be8SEnji Cooper if (verbose) {
17657718be8SEnji Cooper printf("Writers have closed, looks like we "
17757718be8SEnji Cooper "are done\n");
17857718be8SEnji Cooper fflush(stdout);
17957718be8SEnji Cooper }
18057718be8SEnji Cooper break;
18157718be8SEnji Cooper }
18257718be8SEnji Cooper
18357718be8SEnji Cooper if (verbose) {
18457718be8SEnji Cooper printf("Received %zd bytes message '%s'\n", rv, buf);
18557718be8SEnji Cooper fflush(stdout);
18657718be8SEnji Cooper }
18757718be8SEnji Cooper }
18857718be8SEnji Cooper
18957718be8SEnji Cooper close(fd);
19057718be8SEnji Cooper
19157718be8SEnji Cooper if (verbose) {
19257718be8SEnji Cooper printf("We are done.. now reap the child");
19357718be8SEnji Cooper fflush(stdout);
19457718be8SEnji Cooper }
19557718be8SEnji Cooper
19657718be8SEnji Cooper // Read the child...
19757718be8SEnji Cooper while (waitpid(pid, &status, 0) == -1)
19857718be8SEnji Cooper if (errno != EINTR) {
19957718be8SEnji Cooper warn("Failed to reap the child");
20057718be8SEnji Cooper return 1;
20157718be8SEnji Cooper }
20257718be8SEnji Cooper
20357718be8SEnji Cooper if (verbose) {
20457718be8SEnji Cooper printf("We are done completely\n");
20557718be8SEnji Cooper fflush(stdout);
20657718be8SEnji Cooper }
20757718be8SEnji Cooper return 0;
20857718be8SEnji Cooper }
20957718be8SEnji Cooper
21057718be8SEnji Cooper #ifndef STANDALONE
21157718be8SEnji Cooper ATF_TC(parent_child);
21257718be8SEnji Cooper
ATF_TC_HEAD(parent_child,tc)21357718be8SEnji Cooper ATF_TC_HEAD(parent_child, tc)
21457718be8SEnji Cooper {
21557718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared "
21657718be8SEnji Cooper "between a reader parent and a writer child, that read will "
21757718be8SEnji Cooper "return EOF, and not get stuck after the child exits");
21857718be8SEnji Cooper }
21957718be8SEnji Cooper
ATF_TC_BODY(parent_child,tc)22057718be8SEnji Cooper ATF_TC_BODY(parent_child, tc)
22157718be8SEnji Cooper {
22257718be8SEnji Cooper ATF_REQUIRE(run() == 0);
22357718be8SEnji Cooper }
22457718be8SEnji Cooper
ATF_TP_ADD_TCS(tp)22557718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
22657718be8SEnji Cooper {
22757718be8SEnji Cooper ATF_TP_ADD_TC(tp, parent_child);
22857718be8SEnji Cooper
22957718be8SEnji Cooper return atf_no_error();
23057718be8SEnji Cooper }
23157718be8SEnji Cooper #else
23257718be8SEnji Cooper int
main(void)23357718be8SEnji Cooper main(void)
23457718be8SEnji Cooper {
23557718be8SEnji Cooper verbose = 1;
23657718be8SEnji Cooper return run();
23757718be8SEnji Cooper }
23857718be8SEnji Cooper #endif
239