// Symbian main hook for tclappinit
EXPORT_C int ChildProcessInit (int *argc, char ***argv)
{
    //set the stdin,stdout,stderr to the child process. the fds pass to the posix_spawn() in argv
    TclFile inputFile = NULL;
    TclFile outputFile= NULL;
    TclFile errorFile = NULL;
    int joinThisError;
    int fd[4] = {0, 0, 0, 0};
    char errSpace[200 + TCL_INTEGER_SPACE];
    int anerr = 0;
	TBuf<256> buf;

    RDebug::Print(_L("###TclSqlite3: Child process init - begin. argc = %d.\r\n"), argc != NULL ? *argc : 0);
    if(argc)
    	{
    	for(TInt i=0;i<*argc;++i)
    		{
    		TPtrC8 p((const unsigned char*)((*argv)[i]));
    		buf.Copy(p);
    	    RDebug::Print(_L("   ### arg %d, value \"%S\"\r\n"), i, &buf);
    		}
    	}
   //set the stdin,stdout,stderr and pipeid to the child process. the fds pass to the posix_spawn() in argv
	if (*argc >= 5)
		{
		// fifoFile
		RDebug::Print(_L("  ### Fifo file. Arg %d.\r\n"), *argc-4);
		if((*argv)[*argc-4])
			{
			fd[0] = open((*argv)[*argc-4],O_WRONLY);
			if (fd[0] == -1)
				{
				RDebug::Print(_L("   ### fd[0](fifoFile) errno is %d\r\n"), errno);
				}
			else
				{
	    		TPtrC8 p((const unsigned char*)((*argv)[*argc-4]));
	    		buf.Copy(p);
				RDebug::Print(_L("   ### fifoFile is \"%S\", fd[0] is %d\r\n"), &buf, fd[0]);				
				}
		    //fd = atoi((*argv)[*argc-1]);
			}
		else
			{
			RDebug::Print(_L("   ### Fifo file - (*argv)[*argc-4] is 0.\r\n"));
			//should add later
			}
		// inputFile
		RDebug::Print(_L("  ### Input file. Arg %d.\r\n"), *argc-3);
		if(((*argv)[*argc-3])&&(strcmp((*argv)[*argc-3],"STD")))
			{
			fd[3] = open((*argv)[*argc-3],O_RDONLY); 
			inputFile = MakeFile(fd[3]);
			if (fd[3] == -1)
				{
				RDebug::Print(_L("   ### fd[3](inputFile) errno is %d\r\n"), errno);
				}
			else
				{
	    		TPtrC8 p((const unsigned char*)((*argv)[*argc-3]));
	    		buf.Copy(p);
				RDebug::Print(_L("   ### inputFile is \"%S\", fd[3] is %d\r\n"), &buf, fd[3]);					
				}
			    //inputFile = (TclFile) (atoi((*argv)[*argc-4]));
			}
		else
			{
			RDebug::Print(_L("   ### Input file - ((*argv)[*argc-3])&&(strcmp((*argv)[*argc-3],\"STD\")) is 0.\r\n"));
			//should add later
			}
		// outputFile
		RDebug::Print(_L("  ### Output file. Arg %d\r\n"), *argc-2);
		if(((*argv)[*argc-2])&&(strcmp((*argv)[*argc-2],"STD")))
			{
			fd[2] = open((*argv)[*argc-2],O_WRONLY);
			outputFile = MakeFile(fd[2]);
		    if (fd[2] == -1)
		    	{
		    	RDebug::Print(_L("   ### fd[2](outputFile) errno is %d\r\n"), errno);
		    	}
		    else
				{
	    		TPtrC8 p((const unsigned char*)((*argv)[*argc-2]));
	    		buf.Copy(p);
				RDebug::Print(_L("   ### outputFile is \"%S\", fd[2] is %d\r\n"), &buf, fd[2]);					
				}
		    
			//outputFile = (TclFile) (atoi((*argv)[*argc-3]));
			}
		else
			{
			RDebug::Print(_L("   ### Output file - ((*argv)[*argc-2])&&(strcmp((*argv)[*argc-2],\"STD\")) is 0.\r\n"));
			//should add later
			//outputFile = MakeFile(1);
			}
		// errorFile
		RDebug::Print(_L("  ### Error file. Arg %d\r\n"), *argc-1);
		if(((*argv)[*argc-1])&&(strcmp((*argv)[*argc-1],"STD")))
			{
			fd[1] = open((*argv)[*argc-1],O_WRONLY);
			errorFile = MakeFile(fd[1]);
			if (fd[1] == -1)
				{
				RDebug::Print(_L("   ### fd[1] errorFile errno is %d\r\n"), errno);
				}
			else
				{
	    		TPtrC8 p((const unsigned char*)((*argv)[*argc-1]));
	    		buf.Copy(p);
				RDebug::Print(_L("   ### errorFile is \"%S\", fd[1] is %d\r\n"), &buf, fd[1]);
				}
		    //errorFile = (TclFile) (atoi((*argv)[*argc-2]));
			}
		else
			{
			RDebug::Print(_L("   ### Output file - ((*argv)[*argc-1])&&(strcmp((*argv)[*argc-1],\"STD\")) is 0.\r\n"));
			//should add later
			}
		//*argc = *argc-4;
		
		joinThisError = errorFile && (errorFile == outputFile);

		//fd = GetFd(errPipeOut);
    
		//
		// Set up stdio file handles for the child process.
		//

		if (!SetupStdFile(inputFile, TCL_STDIN)
			|| !SetupStdFile(outputFile, TCL_STDOUT)
			|| (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
			|| (joinThisError &&
				((dup2(1,2) == -1) ||
				 (fcntl(2, F_SETFD, 0) != 0)))) 
			//if (!SetupStdFile(errorFile, TCL_STDERR))
			{
			RDebug::Print(_L("   ### child process couldn't set up input/output, error: %d\r\n"), errno);
			sprintf(errSpace,"child process couldn't set up input/output, error: %d\r\n", errno);
			write(fd[0], errSpace, (size_t) strlen(errSpace));
			close(fd[0]);
			unlink((*argv)[*argc-4]);
		    RDebug::Print(_L("###TclSqlite3: Child process init - end 1.\r\n"));
			_exit(1);
			}

		sprintf(errSpace,"OK\r\n");
		write(fd[0], errSpace, (size_t) strlen(errSpace));
		anerr = close(fd[0]);
		anerr = unlink((*argv)[*argc-4]);
	    RDebug::Print(_L("###TclSqlite3: Child process init - end 2. anerr=%d.\r\n"), anerr);
	   	return 1;
		}
    
    RDebug::Print(_L("###TclSqlite3: Child process init - end 3.\r\n"));
    return 0;			
}
Esempio n. 2
0
    /* ARGSUSED */
int
TclpCreateProcess(
    Tcl_Interp *interp,		/* Interpreter in which to leave errors that
				 * occurred when creating the child process.
				 * Error messages from the child process
				 * itself are sent to errorFile. */
    int argc,			/* Number of arguments in following array. */
    const char **argv,		/* Array of argument strings in UTF-8.
				 * argv[0] contains the name of the executable
				 * translated using Tcl_TranslateFileName
				 * call). Additional arguments have not been
				 * converted. */
    TclFile inputFile,		/* If non-NULL, gives the file to use as input
				 * for the child process. If inputFile file is
				 * not readable or is NULL, the child will
				 * receive no standard input. */
    TclFile outputFile,		/* If non-NULL, gives the file that receives
				 * output from the child process. If
				 * outputFile file is not writeable or is
				 * NULL, output from the child will be
				 * discarded. */
    TclFile errorFile,		/* If non-NULL, gives the file that receives
				 * errors from the child process. If errorFile
				 * file is not writeable or is NULL, errors
				 * from the child will be discarded. errorFile
				 * may be the same as outputFile. */
    Tcl_Pid *pidPtr)		/* If this function is successful, pidPtr is
				 * filled with the process id of the child
				 * process. */
{
    TclFile errPipeIn, errPipeOut;
    int count, status, fd;
    char errSpace[200 + TCL_INTEGER_SPACE];
    Tcl_DString *dsArray;
    char **newArgv;
    int pid, i;

    errPipeIn = NULL;
    errPipeOut = NULL;
    pid = -1;

    /*
     * Create a pipe that the child can use to return error information if
     * anything goes wrong.
     */

    if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) {
	Tcl_AppendResult(interp, "couldn't create pipe: ",
		Tcl_PosixError(interp), NULL);
	goto error;
    }

    /*
     * We need to allocate and convert this before the fork so it is properly
     * deallocated later
     */

    dsArray = (Tcl_DString *)
	    TclStackAlloc(interp, argc * sizeof(Tcl_DString));
    newArgv = (char **) TclStackAlloc(interp, (argc+1) * sizeof(char *));
    newArgv[argc] = NULL;
    for (i = 0; i < argc; i++) {
	newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]);
    }

