summaryrefslogtreecommitdiff
path: root/src/bin/utils.h
blob: 3baa1b13bdefa6576e2535c067b8d257d0726c55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#pragma once

// #include <spawn.h>
#include <sys/wait.h>
#include <unistd.h>

struct proc {
   pid_t pid;
   int fds[2];
};

static inline void
close_fd(int *fd)
{
   assert(fd);
   if (*fd >= 0)
      close(*fd);
}

static inline bool
proc_open(const char *file, char *const argv[], struct proc *out_proc)
{
   assert(file && argv && out_proc);
   *out_proc = (struct proc){0};

   int pipes[4];
   pipe(&pipes[0]); /* parent */
   pipe(&pipes[2]); /* child */

#if 0
   // Doesn't work, no idea why
   posix_spawn_file_actions_t fa;
   if (posix_spawn_file_actions_init(&fa) != 0 ||
       posix_spawn_file_actions_addclose(&fa, pipes[0]) != 0 ||
       posix_spawn_file_actions_addclose(&fa, pipes[3]) != 0 ||
       posix_spawn_file_actions_adddup2(&fa, pipes[2], 0) != 0 ||
       posix_spawn_file_actions_adddup2(&fa, pipes[1], 1) != 0 ||
       posix_spawn_file_actions_addclose(&fa, pipes[2]) != 0 ||
       posix_spawn_file_actions_addclose(&fa, pipes[1]) != 0 ||
       posix_spawnp(&out_proc->pid, file, &fa, NULL, argv, NULL) != 0) {
      posix_spawn_file_actions_destroy(&fa);
      for (uint8_t i = 0; i < ARRAY_SIZE(pipes); ++i)
         close(pipes[i]);
      return false;
   }
   posix_spawn_file_actions_destroy(&fa);
#else
   if ((out_proc->pid = fork()) > 0) {
      out_proc->fds[0] = pipes[3];
      out_proc->fds[1] = pipes[0];
      close(pipes[1]);
      close(pipes[2]);
      return true;
   } else {
      close(pipes[0]);
      close(pipes[3]);
      dup2(pipes[2], 0);
      dup2(pipes[1], 1);
      close(pipes[2]);
      close(pipes[1]);
      execvp(file, argv);
      _exit(0);
   }
#endif

   out_proc->fds[0] = pipes[3];
   out_proc->fds[1] = pipes[0];
   close(pipes[1]);
   close(pipes[2]);
   return true;
}

static inline void
proc_close(struct proc *proc)
{
   assert(proc);
   waitpid(proc->pid, NULL0);
   close_fd(&proc->fds[0]);
   close_fd(&proc->fds[1]);
   *proc = (struct proc){0};
}