7#error "USING_PIDFD was already defined; it should not be."
14#if (defined(__linux__))
15#include <linux/wait.h>
16#include <asm/unistd.h>
17#include <linux/sched.h>
18#define NCPOLLEVENTS (POLLIN | POLLRDHUP)
19#if (defined(__NR_clone3) && defined(P_PIDFD) && defined(CLONE_CLEAR_SIGHAND))
23#define NCPOLLEVENTS (POLLIN)
30 int ret = close(
n->fd);
38 struct pollfd pfds[2];
39 memset(pfds, 0,
sizeof(pfds));
40 char* buf = malloc(BUFSIZ + 1);
41 pfds[0].fd = ncfp->
fd;
43 const int fdcount = pidfd < 0 ? 1 : 2;
50 while(poll(pfds, fdcount, -1) >= 0 || errno == EINTR){
52 while(WSAPoll(pfds, fdcount, -1) >= 0){
55 while((
r = read(ncfp->
fd, buf, BUFSIZ)) >= 0){
60 if( (
r = ncfp->
cb(ncfp, buf,
r, ncfp->
curry)) ){
72 if(fdcount > 1 && pfds[1].revents){
77 if(r <= 0 && !ncfp->destroyed){
78 ncfp->
donecb(ncfp,
r == 0 ? 0 : errno, ncfp->curry);
81 ncfdplane_destroy_inner(ncfp);
87ncfdplane_thread(
void* vncfp){
112 if(pthread_create(&ret->
tid,
NULL, ncfdplane_thread, ret)){
126 if(fd < 0 || !cbfxn || !donecbfxn){
129 return ncfdplane_create_internal(
n,
opts, fd, cbfxn, donecbfxn,
true);
139 if(pthread_equal(pthread_self(),
n->tid)){
143 ret |= cancel_and_join(
"fdplane",
n->tid, &vret);
144 ret |= ncfdplane_destroy_inner(
n);
153lay_pipes(
int pipes[
static 2]){
155 if(pipe2(pipes, O_CLOEXEC)){
162 if(set_fd_cloexec(pipes[0], 1,
NULL) || set_fd_cloexec(pipes[1], 1,
NULL)){
177launch_pipe_process(
int* pipefd,
int* pidfd,
unsigned usepath,
178 const char* bin,
char*
const arg[],
char*
const env[]){
181 if(lay_pipes(pipes)){
189 struct clone_args clargs;
190 memset(&clargs, 0,
sizeof(clargs));
191 clargs.pidfd = (uintptr_t)pidfd;
192 clargs.flags = CLONE_CLEAR_SIGHAND | CLONE_FS | CLONE_PIDFD;
193 clargs.exit_signal = SIGCHLD;
194 p = syscall(__NR_clone3, &clargs,
sizeof(clargs));
196 if(dup2(pipes[1], STDOUT_FILENO) < 0 || dup2(pipes[1], STDERR_FILENO) < 0){
197 logerror(
"couldn't dup() %d (%s)", pipes[1], strerror(errno));
201 execvpe(bin, arg, env);
209 logwarn(
"clone3() failed (%s), using posix_spawn()", strerror(errno));
213 posix_spawn_file_actions_t factions;
214 if(posix_spawn_file_actions_init(&factions)){
215 logerror(
"couldn't initialize spawn file actions");
218 posix_spawn_file_actions_adddup2(&factions, pipes[1], STDOUT_FILENO);
219 posix_spawn_file_actions_adddup2(&factions, pipes[1], STDERR_FILENO);
222 r = posix_spawnp(&p, bin, &factions,
NULL, arg, env);
224 r = posix_spawn(&p, bin, &factions,
NULL, arg, env);
227 logerror(
"posix_spawn %s failed (%s)", bin, strerror(errno));
229 posix_spawn_file_actions_destroy(&factions);
243kill_and_wait_subproc(pid_t pid,
int pidfd,
int* status){
249 ret = syscall(__NR_pidfd_send_signal, pidfd, SIGKILL,
NULL, 0);
251 memset(&info, 0,
sizeof(info));
252 waitid(P_PIDFD, pidfd, &info, 0);
260 if(pid != waitpid(pid, status, WNOHANG)){
268ncsubproc_thread(
void* vncsp){
269 int* status = malloc(
sizeof(*status));
273 if(kill_and_wait_subproc(ncsp->
pid, ncsp->
pidfd, status)){
277 ncfdplane_destroy_inner(ncsp->
nfp);
289ncsubproc_waiter(
void* vncsp){
291 int* status = malloc(
sizeof(*status));
293 while((pid = waitpid(ncsp->
pid, status, 0)) < 0 && errno == EINTR){
296 if(pid != ncsp->
pid){
300 pthread_mutex_lock(&ncsp->
lock);
302 pthread_mutex_unlock(&ncsp->
lock);
316 ret->
nfp = ncfdplane_create_internal(
n, &popts, fd, cbfxn, donecbfxn,
false);
320 if(pthread_create(&ret->
nfp->
tid,
NULL, ncsubproc_thread, ret)){
321 ncfdplane_destroy_inner(ret->
nfp);
327 if(pthread_create(&ret->
waittid,
NULL, ncsubproc_waiter, ret)){
329 ncfdplane_destroy_inner(ret->
nfp);
340 const char* bin,
char*
const arg[],
char*
const env[],
346 if(!cbfxn || !donecbfxn){
358 memset(ret, 0,
sizeof(*ret));
359 ret->
pid = launch_pipe_process(&fd, &ret->
pidfd, usepath, bin, arg, env);
364 if((ret->
nfp = ncsubproc_launch(
n, ret,
opts, fd, cbfxn, donecbfxn)) ==
NULL){
384 const char* bin,
const char*
const arg[],
386 return ncexecvpe(
n,
opts, 0, bin, (
char*
const *)arg,
NULL, cbfxn, donecbfxn);
390 const char* bin,
const char*
const arg[],
392 return ncexecvpe(
n,
opts, 1, bin, (
char*
const *)arg,
NULL, cbfxn, donecbfxn);
396 const char* bin,
const char*
const arg[],
397 const char*
const env[],
399 return ncexecvpe(
n,
opts, 1, bin, (
char*
const *)arg, (
char*
const*)env, cbfxn, donecbfxn);
410 loginfo(
"sending SIGKILL to pidfd %d",
n->pidfd);
411 if(syscall(__NR_pidfd_send_signal,
n->pidfd, SIGKILL,
NULL, 0)){
412 kill(
n->pid, SIGKILL);
416 pthread_mutex_lock(&
n->lock);
418 loginfo(
"sending SIGKILL to PID %d",
n->pid);
419 kill(
n->pid, SIGKILL);
421 pthread_mutex_unlock(&
n->lock);
428 pthread_cancel(
n->nfp->tid);
430 pthread_join(
n->waittid, &vret);
433 pthread_join(
n->nfp->tid, &vret);
435 pthread_join(
n->nfp->tid,
NULL);
437 pthread_mutex_destroy(&
n->lock);
441 }
else if(vret != PTHREAD_CANCELED){
458 if((fd = fileno(ttyfp)) < 0){
459 logwarn(
"no file descriptor was available in outfp %p", ttyfp);
464 loginfo(
"fd %d is not a TTY", fd);
470 fd = open(
"/dev/tty", O_RDWR | O_CLOEXEC | O_NOCTTY);
472 loginfo(
"couldn't open /dev/tty (%s)", strerror(errno));
475 loginfo(
"file descriptor for /dev/tty (%d) is not actually a TTY", fd);
482 loginfo(
"returning TTY fd %d", fd);
int ncfdplane_destroy(ncfdplane *n)
ncsubproc * ncsubproc_createv(ncplane *n, const ncsubproc_options *opts, const char *bin, const char *const arg[], ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn)
ncsubproc * ncsubproc_createvp(ncplane *n, const ncsubproc_options *opts, const char *bin, const char *const arg[], ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn)
ncplane * ncfdplane_plane(ncfdplane *n)
ncsubproc * ncsubproc_createvpe(ncplane *n, const ncsubproc_options *opts, const char *bin, const char *const arg[], const char *const env[], ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn)
ncplane * ncsubproc_plane(ncsubproc *n)
int get_tty_fd(FILE *ttyfp)
int ncsubproc_destroy(ncsubproc *n)
ncfdplane * ncfdplane_create(ncplane *n, const ncfdplane_options *opts, int fd, ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn)
int set_fd_nonblocking(int fd, unsigned state, unsigned *oldstate)
#define logerror(fmt,...)
bool ncplane_set_scrolling(ncplane *n, unsigned scrollp)
const struct ncplane_options * opts
int(* ncfdplane_done_cb)(struct ncfdplane *n, int fderrno, void *curry)
int(* ncfdplane_callback)(struct ncfdplane *n, const void *buf, size_t s, void *curry)