fd-io.c 8.3 KB

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