--- a/src/utils/execmd.cpp
+++ b/src/utils/execmd.cpp
@@ -28,10 +28,6 @@
 #include <errno.h>
 #include <signal.h>
 
-#if !defined(PUTENV_ARG_CONST)
-#include <string.h>
-#endif
-
 #include <vector>
 #include <string>
 #include <sstream>
@@ -44,8 +40,10 @@
 #include "smallut.h"
 #include "netcon.h"
 #include "closefrom.h"
-#include "ptmutex.h"
-
+
+extern char **environ;
+
+bool ExecCmd::o_useVfork = false;
 
 /* From FreeBSD's which command */
 static bool exec_is_there(const char *candidate)
@@ -167,6 +165,80 @@
     ExecCmdRsrc(this);
 }
 
+// In child process. Set up pipes and exec command. 
+// This must not return. _exit() on error.
+// *** This can be called after a vfork, so no modification of the
+//     process memory at all is allowed ***
+// The LOGXX calls should not be there, but they occur only after "impossible"
+// errors, which we would most definitely want to have a hint about
+inline void ExecCmd::dochild(const string &cmd, const char **argv,
+			     const char **envv,
+			     bool has_input, bool has_output)
+{
+    // Start our own process group
+    if (setpgid(0, getpid())) {
+	LOGINFO(("ExecCmd::dochild: setpgid(0, %d) failed: errno %d\n",
+		 getpid(), errno));
+    }
+
+    // Restore SIGTERM to default. Really, signal handling should be
+    // specified when creating the execmd. Help Recoll get rid of its
+    // filter children though. To be fixed one day... Not sure that
+    // all of this is needed. But an ignored sigterm and the masks are
+    // normally inherited.
+    if (signal(SIGTERM, SIG_DFL) == SIG_ERR) {
+	LOGERR(("ExecCmd::dochild: signal() failed, errno %d\n", errno));
+    }
+    sigset_t sset;
+    sigfillset(&sset);
+    pthread_sigmask(SIG_UNBLOCK, &sset, 0);
+    sigprocmask(SIG_UNBLOCK, &sset, 0);
+
+    if (has_input) {
+	close(m_pipein[1]);
+	if (m_pipein[0] != 0) {
+	    dup2(m_pipein[0], 0);
+	    close(m_pipein[0]);
+	}
+    }
+    if (has_output) {
+	close(m_pipeout[0]);
+	if (m_pipeout[1] != 1) {
+	    if (dup2(m_pipeout[1], 1) < 0) {
+		LOGERR(("ExecCmd::doexec: dup2(2) failed. errno %d\n", errno));
+	    }
+	    if (close(m_pipeout[1]) < 0) {
+		LOGERR(("ExecCmd::doexec: close(2) failed. errno %d\n", errno));
+	    }
+	}
+    }
+    // Do we need to redirect stderr ?
+    if (!m_stderrFile.empty()) {
+	int fd = open(m_stderrFile.c_str(), O_WRONLY|O_CREAT
+#ifdef O_APPEND
+		      |O_APPEND
+#endif
+		      , 0600);
+	if (fd < 0) {
+	    close(2);
+	} else {
+	    if (fd != 2) {
+		dup2(fd, 2);
+	    }
+	    lseek(2, 0, 2);
+	}
+    }
+
+    // Close all descriptors except 0,1,2
+    libclf_closefrom(3);
+
+    execve(cmd.c_str(), (char *const*)argv, (char *const*)envv);
+    // Hu ho
+    LOGERR(("ExecCmd::doexec: execvp(%s) failed. errno %d\n", cmd.c_str(),
+	    errno));
+    _exit(127);
+}
+
 int ExecCmd::startExec(const string &cmd, const vector<string>& args,
 		       bool has_input, bool has_output)
 {
@@ -192,19 +264,76 @@
 	return -1;
     }
 
-    m_pid = fork();
+
+//////////// vfork setup section
+    // We do here things that we could/should do after a fork(), but
+    // not a vfork(). Does no harm to do it here in both cases, except
+    // that it needs cleanup (as compared to doing it just before
+    // exec()).
+
+    // Allocate arg vector (2 more for arg0 + final 0)
+    typedef const char *Ccharp;
+    Ccharp *argv;
+    argv = (Ccharp *)malloc((args.size()+2) * sizeof(char *));
+    if (argv == 0) {
+	LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n",	errno));
+	exit(1);
+    }
+    // Fill up argv
+    argv[0] = cmd.c_str();
+    int i = 1;
+    vector<string>::const_iterator it;
+    for (it = args.begin(); it != args.end(); it++) {
+	argv[i++] = it->c_str();
+    }
+    argv[i] = 0;
+
+    Ccharp *envv;
+    int envsize;
+    for (envsize = 0; ; envsize++) 
+	if (environ[envsize] == 0)
+	    break;
+    envv = (Ccharp *)malloc((envsize + m_env.size() + 2) * sizeof(char *));
+    int eidx;
+    for (eidx = 0; eidx < envsize; eidx++)
+	envv[eidx] = environ[eidx];
+    for (vector<string>::const_iterator it = m_env.begin(); 
+	 it != m_env.end(); it++) {
+	envv[eidx++] = it->c_str();
+    }
+    envv[eidx] = 0;
+
+    // As we are going to use execve, not execvp, do the PATH
+    // thing. If the command is not found, exe will be empty and the
+    // exec will fail, which is what we want.
+    string exe;
+    which(cmd, exe);
+////////////////////////////////
+
+    if (o_useVfork) {
+	m_pid = vfork();
+    } else {
+	m_pid = fork();
+    }
     if (m_pid < 0) {
 	LOGERR(("ExecCmd::startExec: fork(2) failed. errno %d\n", errno));
 	return -1;
     }
     if (m_pid == 0) {
-	e.inactivate(); // needed ?
-	dochild(cmd, args, has_input, has_output);
+	// e.inactivate() is not needed. As we do not return, the call
+	// stack won't be unwound and destructors of local objects
+	// won't be called.
+	dochild(exe, argv, envv, has_input, has_output);
 	// dochild does not return. Just in case...
 	_exit(1);
     }
 
     // Father process
