forked from lem-project/async-process
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathasync-process.c
More file actions
133 lines (116 loc) · 3.26 KB
/
async-process.c
File metadata and controls
133 lines (116 loc) · 3.26 KB
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
127
128
129
130
131
132
133
#include "async-process.h"
static const char* open_pty(int *out_fd)
{
int fd = posix_openpt(O_RDWR | O_CLOEXEC | O_NOCTTY);
if (fd < 0) return NULL;
if (grantpt(fd) == -1 || unlockpt(fd) == -1) return NULL;
fcntl(fd, F_SETFD, FD_CLOEXEC);
const char *name = ptsname(fd);
if (name == NULL) {
close(fd);
return NULL;
}
*out_fd = fd;
return name;
}
static struct process* allocate_process(int fd, const char *pts_name, int pid)
{
struct process *process = malloc(sizeof(struct process));
if (process == NULL)
return NULL;
process->fd = fd;
process->pty_name = malloc(strlen(pts_name) + 1);
process->pid = pid;
strcpy(process->pty_name, pts_name);
return process;
}
void my_exit(int status) {
// exitを使うとatexitで動作に影響を与えられる、これが原因でプロセスを終了できなくなる事があるので使うのを避ける
// 例えばSDL2はat_exitを使っているせいか、lemのSDL2 frontendでasync_processが動作しなくなっていた
_exit(status);
}
struct process* create_process(char *const command[], bool nonblock, const char *path)
{
int pty_master;
const char *pts_name = open_pty(&pty_master);
if (pts_name == NULL)
return NULL;
if (nonblock)
fcntl(pty_master, F_SETFL, O_NONBLOCK);
int pipefd[2];
if (pipe(pipefd) == -1) return NULL;
pid_t pid = fork();
if (pid == 0) {
close(pipefd[0]);
pid = fork();
if (pid == 0) {
close(pipefd[1]);
setsid();
int pty_slave = open(pts_name, O_RDWR | O_NOCTTY);
close(pty_master);
// Set raw mode
struct termios tty;
tcgetattr(pty_slave, &tty);
cfmakeraw(&tty);
tcsetattr(pty_slave, TCSANOW, &tty);
dup2(pty_slave, STDIN_FILENO);
dup2(pty_slave, STDOUT_FILENO);
dup2(pty_slave, STDERR_FILENO);
close(pty_slave);
if (path != NULL) chdir(path);
execvp(command[0], command);
int error_status = errno;
if (error_status == ENOENT) {
char str[128];
sprintf(str, "%s: command not found", command[0]);
write(STDIN_FILENO, str, strlen(str));
} else {
char *str = strerror(error_status);
write(STDIN_FILENO, str, strlen(str));
}
my_exit(error_status);
} else {
char buf[12];
sprintf(buf, "%d", pid);
write(pipefd[1], buf, strlen(buf)+1);
close(pipefd[1]);
my_exit(0);
}
} else {
close(pipefd[1]);
if (waitpid(pid, NULL, 0) == -1)
return NULL;
char buf[12];
read(pipefd[0], buf, sizeof(buf));
close(pipefd[0]);
return allocate_process(pty_master, pts_name, atoi(buf));
}
return NULL;
}
void delete_process(struct process *process)
{
kill(process->pid, 9);
close(process->fd);
free(process->pty_name);
free(process);
}
int process_pid(struct process *process)
{
return process->pid;
}
void process_send_input(struct process *process, const char *string)
{
write(process->fd, string, strlen(string));
}
const char* process_receive_output(struct process *process)
{
int n = read(process->fd, process->buffer, sizeof(process->buffer)-1);
if (n == -1)
return NULL;
process->buffer[n] = '\0';
return process->buffer;
}
int process_alive_p(struct process *process)
{
return kill(process->pid, 0) == 0;
}