job.c revision 8874
11590Srgrimes/*
25814Sjkh * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
35814Sjkh * Copyright (c) 1988, 1989 by Adam de Boor
41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * This code is derived from software contributed to Berkeley by
81590Srgrimes * Adam de Boor.
91590Srgrimes *
101590Srgrimes * Redistribution and use in source and binary forms, with or without
111590Srgrimes * modification, are permitted provided that the following conditions
121590Srgrimes * are met:
131590Srgrimes * 1. Redistributions of source code must retain the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer.
151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161590Srgrimes *    notice, this list of conditions and the following disclaimer in the
171590Srgrimes *    documentation and/or other materials provided with the distribution.
181590Srgrimes * 3. All advertising materials mentioning features or use of this software
191590Srgrimes *    must display the following acknowledgement:
201590Srgrimes *	This product includes software developed by the University of
211590Srgrimes *	California, Berkeley and its contributors.
221590Srgrimes * 4. Neither the name of the University nor the names of its contributors
231590Srgrimes *    may be used to endorse or promote products derived from this software
241590Srgrimes *    without specific prior written permission.
251590Srgrimes *
261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361590Srgrimes * SUCH DAMAGE.
371590Srgrimes */
381590Srgrimes
391590Srgrimes#ifndef lint
401590Srgrimesstatic char sccsid[] = "@(#)job.c	8.2 (Berkeley) 3/19/94";
411590Srgrimes#endif /* not lint */
421590Srgrimes
431590Srgrimes/*-
441590Srgrimes * job.c --
451590Srgrimes *	handle the creation etc. of our child processes.
461590Srgrimes *
471590Srgrimes * Interface:
481590Srgrimes *	Job_Make  	    	Start the creation of the given target.
491590Srgrimes *
501590Srgrimes *	Job_CatchChildren   	Check for and handle the termination of any
511590Srgrimes *	    	  	    	children. This must be called reasonably
521590Srgrimes *	    	  	    	frequently to keep the whole make going at
531590Srgrimes *	    	  	    	a decent clip, since job table entries aren't
541590Srgrimes *	    	  	    	removed until their process is caught this way.
551590Srgrimes *	    	  	    	Its single argument is TRUE if the function
561590Srgrimes *	    	  	    	should block waiting for a child to terminate.
571590Srgrimes *
581590Srgrimes *	Job_CatchOutput	    	Print any output our children have produced.
591590Srgrimes *	    	  	    	Should also be called fairly frequently to
601590Srgrimes *	    	  	    	keep the user informed of what's going on.
611590Srgrimes *	    	  	    	If no output is waiting, it will block for
621590Srgrimes *	    	  	    	a time given by the SEL_* constants, below,
631590Srgrimes *	    	  	    	or until output is ready.
641590Srgrimes *
651590Srgrimes *	Job_Init  	    	Called to intialize this module. in addition,
661590Srgrimes *	    	  	    	any commands attached to the .BEGIN target
671590Srgrimes *	    	  	    	are executed before this function returns.
681590Srgrimes *	    	  	    	Hence, the makefile must have been parsed
691590Srgrimes *	    	  	    	before this function is called.
701590Srgrimes *
711590Srgrimes *	Job_Full  	    	Return TRUE if the job table is filled.
721590Srgrimes *
731590Srgrimes *	Job_Empty 	    	Return TRUE if the job table is completely
741590Srgrimes *	    	  	    	empty.
751590Srgrimes *
761590Srgrimes *	Job_ParseShell	    	Given the line following a .SHELL target, parse
771590Srgrimes *	    	  	    	the line as a shell specification. Returns
781590Srgrimes *	    	  	    	FAILURE if the spec was incorrect.
791590Srgrimes *
801590Srgrimes *	Job_End	  	    	Perform any final processing which needs doing.
811590Srgrimes *	    	  	    	This includes the execution of any commands
821590Srgrimes *	    	  	    	which have been/were attached to the .END
831590Srgrimes *	    	  	    	target. It should only be called when the
841590Srgrimes *	    	  	    	job table is empty.
851590Srgrimes *
861590Srgrimes *	Job_AbortAll	    	Abort all currently running jobs. It doesn't
871590Srgrimes *	    	  	    	handle output or do anything for the jobs,
881590Srgrimes *	    	  	    	just kills them. It should only be called in
891590Srgrimes *	    	  	    	an emergency, as it were.
901590Srgrimes *
911590Srgrimes *	Job_CheckCommands   	Verify that the commands for a target are
921590Srgrimes *	    	  	    	ok. Provide them if necessary and possible.
931590Srgrimes *
941590Srgrimes *	Job_Touch 	    	Update a target without really updating it.
951590Srgrimes *
961590Srgrimes *	Job_Wait  	    	Wait for all currently-running jobs to finish.
971590Srgrimes */
981590Srgrimes
991590Srgrimes#include <sys/types.h>
1005814Sjkh#include <sys/signal.h>
1011590Srgrimes#include <sys/stat.h>
1021590Srgrimes#include <sys/file.h>
1031590Srgrimes#include <sys/time.h>
1041590Srgrimes#include <sys/wait.h>
1055814Sjkh#include <fcntl.h>
1061590Srgrimes#include <errno.h>
1071590Srgrimes#include <stdio.h>
1081590Srgrimes#include <string.h>
1095814Sjkh#include <signal.h>
1101590Srgrimes#include "make.h"
1111590Srgrimes#include "hash.h"
1121590Srgrimes#include "dir.h"
1131590Srgrimes#include "job.h"
1141590Srgrimes#include "pathnames.h"
1151590Srgrimes
1161590Srgrimesextern int  errno;
1171590Srgrimes
1181590Srgrimes/*
1198874Srgrimes * error handling variables
1201590Srgrimes */
1211590Srgrimesstatic int     	errors = 0;	    /* number of errors reported */
1221590Srgrimesstatic int    	aborting = 0;	    /* why is the make aborting? */
1231590Srgrimes#define ABORT_ERROR	1   	    /* Because of an error */
1241590Srgrimes#define ABORT_INTERRUPT	2   	    /* Because it was interrupted */
1251590Srgrimes#define ABORT_WAIT	3   	    /* Waiting for jobs to finish */
1261590Srgrimes
1271590Srgrimes
1281590Srgrimes/*
1291590Srgrimes * post-make command processing. The node postCommands is really just the
1301590Srgrimes * .END target but we keep it around to avoid having to search for it
1311590Srgrimes * all the time.
1321590Srgrimes */
1331590Srgrimesstatic GNode   	  *postCommands;    /* node containing commands to execute when
1341590Srgrimes				     * everything else is done */
1351590Srgrimesstatic int     	  numCommands; 	    /* The number of commands actually printed
1361590Srgrimes				     * for a target. Should this number be
1371590Srgrimes				     * 0, no shell will be executed. */
1381590Srgrimes
1391590Srgrimes
1401590Srgrimes/*
1411590Srgrimes * Return values from JobStart.
1421590Srgrimes */
1431590Srgrimes#define JOB_RUNNING	0   	/* Job is running */
1441590Srgrimes#define JOB_ERROR 	1   	/* Error in starting the job */
1451590Srgrimes#define JOB_FINISHED	2   	/* The job is already finished */
1461590Srgrimes#define JOB_STOPPED	3   	/* The job is stopped */
1471590Srgrimes
1481590Srgrimes/*
1491590Srgrimes * tfile is the name of a file into which all shell commands are put. It is
1501590Srgrimes * used over by removing it before the child shell is executed. The XXXXX in
1511590Srgrimes * the string are replaced by the pid of the make process in a 5-character
1528874Srgrimes * field with leading zeroes.
1531590Srgrimes */
1541590Srgrimesstatic char     tfile[] = TMPPAT;
1551590Srgrimes
1561590Srgrimes
1571590Srgrimes/*
1581590Srgrimes * Descriptions for various shells.
1591590Srgrimes */
1601590Srgrimesstatic Shell    shells[] = {
1611590Srgrimes    /*
1621590Srgrimes     * CSH description. The csh can do echo control by playing
1631590Srgrimes     * with the setting of the 'echo' shell variable. Sadly,
1641590Srgrimes     * however, it is unable to do error control nicely.
1651590Srgrimes     */
1661590Srgrimes{
1671590Srgrimes    "csh",
1681590Srgrimes    TRUE, "unset verbose", "set verbose", "unset verbose", 10,
1691590Srgrimes    FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"",
1701590Srgrimes    "v", "e",
1711590Srgrimes},
1721590Srgrimes    /*
1731590Srgrimes     * SH description. Echo control is also possible and, under
1741590Srgrimes     * sun UNIX anyway, one can even control error checking.
1751590Srgrimes     */
1761590Srgrimes{
1771590Srgrimes    "sh",
1781590Srgrimes    TRUE, "set -", "set -v", "set -", 5,
1791590Srgrimes    FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n",
1801590Srgrimes    "v", "e",
1811590Srgrimes},
1821590Srgrimes    /*
1831590Srgrimes     * UNKNOWN.
1841590Srgrimes     */
1851590Srgrimes{
1861590Srgrimes    (char *)0,
1871590Srgrimes    FALSE, (char *)0, (char *)0, (char *)0, 0,
1881590Srgrimes    FALSE, (char *)0, (char *)0,
1891590Srgrimes    (char *)0, (char *)0,
1901590Srgrimes}
1911590Srgrimes};
1921590Srgrimesstatic Shell 	*commandShell = &shells[DEFSHELL];/* this is the shell to
1931590Srgrimes						   * which we pass all
1941590Srgrimes						   * commands in the Makefile.
1951590Srgrimes						   * It is set by the
1961590Srgrimes						   * Job_ParseShell function */
1971590Srgrimesstatic char   	*shellPath = (char *) NULL,	  /* full pathname of
1981590Srgrimes						   * executable image */
1991590Srgrimes               	*shellName;	      	      	  /* last component of shell */
2001590Srgrimes
2011590Srgrimes
2021590Srgrimesstatic int  	maxJobs;    	/* The most children we can run at once */
2031590Srgrimesstatic int  	maxLocal;    	/* The most local ones we can have */
2045814Sjkhint     	nJobs;	    	/* The number of children currently running */
2055814Sjkhint  		nLocal;    	/* The number of local children */
2065814SjkhLst     	jobs;		/* The structures that describe them */
2075814SjkhBoolean		jobFull;    	/* Flag to tell when the job table is full. It
2081590Srgrimes				 * is set TRUE when (1) the total number of
2091590Srgrimes				 * running jobs equals the maximum allowed or
2101590Srgrimes				 * (2) a job can only be run locally, but
2111590Srgrimes				 * nLocal equals maxLocal */
2121590Srgrimes#ifndef RMT_WILL_WATCH
2131590Srgrimesstatic fd_set  	outputs;    	/* Set of descriptors of pipes connected to
2141590Srgrimes				 * the output channels of children */
2151590Srgrimes#endif
2161590Srgrimes
2175814SjkhGNode   	*lastNode;	/* The node for which output was most recently
2181590Srgrimes				 * produced. */
2195814Sjkhchar    	*targFmt;   	/* Format string to use to head output from a
2201590Srgrimes				 * job when it's not the most-recent job heard
2211590Srgrimes				 * from */
2221590Srgrimes#define TARG_FMT  "--- %s ---\n" /* Default format */
2231590Srgrimes
2241590Srgrimes/*
2251590Srgrimes * When JobStart attempts to run a job remotely but can't, and isn't allowed
2261590Srgrimes * to run the job locally, or when Job_CatchChildren detects a job that has
2271590Srgrimes * been migrated home, the job is placed on the stoppedJobs queue to be run
2288874Srgrimes * when the next job finishes.
2291590Srgrimes */
2305814SjkhLst		stoppedJobs;	/* Lst of Job structures describing
2311590Srgrimes				 * jobs that were stopped due to concurrency
2321590Srgrimes				 * limits or migration home */
2331590Srgrimes
2341590Srgrimes
2351590Srgrimes#if defined(USE_PGRP) && defined(SYSV)
2361590Srgrimes#define KILL(pid,sig)	killpg (-(pid),(sig))
2371590Srgrimes#else
2381590Srgrimes# if defined(USE_PGRP)
2391590Srgrimes#define KILL(pid,sig)	killpg ((pid),(sig))
2401590Srgrimes# else
2411590Srgrimes#define KILL(pid,sig)	kill ((pid),(sig))
2421590Srgrimes# endif
2431590Srgrimes#endif
2441590Srgrimes
2455814Sjkhstatic int JobCondPassSig __P((ClientData, ClientData));
2461590Srgrimesstatic void JobPassSig __P((int));
2475814Sjkhstatic int JobCmpPid __P((ClientData, ClientData));
2485814Sjkhstatic int JobPrintCommand __P((ClientData, ClientData));
2495814Sjkhstatic int JobSaveCommand __P((ClientData, ClientData));
2501590Srgrimesstatic void JobFinish __P((Job *, union wait));
2511590Srgrimesstatic void JobExec __P((Job *, char **));
2521590Srgrimesstatic void JobMakeArgv __P((Job *, char **));
2531590Srgrimesstatic void JobRestart __P((Job *));
2541590Srgrimesstatic int JobStart __P((GNode *, int, Job *));
2551590Srgrimesstatic void JobDoOutput __P((Job *, Boolean));
2561590Srgrimesstatic Shell *JobMatchShell __P((char *));
2571590Srgrimesstatic void JobInterrupt __P((int));
2581590Srgrimes
2591590Srgrimes/*-
2601590Srgrimes *-----------------------------------------------------------------------
2611590Srgrimes * JobCondPassSig --
2621590Srgrimes *	Pass a signal to a job if the job is remote or if USE_PGRP
2631590Srgrimes *	is defined.
2641590Srgrimes *
2651590Srgrimes * Results:
2661590Srgrimes *	=== 0
2671590Srgrimes *
2681590Srgrimes * Side Effects:
2691590Srgrimes *	None, except the job may bite it.
2701590Srgrimes *
2711590Srgrimes *-----------------------------------------------------------------------
2721590Srgrimes */
2731590Srgrimesstatic int
2745814SjkhJobCondPassSig(jobp, signop)
2755814Sjkh    ClientData	    	jobp;	    /* Job to biff */
2765814Sjkh    ClientData	    	signop;	    /* Signal to send it */
2771590Srgrimes{
2785814Sjkh    Job	*job = (Job *) jobp;
2795814Sjkh    int	signo = *(int *) signop;
2801590Srgrimes#ifdef RMT_WANTS_SIGNALS
2811590Srgrimes    if (job->flags & JOB_REMOTE) {
2821590Srgrimes	(void)Rmt_Signal(job, signo);
2831590Srgrimes    } else {
2841590Srgrimes	KILL(job->pid, signo);
2851590Srgrimes    }
2861590Srgrimes#else
2871590Srgrimes    /*
2881590Srgrimes     * Assume that sending the signal to job->pid will signal any remote
2891590Srgrimes     * job as well.
2901590Srgrimes     */
2911590Srgrimes    KILL(job->pid, signo);
2921590Srgrimes#endif
2931590Srgrimes    return(0);
2941590Srgrimes}
2951590Srgrimes
2961590Srgrimes/*-
2971590Srgrimes *-----------------------------------------------------------------------
2981590Srgrimes * JobPassSig --
2991590Srgrimes *	Pass a signal on to all remote jobs and to all local jobs if
3001590Srgrimes *	USE_PGRP is defined, then die ourselves.
3011590Srgrimes *
3021590Srgrimes * Results:
3031590Srgrimes *	None.
3041590Srgrimes *
3051590Srgrimes * Side Effects:
3061590Srgrimes *	We die by the same signal.
3078874Srgrimes *
3081590Srgrimes *-----------------------------------------------------------------------
3091590Srgrimes */
3101590Srgrimesstatic void
3111590SrgrimesJobPassSig(signo)
3121590Srgrimes    int	    signo;	/* The signal number we've received */
3131590Srgrimes{
3141590Srgrimes    int	    mask;
3158874Srgrimes
3165814Sjkh    Lst_ForEach(jobs, JobCondPassSig, (ClientData)(long)signo);
3171590Srgrimes
3181590Srgrimes    /*
3191590Srgrimes     * Deal with proper cleanup based on the signal received. We only run
3201590Srgrimes     * the .INTERRUPT target if the signal was in fact an interrupt. The other
3211590Srgrimes     * three termination signals are more of a "get out *now*" command.
3221590Srgrimes     */
3231590Srgrimes    if (signo == SIGINT) {
3241590Srgrimes	JobInterrupt(TRUE);
3251590Srgrimes    } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) {
3261590Srgrimes	JobInterrupt(FALSE);
3271590Srgrimes    }
3288874Srgrimes
3291590Srgrimes    /*
3301590Srgrimes     * Leave gracefully if SIGQUIT, rather than core dumping.
3311590Srgrimes     */
3321590Srgrimes    if (signo == SIGQUIT) {
3331590Srgrimes	Finish(0);
3341590Srgrimes    }
3358874Srgrimes
3361590Srgrimes    /*
3371590Srgrimes     * Send ourselves the signal now we've given the message to everyone else.
3381590Srgrimes     * Note we block everything else possible while we're getting the signal.
3391590Srgrimes     * This ensures that all our jobs get continued when we wake up before
3401590Srgrimes     * we take any other signal.
3411590Srgrimes     */
3421590Srgrimes    mask = sigblock(0);
3431590Srgrimes    (void) sigsetmask(~0 & ~(1 << (signo-1)));
3441590Srgrimes    signal(signo, SIG_DFL);
3451590Srgrimes
3461590Srgrimes    kill(getpid(), signo);
3471590Srgrimes
3485814Sjkh    signo = SIGCONT;
3495814Sjkh    Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo);
3501590Srgrimes
3511590Srgrimes    sigsetmask(mask);
3521590Srgrimes    signal(signo, JobPassSig);
3531590Srgrimes
3541590Srgrimes}
3551590Srgrimes
3561590Srgrimes/*-
3571590Srgrimes *-----------------------------------------------------------------------
3581590Srgrimes * JobCmpPid  --
3591590Srgrimes *	Compare the pid of the job with the given pid and return 0 if they
3601590Srgrimes *	are equal. This function is called from Job_CatchChildren via
3611590Srgrimes *	Lst_Find to find the job descriptor of the finished job.
3621590Srgrimes *
3631590Srgrimes * Results:
3641590Srgrimes *	0 if the pid's match
3651590Srgrimes *
3661590Srgrimes * Side Effects:
3671590Srgrimes *	None
3681590Srgrimes *-----------------------------------------------------------------------
3691590Srgrimes */
3701590Srgrimesstatic int
3711590SrgrimesJobCmpPid (job, pid)
3725814Sjkh    ClientData        job;	/* job to examine */
3735814Sjkh    ClientData        pid;	/* process id desired */
3741590Srgrimes{
3755814Sjkh    return ( *(int *) pid - ((Job *) job)->pid);
3761590Srgrimes}
3771590Srgrimes
3781590Srgrimes/*-
3791590Srgrimes *-----------------------------------------------------------------------
3801590Srgrimes * JobPrintCommand  --
3811590Srgrimes *	Put out another command for the given job. If the command starts
3821590Srgrimes *	with an @ or a - we process it specially. In the former case,
3831590Srgrimes *	so long as the -s and -n flags weren't given to make, we stick
3841590Srgrimes *	a shell-specific echoOff command in the script. In the latter,
3851590Srgrimes *	we ignore errors for the entire job, unless the shell has error
3861590Srgrimes *	control.
3871590Srgrimes *	If the command is just "..." we take all future commands for this
3881590Srgrimes *	job to be commands to be executed once the entire graph has been
3891590Srgrimes *	made and return non-zero to signal that the end of the commands
3901590Srgrimes *	was reached. These commands are later attached to the postCommands
3911590Srgrimes *	node and executed by Job_End when all things are done.
3921590Srgrimes *	This function is called from JobStart via Lst_ForEach.
3931590Srgrimes *
3941590Srgrimes * Results:
3951590Srgrimes *	Always 0, unless the command was "..."
3961590Srgrimes *
3971590Srgrimes * Side Effects:
3981590Srgrimes *	If the command begins with a '-' and the shell has no error control,
3991590Srgrimes *	the JOB_IGNERR flag is set in the job descriptor.
4001590Srgrimes *	If the command is "..." and we're not ignoring such things,
4011590Srgrimes *	tailCmds is set to the successor node of the cmd.
4021590Srgrimes *	numCommands is incremented if the command is actually printed.
4031590Srgrimes *-----------------------------------------------------------------------
4041590Srgrimes */
4051590Srgrimesstatic int
4065814SjkhJobPrintCommand (cmdp, jobp)
4075814Sjkh    ClientData    cmdp;	    	    /* command string to print */
4085814Sjkh    ClientData    jobp;	    	    /* job for which to print it */
4091590Srgrimes{
4101590Srgrimes    Boolean	  noSpecials;	    /* true if we shouldn't worry about
4111590Srgrimes				     * inserting special commands into
4121590Srgrimes				     * the input stream. */
4131590Srgrimes    Boolean       shutUp = FALSE;   /* true if we put a no echo command
4141590Srgrimes				     * into the command file */
4151590Srgrimes    Boolean	  errOff = FALSE;   /* true if we turned error checking
4161590Srgrimes				     * off before printing the command
4171590Srgrimes				     * and need to turn it back on */
4181590Srgrimes    char       	  *cmdTemplate;	    /* Template to use when printing the
4191590Srgrimes				     * command */
4201590Srgrimes    char    	  *cmdStart;	    /* Start of expanded command */
4211590Srgrimes    LstNode 	  cmdNode;  	    /* Node for replacing the command */
4225814Sjkh    char     	  *cmd = (char *) cmdp;
4238874Srgrimes    Job           *job = (Job *) jobp;
4241590Srgrimes
4251590Srgrimes    noSpecials = (noExecute && ! (job->node->type & OP_MAKE));
4261590Srgrimes
4271590Srgrimes    if (strcmp (cmd, "...") == 0) {
4288874Srgrimes	job->node->type |= OP_SAVE_CMDS;
4291590Srgrimes	if ((job->flags & JOB_IGNDOTS) == 0) {
4301590Srgrimes	    job->tailCmds = Lst_Succ (Lst_Member (job->node->commands,
4311590Srgrimes						  (ClientData)cmd));
4321590Srgrimes	    return (1);
4331590Srgrimes	}
4341590Srgrimes	return (0);
4351590Srgrimes    }
4361590Srgrimes
4371590Srgrimes#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) printf (fmt, arg); fprintf (job->cmdFILE, fmt, arg)
4381590Srgrimes
4391590Srgrimes    numCommands += 1;
4401590Srgrimes
4411590Srgrimes    /*
4421590Srgrimes     * For debugging, we replace each command with the result of expanding
4431590Srgrimes     * the variables in the command.
4441590Srgrimes     */
4451590Srgrimes    cmdNode = Lst_Member (job->node->commands, (ClientData)cmd);
4461590Srgrimes    cmdStart = cmd = Var_Subst (NULL, cmd, job->node, FALSE);
4471590Srgrimes    Lst_Replace (cmdNode, (ClientData)cmdStart);
4481590Srgrimes
4491590Srgrimes    cmdTemplate = "%s\n";
4501590Srgrimes
4511590Srgrimes    /*
4521590Srgrimes     * Check for leading @' and -'s to control echoing and error checking.
4531590Srgrimes     */
4541590Srgrimes    while (*cmd == '@' || *cmd == '-') {
4551590Srgrimes	if (*cmd == '@') {
4561590Srgrimes	    shutUp = TRUE;
4571590Srgrimes	} else {
4581590Srgrimes	    errOff = TRUE;
4591590Srgrimes	}
4601590Srgrimes	cmd++;
4611590Srgrimes    }
4621590Srgrimes
4631590Srgrimes    while (isspace((unsigned char) *cmd))
4641590Srgrimes	cmd++;
4651590Srgrimes
4661590Srgrimes    if (shutUp) {
4671590Srgrimes	if (! (job->flags & JOB_SILENT) && !noSpecials &&
4681590Srgrimes	    commandShell->hasEchoCtl) {
4691590Srgrimes		DBPRINTF ("%s\n", commandShell->echoOff);
4701590Srgrimes	} else {
4711590Srgrimes	    shutUp = FALSE;
4721590Srgrimes	}
4731590Srgrimes    }
4741590Srgrimes
4751590Srgrimes    if (errOff) {
4761590Srgrimes	if ( ! (job->flags & JOB_IGNERR) && !noSpecials) {
4771590Srgrimes	    if (commandShell->hasErrCtl) {
4781590Srgrimes		/*
4791590Srgrimes		 * we don't want the error-control commands showing
4801590Srgrimes		 * up either, so we turn off echoing while executing
4811590Srgrimes		 * them. We could put another field in the shell
4821590Srgrimes		 * structure to tell JobDoOutput to look for this
4831590Srgrimes		 * string too, but why make it any more complex than
4841590Srgrimes		 * it already is?
4851590Srgrimes		 */
4861590Srgrimes		if (! (job->flags & JOB_SILENT) && !shutUp &&
4871590Srgrimes		    commandShell->hasEchoCtl) {
4881590Srgrimes			DBPRINTF ("%s\n", commandShell->echoOff);
4891590Srgrimes			DBPRINTF ("%s\n", commandShell->ignErr);
4901590Srgrimes			DBPRINTF ("%s\n", commandShell->echoOn);
4911590Srgrimes		} else {
4921590Srgrimes		    DBPRINTF ("%s\n", commandShell->ignErr);
4931590Srgrimes		}
4941590Srgrimes	    } else if (commandShell->ignErr &&
4951590Srgrimes		       (*commandShell->ignErr != '\0'))
4961590Srgrimes	    {
4971590Srgrimes		/*
4981590Srgrimes		 * The shell has no error control, so we need to be
4991590Srgrimes		 * weird to get it to ignore any errors from the command.
5001590Srgrimes		 * If echoing is turned on, we turn it off and use the
5011590Srgrimes		 * errCheck template to echo the command. Leave echoing
5021590Srgrimes		 * off so the user doesn't see the weirdness we go through
5031590Srgrimes		 * to ignore errors. Set cmdTemplate to use the weirdness
5041590Srgrimes		 * instead of the simple "%s\n" template.
5051590Srgrimes		 */
5061590Srgrimes		if (! (job->flags & JOB_SILENT) && !shutUp &&
5071590Srgrimes		    commandShell->hasEchoCtl) {
5081590Srgrimes			DBPRINTF ("%s\n", commandShell->echoOff);
5091590Srgrimes			DBPRINTF (commandShell->errCheck, cmd);
5101590Srgrimes			shutUp = TRUE;
5111590Srgrimes		}
5121590Srgrimes		cmdTemplate = commandShell->ignErr;
5131590Srgrimes		/*
5141590Srgrimes		 * The error ignoration (hee hee) is already taken care
5151590Srgrimes		 * of by the ignErr template, so pretend error checking
5161590Srgrimes		 * is still on.
5171590Srgrimes		 */
5181590Srgrimes		errOff = FALSE;
5191590Srgrimes	    } else {
5201590Srgrimes		errOff = FALSE;
5211590Srgrimes	    }
5221590Srgrimes	} else {
5231590Srgrimes	    errOff = FALSE;
5241590Srgrimes	}
5251590Srgrimes    }
5268874Srgrimes
5271590Srgrimes    DBPRINTF (cmdTemplate, cmd);
5288874Srgrimes
5291590Srgrimes    if (errOff) {
5301590Srgrimes	/*
5311590Srgrimes	 * If echoing is already off, there's no point in issuing the
5321590Srgrimes	 * echoOff command. Otherwise we issue it and pretend it was on
5331590Srgrimes	 * for the whole command...
5341590Srgrimes	 */
5351590Srgrimes	if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){
5361590Srgrimes	    DBPRINTF ("%s\n", commandShell->echoOff);
5371590Srgrimes	    shutUp = TRUE;
5381590Srgrimes	}
5391590Srgrimes	DBPRINTF ("%s\n", commandShell->errCheck);
5401590Srgrimes    }
5411590Srgrimes    if (shutUp) {
5421590Srgrimes	DBPRINTF ("%s\n", commandShell->echoOn);
5431590Srgrimes    }
5441590Srgrimes    return (0);
5451590Srgrimes}
5461590Srgrimes
5471590Srgrimes/*-
5481590Srgrimes *-----------------------------------------------------------------------
5491590Srgrimes * JobSaveCommand --
5501590Srgrimes *	Save a command to be executed when everything else is done.
5511590Srgrimes *	Callback function for JobFinish...
5521590Srgrimes *
5531590Srgrimes * Results:
5541590Srgrimes *	Always returns 0
5551590Srgrimes *
5561590Srgrimes * Side Effects:
5571590Srgrimes *	The command is tacked onto the end of postCommands's commands list.
5581590Srgrimes *
5591590Srgrimes *-----------------------------------------------------------------------
5601590Srgrimes */
5611590Srgrimesstatic int
5621590SrgrimesJobSaveCommand (cmd, gn)
5635814Sjkh    ClientData   cmd;
5645814Sjkh    ClientData   gn;
5651590Srgrimes{
5665814Sjkh    cmd = (ClientData) Var_Subst (NULL, (char *) cmd, (GNode *) gn, FALSE);
5675814Sjkh    (void)Lst_AtEnd (postCommands->commands, cmd);
5681590Srgrimes    return (0);
5691590Srgrimes}
5701590Srgrimes
5711590Srgrimes/*-
5721590Srgrimes *-----------------------------------------------------------------------
5731590Srgrimes * JobFinish  --
5741590Srgrimes *	Do final processing for the given job including updating
5751590Srgrimes *	parents and starting new jobs as available/necessary. Note
5761590Srgrimes *	that we pay no attention to the JOB_IGNERR flag here.
5771590Srgrimes *	This is because when we're called because of a noexecute flag
5781590Srgrimes *	or something, jstat.w_status is 0 and when called from
5791590Srgrimes *	Job_CatchChildren, the status is zeroed if it s/b ignored.
5801590Srgrimes *
5811590Srgrimes * Results:
5821590Srgrimes *	None
5831590Srgrimes *
5841590Srgrimes * Side Effects:
5851590Srgrimes *	Some nodes may be put on the toBeMade queue.
5861590Srgrimes *	Final commands for the job are placed on postCommands.
5871590Srgrimes *
5881590Srgrimes *	If we got an error and are aborting (aborting == ABORT_ERROR) and
5891590Srgrimes *	the job list is now empty, we are done for the day.
5901590Srgrimes *	If we recognized an error (errors !=0), we set the aborting flag
5911590Srgrimes *	to ABORT_ERROR so no more jobs will be started.
5921590Srgrimes *-----------------------------------------------------------------------
5931590Srgrimes */
5941590Srgrimes/*ARGSUSED*/
5951590Srgrimesstatic void
5961590SrgrimesJobFinish (job, status)
5971590Srgrimes    Job           *job;	      	  /* job to finish */
5981590Srgrimes    union wait	  status;     	  /* sub-why job went away */
5991590Srgrimes{
6001590Srgrimes    Boolean 	  done;
6011590Srgrimes
6021590Srgrimes    if ((WIFEXITED(status) &&
6031590Srgrimes	  (((status.w_retcode != 0) && !(job->flags & JOB_IGNERR)))) ||
6041590Srgrimes	(WIFSIGNALED(status) && (status.w_termsig != SIGCONT)))
6051590Srgrimes    {
6061590Srgrimes	/*
6071590Srgrimes	 * If it exited non-zero and either we're doing things our
6081590Srgrimes	 * way or we're not ignoring errors, the job is finished.
6091590Srgrimes	 * Similarly, if the shell died because of a signal
6101590Srgrimes	 * the job is also finished. In these
6111590Srgrimes	 * cases, finish out the job's output before printing the exit
6121590Srgrimes	 * status...
6131590Srgrimes	 */
6141590Srgrimes	if (usePipes) {
6151590Srgrimes#ifdef RMT_WILL_WATCH
6161590Srgrimes	    Rmt_Ignore(job->inPipe);
6171590Srgrimes#else
6181590Srgrimes	    FD_CLR(job->inPipe, &outputs);
6191590Srgrimes#endif /* RMT_WILL_WATCH */
6201590Srgrimes	    if (job->outPipe != job->inPipe) {
6211590Srgrimes		(void)close (job->outPipe);
6221590Srgrimes	    }
6231590Srgrimes	    JobDoOutput (job, TRUE);
6241590Srgrimes	    (void)close (job->inPipe);
6251590Srgrimes	} else {
6261590Srgrimes	    (void)close (job->outFd);
6271590Srgrimes	    JobDoOutput (job, TRUE);
6281590Srgrimes	}
6291590Srgrimes
6301590Srgrimes	if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
6311590Srgrimes	    fclose(job->cmdFILE);
6321590Srgrimes	}
6331590Srgrimes	done = TRUE;
6341590Srgrimes    } else if (WIFEXITED(status) && status.w_retcode != 0) {
6351590Srgrimes	/*
6361590Srgrimes	 * Deal with ignored errors in -B mode. We need to print a message
6371590Srgrimes	 * telling of the ignored error as well as setting status.w_status
6381590Srgrimes	 * to 0 so the next command gets run. To do this, we set done to be
6391590Srgrimes	 * TRUE if in -B mode and the job exited non-zero. Note we don't
6401590Srgrimes	 * want to close down any of the streams until we know we're at the
6411590Srgrimes	 * end.
6421590Srgrimes	 */
6431590Srgrimes	done = TRUE;
6441590Srgrimes    } else {
6451590Srgrimes	/*
6461590Srgrimes	 * No need to close things down or anything.
6471590Srgrimes	 */
6481590Srgrimes	done = FALSE;
6491590Srgrimes    }
6508874Srgrimes
6511590Srgrimes    if (done ||
6521590Srgrimes	WIFSTOPPED(status) ||
6531590Srgrimes	(WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) ||
6541590Srgrimes	DEBUG(JOB))
6551590Srgrimes    {
6561590Srgrimes	FILE	  *out;
6578874Srgrimes
6581590Srgrimes	if (!usePipes && (job->flags & JOB_IGNERR)) {
6591590Srgrimes	    /*
6601590Srgrimes	     * If output is going to a file and this job is ignoring
6611590Srgrimes	     * errors, arrange to have the exit status sent to the
6621590Srgrimes	     * output file as well.
6631590Srgrimes	     */
6641590Srgrimes	    out = fdopen (job->outFd, "w");
6651590Srgrimes	} else {
6661590Srgrimes	    out = stdout;
6671590Srgrimes	}
6681590Srgrimes
6691590Srgrimes	if (WIFEXITED(status)) {
6701590Srgrimes	    if (status.w_retcode != 0) {
6711590Srgrimes		if (usePipes && job->node != lastNode) {
6721590Srgrimes		    fprintf (out, targFmt, job->node->name);
6731590Srgrimes		    lastNode = job->node;
6741590Srgrimes		}
6751590Srgrimes		fprintf (out, "*** Error code %d%s\n", status.w_retcode,
6761590Srgrimes			 (job->flags & JOB_IGNERR) ? " (ignored)" : "");
6771590Srgrimes
6781590Srgrimes		if (job->flags & JOB_IGNERR) {
6791590Srgrimes		    status.w_status = 0;
6801590Srgrimes		}
6811590Srgrimes	    } else if (DEBUG(JOB)) {
6821590Srgrimes		if (usePipes && job->node != lastNode) {
6831590Srgrimes		    fprintf (out, targFmt, job->node->name);
6841590Srgrimes		    lastNode = job->node;
6851590Srgrimes		}
6861590Srgrimes		fprintf (out, "*** Completed successfully\n");
6871590Srgrimes	    }
6881590Srgrimes	} else if (WIFSTOPPED(status)) {
6891590Srgrimes	    if (usePipes && job->node != lastNode) {
6901590Srgrimes		fprintf (out, targFmt, job->node->name);
6911590Srgrimes		lastNode = job->node;
6921590Srgrimes	    }
6931590Srgrimes	    if (! (job->flags & JOB_REMIGRATE)) {
6941590Srgrimes		fprintf (out, "*** Stopped -- signal %d\n", status.w_stopsig);
6951590Srgrimes	    }
6961590Srgrimes	    job->flags |= JOB_RESUME;
6971590Srgrimes	    (void)Lst_AtEnd(stoppedJobs, (ClientData)job);
6981590Srgrimes	    fflush(out);
6991590Srgrimes	    return;
7001590Srgrimes	} else if (status.w_termsig == SIGCONT) {
7011590Srgrimes	    /*
7021590Srgrimes	     * If the beastie has continued, shift the Job from the stopped
7031590Srgrimes	     * list to the running one (or re-stop it if concurrency is
7041590Srgrimes	     * exceeded) and go and get another child.
7051590Srgrimes	     */
7061590Srgrimes	    if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) {
7071590Srgrimes		if (usePipes && job->node != lastNode) {
7081590Srgrimes		    fprintf (out, targFmt, job->node->name);
7091590Srgrimes		    lastNode = job->node;
7101590Srgrimes		}
7111590Srgrimes		fprintf (out, "*** Continued\n");
7121590Srgrimes	    }
7131590Srgrimes	    if (! (job->flags & JOB_CONTINUING)) {
7141590Srgrimes		JobRestart(job);
7151590Srgrimes	    } else {
7161590Srgrimes		Lst_AtEnd(jobs, (ClientData)job);
7171590Srgrimes		nJobs += 1;
7181590Srgrimes		if (! (job->flags & JOB_REMOTE)) {
7191590Srgrimes		    nLocal += 1;
7201590Srgrimes		}
7211590Srgrimes		if (nJobs == maxJobs) {
7221590Srgrimes		    jobFull = TRUE;
7231590Srgrimes		    if (DEBUG(JOB)) {
7241590Srgrimes			printf("Job queue is full.\n");
7251590Srgrimes		    }
7261590Srgrimes		}
7271590Srgrimes	    }
7281590Srgrimes	    fflush(out);
7291590Srgrimes	    return;
7301590Srgrimes	} else {
7311590Srgrimes	    if (usePipes && job->node != lastNode) {
7321590Srgrimes		fprintf (out, targFmt, job->node->name);
7331590Srgrimes		lastNode = job->node;
7341590Srgrimes	    }
7351590Srgrimes	    fprintf (out, "*** Signal %d\n", status.w_termsig);
7361590Srgrimes	}
7371590Srgrimes
7381590Srgrimes	fflush (out);
7391590Srgrimes    }
7401590Srgrimes
7411590Srgrimes    /*
7421590Srgrimes     * Now handle the -B-mode stuff. If the beast still isn't finished,
7431590Srgrimes     * try and restart the job on the next command. If JobStart says it's
7441590Srgrimes     * ok, it's ok. If there's an error, this puppy is done.
7451590Srgrimes     */
7461590Srgrimes    if ((status.w_status == 0) &&
7471590Srgrimes	!Lst_IsAtEnd (job->node->commands))
7481590Srgrimes    {
7491590Srgrimes	switch (JobStart (job->node,
7501590Srgrimes			  job->flags & JOB_IGNDOTS,
7511590Srgrimes			  job))
7521590Srgrimes	{
7531590Srgrimes	    case JOB_RUNNING:
7541590Srgrimes		done = FALSE;
7551590Srgrimes		break;
7561590Srgrimes	    case JOB_ERROR:
7571590Srgrimes		done = TRUE;
7581590Srgrimes		status.w_retcode = 1;
7591590Srgrimes		break;
7601590Srgrimes	    case JOB_FINISHED:
7611590Srgrimes		/*
7621590Srgrimes		 * If we got back a JOB_FINISHED code, JobStart has already
7631590Srgrimes		 * called Make_Update and freed the job descriptor. We set
7641590Srgrimes		 * done to false here to avoid fake cycles and double frees.
7651590Srgrimes		 * JobStart needs to do the update so we can proceed up the
7661590Srgrimes		 * graph when given the -n flag..
7671590Srgrimes		 */
7681590Srgrimes		done = FALSE;
7691590Srgrimes		break;
7701590Srgrimes	}
7711590Srgrimes    } else {
7721590Srgrimes	done = TRUE;
7731590Srgrimes    }
7741590Srgrimes
7758874Srgrimes
7761590Srgrimes    if (done &&
7771590Srgrimes	(aborting != ABORT_ERROR) &&
7781590Srgrimes	(aborting != ABORT_INTERRUPT) &&
7791590Srgrimes	(status.w_status == 0))
7801590Srgrimes    {
7811590Srgrimes	/*
7821590Srgrimes	 * As long as we aren't aborting and the job didn't return a non-zero
7831590Srgrimes	 * status that we shouldn't ignore, we call Make_Update to update
7841590Srgrimes	 * the parents. In addition, any saved commands for the node are placed
7851590Srgrimes	 * on the .END target.
7861590Srgrimes	 */
7871590Srgrimes	if (job->tailCmds != NILLNODE) {
7881590Srgrimes	    Lst_ForEachFrom (job->node->commands, job->tailCmds,
7891590Srgrimes			     JobSaveCommand,
7901590Srgrimes			     (ClientData)job->node);
7911590Srgrimes	}
7921590Srgrimes	job->node->made = MADE;
7931590Srgrimes	Make_Update (job->node);
7941590Srgrimes	free((Address)job);
7951590Srgrimes    } else if (status.w_status) {
7961590Srgrimes	errors += 1;
7971590Srgrimes	free((Address)job);
7981590Srgrimes    }
7991590Srgrimes
8001590Srgrimes    while (!errors && !jobFull && !Lst_IsEmpty(stoppedJobs)) {
8011590Srgrimes	JobRestart((Job *)Lst_DeQueue(stoppedJobs));
8021590Srgrimes    }
8031590Srgrimes
8041590Srgrimes    /*
8051590Srgrimes     * Set aborting if any error.
8061590Srgrimes     */
8071590Srgrimes    if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) {
8081590Srgrimes	/*
8091590Srgrimes	 * If we found any errors in this batch of children and the -k flag
8101590Srgrimes	 * wasn't given, we set the aborting flag so no more jobs get
8111590Srgrimes	 * started.
8121590Srgrimes	 */
8131590Srgrimes	aborting = ABORT_ERROR;
8141590Srgrimes    }
8158874Srgrimes
8161590Srgrimes    if ((aborting == ABORT_ERROR) && Job_Empty()) {
8171590Srgrimes	/*
8181590Srgrimes	 * If we are aborting and the job table is now empty, we finish.
8191590Srgrimes	 */
8201590Srgrimes	(void) unlink (tfile);
8211590Srgrimes	Finish (errors);
8221590Srgrimes    }
8231590Srgrimes}
8241590Srgrimes
8251590Srgrimes/*-
8261590Srgrimes *-----------------------------------------------------------------------
8271590Srgrimes * Job_Touch --
8281590Srgrimes *	Touch the given target. Called by JobStart when the -t flag was
8291590Srgrimes *	given
8301590Srgrimes *
8311590Srgrimes * Results:
8321590Srgrimes *	None
8331590Srgrimes *
8341590Srgrimes * Side Effects:
8351590Srgrimes *	The data modification of the file is changed. In addition, if the
8361590Srgrimes *	file did not exist, it is created.
8371590Srgrimes *-----------------------------------------------------------------------
8381590Srgrimes */
8391590Srgrimesvoid
8401590SrgrimesJob_Touch (gn, silent)
8411590Srgrimes    GNode         *gn;	      	/* the node of the file to touch */
8421590Srgrimes    Boolean 	  silent;   	/* TRUE if should not print messages */
8431590Srgrimes{
8441590Srgrimes    int		  streamID;   	/* ID of stream opened to do the touch */
8451590Srgrimes    struct timeval times[2];	/* Times for utimes() call */
8461590Srgrimes
8471590Srgrimes    if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) {
8481590Srgrimes	/*
8491590Srgrimes	 * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets
8501590Srgrimes	 * and, as such, shouldn't really be created.
8511590Srgrimes	 */
8521590Srgrimes	return;
8531590Srgrimes    }
8548874Srgrimes
8551590Srgrimes    if (!silent) {
8561590Srgrimes	printf ("touch %s\n", gn->name);
8571590Srgrimes    }
8581590Srgrimes
8591590Srgrimes    if (noExecute) {
8601590Srgrimes	return;
8611590Srgrimes    }
8621590Srgrimes
8631590Srgrimes    if (gn->type & OP_ARCHV) {
8641590Srgrimes	Arch_Touch (gn);
8651590Srgrimes    } else if (gn->type & OP_LIB) {
8661590Srgrimes	Arch_TouchLib (gn);
8671590Srgrimes    } else {
8681590Srgrimes	char	*file = gn->path ? gn->path : gn->name;
8691590Srgrimes
8701590Srgrimes	times[0].tv_sec = times[1].tv_sec = now;
8711590Srgrimes	times[0].tv_usec = times[1].tv_usec = 0;
8721590Srgrimes	if (utimes(file, times) < 0){
8731590Srgrimes	    streamID = open (file, O_RDWR | O_CREAT, 0666);
8741590Srgrimes
8751590Srgrimes	    if (streamID >= 0) {
8761590Srgrimes		char	c;
8771590Srgrimes
8781590Srgrimes		/*
8791590Srgrimes		 * Read and write a byte to the file to change the
8801590Srgrimes		 * modification time, then close the file.
8811590Srgrimes		 */
8821590Srgrimes		if (read(streamID, &c, 1) == 1) {
8831590Srgrimes		    lseek(streamID, 0L, L_SET);
8841590Srgrimes		    write(streamID, &c, 1);
8851590Srgrimes		}
8868874Srgrimes
8871590Srgrimes		(void)close (streamID);
8881590Srgrimes	    } else
8891590Srgrimes		printf("*** couldn't touch %s: %s", file, strerror(errno));
8901590Srgrimes	}
8911590Srgrimes    }
8921590Srgrimes}
8931590Srgrimes
8941590Srgrimes/*-
8951590Srgrimes *-----------------------------------------------------------------------
8961590Srgrimes * Job_CheckCommands --
8978874Srgrimes *	Make sure the given node has all the commands it needs.
8981590Srgrimes *
8991590Srgrimes * Results:
9001590Srgrimes *	TRUE if the commands list is/was ok.
9011590Srgrimes *
9021590Srgrimes * Side Effects:
9031590Srgrimes *	The node will have commands from the .DEFAULT rule added to it
9041590Srgrimes *	if it needs them.
9051590Srgrimes *-----------------------------------------------------------------------
9061590Srgrimes */
9071590SrgrimesBoolean
9081590SrgrimesJob_CheckCommands (gn, abortProc)
9091590Srgrimes    GNode          *gn;	    	    /* The target whose commands need
9101590Srgrimes				     * verifying */
9118874Srgrimes    void    	  (*abortProc) __P((char *, ...));
9121590Srgrimes			/* Function to abort with message */
9131590Srgrimes{
9141590Srgrimes    if (OP_NOP(gn->type) && Lst_IsEmpty (gn->commands) &&
9151590Srgrimes	(gn->type & OP_LIB) == 0) {
9161590Srgrimes	/*
9171590Srgrimes	 * No commands. Look for .DEFAULT rule from which we might infer
9188874Srgrimes	 * commands
9191590Srgrimes	 */
9201590Srgrimes	if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands)) {
9215814Sjkh	    char *p1;
9221590Srgrimes	    /*
9231590Srgrimes	     * Make only looks for a .DEFAULT if the node was never the
9241590Srgrimes	     * target of an operator, so that's what we do too. If
9251590Srgrimes	     * a .DEFAULT was given, we substitute its commands for gn's
9261590Srgrimes	     * commands and set the IMPSRC variable to be the target's name
9271590Srgrimes	     * The DEFAULT node acts like a transformation rule, in that
9281590Srgrimes	     * gn also inherits any attributes or sources attached to
9291590Srgrimes	     * .DEFAULT itself.
9301590Srgrimes	     */
9311590Srgrimes	    Make_HandleUse(DEFAULT, gn);
9325814Sjkh	    Var_Set (IMPSRC, Var_Value (TARGET, gn, &p1), gn);
9335814Sjkh	    if (p1)
9345814Sjkh		free(p1);
9351590Srgrimes	} else if (Dir_MTime (gn) == 0) {
9361590Srgrimes	    /*
9371590Srgrimes	     * The node wasn't the target of an operator we have no .DEFAULT
9381590Srgrimes	     * rule to go on and the target doesn't already exist. There's
9391590Srgrimes	     * nothing more we can do for this branch. If the -k flag wasn't
9401590Srgrimes	     * given, we stop in our tracks, otherwise we just don't update
9418874Srgrimes	     * this node's parents so they never get examined.
9421590Srgrimes	     */
9431590Srgrimes	    if (gn->type & OP_OPTIONAL) {
9441590Srgrimes		printf ("make: don't know how to make %s (ignored)\n",
9451590Srgrimes			gn->name);
9461590Srgrimes	    } else if (keepgoing) {
9471590Srgrimes		printf ("make: don't know how to make %s (continuing)\n",
9481590Srgrimes			gn->name);
9491590Srgrimes		return (FALSE);
9501590Srgrimes	    } else {
9511590Srgrimes		(*abortProc) ("make: don't know how to make %s. Stop",
9521590Srgrimes			     gn->name);
9531590Srgrimes		return(FALSE);
9541590Srgrimes	    }
9551590Srgrimes	}
9561590Srgrimes    }
9571590Srgrimes    return (TRUE);
9581590Srgrimes}
9591590Srgrimes#ifdef RMT_WILL_WATCH
9601590Srgrimes/*-
9611590Srgrimes *-----------------------------------------------------------------------
9621590Srgrimes * JobLocalInput --
9631590Srgrimes *	Handle a pipe becoming readable. Callback function for Rmt_Watch
9641590Srgrimes *
9651590Srgrimes * Results:
9661590Srgrimes *	None
9671590Srgrimes *
9681590Srgrimes * Side Effects:
9691590Srgrimes *	JobDoOutput is called.
9708874Srgrimes *
9711590Srgrimes *-----------------------------------------------------------------------
9721590Srgrimes */
9731590Srgrimes/*ARGSUSED*/
9741590Srgrimesstatic void
9751590SrgrimesJobLocalInput(stream, job)
9761590Srgrimes    int	    stream; 	/* Stream that's ready (ignored) */
9771590Srgrimes    Job	    *job;   	/* Job to which the stream belongs */
9781590Srgrimes{
9791590Srgrimes    JobDoOutput(job, FALSE);
9801590Srgrimes}
9811590Srgrimes#endif /* RMT_WILL_WATCH */
9821590Srgrimes
9831590Srgrimes/*-
9841590Srgrimes *-----------------------------------------------------------------------
9851590Srgrimes * JobExec --
9861590Srgrimes *	Execute the shell for the given job. Called from JobStart and
9871590Srgrimes *	JobRestart.
9881590Srgrimes *
9891590Srgrimes * Results:
9901590Srgrimes *	None.
9911590Srgrimes *
9921590Srgrimes * Side Effects:
9931590Srgrimes *	A shell is executed, outputs is altered and the Job structure added
9941590Srgrimes *	to the job table.
9951590Srgrimes *
9961590Srgrimes *-----------------------------------------------------------------------
9971590Srgrimes */
9981590Srgrimesstatic void
9991590SrgrimesJobExec(job, argv)
10001590Srgrimes    Job	    	  *job; 	/* Job to execute */
10011590Srgrimes    char    	  **argv;
10021590Srgrimes{
10031590Srgrimes    int	    	  cpid;	    	/* ID of new child */
10048874Srgrimes
10051590Srgrimes    if (DEBUG(JOB)) {
10061590Srgrimes	int 	  i;
10078874Srgrimes
10081590Srgrimes	printf("Running %s %sly\n", job->node->name,
10091590Srgrimes	       job->flags&JOB_REMOTE?"remote":"local");
10101590Srgrimes	printf("\tCommand: ");
10111590Srgrimes	for (i = 0; argv[i] != (char *)NULL; i++) {
10121590Srgrimes	    printf("%s ", argv[i]);
10131590Srgrimes	}
10141590Srgrimes	printf("\n");
10151590Srgrimes    }
10168874Srgrimes
10171590Srgrimes    /*
10181590Srgrimes     * Some jobs produce no output and it's disconcerting to have
10191590Srgrimes     * no feedback of their running (since they produce no output, the
10201590Srgrimes     * banner with their name in it never appears). This is an attempt to
10211590Srgrimes     * provide that feedback, even if nothing follows it.
10221590Srgrimes     */
10231590Srgrimes    if ((lastNode != job->node) && (job->flags & JOB_FIRST) &&
10241590Srgrimes	!(job->flags & JOB_SILENT))
10251590Srgrimes    {
10261590Srgrimes	printf(targFmt, job->node->name);
10271590Srgrimes	lastNode = job->node;
10281590Srgrimes    }
10298874Srgrimes
10301590Srgrimes#ifdef RMT_NO_EXEC
10311590Srgrimes    if (job->flags & JOB_REMOTE) {
10321590Srgrimes	goto jobExecFinish;
10331590Srgrimes    }
10341590Srgrimes#endif /* RMT_NO_EXEC */
10351590Srgrimes
10361590Srgrimes    if ((cpid =  vfork()) == -1) {
10371590Srgrimes	Punt ("Cannot fork");
10381590Srgrimes    } else if (cpid == 0) {
10391590Srgrimes
10401590Srgrimes	/*
10411590Srgrimes	 * Must duplicate the input stream down to the child's input and
10421590Srgrimes	 * reset it to the beginning (again). Since the stream was marked
10431590Srgrimes	 * close-on-exec, we must clear that bit in the new input.
10441590Srgrimes	 */
10451590Srgrimes	(void) dup2(fileno(job->cmdFILE), 0);
10461590Srgrimes	fcntl(0, F_SETFD, 0);
10471590Srgrimes	lseek(0, 0, L_SET);
10488874Srgrimes
10491590Srgrimes	if (usePipes) {
10501590Srgrimes	    /*
10511590Srgrimes	     * Set up the child's output to be routed through the pipe
10521590Srgrimes	     * we've created for it.
10531590Srgrimes	     */
10541590Srgrimes	    (void) dup2 (job->outPipe, 1);
10551590Srgrimes	} else {
10561590Srgrimes	    /*
10571590Srgrimes	     * We're capturing output in a file, so we duplicate the
10581590Srgrimes	     * descriptor to the temporary file into the standard
10591590Srgrimes	     * output.
10601590Srgrimes	     */
10611590Srgrimes	    (void) dup2 (job->outFd, 1);
10621590Srgrimes	}
10631590Srgrimes	/*
10641590Srgrimes	 * The output channels are marked close on exec. This bit was
10651590Srgrimes	 * duplicated by the dup2 (on some systems), so we have to clear
10661590Srgrimes	 * it before routing the shell's error output to the same place as
10671590Srgrimes	 * its standard output.
10681590Srgrimes	 */
10691590Srgrimes	fcntl(1, F_SETFD, 0);
10701590Srgrimes	(void) dup2 (1, 2);
10711590Srgrimes
10721590Srgrimes#ifdef USE_PGRP
10731590Srgrimes	/*
10741590Srgrimes	 * We want to switch the child into a different process family so
10751590Srgrimes	 * we can kill it and all its descendants in one fell swoop,
10761590Srgrimes	 * by killing its process family, but not commit suicide.
10771590Srgrimes	 */
10788874Srgrimes
10791590Srgrimes	(void) setpgrp(0, getpid());
10801590Srgrimes#endif USE_PGRP
10811590Srgrimes
10821590Srgrimes	(void) execv (shellPath, argv);
10831590Srgrimes	(void) write (2, "Could not execute shell\n",
10841590Srgrimes		 sizeof ("Could not execute shell"));
10851590Srgrimes	_exit (1);
10861590Srgrimes    } else {
10871590Srgrimes	job->pid = cpid;
10881590Srgrimes
10891590Srgrimes	if (usePipes && (job->flags & JOB_FIRST) ) {
10901590Srgrimes	    /*
10911590Srgrimes	     * The first time a job is run for a node, we set the current
10921590Srgrimes	     * position in the buffer to the beginning and mark another
10931590Srgrimes	     * stream to watch in the outputs mask
10941590Srgrimes	     */
10951590Srgrimes	    job->curPos = 0;
10968874Srgrimes
10971590Srgrimes#ifdef RMT_WILL_WATCH
10981590Srgrimes	    Rmt_Watch(job->inPipe, JobLocalInput, job);
10991590Srgrimes#else
11001590Srgrimes	    FD_SET(job->inPipe, &outputs);
11011590Srgrimes#endif /* RMT_WILL_WATCH */
11021590Srgrimes	}
11031590Srgrimes
11041590Srgrimes	if (job->flags & JOB_REMOTE) {
11051590Srgrimes	    job->rmtID = 0;
11061590Srgrimes	} else {
11071590Srgrimes	    nLocal += 1;
11081590Srgrimes	    /*
11091590Srgrimes	     * XXX: Used to not happen if CUSTOMS. Why?
11101590Srgrimes	     */
11111590Srgrimes	    if (job->cmdFILE != stdout) {
11121590Srgrimes		fclose(job->cmdFILE);
11131590Srgrimes		job->cmdFILE = NULL;
11141590Srgrimes	    }
11151590Srgrimes	}
11161590Srgrimes    }
11171590Srgrimes
11181590Srgrimes#ifdef RMT_NO_EXEC
11198874SrgrimesjobExecFinish:
11201590Srgrimes#endif
11211590Srgrimes    /*
11221590Srgrimes     * Now the job is actually running, add it to the table.
11231590Srgrimes     */
11241590Srgrimes    nJobs += 1;
11251590Srgrimes    (void)Lst_AtEnd (jobs, (ClientData)job);
11261590Srgrimes    if (nJobs == maxJobs) {
11271590Srgrimes	jobFull = TRUE;
11281590Srgrimes    }
11291590Srgrimes}
11301590Srgrimes
11311590Srgrimes/*-
11321590Srgrimes *-----------------------------------------------------------------------
11331590Srgrimes * JobMakeArgv --
11341590Srgrimes *	Create the argv needed to execute the shell for a given job.
11351590Srgrimes *
11368874Srgrimes *
11371590Srgrimes * Results:
11381590Srgrimes *
11391590Srgrimes * Side Effects:
11401590Srgrimes *
11411590Srgrimes *-----------------------------------------------------------------------
11421590Srgrimes */
11431590Srgrimesstatic void
11441590SrgrimesJobMakeArgv(job, argv)
11451590Srgrimes    Job	    	  *job;
11461590Srgrimes    char	  **argv;
11471590Srgrimes{
11481590Srgrimes    int	    	  argc;
11491590Srgrimes    static char	  args[10]; 	/* For merged arguments */
11508874Srgrimes
11511590Srgrimes    argv[0] = shellName;
11521590Srgrimes    argc = 1;
11531590Srgrimes
11541590Srgrimes    if ((commandShell->exit && (*commandShell->exit != '-')) ||
11551590Srgrimes	(commandShell->echo && (*commandShell->echo != '-')))
11561590Srgrimes    {
11571590Srgrimes	/*
11581590Srgrimes	 * At least one of the flags doesn't have a minus before it, so
11591590Srgrimes	 * merge them together. Have to do this because the *(&(@*#*&#$#
11601590Srgrimes	 * Bourne shell thinks its second argument is a file to source.
11611590Srgrimes	 * Grrrr. Note the ten-character limitation on the combined arguments.
11621590Srgrimes	 */
11631590Srgrimes	(void)sprintf(args, "-%s%s",
11641590Srgrimes		      ((job->flags & JOB_IGNERR) ? "" :
11651590Srgrimes		       (commandShell->exit ? commandShell->exit : "")),
11661590Srgrimes		      ((job->flags & JOB_SILENT) ? "" :
11671590Srgrimes		       (commandShell->echo ? commandShell->echo : "")));
11681590Srgrimes
11691590Srgrimes	if (args[1]) {
11701590Srgrimes	    argv[argc] = args;
11711590Srgrimes	    argc++;
11721590Srgrimes	}
11731590Srgrimes    } else {
11741590Srgrimes	if (!(job->flags & JOB_IGNERR) && commandShell->exit) {
11751590Srgrimes	    argv[argc] = commandShell->exit;
11761590Srgrimes	    argc++;
11771590Srgrimes	}
11781590Srgrimes	if (!(job->flags & JOB_SILENT) && commandShell->echo) {
11791590Srgrimes	    argv[argc] = commandShell->echo;
11801590Srgrimes	    argc++;
11811590Srgrimes	}
11821590Srgrimes    }
11831590Srgrimes    argv[argc] = (char *)NULL;
11841590Srgrimes}
11851590Srgrimes
11861590Srgrimes/*-
11871590Srgrimes *-----------------------------------------------------------------------
11881590Srgrimes * JobRestart --
11898874Srgrimes *	Restart a job that stopped for some reason.
11901590Srgrimes *
11911590Srgrimes * Results:
11921590Srgrimes *	None.
11931590Srgrimes *
11941590Srgrimes * Side Effects:
11951590Srgrimes *	jobFull will be set if the job couldn't be run.
11961590Srgrimes *
11971590Srgrimes *-----------------------------------------------------------------------
11981590Srgrimes */
11991590Srgrimesstatic void
12001590SrgrimesJobRestart(job)
12011590Srgrimes    Job 	  *job;    	/* Job to restart */
12021590Srgrimes{
12031590Srgrimes    if (job->flags & JOB_REMIGRATE) {
12041590Srgrimes	if (DEBUG(JOB)) {
12051590Srgrimes	    printf("Remigrating %x\n", job->pid);
12061590Srgrimes	}
12071590Srgrimes	if (nLocal != maxLocal) {
12081590Srgrimes		/*
12091590Srgrimes		 * Job cannot be remigrated, but there's room on the local
12101590Srgrimes		 * machine, so resume the job and note that another
12111590Srgrimes		 * local job has started.
12121590Srgrimes		 */
12131590Srgrimes		if (DEBUG(JOB)) {
12141590Srgrimes		    printf("resuming on local machine\n");
12151590Srgrimes	        }
12161590Srgrimes		KILL(job->pid, SIGCONT);
12171590Srgrimes		nLocal +=1;
12181590Srgrimes		job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);
12191590Srgrimes	} else {
12201590Srgrimes		/*
12211590Srgrimes		 * Job cannot be restarted. Mark the table as full and
12221590Srgrimes		 * place the job back on the list of stopped jobs.
12231590Srgrimes		 */
12241590Srgrimes		if (DEBUG(JOB)) {
12251590Srgrimes		    printf("holding\n");
12261590Srgrimes		}
12271590Srgrimes		(void)Lst_AtFront(stoppedJobs, (ClientData)job);
12281590Srgrimes		jobFull = TRUE;
12291590Srgrimes		if (DEBUG(JOB)) {
12301590Srgrimes		    printf("Job queue is full.\n");
12311590Srgrimes		}
12321590Srgrimes		return;
12331590Srgrimes	}
12348874Srgrimes
12351590Srgrimes	(void)Lst_AtEnd(jobs, (ClientData)job);
12361590Srgrimes	nJobs += 1;
12371590Srgrimes	if (nJobs == maxJobs) {
12381590Srgrimes	    jobFull = TRUE;
12391590Srgrimes	    if (DEBUG(JOB)) {
12401590Srgrimes		printf("Job queue is full.\n");
12411590Srgrimes	    }
12421590Srgrimes	}
12431590Srgrimes    } else if (job->flags & JOB_RESTART) {
12441590Srgrimes	/*
12451590Srgrimes	 * Set up the control arguments to the shell. This is based on the
12461590Srgrimes	 * flags set earlier for this job. If the JOB_IGNERR flag is clear,
12471590Srgrimes	 * the 'exit' flag of the commandShell is used to cause it to exit
12481590Srgrimes	 * upon receiving an error. If the JOB_SILENT flag is clear, the
12491590Srgrimes	 * 'echo' flag of the commandShell is used to get it to start echoing
12508874Srgrimes	 * as soon as it starts processing commands.
12511590Srgrimes	 */
12521590Srgrimes	char	  *argv[4];
12538874Srgrimes
12541590Srgrimes	JobMakeArgv(job, argv);
12558874Srgrimes
12561590Srgrimes	if (DEBUG(JOB)) {
12571590Srgrimes	    printf("Restarting %s...", job->node->name);
12581590Srgrimes	}
12591590Srgrimes	if (((nLocal >= maxLocal) && ! (job->flags & JOB_SPECIAL))) {
12601590Srgrimes		/*
12611590Srgrimes		 * Can't be exported and not allowed to run locally -- put it
12621590Srgrimes		 * back on the hold queue and mark the table full
12631590Srgrimes		 */
12641590Srgrimes		if (DEBUG(JOB)) {
12651590Srgrimes		    printf("holding\n");
12661590Srgrimes		}
12671590Srgrimes		(void)Lst_AtFront(stoppedJobs, (ClientData)job);
12681590Srgrimes		jobFull = TRUE;
12691590Srgrimes		if (DEBUG(JOB)) {
12701590Srgrimes		    printf("Job queue is full.\n");
12711590Srgrimes		}
12721590Srgrimes		return;
12731590Srgrimes	} else {
12741590Srgrimes		/*
12751590Srgrimes		 * Job may be run locally.
12761590Srgrimes		 */
12771590Srgrimes		if (DEBUG(JOB)) {
12781590Srgrimes		    printf("running locally\n");
12791590Srgrimes		}
12801590Srgrimes		job->flags &= ~JOB_REMOTE;
12811590Srgrimes	}
12821590Srgrimes	JobExec(job, argv);
12831590Srgrimes    } else {
12841590Srgrimes	/*
12851590Srgrimes	 * The job has stopped and needs to be restarted. Why it stopped,
12861590Srgrimes	 * we don't know...
12871590Srgrimes	 */
12881590Srgrimes	if (DEBUG(JOB)) {
12891590Srgrimes	    printf("Resuming %s...", job->node->name);
12901590Srgrimes	}
12911590Srgrimes	if (((job->flags & JOB_REMOTE) ||
12921590Srgrimes	     (nLocal < maxLocal) ||
12931590Srgrimes	     (((job->flags & JOB_SPECIAL)) &&
12941590Srgrimes	      (maxLocal == 0))) &&
12951590Srgrimes	    (nJobs != maxJobs))
12961590Srgrimes	{
12971590Srgrimes	    /*
12981590Srgrimes	     * If the job is remote, it's ok to resume it as long as the
12991590Srgrimes	     * maximum concurrency won't be exceeded. If it's local and
13001590Srgrimes	     * we haven't reached the local concurrency limit already (or the
13011590Srgrimes	     * job must be run locally and maxLocal is 0), it's also ok to
13021590Srgrimes	     * resume it.
13031590Srgrimes	     */
13041590Srgrimes	    Boolean error;
13051590Srgrimes	    extern int errno;
13061590Srgrimes	    union wait status;
13078874Srgrimes
13081590Srgrimes#ifdef RMT_WANTS_SIGNALS
13091590Srgrimes	    if (job->flags & JOB_REMOTE) {
13101590Srgrimes		error = !Rmt_Signal(job, SIGCONT);
13111590Srgrimes	    } else
13121590Srgrimes#endif	/* RMT_WANTS_SIGNALS */
13131590Srgrimes		error = (KILL(job->pid, SIGCONT) != 0);
13141590Srgrimes
13151590Srgrimes	    if (!error) {
13161590Srgrimes		/*
13171590Srgrimes		 * Make sure the user knows we've continued the beast and
13181590Srgrimes		 * actually put the thing in the job table.
13191590Srgrimes		 */
13201590Srgrimes		job->flags |= JOB_CONTINUING;
13211590Srgrimes		status.w_termsig = SIGCONT;
13221590Srgrimes		JobFinish(job, status);
13238874Srgrimes
13241590Srgrimes		job->flags &= ~(JOB_RESUME|JOB_CONTINUING);
13251590Srgrimes		if (DEBUG(JOB)) {
13261590Srgrimes		    printf("done\n");
13271590Srgrimes		}
13281590Srgrimes	    } else {
13291590Srgrimes		Error("couldn't resume %s: %s",
13301590Srgrimes		    job->node->name, strerror(errno));
13311590Srgrimes		status.w_status = 0;
13321590Srgrimes		status.w_retcode = 1;
13331590Srgrimes		JobFinish(job, status);
13341590Srgrimes	    }
13351590Srgrimes	} else {
13361590Srgrimes	    /*
13371590Srgrimes	     * Job cannot be restarted. Mark the table as full and
13381590Srgrimes	     * place the job back on the list of stopped jobs.
13391590Srgrimes	     */
13401590Srgrimes	    if (DEBUG(JOB)) {
13411590Srgrimes		printf("table full\n");
13421590Srgrimes	    }
13431590Srgrimes	    (void)Lst_AtFront(stoppedJobs, (ClientData)job);
13441590Srgrimes	    jobFull = TRUE;
13451590Srgrimes	    if (DEBUG(JOB)) {
13461590Srgrimes		printf("Job queue is full.\n");
13471590Srgrimes	    }
13481590Srgrimes	}
13491590Srgrimes    }
13501590Srgrimes}
13511590Srgrimes
13521590Srgrimes/*-
13531590Srgrimes *-----------------------------------------------------------------------
13541590Srgrimes * JobStart  --
13551590Srgrimes *	Start a target-creation process going for the target described
13568874Srgrimes *	by the graph node gn.
13571590Srgrimes *
13581590Srgrimes * Results:
13591590Srgrimes *	JOB_ERROR if there was an error in the commands, JOB_FINISHED
13601590Srgrimes *	if there isn't actually anything left to do for the job and
13611590Srgrimes *	JOB_RUNNING if the job has been started.
13621590Srgrimes *
13631590Srgrimes * Side Effects:
13641590Srgrimes *	A new Job node is created and added to the list of running
13651590Srgrimes *	jobs. PMake is forked and a child shell created.
13661590Srgrimes *-----------------------------------------------------------------------
13671590Srgrimes */
13681590Srgrimesstatic int
13691590SrgrimesJobStart (gn, flags, previous)
13701590Srgrimes    GNode         *gn;	      /* target to create */
13715814Sjkh    int	  	   flags;      /* flags for the job to override normal ones.
13721590Srgrimes			       * e.g. JOB_SPECIAL or JOB_IGNDOTS */
13731590Srgrimes    Job 	  *previous;  /* The previous Job structure for this node,
13741590Srgrimes			       * if any. */
13751590Srgrimes{
13761590Srgrimes    register Job  *job;       /* new job descriptor */
13771590Srgrimes    char	  *argv[4];   /* Argument vector to shell */
13781590Srgrimes    static int    jobno = 0;  /* job number of catching output in a file */
13791590Srgrimes    Boolean	  cmdsOK;     /* true if the nodes commands were all right */
13801590Srgrimes    Boolean 	  local;      /* Set true if the job was run locally */
13811590Srgrimes    Boolean 	  noExec;     /* Set true if we decide not to run the job */
13821590Srgrimes
13831590Srgrimes    if (previous != (Job *)NULL) {
13841590Srgrimes	previous->flags &= ~ (JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);
13851590Srgrimes	job = previous;
13861590Srgrimes    } else {
13871590Srgrimes	job = (Job *) emalloc (sizeof (Job));
13881590Srgrimes	if (job == (Job *)NULL) {
13891590Srgrimes	    Punt("JobStart out of memory");
13901590Srgrimes	}
13911590Srgrimes	flags |= JOB_FIRST;
13921590Srgrimes    }
13931590Srgrimes
13941590Srgrimes    job->node = gn;
13951590Srgrimes    job->tailCmds = NILLNODE;
13961590Srgrimes
13971590Srgrimes    /*
13981590Srgrimes     * Set the initial value of the flags for this job based on the global
13991590Srgrimes     * ones and the node's attributes... Any flags supplied by the caller
14001590Srgrimes     * are also added to the field.
14011590Srgrimes     */
14021590Srgrimes    job->flags = 0;
14031590Srgrimes    if (Targ_Ignore (gn)) {
14041590Srgrimes	job->flags |= JOB_IGNERR;
14051590Srgrimes    }
14061590Srgrimes    if (Targ_Silent (gn)) {
14071590Srgrimes	job->flags |= JOB_SILENT;
14081590Srgrimes    }
14091590Srgrimes    job->flags |= flags;
14101590Srgrimes
14111590Srgrimes    /*
14121590Srgrimes     * Check the commands now so any attributes from .DEFAULT have a chance
14131590Srgrimes     * to migrate to the node
14141590Srgrimes     */
14151590Srgrimes    if (job->flags & JOB_FIRST) {
14161590Srgrimes	cmdsOK = Job_CheckCommands(gn, Error);
14171590Srgrimes    } else {
14181590Srgrimes	cmdsOK = TRUE;
14191590Srgrimes    }
14208874Srgrimes
14211590Srgrimes    /*
14221590Srgrimes     * If the -n flag wasn't given, we open up OUR (not the child's)
14231590Srgrimes     * temporary file to stuff commands in it. The thing is rd/wr so we don't
14241590Srgrimes     * need to reopen it to feed it to the shell. If the -n flag *was* given,
14251590Srgrimes     * we just set the file to be stdout. Cute, huh?
14261590Srgrimes     */
14271590Srgrimes    if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) {
14281590Srgrimes	/*
14291590Srgrimes	 * We're serious here, but if the commands were bogus, we're
14301590Srgrimes	 * also dead...
14311590Srgrimes	 */
14321590Srgrimes	if (!cmdsOK) {
14331590Srgrimes	    DieHorribly();
14341590Srgrimes	}
14358874Srgrimes
14361590Srgrimes	job->cmdFILE = fopen (tfile, "w+");
14371590Srgrimes	if (job->cmdFILE == (FILE *) NULL) {
14381590Srgrimes	    Punt ("Could not open %s", tfile);
14391590Srgrimes	}
14401590Srgrimes	fcntl(fileno(job->cmdFILE), F_SETFD, 1);
14411590Srgrimes	/*
14421590Srgrimes	 * Send the commands to the command file, flush all its buffers then
14431590Srgrimes	 * rewind and remove the thing.
14441590Srgrimes	 */
14451590Srgrimes	noExec = FALSE;
14461590Srgrimes
14471590Srgrimes	/*
14481590Srgrimes	 * used to be backwards; replace when start doing multiple commands
14491590Srgrimes	 * per shell.
14501590Srgrimes	 */
14511590Srgrimes	if (compatMake) {
14521590Srgrimes	    /*
14531590Srgrimes	     * Be compatible: If this is the first time for this node,
14541590Srgrimes	     * verify its commands are ok and open the commands list for
14551590Srgrimes	     * sequential access by later invocations of JobStart.
14561590Srgrimes	     * Once that is done, we take the next command off the list
14571590Srgrimes	     * and print it to the command file. If the command was an
14581590Srgrimes	     * ellipsis, note that there's nothing more to execute.
14591590Srgrimes	     */
14601590Srgrimes	    if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){
14611590Srgrimes		cmdsOK = FALSE;
14621590Srgrimes	    } else {
14631590Srgrimes		LstNode	ln = Lst_Next (gn->commands);
14648874Srgrimes
14651590Srgrimes		if ((ln == NILLNODE) ||
14661590Srgrimes		    JobPrintCommand ((char *)Lst_Datum (ln), job))
14671590Srgrimes		{
14681590Srgrimes		    noExec = TRUE;
14691590Srgrimes		    Lst_Close (gn->commands);
14701590Srgrimes		}
14711590Srgrimes		if (noExec && !(job->flags & JOB_FIRST)) {
14721590Srgrimes		    /*
14731590Srgrimes		     * If we're not going to execute anything, the job
14741590Srgrimes		     * is done and we need to close down the various
14751590Srgrimes		     * file descriptors we've opened for output, then
14761590Srgrimes		     * call JobDoOutput to catch the final characters or
14771590Srgrimes		     * send the file to the screen... Note that the i/o streams
14781590Srgrimes		     * are only open if this isn't the first job.
14791590Srgrimes		     * Note also that this could not be done in
14801590Srgrimes		     * Job_CatchChildren b/c it wasn't clear if there were
14811590Srgrimes		     * more commands to execute or not...
14821590Srgrimes		     */
14831590Srgrimes		    if (usePipes) {
14841590Srgrimes#ifdef RMT_WILL_WATCH
14851590Srgrimes			Rmt_Ignore(job->inPipe);
14861590Srgrimes#else
14871590Srgrimes			FD_CLR(job->inPipe, &outputs);
14881590Srgrimes#endif
14891590Srgrimes			if (job->outPipe != job->inPipe) {
14901590Srgrimes			    (void)close (job->outPipe);
14911590Srgrimes			}
14921590Srgrimes			JobDoOutput (job, TRUE);
14931590Srgrimes			(void)close (job->inPipe);
14941590Srgrimes		    } else {
14951590Srgrimes			(void)close (job->outFd);
14961590Srgrimes			JobDoOutput (job, TRUE);
14971590Srgrimes		    }
14981590Srgrimes		}
14991590Srgrimes	    }
15001590Srgrimes	} else {
15011590Srgrimes	    /*
15021590Srgrimes	     * We can do all the commands at once. hooray for sanity
15031590Srgrimes	     */
15041590Srgrimes	    numCommands = 0;
15051590Srgrimes	    Lst_ForEach (gn->commands, JobPrintCommand, (ClientData)job);
15068874Srgrimes
15071590Srgrimes	    /*
15081590Srgrimes	     * If we didn't print out any commands to the shell script,
15091590Srgrimes	     * there's not much point in executing the shell, is there?
15101590Srgrimes	     */
15111590Srgrimes	    if (numCommands == 0) {
15121590Srgrimes		noExec = TRUE;
15131590Srgrimes	    }
15141590Srgrimes	}
15151590Srgrimes    } else if (noExecute) {
15161590Srgrimes	/*
15171590Srgrimes	 * Not executing anything -- just print all the commands to stdout
15181590Srgrimes	 * in one fell swoop. This will still set up job->tailCmds correctly.
15191590Srgrimes	 */
15201590Srgrimes	if (lastNode != gn) {
15211590Srgrimes	    printf (targFmt, gn->name);
15221590Srgrimes	    lastNode = gn;
15231590Srgrimes	}
15241590Srgrimes	job->cmdFILE = stdout;
15251590Srgrimes	/*
15261590Srgrimes	 * Only print the commands if they're ok, but don't die if they're
15271590Srgrimes	 * not -- just let the user know they're bad and keep going. It
15281590Srgrimes	 * doesn't do any harm in this case and may do some good.
15291590Srgrimes	 */
15301590Srgrimes	if (cmdsOK) {
15311590Srgrimes	    Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);
15321590Srgrimes	}
15331590Srgrimes	/*
15341590Srgrimes	 * Don't execute the shell, thank you.
15351590Srgrimes	 */
15361590Srgrimes	noExec = TRUE;
15371590Srgrimes    } else {
15381590Srgrimes	/*
15391590Srgrimes	 * Just touch the target and note that no shell should be executed.
15401590Srgrimes	 * Set cmdFILE to stdout to make life easier. Check the commands, too,
15411590Srgrimes	 * but don't die if they're no good -- it does no harm to keep working
15421590Srgrimes	 * up the graph.
15431590Srgrimes	 */
15441590Srgrimes	job->cmdFILE = stdout;
15451590Srgrimes    	Job_Touch (gn, job->flags&JOB_SILENT);
15461590Srgrimes	noExec = TRUE;
15471590Srgrimes    }
15481590Srgrimes
15491590Srgrimes    /*
15508874Srgrimes     * If we're not supposed to execute a shell, don't.
15511590Srgrimes     */
15521590Srgrimes    if (noExec) {
15531590Srgrimes	/*
15541590Srgrimes	 * Unlink and close the command file if we opened one
15551590Srgrimes	 */
15561590Srgrimes	if (job->cmdFILE != stdout) {
15571590Srgrimes	    (void) unlink (tfile);
15581590Srgrimes	    fclose(job->cmdFILE);
15591590Srgrimes	} else {
15601590Srgrimes	    fflush (stdout);
15611590Srgrimes	}
15621590Srgrimes
15631590Srgrimes	/*
15641590Srgrimes	 * We only want to work our way up the graph if we aren't here because
15651590Srgrimes	 * the commands for the job were no good.
15661590Srgrimes	 */
15671590Srgrimes	if (cmdsOK) {
15681590Srgrimes	    if (aborting == 0) {
15691590Srgrimes		if (job->tailCmds != NILLNODE) {
15701590Srgrimes		    Lst_ForEachFrom(job->node->commands, job->tailCmds,
15711590Srgrimes				    JobSaveCommand,
15721590Srgrimes				    (ClientData)job->node);
15731590Srgrimes		}
15741590Srgrimes		Make_Update(job->node);
15751590Srgrimes	    }
15761590Srgrimes	    free((Address)job);
15771590Srgrimes	    return(JOB_FINISHED);
15781590Srgrimes	} else {
15791590Srgrimes	    free((Address)job);
15801590Srgrimes	    return(JOB_ERROR);
15811590Srgrimes	}
15821590Srgrimes    } else {
15831590Srgrimes	fflush (job->cmdFILE);
15841590Srgrimes	(void) unlink (tfile);
15851590Srgrimes    }
15861590Srgrimes
15871590Srgrimes    /*
15881590Srgrimes     * Set up the control arguments to the shell. This is based on the flags
15891590Srgrimes     * set earlier for this job.
15901590Srgrimes     */
15911590Srgrimes    JobMakeArgv(job, argv);
15921590Srgrimes
15931590Srgrimes    /*
15941590Srgrimes     * If we're using pipes to catch output, create the pipe by which we'll
15951590Srgrimes     * get the shell's output. If we're using files, print out that we're
15961590Srgrimes     * starting a job and then set up its temporary-file name. This is just
15971590Srgrimes     * tfile with two extra digits tacked on -- jobno.
15981590Srgrimes     */
15991590Srgrimes    if (job->flags & JOB_FIRST) {
16001590Srgrimes	if (usePipes) {
16011590Srgrimes	    int fd[2];
16028874Srgrimes	    (void) pipe(fd);
16031590Srgrimes	    job->inPipe = fd[0];
16041590Srgrimes	    job->outPipe = fd[1];
16051590Srgrimes	    (void)fcntl (job->inPipe, F_SETFD, 1);
16061590Srgrimes	    (void)fcntl (job->outPipe, F_SETFD, 1);
16071590Srgrimes	} else {
16081590Srgrimes	    printf ("Remaking `%s'\n", gn->name);
16091590Srgrimes	    fflush (stdout);
16101590Srgrimes	    sprintf (job->outFile, "%s%02d", tfile, jobno);
16111590Srgrimes	    jobno = (jobno + 1) % 100;
16121590Srgrimes	    job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600);
16131590Srgrimes	    (void)fcntl (job->outFd, F_SETFD, 1);
16141590Srgrimes	}
16151590Srgrimes    }
16161590Srgrimes
16171590Srgrimes    local = TRUE;
16181590Srgrimes
16191590Srgrimes    if (local && (((nLocal >= maxLocal) &&
16201590Srgrimes	 !(job->flags & JOB_SPECIAL) &&
16211590Srgrimes	 (maxLocal != 0))))
16221590Srgrimes    {
16231590Srgrimes	/*
16241590Srgrimes	 * The job can only be run locally, but we've hit the limit of
16251590Srgrimes	 * local concurrency, so put the job on hold until some other job
16261590Srgrimes	 * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END)
16271590Srgrimes	 * may be run locally even when the local limit has been reached
16281590Srgrimes	 * (e.g. when maxLocal == 0), though they will be exported if at
16298874Srgrimes	 * all possible.
16301590Srgrimes	 */
16311590Srgrimes	jobFull = TRUE;
16328874Srgrimes
16331590Srgrimes	if (DEBUG(JOB)) {
16341590Srgrimes	    printf("Can only run job locally.\n");
16351590Srgrimes	}
16361590Srgrimes	job->flags |= JOB_RESTART;
16371590Srgrimes	(void)Lst_AtEnd(stoppedJobs, (ClientData)job);
16381590Srgrimes    } else {
16391590Srgrimes	if ((nLocal >= maxLocal) && local) {
16401590Srgrimes	    /*
16411590Srgrimes	     * If we're running this job locally as a special case (see above),
16421590Srgrimes	     * at least say the table is full.
16431590Srgrimes	     */
16441590Srgrimes	    jobFull = TRUE;
16451590Srgrimes	    if (DEBUG(JOB)) {
16461590Srgrimes		printf("Local job queue is full.\n");
16471590Srgrimes	    }
16481590Srgrimes	}
16491590Srgrimes	JobExec(job, argv);
16501590Srgrimes    }
16511590Srgrimes    return(JOB_RUNNING);
16521590Srgrimes}
16531590Srgrimes
16541590Srgrimes/*-
16551590Srgrimes *-----------------------------------------------------------------------
16561590Srgrimes * JobDoOutput  --
16571590Srgrimes *	This function is called at different times depending on
16581590Srgrimes *	whether the user has specified that output is to be collected
16591590Srgrimes *	via pipes or temporary files. In the former case, we are called
16601590Srgrimes *	whenever there is something to read on the pipe. We collect more
16611590Srgrimes *	output from the given job and store it in the job's outBuf. If
16621590Srgrimes *	this makes up a line, we print it tagged by the job's identifier,
16631590Srgrimes *	as necessary.
16641590Srgrimes *	If output has been collected in a temporary file, we open the
16651590Srgrimes *	file and read it line by line, transfering it to our own
16661590Srgrimes *	output channel until the file is empty. At which point we
16671590Srgrimes *	remove the temporary file.
16681590Srgrimes *	In both cases, however, we keep our figurative eye out for the
16691590Srgrimes *	'noPrint' line for the shell from which the output came. If
16701590Srgrimes *	we recognize a line, we don't print it. If the command is not
16711590Srgrimes *	alone on the line (the character after it is not \0 or \n), we
16721590Srgrimes *	do print whatever follows it.
16731590Srgrimes *
16741590Srgrimes * Results:
16751590Srgrimes *	None
16761590Srgrimes *
16771590Srgrimes * Side Effects:
16781590Srgrimes *	curPos may be shifted as may the contents of outBuf.
16791590Srgrimes *-----------------------------------------------------------------------
16801590Srgrimes */
16811590Srgrimesstatic void
16821590SrgrimesJobDoOutput (job, finish)
16831590Srgrimes    register Job   *job;	  /* the job whose output needs printing */
16841590Srgrimes    Boolean	   finish;	  /* TRUE if this is the last time we'll be
16851590Srgrimes				   * called for this job */
16861590Srgrimes{
16871590Srgrimes    Boolean       gotNL = FALSE;  /* true if got a newline */
16881590Srgrimes    register int  nr;	      	  /* number of bytes read */
16891590Srgrimes    register int  i;	      	  /* auxiliary index into outBuf */
16901590Srgrimes    register int  max;	      	  /* limit for i (end of current data) */
16911590Srgrimes    int		  nRead;      	  /* (Temporary) number of bytes read */
16921590Srgrimes
16931590Srgrimes    FILE      	  *oFILE;	  /* Stream pointer to shell's output file */
16941590Srgrimes    char          inLine[132];
16951590Srgrimes
16968874Srgrimes
16971590Srgrimes    if (usePipes) {
16981590Srgrimes	/*
16991590Srgrimes	 * Read as many bytes as will fit in the buffer.
17001590Srgrimes	 */
17011590Srgrimesend_loop:
17028874Srgrimes
17031590Srgrimes	nRead = read (job->inPipe, &job->outBuf[job->curPos],
17041590Srgrimes			 JOB_BUFSIZE - job->curPos);
17051590Srgrimes	if (nRead < 0) {
17061590Srgrimes	    if (DEBUG(JOB)) {
17071590Srgrimes		perror("JobDoOutput(piperead)");
17081590Srgrimes	    }
17091590Srgrimes	    nr = 0;
17101590Srgrimes	} else {
17111590Srgrimes	    nr = nRead;
17121590Srgrimes	}
17131590Srgrimes
17141590Srgrimes	/*
17151590Srgrimes	 * If we hit the end-of-file (the job is dead), we must flush its
17161590Srgrimes	 * remaining output, so pretend we read a newline if there's any
17171590Srgrimes	 * output remaining in the buffer.
17181590Srgrimes	 * Also clear the 'finish' flag so we stop looping.
17191590Srgrimes	 */
17201590Srgrimes	if ((nr == 0) && (job->curPos != 0)) {
17211590Srgrimes	    job->outBuf[job->curPos] = '\n';
17221590Srgrimes	    nr = 1;
17231590Srgrimes	    finish = FALSE;
17241590Srgrimes	} else if (nr == 0) {
17251590Srgrimes	    finish = FALSE;
17261590Srgrimes	}
17278874Srgrimes
17281590Srgrimes	/*
17291590Srgrimes	 * Look for the last newline in the bytes we just got. If there is
17301590Srgrimes	 * one, break out of the loop with 'i' as its index and gotNL set
17318874Srgrimes	 * TRUE.
17321590Srgrimes	 */
17331590Srgrimes	max = job->curPos + nr;
17341590Srgrimes	for (i = job->curPos + nr - 1; i >= job->curPos; i--) {
17351590Srgrimes	    if (job->outBuf[i] == '\n') {
17361590Srgrimes		gotNL = TRUE;
17371590Srgrimes		break;
17381590Srgrimes	    } else if (job->outBuf[i] == '\0') {
17391590Srgrimes		/*
17401590Srgrimes		 * Why?
17411590Srgrimes		 */
17421590Srgrimes		job->outBuf[i] = ' ';
17431590Srgrimes	    }
17441590Srgrimes	}
17458874Srgrimes
17461590Srgrimes	if (!gotNL) {
17471590Srgrimes	    job->curPos += nr;
17481590Srgrimes	    if (job->curPos == JOB_BUFSIZE) {
17491590Srgrimes		/*
17501590Srgrimes		 * If we've run out of buffer space, we have no choice
17518874Srgrimes		 * but to print the stuff. sigh.
17521590Srgrimes		 */
17531590Srgrimes		gotNL = TRUE;
17541590Srgrimes		i = job->curPos;
17551590Srgrimes	    }
17561590Srgrimes	}
17571590Srgrimes	if (gotNL) {
17581590Srgrimes	    /*
17591590Srgrimes	     * Need to send the output to the screen. Null terminate it
17601590Srgrimes	     * first, overwriting the newline character if there was one.
17611590Srgrimes	     * So long as the line isn't one we should filter (according
17621590Srgrimes	     * to the shell description), we print the line, preceeded
17631590Srgrimes	     * by a target banner if this target isn't the same as the
17641590Srgrimes	     * one for which we last printed something.
17651590Srgrimes	     * The rest of the data in the buffer are then shifted down
17668874Srgrimes	     * to the start of the buffer and curPos is set accordingly.
17671590Srgrimes	     */
17681590Srgrimes	    job->outBuf[i] = '\0';
17691590Srgrimes	    if (i >= job->curPos) {
17701590Srgrimes		register char	*cp, *ecp;
17711590Srgrimes
17721590Srgrimes		cp = job->outBuf;
17731590Srgrimes		if (commandShell->noPrint) {
17741590Srgrimes		    ecp = Str_FindSubstring(job->outBuf,
17751590Srgrimes					    commandShell->noPrint);
17761590Srgrimes		    while (ecp != (char *)NULL) {
17771590Srgrimes			if (cp != ecp) {
17781590Srgrimes			    *ecp = '\0';
17791590Srgrimes			    if (job->node != lastNode) {
17801590Srgrimes				printf (targFmt, job->node->name);
17811590Srgrimes				lastNode = job->node;
17821590Srgrimes			    }
17831590Srgrimes			    /*
17841590Srgrimes			     * The only way there wouldn't be a newline after
17851590Srgrimes			     * this line is if it were the last in the buffer.
17861590Srgrimes			     * however, since the non-printable comes after it,
17871590Srgrimes			     * there must be a newline, so we don't print one.
17881590Srgrimes			     */
17891590Srgrimes			    printf ("%s", cp);
17901590Srgrimes			}
17911590Srgrimes			cp = ecp + commandShell->noPLen;
17921590Srgrimes			if (cp != &job->outBuf[i]) {
17931590Srgrimes			    /*
17941590Srgrimes			     * Still more to print, look again after skipping
17951590Srgrimes			     * the whitespace following the non-printable
17961590Srgrimes			     * command....
17971590Srgrimes			     */
17981590Srgrimes			    cp++;
17991590Srgrimes			    while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
18001590Srgrimes				cp++;
18011590Srgrimes			    }
18021590Srgrimes			    ecp = Str_FindSubstring (cp,
18031590Srgrimes						     commandShell->noPrint);
18041590Srgrimes			} else {
18051590Srgrimes			    break;
18061590Srgrimes			}
18071590Srgrimes		    }
18081590Srgrimes		}
18091590Srgrimes
18101590Srgrimes		/*
18111590Srgrimes		 * There's still more in that thar buffer. This time, though,
18121590Srgrimes		 * we know there's no newline at the end, so we add one of
18131590Srgrimes		 * our own free will.
18141590Srgrimes		 */
18151590Srgrimes		if (*cp != '\0') {
18161590Srgrimes		    if (job->node != lastNode) {
18171590Srgrimes			printf (targFmt, job->node->name);
18181590Srgrimes			lastNode = job->node;
18191590Srgrimes		    }
18201590Srgrimes		    printf ("%s\n", cp);
18211590Srgrimes		}
18221590Srgrimes
18231590Srgrimes		fflush (stdout);
18241590Srgrimes	    }
18251590Srgrimes	    if (i < max - 1) {
18261590Srgrimes		/* shift the remaining characters down */
18271590Srgrimes		memcpy ( job->outBuf, &job->outBuf[i + 1], max - (i + 1));
18281590Srgrimes		job->curPos = max - (i + 1);
18298874Srgrimes
18301590Srgrimes	    } else {
18311590Srgrimes		/*
18321590Srgrimes		 * We have written everything out, so we just start over
18331590Srgrimes		 * from the start of the buffer. No copying. No nothing.
18341590Srgrimes		 */
18351590Srgrimes		job->curPos = 0;
18361590Srgrimes	    }
18371590Srgrimes	}
18381590Srgrimes	if (finish) {
18391590Srgrimes	    /*
18401590Srgrimes	     * If the finish flag is true, we must loop until we hit
18411590Srgrimes	     * end-of-file on the pipe. This is guaranteed to happen eventually
18421590Srgrimes	     * since the other end of the pipe is now closed (we closed it
18431590Srgrimes	     * explicitly and the child has exited). When we do get an EOF,
18441590Srgrimes	     * finish will be set FALSE and we'll fall through and out.
18451590Srgrimes	     */
18461590Srgrimes	    goto end_loop;
18471590Srgrimes	}
18481590Srgrimes    } else {
18491590Srgrimes	/*
18501590Srgrimes	 * We've been called to retrieve the output of the job from the
18511590Srgrimes	 * temporary file where it's been squirreled away. This consists of
18521590Srgrimes	 * opening the file, reading the output line by line, being sure not
18531590Srgrimes	 * to print the noPrint line for the shell we used, then close and
18541590Srgrimes	 * remove the temporary file. Very simple.
18551590Srgrimes	 *
18561590Srgrimes	 * Change to read in blocks and do FindSubString type things as for
18571590Srgrimes	 * pipes? That would allow for "@echo -n..."
18581590Srgrimes	 */
18591590Srgrimes	oFILE = fopen (job->outFile, "r");
18601590Srgrimes	if (oFILE != (FILE *) NULL) {
18611590Srgrimes	    printf ("Results of making %s:\n", job->node->name);
18621590Srgrimes	    while (fgets (inLine, sizeof(inLine), oFILE) != NULL) {
18631590Srgrimes		register char	*cp, *ecp, *endp;
18641590Srgrimes
18651590Srgrimes		cp = inLine;
18661590Srgrimes		endp = inLine + strlen(inLine);
18671590Srgrimes		if (endp[-1] == '\n') {
18681590Srgrimes		    *--endp = '\0';
18691590Srgrimes		}
18701590Srgrimes		if (commandShell->noPrint) {
18711590Srgrimes		    ecp = Str_FindSubstring(cp, commandShell->noPrint);
18721590Srgrimes		    while (ecp != (char *)NULL) {
18731590Srgrimes			if (cp != ecp) {
18741590Srgrimes			    *ecp = '\0';
18751590Srgrimes			    /*
18761590Srgrimes			     * The only way there wouldn't be a newline after
18771590Srgrimes			     * this line is if it were the last in the buffer.
18781590Srgrimes			     * however, since the non-printable comes after it,
18791590Srgrimes			     * there must be a newline, so we don't print one.
18801590Srgrimes			     */
18811590Srgrimes			    printf ("%s", cp);
18821590Srgrimes			}
18831590Srgrimes			cp = ecp + commandShell->noPLen;
18841590Srgrimes			if (cp != endp) {
18851590Srgrimes			    /*
18861590Srgrimes			     * Still more to print, look again after skipping
18871590Srgrimes			     * the whitespace following the non-printable
18881590Srgrimes			     * command....
18891590Srgrimes			     */
18901590Srgrimes			    cp++;
18911590Srgrimes			    while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
18921590Srgrimes				cp++;
18931590Srgrimes			    }
18941590Srgrimes			    ecp = Str_FindSubstring(cp, commandShell->noPrint);
18951590Srgrimes			} else {
18961590Srgrimes			    break;
18971590Srgrimes			}
18981590Srgrimes		    }
18991590Srgrimes		}
19001590Srgrimes
19011590Srgrimes		/*
19021590Srgrimes		 * There's still more in that thar buffer. This time, though,
19031590Srgrimes		 * we know there's no newline at the end, so we add one of
19041590Srgrimes		 * our own free will.
19051590Srgrimes		 */
19061590Srgrimes		if (*cp != '\0') {
19071590Srgrimes		    printf ("%s\n", cp);
19081590Srgrimes		}
19091590Srgrimes	    }
19101590Srgrimes	    fclose (oFILE);
19111590Srgrimes	    (void) unlink (job->outFile);
19121590Srgrimes	}
19131590Srgrimes    }
19141590Srgrimes    fflush(stdout);
19151590Srgrimes}
19161590Srgrimes
19171590Srgrimes/*-
19181590Srgrimes *-----------------------------------------------------------------------
19191590Srgrimes * Job_CatchChildren --
19201590Srgrimes *	Handle the exit of a child. Called from Make_Make.
19211590Srgrimes *
19221590Srgrimes * Results:
19231590Srgrimes *	none.
19241590Srgrimes *
19251590Srgrimes * Side Effects:
19261590Srgrimes *	The job descriptor is removed from the list of children.
19271590Srgrimes *
19281590Srgrimes * Notes:
19291590Srgrimes *	We do waits, blocking or not, according to the wisdom of our
19301590Srgrimes *	caller, until there are no more children to report. For each
19311590Srgrimes *	job, call JobFinish to finish things off. This will take care of
19321590Srgrimes *	putting jobs on the stoppedJobs queue.
19331590Srgrimes *
19341590Srgrimes *-----------------------------------------------------------------------
19351590Srgrimes */
19361590Srgrimesvoid
19371590SrgrimesJob_CatchChildren (block)
19381590Srgrimes    Boolean	  block;    	/* TRUE if should block on the wait. */
19391590Srgrimes{
19401590Srgrimes    int    	  pid;	    	/* pid of dead child */
19411590Srgrimes    register Job  *job;	    	/* job descriptor for dead child */
19421590Srgrimes    LstNode       jnode;    	/* list element for finding job */
19431590Srgrimes    union wait	  status;   	/* Exit/termination status */
19441590Srgrimes
19451590Srgrimes    /*
19461590Srgrimes     * Don't even bother if we know there's no one around.
19471590Srgrimes     */
19481590Srgrimes    if (nLocal == 0) {
19491590Srgrimes	return;
19501590Srgrimes    }
19518874Srgrimes
19521590Srgrimes    while ((pid = wait3((int *)&status, (block?0:WNOHANG)|WUNTRACED,
19531590Srgrimes			(struct rusage *)0)) > 0)
19541590Srgrimes    {
19551590Srgrimes	if (DEBUG(JOB))
19561590Srgrimes	    printf("Process %d exited or stopped.\n", pid);
19571590Srgrimes
19588874Srgrimes
19595814Sjkh	jnode = Lst_Find (jobs, (ClientData)&pid, JobCmpPid);
19601590Srgrimes
19611590Srgrimes	if (jnode == NILLNODE) {
19621590Srgrimes	    if (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) {
19635814Sjkh		jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid);
19641590Srgrimes		if (jnode == NILLNODE) {
19651590Srgrimes		    Error("Resumed child (%d) not in table", pid);
19661590Srgrimes		    continue;
19671590Srgrimes		}
19681590Srgrimes		job = (Job *)Lst_Datum(jnode);
19691590Srgrimes		(void)Lst_Remove(stoppedJobs, jnode);
19701590Srgrimes	    } else {
19711590Srgrimes		Error ("Child (%d) not in table?", pid);
19721590Srgrimes		continue;
19731590Srgrimes	    }
19741590Srgrimes	} else {
19751590Srgrimes	    job = (Job *) Lst_Datum (jnode);
19761590Srgrimes	    (void)Lst_Remove (jobs, jnode);
19771590Srgrimes	    nJobs -= 1;
19781590Srgrimes	    if (jobFull && DEBUG(JOB)) {
19791590Srgrimes		printf("Job queue is no longer full.\n");
19801590Srgrimes	    }
19811590Srgrimes	    jobFull = FALSE;
19821590Srgrimes	    nLocal -= 1;
19831590Srgrimes	}
19841590Srgrimes
19851590Srgrimes	JobFinish (job, status);
19861590Srgrimes    }
19871590Srgrimes}
19881590Srgrimes
19891590Srgrimes/*-
19901590Srgrimes *-----------------------------------------------------------------------
19911590Srgrimes * Job_CatchOutput --
19921590Srgrimes *	Catch the output from our children, if we're using
19931590Srgrimes *	pipes do so. Otherwise just block time until we get a
19941590Srgrimes *	signal (most likely a SIGCHLD) since there's no point in
19951590Srgrimes *	just spinning when there's nothing to do and the reaping
19968874Srgrimes *	of a child can wait for a while.
19971590Srgrimes *
19981590Srgrimes * Results:
19998874Srgrimes *	None
20001590Srgrimes *
20011590Srgrimes * Side Effects:
20021590Srgrimes *	Output is read from pipes if we're piping.
20031590Srgrimes * -----------------------------------------------------------------------
20041590Srgrimes */
20051590Srgrimesvoid
20061590SrgrimesJob_CatchOutput ()
20071590Srgrimes{
20081590Srgrimes    int           	  nfds;
20091590Srgrimes    struct timeval	  timeout;
20101590Srgrimes    fd_set           	  readfds;
20111590Srgrimes    register LstNode	  ln;
20121590Srgrimes    register Job   	  *job;
20131590Srgrimes#ifdef RMT_WILL_WATCH
20141590Srgrimes    int	    	  	  pnJobs;   	/* Previous nJobs */
20151590Srgrimes#endif
20161590Srgrimes
20171590Srgrimes    fflush(stdout);
20181590Srgrimes#ifdef RMT_WILL_WATCH
20191590Srgrimes    pnJobs = nJobs;
20201590Srgrimes
20211590Srgrimes    /*
20221590Srgrimes     * It is possible for us to be called with nJobs equal to 0. This happens
20231590Srgrimes     * if all the jobs finish and a job that is stopped cannot be run
20241590Srgrimes     * locally (eg if maxLocal is 0) and cannot be exported. The job will
20251590Srgrimes     * be placed back on the stoppedJobs queue, Job_Empty() will return false,
20261590Srgrimes     * Make_Run will call us again when there's nothing for which to wait.
20271590Srgrimes     * nJobs never changes, so we loop forever. Hence the check. It could
20281590Srgrimes     * be argued that we should sleep for a bit so as not to swamp the
20291590Srgrimes     * exportation system with requests. Perhaps we should.
20301590Srgrimes     *
20311590Srgrimes     * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren
20321590Srgrimes     * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT.
20331590Srgrimes     * It may use the variable nLocal to determine if it needs to call
20341590Srgrimes     * Job_CatchChildren (if nLocal is 0, there's nothing for which to
20351590Srgrimes     * wait...)
20361590Srgrimes     */
20371590Srgrimes    while (nJobs != 0 && pnJobs == nJobs) {
20381590Srgrimes	Rmt_Wait();
20391590Srgrimes    }
20401590Srgrimes#else
20411590Srgrimes    if (usePipes) {
20421590Srgrimes	readfds = outputs;
20431590Srgrimes	timeout.tv_sec = SEL_SEC;
20441590Srgrimes	timeout.tv_usec = SEL_USEC;
20451590Srgrimes
20461590Srgrimes	if ((nfds = select (FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout)) < 0)
20471590Srgrimes	{
20481590Srgrimes	    return;
20491590Srgrimes	} else {
20501590Srgrimes	    if (Lst_Open (jobs) == FAILURE) {
20511590Srgrimes		Punt ("Cannot open job table");
20521590Srgrimes	    }
20531590Srgrimes	    while (nfds && (ln = Lst_Next (jobs)) != NILLNODE) {
20541590Srgrimes		job = (Job *) Lst_Datum (ln);
20551590Srgrimes		if (FD_ISSET(job->inPipe, &readfds)) {
20561590Srgrimes		    JobDoOutput (job, FALSE);
20571590Srgrimes		    nfds -= 1;
20581590Srgrimes		}
20591590Srgrimes	    }
20601590Srgrimes	    Lst_Close (jobs);
20611590Srgrimes	}
20621590Srgrimes    }
20631590Srgrimes#endif /* RMT_WILL_WATCH */
20641590Srgrimes}
20651590Srgrimes
20661590Srgrimes/*-
20671590Srgrimes *-----------------------------------------------------------------------
20681590Srgrimes * Job_Make --
20691590Srgrimes *	Start the creation of a target. Basically a front-end for
20701590Srgrimes *	JobStart used by the Make module.
20711590Srgrimes *
20721590Srgrimes * Results:
20731590Srgrimes *	None.
20741590Srgrimes *
20751590Srgrimes * Side Effects:
20761590Srgrimes *	Another job is started.
20771590Srgrimes *
20781590Srgrimes *-----------------------------------------------------------------------
20791590Srgrimes */
20801590Srgrimesvoid
20811590SrgrimesJob_Make (gn)
20821590Srgrimes    GNode   *gn;
20831590Srgrimes{
20841590Srgrimes    (void)JobStart (gn, 0, (Job *)NULL);
20851590Srgrimes}
20861590Srgrimes
20871590Srgrimes/*-
20881590Srgrimes *-----------------------------------------------------------------------
20891590Srgrimes * Job_Init --
20901590Srgrimes *	Initialize the process module
20911590Srgrimes *
20921590Srgrimes * Results:
20931590Srgrimes *	none
20941590Srgrimes *
20951590Srgrimes * Side Effects:
20961590Srgrimes *	lists and counters are initialized
20971590Srgrimes *-----------------------------------------------------------------------
20981590Srgrimes */
20991590Srgrimesvoid
21001590SrgrimesJob_Init (maxproc, maxlocal)
21011590Srgrimes    int           maxproc;  /* the greatest number of jobs which may be
21021590Srgrimes			     * running at one time */
21031590Srgrimes    int	    	  maxlocal; /* the greatest number of local jobs which may
21041590Srgrimes			     * be running at once. */
21051590Srgrimes{
21061590Srgrimes    GNode         *begin;     /* node for commands to do at the very start */
21071590Srgrimes
21081590Srgrimes    sprintf (tfile, "/tmp/make%05d", getpid());
21091590Srgrimes
21101590Srgrimes    jobs =  	  Lst_Init (FALSE);
21111590Srgrimes    stoppedJobs = Lst_Init(FALSE);
21121590Srgrimes    maxJobs = 	  maxproc;
21131590Srgrimes    maxLocal = 	  maxlocal;
21141590Srgrimes    nJobs = 	  0;
21151590Srgrimes    nLocal = 	  0;
21161590Srgrimes    jobFull = 	  FALSE;
21171590Srgrimes
21181590Srgrimes    aborting = 	  0;
21191590Srgrimes    errors = 	  0;
21201590Srgrimes
21211590Srgrimes    lastNode =	  NILGNODE;
21221590Srgrimes
21231590Srgrimes    if (maxJobs == 1) {
21241590Srgrimes	/*
21251590Srgrimes	 * If only one job can run at a time, there's no need for a banner,
21261590Srgrimes	 * no is there?
21271590Srgrimes	 */
21281590Srgrimes	targFmt = "";
21291590Srgrimes    } else {
21301590Srgrimes	targFmt = TARG_FMT;
21311590Srgrimes    }
21328874Srgrimes
21331590Srgrimes    if (shellPath == (char *) NULL) {
21341590Srgrimes	/*
21351590Srgrimes	 * The user didn't specify a shell to use, so we are using the
21361590Srgrimes	 * default one... Both the absolute path and the last component
21371590Srgrimes	 * must be set. The last component is taken from the 'name' field
21381590Srgrimes	 * of the default shell description pointed-to by commandShell.
21391590Srgrimes	 * All default shells are located in _PATH_DEFSHELLDIR.
21401590Srgrimes	 */
21411590Srgrimes	shellName = commandShell->name;
21421590Srgrimes	shellPath = str_concat (_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH);
21431590Srgrimes    }
21441590Srgrimes
21451590Srgrimes    if (commandShell->exit == (char *)NULL) {
21461590Srgrimes	commandShell->exit = "";
21471590Srgrimes    }
21481590Srgrimes    if (commandShell->echo == (char *)NULL) {
21491590Srgrimes	commandShell->echo = "";
21501590Srgrimes    }
21511590Srgrimes
21521590Srgrimes    /*
21531590Srgrimes     * Catch the four signals that POSIX specifies if they aren't ignored.
21541590Srgrimes     * JobPassSig will take care of calling JobInterrupt if appropriate.
21551590Srgrimes     */
21561590Srgrimes    if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
21571590Srgrimes	signal (SIGINT, JobPassSig);
21581590Srgrimes    }
21591590Srgrimes    if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
21601590Srgrimes	signal (SIGHUP, JobPassSig);
21611590Srgrimes    }
21621590Srgrimes    if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) {
21631590Srgrimes	signal (SIGQUIT, JobPassSig);
21641590Srgrimes    }
21651590Srgrimes    if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
21661590Srgrimes	signal (SIGTERM, JobPassSig);
21671590Srgrimes    }
21681590Srgrimes    /*
21691590Srgrimes     * There are additional signals that need to be caught and passed if
21701590Srgrimes     * either the export system wants to be told directly of signals or if
21711590Srgrimes     * we're giving each job its own process group (since then it won't get
21721590Srgrimes     * signals from the terminal driver as we own the terminal)
21731590Srgrimes     */
21741590Srgrimes#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP)
21751590Srgrimes    if (signal (SIGTSTP, SIG_IGN) != SIG_IGN) {
21761590Srgrimes	signal (SIGTSTP, JobPassSig);
21771590Srgrimes    }
21781590Srgrimes    if (signal (SIGTTOU, SIG_IGN) != SIG_IGN) {
21791590Srgrimes	signal (SIGTTOU, JobPassSig);
21801590Srgrimes    }
21811590Srgrimes    if (signal (SIGTTIN, SIG_IGN) != SIG_IGN) {
21821590Srgrimes	signal (SIGTTIN, JobPassSig);
21831590Srgrimes    }
21841590Srgrimes    if (signal (SIGWINCH, SIG_IGN) != SIG_IGN) {
21851590Srgrimes	signal (SIGWINCH, JobPassSig);
21861590Srgrimes    }
21871590Srgrimes#endif
21888874Srgrimes
21891590Srgrimes    begin = Targ_FindNode (".BEGIN", TARG_NOCREATE);
21901590Srgrimes
21911590Srgrimes    if (begin != NILGNODE) {
21921590Srgrimes	JobStart (begin, JOB_SPECIAL, (Job *)0);
21931590Srgrimes	while (nJobs) {
21941590Srgrimes	    Job_CatchOutput();
21951590Srgrimes#ifndef RMT_WILL_WATCH
21961590Srgrimes	    Job_CatchChildren (!usePipes);
21971590Srgrimes#endif /* RMT_WILL_WATCH */
21981590Srgrimes	}
21991590Srgrimes    }
22001590Srgrimes    postCommands = Targ_FindNode (".END", TARG_CREATE);
22011590Srgrimes}
22021590Srgrimes
22031590Srgrimes/*-
22041590Srgrimes *-----------------------------------------------------------------------
22051590Srgrimes * Job_Full --
22061590Srgrimes *	See if the job table is full. It is considered full if it is OR
22071590Srgrimes *	if we are in the process of aborting OR if we have
22081590Srgrimes *	reached/exceeded our local quota. This prevents any more jobs
22091590Srgrimes *	from starting up.
22101590Srgrimes *
22111590Srgrimes * Results:
22121590Srgrimes *	TRUE if the job table is full, FALSE otherwise
22131590Srgrimes * Side Effects:
22141590Srgrimes *	None.
22151590Srgrimes *-----------------------------------------------------------------------
22161590Srgrimes */
22171590SrgrimesBoolean
22181590SrgrimesJob_Full ()
22191590Srgrimes{
22201590Srgrimes    return (aborting || jobFull);
22211590Srgrimes}
22221590Srgrimes
22231590Srgrimes/*-
22241590Srgrimes *-----------------------------------------------------------------------
22251590Srgrimes * Job_Empty --
22261590Srgrimes *	See if the job table is empty.  Because the local concurrency may
22271590Srgrimes *	be set to 0, it is possible for the job table to become empty,
22281590Srgrimes *	while the list of stoppedJobs remains non-empty. In such a case,
22291590Srgrimes *	we want to restart as many jobs as we can.
22301590Srgrimes *
22311590Srgrimes * Results:
22321590Srgrimes *	TRUE if it is. FALSE if it ain't.
22331590Srgrimes *
22341590Srgrimes * Side Effects:
22351590Srgrimes *	None.
22361590Srgrimes *
22371590Srgrimes * -----------------------------------------------------------------------
22381590Srgrimes */
22391590SrgrimesBoolean
22401590SrgrimesJob_Empty ()
22411590Srgrimes{
22421590Srgrimes    if (nJobs == 0) {
22431590Srgrimes	if (!Lst_IsEmpty(stoppedJobs) && !aborting) {
22441590Srgrimes	    /*
22451590Srgrimes	     * The job table is obviously not full if it has no jobs in
22461590Srgrimes	     * it...Try and restart the stopped jobs.
22471590Srgrimes	     */
22481590Srgrimes	    jobFull = FALSE;
22491590Srgrimes	    while (!jobFull && !Lst_IsEmpty(stoppedJobs)) {
22501590Srgrimes		JobRestart((Job *)Lst_DeQueue(stoppedJobs));
22511590Srgrimes	    }
22521590Srgrimes	    return(FALSE);
22531590Srgrimes	} else {
22541590Srgrimes	    return(TRUE);
22551590Srgrimes	}
22561590Srgrimes    } else {
22571590Srgrimes	return(FALSE);
22581590Srgrimes    }
22591590Srgrimes}
22601590Srgrimes
22611590Srgrimes/*-
22621590Srgrimes *-----------------------------------------------------------------------
22631590Srgrimes * JobMatchShell --
22641590Srgrimes *	Find a matching shell in 'shells' given its final component.
22651590Srgrimes *
22661590Srgrimes * Results:
22671590Srgrimes *	A pointer to the Shell structure.
22681590Srgrimes *
22691590Srgrimes * Side Effects:
22701590Srgrimes *	None.
22711590Srgrimes *
22721590Srgrimes *-----------------------------------------------------------------------
22731590Srgrimes */
22741590Srgrimesstatic Shell *
22751590SrgrimesJobMatchShell (name)
22761590Srgrimes    char	  *name;      /* Final component of shell path */
22771590Srgrimes{
22781590Srgrimes    register Shell *sh;	      /* Pointer into shells table */
22791590Srgrimes    Shell	   *match;    /* Longest-matching shell */
22801590Srgrimes    register char *cp1,
22811590Srgrimes		  *cp2;
22821590Srgrimes    char	  *eoname;
22831590Srgrimes
22841590Srgrimes    eoname = name + strlen (name);
22851590Srgrimes
22861590Srgrimes    match = (Shell *) NULL;
22871590Srgrimes
22881590Srgrimes    for (sh = shells; sh->name != NULL; sh++) {
22891590Srgrimes	for (cp1 = eoname - strlen (sh->name), cp2 = sh->name;
22901590Srgrimes	     *cp1 != '\0' && *cp1 == *cp2;
22911590Srgrimes	     cp1++, cp2++) {
22921590Srgrimes		 continue;
22931590Srgrimes	}
22941590Srgrimes	if (*cp1 != *cp2) {
22951590Srgrimes	    continue;
22961590Srgrimes	} else if (match == (Shell *) NULL ||
22971590Srgrimes		   strlen (match->name) < strlen (sh->name)) {
22981590Srgrimes		       match = sh;
22991590Srgrimes	}
23001590Srgrimes    }
23011590Srgrimes    return (match == (Shell *) NULL ? sh : match);
23021590Srgrimes}
23031590Srgrimes
23041590Srgrimes/*-
23051590Srgrimes *-----------------------------------------------------------------------
23061590Srgrimes * Job_ParseShell --
23071590Srgrimes *	Parse a shell specification and set up commandShell, shellPath
23081590Srgrimes *	and shellName appropriately.
23091590Srgrimes *
23101590Srgrimes * Results:
23111590Srgrimes *	FAILURE if the specification was incorrect.
23121590Srgrimes *
23131590Srgrimes * Side Effects:
23141590Srgrimes *	commandShell points to a Shell structure (either predefined or
23151590Srgrimes *	created from the shell spec), shellPath is the full path of the
23161590Srgrimes *	shell described by commandShell, while shellName is just the
23171590Srgrimes *	final component of shellPath.
23181590Srgrimes *
23191590Srgrimes * Notes:
23201590Srgrimes *	A shell specification consists of a .SHELL target, with dependency
23211590Srgrimes *	operator, followed by a series of blank-separated words. Double
23221590Srgrimes *	quotes can be used to use blanks in words. A backslash escapes
23231590Srgrimes *	anything (most notably a double-quote and a space) and
23241590Srgrimes *	provides the functionality it does in C. Each word consists of
23251590Srgrimes *	keyword and value separated by an equal sign. There should be no
23261590Srgrimes *	unnecessary spaces in the word. The keywords are as follows:
23271590Srgrimes *	    name  	    Name of shell.
23281590Srgrimes *	    path  	    Location of shell. Overrides "name" if given
23291590Srgrimes *	    quiet 	    Command to turn off echoing.
23301590Srgrimes *	    echo  	    Command to turn echoing on
23311590Srgrimes *	    filter	    Result of turning off echoing that shouldn't be
23321590Srgrimes *	    	  	    printed.
23331590Srgrimes *	    echoFlag	    Flag to turn echoing on at the start
23341590Srgrimes *	    errFlag	    Flag to turn error checking on at the start
23351590Srgrimes *	    hasErrCtl	    True if shell has error checking control
23361590Srgrimes *	    check 	    Command to turn on error checking if hasErrCtl
23371590Srgrimes *	    	  	    is TRUE or template of command to echo a command
23381590Srgrimes *	    	  	    for which error checking is off if hasErrCtl is
23391590Srgrimes *	    	  	    FALSE.
23401590Srgrimes *	    ignore	    Command to turn off error checking if hasErrCtl
23411590Srgrimes *	    	  	    is TRUE or template of command to execute a
23421590Srgrimes *	    	  	    command so as to ignore any errors it returns if
23431590Srgrimes *	    	  	    hasErrCtl is FALSE.
23441590Srgrimes *
23451590Srgrimes *-----------------------------------------------------------------------
23461590Srgrimes */
23471590SrgrimesReturnStatus
23481590SrgrimesJob_ParseShell (line)
23491590Srgrimes    char	  *line;  /* The shell spec */
23501590Srgrimes{
23511590Srgrimes    char    	  **words;
23521590Srgrimes    int	    	  wordCount;
23531590Srgrimes    register char **argv;
23541590Srgrimes    register int  argc;
23551590Srgrimes    char    	  *path;
23561590Srgrimes    Shell   	  newShell;
23571590Srgrimes    Boolean 	  fullSpec = FALSE;
23581590Srgrimes
23591590Srgrimes    while (isspace (*line)) {
23601590Srgrimes	line++;
23611590Srgrimes    }
23625814Sjkh    words = brk_string (line, &wordCount, TRUE);
23631590Srgrimes
23641590Srgrimes    memset ((Address)&newShell, 0, sizeof(newShell));
23658874Srgrimes
23661590Srgrimes    /*
23671590Srgrimes     * Parse the specification by keyword
23681590Srgrimes     */
23691590Srgrimes    for (path = (char *)NULL, argc = wordCount - 1, argv = words + 1;
23701590Srgrimes	 argc != 0;
23711590Srgrimes	 argc--, argv++) {
23721590Srgrimes	     if (strncmp (*argv, "path=", 5) == 0) {
23731590Srgrimes		 path = &argv[0][5];
23741590Srgrimes	     } else if (strncmp (*argv, "name=", 5) == 0) {
23751590Srgrimes		 newShell.name = &argv[0][5];
23761590Srgrimes	     } else {
23771590Srgrimes		 if (strncmp (*argv, "quiet=", 6) == 0) {
23781590Srgrimes		     newShell.echoOff = &argv[0][6];
23791590Srgrimes		 } else if (strncmp (*argv, "echo=", 5) == 0) {
23801590Srgrimes		     newShell.echoOn = &argv[0][5];
23811590Srgrimes		 } else if (strncmp (*argv, "filter=", 7) == 0) {
23821590Srgrimes		     newShell.noPrint = &argv[0][7];
23831590Srgrimes		     newShell.noPLen = strlen(newShell.noPrint);
23841590Srgrimes		 } else if (strncmp (*argv, "echoFlag=", 9) == 0) {
23851590Srgrimes		     newShell.echo = &argv[0][9];
23861590Srgrimes		 } else if (strncmp (*argv, "errFlag=", 8) == 0) {
23871590Srgrimes		     newShell.exit = &argv[0][8];
23881590Srgrimes		 } else if (strncmp (*argv, "hasErrCtl=", 10) == 0) {
23891590Srgrimes		     char c = argv[0][10];
23901590Srgrimes		     newShell.hasErrCtl = !((c != 'Y') && (c != 'y') &&
23911590Srgrimes					    (c != 'T') && (c != 't'));
23921590Srgrimes		 } else if (strncmp (*argv, "check=", 6) == 0) {
23931590Srgrimes		     newShell.errCheck = &argv[0][6];
23941590Srgrimes		 } else if (strncmp (*argv, "ignore=", 7) == 0) {
23951590Srgrimes		     newShell.ignErr = &argv[0][7];
23961590Srgrimes		 } else {
23971590Srgrimes		     Parse_Error (PARSE_FATAL, "Unknown keyword \"%s\"",
23981590Srgrimes				  *argv);
23991590Srgrimes		     return (FAILURE);
24001590Srgrimes		 }
24011590Srgrimes		 fullSpec = TRUE;
24021590Srgrimes	     }
24031590Srgrimes    }
24041590Srgrimes
24051590Srgrimes    if (path == (char *)NULL) {
24061590Srgrimes	/*
24071590Srgrimes	 * If no path was given, the user wants one of the pre-defined shells,
24081590Srgrimes	 * yes? So we find the one s/he wants with the help of JobMatchShell
24091590Srgrimes	 * and set things up the right way. shellPath will be set up by
24101590Srgrimes	 * Job_Init.
24111590Srgrimes	 */
24121590Srgrimes	if (newShell.name == (char *)NULL) {
24131590Srgrimes	    Parse_Error (PARSE_FATAL, "Neither path nor name specified");
24141590Srgrimes	    return (FAILURE);
24151590Srgrimes	} else {
24161590Srgrimes	    commandShell = JobMatchShell (newShell.name);
24171590Srgrimes	    shellName = newShell.name;
24181590Srgrimes	}
24191590Srgrimes    } else {
24201590Srgrimes	/*
24211590Srgrimes	 * The user provided a path. If s/he gave nothing else (fullSpec is
24221590Srgrimes	 * FALSE), try and find a matching shell in the ones we know of.
24231590Srgrimes	 * Else we just take the specification at its word and copy it
24241590Srgrimes	 * to a new location. In either case, we need to record the
24251590Srgrimes	 * path the user gave for the shell.
24261590Srgrimes	 */
24271590Srgrimes	shellPath = path;
24281590Srgrimes	path = strrchr (path, '/');
24291590Srgrimes	if (path == (char *)NULL) {
24301590Srgrimes	    path = shellPath;
24311590Srgrimes	} else {
24321590Srgrimes	    path += 1;
24331590Srgrimes	}
24341590Srgrimes	if (newShell.name != (char *)NULL) {
24351590Srgrimes	    shellName = newShell.name;
24361590Srgrimes	} else {
24371590Srgrimes	    shellName = path;
24381590Srgrimes	}
24391590Srgrimes	if (!fullSpec) {
24401590Srgrimes	    commandShell = JobMatchShell (shellName);
24411590Srgrimes	} else {
24421590Srgrimes	    commandShell = (Shell *) emalloc(sizeof(Shell));
24431590Srgrimes	    *commandShell = newShell;
24441590Srgrimes	}
24451590Srgrimes    }
24461590Srgrimes
24471590Srgrimes    if (commandShell->echoOn && commandShell->echoOff) {
24481590Srgrimes	commandShell->hasEchoCtl = TRUE;
24491590Srgrimes    }
24508874Srgrimes
24511590Srgrimes    if (!commandShell->hasErrCtl) {
24521590Srgrimes	if (commandShell->errCheck == (char *)NULL) {
24531590Srgrimes	    commandShell->errCheck = "";
24541590Srgrimes	}
24551590Srgrimes	if (commandShell->ignErr == (char *)NULL) {
24561590Srgrimes	    commandShell->ignErr = "%s\n";
24571590Srgrimes	}
24581590Srgrimes    }
24598874Srgrimes
24601590Srgrimes    /*
24611590Srgrimes     * Do not free up the words themselves, since they might be in use by the
24621590Srgrimes     * shell specification...
24631590Srgrimes     */
24641590Srgrimes    free (words);
24651590Srgrimes    return SUCCESS;
24661590Srgrimes}
24671590Srgrimes
24681590Srgrimes/*-
24691590Srgrimes *-----------------------------------------------------------------------
24701590Srgrimes * JobInterrupt --
24711590Srgrimes *	Handle the receipt of an interrupt.
24721590Srgrimes *
24731590Srgrimes * Results:
24741590Srgrimes *	None
24751590Srgrimes *
24761590Srgrimes * Side Effects:
24771590Srgrimes *	All children are killed. Another job will be started if the
24781590Srgrimes *	.INTERRUPT target was given.
24791590Srgrimes *-----------------------------------------------------------------------
24801590Srgrimes */
24811590Srgrimesstatic void
24821590SrgrimesJobInterrupt (runINTERRUPT)
24831590Srgrimes    int	    runINTERRUPT;   	/* Non-zero if commands for the .INTERRUPT
24841590Srgrimes				 * target should be executed */
24851590Srgrimes{
24861590Srgrimes    LstNode 	  ln;		/* element in job table */
24871590Srgrimes    Job           *job;	    	/* job descriptor in that element */
24881590Srgrimes    GNode         *interrupt;	/* the node describing the .INTERRUPT target */
24898874Srgrimes
24901590Srgrimes    aborting = ABORT_INTERRUPT;
24911590Srgrimes
24921590Srgrimes    (void)Lst_Open (jobs);
24931590Srgrimes    while ((ln = Lst_Next (jobs)) != NILLNODE) {
24941590Srgrimes	job = (Job *) Lst_Datum (ln);
24951590Srgrimes
24961590Srgrimes	if (!Targ_Precious (job->node)) {
24971590Srgrimes	    char  	*file = (job->node->path == (char *)NULL ?
24981590Srgrimes				 job->node->name :
24991590Srgrimes				 job->node->path);
25005814Sjkh	    struct stat st;
25018874Srgrimes	    if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) &&
25025814Sjkh		unlink(file) != -1) {
25031590Srgrimes		Error ("*** %s removed", file);
25041590Srgrimes	    }
25051590Srgrimes	}
25061590Srgrimes#ifdef RMT_WANTS_SIGNALS
25071590Srgrimes	if (job->flags & JOB_REMOTE) {
25081590Srgrimes	    /*
25091590Srgrimes	     * If job is remote, let the Rmt module do the killing.
25101590Srgrimes	     */
25111590Srgrimes	    if (!Rmt_Signal(job, SIGINT)) {
25121590Srgrimes		/*
25131590Srgrimes		 * If couldn't kill the thing, finish it out now with an
25141590Srgrimes		 * error code, since no exit report will come in likely.
25151590Srgrimes		 */
25161590Srgrimes		union wait status;
25171590Srgrimes
25181590Srgrimes		status.w_status = 0;
25191590Srgrimes		status.w_retcode = 1;
25201590Srgrimes		JobFinish(job, status);
25211590Srgrimes	    }
25221590Srgrimes	} else if (job->pid) {
25231590Srgrimes	    KILL(job->pid, SIGINT);
25241590Srgrimes	}
25251590Srgrimes#else
25261590Srgrimes	if (job->pid) {
25271590Srgrimes	    KILL(job->pid, SIGINT);
25281590Srgrimes	}
25291590Srgrimes#endif /* RMT_WANTS_SIGNALS */
25301590Srgrimes    }
25311590Srgrimes    Lst_Close (jobs);
25321590Srgrimes
25331590Srgrimes    if (runINTERRUPT && !touchFlag) {
25341590Srgrimes	interrupt = Targ_FindNode (".INTERRUPT", TARG_NOCREATE);
25351590Srgrimes	if (interrupt != NILGNODE) {
25361590Srgrimes	    ignoreErrors = FALSE;
25371590Srgrimes
25381590Srgrimes	    JobStart (interrupt, JOB_IGNDOTS, (Job *)0);
25391590Srgrimes	    while (nJobs) {
25401590Srgrimes		Job_CatchOutput();
25411590Srgrimes#ifndef RMT_WILL_WATCH
25421590Srgrimes		Job_CatchChildren (!usePipes);
25431590Srgrimes#endif /* RMT_WILL_WATCH */
25441590Srgrimes	    }
25451590Srgrimes	}
25461590Srgrimes    }
25471590Srgrimes    (void) unlink (tfile);
25481590Srgrimes    exit (0);
25491590Srgrimes}
25501590Srgrimes
25511590Srgrimes/*
25521590Srgrimes *-----------------------------------------------------------------------
25531590Srgrimes * Job_End --
25541590Srgrimes *	Do final processing such as the running of the commands
25558874Srgrimes *	attached to the .END target.
25561590Srgrimes *
25571590Srgrimes * Results:
25581590Srgrimes *	Number of errors reported.
25591590Srgrimes *
25601590Srgrimes * Side Effects:
25611590Srgrimes *	The process' temporary file (tfile) is removed if it still
25621590Srgrimes *	existed.
25631590Srgrimes *-----------------------------------------------------------------------
25641590Srgrimes */
25651590Srgrimesint
25661590SrgrimesJob_End ()
25671590Srgrimes{
25681590Srgrimes    if (postCommands != NILGNODE && !Lst_IsEmpty (postCommands->commands)) {
25691590Srgrimes	if (errors) {
25701590Srgrimes	    Error ("Errors reported so .END ignored");
25711590Srgrimes	} else {
25721590Srgrimes	    JobStart (postCommands, JOB_SPECIAL | JOB_IGNDOTS,
25731590Srgrimes		       (Job *)0);
25741590Srgrimes
25751590Srgrimes	    while (nJobs) {
25761590Srgrimes		Job_CatchOutput();
25771590Srgrimes#ifndef RMT_WILL_WATCH
25781590Srgrimes		Job_CatchChildren (!usePipes);
25791590Srgrimes#endif /* RMT_WILL_WATCH */
25801590Srgrimes	    }
25811590Srgrimes	}
25821590Srgrimes    }
25831590Srgrimes    (void) unlink (tfile);
25841590Srgrimes    return(errors);
25851590Srgrimes}
25861590Srgrimes
25871590Srgrimes/*-
25881590Srgrimes *-----------------------------------------------------------------------
25891590Srgrimes * Job_Wait --
25901590Srgrimes *	Waits for all running jobs to finish and returns. Sets 'aborting'
25911590Srgrimes *	to ABORT_WAIT to prevent other jobs from starting.
25921590Srgrimes *
25931590Srgrimes * Results:
25941590Srgrimes *	None.
25951590Srgrimes *
25961590Srgrimes * Side Effects:
25971590Srgrimes *	Currently running jobs finish.
25981590Srgrimes *
25991590Srgrimes *-----------------------------------------------------------------------
26001590Srgrimes */
26011590Srgrimesvoid
26021590SrgrimesJob_Wait()
26031590Srgrimes{
26041590Srgrimes    aborting = ABORT_WAIT;
26051590Srgrimes    while (nJobs != 0) {
26061590Srgrimes	Job_CatchOutput();
26071590Srgrimes#ifndef RMT_WILL_WATCH
26081590Srgrimes	Job_CatchChildren(!usePipes);
26091590Srgrimes#endif /* RMT_WILL_WATCH */
26101590Srgrimes    }
26111590Srgrimes    aborting = 0;
26121590Srgrimes}
26131590Srgrimes
26141590Srgrimes/*-
26151590Srgrimes *-----------------------------------------------------------------------
26161590Srgrimes * Job_AbortAll --
26171590Srgrimes *	Abort all currently running jobs without handling output or anything.
26181590Srgrimes *	This function is to be called only in the event of a major
26191590Srgrimes *	error. Most definitely NOT to be called from JobInterrupt.
26201590Srgrimes *
26211590Srgrimes * Results:
26221590Srgrimes *	None
26231590Srgrimes *
26241590Srgrimes * Side Effects:
26251590Srgrimes *	All children are killed, not just the firstborn
26261590Srgrimes *-----------------------------------------------------------------------
26271590Srgrimes */
26281590Srgrimesvoid
26291590SrgrimesJob_AbortAll ()
26301590Srgrimes{
26311590Srgrimes    LstNode           	ln;		/* element in job table */
26321590Srgrimes    Job            	*job;	/* the job descriptor in that element */
26331590Srgrimes    int     	  	foo;
26348874Srgrimes
26351590Srgrimes    aborting = ABORT_ERROR;
26368874Srgrimes
26371590Srgrimes    if (nJobs) {
26381590Srgrimes
26391590Srgrimes	(void)Lst_Open (jobs);
26401590Srgrimes	while ((ln = Lst_Next (jobs)) != NILLNODE) {
26411590Srgrimes	    job = (Job *) Lst_Datum (ln);
26421590Srgrimes
26431590Srgrimes	    /*
26441590Srgrimes	     * kill the child process with increasingly drastic signals to make
26458874Srgrimes	     * darn sure it's dead.
26461590Srgrimes	     */
26471590Srgrimes#ifdef RMT_WANTS_SIGNALS
26481590Srgrimes	    if (job->flags & JOB_REMOTE) {
26491590Srgrimes		Rmt_Signal(job, SIGINT);
26501590Srgrimes		Rmt_Signal(job, SIGKILL);
26511590Srgrimes	    } else {
26521590Srgrimes		KILL(job->pid, SIGINT);
26531590Srgrimes		KILL(job->pid, SIGKILL);
26541590Srgrimes	    }
26551590Srgrimes#else
26561590Srgrimes	    KILL(job->pid, SIGINT);
26571590Srgrimes	    KILL(job->pid, SIGKILL);
26581590Srgrimes#endif /* RMT_WANTS_SIGNALS */
26591590Srgrimes	}
26601590Srgrimes    }
26618874Srgrimes
26621590Srgrimes    /*
26631590Srgrimes     * Catch as many children as want to report in at first, then give up
26641590Srgrimes     */
26651590Srgrimes    while (wait3(&foo, WNOHANG, (struct rusage *)0) > 0)
26661590Srgrimes	continue;
26671590Srgrimes    (void) unlink (tfile);
26681590Srgrimes}
2669