i4 PCreap_withThisPid(int targetPid) { #ifdef xCL_001_WAIT_UNION union wait wait_status; #else int wait_status; #endif i4 proc_stat; i4 sys_stat; register PIDQUE *sqp; /* search queue pointer */ register PID pid; register STATUS rval; TYPESIG (*inthandler)(); TYPESIG (*quithandler)(); /* ** If the Pidq doesn't exist, no point waiting for the child ** since we don't care anyway. */ if(Pidq_init == FALSE) return( -1 ); /* ** Disable the SIGINT and SIGQUIT, and save their old actions. ** EXinterrupt(EX_OFF) now latches incoming keyboard interrupts, ** rather than discarding them; we need to actually turn the ** signal handling off. */ inthandler = signal(SIGINT, SIG_IGN); quithandler = signal(SIGQUIT, SIG_IGN); /* ** Set a default result-code ** - As above return code, meaning "Child does not exist" */ pid = -1; for (sqp = (PIDQUE *) Pidq.q_next; sqp != (PIDQUE *) &Pidq; sqp = (PIDQUE *) sqp->pidq.q_next ) { /* ** Are we looking for a specific child to checkup on ? */ if (targetPid != -1) { /* ** Pick out that child by stepping right over the others. */ if (targetPid != sqp->pid) continue; /** the for loop **/ /* ** The child does exist, so change the default result-code. ** - Now means "Child state changed from executable" */ pid = targetPid; } /* ** Still executing this child ? */ if ( sqp->stat == PC_WT_EXEC ) { /* ** Loop until no error (-1) attempting to read status of this pid ** - A zero result here now means "pid reports no state change" ** - WNOHANG is important, this call will not block if child ** still running ... so we may use routine a a polling agent. */ while (((pid = waitpid ( sqp->pid, (int *)&wait_status, WNOHANG)) == -1) && (errno == EINTR)); if ( pid == sqp->pid ) { /* error pid needs no special handling; it falls on the floor */ # ifdef xCL_001_WAIT_UNION proc_stat = wait_status.w_retcode; sys_stat = wait_status.w_status & ~(proc_stat); # else # ifdef xCL_USE_WAIT_MACROS if ( WIFEXITED( wait_status ) ) { /* process exited, set PC status based on exit value */ proc_stat = WEXITSTATUS( wait_status ); sqp->stat = proc_stat == 0 ? OK : PC_WT_BAD ; break; } else if ( WIFSIGNALED( wait_status ) ) { /* process terminated by signal */ sqp->stat = PC_WT_TERM; break; } else if ( WIFSTOPPED( wait_status ) ) { /* process interrupted by signal */ sqp->stat = PC_WT_INTR; break; } else # endif { proc_stat = wait_status & 0377; sys_stat = wait_status & ~(proc_stat); } # endif /* ** Map the status of the dead child to a PC_WT_code. */ sqp->stat = proc_stat == 0 ? OK : sys_stat == 0 ? PC_WT_TERM : PC_WT_BAD; break; } } /* ** Were we were targetting a particular pid ? */ if (targetPid != -1) { /* ** Break out of for-loop */ break; } } /* reset interrupt and quit signals */ (void) signal(SIGINT, inthandler); (void) signal(SIGQUIT, quithandler); return( pid ); }
/* append = nonzero to append to output file. ** rederr = nonzero to redirect stderr to error log. */ STATUS PCdospawn(i4 argc, char **argv, bool wait, LOCATION *in_name, LOCATION *out_name, i4 append, i4 rederr, PID *pid) { char buf[64]; char *in_fname; char *out_fname; STATUS PCwait(); TYPESIG (*old_handler)(); int flags = 0; STATUS status; /* Flush the output buffers to make sure all child output ** follows the parent output. The streams may be buffered ** if, for example, they were redirected to a file. */ SIflush(stdout); SIflush(stderr); TRflush(); /* Don't want to mess up a sub-shell's handling of this by leaving ** it something odd. This might be a problem if something is ** run out of a DBMS server and an iislave happens to die while the ** subprocess spawned here is running. The symptom of this not working ** right is ckpdb failing, because the shell's handling of child death ** was messed up by our redirected handling of SIGCHLD. Frankly, that ** smells odd to me, but what the heck... (daveb). */ old_handler = EXsetsig(SIGCHLD, SIG_DFL); if ( (argc < 1) || (argv[0] == NULL)) { PCstatus = PC_SP_CALL; } /* ** If we are using fork() instead of vfork(), we must check ** to see if argument is executable now, because ** PCstatus from child process won't be available ** to parent. We don't know if we are using fork, so ** always check. */ else if (access(argv[0], 01) == BAD_ACCESS) { switch (errno) { case EACCES: /* error occurred because path was inaccessable. */ PCstatus = PC_SP_PERM; break; case EPERM: PCstatus = PC_SP_OWNER; break; case ENOTDIR: /* error occurred path didn't exist */ PCstatus = PC_SP_PATH; break; case ENOENT: /* error occurred path didn't exist */ PCstatus = PC_SP_SUCH; break; } } else if ( (*pid = (PID)PCfork( &PCstatus )) > 0 ) /* parent */ { /* ** (v)fork returns control to parent after exec. ** Calling process can ask PCspawn() to wait for ** the child, wait itself or choose not to wait. */ /* ** in the case of PC_NO_WAIT, we are only waiting for ** the intermediate process, which will also do fork/exec */ PCstatus = PCwait(*pid); } else if ( *pid == 0 ) /* child */ { if ( !wait ) { #if !defined xCL_086_SETPGRP_0_ARGS /* BSD flavour setpgrp */ if (setpgrp(0, getpid()) == -1 ) { status = errno; SIprintf("Can't change process group for spawned process\n"); PCexit(status); } # ifdef TIOCNOTTY /* say goodbye to our control terminal */ if ( (fd = open("/dev/tty", O_RDWR) ) >= 0 ) { ioctl(fd, TIOCNOTTY, (char *) NULL); close(fd); } # endif /* TIOCNOTTY */ #else /* SYSV flavour setpgrp */ if(setpgrp() == -1) /* create new pgrp, lose control terminal */ { status = errno; SIprintf("Can't change process group for spawned process\n"); PCexit(status); } #endif /* fork again, so we can't reacquire a control terminal */ if ( (*pid = PCfork(&status)) < 0 ) { status = errno; SIprintf("Can't fork again for spawned process\n"); PCexit(status); } else if (*pid > 0) { /* intermediate parent */ _exit(OK); } /* reset all the signal handlers to default */ EXsetsig( SIGCHLD, SIG_DFL ); } if (in_name != NULL) { LOtos(in_name, &in_fname); if ( *in_fname && freopen(in_fname, "r", stdin) != stdin ) PCstatus = PC_SP_REOPEN; } if (PCstatus == OK) { if (out_name != NULL) { char *mode = (append != 0) ? ERx("a") : ERx("w"); LOtos(out_name, &out_fname); if ( *out_fname ) { if (freopen(out_fname, mode, stdout) != stdout) { PCstatus = PC_SP_REOPEN; } else if (rederr != 0) { close(2); dup(1); } } } if (PCstatus == OK) { STcopy(argv[0], buf); argv[argc] = '\0'; /* insure argv set up properly */ execvp(buf, argv); /* should never reach here, because we checked first */ PCno_exec(buf); } } /* Should only reach here we had a PC_SP_REOPEN failure */ _exit( FAIL ); } (void) EXsetsig(SIGCHLD, old_handler); return( PCstatus ); }