job.c revision 137252
11590Srgrimes/* 294589Sobrien * Copyright (c) 1988, 1989, 1990, 1993 394589Sobrien * The Regents of the University of California. All rights reserved. 45814Sjkh * Copyright (c) 1988, 1989 by Adam de Boor 51590Srgrimes * Copyright (c) 1989 by Berkeley Softworks 61590Srgrimes * All rights reserved. 71590Srgrimes * 81590Srgrimes * This code is derived from software contributed to Berkeley by 91590Srgrimes * Adam de Boor. 101590Srgrimes * 111590Srgrimes * Redistribution and use in source and binary forms, with or without 121590Srgrimes * modification, are permitted provided that the following conditions 131590Srgrimes * are met: 141590Srgrimes * 1. Redistributions of source code must retain the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer. 161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171590Srgrimes * notice, this list of conditions and the following disclaimer in the 181590Srgrimes * documentation and/or other materials provided with the distribution. 191590Srgrimes * 3. All advertising materials mentioning features or use of this software 201590Srgrimes * must display the following acknowledgement: 211590Srgrimes * This product includes software developed by the University of 221590Srgrimes * California, Berkeley and its contributors. 231590Srgrimes * 4. Neither the name of the University nor the names of its contributors 241590Srgrimes * may be used to endorse or promote products derived from this software 251590Srgrimes * without specific prior written permission. 261590Srgrimes * 271590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 281590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 291590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 301590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 311590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 321590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 331590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 341590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 351590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 361590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 371590Srgrimes * SUCH DAMAGE. 3862833Swsanchez * 3962833Swsanchez * @(#)job.c 8.2 (Berkeley) 3/19/94 401590Srgrimes */ 411590Srgrimes 4262833Swsanchez#include <sys/cdefs.h> 4394587Sobrien__FBSDID("$FreeBSD: head/usr.bin/make/job.c 137252 2004-11-05 11:41:36Z harti $"); 441590Srgrimes 4535483Simp#ifndef OLD_JOKE 46103503Sjmallett#define OLD_JOKE 0 4735483Simp#endif /* OLD_JOKE */ 4835483Simp 491590Srgrimes/*- 501590Srgrimes * job.c -- 511590Srgrimes * handle the creation etc. of our child processes. 521590Srgrimes * 531590Srgrimes * Interface: 541590Srgrimes * Job_Make Start the creation of the given target. 551590Srgrimes * 561590Srgrimes * Job_CatchChildren Check for and handle the termination of any 571590Srgrimes * children. This must be called reasonably 581590Srgrimes * frequently to keep the whole make going at 591590Srgrimes * a decent clip, since job table entries aren't 601590Srgrimes * removed until their process is caught this way. 611590Srgrimes * Its single argument is TRUE if the function 621590Srgrimes * should block waiting for a child to terminate. 631590Srgrimes * 641590Srgrimes * Job_CatchOutput Print any output our children have produced. 651590Srgrimes * Should also be called fairly frequently to 661590Srgrimes * keep the user informed of what's going on. 671590Srgrimes * If no output is waiting, it will block for 681590Srgrimes * a time given by the SEL_* constants, below, 691590Srgrimes * or until output is ready. 701590Srgrimes * 711590Srgrimes * Job_Init Called to intialize this module. in addition, 721590Srgrimes * any commands attached to the .BEGIN target 731590Srgrimes * are executed before this function returns. 741590Srgrimes * Hence, the makefile must have been parsed 751590Srgrimes * before this function is called. 761590Srgrimes * 771590Srgrimes * Job_Full Return TRUE if the job table is filled. 781590Srgrimes * 791590Srgrimes * Job_Empty Return TRUE if the job table is completely 801590Srgrimes * empty. 811590Srgrimes * 821590Srgrimes * Job_ParseShell Given the line following a .SHELL target, parse 831590Srgrimes * the line as a shell specification. Returns 841590Srgrimes * FAILURE if the spec was incorrect. 851590Srgrimes * 8694594Sobrien * Job_Finish Perform any final processing which needs doing. 871590Srgrimes * This includes the execution of any commands 881590Srgrimes * which have been/were attached to the .END 891590Srgrimes * target. It should only be called when the 901590Srgrimes * job table is empty. 911590Srgrimes * 921590Srgrimes * Job_AbortAll Abort all currently running jobs. It doesn't 931590Srgrimes * handle output or do anything for the jobs, 941590Srgrimes * just kills them. It should only be called in 951590Srgrimes * an emergency, as it were. 961590Srgrimes * 971590Srgrimes * Job_CheckCommands Verify that the commands for a target are 981590Srgrimes * ok. Provide them if necessary and possible. 991590Srgrimes * 1001590Srgrimes * Job_Touch Update a target without really updating it. 1011590Srgrimes * 1021590Srgrimes * Job_Wait Wait for all currently-running jobs to finish. 1031590Srgrimes */ 1041590Srgrimes 1051590Srgrimes#include <sys/types.h> 1061590Srgrimes#include <sys/stat.h> 1071590Srgrimes#include <sys/file.h> 1081590Srgrimes#include <sys/time.h> 109107447Sru#ifdef USE_KQUEUE 110104475Sphk#include <sys/event.h> 111107447Sru#endif 1121590Srgrimes#include <sys/wait.h> 11394506Scharnier#include <err.h> 11494506Scharnier#include <errno.h> 1155814Sjkh#include <fcntl.h> 1161590Srgrimes#include <stdio.h> 1171590Srgrimes#include <string.h> 1185814Sjkh#include <signal.h> 11980381Ssheldonh#include <unistd.h> 12094506Scharnier#include <utime.h> 1211590Srgrimes#include "make.h" 1221590Srgrimes#include "hash.h" 1231590Srgrimes#include "dir.h" 1241590Srgrimes#include "job.h" 1251590Srgrimes#include "pathnames.h" 1261590Srgrimes 127137202Sharti#define STATIC static 128137202Sharti 1291590Srgrimes/* 1308874Srgrimes * error handling variables 1311590Srgrimes */ 1321590Srgrimesstatic int errors = 0; /* number of errors reported */ 1331590Srgrimesstatic int aborting = 0; /* why is the make aborting? */ 134103503Sjmallett#define ABORT_ERROR 1 /* Because of an error */ 135103503Sjmallett#define ABORT_INTERRUPT 2 /* Because it was interrupted */ 136103503Sjmallett#define ABORT_WAIT 3 /* Waiting for jobs to finish */ 1371590Srgrimes 13818730Ssteve/* 13918730Ssteve * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file 14018730Ssteve * is a char! So when we go above 127 we turn negative! 14118730Ssteve */ 142103503Sjmallett#define FILENO(a) ((unsigned) fileno(a)) 1431590Srgrimes 1441590Srgrimes/* 1451590Srgrimes * post-make command processing. The node postCommands is really just the 1461590Srgrimes * .END target but we keep it around to avoid having to search for it 1471590Srgrimes * all the time. 1481590Srgrimes */ 1491590Srgrimesstatic GNode *postCommands; /* node containing commands to execute when 1501590Srgrimes * everything else is done */ 1511590Srgrimesstatic int numCommands; /* The number of commands actually printed 1521590Srgrimes * for a target. Should this number be 1531590Srgrimes * 0, no shell will be executed. */ 1541590Srgrimes 1551590Srgrimes/* 1561590Srgrimes * Return values from JobStart. 1571590Srgrimes */ 158103503Sjmallett#define JOB_RUNNING 0 /* Job is running */ 159103503Sjmallett#define JOB_ERROR 1 /* Error in starting the job */ 160103503Sjmallett#define JOB_FINISHED 2 /* The job is already finished */ 161103503Sjmallett#define JOB_STOPPED 3 /* The job is stopped */ 1621590Srgrimes 1631590Srgrimes/* 16468898Skris * tfile is used to build temp file names to store shell commands to 16568898Skris * execute. 16668898Skris */ 16768898Skrisstatic char tfile[sizeof(TMPPAT)]; 16868898Skris 16968898Skris 17068898Skris/* 1711590Srgrimes * Descriptions for various shells. 1721590Srgrimes */ 1731590Srgrimesstatic Shell shells[] = { 1741590Srgrimes /* 1751590Srgrimes * CSH description. The csh can do echo control by playing 1761590Srgrimes * with the setting of the 'echo' shell variable. Sadly, 1771590Srgrimes * however, it is unable to do error control nicely. 1781590Srgrimes */ 1791590Srgrimes{ 1801590Srgrimes "csh", 181136841Sru TRUE, "unset verbose", "set verbose", "unset verbose", 13, 1821590Srgrimes FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"", 1831590Srgrimes "v", "e", 1841590Srgrimes}, 1851590Srgrimes /* 1861590Srgrimes * SH description. Echo control is also possible and, under 1871590Srgrimes * sun UNIX anyway, one can even control error checking. 1881590Srgrimes */ 1891590Srgrimes{ 1901590Srgrimes "sh", 1911590Srgrimes TRUE, "set -", "set -v", "set -", 5, 19218730Ssteve TRUE, "set -e", "set +e", 19318730Ssteve#ifdef OLDBOURNESHELL 1941590Srgrimes FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", 19518730Ssteve#endif 1961590Srgrimes "v", "e", 1971590Srgrimes}, 1981590Srgrimes /* 19964739Sgreen * KSH description. The Korn shell has a superset of 20064739Sgreen * the Bourne shell's functionality. 20164739Sgreen */ 20264739Sgreen{ 20364739Sgreen "ksh", 20464739Sgreen TRUE, "set -", "set -v", "set -", 5, 20564739Sgreen TRUE, "set -e", "set +e", 20664739Sgreen "v", "e", 20764739Sgreen}, 20864739Sgreen /* 2091590Srgrimes * UNKNOWN. 2101590Srgrimes */ 2111590Srgrimes{ 21218730Ssteve (char *) 0, 21318730Ssteve FALSE, (char *) 0, (char *) 0, (char *) 0, 0, 21418730Ssteve FALSE, (char *) 0, (char *) 0, 21518730Ssteve (char *) 0, (char *) 0, 2161590Srgrimes} 2171590Srgrimes}; 2181590Srgrimesstatic Shell *commandShell = &shells[DEFSHELL];/* this is the shell to 2191590Srgrimes * which we pass all 2201590Srgrimes * commands in the Makefile. 2211590Srgrimes * It is set by the 2221590Srgrimes * Job_ParseShell function */ 223136840Sruchar *shellPath = NULL, /* full pathname of 2241590Srgrimes * executable image */ 225136840Sru *shellName = NULL; /* last component of shell */ 2261590Srgrimes 2271590Srgrimes 2281590Srgrimesstatic int maxJobs; /* The most children we can run at once */ 2291590Srgrimesstatic int maxLocal; /* The most local ones we can have */ 23018730SsteveSTATIC int nJobs; /* The number of children currently running */ 23118730SsteveSTATIC int nLocal; /* The number of local children */ 23218730SsteveSTATIC Lst jobs; /* The structures that describe them */ 23318730SsteveSTATIC Boolean jobFull; /* Flag to tell when the job table is full. It 2341590Srgrimes * is set TRUE when (1) the total number of 2351590Srgrimes * running jobs equals the maximum allowed or 2361590Srgrimes * (2) a job can only be run locally, but 2371590Srgrimes * nLocal equals maxLocal */ 238104475Sphk#ifdef USE_KQUEUE 239104475Sphkstatic int kqfd; /* File descriptor obtained by kqueue() */ 240104475Sphk#else 2411590Srgrimesstatic fd_set outputs; /* Set of descriptors of pipes connected to 2421590Srgrimes * the output channels of children */ 2431590Srgrimes#endif 2441590Srgrimes 24518730SsteveSTATIC GNode *lastNode; /* The node for which output was most recently 2461590Srgrimes * produced. */ 24718730SsteveSTATIC char *targFmt; /* Format string to use to head output from a 2481590Srgrimes * job when it's not the most-recent job heard 2491590Srgrimes * from */ 2501590Srgrimes 251137202Sharti#define TARG_FMT "--- %s ---\n" /* Default format */ 252137202Sharti#define MESSAGE(fp, gn) \ 25318730Ssteve (void) fprintf(fp, targFmt, gn->name); 25418730Ssteve 2551590Srgrimes/* 256137252Sharti * When JobStart attempts to run a job but isn't allowed to 257137252Sharti * or when Job_CatchChildren detects a job that has 258137252Sharti * been stopped somehow, the job is placed on the stoppedJobs queue to be run 2598874Srgrimes * when the next job finishes. 2601590Srgrimes */ 26118730SsteveSTATIC Lst stoppedJobs; /* Lst of Job structures describing 2621590Srgrimes * jobs that were stopped due to concurrency 263137252Sharti * limits or externally */ 2641590Srgrimes 2651590Srgrimes 2661590Srgrimes#if defined(USE_PGRP) && defined(SYSV) 26718730Ssteve# define KILL(pid, sig) killpg(-(pid), (sig)) 2681590Srgrimes#else 2691590Srgrimes# if defined(USE_PGRP) 27018730Ssteve# define KILL(pid, sig) killpg((pid), (sig)) 2711590Srgrimes# else 27218730Ssteve# define KILL(pid, sig) kill((pid), (sig)) 2731590Srgrimes# endif 2741590Srgrimes#endif 2751590Srgrimes 27618730Ssteve/* 27718730Ssteve * Grmpf... There is no way to set bits of the wait structure 27818730Ssteve * anymore with the stupid W*() macros. I liked the union wait 27918730Ssteve * stuff much more. So, we devise our own macros... This is 28018730Ssteve * really ugly, use dramamine sparingly. You have been warned. 28118730Ssteve */ 282103503Sjmallett#define W_SETMASKED(st, val, fun) \ 28318730Ssteve { \ 28418730Ssteve int sh = (int) ~0; \ 28518730Ssteve int mask = fun(sh); \ 28618730Ssteve \ 28718730Ssteve for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \ 28818730Ssteve continue; \ 28918730Ssteve *(st) = (*(st) & ~mask) | ((val) << sh); \ 29018730Ssteve } 29118730Ssteve 292103503Sjmallett#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) 293103503Sjmallett#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) 29418730Ssteve 29518730Ssteve 29692921Simpstatic int JobCondPassSig(void *, void *); 29792921Simpstatic void JobPassSig(int); 29892921Simpstatic int JobCmpPid(void *, void *); 29992921Simpstatic int JobPrintCommand(void *, void *); 30092921Simpstatic int JobSaveCommand(void *, void *); 30192921Simpstatic void JobClose(Job *); 30292921Simpstatic void JobFinish(Job *, int *); 30392921Simpstatic void JobExec(Job *, char **); 30492921Simpstatic void JobMakeArgv(Job *, char **); 30592921Simpstatic void JobRestart(Job *); 30692921Simpstatic int JobStart(GNode *, int, Job *); 30792921Simpstatic char *JobOutput(Job *, char *, char *, int); 30892921Simpstatic void JobDoOutput(Job *, Boolean); 30992921Simpstatic Shell *JobMatchShell(char *); 31092921Simpstatic void JobInterrupt(int, int); 31192921Simpstatic void JobRestartJobs(void); 3121590Srgrimes 3131590Srgrimes/*- 3141590Srgrimes *----------------------------------------------------------------------- 3151590Srgrimes * JobCondPassSig -- 316137252Sharti * Pass a signal to a job if USE_PGRP is defined. 3171590Srgrimes * 3181590Srgrimes * Results: 3191590Srgrimes * === 0 3201590Srgrimes * 3211590Srgrimes * Side Effects: 3221590Srgrimes * None, except the job may bite it. 3231590Srgrimes * 3241590Srgrimes *----------------------------------------------------------------------- 3251590Srgrimes */ 3261590Srgrimesstatic int 327104696SjmallettJobCondPassSig(void *jobp, void *signop) 3281590Srgrimes{ 3295814Sjkh Job *job = (Job *) jobp; 3305814Sjkh int signo = *(int *) signop; 331137202Sharti 332137252Sharti DEBUGF(JOB, ("JobCondPassSig passing signal %d to child %d.\n", 333137252Sharti signo, job->pid)); 3341590Srgrimes KILL(job->pid, signo); 33518730Ssteve return 0; 3361590Srgrimes} 3371590Srgrimes 3381590Srgrimes/*- 3391590Srgrimes *----------------------------------------------------------------------- 3401590Srgrimes * JobPassSig -- 341137252Sharti * Pass a signal on to all local jobs if 3421590Srgrimes * USE_PGRP is defined, then die ourselves. 3431590Srgrimes * 3441590Srgrimes * Results: 3451590Srgrimes * None. 3461590Srgrimes * 3471590Srgrimes * Side Effects: 3481590Srgrimes * We die by the same signal. 3498874Srgrimes * 3501590Srgrimes *----------------------------------------------------------------------- 3511590Srgrimes */ 3521590Srgrimesstatic void 353104696SjmallettJobPassSig(int signo) 3541590Srgrimes{ 35518730Ssteve sigset_t nmask, omask; 35618730Ssteve struct sigaction act; 3578874Srgrimes 358103545Sjmallett DEBUGF(JOB, ("JobPassSig(%d) called.\n", signo)); 35969531Swill Lst_ForEach(jobs, JobCondPassSig, (void *) &signo); 3601590Srgrimes 3611590Srgrimes /* 3621590Srgrimes * Deal with proper cleanup based on the signal received. We only run 3631590Srgrimes * the .INTERRUPT target if the signal was in fact an interrupt. The other 3641590Srgrimes * three termination signals are more of a "get out *now*" command. 3651590Srgrimes */ 3661590Srgrimes if (signo == SIGINT) { 36718730Ssteve JobInterrupt(TRUE, signo); 3681590Srgrimes } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { 36918730Ssteve JobInterrupt(FALSE, signo); 3701590Srgrimes } 3718874Srgrimes 3721590Srgrimes /* 3731590Srgrimes * Leave gracefully if SIGQUIT, rather than core dumping. 3741590Srgrimes */ 3751590Srgrimes if (signo == SIGQUIT) { 37638520Scracauer signo = SIGINT; 3771590Srgrimes } 3788874Srgrimes 3791590Srgrimes /* 3801590Srgrimes * Send ourselves the signal now we've given the message to everyone else. 3811590Srgrimes * Note we block everything else possible while we're getting the signal. 3821590Srgrimes * This ensures that all our jobs get continued when we wake up before 3831590Srgrimes * we take any other signal. 3841590Srgrimes */ 38518730Ssteve sigemptyset(&nmask); 38618730Ssteve sigaddset(&nmask, signo); 38718730Ssteve sigprocmask(SIG_SETMASK, &nmask, &omask); 38818730Ssteve act.sa_handler = SIG_DFL; 38918730Ssteve sigemptyset(&act.sa_mask); 39018730Ssteve act.sa_flags = 0; 39118730Ssteve sigaction(signo, &act, NULL); 3921590Srgrimes 393103545Sjmallett DEBUGF(JOB, ("JobPassSig passing signal to self, mask = %x.\n", ~0 & ~(1 << (signo-1)))); 39418730Ssteve (void) signal(signo, SIG_DFL); 3951590Srgrimes 39618730Ssteve (void) KILL(getpid(), signo); 39718730Ssteve 3985814Sjkh signo = SIGCONT; 39969531Swill Lst_ForEach(jobs, JobCondPassSig, (void *) &signo); 4001590Srgrimes 40118730Ssteve (void) sigprocmask(SIG_SETMASK, &omask, NULL); 40218730Ssteve sigprocmask(SIG_SETMASK, &omask, NULL); 40318730Ssteve act.sa_handler = JobPassSig; 40418730Ssteve sigaction(signo, &act, NULL); 4051590Srgrimes} 4061590Srgrimes 4071590Srgrimes/*- 4081590Srgrimes *----------------------------------------------------------------------- 4091590Srgrimes * JobCmpPid -- 4101590Srgrimes * Compare the pid of the job with the given pid and return 0 if they 4111590Srgrimes * are equal. This function is called from Job_CatchChildren via 4121590Srgrimes * Lst_Find to find the job descriptor of the finished job. 4131590Srgrimes * 4141590Srgrimes * Results: 4151590Srgrimes * 0 if the pid's match 4161590Srgrimes * 4171590Srgrimes * Side Effects: 4181590Srgrimes * None 4191590Srgrimes *----------------------------------------------------------------------- 4201590Srgrimes */ 4211590Srgrimesstatic int 422104696SjmallettJobCmpPid(void *job, void *pid) 4231590Srgrimes{ 42418730Ssteve return *(int *) pid - ((Job *) job)->pid; 4251590Srgrimes} 4261590Srgrimes 4271590Srgrimes/*- 4281590Srgrimes *----------------------------------------------------------------------- 4291590Srgrimes * JobPrintCommand -- 4301590Srgrimes * Put out another command for the given job. If the command starts 4311590Srgrimes * with an @ or a - we process it specially. In the former case, 4321590Srgrimes * so long as the -s and -n flags weren't given to make, we stick 4331590Srgrimes * a shell-specific echoOff command in the script. In the latter, 4341590Srgrimes * we ignore errors for the entire job, unless the shell has error 4351590Srgrimes * control. 4361590Srgrimes * If the command is just "..." we take all future commands for this 4371590Srgrimes * job to be commands to be executed once the entire graph has been 4381590Srgrimes * made and return non-zero to signal that the end of the commands 4391590Srgrimes * was reached. These commands are later attached to the postCommands 44094594Sobrien * node and executed by Job_Finish when all things are done. 4411590Srgrimes * This function is called from JobStart via Lst_ForEach. 4421590Srgrimes * 4431590Srgrimes * Results: 4441590Srgrimes * Always 0, unless the command was "..." 4451590Srgrimes * 4461590Srgrimes * Side Effects: 4471590Srgrimes * If the command begins with a '-' and the shell has no error control, 4481590Srgrimes * the JOB_IGNERR flag is set in the job descriptor. 4491590Srgrimes * If the command is "..." and we're not ignoring such things, 4501590Srgrimes * tailCmds is set to the successor node of the cmd. 4511590Srgrimes * numCommands is incremented if the command is actually printed. 4521590Srgrimes *----------------------------------------------------------------------- 4531590Srgrimes */ 4541590Srgrimesstatic int 455104696SjmallettJobPrintCommand(void *cmdp, void *jobp) 4561590Srgrimes{ 4571590Srgrimes Boolean noSpecials; /* true if we shouldn't worry about 4581590Srgrimes * inserting special commands into 4591590Srgrimes * the input stream. */ 4601590Srgrimes Boolean shutUp = FALSE; /* true if we put a no echo command 4611590Srgrimes * into the command file */ 4621590Srgrimes Boolean errOff = FALSE; /* true if we turned error checking 4631590Srgrimes * off before printing the command 4641590Srgrimes * and need to turn it back on */ 4651590Srgrimes char *cmdTemplate; /* Template to use when printing the 4661590Srgrimes * command */ 4671590Srgrimes char *cmdStart; /* Start of expanded command */ 4681590Srgrimes LstNode cmdNode; /* Node for replacing the command */ 4695814Sjkh char *cmd = (char *) cmdp; 4708874Srgrimes Job *job = (Job *) jobp; 4711590Srgrimes 47218730Ssteve noSpecials = (noExecute && !(job->node->type & OP_MAKE)); 4731590Srgrimes 47418730Ssteve if (strcmp(cmd, "...") == 0) { 4758874Srgrimes job->node->type |= OP_SAVE_CMDS; 4761590Srgrimes if ((job->flags & JOB_IGNDOTS) == 0) { 47718730Ssteve job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, 47869531Swill (void *)cmd)); 47918730Ssteve return 1; 4801590Srgrimes } 48118730Ssteve return 0; 4821590Srgrimes } 4831590Srgrimes 484103508Sjmallett#define DBPRINTF(fmt, arg) \ 485103545Sjmallett DEBUGF(JOB, (fmt, arg)); \ 48618730Ssteve (void) fprintf(job->cmdFILE, fmt, arg); \ 48718730Ssteve (void) fflush(job->cmdFILE); 4881590Srgrimes 4891590Srgrimes numCommands += 1; 4901590Srgrimes 4911590Srgrimes /* 4921590Srgrimes * For debugging, we replace each command with the result of expanding 4931590Srgrimes * the variables in the command. 4941590Srgrimes */ 49569531Swill cmdNode = Lst_Member(job->node->commands, (void *)cmd); 49618730Ssteve cmdStart = cmd = Var_Subst(NULL, cmd, job->node, FALSE); 49769531Swill Lst_Replace(cmdNode, (void *)cmdStart); 4981590Srgrimes 4991590Srgrimes cmdTemplate = "%s\n"; 5001590Srgrimes 5011590Srgrimes /* 502132839Sharti * Check for leading @', -' or +'s to control echoing, error checking, 503132839Sharti * and execution on -n. 5041590Srgrimes */ 505132839Sharti while (*cmd == '@' || *cmd == '-' || *cmd == '+') { 506132839Sharti switch (*cmd) { 507132839Sharti 508132839Sharti case '@': 50960569Swill shutUp = DEBUG(LOUD) ? FALSE : TRUE; 510132839Sharti break; 511132839Sharti 512132839Sharti case '-': 5131590Srgrimes errOff = TRUE; 514132839Sharti break; 515132839Sharti 516132839Sharti case '+': 517132839Sharti if (noSpecials) { 518132839Sharti /* 519132839Sharti * We're not actually exececuting anything... 520132839Sharti * but this one needs to be - use compat mode just for it. 521132839Sharti */ 522132839Sharti Compat_RunCommand(cmdp, job->node); 523132839Sharti return (0); 524132839Sharti } 525132839Sharti break; 5261590Srgrimes } 5271590Srgrimes cmd++; 5281590Srgrimes } 5291590Srgrimes 5301590Srgrimes while (isspace((unsigned char) *cmd)) 5311590Srgrimes cmd++; 5321590Srgrimes 5331590Srgrimes if (shutUp) { 53418730Ssteve if (!(job->flags & JOB_SILENT) && !noSpecials && 5351590Srgrimes commandShell->hasEchoCtl) { 53618730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 5371590Srgrimes } else { 5381590Srgrimes shutUp = FALSE; 5391590Srgrimes } 5401590Srgrimes } 5411590Srgrimes 5421590Srgrimes if (errOff) { 54318730Ssteve if ( !(job->flags & JOB_IGNERR) && !noSpecials) { 5441590Srgrimes if (commandShell->hasErrCtl) { 5451590Srgrimes /* 5461590Srgrimes * we don't want the error-control commands showing 5471590Srgrimes * up either, so we turn off echoing while executing 5481590Srgrimes * them. We could put another field in the shell 5491590Srgrimes * structure to tell JobDoOutput to look for this 5501590Srgrimes * string too, but why make it any more complex than 5511590Srgrimes * it already is? 5521590Srgrimes */ 55318730Ssteve if (!(job->flags & JOB_SILENT) && !shutUp && 5541590Srgrimes commandShell->hasEchoCtl) { 55518730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 55618730Ssteve DBPRINTF("%s\n", commandShell->ignErr); 55718730Ssteve DBPRINTF("%s\n", commandShell->echoOn); 5581590Srgrimes } else { 55918730Ssteve DBPRINTF("%s\n", commandShell->ignErr); 5601590Srgrimes } 5611590Srgrimes } else if (commandShell->ignErr && 56218730Ssteve (*commandShell->ignErr != '\0')) 5631590Srgrimes { 5641590Srgrimes /* 5651590Srgrimes * The shell has no error control, so we need to be 5661590Srgrimes * weird to get it to ignore any errors from the command. 5671590Srgrimes * If echoing is turned on, we turn it off and use the 5681590Srgrimes * errCheck template to echo the command. Leave echoing 5691590Srgrimes * off so the user doesn't see the weirdness we go through 5701590Srgrimes * to ignore errors. Set cmdTemplate to use the weirdness 5711590Srgrimes * instead of the simple "%s\n" template. 5721590Srgrimes */ 57318730Ssteve if (!(job->flags & JOB_SILENT) && !shutUp && 5741590Srgrimes commandShell->hasEchoCtl) { 57518730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 57618730Ssteve DBPRINTF(commandShell->errCheck, cmd); 5771590Srgrimes shutUp = TRUE; 5781590Srgrimes } 5791590Srgrimes cmdTemplate = commandShell->ignErr; 5801590Srgrimes /* 5811590Srgrimes * The error ignoration (hee hee) is already taken care 5821590Srgrimes * of by the ignErr template, so pretend error checking 5831590Srgrimes * is still on. 5841590Srgrimes */ 5851590Srgrimes errOff = FALSE; 5861590Srgrimes } else { 5871590Srgrimes errOff = FALSE; 5881590Srgrimes } 5891590Srgrimes } else { 5901590Srgrimes errOff = FALSE; 5911590Srgrimes } 5921590Srgrimes } 5938874Srgrimes 59418730Ssteve DBPRINTF(cmdTemplate, cmd); 5958874Srgrimes 5961590Srgrimes if (errOff) { 5971590Srgrimes /* 5981590Srgrimes * If echoing is already off, there's no point in issuing the 5991590Srgrimes * echoOff command. Otherwise we issue it and pretend it was on 6001590Srgrimes * for the whole command... 6011590Srgrimes */ 6021590Srgrimes if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ 60318730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 6041590Srgrimes shutUp = TRUE; 6051590Srgrimes } 60618730Ssteve DBPRINTF("%s\n", commandShell->errCheck); 6071590Srgrimes } 6081590Srgrimes if (shutUp) { 60918730Ssteve DBPRINTF("%s\n", commandShell->echoOn); 6101590Srgrimes } 61118730Ssteve return 0; 6121590Srgrimes} 6131590Srgrimes 6141590Srgrimes/*- 6151590Srgrimes *----------------------------------------------------------------------- 6161590Srgrimes * JobSaveCommand -- 6171590Srgrimes * Save a command to be executed when everything else is done. 6181590Srgrimes * Callback function for JobFinish... 6191590Srgrimes * 6201590Srgrimes * Results: 6211590Srgrimes * Always returns 0 6221590Srgrimes * 6231590Srgrimes * Side Effects: 6241590Srgrimes * The command is tacked onto the end of postCommands's commands list. 6251590Srgrimes * 6261590Srgrimes *----------------------------------------------------------------------- 6271590Srgrimes */ 6281590Srgrimesstatic int 629104696SjmallettJobSaveCommand(void *cmd, void *gn) 6301590Srgrimes{ 63169531Swill cmd = (void *) Var_Subst(NULL, (char *) cmd, (GNode *) gn, FALSE); 63218730Ssteve (void) Lst_AtEnd(postCommands->commands, cmd); 63318730Ssteve return(0); 6341590Srgrimes} 6351590Srgrimes 63618730Ssteve 6371590Srgrimes/*- 6381590Srgrimes *----------------------------------------------------------------------- 63918730Ssteve * JobClose -- 64018730Ssteve * Called to close both input and output pipes when a job is finished. 64118730Ssteve * 64218730Ssteve * Results: 64318730Ssteve * Nada 64418730Ssteve * 64518730Ssteve * Side Effects: 64618730Ssteve * The file descriptors associated with the job are closed. 64718730Ssteve * 64818730Ssteve *----------------------------------------------------------------------- 64918730Ssteve */ 65018730Sstevestatic void 651104696SjmallettJobClose(Job *job) 65218730Ssteve{ 65318730Ssteve if (usePipes) { 654137202Sharti#if !defined(USE_KQUEUE) 65518730Ssteve FD_CLR(job->inPipe, &outputs); 65618730Ssteve#endif 65718730Ssteve if (job->outPipe != job->inPipe) { 65818730Ssteve (void) close(job->outPipe); 65918730Ssteve } 66018730Ssteve JobDoOutput(job, TRUE); 66118730Ssteve (void) close(job->inPipe); 66218730Ssteve } else { 66318730Ssteve (void) close(job->outFd); 66418730Ssteve JobDoOutput(job, TRUE); 66518730Ssteve } 66618730Ssteve} 66718730Ssteve 66818730Ssteve/*- 66918730Ssteve *----------------------------------------------------------------------- 6701590Srgrimes * JobFinish -- 6711590Srgrimes * Do final processing for the given job including updating 6721590Srgrimes * parents and starting new jobs as available/necessary. Note 6731590Srgrimes * that we pay no attention to the JOB_IGNERR flag here. 6741590Srgrimes * This is because when we're called because of a noexecute flag 6751590Srgrimes * or something, jstat.w_status is 0 and when called from 6761590Srgrimes * Job_CatchChildren, the status is zeroed if it s/b ignored. 6771590Srgrimes * 6781590Srgrimes * Results: 6791590Srgrimes * None 6801590Srgrimes * 6811590Srgrimes * Side Effects: 6821590Srgrimes * Some nodes may be put on the toBeMade queue. 6831590Srgrimes * Final commands for the job are placed on postCommands. 6841590Srgrimes * 6851590Srgrimes * If we got an error and are aborting (aborting == ABORT_ERROR) and 6861590Srgrimes * the job list is now empty, we are done for the day. 6871590Srgrimes * If we recognized an error (errors !=0), we set the aborting flag 6881590Srgrimes * to ABORT_ERROR so no more jobs will be started. 6891590Srgrimes *----------------------------------------------------------------------- 6901590Srgrimes */ 6911590Srgrimes/*ARGSUSED*/ 6921590Srgrimesstatic void 693104696SjmallettJobFinish(Job *job, int *status) 6941590Srgrimes{ 69518730Ssteve Boolean done; 6961590Srgrimes 69718730Ssteve if ((WIFEXITED(*status) && 69818730Ssteve (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || 69918730Ssteve (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) 7001590Srgrimes { 7011590Srgrimes /* 7021590Srgrimes * If it exited non-zero and either we're doing things our 7031590Srgrimes * way or we're not ignoring errors, the job is finished. 7041590Srgrimes * Similarly, if the shell died because of a signal 7051590Srgrimes * the job is also finished. In these 7061590Srgrimes * cases, finish out the job's output before printing the exit 7071590Srgrimes * status... 7081590Srgrimes */ 70918730Ssteve JobClose(job); 7101590Srgrimes if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 71118730Ssteve (void) fclose(job->cmdFILE); 7121590Srgrimes } 7131590Srgrimes done = TRUE; 71418730Ssteve } else if (WIFEXITED(*status)) { 7151590Srgrimes /* 7161590Srgrimes * Deal with ignored errors in -B mode. We need to print a message 7171590Srgrimes * telling of the ignored error as well as setting status.w_status 7181590Srgrimes * to 0 so the next command gets run. To do this, we set done to be 71918730Ssteve * TRUE if in -B mode and the job exited non-zero. 72018730Ssteve */ 72118730Ssteve done = WEXITSTATUS(*status) != 0; 72218730Ssteve /* 72318730Ssteve * Old comment said: "Note we don't 7241590Srgrimes * want to close down any of the streams until we know we're at the 72518730Ssteve * end." 72618730Ssteve * But we do. Otherwise when are we going to print the rest of the 72718730Ssteve * stuff? 7281590Srgrimes */ 72918730Ssteve JobClose(job); 7301590Srgrimes } else { 7311590Srgrimes /* 7321590Srgrimes * No need to close things down or anything. 7331590Srgrimes */ 7341590Srgrimes done = FALSE; 7351590Srgrimes } 7368874Srgrimes 7371590Srgrimes if (done || 73818730Ssteve WIFSTOPPED(*status) || 73918730Ssteve (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) || 7401590Srgrimes DEBUG(JOB)) 7411590Srgrimes { 7421590Srgrimes FILE *out; 7438874Srgrimes 74418730Ssteve if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { 7451590Srgrimes /* 7461590Srgrimes * If output is going to a file and this job is ignoring 7471590Srgrimes * errors, arrange to have the exit status sent to the 7481590Srgrimes * output file as well. 7491590Srgrimes */ 75018730Ssteve out = fdopen(job->outFd, "w"); 75194582Sobrien if (out == NULL) 75294582Sobrien Punt("Cannot fdopen"); 7531590Srgrimes } else { 7541590Srgrimes out = stdout; 7551590Srgrimes } 7561590Srgrimes 75718730Ssteve if (WIFEXITED(*status)) { 758103545Sjmallett DEBUGF(JOB, ("Process %d exited.\n", job->pid)); 75918730Ssteve if (WEXITSTATUS(*status) != 0) { 7601590Srgrimes if (usePipes && job->node != lastNode) { 76118730Ssteve MESSAGE(out, job->node); 7621590Srgrimes lastNode = job->node; 7631590Srgrimes } 76418730Ssteve (void) fprintf(out, "*** Error code %d%s\n", 76518730Ssteve WEXITSTATUS(*status), 76618730Ssteve (job->flags & JOB_IGNERR) ? "(ignored)" : ""); 7671590Srgrimes 7681590Srgrimes if (job->flags & JOB_IGNERR) { 76918730Ssteve *status = 0; 7701590Srgrimes } 7711590Srgrimes } else if (DEBUG(JOB)) { 7721590Srgrimes if (usePipes && job->node != lastNode) { 77318730Ssteve MESSAGE(out, job->node); 7741590Srgrimes lastNode = job->node; 7751590Srgrimes } 77618730Ssteve (void) fprintf(out, "*** Completed successfully\n"); 7771590Srgrimes } 77818730Ssteve } else if (WIFSTOPPED(*status)) { 779103545Sjmallett DEBUGF(JOB, ("Process %d stopped.\n", job->pid)); 7801590Srgrimes if (usePipes && job->node != lastNode) { 78118730Ssteve MESSAGE(out, job->node); 7821590Srgrimes lastNode = job->node; 7831590Srgrimes } 784137252Sharti (void) fprintf(out, "*** Stopped -- signal %d\n", 785137252Sharti WSTOPSIG(*status)); 7861590Srgrimes job->flags |= JOB_RESUME; 78769531Swill (void)Lst_AtEnd(stoppedJobs, (void *)job); 78818730Ssteve (void) fflush(out); 7891590Srgrimes return; 79018730Ssteve } else if (WTERMSIG(*status) == SIGCONT) { 7911590Srgrimes /* 7921590Srgrimes * If the beastie has continued, shift the Job from the stopped 7931590Srgrimes * list to the running one (or re-stop it if concurrency is 7941590Srgrimes * exceeded) and go and get another child. 7951590Srgrimes */ 796137252Sharti if (job->flags & (JOB_RESUME|JOB_RESTART)) { 7971590Srgrimes if (usePipes && job->node != lastNode) { 79818730Ssteve MESSAGE(out, job->node); 7991590Srgrimes lastNode = job->node; 8001590Srgrimes } 80118730Ssteve (void) fprintf(out, "*** Continued\n"); 8021590Srgrimes } 80318730Ssteve if (!(job->flags & JOB_CONTINUING)) { 804103545Sjmallett DEBUGF(JOB, ("Warning: process %d was not continuing.\n", job->pid)); 80518730Ssteve#ifdef notdef 80618730Ssteve /* 80718730Ssteve * We don't really want to restart a job from scratch just 80818730Ssteve * because it continued, especially not without killing the 80918730Ssteve * continuing process! That's why this is ifdef'ed out. 81018730Ssteve * FD - 9/17/90 81118730Ssteve */ 8121590Srgrimes JobRestart(job); 81318730Ssteve#endif 8141590Srgrimes } 81518730Ssteve job->flags &= ~JOB_CONTINUING; 81669531Swill Lst_AtEnd(jobs, (void *)job); 81718730Ssteve nJobs += 1; 818137252Sharti DEBUGF(JOB, ("Process %d is continuing locally.\n", job->pid)); 819137252Sharti nLocal += 1; 82018730Ssteve if (nJobs == maxJobs) { 82118730Ssteve jobFull = TRUE; 822103545Sjmallett DEBUGF(JOB, ("Job queue is full.\n")); 82318730Ssteve } 82418730Ssteve (void) fflush(out); 82518730Ssteve return; 8261590Srgrimes } else { 8271590Srgrimes if (usePipes && job->node != lastNode) { 82818730Ssteve MESSAGE(out, job->node); 8291590Srgrimes lastNode = job->node; 8301590Srgrimes } 83118730Ssteve (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); 8321590Srgrimes } 8331590Srgrimes 83418730Ssteve (void) fflush(out); 8351590Srgrimes } 8361590Srgrimes 8371590Srgrimes /* 8381590Srgrimes * Now handle the -B-mode stuff. If the beast still isn't finished, 8391590Srgrimes * try and restart the job on the next command. If JobStart says it's 8401590Srgrimes * ok, it's ok. If there's an error, this puppy is done. 8411590Srgrimes */ 84218730Ssteve if (compatMake && (WIFEXITED(*status) && 84318730Ssteve !Lst_IsAtEnd(job->node->commands))) { 84418730Ssteve switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { 84518730Ssteve case JOB_RUNNING: 84618730Ssteve done = FALSE; 84718730Ssteve break; 84818730Ssteve case JOB_ERROR: 84918730Ssteve done = TRUE; 85018730Ssteve W_SETEXITSTATUS(status, 1); 85118730Ssteve break; 85218730Ssteve case JOB_FINISHED: 85318730Ssteve /* 85418730Ssteve * If we got back a JOB_FINISHED code, JobStart has already 85518730Ssteve * called Make_Update and freed the job descriptor. We set 85618730Ssteve * done to false here to avoid fake cycles and double frees. 85718730Ssteve * JobStart needs to do the update so we can proceed up the 85818730Ssteve * graph when given the -n flag.. 85918730Ssteve */ 86018730Ssteve done = FALSE; 86118730Ssteve break; 862104108Sjmallett default: 863104108Sjmallett break; 8641590Srgrimes } 8651590Srgrimes } else { 8661590Srgrimes done = TRUE; 8671590Srgrimes } 8681590Srgrimes 8698874Srgrimes 8701590Srgrimes if (done && 8711590Srgrimes (aborting != ABORT_ERROR) && 8721590Srgrimes (aborting != ABORT_INTERRUPT) && 87318730Ssteve (*status == 0)) 8741590Srgrimes { 8751590Srgrimes /* 8761590Srgrimes * As long as we aren't aborting and the job didn't return a non-zero 8771590Srgrimes * status that we shouldn't ignore, we call Make_Update to update 8781590Srgrimes * the parents. In addition, any saved commands for the node are placed 8791590Srgrimes * on the .END target. 8801590Srgrimes */ 88169527Swill if (job->tailCmds != NULL) { 88218730Ssteve Lst_ForEachFrom(job->node->commands, job->tailCmds, 8831590Srgrimes JobSaveCommand, 88469531Swill (void *)job->node); 8851590Srgrimes } 8861590Srgrimes job->node->made = MADE; 88718730Ssteve Make_Update(job->node); 88869531Swill free(job); 88918730Ssteve } else if (*status != 0) { 8901590Srgrimes errors += 1; 89169531Swill free(job); 8921590Srgrimes } 8931590Srgrimes 89418730Ssteve JobRestartJobs(); 8951590Srgrimes 8961590Srgrimes /* 8971590Srgrimes * Set aborting if any error. 8981590Srgrimes */ 8991590Srgrimes if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { 9001590Srgrimes /* 9011590Srgrimes * If we found any errors in this batch of children and the -k flag 9021590Srgrimes * wasn't given, we set the aborting flag so no more jobs get 9031590Srgrimes * started. 9041590Srgrimes */ 9051590Srgrimes aborting = ABORT_ERROR; 9061590Srgrimes } 9078874Srgrimes 90868898Skris if ((aborting == ABORT_ERROR) && Job_Empty()) 9091590Srgrimes /* 9101590Srgrimes * If we are aborting and the job table is now empty, we finish. 9111590Srgrimes */ 91218730Ssteve Finish(errors); 9131590Srgrimes} 9141590Srgrimes 9151590Srgrimes/*- 9161590Srgrimes *----------------------------------------------------------------------- 9171590Srgrimes * Job_Touch -- 9181590Srgrimes * Touch the given target. Called by JobStart when the -t flag was 919104696Sjmallett * given. Prints messages unless told to be silent. 9201590Srgrimes * 9211590Srgrimes * Results: 9221590Srgrimes * None 9231590Srgrimes * 9241590Srgrimes * Side Effects: 9251590Srgrimes * The data modification of the file is changed. In addition, if the 9261590Srgrimes * file did not exist, it is created. 9271590Srgrimes *----------------------------------------------------------------------- 9281590Srgrimes */ 9291590Srgrimesvoid 930104696SjmallettJob_Touch(GNode *gn, Boolean silent) 9311590Srgrimes{ 9321590Srgrimes int streamID; /* ID of stream opened to do the touch */ 93318730Ssteve struct utimbuf times; /* Times for utime() call */ 9341590Srgrimes 9351590Srgrimes if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { 9361590Srgrimes /* 9371590Srgrimes * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets 9381590Srgrimes * and, as such, shouldn't really be created. 9391590Srgrimes */ 9401590Srgrimes return; 9411590Srgrimes } 9428874Srgrimes 9431590Srgrimes if (!silent) { 94418730Ssteve (void) fprintf(stdout, "touch %s\n", gn->name); 94518730Ssteve (void) fflush(stdout); 9461590Srgrimes } 9471590Srgrimes 9481590Srgrimes if (noExecute) { 9491590Srgrimes return; 9501590Srgrimes } 9511590Srgrimes 9521590Srgrimes if (gn->type & OP_ARCHV) { 95318730Ssteve Arch_Touch(gn); 9541590Srgrimes } else if (gn->type & OP_LIB) { 95518730Ssteve Arch_TouchLib(gn); 9561590Srgrimes } else { 9571590Srgrimes char *file = gn->path ? gn->path : gn->name; 9581590Srgrimes 95918730Ssteve times.actime = times.modtime = now; 96018730Ssteve if (utime(file, ×) < 0){ 96118730Ssteve streamID = open(file, O_RDWR | O_CREAT, 0666); 9621590Srgrimes 9631590Srgrimes if (streamID >= 0) { 9641590Srgrimes char c; 9651590Srgrimes 9661590Srgrimes /* 9671590Srgrimes * Read and write a byte to the file to change the 9681590Srgrimes * modification time, then close the file. 9691590Srgrimes */ 9701590Srgrimes if (read(streamID, &c, 1) == 1) { 97194506Scharnier (void) lseek(streamID, (off_t)0, SEEK_SET); 97218730Ssteve (void) write(streamID, &c, 1); 9731590Srgrimes } 9748874Srgrimes 97518730Ssteve (void) close(streamID); 97618730Ssteve } else { 97718730Ssteve (void) fprintf(stdout, "*** couldn't touch %s: %s", 97818730Ssteve file, strerror(errno)); 97918730Ssteve (void) fflush(stdout); 98018730Ssteve } 9811590Srgrimes } 9821590Srgrimes } 9831590Srgrimes} 9841590Srgrimes 9851590Srgrimes/*- 9861590Srgrimes *----------------------------------------------------------------------- 9871590Srgrimes * Job_CheckCommands -- 9888874Srgrimes * Make sure the given node has all the commands it needs. 9891590Srgrimes * 9901590Srgrimes * Results: 9911590Srgrimes * TRUE if the commands list is/was ok. 9921590Srgrimes * 9931590Srgrimes * Side Effects: 9941590Srgrimes * The node will have commands from the .DEFAULT rule added to it 9951590Srgrimes * if it needs them. 9961590Srgrimes *----------------------------------------------------------------------- 9971590Srgrimes */ 9981590SrgrimesBoolean 999104696SjmallettJob_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) 10001590Srgrimes{ 100118730Ssteve if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && 10021590Srgrimes (gn->type & OP_LIB) == 0) { 10031590Srgrimes /* 10041590Srgrimes * No commands. Look for .DEFAULT rule from which we might infer 10058874Srgrimes * commands 10061590Srgrimes */ 100769527Swill if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands)) { 10085814Sjkh char *p1; 10091590Srgrimes /* 10101590Srgrimes * Make only looks for a .DEFAULT if the node was never the 10111590Srgrimes * target of an operator, so that's what we do too. If 10121590Srgrimes * a .DEFAULT was given, we substitute its commands for gn's 10131590Srgrimes * commands and set the IMPSRC variable to be the target's name 10141590Srgrimes * The DEFAULT node acts like a transformation rule, in that 10151590Srgrimes * gn also inherits any attributes or sources attached to 10161590Srgrimes * .DEFAULT itself. 10171590Srgrimes */ 10181590Srgrimes Make_HandleUse(DEFAULT, gn); 101918730Ssteve Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); 1020105826Sjmallett free(p1); 102118730Ssteve } else if (Dir_MTime(gn) == 0) { 10221590Srgrimes /* 10231590Srgrimes * The node wasn't the target of an operator we have no .DEFAULT 10241590Srgrimes * rule to go on and the target doesn't already exist. There's 10251590Srgrimes * nothing more we can do for this branch. If the -k flag wasn't 10261590Srgrimes * given, we stop in our tracks, otherwise we just don't update 10278874Srgrimes * this node's parents so they never get examined. 10281590Srgrimes */ 102918730Ssteve static const char msg[] = "make: don't know how to make"; 103018730Ssteve 10311590Srgrimes if (gn->type & OP_OPTIONAL) { 103218730Ssteve (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); 103318730Ssteve (void) fflush(stdout); 10341590Srgrimes } else if (keepgoing) { 103518730Ssteve (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); 103618730Ssteve (void) fflush(stdout); 103718730Ssteve return FALSE; 10381590Srgrimes } else { 103935483Simp#if OLD_JOKE 104035483Simp if (strcmp(gn->name,"love") == 0) 104135483Simp (*abortProc)("Not war."); 104235483Simp else 104335483Simp#endif 104435483Simp (*abortProc)("%s %s. Stop", msg, gn->name); 104518730Ssteve return FALSE; 10461590Srgrimes } 10471590Srgrimes } 10481590Srgrimes } 104918730Ssteve return TRUE; 10501590Srgrimes} 10511590Srgrimes 10521590Srgrimes/*- 10531590Srgrimes *----------------------------------------------------------------------- 10541590Srgrimes * JobExec -- 10551590Srgrimes * Execute the shell for the given job. Called from JobStart and 10561590Srgrimes * JobRestart. 10571590Srgrimes * 10581590Srgrimes * Results: 10591590Srgrimes * None. 10601590Srgrimes * 10611590Srgrimes * Side Effects: 10621590Srgrimes * A shell is executed, outputs is altered and the Job structure added 10631590Srgrimes * to the job table. 10641590Srgrimes * 10651590Srgrimes *----------------------------------------------------------------------- 10661590Srgrimes */ 10671590Srgrimesstatic void 1068104696SjmallettJobExec(Job *job, char **argv) 10691590Srgrimes{ 10701590Srgrimes int cpid; /* ID of new child */ 10718874Srgrimes 10721590Srgrimes if (DEBUG(JOB)) { 10731590Srgrimes int i; 10748874Srgrimes 1075137252Sharti DEBUGF(JOB, ("Running %s\n", job->node->name)); 1076103545Sjmallett DEBUGF(JOB, ("\tCommand: ")); 107718730Ssteve for (i = 0; argv[i] != NULL; i++) { 1078103545Sjmallett DEBUGF(JOB, ("%s ", argv[i])); 10791590Srgrimes } 1080103545Sjmallett DEBUGF(JOB, ("\n")); 10811590Srgrimes } 10828874Srgrimes 10831590Srgrimes /* 10841590Srgrimes * Some jobs produce no output and it's disconcerting to have 10851590Srgrimes * no feedback of their running (since they produce no output, the 10861590Srgrimes * banner with their name in it never appears). This is an attempt to 10871590Srgrimes * provide that feedback, even if nothing follows it. 10881590Srgrimes */ 10891590Srgrimes if ((lastNode != job->node) && (job->flags & JOB_FIRST) && 109018730Ssteve !(job->flags & JOB_SILENT)) { 109118730Ssteve MESSAGE(stdout, job->node); 10921590Srgrimes lastNode = job->node; 10931590Srgrimes } 10948874Srgrimes 109518730Ssteve if ((cpid = vfork()) == -1) { 109618730Ssteve Punt("Cannot fork"); 10971590Srgrimes } else if (cpid == 0) { 10981590Srgrimes 10991590Srgrimes /* 11001590Srgrimes * Must duplicate the input stream down to the child's input and 11011590Srgrimes * reset it to the beginning (again). Since the stream was marked 11021590Srgrimes * close-on-exec, we must clear that bit in the new input. 11031590Srgrimes */ 110418730Ssteve if (dup2(FILENO(job->cmdFILE), 0) == -1) 110518730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 110618730Ssteve (void) fcntl(0, F_SETFD, 0); 110794506Scharnier (void) lseek(0, (off_t)0, SEEK_SET); 11088874Srgrimes 11091590Srgrimes if (usePipes) { 11101590Srgrimes /* 11111590Srgrimes * Set up the child's output to be routed through the pipe 11121590Srgrimes * we've created for it. 11131590Srgrimes */ 111418730Ssteve if (dup2(job->outPipe, 1) == -1) 111518730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 11161590Srgrimes } else { 11171590Srgrimes /* 11181590Srgrimes * We're capturing output in a file, so we duplicate the 11191590Srgrimes * descriptor to the temporary file into the standard 11201590Srgrimes * output. 11211590Srgrimes */ 112218730Ssteve if (dup2(job->outFd, 1) == -1) 112318730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 11241590Srgrimes } 11251590Srgrimes /* 11261590Srgrimes * The output channels are marked close on exec. This bit was 11271590Srgrimes * duplicated by the dup2 (on some systems), so we have to clear 11281590Srgrimes * it before routing the shell's error output to the same place as 11291590Srgrimes * its standard output. 11301590Srgrimes */ 113118730Ssteve (void) fcntl(1, F_SETFD, 0); 113218730Ssteve if (dup2(1, 2) == -1) 113318730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 11341590Srgrimes 11351590Srgrimes#ifdef USE_PGRP 11361590Srgrimes /* 11371590Srgrimes * We want to switch the child into a different process family so 11381590Srgrimes * we can kill it and all its descendants in one fell swoop, 11391590Srgrimes * by killing its process family, but not commit suicide. 11401590Srgrimes */ 114118730Ssteve# if defined(SYSV) 114218730Ssteve (void) setsid(); 114318730Ssteve# else 114418730Ssteve (void) setpgid(0, getpid()); 114518730Ssteve# endif 114618730Ssteve#endif /* USE_PGRP */ 11478874Srgrimes 1148137202Sharti (void) execv(shellPath, argv); 11491590Srgrimes 115080381Ssheldonh (void) write(STDERR_FILENO, "Could not execute shell\n", 115118730Ssteve sizeof("Could not execute shell")); 115218730Ssteve _exit(1); 11531590Srgrimes } else { 11541590Srgrimes job->pid = cpid; 11551590Srgrimes 11561590Srgrimes if (usePipes && (job->flags & JOB_FIRST) ) { 11571590Srgrimes /* 11581590Srgrimes * The first time a job is run for a node, we set the current 11591590Srgrimes * position in the buffer to the beginning and mark another 11601590Srgrimes * stream to watch in the outputs mask 11611590Srgrimes */ 1162104475Sphk#ifdef USE_KQUEUE 1163104475Sphk struct kevent kev[2]; 1164104475Sphk#endif 11651590Srgrimes job->curPos = 0; 11668874Srgrimes 1167137202Sharti#if defined(USE_KQUEUE) 1168104475Sphk EV_SET(&kev[0], job->inPipe, EVFILT_READ, EV_ADD, 0, 0, job); 1169104475Sphk EV_SET(&kev[1], job->pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, 1170104475Sphk NOTE_EXIT, 0, NULL); 1171104475Sphk if (kevent(kqfd, kev, 2, NULL, 0, NULL) != 0) { 1172104475Sphk /* kevent() will fail if the job is already finished */ 1173128500Sgreen if (errno != EINTR && errno != EBADF && errno != ESRCH) 1174104475Sphk Punt("kevent: %s", strerror(errno)); 1175104475Sphk } 11761590Srgrimes#else 11771590Srgrimes FD_SET(job->inPipe, &outputs); 1178137202Sharti#endif /* USE_KQUEUE */ 11791590Srgrimes } 11801590Srgrimes 1181137252Sharti nLocal += 1; 1182137252Sharti if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 1183137252Sharti (void) fclose(job->cmdFILE); 1184137252Sharti job->cmdFILE = NULL; 11851590Srgrimes } 11861590Srgrimes } 11871590Srgrimes 11881590Srgrimes /* 11891590Srgrimes * Now the job is actually running, add it to the table. 11901590Srgrimes */ 11911590Srgrimes nJobs += 1; 119269531Swill (void) Lst_AtEnd(jobs, (void *)job); 11931590Srgrimes if (nJobs == maxJobs) { 11941590Srgrimes jobFull = TRUE; 11951590Srgrimes } 11961590Srgrimes} 11971590Srgrimes 11981590Srgrimes/*- 11991590Srgrimes *----------------------------------------------------------------------- 12001590Srgrimes * JobMakeArgv -- 12011590Srgrimes * Create the argv needed to execute the shell for a given job. 12021590Srgrimes * 12038874Srgrimes * 12041590Srgrimes * Results: 12051590Srgrimes * 12061590Srgrimes * Side Effects: 12071590Srgrimes * 12081590Srgrimes *----------------------------------------------------------------------- 12091590Srgrimes */ 12101590Srgrimesstatic void 1211104696SjmallettJobMakeArgv(Job *job, char **argv) 12121590Srgrimes{ 12131590Srgrimes int argc; 12141590Srgrimes static char args[10]; /* For merged arguments */ 12158874Srgrimes 12161590Srgrimes argv[0] = shellName; 12171590Srgrimes argc = 1; 12181590Srgrimes 12191590Srgrimes if ((commandShell->exit && (*commandShell->exit != '-')) || 12201590Srgrimes (commandShell->echo && (*commandShell->echo != '-'))) 12211590Srgrimes { 12221590Srgrimes /* 12231590Srgrimes * At least one of the flags doesn't have a minus before it, so 12241590Srgrimes * merge them together. Have to do this because the *(&(@*#*&#$# 12251590Srgrimes * Bourne shell thinks its second argument is a file to source. 12261590Srgrimes * Grrrr. Note the ten-character limitation on the combined arguments. 12271590Srgrimes */ 12281590Srgrimes (void)sprintf(args, "-%s%s", 12291590Srgrimes ((job->flags & JOB_IGNERR) ? "" : 12301590Srgrimes (commandShell->exit ? commandShell->exit : "")), 12311590Srgrimes ((job->flags & JOB_SILENT) ? "" : 12321590Srgrimes (commandShell->echo ? commandShell->echo : ""))); 12331590Srgrimes 12341590Srgrimes if (args[1]) { 12351590Srgrimes argv[argc] = args; 12361590Srgrimes argc++; 12371590Srgrimes } 12381590Srgrimes } else { 12391590Srgrimes if (!(job->flags & JOB_IGNERR) && commandShell->exit) { 12401590Srgrimes argv[argc] = commandShell->exit; 12411590Srgrimes argc++; 12421590Srgrimes } 12431590Srgrimes if (!(job->flags & JOB_SILENT) && commandShell->echo) { 12441590Srgrimes argv[argc] = commandShell->echo; 12451590Srgrimes argc++; 12461590Srgrimes } 12471590Srgrimes } 124818730Ssteve argv[argc] = NULL; 12491590Srgrimes} 12501590Srgrimes 12511590Srgrimes/*- 12521590Srgrimes *----------------------------------------------------------------------- 12531590Srgrimes * JobRestart -- 12548874Srgrimes * Restart a job that stopped for some reason. 12551590Srgrimes * 12561590Srgrimes * Results: 12571590Srgrimes * None. 12581590Srgrimes * 12591590Srgrimes * Side Effects: 12601590Srgrimes * jobFull will be set if the job couldn't be run. 12611590Srgrimes * 12621590Srgrimes *----------------------------------------------------------------------- 12631590Srgrimes */ 12641590Srgrimesstatic void 1265104696SjmallettJobRestart(Job *job) 12661590Srgrimes{ 126718730Ssteve 1268137252Sharti if (job->flags & JOB_RESTART) { 12691590Srgrimes /* 12701590Srgrimes * Set up the control arguments to the shell. This is based on the 12711590Srgrimes * flags set earlier for this job. If the JOB_IGNERR flag is clear, 12721590Srgrimes * the 'exit' flag of the commandShell is used to cause it to exit 12731590Srgrimes * upon receiving an error. If the JOB_SILENT flag is clear, the 12741590Srgrimes * 'echo' flag of the commandShell is used to get it to start echoing 12758874Srgrimes * as soon as it starts processing commands. 12761590Srgrimes */ 12771590Srgrimes char *argv[4]; 12788874Srgrimes 12791590Srgrimes JobMakeArgv(job, argv); 12808874Srgrimes 1281103545Sjmallett DEBUGF(JOB, ("Restarting %s...", job->node->name)); 1282137202Sharti if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) { 128318730Ssteve /* 1284137202Sharti * Can't be exported and not allowed to run locally -- put it 1285137202Sharti * back on the hold queue and mark the table full 128618730Ssteve */ 1287137202Sharti DEBUGF(JOB, ("holding\n")); 1288137202Sharti (void)Lst_AtFront(stoppedJobs, (void *)job); 1289137202Sharti jobFull = TRUE; 1290137202Sharti DEBUGF(JOB, ("Job queue is full.\n")); 1291137202Sharti return; 1292137202Sharti } else { 1293137202Sharti /* 1294137202Sharti * Job may be run locally. 1295137202Sharti */ 1296137202Sharti DEBUGF(JOB, ("running locally\n")); 129718730Ssteve } 12981590Srgrimes JobExec(job, argv); 12991590Srgrimes } else { 13001590Srgrimes /* 13011590Srgrimes * The job has stopped and needs to be restarted. Why it stopped, 13021590Srgrimes * we don't know... 13031590Srgrimes */ 1304103545Sjmallett DEBUGF(JOB, ("Resuming %s...", job->node->name)); 1305137252Sharti if (((nLocal < maxLocal) || 130618730Ssteve ((job->flags & JOB_SPECIAL) && 130718730Ssteve (maxLocal == 0))) && 130818730Ssteve (nJobs != maxJobs)) 13091590Srgrimes { 13101590Srgrimes /* 1311137252Sharti * If we haven't reached the concurrency limit already (or the 1312137252Sharti * job must be run and maxLocal is 0), it's ok to resume it. 13131590Srgrimes */ 13141590Srgrimes Boolean error; 131518730Ssteve int status; 13168874Srgrimes 1317137202Sharti error = (KILL(job->pid, SIGCONT) != 0); 13181590Srgrimes 13191590Srgrimes if (!error) { 13201590Srgrimes /* 13211590Srgrimes * Make sure the user knows we've continued the beast and 13221590Srgrimes * actually put the thing in the job table. 13231590Srgrimes */ 13241590Srgrimes job->flags |= JOB_CONTINUING; 132518730Ssteve W_SETTERMSIG(&status, SIGCONT); 132618730Ssteve JobFinish(job, &status); 13278874Srgrimes 13281590Srgrimes job->flags &= ~(JOB_RESUME|JOB_CONTINUING); 1329103545Sjmallett DEBUGF(JOB, ("done\n")); 13301590Srgrimes } else { 13311590Srgrimes Error("couldn't resume %s: %s", 13321590Srgrimes job->node->name, strerror(errno)); 133318730Ssteve status = 0; 133418730Ssteve W_SETEXITSTATUS(&status, 1); 133518730Ssteve JobFinish(job, &status); 13361590Srgrimes } 13371590Srgrimes } else { 13381590Srgrimes /* 13391590Srgrimes * Job cannot be restarted. Mark the table as full and 13401590Srgrimes * place the job back on the list of stopped jobs. 13411590Srgrimes */ 1342103545Sjmallett DEBUGF(JOB, ("table full\n")); 134369531Swill (void) Lst_AtFront(stoppedJobs, (void *)job); 13441590Srgrimes jobFull = TRUE; 1345103545Sjmallett DEBUGF(JOB, ("Job queue is full.\n")); 13461590Srgrimes } 13471590Srgrimes } 13481590Srgrimes} 13491590Srgrimes 13501590Srgrimes/*- 13511590Srgrimes *----------------------------------------------------------------------- 13521590Srgrimes * JobStart -- 13531590Srgrimes * Start a target-creation process going for the target described 13548874Srgrimes * by the graph node gn. 13551590Srgrimes * 13561590Srgrimes * Results: 13571590Srgrimes * JOB_ERROR if there was an error in the commands, JOB_FINISHED 13581590Srgrimes * if there isn't actually anything left to do for the job and 13591590Srgrimes * JOB_RUNNING if the job has been started. 13601590Srgrimes * 13611590Srgrimes * Side Effects: 13621590Srgrimes * A new Job node is created and added to the list of running 13631590Srgrimes * jobs. PMake is forked and a child shell created. 13641590Srgrimes *----------------------------------------------------------------------- 13651590Srgrimes */ 13661590Srgrimesstatic int 1367104696SjmallettJobStart(GNode *gn, int flags, Job *previous) 13681590Srgrimes{ 136994584Sobrien Job *job; /* new job descriptor */ 13701590Srgrimes char *argv[4]; /* Argument vector to shell */ 13711590Srgrimes Boolean cmdsOK; /* true if the nodes commands were all right */ 13721590Srgrimes Boolean noExec; /* Set true if we decide not to run the job */ 137356151Skris int tfd; /* File descriptor for temp file */ 13741590Srgrimes 137518730Ssteve if (previous != NULL) { 1376137252Sharti previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT); 13771590Srgrimes job = previous; 13781590Srgrimes } else { 137918730Ssteve job = (Job *) emalloc(sizeof(Job)); 13801590Srgrimes flags |= JOB_FIRST; 13811590Srgrimes } 13821590Srgrimes 13831590Srgrimes job->node = gn; 138469527Swill job->tailCmds = NULL; 13851590Srgrimes 13861590Srgrimes /* 13871590Srgrimes * Set the initial value of the flags for this job based on the global 13881590Srgrimes * ones and the node's attributes... Any flags supplied by the caller 13891590Srgrimes * are also added to the field. 13901590Srgrimes */ 13911590Srgrimes job->flags = 0; 139218730Ssteve if (Targ_Ignore(gn)) { 13931590Srgrimes job->flags |= JOB_IGNERR; 13941590Srgrimes } 139518730Ssteve if (Targ_Silent(gn)) { 13961590Srgrimes job->flags |= JOB_SILENT; 13971590Srgrimes } 13981590Srgrimes job->flags |= flags; 13991590Srgrimes 14001590Srgrimes /* 14011590Srgrimes * Check the commands now so any attributes from .DEFAULT have a chance 14021590Srgrimes * to migrate to the node 14031590Srgrimes */ 140418730Ssteve if (!compatMake && job->flags & JOB_FIRST) { 14051590Srgrimes cmdsOK = Job_CheckCommands(gn, Error); 14061590Srgrimes } else { 14071590Srgrimes cmdsOK = TRUE; 14081590Srgrimes } 14098874Srgrimes 14101590Srgrimes /* 14111590Srgrimes * If the -n flag wasn't given, we open up OUR (not the child's) 14121590Srgrimes * temporary file to stuff commands in it. The thing is rd/wr so we don't 14131590Srgrimes * need to reopen it to feed it to the shell. If the -n flag *was* given, 14141590Srgrimes * we just set the file to be stdout. Cute, huh? 14151590Srgrimes */ 14161590Srgrimes if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) { 14171590Srgrimes /* 14181590Srgrimes * We're serious here, but if the commands were bogus, we're 14191590Srgrimes * also dead... 14201590Srgrimes */ 14211590Srgrimes if (!cmdsOK) { 14221590Srgrimes DieHorribly(); 14231590Srgrimes } 14248874Srgrimes 142568898Skris (void) strcpy(tfile, TMPPAT); 142668898Skris if ((tfd = mkstemp(tfile)) == -1) 142768898Skris Punt("Cannot create temp file: %s", strerror(errno)); 142868898Skris job->cmdFILE = fdopen(tfd, "w+"); 142968898Skris eunlink(tfile); 143018730Ssteve if (job->cmdFILE == NULL) { 143168898Skris close(tfd); 143268898Skris Punt("Could not open %s", tfile); 14331590Srgrimes } 143418730Ssteve (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1); 14351590Srgrimes /* 14361590Srgrimes * Send the commands to the command file, flush all its buffers then 14371590Srgrimes * rewind and remove the thing. 14381590Srgrimes */ 14391590Srgrimes noExec = FALSE; 14401590Srgrimes 14411590Srgrimes /* 14421590Srgrimes * used to be backwards; replace when start doing multiple commands 14431590Srgrimes * per shell. 14441590Srgrimes */ 14451590Srgrimes if (compatMake) { 14461590Srgrimes /* 14471590Srgrimes * Be compatible: If this is the first time for this node, 14481590Srgrimes * verify its commands are ok and open the commands list for 14491590Srgrimes * sequential access by later invocations of JobStart. 14501590Srgrimes * Once that is done, we take the next command off the list 14511590Srgrimes * and print it to the command file. If the command was an 14521590Srgrimes * ellipsis, note that there's nothing more to execute. 14531590Srgrimes */ 14541590Srgrimes if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){ 14551590Srgrimes cmdsOK = FALSE; 14561590Srgrimes } else { 145718730Ssteve LstNode ln = Lst_Next(gn->commands); 14588874Srgrimes 145969527Swill if ((ln == NULL) || 146069531Swill JobPrintCommand((void *) Lst_Datum(ln), 146169531Swill (void *) job)) 14621590Srgrimes { 14631590Srgrimes noExec = TRUE; 146418730Ssteve Lst_Close(gn->commands); 14651590Srgrimes } 14661590Srgrimes if (noExec && !(job->flags & JOB_FIRST)) { 14671590Srgrimes /* 14681590Srgrimes * If we're not going to execute anything, the job 14691590Srgrimes * is done and we need to close down the various 14701590Srgrimes * file descriptors we've opened for output, then 14711590Srgrimes * call JobDoOutput to catch the final characters or 14721590Srgrimes * send the file to the screen... Note that the i/o streams 14731590Srgrimes * are only open if this isn't the first job. 14741590Srgrimes * Note also that this could not be done in 14751590Srgrimes * Job_CatchChildren b/c it wasn't clear if there were 14761590Srgrimes * more commands to execute or not... 14771590Srgrimes */ 147818730Ssteve JobClose(job); 14791590Srgrimes } 14801590Srgrimes } 14811590Srgrimes } else { 14821590Srgrimes /* 14831590Srgrimes * We can do all the commands at once. hooray for sanity 14841590Srgrimes */ 14851590Srgrimes numCommands = 0; 148669531Swill Lst_ForEach(gn->commands, JobPrintCommand, (void *)job); 14878874Srgrimes 14881590Srgrimes /* 14891590Srgrimes * If we didn't print out any commands to the shell script, 14901590Srgrimes * there's not much point in executing the shell, is there? 14911590Srgrimes */ 14921590Srgrimes if (numCommands == 0) { 14931590Srgrimes noExec = TRUE; 14941590Srgrimes } 14951590Srgrimes } 14961590Srgrimes } else if (noExecute) { 14971590Srgrimes /* 14981590Srgrimes * Not executing anything -- just print all the commands to stdout 14991590Srgrimes * in one fell swoop. This will still set up job->tailCmds correctly. 15001590Srgrimes */ 15011590Srgrimes if (lastNode != gn) { 150218730Ssteve MESSAGE(stdout, gn); 15031590Srgrimes lastNode = gn; 15041590Srgrimes } 15051590Srgrimes job->cmdFILE = stdout; 15061590Srgrimes /* 15071590Srgrimes * Only print the commands if they're ok, but don't die if they're 15081590Srgrimes * not -- just let the user know they're bad and keep going. It 15091590Srgrimes * doesn't do any harm in this case and may do some good. 15101590Srgrimes */ 15111590Srgrimes if (cmdsOK) { 151269531Swill Lst_ForEach(gn->commands, JobPrintCommand, (void *)job); 15131590Srgrimes } 15141590Srgrimes /* 15151590Srgrimes * Don't execute the shell, thank you. 15161590Srgrimes */ 15171590Srgrimes noExec = TRUE; 15181590Srgrimes } else { 15191590Srgrimes /* 15201590Srgrimes * Just touch the target and note that no shell should be executed. 15211590Srgrimes * Set cmdFILE to stdout to make life easier. Check the commands, too, 15221590Srgrimes * but don't die if they're no good -- it does no harm to keep working 15231590Srgrimes * up the graph. 15241590Srgrimes */ 15251590Srgrimes job->cmdFILE = stdout; 152618730Ssteve Job_Touch(gn, job->flags&JOB_SILENT); 15271590Srgrimes noExec = TRUE; 15281590Srgrimes } 15291590Srgrimes 15301590Srgrimes /* 15318874Srgrimes * If we're not supposed to execute a shell, don't. 15321590Srgrimes */ 15331590Srgrimes if (noExec) { 15341590Srgrimes /* 15351590Srgrimes * Unlink and close the command file if we opened one 15361590Srgrimes */ 15371590Srgrimes if (job->cmdFILE != stdout) { 153818730Ssteve if (job->cmdFILE != NULL) 153918730Ssteve (void) fclose(job->cmdFILE); 15401590Srgrimes } else { 154118730Ssteve (void) fflush(stdout); 15421590Srgrimes } 15431590Srgrimes 15441590Srgrimes /* 15451590Srgrimes * We only want to work our way up the graph if we aren't here because 15461590Srgrimes * the commands for the job were no good. 15471590Srgrimes */ 15481590Srgrimes if (cmdsOK) { 15491590Srgrimes if (aborting == 0) { 155069527Swill if (job->tailCmds != NULL) { 15511590Srgrimes Lst_ForEachFrom(job->node->commands, job->tailCmds, 15521590Srgrimes JobSaveCommand, 155369531Swill (void *)job->node); 15541590Srgrimes } 155536621Sbde job->node->made = MADE; 15561590Srgrimes Make_Update(job->node); 15571590Srgrimes } 155869531Swill free(job); 15591590Srgrimes return(JOB_FINISHED); 15601590Srgrimes } else { 156169531Swill free(job); 15621590Srgrimes return(JOB_ERROR); 15631590Srgrimes } 15641590Srgrimes } else { 156518730Ssteve (void) fflush(job->cmdFILE); 15661590Srgrimes } 15671590Srgrimes 15681590Srgrimes /* 15691590Srgrimes * Set up the control arguments to the shell. This is based on the flags 15701590Srgrimes * set earlier for this job. 15711590Srgrimes */ 15721590Srgrimes JobMakeArgv(job, argv); 15731590Srgrimes 15741590Srgrimes /* 15751590Srgrimes * If we're using pipes to catch output, create the pipe by which we'll 15761590Srgrimes * get the shell's output. If we're using files, print out that we're 157750145Shoek * starting a job and then set up its temporary-file name. 15781590Srgrimes */ 157918730Ssteve if (!compatMake || (job->flags & JOB_FIRST)) { 15801590Srgrimes if (usePipes) { 15811590Srgrimes int fd[2]; 158218730Ssteve if (pipe(fd) == -1) 158318730Ssteve Punt("Cannot create pipe: %s", strerror(errno)); 15841590Srgrimes job->inPipe = fd[0]; 15851590Srgrimes job->outPipe = fd[1]; 158618730Ssteve (void) fcntl(job->inPipe, F_SETFD, 1); 158718730Ssteve (void) fcntl(job->outPipe, F_SETFD, 1); 15881590Srgrimes } else { 158918730Ssteve (void) fprintf(stdout, "Remaking `%s'\n", gn->name); 159018730Ssteve (void) fflush(stdout); 159150145Shoek (void) strcpy(job->outFile, TMPPAT); 159250145Shoek if ((job->outFd = mkstemp(job->outFile)) == -1) 159350145Shoek Punt("cannot create temp file: %s", strerror(errno)); 159418730Ssteve (void) fcntl(job->outFd, F_SETFD, 1); 15951590Srgrimes } 15961590Srgrimes } 15971590Srgrimes 1598137252Sharti if ((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL) && 1599137252Sharti (maxLocal != 0)) { 16001590Srgrimes /* 1601137252Sharti * We've hit the limit of concurrency, so put the job on hold until 1602137252Sharti * some other job finishes. Note that the special jobs (.BEGIN, 1603137252Sharti * .INTERRUPT and .END) may be run even when the limit has been reached 1604137252Sharti * (e.g. when maxLocal == 0). 16051590Srgrimes */ 16061590Srgrimes jobFull = TRUE; 16078874Srgrimes 1608103545Sjmallett DEBUGF(JOB, ("Can only run job locally.\n")); 16091590Srgrimes job->flags |= JOB_RESTART; 161069531Swill (void) Lst_AtEnd(stoppedJobs, (void *)job); 16111590Srgrimes } else { 1612137252Sharti if (nLocal >= maxLocal) { 16131590Srgrimes /* 16141590Srgrimes * If we're running this job locally as a special case (see above), 16151590Srgrimes * at least say the table is full. 16161590Srgrimes */ 16171590Srgrimes jobFull = TRUE; 1618103545Sjmallett DEBUGF(JOB, ("Local job queue is full.\n")); 16191590Srgrimes } 16201590Srgrimes JobExec(job, argv); 16211590Srgrimes } 16221590Srgrimes return(JOB_RUNNING); 16231590Srgrimes} 16241590Srgrimes 162518730Sstevestatic char * 1626104696SjmallettJobOutput(Job *job, char *cp, char *endp, int msg) 162718730Ssteve{ 162894584Sobrien char *ecp; 162918730Ssteve 163018730Ssteve if (commandShell->noPrint) { 1631106106Sjmallett ecp = strstr(cp, commandShell->noPrint); 163218730Ssteve while (ecp != NULL) { 163318730Ssteve if (cp != ecp) { 163418730Ssteve *ecp = '\0'; 163518730Ssteve if (msg && job->node != lastNode) { 163618730Ssteve MESSAGE(stdout, job->node); 163718730Ssteve lastNode = job->node; 163818730Ssteve } 163918730Ssteve /* 164018730Ssteve * The only way there wouldn't be a newline after 164118730Ssteve * this line is if it were the last in the buffer. 164218730Ssteve * however, since the non-printable comes after it, 164318730Ssteve * there must be a newline, so we don't print one. 164418730Ssteve */ 164518730Ssteve (void) fprintf(stdout, "%s", cp); 164618730Ssteve (void) fflush(stdout); 164718730Ssteve } 164818730Ssteve cp = ecp + commandShell->noPLen; 164918730Ssteve if (cp != endp) { 165018730Ssteve /* 165118730Ssteve * Still more to print, look again after skipping 165218730Ssteve * the whitespace following the non-printable 165318730Ssteve * command.... 165418730Ssteve */ 165518730Ssteve cp++; 165618730Ssteve while (*cp == ' ' || *cp == '\t' || *cp == '\n') { 165718730Ssteve cp++; 165818730Ssteve } 1659106106Sjmallett ecp = strstr(cp, commandShell->noPrint); 166018730Ssteve } else { 166118730Ssteve return cp; 166218730Ssteve } 166318730Ssteve } 166418730Ssteve } 166518730Ssteve return cp; 166618730Ssteve} 166718730Ssteve 16681590Srgrimes/*- 16691590Srgrimes *----------------------------------------------------------------------- 16701590Srgrimes * JobDoOutput -- 16711590Srgrimes * This function is called at different times depending on 16721590Srgrimes * whether the user has specified that output is to be collected 16731590Srgrimes * via pipes or temporary files. In the former case, we are called 16741590Srgrimes * whenever there is something to read on the pipe. We collect more 16751590Srgrimes * output from the given job and store it in the job's outBuf. If 16761590Srgrimes * this makes up a line, we print it tagged by the job's identifier, 16771590Srgrimes * as necessary. 16781590Srgrimes * If output has been collected in a temporary file, we open the 16791590Srgrimes * file and read it line by line, transfering it to our own 16801590Srgrimes * output channel until the file is empty. At which point we 16811590Srgrimes * remove the temporary file. 16821590Srgrimes * In both cases, however, we keep our figurative eye out for the 16831590Srgrimes * 'noPrint' line for the shell from which the output came. If 16841590Srgrimes * we recognize a line, we don't print it. If the command is not 16851590Srgrimes * alone on the line (the character after it is not \0 or \n), we 16861590Srgrimes * do print whatever follows it. 16871590Srgrimes * 16881590Srgrimes * Results: 16891590Srgrimes * None 16901590Srgrimes * 16911590Srgrimes * Side Effects: 16921590Srgrimes * curPos may be shifted as may the contents of outBuf. 16931590Srgrimes *----------------------------------------------------------------------- 16941590Srgrimes */ 169518730SsteveSTATIC void 1696104696SjmallettJobDoOutput(Job *job, Boolean finish) 16971590Srgrimes{ 16981590Srgrimes Boolean gotNL = FALSE; /* true if got a newline */ 169918730Ssteve Boolean fbuf; /* true if our buffer filled up */ 170094584Sobrien int nr; /* number of bytes read */ 170194584Sobrien int i; /* auxiliary index into outBuf */ 170294584Sobrien int max; /* limit for i (end of current data) */ 17031590Srgrimes int nRead; /* (Temporary) number of bytes read */ 17041590Srgrimes 17051590Srgrimes FILE *oFILE; /* Stream pointer to shell's output file */ 17061590Srgrimes char inLine[132]; 17071590Srgrimes 17088874Srgrimes 17091590Srgrimes if (usePipes) { 17101590Srgrimes /* 17111590Srgrimes * Read as many bytes as will fit in the buffer. 17121590Srgrimes */ 17131590Srgrimesend_loop: 171418730Ssteve gotNL = FALSE; 171518730Ssteve fbuf = FALSE; 17168874Srgrimes 171718730Ssteve nRead = read(job->inPipe, &job->outBuf[job->curPos], 17181590Srgrimes JOB_BUFSIZE - job->curPos); 17191590Srgrimes if (nRead < 0) { 1720103545Sjmallett DEBUGF(JOB, ("JobDoOutput(piperead)")); 17211590Srgrimes nr = 0; 17221590Srgrimes } else { 17231590Srgrimes nr = nRead; 17241590Srgrimes } 17251590Srgrimes 17261590Srgrimes /* 17271590Srgrimes * If we hit the end-of-file (the job is dead), we must flush its 17281590Srgrimes * remaining output, so pretend we read a newline if there's any 17291590Srgrimes * output remaining in the buffer. 17301590Srgrimes * Also clear the 'finish' flag so we stop looping. 17311590Srgrimes */ 17321590Srgrimes if ((nr == 0) && (job->curPos != 0)) { 17331590Srgrimes job->outBuf[job->curPos] = '\n'; 17341590Srgrimes nr = 1; 17351590Srgrimes finish = FALSE; 17361590Srgrimes } else if (nr == 0) { 17371590Srgrimes finish = FALSE; 17381590Srgrimes } 17398874Srgrimes 17401590Srgrimes /* 17411590Srgrimes * Look for the last newline in the bytes we just got. If there is 17421590Srgrimes * one, break out of the loop with 'i' as its index and gotNL set 17438874Srgrimes * TRUE. 17441590Srgrimes */ 17451590Srgrimes max = job->curPos + nr; 17461590Srgrimes for (i = job->curPos + nr - 1; i >= job->curPos; i--) { 17471590Srgrimes if (job->outBuf[i] == '\n') { 17481590Srgrimes gotNL = TRUE; 17491590Srgrimes break; 17501590Srgrimes } else if (job->outBuf[i] == '\0') { 17511590Srgrimes /* 17521590Srgrimes * Why? 17531590Srgrimes */ 17541590Srgrimes job->outBuf[i] = ' '; 17551590Srgrimes } 17561590Srgrimes } 17578874Srgrimes 17581590Srgrimes if (!gotNL) { 17591590Srgrimes job->curPos += nr; 17601590Srgrimes if (job->curPos == JOB_BUFSIZE) { 17611590Srgrimes /* 17621590Srgrimes * If we've run out of buffer space, we have no choice 17638874Srgrimes * but to print the stuff. sigh. 17641590Srgrimes */ 176518730Ssteve fbuf = TRUE; 17661590Srgrimes i = job->curPos; 17671590Srgrimes } 17681590Srgrimes } 176918730Ssteve if (gotNL || fbuf) { 17701590Srgrimes /* 17711590Srgrimes * Need to send the output to the screen. Null terminate it 17721590Srgrimes * first, overwriting the newline character if there was one. 17731590Srgrimes * So long as the line isn't one we should filter (according 177472645Sasmodai * to the shell description), we print the line, preceded 17751590Srgrimes * by a target banner if this target isn't the same as the 17761590Srgrimes * one for which we last printed something. 17771590Srgrimes * The rest of the data in the buffer are then shifted down 17788874Srgrimes * to the start of the buffer and curPos is set accordingly. 17791590Srgrimes */ 17801590Srgrimes job->outBuf[i] = '\0'; 17811590Srgrimes if (i >= job->curPos) { 178218730Ssteve char *cp; 17831590Srgrimes 178418730Ssteve cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); 17851590Srgrimes 17861590Srgrimes /* 17871590Srgrimes * There's still more in that thar buffer. This time, though, 17881590Srgrimes * we know there's no newline at the end, so we add one of 17891590Srgrimes * our own free will. 17901590Srgrimes */ 17911590Srgrimes if (*cp != '\0') { 17921590Srgrimes if (job->node != lastNode) { 179318730Ssteve MESSAGE(stdout, job->node); 17941590Srgrimes lastNode = job->node; 17951590Srgrimes } 179618730Ssteve (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); 179718730Ssteve (void) fflush(stdout); 17981590Srgrimes } 17991590Srgrimes } 18001590Srgrimes if (i < max - 1) { 18011590Srgrimes /* shift the remaining characters down */ 180218730Ssteve (void) memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); 18031590Srgrimes job->curPos = max - (i + 1); 18048874Srgrimes 18051590Srgrimes } else { 18061590Srgrimes /* 18071590Srgrimes * We have written everything out, so we just start over 18081590Srgrimes * from the start of the buffer. No copying. No nothing. 18091590Srgrimes */ 18101590Srgrimes job->curPos = 0; 18111590Srgrimes } 18121590Srgrimes } 18131590Srgrimes if (finish) { 18141590Srgrimes /* 18151590Srgrimes * If the finish flag is true, we must loop until we hit 181618730Ssteve * end-of-file on the pipe. This is guaranteed to happen 181718730Ssteve * eventually since the other end of the pipe is now closed 181818730Ssteve * (we closed it explicitly and the child has exited). When 181918730Ssteve * we do get an EOF, finish will be set FALSE and we'll fall 182018730Ssteve * through and out. 18211590Srgrimes */ 18221590Srgrimes goto end_loop; 18231590Srgrimes } 18241590Srgrimes } else { 18251590Srgrimes /* 18261590Srgrimes * We've been called to retrieve the output of the job from the 18271590Srgrimes * temporary file where it's been squirreled away. This consists of 18281590Srgrimes * opening the file, reading the output line by line, being sure not 18291590Srgrimes * to print the noPrint line for the shell we used, then close and 18301590Srgrimes * remove the temporary file. Very simple. 18311590Srgrimes * 18321590Srgrimes * Change to read in blocks and do FindSubString type things as for 18331590Srgrimes * pipes? That would allow for "@echo -n..." 18341590Srgrimes */ 183518730Ssteve oFILE = fopen(job->outFile, "r"); 183618730Ssteve if (oFILE != NULL) { 183718730Ssteve (void) fprintf(stdout, "Results of making %s:\n", job->node->name); 183818730Ssteve (void) fflush(stdout); 183918730Ssteve while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { 184094584Sobrien char *cp, *endp, *oendp; 18411590Srgrimes 18421590Srgrimes cp = inLine; 184318730Ssteve oendp = endp = inLine + strlen(inLine); 18441590Srgrimes if (endp[-1] == '\n') { 18451590Srgrimes *--endp = '\0'; 18461590Srgrimes } 184718730Ssteve cp = JobOutput(job, inLine, endp, FALSE); 18481590Srgrimes 18491590Srgrimes /* 18501590Srgrimes * There's still more in that thar buffer. This time, though, 18511590Srgrimes * we know there's no newline at the end, so we add one of 18521590Srgrimes * our own free will. 18531590Srgrimes */ 185418730Ssteve (void) fprintf(stdout, "%s", cp); 185518730Ssteve (void) fflush(stdout); 185618730Ssteve if (endp != oendp) { 185718730Ssteve (void) fprintf(stdout, "\n"); 185818730Ssteve (void) fflush(stdout); 18591590Srgrimes } 18601590Srgrimes } 186118730Ssteve (void) fclose(oFILE); 186218730Ssteve (void) eunlink(job->outFile); 18631590Srgrimes } 18641590Srgrimes } 18651590Srgrimes} 18661590Srgrimes 18671590Srgrimes/*- 18681590Srgrimes *----------------------------------------------------------------------- 18691590Srgrimes * Job_CatchChildren -- 18701590Srgrimes * Handle the exit of a child. Called from Make_Make. 18711590Srgrimes * 18721590Srgrimes * Results: 18731590Srgrimes * none. 18741590Srgrimes * 18751590Srgrimes * Side Effects: 18761590Srgrimes * The job descriptor is removed from the list of children. 18771590Srgrimes * 18781590Srgrimes * Notes: 18791590Srgrimes * We do waits, blocking or not, according to the wisdom of our 18801590Srgrimes * caller, until there are no more children to report. For each 18811590Srgrimes * job, call JobFinish to finish things off. This will take care of 18821590Srgrimes * putting jobs on the stoppedJobs queue. 18831590Srgrimes * 18841590Srgrimes *----------------------------------------------------------------------- 18851590Srgrimes */ 18861590Srgrimesvoid 1887104696SjmallettJob_CatchChildren(Boolean block) 18881590Srgrimes{ 18891590Srgrimes int pid; /* pid of dead child */ 189094584Sobrien Job *job; /* job descriptor for dead child */ 18911590Srgrimes LstNode jnode; /* list element for finding job */ 189218730Ssteve int status; /* Exit/termination status */ 18931590Srgrimes 18941590Srgrimes /* 18951590Srgrimes * Don't even bother if we know there's no one around. 18961590Srgrimes */ 18971590Srgrimes if (nLocal == 0) { 18981590Srgrimes return; 18991590Srgrimes } 19008874Srgrimes 190118730Ssteve while ((pid = waitpid((pid_t) -1, &status, 190218730Ssteve (block?0:WNOHANG)|WUNTRACED)) > 0) 19031590Srgrimes { 1904103545Sjmallett DEBUGF(JOB, ("Process %d exited or stopped.\n", pid)); 19051590Srgrimes 190669531Swill jnode = Lst_Find(jobs, (void *)&pid, JobCmpPid); 19071590Srgrimes 190869527Swill if (jnode == NULL) { 190918730Ssteve if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) { 191069531Swill jnode = Lst_Find(stoppedJobs, (void *) &pid, JobCmpPid); 191169527Swill if (jnode == NULL) { 19121590Srgrimes Error("Resumed child (%d) not in table", pid); 19131590Srgrimes continue; 19141590Srgrimes } 19151590Srgrimes job = (Job *)Lst_Datum(jnode); 191618730Ssteve (void) Lst_Remove(stoppedJobs, jnode); 19171590Srgrimes } else { 191818730Ssteve Error("Child (%d) not in table?", pid); 19191590Srgrimes continue; 19201590Srgrimes } 19211590Srgrimes } else { 192218730Ssteve job = (Job *) Lst_Datum(jnode); 192318730Ssteve (void) Lst_Remove(jobs, jnode); 19241590Srgrimes nJobs -= 1; 1925103545Sjmallett DEBUGF(JOB, ("Job queue is no longer full.\n")); 19261590Srgrimes jobFull = FALSE; 19271590Srgrimes nLocal -= 1; 19281590Srgrimes } 19291590Srgrimes 193018730Ssteve JobFinish(job, &status); 19311590Srgrimes } 19321590Srgrimes} 19331590Srgrimes 19341590Srgrimes/*- 19351590Srgrimes *----------------------------------------------------------------------- 19361590Srgrimes * Job_CatchOutput -- 19371590Srgrimes * Catch the output from our children, if we're using 19381590Srgrimes * pipes do so. Otherwise just block time until we get a 19391590Srgrimes * signal (most likely a SIGCHLD) since there's no point in 19401590Srgrimes * just spinning when there's nothing to do and the reaping 19418874Srgrimes * of a child can wait for a while. 19421590Srgrimes * 19431590Srgrimes * Results: 19448874Srgrimes * None 19451590Srgrimes * 19461590Srgrimes * Side Effects: 19471590Srgrimes * Output is read from pipes if we're piping. 19481590Srgrimes * ----------------------------------------------------------------------- 19491590Srgrimes */ 19501590Srgrimesvoid 1951104696SjmallettJob_CatchOutput(void) 19521590Srgrimes{ 19531590Srgrimes int nfds; 1954104475Sphk#ifdef USE_KQUEUE 1955104475Sphk#define KEV_SIZE 4 1956104475Sphk struct kevent kev[KEV_SIZE]; 1957104475Sphk int i; 1958104475Sphk#else 19591590Srgrimes struct timeval timeout; 19601590Srgrimes fd_set readfds; 196194584Sobrien LstNode ln; 196294584Sobrien Job *job; 1963104475Sphk#endif 19641590Srgrimes 196518730Ssteve (void) fflush(stdout); 19661590Srgrimes 19671590Srgrimes if (usePipes) { 1968104475Sphk#ifdef USE_KQUEUE 1969104475Sphk if ((nfds = kevent(kqfd, NULL, 0, kev, KEV_SIZE, NULL)) == -1) { 1970128500Sgreen if (errno != EINTR) 1971128500Sgreen Punt("kevent: %s", strerror(errno)); 1972104475Sphk } else { 1973104475Sphk for (i = 0; i < nfds; i++) { 1974104475Sphk if (kev[i].flags & EV_ERROR) { 1975104475Sphk warnc(kev[i].data, "kevent"); 1976104475Sphk continue; 1977104475Sphk } 1978104475Sphk switch (kev[i].filter) { 1979104475Sphk case EVFILT_READ: 1980104475Sphk JobDoOutput(kev[i].udata, FALSE); 1981104475Sphk break; 1982104475Sphk case EVFILT_PROC: 1983104475Sphk /* Just wake up and let Job_CatchChildren() collect the 1984104475Sphk * terminated job. */ 1985104475Sphk break; 1986104475Sphk } 1987104475Sphk } 1988104475Sphk } 1989104475Sphk#else 19901590Srgrimes readfds = outputs; 19911590Srgrimes timeout.tv_sec = SEL_SEC; 19921590Srgrimes timeout.tv_usec = SEL_USEC; 19931590Srgrimes 199418730Ssteve if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, 199518730Ssteve (fd_set *) 0, &timeout)) <= 0) 19961590Srgrimes return; 199718730Ssteve else { 199818730Ssteve if (Lst_Open(jobs) == FAILURE) { 199918730Ssteve Punt("Cannot open job table"); 20001590Srgrimes } 200169527Swill while (nfds && (ln = Lst_Next(jobs)) != NULL) { 200218730Ssteve job = (Job *) Lst_Datum(ln); 20031590Srgrimes if (FD_ISSET(job->inPipe, &readfds)) { 200418730Ssteve JobDoOutput(job, FALSE); 20051590Srgrimes nfds -= 1; 20061590Srgrimes } 20071590Srgrimes } 200818730Ssteve Lst_Close(jobs); 20091590Srgrimes } 2010104475Sphk#endif /* !USE_KQUEUE */ 20111590Srgrimes } 20121590Srgrimes} 20131590Srgrimes 20141590Srgrimes/*- 20151590Srgrimes *----------------------------------------------------------------------- 20161590Srgrimes * Job_Make -- 20171590Srgrimes * Start the creation of a target. Basically a front-end for 20181590Srgrimes * JobStart used by the Make module. 20191590Srgrimes * 20201590Srgrimes * Results: 20211590Srgrimes * None. 20221590Srgrimes * 20231590Srgrimes * Side Effects: 20241590Srgrimes * Another job is started. 20251590Srgrimes * 20261590Srgrimes *----------------------------------------------------------------------- 20271590Srgrimes */ 20281590Srgrimesvoid 2029104696SjmallettJob_Make(GNode *gn) 20301590Srgrimes{ 203118730Ssteve (void) JobStart(gn, 0, NULL); 20321590Srgrimes} 20331590Srgrimes 2034136840Sruvoid 2035136840SruShell_Init(void) 2036136840Sru{ 2037136840Sru if (shellPath == NULL) { 2038136840Sru /* 2039136840Sru * The user didn't specify a shell to use, so we are using the 2040136840Sru * default one... Both the absolute path and the last component 2041136840Sru * must be set. The last component is taken from the 'name' field 2042136840Sru * of the default shell description pointed-to by commandShell. 2043136840Sru * All default shells are located in _PATH_DEFSHELLDIR. 2044136840Sru */ 2045136840Sru shellName = commandShell->name; 2046136840Sru shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); 2047136840Sru } 2048136840Sru} 2049136840Sru 20501590Srgrimes/*- 20511590Srgrimes *----------------------------------------------------------------------- 20521590Srgrimes * Job_Init -- 2053104696Sjmallett * Initialize the process module, given a maximum number of jobs, and 2054104696Sjmallett * a maximum number of local jobs. 20551590Srgrimes * 20561590Srgrimes * Results: 20571590Srgrimes * none 20581590Srgrimes * 20591590Srgrimes * Side Effects: 20601590Srgrimes * lists and counters are initialized 20611590Srgrimes *----------------------------------------------------------------------- 20621590Srgrimes */ 20631590Srgrimesvoid 2064104696SjmallettJob_Init(int maxproc, int maxlocal) 20651590Srgrimes{ 20661590Srgrimes GNode *begin; /* node for commands to do at the very start */ 20671590Srgrimes 206818730Ssteve jobs = Lst_Init(FALSE); 20691590Srgrimes stoppedJobs = Lst_Init(FALSE); 20701590Srgrimes maxJobs = maxproc; 20711590Srgrimes maxLocal = maxlocal; 20721590Srgrimes nJobs = 0; 20731590Srgrimes nLocal = 0; 20741590Srgrimes jobFull = FALSE; 20751590Srgrimes 20761590Srgrimes aborting = 0; 20771590Srgrimes errors = 0; 20781590Srgrimes 207969527Swill lastNode = NULL; 20801590Srgrimes 2081137202Sharti if (maxJobs == 1 || beVerbose == 0) { 20821590Srgrimes /* 20831590Srgrimes * If only one job can run at a time, there's no need for a banner, 20841590Srgrimes * no is there? 20851590Srgrimes */ 20861590Srgrimes targFmt = ""; 20871590Srgrimes } else { 20881590Srgrimes targFmt = TARG_FMT; 20891590Srgrimes } 20908874Srgrimes 2091136840Sru Shell_Init(); 209218730Ssteve if (commandShell->exit == NULL) { 20931590Srgrimes commandShell->exit = ""; 20941590Srgrimes } 209518730Ssteve if (commandShell->echo == NULL) { 20961590Srgrimes commandShell->echo = ""; 20971590Srgrimes } 20981590Srgrimes 20991590Srgrimes /* 21001590Srgrimes * Catch the four signals that POSIX specifies if they aren't ignored. 21011590Srgrimes * JobPassSig will take care of calling JobInterrupt if appropriate. 21021590Srgrimes */ 210318730Ssteve if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 210418730Ssteve (void) signal(SIGINT, JobPassSig); 21051590Srgrimes } 210618730Ssteve if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 210718730Ssteve (void) signal(SIGHUP, JobPassSig); 21081590Srgrimes } 210918730Ssteve if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 211018730Ssteve (void) signal(SIGQUIT, JobPassSig); 21111590Srgrimes } 211218730Ssteve if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 211318730Ssteve (void) signal(SIGTERM, JobPassSig); 21141590Srgrimes } 21151590Srgrimes /* 21161590Srgrimes * There are additional signals that need to be caught and passed if 21171590Srgrimes * either the export system wants to be told directly of signals or if 21181590Srgrimes * we're giving each job its own process group (since then it won't get 21191590Srgrimes * signals from the terminal driver as we own the terminal) 21201590Srgrimes */ 2121137202Sharti#if defined(USE_PGRP) 212218730Ssteve if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { 212318730Ssteve (void) signal(SIGTSTP, JobPassSig); 21241590Srgrimes } 212518730Ssteve if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { 212618730Ssteve (void) signal(SIGTTOU, JobPassSig); 21271590Srgrimes } 212818730Ssteve if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { 212918730Ssteve (void) signal(SIGTTIN, JobPassSig); 21301590Srgrimes } 213118730Ssteve if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { 213218730Ssteve (void) signal(SIGWINCH, JobPassSig); 21331590Srgrimes } 21341590Srgrimes#endif 21358874Srgrimes 2136104475Sphk#ifdef USE_KQUEUE 2137104475Sphk if ((kqfd = kqueue()) == -1) { 2138104475Sphk Punt("kqueue: %s", strerror(errno)); 2139104475Sphk } 2140104475Sphk#endif 2141104475Sphk 214218730Ssteve begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); 21431590Srgrimes 214469527Swill if (begin != NULL) { 214518730Ssteve JobStart(begin, JOB_SPECIAL, (Job *)0); 21461590Srgrimes while (nJobs) { 21471590Srgrimes Job_CatchOutput(); 214818730Ssteve Job_CatchChildren(!usePipes); 21491590Srgrimes } 21501590Srgrimes } 215118730Ssteve postCommands = Targ_FindNode(".END", TARG_CREATE); 21521590Srgrimes} 21531590Srgrimes 21541590Srgrimes/*- 21551590Srgrimes *----------------------------------------------------------------------- 21561590Srgrimes * Job_Full -- 21571590Srgrimes * See if the job table is full. It is considered full if it is OR 21581590Srgrimes * if we are in the process of aborting OR if we have 21591590Srgrimes * reached/exceeded our local quota. This prevents any more jobs 21601590Srgrimes * from starting up. 21611590Srgrimes * 21621590Srgrimes * Results: 21631590Srgrimes * TRUE if the job table is full, FALSE otherwise 21641590Srgrimes * Side Effects: 21651590Srgrimes * None. 21661590Srgrimes *----------------------------------------------------------------------- 21671590Srgrimes */ 21681590SrgrimesBoolean 2169104696SjmallettJob_Full(void) 21701590Srgrimes{ 217118730Ssteve return(aborting || jobFull); 21721590Srgrimes} 21731590Srgrimes 21741590Srgrimes/*- 21751590Srgrimes *----------------------------------------------------------------------- 21761590Srgrimes * Job_Empty -- 21771590Srgrimes * See if the job table is empty. Because the local concurrency may 21781590Srgrimes * be set to 0, it is possible for the job table to become empty, 21791590Srgrimes * while the list of stoppedJobs remains non-empty. In such a case, 21801590Srgrimes * we want to restart as many jobs as we can. 21811590Srgrimes * 21821590Srgrimes * Results: 21831590Srgrimes * TRUE if it is. FALSE if it ain't. 21841590Srgrimes * 21851590Srgrimes * Side Effects: 21861590Srgrimes * None. 21871590Srgrimes * 21881590Srgrimes * ----------------------------------------------------------------------- 21891590Srgrimes */ 21901590SrgrimesBoolean 2191104696SjmallettJob_Empty(void) 21921590Srgrimes{ 21931590Srgrimes if (nJobs == 0) { 21941590Srgrimes if (!Lst_IsEmpty(stoppedJobs) && !aborting) { 21951590Srgrimes /* 21961590Srgrimes * The job table is obviously not full if it has no jobs in 21971590Srgrimes * it...Try and restart the stopped jobs. 21981590Srgrimes */ 21991590Srgrimes jobFull = FALSE; 220018730Ssteve JobRestartJobs(); 22011590Srgrimes return(FALSE); 22021590Srgrimes } else { 22031590Srgrimes return(TRUE); 22041590Srgrimes } 22051590Srgrimes } else { 22061590Srgrimes return(FALSE); 22071590Srgrimes } 22081590Srgrimes} 22091590Srgrimes 22101590Srgrimes/*- 22111590Srgrimes *----------------------------------------------------------------------- 22121590Srgrimes * JobMatchShell -- 22131590Srgrimes * Find a matching shell in 'shells' given its final component. 22141590Srgrimes * 22151590Srgrimes * Results: 22161590Srgrimes * A pointer to the Shell structure. 22171590Srgrimes * 22181590Srgrimes * Side Effects: 22191590Srgrimes * None. 22201590Srgrimes * 22211590Srgrimes *----------------------------------------------------------------------- 22221590Srgrimes */ 22231590Srgrimesstatic Shell * 2224104696SjmallettJobMatchShell(char *name) 22251590Srgrimes{ 222694584Sobrien Shell *sh; /* Pointer into shells table */ 222794584Sobrien Shell *match; /* Longest-matching shell */ 222894584Sobrien char *cp1, 22291590Srgrimes *cp2; 22301590Srgrimes char *eoname; 22311590Srgrimes 223218730Ssteve eoname = name + strlen(name); 22331590Srgrimes 223418730Ssteve match = NULL; 22351590Srgrimes 22361590Srgrimes for (sh = shells; sh->name != NULL; sh++) { 223718730Ssteve for (cp1 = eoname - strlen(sh->name), cp2 = sh->name; 22381590Srgrimes *cp1 != '\0' && *cp1 == *cp2; 22391590Srgrimes cp1++, cp2++) { 22401590Srgrimes continue; 22411590Srgrimes } 22421590Srgrimes if (*cp1 != *cp2) { 22431590Srgrimes continue; 224418730Ssteve } else if (match == NULL || strlen(match->name) < strlen(sh->name)) { 224518730Ssteve match = sh; 22461590Srgrimes } 22471590Srgrimes } 2248136840Sru return(match); 22491590Srgrimes} 22501590Srgrimes 22511590Srgrimes/*- 22521590Srgrimes *----------------------------------------------------------------------- 22531590Srgrimes * Job_ParseShell -- 22541590Srgrimes * Parse a shell specification and set up commandShell, shellPath 22551590Srgrimes * and shellName appropriately. 22561590Srgrimes * 22571590Srgrimes * Results: 22581590Srgrimes * FAILURE if the specification was incorrect. 22591590Srgrimes * 22601590Srgrimes * Side Effects: 22611590Srgrimes * commandShell points to a Shell structure (either predefined or 22621590Srgrimes * created from the shell spec), shellPath is the full path of the 22631590Srgrimes * shell described by commandShell, while shellName is just the 22641590Srgrimes * final component of shellPath. 22651590Srgrimes * 22661590Srgrimes * Notes: 22671590Srgrimes * A shell specification consists of a .SHELL target, with dependency 22681590Srgrimes * operator, followed by a series of blank-separated words. Double 22691590Srgrimes * quotes can be used to use blanks in words. A backslash escapes 22701590Srgrimes * anything (most notably a double-quote and a space) and 22711590Srgrimes * provides the functionality it does in C. Each word consists of 22721590Srgrimes * keyword and value separated by an equal sign. There should be no 22731590Srgrimes * unnecessary spaces in the word. The keywords are as follows: 22741590Srgrimes * name Name of shell. 22751590Srgrimes * path Location of shell. Overrides "name" if given 22761590Srgrimes * quiet Command to turn off echoing. 22771590Srgrimes * echo Command to turn echoing on 22781590Srgrimes * filter Result of turning off echoing that shouldn't be 22791590Srgrimes * printed. 22801590Srgrimes * echoFlag Flag to turn echoing on at the start 22811590Srgrimes * errFlag Flag to turn error checking on at the start 22821590Srgrimes * hasErrCtl True if shell has error checking control 22831590Srgrimes * check Command to turn on error checking if hasErrCtl 22841590Srgrimes * is TRUE or template of command to echo a command 22851590Srgrimes * for which error checking is off if hasErrCtl is 22861590Srgrimes * FALSE. 22871590Srgrimes * ignore Command to turn off error checking if hasErrCtl 22881590Srgrimes * is TRUE or template of command to execute a 22891590Srgrimes * command so as to ignore any errors it returns if 22901590Srgrimes * hasErrCtl is FALSE. 22911590Srgrimes * 22921590Srgrimes *----------------------------------------------------------------------- 22931590Srgrimes */ 22941590SrgrimesReturnStatus 2295104696SjmallettJob_ParseShell(char *line) 22961590Srgrimes{ 22971590Srgrimes char **words; 22981590Srgrimes int wordCount; 229994584Sobrien char **argv; 230094584Sobrien int argc; 23011590Srgrimes char *path; 2302136840Sru Shell newShell, *sh; 23031590Srgrimes Boolean fullSpec = FALSE; 23041590Srgrimes 230598500Sjmallett while (isspace((unsigned char) *line)) { 23061590Srgrimes line++; 23071590Srgrimes } 230818730Ssteve words = brk_string(line, &wordCount, TRUE); 23091590Srgrimes 231069531Swill memset(&newShell, 0, sizeof(newShell)); 23118874Srgrimes 23121590Srgrimes /* 23131590Srgrimes * Parse the specification by keyword 23141590Srgrimes */ 231518730Ssteve for (path = NULL, argc = wordCount - 1, argv = words + 1; 23161590Srgrimes argc != 0; 23171590Srgrimes argc--, argv++) { 231818730Ssteve if (strncmp(*argv, "path=", 5) == 0) { 23191590Srgrimes path = &argv[0][5]; 232018730Ssteve } else if (strncmp(*argv, "name=", 5) == 0) { 23211590Srgrimes newShell.name = &argv[0][5]; 23221590Srgrimes } else { 232318730Ssteve if (strncmp(*argv, "quiet=", 6) == 0) { 23241590Srgrimes newShell.echoOff = &argv[0][6]; 232518730Ssteve } else if (strncmp(*argv, "echo=", 5) == 0) { 23261590Srgrimes newShell.echoOn = &argv[0][5]; 232718730Ssteve } else if (strncmp(*argv, "filter=", 7) == 0) { 23281590Srgrimes newShell.noPrint = &argv[0][7]; 23291590Srgrimes newShell.noPLen = strlen(newShell.noPrint); 233018730Ssteve } else if (strncmp(*argv, "echoFlag=", 9) == 0) { 23311590Srgrimes newShell.echo = &argv[0][9]; 233218730Ssteve } else if (strncmp(*argv, "errFlag=", 8) == 0) { 23331590Srgrimes newShell.exit = &argv[0][8]; 233418730Ssteve } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { 23351590Srgrimes char c = argv[0][10]; 23361590Srgrimes newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && 233718730Ssteve (c != 'T') && (c != 't')); 233818730Ssteve } else if (strncmp(*argv, "check=", 6) == 0) { 23391590Srgrimes newShell.errCheck = &argv[0][6]; 234018730Ssteve } else if (strncmp(*argv, "ignore=", 7) == 0) { 23411590Srgrimes newShell.ignErr = &argv[0][7]; 23421590Srgrimes } else { 234318730Ssteve Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", 23441590Srgrimes *argv); 234518730Ssteve return(FAILURE); 23461590Srgrimes } 23471590Srgrimes fullSpec = TRUE; 23481590Srgrimes } 23491590Srgrimes } 23501590Srgrimes 235118730Ssteve if (path == NULL) { 23521590Srgrimes /* 23531590Srgrimes * If no path was given, the user wants one of the pre-defined shells, 23541590Srgrimes * yes? So we find the one s/he wants with the help of JobMatchShell 23551590Srgrimes * and set things up the right way. shellPath will be set up by 23561590Srgrimes * Job_Init. 23571590Srgrimes */ 235818730Ssteve if (newShell.name == NULL) { 235918730Ssteve Parse_Error(PARSE_FATAL, "Neither path nor name specified"); 236018730Ssteve return(FAILURE); 23611590Srgrimes } else { 2362136840Sru if ((sh = JobMatchShell(newShell.name)) == NULL) { 2363136840Sru Parse_Error(PARSE_FATAL, "%s: no matching shell", 2364136840Sru newShell.name); 2365136840Sru return(FAILURE); 2366136840Sru } 2367136840Sru commandShell = sh; 23681590Srgrimes shellName = newShell.name; 23691590Srgrimes } 23701590Srgrimes } else { 23711590Srgrimes /* 23721590Srgrimes * The user provided a path. If s/he gave nothing else (fullSpec is 23731590Srgrimes * FALSE), try and find a matching shell in the ones we know of. 23741590Srgrimes * Else we just take the specification at its word and copy it 23751590Srgrimes * to a new location. In either case, we need to record the 23761590Srgrimes * path the user gave for the shell. 23771590Srgrimes */ 23781590Srgrimes shellPath = path; 237918730Ssteve path = strrchr(path, '/'); 238018730Ssteve if (path == NULL) { 23811590Srgrimes path = shellPath; 23821590Srgrimes } else { 23831590Srgrimes path += 1; 23841590Srgrimes } 238518730Ssteve if (newShell.name != NULL) { 23861590Srgrimes shellName = newShell.name; 23871590Srgrimes } else { 23881590Srgrimes shellName = path; 23891590Srgrimes } 23901590Srgrimes if (!fullSpec) { 2391136840Sru if ((sh = JobMatchShell(shellName)) == NULL) { 2392136840Sru Parse_Error(PARSE_FATAL, "%s: no matching shell", 2393136840Sru shellName); 2394136840Sru return(FAILURE); 2395136840Sru } 2396136840Sru commandShell = sh; 23971590Srgrimes } else { 23981590Srgrimes commandShell = (Shell *) emalloc(sizeof(Shell)); 23991590Srgrimes *commandShell = newShell; 24001590Srgrimes } 24011590Srgrimes } 24021590Srgrimes 24031590Srgrimes if (commandShell->echoOn && commandShell->echoOff) { 24041590Srgrimes commandShell->hasEchoCtl = TRUE; 24051590Srgrimes } 24068874Srgrimes 24071590Srgrimes if (!commandShell->hasErrCtl) { 240818730Ssteve if (commandShell->errCheck == NULL) { 24091590Srgrimes commandShell->errCheck = ""; 24101590Srgrimes } 241118730Ssteve if (commandShell->ignErr == NULL) { 24121590Srgrimes commandShell->ignErr = "%s\n"; 24131590Srgrimes } 24141590Srgrimes } 24158874Srgrimes 24161590Srgrimes return SUCCESS; 24171590Srgrimes} 24181590Srgrimes 24191590Srgrimes/*- 24201590Srgrimes *----------------------------------------------------------------------- 24211590Srgrimes * JobInterrupt -- 24221590Srgrimes * Handle the receipt of an interrupt. 24231590Srgrimes * 24241590Srgrimes * Results: 24251590Srgrimes * None 24261590Srgrimes * 24271590Srgrimes * Side Effects: 24281590Srgrimes * All children are killed. Another job will be started if the 24291590Srgrimes * .INTERRUPT target was given. 24301590Srgrimes *----------------------------------------------------------------------- 24311590Srgrimes */ 24321590Srgrimesstatic void 2433104696SjmallettJobInterrupt(int runINTERRUPT, int signo) 24341590Srgrimes{ 24351590Srgrimes LstNode ln; /* element in job table */ 243662830Swsanchez Job *job = NULL; /* job descriptor in that element */ 24371590Srgrimes GNode *interrupt; /* the node describing the .INTERRUPT target */ 24388874Srgrimes 24391590Srgrimes aborting = ABORT_INTERRUPT; 24401590Srgrimes 2441104125Sjmallett (void) Lst_Open(jobs); 244269527Swill while ((ln = Lst_Next(jobs)) != NULL) { 244318730Ssteve job = (Job *) Lst_Datum(ln); 24441590Srgrimes 244518730Ssteve if (!Targ_Precious(job->node)) { 244618730Ssteve char *file = (job->node->path == NULL ? 24471590Srgrimes job->node->name : 24481590Srgrimes job->node->path); 244918730Ssteve if (!noExecute && eunlink(file) != -1) { 245018730Ssteve Error("*** %s removed", file); 24511590Srgrimes } 24521590Srgrimes } 24531590Srgrimes if (job->pid) { 2454103545Sjmallett DEBUGF(JOB, ("JobInterrupt passing signal to child %d.\n", 2455103545Sjmallett job->pid)); 245618730Ssteve KILL(job->pid, signo); 245718730Ssteve } 245818730Ssteve } 245918730Ssteve 24601590Srgrimes if (runINTERRUPT && !touchFlag) { 246118730Ssteve interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 246269527Swill if (interrupt != NULL) { 24631590Srgrimes ignoreErrors = FALSE; 24641590Srgrimes 246518730Ssteve JobStart(interrupt, JOB_IGNDOTS, (Job *)0); 24661590Srgrimes while (nJobs) { 24671590Srgrimes Job_CatchOutput(); 246818730Ssteve Job_CatchChildren(!usePipes); 24691590Srgrimes } 24701590Srgrimes } 24711590Srgrimes } 24721590Srgrimes} 24731590Srgrimes 24741590Srgrimes/* 24751590Srgrimes *----------------------------------------------------------------------- 247694594Sobrien * Job_Finish -- 24771590Srgrimes * Do final processing such as the running of the commands 24788874Srgrimes * attached to the .END target. 24791590Srgrimes * 24801590Srgrimes * Results: 24811590Srgrimes * Number of errors reported. 24821590Srgrimes *----------------------------------------------------------------------- 24831590Srgrimes */ 24841590Srgrimesint 2485104696SjmallettJob_Finish(void) 24861590Srgrimes{ 248769527Swill if (postCommands != NULL && !Lst_IsEmpty(postCommands->commands)) { 24881590Srgrimes if (errors) { 248918730Ssteve Error("Errors reported so .END ignored"); 24901590Srgrimes } else { 249118730Ssteve JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); 24921590Srgrimes 24931590Srgrimes while (nJobs) { 24941590Srgrimes Job_CatchOutput(); 249518730Ssteve Job_CatchChildren(!usePipes); 24961590Srgrimes } 24971590Srgrimes } 24981590Srgrimes } 24991590Srgrimes return(errors); 25001590Srgrimes} 25011590Srgrimes 25021590Srgrimes/*- 25031590Srgrimes *----------------------------------------------------------------------- 25041590Srgrimes * Job_Wait -- 25051590Srgrimes * Waits for all running jobs to finish and returns. Sets 'aborting' 25061590Srgrimes * to ABORT_WAIT to prevent other jobs from starting. 25071590Srgrimes * 25081590Srgrimes * Results: 25091590Srgrimes * None. 25101590Srgrimes * 25111590Srgrimes * Side Effects: 25121590Srgrimes * Currently running jobs finish. 25131590Srgrimes * 25141590Srgrimes *----------------------------------------------------------------------- 25151590Srgrimes */ 25161590Srgrimesvoid 2517104696SjmallettJob_Wait(void) 25181590Srgrimes{ 25191590Srgrimes aborting = ABORT_WAIT; 25201590Srgrimes while (nJobs != 0) { 25211590Srgrimes Job_CatchOutput(); 25221590Srgrimes Job_CatchChildren(!usePipes); 25231590Srgrimes } 25241590Srgrimes aborting = 0; 25251590Srgrimes} 25261590Srgrimes 25271590Srgrimes/*- 25281590Srgrimes *----------------------------------------------------------------------- 25291590Srgrimes * Job_AbortAll -- 25301590Srgrimes * Abort all currently running jobs without handling output or anything. 25311590Srgrimes * This function is to be called only in the event of a major 25321590Srgrimes * error. Most definitely NOT to be called from JobInterrupt. 25331590Srgrimes * 25341590Srgrimes * Results: 25351590Srgrimes * None 25361590Srgrimes * 25371590Srgrimes * Side Effects: 25381590Srgrimes * All children are killed, not just the firstborn 25391590Srgrimes *----------------------------------------------------------------------- 25401590Srgrimes */ 25411590Srgrimesvoid 2542104696SjmallettJob_AbortAll(void) 25431590Srgrimes{ 254418730Ssteve LstNode ln; /* element in job table */ 25451590Srgrimes Job *job; /* the job descriptor in that element */ 25461590Srgrimes int foo; 25478874Srgrimes 25481590Srgrimes aborting = ABORT_ERROR; 25498874Srgrimes 25501590Srgrimes if (nJobs) { 25511590Srgrimes 255218730Ssteve (void) Lst_Open(jobs); 255369527Swill while ((ln = Lst_Next(jobs)) != NULL) { 255418730Ssteve job = (Job *) Lst_Datum(ln); 25551590Srgrimes 25561590Srgrimes /* 25571590Srgrimes * kill the child process with increasingly drastic signals to make 25588874Srgrimes * darn sure it's dead. 25591590Srgrimes */ 25601590Srgrimes KILL(job->pid, SIGINT); 25611590Srgrimes KILL(job->pid, SIGKILL); 25621590Srgrimes } 25631590Srgrimes } 25648874Srgrimes 25651590Srgrimes /* 25661590Srgrimes * Catch as many children as want to report in at first, then give up 25671590Srgrimes */ 256818730Ssteve while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) 25691590Srgrimes continue; 25701590Srgrimes} 257118730Ssteve 257218730Ssteve/*- 257318730Ssteve *----------------------------------------------------------------------- 257418730Ssteve * JobRestartJobs -- 257518730Ssteve * Tries to restart stopped jobs if there are slots available. 257618730Ssteve * Note that this tries to restart them regardless of pending errors. 257718730Ssteve * It's not good to leave stopped jobs lying around! 257818730Ssteve * 257918730Ssteve * Results: 258018730Ssteve * None. 258118730Ssteve * 258218730Ssteve * Side Effects: 258318730Ssteve * Resumes(and possibly migrates) jobs. 258418730Ssteve * 258518730Ssteve *----------------------------------------------------------------------- 258618730Ssteve */ 258718730Sstevestatic void 2588104696SjmallettJobRestartJobs(void) 258918730Ssteve{ 259018730Ssteve while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { 2591103545Sjmallett DEBUGF(JOB, ("Job queue is not full. Restarting a stopped job.\n")); 259218730Ssteve JobRestart((Job *)Lst_DeQueue(stoppedJobs)); 259318730Ssteve } 259418730Ssteve} 2595