pipe-posix.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (c) 2023 Lain Bailey <[email protected]>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <stdio.h>
  17. #include <sys/wait.h>
  18. #include <unistd.h>
  19. #include <errno.h>
  20. #include <spawn.h>
  21. #include "bmem.h"
  22. #include "pipe.h"
  23. struct os_process_pipe {
  24. bool read_pipe;
  25. int pid;
  26. FILE *file;
  27. FILE *err_file;
  28. };
  29. os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
  30. const char *type)
  31. {
  32. struct os_process_pipe process_pipe = {0};
  33. struct os_process_pipe *out;
  34. posix_spawn_file_actions_t file_actions;
  35. if (!cmd_line || !type) {
  36. return NULL;
  37. }
  38. process_pipe.read_pipe = *type == 'r';
  39. int mainfds[2] = {0};
  40. int errfds[2] = {0};
  41. if (pipe(mainfds) != 0) {
  42. return NULL;
  43. }
  44. if (pipe(errfds) != 0) {
  45. close(mainfds[0]);
  46. close(mainfds[1]);
  47. return NULL;
  48. }
  49. if (posix_spawn_file_actions_init(&file_actions) != 0) {
  50. close(mainfds[0]);
  51. close(mainfds[1]);
  52. close(errfds[0]);
  53. close(errfds[1]);
  54. return NULL;
  55. }
  56. if (process_pipe.read_pipe) {
  57. posix_spawn_file_actions_addclose(&file_actions, mainfds[0]);
  58. if (mainfds[1] != STDOUT_FILENO) {
  59. posix_spawn_file_actions_adddup2(
  60. &file_actions, mainfds[1], STDOUT_FILENO);
  61. posix_spawn_file_actions_addclose(&file_actions,
  62. mainfds[0]);
  63. }
  64. } else {
  65. if (mainfds[0] != STDIN_FILENO) {
  66. posix_spawn_file_actions_adddup2(
  67. &file_actions, mainfds[0], STDIN_FILENO);
  68. posix_spawn_file_actions_addclose(&file_actions,
  69. mainfds[1]);
  70. }
  71. }
  72. posix_spawn_file_actions_addclose(&file_actions, errfds[0]);
  73. posix_spawn_file_actions_adddup2(&file_actions, errfds[1],
  74. STDERR_FILENO);
  75. int pid;
  76. char *argv[4] = {"sh", "-c", (char *)cmd_line, NULL};
  77. int ret = posix_spawn(&pid, "/bin/sh", &file_actions, NULL, argv, NULL);
  78. posix_spawn_file_actions_destroy(&file_actions);
  79. if (ret != 0) {
  80. close(mainfds[0]);
  81. close(mainfds[1]);
  82. close(errfds[0]);
  83. close(errfds[1]);
  84. return NULL;
  85. }
  86. close(errfds[1]);
  87. process_pipe.err_file = fdopen(errfds[0], "r");
  88. if (process_pipe.read_pipe) {
  89. close(mainfds[1]);
  90. process_pipe.file = fdopen(mainfds[0], "r");
  91. } else {
  92. close(mainfds[0]);
  93. process_pipe.file = fdopen(mainfds[1], "w");
  94. }
  95. process_pipe.pid = pid;
  96. out = bmalloc(sizeof(os_process_pipe_t));
  97. *out = process_pipe;
  98. return out;
  99. }
  100. int os_process_pipe_destroy(os_process_pipe_t *pp)
  101. {
  102. int ret = 0;
  103. if (pp) {
  104. int status;
  105. fclose(pp->file);
  106. pp->file = NULL;
  107. fclose(pp->err_file);
  108. pp->err_file = NULL;
  109. do {
  110. ret = waitpid(pp->pid, &status, 0);
  111. } while (ret == -1 && errno == EINTR);
  112. if (WIFEXITED(status))
  113. ret = (int)(char)WEXITSTATUS(status);
  114. bfree(pp);
  115. }
  116. return ret;
  117. }
  118. size_t os_process_pipe_read(os_process_pipe_t *pp, uint8_t *data, size_t len)
  119. {
  120. if (!pp) {
  121. return 0;
  122. }
  123. if (!pp->read_pipe) {
  124. return 0;
  125. }
  126. return fread(data, 1, len, pp->file);
  127. }
  128. size_t os_process_pipe_read_err(os_process_pipe_t *pp, uint8_t *data,
  129. size_t len)
  130. {
  131. if (!pp) {
  132. return 0;
  133. }
  134. return fread(data, 1, len, pp->err_file);
  135. }
  136. size_t os_process_pipe_write(os_process_pipe_t *pp, const uint8_t *data,
  137. size_t len)
  138. {
  139. if (!pp) {
  140. return 0;
  141. }
  142. if (pp->read_pipe) {
  143. return 0;
  144. }
  145. size_t written = 0;
  146. while (written < len) {
  147. size_t ret = fwrite(data + written, 1, len - written, pp->file);
  148. if (!ret)
  149. return written;
  150. written += ret;
  151. }
  152. return written;
  153. }