+////////////////////
+    // Vfork cleanup section
+    free(argv);
+    free(envv);
+///////////////////
 
     // Set the process group for the child. This is also done in the
     // child process see wikipedia(Process_group)
@@ -497,110 +626,6 @@
     }
 }
 
-// In child process. Set up pipes, environment, and exec command. 
-// This must not return. exit() on error.
-void ExecCmd::dochild(const string &cmd, const vector<string>& args,
-		      bool has_input, bool has_output)
-{
-    // Start our own process group
-    if (setpgid(0, getpid())) {
-	LOGINFO(("ExecCmd::dochild: setpgid(0, %d) failed: errno %d\n",
-		 getpid(), errno));
-    }
-
-    // Restore SIGTERM to default. Really, signal handling should be
-    // specified when creating the execmd. Help Recoll get rid of its
-    // filter children though. To be fixed one day... Not sure that
-    // all of this is needed. But an ignored sigterm and the masks are
-    // normally inherited.
-    if (signal(SIGTERM, SIG_DFL) == SIG_ERR) {
-	LOGERR(("ExecCmd::dochild: signal() failed, errno %d\n", errno));
-    }
-    sigset_t sset;
-    sigfillset(&sset);
-    pthread_sigmask(SIG_UNBLOCK, &sset, 0);
-    sigprocmask(SIG_UNBLOCK, &sset, 0);
-
-    if (has_input) {
-	close(m_pipein[1]);
-	m_pipein[1] = -1;
-	if (m_pipein[0] != 0) {
-	    dup2(m_pipein[0], 0);
-	    close(m_pipein[0]);
-	    m_pipein[0] = -1;
-	}
-    }
-    if (has_output) {
-	close(m_pipeout[0]);
-	m_pipeout[0] = -1;
-	if (m_pipeout[1] != 1) {
-	    if (dup2(m_pipeout[1], 1) < 0) {
-		LOGERR(("ExecCmd::doexec: dup2(2) failed. errno %d\n", errno));
-	    }
-	    if (close(m_pipeout[1]) < 0) {
-		LOGERR(("ExecCmd::doexec: close(2) failed. errno %d\n", errno));
-	    }
-	    m_pipeout[1] = -1;
-	}
-    }
-    // Do we need to redirect stderr ?
-    if (!m_stderrFile.empty()) {
-	int fd = open(m_stderrFile.c_str(), O_WRONLY|O_CREAT
-#ifdef O_APPEND
-		      |O_APPEND
-#endif
-		      , 0600);
-	if (fd < 0) {
-	    close(2);
-	} else {
-	    if (fd != 2) {
-		dup2(fd, 2);
-	    }
-	    lseek(2, 0, 2);
-	}
-    }
-
-    // Close all descriptors except 0,1,2
-    libclf_closefrom(3);
-
-    // Allocate arg vector (2 more for arg0 + final 0)
-    typedef const char *Ccharp;
-    Ccharp *argv;
-    argv = (Ccharp *)malloc((args.size()+2) * sizeof(char *));
-    if (argv == 0) {
-	LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n",	errno));
-	exit(1);
-    }
-	
-    // Fill up argv
-    argv[0] = cmd.c_str();
-    int i = 1;
-    vector<string>::const_iterator it;
-    for (it = args.begin(); it != args.end(); it++) {
-	argv[i++] = it->c_str();
-    }
-    argv[i] = 0;
-
-#if 0
-    {int i = 0;cerr << "cmd: " << cmd << endl << "ARGS: " << endl; 
-	while (argv[i]) cerr << argv[i++] << endl;}
-#endif
-
-    for (vector<string>::const_iterator it = m_env.begin(); 
-	 it != m_env.end(); it++) {
-#ifdef PUTENV_ARG_CONST
-	::putenv(it->c_str());
-#else
-	::putenv(strdup(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(),
-	    errno));
-    _exit(127);
-}
-
 ReExec::ReExec(int argc, char *args[])
 {
     init(argc, args);