node-pty 0.11.0-beta3 → 0.11.0-beta30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/binding.gyp +69 -29
- package/lib/conpty_console_list_agent.js.map +1 -1
- package/lib/terminal.js +10 -4
- package/lib/terminal.js.map +1 -1
- package/lib/unixTerminal.js +26 -4
- package/lib/unixTerminal.js.map +1 -1
- package/lib/unixTerminal.test.js +127 -18
- package/lib/unixTerminal.test.js.map +1 -1
- package/lib/windowsConoutConnection.js +2 -1
- package/lib/windowsConoutConnection.js.map +1 -1
- package/lib/windowsPtyAgent.js +3 -0
- package/lib/windowsPtyAgent.js.map +1 -1
- package/lib/windowsTerminal.js +15 -3
- package/lib/windowsTerminal.js.map +1 -1
- package/lib/windowsTerminal.test.js +4 -5
- package/lib/windowsTerminal.test.js.map +1 -1
- package/lib/worker/conoutSocketWorker.js +3 -0
- package/lib/worker/conoutSocketWorker.js.map +1 -1
- package/package.json +2 -3
- package/scripts/post-install.js +1 -0
- package/src/conpty_console_list_agent.ts +1 -1
- package/src/interfaces.ts +3 -2
- package/src/native.d.ts +1 -1
- package/src/terminal.ts +20 -20
- package/src/tsconfig.json +1 -3
- package/src/unix/comms.h +5 -0
- package/src/unix/pty.cc +146 -172
- package/src/unix/spawn-helper.cc +70 -0
- package/src/unixTerminal.test.ts +145 -25
- package/src/unixTerminal.ts +24 -11
- package/src/win/conpty.cc +34 -22
- package/src/win/path_util.cc +1 -1
- package/src/windowsConoutConnection.ts +3 -2
- package/src/windowsPtyAgent.ts +5 -5
- package/src/windowsTerminal.test.ts +5 -6
- package/src/windowsTerminal.ts +17 -4
- package/src/worker/conoutSocketWorker.ts +4 -0
- package/typings/node-pty.d.ts +9 -3
- package/deps/winpty/.gitignore +0 -15
- package/deps/winpty/misc/.gitignore +0 -2
- package/scripts/install.js +0 -18
package/src/unix/pty.cc
CHANGED
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
#include <sys/wait.h>
|
|
30
30
|
#include <fcntl.h>
|
|
31
31
|
#include <signal.h>
|
|
32
|
+
#include <spawn.h>
|
|
33
|
+
|
|
34
|
+
#include "comms.h"
|
|
32
35
|
|
|
33
36
|
/* forkpty */
|
|
34
37
|
/* http://www.gnu.org/software/gnulib/manual/html_node/forkpty.html */
|
|
@@ -54,15 +57,6 @@
|
|
|
54
57
|
#define VDISCARD VDISCRD
|
|
55
58
|
#endif
|
|
56
59
|
|
|
57
|
-
/* environ for execvpe */
|
|
58
|
-
/* node/src/node_child_process.cc */
|
|
59
|
-
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
|
60
|
-
#include <crt_externs.h>
|
|
61
|
-
#define environ (*_NSGetEnviron())
|
|
62
|
-
#else
|
|
63
|
-
extern char **environ;
|
|
64
|
-
#endif
|
|
65
|
-
|
|
66
60
|
/* for pty_getproc */
|
|
67
61
|
#if defined(__linux__)
|
|
68
62
|
#include <stdio.h>
|
|
@@ -77,6 +71,17 @@ extern char **environ;
|
|
|
77
71
|
#define NSIG 32
|
|
78
72
|
#endif
|
|
79
73
|
|
|
74
|
+
#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
|
|
75
|
+
#define HAVE_POSIX_SPAWN_CLOEXEC_DEFAULT 1
|
|
76
|
+
#else
|
|
77
|
+
#define HAVE_POSIX_SPAWN_CLOEXEC_DEFAULT 0
|
|
78
|
+
#define POSIX_SPAWN_CLOEXEC_DEFAULT 0
|
|
79
|
+
#endif
|
|
80
|
+
|
|
81
|
+
#ifndef POSIX_SPAWN_USEVFORK
|
|
82
|
+
#define POSIX_SPAWN_USEVFORK 0
|
|
83
|
+
#endif
|
|
84
|
+
|
|
80
85
|
/**
|
|
81
86
|
* Structs
|
|
82
87
|
*/
|
|
@@ -103,9 +108,6 @@ NAN_METHOD(PtyGetProc);
|
|
|
103
108
|
* Functions
|
|
104
109
|
*/
|
|
105
110
|
|
|
106
|
-
static int
|
|
107
|
-
pty_execvpe(const char *, char **, char **);
|
|
108
|
-
|
|
109
111
|
static int
|
|
110
112
|
pty_nonblock(int);
|
|
111
113
|
|
|
@@ -117,11 +119,6 @@ pty_openpty(int *, int *, char *,
|
|
|
117
119
|
const struct termios *,
|
|
118
120
|
const struct winsize *);
|
|
119
121
|
|
|
120
|
-
static pid_t
|
|
121
|
-
pty_forkpty(int *, char *,
|
|
122
|
-
const struct termios *,
|
|
123
|
-
const struct winsize *);
|
|
124
|
-
|
|
125
122
|
static void
|
|
126
123
|
pty_waitpid(void *);
|
|
127
124
|
|
|
@@ -131,10 +128,16 @@ pty_after_waitpid(uv_async_t *);
|
|
|
131
128
|
static void
|
|
132
129
|
pty_after_close(uv_handle_t *);
|
|
133
130
|
|
|
131
|
+
static void throw_for_errno(const char* message, int _errno) {
|
|
132
|
+
Nan::ThrowError((
|
|
133
|
+
message + std::string(strerror(_errno))
|
|
134
|
+
).c_str());
|
|
135
|
+
}
|
|
136
|
+
|
|
134
137
|
NAN_METHOD(PtyFork) {
|
|
135
138
|
Nan::HandleScope scope;
|
|
136
139
|
|
|
137
|
-
if (info.Length() !=
|
|
140
|
+
if (info.Length() != 12 ||
|
|
138
141
|
!info[0]->IsString() ||
|
|
139
142
|
!info[1]->IsArray() ||
|
|
140
143
|
!info[2]->IsArray() ||
|
|
@@ -144,41 +147,31 @@ NAN_METHOD(PtyFork) {
|
|
|
144
147
|
!info[6]->IsNumber() ||
|
|
145
148
|
!info[7]->IsNumber() ||
|
|
146
149
|
!info[8]->IsBoolean() ||
|
|
147
|
-
!info[9]->
|
|
150
|
+
!info[9]->IsBoolean() ||
|
|
151
|
+
!info[10]->IsFunction() ||
|
|
152
|
+
!info[11]->IsString()) {
|
|
148
153
|
return Nan::ThrowError(
|
|
149
|
-
"Usage: pty.fork(file, args, env, cwd, cols, rows, uid, gid, utf8, onexit)");
|
|
154
|
+
"Usage: pty.fork(file, args, env, cwd, cols, rows, uid, gid, utf8, closeFDs, onexit, helperPath)");
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
// file
|
|
153
158
|
Nan::Utf8String file(info[0]);
|
|
154
159
|
|
|
155
160
|
// args
|
|
156
|
-
int i = 0;
|
|
157
161
|
v8::Local<v8::Array> argv_ = v8::Local<v8::Array>::Cast(info[1]);
|
|
158
|
-
int argc = argv_->Length();
|
|
159
|
-
int argl = argc + 1 + 1;
|
|
160
|
-
char **argv = new char*[argl];
|
|
161
|
-
argv[0] = strdup(*file);
|
|
162
|
-
argv[argl-1] = NULL;
|
|
163
|
-
for (; i < argc; i++) {
|
|
164
|
-
Nan::Utf8String arg(Nan::Get(argv_, i).ToLocalChecked());
|
|
165
|
-
argv[i+1] = strdup(*arg);
|
|
166
|
-
}
|
|
167
162
|
|
|
168
163
|
// env
|
|
169
|
-
i = 0;
|
|
170
164
|
v8::Local<v8::Array> env_ = v8::Local<v8::Array>::Cast(info[2]);
|
|
171
165
|
int envc = env_->Length();
|
|
172
166
|
char **env = new char*[envc+1];
|
|
173
167
|
env[envc] = NULL;
|
|
174
|
-
for (; i < envc; i++) {
|
|
168
|
+
for (int i = 0; i < envc; i++) {
|
|
175
169
|
Nan::Utf8String pair(Nan::Get(env_, i).ToLocalChecked());
|
|
176
170
|
env[i] = strdup(*pair);
|
|
177
171
|
}
|
|
178
172
|
|
|
179
173
|
// cwd
|
|
180
174
|
Nan::Utf8String cwd_(info[3]);
|
|
181
|
-
char *cwd = strdup(*cwd_);
|
|
182
175
|
|
|
183
176
|
// size
|
|
184
177
|
struct winsize winp;
|
|
@@ -187,6 +180,10 @@ NAN_METHOD(PtyFork) {
|
|
|
187
180
|
winp.ws_xpixel = 0;
|
|
188
181
|
winp.ws_ypixel = 0;
|
|
189
182
|
|
|
183
|
+
// uid / gid
|
|
184
|
+
int uid = info[6]->IntegerValue(Nan::GetCurrentContext()).FromJust();
|
|
185
|
+
int gid = info[7]->IntegerValue(Nan::GetCurrentContext()).FromJust();
|
|
186
|
+
|
|
190
187
|
// termios
|
|
191
188
|
struct termios t = termios();
|
|
192
189
|
struct termios *term = &t;
|
|
@@ -222,18 +219,35 @@ NAN_METHOD(PtyFork) {
|
|
|
222
219
|
term->c_cc[VSTATUS] = 20;
|
|
223
220
|
#endif
|
|
224
221
|
|
|
225
|
-
|
|
226
|
-
|
|
222
|
+
// closeFDs
|
|
223
|
+
bool closeFDs = Nan::To<bool>(info[9]).FromJust();
|
|
224
|
+
bool explicitlyCloseFDs = closeFDs && !HAVE_POSIX_SPAWN_CLOEXEC_DEFAULT;
|
|
227
225
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
226
|
+
// helperPath
|
|
227
|
+
Nan::Utf8String helper_path_(info[11]);
|
|
228
|
+
char *helper_path = strdup(*helper_path_);
|
|
229
|
+
|
|
230
|
+
const int EXTRA_ARGS = 6;
|
|
231
|
+
int argc = argv_->Length();
|
|
232
|
+
int argl = argc + EXTRA_ARGS + 1;
|
|
233
|
+
char **argv = new char*[argl];
|
|
234
|
+
argv[0] = strdup(helper_path);
|
|
235
|
+
argv[1] = strdup(*cwd_);
|
|
236
|
+
argv[2] = strdup(std::to_string(uid).c_str());
|
|
237
|
+
argv[3] = strdup(std::to_string(gid).c_str());
|
|
238
|
+
argv[4] = strdup(explicitlyCloseFDs ? "1": "0");
|
|
239
|
+
argv[5] = strdup(*file);
|
|
240
|
+
argv[argl - 1] = NULL;
|
|
241
|
+
for (int i = 0; i < argc; i++) {
|
|
242
|
+
Nan::Utf8String arg(Nan::Get(argv_, i).ToLocalChecked());
|
|
243
|
+
argv[i + EXTRA_ARGS] = strdup(*arg);
|
|
244
|
+
}
|
|
231
245
|
|
|
232
|
-
|
|
233
|
-
|
|
246
|
+
cfsetispeed(term, B38400);
|
|
247
|
+
cfsetospeed(term, B38400);
|
|
234
248
|
|
|
235
249
|
sigset_t newmask, oldmask;
|
|
236
|
-
|
|
250
|
+
int flags = POSIX_SPAWN_USEVFORK;
|
|
237
251
|
|
|
238
252
|
// temporarily block all signals
|
|
239
253
|
// this is needed due to a race condition in openpty
|
|
@@ -242,85 +256,109 @@ NAN_METHOD(PtyFork) {
|
|
|
242
256
|
sigfillset(&newmask);
|
|
243
257
|
pthread_sigmask(SIG_SETMASK, &newmask, &oldmask);
|
|
244
258
|
|
|
245
|
-
|
|
259
|
+
int master, slave;
|
|
260
|
+
int ret = pty_openpty(&master, &slave, nullptr, term, &winp);
|
|
261
|
+
if (ret == -1) {
|
|
262
|
+
perror("openpty failed");
|
|
263
|
+
Nan::ThrowError("openpty failed.");
|
|
264
|
+
goto done;
|
|
265
|
+
}
|
|
246
266
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
for (int i = 0 ; i < NSIG ; i++) { // NSIG is a macro for all signals + 1
|
|
253
|
-
sigaction(i, &sig_action, NULL);
|
|
254
|
-
}
|
|
267
|
+
int comms_pipe[2];
|
|
268
|
+
if (pipe(comms_pipe)) {
|
|
269
|
+
perror("pipe() failed");
|
|
270
|
+
Nan::ThrowError("pipe() failed.");
|
|
271
|
+
goto done;
|
|
255
272
|
}
|
|
256
|
-
// reenable signals
|
|
257
|
-
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
|
|
258
273
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
274
|
+
posix_spawn_file_actions_t acts;
|
|
275
|
+
posix_spawn_file_actions_init(&acts);
|
|
276
|
+
posix_spawn_file_actions_adddup2(&acts, slave, STDIN_FILENO);
|
|
277
|
+
posix_spawn_file_actions_adddup2(&acts, slave, STDOUT_FILENO);
|
|
278
|
+
posix_spawn_file_actions_adddup2(&acts, slave, STDERR_FILENO);
|
|
279
|
+
posix_spawn_file_actions_adddup2(&acts, comms_pipe[1], COMM_PIPE_FD);
|
|
280
|
+
posix_spawn_file_actions_addclose(&acts, comms_pipe[1]);
|
|
281
|
+
|
|
282
|
+
posix_spawnattr_t attrs;
|
|
283
|
+
posix_spawnattr_init(&attrs);
|
|
284
|
+
if (closeFDs) {
|
|
285
|
+
flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
|
|
265
286
|
}
|
|
287
|
+
posix_spawnattr_setflags(&attrs, flags);
|
|
266
288
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
case 0:
|
|
271
|
-
if (strlen(cwd)) {
|
|
272
|
-
if (chdir(cwd) == -1) {
|
|
273
|
-
perror("chdir(2) failed.");
|
|
274
|
-
_exit(1);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
289
|
+
{ // suppresses "jump bypasses variable initialization" errors
|
|
290
|
+
pid_t pid;
|
|
291
|
+
auto error = posix_spawn(&pid, argv[0], &acts, &attrs, argv, env);
|
|
277
292
|
|
|
278
|
-
|
|
279
|
-
if (setgid(gid) == -1) {
|
|
280
|
-
perror("setgid(2) failed.");
|
|
281
|
-
_exit(1);
|
|
282
|
-
}
|
|
283
|
-
if (setuid(uid) == -1) {
|
|
284
|
-
perror("setuid(2) failed.");
|
|
285
|
-
_exit(1);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
293
|
+
close(comms_pipe[1]);
|
|
288
294
|
|
|
289
|
-
|
|
295
|
+
// reenable signals
|
|
296
|
+
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
|
|
297
|
+
|
|
298
|
+
if (error) {
|
|
299
|
+
throw_for_errno("posix_spawn failed: ", error);
|
|
300
|
+
goto done;
|
|
301
|
+
}
|
|
290
302
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
303
|
+
int helper_error[2];
|
|
304
|
+
auto bytes_read = read(comms_pipe[0], &helper_error, sizeof(helper_error));
|
|
305
|
+
close(comms_pipe[0]);
|
|
306
|
+
|
|
307
|
+
if (bytes_read == sizeof(helper_error)) {
|
|
308
|
+
if (helper_error[0] == COMM_ERR_EXEC) {
|
|
309
|
+
throw_for_errno("exec() failed: ", helper_error[1]);
|
|
310
|
+
} else if (helper_error[0] == COMM_ERR_CHDIR) {
|
|
311
|
+
throw_for_errno("chdir() failed: ", helper_error[1]);
|
|
312
|
+
} else if (helper_error[0] == COMM_ERR_SETUID) {
|
|
313
|
+
throw_for_errno("setuid() failed: ", helper_error[1]);
|
|
314
|
+
} else if (helper_error[0] == COMM_ERR_SETGID) {
|
|
315
|
+
throw_for_errno("setgid() failed: ", helper_error[1]);
|
|
296
316
|
}
|
|
317
|
+
goto done;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (pty_nonblock(master) == -1) {
|
|
321
|
+
Nan::ThrowError("Could not set master fd to nonblocking.");
|
|
322
|
+
goto done;
|
|
323
|
+
}
|
|
297
324
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
325
|
+
v8::Local<v8::Object> obj = Nan::New<v8::Object>();
|
|
326
|
+
Nan::Set(obj,
|
|
327
|
+
Nan::New<v8::String>("fd").ToLocalChecked(),
|
|
328
|
+
Nan::New<v8::Number>(master));
|
|
329
|
+
Nan::Set(obj,
|
|
330
|
+
Nan::New<v8::String>("pid").ToLocalChecked(),
|
|
331
|
+
Nan::New<v8::Number>(pid));
|
|
332
|
+
Nan::Set(obj,
|
|
333
|
+
Nan::New<v8::String>("pty").ToLocalChecked(),
|
|
334
|
+
Nan::New<v8::String>(ptsname(master)).ToLocalChecked());
|
|
335
|
+
|
|
336
|
+
pty_baton *baton = new pty_baton();
|
|
337
|
+
baton->exit_code = 0;
|
|
338
|
+
baton->signal_code = 0;
|
|
339
|
+
baton->cb.Reset(v8::Local<v8::Function>::Cast(info[10]));
|
|
340
|
+
baton->pid = pid;
|
|
341
|
+
baton->async.data = baton;
|
|
342
|
+
|
|
343
|
+
uv_async_init(uv_default_loop(), &baton->async, pty_after_waitpid);
|
|
344
|
+
|
|
345
|
+
uv_thread_create(&baton->tid, pty_waitpid, static_cast<void*>(baton));
|
|
346
|
+
|
|
347
|
+
info.GetReturnValue().Set(obj);
|
|
321
348
|
}
|
|
349
|
+
done:
|
|
350
|
+
posix_spawn_file_actions_destroy(&acts);
|
|
351
|
+
posix_spawnattr_destroy(&attrs);
|
|
322
352
|
|
|
323
|
-
|
|
353
|
+
if (argv) {
|
|
354
|
+
for (int i = 0; i < argl; i++) free(argv[i]);
|
|
355
|
+
delete[] argv;
|
|
356
|
+
}
|
|
357
|
+
if (env) {
|
|
358
|
+
for (int i = 0; i < envc; i++) free(env[i]);
|
|
359
|
+
delete[] env;
|
|
360
|
+
}
|
|
361
|
+
free(helper_path);
|
|
324
362
|
}
|
|
325
363
|
|
|
326
364
|
NAN_METHOD(PtyOpen) {
|
|
@@ -428,21 +466,6 @@ NAN_METHOD(PtyGetProc) {
|
|
|
428
466
|
return info.GetReturnValue().Set(name_);
|
|
429
467
|
}
|
|
430
468
|
|
|
431
|
-
/**
|
|
432
|
-
* execvpe
|
|
433
|
-
*/
|
|
434
|
-
|
|
435
|
-
// execvpe(3) is not portable.
|
|
436
|
-
// http://www.gnu.org/software/gnulib/manual/html_node/execvpe.html
|
|
437
|
-
static int
|
|
438
|
-
pty_execvpe(const char *file, char **argv, char **envp) {
|
|
439
|
-
char **old = environ;
|
|
440
|
-
environ = envp;
|
|
441
|
-
int ret = execvp(file, argv);
|
|
442
|
-
environ = old;
|
|
443
|
-
return ret;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
469
|
/**
|
|
447
470
|
* Nonblocking FD
|
|
448
471
|
*/
|
|
@@ -670,55 +693,6 @@ err:
|
|
|
670
693
|
#endif
|
|
671
694
|
}
|
|
672
695
|
|
|
673
|
-
static pid_t
|
|
674
|
-
pty_forkpty(int *amaster,
|
|
675
|
-
char *name,
|
|
676
|
-
const struct termios *termp,
|
|
677
|
-
const struct winsize *winp) {
|
|
678
|
-
#if defined(__sun)
|
|
679
|
-
int master, slave;
|
|
680
|
-
|
|
681
|
-
int ret = pty_openpty(&master, &slave, name, termp, winp);
|
|
682
|
-
if (ret == -1) return -1;
|
|
683
|
-
if (amaster) *amaster = master;
|
|
684
|
-
|
|
685
|
-
pid_t pid = fork();
|
|
686
|
-
|
|
687
|
-
switch (pid) {
|
|
688
|
-
case -1: // error in fork, we are still in parent
|
|
689
|
-
close(master);
|
|
690
|
-
close(slave);
|
|
691
|
-
return -1;
|
|
692
|
-
case 0: // we are in the child process
|
|
693
|
-
close(master);
|
|
694
|
-
setsid();
|
|
695
|
-
|
|
696
|
-
#if defined(TIOCSCTTY)
|
|
697
|
-
// glibc does this
|
|
698
|
-
if (ioctl(slave, TIOCSCTTY, NULL) == -1) {
|
|
699
|
-
_exit(1);
|
|
700
|
-
}
|
|
701
|
-
#endif
|
|
702
|
-
|
|
703
|
-
dup2(slave, 0);
|
|
704
|
-
dup2(slave, 1);
|
|
705
|
-
dup2(slave, 2);
|
|
706
|
-
|
|
707
|
-
if (slave > 2) close(slave);
|
|
708
|
-
|
|
709
|
-
return 0;
|
|
710
|
-
default: // we are in the parent process
|
|
711
|
-
close(slave);
|
|
712
|
-
return pid;
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
return -1;
|
|
716
|
-
#else
|
|
717
|
-
return forkpty(amaster, name, (termios *)termp, (winsize *)winp);
|
|
718
|
-
#endif
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
|
|
722
696
|
/**
|
|
723
697
|
* Init
|
|
724
698
|
*/
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#include <errno.h>
|
|
2
|
+
#include <fcntl.h>
|
|
3
|
+
#include <signal.h>
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <sys/ioctl.h>
|
|
6
|
+
#include <sys/resource.h>
|
|
7
|
+
#include <termios.h>
|
|
8
|
+
#include <unistd.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
|
|
11
|
+
#include "comms.h"
|
|
12
|
+
|
|
13
|
+
void bail (int type, int code) {
|
|
14
|
+
int buf[2] = { type, code };
|
|
15
|
+
(void)! write(COMM_PIPE_FD, &buf, sizeof(buf));
|
|
16
|
+
_exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
int main (int argc, char** argv) {
|
|
20
|
+
sigset_t empty_set;
|
|
21
|
+
sigemptyset(&empty_set);
|
|
22
|
+
pthread_sigmask(SIG_SETMASK, &empty_set, nullptr);
|
|
23
|
+
|
|
24
|
+
setsid();
|
|
25
|
+
|
|
26
|
+
#if defined(TIOCSCTTY)
|
|
27
|
+
// glibc does this
|
|
28
|
+
if (ioctl(STDIN_FILENO, TIOCSCTTY, NULL) == -1) {
|
|
29
|
+
_exit(1);
|
|
30
|
+
}
|
|
31
|
+
#else
|
|
32
|
+
char *slave_path = ttyname(STDIN_FILENO);
|
|
33
|
+
// open implicit attaches a process to a terminal device if:
|
|
34
|
+
// - process has no controlling terminal yet
|
|
35
|
+
// - O_NOCTTY is not set
|
|
36
|
+
close(open(slave_path, O_RDWR));
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
char *cwd = argv[1];
|
|
40
|
+
int uid = std::stoi(argv[2]);
|
|
41
|
+
int gid = std::stoi(argv[3]);
|
|
42
|
+
bool closeFDs = std::stoi(argv[4]);
|
|
43
|
+
char *file = argv[5];
|
|
44
|
+
argv = &argv[5];
|
|
45
|
+
|
|
46
|
+
fcntl(COMM_PIPE_FD, F_SETFD, FD_CLOEXEC);
|
|
47
|
+
|
|
48
|
+
if (strlen(cwd) && chdir(cwd) == -1) {
|
|
49
|
+
bail(COMM_ERR_CHDIR, errno);
|
|
50
|
+
}
|
|
51
|
+
if (uid != -1 && setuid(uid) == -1) {
|
|
52
|
+
bail(COMM_ERR_SETUID, errno);
|
|
53
|
+
}
|
|
54
|
+
if (gid != -1 && setgid(gid) == -1) {
|
|
55
|
+
bail(COMM_ERR_SETGID, errno);
|
|
56
|
+
}
|
|
57
|
+
if (closeFDs) {
|
|
58
|
+
struct rlimit rlim_ofile;
|
|
59
|
+
getrlimit(RLIMIT_NOFILE, &rlim_ofile);
|
|
60
|
+
for (rlim_t fd = STDERR_FILENO + 1; fd < rlim_ofile.rlim_cur; fd++) {
|
|
61
|
+
if (fd != COMM_PIPE_FD) {
|
|
62
|
+
close(fd);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
execvp(file, argv);
|
|
68
|
+
bail(COMM_ERR_EXEC, errno);
|
|
69
|
+
return 1;
|
|
70
|
+
}
|