static int ast_forall_execute( struct ast_forloop *f, time_t stoptime, const char *name, int argc, char **argv ) { int i; int pid; int result; struct multi_fork_status *s; s = xxmalloc(sizeof(*s)*argc); pid = multi_fork(argc,s,stoptime,f->for_line); if(pid>=0) { random_init(); if(stoptime && (time(0)>stoptime)) _exit(1); ftsh_error(FTSH_ERROR_STRUCTURE,f->for_line,"%s=%s starting",name,argv[pid]); result = buffer_save(name,argv[pid]); if(!result) _exit(1); result = ast_group_execute(f->body,stoptime); if(result) { _exit(0); } else { _exit(1); } } else { for(i=0;i<argc;i++) { char str[LINE_MAX]; if(s[i].state==MULTI_FORK_STATE_GRAVE) { snprintf(str,sizeof(str),"%s=%s",name,argv[i]); process_status(str,s[i].pid,s[i].status,f->for_line); } } free(s); if(pid==MULTI_FORK_SUCCESS) { return 1; } else { return 0; } } }
timed_exec_t timed_exec( int line, const char *path, char **argv, int fds[3], pid_t *pid, int *status, time_t stoptime ) { int fresult; int pfds[2]; int child_errno; int actual; struct multi_fork_status s; actual = pipe(pfds); if(actual!=0) return TIMED_EXEC_NOEXEC; fresult = multi_fork(1,&s,stoptime,line); if(fresult>=0) { /* Move our standard I/O streams into the expected places. */ /* It seems that cygwin doesn't like dup2 on the same fd. */ int i, maxfd; for( i=0; i<=2; i++ ) { if( fds[i]!=i ) { if( dup2(fds[i],i) != i ) { ftsh_error(FTSH_ERROR_PROCESS,line,"failure to dup2(%d,%d): %s\n",fds[i],i,strerror(errno)); goto done; } } } /* Close all of the file descriptors that we don't need. */ maxfd = sysconf( _SC_OPEN_MAX ); if(maxfd<=0) maxfd = 255; for(i=3;i<maxfd;i++) { if(i==pfds[1]) continue; close(i); } /* Set the pipe to automatically close after exec. */ if( fcntl(pfds[1],F_SETFD,FD_CLOEXEC)==0 ) { setsid(); execvp(path,argv); } /* If anything goes wrong, write the errno to the pipe, where the parent process can collect and print it. */ done: child_errno = errno; full_write(pfds[1],&child_errno,sizeof(child_errno)); _exit(1); } else { /* Now clear the pipe. If it contains an int, then the process forked, but was unable to exec. Set the reason appropriately. Otherwise, live with what we have. */ close(pfds[1]); actual = full_read(pfds[0],&child_errno,sizeof(int)); close(pfds[0]); *status = s.status; *pid = s.pid; if(actual==sizeof(int)) { return TIMED_EXEC_NOEXEC; } else if(fresult==MULTI_FORK_SUCCESS) { return TIMED_EXEC_SUCCESS; } else if(fresult==MULTI_FORK_TIMEOUT) { return TIMED_EXEC_TIMEOUT; } else { return TIMED_EXEC_FAILURE; } } }