You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

77 lines
1.8 KiB

  1. #include "spawn.h"
  2. #include <unistd.h>
  3. #include <errno.h>
  4. #include <assert.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #define LOG_MODULE "spawn"
  9. #define LOG_ENABLE_DBG 0
  10. #include "log.h"
  11. bool
  12. spawn(struct reaper *reaper, const char *cwd, char *const argv[],
  13. int stdin_fd, int stdout_fd, int stderr_fd)
  14. {
  15. int pipe_fds[2] = {-1, -1};
  16. if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
  17. LOG_ERRNO("failed to create pipe");
  18. goto err;
  19. }
  20. pid_t pid = fork();
  21. if (pid < 0) {
  22. LOG_ERRNO("failed to fork");
  23. goto err;
  24. }
  25. if (pid == 0) {
  26. /* Child */
  27. close(pipe_fds[0]);
  28. if ((stdin_fd >= 0 && (dup2(stdin_fd, STDIN_FILENO) < 0 || close(stdin_fd) < 0)) ||
  29. (stdout_fd >= 0 && (dup2(stdout_fd, STDOUT_FILENO) < 0 || close(stdout_fd) < 0)) ||
  30. (stderr_fd >= 0 && (dup2(stderr_fd, STDERR_FILENO) < 0 || close(stderr_fd) < 0)) ||
  31. (cwd != NULL && chdir(cwd) < 0) ||
  32. execvp(argv[0], argv) < 0)
  33. {
  34. (void)!write(pipe_fds[1], &errno, sizeof(errno));
  35. _exit(errno);
  36. }
  37. assert(false);
  38. _exit(errno);
  39. }
  40. /* Parent */
  41. close(pipe_fds[1]);
  42. int _errno;
  43. static_assert(sizeof(_errno) == sizeof(errno), "errno size mismatch");
  44. ssize_t ret = read(pipe_fds[0], &_errno, sizeof(_errno));
  45. close(pipe_fds[0]);
  46. if (ret == 0) {
  47. reaper_add(reaper, pid);
  48. return true;
  49. } else if (ret < 0) {
  50. LOG_ERRNO("failed to read from pipe");
  51. return false;
  52. } else {
  53. LOG_ERRNO_P(_errno, "%s: failed to spawn", argv[0]);
  54. errno = _errno;
  55. waitpid(pid, NULL, 0);
  56. return false;
  57. }
  58. err:
  59. if (pipe_fds[0] != -1)
  60. close(pipe_fds[0]);
  61. if (pipe_fds[1] != -1)
  62. close(pipe_fds[1]);
  63. return false;
  64. }