#ifdef USE_VFORK
    /*
     * After vfork(), do not call code in the child that changes global state,
     * because it is using the parent's memory space at that point and writes
     * might corrupt the parent: so ensure standard channels are initialized in
     * the parent, otherwise SetupStdFile() might initialize them in the child.
     */
    if (!inputFile) {
	Tcl_GetStdChannel(TCL_STDIN);
    }
    if (!outputFile) {
        Tcl_GetStdChannel(TCL_STDOUT);
    }
    if (!errorFile) {
        Tcl_GetStdChannel(TCL_STDERR);
    }
#endif
    pid = fork();
    if (pid == 0) {
	int joinThisError = errorFile && (errorFile == outputFile);

	fd = GetFd(errPipeOut);

	/*
	 * Set up stdio file handles for the child process.
	 */

	if (!SetupStdFile(inputFile, TCL_STDIN)
		|| !SetupStdFile(outputFile, TCL_STDOUT)
		|| (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
		|| (joinThisError &&
			((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {
	    sprintf(errSpace,
		    "%dforked process couldn't set up input/output: ", errno);
	    (void)write(fd, errSpace, (size_t) strlen(errSpace));
	    _exit(1);
	}

	/*
	 * Close the input side of the error pipe.
	 */

	RestoreSignals();
	execvp(newArgv[0], newArgv);			/* INTL: Native. */
	sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]);
	(void)write(fd, errSpace, (size_t) strlen(errSpace));
	_exit(1);
    }

    /*
     * Free the mem we used for the fork
     */

    for (i = 0; i < argc; i++) {
	Tcl_DStringFree(&dsArray[i]);
    }
    TclStackFree(interp, newArgv);
    TclStackFree(interp, dsArray);

    if (pid == -1) {
	Tcl_AppendResult(interp, "couldn't fork child process: ",
		Tcl_PosixError(interp), NULL);
	goto error;
    }

    /*
     * Read back from the error pipe to see if the child started up OK. The
     * info in the pipe (if any) consists of a decimal errno value followed by
     * an error message.
     */

    TclpCloseFile(errPipeOut);
    errPipeOut = NULL;

    fd = GetFd(errPipeIn);
    count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
    if (count > 0) {
	char *end;
	errSpace[count] = 0;
	errno = strtol(errSpace, &end, 10);
	Tcl_AppendResult(interp, end, Tcl_PosixError(interp), NULL);
	goto error;
    }

    TclpCloseFile(errPipeIn);
    *pidPtr = (Tcl_Pid) INT2PTR(pid);
    return TCL_OK;

  error:
    if (pid != -1) {
	/*
	 * Reap the child process now if an error occurred during its startup.
	 * We don't call this with WNOHANG because that can lead to defunct
	 * processes on an MP system. We shouldn't have to worry about hanging
	 * here, since this is the error case. [Bug: 6148]
	 */

	Tcl_WaitPid((Tcl_Pid) INT2PTR(pid), &status, 0);
    }

    if (errPipeIn) {
	TclpCloseFile(errPipeIn);
    }
    if (errPipeOut) {
	TclpCloseFile(errPipeOut);
    }
    return TCL_ERROR;
}
Esempio n. 3
0
/* ARGSUSED */
static int
CreateProcess(
    Tcl_Interp *interp,		/* Interpreter in which to leave errors that
				 * occurred when creating the child process.
				 * Error messages from the child process
				 * itself are sent to stderrFd. */
    int argc,			/* Number of arguments in following array. */
    char **argv,		/* Array of argument strings.  argv[0]
				 * contains the name of the executable
				 * converted to native format (using the
				 * Tcl_TranslateFileName call).  Additional
				 * arguments have not been converted. */
    int stdinFd,		/* The file to use as input for the child
				 * process.  If stdinFd file is -1, input is
				 * read from the standard input channel. If
				 * the file isn't readable, the child will
				 * receive no standard input. */
    int stdoutFd,		/* The file that receives output from the
				 * child process.  If stdoutFd is -1, output
				 * is sent to the standard output channel.  If
				 * the file is not writeable, output from the
				 * child will be discarded. */
    int stderrFd,		/* The file that receives errors from the
				 * child process.  If stderrFd file is -1,
				 * errors will be sent to the standard error
				 * channel. If the file isn't writeable,
				 * errors from the child will be discarded.
				 * stderrFd may be the same as stdoutFd. */
    int *pidPtr)		/* (out) If this procedure is successful,
				 * pidPtr is filled with the process id of the
				 * child process. */
{
#if (_TCL_VERSION >= _VERSION(8,1,0)) 
    Tcl_DString *dsArr;
    Tcl_Encoding encoding;
#endif
    char errSpace[200];
    int errPipeIn, errPipeOut;
    int i;
    int joinThisError, status, fd;
    long pid;
    size_t count;

    errPipeIn = errPipeOut = -1;
    pid = -1;

#if (_TCL_VERSION >= _VERSION(8,1,0)) 
    dsArr = Blt_AssertMalloc(argc * sizeof(Tcl_DString));
    encoding = Tcl_GetEncoding(interp, NULL);
    for(i = 0; i < argc; i++) {
	argv[i] = Tcl_UtfToExternalDString(encoding, argv[i], 
		strlen(argv[i]), dsArr + i);
    }
#endif
    /*
     * Create a pipe that the child can use to return error information if
     * anything goes wrong.
     */
    if (CreatePipe(interp, &errPipeIn, &errPipeOut) != TCL_OK) {
	goto error;
    }
    joinThisError = (stderrFd == stdoutFd);
    pid = fork();
    if (pid == 0) {
	ssize_t nWritten;

	fd = errPipeOut;

	/*
	 * Set up stdio file handles for the child process.
	 */
	if (!SetupStdFile(stdinFd, TCL_STDIN) ||
	    !SetupStdFile(stdoutFd, TCL_STDOUT) ||
	    (!joinThisError && !SetupStdFile(stderrFd, TCL_STDERR)) ||
	    (joinThisError &&
		((dup2(1, 2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {
	    sprintf_s(errSpace, 200, 
		"%dforked process can't set up input/output: ", errno);
	    nWritten = write(fd, errSpace, (size_t) strlen(errSpace));
	    _exit(1);
	}
	/*
	 * Close the input side of the error pipe.
	 */
	RestoreSignals();
	execvp(argv[0], &argv[0]);
	sprintf_s(errSpace, 200, "%dcan't execute \"%.150s\": ", errno, argv[0]);
 	nWritten = write(fd, errSpace, (size_t)strlen(errSpace));
	_exit(1);
    }
    if (pid == -1) {
	Tcl_AppendResult(interp, "can't fork child process: ",
	    Tcl_PosixError(interp), (char *)NULL);
	goto error;
    }

    /*
     * Read back from the error pipe to see if the child started up OK.  The
     * info in the pipe (if any) consists of a decimal errno value followed by
     * an error message.
     */
    CloseFile(errPipeOut);
    errPipeOut = -1;

    fd = errPipeIn;
    count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
    if (count > 0) {
	char *end;

	errSpace[count] = 0;
	errno = strtol(errSpace, &end, 10);
	Tcl_AppendResult(interp, end, Tcl_PosixError(interp), (char *)NULL);
	goto error;
    }
#if (_TCL_VERSION >= _VERSION(8,1,0)) 
    for(i = 0; i < argc; i++) {
	Tcl_DStringFree(dsArr + i);
    }
    Blt_Free(dsArr);
#endif
    CloseFile(errPipeIn);
    *pidPtr = pid;
    return TCL_OK;

  error:
    if (pid != -1) {
	/*
	 * Reap the child process now if an error occurred during its startup.
	 */
	Tcl_WaitPid((Tcl_Pid)pid, &status, WNOHANG);
    }
    if (errPipeIn >= 0) {
	CloseFile(errPipeIn);
    }
    if (errPipeOut >= 0) {
	CloseFile(errPipeOut);
    }
#if (_TCL_VERSION >= _VERSION(8,1,0)) 
    for(i = 0; i < argc; i++) {
	Tcl_DStringFree(dsArr + i);
    }
    Blt_Free(dsArr);
#endif
    return TCL_ERROR;
}