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
|
#include <assert.h>
#include <uv.h>
#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
#include "nvim/event/process.h"
#include "nvim/event/libuv_process.h"
#include "nvim/log.h"
#include "nvim/path.h"
#include "nvim/os/os.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/libuv_process.c.generated.h"
#endif
/// @returns zero on success, or negative error code
int libuv_process_spawn(LibuvProcess *uvproc)
FUNC_ATTR_NONNULL_ALL
{
Process *proc = (Process *)uvproc;
uvproc->uvopts.file = proc->argv[0];
uvproc->uvopts.args = proc->argv;
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE;
if (proc->detach) {
uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
}
#ifdef WIN32
// libuv assumes spawned processes follow the convention from
// CommandLineToArgvW(), cmd.exe does not. Disable quoting since it will
// result in unexpected behaviour, the caller is left with the responsibility
// to quote arguments accordingly. system('') has shell* options for this.
//
// Disable quoting for cmd, cmd.exe and $COMSPEC with a cmd.exe filename
bool is_cmd = STRICMP(proc->argv[0], "cmd.exe") == 0
|| STRICMP(proc->argv[0], "cmd") == 0;
if (!is_cmd) {
const char_u *comspec = (char_u *)os_getenv("COMSPEC");
const char_u *comspecshell = path_tail((char_u *)proc->argv[0]);
is_cmd = comspec != NULL && STRICMP(proc->argv[0], comspec) == 0
&& STRICMP("cmd.exe", (char *)comspecshell) == 0;
}
if (is_cmd) {
uvproc->uvopts.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
}
#endif
uvproc->uvopts.exit_cb = exit_cb;
uvproc->uvopts.cwd = proc->cwd;
uvproc->uvopts.env = NULL;
uvproc->uvopts.stdio = uvproc->uvstdio;
uvproc->uvopts.stdio_count = 3;
uvproc->uvstdio[0].flags = UV_IGNORE;
uvproc->uvstdio[1].flags = UV_IGNORE;
uvproc->uvstdio[2].flags = UV_IGNORE;
uvproc->uv.data = proc;
if (proc->in) {
uvproc->uvstdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
uvproc->uvstdio[0].data.stream = (uv_stream_t *)&proc->in->uv.pipe;
}
if (proc->out) {
uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
uvproc->uvstdio[1].data.stream = (uv_stream_t *)&proc->out->uv.pipe;
}
if (proc->err) {
uvproc->uvstdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
uvproc->uvstdio[2].data.stream = (uv_stream_t *)&proc->err->uv.pipe;
}
int status;
if ((status = uv_spawn(&proc->loop->uv, &uvproc->uv, &uvproc->uvopts))) {
ELOG("uv_spawn failed: %s", uv_strerror(status));
return status;
}
proc->pid = uvproc->uv.pid;
return status;
}
void libuv_process_close(LibuvProcess *uvproc)
FUNC_ATTR_NONNULL_ARG(1)
{
uv_close((uv_handle_t *)&uvproc->uv, close_cb);
}
static void close_cb(uv_handle_t *handle)
{
Process *proc = handle->data;
if (proc->internal_close_cb) {
proc->internal_close_cb(proc);
}
}
static void exit_cb(uv_process_t *handle, int64_t status, int term_signal)
{
Process *proc = handle->data;
proc->status = (int)status;
proc->internal_exit_cb(proc);
}
|