PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/test/t40c.c

http://www.minix3.org/
C | 160 lines | 99 code | 33 blank | 28 comment | 29 complexity | ff7b39d7eaf303d7e9ba0c2e0f10215f MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* t40c.c
  2. *
  3. * Test (pseudo) terminal devices
  4. *
  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.
  8. *
  9. * This test is part of a bigger select test. It expects as argument which sub-
  10. * test it is.
  11. */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <unistd.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. #include <sys/select.h>
  19. #include <errno.h>
  20. #include <sys/wait.h>
  21. #include <string.h>
  22. #define TERMINALW "/dev/ttypf"
  23. #define TERMINALR "/dev/ptypf"
  24. #define SENDSTRING "minixrocks"
  25. #define MAX_ERROR 5
  26. int errct = 0, subtest = -1;
  27. void e(int n, char *s) {
  28. printf("Subtest %d, error %d, %s\n", subtest, n, s);
  29. if (errct++ > MAX_ERROR) {
  30. printf("Too many errors; test aborted\n");
  31. exit(errct);
  32. }
  33. }
  34. void open_terminal(int *child_fd, int *parent_fd) {
  35. int fd1, fd2, i;
  36. char opentermw[5+OPEN_MAX+1];
  37. char opentermr[5+OPEN_MAX+1];
  38. char *term[] = {"f","e","d","c","b","a","9","8","7","6","5","4","3","2","1"};
  39. #define TERMS (sizeof(term)/sizeof(term[0]))
  40. 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]);
  44. /* Open master terminal for writing */
  45. if((fd1 = open(opentermw, O_WRONLY)) == -1) continue;
  46. /* Open slave terminal for reading */
  47. if((fd2 = open(opentermr, O_RDONLY)) == -1) {
  48. close(fd1);
  49. continue;
  50. }
  51. *child_fd = fd1;
  52. *parent_fd = fd2;
  53. return;
  54. }
  55. /* If we get here we failed to find a terminal pair */
  56. exit(EXIT_FAILURE);
  57. }
  58. int do_child(int terminal) {
  59. struct timeval tv;
  60. /* Going to sleep for two seconds to allow the parent proc to get ready */
  61. tv.tv_sec = 2;
  62. tv.tv_usec = 0;
  63. select(0, NULL, NULL, NULL, &tv);
  64. /* Try to write. Doesn't matter how many bytes we actually send. */
  65. (void) write(terminal, SENDSTRING, strlen(SENDSTRING));
  66. close(terminal);
  67. /* Wait for another second to allow the parent to process incoming data */
  68. tv.tv_usec = 1000000;
  69. (void) select(0,NULL, NULL, NULL, &tv);
  70. exit(0);
  71. }
  72. int do_parent(int child, int terminal) {
  73. fd_set fds_read, fds_write, fds_error;
  74. int retval;
  75. /* Clear bit masks */
  76. FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error);
  77. /* Set read bits */
  78. FD_SET(terminal, &fds_read);
  79. FD_SET(terminal, &fds_write);
  80. /* Test if we can read or write from/to fd. As fd is opened read only we
  81. * cannot actually write, so the select should return immediately with fd
  82. * set in fds_write, but not in fds_read. Note that the child waits two
  83. * seconds before sending data. This gives us the opportunity run this
  84. * sub-test as reading from fd is blocking at this point. */
  85. retval = select(terminal+1, &fds_read, &fds_write, &fds_error, NULL);
  86. if(retval != 1) e(1, "incorrect amount of ready file descriptors");
  87. if(FD_ISSET(terminal, &fds_read)) e(2, "read should NOT be set");
  88. if(!FD_ISSET(terminal, &fds_write)) e(3, "write should be set");
  89. if(FD_ISSET(terminal, &fds_error)) e(4, "error should NOT be set");
  90. /* Block until ready; until child wrote stuff */
  91. FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error);
  92. FD_SET(terminal, &fds_read);
  93. retval = select(terminal+1, &fds_read, NULL, &fds_error, NULL);
  94. if(retval != 1) e(5, "incorrect amount of ready file descriptors");
  95. if(!FD_ISSET(terminal, &fds_read)) e(6, "read should be set");
  96. if(FD_ISSET(terminal, &fds_error)) e(7, "error should not be set");
  97. FD_ZERO(&fds_read); FD_ZERO(&fds_error);
  98. FD_SET(terminal, &fds_write);
  99. retval = select(terminal+1, NULL, &fds_write, NULL, NULL);
  100. /* As it is impossible to write to a read only fd, this select should return
  101. * immediately with fd set in fds_write. */
  102. if(retval != 1) e(8, "incorrect amount or ready file descriptors");
  103. close(terminal);
  104. waitpid(child, &retval, 0);
  105. exit(errct);
  106. }
  107. int main(int argc, char **argv) {
  108. int forkres;
  109. int master, slave;
  110. /* Get subtest number */
  111. if(argc != 2) {
  112. printf("Usage: %s subtest_no\n", argv[0]);
  113. exit(-1);
  114. } else if(sscanf(argv[1], "%d", &subtest) != 1) {
  115. printf("Usage: %s subtest_no\n", argv[0]);
  116. exit(-1);
  117. }
  118. open_terminal(&master, &slave);
  119. forkres = fork();
  120. if(forkres == 0) do_child(master);
  121. else if(forkres > 0) do_parent(forkres, slave);
  122. else { /* Fork failed */
  123. perror("Unable to fork");
  124. exit(-1);
  125. }
  126. exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/
  127. }