Switch to side-by-side view

--- a/src/utils/execmd.cpp
+++ b/src/utils/execmd.cpp
@@ -1,5 +1,5 @@
 #ifndef lint
-static char rcsid[] = "@(#$Id: execmd.cpp,v 1.13 2006-01-24 12:22:20 dockes Exp $ (C) 2004 J.F.Dockes";
+static char rcsid[] = "@(#$Id: execmd.cpp,v 1.14 2006-01-26 17:44:51 dockes Exp $ (C) 2004 J.F.Dockes";
 #endif
 /*
  *   This program is free software; you can redistribute it and/or modify
@@ -49,6 +49,49 @@
     m_env.push_back(ea);
 }
 
+/** A resource manager to ensure that execcmd cleans up if an exception is 
+ * raised in the callback */
+class ExecCmdRsrc {
+public:
+    int pipein[2];
+    int pipeout[2];
+    pid_t pid;
+    ExecCmdRsrc() {
+	reset();
+    }
+    void reset() {
+	pipein[0] = pipein[1] = pipeout[0] = pipeout[1] = -1;
+	pid = -1;
+    }
+    ~ExecCmdRsrc() {
+	int status;
+	if (pid > 0) {
+	    LOGDEB(("ExecCmd: killing cmd\n"));
+	    if (kill(pid, SIGTERM) == 0) {
+		for (int i = 0; i < 3; i++) {
+		    (void)waitpid(pid, &status, WNOHANG);
+		    if (kill(pid, 0) != 0)
+			break;
+		    sleep(1);
+		    if (i == 2) {
+			LOGDEB(("ExecCmd: killing (KILL) cmd\n"));
+			kill(pid, SIGKILL);
+		    }
+		}
+	    }
+	}
+	if (pipein[0] >= 0)
+	    close(pipein[0]);
+	if (pipein[1] >= 0)
+	    close(pipein[1]);
+	if (pipeout[0] >= 0)
+	    close(pipeout[0]);
+	if (pipeout[1] >= 0)
+	    close(pipeout[1]);
+    }
+};
+
+	
 int ExecCmd::doexec(const string &cmd, const list<string>& args,
 		const string *inputstring, string *output)
 {
@@ -63,35 +106,31 @@
     const char *input = inputstring ? inputstring->data() : 0;
     unsigned int inputlen = inputstring ? inputstring->length() : 0;
 
-    int pipein[2]; // subproc input
-    int pipeout[2]; // subproc output
-    pipein[0] = pipein[1] = pipeout[0] = pipeout[1] = -1;
-
-    if (input && pipe(pipein) < 0) {
+    ExecCmdRsrc e;
+
+    if (input && pipe(e.pipein) < 0) {
 	LOGERR(("ExecCmd::doexec: pipe(2) failed. errno %d\n", errno));
 	return -1;
     }
-    if (output && pipe(pipeout) < 0) {
+    if (output && pipe(e.pipeout) < 0) {
 	LOGERR(("ExecCmd::doexec: pipe(2) failed. errno %d\n", errno));
-	if (pipein[0] >= 0) close(pipein[0]);
-	if (pipein[1] >= 0) close(pipein[1]);
 	return -1;
     }
 
-    pid_t pid = fork();
-    if (pid < 0) {
+    e.pid = fork();
+    if (e.pid < 0) {
 	LOGERR(("ExecCmd::doexec: fork(2) failed. errno %d\n", errno));
 	return -1;
     }
 
-    if (pid) {
+    if (e.pid) {
 	if (input) {
-	    close(pipein[0]);
-	    pipein[0] = -1;
+	    close(e.pipein[0]);
+	    e.pipein[0] = -1;
 	}
 	if (output) {
-	    close(pipeout[1]);
-	    pipeout[1] = -1;
+	    close(e.pipeout[1]);
+	    e.pipeout[1] = -1;
 	}
 	fd_set readfds, writefds;
 	struct timeval tv;
@@ -100,25 +139,25 @@
 
 	if (input || output) {
 	    if (input)
-		fcntl(pipein[1], F_SETFL, O_NONBLOCK);
+		fcntl(e.pipein[1], F_SETFL, O_NONBLOCK);
 	    if (output)	
-		fcntl(pipeout[0], F_SETFL, O_NONBLOCK);
+		fcntl(e.pipeout[0], F_SETFL, O_NONBLOCK);
 	    unsigned int nwritten = 0;
-	    int nfds = MAX(pipein[1], pipeout[0]) + 1;
+	    int nfds = MAX(e.pipein[1], e.pipeout[0]) + 1;
 	    for(; nfds > 0;) {
 		if (m_cancelRequest)
 		    break;
 
 		FD_ZERO(&writefds);
 		FD_ZERO(&readfds);
-		if (pipein[1] >= 0)
-		    FD_SET(pipein[1], &writefds);
-		if (pipeout[0] >= 0)
-		    FD_SET(pipeout[0], &readfds);
-		nfds = MAX(pipein[1], pipeout[0]) + 1;
+		if (e.pipein[1] >= 0)
+		    FD_SET(e.pipein[1], &writefds);
+		if (e.pipeout[0] >= 0)
+		    FD_SET(e.pipeout[0], &readfds);
+		nfds = MAX(e.pipein[1], e.pipeout[0]) + 1;
 		//struct timeval to; to.tv_sec = 1;to.tv_usec=0;
-		//cerr << "pipein[1] "<< pipein[1] << " pipeout[0] " << 
-		//pipeout[0] << " nfds " << nfds << endl;
+		//cerr << "e.pipein[1] "<< e.pipein[1] << " e.pipeout[0] " << 
+		//e.pipeout[0] << " nfds " << nfds << endl;
 		int ss;
 		if ((ss = select(nfds, &readfds, &writefds, 0, &tv)) <= 0) {
 		    if (ss == 0) {
@@ -129,8 +168,8 @@
 			    errno));
 		    break;
 		}
-		if (pipein[1] >= 0 && FD_ISSET(pipein[1], &writefds)) {
-		    int n = write(pipein[1], input + nwritten, 
+		if (e.pipein[1] >= 0 && FD_ISSET(e.pipein[1], &writefds)) {
+		    int n = write(e.pipein[1], input + nwritten, 
 				  inputlen - nwritten);
 		    if (n < 0) {
 			LOGERR(("ExecCmd::doexec: write(2) failed. errno %d\n",
@@ -140,13 +179,13 @@
 		    nwritten += n;
 		    if (nwritten == inputlen) {
 			// cerr << "Closing output" << endl;
-			close(pipein[1]);
-			pipein[1] = -1;
-		    }
-		}
-		if (pipeout[0] > 0 && FD_ISSET(pipeout[0], &readfds)) {
+			close(e.pipein[1]);
+			e.pipein[1] = -1;
+		    }
+		}
+		if (e.pipeout[0] > 0 && FD_ISSET(e.pipeout[0], &readfds)) {
 		    char buf[8192];
-		    int n = read(pipeout[0], buf, 8192);
+		    int n = read(e.pipeout[0], buf, 8192);
 		    if (n == 0) {
 			goto out;
 		    } else if (n < 0) {
@@ -165,30 +204,11 @@
 
     out:
 	int status = -1;
-
-	if (m_cancelRequest) {
-	    // If we were canceled, need to cleanup
-	    LOGDEB1(("Killing cmd\n"));
-	    kill(pid, SIGTERM);
-	    for (int i = 0; i < 3; i++) {
-		if (kill(pid, 0) != 0)
-		    break;
-		sleep(1);
-		if (i == 2) {
-		    LOGDEB1(("Killing (KILL) cmd\n"));
-		    kill(pid, SIGKILL);
-		}
-	    }
-	}
-	(void)waitpid(pid, &status, 0);
-	if (pipein[0] >= 0)
-	    close(pipein[0]);
-	if (pipein[1] >= 0)
-	    close(pipein[1]);
-	if (pipeout[0] >= 0)
-	    close(pipeout[0]);
-	if (pipeout[1] >= 0)
-	    close(pipeout[1]);
+	if (!m_cancelRequest) {
+	    LOGDEB(("Execmd: canceled\n"));
+	    (void)waitpid(e.pid, &status, 0);
+	    e.pid = -1;
+	}
 	LOGDEB1(("ExecCmd::doexec: father got status 0x%x\n", status));
 	return status;
 
@@ -196,38 +216,36 @@
 	// In child process. Set up pipes, environment, and exec command
 
 	if (input) {
-	    close(pipein[1]);
-	    pipein[1] = -1;
-	    if (pipein[0] != 0) {
-		dup2(pipein[0], 0);
-		close(pipein[0]);
-		pipein[0] = -1;
+	    close(e.pipein[1]);
+	    e.pipein[1] = -1;
+	    if (e.pipein[0] != 0) {
+		dup2(e.pipein[0], 0);
+		close(e.pipein[0]);
+		e.pipein[0] = -1;
 	    }
 	}
 	if (output) {
-	    close(pipeout[0]);
-	    pipeout[0] = -1;
-	    if (pipeout[1] != 1) {
-		if (dup2(pipeout[1], 1) < 0) {
+	    close(e.pipeout[0]);
+	    e.pipeout[0] = -1;
+	    if (e.pipeout[1] != 1) {
+		if (dup2(e.pipeout[1], 1) < 0) {
 		    LOGERR(("ExecCmd::doexec: dup2(2) failed. errno %d\n",
 			    errno));
 		}
-		if (close(pipeout[1]) < 0) {
+		if (close(e.pipeout[1]) < 0) {
 		    LOGERR(("ExecCmd::doexec: close(2) failed. errno %d\n",
 			    errno));
 		}
-		pipeout[1] = -1;
+		e.pipeout[1] = -1;
 	    }
 	}
 
-	// Count args
-	list<string>::const_iterator it;
-	int i = 0;
-	for (it = args.begin(); it != args.end(); it++) i++;
+	e.reset();
+
 	// Allocate arg vector (2 more for arg0 + final 0)
 	typedef const char *Ccharp;
 	Ccharp *argv;
-	argv = (Ccharp *)malloc((i+2) * sizeof(char *));
+	argv = (Ccharp *)malloc((args.size()+2) * sizeof(char *));
 	if (argv == 0) {
 	    LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n",
 		    errno));
@@ -236,7 +254,8 @@
 	
 	// Fill up argv
 	argv[0] = path_getsimple(cmd).c_str();
-	i = 1;
+	int i = 1;
+	list<string>::const_iterator it;
 	for (it = args.begin(); it != args.end(); it++) {
 	    argv[i++] = it->c_str();
 	}
@@ -254,7 +273,6 @@
 	    ::putenv(it->c_str());
 #endif
 	}
-	
 	execvp(cmd.c_str(), (char *const*)argv);
 	// Hu ho
 	LOGERR(("ExecCmd::doexec: execvp(%s) failed. errno %d\n", cmd.c_str(),
@@ -269,6 +287,8 @@
 #include <iostream>
 #include <list>
 #include "debuglog.h"
+#include "cancelcheck.h"
+
 using namespace std;
 
 #include "execmd.h"
@@ -277,8 +297,14 @@
 class MEAdv : public ExecCmdAdvise {
 public:
     ExecCmd *cmd;
-    void newData() {cerr << "New Data!" << endl;cmd->setCancel();}
+    void newData() {
+	cerr << "New Data!" << endl;
+	CancelCheck::instance().setCancel();
+	CancelCheck::instance().checkCancel();
+	//	cmd->setCancel();
+    }
 };
+
 int main(int argc, const char **argv)
 {
     DebugLog::getdbl()->setloglevel(DEBDEB1);
@@ -304,7 +330,12 @@
     mexec.putenv("TESTVARIABLE2=TESTVALUE2");
     mexec.putenv("TESTVARIABLE3=TESTVALUE3");
 
-    int status = mexec.doexec(cmd, l, ip, &output);
+    int status = -1;
+    try {
+	status = mexec.doexec(cmd, l, ip, &output);
+    } catch (CancelExcept) {
+	cerr << "CANCELED" << endl;
+    }
 
     fprintf(stderr, "Status: 0x%x\n", status);
     cout << "Output:" << output << endl;