summaryrefslogtreecommitdiff
path: root/src/dged/process-posix.c
blob: 94ceb5f8b681638b8169c67c5710567007dbffb7 (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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "process.h"

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/wait.h>

static int create_pipe(int *read_end, int *write_end, bool read_nonblock,
                       bool write_nonblock) {
  int pipes[2] = {0};
  if (pipe(pipes) < 0) {
    return -1;
  }

  if (write_nonblock) {
    int flags = fcntl(pipes[1], F_GETFL, 0);
    if (flags < 0) {
      return -1;
    }

    flags |= O_NONBLOCK;
    if (fcntl(pipes[1], F_SETFL, flags) < 0) {
      return -1;
    }
  }

  if (read_nonblock) {
    int flags = fcntl(pipes[0], F_GETFL, 0);
    if (flags < 0) {
      return -1;
    }

    flags |= O_NONBLOCK;
    if (fcntl(pipes[0], F_SETFL, flags) < 0) {
      return -1;
    }
  }

  *read_end = pipes[0];
  *write_end = pipes[1];

  return 0;
}

struct process_create_result process_create(char *const command[],
                                            struct process *result) {

  int stdin_read, stdin_write;
  if (create_pipe(&stdin_read, &stdin_write, false, true) < 0) {
    return (struct process_create_result){
        .ok = false,
        .error_message = strerror(errno),
    };
  }

  int stdout_read, stdout_write;
  if (create_pipe(&stdout_read, &stdout_write, true, false) < 0) {
    return (struct process_create_result){
        .ok = false,
        .error_message = strerror(errno),
    };
  }

  int stderr_read, stderr_write;
  if (create_pipe(&stderr_read, &stderr_write, true, false) < 0) {
    return (struct process_create_result){
        .ok = false,
        .error_message = strerror(errno),
    };
  }

  pid_t pid = fork();
  if (pid == -1) {
    return (struct process_create_result){
        .ok = false,
        .error_message = strerror(errno),
    };
  } else if (pid == 0) {
    close(stdin_write);
    close(stdout_read);
    close(stderr_read);

    if (dup2(stdin_read, STDIN_FILENO) < 0) {
      exit(16);
    }

    if (dup2(stdout_write, STDOUT_FILENO) < 0) {
      exit(16);
    }

    if (dup2(stderr_write, STDERR_FILENO) < 0) {
      exit(16);
    }

    if (execvp(command[0], command) < 0) {
      exit(16);
    }
  } else {
    close(stdin_read);
    close(stdout_write);
    close(stderr_write);

    result->stdin = stdin_write;
    result->stdout = stdout_read;
    result->stderr = stderr_read;
    result->id = (fd_t)pid;
    result->impl = NULL;
  }

  return (struct process_create_result){
      .ok = true,
  };
}

void process_destroy(struct process *p) { (void)p; }

bool process_running(const struct process *p) {
  return waitpid(p->id, NULL, WNOHANG) == 0;
}

bool process_kill(const struct process *p) { return kill(p->id, SIGTERM) == 0; }