Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / tests / t40c.c
blob54cc29f8c790dbc0a23151175bd30e5774924f0d
1 /* t40c.c
3 * Test (pseudo) terminal devices
5 * Select works on regular files, (pseudo) terminal devices, streams-based
6 * files, FIFOs, pipes, and sockets. This test verifies selecting for (pseudo)
7 * terminal devices.
9 * This test is part of a bigger select test. It expects as argument which sub-
10 * test it is.
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <sys/select.h>
20 #include <sys/syslimits.h>
21 #include <errno.h>
22 #include <sys/wait.h>
23 #include <string.h>
25 #include "common.h"
27 #define TERMINALW "/dev/ttypf"
28 #define TERMINALR "/dev/ptypf"
29 #define SENDSTRING "minixrocks"
30 #define MAX_ERROR 5
32 static void open_terminal(int *child_fd, int *parent_fd) {
33 int fd1, fd2, i;
34 char opentermw[5+OPEN_MAX+1];
35 char opentermr[5+OPEN_MAX+1];
36 char *term[] = {"f","e","d","c","b","a","9","8","7","6","5","4","3","2","1"};
37 #define TERMS (sizeof(term)/sizeof(term[0]))
39 if (!child_fd || !parent_fd) exit(EXIT_FAILURE);
41 for (i = 0; i < TERMS; i++) {
42 snprintf(opentermw, 5+OPEN_MAX, "/dev/ttyp%s", term[i]);
43 snprintf(opentermr, 5+OPEN_MAX, "/dev/ptyp%s", term[i]);
45 /* Open master terminal for writing */
46 if((fd1 = open(opentermw, O_WRONLY)) == -1) continue;
48 /* Open slave terminal for reading */
49 if((fd2 = open(opentermr, O_RDONLY)) == -1) {
50 close(fd1);
51 continue;
54 *child_fd = fd1;
55 *parent_fd = fd2;
56 return;
59 /* If we get here we failed to find a terminal pair */
60 exit(EXIT_FAILURE);
63 static int do_child(int terminal) {
64 /* Going to sleep for two seconds to allow the parent proc to get ready */
65 sleep(2);
67 /* Try to write. Doesn't matter how many bytes we actually send. */
68 (void) write(terminal, SENDSTRING, strlen(SENDSTRING));
70 /* Wait for another second to allow the parent to process incoming data */
71 sleep(1);
73 /* Write some more, and wait some more. */
74 (void) write(terminal, SENDSTRING, strlen(SENDSTRING));
76 sleep(1);
78 close(terminal);
79 exit(0);
82 static int do_parent(int child, int terminal) {
83 fd_set fds_read, fds_read2, fds_write, fds_error;
84 int retval, terminal2, highest;
85 char buf[256];
87 /* Clear bit masks */
88 FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error);
89 /* Set read bits */
90 FD_SET(terminal, &fds_read);
91 FD_SET(terminal, &fds_write);
93 /* Test if we can read or write from/to fd. As fd is opened read only we
94 * cannot actually write, so the select should return immediately with fd
95 * set in fds_write, but not in fds_read. Note that the child waits two
96 * seconds before sending data. This gives us the opportunity run this
97 * sub-test as reading from fd is blocking at this point. */
98 retval = select(terminal+1, &fds_read, &fds_write, &fds_error, NULL);
100 if(retval != 1) em(1, "incorrect amount of ready file descriptors");
102 if(FD_ISSET(terminal, &fds_read)) em(2, "read should NOT be set");
103 if(!FD_ISSET(terminal, &fds_write)) em(3, "write should be set");
104 if(FD_ISSET(terminal, &fds_error)) em(4, "error should NOT be set");
106 /* Block until ready; until child wrote stuff */
107 FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error);
108 FD_SET(terminal, &fds_read);
109 retval = select(terminal+1, &fds_read, NULL, &fds_error, NULL);
111 if(retval != 1) em(5, "incorrect amount of ready file descriptors");
112 if(!FD_ISSET(terminal, &fds_read)) em(6, "read should be set");
113 if(FD_ISSET(terminal, &fds_error)) em(7, "error should not be set");
115 FD_ZERO(&fds_read); FD_ZERO(&fds_error);
116 FD_SET(terminal, &fds_write);
117 retval = select(terminal+1, NULL, &fds_write, NULL, NULL);
118 /* As it is impossible to write to a read only fd, this select should return
119 * immediately with fd set in fds_write. */
120 if(retval != 1) em(8, "incorrect amount or ready file descriptors");
122 /* See if selecting on the same object with two different fds results in both
123 * fds being returned as ready, immediately.
125 terminal2 = dup(terminal);
126 if (terminal2 < 0) em(9, "unable to dup file descriptor");
128 FD_ZERO(&fds_read);
129 FD_SET(terminal, &fds_read);
130 FD_SET(terminal2, &fds_read);
131 fds_read2 = fds_read;
132 highest = terminal > terminal2 ? terminal : terminal2;
134 retval = select(highest+1, &fds_read, NULL, NULL, NULL);
135 if (retval != 2) em(10, "incorrect amount of ready file descriptors");
136 if (!FD_ISSET(terminal, &fds_read)) em(11, "first fd missing from set");
137 if (!FD_ISSET(terminal2, &fds_read)) em(12, "second fd missing from set");
139 /* Empty the buffer. */
140 if (read(terminal, buf, sizeof(buf)) <= 0) em(13, "unable to read data");
142 /* Repeat the test, now with a delay. */
143 retval = select(highest+1, &fds_read2, NULL, NULL, NULL);
144 if (retval != 2) em(10, "incorrect amount of ready file descriptors");
145 if (!FD_ISSET(terminal, &fds_read2)) em(11, "first fd missing from set");
146 if (!FD_ISSET(terminal2, &fds_read2)) em(12, "second fd missing from set");
148 close(terminal2);
149 close(terminal);
150 waitpid(child, &retval, 0);
151 exit(errct);
154 int main(int argc, char **argv) {
155 int forkres;
156 int master, slave;
158 /* Get subtest number */
159 if(argc != 2) {
160 printf("Usage: %s subtest_no\n", argv[0]);
161 exit(-1);
162 } else if(sscanf(argv[1], "%d", &subtest) != 1) {
163 printf("Usage: %s subtest_no\n", argv[0]);
164 exit(-1);
167 open_terminal(&master, &slave);
169 forkres = fork();
170 if(forkres == 0) do_child(master);
171 else if(forkres > 0) do_parent(forkres, slave);
172 else { /* Fork failed */
173 perror("Unable to fork");
174 exit(-1);
177 exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/