grabber.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /** @file kexec.c
  2. */
  3. #include <assert.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <errno.h>
  11. #include <faux/list.h>
  12. #include <faux/buf.h>
  13. #include <faux/eloop.h>
  14. typedef struct {
  15. int fd_in;
  16. int fd_out;
  17. faux_buf_t *buf;
  18. } grabber_stream_t;
  19. typedef enum {
  20. IN,
  21. OUT
  22. } direction_t;
  23. grabber_stream_t *grabber_stream_new(int fd_in, int fd_out)
  24. {
  25. grabber_stream_t *stream = NULL;
  26. stream = malloc(sizeof(*stream));
  27. assert(stream);
  28. stream->fd_in = fd_in;
  29. stream->fd_out = fd_out;
  30. stream->buf = faux_buf_new(FAUX_BUF_UNLIMITED);
  31. return stream;
  32. }
  33. void grabber_stream_free(grabber_stream_t *stream)
  34. {
  35. if (!stream)
  36. return;
  37. faux_buf_free(stream->buf);
  38. faux_free(stream);
  39. }
  40. static bool_t grabber_stop_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  41. void *associated_data, void *user_data)
  42. {
  43. // Happy compiler
  44. eloop = eloop;
  45. type = type;
  46. associated_data = associated_data;
  47. user_data = user_data;
  48. return BOOL_FALSE; // Stop Event Loop
  49. }
  50. static bool_t grabber_fd_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  51. void *associated_data, void *user_data)
  52. {
  53. faux_eloop_info_fd_t *info = (faux_eloop_info_fd_t *)associated_data;
  54. faux_list_t *stream_list = (faux_list_t *)user_data;
  55. grabber_stream_t *stream = NULL;
  56. grabber_stream_t *cur_stream = NULL;
  57. direction_t direction = IN;
  58. faux_list_node_t *iter = NULL;
  59. type = type; // Happy compiler
  60. iter = faux_list_head(stream_list);
  61. while((cur_stream = (grabber_stream_t *)faux_list_each(&iter))) {
  62. if (info->fd == cur_stream->fd_in) {
  63. direction = IN;
  64. stream = cur_stream;
  65. break;
  66. }
  67. if (info->fd == cur_stream->fd_out) {
  68. direction = OUT;
  69. stream = cur_stream;
  70. break;
  71. }
  72. }
  73. if (!stream)
  74. return BOOL_FALSE; // Problems
  75. // Read data (must locates before write data code)
  76. if (info->revents & POLLIN) {
  77. ssize_t r = 0;
  78. do {
  79. ssize_t len = 0;
  80. void *data = NULL;
  81. size_t readed = 0;
  82. len = faux_buf_dwrite_lock_easy(stream->buf, &data);
  83. if (len <= 0)
  84. break;
  85. r = read(stream->fd_in, data, len);
  86. readed = r < 0 ? 0 : r;
  87. faux_buf_dwrite_unlock_easy(stream->buf, readed);
  88. } while (r > 0);
  89. }
  90. // Write data
  91. if (faux_buf_len(stream->buf) > 0) {
  92. ssize_t r = 0;
  93. ssize_t sent = 0;
  94. ssize_t len = 0;
  95. do {
  96. void *data = NULL;
  97. len = faux_buf_dread_lock_easy(stream->buf, &data);
  98. if (len <= 0)
  99. break;
  100. r = write(stream->fd_out, data, len);
  101. sent = r < 0 ? 0 : r;
  102. faux_buf_dread_unlock_easy(stream->buf, sent);
  103. } while (sent == len);
  104. }
  105. // EOF
  106. if (info->revents & (POLLHUP | POLLERR | POLLNVAL)) {
  107. faux_eloop_del_fd(eloop, info->fd);
  108. if (IN == direction)
  109. stream->fd_in = -1;
  110. else
  111. stream->fd_out = -1;
  112. }
  113. // Check if there additional data to send
  114. if (stream->fd_out >= 0) {
  115. if (faux_buf_len(stream->buf) == 0) {
  116. faux_eloop_exclude_fd_event(eloop, stream->fd_out, POLLOUT);
  117. // If correspondent IN is closed and buffer is empty
  118. // then out stream descriptor is not needed any more too
  119. if (stream->fd_in < 0)
  120. stream->fd_out = -1;
  121. } else {
  122. faux_eloop_include_fd_event(eloop, stream->fd_out, POLLOUT);
  123. }
  124. }
  125. iter = faux_list_head(stream_list);
  126. while((cur_stream = (grabber_stream_t *)faux_list_each(&iter))) {
  127. // Check is there any writers
  128. if (cur_stream->fd_in != -1)
  129. return BOOL_TRUE;
  130. // Process can have no writers but buffer can be non-empty in
  131. // same time
  132. if (cur_stream->fd_out != -1)
  133. return BOOL_TRUE;
  134. }
  135. return BOOL_FALSE;
  136. }
  137. void grabber(int fds[][2])
  138. {
  139. faux_eloop_t *eloop = NULL;
  140. int i = 0;
  141. faux_list_t *stream_list = NULL;
  142. int fdmax = 0;
  143. // Close all inherited fds except fds[] array
  144. fdmax = (int)sysconf(_SC_OPEN_MAX);
  145. for (i = (STDERR_FILENO + 1); i < fdmax; i++) {
  146. int j = 0;
  147. bool_t dont_close = BOOL_FALSE;
  148. while (fds[j][0] != -1) {
  149. if ((fds[j][0] == i) || (fds[j][1] == i)) {
  150. dont_close = BOOL_TRUE;
  151. break;
  152. }
  153. j++;
  154. }
  155. if (!dont_close)
  156. close(i);
  157. }
  158. stream_list = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  159. NULL, NULL, (void (*)(void *))grabber_stream_free);
  160. eloop = faux_eloop_new(NULL);
  161. faux_eloop_add_signal(eloop, SIGINT, grabber_stop_ev, NULL);
  162. faux_eloop_add_signal(eloop, SIGTERM, grabber_stop_ev, NULL);
  163. faux_eloop_add_signal(eloop, SIGQUIT, grabber_stop_ev, NULL);
  164. faux_eloop_add_signal(eloop, SIGPIPE, grabber_stop_ev, NULL);
  165. i = 0;
  166. while (fds[i][0] != -1) {
  167. grabber_stream_t *stream = grabber_stream_new(fds[i][0], fds[i][1]);
  168. int fflags = 0;
  169. faux_list_add(stream_list, stream);
  170. fflags = fcntl(stream->fd_in, F_GETFL);
  171. fcntl(stream->fd_in, F_SETFL, fflags | O_NONBLOCK);
  172. fflags = fcntl(stream->fd_out, F_GETFL);
  173. fcntl(stream->fd_out, F_SETFL, fflags | O_NONBLOCK);
  174. faux_eloop_add_fd(eloop, stream->fd_in, POLLIN, grabber_fd_ev, stream_list);
  175. faux_eloop_add_fd(eloop, stream->fd_out, 0, grabber_fd_ev, stream_list);
  176. i++;
  177. }
  178. faux_eloop_loop(eloop);
  179. faux_eloop_free(eloop);
  180. faux_list_free(stream_list);
  181. // Close file handlers
  182. i = 0;
  183. while (fds[i][0] != -1) {
  184. close(fds[i][0]);
  185. close(fds[i][1]);
  186. i++;
  187. }
  188. _exit(0);
  189. }