char *buffer_append(buffer *b, char *bytes, unsigned int size) { if (!b || !bytes) return NULL; char *space = buffer_makespace(b, size); if (!space) return NULL; memcpy(space, bytes, size); buffer_usespace(b, size); return space; }
proc *process_run(char executable[], char *args[], int timeout) { proc *retval = NULL; char *text; int status; tl_stream stdout_p; tl_stream stdin_p; SECURITY_ATTRIBUTES saAttr; PROCESS_INFORMATION pi; STARTUPINFO si; BOOL createproc_success = FALSE; BOOL timedout = FALSE; TCHAR *commandline = NULL; proc *p = process_new(); if (p == NULL) return NULL; /* Make sure pipe handles are inherited */ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; p->causeofdeath = PROC_PIPECREATE; DEBUG(("making pipes \n")); /* Child's Stdout */ if ( ! CreatePipe(&stdout_p.read, &stdout_p.write, &saAttr, 1) ) { printlasterror(); RETURN(p); } DEBUG(("stdout done \n")); /* read handle to the pipe for STDOUT is not inherited */ if ( ! SetHandleInformation(stdout_p.read, HANDLE_FLAG_INHERIT, 0) ) { printlasterror(); RETURN(p); } DEBUG(("stdout noinherit \n")); /* a pipe for the child process's STDIN */ if ( ! CreatePipe(&stdin_p.read, &stdin_p.write, &saAttr, 0) ) { printlasterror(); RETURN(p); } DEBUG(("stdin done \n")); /* write handle to the pipe for STDIN not inherited */ if ( ! SetHandleInformation(stdin_p.read, HANDLE_FLAG_INHERIT, 0) ) { printlasterror(); RETURN(p); } DEBUG(("pipes done \n")); p->causeofdeath = PROC_START; ZeroMemory( &si, sizeof(STARTUPINFO) ); ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) ); si.cb = sizeof(STARTUPINFO); si.hStdError = stdout_p.write; si.hStdOutput = stdout_p.write; /* Rather than use the stdin pipe, which would be si.hStdInput = stdin_p.read; Pass on talon's own standard input to the child process This helps with programs like xcopy which demand that they are attached to a console and not just any type of input file. */ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.dwFlags |= STARTF_USESTDHANDLES; DEBUG(("pre commandline \n")); /* create the commandline string */ int len = 0; int i = 0; while (args[i] != NULL) { len += strlen(args[i++]) + 1; } len+=2; commandline = malloc(len*2); if (! commandline) RETURN(p); commandline[0] = '\0'; i = 0; while (args[i] != NULL) { strcat(commandline, args[i]); strcat(commandline, " "); i++; } /* Get the read thread ready to go before creating * the process. */ ReadOpQ *ropq = malloc(sizeof(ReadOpQ)); ropq->first=NULL; ropq->last=NULL; ropq->semaphore = CreateSemaphore(NULL, 0, 1, NULL); DEBUG(("Creating read thread. \n")); DWORD readpipe_threadid; HANDLE h_readpipe_thread = CreateThread(NULL, 8192, (LPTHREAD_START_ROUTINE) readpipe_thread, (void*)ropq, 0, &readpipe_threadid); /* ready to run the process */ DEBUG(("process commandline:\n%s \n", commandline)); DEBUG(("\n")); createproc_success = CreateProcess(executable, commandline, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &si, // STARTUPINFO pointer &pi); // receives PROCESS_INFORMATION if (! createproc_success) { DEBUG(("Createprocess failed. \n")); p->causeofdeath = PROC_SOMEODDDEATH; RETURN(p); } int have_status = 0; DEBUG(("Closing Handles. \n")); if (!CloseHandle(stdout_p.write)) RETURN(p); if (!CloseHandle(stdin_p.read)) RETURN(p); DEBUG(("Closed Handles. \n")); static int id=0; do { char *space = buffer_makespace(p->output, READSIZE); DWORD waitres; ReadOp *iopipe_op = malloc(sizeof(ReadOp)); iopipe_op->semaphore = CreateSemaphore(NULL, 0, 1, NULL); iopipe_op->thread = h_readpipe_thread; iopipe_op->timeout = timeout; iopipe_op->file = stdout_p.read; iopipe_op->space = malloc(READSIZE); iopipe_op->id = id++; iopipe_op->nbytes = READSIZE; iopipe_op->next = NULL; if (!ropq->first) { ropq->first = iopipe_op; ropq->last = iopipe_op; } else { ropq->last->next = iopipe_op; ropq->last = iopipe_op; } ReleaseSemaphore(ropq->semaphore, 1, NULL); DEBUG(("waiting for read %d\n", timeout)); waitres = WaitForSingleObject(iopipe_op->semaphore, timeout); DEBUG(("read wait finished result= %d\n", waitres)); if (waitres != WAIT_OBJECT_0) { DEBUG(("timeout \n")); timedout = TRUE; break; } else { DEBUG(("read signalled: nbytes: %d \n", iopipe_op->nbytes)); if (iopipe_op->nbytes <= 0) { break; } memcpy(space, iopipe_op->space, iopipe_op->nbytes); buffer_usespace(p->output, iopipe_op->nbytes); DEBUG(("buffer took on nbytes: %d \n", iopipe_op->nbytes)); } } while (1); if (timedout == FALSE) { DEBUG(("Wait for process exit\n")); // Wait until child process exits. WaitForSingleObject(pi.hProcess, INFINITE); DEBUG(("Process exited\n")); DWORD exitcode; if (GetExitCodeProcess(pi.hProcess, &exitcode)) { p->causeofdeath = PROC_NORMALDEATH; p->returncode = exitcode; DEBUG(("process exited normally = %d:\n", p->returncode)); RETURN(p); } else { p->causeofdeath = PROC_SOMEODDDEATH; p->returncode = 128; DEBUG(("process terminated \n")); RETURN(p); } } else { TerminateProcess(pi.hProcess,1); p->causeofdeath = PROC_TIMEOUTDEATH; p->returncode = 128; DEBUG(("process timedout \n")); RETURN(p); } /* Clean up the read operation queue ReadOp *r = ropq.first; do { CloseHandle(r->semaphore); free(r->space); free(r); r = r->next; } while (r != NULL); */ CLEANUP(); if (retval == NULL) { if (p) process_free(&p); } if (commandline) free(commandline); return retval; }