// 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; }
/* 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; }
/* 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; }