int execute(const char *file, char * const*args) { if(strcmp(file, "exit") == 0) { kill(getpid(), SIGINT); exit(0); } pid_t childProc = fork(); int saved_stdout = dup(STDOUT_FILENO); int saved_stdin = dup(STDIN_FILENO); if(childProc >= 0) { if(childProc == 0) { if(!fix_fds()) { exit(0); } execvp(file, args); fprintf(stderr, "Error: %s\n", strerror(errno)); exit(0); } else { if(!background) { children[nchildren++] = childProc; } int status; if(!background) { waitpid(childProc, &status, 0); nchildren--; } else { int pid; while((pid=waitpid(-1, &status, WNOHANG)) > 0) { printf("PID %d exited.\n", pid); } } restore_fds(saved_stdin, saved_stdout); return status; } } else { fprintf(stderr, "Error: %s\n", strerror(errno)); } return -1; }
int fork(void) { size_t rc; size_t stacksize; char modname[512];/*FIXBUF*/ HANDLE hProc,hThread, hArray[2]; STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD dwCreationflags; unsigned int priority; HANDLE h64Parent,h64Child; #ifndef _M_ALPHA unsigned long fork_stack_end; #endif _M_ALPHA __fork_stack_begin =GETSTACKBASE(); #ifndef _M_ALPHA __fork_stack_end = &fork_stack_end; #else __fork_stack_end = (unsigned long *)__asm("mov $sp, $0"); #endif /*_M_ALPHA*/ h64Parent = h64Child = NULL; // // Create two inheritable events // sa.nLength = sizeof(sa); sa.lpSecurityDescriptor =0; sa.bInheritHandle = TRUE; if (!__hforkchild) __hforkchild = CreateEvent(&sa,TRUE,FALSE,NULL); if (!__hforkparent) __hforkparent = CreateEvent(&sa,TRUE,FALSE,NULL); rc = setjmp(__fork_context); if (rc) { // child #ifdef _M_IX86 // // Restore old registration // -amol 2/2/97 GETEXCEPTIONREGIST() = (struct _EXCEPTION_REGISTRATION_RECORD*)_old_exr; #endif // _M_ALPHA SetEvent(__hforkchild); dprintf("Child ready to rumble\n"); if(WaitForSingleObject(__hforkparent,FORK_TIMEOUT) != WAIT_OBJECT_0) ExitProcess(0xFFFF); CloseHandle(__hforkchild); CloseHandle(__hforkparent); __hforkchild = __hforkparent=0; //__asm { int 3}; restore_fds(); STR_environ = blk2short(environ); environ = short2blk(STR_environ); /* So that we can free it */ return 0; } copy_fds(); memset(&si,0,sizeof(si)); si.cb= sizeof(si); /* * This f!@#!@% function returns the old value even if the std handles * have been closed. * Skip this step, since we know tcsh will do the right thing later. * si.hStdInput= GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); */ if (!GetModuleFileName(GetModuleHandle(NULL),modname,512) ) { rc = GetLastError(); return -1; } dwCreationflags = GetPriorityClass(GetCurrentProcess()); priority = GetThreadPriority(GetCurrentThread()); rc = CreateProcess(NULL, modname, NULL, NULL, TRUE, CREATE_SUSPENDED | dwCreationflags, NULL, NULL, &si, &pi); if (!rc) { rc = GetLastError(); return -1; } ResetEvent(__hforkchild); ResetEvent(__hforkparent); hProc = pi.hProcess; hThread = pi.hThread; __forked=1; /* * Usage of events in the wow64 case: * * h64Parent : initially non-signalled * h64Child : initially non-signalled * * 1. Create the events, resume the child thread. * 2. Child opens h64Parent to see if it is a child process in wow64 * 3. Child opens and sets h64Child to tell parent it's running. (This * step is needed because we can't copy to a process created in the * suspended state on wow64.) * 4. Copy gForkData and then set h64Parent. This tells the child * that the parameters in the structure are trustworthy. * 5. Wait for h64Child so that we know the child has created the stack * in dynamic memory. * * The rest of the fork hack should now proceed as in x86 * */ if (bIsWow64Process) { // allocate the heap for the child. this can be done even when // the child is suspended. // avoids inexplicable allocation failures in the child. if (VirtualAllocEx(hProc, __heap_base, __heap_size, MEM_RESERVE, PAGE_READWRITE) == NULL) { dprintf("virtual allocex failed %d\n",GetLastError()); goto error; } if (VirtualAllocEx(hProc, __heap_base, __heap_size, MEM_COMMIT, PAGE_READWRITE) == NULL) { dprintf("virtual allocex2 failed %d\n",GetLastError()); goto error; } // Do NOT expect existing events if (!CreateWow64Events(pi.dwProcessId,&h64Parent,&h64Child,FALSE)) { goto error; } ResumeThread(hThread); // wait for the child to tell us it is running //if (WaitForSingleObject(h64Child,FORK_TIMEOUT) != WAIT_OBJECT_0) { // rc = GetLastError(); // goto error; //} hArray[0] = h64Child; hArray[1] = hProc; if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) != WAIT_OBJECT_0){ rc = GetLastError(); goto error; } } // // Copy all the shared data // if (!WriteProcessMemory(hProc,&gForkData,&gForkData, sizeof(ForkData),&rc)) { goto error; } if (rc != sizeof(ForkData)) goto error; if (!bIsWow64Process) { rc = ResumeThread(hThread); } // in the wow64 case, the child will be waiting on h64parent again. // set it, and then wait for h64child. This will mean the child has // a stack set up at the right location. else { SetEvent(h64Parent); hArray[0] = h64Child; hArray[1] = hProc; if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) != WAIT_OBJECT_0){ rc = GetLastError(); goto error; } CloseHandle(h64Parent); CloseHandle(h64Child); h64Parent = h64Child = NULL; } // // Wait for the child to start and init itself. // The timeout is so that we don't wait too long // hArray[0] = __hforkchild; hArray[1] = hProc; if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) != WAIT_OBJECT_0){ int err = GetLastError(); // For debugging purposes dprintf("wait failed err %d\n",err); goto error; } // Stop the child again and copy the stack and heap // SuspendThread(hThread); if (!SetThreadPriority(hThread,priority) ) { priority =GetLastError(); } // stack stacksize = (char*)__fork_stack_begin - (char*)__fork_stack_end; if (!WriteProcessMemory(hProc,(char *)__fork_stack_end, (char *)__fork_stack_end, (u_long)stacksize, &rc)){ goto error; } // // copy heap itself if (!WriteProcessMemory(hProc, (void*)__heap_base,(void*)__heap_base, (DWORD)((char*)__heap_top-(char*)__heap_base), &rc)){ goto error; } rc = fork_copy_user_mem(hProc); if(rc) { goto error; } // Release the child. SetEvent(__hforkparent); rc = ResumeThread(hThread); __forked=0; dprintf("forked process %d\n",pi.dwProcessId); start_sigchild_thread(hProc,pi.dwProcessId); close_copied_fds(); CloseHandle(hThread); // // return process id to parent. return pi.dwProcessId; error: __forked=0; SetEvent(__hforkparent); ResumeThread(hThread); CloseHandle(hProc); CloseHandle(hThread); if (h64Parent) { SetEvent(h64Parent); // don't let child block forever CloseHandle(h64Parent); } if (h64Child) CloseHandle(h64Child); return -1; }
void run_cmd(char * const *args, int *cmds, int numcmds) { int s_stdin = dup(STDIN_FILENO); int s_stdout = dup(STDOUT_FILENO); if(numcmds <= 0) { return; } int fds[2*(numcmds-1)]; for(int i=0; i<numcmds-1; i++) { if(pipe(fds + i*2) < 0) { fprintf(stderr, "Pipe error on line %d", __LINE__); perror(""); restore_fds(s_stdin, s_stdout); return; } } int childpid; for(int i=0; i<numcmds; i++) { int index = cmds[i]; childpid = fork(); if(childpid == 0) { if(!fix_fds()) { return; } // child proc //fprintf(stderr, "%d\n", i); if(i < numcmds-1) { //fprintf(stderr, "Duping stdout for cmd %s\n", *(args + index)); if(dup2(fds[i*2 + 1], 1) < 0) { fprintf(stderr, "Dup2 error on line %d", __LINE__); perror(""); // restore_fds(s_stdin, s_stdout); exit(0); } } if(i > 0) { //fprintf(stderr, "Duping stdin for cmd %s\n", *(args + index)); if(dup2(fds[i*2-2], 0) < 0) { fprintf(stderr, "Dup2 error on line %d\n", __LINE__); fprintf(stderr, "File descriptor: %d", fds[i*2-2]); perror(""); // restore_fds(s_stdin, s_stdout); // exit(0); kill(getppid(), SIGINT); exit(0); } } for(int j=0; j<numcmds*2-2; j++) { close(fds[j]); } //fprintf(stderr, "Exec cmd %s\n", *(args + index)); execvp(*(args + index), args + index); exit(0); } else if(childpid < 0) { fprintf(stderr, "Fork Error on line %d", __LINE__); perror(""); // restore_fds(s_stdin, s_stdout); exit(0); } else if(!background) { children[nchildren++] = childpid; } } for(int i=0; i<2*(numcmds-1); i++) { close(fds[i]); } int status; if(!background) { for(int i=0; i<numcmds; i++) { wait(&status); nchildren--; } } else { int pid; while((pid=waitpid(-1, &status, WNOHANG)) > 0) { fprintf(stderr, "PID %d exited.\n", pid); } } restore_fds(s_stdin, s_stdout); }