Last active
January 21, 2020 06:07
-
-
Save Qix-/25f4a226627f84e9d622a1f1526864c9 to your computer and use it in GitHub Desktop.
Test openpty() (pseudo-terminal) integration with libuv
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Simple testbed for checking TTY status. Use with the other program if you'd like. | |
*/ | |
#include <unistd.h> | |
#include <stdio.h> | |
static void check(const char *name, int fd) { | |
if (isatty(fd)) { | |
printf("%s IS a tty: %s\n", name, ttyname(fd)); | |
} else { | |
printf("%s IS NOT a tty\n", name); | |
} | |
} | |
int main(void) { | |
check("stdin", 0); | |
check("stdout", 1); | |
check("stderr", 2); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Tests uv_spawn() with a process that uses a pseudo-terminal to write to stderr. | |
Fun tests include: | |
cc -o uv_pty uv_pty.c -luv_a | |
./uv_pty node -e 'console.log(process.stderr.isTTY); console.error("hello stderr");' 2<NUL | |
*/ | |
#include <uv.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <util.h> | |
#include <sys/types.h> | |
#include <sys/uio.h> | |
extern char **environ; | |
static int uv_perror(int r, const char *msg) { | |
printf("%s: %s (%s)\n", msg, uv_strerror(r), uv_err_name(r)); | |
return 1; | |
} | |
static void on_exit(uv_process_t *proc, long long stat, int sig) { | |
printf("\n(process %d exited with status %lld and sig %d)\n", proc->pid, stat, sig); | |
} | |
static void on_polled(uv_poll_t *poller, int status, int events) { | |
if (status != 0) { | |
uv_perror(status, "could not poll pty"); | |
return; | |
} | |
if (events & UV_READABLE) { | |
char buf[1024]; | |
ssize_t r = read((int) poller->data, buf, sizeof(buf)); | |
if (r == 0) { | |
// EOF | |
puts("encountered eof"); | |
int res = uv_poll_stop(poller); | |
if (res != 0) { | |
uv_perror(res, "could not stop poller upon EOF"); | |
return; | |
} | |
} else if (r < 0) { | |
// error | |
perror("could not read from pty"); | |
int res = uv_poll_stop(poller); | |
if (res != 0) { | |
uv_perror(res, "could not stop poller upon error"); | |
} | |
return; | |
} else { | |
// success | |
printf("STDERR: %.*s\n", (int) r, buf); | |
} | |
} | |
if (events & UV_DISCONNECT) { | |
puts("encountered disconnect"); | |
int res = uv_poll_stop(poller); | |
if (res != 0) { | |
uv_perror(res, "could not stop poller upon disconnect"); | |
} | |
} | |
} | |
int main(int argc, char *argv[]) { | |
uv_loop_t *loop = uv_default_loop(); | |
int amaster = 0; | |
int aslave = 0; | |
int r = openpty( | |
&amaster, | |
&aslave, | |
NULL, | |
NULL, | |
NULL | |
); | |
if (r == -1) { | |
perror("could not open pty"); | |
return 1; | |
} | |
uv_poll_t poller; | |
poller.data = (void *) (size_t) amaster; | |
uv_poll_init(loop, &poller, amaster); | |
uv_poll_start(&poller, UV_READABLE | UV_DISCONNECT, &on_polled); | |
uv_unref((uv_handle_t *) &poller); // total hack. you should do proper cleaning up. | |
uv_process_options_t opts; | |
char **argv_n = malloc(sizeof(*argv_n) * argc); | |
for (int i = 0; i < argc; i++) { | |
argv_n[i] = argv[i + 1]; | |
} | |
argv[argc] = 0; | |
opts.args = argv_n; | |
static char wdbuf[PATH_MAX]; | |
opts.cwd = getcwd(wdbuf, sizeof(wdbuf)); | |
opts.env = environ; | |
opts.exit_cb = &on_exit; | |
opts.file = argv_n[0]; | |
opts.flags = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; | |
opts.stdio_count = 3; | |
static uv_stdio_container_t child_stdio[3]; | |
child_stdio[0].flags = UV_IGNORE; | |
child_stdio[1].flags = UV_INHERIT_FD; | |
child_stdio[1].data.fd = 1; | |
child_stdio[2].flags = UV_INHERIT_FD; | |
child_stdio[2].data.fd = aslave; | |
opts.stdio = child_stdio; | |
uv_process_t proc; | |
r = uv_spawn(loop, &proc, &opts); | |
if (r != 0) { | |
return uv_perror(r, "could not spawn process"); | |
} | |
return uv_run(loop, UV_RUN_DEFAULT); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment