job.c revision 92921
11590Srgrimes/* 25814Sjkh * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 35814Sjkh * Copyright (c) 1988, 1989 by Adam de Boor 41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks 51590Srgrimes * All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to Berkeley by 81590Srgrimes * Adam de Boor. 91590Srgrimes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 181590Srgrimes * 3. All advertising materials mentioning features or use of this software 191590Srgrimes * must display the following acknowledgement: 201590Srgrimes * This product includes software developed by the University of 211590Srgrimes * California, Berkeley and its contributors. 221590Srgrimes * 4. Neither the name of the University nor the names of its contributors 231590Srgrimes * may be used to endorse or promote products derived from this software 241590Srgrimes * without specific prior written permission. 251590Srgrimes * 261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361590Srgrimes * SUCH DAMAGE. 3762833Swsanchez * 3862833Swsanchez * @(#)job.c 8.2 (Berkeley) 3/19/94 391590Srgrimes */ 401590Srgrimes 411590Srgrimes#ifndef lint 4262833Swsanchez#include <sys/cdefs.h> 4362833Swsanchez__RCSID("$FreeBSD: head/usr.bin/make/job.c 92921 2002-03-22 01:33:25Z imp $"); 441590Srgrimes#endif /* not lint */ 451590Srgrimes 4635483Simp#ifndef OLD_JOKE 4735483Simp#define OLD_JOKE 0 4835483Simp#endif /* OLD_JOKE */ 4935483Simp 501590Srgrimes/*- 511590Srgrimes * job.c -- 521590Srgrimes * handle the creation etc. of our child processes. 531590Srgrimes * 541590Srgrimes * Interface: 551590Srgrimes * Job_Make Start the creation of the given target. 561590Srgrimes * 571590Srgrimes * Job_CatchChildren Check for and handle the termination of any 581590Srgrimes * children. This must be called reasonably 591590Srgrimes * frequently to keep the whole make going at 601590Srgrimes * a decent clip, since job table entries aren't 611590Srgrimes * removed until their process is caught this way. 621590Srgrimes * Its single argument is TRUE if the function 631590Srgrimes * should block waiting for a child to terminate. 641590Srgrimes * 651590Srgrimes * Job_CatchOutput Print any output our children have produced. 661590Srgrimes * Should also be called fairly frequently to 671590Srgrimes * keep the user informed of what's going on. 681590Srgrimes * If no output is waiting, it will block for 691590Srgrimes * a time given by the SEL_* constants, below, 701590Srgrimes * or until output is ready. 711590Srgrimes * 721590Srgrimes * Job_Init Called to intialize this module. in addition, 731590Srgrimes * any commands attached to the .BEGIN target 741590Srgrimes * are executed before this function returns. 751590Srgrimes * Hence, the makefile must have been parsed 761590Srgrimes * before this function is called. 771590Srgrimes * 781590Srgrimes * Job_Full Return TRUE if the job table is filled. 791590Srgrimes * 801590Srgrimes * Job_Empty Return TRUE if the job table is completely 811590Srgrimes * empty. 821590Srgrimes * 831590Srgrimes * Job_ParseShell Given the line following a .SHELL target, parse 841590Srgrimes * the line as a shell specification. Returns 851590Srgrimes * FAILURE if the spec was incorrect. 861590Srgrimes * 871590Srgrimes * Job_End Perform any final processing which needs doing. 881590Srgrimes * This includes the execution of any commands 891590Srgrimes * which have been/were attached to the .END 901590Srgrimes * target. It should only be called when the 911590Srgrimes * job table is empty. 921590Srgrimes * 931590Srgrimes * Job_AbortAll Abort all currently running jobs. It doesn't 941590Srgrimes * handle output or do anything for the jobs, 951590Srgrimes * just kills them. It should only be called in 961590Srgrimes * an emergency, as it were. 971590Srgrimes * 981590Srgrimes * Job_CheckCommands Verify that the commands for a target are 991590Srgrimes * ok. Provide them if necessary and possible. 1001590Srgrimes * 1011590Srgrimes * Job_Touch Update a target without really updating it. 1021590Srgrimes * 1031590Srgrimes * Job_Wait Wait for all currently-running jobs to finish. 1041590Srgrimes */ 1051590Srgrimes 1061590Srgrimes#include <sys/types.h> 1071590Srgrimes#include <sys/stat.h> 1081590Srgrimes#include <sys/file.h> 1091590Srgrimes#include <sys/time.h> 1101590Srgrimes#include <sys/wait.h> 1115814Sjkh#include <fcntl.h> 1121590Srgrimes#include <errno.h> 11318730Ssteve#include <utime.h> 1141590Srgrimes#include <stdio.h> 1151590Srgrimes#include <string.h> 1165814Sjkh#include <signal.h> 11780381Ssheldonh#include <unistd.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? */ 1351590Srgrimes#define ABORT_ERROR 1 /* Because of an error */ 1361590Srgrimes#define ABORT_INTERRUPT 2 /* Because it was interrupted */ 1371590Srgrimes#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 */ 14318730Ssteve#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 */ 1591590Srgrimes#define JOB_RUNNING 0 /* Job is running */ 1601590Srgrimes#define JOB_ERROR 1 /* Error in starting the job */ 1611590Srgrimes#define JOB_FINISHED 2 /* The job is already finished */ 1621590Srgrimes#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 */ 28718730Ssteve#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 29718730Ssteve#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) 29818730Ssteve#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 5041590Srgrimes * node and executed by Job_End 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 55018730Ssteve#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"); 8201590Srgrimes } else { 8211590Srgrimes out = stdout; 8221590Srgrimes } 8231590Srgrimes 82418730Ssteve if (WIFEXITED(*status)) { 82518730Ssteve if (DEBUG(JOB)) { 82618730Ssteve (void) fprintf(stdout, "Process %d exited.\n", job->pid); 82718730Ssteve (void) fflush(stdout); 82818730Ssteve } 82918730Ssteve if (WEXITSTATUS(*status) != 0) { 8301590Srgrimes if (usePipes && job->node != lastNode) { 83118730Ssteve MESSAGE(out, job->node); 8321590Srgrimes lastNode = job->node; 8331590Srgrimes } 83418730Ssteve (void) fprintf(out, "*** Error code %d%s\n", 83518730Ssteve WEXITSTATUS(*status), 83618730Ssteve (job->flags & JOB_IGNERR) ? "(ignored)" : ""); 8371590Srgrimes 8381590Srgrimes if (job->flags & JOB_IGNERR) { 83918730Ssteve *status = 0; 8401590Srgrimes } 8411590Srgrimes } else if (DEBUG(JOB)) { 8421590Srgrimes if (usePipes && job->node != lastNode) { 84318730Ssteve MESSAGE(out, job->node); 8441590Srgrimes lastNode = job->node; 8451590Srgrimes } 84618730Ssteve (void) fprintf(out, "*** Completed successfully\n"); 8471590Srgrimes } 84818730Ssteve } else if (WIFSTOPPED(*status)) { 84918730Ssteve if (DEBUG(JOB)) { 85018730Ssteve (void) fprintf(stdout, "Process %d stopped.\n", job->pid); 85118730Ssteve (void) fflush(stdout); 85218730Ssteve } 8531590Srgrimes if (usePipes && job->node != lastNode) { 85418730Ssteve MESSAGE(out, job->node); 8551590Srgrimes lastNode = job->node; 8561590Srgrimes } 85718730Ssteve if (!(job->flags & JOB_REMIGRATE)) { 85818730Ssteve (void) fprintf(out, "*** Stopped -- signal %d\n", 85918730Ssteve WSTOPSIG(*status)); 8601590Srgrimes } 8611590Srgrimes job->flags |= JOB_RESUME; 86269531Swill (void)Lst_AtEnd(stoppedJobs, (void *)job); 86318730Ssteve#ifdef REMOTE 86418730Ssteve if (job->flags & JOB_REMIGRATE) 86518730Ssteve JobRestart(job); 86618730Ssteve#endif 86718730Ssteve (void) fflush(out); 8681590Srgrimes return; 86918730Ssteve } else if (WTERMSIG(*status) == SIGCONT) { 8701590Srgrimes /* 8711590Srgrimes * If the beastie has continued, shift the Job from the stopped 8721590Srgrimes * list to the running one (or re-stop it if concurrency is 8731590Srgrimes * exceeded) and go and get another child. 8741590Srgrimes */ 8751590Srgrimes if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) { 8761590Srgrimes if (usePipes && job->node != lastNode) { 87718730Ssteve MESSAGE(out, job->node); 8781590Srgrimes lastNode = job->node; 8791590Srgrimes } 88018730Ssteve (void) fprintf(out, "*** Continued\n"); 8811590Srgrimes } 88218730Ssteve if (!(job->flags & JOB_CONTINUING)) { 88318730Ssteve if (DEBUG(JOB)) { 88418730Ssteve (void) fprintf(stdout, 88518730Ssteve "Warning: process %d was not continuing.\n", 88618730Ssteve job->pid); 88718730Ssteve (void) fflush(stdout); 88818730Ssteve } 88918730Ssteve#ifdef notdef 89018730Ssteve /* 89118730Ssteve * We don't really want to restart a job from scratch just 89218730Ssteve * because it continued, especially not without killing the 89318730Ssteve * continuing process! That's why this is ifdef'ed out. 89418730Ssteve * FD - 9/17/90 89518730Ssteve */ 8961590Srgrimes JobRestart(job); 89718730Ssteve#endif 8981590Srgrimes } 89918730Ssteve job->flags &= ~JOB_CONTINUING; 90069531Swill Lst_AtEnd(jobs, (void *)job); 90118730Ssteve nJobs += 1; 90218730Ssteve if (!(job->flags & JOB_REMOTE)) { 90318730Ssteve if (DEBUG(JOB)) { 90418730Ssteve (void) fprintf(stdout, 90518730Ssteve "Process %d is continuing locally.\n", 90618730Ssteve job->pid); 90718730Ssteve (void) fflush(stdout); 90818730Ssteve } 90918730Ssteve nLocal += 1; 91018730Ssteve } 91118730Ssteve if (nJobs == maxJobs) { 91218730Ssteve jobFull = TRUE; 91318730Ssteve if (DEBUG(JOB)) { 91418730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 91518730Ssteve (void) fflush(stdout); 91618730Ssteve } 91718730Ssteve } 91818730Ssteve (void) fflush(out); 91918730Ssteve return; 9201590Srgrimes } else { 9211590Srgrimes if (usePipes && job->node != lastNode) { 92218730Ssteve MESSAGE(out, job->node); 9231590Srgrimes lastNode = job->node; 9241590Srgrimes } 92518730Ssteve (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); 9261590Srgrimes } 9271590Srgrimes 92818730Ssteve (void) fflush(out); 9291590Srgrimes } 9301590Srgrimes 9311590Srgrimes /* 9321590Srgrimes * Now handle the -B-mode stuff. If the beast still isn't finished, 9331590Srgrimes * try and restart the job on the next command. If JobStart says it's 9341590Srgrimes * ok, it's ok. If there's an error, this puppy is done. 9351590Srgrimes */ 93618730Ssteve if (compatMake && (WIFEXITED(*status) && 93718730Ssteve !Lst_IsAtEnd(job->node->commands))) { 93818730Ssteve switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { 93918730Ssteve case JOB_RUNNING: 94018730Ssteve done = FALSE; 94118730Ssteve break; 94218730Ssteve case JOB_ERROR: 94318730Ssteve done = TRUE; 94418730Ssteve W_SETEXITSTATUS(status, 1); 94518730Ssteve break; 94618730Ssteve case JOB_FINISHED: 94718730Ssteve /* 94818730Ssteve * If we got back a JOB_FINISHED code, JobStart has already 94918730Ssteve * called Make_Update and freed the job descriptor. We set 95018730Ssteve * done to false here to avoid fake cycles and double frees. 95118730Ssteve * JobStart needs to do the update so we can proceed up the 95218730Ssteve * graph when given the -n flag.. 95318730Ssteve */ 95418730Ssteve done = FALSE; 95518730Ssteve break; 9561590Srgrimes } 9571590Srgrimes } else { 9581590Srgrimes done = TRUE; 9591590Srgrimes } 9601590Srgrimes 9618874Srgrimes 9621590Srgrimes if (done && 9631590Srgrimes (aborting != ABORT_ERROR) && 9641590Srgrimes (aborting != ABORT_INTERRUPT) && 96518730Ssteve (*status == 0)) 9661590Srgrimes { 9671590Srgrimes /* 9681590Srgrimes * As long as we aren't aborting and the job didn't return a non-zero 9691590Srgrimes * status that we shouldn't ignore, we call Make_Update to update 9701590Srgrimes * the parents. In addition, any saved commands for the node are placed 9711590Srgrimes * on the .END target. 9721590Srgrimes */ 97369527Swill if (job->tailCmds != NULL) { 97418730Ssteve Lst_ForEachFrom(job->node->commands, job->tailCmds, 9751590Srgrimes JobSaveCommand, 97669531Swill (void *)job->node); 9771590Srgrimes } 9781590Srgrimes job->node->made = MADE; 97918730Ssteve Make_Update(job->node); 98069531Swill free(job); 98118730Ssteve } else if (*status != 0) { 9821590Srgrimes errors += 1; 98369531Swill free(job); 9841590Srgrimes } 9851590Srgrimes 98618730Ssteve JobRestartJobs(); 9871590Srgrimes 9881590Srgrimes /* 9891590Srgrimes * Set aborting if any error. 9901590Srgrimes */ 9911590Srgrimes if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { 9921590Srgrimes /* 9931590Srgrimes * If we found any errors in this batch of children and the -k flag 9941590Srgrimes * wasn't given, we set the aborting flag so no more jobs get 9951590Srgrimes * started. 9961590Srgrimes */ 9971590Srgrimes aborting = ABORT_ERROR; 9981590Srgrimes } 9998874Srgrimes 100068898Skris if ((aborting == ABORT_ERROR) && Job_Empty()) 10011590Srgrimes /* 10021590Srgrimes * If we are aborting and the job table is now empty, we finish. 10031590Srgrimes */ 100418730Ssteve Finish(errors); 10051590Srgrimes} 10061590Srgrimes 10071590Srgrimes/*- 10081590Srgrimes *----------------------------------------------------------------------- 10091590Srgrimes * Job_Touch -- 10101590Srgrimes * Touch the given target. Called by JobStart when the -t flag was 10111590Srgrimes * given 10121590Srgrimes * 10131590Srgrimes * Results: 10141590Srgrimes * None 10151590Srgrimes * 10161590Srgrimes * Side Effects: 10171590Srgrimes * The data modification of the file is changed. In addition, if the 10181590Srgrimes * file did not exist, it is created. 10191590Srgrimes *----------------------------------------------------------------------- 10201590Srgrimes */ 10211590Srgrimesvoid 102218730SsteveJob_Touch(gn, silent) 10231590Srgrimes GNode *gn; /* the node of the file to touch */ 10241590Srgrimes Boolean silent; /* TRUE if should not print messages */ 10251590Srgrimes{ 10261590Srgrimes int streamID; /* ID of stream opened to do the touch */ 102718730Ssteve struct utimbuf times; /* Times for utime() call */ 10281590Srgrimes 10291590Srgrimes if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { 10301590Srgrimes /* 10311590Srgrimes * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets 10321590Srgrimes * and, as such, shouldn't really be created. 10331590Srgrimes */ 10341590Srgrimes return; 10351590Srgrimes } 10368874Srgrimes 10371590Srgrimes if (!silent) { 103818730Ssteve (void) fprintf(stdout, "touch %s\n", gn->name); 103918730Ssteve (void) fflush(stdout); 10401590Srgrimes } 10411590Srgrimes 10421590Srgrimes if (noExecute) { 10431590Srgrimes return; 10441590Srgrimes } 10451590Srgrimes 10461590Srgrimes if (gn->type & OP_ARCHV) { 104718730Ssteve Arch_Touch(gn); 10481590Srgrimes } else if (gn->type & OP_LIB) { 104918730Ssteve Arch_TouchLib(gn); 10501590Srgrimes } else { 10511590Srgrimes char *file = gn->path ? gn->path : gn->name; 10521590Srgrimes 105318730Ssteve times.actime = times.modtime = now; 105418730Ssteve if (utime(file, ×) < 0){ 105518730Ssteve streamID = open(file, O_RDWR | O_CREAT, 0666); 10561590Srgrimes 10571590Srgrimes if (streamID >= 0) { 10581590Srgrimes char c; 10591590Srgrimes 10601590Srgrimes /* 10611590Srgrimes * Read and write a byte to the file to change the 10621590Srgrimes * modification time, then close the file. 10631590Srgrimes */ 10641590Srgrimes if (read(streamID, &c, 1) == 1) { 106549938Shoek (void) lseek(streamID, 0L, SEEK_SET); 106618730Ssteve (void) write(streamID, &c, 1); 10671590Srgrimes } 10688874Srgrimes 106918730Ssteve (void) close(streamID); 107018730Ssteve } else { 107118730Ssteve (void) fprintf(stdout, "*** couldn't touch %s: %s", 107218730Ssteve file, strerror(errno)); 107318730Ssteve (void) fflush(stdout); 107418730Ssteve } 10751590Srgrimes } 10761590Srgrimes } 10771590Srgrimes} 10781590Srgrimes 10791590Srgrimes/*- 10801590Srgrimes *----------------------------------------------------------------------- 10811590Srgrimes * Job_CheckCommands -- 10828874Srgrimes * Make sure the given node has all the commands it needs. 10831590Srgrimes * 10841590Srgrimes * Results: 10851590Srgrimes * TRUE if the commands list is/was ok. 10861590Srgrimes * 10871590Srgrimes * Side Effects: 10881590Srgrimes * The node will have commands from the .DEFAULT rule added to it 10891590Srgrimes * if it needs them. 10901590Srgrimes *----------------------------------------------------------------------- 10911590Srgrimes */ 10921590SrgrimesBoolean 109318730SsteveJob_CheckCommands(gn, abortProc) 10941590Srgrimes GNode *gn; /* The target whose commands need 10951590Srgrimes * verifying */ 109692921Simp void (*abortProc)(char *, ...); 10971590Srgrimes /* Function to abort with message */ 10981590Srgrimes{ 109918730Ssteve if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && 11001590Srgrimes (gn->type & OP_LIB) == 0) { 11011590Srgrimes /* 11021590Srgrimes * No commands. Look for .DEFAULT rule from which we might infer 11038874Srgrimes * commands 11041590Srgrimes */ 110569527Swill if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands)) { 11065814Sjkh char *p1; 11071590Srgrimes /* 11081590Srgrimes * Make only looks for a .DEFAULT if the node was never the 11091590Srgrimes * target of an operator, so that's what we do too. If 11101590Srgrimes * a .DEFAULT was given, we substitute its commands for gn's 11111590Srgrimes * commands and set the IMPSRC variable to be the target's name 11121590Srgrimes * The DEFAULT node acts like a transformation rule, in that 11131590Srgrimes * gn also inherits any attributes or sources attached to 11141590Srgrimes * .DEFAULT itself. 11151590Srgrimes */ 11161590Srgrimes Make_HandleUse(DEFAULT, gn); 111718730Ssteve Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); 111849938Shoek efree(p1); 111918730Ssteve } else if (Dir_MTime(gn) == 0) { 11201590Srgrimes /* 11211590Srgrimes * The node wasn't the target of an operator we have no .DEFAULT 11221590Srgrimes * rule to go on and the target doesn't already exist. There's 11231590Srgrimes * nothing more we can do for this branch. If the -k flag wasn't 11241590Srgrimes * given, we stop in our tracks, otherwise we just don't update 11258874Srgrimes * this node's parents so they never get examined. 11261590Srgrimes */ 112718730Ssteve static const char msg[] = "make: don't know how to make"; 112818730Ssteve 11291590Srgrimes if (gn->type & OP_OPTIONAL) { 113018730Ssteve (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); 113118730Ssteve (void) fflush(stdout); 11321590Srgrimes } else if (keepgoing) { 113318730Ssteve (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); 113418730Ssteve (void) fflush(stdout); 113518730Ssteve return FALSE; 11361590Srgrimes } else { 113735483Simp#if OLD_JOKE 113835483Simp if (strcmp(gn->name,"love") == 0) 113935483Simp (*abortProc)("Not war."); 114035483Simp else 114135483Simp#endif 114235483Simp (*abortProc)("%s %s. Stop", msg, gn->name); 114318730Ssteve return FALSE; 11441590Srgrimes } 11451590Srgrimes } 11461590Srgrimes } 114718730Ssteve return TRUE; 11481590Srgrimes} 11491590Srgrimes#ifdef RMT_WILL_WATCH 11501590Srgrimes/*- 11511590Srgrimes *----------------------------------------------------------------------- 11521590Srgrimes * JobLocalInput -- 11531590Srgrimes * Handle a pipe becoming readable. Callback function for Rmt_Watch 11541590Srgrimes * 11551590Srgrimes * Results: 11561590Srgrimes * None 11571590Srgrimes * 11581590Srgrimes * Side Effects: 11591590Srgrimes * JobDoOutput is called. 11608874Srgrimes * 11611590Srgrimes *----------------------------------------------------------------------- 11621590Srgrimes */ 11631590Srgrimes/*ARGSUSED*/ 11641590Srgrimesstatic void 11651590SrgrimesJobLocalInput(stream, job) 11661590Srgrimes int stream; /* Stream that's ready (ignored) */ 11671590Srgrimes Job *job; /* Job to which the stream belongs */ 11681590Srgrimes{ 11691590Srgrimes JobDoOutput(job, FALSE); 11701590Srgrimes} 11711590Srgrimes#endif /* RMT_WILL_WATCH */ 11721590Srgrimes 11731590Srgrimes/*- 11741590Srgrimes *----------------------------------------------------------------------- 11751590Srgrimes * JobExec -- 11761590Srgrimes * Execute the shell for the given job. Called from JobStart and 11771590Srgrimes * JobRestart. 11781590Srgrimes * 11791590Srgrimes * Results: 11801590Srgrimes * None. 11811590Srgrimes * 11821590Srgrimes * Side Effects: 11831590Srgrimes * A shell is executed, outputs is altered and the Job structure added 11841590Srgrimes * to the job table. 11851590Srgrimes * 11861590Srgrimes *----------------------------------------------------------------------- 11871590Srgrimes */ 11881590Srgrimesstatic void 11891590SrgrimesJobExec(job, argv) 11901590Srgrimes Job *job; /* Job to execute */ 11911590Srgrimes char **argv; 11921590Srgrimes{ 11931590Srgrimes int cpid; /* ID of new child */ 11948874Srgrimes 11951590Srgrimes if (DEBUG(JOB)) { 11961590Srgrimes int i; 11978874Srgrimes 119818730Ssteve (void) fprintf(stdout, "Running %s %sly\n", job->node->name, 119918730Ssteve job->flags&JOB_REMOTE?"remote":"local"); 120018730Ssteve (void) fprintf(stdout, "\tCommand: "); 120118730Ssteve for (i = 0; argv[i] != NULL; i++) { 120218730Ssteve (void) fprintf(stdout, "%s ", argv[i]); 12031590Srgrimes } 120418730Ssteve (void) fprintf(stdout, "\n"); 120518730Ssteve (void) fflush(stdout); 12061590Srgrimes } 12078874Srgrimes 12081590Srgrimes /* 12091590Srgrimes * Some jobs produce no output and it's disconcerting to have 12101590Srgrimes * no feedback of their running (since they produce no output, the 12111590Srgrimes * banner with their name in it never appears). This is an attempt to 12121590Srgrimes * provide that feedback, even if nothing follows it. 12131590Srgrimes */ 12141590Srgrimes if ((lastNode != job->node) && (job->flags & JOB_FIRST) && 121518730Ssteve !(job->flags & JOB_SILENT)) { 121618730Ssteve MESSAGE(stdout, job->node); 12171590Srgrimes lastNode = job->node; 12181590Srgrimes } 12198874Srgrimes 12201590Srgrimes#ifdef RMT_NO_EXEC 12211590Srgrimes if (job->flags & JOB_REMOTE) { 12221590Srgrimes goto jobExecFinish; 12231590Srgrimes } 12241590Srgrimes#endif /* RMT_NO_EXEC */ 12251590Srgrimes 122618730Ssteve if ((cpid = vfork()) == -1) { 122718730Ssteve Punt("Cannot fork"); 12281590Srgrimes } else if (cpid == 0) { 12291590Srgrimes 12301590Srgrimes /* 12311590Srgrimes * Must duplicate the input stream down to the child's input and 12321590Srgrimes * reset it to the beginning (again). Since the stream was marked 12331590Srgrimes * close-on-exec, we must clear that bit in the new input. 12341590Srgrimes */ 123518730Ssteve if (dup2(FILENO(job->cmdFILE), 0) == -1) 123618730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 123718730Ssteve (void) fcntl(0, F_SETFD, 0); 123849938Shoek (void) lseek(0, 0, SEEK_SET); 12398874Srgrimes 12401590Srgrimes if (usePipes) { 12411590Srgrimes /* 12421590Srgrimes * Set up the child's output to be routed through the pipe 12431590Srgrimes * we've created for it. 12441590Srgrimes */ 124518730Ssteve if (dup2(job->outPipe, 1) == -1) 124618730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 12471590Srgrimes } else { 12481590Srgrimes /* 12491590Srgrimes * We're capturing output in a file, so we duplicate the 12501590Srgrimes * descriptor to the temporary file into the standard 12511590Srgrimes * output. 12521590Srgrimes */ 125318730Ssteve if (dup2(job->outFd, 1) == -1) 125418730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 12551590Srgrimes } 12561590Srgrimes /* 12571590Srgrimes * The output channels are marked close on exec. This bit was 12581590Srgrimes * duplicated by the dup2 (on some systems), so we have to clear 12591590Srgrimes * it before routing the shell's error output to the same place as 12601590Srgrimes * its standard output. 12611590Srgrimes */ 126218730Ssteve (void) fcntl(1, F_SETFD, 0); 126318730Ssteve if (dup2(1, 2) == -1) 126418730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 12651590Srgrimes 12661590Srgrimes#ifdef USE_PGRP 12671590Srgrimes /* 12681590Srgrimes * We want to switch the child into a different process family so 12691590Srgrimes * we can kill it and all its descendants in one fell swoop, 12701590Srgrimes * by killing its process family, but not commit suicide. 12711590Srgrimes */ 127218730Ssteve# if defined(SYSV) 127318730Ssteve (void) setsid(); 127418730Ssteve# else 127518730Ssteve (void) setpgid(0, getpid()); 127618730Ssteve# endif 127718730Ssteve#endif /* USE_PGRP */ 12788874Srgrimes 127918730Ssteve#ifdef REMOTE 128018730Ssteve if (job->flags & JOB_REMOTE) { 128118730Ssteve Rmt_Exec(shellPath, argv, FALSE); 128218730Ssteve } else 128318730Ssteve#endif /* REMOTE */ 128418730Ssteve (void) execv(shellPath, argv); 12851590Srgrimes 128680381Ssheldonh (void) write(STDERR_FILENO, "Could not execute shell\n", 128718730Ssteve sizeof("Could not execute shell")); 128818730Ssteve _exit(1); 12891590Srgrimes } else { 129018730Ssteve#ifdef REMOTE 129118730Ssteve long omask = sigblock(sigmask(SIGCHLD)); 129218730Ssteve#endif 12931590Srgrimes job->pid = cpid; 12941590Srgrimes 12951590Srgrimes if (usePipes && (job->flags & JOB_FIRST) ) { 12961590Srgrimes /* 12971590Srgrimes * The first time a job is run for a node, we set the current 12981590Srgrimes * position in the buffer to the beginning and mark another 12991590Srgrimes * stream to watch in the outputs mask 13001590Srgrimes */ 13011590Srgrimes job->curPos = 0; 13028874Srgrimes 13031590Srgrimes#ifdef RMT_WILL_WATCH 13041590Srgrimes Rmt_Watch(job->inPipe, JobLocalInput, job); 13051590Srgrimes#else 13061590Srgrimes FD_SET(job->inPipe, &outputs); 13071590Srgrimes#endif /* RMT_WILL_WATCH */ 13081590Srgrimes } 13091590Srgrimes 13101590Srgrimes if (job->flags & JOB_REMOTE) { 131118730Ssteve#ifndef REMOTE 13121590Srgrimes job->rmtID = 0; 131318730Ssteve#else 131418730Ssteve job->rmtID = Rmt_LastID(job->pid); 131518730Ssteve#endif /* REMOTE */ 13161590Srgrimes } else { 13171590Srgrimes nLocal += 1; 13181590Srgrimes /* 131918730Ssteve * XXX: Used to not happen if REMOTE. Why? 13201590Srgrimes */ 132118730Ssteve if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 132218730Ssteve (void) fclose(job->cmdFILE); 13231590Srgrimes job->cmdFILE = NULL; 13241590Srgrimes } 13251590Srgrimes } 132618730Ssteve#ifdef REMOTE 132718730Ssteve (void) sigsetmask(omask); 132818730Ssteve#endif 13291590Srgrimes } 13301590Srgrimes 13311590Srgrimes#ifdef RMT_NO_EXEC 13328874SrgrimesjobExecFinish: 13331590Srgrimes#endif 13341590Srgrimes /* 13351590Srgrimes * Now the job is actually running, add it to the table. 13361590Srgrimes */ 13371590Srgrimes nJobs += 1; 133869531Swill (void) Lst_AtEnd(jobs, (void *)job); 13391590Srgrimes if (nJobs == maxJobs) { 13401590Srgrimes jobFull = TRUE; 13411590Srgrimes } 13421590Srgrimes} 13431590Srgrimes 13441590Srgrimes/*- 13451590Srgrimes *----------------------------------------------------------------------- 13461590Srgrimes * JobMakeArgv -- 13471590Srgrimes * Create the argv needed to execute the shell for a given job. 13481590Srgrimes * 13498874Srgrimes * 13501590Srgrimes * Results: 13511590Srgrimes * 13521590Srgrimes * Side Effects: 13531590Srgrimes * 13541590Srgrimes *----------------------------------------------------------------------- 13551590Srgrimes */ 13561590Srgrimesstatic void 13571590SrgrimesJobMakeArgv(job, argv) 13581590Srgrimes Job *job; 13591590Srgrimes char **argv; 13601590Srgrimes{ 13611590Srgrimes int argc; 13621590Srgrimes static char args[10]; /* For merged arguments */ 13638874Srgrimes 13641590Srgrimes argv[0] = shellName; 13651590Srgrimes argc = 1; 13661590Srgrimes 13671590Srgrimes if ((commandShell->exit && (*commandShell->exit != '-')) || 13681590Srgrimes (commandShell->echo && (*commandShell->echo != '-'))) 13691590Srgrimes { 13701590Srgrimes /* 13711590Srgrimes * At least one of the flags doesn't have a minus before it, so 13721590Srgrimes * merge them together. Have to do this because the *(&(@*#*&#$# 13731590Srgrimes * Bourne shell thinks its second argument is a file to source. 13741590Srgrimes * Grrrr. Note the ten-character limitation on the combined arguments. 13751590Srgrimes */ 13761590Srgrimes (void)sprintf(args, "-%s%s", 13771590Srgrimes ((job->flags & JOB_IGNERR) ? "" : 13781590Srgrimes (commandShell->exit ? commandShell->exit : "")), 13791590Srgrimes ((job->flags & JOB_SILENT) ? "" : 13801590Srgrimes (commandShell->echo ? commandShell->echo : ""))); 13811590Srgrimes 13821590Srgrimes if (args[1]) { 13831590Srgrimes argv[argc] = args; 13841590Srgrimes argc++; 13851590Srgrimes } 13861590Srgrimes } else { 13871590Srgrimes if (!(job->flags & JOB_IGNERR) && commandShell->exit) { 13881590Srgrimes argv[argc] = commandShell->exit; 13891590Srgrimes argc++; 13901590Srgrimes } 13911590Srgrimes if (!(job->flags & JOB_SILENT) && commandShell->echo) { 13921590Srgrimes argv[argc] = commandShell->echo; 13931590Srgrimes argc++; 13941590Srgrimes } 13951590Srgrimes } 139618730Ssteve argv[argc] = NULL; 13971590Srgrimes} 13981590Srgrimes 13991590Srgrimes/*- 14001590Srgrimes *----------------------------------------------------------------------- 14011590Srgrimes * JobRestart -- 14028874Srgrimes * Restart a job that stopped for some reason. 14031590Srgrimes * 14041590Srgrimes * Results: 14051590Srgrimes * None. 14061590Srgrimes * 14071590Srgrimes * Side Effects: 14081590Srgrimes * jobFull will be set if the job couldn't be run. 14091590Srgrimes * 14101590Srgrimes *----------------------------------------------------------------------- 14111590Srgrimes */ 14121590Srgrimesstatic void 14131590SrgrimesJobRestart(job) 14141590Srgrimes Job *job; /* Job to restart */ 14151590Srgrimes{ 141618730Ssteve#ifdef REMOTE 141718730Ssteve int host; 141818730Ssteve#endif 141918730Ssteve 14201590Srgrimes if (job->flags & JOB_REMIGRATE) { 142118730Ssteve if ( 142218730Ssteve#ifdef REMOTE 142318730Ssteve verboseRemigrates || 142418730Ssteve#endif 142518730Ssteve DEBUG(JOB)) { 142618730Ssteve (void) fprintf(stdout, "*** remigrating %x(%s)\n", 142718730Ssteve job->pid, job->node->name); 142818730Ssteve (void) fflush(stdout); 14291590Srgrimes } 143018730Ssteve 143118730Ssteve#ifdef REMOTE 143218730Ssteve if (!Rmt_ReExport(job->pid, job->node, &host)) { 143318730Ssteve if (verboseRemigrates || DEBUG(JOB)) { 143418730Ssteve (void) fprintf(stdout, "*** couldn't migrate...\n"); 143518730Ssteve (void) fflush(stdout); 143618730Ssteve } 143718730Ssteve#endif 143818730Ssteve if (nLocal != maxLocal) { 14391590Srgrimes /* 14401590Srgrimes * Job cannot be remigrated, but there's room on the local 14411590Srgrimes * machine, so resume the job and note that another 14421590Srgrimes * local job has started. 14431590Srgrimes */ 144418730Ssteve if ( 144518730Ssteve#ifdef REMOTE 144618730Ssteve verboseRemigrates || 144718730Ssteve#endif 144818730Ssteve DEBUG(JOB)) { 144918730Ssteve (void) fprintf(stdout, "*** resuming on local machine\n"); 145018730Ssteve (void) fflush(stdout); 145118730Ssteve } 14521590Srgrimes KILL(job->pid, SIGCONT); 14531590Srgrimes nLocal +=1; 145418730Ssteve#ifdef REMOTE 145518730Ssteve job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE); 145618730Ssteve job->flags |= JOB_CONTINUING; 145718730Ssteve#else 14581590Srgrimes job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); 145918730Ssteve#endif 14601590Srgrimes } else { 14611590Srgrimes /* 14621590Srgrimes * Job cannot be restarted. Mark the table as full and 14631590Srgrimes * place the job back on the list of stopped jobs. 14641590Srgrimes */ 146518730Ssteve if ( 146618730Ssteve#ifdef REMOTE 146718730Ssteve verboseRemigrates || 146818730Ssteve#endif 146918730Ssteve DEBUG(JOB)) { 147018730Ssteve (void) fprintf(stdout, "*** holding\n"); 147118730Ssteve (void) fflush(stdout); 147218730Ssteve } 147369531Swill (void)Lst_AtFront(stoppedJobs, (void *)job); 14741590Srgrimes jobFull = TRUE; 14751590Srgrimes if (DEBUG(JOB)) { 147618730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 147718730Ssteve (void) fflush(stdout); 14781590Srgrimes } 14791590Srgrimes return; 148018730Ssteve } 148118730Ssteve#ifdef REMOTE 148218730Ssteve } else { 148318730Ssteve /* 148418730Ssteve * Clear out the remigrate and resume flags. Set the continuing 148518730Ssteve * flag so we know later on that the process isn't exiting just 148618730Ssteve * because of a signal. 148718730Ssteve */ 148818730Ssteve job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); 148918730Ssteve job->flags |= JOB_CONTINUING; 149018730Ssteve job->rmtID = host; 14911590Srgrimes } 149218730Ssteve#endif 14938874Srgrimes 149469531Swill (void)Lst_AtEnd(jobs, (void *)job); 14951590Srgrimes nJobs += 1; 14961590Srgrimes if (nJobs == maxJobs) { 14971590Srgrimes jobFull = TRUE; 14981590Srgrimes if (DEBUG(JOB)) { 149918730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 150018730Ssteve (void) fflush(stdout); 15011590Srgrimes } 15021590Srgrimes } 15031590Srgrimes } else if (job->flags & JOB_RESTART) { 15041590Srgrimes /* 15051590Srgrimes * Set up the control arguments to the shell. This is based on the 15061590Srgrimes * flags set earlier for this job. If the JOB_IGNERR flag is clear, 15071590Srgrimes * the 'exit' flag of the commandShell is used to cause it to exit 15081590Srgrimes * upon receiving an error. If the JOB_SILENT flag is clear, the 15091590Srgrimes * 'echo' flag of the commandShell is used to get it to start echoing 15108874Srgrimes * as soon as it starts processing commands. 15111590Srgrimes */ 15121590Srgrimes char *argv[4]; 15138874Srgrimes 15141590Srgrimes JobMakeArgv(job, argv); 15158874Srgrimes 15161590Srgrimes if (DEBUG(JOB)) { 151718730Ssteve (void) fprintf(stdout, "Restarting %s...", job->node->name); 151818730Ssteve (void) fflush(stdout); 15191590Srgrimes } 152018730Ssteve#ifdef REMOTE 152118730Ssteve if ((job->node->type&OP_NOEXPORT) || 152218730Ssteve (nLocal < maxLocal && runLocalFirst) 152318730Ssteve# ifdef RMT_NO_EXEC 152418730Ssteve || !Rmt_Export(shellPath, argv, job) 152518730Ssteve# else 152618730Ssteve || !Rmt_Begin(shellPath, argv, job->node) 152718730Ssteve# endif 152818730Ssteve#endif 152918730Ssteve { 153018730Ssteve if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) { 15311590Srgrimes /* 15321590Srgrimes * Can't be exported and not allowed to run locally -- put it 15331590Srgrimes * back on the hold queue and mark the table full 15341590Srgrimes */ 15351590Srgrimes if (DEBUG(JOB)) { 153618730Ssteve (void) fprintf(stdout, "holding\n"); 153718730Ssteve (void) fflush(stdout); 15381590Srgrimes } 153969531Swill (void)Lst_AtFront(stoppedJobs, (void *)job); 15401590Srgrimes jobFull = TRUE; 15411590Srgrimes if (DEBUG(JOB)) { 154218730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 154318730Ssteve (void) fflush(stdout); 15441590Srgrimes } 15451590Srgrimes return; 154618730Ssteve } else { 15471590Srgrimes /* 15481590Srgrimes * Job may be run locally. 15491590Srgrimes */ 15501590Srgrimes if (DEBUG(JOB)) { 155118730Ssteve (void) fprintf(stdout, "running locally\n"); 155218730Ssteve (void) fflush(stdout); 15531590Srgrimes } 15541590Srgrimes job->flags &= ~JOB_REMOTE; 155518730Ssteve } 15561590Srgrimes } 155718730Ssteve#ifdef REMOTE 155818730Ssteve else { 155918730Ssteve /* 156018730Ssteve * Can be exported. Hooray! 156118730Ssteve */ 156218730Ssteve if (DEBUG(JOB)) { 156318730Ssteve (void) fprintf(stdout, "exporting\n"); 156418730Ssteve (void) fflush(stdout); 156518730Ssteve } 156618730Ssteve job->flags |= JOB_REMOTE; 156718730Ssteve } 156818730Ssteve#endif 15691590Srgrimes JobExec(job, argv); 15701590Srgrimes } else { 15711590Srgrimes /* 15721590Srgrimes * The job has stopped and needs to be restarted. Why it stopped, 15731590Srgrimes * we don't know... 15741590Srgrimes */ 15751590Srgrimes if (DEBUG(JOB)) { 157618730Ssteve (void) fprintf(stdout, "Resuming %s...", job->node->name); 157718730Ssteve (void) fflush(stdout); 15781590Srgrimes } 15791590Srgrimes if (((job->flags & JOB_REMOTE) || 158018730Ssteve (nLocal < maxLocal) || 158118730Ssteve#ifdef REMOTE 158218730Ssteve (((job->flags & JOB_SPECIAL) && 158318730Ssteve (job->node->type & OP_NOEXPORT)) && 158418730Ssteve (maxLocal == 0))) && 158518730Ssteve#else 158618730Ssteve ((job->flags & JOB_SPECIAL) && 158718730Ssteve (maxLocal == 0))) && 158818730Ssteve#endif 158918730Ssteve (nJobs != maxJobs)) 15901590Srgrimes { 15911590Srgrimes /* 15921590Srgrimes * If the job is remote, it's ok to resume it as long as the 15931590Srgrimes * maximum concurrency won't be exceeded. If it's local and 15941590Srgrimes * we haven't reached the local concurrency limit already (or the 15951590Srgrimes * job must be run locally and maxLocal is 0), it's also ok to 15961590Srgrimes * resume it. 15971590Srgrimes */ 15981590Srgrimes Boolean error; 159918730Ssteve int status; 16008874Srgrimes 16011590Srgrimes#ifdef RMT_WANTS_SIGNALS 16021590Srgrimes if (job->flags & JOB_REMOTE) { 16031590Srgrimes error = !Rmt_Signal(job, SIGCONT); 16041590Srgrimes } else 16051590Srgrimes#endif /* RMT_WANTS_SIGNALS */ 16061590Srgrimes error = (KILL(job->pid, SIGCONT) != 0); 16071590Srgrimes 16081590Srgrimes if (!error) { 16091590Srgrimes /* 16101590Srgrimes * Make sure the user knows we've continued the beast and 16111590Srgrimes * actually put the thing in the job table. 16121590Srgrimes */ 16131590Srgrimes job->flags |= JOB_CONTINUING; 161418730Ssteve W_SETTERMSIG(&status, SIGCONT); 161518730Ssteve JobFinish(job, &status); 16168874Srgrimes 16171590Srgrimes job->flags &= ~(JOB_RESUME|JOB_CONTINUING); 16181590Srgrimes if (DEBUG(JOB)) { 161918730Ssteve (void) fprintf(stdout, "done\n"); 162018730Ssteve (void) fflush(stdout); 16211590Srgrimes } 16221590Srgrimes } else { 16231590Srgrimes Error("couldn't resume %s: %s", 16241590Srgrimes job->node->name, strerror(errno)); 162518730Ssteve status = 0; 162618730Ssteve W_SETEXITSTATUS(&status, 1); 162718730Ssteve JobFinish(job, &status); 16281590Srgrimes } 16291590Srgrimes } else { 16301590Srgrimes /* 16311590Srgrimes * Job cannot be restarted. Mark the table as full and 16321590Srgrimes * place the job back on the list of stopped jobs. 16331590Srgrimes */ 16341590Srgrimes if (DEBUG(JOB)) { 163518730Ssteve (void) fprintf(stdout, "table full\n"); 163618730Ssteve (void) fflush(stdout); 16371590Srgrimes } 163869531Swill (void) Lst_AtFront(stoppedJobs, (void *)job); 16391590Srgrimes jobFull = TRUE; 16401590Srgrimes if (DEBUG(JOB)) { 164118730Ssteve (void) fprintf(stdout, "Job queue is full.\n"); 164218730Ssteve (void) fflush(stdout); 16431590Srgrimes } 16441590Srgrimes } 16451590Srgrimes } 16461590Srgrimes} 16471590Srgrimes 16481590Srgrimes/*- 16491590Srgrimes *----------------------------------------------------------------------- 16501590Srgrimes * JobStart -- 16511590Srgrimes * Start a target-creation process going for the target described 16528874Srgrimes * by the graph node gn. 16531590Srgrimes * 16541590Srgrimes * Results: 16551590Srgrimes * JOB_ERROR if there was an error in the commands, JOB_FINISHED 16561590Srgrimes * if there isn't actually anything left to do for the job and 16571590Srgrimes * JOB_RUNNING if the job has been started. 16581590Srgrimes * 16591590Srgrimes * Side Effects: 16601590Srgrimes * A new Job node is created and added to the list of running 16611590Srgrimes * jobs. PMake is forked and a child shell created. 16621590Srgrimes *----------------------------------------------------------------------- 16631590Srgrimes */ 16641590Srgrimesstatic int 166518730SsteveJobStart(gn, flags, previous) 16661590Srgrimes GNode *gn; /* target to create */ 16675814Sjkh int flags; /* flags for the job to override normal ones. 16681590Srgrimes * e.g. JOB_SPECIAL or JOB_IGNDOTS */ 16691590Srgrimes Job *previous; /* The previous Job structure for this node, 16701590Srgrimes * if any. */ 16711590Srgrimes{ 16721590Srgrimes register Job *job; /* new job descriptor */ 16731590Srgrimes char *argv[4]; /* Argument vector to shell */ 16741590Srgrimes Boolean cmdsOK; /* true if the nodes commands were all right */ 16751590Srgrimes Boolean local; /* Set true if the job was run locally */ 16761590Srgrimes Boolean noExec; /* Set true if we decide not to run the job */ 167756151Skris int tfd; /* File descriptor for temp file */ 16781590Srgrimes 167918730Ssteve if (previous != NULL) { 168018730Ssteve previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); 16811590Srgrimes job = previous; 16821590Srgrimes } else { 168318730Ssteve job = (Job *) emalloc(sizeof(Job)); 168418730Ssteve if (job == NULL) { 16851590Srgrimes Punt("JobStart out of memory"); 16861590Srgrimes } 16871590Srgrimes flags |= JOB_FIRST; 16881590Srgrimes } 16891590Srgrimes 16901590Srgrimes job->node = gn; 169169527Swill job->tailCmds = NULL; 16921590Srgrimes 16931590Srgrimes /* 16941590Srgrimes * Set the initial value of the flags for this job based on the global 16951590Srgrimes * ones and the node's attributes... Any flags supplied by the caller 16961590Srgrimes * are also added to the field. 16971590Srgrimes */ 16981590Srgrimes job->flags = 0; 169918730Ssteve if (Targ_Ignore(gn)) { 17001590Srgrimes job->flags |= JOB_IGNERR; 17011590Srgrimes } 170218730Ssteve if (Targ_Silent(gn)) { 17031590Srgrimes job->flags |= JOB_SILENT; 17041590Srgrimes } 17051590Srgrimes job->flags |= flags; 17061590Srgrimes 17071590Srgrimes /* 17081590Srgrimes * Check the commands now so any attributes from .DEFAULT have a chance 17091590Srgrimes * to migrate to the node 17101590Srgrimes */ 171118730Ssteve if (!compatMake && job->flags & JOB_FIRST) { 17121590Srgrimes cmdsOK = Job_CheckCommands(gn, Error); 17131590Srgrimes } else { 17141590Srgrimes cmdsOK = TRUE; 17151590Srgrimes } 17168874Srgrimes 17171590Srgrimes /* 17181590Srgrimes * If the -n flag wasn't given, we open up OUR (not the child's) 17191590Srgrimes * temporary file to stuff commands in it. The thing is rd/wr so we don't 17201590Srgrimes * need to reopen it to feed it to the shell. If the -n flag *was* given, 17211590Srgrimes * we just set the file to be stdout. Cute, huh? 17221590Srgrimes */ 17231590Srgrimes if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) { 17241590Srgrimes /* 17251590Srgrimes * We're serious here, but if the commands were bogus, we're 17261590Srgrimes * also dead... 17271590Srgrimes */ 17281590Srgrimes if (!cmdsOK) { 17291590Srgrimes DieHorribly(); 17301590Srgrimes } 17318874Srgrimes 173268898Skris (void) strcpy(tfile, TMPPAT); 173368898Skris if ((tfd = mkstemp(tfile)) == -1) 173468898Skris Punt("Cannot create temp file: %s", strerror(errno)); 173568898Skris job->cmdFILE = fdopen(tfd, "w+"); 173668898Skris eunlink(tfile); 173718730Ssteve if (job->cmdFILE == NULL) { 173868898Skris close(tfd); 173968898Skris Punt("Could not open %s", tfile); 17401590Srgrimes } 174118730Ssteve (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1); 17421590Srgrimes /* 17431590Srgrimes * Send the commands to the command file, flush all its buffers then 17441590Srgrimes * rewind and remove the thing. 17451590Srgrimes */ 17461590Srgrimes noExec = FALSE; 17471590Srgrimes 17481590Srgrimes /* 17491590Srgrimes * used to be backwards; replace when start doing multiple commands 17501590Srgrimes * per shell. 17511590Srgrimes */ 17521590Srgrimes if (compatMake) { 17531590Srgrimes /* 17541590Srgrimes * Be compatible: If this is the first time for this node, 17551590Srgrimes * verify its commands are ok and open the commands list for 17561590Srgrimes * sequential access by later invocations of JobStart. 17571590Srgrimes * Once that is done, we take the next command off the list 17581590Srgrimes * and print it to the command file. If the command was an 17591590Srgrimes * ellipsis, note that there's nothing more to execute. 17601590Srgrimes */ 17611590Srgrimes if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){ 17621590Srgrimes cmdsOK = FALSE; 17631590Srgrimes } else { 176418730Ssteve LstNode ln = Lst_Next(gn->commands); 17658874Srgrimes 176669527Swill if ((ln == NULL) || 176769531Swill JobPrintCommand((void *) Lst_Datum(ln), 176869531Swill (void *) job)) 17691590Srgrimes { 17701590Srgrimes noExec = TRUE; 177118730Ssteve Lst_Close(gn->commands); 17721590Srgrimes } 17731590Srgrimes if (noExec && !(job->flags & JOB_FIRST)) { 17741590Srgrimes /* 17751590Srgrimes * If we're not going to execute anything, the job 17761590Srgrimes * is done and we need to close down the various 17771590Srgrimes * file descriptors we've opened for output, then 17781590Srgrimes * call JobDoOutput to catch the final characters or 17791590Srgrimes * send the file to the screen... Note that the i/o streams 17801590Srgrimes * are only open if this isn't the first job. 17811590Srgrimes * Note also that this could not be done in 17821590Srgrimes * Job_CatchChildren b/c it wasn't clear if there were 17831590Srgrimes * more commands to execute or not... 17841590Srgrimes */ 178518730Ssteve JobClose(job); 17861590Srgrimes } 17871590Srgrimes } 17881590Srgrimes } else { 17891590Srgrimes /* 17901590Srgrimes * We can do all the commands at once. hooray for sanity 17911590Srgrimes */ 17921590Srgrimes numCommands = 0; 179369531Swill Lst_ForEach(gn->commands, JobPrintCommand, (void *)job); 17948874Srgrimes 17951590Srgrimes /* 17961590Srgrimes * If we didn't print out any commands to the shell script, 17971590Srgrimes * there's not much point in executing the shell, is there? 17981590Srgrimes */ 17991590Srgrimes if (numCommands == 0) { 18001590Srgrimes noExec = TRUE; 18011590Srgrimes } 18021590Srgrimes } 18031590Srgrimes } else if (noExecute) { 18041590Srgrimes /* 18051590Srgrimes * Not executing anything -- just print all the commands to stdout 18061590Srgrimes * in one fell swoop. This will still set up job->tailCmds correctly. 18071590Srgrimes */ 18081590Srgrimes if (lastNode != gn) { 180918730Ssteve MESSAGE(stdout, gn); 18101590Srgrimes lastNode = gn; 18111590Srgrimes } 18121590Srgrimes job->cmdFILE = stdout; 18131590Srgrimes /* 18141590Srgrimes * Only print the commands if they're ok, but don't die if they're 18151590Srgrimes * not -- just let the user know they're bad and keep going. It 18161590Srgrimes * doesn't do any harm in this case and may do some good. 18171590Srgrimes */ 18181590Srgrimes if (cmdsOK) { 181969531Swill Lst_ForEach(gn->commands, JobPrintCommand, (void *)job); 18201590Srgrimes } 18211590Srgrimes /* 18221590Srgrimes * Don't execute the shell, thank you. 18231590Srgrimes */ 18241590Srgrimes noExec = TRUE; 18251590Srgrimes } else { 18261590Srgrimes /* 18271590Srgrimes * Just touch the target and note that no shell should be executed. 18281590Srgrimes * Set cmdFILE to stdout to make life easier. Check the commands, too, 18291590Srgrimes * but don't die if they're no good -- it does no harm to keep working 18301590Srgrimes * up the graph. 18311590Srgrimes */ 18321590Srgrimes job->cmdFILE = stdout; 183318730Ssteve Job_Touch(gn, job->flags&JOB_SILENT); 18341590Srgrimes noExec = TRUE; 18351590Srgrimes } 18361590Srgrimes 18371590Srgrimes /* 18388874Srgrimes * If we're not supposed to execute a shell, don't. 18391590Srgrimes */ 18401590Srgrimes if (noExec) { 18411590Srgrimes /* 18421590Srgrimes * Unlink and close the command file if we opened one 18431590Srgrimes */ 18441590Srgrimes if (job->cmdFILE != stdout) { 184518730Ssteve if (job->cmdFILE != NULL) 184618730Ssteve (void) fclose(job->cmdFILE); 18471590Srgrimes } else { 184818730Ssteve (void) fflush(stdout); 18491590Srgrimes } 18501590Srgrimes 18511590Srgrimes /* 18521590Srgrimes * We only want to work our way up the graph if we aren't here because 18531590Srgrimes * the commands for the job were no good. 18541590Srgrimes */ 18551590Srgrimes if (cmdsOK) { 18561590Srgrimes if (aborting == 0) { 185769527Swill if (job->tailCmds != NULL) { 18581590Srgrimes Lst_ForEachFrom(job->node->commands, job->tailCmds, 18591590Srgrimes JobSaveCommand, 186069531Swill (void *)job->node); 18611590Srgrimes } 186236621Sbde job->node->made = MADE; 18631590Srgrimes Make_Update(job->node); 18641590Srgrimes } 186569531Swill free(job); 18661590Srgrimes return(JOB_FINISHED); 18671590Srgrimes } else { 186869531Swill free(job); 18691590Srgrimes return(JOB_ERROR); 18701590Srgrimes } 18711590Srgrimes } else { 187218730Ssteve (void) fflush(job->cmdFILE); 18731590Srgrimes } 18741590Srgrimes 18751590Srgrimes /* 18761590Srgrimes * Set up the control arguments to the shell. This is based on the flags 18771590Srgrimes * set earlier for this job. 18781590Srgrimes */ 18791590Srgrimes JobMakeArgv(job, argv); 18801590Srgrimes 18811590Srgrimes /* 18821590Srgrimes * If we're using pipes to catch output, create the pipe by which we'll 18831590Srgrimes * get the shell's output. If we're using files, print out that we're 188450145Shoek * starting a job and then set up its temporary-file name. 18851590Srgrimes */ 188618730Ssteve if (!compatMake || (job->flags & JOB_FIRST)) { 18871590Srgrimes if (usePipes) { 18881590Srgrimes int fd[2]; 188918730Ssteve if (pipe(fd) == -1) 189018730Ssteve Punt("Cannot create pipe: %s", strerror(errno)); 18911590Srgrimes job->inPipe = fd[0]; 18921590Srgrimes job->outPipe = fd[1]; 189318730Ssteve (void) fcntl(job->inPipe, F_SETFD, 1); 189418730Ssteve (void) fcntl(job->outPipe, F_SETFD, 1); 18951590Srgrimes } else { 189618730Ssteve (void) fprintf(stdout, "Remaking `%s'\n", gn->name); 189718730Ssteve (void) fflush(stdout); 189850145Shoek (void) strcpy(job->outFile, TMPPAT); 189950145Shoek if ((job->outFd = mkstemp(job->outFile)) == -1) 190050145Shoek Punt("cannot create temp file: %s", strerror(errno)); 190118730Ssteve (void) fcntl(job->outFd, F_SETFD, 1); 19021590Srgrimes } 19031590Srgrimes } 19041590Srgrimes 190518730Ssteve#ifdef REMOTE 190618730Ssteve if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) { 190718730Ssteve#ifdef RMT_NO_EXEC 190818730Ssteve local = !Rmt_Export(shellPath, argv, job); 190918730Ssteve#else 191018730Ssteve local = !Rmt_Begin(shellPath, argv, job->node); 191118730Ssteve#endif /* RMT_NO_EXEC */ 191218730Ssteve if (!local) { 191318730Ssteve job->flags |= JOB_REMOTE; 191418730Ssteve } 191518730Ssteve } else 191618730Ssteve#endif 191718730Ssteve local = TRUE; 19181590Srgrimes 19191590Srgrimes if (local && (((nLocal >= maxLocal) && 192018730Ssteve !(job->flags & JOB_SPECIAL) && 192118730Ssteve#ifdef REMOTE 192218730Ssteve (!(gn->type & OP_NOEXPORT) || (maxLocal != 0)) 192318730Ssteve#else 192418730Ssteve (maxLocal != 0) 192518730Ssteve#endif 192618730Ssteve ))) 19271590Srgrimes { 19281590Srgrimes /* 19291590Srgrimes * The job can only be run locally, but we've hit the limit of 19301590Srgrimes * local concurrency, so put the job on hold until some other job 19311590Srgrimes * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END) 19321590Srgrimes * may be run locally even when the local limit has been reached 19331590Srgrimes * (e.g. when maxLocal == 0), though they will be exported if at 193418730Ssteve * all possible. In addition, any target marked with .NOEXPORT will 193518730Ssteve * be run locally if maxLocal is 0. 19361590Srgrimes */ 19371590Srgrimes jobFull = TRUE; 19388874Srgrimes 19391590Srgrimes if (DEBUG(JOB)) { 194018730Ssteve (void) fprintf(stdout, "Can only run job locally.\n"); 194118730Ssteve (void) fflush(stdout); 19421590Srgrimes } 19431590Srgrimes job->flags |= JOB_RESTART; 194469531Swill (void) Lst_AtEnd(stoppedJobs, (void *)job); 19451590Srgrimes } else { 19461590Srgrimes if ((nLocal >= maxLocal) && local) { 19471590Srgrimes /* 19481590Srgrimes * If we're running this job locally as a special case (see above), 19491590Srgrimes * at least say the table is full. 19501590Srgrimes */ 19511590Srgrimes jobFull = TRUE; 19521590Srgrimes if (DEBUG(JOB)) { 195318730Ssteve (void) fprintf(stdout, "Local job queue is full.\n"); 195418730Ssteve (void) fflush(stdout); 19551590Srgrimes } 19561590Srgrimes } 19571590Srgrimes JobExec(job, argv); 19581590Srgrimes } 19591590Srgrimes return(JOB_RUNNING); 19601590Srgrimes} 19611590Srgrimes 196218730Sstevestatic char * 196318730SsteveJobOutput(job, cp, endp, msg) 196418730Ssteve register Job *job; 196518730Ssteve register char *cp, *endp; 196618730Ssteve int msg; 196718730Ssteve{ 196818730Ssteve register char *ecp; 196918730Ssteve 197018730Ssteve if (commandShell->noPrint) { 197118730Ssteve ecp = Str_FindSubstring(cp, commandShell->noPrint); 197218730Ssteve while (ecp != NULL) { 197318730Ssteve if (cp != ecp) { 197418730Ssteve *ecp = '\0'; 197518730Ssteve if (msg && job->node != lastNode) { 197618730Ssteve MESSAGE(stdout, job->node); 197718730Ssteve lastNode = job->node; 197818730Ssteve } 197918730Ssteve /* 198018730Ssteve * The only way there wouldn't be a newline after 198118730Ssteve * this line is if it were the last in the buffer. 198218730Ssteve * however, since the non-printable comes after it, 198318730Ssteve * there must be a newline, so we don't print one. 198418730Ssteve */ 198518730Ssteve (void) fprintf(stdout, "%s", cp); 198618730Ssteve (void) fflush(stdout); 198718730Ssteve } 198818730Ssteve cp = ecp + commandShell->noPLen; 198918730Ssteve if (cp != endp) { 199018730Ssteve /* 199118730Ssteve * Still more to print, look again after skipping 199218730Ssteve * the whitespace following the non-printable 199318730Ssteve * command.... 199418730Ssteve */ 199518730Ssteve cp++; 199618730Ssteve while (*cp == ' ' || *cp == '\t' || *cp == '\n') { 199718730Ssteve cp++; 199818730Ssteve } 199918730Ssteve ecp = Str_FindSubstring(cp, commandShell->noPrint); 200018730Ssteve } else { 200118730Ssteve return cp; 200218730Ssteve } 200318730Ssteve } 200418730Ssteve } 200518730Ssteve return cp; 200618730Ssteve} 200718730Ssteve 20081590Srgrimes/*- 20091590Srgrimes *----------------------------------------------------------------------- 20101590Srgrimes * JobDoOutput -- 20111590Srgrimes * This function is called at different times depending on 20121590Srgrimes * whether the user has specified that output is to be collected 20131590Srgrimes * via pipes or temporary files. In the former case, we are called 20141590Srgrimes * whenever there is something to read on the pipe. We collect more 20151590Srgrimes * output from the given job and store it in the job's outBuf. If 20161590Srgrimes * this makes up a line, we print it tagged by the job's identifier, 20171590Srgrimes * as necessary. 20181590Srgrimes * If output has been collected in a temporary file, we open the 20191590Srgrimes * file and read it line by line, transfering it to our own 20201590Srgrimes * output channel until the file is empty. At which point we 20211590Srgrimes * remove the temporary file. 20221590Srgrimes * In both cases, however, we keep our figurative eye out for the 20231590Srgrimes * 'noPrint' line for the shell from which the output came. If 20241590Srgrimes * we recognize a line, we don't print it. If the command is not 20251590Srgrimes * alone on the line (the character after it is not \0 or \n), we 20261590Srgrimes * do print whatever follows it. 20271590Srgrimes * 20281590Srgrimes * Results: 20291590Srgrimes * None 20301590Srgrimes * 20311590Srgrimes * Side Effects: 20321590Srgrimes * curPos may be shifted as may the contents of outBuf. 20331590Srgrimes *----------------------------------------------------------------------- 20341590Srgrimes */ 203518730SsteveSTATIC void 203618730SsteveJobDoOutput(job, finish) 20371590Srgrimes register Job *job; /* the job whose output needs printing */ 20381590Srgrimes Boolean finish; /* TRUE if this is the last time we'll be 20391590Srgrimes * called for this job */ 20401590Srgrimes{ 20411590Srgrimes Boolean gotNL = FALSE; /* true if got a newline */ 204218730Ssteve Boolean fbuf; /* true if our buffer filled up */ 20431590Srgrimes register int nr; /* number of bytes read */ 20441590Srgrimes register int i; /* auxiliary index into outBuf */ 20451590Srgrimes register int max; /* limit for i (end of current data) */ 20461590Srgrimes int nRead; /* (Temporary) number of bytes read */ 20471590Srgrimes 20481590Srgrimes FILE *oFILE; /* Stream pointer to shell's output file */ 20491590Srgrimes char inLine[132]; 20501590Srgrimes 20518874Srgrimes 20521590Srgrimes if (usePipes) { 20531590Srgrimes /* 20541590Srgrimes * Read as many bytes as will fit in the buffer. 20551590Srgrimes */ 20561590Srgrimesend_loop: 205718730Ssteve gotNL = FALSE; 205818730Ssteve fbuf = FALSE; 20598874Srgrimes 206018730Ssteve nRead = read(job->inPipe, &job->outBuf[job->curPos], 20611590Srgrimes JOB_BUFSIZE - job->curPos); 20621590Srgrimes if (nRead < 0) { 20631590Srgrimes if (DEBUG(JOB)) { 20641590Srgrimes perror("JobDoOutput(piperead)"); 20651590Srgrimes } 20661590Srgrimes nr = 0; 20671590Srgrimes } else { 20681590Srgrimes nr = nRead; 20691590Srgrimes } 20701590Srgrimes 20711590Srgrimes /* 20721590Srgrimes * If we hit the end-of-file (the job is dead), we must flush its 20731590Srgrimes * remaining output, so pretend we read a newline if there's any 20741590Srgrimes * output remaining in the buffer. 20751590Srgrimes * Also clear the 'finish' flag so we stop looping. 20761590Srgrimes */ 20771590Srgrimes if ((nr == 0) && (job->curPos != 0)) { 20781590Srgrimes job->outBuf[job->curPos] = '\n'; 20791590Srgrimes nr = 1; 20801590Srgrimes finish = FALSE; 20811590Srgrimes } else if (nr == 0) { 20821590Srgrimes finish = FALSE; 20831590Srgrimes } 20848874Srgrimes 20851590Srgrimes /* 20861590Srgrimes * Look for the last newline in the bytes we just got. If there is 20871590Srgrimes * one, break out of the loop with 'i' as its index and gotNL set 20888874Srgrimes * TRUE. 20891590Srgrimes */ 20901590Srgrimes max = job->curPos + nr; 20911590Srgrimes for (i = job->curPos + nr - 1; i >= job->curPos; i--) { 20921590Srgrimes if (job->outBuf[i] == '\n') { 20931590Srgrimes gotNL = TRUE; 20941590Srgrimes break; 20951590Srgrimes } else if (job->outBuf[i] == '\0') { 20961590Srgrimes /* 20971590Srgrimes * Why? 20981590Srgrimes */ 20991590Srgrimes job->outBuf[i] = ' '; 21001590Srgrimes } 21011590Srgrimes } 21028874Srgrimes 21031590Srgrimes if (!gotNL) { 21041590Srgrimes job->curPos += nr; 21051590Srgrimes if (job->curPos == JOB_BUFSIZE) { 21061590Srgrimes /* 21071590Srgrimes * If we've run out of buffer space, we have no choice 21088874Srgrimes * but to print the stuff. sigh. 21091590Srgrimes */ 211018730Ssteve fbuf = TRUE; 21111590Srgrimes i = job->curPos; 21121590Srgrimes } 21131590Srgrimes } 211418730Ssteve if (gotNL || fbuf) { 21151590Srgrimes /* 21161590Srgrimes * Need to send the output to the screen. Null terminate it 21171590Srgrimes * first, overwriting the newline character if there was one. 21181590Srgrimes * So long as the line isn't one we should filter (according 211972645Sasmodai * to the shell description), we print the line, preceded 21201590Srgrimes * by a target banner if this target isn't the same as the 21211590Srgrimes * one for which we last printed something. 21221590Srgrimes * The rest of the data in the buffer are then shifted down 21238874Srgrimes * to the start of the buffer and curPos is set accordingly. 21241590Srgrimes */ 21251590Srgrimes job->outBuf[i] = '\0'; 21261590Srgrimes if (i >= job->curPos) { 212718730Ssteve char *cp; 21281590Srgrimes 212918730Ssteve cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); 21301590Srgrimes 21311590Srgrimes /* 21321590Srgrimes * There's still more in that thar buffer. This time, though, 21331590Srgrimes * we know there's no newline at the end, so we add one of 21341590Srgrimes * our own free will. 21351590Srgrimes */ 21361590Srgrimes if (*cp != '\0') { 21371590Srgrimes if (job->node != lastNode) { 213818730Ssteve MESSAGE(stdout, job->node); 21391590Srgrimes lastNode = job->node; 21401590Srgrimes } 214118730Ssteve (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); 214218730Ssteve (void) fflush(stdout); 21431590Srgrimes } 21441590Srgrimes } 21451590Srgrimes if (i < max - 1) { 21461590Srgrimes /* shift the remaining characters down */ 214718730Ssteve (void) memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); 21481590Srgrimes job->curPos = max - (i + 1); 21498874Srgrimes 21501590Srgrimes } else { 21511590Srgrimes /* 21521590Srgrimes * We have written everything out, so we just start over 21531590Srgrimes * from the start of the buffer. No copying. No nothing. 21541590Srgrimes */ 21551590Srgrimes job->curPos = 0; 21561590Srgrimes } 21571590Srgrimes } 21581590Srgrimes if (finish) { 21591590Srgrimes /* 21601590Srgrimes * If the finish flag is true, we must loop until we hit 216118730Ssteve * end-of-file on the pipe. This is guaranteed to happen 216218730Ssteve * eventually since the other end of the pipe is now closed 216318730Ssteve * (we closed it explicitly and the child has exited). When 216418730Ssteve * we do get an EOF, finish will be set FALSE and we'll fall 216518730Ssteve * through and out. 21661590Srgrimes */ 21671590Srgrimes goto end_loop; 21681590Srgrimes } 21691590Srgrimes } else { 21701590Srgrimes /* 21711590Srgrimes * We've been called to retrieve the output of the job from the 21721590Srgrimes * temporary file where it's been squirreled away. This consists of 21731590Srgrimes * opening the file, reading the output line by line, being sure not 21741590Srgrimes * to print the noPrint line for the shell we used, then close and 21751590Srgrimes * remove the temporary file. Very simple. 21761590Srgrimes * 21771590Srgrimes * Change to read in blocks and do FindSubString type things as for 21781590Srgrimes * pipes? That would allow for "@echo -n..." 21791590Srgrimes */ 218018730Ssteve oFILE = fopen(job->outFile, "r"); 218118730Ssteve if (oFILE != NULL) { 218218730Ssteve (void) fprintf(stdout, "Results of making %s:\n", job->node->name); 218318730Ssteve (void) fflush(stdout); 218418730Ssteve while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { 218518730Ssteve register char *cp, *endp, *oendp; 21861590Srgrimes 21871590Srgrimes cp = inLine; 218818730Ssteve oendp = endp = inLine + strlen(inLine); 21891590Srgrimes if (endp[-1] == '\n') { 21901590Srgrimes *--endp = '\0'; 21911590Srgrimes } 219218730Ssteve cp = JobOutput(job, inLine, endp, FALSE); 21931590Srgrimes 21941590Srgrimes /* 21951590Srgrimes * There's still more in that thar buffer. This time, though, 21961590Srgrimes * we know there's no newline at the end, so we add one of 21971590Srgrimes * our own free will. 21981590Srgrimes */ 219918730Ssteve (void) fprintf(stdout, "%s", cp); 220018730Ssteve (void) fflush(stdout); 220118730Ssteve if (endp != oendp) { 220218730Ssteve (void) fprintf(stdout, "\n"); 220318730Ssteve (void) fflush(stdout); 22041590Srgrimes } 22051590Srgrimes } 220618730Ssteve (void) fclose(oFILE); 220718730Ssteve (void) eunlink(job->outFile); 22081590Srgrimes } 22091590Srgrimes } 22101590Srgrimes} 22111590Srgrimes 22121590Srgrimes/*- 22131590Srgrimes *----------------------------------------------------------------------- 22141590Srgrimes * Job_CatchChildren -- 22151590Srgrimes * Handle the exit of a child. Called from Make_Make. 22161590Srgrimes * 22171590Srgrimes * Results: 22181590Srgrimes * none. 22191590Srgrimes * 22201590Srgrimes * Side Effects: 22211590Srgrimes * The job descriptor is removed from the list of children. 22221590Srgrimes * 22231590Srgrimes * Notes: 22241590Srgrimes * We do waits, blocking or not, according to the wisdom of our 22251590Srgrimes * caller, until there are no more children to report. For each 22261590Srgrimes * job, call JobFinish to finish things off. This will take care of 22271590Srgrimes * putting jobs on the stoppedJobs queue. 22281590Srgrimes * 22291590Srgrimes *----------------------------------------------------------------------- 22301590Srgrimes */ 22311590Srgrimesvoid 223218730SsteveJob_CatchChildren(block) 22331590Srgrimes Boolean block; /* TRUE if should block on the wait. */ 22341590Srgrimes{ 22351590Srgrimes int pid; /* pid of dead child */ 22361590Srgrimes register Job *job; /* job descriptor for dead child */ 22371590Srgrimes LstNode jnode; /* list element for finding job */ 223818730Ssteve int status; /* Exit/termination status */ 22391590Srgrimes 22401590Srgrimes /* 22411590Srgrimes * Don't even bother if we know there's no one around. 22421590Srgrimes */ 22431590Srgrimes if (nLocal == 0) { 22441590Srgrimes return; 22451590Srgrimes } 22468874Srgrimes 224718730Ssteve while ((pid = waitpid((pid_t) -1, &status, 224818730Ssteve (block?0:WNOHANG)|WUNTRACED)) > 0) 22491590Srgrimes { 225018730Ssteve if (DEBUG(JOB)) { 225118730Ssteve (void) fprintf(stdout, "Process %d exited or stopped.\n", pid); 225218730Ssteve (void) fflush(stdout); 225318730Ssteve } 22541590Srgrimes 22558874Srgrimes 225669531Swill jnode = Lst_Find(jobs, (void *)&pid, JobCmpPid); 22571590Srgrimes 225869527Swill if (jnode == NULL) { 225918730Ssteve if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) { 226069531Swill jnode = Lst_Find(stoppedJobs, (void *) &pid, JobCmpPid); 226169527Swill if (jnode == NULL) { 22621590Srgrimes Error("Resumed child (%d) not in table", pid); 22631590Srgrimes continue; 22641590Srgrimes } 22651590Srgrimes job = (Job *)Lst_Datum(jnode); 226618730Ssteve (void) Lst_Remove(stoppedJobs, jnode); 22671590Srgrimes } else { 226818730Ssteve Error("Child (%d) not in table?", pid); 22691590Srgrimes continue; 22701590Srgrimes } 22711590Srgrimes } else { 227218730Ssteve job = (Job *) Lst_Datum(jnode); 227318730Ssteve (void) Lst_Remove(jobs, jnode); 22741590Srgrimes nJobs -= 1; 22751590Srgrimes if (jobFull && DEBUG(JOB)) { 227618730Ssteve (void) fprintf(stdout, "Job queue is no longer full.\n"); 227718730Ssteve (void) fflush(stdout); 22781590Srgrimes } 22791590Srgrimes jobFull = FALSE; 228018730Ssteve#ifdef REMOTE 228118730Ssteve if (!(job->flags & JOB_REMOTE)) { 228218730Ssteve if (DEBUG(JOB)) { 228318730Ssteve (void) fprintf(stdout, 228418730Ssteve "Job queue has one fewer local process.\n"); 228518730Ssteve (void) fflush(stdout); 228618730Ssteve } 228718730Ssteve nLocal -= 1; 228818730Ssteve } 228918730Ssteve#else 22901590Srgrimes nLocal -= 1; 229118730Ssteve#endif 22921590Srgrimes } 22931590Srgrimes 229418730Ssteve JobFinish(job, &status); 22951590Srgrimes } 22961590Srgrimes} 22971590Srgrimes 22981590Srgrimes/*- 22991590Srgrimes *----------------------------------------------------------------------- 23001590Srgrimes * Job_CatchOutput -- 23011590Srgrimes * Catch the output from our children, if we're using 23021590Srgrimes * pipes do so. Otherwise just block time until we get a 23031590Srgrimes * signal (most likely a SIGCHLD) since there's no point in 23041590Srgrimes * just spinning when there's nothing to do and the reaping 23058874Srgrimes * of a child can wait for a while. 23061590Srgrimes * 23071590Srgrimes * Results: 23088874Srgrimes * None 23091590Srgrimes * 23101590Srgrimes * Side Effects: 23111590Srgrimes * Output is read from pipes if we're piping. 23121590Srgrimes * ----------------------------------------------------------------------- 23131590Srgrimes */ 23141590Srgrimesvoid 231518730SsteveJob_CatchOutput() 23161590Srgrimes{ 23171590Srgrimes int nfds; 23181590Srgrimes struct timeval timeout; 23191590Srgrimes fd_set readfds; 23201590Srgrimes register LstNode ln; 23211590Srgrimes register Job *job; 23221590Srgrimes#ifdef RMT_WILL_WATCH 23231590Srgrimes int pnJobs; /* Previous nJobs */ 23241590Srgrimes#endif 23251590Srgrimes 232618730Ssteve (void) fflush(stdout); 23271590Srgrimes#ifdef RMT_WILL_WATCH 23281590Srgrimes pnJobs = nJobs; 23291590Srgrimes 23301590Srgrimes /* 23311590Srgrimes * It is possible for us to be called with nJobs equal to 0. This happens 23321590Srgrimes * if all the jobs finish and a job that is stopped cannot be run 23331590Srgrimes * locally (eg if maxLocal is 0) and cannot be exported. The job will 23341590Srgrimes * be placed back on the stoppedJobs queue, Job_Empty() will return false, 23351590Srgrimes * Make_Run will call us again when there's nothing for which to wait. 23361590Srgrimes * nJobs never changes, so we loop forever. Hence the check. It could 23371590Srgrimes * be argued that we should sleep for a bit so as not to swamp the 23381590Srgrimes * exportation system with requests. Perhaps we should. 23391590Srgrimes * 23401590Srgrimes * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren 23411590Srgrimes * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT. 23421590Srgrimes * It may use the variable nLocal to determine if it needs to call 23431590Srgrimes * Job_CatchChildren (if nLocal is 0, there's nothing for which to 23441590Srgrimes * wait...) 23451590Srgrimes */ 23461590Srgrimes while (nJobs != 0 && pnJobs == nJobs) { 23471590Srgrimes Rmt_Wait(); 23481590Srgrimes } 23491590Srgrimes#else 23501590Srgrimes if (usePipes) { 23511590Srgrimes readfds = outputs; 23521590Srgrimes timeout.tv_sec = SEL_SEC; 23531590Srgrimes timeout.tv_usec = SEL_USEC; 23541590Srgrimes 235518730Ssteve if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, 235618730Ssteve (fd_set *) 0, &timeout)) <= 0) 23571590Srgrimes return; 235818730Ssteve else { 235918730Ssteve if (Lst_Open(jobs) == FAILURE) { 236018730Ssteve Punt("Cannot open job table"); 23611590Srgrimes } 236269527Swill while (nfds && (ln = Lst_Next(jobs)) != NULL) { 236318730Ssteve job = (Job *) Lst_Datum(ln); 23641590Srgrimes if (FD_ISSET(job->inPipe, &readfds)) { 236518730Ssteve JobDoOutput(job, FALSE); 23661590Srgrimes nfds -= 1; 23671590Srgrimes } 23681590Srgrimes } 236918730Ssteve Lst_Close(jobs); 23701590Srgrimes } 23711590Srgrimes } 23721590Srgrimes#endif /* RMT_WILL_WATCH */ 23731590Srgrimes} 23741590Srgrimes 23751590Srgrimes/*- 23761590Srgrimes *----------------------------------------------------------------------- 23771590Srgrimes * Job_Make -- 23781590Srgrimes * Start the creation of a target. Basically a front-end for 23791590Srgrimes * JobStart used by the Make module. 23801590Srgrimes * 23811590Srgrimes * Results: 23821590Srgrimes * None. 23831590Srgrimes * 23841590Srgrimes * Side Effects: 23851590Srgrimes * Another job is started. 23861590Srgrimes * 23871590Srgrimes *----------------------------------------------------------------------- 23881590Srgrimes */ 23891590Srgrimesvoid 239018730SsteveJob_Make(gn) 23911590Srgrimes GNode *gn; 23921590Srgrimes{ 239318730Ssteve (void) JobStart(gn, 0, NULL); 23941590Srgrimes} 23951590Srgrimes 23961590Srgrimes/*- 23971590Srgrimes *----------------------------------------------------------------------- 23981590Srgrimes * Job_Init -- 23991590Srgrimes * Initialize the process module 24001590Srgrimes * 24011590Srgrimes * Results: 24021590Srgrimes * none 24031590Srgrimes * 24041590Srgrimes * Side Effects: 24051590Srgrimes * lists and counters are initialized 24061590Srgrimes *----------------------------------------------------------------------- 24071590Srgrimes */ 24081590Srgrimesvoid 240918730SsteveJob_Init(maxproc, maxlocal) 24101590Srgrimes int maxproc; /* the greatest number of jobs which may be 24111590Srgrimes * running at one time */ 24121590Srgrimes int maxlocal; /* the greatest number of local jobs which may 24131590Srgrimes * be running at once. */ 24141590Srgrimes{ 24151590Srgrimes GNode *begin; /* node for commands to do at the very start */ 24161590Srgrimes 241718730Ssteve jobs = Lst_Init(FALSE); 24181590Srgrimes stoppedJobs = Lst_Init(FALSE); 24191590Srgrimes maxJobs = maxproc; 24201590Srgrimes maxLocal = maxlocal; 24211590Srgrimes nJobs = 0; 24221590Srgrimes nLocal = 0; 24231590Srgrimes jobFull = FALSE; 24241590Srgrimes 24251590Srgrimes aborting = 0; 24261590Srgrimes errors = 0; 24271590Srgrimes 242869527Swill lastNode = NULL; 24291590Srgrimes 243041151Sdg if (maxJobs == 1 || beVerbose == 0 243118730Ssteve#ifdef REMOTE 243218730Ssteve || noMessages 243318730Ssteve#endif 243418730Ssteve ) { 24351590Srgrimes /* 24361590Srgrimes * If only one job can run at a time, there's no need for a banner, 24371590Srgrimes * no is there? 24381590Srgrimes */ 24391590Srgrimes targFmt = ""; 24401590Srgrimes } else { 24411590Srgrimes targFmt = TARG_FMT; 24421590Srgrimes } 24438874Srgrimes 244418730Ssteve if (shellPath == NULL) { 24451590Srgrimes /* 24461590Srgrimes * The user didn't specify a shell to use, so we are using the 24471590Srgrimes * default one... Both the absolute path and the last component 24481590Srgrimes * must be set. The last component is taken from the 'name' field 24491590Srgrimes * of the default shell description pointed-to by commandShell. 24501590Srgrimes * All default shells are located in _PATH_DEFSHELLDIR. 24511590Srgrimes */ 24521590Srgrimes shellName = commandShell->name; 245318730Ssteve shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); 24541590Srgrimes } 24551590Srgrimes 245618730Ssteve if (commandShell->exit == NULL) { 24571590Srgrimes commandShell->exit = ""; 24581590Srgrimes } 245918730Ssteve if (commandShell->echo == NULL) { 24601590Srgrimes commandShell->echo = ""; 24611590Srgrimes } 24621590Srgrimes 24631590Srgrimes /* 24641590Srgrimes * Catch the four signals that POSIX specifies if they aren't ignored. 24651590Srgrimes * JobPassSig will take care of calling JobInterrupt if appropriate. 24661590Srgrimes */ 246718730Ssteve if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 246818730Ssteve (void) signal(SIGINT, JobPassSig); 24691590Srgrimes } 247018730Ssteve if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 247118730Ssteve (void) signal(SIGHUP, JobPassSig); 24721590Srgrimes } 247318730Ssteve if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 247418730Ssteve (void) signal(SIGQUIT, JobPassSig); 24751590Srgrimes } 247618730Ssteve if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 247718730Ssteve (void) signal(SIGTERM, JobPassSig); 24781590Srgrimes } 24791590Srgrimes /* 24801590Srgrimes * There are additional signals that need to be caught and passed if 24811590Srgrimes * either the export system wants to be told directly of signals or if 24821590Srgrimes * we're giving each job its own process group (since then it won't get 24831590Srgrimes * signals from the terminal driver as we own the terminal) 24841590Srgrimes */ 24851590Srgrimes#if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) 248618730Ssteve if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { 248718730Ssteve (void) signal(SIGTSTP, JobPassSig); 24881590Srgrimes } 248918730Ssteve if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { 249018730Ssteve (void) signal(SIGTTOU, JobPassSig); 24911590Srgrimes } 249218730Ssteve if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { 249318730Ssteve (void) signal(SIGTTIN, JobPassSig); 24941590Srgrimes } 249518730Ssteve if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { 249618730Ssteve (void) signal(SIGWINCH, JobPassSig); 24971590Srgrimes } 24981590Srgrimes#endif 24998874Srgrimes 250018730Ssteve begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); 25011590Srgrimes 250269527Swill if (begin != NULL) { 250318730Ssteve JobStart(begin, JOB_SPECIAL, (Job *)0); 25041590Srgrimes while (nJobs) { 25051590Srgrimes Job_CatchOutput(); 25061590Srgrimes#ifndef RMT_WILL_WATCH 250718730Ssteve Job_CatchChildren(!usePipes); 25081590Srgrimes#endif /* RMT_WILL_WATCH */ 25091590Srgrimes } 25101590Srgrimes } 251118730Ssteve postCommands = Targ_FindNode(".END", TARG_CREATE); 25121590Srgrimes} 25131590Srgrimes 25141590Srgrimes/*- 25151590Srgrimes *----------------------------------------------------------------------- 25161590Srgrimes * Job_Full -- 25171590Srgrimes * See if the job table is full. It is considered full if it is OR 25181590Srgrimes * if we are in the process of aborting OR if we have 25191590Srgrimes * reached/exceeded our local quota. This prevents any more jobs 25201590Srgrimes * from starting up. 25211590Srgrimes * 25221590Srgrimes * Results: 25231590Srgrimes * TRUE if the job table is full, FALSE otherwise 25241590Srgrimes * Side Effects: 25251590Srgrimes * None. 25261590Srgrimes *----------------------------------------------------------------------- 25271590Srgrimes */ 25281590SrgrimesBoolean 252918730SsteveJob_Full() 25301590Srgrimes{ 253118730Ssteve return(aborting || jobFull); 25321590Srgrimes} 25331590Srgrimes 25341590Srgrimes/*- 25351590Srgrimes *----------------------------------------------------------------------- 25361590Srgrimes * Job_Empty -- 25371590Srgrimes * See if the job table is empty. Because the local concurrency may 25381590Srgrimes * be set to 0, it is possible for the job table to become empty, 25391590Srgrimes * while the list of stoppedJobs remains non-empty. In such a case, 25401590Srgrimes * we want to restart as many jobs as we can. 25411590Srgrimes * 25421590Srgrimes * Results: 25431590Srgrimes * TRUE if it is. FALSE if it ain't. 25441590Srgrimes * 25451590Srgrimes * Side Effects: 25461590Srgrimes * None. 25471590Srgrimes * 25481590Srgrimes * ----------------------------------------------------------------------- 25491590Srgrimes */ 25501590SrgrimesBoolean 255118730SsteveJob_Empty() 25521590Srgrimes{ 25531590Srgrimes if (nJobs == 0) { 25541590Srgrimes if (!Lst_IsEmpty(stoppedJobs) && !aborting) { 25551590Srgrimes /* 25561590Srgrimes * The job table is obviously not full if it has no jobs in 25571590Srgrimes * it...Try and restart the stopped jobs. 25581590Srgrimes */ 25591590Srgrimes jobFull = FALSE; 256018730Ssteve JobRestartJobs(); 25611590Srgrimes return(FALSE); 25621590Srgrimes } else { 25631590Srgrimes return(TRUE); 25641590Srgrimes } 25651590Srgrimes } else { 25661590Srgrimes return(FALSE); 25671590Srgrimes } 25681590Srgrimes} 25691590Srgrimes 25701590Srgrimes/*- 25711590Srgrimes *----------------------------------------------------------------------- 25721590Srgrimes * JobMatchShell -- 25731590Srgrimes * Find a matching shell in 'shells' given its final component. 25741590Srgrimes * 25751590Srgrimes * Results: 25761590Srgrimes * A pointer to the Shell structure. 25771590Srgrimes * 25781590Srgrimes * Side Effects: 25791590Srgrimes * None. 25801590Srgrimes * 25811590Srgrimes *----------------------------------------------------------------------- 25821590Srgrimes */ 25831590Srgrimesstatic Shell * 258418730SsteveJobMatchShell(name) 25851590Srgrimes char *name; /* Final component of shell path */ 25861590Srgrimes{ 25871590Srgrimes register Shell *sh; /* Pointer into shells table */ 25881590Srgrimes Shell *match; /* Longest-matching shell */ 25891590Srgrimes register char *cp1, 25901590Srgrimes *cp2; 25911590Srgrimes char *eoname; 25921590Srgrimes 259318730Ssteve eoname = name + strlen(name); 25941590Srgrimes 259518730Ssteve match = NULL; 25961590Srgrimes 25971590Srgrimes for (sh = shells; sh->name != NULL; sh++) { 259818730Ssteve for (cp1 = eoname - strlen(sh->name), cp2 = sh->name; 25991590Srgrimes *cp1 != '\0' && *cp1 == *cp2; 26001590Srgrimes cp1++, cp2++) { 26011590Srgrimes continue; 26021590Srgrimes } 26031590Srgrimes if (*cp1 != *cp2) { 26041590Srgrimes continue; 260518730Ssteve } else if (match == NULL || strlen(match->name) < strlen(sh->name)) { 260618730Ssteve match = sh; 26071590Srgrimes } 26081590Srgrimes } 260918730Ssteve return(match == NULL ? sh : match); 26101590Srgrimes} 26111590Srgrimes 26121590Srgrimes/*- 26131590Srgrimes *----------------------------------------------------------------------- 26141590Srgrimes * Job_ParseShell -- 26151590Srgrimes * Parse a shell specification and set up commandShell, shellPath 26161590Srgrimes * and shellName appropriately. 26171590Srgrimes * 26181590Srgrimes * Results: 26191590Srgrimes * FAILURE if the specification was incorrect. 26201590Srgrimes * 26211590Srgrimes * Side Effects: 26221590Srgrimes * commandShell points to a Shell structure (either predefined or 26231590Srgrimes * created from the shell spec), shellPath is the full path of the 26241590Srgrimes * shell described by commandShell, while shellName is just the 26251590Srgrimes * final component of shellPath. 26261590Srgrimes * 26271590Srgrimes * Notes: 26281590Srgrimes * A shell specification consists of a .SHELL target, with dependency 26291590Srgrimes * operator, followed by a series of blank-separated words. Double 26301590Srgrimes * quotes can be used to use blanks in words. A backslash escapes 26311590Srgrimes * anything (most notably a double-quote and a space) and 26321590Srgrimes * provides the functionality it does in C. Each word consists of 26331590Srgrimes * keyword and value separated by an equal sign. There should be no 26341590Srgrimes * unnecessary spaces in the word. The keywords are as follows: 26351590Srgrimes * name Name of shell. 26361590Srgrimes * path Location of shell. Overrides "name" if given 26371590Srgrimes * quiet Command to turn off echoing. 26381590Srgrimes * echo Command to turn echoing on 26391590Srgrimes * filter Result of turning off echoing that shouldn't be 26401590Srgrimes * printed. 26411590Srgrimes * echoFlag Flag to turn echoing on at the start 26421590Srgrimes * errFlag Flag to turn error checking on at the start 26431590Srgrimes * hasErrCtl True if shell has error checking control 26441590Srgrimes * check Command to turn on error checking if hasErrCtl 26451590Srgrimes * is TRUE or template of command to echo a command 26461590Srgrimes * for which error checking is off if hasErrCtl is 26471590Srgrimes * FALSE. 26481590Srgrimes * ignore Command to turn off error checking if hasErrCtl 26491590Srgrimes * is TRUE or template of command to execute a 26501590Srgrimes * command so as to ignore any errors it returns if 26511590Srgrimes * hasErrCtl is FALSE. 26521590Srgrimes * 26531590Srgrimes *----------------------------------------------------------------------- 26541590Srgrimes */ 26551590SrgrimesReturnStatus 265618730SsteveJob_ParseShell(line) 26571590Srgrimes char *line; /* The shell spec */ 26581590Srgrimes{ 26591590Srgrimes char **words; 26601590Srgrimes int wordCount; 26611590Srgrimes register char **argv; 26621590Srgrimes register int argc; 26631590Srgrimes char *path; 26641590Srgrimes Shell newShell; 26651590Srgrimes Boolean fullSpec = FALSE; 26661590Srgrimes 266718730Ssteve while (isspace(*line)) { 26681590Srgrimes line++; 26691590Srgrimes } 267018730Ssteve words = brk_string(line, &wordCount, TRUE); 26711590Srgrimes 267269531Swill memset(&newShell, 0, sizeof(newShell)); 26738874Srgrimes 26741590Srgrimes /* 26751590Srgrimes * Parse the specification by keyword 26761590Srgrimes */ 267718730Ssteve for (path = NULL, argc = wordCount - 1, argv = words + 1; 26781590Srgrimes argc != 0; 26791590Srgrimes argc--, argv++) { 268018730Ssteve if (strncmp(*argv, "path=", 5) == 0) { 26811590Srgrimes path = &argv[0][5]; 268218730Ssteve } else if (strncmp(*argv, "name=", 5) == 0) { 26831590Srgrimes newShell.name = &argv[0][5]; 26841590Srgrimes } else { 268518730Ssteve if (strncmp(*argv, "quiet=", 6) == 0) { 26861590Srgrimes newShell.echoOff = &argv[0][6]; 268718730Ssteve } else if (strncmp(*argv, "echo=", 5) == 0) { 26881590Srgrimes newShell.echoOn = &argv[0][5]; 268918730Ssteve } else if (strncmp(*argv, "filter=", 7) == 0) { 26901590Srgrimes newShell.noPrint = &argv[0][7]; 26911590Srgrimes newShell.noPLen = strlen(newShell.noPrint); 269218730Ssteve } else if (strncmp(*argv, "echoFlag=", 9) == 0) { 26931590Srgrimes newShell.echo = &argv[0][9]; 269418730Ssteve } else if (strncmp(*argv, "errFlag=", 8) == 0) { 26951590Srgrimes newShell.exit = &argv[0][8]; 269618730Ssteve } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { 26971590Srgrimes char c = argv[0][10]; 26981590Srgrimes newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && 269918730Ssteve (c != 'T') && (c != 't')); 270018730Ssteve } else if (strncmp(*argv, "check=", 6) == 0) { 27011590Srgrimes newShell.errCheck = &argv[0][6]; 270218730Ssteve } else if (strncmp(*argv, "ignore=", 7) == 0) { 27031590Srgrimes newShell.ignErr = &argv[0][7]; 27041590Srgrimes } else { 270518730Ssteve Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", 27061590Srgrimes *argv); 270718730Ssteve return(FAILURE); 27081590Srgrimes } 27091590Srgrimes fullSpec = TRUE; 27101590Srgrimes } 27111590Srgrimes } 27121590Srgrimes 271318730Ssteve if (path == NULL) { 27141590Srgrimes /* 27151590Srgrimes * If no path was given, the user wants one of the pre-defined shells, 27161590Srgrimes * yes? So we find the one s/he wants with the help of JobMatchShell 27171590Srgrimes * and set things up the right way. shellPath will be set up by 27181590Srgrimes * Job_Init. 27191590Srgrimes */ 272018730Ssteve if (newShell.name == NULL) { 272118730Ssteve Parse_Error(PARSE_FATAL, "Neither path nor name specified"); 272218730Ssteve return(FAILURE); 27231590Srgrimes } else { 272418730Ssteve commandShell = JobMatchShell(newShell.name); 27251590Srgrimes shellName = newShell.name; 27261590Srgrimes } 27271590Srgrimes } else { 27281590Srgrimes /* 27291590Srgrimes * The user provided a path. If s/he gave nothing else (fullSpec is 27301590Srgrimes * FALSE), try and find a matching shell in the ones we know of. 27311590Srgrimes * Else we just take the specification at its word and copy it 27321590Srgrimes * to a new location. In either case, we need to record the 27331590Srgrimes * path the user gave for the shell. 27341590Srgrimes */ 27351590Srgrimes shellPath = path; 273618730Ssteve path = strrchr(path, '/'); 273718730Ssteve if (path == NULL) { 27381590Srgrimes path = shellPath; 27391590Srgrimes } else { 27401590Srgrimes path += 1; 27411590Srgrimes } 274218730Ssteve if (newShell.name != NULL) { 27431590Srgrimes shellName = newShell.name; 27441590Srgrimes } else { 27451590Srgrimes shellName = path; 27461590Srgrimes } 27471590Srgrimes if (!fullSpec) { 274818730Ssteve commandShell = JobMatchShell(shellName); 27491590Srgrimes } else { 27501590Srgrimes commandShell = (Shell *) emalloc(sizeof(Shell)); 27511590Srgrimes *commandShell = newShell; 27521590Srgrimes } 27531590Srgrimes } 27541590Srgrimes 27551590Srgrimes if (commandShell->echoOn && commandShell->echoOff) { 27561590Srgrimes commandShell->hasEchoCtl = TRUE; 27571590Srgrimes } 27588874Srgrimes 27591590Srgrimes if (!commandShell->hasErrCtl) { 276018730Ssteve if (commandShell->errCheck == NULL) { 27611590Srgrimes commandShell->errCheck = ""; 27621590Srgrimes } 276318730Ssteve if (commandShell->ignErr == NULL) { 27641590Srgrimes commandShell->ignErr = "%s\n"; 27651590Srgrimes } 27661590Srgrimes } 27678874Srgrimes 27681590Srgrimes return SUCCESS; 27691590Srgrimes} 27701590Srgrimes 27711590Srgrimes/*- 27721590Srgrimes *----------------------------------------------------------------------- 27731590Srgrimes * JobInterrupt -- 27741590Srgrimes * Handle the receipt of an interrupt. 27751590Srgrimes * 27761590Srgrimes * Results: 27771590Srgrimes * None 27781590Srgrimes * 27791590Srgrimes * Side Effects: 27801590Srgrimes * All children are killed. Another job will be started if the 27811590Srgrimes * .INTERRUPT target was given. 27821590Srgrimes *----------------------------------------------------------------------- 27831590Srgrimes */ 27841590Srgrimesstatic void 278518730SsteveJobInterrupt(runINTERRUPT, signo) 27861590Srgrimes int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT 27871590Srgrimes * target should be executed */ 278818730Ssteve int signo; /* signal received */ 27891590Srgrimes{ 27901590Srgrimes LstNode ln; /* element in job table */ 279162830Swsanchez Job *job = NULL; /* job descriptor in that element */ 27921590Srgrimes GNode *interrupt; /* the node describing the .INTERRUPT target */ 27938874Srgrimes 27941590Srgrimes aborting = ABORT_INTERRUPT; 27951590Srgrimes 279618730Ssteve (void) Lst_Open(jobs); 279769527Swill while ((ln = Lst_Next(jobs)) != NULL) { 279818730Ssteve job = (Job *) Lst_Datum(ln); 27991590Srgrimes 280018730Ssteve if (!Targ_Precious(job->node)) { 280118730Ssteve char *file = (job->node->path == NULL ? 28021590Srgrimes job->node->name : 28031590Srgrimes job->node->path); 280418730Ssteve if (!noExecute && eunlink(file) != -1) { 280518730Ssteve Error("*** %s removed", file); 28061590Srgrimes } 28071590Srgrimes } 28081590Srgrimes#ifdef RMT_WANTS_SIGNALS 28091590Srgrimes if (job->flags & JOB_REMOTE) { 28101590Srgrimes /* 28111590Srgrimes * If job is remote, let the Rmt module do the killing. 28121590Srgrimes */ 281318730Ssteve if (!Rmt_Signal(job, signo)) { 28141590Srgrimes /* 28151590Srgrimes * If couldn't kill the thing, finish it out now with an 28161590Srgrimes * error code, since no exit report will come in likely. 28171590Srgrimes */ 281818730Ssteve int status; 28191590Srgrimes 28201590Srgrimes status.w_status = 0; 28211590Srgrimes status.w_retcode = 1; 282218730Ssteve JobFinish(job, &status); 28231590Srgrimes } 28241590Srgrimes } else if (job->pid) { 282518730Ssteve KILL(job->pid, signo); 28261590Srgrimes } 28271590Srgrimes#else 28281590Srgrimes if (job->pid) { 282918730Ssteve if (DEBUG(JOB)) { 283018730Ssteve (void) fprintf(stdout, 283118730Ssteve "JobInterrupt passing signal to child %d.\n", 283218730Ssteve job->pid); 283318730Ssteve (void) fflush(stdout); 283418730Ssteve } 283518730Ssteve KILL(job->pid, signo); 283618730Ssteve } 283718730Ssteve#endif /* RMT_WANTS_SIGNALS */ 283818730Ssteve } 283918730Ssteve 284018730Ssteve#ifdef REMOTE 284118730Ssteve (void)Lst_Open(stoppedJobs); 284269527Swill while ((ln = Lst_Next(stoppedJobs)) != NULL) { 284318730Ssteve job = (Job *) Lst_Datum(ln); 284418730Ssteve 284518730Ssteve if (job->flags & JOB_RESTART) { 284618730Ssteve if (DEBUG(JOB)) { 284718730Ssteve (void) fprintf(stdout, "%s%s", 284818730Ssteve "JobInterrupt skipping job on stopped queue", 284918730Ssteve "-- it was waiting to be restarted.\n"); 285018730Ssteve (void) fflush(stdout); 285118730Ssteve } 285218730Ssteve continue; 285318730Ssteve } 285418730Ssteve if (!Targ_Precious(job->node)) { 285518730Ssteve char *file = (job->node->path == NULL ? 285618730Ssteve job->node->name : 285718730Ssteve job->node->path); 285818730Ssteve if (eunlink(file) == 0) { 285918730Ssteve Error("*** %s removed", file); 286018730Ssteve } 286118730Ssteve } 286218730Ssteve /* 286318730Ssteve * Resume the thing so it will take the signal. 286418730Ssteve */ 286518730Ssteve if (DEBUG(JOB)) { 286618730Ssteve (void) fprintf(stdout, 286718730Ssteve "JobInterrupt passing CONT to stopped child %d.\n", 286818730Ssteve job->pid); 286918730Ssteve (void) fflush(stdout); 287018730Ssteve } 287118730Ssteve KILL(job->pid, SIGCONT); 287218730Ssteve#ifdef RMT_WANTS_SIGNALS 287318730Ssteve if (job->flags & JOB_REMOTE) { 287418730Ssteve /* 287518730Ssteve * If job is remote, let the Rmt module do the killing. 287618730Ssteve */ 287718730Ssteve if (!Rmt_Signal(job, SIGINT)) { 287818730Ssteve /* 287918730Ssteve * If couldn't kill the thing, finish it out now with an 288018730Ssteve * error code, since no exit report will come in likely. 288118730Ssteve */ 288218730Ssteve int status; 288318730Ssteve status.w_status = 0; 288418730Ssteve status.w_retcode = 1; 288518730Ssteve JobFinish(job, &status); 288618730Ssteve } 288718730Ssteve } else if (job->pid) { 288818730Ssteve if (DEBUG(JOB)) { 288918730Ssteve (void) fprintf(stdout, 289018730Ssteve "JobInterrupt passing interrupt to stopped child %d.\n", 289118730Ssteve job->pid); 289218730Ssteve (void) fflush(stdout); 289318730Ssteve } 28941590Srgrimes KILL(job->pid, SIGINT); 28951590Srgrimes } 28961590Srgrimes#endif /* RMT_WANTS_SIGNALS */ 28971590Srgrimes } 289818730Ssteve#endif 289918730Ssteve Lst_Close(stoppedJobs); 29001590Srgrimes 29011590Srgrimes if (runINTERRUPT && !touchFlag) { 290218730Ssteve interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 290369527Swill if (interrupt != NULL) { 29041590Srgrimes ignoreErrors = FALSE; 29051590Srgrimes 290618730Ssteve JobStart(interrupt, JOB_IGNDOTS, (Job *)0); 29071590Srgrimes while (nJobs) { 29081590Srgrimes Job_CatchOutput(); 29091590Srgrimes#ifndef RMT_WILL_WATCH 291018730Ssteve Job_CatchChildren(!usePipes); 29111590Srgrimes#endif /* RMT_WILL_WATCH */ 29121590Srgrimes } 29131590Srgrimes } 29141590Srgrimes } 29151590Srgrimes} 29161590Srgrimes 29171590Srgrimes/* 29181590Srgrimes *----------------------------------------------------------------------- 29191590Srgrimes * Job_End -- 29201590Srgrimes * Do final processing such as the running of the commands 29218874Srgrimes * attached to the .END target. 29221590Srgrimes * 29231590Srgrimes * Results: 29241590Srgrimes * Number of errors reported. 29251590Srgrimes *----------------------------------------------------------------------- 29261590Srgrimes */ 29271590Srgrimesint 292818730SsteveJob_End() 29291590Srgrimes{ 293069527Swill if (postCommands != NULL && !Lst_IsEmpty(postCommands->commands)) { 29311590Srgrimes if (errors) { 293218730Ssteve Error("Errors reported so .END ignored"); 29331590Srgrimes } else { 293418730Ssteve JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); 29351590Srgrimes 29361590Srgrimes while (nJobs) { 29371590Srgrimes Job_CatchOutput(); 29381590Srgrimes#ifndef RMT_WILL_WATCH 293918730Ssteve Job_CatchChildren(!usePipes); 29401590Srgrimes#endif /* RMT_WILL_WATCH */ 29411590Srgrimes } 29421590Srgrimes } 29431590Srgrimes } 29441590Srgrimes return(errors); 29451590Srgrimes} 29461590Srgrimes 29471590Srgrimes/*- 29481590Srgrimes *----------------------------------------------------------------------- 29491590Srgrimes * Job_Wait -- 29501590Srgrimes * Waits for all running jobs to finish and returns. Sets 'aborting' 29511590Srgrimes * to ABORT_WAIT to prevent other jobs from starting. 29521590Srgrimes * 29531590Srgrimes * Results: 29541590Srgrimes * None. 29551590Srgrimes * 29561590Srgrimes * Side Effects: 29571590Srgrimes * Currently running jobs finish. 29581590Srgrimes * 29591590Srgrimes *----------------------------------------------------------------------- 29601590Srgrimes */ 29611590Srgrimesvoid 29621590SrgrimesJob_Wait() 29631590Srgrimes{ 29641590Srgrimes aborting = ABORT_WAIT; 29651590Srgrimes while (nJobs != 0) { 29661590Srgrimes Job_CatchOutput(); 29671590Srgrimes#ifndef RMT_WILL_WATCH 29681590Srgrimes Job_CatchChildren(!usePipes); 29691590Srgrimes#endif /* RMT_WILL_WATCH */ 29701590Srgrimes } 29711590Srgrimes aborting = 0; 29721590Srgrimes} 29731590Srgrimes 29741590Srgrimes/*- 29751590Srgrimes *----------------------------------------------------------------------- 29761590Srgrimes * Job_AbortAll -- 29771590Srgrimes * Abort all currently running jobs without handling output or anything. 29781590Srgrimes * This function is to be called only in the event of a major 29791590Srgrimes * error. Most definitely NOT to be called from JobInterrupt. 29801590Srgrimes * 29811590Srgrimes * Results: 29821590Srgrimes * None 29831590Srgrimes * 29841590Srgrimes * Side Effects: 29851590Srgrimes * All children are killed, not just the firstborn 29861590Srgrimes *----------------------------------------------------------------------- 29871590Srgrimes */ 29881590Srgrimesvoid 298918730SsteveJob_AbortAll() 29901590Srgrimes{ 299118730Ssteve LstNode ln; /* element in job table */ 29921590Srgrimes Job *job; /* the job descriptor in that element */ 29931590Srgrimes int foo; 29948874Srgrimes 29951590Srgrimes aborting = ABORT_ERROR; 29968874Srgrimes 29971590Srgrimes if (nJobs) { 29981590Srgrimes 299918730Ssteve (void) Lst_Open(jobs); 300069527Swill while ((ln = Lst_Next(jobs)) != NULL) { 300118730Ssteve job = (Job *) Lst_Datum(ln); 30021590Srgrimes 30031590Srgrimes /* 30041590Srgrimes * kill the child process with increasingly drastic signals to make 30058874Srgrimes * darn sure it's dead. 30061590Srgrimes */ 30071590Srgrimes#ifdef RMT_WANTS_SIGNALS 30081590Srgrimes if (job->flags & JOB_REMOTE) { 30091590Srgrimes Rmt_Signal(job, SIGINT); 30101590Srgrimes Rmt_Signal(job, SIGKILL); 30111590Srgrimes } else { 30121590Srgrimes KILL(job->pid, SIGINT); 30131590Srgrimes KILL(job->pid, SIGKILL); 30141590Srgrimes } 30151590Srgrimes#else 30161590Srgrimes KILL(job->pid, SIGINT); 30171590Srgrimes KILL(job->pid, SIGKILL); 30181590Srgrimes#endif /* RMT_WANTS_SIGNALS */ 30191590Srgrimes } 30201590Srgrimes } 30218874Srgrimes 30221590Srgrimes /* 30231590Srgrimes * Catch as many children as want to report in at first, then give up 30241590Srgrimes */ 302518730Ssteve while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) 30261590Srgrimes continue; 30271590Srgrimes} 302818730Ssteve 302918730Ssteve#ifdef REMOTE 303018730Ssteve/*- 303118730Ssteve *----------------------------------------------------------------------- 303218730Ssteve * JobFlagForMigration -- 303318730Ssteve * Handle the eviction of a child. Called from RmtStatusChange. 303418730Ssteve * Flags the child as remigratable and then suspends it. 303518730Ssteve * 303618730Ssteve * Results: 303718730Ssteve * none. 303818730Ssteve * 303918730Ssteve * Side Effects: 304018730Ssteve * The job descriptor is flagged for remigration. 304118730Ssteve * 304218730Ssteve *----------------------------------------------------------------------- 304318730Ssteve */ 304418730Sstevevoid 304518730SsteveJobFlagForMigration(hostID) 304618730Ssteve int hostID; /* ID of host we used, for matching children. */ 304718730Ssteve{ 304818730Ssteve register Job *job; /* job descriptor for dead child */ 304918730Ssteve LstNode jnode; /* list element for finding job */ 305018730Ssteve 305118730Ssteve if (DEBUG(JOB)) { 305218730Ssteve (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID); 305318730Ssteve (void) fflush(stdout); 305418730Ssteve } 305569531Swill jnode = Lst_Find(jobs, (void *)hostID, JobCmpRmtID); 305618730Ssteve 305769527Swill if (jnode == NULL) { 305869531Swill jnode = Lst_Find(stoppedJobs, (void *)hostID, JobCmpRmtID); 305969527Swill if (jnode == NULL) { 306018730Ssteve if (DEBUG(JOB)) { 306118730Ssteve Error("Evicting host(%d) not in table", hostID); 306218730Ssteve } 306318730Ssteve return; 306418730Ssteve } 306518730Ssteve } 306618730Ssteve job = (Job *) Lst_Datum(jnode); 306718730Ssteve 306818730Ssteve if (DEBUG(JOB)) { 306918730Ssteve (void) fprintf(stdout, 307018730Ssteve "JobFlagForMigration(%d) found job '%s'.\n", hostID, 307118730Ssteve job->node->name); 307218730Ssteve (void) fflush(stdout); 307318730Ssteve } 307418730Ssteve 307518730Ssteve KILL(job->pid, SIGSTOP); 307618730Ssteve 307718730Ssteve job->flags |= JOB_REMIGRATE; 307818730Ssteve} 307918730Ssteve 308018730Ssteve#endif 308118730Ssteve 308218730Ssteve/*- 308318730Ssteve *----------------------------------------------------------------------- 308418730Ssteve * JobRestartJobs -- 308518730Ssteve * Tries to restart stopped jobs if there are slots available. 308618730Ssteve * Note that this tries to restart them regardless of pending errors. 308718730Ssteve * It's not good to leave stopped jobs lying around! 308818730Ssteve * 308918730Ssteve * Results: 309018730Ssteve * None. 309118730Ssteve * 309218730Ssteve * Side Effects: 309318730Ssteve * Resumes(and possibly migrates) jobs. 309418730Ssteve * 309518730Ssteve *----------------------------------------------------------------------- 309618730Ssteve */ 309718730Sstevestatic void 309818730SsteveJobRestartJobs() 309918730Ssteve{ 310018730Ssteve while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { 310118730Ssteve if (DEBUG(JOB)) { 310218730Ssteve (void) fprintf(stdout, 310318730Ssteve "Job queue is not full. Restarting a stopped job.\n"); 310418730Ssteve (void) fflush(stdout); 310518730Ssteve } 310618730Ssteve JobRestart((Job *)Lst_DeQueue(stoppedJobs)); 310718730Ssteve } 310818730Ssteve} 3109