job.c revision 103503
11590Srgrimes/* 294589Sobrien * Copyright (c) 1988, 1989, 1990, 1993 394589Sobrien * The Regents of the University of California. All rights reserved. 45814Sjkh * Copyright (c) 1988, 1989 by Adam de Boor 51590Srgrimes * Copyright (c) 1989 by Berkeley Softworks 61590Srgrimes * All rights reserved. 71590Srgrimes * 81590Srgrimes * This code is derived from software contributed to Berkeley by 91590Srgrimes * Adam de Boor. 101590Srgrimes * 111590Srgrimes * Redistribution and use in source and binary forms, with or without 121590Srgrimes * modification, are permitted provided that the following conditions 131590Srgrimes * are met: 141590Srgrimes * 1. Redistributions of source code must retain the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer. 161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171590Srgrimes * notice, this list of conditions and the following disclaimer in the 181590Srgrimes * documentation and/or other materials provided with the distribution. 191590Srgrimes * 3. All advertising materials mentioning features or use of this software 201590Srgrimes * must display the following acknowledgement: 211590Srgrimes * This product includes software developed by the University of 221590Srgrimes * California, Berkeley and its contributors. 231590Srgrimes * 4. Neither the name of the University nor the names of its contributors 241590Srgrimes * may be used to endorse or promote products derived from this software 251590Srgrimes * without specific prior written permission. 261590Srgrimes * 271590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 281590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 291590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 301590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 311590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 321590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 331590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 341590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 351590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 361590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 371590Srgrimes * SUCH DAMAGE. 3862833Swsanchez * 3962833Swsanchez * @(#)job.c 8.2 (Berkeley) 3/19/94 401590Srgrimes */ 411590Srgrimes 4262833Swsanchez#include <sys/cdefs.h> 4394587Sobrien__FBSDID("$FreeBSD: head/usr.bin/make/job.c 103503 2002-09-17 21:29:06Z jmallett $"); 441590Srgrimes 4535483Simp#ifndef OLD_JOKE 46103503Sjmallett#define OLD_JOKE 0 4735483Simp#endif /* OLD_JOKE */ 4835483Simp 491590Srgrimes/*- 501590Srgrimes * job.c -- 511590Srgrimes * handle the creation etc. of our child processes. 521590Srgrimes * 531590Srgrimes * Interface: 541590Srgrimes * Job_Make Start the creation of the given target. 551590Srgrimes * 561590Srgrimes * Job_CatchChildren Check for and handle the termination of any 571590Srgrimes * children. This must be called reasonably 581590Srgrimes * frequently to keep the whole make going at 591590Srgrimes * a decent clip, since job table entries aren't 601590Srgrimes * removed until their process is caught this way. 611590Srgrimes * Its single argument is TRUE if the function 621590Srgrimes * should block waiting for a child to terminate. 631590Srgrimes * 641590Srgrimes * Job_CatchOutput Print any output our children have produced. 651590Srgrimes * Should also be called fairly frequently to 661590Srgrimes * keep the user informed of what's going on. 671590Srgrimes * If no output is waiting, it will block for 681590Srgrimes * a time given by the SEL_* constants, below, 691590Srgrimes * or until output is ready. 701590Srgrimes * 711590Srgrimes * Job_Init Called to intialize this module. in addition, 721590Srgrimes * any commands attached to the .BEGIN target 731590Srgrimes * are executed before this function returns. 741590Srgrimes * Hence, the makefile must have been parsed 751590Srgrimes * before this function is called. 761590Srgrimes * 771590Srgrimes * Job_Full Return TRUE if the job table is filled. 781590Srgrimes * 791590Srgrimes * Job_Empty Return TRUE if the job table is completely 801590Srgrimes * empty. 811590Srgrimes * 821590Srgrimes * Job_ParseShell Given the line following a .SHELL target, parse 831590Srgrimes * the line as a shell specification. Returns 841590Srgrimes * FAILURE if the spec was incorrect. 851590Srgrimes * 8694594Sobrien * Job_Finish Perform any final processing which needs doing. 871590Srgrimes * This includes the execution of any commands 881590Srgrimes * which have been/were attached to the .END 891590Srgrimes * target. It should only be called when the 901590Srgrimes * job table is empty. 911590Srgrimes * 921590Srgrimes * Job_AbortAll Abort all currently running jobs. It doesn't 931590Srgrimes * handle output or do anything for the jobs, 941590Srgrimes * just kills them. It should only be called in 951590Srgrimes * an emergency, as it were. 961590Srgrimes * 971590Srgrimes * Job_CheckCommands Verify that the commands for a target are 981590Srgrimes * ok. Provide them if necessary and possible. 991590Srgrimes * 1001590Srgrimes * Job_Touch Update a target without really updating it. 1011590Srgrimes * 1021590Srgrimes * Job_Wait Wait for all currently-running jobs to finish. 1031590Srgrimes */ 1041590Srgrimes 1051590Srgrimes#include <sys/types.h> 1061590Srgrimes#include <sys/stat.h> 1071590Srgrimes#include <sys/file.h> 1081590Srgrimes#include <sys/time.h> 1091590Srgrimes#include <sys/wait.h> 11094506Scharnier#include <err.h> 11194506Scharnier#include <errno.h> 1125814Sjkh#include <fcntl.h> 1131590Srgrimes#include <stdio.h> 1141590Srgrimes#include <string.h> 1155814Sjkh#include <signal.h> 11680381Ssheldonh#include <unistd.h> 11794506Scharnier#include <utime.h> 1181590Srgrimes#include "make.h" 1191590Srgrimes#include "hash.h" 1201590Srgrimes#include "dir.h" 1211590Srgrimes#include "job.h" 1221590Srgrimes#include "pathnames.h" 12318730Ssteve#ifdef REMOTE 12418730Ssteve#include "rmt.h" 12518730Ssteve# define STATIC 12618730Ssteve#else 12718730Ssteve# define STATIC static 12818730Ssteve#endif 1291590Srgrimes 1301590Srgrimes/* 1318874Srgrimes * error handling variables 1321590Srgrimes */ 1331590Srgrimesstatic int errors = 0; /* number of errors reported */ 1341590Srgrimesstatic int aborting = 0; /* why is the make aborting? */ 135103503Sjmallett#define ABORT_ERROR 1 /* Because of an error */ 136103503Sjmallett#define ABORT_INTERRUPT 2 /* Because it was interrupted */ 137103503Sjmallett#define ABORT_WAIT 3 /* Waiting for jobs to finish */ 1381590Srgrimes 13918730Ssteve/* 14018730Ssteve * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file 14118730Ssteve * is a char! So when we go above 127 we turn negative! 14218730Ssteve */ 143103503Sjmallett#define FILENO(a) ((unsigned) fileno(a)) 1441590Srgrimes 1451590Srgrimes/* 1461590Srgrimes * post-make command processing. The node postCommands is really just the 1471590Srgrimes * .END target but we keep it around to avoid having to search for it 1481590Srgrimes * all the time. 1491590Srgrimes */ 1501590Srgrimesstatic GNode *postCommands; /* node containing commands to execute when 1511590Srgrimes * everything else is done */ 1521590Srgrimesstatic int numCommands; /* The number of commands actually printed 1531590Srgrimes * for a target. Should this number be 1541590Srgrimes * 0, no shell will be executed. */ 1551590Srgrimes 1561590Srgrimes/* 1571590Srgrimes * Return values from JobStart. 1581590Srgrimes */ 159103503Sjmallett#define JOB_RUNNING 0 /* Job is running */ 160103503Sjmallett#define JOB_ERROR 1 /* Error in starting the job */ 161103503Sjmallett#define JOB_FINISHED 2 /* The job is already finished */ 162103503Sjmallett#define JOB_STOPPED 3 /* The job is stopped */ 1631590Srgrimes 1641590Srgrimes/* 16568898Skris * tfile is used to build temp file names to store shell commands to 16668898Skris * execute. 16768898Skris */ 16868898Skrisstatic char tfile[sizeof(TMPPAT)]; 16968898Skris 17068898Skris 17168898Skris/* 1721590Srgrimes * Descriptions for various shells. 1731590Srgrimes */ 1741590Srgrimesstatic Shell shells[] = { 1751590Srgrimes /* 1761590Srgrimes * CSH description. The csh can do echo control by playing 1771590Srgrimes * with the setting of the 'echo' shell variable. Sadly, 1781590Srgrimes * however, it is unable to do error control nicely. 1791590Srgrimes */ 1801590Srgrimes{ 1811590Srgrimes "csh", 1821590Srgrimes TRUE, "unset verbose", "set verbose", "unset verbose", 10, 1831590Srgrimes FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"", 1841590Srgrimes "v", "e", 1851590Srgrimes}, 1861590Srgrimes /* 1871590Srgrimes * SH description. Echo control is also possible and, under 1881590Srgrimes * sun UNIX anyway, one can even control error checking. 1891590Srgrimes */ 1901590Srgrimes{ 1911590Srgrimes "sh", 1921590Srgrimes TRUE, "set -", "set -v", "set -", 5, 19318730Ssteve TRUE, "set -e", "set +e", 19418730Ssteve#ifdef OLDBOURNESHELL 1951590Srgrimes FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", 19618730Ssteve#endif 1971590Srgrimes "v", "e", 1981590Srgrimes}, 1991590Srgrimes /* 20064739Sgreen * KSH description. The Korn shell has a superset of 20164739Sgreen * the Bourne shell's functionality. 20264739Sgreen */ 20364739Sgreen{ 20464739Sgreen "ksh", 20564739Sgreen TRUE, "set -", "set -v", "set -", 5, 20664739Sgreen TRUE, "set -e", "set +e", 20764739Sgreen "v", "e", 20864739Sgreen}, 20964739Sgreen /* 2101590Srgrimes * UNKNOWN. 2111590Srgrimes */ 2121590Srgrimes{ 21318730Ssteve (char *) 0, 21418730Ssteve FALSE, (char *) 0, (char *) 0, (char *) 0, 0, 21518730Ssteve FALSE, (char *) 0, (char *) 0, 21618730Ssteve (char *) 0, (char *) 0, 2171590Srgrimes} 2181590Srgrimes}; 2191590Srgrimesstatic Shell *commandShell = &shells[DEFSHELL];/* this is the shell to 2201590Srgrimes * which we pass all 2211590Srgrimes * commands in the Makefile. 2221590Srgrimes * It is set by the 2231590Srgrimes * Job_ParseShell function */ 22418730Sstevestatic char *shellPath = NULL, /* full pathname of 2251590Srgrimes * executable image */ 2261590Srgrimes *shellName; /* last component of shell */ 2271590Srgrimes 2281590Srgrimes 2291590Srgrimesstatic int maxJobs; /* The most children we can run at once */ 2301590Srgrimesstatic int maxLocal; /* The most local ones we can have */ 23118730SsteveSTATIC int nJobs; /* The number of children currently running */ 23218730SsteveSTATIC int nLocal; /* The number of local children */ 23318730SsteveSTATIC Lst jobs; /* The structures that describe them */ 23418730SsteveSTATIC Boolean jobFull; /* Flag to tell when the job table is full. It 2351590Srgrimes * is set TRUE when (1) the total number of 2361590Srgrimes * running jobs equals the maximum allowed or 2371590Srgrimes * (2) a job can only be run locally, but 2381590Srgrimes * nLocal equals maxLocal */ 2391590Srgrimes#ifndef RMT_WILL_WATCH 2401590Srgrimesstatic fd_set outputs; /* Set of descriptors of pipes connected to 2411590Srgrimes * the output channels of children */ 2421590Srgrimes#endif 2431590Srgrimes 24418730SsteveSTATIC GNode *lastNode; /* The node for which output was most recently 2451590Srgrimes * produced. */ 24618730SsteveSTATIC char *targFmt; /* Format string to use to head output from a 2471590Srgrimes * job when it's not the most-recent job heard 2481590Srgrimes * from */ 2491590Srgrimes 25018730Ssteve#ifdef REMOTE 25118730Ssteve# define TARG_FMT "--- %s at %s ---\n" /* Default format */ 25218730Ssteve# define MESSAGE(fp, gn) \ 25318730Ssteve (void) fprintf(fp, targFmt, gn->name, gn->rem.hname); 25418730Ssteve#else 25518730Ssteve# define TARG_FMT "--- %s ---\n" /* Default format */ 25618730Ssteve# define MESSAGE(fp, gn) \ 25718730Ssteve (void) fprintf(fp, targFmt, gn->name); 25818730Ssteve#endif 25918730Ssteve 2601590Srgrimes/* 2611590Srgrimes * When JobStart attempts to run a job remotely but can't, and isn't allowed 2621590Srgrimes * to run the job locally, or when Job_CatchChildren detects a job that has 2631590Srgrimes * been migrated home, the job is placed on the stoppedJobs queue to be run 2648874Srgrimes * when the next job finishes. 2651590Srgrimes */ 26618730SsteveSTATIC Lst stoppedJobs; /* Lst of Job structures describing 2671590Srgrimes * jobs that were stopped due to concurrency 2681590Srgrimes * limits or migration home */ 2691590Srgrimes 2701590Srgrimes 2711590Srgrimes#if defined(USE_PGRP) && defined(SYSV) 27218730Ssteve# define KILL(pid, sig) killpg(-(pid), (sig)) 2731590Srgrimes#else 2741590Srgrimes# if defined(USE_PGRP) 27518730Ssteve# define KILL(pid, sig) killpg((pid), (sig)) 2761590Srgrimes# else 27718730Ssteve# define KILL(pid, sig) kill((pid), (sig)) 2781590Srgrimes# endif 2791590Srgrimes#endif 2801590Srgrimes 28118730Ssteve/* 28218730Ssteve * Grmpf... There is no way to set bits of the wait structure 28318730Ssteve * anymore with the stupid W*() macros. I liked the union wait 28418730Ssteve * stuff much more. So, we devise our own macros... This is 28518730Ssteve * really ugly, use dramamine sparingly. You have been warned. 28618730Ssteve */ 287103503Sjmallett#define W_SETMASKED(st, val, fun) \ 28818730Ssteve { \ 28918730Ssteve int sh = (int) ~0; \ 29018730Ssteve int mask = fun(sh); \ 29118730Ssteve \ 29218730Ssteve for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \ 29318730Ssteve continue; \ 29418730Ssteve *(st) = (*(st) & ~mask) | ((val) << sh); \ 29518730Ssteve } 29618730Ssteve 297103503Sjmallett#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) 298103503Sjmallett#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) 29918730Ssteve 30018730Ssteve 30192921Simpstatic int JobCondPassSig(void *, void *); 30292921Simpstatic void JobPassSig(int); 30392921Simpstatic int JobCmpPid(void *, void *); 30492921Simpstatic int JobPrintCommand(void *, void *); 30592921Simpstatic int JobSaveCommand(void *, void *); 30692921Simpstatic void JobClose(Job *); 30718730Ssteve#ifdef REMOTE 30892921Simpstatic int JobCmpRmtID(Job *, int); 30918730Ssteve# ifdef RMT_WILL_WATCH 31092921Simpstatic void JobLocalInput(int, Job *); 31118730Ssteve# endif 31218730Ssteve#else 31392921Simpstatic void JobFinish(Job *, int *); 31492921Simpstatic void JobExec(Job *, char **); 31518730Ssteve#endif 31692921Simpstatic void JobMakeArgv(Job *, char **); 31792921Simpstatic void JobRestart(Job *); 31892921Simpstatic int JobStart(GNode *, int, Job *); 31992921Simpstatic char *JobOutput(Job *, char *, char *, int); 32092921Simpstatic void JobDoOutput(Job *, Boolean); 32192921Simpstatic Shell *JobMatchShell(char *); 32292921Simpstatic void JobInterrupt(int, int); 32392921Simpstatic void JobRestartJobs(void); 3241590Srgrimes 3251590Srgrimes/*- 3261590Srgrimes *----------------------------------------------------------------------- 3271590Srgrimes * JobCondPassSig -- 3281590Srgrimes * Pass a signal to a job if the job is remote or if USE_PGRP 3291590Srgrimes * is defined. 3301590Srgrimes * 3311590Srgrimes * Results: 3321590Srgrimes * === 0 3331590Srgrimes * 3341590Srgrimes * Side Effects: 3351590Srgrimes * None, except the job may bite it. 3361590Srgrimes * 3371590Srgrimes *----------------------------------------------------------------------- 3381590Srgrimes */ 3391590Srgrimesstatic int 3405814SjkhJobCondPassSig(jobp, signop) 34169531Swill void * jobp; /* Job to biff */ 34269531Swill void * signop; /* Signal to send it */ 3431590Srgrimes{ 3445814Sjkh Job *job = (Job *) jobp; 3455814Sjkh int signo = *(int *) signop; 3461590Srgrimes#ifdef RMT_WANTS_SIGNALS 3471590Srgrimes if (job->flags & JOB_REMOTE) { 34818730Ssteve (void) Rmt_Signal(job, signo); 3491590Srgrimes } else { 3501590Srgrimes KILL(job->pid, signo); 3511590Srgrimes } 3521590Srgrimes#else 3531590Srgrimes /* 3541590Srgrimes * Assume that sending the signal to job->pid will signal any remote 3551590Srgrimes * job as well. 3561590Srgrimes */ 35718730Ssteve if (DEBUG(JOB)) { 35818730Ssteve (void) fprintf(stdout, 35918730Ssteve "JobCondPassSig passing signal %d to child %d.\n", 36018730Ssteve signo, job->pid); 36118730Ssteve (void) fflush(stdout); 36218730Ssteve } 3631590Srgrimes KILL(job->pid, signo); 3641590Srgrimes#endif 36518730Ssteve return 0; 3661590Srgrimes} 3671590Srgrimes 3681590Srgrimes/*- 3691590Srgrimes *----------------------------------------------------------------------- 3701590Srgrimes * JobPassSig -- 3711590Srgrimes * Pass a signal on to all remote jobs and to all local jobs if 3721590Srgrimes * USE_PGRP is defined, then die ourselves. 3731590Srgrimes * 3741590Srgrimes * Results: 3751590Srgrimes * None. 3761590Srgrimes * 3771590Srgrimes * Side Effects: 3781590Srgrimes * We die by the same signal. 3798874Srgrimes * 3801590Srgrimes *----------------------------------------------------------------------- 3811590Srgrimes */ 3821590Srgrimesstatic void 3831590SrgrimesJobPassSig(signo) 3841590Srgrimes int signo; /* The signal number we've received */ 3851590Srgrimes{ 38618730Ssteve sigset_t nmask, omask; 38718730Ssteve struct sigaction act; 3888874Srgrimes 38918730Ssteve if (DEBUG(JOB)) { 39018730Ssteve (void) fprintf(stdout, "JobPassSig(%d) called.\n", signo); 39118730Ssteve (void) fflush(stdout); 39218730Ssteve } 39369531Swill Lst_ForEach(jobs, JobCondPassSig, (void *) &signo); 3941590Srgrimes 3951590Srgrimes /* 3961590Srgrimes * Deal with proper cleanup based on the signal received. We only run 3971590Srgrimes * the .INTERRUPT target if the signal was in fact an interrupt. The other 3981590Srgrimes * three termination signals are more of a "get out *now*" command. 3991590Srgrimes */ 4001590Srgrimes if (signo == SIGINT) { 40118730Ssteve JobInterrupt(TRUE, signo); 4021590Srgrimes } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { 40318730Ssteve JobInterrupt(FALSE, signo); 4041590Srgrimes } 4058874Srgrimes 4061590Srgrimes /* 4071590Srgrimes * Leave gracefully if SIGQUIT, rather than core dumping. 4081590Srgrimes */ 4091590Srgrimes if (signo == SIGQUIT) { 41038520Scracauer signo = SIGINT; 4111590Srgrimes } 4128874Srgrimes 4131590Srgrimes /* 4141590Srgrimes * Send ourselves the signal now we've given the message to everyone else. 4151590Srgrimes * Note we block everything else possible while we're getting the signal. 4161590Srgrimes * This ensures that all our jobs get continued when we wake up before 4171590Srgrimes * we take any other signal. 4181590Srgrimes */ 41918730Ssteve sigemptyset(&nmask); 42018730Ssteve sigaddset(&nmask, signo); 42118730Ssteve sigprocmask(SIG_SETMASK, &nmask, &omask); 42218730Ssteve act.sa_handler = SIG_DFL; 42318730Ssteve sigemptyset(&act.sa_mask); 42418730Ssteve act.sa_flags = 0; 42518730Ssteve sigaction(signo, &act, NULL); 4261590Srgrimes 42718730Ssteve if (DEBUG(JOB)) { 42818730Ssteve (void) fprintf(stdout, 42918730Ssteve "JobPassSig passing signal to self, mask = %x.\n", 43018730Ssteve ~0 & ~(1 << (signo-1))); 43118730Ssteve (void) fflush(stdout); 43218730Ssteve } 43318730Ssteve (void) signal(signo, SIG_DFL); 4341590Srgrimes 43518730Ssteve (void) KILL(getpid(), signo); 43618730Ssteve 4375814Sjkh signo = SIGCONT; 43869531Swill Lst_ForEach(jobs, JobCondPassSig, (void *) &signo); 4391590Srgrimes 44018730Ssteve (void) sigprocmask(SIG_SETMASK, &omask, NULL); 44118730Ssteve sigprocmask(SIG_SETMASK, &omask, NULL); 44218730Ssteve act.sa_handler = JobPassSig; 44318730Ssteve sigaction(signo, &act, NULL); 4441590Srgrimes} 4451590Srgrimes 4461590Srgrimes/*- 4471590Srgrimes *----------------------------------------------------------------------- 4481590Srgrimes * JobCmpPid -- 4491590Srgrimes * Compare the pid of the job with the given pid and return 0 if they 4501590Srgrimes * are equal. This function is called from Job_CatchChildren via 4511590Srgrimes * Lst_Find to find the job descriptor of the finished job. 4521590Srgrimes * 4531590Srgrimes * Results: 4541590Srgrimes * 0 if the pid's match 4551590Srgrimes * 4561590Srgrimes * Side Effects: 4571590Srgrimes * None 4581590Srgrimes *----------------------------------------------------------------------- 4591590Srgrimes */ 4601590Srgrimesstatic int 46118730SsteveJobCmpPid(job, pid) 46269531Swill void * job; /* job to examine */ 46369531Swill void * pid; /* process id desired */ 4641590Srgrimes{ 46518730Ssteve return *(int *) pid - ((Job *) job)->pid; 4661590Srgrimes} 4671590Srgrimes 46818730Ssteve#ifdef REMOTE 4691590Srgrimes/*- 4701590Srgrimes *----------------------------------------------------------------------- 47118730Ssteve * JobCmpRmtID -- 47218730Ssteve * Compare the rmtID of the job with the given rmtID and return 0 if they 47318730Ssteve * are equal. 47418730Ssteve * 47518730Ssteve * Results: 47618730Ssteve * 0 if the rmtID's match 47718730Ssteve * 47818730Ssteve * Side Effects: 47918730Ssteve * None. 48018730Ssteve *----------------------------------------------------------------------- 48118730Ssteve */ 48218730Sstevestatic int 48318730SsteveJobCmpRmtID(job, rmtID) 48469531Swill void * job; /* job to examine */ 48569531Swill void * rmtID; /* remote id desired */ 48618730Ssteve{ 48718730Ssteve return(*(int *) rmtID - *(int *) job->rmtID); 48818730Ssteve} 48918730Ssteve#endif 49018730Ssteve 49118730Ssteve/*- 49218730Ssteve *----------------------------------------------------------------------- 4931590Srgrimes * JobPrintCommand -- 4941590Srgrimes * Put out another command for the given job. If the command starts 4951590Srgrimes * with an @ or a - we process it specially. In the former case, 4961590Srgrimes * so long as the -s and -n flags weren't given to make, we stick 4971590Srgrimes * a shell-specific echoOff command in the script. In the latter, 4981590Srgrimes * we ignore errors for the entire job, unless the shell has error 4991590Srgrimes * control. 5001590Srgrimes * If the command is just "..." we take all future commands for this 5011590Srgrimes * job to be commands to be executed once the entire graph has been 5021590Srgrimes * made and return non-zero to signal that the end of the commands 5031590Srgrimes * was reached. These commands are later attached to the postCommands 50494594Sobrien * node and executed by Job_Finish when all things are done. 5051590Srgrimes * This function is called from JobStart via Lst_ForEach. 5061590Srgrimes * 5071590Srgrimes * Results: 5081590Srgrimes * Always 0, unless the command was "..." 5091590Srgrimes * 5101590Srgrimes * Side Effects: 5111590Srgrimes * If the command begins with a '-' and the shell has no error control, 5121590Srgrimes * the JOB_IGNERR flag is set in the job descriptor. 5131590Srgrimes * If the command is "..." and we're not ignoring such things, 5141590Srgrimes * tailCmds is set to the successor node of the cmd. 5151590Srgrimes * numCommands is incremented if the command is actually printed. 5161590Srgrimes *----------------------------------------------------------------------- 5171590Srgrimes */ 5181590Srgrimesstatic int 51918730SsteveJobPrintCommand(cmdp, jobp) 52069531Swill void * cmdp; /* command string to print */ 52169531Swill void * jobp; /* job for which to print it */ 5221590Srgrimes{ 5231590Srgrimes Boolean noSpecials; /* true if we shouldn't worry about 5241590Srgrimes * inserting special commands into 5251590Srgrimes * the input stream. */ 5261590Srgrimes Boolean shutUp = FALSE; /* true if we put a no echo command 5271590Srgrimes * into the command file */ 5281590Srgrimes Boolean errOff = FALSE; /* true if we turned error checking 5291590Srgrimes * off before printing the command 5301590Srgrimes * and need to turn it back on */ 5311590Srgrimes char *cmdTemplate; /* Template to use when printing the 5321590Srgrimes * command */ 5331590Srgrimes char *cmdStart; /* Start of expanded command */ 5341590Srgrimes LstNode cmdNode; /* Node for replacing the command */ 5355814Sjkh char *cmd = (char *) cmdp; 5368874Srgrimes Job *job = (Job *) jobp; 5371590Srgrimes 53818730Ssteve noSpecials = (noExecute && !(job->node->type & OP_MAKE)); 5391590Srgrimes 54018730Ssteve if (strcmp(cmd, "...") == 0) { 5418874Srgrimes job->node->type |= OP_SAVE_CMDS; 5421590Srgrimes if ((job->flags & JOB_IGNDOTS) == 0) { 54318730Ssteve job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, 54469531Swill (void *)cmd)); 54518730Ssteve return 1; 5461590Srgrimes } 54718730Ssteve return 0; 5481590Srgrimes } 5491590Srgrimes 550103503Sjmallett#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ 55118730Ssteve (void) fprintf(stdout, fmt, arg); \ 55218730Ssteve (void) fflush(stdout); \ 55318730Ssteve } \ 55418730Ssteve (void) fprintf(job->cmdFILE, fmt, arg); \ 55518730Ssteve (void) fflush(job->cmdFILE); 5561590Srgrimes 5571590Srgrimes numCommands += 1; 5581590Srgrimes 5591590Srgrimes /* 5601590Srgrimes * For debugging, we replace each command with the result of expanding 5611590Srgrimes * the variables in the command. 5621590Srgrimes */ 56369531Swill cmdNode = Lst_Member(job->node->commands, (void *)cmd); 56418730Ssteve cmdStart = cmd = Var_Subst(NULL, cmd, job->node, FALSE); 56569531Swill Lst_Replace(cmdNode, (void *)cmdStart); 5661590Srgrimes 5671590Srgrimes cmdTemplate = "%s\n"; 5681590Srgrimes 5691590Srgrimes /* 5701590Srgrimes * Check for leading @' and -'s to control echoing and error checking. 5711590Srgrimes */ 5721590Srgrimes while (*cmd == '@' || *cmd == '-') { 5731590Srgrimes if (*cmd == '@') { 57460569Swill shutUp = DEBUG(LOUD) ? FALSE : TRUE; 5751590Srgrimes } else { 5761590Srgrimes errOff = TRUE; 5771590Srgrimes } 5781590Srgrimes cmd++; 5791590Srgrimes } 5801590Srgrimes 5811590Srgrimes while (isspace((unsigned char) *cmd)) 5821590Srgrimes cmd++; 5831590Srgrimes 5841590Srgrimes if (shutUp) { 58518730Ssteve if (!(job->flags & JOB_SILENT) && !noSpecials && 5861590Srgrimes commandShell->hasEchoCtl) { 58718730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 5881590Srgrimes } else { 5891590Srgrimes shutUp = FALSE; 5901590Srgrimes } 5911590Srgrimes } 5921590Srgrimes 5931590Srgrimes if (errOff) { 59418730Ssteve if ( !(job->flags & JOB_IGNERR) && !noSpecials) { 5951590Srgrimes if (commandShell->hasErrCtl) { 5961590Srgrimes /* 5971590Srgrimes * we don't want the error-control commands showing 5981590Srgrimes * up either, so we turn off echoing while executing 5991590Srgrimes * them. We could put another field in the shell 6001590Srgrimes * structure to tell JobDoOutput to look for this 6011590Srgrimes * string too, but why make it any more complex than 6021590Srgrimes * it already is? 6031590Srgrimes */ 60418730Ssteve if (!(job->flags & JOB_SILENT) && !shutUp && 6051590Srgrimes commandShell->hasEchoCtl) { 60618730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 60718730Ssteve DBPRINTF("%s\n", commandShell->ignErr); 60818730Ssteve DBPRINTF("%s\n", commandShell->echoOn); 6091590Srgrimes } else { 61018730Ssteve DBPRINTF("%s\n", commandShell->ignErr); 6111590Srgrimes } 6121590Srgrimes } else if (commandShell->ignErr && 61318730Ssteve (*commandShell->ignErr != '\0')) 6141590Srgrimes { 6151590Srgrimes /* 6161590Srgrimes * The shell has no error control, so we need to be 6171590Srgrimes * weird to get it to ignore any errors from the command. 6181590Srgrimes * If echoing is turned on, we turn it off and use the 6191590Srgrimes * errCheck template to echo the command. Leave echoing 6201590Srgrimes * off so the user doesn't see the weirdness we go through 6211590Srgrimes * to ignore errors. Set cmdTemplate to use the weirdness 6221590Srgrimes * instead of the simple "%s\n" template. 6231590Srgrimes */ 62418730Ssteve if (!(job->flags & JOB_SILENT) && !shutUp && 6251590Srgrimes commandShell->hasEchoCtl) { 62618730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 62718730Ssteve DBPRINTF(commandShell->errCheck, cmd); 6281590Srgrimes shutUp = TRUE; 6291590Srgrimes } 6301590Srgrimes cmdTemplate = commandShell->ignErr; 6311590Srgrimes /* 6321590Srgrimes * The error ignoration (hee hee) is already taken care 6331590Srgrimes * of by the ignErr template, so pretend error checking 6341590Srgrimes * is still on. 6351590Srgrimes */ 6361590Srgrimes errOff = FALSE; 6371590Srgrimes } else { 6381590Srgrimes errOff = FALSE; 6391590Srgrimes } 6401590Srgrimes } else { 6411590Srgrimes errOff = FALSE; 6421590Srgrimes } 6431590Srgrimes } 6448874Srgrimes 64518730Ssteve DBPRINTF(cmdTemplate, cmd); 6468874Srgrimes 6471590Srgrimes if (errOff) { 6481590Srgrimes /* 6491590Srgrimes * If echoing is already off, there's no point in issuing the 6501590Srgrimes * echoOff command. Otherwise we issue it and pretend it was on 6511590Srgrimes * for the whole command... 6521590Srgrimes */ 6531590Srgrimes if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ 65418730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 6551590Srgrimes shutUp = TRUE; 6561590Srgrimes } 65718730Ssteve DBPRINTF("%s\n", commandShell->errCheck); 6581590Srgrimes } 6591590Srgrimes if (shutUp) { 66018730Ssteve DBPRINTF("%s\n", commandShell->echoOn); 6611590Srgrimes } 66218730Ssteve return 0; 6631590Srgrimes} 6641590Srgrimes 6651590Srgrimes/*- 6661590Srgrimes *----------------------------------------------------------------------- 6671590Srgrimes * JobSaveCommand -- 6681590Srgrimes * Save a command to be executed when everything else is done. 6691590Srgrimes * Callback function for JobFinish... 6701590Srgrimes * 6711590Srgrimes * Results: 6721590Srgrimes * Always returns 0 6731590Srgrimes * 6741590Srgrimes * Side Effects: 6751590Srgrimes * The command is tacked onto the end of postCommands's commands list. 6761590Srgrimes * 6771590Srgrimes *----------------------------------------------------------------------- 6781590Srgrimes */ 6791590Srgrimesstatic int 68018730SsteveJobSaveCommand(cmd, gn) 68169531Swill void * cmd; 68269531Swill void * gn; 6831590Srgrimes{ 68469531Swill cmd = (void *) Var_Subst(NULL, (char *) cmd, (GNode *) gn, FALSE); 68518730Ssteve (void) Lst_AtEnd(postCommands->commands, cmd); 68618730Ssteve return(0); 6871590Srgrimes} 6881590Srgrimes 68918730Ssteve 6901590Srgrimes/*- 6911590Srgrimes *----------------------------------------------------------------------- 69218730Ssteve * JobClose -- 69318730Ssteve * Called to close both input and output pipes when a job is finished. 69418730Ssteve * 69518730Ssteve * Results: 69618730Ssteve * Nada 69718730Ssteve * 69818730Ssteve * Side Effects: 69918730Ssteve * The file descriptors associated with the job are closed. 70018730Ssteve * 70118730Ssteve *----------------------------------------------------------------------- 70218730Ssteve */ 70318730Sstevestatic void 70418730SsteveJobClose(job) 70518730Ssteve Job *job; 70618730Ssteve{ 70718730Ssteve if (usePipes) { 70818730Ssteve#ifdef RMT_WILL_WATCH 70918730Ssteve Rmt_Ignore(job->inPipe); 71018730Ssteve#else 71118730Ssteve FD_CLR(job->inPipe, &outputs); 71218730Ssteve#endif 71318730Ssteve if (job->outPipe != job->inPipe) { 71418730Ssteve (void) close(job->outPipe); 71518730Ssteve } 71618730Ssteve JobDoOutput(job, TRUE); 71718730Ssteve (void) close(job->inPipe); 71818730Ssteve } else { 71918730Ssteve (void) close(job->outFd); 72018730Ssteve JobDoOutput(job, TRUE); 72118730Ssteve } 72218730Ssteve} 72318730Ssteve 72418730Ssteve/*- 72518730Ssteve *----------------------------------------------------------------------- 7261590Srgrimes * JobFinish -- 7271590Srgrimes * Do final processing for the given job including updating 7281590Srgrimes * parents and starting new jobs as available/necessary. Note 7291590Srgrimes * that we pay no attention to the JOB_IGNERR flag here. 7301590Srgrimes * This is because when we're called because of a noexecute flag 7311590Srgrimes * or something, jstat.w_status is 0 and when called from 7321590Srgrimes * Job_CatchChildren, the status is zeroed if it s/b ignored. 7331590Srgrimes * 7341590Srgrimes * Results: 7351590Srgrimes * None 7361590Srgrimes * 7371590Srgrimes * Side Effects: 7381590Srgrimes * Some nodes may be put on the toBeMade queue. 7391590Srgrimes * Final commands for the job are placed on postCommands. 7401590Srgrimes * 7411590Srgrimes * If we got an error and are aborting (aborting == ABORT_ERROR) and 7421590Srgrimes * the job list is now empty, we are done for the day. 7431590Srgrimes * If we recognized an error (errors !=0), we set the aborting flag 7441590Srgrimes * to ABORT_ERROR so no more jobs will be started. 7451590Srgrimes *----------------------------------------------------------------------- 7461590Srgrimes */ 7471590Srgrimes/*ARGSUSED*/ 7481590Srgrimesstatic void 74918730SsteveJobFinish(job, status) 75018730Ssteve Job *job; /* job to finish */ 75118730Ssteve int *status; /* sub-why job went away */ 7521590Srgrimes{ 75318730Ssteve Boolean done; 7541590Srgrimes 75518730Ssteve if ((WIFEXITED(*status) && 75618730Ssteve (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || 75718730Ssteve (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) 7581590Srgrimes { 7591590Srgrimes /* 7601590Srgrimes * If it exited non-zero and either we're doing things our 7611590Srgrimes * way or we're not ignoring errors, the job is finished. 7621590Srgrimes * Similarly, if the shell died because of a signal 7631590Srgrimes * the job is also finished. In these 7641590Srgrimes * cases, finish out the job's output before printing the exit 7651590Srgrimes * status... 7661590Srgrimes */ 76718730Ssteve#ifdef REMOTE 76818730Ssteve KILL(job->pid, SIGCONT); 76918730Ssteve#endif 77018730Ssteve JobClose(job); 7711590Srgrimes if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 77218730Ssteve (void) fclose(job->cmdFILE); 7731590Srgrimes } 7741590Srgrimes done = TRUE; 77518730Ssteve#ifdef REMOTE 77618730Ssteve if (job->flags & JOB_REMOTE) 77718730Ssteve Rmt_Done(job->rmtID, job->node); 77818730Ssteve#endif 77918730Ssteve } else if (WIFEXITED(*status)) { 7801590Srgrimes /* 7811590Srgrimes * Deal with ignored errors in -B mode. We need to print a message 7821590Srgrimes * telling of the ignored error as well as setting status.w_status 7831590Srgrimes * to 0 so the next command gets run. To do this, we set done to be 78418730Ssteve * TRUE if in -B mode and the job exited non-zero. 78518730Ssteve */ 78618730Ssteve done = WEXITSTATUS(*status) != 0; 78718730Ssteve /* 78818730Ssteve * Old comment said: "Note we don't 7891590Srgrimes * want to close down any of the streams until we know we're at the 79018730Ssteve * end." 79118730Ssteve * But we do. Otherwise when are we going to print the rest of the 79218730Ssteve * stuff? 7931590Srgrimes */ 79418730Ssteve JobClose(job); 79518730Ssteve#ifdef REMOTE 79618730Ssteve if (job->flags & JOB_REMOTE) 79718730Ssteve Rmt_Done(job->rmtID, job->node); 79818730Ssteve#endif /* REMOTE */ 7991590Srgrimes } else { 8001590Srgrimes /* 8011590Srgrimes * No need to close things down or anything. 8021590Srgrimes */ 8031590Srgrimes done = FALSE; 8041590Srgrimes } 8058874Srgrimes 8061590Srgrimes if (done || 80718730Ssteve WIFSTOPPED(*status) || 80818730Ssteve (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) || 8091590Srgrimes DEBUG(JOB)) 8101590Srgrimes { 8111590Srgrimes FILE *out; 8128874Srgrimes 81318730Ssteve if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { 8141590Srgrimes /* 8151590Srgrimes * If output is going to a file and this job is ignoring 8161590Srgrimes * errors, arrange to have the exit status sent to the 8171590Srgrimes * output file as well. 8181590Srgrimes */ 81918730Ssteve out = fdopen(job->outFd, "w"); 82094582Sobrien if (out == NULL) 82194582Sobrien Punt("Cannot fdopen"); 8221590Srgrimes } else { 8231590Srgrimes out = stdout; 8241590Srgrimes } 8251590Srgrimes 82618730Ssteve if (WIFEXITED(*status)) { 82718730Ssteve if (DEBUG(JOB)) { 82818730Ssteve (void) fprintf(stdout, "Process %d exited.\n", job->pid); 82918730Ssteve (void) fflush(stdout); 83018730Ssteve } 83118730Ssteve if (WEXITSTATUS(*status) != 0) { 8321590Srgrimes if (usePipes && job->node != lastNode) { 83318730Ssteve MESSAGE(out, job->node); 8341590Srgrimes lastNode = job->node; 8351590Srgrimes } 83618730Ssteve (void) fprintf(out, "*** Error code %d%s\n", 83718730Ssteve WEXITSTATUS(*status), 83818730Ssteve (job->flags & JOB_IGNERR) ? "(ignored)" : ""); 8391590Srgrimes 8401590Srgrimes if (job->flags & JOB_IGNERR) { 84118730Ssteve *status = 0; 8421590Srgrimes } 8431590Srgrimes } else if (DEBUG(JOB)) { 8441590Srgrimes if (usePipes && job->node != lastNode) { 84518730Ssteve MESSAGE(out, job->node); 8461590Srgrimes lastNode = job->node; 8471590Srgrimes } 84818730Ssteve (void) fprintf(out, "*** Completed successfully\n"); 8491590Srgrimes } 85018730Ssteve } else if (WIFSTOPPED(*status)) { 85118730Ssteve if (DEBUG(JOB)) { 85218730Ssteve (void) fprintf(stdout, "Process %d stopped.\n", job->pid); 85318730Ssteve (void) fflush(stdout); 85418730Ssteve } 8551590Srgrimes if (usePipes && job->node != lastNode) { 85618730Ssteve MESSAGE(out, job->node); 8571590Srgrimes lastNode = job->node; 8581590Srgrimes } 85918730Ssteve if (!(job->flags & JOB_REMIGRATE)) { 86018730Ssteve (void) fprintf(out, "*** Stopped -- signal %d\n", 86118730Ssteve WSTOPSIG(*status)); 8621590Srgrimes } 8631590Srgrimes job->flags |= JOB_RESUME; 86469531Swill (void)Lst_AtEnd(stoppedJobs, (void *)job); 86518730Ssteve#ifdef REMOTE 86618730Ssteve if (job->flags & JOB_REMIGRATE) 86718730Ssteve JobRestart(job); 86818730Ssteve#endif 86918730Ssteve (void) fflush(out); 8701590Srgrimes return; 87118730Ssteve } else if (WTERMSIG(*status) == SIGCONT) { 8721590Srgrimes /* 8731590Srgrimes * If the beastie has continued, shift the Job from the stopped 8741590Srgrimes * list to the running one (or re-stop it if concurrency is 8751590Srgrimes * exceeded) and go and get another child. 8761590Srgrimes */ 8771590Srgrimes if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) { 8781590Srgrimes if (usePipes && job->node != lastNode) { 87918730Ssteve MESSAGE(out, job->node); 8801590Srgrimes lastNode = job->node; 8811590Srgrimes } 88218730Ssteve (void) fprintf(out, "*** Continued\n"); 8831590Srgrimes } 88418730Ssteve if (!(job->flags & JOB_CONTINUING)) { 88518730Ssteve if (DEBUG(JOB)) { 88618730Ssteve (void) fprintf(stdout, 88718730Ssteve "Warning: process %d was not continuing.\n", 88818730Ssteve job->pid); 88918730Ssteve (void) fflush(stdout); 89018730Ssteve } 89118730Ssteve#ifdef notdef 89218730Ssteve /* 89318730Ssteve * We don't really want to restart a job from scratch just 89418730Ssteve * because it continued, especially not without killing the 89518730Ssteve * continuing process! That's why this is ifdef'ed out. 89618730Ssteve * FD - 9/17/90 89718730Ssteve */ 8981590Srgrimes JobRestart(job); 89918730Ssteve#endif 9001590Srgrimes } 90118730Ssteve job->flags &= ~JOB_CONTINUING; 90269531Swill Lst_AtEnd(jobs, (void *)job); 90318730Ssteve nJobs += 1; 90418730Ssteve if (!(job->flags & JOB_REMOTE)) { 90518730Ssteve if (DEBUG(JOB)) { 90618730Ssteve (void) fprintf(stdout, 90718730Ssteve "Process %d is continuing locally.\n", 90818730Ssteve job->pid); 90918730Ssteve (void) fflush(stdout); 91018730Ssteve } 91118730Ssteve nLocal += 1; 91218730Ssteve } 91318730Ssteve if (nJobs == maxJobs) { 91418730Ssteve jobFull = TRUE; 91518730Ssteve if (DEBUG(JOB)) { 91618730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 91718730Ssteve (void) fflush(stdout); 91818730Ssteve } 91918730Ssteve } 92018730Ssteve (void) fflush(out); 92118730Ssteve return; 9221590Srgrimes } else { 9231590Srgrimes if (usePipes && job->node != lastNode) { 92418730Ssteve MESSAGE(out, job->node); 9251590Srgrimes lastNode = job->node; 9261590Srgrimes } 92718730Ssteve (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); 9281590Srgrimes } 9291590Srgrimes 93018730Ssteve (void) fflush(out); 9311590Srgrimes } 9321590Srgrimes 9331590Srgrimes /* 9341590Srgrimes * Now handle the -B-mode stuff. If the beast still isn't finished, 9351590Srgrimes * try and restart the job on the next command. If JobStart says it's 9361590Srgrimes * ok, it's ok. If there's an error, this puppy is done. 9371590Srgrimes */ 93818730Ssteve if (compatMake && (WIFEXITED(*status) && 93918730Ssteve !Lst_IsAtEnd(job->node->commands))) { 94018730Ssteve switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { 94118730Ssteve case JOB_RUNNING: 94218730Ssteve done = FALSE; 94318730Ssteve break; 94418730Ssteve case JOB_ERROR: 94518730Ssteve done = TRUE; 94618730Ssteve W_SETEXITSTATUS(status, 1); 94718730Ssteve break; 94818730Ssteve case JOB_FINISHED: 94918730Ssteve /* 95018730Ssteve * If we got back a JOB_FINISHED code, JobStart has already 95118730Ssteve * called Make_Update and freed the job descriptor. We set 95218730Ssteve * done to false here to avoid fake cycles and double frees. 95318730Ssteve * JobStart needs to do the update so we can proceed up the 95418730Ssteve * graph when given the -n flag.. 95518730Ssteve */ 95618730Ssteve done = FALSE; 95718730Ssteve break; 9581590Srgrimes } 9591590Srgrimes } else { 9601590Srgrimes done = TRUE; 9611590Srgrimes } 9621590Srgrimes 9638874Srgrimes 9641590Srgrimes if (done && 9651590Srgrimes (aborting != ABORT_ERROR) && 9661590Srgrimes (aborting != ABORT_INTERRUPT) && 96718730Ssteve (*status == 0)) 9681590Srgrimes { 9691590Srgrimes /* 9701590Srgrimes * As long as we aren't aborting and the job didn't return a non-zero 9711590Srgrimes * status that we shouldn't ignore, we call Make_Update to update 9721590Srgrimes * the parents. In addition, any saved commands for the node are placed 9731590Srgrimes * on the .END target. 9741590Srgrimes */ 97569527Swill if (job->tailCmds != NULL) { 97618730Ssteve Lst_ForEachFrom(job->node->commands, job->tailCmds, 9771590Srgrimes JobSaveCommand, 97869531Swill (void *)job->node); 9791590Srgrimes } 9801590Srgrimes job->node->made = MADE; 98118730Ssteve Make_Update(job->node); 98269531Swill free(job); 98318730Ssteve } else if (*status != 0) { 9841590Srgrimes errors += 1; 98569531Swill free(job); 9861590Srgrimes } 9871590Srgrimes 98818730Ssteve JobRestartJobs(); 9891590Srgrimes 9901590Srgrimes /* 9911590Srgrimes * Set aborting if any error. 9921590Srgrimes */ 9931590Srgrimes if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { 9941590Srgrimes /* 9951590Srgrimes * If we found any errors in this batch of children and the -k flag 9961590Srgrimes * wasn't given, we set the aborting flag so no more jobs get 9971590Srgrimes * started. 9981590Srgrimes */ 9991590Srgrimes aborting = ABORT_ERROR; 10001590Srgrimes } 10018874Srgrimes 100268898Skris if ((aborting == ABORT_ERROR) && Job_Empty()) 10031590Srgrimes /* 10041590Srgrimes * If we are aborting and the job table is now empty, we finish. 10051590Srgrimes */ 100618730Ssteve Finish(errors); 10071590Srgrimes} 10081590Srgrimes 10091590Srgrimes/*- 10101590Srgrimes *----------------------------------------------------------------------- 10111590Srgrimes * Job_Touch -- 10121590Srgrimes * Touch the given target. Called by JobStart when the -t flag was 10131590Srgrimes * given 10141590Srgrimes * 10151590Srgrimes * Results: 10161590Srgrimes * None 10171590Srgrimes * 10181590Srgrimes * Side Effects: 10191590Srgrimes * The data modification of the file is changed. In addition, if the 10201590Srgrimes * file did not exist, it is created. 10211590Srgrimes *----------------------------------------------------------------------- 10221590Srgrimes */ 10231590Srgrimesvoid 102418730SsteveJob_Touch(gn, silent) 10251590Srgrimes GNode *gn; /* the node of the file to touch */ 10261590Srgrimes Boolean silent; /* TRUE if should not print messages */ 10271590Srgrimes{ 10281590Srgrimes int streamID; /* ID of stream opened to do the touch */ 102918730Ssteve struct utimbuf times; /* Times for utime() call */ 10301590Srgrimes 10311590Srgrimes if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { 10321590Srgrimes /* 10331590Srgrimes * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets 10341590Srgrimes * and, as such, shouldn't really be created. 10351590Srgrimes */ 10361590Srgrimes return; 10371590Srgrimes } 10388874Srgrimes 10391590Srgrimes if (!silent) { 104018730Ssteve (void) fprintf(stdout, "touch %s\n", gn->name); 104118730Ssteve (void) fflush(stdout); 10421590Srgrimes } 10431590Srgrimes 10441590Srgrimes if (noExecute) { 10451590Srgrimes return; 10461590Srgrimes } 10471590Srgrimes 10481590Srgrimes if (gn->type & OP_ARCHV) { 104918730Ssteve Arch_Touch(gn); 10501590Srgrimes } else if (gn->type & OP_LIB) { 105118730Ssteve Arch_TouchLib(gn); 10521590Srgrimes } else { 10531590Srgrimes char *file = gn->path ? gn->path : gn->name; 10541590Srgrimes 105518730Ssteve times.actime = times.modtime = now; 105618730Ssteve if (utime(file, ×) < 0){ 105718730Ssteve streamID = open(file, O_RDWR | O_CREAT, 0666); 10581590Srgrimes 10591590Srgrimes if (streamID >= 0) { 10601590Srgrimes char c; 10611590Srgrimes 10621590Srgrimes /* 10631590Srgrimes * Read and write a byte to the file to change the 10641590Srgrimes * modification time, then close the file. 10651590Srgrimes */ 10661590Srgrimes if (read(streamID, &c, 1) == 1) { 106794506Scharnier (void) lseek(streamID, (off_t)0, SEEK_SET); 106818730Ssteve (void) write(streamID, &c, 1); 10691590Srgrimes } 10708874Srgrimes 107118730Ssteve (void) close(streamID); 107218730Ssteve } else { 107318730Ssteve (void) fprintf(stdout, "*** couldn't touch %s: %s", 107418730Ssteve file, strerror(errno)); 107518730Ssteve (void) fflush(stdout); 107618730Ssteve } 10771590Srgrimes } 10781590Srgrimes } 10791590Srgrimes} 10801590Srgrimes 10811590Srgrimes/*- 10821590Srgrimes *----------------------------------------------------------------------- 10831590Srgrimes * Job_CheckCommands -- 10848874Srgrimes * Make sure the given node has all the commands it needs. 10851590Srgrimes * 10861590Srgrimes * Results: 10871590Srgrimes * TRUE if the commands list is/was ok. 10881590Srgrimes * 10891590Srgrimes * Side Effects: 10901590Srgrimes * The node will have commands from the .DEFAULT rule added to it 10911590Srgrimes * if it needs them. 10921590Srgrimes *----------------------------------------------------------------------- 10931590Srgrimes */ 10941590SrgrimesBoolean 109518730SsteveJob_CheckCommands(gn, abortProc) 10961590Srgrimes GNode *gn; /* The target whose commands need 10971590Srgrimes * verifying */ 109898136Sjmallett void (*abortProc)(const char *, ...); 10991590Srgrimes /* Function to abort with message */ 11001590Srgrimes{ 110118730Ssteve if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && 11021590Srgrimes (gn->type & OP_LIB) == 0) { 11031590Srgrimes /* 11041590Srgrimes * No commands. Look for .DEFAULT rule from which we might infer 11058874Srgrimes * commands 11061590Srgrimes */ 110769527Swill if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands)) { 11085814Sjkh char *p1; 11091590Srgrimes /* 11101590Srgrimes * Make only looks for a .DEFAULT if the node was never the 11111590Srgrimes * target of an operator, so that's what we do too. If 11121590Srgrimes * a .DEFAULT was given, we substitute its commands for gn's 11131590Srgrimes * commands and set the IMPSRC variable to be the target's name 11141590Srgrimes * The DEFAULT node acts like a transformation rule, in that 11151590Srgrimes * gn also inherits any attributes or sources attached to 11161590Srgrimes * .DEFAULT itself. 11171590Srgrimes */ 11181590Srgrimes Make_HandleUse(DEFAULT, gn); 111918730Ssteve Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); 112049938Shoek efree(p1); 112118730Ssteve } else if (Dir_MTime(gn) == 0) { 11221590Srgrimes /* 11231590Srgrimes * The node wasn't the target of an operator we have no .DEFAULT 11241590Srgrimes * rule to go on and the target doesn't already exist. There's 11251590Srgrimes * nothing more we can do for this branch. If the -k flag wasn't 11261590Srgrimes * given, we stop in our tracks, otherwise we just don't update 11278874Srgrimes * this node's parents so they never get examined. 11281590Srgrimes */ 112918730Ssteve static const char msg[] = "make: don't know how to make"; 113018730Ssteve 11311590Srgrimes if (gn->type & OP_OPTIONAL) { 113218730Ssteve (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); 113318730Ssteve (void) fflush(stdout); 11341590Srgrimes } else if (keepgoing) { 113518730Ssteve (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); 113618730Ssteve (void) fflush(stdout); 113718730Ssteve return FALSE; 11381590Srgrimes } else { 113935483Simp#if OLD_JOKE 114035483Simp if (strcmp(gn->name,"love") == 0) 114135483Simp (*abortProc)("Not war."); 114235483Simp else 114335483Simp#endif 114435483Simp (*abortProc)("%s %s. Stop", msg, gn->name); 114518730Ssteve return FALSE; 11461590Srgrimes } 11471590Srgrimes } 11481590Srgrimes } 114918730Ssteve return TRUE; 11501590Srgrimes} 11511590Srgrimes#ifdef RMT_WILL_WATCH 11521590Srgrimes/*- 11531590Srgrimes *----------------------------------------------------------------------- 11541590Srgrimes * JobLocalInput -- 11551590Srgrimes * Handle a pipe becoming readable. Callback function for Rmt_Watch 11561590Srgrimes * 11571590Srgrimes * Results: 11581590Srgrimes * None 11591590Srgrimes * 11601590Srgrimes * Side Effects: 11611590Srgrimes * JobDoOutput is called. 11628874Srgrimes * 11631590Srgrimes *----------------------------------------------------------------------- 11641590Srgrimes */ 11651590Srgrimes/*ARGSUSED*/ 11661590Srgrimesstatic void 11671590SrgrimesJobLocalInput(stream, job) 11681590Srgrimes int stream; /* Stream that's ready (ignored) */ 11691590Srgrimes Job *job; /* Job to which the stream belongs */ 11701590Srgrimes{ 11711590Srgrimes JobDoOutput(job, FALSE); 11721590Srgrimes} 11731590Srgrimes#endif /* RMT_WILL_WATCH */ 11741590Srgrimes 11751590Srgrimes/*- 11761590Srgrimes *----------------------------------------------------------------------- 11771590Srgrimes * JobExec -- 11781590Srgrimes * Execute the shell for the given job. Called from JobStart and 11791590Srgrimes * JobRestart. 11801590Srgrimes * 11811590Srgrimes * Results: 11821590Srgrimes * None. 11831590Srgrimes * 11841590Srgrimes * Side Effects: 11851590Srgrimes * A shell is executed, outputs is altered and the Job structure added 11861590Srgrimes * to the job table. 11871590Srgrimes * 11881590Srgrimes *----------------------------------------------------------------------- 11891590Srgrimes */ 11901590Srgrimesstatic void 11911590SrgrimesJobExec(job, argv) 11921590Srgrimes Job *job; /* Job to execute */ 11931590Srgrimes char **argv; 11941590Srgrimes{ 11951590Srgrimes int cpid; /* ID of new child */ 11968874Srgrimes 11971590Srgrimes if (DEBUG(JOB)) { 11981590Srgrimes int i; 11998874Srgrimes 120018730Ssteve (void) fprintf(stdout, "Running %s %sly\n", job->node->name, 120118730Ssteve job->flags&JOB_REMOTE?"remote":"local"); 120218730Ssteve (void) fprintf(stdout, "\tCommand: "); 120318730Ssteve for (i = 0; argv[i] != NULL; i++) { 120418730Ssteve (void) fprintf(stdout, "%s ", argv[i]); 12051590Srgrimes } 120618730Ssteve (void) fprintf(stdout, "\n"); 120718730Ssteve (void) fflush(stdout); 12081590Srgrimes } 12098874Srgrimes 12101590Srgrimes /* 12111590Srgrimes * Some jobs produce no output and it's disconcerting to have 12121590Srgrimes * no feedback of their running (since they produce no output, the 12131590Srgrimes * banner with their name in it never appears). This is an attempt to 12141590Srgrimes * provide that feedback, even if nothing follows it. 12151590Srgrimes */ 12161590Srgrimes if ((lastNode != job->node) && (job->flags & JOB_FIRST) && 121718730Ssteve !(job->flags & JOB_SILENT)) { 121818730Ssteve MESSAGE(stdout, job->node); 12191590Srgrimes lastNode = job->node; 12201590Srgrimes } 12218874Srgrimes 12221590Srgrimes#ifdef RMT_NO_EXEC 12231590Srgrimes if (job->flags & JOB_REMOTE) { 12241590Srgrimes goto jobExecFinish; 12251590Srgrimes } 12261590Srgrimes#endif /* RMT_NO_EXEC */ 12271590Srgrimes 122818730Ssteve if ((cpid = vfork()) == -1) { 122918730Ssteve Punt("Cannot fork"); 12301590Srgrimes } else if (cpid == 0) { 12311590Srgrimes 12321590Srgrimes /* 12331590Srgrimes * Must duplicate the input stream down to the child's input and 12341590Srgrimes * reset it to the beginning (again). Since the stream was marked 12351590Srgrimes * close-on-exec, we must clear that bit in the new input. 12361590Srgrimes */ 123718730Ssteve if (dup2(FILENO(job->cmdFILE), 0) == -1) 123818730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 123918730Ssteve (void) fcntl(0, F_SETFD, 0); 124094506Scharnier (void) lseek(0, (off_t)0, SEEK_SET); 12418874Srgrimes 12421590Srgrimes if (usePipes) { 12431590Srgrimes /* 12441590Srgrimes * Set up the child's output to be routed through the pipe 12451590Srgrimes * we've created for it. 12461590Srgrimes */ 124718730Ssteve if (dup2(job->outPipe, 1) == -1) 124818730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 12491590Srgrimes } else { 12501590Srgrimes /* 12511590Srgrimes * We're capturing output in a file, so we duplicate the 12521590Srgrimes * descriptor to the temporary file into the standard 12531590Srgrimes * output. 12541590Srgrimes */ 125518730Ssteve if (dup2(job->outFd, 1) == -1) 125618730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 12571590Srgrimes } 12581590Srgrimes /* 12591590Srgrimes * The output channels are marked close on exec. This bit was 12601590Srgrimes * duplicated by the dup2 (on some systems), so we have to clear 12611590Srgrimes * it before routing the shell's error output to the same place as 12621590Srgrimes * its standard output. 12631590Srgrimes */ 126418730Ssteve (void) fcntl(1, F_SETFD, 0); 126518730Ssteve if (dup2(1, 2) == -1) 126618730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 12671590Srgrimes 12681590Srgrimes#ifdef USE_PGRP 12691590Srgrimes /* 12701590Srgrimes * We want to switch the child into a different process family so 12711590Srgrimes * we can kill it and all its descendants in one fell swoop, 12721590Srgrimes * by killing its process family, but not commit suicide. 12731590Srgrimes */ 127418730Ssteve# if defined(SYSV) 127518730Ssteve (void) setsid(); 127618730Ssteve# else 127718730Ssteve (void) setpgid(0, getpid()); 127818730Ssteve# endif 127918730Ssteve#endif /* USE_PGRP */ 12808874Srgrimes 128118730Ssteve#ifdef REMOTE 128218730Ssteve if (job->flags & JOB_REMOTE) { 128318730Ssteve Rmt_Exec(shellPath, argv, FALSE); 128418730Ssteve } else 128518730Ssteve#endif /* REMOTE */ 128697251Sru (void) execv(shellPath, argv); 12871590Srgrimes 128880381Ssheldonh (void) write(STDERR_FILENO, "Could not execute shell\n", 128918730Ssteve sizeof("Could not execute shell")); 129018730Ssteve _exit(1); 12911590Srgrimes } else { 129218730Ssteve#ifdef REMOTE 129318730Ssteve long omask = sigblock(sigmask(SIGCHLD)); 129418730Ssteve#endif 12951590Srgrimes job->pid = cpid; 12961590Srgrimes 12971590Srgrimes if (usePipes && (job->flags & JOB_FIRST) ) { 12981590Srgrimes /* 12991590Srgrimes * The first time a job is run for a node, we set the current 13001590Srgrimes * position in the buffer to the beginning and mark another 13011590Srgrimes * stream to watch in the outputs mask 13021590Srgrimes */ 13031590Srgrimes job->curPos = 0; 13048874Srgrimes 13051590Srgrimes#ifdef RMT_WILL_WATCH 13061590Srgrimes Rmt_Watch(job->inPipe, JobLocalInput, job); 13071590Srgrimes#else 13081590Srgrimes FD_SET(job->inPipe, &outputs); 13091590Srgrimes#endif /* RMT_WILL_WATCH */ 13101590Srgrimes } 13111590Srgrimes 13121590Srgrimes if (job->flags & JOB_REMOTE) { 131318730Ssteve#ifndef REMOTE 13141590Srgrimes job->rmtID = 0; 131518730Ssteve#else 131618730Ssteve job->rmtID = Rmt_LastID(job->pid); 131718730Ssteve#endif /* REMOTE */ 13181590Srgrimes } else { 13191590Srgrimes nLocal += 1; 13201590Srgrimes /* 132118730Ssteve * XXX: Used to not happen if REMOTE. Why? 13221590Srgrimes */ 132318730Ssteve if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 132418730Ssteve (void) fclose(job->cmdFILE); 13251590Srgrimes job->cmdFILE = NULL; 13261590Srgrimes } 13271590Srgrimes } 132818730Ssteve#ifdef REMOTE 132918730Ssteve (void) sigsetmask(omask); 133018730Ssteve#endif 13311590Srgrimes } 13321590Srgrimes 13331590Srgrimes#ifdef RMT_NO_EXEC 13348874SrgrimesjobExecFinish: 13351590Srgrimes#endif 13361590Srgrimes /* 13371590Srgrimes * Now the job is actually running, add it to the table. 13381590Srgrimes */ 13391590Srgrimes nJobs += 1; 134069531Swill (void) Lst_AtEnd(jobs, (void *)job); 13411590Srgrimes if (nJobs == maxJobs) { 13421590Srgrimes jobFull = TRUE; 13431590Srgrimes } 13441590Srgrimes} 13451590Srgrimes 13461590Srgrimes/*- 13471590Srgrimes *----------------------------------------------------------------------- 13481590Srgrimes * JobMakeArgv -- 13491590Srgrimes * Create the argv needed to execute the shell for a given job. 13501590Srgrimes * 13518874Srgrimes * 13521590Srgrimes * Results: 13531590Srgrimes * 13541590Srgrimes * Side Effects: 13551590Srgrimes * 13561590Srgrimes *----------------------------------------------------------------------- 13571590Srgrimes */ 13581590Srgrimesstatic void 13591590SrgrimesJobMakeArgv(job, argv) 13601590Srgrimes Job *job; 13611590Srgrimes char **argv; 13621590Srgrimes{ 13631590Srgrimes int argc; 13641590Srgrimes static char args[10]; /* For merged arguments */ 13658874Srgrimes 13661590Srgrimes argv[0] = shellName; 13671590Srgrimes argc = 1; 13681590Srgrimes 13691590Srgrimes if ((commandShell->exit && (*commandShell->exit != '-')) || 13701590Srgrimes (commandShell->echo && (*commandShell->echo != '-'))) 13711590Srgrimes { 13721590Srgrimes /* 13731590Srgrimes * At least one of the flags doesn't have a minus before it, so 13741590Srgrimes * merge them together. Have to do this because the *(&(@*#*&#$# 13751590Srgrimes * Bourne shell thinks its second argument is a file to source. 13761590Srgrimes * Grrrr. Note the ten-character limitation on the combined arguments. 13771590Srgrimes */ 13781590Srgrimes (void)sprintf(args, "-%s%s", 13791590Srgrimes ((job->flags & JOB_IGNERR) ? "" : 13801590Srgrimes (commandShell->exit ? commandShell->exit : "")), 13811590Srgrimes ((job->flags & JOB_SILENT) ? "" : 13821590Srgrimes (commandShell->echo ? commandShell->echo : ""))); 13831590Srgrimes 13841590Srgrimes if (args[1]) { 13851590Srgrimes argv[argc] = args; 13861590Srgrimes argc++; 13871590Srgrimes } 13881590Srgrimes } else { 13891590Srgrimes if (!(job->flags & JOB_IGNERR) && commandShell->exit) { 13901590Srgrimes argv[argc] = commandShell->exit; 13911590Srgrimes argc++; 13921590Srgrimes } 13931590Srgrimes if (!(job->flags & JOB_SILENT) && commandShell->echo) { 13941590Srgrimes argv[argc] = commandShell->echo; 13951590Srgrimes argc++; 13961590Srgrimes } 13971590Srgrimes } 139818730Ssteve argv[argc] = NULL; 13991590Srgrimes} 14001590Srgrimes 14011590Srgrimes/*- 14021590Srgrimes *----------------------------------------------------------------------- 14031590Srgrimes * JobRestart -- 14048874Srgrimes * Restart a job that stopped for some reason. 14051590Srgrimes * 14061590Srgrimes * Results: 14071590Srgrimes * None. 14081590Srgrimes * 14091590Srgrimes * Side Effects: 14101590Srgrimes * jobFull will be set if the job couldn't be run. 14111590Srgrimes * 14121590Srgrimes *----------------------------------------------------------------------- 14131590Srgrimes */ 14141590Srgrimesstatic void 14151590SrgrimesJobRestart(job) 14161590Srgrimes Job *job; /* Job to restart */ 14171590Srgrimes{ 141818730Ssteve#ifdef REMOTE 141918730Ssteve int host; 142018730Ssteve#endif 142118730Ssteve 14221590Srgrimes if (job->flags & JOB_REMIGRATE) { 142318730Ssteve if ( 142418730Ssteve#ifdef REMOTE 142518730Ssteve verboseRemigrates || 142618730Ssteve#endif 142718730Ssteve DEBUG(JOB)) { 142818730Ssteve (void) fprintf(stdout, "*** remigrating %x(%s)\n", 142918730Ssteve job->pid, job->node->name); 143018730Ssteve (void) fflush(stdout); 14311590Srgrimes } 143218730Ssteve 143318730Ssteve#ifdef REMOTE 143418730Ssteve if (!Rmt_ReExport(job->pid, job->node, &host)) { 143518730Ssteve if (verboseRemigrates || DEBUG(JOB)) { 143618730Ssteve (void) fprintf(stdout, "*** couldn't migrate...\n"); 143718730Ssteve (void) fflush(stdout); 143818730Ssteve } 143918730Ssteve#endif 144018730Ssteve if (nLocal != maxLocal) { 14411590Srgrimes /* 14421590Srgrimes * Job cannot be remigrated, but there's room on the local 14431590Srgrimes * machine, so resume the job and note that another 14441590Srgrimes * local job has started. 14451590Srgrimes */ 144618730Ssteve if ( 144718730Ssteve#ifdef REMOTE 144818730Ssteve verboseRemigrates || 144918730Ssteve#endif 145018730Ssteve DEBUG(JOB)) { 145118730Ssteve (void) fprintf(stdout, "*** resuming on local machine\n"); 145218730Ssteve (void) fflush(stdout); 145318730Ssteve } 14541590Srgrimes KILL(job->pid, SIGCONT); 14551590Srgrimes nLocal +=1; 145618730Ssteve#ifdef REMOTE 145718730Ssteve job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE); 145818730Ssteve job->flags |= JOB_CONTINUING; 145918730Ssteve#else 14601590Srgrimes job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); 146118730Ssteve#endif 14621590Srgrimes } else { 14631590Srgrimes /* 14641590Srgrimes * Job cannot be restarted. Mark the table as full and 14651590Srgrimes * place the job back on the list of stopped jobs. 14661590Srgrimes */ 146718730Ssteve if ( 146818730Ssteve#ifdef REMOTE 146918730Ssteve verboseRemigrates || 147018730Ssteve#endif 147118730Ssteve DEBUG(JOB)) { 147218730Ssteve (void) fprintf(stdout, "*** holding\n"); 147318730Ssteve (void) fflush(stdout); 147418730Ssteve } 147569531Swill (void)Lst_AtFront(stoppedJobs, (void *)job); 14761590Srgrimes jobFull = TRUE; 14771590Srgrimes if (DEBUG(JOB)) { 147818730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 147918730Ssteve (void) fflush(stdout); 14801590Srgrimes } 14811590Srgrimes return; 148218730Ssteve } 148318730Ssteve#ifdef REMOTE 148418730Ssteve } else { 148518730Ssteve /* 148618730Ssteve * Clear out the remigrate and resume flags. Set the continuing 148718730Ssteve * flag so we know later on that the process isn't exiting just 148818730Ssteve * because of a signal. 148918730Ssteve */ 149018730Ssteve job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); 149118730Ssteve job->flags |= JOB_CONTINUING; 149218730Ssteve job->rmtID = host; 14931590Srgrimes } 149418730Ssteve#endif 14958874Srgrimes 149669531Swill (void)Lst_AtEnd(jobs, (void *)job); 14971590Srgrimes nJobs += 1; 14981590Srgrimes if (nJobs == maxJobs) { 14991590Srgrimes jobFull = TRUE; 15001590Srgrimes if (DEBUG(JOB)) { 150118730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 150218730Ssteve (void) fflush(stdout); 15031590Srgrimes } 15041590Srgrimes } 15051590Srgrimes } else if (job->flags & JOB_RESTART) { 15061590Srgrimes /* 15071590Srgrimes * Set up the control arguments to the shell. This is based on the 15081590Srgrimes * flags set earlier for this job. If the JOB_IGNERR flag is clear, 15091590Srgrimes * the 'exit' flag of the commandShell is used to cause it to exit 15101590Srgrimes * upon receiving an error. If the JOB_SILENT flag is clear, the 15111590Srgrimes * 'echo' flag of the commandShell is used to get it to start echoing 15128874Srgrimes * as soon as it starts processing commands. 15131590Srgrimes */ 15141590Srgrimes char *argv[4]; 15158874Srgrimes 15161590Srgrimes JobMakeArgv(job, argv); 15178874Srgrimes 15181590Srgrimes if (DEBUG(JOB)) { 151918730Ssteve (void) fprintf(stdout, "Restarting %s...", job->node->name); 152018730Ssteve (void) fflush(stdout); 15211590Srgrimes } 152218730Ssteve#ifdef REMOTE 152318730Ssteve if ((job->node->type&OP_NOEXPORT) || 152418730Ssteve (nLocal < maxLocal && runLocalFirst) 152518730Ssteve# ifdef RMT_NO_EXEC 152618730Ssteve || !Rmt_Export(shellPath, argv, job) 152718730Ssteve# else 152818730Ssteve || !Rmt_Begin(shellPath, argv, job->node) 152918730Ssteve# endif 153018730Ssteve#endif 153118730Ssteve { 153218730Ssteve if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) { 15331590Srgrimes /* 15341590Srgrimes * Can't be exported and not allowed to run locally -- put it 15351590Srgrimes * back on the hold queue and mark the table full 15361590Srgrimes */ 15371590Srgrimes if (DEBUG(JOB)) { 153818730Ssteve (void) fprintf(stdout, "holding\n"); 153918730Ssteve (void) fflush(stdout); 15401590Srgrimes } 154169531Swill (void)Lst_AtFront(stoppedJobs, (void *)job); 15421590Srgrimes jobFull = TRUE; 15431590Srgrimes if (DEBUG(JOB)) { 154418730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 154518730Ssteve (void) fflush(stdout); 15461590Srgrimes } 15471590Srgrimes return; 154818730Ssteve } else { 15491590Srgrimes /* 15501590Srgrimes * Job may be run locally. 15511590Srgrimes */ 15521590Srgrimes if (DEBUG(JOB)) { 155318730Ssteve (void) fprintf(stdout, "running locally\n"); 155418730Ssteve (void) fflush(stdout); 15551590Srgrimes } 15561590Srgrimes job->flags &= ~JOB_REMOTE; 155718730Ssteve } 15581590Srgrimes } 155918730Ssteve#ifdef REMOTE 156018730Ssteve else { 156118730Ssteve /* 156218730Ssteve * Can be exported. Hooray! 156318730Ssteve */ 156418730Ssteve if (DEBUG(JOB)) { 156518730Ssteve (void) fprintf(stdout, "exporting\n"); 156618730Ssteve (void) fflush(stdout); 156718730Ssteve } 156818730Ssteve job->flags |= JOB_REMOTE; 156918730Ssteve } 157018730Ssteve#endif 15711590Srgrimes JobExec(job, argv); 15721590Srgrimes } else { 15731590Srgrimes /* 15741590Srgrimes * The job has stopped and needs to be restarted. Why it stopped, 15751590Srgrimes * we don't know... 15761590Srgrimes */ 15771590Srgrimes if (DEBUG(JOB)) { 157818730Ssteve (void) fprintf(stdout, "Resuming %s...", job->node->name); 157918730Ssteve (void) fflush(stdout); 15801590Srgrimes } 15811590Srgrimes if (((job->flags & JOB_REMOTE) || 158218730Ssteve (nLocal < maxLocal) || 158318730Ssteve#ifdef REMOTE 158418730Ssteve (((job->flags & JOB_SPECIAL) && 158518730Ssteve (job->node->type & OP_NOEXPORT)) && 158618730Ssteve (maxLocal == 0))) && 158718730Ssteve#else 158818730Ssteve ((job->flags & JOB_SPECIAL) && 158918730Ssteve (maxLocal == 0))) && 159018730Ssteve#endif 159118730Ssteve (nJobs != maxJobs)) 15921590Srgrimes { 15931590Srgrimes /* 15941590Srgrimes * If the job is remote, it's ok to resume it as long as the 15951590Srgrimes * maximum concurrency won't be exceeded. If it's local and 15961590Srgrimes * we haven't reached the local concurrency limit already (or the 15971590Srgrimes * job must be run locally and maxLocal is 0), it's also ok to 15981590Srgrimes * resume it. 15991590Srgrimes */ 16001590Srgrimes Boolean error; 160118730Ssteve int status; 16028874Srgrimes 16031590Srgrimes#ifdef RMT_WANTS_SIGNALS 16041590Srgrimes if (job->flags & JOB_REMOTE) { 16051590Srgrimes error = !Rmt_Signal(job, SIGCONT); 16061590Srgrimes } else 16071590Srgrimes#endif /* RMT_WANTS_SIGNALS */ 16081590Srgrimes error = (KILL(job->pid, SIGCONT) != 0); 16091590Srgrimes 16101590Srgrimes if (!error) { 16111590Srgrimes /* 16121590Srgrimes * Make sure the user knows we've continued the beast and 16131590Srgrimes * actually put the thing in the job table. 16141590Srgrimes */ 16151590Srgrimes job->flags |= JOB_CONTINUING; 161618730Ssteve W_SETTERMSIG(&status, SIGCONT); 161718730Ssteve JobFinish(job, &status); 16188874Srgrimes 16191590Srgrimes job->flags &= ~(JOB_RESUME|JOB_CONTINUING); 16201590Srgrimes if (DEBUG(JOB)) { 162118730Ssteve (void) fprintf(stdout, "done\n"); 162218730Ssteve (void) fflush(stdout); 16231590Srgrimes } 16241590Srgrimes } else { 16251590Srgrimes Error("couldn't resume %s: %s", 16261590Srgrimes job->node->name, strerror(errno)); 162718730Ssteve status = 0; 162818730Ssteve W_SETEXITSTATUS(&status, 1); 162918730Ssteve JobFinish(job, &status); 16301590Srgrimes } 16311590Srgrimes } else { 16321590Srgrimes /* 16331590Srgrimes * Job cannot be restarted. Mark the table as full and 16341590Srgrimes * place the job back on the list of stopped jobs. 16351590Srgrimes */ 16361590Srgrimes if (DEBUG(JOB)) { 163718730Ssteve (void) fprintf(stdout, "table full\n"); 163818730Ssteve (void) fflush(stdout); 16391590Srgrimes } 164069531Swill (void) Lst_AtFront(stoppedJobs, (void *)job); 16411590Srgrimes jobFull = TRUE; 16421590Srgrimes if (DEBUG(JOB)) { 164318730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 164418730Ssteve (void) fflush(stdout); 16451590Srgrimes } 16461590Srgrimes } 16471590Srgrimes } 16481590Srgrimes} 16491590Srgrimes 16501590Srgrimes/*- 16511590Srgrimes *----------------------------------------------------------------------- 16521590Srgrimes * JobStart -- 16531590Srgrimes * Start a target-creation process going for the target described 16548874Srgrimes * by the graph node gn. 16551590Srgrimes * 16561590Srgrimes * Results: 16571590Srgrimes * JOB_ERROR if there was an error in the commands, JOB_FINISHED 16581590Srgrimes * if there isn't actually anything left to do for the job and 16591590Srgrimes * JOB_RUNNING if the job has been started. 16601590Srgrimes * 16611590Srgrimes * Side Effects: 16621590Srgrimes * A new Job node is created and added to the list of running 16631590Srgrimes * jobs. PMake is forked and a child shell created. 16641590Srgrimes *----------------------------------------------------------------------- 16651590Srgrimes */ 16661590Srgrimesstatic int 166718730SsteveJobStart(gn, flags, previous) 16681590Srgrimes GNode *gn; /* target to create */ 16695814Sjkh int flags; /* flags for the job to override normal ones. 16701590Srgrimes * e.g. JOB_SPECIAL or JOB_IGNDOTS */ 16711590Srgrimes Job *previous; /* The previous Job structure for this node, 16721590Srgrimes * if any. */ 16731590Srgrimes{ 167494584Sobrien Job *job; /* new job descriptor */ 16751590Srgrimes char *argv[4]; /* Argument vector to shell */ 16761590Srgrimes Boolean cmdsOK; /* true if the nodes commands were all right */ 16771590Srgrimes Boolean local; /* Set true if the job was run locally */ 16781590Srgrimes Boolean noExec; /* Set true if we decide not to run the job */ 167956151Skris int tfd; /* File descriptor for temp file */ 16801590Srgrimes 168118730Ssteve if (previous != NULL) { 168218730Ssteve previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); 16831590Srgrimes job = previous; 16841590Srgrimes } else { 168518730Ssteve job = (Job *) emalloc(sizeof(Job)); 16861590Srgrimes flags |= JOB_FIRST; 16871590Srgrimes } 16881590Srgrimes 16891590Srgrimes job->node = gn; 169069527Swill job->tailCmds = NULL; 16911590Srgrimes 16921590Srgrimes /* 16931590Srgrimes * Set the initial value of the flags for this job based on the global 16941590Srgrimes * ones and the node's attributes... Any flags supplied by the caller 16951590Srgrimes * are also added to the field. 16961590Srgrimes */ 16971590Srgrimes job->flags = 0; 169818730Ssteve if (Targ_Ignore(gn)) { 16991590Srgrimes job->flags |= JOB_IGNERR; 17001590Srgrimes } 170118730Ssteve if (Targ_Silent(gn)) { 17021590Srgrimes job->flags |= JOB_SILENT; 17031590Srgrimes } 17041590Srgrimes job->flags |= flags; 17051590Srgrimes 17061590Srgrimes /* 17071590Srgrimes * Check the commands now so any attributes from .DEFAULT have a chance 17081590Srgrimes * to migrate to the node 17091590Srgrimes */ 171018730Ssteve if (!compatMake && job->flags & JOB_FIRST) { 17111590Srgrimes cmdsOK = Job_CheckCommands(gn, Error); 17121590Srgrimes } else { 17131590Srgrimes cmdsOK = TRUE; 17141590Srgrimes } 17158874Srgrimes 17161590Srgrimes /* 17171590Srgrimes * If the -n flag wasn't given, we open up OUR (not the child's) 17181590Srgrimes * temporary file to stuff commands in it. The thing is rd/wr so we don't 17191590Srgrimes * need to reopen it to feed it to the shell. If the -n flag *was* given, 17201590Srgrimes * we just set the file to be stdout. Cute, huh? 17211590Srgrimes */ 17221590Srgrimes if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) { 17231590Srgrimes /* 17241590Srgrimes * We're serious here, but if the commands were bogus, we're 17251590Srgrimes * also dead... 17261590Srgrimes */ 17271590Srgrimes if (!cmdsOK) { 17281590Srgrimes DieHorribly(); 17291590Srgrimes } 17308874Srgrimes 173168898Skris (void) strcpy(tfile, TMPPAT); 173268898Skris if ((tfd = mkstemp(tfile)) == -1) 173368898Skris Punt("Cannot create temp file: %s", strerror(errno)); 173468898Skris job->cmdFILE = fdopen(tfd, "w+"); 173568898Skris eunlink(tfile); 173618730Ssteve if (job->cmdFILE == NULL) { 173768898Skris close(tfd); 173868898Skris Punt("Could not open %s", tfile); 17391590Srgrimes } 174018730Ssteve (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1); 17411590Srgrimes /* 17421590Srgrimes * Send the commands to the command file, flush all its buffers then 17431590Srgrimes * rewind and remove the thing. 17441590Srgrimes */ 17451590Srgrimes noExec = FALSE; 17461590Srgrimes 17471590Srgrimes /* 17481590Srgrimes * used to be backwards; replace when start doing multiple commands 17491590Srgrimes * per shell. 17501590Srgrimes */ 17511590Srgrimes if (compatMake) { 17521590Srgrimes /* 17531590Srgrimes * Be compatible: If this is the first time for this node, 17541590Srgrimes * verify its commands are ok and open the commands list for 17551590Srgrimes * sequential access by later invocations of JobStart. 17561590Srgrimes * Once that is done, we take the next command off the list 17571590Srgrimes * and print it to the command file. If the command was an 17581590Srgrimes * ellipsis, note that there's nothing more to execute. 17591590Srgrimes */ 17601590Srgrimes if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){ 17611590Srgrimes cmdsOK = FALSE; 17621590Srgrimes } else { 176318730Ssteve LstNode ln = Lst_Next(gn->commands); 17648874Srgrimes 176569527Swill if ((ln == NULL) || 176669531Swill JobPrintCommand((void *) Lst_Datum(ln), 176769531Swill (void *) job)) 17681590Srgrimes { 17691590Srgrimes noExec = TRUE; 177018730Ssteve Lst_Close(gn->commands); 17711590Srgrimes } 17721590Srgrimes if (noExec && !(job->flags & JOB_FIRST)) { 17731590Srgrimes /* 17741590Srgrimes * If we're not going to execute anything, the job 17751590Srgrimes * is done and we need to close down the various 17761590Srgrimes * file descriptors we've opened for output, then 17771590Srgrimes * call JobDoOutput to catch the final characters or 17781590Srgrimes * send the file to the screen... Note that the i/o streams 17791590Srgrimes * are only open if this isn't the first job. 17801590Srgrimes * Note also that this could not be done in 17811590Srgrimes * Job_CatchChildren b/c it wasn't clear if there were 17821590Srgrimes * more commands to execute or not... 17831590Srgrimes */ 178418730Ssteve JobClose(job); 17851590Srgrimes } 17861590Srgrimes } 17871590Srgrimes } else { 17881590Srgrimes /* 17891590Srgrimes * We can do all the commands at once. hooray for sanity 17901590Srgrimes */ 17911590Srgrimes numCommands = 0; 179269531Swill Lst_ForEach(gn->commands, JobPrintCommand, (void *)job); 17938874Srgrimes 17941590Srgrimes /* 17951590Srgrimes * If we didn't print out any commands to the shell script, 17961590Srgrimes * there's not much point in executing the shell, is there? 17971590Srgrimes */ 17981590Srgrimes if (numCommands == 0) { 17991590Srgrimes noExec = TRUE; 18001590Srgrimes } 18011590Srgrimes } 18021590Srgrimes } else if (noExecute) { 18031590Srgrimes /* 18041590Srgrimes * Not executing anything -- just print all the commands to stdout 18051590Srgrimes * in one fell swoop. This will still set up job->tailCmds correctly. 18061590Srgrimes */ 18071590Srgrimes if (lastNode != gn) { 180818730Ssteve MESSAGE(stdout, gn); 18091590Srgrimes lastNode = gn; 18101590Srgrimes } 18111590Srgrimes job->cmdFILE = stdout; 18121590Srgrimes /* 18131590Srgrimes * Only print the commands if they're ok, but don't die if they're 18141590Srgrimes * not -- just let the user know they're bad and keep going. It 18151590Srgrimes * doesn't do any harm in this case and may do some good. 18161590Srgrimes */ 18171590Srgrimes if (cmdsOK) { 181869531Swill Lst_ForEach(gn->commands, JobPrintCommand, (void *)job); 18191590Srgrimes } 18201590Srgrimes /* 18211590Srgrimes * Don't execute the shell, thank you. 18221590Srgrimes */ 18231590Srgrimes noExec = TRUE; 18241590Srgrimes } else { 18251590Srgrimes /* 18261590Srgrimes * Just touch the target and note that no shell should be executed. 18271590Srgrimes * Set cmdFILE to stdout to make life easier. Check the commands, too, 18281590Srgrimes * but don't die if they're no good -- it does no harm to keep working 18291590Srgrimes * up the graph. 18301590Srgrimes */ 18311590Srgrimes job->cmdFILE = stdout; 183218730Ssteve Job_Touch(gn, job->flags&JOB_SILENT); 18331590Srgrimes noExec = TRUE; 18341590Srgrimes } 18351590Srgrimes 18361590Srgrimes /* 18378874Srgrimes * If we're not supposed to execute a shell, don't. 18381590Srgrimes */ 18391590Srgrimes if (noExec) { 18401590Srgrimes /* 18411590Srgrimes * Unlink and close the command file if we opened one 18421590Srgrimes */ 18431590Srgrimes if (job->cmdFILE != stdout) { 184418730Ssteve if (job->cmdFILE != NULL) 184518730Ssteve (void) fclose(job->cmdFILE); 18461590Srgrimes } else { 184718730Ssteve (void) fflush(stdout); 18481590Srgrimes } 18491590Srgrimes 18501590Srgrimes /* 18511590Srgrimes * We only want to work our way up the graph if we aren't here because 18521590Srgrimes * the commands for the job were no good. 18531590Srgrimes */ 18541590Srgrimes if (cmdsOK) { 18551590Srgrimes if (aborting == 0) { 185669527Swill if (job->tailCmds != NULL) { 18571590Srgrimes Lst_ForEachFrom(job->node->commands, job->tailCmds, 18581590Srgrimes JobSaveCommand, 185969531Swill (void *)job->node); 18601590Srgrimes } 186136621Sbde job->node->made = MADE; 18621590Srgrimes Make_Update(job->node); 18631590Srgrimes } 186469531Swill free(job); 18651590Srgrimes return(JOB_FINISHED); 18661590Srgrimes } else { 186769531Swill free(job); 18681590Srgrimes return(JOB_ERROR); 18691590Srgrimes } 18701590Srgrimes } else { 187118730Ssteve (void) fflush(job->cmdFILE); 18721590Srgrimes } 18731590Srgrimes 18741590Srgrimes /* 18751590Srgrimes * Set up the control arguments to the shell. This is based on the flags 18761590Srgrimes * set earlier for this job. 18771590Srgrimes */ 18781590Srgrimes JobMakeArgv(job, argv); 18791590Srgrimes 18801590Srgrimes /* 18811590Srgrimes * If we're using pipes to catch output, create the pipe by which we'll 18821590Srgrimes * get the shell's output. If we're using files, print out that we're 188350145Shoek * starting a job and then set up its temporary-file name. 18841590Srgrimes */ 188518730Ssteve if (!compatMake || (job->flags & JOB_FIRST)) { 18861590Srgrimes if (usePipes) { 18871590Srgrimes int fd[2]; 188818730Ssteve if (pipe(fd) == -1) 188918730Ssteve Punt("Cannot create pipe: %s", strerror(errno)); 18901590Srgrimes job->inPipe = fd[0]; 18911590Srgrimes job->outPipe = fd[1]; 189218730Ssteve (void) fcntl(job->inPipe, F_SETFD, 1); 189318730Ssteve (void) fcntl(job->outPipe, F_SETFD, 1); 18941590Srgrimes } else { 189518730Ssteve (void) fprintf(stdout, "Remaking `%s'\n", gn->name); 189618730Ssteve (void) fflush(stdout); 189750145Shoek (void) strcpy(job->outFile, TMPPAT); 189850145Shoek if ((job->outFd = mkstemp(job->outFile)) == -1) 189950145Shoek Punt("cannot create temp file: %s", strerror(errno)); 190018730Ssteve (void) fcntl(job->outFd, F_SETFD, 1); 19011590Srgrimes } 19021590Srgrimes } 19031590Srgrimes 190418730Ssteve#ifdef REMOTE 190518730Ssteve if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) { 190618730Ssteve#ifdef RMT_NO_EXEC 190718730Ssteve local = !Rmt_Export(shellPath, argv, job); 190818730Ssteve#else 190918730Ssteve local = !Rmt_Begin(shellPath, argv, job->node); 191018730Ssteve#endif /* RMT_NO_EXEC */ 191118730Ssteve if (!local) { 191218730Ssteve job->flags |= JOB_REMOTE; 191318730Ssteve } 191418730Ssteve } else 191518730Ssteve#endif 191618730Ssteve local = TRUE; 19171590Srgrimes 19181590Srgrimes if (local && (((nLocal >= maxLocal) && 191918730Ssteve !(job->flags & JOB_SPECIAL) && 192018730Ssteve#ifdef REMOTE 192118730Ssteve (!(gn->type & OP_NOEXPORT) || (maxLocal != 0)) 192218730Ssteve#else 192318730Ssteve (maxLocal != 0) 192418730Ssteve#endif 192518730Ssteve ))) 19261590Srgrimes { 19271590Srgrimes /* 19281590Srgrimes * The job can only be run locally, but we've hit the limit of 19291590Srgrimes * local concurrency, so put the job on hold until some other job 19301590Srgrimes * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END) 19311590Srgrimes * may be run locally even when the local limit has been reached 19321590Srgrimes * (e.g. when maxLocal == 0), though they will be exported if at 193318730Ssteve * all possible. In addition, any target marked with .NOEXPORT will 193418730Ssteve * be run locally if maxLocal is 0. 19351590Srgrimes */ 19361590Srgrimes jobFull = TRUE; 19378874Srgrimes 19381590Srgrimes if (DEBUG(JOB)) { 193918730Ssteve (void) fprintf(stdout, "Can only run job locally.\n"); 194018730Ssteve (void) fflush(stdout); 19411590Srgrimes } 19421590Srgrimes job->flags |= JOB_RESTART; 194369531Swill (void) Lst_AtEnd(stoppedJobs, (void *)job); 19441590Srgrimes } else { 19451590Srgrimes if ((nLocal >= maxLocal) && local) { 19461590Srgrimes /* 19471590Srgrimes * If we're running this job locally as a special case (see above), 19481590Srgrimes * at least say the table is full. 19491590Srgrimes */ 19501590Srgrimes jobFull = TRUE; 19511590Srgrimes if (DEBUG(JOB)) { 195218730Ssteve (void) fprintf(stdout, "Local job queue is full.\n"); 195318730Ssteve (void) fflush(stdout); 19541590Srgrimes } 19551590Srgrimes } 19561590Srgrimes JobExec(job, argv); 19571590Srgrimes } 19581590Srgrimes return(JOB_RUNNING); 19591590Srgrimes} 19601590Srgrimes 196118730Sstevestatic char * 196218730SsteveJobOutput(job, cp, endp, msg) 196394584Sobrien Job *job; 196494584Sobrien char *cp, *endp; 196518730Ssteve int msg; 196618730Ssteve{ 196794584Sobrien char *ecp; 196818730Ssteve 196918730Ssteve if (commandShell->noPrint) { 197018730Ssteve ecp = Str_FindSubstring(cp, commandShell->noPrint); 197118730Ssteve while (ecp != NULL) { 197218730Ssteve if (cp != ecp) { 197318730Ssteve *ecp = '\0'; 197418730Ssteve if (msg && job->node != lastNode) { 197518730Ssteve MESSAGE(stdout, job->node); 197618730Ssteve lastNode = job->node; 197718730Ssteve } 197818730Ssteve /* 197918730Ssteve * The only way there wouldn't be a newline after 198018730Ssteve * this line is if it were the last in the buffer. 198118730Ssteve * however, since the non-printable comes after it, 198218730Ssteve * there must be a newline, so we don't print one. 198318730Ssteve */ 198418730Ssteve (void) fprintf(stdout, "%s", cp); 198518730Ssteve (void) fflush(stdout); 198618730Ssteve } 198718730Ssteve cp = ecp + commandShell->noPLen; 198818730Ssteve if (cp != endp) { 198918730Ssteve /* 199018730Ssteve * Still more to print, look again after skipping 199118730Ssteve * the whitespace following the non-printable 199218730Ssteve * command.... 199318730Ssteve */ 199418730Ssteve cp++; 199518730Ssteve while (*cp == ' ' || *cp == '\t' || *cp == '\n') { 199618730Ssteve cp++; 199718730Ssteve } 199818730Ssteve ecp = Str_FindSubstring(cp, commandShell->noPrint); 199918730Ssteve } else { 200018730Ssteve return cp; 200118730Ssteve } 200218730Ssteve } 200318730Ssteve } 200418730Ssteve return cp; 200518730Ssteve} 200618730Ssteve 20071590Srgrimes/*- 20081590Srgrimes *----------------------------------------------------------------------- 20091590Srgrimes * JobDoOutput -- 20101590Srgrimes * This function is called at different times depending on 20111590Srgrimes * whether the user has specified that output is to be collected 20121590Srgrimes * via pipes or temporary files. In the former case, we are called 20131590Srgrimes * whenever there is something to read on the pipe. We collect more 20141590Srgrimes * output from the given job and store it in the job's outBuf. If 20151590Srgrimes * this makes up a line, we print it tagged by the job's identifier, 20161590Srgrimes * as necessary. 20171590Srgrimes * If output has been collected in a temporary file, we open the 20181590Srgrimes * file and read it line by line, transfering it to our own 20191590Srgrimes * output channel until the file is empty. At which point we 20201590Srgrimes * remove the temporary file. 20211590Srgrimes * In both cases, however, we keep our figurative eye out for the 20221590Srgrimes * 'noPrint' line for the shell from which the output came. If 20231590Srgrimes * we recognize a line, we don't print it. If the command is not 20241590Srgrimes * alone on the line (the character after it is not \0 or \n), we 20251590Srgrimes * do print whatever follows it. 20261590Srgrimes * 20271590Srgrimes * Results: 20281590Srgrimes * None 20291590Srgrimes * 20301590Srgrimes * Side Effects: 20311590Srgrimes * curPos may be shifted as may the contents of outBuf. 20321590Srgrimes *----------------------------------------------------------------------- 20331590Srgrimes */ 203418730SsteveSTATIC void 203518730SsteveJobDoOutput(job, finish) 203694584Sobrien Job *job; /* the job whose output needs printing */ 20371590Srgrimes Boolean finish; /* TRUE if this is the last time we'll be 20381590Srgrimes * called for this job */ 20391590Srgrimes{ 20401590Srgrimes Boolean gotNL = FALSE; /* true if got a newline */ 204118730Ssteve Boolean fbuf; /* true if our buffer filled up */ 204294584Sobrien int nr; /* number of bytes read */ 204394584Sobrien int i; /* auxiliary index into outBuf */ 204494584Sobrien int max; /* limit for i (end of current data) */ 20451590Srgrimes int nRead; /* (Temporary) number of bytes read */ 20461590Srgrimes 20471590Srgrimes FILE *oFILE; /* Stream pointer to shell's output file */ 20481590Srgrimes char inLine[132]; 20491590Srgrimes 20508874Srgrimes 20511590Srgrimes if (usePipes) { 20521590Srgrimes /* 20531590Srgrimes * Read as many bytes as will fit in the buffer. 20541590Srgrimes */ 20551590Srgrimesend_loop: 205618730Ssteve gotNL = FALSE; 205718730Ssteve fbuf = FALSE; 20588874Srgrimes 205918730Ssteve nRead = read(job->inPipe, &job->outBuf[job->curPos], 20601590Srgrimes JOB_BUFSIZE - job->curPos); 20611590Srgrimes if (nRead < 0) { 20621590Srgrimes if (DEBUG(JOB)) { 206394506Scharnier warn("JobDoOutput(piperead)"); 20641590Srgrimes } 20651590Srgrimes nr = 0; 20661590Srgrimes } else { 20671590Srgrimes nr = nRead; 20681590Srgrimes } 20691590Srgrimes 20701590Srgrimes /* 20711590Srgrimes * If we hit the end-of-file (the job is dead), we must flush its 20721590Srgrimes * remaining output, so pretend we read a newline if there's any 20731590Srgrimes * output remaining in the buffer. 20741590Srgrimes * Also clear the 'finish' flag so we stop looping. 20751590Srgrimes */ 20761590Srgrimes if ((nr == 0) && (job->curPos != 0)) { 20771590Srgrimes job->outBuf[job->curPos] = '\n'; 20781590Srgrimes nr = 1; 20791590Srgrimes finish = FALSE; 20801590Srgrimes } else if (nr == 0) { 20811590Srgrimes finish = FALSE; 20821590Srgrimes } 20838874Srgrimes 20841590Srgrimes /* 20851590Srgrimes * Look for the last newline in the bytes we just got. If there is 20861590Srgrimes * one, break out of the loop with 'i' as its index and gotNL set 20878874Srgrimes * TRUE. 20881590Srgrimes */ 20891590Srgrimes max = job->curPos + nr; 20901590Srgrimes for (i = job->curPos + nr - 1; i >= job->curPos; i--) { 20911590Srgrimes if (job->outBuf[i] == '\n') { 20921590Srgrimes gotNL = TRUE; 20931590Srgrimes break; 20941590Srgrimes } else if (job->outBuf[i] == '\0') { 20951590Srgrimes /* 20961590Srgrimes * Why? 20971590Srgrimes */ 20981590Srgrimes job->outBuf[i] = ' '; 20991590Srgrimes } 21001590Srgrimes } 21018874Srgrimes 21021590Srgrimes if (!gotNL) { 21031590Srgrimes job->curPos += nr; 21041590Srgrimes if (job->curPos == JOB_BUFSIZE) { 21051590Srgrimes /* 21061590Srgrimes * If we've run out of buffer space, we have no choice 21078874Srgrimes * but to print the stuff. sigh. 21081590Srgrimes */ 210918730Ssteve fbuf = TRUE; 21101590Srgrimes i = job->curPos; 21111590Srgrimes } 21121590Srgrimes } 211318730Ssteve if (gotNL || fbuf) { 21141590Srgrimes /* 21151590Srgrimes * Need to send the output to the screen. Null terminate it 21161590Srgrimes * first, overwriting the newline character if there was one. 21171590Srgrimes * So long as the line isn't one we should filter (according 211872645Sasmodai * to the shell description), we print the line, preceded 21191590Srgrimes * by a target banner if this target isn't the same as the 21201590Srgrimes * one for which we last printed something. 21211590Srgrimes * The rest of the data in the buffer are then shifted down 21228874Srgrimes * to the start of the buffer and curPos is set accordingly. 21231590Srgrimes */ 21241590Srgrimes job->outBuf[i] = '\0'; 21251590Srgrimes if (i >= job->curPos) { 212618730Ssteve char *cp; 21271590Srgrimes 212818730Ssteve cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); 21291590Srgrimes 21301590Srgrimes /* 21311590Srgrimes * There's still more in that thar buffer. This time, though, 21321590Srgrimes * we know there's no newline at the end, so we add one of 21331590Srgrimes * our own free will. 21341590Srgrimes */ 21351590Srgrimes if (*cp != '\0') { 21361590Srgrimes if (job->node != lastNode) { 213718730Ssteve MESSAGE(stdout, job->node); 21381590Srgrimes lastNode = job->node; 21391590Srgrimes } 214018730Ssteve (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); 214118730Ssteve (void) fflush(stdout); 21421590Srgrimes } 21431590Srgrimes } 21441590Srgrimes if (i < max - 1) { 21451590Srgrimes /* shift the remaining characters down */ 214618730Ssteve (void) memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); 21471590Srgrimes job->curPos = max - (i + 1); 21488874Srgrimes 21491590Srgrimes } else { 21501590Srgrimes /* 21511590Srgrimes * We have written everything out, so we just start over 21521590Srgrimes * from the start of the buffer. No copying. No nothing. 21531590Srgrimes */ 21541590Srgrimes job->curPos = 0; 21551590Srgrimes } 21561590Srgrimes } 21571590Srgrimes if (finish) { 21581590Srgrimes /* 21591590Srgrimes * If the finish flag is true, we must loop until we hit 216018730Ssteve * end-of-file on the pipe. This is guaranteed to happen 216118730Ssteve * eventually since the other end of the pipe is now closed 216218730Ssteve * (we closed it explicitly and the child has exited). When 216318730Ssteve * we do get an EOF, finish will be set FALSE and we'll fall 216418730Ssteve * through and out. 21651590Srgrimes */ 21661590Srgrimes goto end_loop; 21671590Srgrimes } 21681590Srgrimes } else { 21691590Srgrimes /* 21701590Srgrimes * We've been called to retrieve the output of the job from the 21711590Srgrimes * temporary file where it's been squirreled away. This consists of 21721590Srgrimes * opening the file, reading the output line by line, being sure not 21731590Srgrimes * to print the noPrint line for the shell we used, then close and 21741590Srgrimes * remove the temporary file. Very simple. 21751590Srgrimes * 21761590Srgrimes * Change to read in blocks and do FindSubString type things as for 21771590Srgrimes * pipes? That would allow for "@echo -n..." 21781590Srgrimes */ 217918730Ssteve oFILE = fopen(job->outFile, "r"); 218018730Ssteve if (oFILE != NULL) { 218118730Ssteve (void) fprintf(stdout, "Results of making %s:\n", job->node->name); 218218730Ssteve (void) fflush(stdout); 218318730Ssteve while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { 218494584Sobrien char *cp, *endp, *oendp; 21851590Srgrimes 21861590Srgrimes cp = inLine; 218718730Ssteve oendp = endp = inLine + strlen(inLine); 21881590Srgrimes if (endp[-1] == '\n') { 21891590Srgrimes *--endp = '\0'; 21901590Srgrimes } 219118730Ssteve cp = JobOutput(job, inLine, endp, FALSE); 21921590Srgrimes 21931590Srgrimes /* 21941590Srgrimes * There's still more in that thar buffer. This time, though, 21951590Srgrimes * we know there's no newline at the end, so we add one of 21961590Srgrimes * our own free will. 21971590Srgrimes */ 219818730Ssteve (void) fprintf(stdout, "%s", cp); 219918730Ssteve (void) fflush(stdout); 220018730Ssteve if (endp != oendp) { 220118730Ssteve (void) fprintf(stdout, "\n"); 220218730Ssteve (void) fflush(stdout); 22031590Srgrimes } 22041590Srgrimes } 220518730Ssteve (void) fclose(oFILE); 220618730Ssteve (void) eunlink(job->outFile); 22071590Srgrimes } 22081590Srgrimes } 22091590Srgrimes} 22101590Srgrimes 22111590Srgrimes/*- 22121590Srgrimes *----------------------------------------------------------------------- 22131590Srgrimes * Job_CatchChildren -- 22141590Srgrimes * Handle the exit of a child. Called from Make_Make. 22151590Srgrimes * 22161590Srgrimes * Results: 22171590Srgrimes * none. 22181590Srgrimes * 22191590Srgrimes * Side Effects: 22201590Srgrimes * The job descriptor is removed from the list of children. 22211590Srgrimes * 22221590Srgrimes * Notes: 22231590Srgrimes * We do waits, blocking or not, according to the wisdom of our 22241590Srgrimes * caller, until there are no more children to report. For each 22251590Srgrimes * job, call JobFinish to finish things off. This will take care of 22261590Srgrimes * putting jobs on the stoppedJobs queue. 22271590Srgrimes * 22281590Srgrimes *----------------------------------------------------------------------- 22291590Srgrimes */ 22301590Srgrimesvoid 223118730SsteveJob_CatchChildren(block) 22321590Srgrimes Boolean block; /* TRUE if should block on the wait. */ 22331590Srgrimes{ 22341590Srgrimes int pid; /* pid of dead child */ 223594584Sobrien Job *job; /* job descriptor for dead child */ 22361590Srgrimes LstNode jnode; /* list element for finding job */ 223718730Ssteve int status; /* Exit/termination status */ 22381590Srgrimes 22391590Srgrimes /* 22401590Srgrimes * Don't even bother if we know there's no one around. 22411590Srgrimes */ 22421590Srgrimes if (nLocal == 0) { 22431590Srgrimes return; 22441590Srgrimes } 22458874Srgrimes 224618730Ssteve while ((pid = waitpid((pid_t) -1, &status, 224718730Ssteve (block?0:WNOHANG)|WUNTRACED)) > 0) 22481590Srgrimes { 224918730Ssteve if (DEBUG(JOB)) { 225018730Ssteve (void) fprintf(stdout, "Process %d exited or stopped.\n", pid); 225118730Ssteve (void) fflush(stdout); 225218730Ssteve } 22531590Srgrimes 22548874Srgrimes 225569531Swill jnode = Lst_Find(jobs, (void *)&pid, JobCmpPid); 22561590Srgrimes 225769527Swill if (jnode == NULL) { 225818730Ssteve if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) { 225969531Swill jnode = Lst_Find(stoppedJobs, (void *) &pid, JobCmpPid); 226069527Swill if (jnode == NULL) { 22611590Srgrimes Error("Resumed child (%d) not in table", pid); 22621590Srgrimes continue; 22631590Srgrimes } 22641590Srgrimes job = (Job *)Lst_Datum(jnode); 226518730Ssteve (void) Lst_Remove(stoppedJobs, jnode); 22661590Srgrimes } else { 226718730Ssteve Error("Child (%d) not in table?", pid); 22681590Srgrimes continue; 22691590Srgrimes } 22701590Srgrimes } else { 227118730Ssteve job = (Job *) Lst_Datum(jnode); 227218730Ssteve (void) Lst_Remove(jobs, jnode); 22731590Srgrimes nJobs -= 1; 22741590Srgrimes if (jobFull && DEBUG(JOB)) { 227518730Ssteve (void) fprintf(stdout, "Job queue is no longer full.\n"); 227618730Ssteve (void) fflush(stdout); 22771590Srgrimes } 22781590Srgrimes jobFull = FALSE; 227918730Ssteve#ifdef REMOTE 228018730Ssteve if (!(job->flags & JOB_REMOTE)) { 228118730Ssteve if (DEBUG(JOB)) { 228218730Ssteve (void) fprintf(stdout, 228318730Ssteve "Job queue has one fewer local process.\n"); 228418730Ssteve (void) fflush(stdout); 228518730Ssteve } 228618730Ssteve nLocal -= 1; 228718730Ssteve } 228818730Ssteve#else 22891590Srgrimes nLocal -= 1; 229018730Ssteve#endif 22911590Srgrimes } 22921590Srgrimes 229318730Ssteve JobFinish(job, &status); 22941590Srgrimes } 22951590Srgrimes} 22961590Srgrimes 22971590Srgrimes/*- 22981590Srgrimes *----------------------------------------------------------------------- 22991590Srgrimes * Job_CatchOutput -- 23001590Srgrimes * Catch the output from our children, if we're using 23011590Srgrimes * pipes do so. Otherwise just block time until we get a 23021590Srgrimes * signal (most likely a SIGCHLD) since there's no point in 23031590Srgrimes * just spinning when there's nothing to do and the reaping 23048874Srgrimes * of a child can wait for a while. 23051590Srgrimes * 23061590Srgrimes * Results: 23078874Srgrimes * None 23081590Srgrimes * 23091590Srgrimes * Side Effects: 23101590Srgrimes * Output is read from pipes if we're piping. 23111590Srgrimes * ----------------------------------------------------------------------- 23121590Srgrimes */ 23131590Srgrimesvoid 231418730SsteveJob_CatchOutput() 23151590Srgrimes{ 23161590Srgrimes int nfds; 23171590Srgrimes struct timeval timeout; 23181590Srgrimes fd_set readfds; 231994584Sobrien LstNode ln; 232094584Sobrien Job *job; 23211590Srgrimes#ifdef RMT_WILL_WATCH 23221590Srgrimes int pnJobs; /* Previous nJobs */ 23231590Srgrimes#endif 23241590Srgrimes 232518730Ssteve (void) fflush(stdout); 23261590Srgrimes#ifdef RMT_WILL_WATCH 23271590Srgrimes pnJobs = nJobs; 23281590Srgrimes 23291590Srgrimes /* 23301590Srgrimes * It is possible for us to be called with nJobs equal to 0. This happens 23311590Srgrimes * if all the jobs finish and a job that is stopped cannot be run 23321590Srgrimes * locally (eg if maxLocal is 0) and cannot be exported. The job will 23331590Srgrimes * be placed back on the stoppedJobs queue, Job_Empty() will return false, 23341590Srgrimes * Make_Run will call us again when there's nothing for which to wait. 23351590Srgrimes * nJobs never changes, so we loop forever. Hence the check. It could 23361590Srgrimes * be argued that we should sleep for a bit so as not to swamp the 23371590Srgrimes * exportation system with requests. Perhaps we should. 23381590Srgrimes * 23391590Srgrimes * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren 23401590Srgrimes * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT. 23411590Srgrimes * It may use the variable nLocal to determine if it needs to call 23421590Srgrimes * Job_CatchChildren (if nLocal is 0, there's nothing for which to 23431590Srgrimes * wait...) 23441590Srgrimes */ 23451590Srgrimes while (nJobs != 0 && pnJobs == nJobs) { 23461590Srgrimes Rmt_Wait(); 23471590Srgrimes } 23481590Srgrimes#else 23491590Srgrimes if (usePipes) { 23501590Srgrimes readfds = outputs; 23511590Srgrimes timeout.tv_sec = SEL_SEC; 23521590Srgrimes timeout.tv_usec = SEL_USEC; 23531590Srgrimes 235418730Ssteve if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, 235518730Ssteve (fd_set *) 0, &timeout)) <= 0) 23561590Srgrimes return; 235718730Ssteve else { 235818730Ssteve if (Lst_Open(jobs) == FAILURE) { 235918730Ssteve Punt("Cannot open job table"); 23601590Srgrimes } 236169527Swill while (nfds && (ln = Lst_Next(jobs)) != NULL) { 236218730Ssteve job = (Job *) Lst_Datum(ln); 23631590Srgrimes if (FD_ISSET(job->inPipe, &readfds)) { 236418730Ssteve JobDoOutput(job, FALSE); 23651590Srgrimes nfds -= 1; 23661590Srgrimes } 23671590Srgrimes } 236818730Ssteve Lst_Close(jobs); 23691590Srgrimes } 23701590Srgrimes } 23711590Srgrimes#endif /* RMT_WILL_WATCH */ 23721590Srgrimes} 23731590Srgrimes 23741590Srgrimes/*- 23751590Srgrimes *----------------------------------------------------------------------- 23761590Srgrimes * Job_Make -- 23771590Srgrimes * Start the creation of a target. Basically a front-end for 23781590Srgrimes * JobStart used by the Make module. 23791590Srgrimes * 23801590Srgrimes * Results: 23811590Srgrimes * None. 23821590Srgrimes * 23831590Srgrimes * Side Effects: 23841590Srgrimes * Another job is started. 23851590Srgrimes * 23861590Srgrimes *----------------------------------------------------------------------- 23871590Srgrimes */ 23881590Srgrimesvoid 238918730SsteveJob_Make(gn) 23901590Srgrimes GNode *gn; 23911590Srgrimes{ 239218730Ssteve (void) JobStart(gn, 0, NULL); 23931590Srgrimes} 23941590Srgrimes 23951590Srgrimes/*- 23961590Srgrimes *----------------------------------------------------------------------- 23971590Srgrimes * Job_Init -- 23981590Srgrimes * Initialize the process module 23991590Srgrimes * 24001590Srgrimes * Results: 24011590Srgrimes * none 24021590Srgrimes * 24031590Srgrimes * Side Effects: 24041590Srgrimes * lists and counters are initialized 24051590Srgrimes *----------------------------------------------------------------------- 24061590Srgrimes */ 24071590Srgrimesvoid 240818730SsteveJob_Init(maxproc, maxlocal) 24091590Srgrimes int maxproc; /* the greatest number of jobs which may be 24101590Srgrimes * running at one time */ 24111590Srgrimes int maxlocal; /* the greatest number of local jobs which may 24121590Srgrimes * be running at once. */ 24131590Srgrimes{ 24141590Srgrimes GNode *begin; /* node for commands to do at the very start */ 24151590Srgrimes 241618730Ssteve jobs = Lst_Init(FALSE); 24171590Srgrimes stoppedJobs = Lst_Init(FALSE); 24181590Srgrimes maxJobs = maxproc; 24191590Srgrimes maxLocal = maxlocal; 24201590Srgrimes nJobs = 0; 24211590Srgrimes nLocal = 0; 24221590Srgrimes jobFull = FALSE; 24231590Srgrimes 24241590Srgrimes aborting = 0; 24251590Srgrimes errors = 0; 24261590Srgrimes 242769527Swill lastNode = NULL; 24281590Srgrimes 242941151Sdg if (maxJobs == 1 || beVerbose == 0 243018730Ssteve#ifdef REMOTE 243118730Ssteve || noMessages 243218730Ssteve#endif 243318730Ssteve ) { 24341590Srgrimes /* 24351590Srgrimes * If only one job can run at a time, there's no need for a banner, 24361590Srgrimes * no is there? 24371590Srgrimes */ 24381590Srgrimes targFmt = ""; 24391590Srgrimes } else { 24401590Srgrimes targFmt = TARG_FMT; 24411590Srgrimes } 24428874Srgrimes 244318730Ssteve if (shellPath == NULL) { 24441590Srgrimes /* 24451590Srgrimes * The user didn't specify a shell to use, so we are using the 24461590Srgrimes * default one... Both the absolute path and the last component 24471590Srgrimes * must be set. The last component is taken from the 'name' field 24481590Srgrimes * of the default shell description pointed-to by commandShell. 24491590Srgrimes * All default shells are located in _PATH_DEFSHELLDIR. 24501590Srgrimes */ 24511590Srgrimes shellName = commandShell->name; 245218730Ssteve shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); 24531590Srgrimes } 24541590Srgrimes 245518730Ssteve if (commandShell->exit == NULL) { 24561590Srgrimes commandShell->exit = ""; 24571590Srgrimes } 245818730Ssteve if (commandShell->echo == NULL) { 24591590Srgrimes commandShell->echo = ""; 24601590Srgrimes } 24611590Srgrimes 24621590Srgrimes /* 24631590Srgrimes * Catch the four signals that POSIX specifies if they aren't ignored. 24641590Srgrimes * JobPassSig will take care of calling JobInterrupt if appropriate. 24651590Srgrimes */ 246618730Ssteve if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 246718730Ssteve (void) signal(SIGINT, JobPassSig); 24681590Srgrimes } 246918730Ssteve if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 247018730Ssteve (void) signal(SIGHUP, JobPassSig); 24711590Srgrimes } 247218730Ssteve if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 247318730Ssteve (void) signal(SIGQUIT, JobPassSig); 24741590Srgrimes } 247518730Ssteve if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 247618730Ssteve (void) signal(SIGTERM, JobPassSig); 24771590Srgrimes } 24781590Srgrimes /* 24791590Srgrimes * There are additional signals that need to be caught and passed if 24801590Srgrimes * either the export system wants to be told directly of signals or if 24811590Srgrimes * we're giving each job its own process group (since then it won't get 24821590Srgrimes * signals from the terminal driver as we own the terminal) 24831590Srgrimes */ 24841590Srgrimes#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) 248518730Ssteve if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { 248618730Ssteve (void) signal(SIGTSTP, JobPassSig); 24871590Srgrimes } 248818730Ssteve if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { 248918730Ssteve (void) signal(SIGTTOU, JobPassSig); 24901590Srgrimes } 249118730Ssteve if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { 249218730Ssteve (void) signal(SIGTTIN, JobPassSig); 24931590Srgrimes } 249418730Ssteve if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { 249518730Ssteve (void) signal(SIGWINCH, JobPassSig); 24961590Srgrimes } 24971590Srgrimes#endif 24988874Srgrimes 249918730Ssteve begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); 25001590Srgrimes 250169527Swill if (begin != NULL) { 250218730Ssteve JobStart(begin, JOB_SPECIAL, (Job *)0); 25031590Srgrimes while (nJobs) { 25041590Srgrimes Job_CatchOutput(); 25051590Srgrimes#ifndef RMT_WILL_WATCH 250618730Ssteve Job_CatchChildren(!usePipes); 25071590Srgrimes#endif /* RMT_WILL_WATCH */ 25081590Srgrimes } 25091590Srgrimes } 251018730Ssteve postCommands = Targ_FindNode(".END", TARG_CREATE); 25111590Srgrimes} 25121590Srgrimes 25131590Srgrimes/*- 25141590Srgrimes *----------------------------------------------------------------------- 25151590Srgrimes * Job_Full -- 25161590Srgrimes * See if the job table is full. It is considered full if it is OR 25171590Srgrimes * if we are in the process of aborting OR if we have 25181590Srgrimes * reached/exceeded our local quota. This prevents any more jobs 25191590Srgrimes * from starting up. 25201590Srgrimes * 25211590Srgrimes * Results: 25221590Srgrimes * TRUE if the job table is full, FALSE otherwise 25231590Srgrimes * Side Effects: 25241590Srgrimes * None. 25251590Srgrimes *----------------------------------------------------------------------- 25261590Srgrimes */ 25271590SrgrimesBoolean 252818730SsteveJob_Full() 25291590Srgrimes{ 253018730Ssteve return(aborting || jobFull); 25311590Srgrimes} 25321590Srgrimes 25331590Srgrimes/*- 25341590Srgrimes *----------------------------------------------------------------------- 25351590Srgrimes * Job_Empty -- 25361590Srgrimes * See if the job table is empty. Because the local concurrency may 25371590Srgrimes * be set to 0, it is possible for the job table to become empty, 25381590Srgrimes * while the list of stoppedJobs remains non-empty. In such a case, 25391590Srgrimes * we want to restart as many jobs as we can. 25401590Srgrimes * 25411590Srgrimes * Results: 25421590Srgrimes * TRUE if it is. FALSE if it ain't. 25431590Srgrimes * 25441590Srgrimes * Side Effects: 25451590Srgrimes * None. 25461590Srgrimes * 25471590Srgrimes * ----------------------------------------------------------------------- 25481590Srgrimes */ 25491590SrgrimesBoolean 255018730SsteveJob_Empty() 25511590Srgrimes{ 25521590Srgrimes if (nJobs == 0) { 25531590Srgrimes if (!Lst_IsEmpty(stoppedJobs) && !aborting) { 25541590Srgrimes /* 25551590Srgrimes * The job table is obviously not full if it has no jobs in 25561590Srgrimes * it...Try and restart the stopped jobs. 25571590Srgrimes */ 25581590Srgrimes jobFull = FALSE; 255918730Ssteve JobRestartJobs(); 25601590Srgrimes return(FALSE); 25611590Srgrimes } else { 25621590Srgrimes return(TRUE); 25631590Srgrimes } 25641590Srgrimes } else { 25651590Srgrimes return(FALSE); 25661590Srgrimes } 25671590Srgrimes} 25681590Srgrimes 25691590Srgrimes/*- 25701590Srgrimes *----------------------------------------------------------------------- 25711590Srgrimes * JobMatchShell -- 25721590Srgrimes * Find a matching shell in 'shells' given its final component. 25731590Srgrimes * 25741590Srgrimes * Results: 25751590Srgrimes * A pointer to the Shell structure. 25761590Srgrimes * 25771590Srgrimes * Side Effects: 25781590Srgrimes * None. 25791590Srgrimes * 25801590Srgrimes *----------------------------------------------------------------------- 25811590Srgrimes */ 25821590Srgrimesstatic Shell * 258318730SsteveJobMatchShell(name) 25841590Srgrimes char *name; /* Final component of shell path */ 25851590Srgrimes{ 258694584Sobrien Shell *sh; /* Pointer into shells table */ 258794584Sobrien Shell *match; /* Longest-matching shell */ 258894584Sobrien char *cp1, 25891590Srgrimes *cp2; 25901590Srgrimes char *eoname; 25911590Srgrimes 259218730Ssteve eoname = name + strlen(name); 25931590Srgrimes 259418730Ssteve match = NULL; 25951590Srgrimes 25961590Srgrimes for (sh = shells; sh->name != NULL; sh++) { 259718730Ssteve for (cp1 = eoname - strlen(sh->name), cp2 = sh->name; 25981590Srgrimes *cp1 != '\0' && *cp1 == *cp2; 25991590Srgrimes cp1++, cp2++) { 26001590Srgrimes continue; 26011590Srgrimes } 26021590Srgrimes if (*cp1 != *cp2) { 26031590Srgrimes continue; 260418730Ssteve } else if (match == NULL || strlen(match->name) < strlen(sh->name)) { 260518730Ssteve match = sh; 26061590Srgrimes } 26071590Srgrimes } 260818730Ssteve return(match == NULL ? sh : match); 26091590Srgrimes} 26101590Srgrimes 26111590Srgrimes/*- 26121590Srgrimes *----------------------------------------------------------------------- 26131590Srgrimes * Job_ParseShell -- 26141590Srgrimes * Parse a shell specification and set up commandShell, shellPath 26151590Srgrimes * and shellName appropriately. 26161590Srgrimes * 26171590Srgrimes * Results: 26181590Srgrimes * FAILURE if the specification was incorrect. 26191590Srgrimes * 26201590Srgrimes * Side Effects: 26211590Srgrimes * commandShell points to a Shell structure (either predefined or 26221590Srgrimes * created from the shell spec), shellPath is the full path of the 26231590Srgrimes * shell described by commandShell, while shellName is just the 26241590Srgrimes * final component of shellPath. 26251590Srgrimes * 26261590Srgrimes * Notes: 26271590Srgrimes * A shell specification consists of a .SHELL target, with dependency 26281590Srgrimes * operator, followed by a series of blank-separated words. Double 26291590Srgrimes * quotes can be used to use blanks in words. A backslash escapes 26301590Srgrimes * anything (most notably a double-quote and a space) and 26311590Srgrimes * provides the functionality it does in C. Each word consists of 26321590Srgrimes * keyword and value separated by an equal sign. There should be no 26331590Srgrimes * unnecessary spaces in the word. The keywords are as follows: 26341590Srgrimes * name Name of shell. 26351590Srgrimes * path Location of shell. Overrides "name" if given 26361590Srgrimes * quiet Command to turn off echoing. 26371590Srgrimes * echo Command to turn echoing on 26381590Srgrimes * filter Result of turning off echoing that shouldn't be 26391590Srgrimes * printed. 26401590Srgrimes * echoFlag Flag to turn echoing on at the start 26411590Srgrimes * errFlag Flag to turn error checking on at the start 26421590Srgrimes * hasErrCtl True if shell has error checking control 26431590Srgrimes * check Command to turn on error checking if hasErrCtl 26441590Srgrimes * is TRUE or template of command to echo a command 26451590Srgrimes * for which error checking is off if hasErrCtl is 26461590Srgrimes * FALSE. 26471590Srgrimes * ignore Command to turn off error checking if hasErrCtl 26481590Srgrimes * is TRUE or template of command to execute a 26491590Srgrimes * command so as to ignore any errors it returns if 26501590Srgrimes * hasErrCtl is FALSE. 26511590Srgrimes * 26521590Srgrimes *----------------------------------------------------------------------- 26531590Srgrimes */ 26541590SrgrimesReturnStatus 265518730SsteveJob_ParseShell(line) 26561590Srgrimes char *line; /* The shell spec */ 26571590Srgrimes{ 26581590Srgrimes char **words; 26591590Srgrimes int wordCount; 266094584Sobrien char **argv; 266194584Sobrien int argc; 26621590Srgrimes char *path; 26631590Srgrimes Shell newShell; 26641590Srgrimes Boolean fullSpec = FALSE; 26651590Srgrimes 266698500Sjmallett while (isspace((unsigned char) *line)) { 26671590Srgrimes line++; 26681590Srgrimes } 266918730Ssteve words = brk_string(line, &wordCount, TRUE); 26701590Srgrimes 267169531Swill memset(&newShell, 0, sizeof(newShell)); 26728874Srgrimes 26731590Srgrimes /* 26741590Srgrimes * Parse the specification by keyword 26751590Srgrimes */ 267618730Ssteve for (path = NULL, argc = wordCount - 1, argv = words + 1; 26771590Srgrimes argc != 0; 26781590Srgrimes argc--, argv++) { 267918730Ssteve if (strncmp(*argv, "path=", 5) == 0) { 26801590Srgrimes path = &argv[0][5]; 268118730Ssteve } else if (strncmp(*argv, "name=", 5) == 0) { 26821590Srgrimes newShell.name = &argv[0][5]; 26831590Srgrimes } else { 268418730Ssteve if (strncmp(*argv, "quiet=", 6) == 0) { 26851590Srgrimes newShell.echoOff = &argv[0][6]; 268618730Ssteve } else if (strncmp(*argv, "echo=", 5) == 0) { 26871590Srgrimes newShell.echoOn = &argv[0][5]; 268818730Ssteve } else if (strncmp(*argv, "filter=", 7) == 0) { 26891590Srgrimes newShell.noPrint = &argv[0][7]; 26901590Srgrimes newShell.noPLen = strlen(newShell.noPrint); 269118730Ssteve } else if (strncmp(*argv, "echoFlag=", 9) == 0) { 26921590Srgrimes newShell.echo = &argv[0][9]; 269318730Ssteve } else if (strncmp(*argv, "errFlag=", 8) == 0) { 26941590Srgrimes newShell.exit = &argv[0][8]; 269518730Ssteve } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { 26961590Srgrimes char c = argv[0][10]; 26971590Srgrimes newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && 269818730Ssteve (c != 'T') && (c != 't')); 269918730Ssteve } else if (strncmp(*argv, "check=", 6) == 0) { 27001590Srgrimes newShell.errCheck = &argv[0][6]; 270118730Ssteve } else if (strncmp(*argv, "ignore=", 7) == 0) { 27021590Srgrimes newShell.ignErr = &argv[0][7]; 27031590Srgrimes } else { 270418730Ssteve Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", 27051590Srgrimes *argv); 270618730Ssteve return(FAILURE); 27071590Srgrimes } 27081590Srgrimes fullSpec = TRUE; 27091590Srgrimes } 27101590Srgrimes } 27111590Srgrimes 271218730Ssteve if (path == NULL) { 27131590Srgrimes /* 27141590Srgrimes * If no path was given, the user wants one of the pre-defined shells, 27151590Srgrimes * yes? So we find the one s/he wants with the help of JobMatchShell 27161590Srgrimes * and set things up the right way. shellPath will be set up by 27171590Srgrimes * Job_Init. 27181590Srgrimes */ 271918730Ssteve if (newShell.name == NULL) { 272018730Ssteve Parse_Error(PARSE_FATAL, "Neither path nor name specified"); 272118730Ssteve return(FAILURE); 27221590Srgrimes } else { 272318730Ssteve commandShell = JobMatchShell(newShell.name); 27241590Srgrimes shellName = newShell.name; 27251590Srgrimes } 27261590Srgrimes } else { 27271590Srgrimes /* 27281590Srgrimes * The user provided a path. If s/he gave nothing else (fullSpec is 27291590Srgrimes * FALSE), try and find a matching shell in the ones we know of. 27301590Srgrimes * Else we just take the specification at its word and copy it 27311590Srgrimes * to a new location. In either case, we need to record the 27321590Srgrimes * path the user gave for the shell. 27331590Srgrimes */ 27341590Srgrimes shellPath = path; 273518730Ssteve path = strrchr(path, '/'); 273618730Ssteve if (path == NULL) { 27371590Srgrimes path = shellPath; 27381590Srgrimes } else { 27391590Srgrimes path += 1; 27401590Srgrimes } 274118730Ssteve if (newShell.name != NULL) { 27421590Srgrimes shellName = newShell.name; 27431590Srgrimes } else { 27441590Srgrimes shellName = path; 27451590Srgrimes } 27461590Srgrimes if (!fullSpec) { 274718730Ssteve commandShell = JobMatchShell(shellName); 27481590Srgrimes } else { 27491590Srgrimes commandShell = (Shell *) emalloc(sizeof(Shell)); 27501590Srgrimes *commandShell = newShell; 27511590Srgrimes } 27521590Srgrimes } 27531590Srgrimes 27541590Srgrimes if (commandShell->echoOn && commandShell->echoOff) { 27551590Srgrimes commandShell->hasEchoCtl = TRUE; 27561590Srgrimes } 27578874Srgrimes 27581590Srgrimes if (!commandShell->hasErrCtl) { 275918730Ssteve if (commandShell->errCheck == NULL) { 27601590Srgrimes commandShell->errCheck = ""; 27611590Srgrimes } 276218730Ssteve if (commandShell->ignErr == NULL) { 27631590Srgrimes commandShell->ignErr = "%s\n"; 27641590Srgrimes } 27651590Srgrimes } 27668874Srgrimes 27671590Srgrimes return SUCCESS; 27681590Srgrimes} 27691590Srgrimes 27701590Srgrimes/*- 27711590Srgrimes *----------------------------------------------------------------------- 27721590Srgrimes * JobInterrupt -- 27731590Srgrimes * Handle the receipt of an interrupt. 27741590Srgrimes * 27751590Srgrimes * Results: 27761590Srgrimes * None 27771590Srgrimes * 27781590Srgrimes * Side Effects: 27791590Srgrimes * All children are killed. Another job will be started if the 27801590Srgrimes * .INTERRUPT target was given. 27811590Srgrimes *----------------------------------------------------------------------- 27821590Srgrimes */ 27831590Srgrimesstatic void 278418730SsteveJobInterrupt(runINTERRUPT, signo) 27851590Srgrimes int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT 27861590Srgrimes * target should be executed */ 278718730Ssteve int signo; /* signal received */ 27881590Srgrimes{ 27891590Srgrimes LstNode ln; /* element in job table */ 279062830Swsanchez Job *job = NULL; /* job descriptor in that element */ 27911590Srgrimes GNode *interrupt; /* the node describing the .INTERRUPT target */ 27928874Srgrimes 27931590Srgrimes aborting = ABORT_INTERRUPT; 27941590Srgrimes 279518730Ssteve (void) Lst_Open(jobs); 279669527Swill while ((ln = Lst_Next(jobs)) != NULL) { 279718730Ssteve job = (Job *) Lst_Datum(ln); 27981590Srgrimes 279918730Ssteve if (!Targ_Precious(job->node)) { 280018730Ssteve char *file = (job->node->path == NULL ? 28011590Srgrimes job->node->name : 28021590Srgrimes job->node->path); 280318730Ssteve if (!noExecute && eunlink(file) != -1) { 280418730Ssteve Error("*** %s removed", file); 28051590Srgrimes } 28061590Srgrimes } 28071590Srgrimes#ifdef RMT_WANTS_SIGNALS 28081590Srgrimes if (job->flags & JOB_REMOTE) { 28091590Srgrimes /* 28101590Srgrimes * If job is remote, let the Rmt module do the killing. 28111590Srgrimes */ 281218730Ssteve if (!Rmt_Signal(job, signo)) { 28131590Srgrimes /* 28141590Srgrimes * If couldn't kill the thing, finish it out now with an 28151590Srgrimes * error code, since no exit report will come in likely. 28161590Srgrimes */ 281718730Ssteve int status; 28181590Srgrimes 28191590Srgrimes status.w_status = 0; 28201590Srgrimes status.w_retcode = 1; 282118730Ssteve JobFinish(job, &status); 28221590Srgrimes } 28231590Srgrimes } else if (job->pid) { 282418730Ssteve KILL(job->pid, signo); 28251590Srgrimes } 28261590Srgrimes#else 28271590Srgrimes if (job->pid) { 282818730Ssteve if (DEBUG(JOB)) { 282918730Ssteve (void) fprintf(stdout, 283018730Ssteve "JobInterrupt passing signal to child %d.\n", 283118730Ssteve job->pid); 283218730Ssteve (void) fflush(stdout); 283318730Ssteve } 283418730Ssteve KILL(job->pid, signo); 283518730Ssteve } 283618730Ssteve#endif /* RMT_WANTS_SIGNALS */ 283718730Ssteve } 283818730Ssteve 283918730Ssteve#ifdef REMOTE 284018730Ssteve (void)Lst_Open(stoppedJobs); 284169527Swill while ((ln = Lst_Next(stoppedJobs)) != NULL) { 284218730Ssteve job = (Job *) Lst_Datum(ln); 284318730Ssteve 284418730Ssteve if (job->flags & JOB_RESTART) { 284518730Ssteve if (DEBUG(JOB)) { 284618730Ssteve (void) fprintf(stdout, "%s%s", 284718730Ssteve "JobInterrupt skipping job on stopped queue", 284818730Ssteve "-- it was waiting to be restarted.\n"); 284918730Ssteve (void) fflush(stdout); 285018730Ssteve } 285118730Ssteve continue; 285218730Ssteve } 285318730Ssteve if (!Targ_Precious(job->node)) { 285418730Ssteve char *file = (job->node->path == NULL ? 285518730Ssteve job->node->name : 285618730Ssteve job->node->path); 285718730Ssteve if (eunlink(file) == 0) { 285818730Ssteve Error("*** %s removed", file); 285918730Ssteve } 286018730Ssteve } 286118730Ssteve /* 286218730Ssteve * Resume the thing so it will take the signal. 286318730Ssteve */ 286418730Ssteve if (DEBUG(JOB)) { 286518730Ssteve (void) fprintf(stdout, 286618730Ssteve "JobInterrupt passing CONT to stopped child %d.\n", 286718730Ssteve job->pid); 286818730Ssteve (void) fflush(stdout); 286918730Ssteve } 287018730Ssteve KILL(job->pid, SIGCONT); 287118730Ssteve#ifdef RMT_WANTS_SIGNALS 287218730Ssteve if (job->flags & JOB_REMOTE) { 287318730Ssteve /* 287418730Ssteve * If job is remote, let the Rmt module do the killing. 287518730Ssteve */ 287618730Ssteve if (!Rmt_Signal(job, SIGINT)) { 287718730Ssteve /* 287818730Ssteve * If couldn't kill the thing, finish it out now with an 287918730Ssteve * error code, since no exit report will come in likely. 288018730Ssteve */ 288118730Ssteve int status; 288218730Ssteve status.w_status = 0; 288318730Ssteve status.w_retcode = 1; 288418730Ssteve JobFinish(job, &status); 288518730Ssteve } 288618730Ssteve } else if (job->pid) { 288718730Ssteve if (DEBUG(JOB)) { 288818730Ssteve (void) fprintf(stdout, 288918730Ssteve "JobInterrupt passing interrupt to stopped child %d.\n", 289018730Ssteve job->pid); 289118730Ssteve (void) fflush(stdout); 289218730Ssteve } 28931590Srgrimes KILL(job->pid, SIGINT); 28941590Srgrimes } 28951590Srgrimes#endif /* RMT_WANTS_SIGNALS */ 28961590Srgrimes } 289718730Ssteve#endif 289818730Ssteve Lst_Close(stoppedJobs); 28991590Srgrimes 29001590Srgrimes if (runINTERRUPT && !touchFlag) { 290118730Ssteve interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 290269527Swill if (interrupt != NULL) { 29031590Srgrimes ignoreErrors = FALSE; 29041590Srgrimes 290518730Ssteve JobStart(interrupt, JOB_IGNDOTS, (Job *)0); 29061590Srgrimes while (nJobs) { 29071590Srgrimes Job_CatchOutput(); 29081590Srgrimes#ifndef RMT_WILL_WATCH 290918730Ssteve Job_CatchChildren(!usePipes); 29101590Srgrimes#endif /* RMT_WILL_WATCH */ 29111590Srgrimes } 29121590Srgrimes } 29131590Srgrimes } 29141590Srgrimes} 29151590Srgrimes 29161590Srgrimes/* 29171590Srgrimes *----------------------------------------------------------------------- 291894594Sobrien * Job_Finish -- 29191590Srgrimes * Do final processing such as the running of the commands 29208874Srgrimes * attached to the .END target. 29211590Srgrimes * 29221590Srgrimes * Results: 29231590Srgrimes * Number of errors reported. 29241590Srgrimes *----------------------------------------------------------------------- 29251590Srgrimes */ 29261590Srgrimesint 292794594SobrienJob_Finish() 29281590Srgrimes{ 292969527Swill if (postCommands != NULL && !Lst_IsEmpty(postCommands->commands)) { 29301590Srgrimes if (errors) { 293118730Ssteve Error("Errors reported so .END ignored"); 29321590Srgrimes } else { 293318730Ssteve JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); 29341590Srgrimes 29351590Srgrimes while (nJobs) { 29361590Srgrimes Job_CatchOutput(); 29371590Srgrimes#ifndef RMT_WILL_WATCH 293818730Ssteve Job_CatchChildren(!usePipes); 29391590Srgrimes#endif /* RMT_WILL_WATCH */ 29401590Srgrimes } 29411590Srgrimes } 29421590Srgrimes } 29431590Srgrimes return(errors); 29441590Srgrimes} 29451590Srgrimes 29461590Srgrimes/*- 29471590Srgrimes *----------------------------------------------------------------------- 29481590Srgrimes * Job_Wait -- 29491590Srgrimes * Waits for all running jobs to finish and returns. Sets 'aborting' 29501590Srgrimes * to ABORT_WAIT to prevent other jobs from starting. 29511590Srgrimes * 29521590Srgrimes * Results: 29531590Srgrimes * None. 29541590Srgrimes * 29551590Srgrimes * Side Effects: 29561590Srgrimes * Currently running jobs finish. 29571590Srgrimes * 29581590Srgrimes *----------------------------------------------------------------------- 29591590Srgrimes */ 29601590Srgrimesvoid 29611590SrgrimesJob_Wait() 29621590Srgrimes{ 29631590Srgrimes aborting = ABORT_WAIT; 29641590Srgrimes while (nJobs != 0) { 29651590Srgrimes Job_CatchOutput(); 29661590Srgrimes#ifndef RMT_WILL_WATCH 29671590Srgrimes Job_CatchChildren(!usePipes); 29681590Srgrimes#endif /* RMT_WILL_WATCH */ 29691590Srgrimes } 29701590Srgrimes aborting = 0; 29711590Srgrimes} 29721590Srgrimes 29731590Srgrimes/*- 29741590Srgrimes *----------------------------------------------------------------------- 29751590Srgrimes * Job_AbortAll -- 29761590Srgrimes * Abort all currently running jobs without handling output or anything. 29771590Srgrimes * This function is to be called only in the event of a major 29781590Srgrimes * error. Most definitely NOT to be called from JobInterrupt. 29791590Srgrimes * 29801590Srgrimes * Results: 29811590Srgrimes * None 29821590Srgrimes * 29831590Srgrimes * Side Effects: 29841590Srgrimes * All children are killed, not just the firstborn 29851590Srgrimes *----------------------------------------------------------------------- 29861590Srgrimes */ 29871590Srgrimesvoid 298818730SsteveJob_AbortAll() 29891590Srgrimes{ 299018730Ssteve LstNode ln; /* element in job table */ 29911590Srgrimes Job *job; /* the job descriptor in that element */ 29921590Srgrimes int foo; 29938874Srgrimes 29941590Srgrimes aborting = ABORT_ERROR; 29958874Srgrimes 29961590Srgrimes if (nJobs) { 29971590Srgrimes 299818730Ssteve (void) Lst_Open(jobs); 299969527Swill while ((ln = Lst_Next(jobs)) != NULL) { 300018730Ssteve job = (Job *) Lst_Datum(ln); 30011590Srgrimes 30021590Srgrimes /* 30031590Srgrimes * kill the child process with increasingly drastic signals to make 30048874Srgrimes * darn sure it's dead. 30051590Srgrimes */ 30061590Srgrimes#ifdef RMT_WANTS_SIGNALS 30071590Srgrimes if (job->flags & JOB_REMOTE) { 30081590Srgrimes Rmt_Signal(job, SIGINT); 30091590Srgrimes Rmt_Signal(job, SIGKILL); 30101590Srgrimes } else { 30111590Srgrimes KILL(job->pid, SIGINT); 30121590Srgrimes KILL(job->pid, SIGKILL); 30131590Srgrimes } 30141590Srgrimes#else 30151590Srgrimes KILL(job->pid, SIGINT); 30161590Srgrimes KILL(job->pid, SIGKILL); 30171590Srgrimes#endif /* RMT_WANTS_SIGNALS */ 30181590Srgrimes } 30191590Srgrimes } 30208874Srgrimes 30211590Srgrimes /* 30221590Srgrimes * Catch as many children as want to report in at first, then give up 30231590Srgrimes */ 302418730Ssteve while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) 30251590Srgrimes continue; 30261590Srgrimes} 302718730Ssteve 302818730Ssteve#ifdef REMOTE 302918730Ssteve/*- 303018730Ssteve *----------------------------------------------------------------------- 303118730Ssteve * JobFlagForMigration -- 303218730Ssteve * Handle the eviction of a child. Called from RmtStatusChange. 303318730Ssteve * Flags the child as remigratable and then suspends it. 303418730Ssteve * 303518730Ssteve * Results: 303618730Ssteve * none. 303718730Ssteve * 303818730Ssteve * Side Effects: 303918730Ssteve * The job descriptor is flagged for remigration. 304018730Ssteve * 304118730Ssteve *----------------------------------------------------------------------- 304218730Ssteve */ 304318730Sstevevoid 304418730SsteveJobFlagForMigration(hostID) 304518730Ssteve int hostID; /* ID of host we used, for matching children. */ 304618730Ssteve{ 304794584Sobrien Job *job; /* job descriptor for dead child */ 304818730Ssteve LstNode jnode; /* list element for finding job */ 304918730Ssteve 305018730Ssteve if (DEBUG(JOB)) { 305118730Ssteve (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID); 305218730Ssteve (void) fflush(stdout); 305318730Ssteve } 305469531Swill jnode = Lst_Find(jobs, (void *)hostID, JobCmpRmtID); 305518730Ssteve 305669527Swill if (jnode == NULL) { 305769531Swill jnode = Lst_Find(stoppedJobs, (void *)hostID, JobCmpRmtID); 305869527Swill if (jnode == NULL) { 305918730Ssteve if (DEBUG(JOB)) { 306018730Ssteve Error("Evicting host(%d) not in table", hostID); 306118730Ssteve } 306218730Ssteve return; 306318730Ssteve } 306418730Ssteve } 306518730Ssteve job = (Job *) Lst_Datum(jnode); 306618730Ssteve 306718730Ssteve if (DEBUG(JOB)) { 306818730Ssteve (void) fprintf(stdout, 306918730Ssteve "JobFlagForMigration(%d) found job '%s'.\n", hostID, 307018730Ssteve job->node->name); 307118730Ssteve (void) fflush(stdout); 307218730Ssteve } 307318730Ssteve 307418730Ssteve KILL(job->pid, SIGSTOP); 307518730Ssteve 307618730Ssteve job->flags |= JOB_REMIGRATE; 307718730Ssteve} 307818730Ssteve 307918730Ssteve#endif 308018730Ssteve 308118730Ssteve/*- 308218730Ssteve *----------------------------------------------------------------------- 308318730Ssteve * JobRestartJobs -- 308418730Ssteve * Tries to restart stopped jobs if there are slots available. 308518730Ssteve * Note that this tries to restart them regardless of pending errors. 308618730Ssteve * It's not good to leave stopped jobs lying around! 308718730Ssteve * 308818730Ssteve * Results: 308918730Ssteve * None. 309018730Ssteve * 309118730Ssteve * Side Effects: 309218730Ssteve * Resumes(and possibly migrates) jobs. 309318730Ssteve * 309418730Ssteve *----------------------------------------------------------------------- 309518730Ssteve */ 309618730Sstevestatic void 309718730SsteveJobRestartJobs() 309818730Ssteve{ 309918730Ssteve while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { 310018730Ssteve if (DEBUG(JOB)) { 310118730Ssteve (void) fprintf(stdout, 310218730Ssteve "Job queue is not full. Restarting a stopped job.\n"); 310318730Ssteve (void) fflush(stdout); 310418730Ssteve } 310518730Ssteve JobRestart((Job *)Lst_DeQueue(stoppedJobs)); 310618730Ssteve } 310718730Ssteve} 3108