1 /* Test case written by Bharat Joshi */ 2 #include <sys/cdefs.h> 3 __RCSID("$NetBSD: t_fifo.c,v 1.2 2017/01/10 22:36:29 christos Exp $"); 4 5 #include <sys/types.h> 6 #include <sys/wait.h> 7 #include <sys/stat.h> 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <unistd.h> 12 #include <fcntl.h> 13 #include <errno.h> 14 #include <string.h> 15 #include <err.h> 16 #include <signal.h> 17 18 #ifndef STANDALONE 19 #include <atf-c.h> 20 #endif 21 22 #define FIFO_FILE_PATH "./fifo_file" 23 #define NUM_MESSAGES 20 24 #define MSG_SIZE 240 25 #define MESSAGE "I am fine" 26 27 static int verbose = 0; 28 29 /* 30 * child_writer 31 * 32 * Function that runs in child context and opens and write to the FIFO. 33 */ 34 static void 35 child_writer(void) 36 { 37 ssize_t rv; 38 int fd; 39 size_t count; 40 char message[MSG_SIZE] = MESSAGE; 41 static const struct timespec ts = { 0, 10000 }; 42 43 /* Open the fifo in write-mode */ 44 for (;;) { 45 fd = open(FIFO_FILE_PATH, O_WRONLY, 0); 46 if (fd == -1) { 47 if (errno == EINTR) 48 continue; 49 err(1, "Child: can't open fifo in write mode"); 50 } 51 break; 52 } 53 54 for (count = 0; count < NUM_MESSAGES; count++) { 55 rv = write(fd, message, MSG_SIZE); 56 if (rv == -1) { 57 warn("Child: Failed to write"); 58 break; 59 } 60 if (rv != MSG_SIZE) 61 warnx("Child: wrote only %zd", rv); 62 nanosleep(&ts, NULL); 63 } 64 65 close(fd); 66 if (verbose) { 67 printf("Child: Closed the fifo file\n"); 68 fflush(stdout); 69 } 70 } 71 72 /* 73 * _sigchild_handler 74 * 75 * Called when a sigchild is delivered 76 */ 77 static void 78 sigchild_handler(int signo) 79 { 80 if (verbose) { 81 if (signo == SIGCHLD) { 82 printf("Got sigchild\n"); 83 } else { 84 printf("Got %d signal\n", signo); 85 } 86 fflush(stdout); 87 } 88 89 } 90 91 static int 92 run(void) 93 { 94 pid_t pid; 95 ssize_t rv; 96 int fd, status; 97 size_t buf_size = MSG_SIZE; 98 char buf[MSG_SIZE]; 99 struct sigaction action; 100 static const struct timespec ts = { 0, 500000000 }; 101 102 /* Catch sigchild Signal */ 103 memset(&action, 0, sizeof(action)); 104 action.sa_handler = sigchild_handler; 105 sigemptyset(&action.sa_mask); 106 107 if (sigaction(SIGCHLD, &action, NULL) == -1) 108 err(1, "sigaction"); 109 110 (void)unlink(FIFO_FILE_PATH); 111 /* First create a fifo */ 112 if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1) 113 err(1, "mkfifo"); 114 115 switch ((pid = fork())) { 116 case -1: 117 err(1, "fork"); 118 case 0: 119 /* Open the file in write mode so that subsequent read 120 * from parent side does not block the parent.. 121 */ 122 if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1) 123 err(1, "failed to open fifo"); 124 125 /* In child */ 126 child_writer(); 127 return 0; 128 129 default: 130 break; 131 } 132 133 if (verbose) { 134 printf("Child pid is %d\n", pid ); 135 fflush(stdout); 136 } 137 138 /* In parent */ 139 for (;;) { 140 if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) { 141 if (errno == EINTR) 142 continue; 143 else 144 err(1, "Failed to open the fifo in read mode"); 145 } 146 /* Read mode is opened */ 147 break; 148 149 } 150 151 nanosleep(&ts, NULL); 152 if (verbose) { 153 printf("Was sleeping...\n"); 154 fflush(stdout); 155 } 156 157 for (;;) { 158 rv = read(fd, buf, buf_size); 159 160 if (rv == -1) { 161 warn("Failed to read"); 162 if (errno == EINTR) { 163 if (verbose) { 164 printf("Parent interrupted, " 165 "continuing...\n"); 166 fflush(stdout); 167 } 168 continue; 169 } 170 171 break; 172 } 173 174 if (rv == 0) { 175 if (verbose) { 176 printf("Writers have closed, looks like we " 177 "are done\n"); 178 fflush(stdout); 179 } 180 break; 181 } 182 183 if (verbose) { 184 printf("Received %zd bytes message '%s'\n", rv, buf); 185 fflush(stdout); 186 } 187 } 188 189 close(fd); 190 191 if (verbose) { 192 printf("We are done.. now reap the child"); 193 fflush(stdout); 194 } 195 196 // Read the child... 197 while (waitpid(pid, &status, 0) == -1) 198 if (errno != EINTR) { 199 warn("Failed to reap the child"); 200 return 1; 201 } 202 203 if (verbose) { 204 printf("We are done completely\n"); 205 fflush(stdout); 206 } 207 return 0; 208 } 209 210 #ifndef STANDALONE 211 ATF_TC(parent_child); 212 213 ATF_TC_HEAD(parent_child, tc) 214 { 215 atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared " 216 "between a reader parent and a writer child, that read will " 217 "return EOF, and not get stuck after the child exits"); 218 } 219 220 ATF_TC_BODY(parent_child, tc) 221 { 222 ATF_REQUIRE(run() == 0); 223 } 224 225 ATF_TP_ADD_TCS(tp) 226 { 227 ATF_TP_ADD_TC(tp, parent_child); 228 229 return atf_no_error(); 230 } 231 #else 232 int 233 main(void) 234 { 235 verbose = 1; 236 return run(); 237 } 238 #endif 239