예제 #1
0
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 );
}
예제 #2
0
/* 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 );
}