-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsubp.h
154 lines (124 loc) · 3.78 KB
/
subp.h
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#ifndef ZAKAROUF_Z_IMP__SUB_H
#define ZAKAROUF_Z_IMP__SUB_H
/**
* Get Enviorment Variable
*/
char** z__subp_getenv(void);
/**
* Use fork() to create a child process
*/
int z__subp_fork(char const *cmd);
/**
* Use posix_spawn() to create a child process
*/
int z__subp_spawn(char * const cmd);
/**
* Use posix_spawn() to execute a binary, must provide absolute path of the binary
*/
int z__subp_exec_raw(char const *absolute_exec_path, char * const *argv);
/**
* Same as z__sub_exec_raw(), but does not wait for child process to exit.
*/
int z__subp_exec_nowait_raw(int *pid, char const *absolute_exec_path, char * const *argv);
/**
* Macro wrapper around z__sub_exec_nowait_raw()
*/
#define z__subp_exec_nowait(p, exec, ...)\
z__subp_exec_nowait_raw(p, exec, (char *const[]){__VA_ARGS__, NULL})
/**
* Macro wrapper around z__sub_exec_raw()
*/
#define z__subp_exec(exec_path, ...)\
z__subp_exec_raw(exec_path, (char *const []){__VA_ARGS__, NULL})
#ifdef Z__IMPLEMENTATION
#include <stdlib.h>
#include <spawn.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
extern char **environ;
char** z__subp_getenv(void) { return environ; }
int z__subp_fork(const char *command)
{
pid_t child, p;
int status;
/*
* Prepare pipes et cetera first.
*/
/* Fork to create the subprocess. */
child = fork();
if (child == (pid_t)-1) {
/* Cannot fork(); usually out of resources (user limits).
* see errno for details. With <string.h>, you can use
* strerror(errno) to obtain the error string itself. */
return 0;
} else if (!child) {
/* This is the child process itself.
* Do whatever cleanup is necessary, then
* execute the subprocess command. */
execl("/bin/sh", "sh", "-c", command, NULL);
/* This is only reached if the exec failed;
* again, see errno for reason.
* Always have the child process exit! */
return 0;
}
/* This is only run by the parent process
* (because the child always exits within the
* else if body above).
*
* The subprocess PID is 'child'.
*/
/* Wait for the child process to exit. */
do {
status = 0;
p = waitpid(child, &status, 0);
if (p == (pid_t)-1 && errno != EINTR)
break; /* Error */
} while (p != child);
if (p != child) {
/* Child process was lost.
* If (p == (pid_t)-1), errno describes the error.
*/
} else if (WIFEXITED(status)) {
/* Child process exited with WEXITSTATUS(status) status.
* A status of 0 (or EXIT_SUCCESS) means success,
* no errors occurred. Nonzero usually means an error,
* but codes vary from binary to binary.
*/
} else if (WIFSIGNALED(status)) {
/* Child process died from WTERMSIG(status) signal.
* If you include <string.h>, you can use
* strsignal(WTERMSIG(status))
* to obtain the name (string) of the terminating signal.
*/
} else {
/* Child process died from unknown causes.
*/
}
/* All done. */
return 1;
}
int z__subp_exec_nowait_raw(int *pid, char const *exec_path, char * const *argv)
{
int status = posix_spawn(pid, exec_path, NULL, NULL, argv, environ);
return status;
}
int z__subp_exec_raw(char const *exec_path, char * const *argv)
{
pid_t pid;
int status = posix_spawn(&pid, exec_path, NULL, NULL, argv, environ);
if (status == 0) {
do {
if (waitpid(pid, &status, 0) == -1) {
exit(1);
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}
int z__subp_spawn(char * const cmd)
{
return z__subp_exec("/bin/sh", "sh", "-c", cmd);
}
#endif //Z__IMPLEMENTATION
#endif