/*
Copyright (C) 2010 Paul Davis
+ Copyright 2005-2008 Lennart Poettering
Author: Robin Gareus <robin@gareus.org>
This program is free software; you can redistribute it and/or modify
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifdef WITH_VIDEOTIMELINE
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <assert.h>
+#include <dirent.h>
+
#ifdef __WIN32__
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#endif
+
#include "system_exec.h"
using namespace std;
void * interposer_thread (void *arg);
+static void close_fd (int& fd) { if (fd >= 0) ::close (fd); fd = -1; }
+
+#ifndef __WIN32__
+/*
+ * This function was part of libasyncns.
+ * LGPL v2.1
+ * Copyright 2005-2008 Lennart Poettering
+ */
+static int close_allv(const int except_fds[]) {
+ struct rlimit rl;
+ int fd;
+
+#ifdef __linux__
+
+ DIR *d;
+
+ assert(except_fds);
+
+ if ((d = opendir("/proc/self/fd"))) {
+ struct dirent *de;
+
+ while ((de = readdir(d))) {
+ int found;
+ long l;
+ char *e = NULL;
+ int i;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ errno = 0;
+ l = strtol(de->d_name, &e, 10);
+ if (errno != 0 || !e || *e) {
+ closedir(d);
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = (int) l;
+
+ if ((long) fd != l) {
+ closedir(d);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (fd < 3)
+ continue;
+
+ if (fd == dirfd(d))
+ continue;
+
+ found = 0;
+ for (i = 0; except_fds[i] >= 0; i++)
+ if (except_fds[i] == fd) {
+ found = 1;
+ break;
+ }
+
+ if (found) continue;
+
+ if (close(fd) < 0) {
+ int saved_errno;
+
+ saved_errno = errno;
+ closedir(d);
+ errno = saved_errno;
+
+ return -1;
+ }
+ }
+
+ closedir(d);
+ return 0;
+ }
+
+#endif
+
+ if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
+ return -1;
+
+ for (fd = 0; fd < (int) rl.rlim_max; fd++) {
+ int i;
+
+ if (fd <= 3)
+ continue;
+
+ for (i = 0; except_fds[i] >= 0; i++)
+ if (except_fds[i] == fd)
+ continue;
+
+ if (close(fd) < 0 && errno != EBADF)
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* not on windows */
+
+
SystemExec::SystemExec (std::string c, std::string a)
: cmd(c)
{
{
DWORD bytesRead = 0;
char data[BUFSIZ];
+#if 0 // untested code to set up nonblocking
+ unsigned long l = 1;
+ ioctlsocket(stdoutP[0], FIONBIO, &l);
+#endif
while(1) {
#if 0 // for non-blocking pipes..
DWORD bytesAvail = 0;
SystemExec::terminate ()
{
::pthread_mutex_lock(&write_lock);
+
+ /* close stdin in an attempt to get the child to exit cleanly.
+ */
+
close_stdin();
+
if (pid) {
- ::usleep(100000);
+ ::usleep(50000);
+ sched_yield();
wait(WNOHANG);
}
+ /* if pid is non-zero, the child task is still executing (i.e. it did
+ * not exit in response to stdin being closed). try to kill it.
+ */
+
if (pid) {
- ::fprintf(stderr, "Child process is running. trying SIGTERM\n");
::kill(pid, SIGTERM);
- ::usleep(10000);
+ ::usleep(50000);
+ sched_yield();
wait(WNOHANG);
}
+
+ /* if pid is non-zero, the child task is STILL executing after being
+ * sent SIGTERM. Act tough ... send SIGKILL
+ */
+
if (pid) {
::fprintf(stderr, "Process is still running! trying SIGKILL\n");
::kill(pid, SIGKILL);
SystemExec::wait (int options)
{
int status=0;
+ int ret;
+
if (pid==0) return -1;
- if (pid==::waitpid(pid, &status, options)) {
- pid=0;
- }
- if (errno == ECHILD) {
- pid=0;
+
+ ret = waitpid (pid, &status, options);
+
+ if (ret == pid) {
+ if (WEXITSTATUS(status) || WIFSIGNALED(status)) {
+ pid=0;
+ }
+ } else {
+ if (ret != 0) {
+ if (errno == ECHILD) {
+ /* no currently running children, reset pid */
+ pid=0;
+ }
+ } /* else the process is still running */
}
return status;
}
pid=r;
/* check if execve was successful. */
- ::close(pok[1]);
+ close_fd(pok[1]);
char buf;
for ( ;; ) {
- int n = ::read(pok[0], &buf, 1 );
+ ssize_t n = ::read(pok[0], &buf, 1 );
if ( n==1 ) {
/* child process returned from execve */
pid=0;
- ::close(pok[0]);
- ::close(pin[1]);
- ::close(pin[0]);
- ::close(pout[1]);
- ::close(pout[0]);
+ close_fd(pok[0]);
+ close_fd(pin[1]);
+ close_fd(pin[0]);
+ close_fd(pout[1]);
+ close_fd(pout[0]);
pin[1] = -1;
return -3;
} else if ( n==-1 ) {
}
break;
}
- ::close(pok[0]);
+ close_fd(pok[0]);
/* child started successfully */
#if 0
}
if (r == 0) {
/* 2nd child process - catch stdout */
- ::close(pin[1]);
- ::close(pout[1]);
+ close_fd(pin[1]);
+ close_fd(pout[1]);
output_interposer();
exit(0);
}
- ::close(pout[1]);
- ::close(pin[0]);
- ::close(pout[0]);
+ close_fd(pout[1]);
+ close_fd(pin[0]);
+ close_fd(pout[0]);
#else /* use pthread */
- ::close(pout[1]);
- ::close(pin[0]);
+ close_fd(pout[1]);
+ close_fd(pin[0]);
int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
thread_active=true;
}
/* child process - exec external process */
- ::close(pok[0]);
+ close_fd(pok[0]);
::fcntl(pok[1], F_SETFD, FD_CLOEXEC);
- ::close(pin[1]);
+ close_fd(pin[1]);
if (pin[0] != STDIN_FILENO) {
::dup2(pin[0], STDIN_FILENO);
}
- ::close(pin[0]);
- ::close(pout[0]);
+ close_fd(pin[0]);
+ close_fd(pout[0]);
if (pout[1] != STDOUT_FILENO) {
::dup2(pout[1], STDOUT_FILENO);
}
}
if (pout[1] != STDOUT_FILENO && pout[1] != STDERR_FILENO) {
- ::close(pout[1]);
+ close_fd(pout[1]);
}
if (nicelevel !=0) {
signal(SIGPIPE, SIG_DFL);
#endif
+#ifndef __WIN32__
+ int good_fds[1] = { 0 };
+ close_allv(good_fds);
+#endif
+
::execve(argp[0], argp, envp);
/* if we reach here something went wrong.. */
char buf = 0;
(void) ::write(pok[1], &buf, 1 );
- (void) ::close(pok[1]);
+ close_fd(pok[1]);
exit(-1);
return -1;
}
{
int rfd=pout[0];
char buf[BUFSIZ];
- size_t r;
+ ssize_t r;
+ unsigned long l = 1;
+
+ ioctl(rfd, FIONBIO, &l); // set non-blocking I/O
+
for (;fcntl(rfd, F_GETFL)!=-1;) {
r = read(rfd, buf, sizeof(buf));
if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
SystemExec::close_stdin()
{
if (pin[1]<0) return;
- ::close(pin[0]);
- ::close(pin[1]);
- ::close(pout[0]);
- ::close(pout[1]);
- pin[1] = - 1; // mark as closed
+ close_fd(pin[0]);
+ close_fd(pin[1]);
+ close_fd(pout[0]);
+ close_fd(pout[1]);
}
int
SystemExec::write_to_stdin(std::string d, size_t len)
{
const char *data;
- size_t r,c;
+ ssize_t r;
+ size_t c;
::pthread_mutex_lock(&write_lock);
data=d.c_str();
sleep(1);
continue;
}
- if (r != (len-c)) {
+ if ((size_t) r != (len-c)) {
::pthread_mutex_unlock(&write_lock);
return c;
}
}
#endif // end UNIX process
-
-#endif /* WITH_VIDEOTIMELINE */