rem: Ns_Log(Debug, "exec: child process %d started", pid);
context: Ns_ExecArgblk(char *exec, char *dir, int fdin, int fdout, char *args, Ns_Set *env){#ifndef WIN32    /*     * Unix ExecArgblk simply calls ExecArgv.     */         int    pid;    char **argv;    if (args != NULL) {        argv = BuildVector(args);    } else {        argv = NULL;    }    pid = Ns_ExecArgv(exec, dir, fdin, fdout, argv, env);    if (args != NULL) {        ns_free(argv);    }#else    STARTUPINFO     si;    PROCESS_INFORMATION pi;    HANDLE          hCurrentProcess;    int             pid;    Ns_DString      dsCmd, dsExec;    char           *envBlock;    OSVERSIONINFO   oinfo;    char           *cmd;    if (exec == NULL) {        Ns_Log(Bug, "exec: attempt to give null command child process");        return -1;    }    oinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);    if (GetVersionEx(&oinfo) == TRUE && oinfo.dwPlatformId != VER_PLATFORM_WIN32_NT) {        cmd = "command.com";    } else {        cmd = "cmd.exe";    }    /*     * Setup STARTUPINFO with stdin, stdout, and stderr.     */    memset(&si, 0, sizeof(si));    si.cb = sizeof(si);    si.dwFlags = STARTF_USESTDHANDLES;    si.hStdError = (HANDLE) _get_osfhandle(_fileno(stderr));    hCurrentProcess = GetCurrentProcess();    if (fdout < 0) {	fdout = 1;    }    if (DuplicateHandle(hCurrentProcess, (HANDLE) _get_osfhandle(fdout), hCurrentProcess,            &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS) != TRUE) {        Ns_Log(Error, "exec: failed to duplicate handle: %s",	       NsWin32ErrMsg(GetLastError()));        return -1;    }    if (fdin < 0) {        fdin = 0;    }    if (DuplicateHandle(hCurrentProcess, (HANDLE) _get_osfhandle(fdin), hCurrentProcess,            &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS) != TRUE) {        Ns_Log(Error, "exec: failed to duplicate handle: %s",	       NsWin32ErrMsg(GetLastError()));        (void) CloseHandle(si.hStdOutput);        return -1;    }        /*     * Setup the command line and environment block and create the new     * subprocess.     */        Ns_DStringInit(&dsCmd);    Ns_DStringInit(&dsExec);    if (args == NULL) {        /* NB: exec specifies a complete cmd.exe command string. */        Ns_DStringVarAppend(&dsCmd, cmd, " /c ", exec, NULL);        exec = NULL;    } else {        char           *s;        s = args;        while (*s != '\0') {            int             len;            len = strlen(s);            Ns_DStringNAppend(&dsCmd, s, len);            s += len + 1;            if (*s != '\0') {                Ns_DStringNAppend(&dsCmd, " ", 1);            }        }	Ns_NormalizePath(&dsExec, exec);	s = dsExec.string;	while (*s != '\0') {	    if (*s == '/') {		*s = '\\';	    }	    ++s;	}	exec = dsExec.string;    }    if (env == NULL) {        envBlock = NULL;    } else {        envBlock = GetEnvBlock(env);    }    if (CreateProcess(exec, dsCmd.string, NULL, NULL, TRUE, 0, envBlock, dir, &si, &pi) != TRUE) {        Ns_Log(Error, "exec: failed to create process: %s: %s",	       exec ? exec : dsCmd.string, NsWin32ErrMsg(GetLastError()));        pid = -1;    } else {        CloseHandle(pi.hThread);        pid = (int) pi.hProcess;        Ns_Log(Debug, "exec: child process %d started", pid);    }    Ns_DStringFree(&dsCmd);    Ns_DStringFree(&dsExec);    if (envBlock != NULL) {        ns_free(envBlock);    }    CloseHandle(si.hStdInput);    CloseHandle(si.hStdOutput);#endif    return pid;}