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)
9 * This test is part of a bigger select test. It expects as argument which sub-
16 #include <sys/types.h>
19 #include <sys/select.h>
20 #include <sys/syslimits.h>
27 #define TERMINALW "/dev/ttypf"
28 #define TERMINALR "/dev/ptypf"
29 #define SENDSTRING "minixrocks"
32 static void open_terminal(int *child_fd
, int *parent_fd
) {
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) {
59 /* If we get here we failed to find a terminal pair */
63 static int do_child(int terminal
) {
64 /* Going to sleep for two seconds to allow the parent proc to get ready */
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 */
73 /* Write some more, and wait some more. */
74 (void) write(terminal
, SENDSTRING
, strlen(SENDSTRING
));
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
;
88 FD_ZERO(&fds_read
); FD_ZERO(&fds_write
); FD_ZERO(&fds_error
);
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");
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");
150 waitpid(child
, &retval
, 0);
154 int main(int argc
, char **argv
) {
158 /* Get subtest number */
160 printf("Usage: %s subtest_no\n", argv
[0]);
162 } else if(sscanf(argv
[1], "%d", &subtest
) != 1) {
163 printf("Usage: %s subtest_no\n", argv
[0]);
167 open_terminal(&master
, &slave
);
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");
177 exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/