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