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