fd-io.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /* Copyright (c) 1993-2007 by Richard Kelsey and Jonathan Rees.
  2. See file COPYING. */
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <sys/time.h>
  9. #include <errno.h> /* for errno, (POSIX?/ANSI) */
  10. #include <string.h> /* FD_ZERO sometimes needs this */
  11. #include <locale.h> /* ISO C99 */
  12. #include <langinfo.h> /* SUSv2 */
  13. #include "sysdep.h"
  14. #include "c-mods.h"
  15. #include "scheme48vm.h"
  16. #include "event.h"
  17. #include "fd-io.h"
  18. #include "unix.h"
  19. /* Non-blocking I/O on file descriptors.
  20. There appear to be two ways to get non-blocking input and output. One
  21. is to open files with the O_NONBLOCK flag (and to use fcntl() to do the
  22. same to stdin and stdout), the other is to call select() on each file
  23. descriptor before doing the I/O operation. O_NONBLOCK has the problem
  24. of being a property of the file descriptor, and its use with stdin and
  25. stdout can lead to horrible results.
  26. We use a mixture of both. For input files we call select() before doing
  27. a read(), because read() will return immediately if there are any bytes
  28. available at all, and using O_NONBLOCK on stdin is a very bad idea.
  29. Output files are opened using O_NONBLOCK and stdout is left alone.
  30. */
  31. int
  32. ps_open_fd(char *filename, psbool is_input, long *status)
  33. {
  34. #define FILE_NAME_SIZE 1024
  35. #define PERMISSION 0666 /* read and write for everyone */
  36. char filename_temp[FILE_NAME_SIZE];
  37. char *expanded;
  38. extern char *s48_expand_file_name(char *, char *, int);
  39. int flags;
  40. mode_t mode;
  41. expanded = s48_expand_file_name(filename, filename_temp, FILE_NAME_SIZE);
  42. if (expanded == NULL)
  43. return -1;
  44. if (is_input) {
  45. flags = O_RDONLY;
  46. mode = 0; }
  47. else {
  48. flags = O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK;
  49. mode = PERMISSION; }
  50. /* keep trying if interrupted */
  51. while(1) {
  52. int fd = open(expanded, flags, mode);
  53. if (fd != -1) {
  54. *status = NO_ERRORS;
  55. return fd; }
  56. else if (errno != EINTR) {
  57. *status = errno;
  58. return -1; }
  59. }
  60. }
  61. int
  62. ps_close_fd(long fd_as_long)
  63. {
  64. int fd = (int)fd_as_long;
  65. /* keep retrying if interrupted */
  66. while(1) {
  67. int status = close(fd);
  68. if (status != -1) {
  69. s48_remove_fd(fd);
  70. return NO_ERRORS; }
  71. else if (errno != EINTR)
  72. return errno;
  73. }
  74. }
  75. psbool ps_check_fd(long fd_as_long, psbool is_read, long *status)
  76. {
  77. int fd = (int)fd_as_long;
  78. int ready;
  79. struct timeval timeout;
  80. fd_set fds;
  81. FD_ZERO(&fds);
  82. FD_SET(fd, &fds);
  83. timerclear(&timeout);
  84. *status = NO_ERRORS;
  85. while(1) {
  86. ready = select(fd + 1,
  87. is_read ? &fds : NULL,
  88. is_read ? NULL : &fds,
  89. &fds,
  90. &timeout);
  91. if (ready == 0)
  92. return PSFALSE;
  93. /* Mike has witnessed it return 2 on Mac OS X. */
  94. else if (ready >= 1)
  95. return PSTRUE;
  96. else if (errno != EINTR) {
  97. *status = errno;
  98. return PSFALSE; } }
  99. }
  100. long
  101. ps_read_fd(long fd_as_long, char *buffer, long max, psbool waitp,
  102. psbool *eofp, psbool *pending, long *status)
  103. {
  104. int got, ready;
  105. void *buf = (void *)buffer;
  106. int fd = (int)fd_as_long;
  107. struct timeval timeout;
  108. fd_set readfds;
  109. FD_ZERO(&readfds);
  110. FD_SET(fd, &readfds);
  111. timerclear(&timeout);
  112. /* for the normal return */
  113. *eofp = PSFALSE;
  114. *pending = PSFALSE;
  115. *status = NO_ERRORS;
  116. while(1) {
  117. ready = select(fd + 1, &readfds, NULL, &readfds, &timeout);
  118. if (ready == 0) {
  119. if (!waitp)
  120. return 0;
  121. else if (s48_add_pending_fd(fd, PSTRUE)) {
  122. *pending = PSTRUE;
  123. return 0; }
  124. else {
  125. *status = ENOMEM; /* as close as POSIX gets */
  126. return 0; }}
  127. else if (ready == -1) {
  128. if (errno != EINTR) {
  129. *status = errno;
  130. return 0; } }
  131. else { /* characters waiting */
  132. got = read(fd, buf, max);
  133. if (got > 0) { /* all is well */
  134. return got; }
  135. else if (got == 0) { /* end of file */
  136. *eofp = PSTRUE;
  137. return 0; }
  138. else if (errno == EINTR) { /* HCC */
  139. return 0; }
  140. else if (errno == EAGAIN) { /* HCC */
  141. if (!waitp)
  142. return 0;
  143. else if (s48_add_pending_fd(fd, PSTRUE)) {
  144. *pending = PSTRUE;
  145. return 0; }
  146. else {
  147. *status = ENOMEM; /* as close as POSIX gets */
  148. return 0; } }
  149. else {
  150. *status = errno;
  151. return 0; } } }
  152. }
  153. long
  154. ps_write_fd(long fd_as_long, char *buffer, long max, psbool *pending, long *status)
  155. {
  156. int sent;
  157. int fd = (int)fd_as_long;
  158. void *buf = (void *)buffer;
  159. *pending = PSFALSE;
  160. *status = NO_ERRORS;
  161. sent = write(fd, buf, max);
  162. if (sent > 0)
  163. {}
  164. else if (errno == EINTR || errno == EAGAIN) { /* HCC */
  165. if (s48_add_pending_fd(fd, PSFALSE))
  166. *pending = PSTRUE;
  167. else
  168. *status = ENOMEM; /* as close as POSIX gets */
  169. sent = 0; }
  170. else {
  171. *status = errno;
  172. sent = 0; }
  173. return sent;
  174. }
  175. long
  176. ps_io_buffer_size(void)
  177. {
  178. return 4096;
  179. }
  180. psbool
  181. ps_io_crlf_p(void)
  182. {
  183. return PSFALSE;
  184. }
  185. char *
  186. ps_console_encoding(long fd_as_long)
  187. {
  188. static char *encoding_STDIN = NULL;
  189. static char *encoding_STDOUT = NULL;
  190. static char *encoding_STDERR = NULL;
  191. static char setlocale_called = PSFALSE;
  192. char *codeset;
  193. char** encoding_p;
  194. if (fd_as_long == STDIN_FD())
  195. encoding_p = &encoding_STDIN;
  196. else if (fd_as_long == STDOUT_FD())
  197. encoding_p = &encoding_STDOUT;
  198. else if (fd_as_long == STDERR_FD())
  199. encoding_p = &encoding_STDERR;
  200. /* Mike has no clue what the rationale for needing this is. */
  201. if (!setlocale_called)
  202. {
  203. setlocale(LC_CTYPE, "");
  204. setlocale_called = PSTRUE;
  205. }
  206. if (*encoding_p == NULL)
  207. {
  208. codeset = nl_langinfo(CODESET); /* this ain't reentrant */
  209. *encoding_p = malloc(strlen(codeset) + 1);
  210. if (*encoding_p == NULL)
  211. return NULL;
  212. strcpy(*encoding_p, codeset);
  213. }
  214. return *encoding_p;
  215. }
  216. long
  217. ps_abort_fd_op(long fd_as_long)
  218. {
  219. int fd = (int)fd_as_long;
  220. if (!s48_remove_fd(fd))
  221. fprintf(stderr, "Error: ps_abort_fd_op, no pending operation on fd %d\n",
  222. fd);
  223. return 0; /* because we do not actually do any I/O in parallel the
  224. status is always zero: no characters transfered. */
  225. }
  226. /*
  227. * This checks that fd's destined for output channels are marked
  228. * as nonblocking. Stdout and stderr are a special case because
  229. * we do not want to screw up the shell, if we were invoked from
  230. * one.
  231. */
  232. s48_value
  233. s48_add_channel(s48_value mode, s48_value id, long fd)
  234. {
  235. if (mode == S48_CHANNEL_STATUS_OUTPUT
  236. && fd != 1
  237. && fd != 2) {
  238. int flags;
  239. RETRY_OR_RAISE_NEG(flags, fcntl(fd, F_GETFL));
  240. if ((flags & O_NONBLOCK) == 0)
  241. fprintf(stderr,
  242. "Warning: output channel file descriptor %d is not non-blocking\n",
  243. (int) fd); }
  244. return s48_really_add_channel(mode, id, fd);
  245. }