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