job.c revision 142457
1141104Sharti/*- 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 142457 2005-02-25 13:16:56Z 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> 106141104Sharti#include <sys/select.h> 1071590Srgrimes#include <sys/stat.h> 108107447Sru#ifdef USE_KQUEUE 109104475Sphk#include <sys/event.h> 110107447Sru#endif 1111590Srgrimes#include <sys/wait.h> 112141104Sharti#include <ctype.h> 11394506Scharnier#include <errno.h> 1145814Sjkh#include <fcntl.h> 1151590Srgrimes#include <string.h> 1165814Sjkh#include <signal.h> 117141104Sharti#include <stdlib.h> 11880381Ssheldonh#include <unistd.h> 11994506Scharnier#include <utime.h> 120141104Sharti 121141104Sharti#include "arch.h" 122142457Sharti#include "buf.h" 123141104Sharti#include "compat.h" 1241590Srgrimes#include "dir.h" 125141104Sharti#include "globals.h" 126141104Sharti#include "GNode.h" 1271590Srgrimes#include "job.h" 128141104Sharti#include "make.h" 129141104Sharti#include "parse.h" 1301590Srgrimes#include "pathnames.h" 131141104Sharti#include "str.h" 132141104Sharti#include "targ.h" 133141104Sharti#include "util.h" 134141104Sharti#include "var.h" 1351590Srgrimes 136137202Sharti#define STATIC static 137137202Sharti 1381590Srgrimes/* 1398874Srgrimes * error handling variables 1401590Srgrimes */ 1411590Srgrimesstatic int errors = 0; /* number of errors reported */ 1421590Srgrimesstatic int aborting = 0; /* why is the make aborting? */ 143103503Sjmallett#define ABORT_ERROR 1 /* Because of an error */ 144103503Sjmallett#define ABORT_INTERRUPT 2 /* Because it was interrupted */ 145103503Sjmallett#define ABORT_WAIT 3 /* Waiting for jobs to finish */ 1461590Srgrimes 14718730Ssteve/* 14818730Ssteve * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file 14918730Ssteve * is a char! So when we go above 127 we turn negative! 15018730Ssteve */ 151138232Sharti#define FILENO(a) ((unsigned)fileno(a)) 1521590Srgrimes 1531590Srgrimes/* 1541590Srgrimes * post-make command processing. The node postCommands is really just the 1551590Srgrimes * .END target but we keep it around to avoid having to search for it 1561590Srgrimes * all the time. 1571590Srgrimes */ 1581590Srgrimesstatic GNode *postCommands; /* node containing commands to execute when 1591590Srgrimes * everything else is done */ 1601590Srgrimesstatic int numCommands; /* The number of commands actually printed 1611590Srgrimes * for a target. Should this number be 1621590Srgrimes * 0, no shell will be executed. */ 1631590Srgrimes 1641590Srgrimes/* 1651590Srgrimes * Return values from JobStart. 1661590Srgrimes */ 167103503Sjmallett#define JOB_RUNNING 0 /* Job is running */ 168103503Sjmallett#define JOB_ERROR 1 /* Error in starting the job */ 169103503Sjmallett#define JOB_FINISHED 2 /* The job is already finished */ 170103503Sjmallett#define JOB_STOPPED 3 /* The job is stopped */ 1711590Srgrimes 1721590Srgrimes/* 17368898Skris * tfile is used to build temp file names to store shell commands to 174138232Sharti * execute. 17568898Skris */ 17668898Skrisstatic char tfile[sizeof(TMPPAT)]; 17768898Skris 17868898Skris/* 1791590Srgrimes * Descriptions for various shells. 1801590Srgrimes */ 181138228Shartistatic const DEF_SHELL_STRUCT(CShell, const) shells[] = { 1821590Srgrimes /* 1831590Srgrimes * CSH description. The csh can do echo control by playing 1841590Srgrimes * with the setting of the 'echo' shell variable. Sadly, 1851590Srgrimes * however, it is unable to do error control nicely. 1861590Srgrimes */ 1871590Srgrimes{ 1881590Srgrimes "csh", 189136841Sru TRUE, "unset verbose", "set verbose", "unset verbose", 13, 1901590Srgrimes FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"", 1911590Srgrimes "v", "e", 1921590Srgrimes}, 1931590Srgrimes /* 1941590Srgrimes * SH description. Echo control is also possible and, under 1951590Srgrimes * sun UNIX anyway, one can even control error checking. 1961590Srgrimes */ 1971590Srgrimes{ 1981590Srgrimes "sh", 1991590Srgrimes TRUE, "set -", "set -v", "set -", 5, 20018730Ssteve TRUE, "set -e", "set +e", 20118730Ssteve#ifdef OLDBOURNESHELL 2021590Srgrimes FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", 20318730Ssteve#endif 2041590Srgrimes "v", "e", 2051590Srgrimes}, 2061590Srgrimes /* 20764739Sgreen * KSH description. The Korn shell has a superset of 20864739Sgreen * the Bourne shell's functionality. 20964739Sgreen */ 21064739Sgreen{ 21164739Sgreen "ksh", 21264739Sgreen TRUE, "set -", "set -v", "set -", 5, 21364739Sgreen TRUE, "set -e", "set +e", 21464739Sgreen "v", "e", 21564739Sgreen}, 2161590Srgrimes}; 217138079Shartistatic Shell *commandShell = NULL; /* this is the shell to which we pass 218138079Sharti * all commands in the Makefile. It is 219138079Sharti * set by the Job_ParseShell function */ 220138079Shartichar *shellPath = NULL, /* full pathname of executable image */ 221138079Sharti *shellName = NULL; /* last component of shell */ 2221590Srgrimes 2231590Srgrimes 224139062Shartiint maxJobs; /* The most children we can run at once */ 22518730SsteveSTATIC int nJobs; /* The number of children currently running */ 226138916Sharti 227138916Sharti/* The structures that describe them */ 228138916ShartiSTATIC Lst jobs = Lst_Initializer(jobs); 229138916Sharti 23018730SsteveSTATIC Boolean jobFull; /* Flag to tell when the job table is full. It 2311590Srgrimes * is set TRUE when (1) the total number of 232137572Sphk * running jobs equals the maximum allowed */ 233104475Sphk#ifdef USE_KQUEUE 234104475Sphkstatic int kqfd; /* File descriptor obtained by kqueue() */ 235104475Sphk#else 2361590Srgrimesstatic fd_set outputs; /* Set of descriptors of pipes connected to 2371590Srgrimes * the output channels of children */ 2381590Srgrimes#endif 2391590Srgrimes 24018730SsteveSTATIC GNode *lastNode; /* The node for which output was most recently 2411590Srgrimes * produced. */ 242141252ShartiSTATIC const char *targFmt; /* Format string to use to head output from a 2431590Srgrimes * job when it's not the most-recent job heard 2441590Srgrimes * from */ 2451590Srgrimes 246137202Sharti#define TARG_FMT "--- %s ---\n" /* Default format */ 247137202Sharti#define MESSAGE(fp, gn) \ 248138232Sharti fprintf(fp, targFmt, gn->name); 24918730Ssteve 2501590Srgrimes/* 251137252Sharti * When JobStart attempts to run a job but isn't allowed to 252137252Sharti * or when Job_CatchChildren detects a job that has 253137252Sharti * been stopped somehow, the job is placed on the stoppedJobs queue to be run 2548874Srgrimes * when the next job finishes. 255138916Sharti * 256138916Sharti * Lst of Job structures describing jobs that were stopped due to 257138916Sharti * concurrency limits or externally 2581590Srgrimes */ 259138916ShartiSTATIC Lst stoppedJobs = Lst_Initializer(stoppedJobs); 2601590Srgrimes 261137606SphkSTATIC int fifoFd; /* Fd of our job fifo */ 262137606SphkSTATIC char fifoName[] = "/tmp/make_fifo_XXXXXXXXX"; 263137606SphkSTATIC int fifoMaster; 2641590Srgrimes 265137605Shartistatic sig_atomic_t interrupted; 266137605Sharti 267137605Sharti 2681590Srgrimes#if defined(USE_PGRP) && defined(SYSV) 26918730Ssteve# define KILL(pid, sig) killpg(-(pid), (sig)) 2701590Srgrimes#else 2711590Srgrimes# if defined(USE_PGRP) 27218730Ssteve# define KILL(pid, sig) killpg((pid), (sig)) 2731590Srgrimes# else 27418730Ssteve# define KILL(pid, sig) kill((pid), (sig)) 2751590Srgrimes# endif 2761590Srgrimes#endif 2771590Srgrimes 27818730Ssteve/* 27918730Ssteve * Grmpf... There is no way to set bits of the wait structure 28018730Ssteve * anymore with the stupid W*() macros. I liked the union wait 28118730Ssteve * stuff much more. So, we devise our own macros... This is 28218730Ssteve * really ugly, use dramamine sparingly. You have been warned. 28318730Ssteve */ 284103503Sjmallett#define W_SETMASKED(st, val, fun) \ 28518730Ssteve { \ 286138232Sharti int sh = (int)~0; \ 28718730Ssteve int mask = fun(sh); \ 28818730Ssteve \ 28918730Ssteve for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \ 29018730Ssteve continue; \ 29118730Ssteve *(st) = (*(st) & ~mask) | ((val) << sh); \ 29218730Ssteve } 29318730Ssteve 294103503Sjmallett#define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) 295103503Sjmallett#define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS) 29618730Ssteve 29718730Ssteve 29892921Simpstatic int JobCondPassSig(void *, void *); 29992921Simpstatic void JobPassSig(int); 30092921Simpstatic int JobPrintCommand(void *, void *); 30192921Simpstatic int JobSaveCommand(void *, void *); 30292921Simpstatic void JobClose(Job *); 30392921Simpstatic void JobFinish(Job *, int *); 30492921Simpstatic void JobExec(Job *, char **); 30592921Simpstatic void JobMakeArgv(Job *, char **); 30692921Simpstatic void JobRestart(Job *); 30792921Simpstatic int JobStart(GNode *, int, Job *); 30892921Simpstatic char *JobOutput(Job *, char *, char *, int); 30992921Simpstatic void JobDoOutput(Job *, Boolean); 310138228Shartistatic Shell *JobMatchShell(const char *); 31192921Simpstatic void JobInterrupt(int, int); 31292921Simpstatic void JobRestartJobs(void); 3131590Srgrimes 314137605Sharti/* 315137605Sharti * JobCatchSignal 316137605Sharti * 317137605Sharti * Got a signal. Set global variables and hope that someone will 318137605Sharti * handle it. 319137605Sharti */ 320137605Shartistatic void 321137605ShartiJobCatchSig(int signo) 322137605Sharti{ 323137605Sharti 324137605Sharti interrupted = signo; 325137605Sharti} 326137605Sharti 3271590Srgrimes/*- 3281590Srgrimes *----------------------------------------------------------------------- 3291590Srgrimes * JobCondPassSig -- 330137252Sharti * Pass a signal to a job if USE_PGRP is defined. 3311590Srgrimes * 3321590Srgrimes * Results: 3331590Srgrimes * === 0 3341590Srgrimes * 3351590Srgrimes * Side Effects: 3361590Srgrimes * None, except the job may bite it. 3371590Srgrimes * 3381590Srgrimes *----------------------------------------------------------------------- 3391590Srgrimes */ 3401590Srgrimesstatic int 341104696SjmallettJobCondPassSig(void *jobp, void *signop) 3421590Srgrimes{ 343138264Sharti Job *job = jobp; 344138232Sharti int signo = *(int *)signop; 345137202Sharti 346137252Sharti DEBUGF(JOB, ("JobCondPassSig passing signal %d to child %d.\n", 347137252Sharti signo, job->pid)); 3481590Srgrimes KILL(job->pid, signo); 349138232Sharti return (0); 3501590Srgrimes} 3511590Srgrimes 3521590Srgrimes/*- 3531590Srgrimes *----------------------------------------------------------------------- 3541590Srgrimes * JobPassSig -- 355137252Sharti * Pass a signal on to all local jobs if 3561590Srgrimes * USE_PGRP is defined, then die ourselves. 3571590Srgrimes * 3581590Srgrimes * Results: 3591590Srgrimes * None. 3601590Srgrimes * 3611590Srgrimes * Side Effects: 3621590Srgrimes * We die by the same signal. 3638874Srgrimes * 3641590Srgrimes *----------------------------------------------------------------------- 3651590Srgrimes */ 3661590Srgrimesstatic void 367104696SjmallettJobPassSig(int signo) 3681590Srgrimes{ 36918730Ssteve sigset_t nmask, omask; 37018730Ssteve struct sigaction act; 3718874Srgrimes 372137605Sharti sigemptyset(&nmask); 373137605Sharti sigaddset(&nmask, signo); 374137605Sharti sigprocmask(SIG_SETMASK, &nmask, &omask); 375137605Sharti 376103545Sjmallett DEBUGF(JOB, ("JobPassSig(%d) called.\n", signo)); 377138916Sharti Lst_ForEach(&jobs, JobCondPassSig, &signo); 3781590Srgrimes 3791590Srgrimes /* 3801590Srgrimes * Deal with proper cleanup based on the signal received. We only run 3811590Srgrimes * the .INTERRUPT target if the signal was in fact an interrupt. The other 3821590Srgrimes * three termination signals are more of a "get out *now*" command. 3831590Srgrimes */ 3841590Srgrimes if (signo == SIGINT) { 38518730Ssteve JobInterrupt(TRUE, signo); 3861590Srgrimes } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { 38718730Ssteve JobInterrupt(FALSE, signo); 3881590Srgrimes } 3898874Srgrimes 3901590Srgrimes /* 3911590Srgrimes * Leave gracefully if SIGQUIT, rather than core dumping. 3921590Srgrimes */ 3931590Srgrimes if (signo == SIGQUIT) { 39438520Scracauer signo = SIGINT; 3951590Srgrimes } 3968874Srgrimes 3971590Srgrimes /* 3981590Srgrimes * Send ourselves the signal now we've given the message to everyone else. 3991590Srgrimes * Note we block everything else possible while we're getting the signal. 4001590Srgrimes * This ensures that all our jobs get continued when we wake up before 4011590Srgrimes * we take any other signal. 402137605Sharti * XXX this comment seems wrong. 4031590Srgrimes */ 40418730Ssteve act.sa_handler = SIG_DFL; 40518730Ssteve sigemptyset(&act.sa_mask); 40618730Ssteve act.sa_flags = 0; 40718730Ssteve sigaction(signo, &act, NULL); 4081590Srgrimes 409138232Sharti DEBUGF(JOB, ("JobPassSig passing signal to self, mask = %x.\n", 410138232Sharti ~0 & ~(1 << (signo - 1)))); 411138232Sharti signal(signo, SIG_DFL); 4121590Srgrimes 413138232Sharti KILL(getpid(), signo); 41418730Ssteve 4155814Sjkh signo = SIGCONT; 416138916Sharti Lst_ForEach(&jobs, JobCondPassSig, &signo); 4171590Srgrimes 41818730Ssteve sigprocmask(SIG_SETMASK, &omask, NULL); 419138232Sharti sigprocmask(SIG_SETMASK, &omask, NULL); 42018730Ssteve act.sa_handler = JobPassSig; 42118730Ssteve sigaction(signo, &act, NULL); 4221590Srgrimes} 4231590Srgrimes 4241590Srgrimes/*- 4251590Srgrimes *----------------------------------------------------------------------- 4261590Srgrimes * JobCmpPid -- 4271590Srgrimes * Compare the pid of the job with the given pid and return 0 if they 4281590Srgrimes * are equal. This function is called from Job_CatchChildren via 4291590Srgrimes * Lst_Find to find the job descriptor of the finished job. 4301590Srgrimes * 4311590Srgrimes * Results: 4321590Srgrimes * 0 if the pid's match 4331590Srgrimes * 4341590Srgrimes * Side Effects: 4351590Srgrimes * None 4361590Srgrimes *----------------------------------------------------------------------- 4371590Srgrimes */ 4381590Srgrimesstatic int 439138561ShartiJobCmpPid(const void *job, const void *pid) 4401590Srgrimes{ 441138264Sharti 442138561Sharti return (*(const int *)pid - ((const Job *)job)->pid); 4431590Srgrimes} 4441590Srgrimes 4451590Srgrimes/*- 4461590Srgrimes *----------------------------------------------------------------------- 4471590Srgrimes * JobPrintCommand -- 4481590Srgrimes * Put out another command for the given job. If the command starts 4491590Srgrimes * with an @ or a - we process it specially. In the former case, 4501590Srgrimes * so long as the -s and -n flags weren't given to make, we stick 4511590Srgrimes * a shell-specific echoOff command in the script. In the latter, 4521590Srgrimes * we ignore errors for the entire job, unless the shell has error 4531590Srgrimes * control. 4541590Srgrimes * If the command is just "..." we take all future commands for this 4551590Srgrimes * job to be commands to be executed once the entire graph has been 4561590Srgrimes * made and return non-zero to signal that the end of the commands 4571590Srgrimes * was reached. These commands are later attached to the postCommands 45894594Sobrien * node and executed by Job_Finish when all things are done. 4591590Srgrimes * This function is called from JobStart via Lst_ForEach. 4601590Srgrimes * 4611590Srgrimes * Results: 4621590Srgrimes * Always 0, unless the command was "..." 4631590Srgrimes * 4641590Srgrimes * Side Effects: 4651590Srgrimes * If the command begins with a '-' and the shell has no error control, 4661590Srgrimes * the JOB_IGNERR flag is set in the job descriptor. 4671590Srgrimes * If the command is "..." and we're not ignoring such things, 4681590Srgrimes * tailCmds is set to the successor node of the cmd. 4691590Srgrimes * numCommands is incremented if the command is actually printed. 4701590Srgrimes *----------------------------------------------------------------------- 4711590Srgrimes */ 4721590Srgrimesstatic int 473104696SjmallettJobPrintCommand(void *cmdp, void *jobp) 4741590Srgrimes{ 475141258Sharti Boolean noSpecials; /* true if we shouldn't worry about 476141258Sharti * inserting special commands into 477141258Sharti * the input stream. */ 478141258Sharti Boolean shutUp = FALSE; /* true if we put a no echo command 479141258Sharti * into the command file */ 480141258Sharti Boolean errOff = FALSE; /* true if we turned error checking 481141258Sharti * off before printing the command 482141258Sharti * and need to turn it back on */ 483141258Sharti const char *cmdTemplate; /* Template to use when printing the 484141258Sharti * command */ 485141258Sharti char *cmdStart; /* Start of expanded command */ 486141258Sharti LstNode *cmdNode; /* Node for replacing the command */ 487141258Sharti char *cmd = cmdp; 488141258Sharti Job *job = jobp; 489142457Sharti Buffer *buf; 4901590Srgrimes 49118730Ssteve noSpecials = (noExecute && !(job->node->type & OP_MAKE)); 4921590Srgrimes 49318730Ssteve if (strcmp(cmd, "...") == 0) { 4948874Srgrimes job->node->type |= OP_SAVE_CMDS; 4951590Srgrimes if ((job->flags & JOB_IGNDOTS) == 0) { 496138916Sharti job->tailCmds = Lst_Succ(Lst_Member(&job->node->commands, cmd)); 497138232Sharti return (1); 4981590Srgrimes } 499138232Sharti return (0); 5001590Srgrimes } 5011590Srgrimes 502103508Sjmallett#define DBPRINTF(fmt, arg) \ 503103545Sjmallett DEBUGF(JOB, (fmt, arg)); \ 504138232Sharti fprintf(job->cmdFILE, fmt, arg); \ 505138232Sharti fflush(job->cmdFILE); 5061590Srgrimes 5071590Srgrimes numCommands += 1; 5081590Srgrimes 5091590Srgrimes /* 5101590Srgrimes * For debugging, we replace each command with the result of expanding 5111590Srgrimes * the variables in the command. 5121590Srgrimes */ 513138916Sharti cmdNode = Lst_Member(&job->node->commands, cmd); 514142457Sharti 515142457Sharti buf = Var_Subst(NULL, cmd, job->node, FALSE); 516142457Sharti cmd = Buf_GetAll(buf, NULL); 517142457Sharti Buf_Destroy(buf, FALSE); 518142457Sharti cmdStart = cmd; 519142457Sharti 520138264Sharti Lst_Replace(cmdNode, cmdStart); 5211590Srgrimes 5221590Srgrimes cmdTemplate = "%s\n"; 5231590Srgrimes 5241590Srgrimes /* 525132839Sharti * Check for leading @', -' or +'s to control echoing, error checking, 526132839Sharti * and execution on -n. 5271590Srgrimes */ 528132839Sharti while (*cmd == '@' || *cmd == '-' || *cmd == '+') { 529132839Sharti switch (*cmd) { 530132839Sharti 531132839Sharti case '@': 53260569Swill shutUp = DEBUG(LOUD) ? FALSE : TRUE; 533132839Sharti break; 534132839Sharti 535132839Sharti case '-': 5361590Srgrimes errOff = TRUE; 537132839Sharti break; 538132839Sharti 539132839Sharti case '+': 540132839Sharti if (noSpecials) { 541132839Sharti /* 542132839Sharti * We're not actually exececuting anything... 543132839Sharti * but this one needs to be - use compat mode just for it. 544132839Sharti */ 545132839Sharti Compat_RunCommand(cmdp, job->node); 546132839Sharti return (0); 547132839Sharti } 548132839Sharti break; 5491590Srgrimes } 5501590Srgrimes cmd++; 5511590Srgrimes } 5521590Srgrimes 553138232Sharti while (isspace((unsigned char)*cmd)) 5541590Srgrimes cmd++; 5551590Srgrimes 5561590Srgrimes if (shutUp) { 55718730Ssteve if (!(job->flags & JOB_SILENT) && !noSpecials && 5581590Srgrimes commandShell->hasEchoCtl) { 55918730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 5601590Srgrimes } else { 5611590Srgrimes shutUp = FALSE; 5621590Srgrimes } 5631590Srgrimes } 5641590Srgrimes 5651590Srgrimes if (errOff) { 56618730Ssteve if ( !(job->flags & JOB_IGNERR) && !noSpecials) { 5671590Srgrimes if (commandShell->hasErrCtl) { 5681590Srgrimes /* 5691590Srgrimes * we don't want the error-control commands showing 5701590Srgrimes * up either, so we turn off echoing while executing 5711590Srgrimes * them. We could put another field in the shell 5721590Srgrimes * structure to tell JobDoOutput to look for this 5731590Srgrimes * string too, but why make it any more complex than 5741590Srgrimes * it already is? 5751590Srgrimes */ 57618730Ssteve if (!(job->flags & JOB_SILENT) && !shutUp && 5771590Srgrimes commandShell->hasEchoCtl) { 57818730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 57918730Ssteve DBPRINTF("%s\n", commandShell->ignErr); 58018730Ssteve DBPRINTF("%s\n", commandShell->echoOn); 5811590Srgrimes } else { 58218730Ssteve DBPRINTF("%s\n", commandShell->ignErr); 5831590Srgrimes } 5841590Srgrimes } else if (commandShell->ignErr && 58518730Ssteve (*commandShell->ignErr != '\0')) 5861590Srgrimes { 5871590Srgrimes /* 5881590Srgrimes * The shell has no error control, so we need to be 5891590Srgrimes * weird to get it to ignore any errors from the command. 5901590Srgrimes * If echoing is turned on, we turn it off and use the 5911590Srgrimes * errCheck template to echo the command. Leave echoing 5921590Srgrimes * off so the user doesn't see the weirdness we go through 5931590Srgrimes * to ignore errors. Set cmdTemplate to use the weirdness 5941590Srgrimes * instead of the simple "%s\n" template. 5951590Srgrimes */ 59618730Ssteve if (!(job->flags & JOB_SILENT) && !shutUp && 5971590Srgrimes commandShell->hasEchoCtl) { 59818730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 59918730Ssteve DBPRINTF(commandShell->errCheck, cmd); 6001590Srgrimes shutUp = TRUE; 6011590Srgrimes } 6021590Srgrimes cmdTemplate = commandShell->ignErr; 6031590Srgrimes /* 6041590Srgrimes * The error ignoration (hee hee) is already taken care 6051590Srgrimes * of by the ignErr template, so pretend error checking 6061590Srgrimes * is still on. 6071590Srgrimes */ 6081590Srgrimes errOff = FALSE; 6091590Srgrimes } else { 6101590Srgrimes errOff = FALSE; 6111590Srgrimes } 6121590Srgrimes } else { 6131590Srgrimes errOff = FALSE; 6141590Srgrimes } 6151590Srgrimes } 6168874Srgrimes 61718730Ssteve DBPRINTF(cmdTemplate, cmd); 6188874Srgrimes 6191590Srgrimes if (errOff) { 6201590Srgrimes /* 6211590Srgrimes * If echoing is already off, there's no point in issuing the 6221590Srgrimes * echoOff command. Otherwise we issue it and pretend it was on 6231590Srgrimes * for the whole command... 6241590Srgrimes */ 625138264Sharti if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl) { 62618730Ssteve DBPRINTF("%s\n", commandShell->echoOff); 6271590Srgrimes shutUp = TRUE; 6281590Srgrimes } 62918730Ssteve DBPRINTF("%s\n", commandShell->errCheck); 6301590Srgrimes } 6311590Srgrimes if (shutUp) { 63218730Ssteve DBPRINTF("%s\n", commandShell->echoOn); 6331590Srgrimes } 634138232Sharti return (0); 6351590Srgrimes} 6361590Srgrimes 6371590Srgrimes/*- 6381590Srgrimes *----------------------------------------------------------------------- 6391590Srgrimes * JobSaveCommand -- 6401590Srgrimes * Save a command to be executed when everything else is done. 6411590Srgrimes * Callback function for JobFinish... 6421590Srgrimes * 6431590Srgrimes * Results: 6441590Srgrimes * Always returns 0 6451590Srgrimes * 6461590Srgrimes * Side Effects: 6471590Srgrimes * The command is tacked onto the end of postCommands's commands list. 6481590Srgrimes * 6491590Srgrimes *----------------------------------------------------------------------- 6501590Srgrimes */ 6511590Srgrimesstatic int 652104696SjmallettJobSaveCommand(void *cmd, void *gn) 6531590Srgrimes{ 654142457Sharti Buffer *buf; 655142457Sharti char *str; 656138232Sharti 657142457Sharti buf = Var_Subst(NULL, cmd, gn, FALSE); 658142457Sharti str = Buf_GetAll(buf, NULL); 659142457Sharti Buf_Destroy(buf, FALSE); 660142457Sharti 661142457Sharti Lst_AtEnd(&postCommands->commands, str); 662138232Sharti return (0); 6631590Srgrimes} 6641590Srgrimes 66518730Ssteve 6661590Srgrimes/*- 6671590Srgrimes *----------------------------------------------------------------------- 66818730Ssteve * JobClose -- 66918730Ssteve * Called to close both input and output pipes when a job is finished. 67018730Ssteve * 67118730Ssteve * Results: 67218730Ssteve * Nada 67318730Ssteve * 67418730Ssteve * Side Effects: 67518730Ssteve * The file descriptors associated with the job are closed. 67618730Ssteve * 67718730Ssteve *----------------------------------------------------------------------- 67818730Ssteve */ 67918730Sstevestatic void 680104696SjmallettJobClose(Job *job) 68118730Ssteve{ 682138232Sharti 68318730Ssteve if (usePipes) { 684137202Sharti#if !defined(USE_KQUEUE) 68518730Ssteve FD_CLR(job->inPipe, &outputs); 68618730Ssteve#endif 68718730Ssteve if (job->outPipe != job->inPipe) { 688138232Sharti close(job->outPipe); 68918730Ssteve } 69018730Ssteve JobDoOutput(job, TRUE); 691138232Sharti close(job->inPipe); 69218730Ssteve } else { 693138232Sharti close(job->outFd); 69418730Ssteve JobDoOutput(job, TRUE); 69518730Ssteve } 69618730Ssteve} 69718730Ssteve 69818730Ssteve/*- 69918730Ssteve *----------------------------------------------------------------------- 7001590Srgrimes * JobFinish -- 7011590Srgrimes * Do final processing for the given job including updating 7021590Srgrimes * parents and starting new jobs as available/necessary. Note 7031590Srgrimes * that we pay no attention to the JOB_IGNERR flag here. 7041590Srgrimes * This is because when we're called because of a noexecute flag 7051590Srgrimes * or something, jstat.w_status is 0 and when called from 7061590Srgrimes * Job_CatchChildren, the status is zeroed if it s/b ignored. 7071590Srgrimes * 7081590Srgrimes * Results: 7091590Srgrimes * None 7101590Srgrimes * 7111590Srgrimes * Side Effects: 7121590Srgrimes * Some nodes may be put on the toBeMade queue. 7131590Srgrimes * Final commands for the job are placed on postCommands. 7141590Srgrimes * 7151590Srgrimes * If we got an error and are aborting (aborting == ABORT_ERROR) and 7161590Srgrimes * the job list is now empty, we are done for the day. 7171590Srgrimes * If we recognized an error (errors !=0), we set the aborting flag 7181590Srgrimes * to ABORT_ERROR so no more jobs will be started. 7191590Srgrimes *----------------------------------------------------------------------- 7201590Srgrimes */ 7211590Srgrimes/*ARGSUSED*/ 7221590Srgrimesstatic void 723104696SjmallettJobFinish(Job *job, int *status) 7241590Srgrimes{ 72518730Ssteve Boolean done; 7261590Srgrimes 72718730Ssteve if ((WIFEXITED(*status) && 72818730Ssteve (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || 72918730Ssteve (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) 7301590Srgrimes { 7311590Srgrimes /* 7321590Srgrimes * If it exited non-zero and either we're doing things our 7331590Srgrimes * way or we're not ignoring errors, the job is finished. 7341590Srgrimes * Similarly, if the shell died because of a signal 7351590Srgrimes * the job is also finished. In these 7361590Srgrimes * cases, finish out the job's output before printing the exit 7371590Srgrimes * status... 7381590Srgrimes */ 73918730Ssteve JobClose(job); 7401590Srgrimes if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 741138232Sharti fclose(job->cmdFILE); 7421590Srgrimes } 7431590Srgrimes done = TRUE; 74418730Ssteve } else if (WIFEXITED(*status)) { 7451590Srgrimes /* 7461590Srgrimes * Deal with ignored errors in -B mode. We need to print a message 7471590Srgrimes * telling of the ignored error as well as setting status.w_status 7481590Srgrimes * to 0 so the next command gets run. To do this, we set done to be 74918730Ssteve * TRUE if in -B mode and the job exited non-zero. 75018730Ssteve */ 75118730Ssteve done = WEXITSTATUS(*status) != 0; 75218730Ssteve /* 75318730Ssteve * Old comment said: "Note we don't 7541590Srgrimes * want to close down any of the streams until we know we're at the 75518730Ssteve * end." 75618730Ssteve * But we do. Otherwise when are we going to print the rest of the 75718730Ssteve * stuff? 7581590Srgrimes */ 75918730Ssteve JobClose(job); 7601590Srgrimes } else { 7611590Srgrimes /* 7621590Srgrimes * No need to close things down or anything. 7631590Srgrimes */ 7641590Srgrimes done = FALSE; 7651590Srgrimes } 7668874Srgrimes 7671590Srgrimes if (done || 76818730Ssteve WIFSTOPPED(*status) || 76918730Ssteve (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) || 7701590Srgrimes DEBUG(JOB)) 7711590Srgrimes { 7721590Srgrimes FILE *out; 7738874Srgrimes 77418730Ssteve if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { 7751590Srgrimes /* 7761590Srgrimes * If output is going to a file and this job is ignoring 7771590Srgrimes * errors, arrange to have the exit status sent to the 7781590Srgrimes * output file as well. 7791590Srgrimes */ 78018730Ssteve out = fdopen(job->outFd, "w"); 78194582Sobrien if (out == NULL) 78294582Sobrien Punt("Cannot fdopen"); 7831590Srgrimes } else { 7841590Srgrimes out = stdout; 7851590Srgrimes } 7861590Srgrimes 78718730Ssteve if (WIFEXITED(*status)) { 788103545Sjmallett DEBUGF(JOB, ("Process %d exited.\n", job->pid)); 78918730Ssteve if (WEXITSTATUS(*status) != 0) { 7901590Srgrimes if (usePipes && job->node != lastNode) { 79118730Ssteve MESSAGE(out, job->node); 7921590Srgrimes lastNode = job->node; 7931590Srgrimes } 794138232Sharti fprintf(out, "*** Error code %d%s\n", 79518730Ssteve WEXITSTATUS(*status), 79618730Ssteve (job->flags & JOB_IGNERR) ? "(ignored)" : ""); 7971590Srgrimes 7981590Srgrimes if (job->flags & JOB_IGNERR) { 79918730Ssteve *status = 0; 8001590Srgrimes } 8011590Srgrimes } else if (DEBUG(JOB)) { 8021590Srgrimes if (usePipes && job->node != lastNode) { 80318730Ssteve MESSAGE(out, job->node); 8041590Srgrimes lastNode = job->node; 8051590Srgrimes } 806138232Sharti fprintf(out, "*** Completed successfully\n"); 8071590Srgrimes } 80818730Ssteve } else if (WIFSTOPPED(*status)) { 809103545Sjmallett DEBUGF(JOB, ("Process %d stopped.\n", job->pid)); 8101590Srgrimes if (usePipes && job->node != lastNode) { 81118730Ssteve MESSAGE(out, job->node); 8121590Srgrimes lastNode = job->node; 8131590Srgrimes } 814138232Sharti fprintf(out, "*** Stopped -- signal %d\n", 815137252Sharti WSTOPSIG(*status)); 8161590Srgrimes job->flags |= JOB_RESUME; 817138916Sharti Lst_AtEnd(&stoppedJobs, job); 818138232Sharti fflush(out); 8191590Srgrimes return; 82018730Ssteve } else if (WTERMSIG(*status) == SIGCONT) { 8211590Srgrimes /* 8221590Srgrimes * If the beastie has continued, shift the Job from the stopped 8231590Srgrimes * list to the running one (or re-stop it if concurrency is 8241590Srgrimes * exceeded) and go and get another child. 8251590Srgrimes */ 826137252Sharti if (job->flags & (JOB_RESUME|JOB_RESTART)) { 8271590Srgrimes if (usePipes && job->node != lastNode) { 82818730Ssteve MESSAGE(out, job->node); 8291590Srgrimes lastNode = job->node; 8301590Srgrimes } 831138232Sharti fprintf(out, "*** Continued\n"); 8321590Srgrimes } 83318730Ssteve if (!(job->flags & JOB_CONTINUING)) { 834103545Sjmallett DEBUGF(JOB, ("Warning: process %d was not continuing.\n", job->pid)); 83518730Ssteve#ifdef notdef 83618730Ssteve /* 83718730Ssteve * We don't really want to restart a job from scratch just 83818730Ssteve * because it continued, especially not without killing the 83918730Ssteve * continuing process! That's why this is ifdef'ed out. 84018730Ssteve * FD - 9/17/90 84118730Ssteve */ 8421590Srgrimes JobRestart(job); 84318730Ssteve#endif 8441590Srgrimes } 84518730Ssteve job->flags &= ~JOB_CONTINUING; 846138916Sharti Lst_AtEnd(&jobs, job); 84718730Ssteve nJobs += 1; 848137252Sharti DEBUGF(JOB, ("Process %d is continuing locally.\n", job->pid)); 84918730Ssteve if (nJobs == maxJobs) { 85018730Ssteve jobFull = TRUE; 851103545Sjmallett DEBUGF(JOB, ("Job queue is full.\n")); 85218730Ssteve } 853138232Sharti fflush(out); 85418730Ssteve return; 8551590Srgrimes } else { 8561590Srgrimes if (usePipes && job->node != lastNode) { 85718730Ssteve MESSAGE(out, job->node); 8581590Srgrimes lastNode = job->node; 8591590Srgrimes } 860138232Sharti fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); 8611590Srgrimes } 8621590Srgrimes 863138232Sharti fflush(out); 8641590Srgrimes } 8651590Srgrimes 8661590Srgrimes /* 8671590Srgrimes * Now handle the -B-mode stuff. If the beast still isn't finished, 8681590Srgrimes * try and restart the job on the next command. If JobStart says it's 8691590Srgrimes * ok, it's ok. If there's an error, this puppy is done. 8701590Srgrimes */ 871138564Sharti if (compatMake && WIFEXITED(*status) && 872138564Sharti Lst_Succ(job->node->compat_command) != NULL) { 87318730Ssteve switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { 87418730Ssteve case JOB_RUNNING: 87518730Ssteve done = FALSE; 87618730Ssteve break; 87718730Ssteve case JOB_ERROR: 87818730Ssteve done = TRUE; 87918730Ssteve W_SETEXITSTATUS(status, 1); 88018730Ssteve break; 88118730Ssteve case JOB_FINISHED: 88218730Ssteve /* 88318730Ssteve * If we got back a JOB_FINISHED code, JobStart has already 88418730Ssteve * called Make_Update and freed the job descriptor. We set 88518730Ssteve * done to false here to avoid fake cycles and double frees. 88618730Ssteve * JobStart needs to do the update so we can proceed up the 88718730Ssteve * graph when given the -n flag.. 88818730Ssteve */ 88918730Ssteve done = FALSE; 89018730Ssteve break; 891104108Sjmallett default: 892104108Sjmallett break; 8931590Srgrimes } 8941590Srgrimes } else { 8951590Srgrimes done = TRUE; 8961590Srgrimes } 8971590Srgrimes 8988874Srgrimes 8991590Srgrimes if (done && 9001590Srgrimes (aborting != ABORT_ERROR) && 9011590Srgrimes (aborting != ABORT_INTERRUPT) && 90218730Ssteve (*status == 0)) 9031590Srgrimes { 9041590Srgrimes /* 9051590Srgrimes * As long as we aren't aborting and the job didn't return a non-zero 9061590Srgrimes * status that we shouldn't ignore, we call Make_Update to update 9071590Srgrimes * the parents. In addition, any saved commands for the node are placed 9081590Srgrimes * on the .END target. 9091590Srgrimes */ 91069527Swill if (job->tailCmds != NULL) { 911138916Sharti Lst_ForEachFrom(&job->node->commands, job->tailCmds, 912138264Sharti JobSaveCommand, job->node); 9131590Srgrimes } 9141590Srgrimes job->node->made = MADE; 91518730Ssteve Make_Update(job->node); 91669531Swill free(job); 91718730Ssteve } else if (*status != 0) { 9181590Srgrimes errors += 1; 91969531Swill free(job); 9201590Srgrimes } 9211590Srgrimes 92218730Ssteve JobRestartJobs(); 9231590Srgrimes 9241590Srgrimes /* 9251590Srgrimes * Set aborting if any error. 9261590Srgrimes */ 9271590Srgrimes if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { 9281590Srgrimes /* 9291590Srgrimes * If we found any errors in this batch of children and the -k flag 9301590Srgrimes * wasn't given, we set the aborting flag so no more jobs get 9311590Srgrimes * started. 9321590Srgrimes */ 9331590Srgrimes aborting = ABORT_ERROR; 9341590Srgrimes } 9358874Srgrimes 93668898Skris if ((aborting == ABORT_ERROR) && Job_Empty()) 9371590Srgrimes /* 9381590Srgrimes * If we are aborting and the job table is now empty, we finish. 9391590Srgrimes */ 94018730Ssteve Finish(errors); 9411590Srgrimes} 9421590Srgrimes 9431590Srgrimes/*- 9441590Srgrimes *----------------------------------------------------------------------- 9451590Srgrimes * Job_Touch -- 9461590Srgrimes * Touch the given target. Called by JobStart when the -t flag was 947104696Sjmallett * given. Prints messages unless told to be silent. 9481590Srgrimes * 9491590Srgrimes * Results: 9501590Srgrimes * None 9511590Srgrimes * 9521590Srgrimes * Side Effects: 9531590Srgrimes * The data modification of the file is changed. In addition, if the 9541590Srgrimes * file did not exist, it is created. 9551590Srgrimes *----------------------------------------------------------------------- 9561590Srgrimes */ 9571590Srgrimesvoid 958104696SjmallettJob_Touch(GNode *gn, Boolean silent) 9591590Srgrimes{ 9601590Srgrimes int streamID; /* ID of stream opened to do the touch */ 96118730Ssteve struct utimbuf times; /* Times for utime() call */ 9621590Srgrimes 963138264Sharti if (gn->type & (OP_JOIN | OP_USE | OP_EXEC | OP_OPTIONAL)) { 9641590Srgrimes /* 9651590Srgrimes * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets 9661590Srgrimes * and, as such, shouldn't really be created. 9671590Srgrimes */ 9681590Srgrimes return; 9691590Srgrimes } 9708874Srgrimes 9711590Srgrimes if (!silent) { 972138232Sharti fprintf(stdout, "touch %s\n", gn->name); 973138232Sharti fflush(stdout); 9741590Srgrimes } 9751590Srgrimes 9761590Srgrimes if (noExecute) { 9771590Srgrimes return; 9781590Srgrimes } 9791590Srgrimes 9801590Srgrimes if (gn->type & OP_ARCHV) { 98118730Ssteve Arch_Touch(gn); 9821590Srgrimes } else if (gn->type & OP_LIB) { 98318730Ssteve Arch_TouchLib(gn); 9841590Srgrimes } else { 9851590Srgrimes char *file = gn->path ? gn->path : gn->name; 9861590Srgrimes 98718730Ssteve times.actime = times.modtime = now; 98818730Ssteve if (utime(file, ×) < 0){ 98918730Ssteve streamID = open(file, O_RDWR | O_CREAT, 0666); 9901590Srgrimes 9911590Srgrimes if (streamID >= 0) { 9921590Srgrimes char c; 9931590Srgrimes 9941590Srgrimes /* 9951590Srgrimes * Read and write a byte to the file to change the 9961590Srgrimes * modification time, then close the file. 9971590Srgrimes */ 9981590Srgrimes if (read(streamID, &c, 1) == 1) { 999138232Sharti lseek(streamID, (off_t)0, SEEK_SET); 1000138232Sharti write(streamID, &c, 1); 10011590Srgrimes } 10028874Srgrimes 1003138232Sharti close(streamID); 100418730Ssteve } else { 1005138232Sharti fprintf(stdout, "*** couldn't touch %s: %s", 100618730Ssteve file, strerror(errno)); 1007138232Sharti fflush(stdout); 100818730Ssteve } 10091590Srgrimes } 10101590Srgrimes } 10111590Srgrimes} 10121590Srgrimes 10131590Srgrimes/*- 10141590Srgrimes *----------------------------------------------------------------------- 10151590Srgrimes * Job_CheckCommands -- 10168874Srgrimes * Make sure the given node has all the commands it needs. 10171590Srgrimes * 10181590Srgrimes * Results: 10191590Srgrimes * TRUE if the commands list is/was ok. 10201590Srgrimes * 10211590Srgrimes * Side Effects: 10221590Srgrimes * The node will have commands from the .DEFAULT rule added to it 10231590Srgrimes * if it needs them. 10241590Srgrimes *----------------------------------------------------------------------- 10251590Srgrimes */ 10261590SrgrimesBoolean 1027104696SjmallettJob_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) 10281590Srgrimes{ 1029138232Sharti 1030138916Sharti if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->commands) && 10311590Srgrimes (gn->type & OP_LIB) == 0) { 10321590Srgrimes /* 10331590Srgrimes * No commands. Look for .DEFAULT rule from which we might infer 10348874Srgrimes * commands 10351590Srgrimes */ 1036138916Sharti if ((DEFAULT != NULL) && !Lst_IsEmpty(&DEFAULT->commands)) { 10375814Sjkh char *p1; 10381590Srgrimes /* 10391590Srgrimes * Make only looks for a .DEFAULT if the node was never the 10401590Srgrimes * target of an operator, so that's what we do too. If 10411590Srgrimes * a .DEFAULT was given, we substitute its commands for gn's 10421590Srgrimes * commands and set the IMPSRC variable to be the target's name 10431590Srgrimes * The DEFAULT node acts like a transformation rule, in that 10441590Srgrimes * gn also inherits any attributes or sources attached to 10451590Srgrimes * .DEFAULT itself. 10461590Srgrimes */ 10471590Srgrimes Make_HandleUse(DEFAULT, gn); 104818730Ssteve Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); 1049105826Sjmallett free(p1); 105018730Ssteve } else if (Dir_MTime(gn) == 0) { 10511590Srgrimes /* 10521590Srgrimes * The node wasn't the target of an operator we have no .DEFAULT 10531590Srgrimes * rule to go on and the target doesn't already exist. There's 10541590Srgrimes * nothing more we can do for this branch. If the -k flag wasn't 10551590Srgrimes * given, we stop in our tracks, otherwise we just don't update 10568874Srgrimes * this node's parents so they never get examined. 10571590Srgrimes */ 105818730Ssteve static const char msg[] = "make: don't know how to make"; 105918730Ssteve 10601590Srgrimes if (gn->type & OP_OPTIONAL) { 1061138232Sharti fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); 1062138232Sharti fflush(stdout); 10631590Srgrimes } else if (keepgoing) { 1064138232Sharti fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); 1065138232Sharti fflush(stdout); 1066138232Sharti return (FALSE); 10671590Srgrimes } else { 106835483Simp#if OLD_JOKE 106935483Simp if (strcmp(gn->name,"love") == 0) 107035483Simp (*abortProc)("Not war."); 107135483Simp else 107235483Simp#endif 107335483Simp (*abortProc)("%s %s. Stop", msg, gn->name); 1074138232Sharti return (FALSE); 10751590Srgrimes } 10761590Srgrimes } 10771590Srgrimes } 1078138232Sharti return (TRUE); 10791590Srgrimes} 10801590Srgrimes 10811590Srgrimes/*- 10821590Srgrimes *----------------------------------------------------------------------- 10831590Srgrimes * JobExec -- 10841590Srgrimes * Execute the shell for the given job. Called from JobStart and 10851590Srgrimes * JobRestart. 10861590Srgrimes * 10871590Srgrimes * Results: 10881590Srgrimes * None. 10891590Srgrimes * 10901590Srgrimes * Side Effects: 10911590Srgrimes * A shell is executed, outputs is altered and the Job structure added 10921590Srgrimes * to the job table. 10931590Srgrimes * 10941590Srgrimes *----------------------------------------------------------------------- 10951590Srgrimes */ 10961590Srgrimesstatic void 1097104696SjmallettJobExec(Job *job, char **argv) 10981590Srgrimes{ 10991590Srgrimes int cpid; /* ID of new child */ 11008874Srgrimes 11011590Srgrimes if (DEBUG(JOB)) { 11021590Srgrimes int i; 11038874Srgrimes 1104137252Sharti DEBUGF(JOB, ("Running %s\n", job->node->name)); 1105103545Sjmallett DEBUGF(JOB, ("\tCommand: ")); 110618730Ssteve for (i = 0; argv[i] != NULL; i++) { 1107103545Sjmallett DEBUGF(JOB, ("%s ", argv[i])); 11081590Srgrimes } 1109103545Sjmallett DEBUGF(JOB, ("\n")); 11101590Srgrimes } 11118874Srgrimes 11121590Srgrimes /* 11131590Srgrimes * Some jobs produce no output and it's disconcerting to have 11141590Srgrimes * no feedback of their running (since they produce no output, the 11151590Srgrimes * banner with their name in it never appears). This is an attempt to 11161590Srgrimes * provide that feedback, even if nothing follows it. 11171590Srgrimes */ 11181590Srgrimes if ((lastNode != job->node) && (job->flags & JOB_FIRST) && 111918730Ssteve !(job->flags & JOB_SILENT)) { 112018730Ssteve MESSAGE(stdout, job->node); 11211590Srgrimes lastNode = job->node; 11221590Srgrimes } 11238874Srgrimes 112418730Ssteve if ((cpid = vfork()) == -1) { 112518730Ssteve Punt("Cannot fork"); 11261590Srgrimes } else if (cpid == 0) { 11271590Srgrimes 1128137606Sphk if (fifoFd >= 0) 1129137606Sphk close(fifoFd); 11301590Srgrimes /* 11311590Srgrimes * Must duplicate the input stream down to the child's input and 11321590Srgrimes * reset it to the beginning (again). Since the stream was marked 11331590Srgrimes * close-on-exec, we must clear that bit in the new input. 11341590Srgrimes */ 113518730Ssteve if (dup2(FILENO(job->cmdFILE), 0) == -1) 113618730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 1137138232Sharti fcntl(0, F_SETFD, 0); 1138138232Sharti lseek(0, (off_t)0, SEEK_SET); 11398874Srgrimes 11401590Srgrimes if (usePipes) { 11411590Srgrimes /* 11421590Srgrimes * Set up the child's output to be routed through the pipe 11431590Srgrimes * we've created for it. 11441590Srgrimes */ 114518730Ssteve if (dup2(job->outPipe, 1) == -1) 114618730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 11471590Srgrimes } else { 11481590Srgrimes /* 11491590Srgrimes * We're capturing output in a file, so we duplicate the 11501590Srgrimes * descriptor to the temporary file into the standard 11511590Srgrimes * output. 11521590Srgrimes */ 115318730Ssteve if (dup2(job->outFd, 1) == -1) 115418730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 11551590Srgrimes } 11561590Srgrimes /* 11571590Srgrimes * The output channels are marked close on exec. This bit was 11581590Srgrimes * duplicated by the dup2 (on some systems), so we have to clear 11591590Srgrimes * it before routing the shell's error output to the same place as 11601590Srgrimes * its standard output. 11611590Srgrimes */ 1162138232Sharti fcntl(1, F_SETFD, 0); 116318730Ssteve if (dup2(1, 2) == -1) 116418730Ssteve Punt("Cannot dup2: %s", strerror(errno)); 11651590Srgrimes 11661590Srgrimes#ifdef USE_PGRP 11671590Srgrimes /* 11681590Srgrimes * We want to switch the child into a different process family so 11691590Srgrimes * we can kill it and all its descendants in one fell swoop, 11701590Srgrimes * by killing its process family, but not commit suicide. 11711590Srgrimes */ 117218730Ssteve# if defined(SYSV) 1173138232Sharti setsid(); 117418730Ssteve# else 1175138232Sharti setpgid(0, getpid()); 117618730Ssteve# endif 117718730Ssteve#endif /* USE_PGRP */ 11788874Srgrimes 1179138232Sharti execv(shellPath, argv); 11801590Srgrimes 1181138232Sharti write(STDERR_FILENO, "Could not execute shell\n", 118218730Ssteve sizeof("Could not execute shell")); 118318730Ssteve _exit(1); 11841590Srgrimes } else { 11851590Srgrimes job->pid = cpid; 11861590Srgrimes 11871590Srgrimes if (usePipes && (job->flags & JOB_FIRST) ) { 11881590Srgrimes /* 11891590Srgrimes * The first time a job is run for a node, we set the current 11901590Srgrimes * position in the buffer to the beginning and mark another 11911590Srgrimes * stream to watch in the outputs mask 11921590Srgrimes */ 1193104475Sphk#ifdef USE_KQUEUE 1194104475Sphk struct kevent kev[2]; 1195104475Sphk#endif 11961590Srgrimes job->curPos = 0; 11978874Srgrimes 1198137202Sharti#if defined(USE_KQUEUE) 1199104475Sphk EV_SET(&kev[0], job->inPipe, EVFILT_READ, EV_ADD, 0, 0, job); 1200104475Sphk EV_SET(&kev[1], job->pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, 1201104475Sphk NOTE_EXIT, 0, NULL); 1202104475Sphk if (kevent(kqfd, kev, 2, NULL, 0, NULL) != 0) { 1203104475Sphk /* kevent() will fail if the job is already finished */ 1204128500Sgreen if (errno != EINTR && errno != EBADF && errno != ESRCH) 1205104475Sphk Punt("kevent: %s", strerror(errno)); 1206104475Sphk } 12071590Srgrimes#else 12081590Srgrimes FD_SET(job->inPipe, &outputs); 1209137202Sharti#endif /* USE_KQUEUE */ 12101590Srgrimes } 12111590Srgrimes 1212137252Sharti if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 1213138232Sharti fclose(job->cmdFILE); 1214137252Sharti job->cmdFILE = NULL; 12151590Srgrimes } 12161590Srgrimes } 12171590Srgrimes 12181590Srgrimes /* 12191590Srgrimes * Now the job is actually running, add it to the table. 12201590Srgrimes */ 12211590Srgrimes nJobs += 1; 1222138916Sharti Lst_AtEnd(&jobs, job); 12231590Srgrimes if (nJobs == maxJobs) { 12241590Srgrimes jobFull = TRUE; 12251590Srgrimes } 12261590Srgrimes} 12271590Srgrimes 12281590Srgrimes/*- 12291590Srgrimes *----------------------------------------------------------------------- 12301590Srgrimes * JobMakeArgv -- 12311590Srgrimes * Create the argv needed to execute the shell for a given job. 12321590Srgrimes * 12338874Srgrimes * 12341590Srgrimes * Results: 12351590Srgrimes * 12361590Srgrimes * Side Effects: 12371590Srgrimes * 12381590Srgrimes *----------------------------------------------------------------------- 12391590Srgrimes */ 12401590Srgrimesstatic void 1241104696SjmallettJobMakeArgv(Job *job, char **argv) 12421590Srgrimes{ 12431590Srgrimes int argc; 12441590Srgrimes static char args[10]; /* For merged arguments */ 12458874Srgrimes 12461590Srgrimes argv[0] = shellName; 12471590Srgrimes argc = 1; 12481590Srgrimes 12491590Srgrimes if ((commandShell->exit && (*commandShell->exit != '-')) || 12501590Srgrimes (commandShell->echo && (*commandShell->echo != '-'))) 12511590Srgrimes { 12521590Srgrimes /* 12531590Srgrimes * At least one of the flags doesn't have a minus before it, so 12541590Srgrimes * merge them together. Have to do this because the *(&(@*#*&#$# 12551590Srgrimes * Bourne shell thinks its second argument is a file to source. 12561590Srgrimes * Grrrr. Note the ten-character limitation on the combined arguments. 12571590Srgrimes */ 1258138232Sharti sprintf(args, "-%s%s", 12591590Srgrimes ((job->flags & JOB_IGNERR) ? "" : 12601590Srgrimes (commandShell->exit ? commandShell->exit : "")), 12611590Srgrimes ((job->flags & JOB_SILENT) ? "" : 12621590Srgrimes (commandShell->echo ? commandShell->echo : ""))); 12631590Srgrimes 12641590Srgrimes if (args[1]) { 12651590Srgrimes argv[argc] = args; 12661590Srgrimes argc++; 12671590Srgrimes } 12681590Srgrimes } else { 12691590Srgrimes if (!(job->flags & JOB_IGNERR) && commandShell->exit) { 12701590Srgrimes argv[argc] = commandShell->exit; 12711590Srgrimes argc++; 12721590Srgrimes } 12731590Srgrimes if (!(job->flags & JOB_SILENT) && commandShell->echo) { 12741590Srgrimes argv[argc] = commandShell->echo; 12751590Srgrimes argc++; 12761590Srgrimes } 12771590Srgrimes } 127818730Ssteve argv[argc] = NULL; 12791590Srgrimes} 12801590Srgrimes 12811590Srgrimes/*- 12821590Srgrimes *----------------------------------------------------------------------- 12831590Srgrimes * JobRestart -- 12848874Srgrimes * Restart a job that stopped for some reason. 12851590Srgrimes * 12861590Srgrimes * Results: 12871590Srgrimes * None. 12881590Srgrimes * 12891590Srgrimes * Side Effects: 12901590Srgrimes * jobFull will be set if the job couldn't be run. 12911590Srgrimes * 12921590Srgrimes *----------------------------------------------------------------------- 12931590Srgrimes */ 12941590Srgrimesstatic void 1295104696SjmallettJobRestart(Job *job) 12961590Srgrimes{ 129718730Ssteve 1298137252Sharti if (job->flags & JOB_RESTART) { 12991590Srgrimes /* 13001590Srgrimes * Set up the control arguments to the shell. This is based on the 13011590Srgrimes * flags set earlier for this job. If the JOB_IGNERR flag is clear, 13021590Srgrimes * the 'exit' flag of the commandShell is used to cause it to exit 13031590Srgrimes * upon receiving an error. If the JOB_SILENT flag is clear, the 13041590Srgrimes * 'echo' flag of the commandShell is used to get it to start echoing 13058874Srgrimes * as soon as it starts processing commands. 13061590Srgrimes */ 13071590Srgrimes char *argv[4]; 13088874Srgrimes 13091590Srgrimes JobMakeArgv(job, argv); 13108874Srgrimes 1311103545Sjmallett DEBUGF(JOB, ("Restarting %s...", job->node->name)); 1312137572Sphk if (((nJobs >= maxJobs) && !(job->flags & JOB_SPECIAL))) { 131318730Ssteve /* 1314137202Sharti * Can't be exported and not allowed to run locally -- put it 1315137202Sharti * back on the hold queue and mark the table full 131618730Ssteve */ 1317137202Sharti DEBUGF(JOB, ("holding\n")); 1318138916Sharti Lst_AtFront(&stoppedJobs, (void *)job); 1319137202Sharti jobFull = TRUE; 1320137202Sharti DEBUGF(JOB, ("Job queue is full.\n")); 1321137202Sharti return; 1322137202Sharti } else { 1323137202Sharti /* 1324137202Sharti * Job may be run locally. 1325137202Sharti */ 1326137202Sharti DEBUGF(JOB, ("running locally\n")); 132718730Ssteve } 13281590Srgrimes JobExec(job, argv); 13291590Srgrimes } else { 13301590Srgrimes /* 13311590Srgrimes * The job has stopped and needs to be restarted. Why it stopped, 13321590Srgrimes * we don't know... 13331590Srgrimes */ 1334103545Sjmallett DEBUGF(JOB, ("Resuming %s...", job->node->name)); 1335137572Sphk if (((nJobs < maxJobs) || 133618730Ssteve ((job->flags & JOB_SPECIAL) && 1337137572Sphk (maxJobs == 0))) && 133818730Ssteve (nJobs != maxJobs)) 13391590Srgrimes { 13401590Srgrimes /* 1341137252Sharti * If we haven't reached the concurrency limit already (or the 1342137572Sphk * job must be run and maxJobs is 0), it's ok to resume it. 13431590Srgrimes */ 13441590Srgrimes Boolean error; 134518730Ssteve int status; 13468874Srgrimes 1347137202Sharti error = (KILL(job->pid, SIGCONT) != 0); 13481590Srgrimes 13491590Srgrimes if (!error) { 13501590Srgrimes /* 13511590Srgrimes * Make sure the user knows we've continued the beast and 13521590Srgrimes * actually put the thing in the job table. 13531590Srgrimes */ 13541590Srgrimes job->flags |= JOB_CONTINUING; 1355141647Sharti status = 0; 135618730Ssteve W_SETTERMSIG(&status, SIGCONT); 135718730Ssteve JobFinish(job, &status); 13588874Srgrimes 13591590Srgrimes job->flags &= ~(JOB_RESUME|JOB_CONTINUING); 1360103545Sjmallett DEBUGF(JOB, ("done\n")); 13611590Srgrimes } else { 13621590Srgrimes Error("couldn't resume %s: %s", 13631590Srgrimes job->node->name, strerror(errno)); 136418730Ssteve status = 0; 136518730Ssteve W_SETEXITSTATUS(&status, 1); 136618730Ssteve JobFinish(job, &status); 13671590Srgrimes } 13681590Srgrimes } else { 13691590Srgrimes /* 13701590Srgrimes * Job cannot be restarted. Mark the table as full and 13711590Srgrimes * place the job back on the list of stopped jobs. 13721590Srgrimes */ 1373103545Sjmallett DEBUGF(JOB, ("table full\n")); 1374138916Sharti Lst_AtFront(&stoppedJobs, (void *)job); 13751590Srgrimes jobFull = TRUE; 1376103545Sjmallett DEBUGF(JOB, ("Job queue is full.\n")); 13771590Srgrimes } 13781590Srgrimes } 13791590Srgrimes} 13801590Srgrimes 13811590Srgrimes/*- 13821590Srgrimes *----------------------------------------------------------------------- 13831590Srgrimes * JobStart -- 13841590Srgrimes * Start a target-creation process going for the target described 13858874Srgrimes * by the graph node gn. 13861590Srgrimes * 13871590Srgrimes * Results: 13881590Srgrimes * JOB_ERROR if there was an error in the commands, JOB_FINISHED 13891590Srgrimes * if there isn't actually anything left to do for the job and 13901590Srgrimes * JOB_RUNNING if the job has been started. 13911590Srgrimes * 13921590Srgrimes * Side Effects: 13931590Srgrimes * A new Job node is created and added to the list of running 13941590Srgrimes * jobs. PMake is forked and a child shell created. 13951590Srgrimes *----------------------------------------------------------------------- 13961590Srgrimes */ 13971590Srgrimesstatic int 1398104696SjmallettJobStart(GNode *gn, int flags, Job *previous) 13991590Srgrimes{ 140094584Sobrien Job *job; /* new job descriptor */ 14011590Srgrimes char *argv[4]; /* Argument vector to shell */ 14021590Srgrimes Boolean cmdsOK; /* true if the nodes commands were all right */ 14031590Srgrimes Boolean noExec; /* Set true if we decide not to run the job */ 140456151Skris int tfd; /* File descriptor for temp file */ 14051590Srgrimes 1406137605Sharti if (interrupted) { 1407137605Sharti JobPassSig(interrupted); 1408137605Sharti return (JOB_ERROR); 1409137605Sharti } 141018730Ssteve if (previous != NULL) { 1411137252Sharti previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT); 14121590Srgrimes job = previous; 14131590Srgrimes } else { 1414138264Sharti job = emalloc(sizeof(Job)); 14151590Srgrimes flags |= JOB_FIRST; 14161590Srgrimes } 14171590Srgrimes 14181590Srgrimes job->node = gn; 141969527Swill job->tailCmds = NULL; 14201590Srgrimes 14211590Srgrimes /* 14221590Srgrimes * Set the initial value of the flags for this job based on the global 14231590Srgrimes * ones and the node's attributes... Any flags supplied by the caller 14241590Srgrimes * are also added to the field. 14251590Srgrimes */ 14261590Srgrimes job->flags = 0; 142718730Ssteve if (Targ_Ignore(gn)) { 14281590Srgrimes job->flags |= JOB_IGNERR; 14291590Srgrimes } 143018730Ssteve if (Targ_Silent(gn)) { 14311590Srgrimes job->flags |= JOB_SILENT; 14321590Srgrimes } 14331590Srgrimes job->flags |= flags; 14341590Srgrimes 14351590Srgrimes /* 14361590Srgrimes * Check the commands now so any attributes from .DEFAULT have a chance 14371590Srgrimes * to migrate to the node 14381590Srgrimes */ 143918730Ssteve if (!compatMake && job->flags & JOB_FIRST) { 14401590Srgrimes cmdsOK = Job_CheckCommands(gn, Error); 14411590Srgrimes } else { 14421590Srgrimes cmdsOK = TRUE; 14431590Srgrimes } 14448874Srgrimes 14451590Srgrimes /* 14461590Srgrimes * If the -n flag wasn't given, we open up OUR (not the child's) 14471590Srgrimes * temporary file to stuff commands in it. The thing is rd/wr so we don't 14481590Srgrimes * need to reopen it to feed it to the shell. If the -n flag *was* given, 14491590Srgrimes * we just set the file to be stdout. Cute, huh? 14501590Srgrimes */ 14511590Srgrimes if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) { 14521590Srgrimes /* 14531590Srgrimes * We're serious here, but if the commands were bogus, we're 14541590Srgrimes * also dead... 14551590Srgrimes */ 14561590Srgrimes if (!cmdsOK) { 14571590Srgrimes DieHorribly(); 14581590Srgrimes } 14598874Srgrimes 1460138232Sharti strcpy(tfile, TMPPAT); 146168898Skris if ((tfd = mkstemp(tfile)) == -1) 146268898Skris Punt("Cannot create temp file: %s", strerror(errno)); 146368898Skris job->cmdFILE = fdopen(tfd, "w+"); 146468898Skris eunlink(tfile); 146518730Ssteve if (job->cmdFILE == NULL) { 146668898Skris close(tfd); 146768898Skris Punt("Could not open %s", tfile); 14681590Srgrimes } 1469138232Sharti fcntl(FILENO(job->cmdFILE), F_SETFD, 1); 14701590Srgrimes /* 14711590Srgrimes * Send the commands to the command file, flush all its buffers then 14721590Srgrimes * rewind and remove the thing. 14731590Srgrimes */ 14741590Srgrimes noExec = FALSE; 14751590Srgrimes 14761590Srgrimes /* 14771590Srgrimes * used to be backwards; replace when start doing multiple commands 14781590Srgrimes * per shell. 14791590Srgrimes */ 14801590Srgrimes if (compatMake) { 14811590Srgrimes /* 14821590Srgrimes * Be compatible: If this is the first time for this node, 14831590Srgrimes * verify its commands are ok and open the commands list for 14841590Srgrimes * sequential access by later invocations of JobStart. 14851590Srgrimes * Once that is done, we take the next command off the list 14861590Srgrimes * and print it to the command file. If the command was an 14871590Srgrimes * ellipsis, note that there's nothing more to execute. 14881590Srgrimes */ 1489138564Sharti if (job->flags & JOB_FIRST) 1490138916Sharti gn->compat_command = Lst_First(&gn->commands); 1491138564Sharti else 1492138564Sharti gn->compat_command = Lst_Succ(gn->compat_command); 14938874Srgrimes 1494138564Sharti if (gn->compat_command == NULL || 1495138564Sharti JobPrintCommand(Lst_Datum(gn->compat_command), job)) 1496138564Sharti noExec = TRUE; 1497138564Sharti 1498138564Sharti if (noExec && !(job->flags & JOB_FIRST)) { 1499138564Sharti /* 1500138564Sharti * If we're not going to execute anything, the job 1501138564Sharti * is done and we need to close down the various 1502138564Sharti * file descriptors we've opened for output, then 1503138564Sharti * call JobDoOutput to catch the final characters or 1504138564Sharti * send the file to the screen... Note that the i/o streams 1505138564Sharti * are only open if this isn't the first job. 1506138564Sharti * Note also that this could not be done in 1507138564Sharti * Job_CatchChildren b/c it wasn't clear if there were 1508138564Sharti * more commands to execute or not... 1509138564Sharti */ 1510138564Sharti JobClose(job); 15111590Srgrimes } 15121590Srgrimes } else { 15131590Srgrimes /* 15141590Srgrimes * We can do all the commands at once. hooray for sanity 15151590Srgrimes */ 15161590Srgrimes numCommands = 0; 1517138916Sharti Lst_ForEach(&gn->commands, JobPrintCommand, job); 15188874Srgrimes 15191590Srgrimes /* 15201590Srgrimes * If we didn't print out any commands to the shell script, 15211590Srgrimes * there's not much point in executing the shell, is there? 15221590Srgrimes */ 15231590Srgrimes if (numCommands == 0) { 15241590Srgrimes noExec = TRUE; 15251590Srgrimes } 15261590Srgrimes } 15271590Srgrimes } else if (noExecute) { 15281590Srgrimes /* 15291590Srgrimes * Not executing anything -- just print all the commands to stdout 15301590Srgrimes * in one fell swoop. This will still set up job->tailCmds correctly. 15311590Srgrimes */ 15321590Srgrimes if (lastNode != gn) { 153318730Ssteve MESSAGE(stdout, gn); 15341590Srgrimes lastNode = gn; 15351590Srgrimes } 15361590Srgrimes job->cmdFILE = stdout; 15371590Srgrimes /* 15381590Srgrimes * Only print the commands if they're ok, but don't die if they're 15391590Srgrimes * not -- just let the user know they're bad and keep going. It 15401590Srgrimes * doesn't do any harm in this case and may do some good. 15411590Srgrimes */ 15421590Srgrimes if (cmdsOK) { 1543138916Sharti Lst_ForEach(&gn->commands, JobPrintCommand, job); 15441590Srgrimes } 15451590Srgrimes /* 15461590Srgrimes * Don't execute the shell, thank you. 15471590Srgrimes */ 15481590Srgrimes noExec = TRUE; 15491590Srgrimes } else { 15501590Srgrimes /* 15511590Srgrimes * Just touch the target and note that no shell should be executed. 15521590Srgrimes * Set cmdFILE to stdout to make life easier. Check the commands, too, 15531590Srgrimes * but don't die if they're no good -- it does no harm to keep working 15541590Srgrimes * up the graph. 15551590Srgrimes */ 15561590Srgrimes job->cmdFILE = stdout; 1557138264Sharti Job_Touch(gn, job->flags & JOB_SILENT); 15581590Srgrimes noExec = TRUE; 15591590Srgrimes } 15601590Srgrimes 15611590Srgrimes /* 15628874Srgrimes * If we're not supposed to execute a shell, don't. 15631590Srgrimes */ 15641590Srgrimes if (noExec) { 15651590Srgrimes /* 15661590Srgrimes * Unlink and close the command file if we opened one 15671590Srgrimes */ 15681590Srgrimes if (job->cmdFILE != stdout) { 156918730Ssteve if (job->cmdFILE != NULL) 1570138232Sharti fclose(job->cmdFILE); 15711590Srgrimes } else { 1572138232Sharti fflush(stdout); 15731590Srgrimes } 15741590Srgrimes 15751590Srgrimes /* 15761590Srgrimes * We only want to work our way up the graph if we aren't here because 15771590Srgrimes * the commands for the job were no good. 15781590Srgrimes */ 15791590Srgrimes if (cmdsOK) { 15801590Srgrimes if (aborting == 0) { 158169527Swill if (job->tailCmds != NULL) { 1582138916Sharti Lst_ForEachFrom(&job->node->commands, job->tailCmds, 1583138264Sharti JobSaveCommand, job->node); 15841590Srgrimes } 158536621Sbde job->node->made = MADE; 15861590Srgrimes Make_Update(job->node); 15871590Srgrimes } 158869531Swill free(job); 15891590Srgrimes return(JOB_FINISHED); 15901590Srgrimes } else { 159169531Swill free(job); 15921590Srgrimes return(JOB_ERROR); 15931590Srgrimes } 15941590Srgrimes } else { 1595138232Sharti fflush(job->cmdFILE); 15961590Srgrimes } 15971590Srgrimes 15981590Srgrimes /* 15991590Srgrimes * Set up the control arguments to the shell. This is based on the flags 16001590Srgrimes * set earlier for this job. 16011590Srgrimes */ 16021590Srgrimes JobMakeArgv(job, argv); 16031590Srgrimes 16041590Srgrimes /* 16051590Srgrimes * If we're using pipes to catch output, create the pipe by which we'll 16061590Srgrimes * get the shell's output. If we're using files, print out that we're 160750145Shoek * starting a job and then set up its temporary-file name. 16081590Srgrimes */ 160918730Ssteve if (!compatMake || (job->flags & JOB_FIRST)) { 16101590Srgrimes if (usePipes) { 16111590Srgrimes int fd[2]; 1612138232Sharti 161318730Ssteve if (pipe(fd) == -1) 161418730Ssteve Punt("Cannot create pipe: %s", strerror(errno)); 16151590Srgrimes job->inPipe = fd[0]; 16161590Srgrimes job->outPipe = fd[1]; 1617138232Sharti fcntl(job->inPipe, F_SETFD, 1); 1618138232Sharti fcntl(job->outPipe, F_SETFD, 1); 16191590Srgrimes } else { 1620138232Sharti fprintf(stdout, "Remaking `%s'\n", gn->name); 1621138232Sharti fflush(stdout); 1622138232Sharti strcpy(job->outFile, TMPPAT); 162350145Shoek if ((job->outFd = mkstemp(job->outFile)) == -1) 162450145Shoek Punt("cannot create temp file: %s", strerror(errno)); 1625138232Sharti fcntl(job->outFd, F_SETFD, 1); 16261590Srgrimes } 16271590Srgrimes } 16281590Srgrimes 1629137572Sphk if ((nJobs >= maxJobs) && !(job->flags & JOB_SPECIAL) && (maxJobs != 0)) { 16301590Srgrimes /* 1631137252Sharti * We've hit the limit of concurrency, so put the job on hold until 1632137252Sharti * some other job finishes. Note that the special jobs (.BEGIN, 1633137252Sharti * .INTERRUPT and .END) may be run even when the limit has been reached 1634137572Sphk * (e.g. when maxJobs == 0). 16351590Srgrimes */ 16361590Srgrimes jobFull = TRUE; 16378874Srgrimes 1638103545Sjmallett DEBUGF(JOB, ("Can only run job locally.\n")); 16391590Srgrimes job->flags |= JOB_RESTART; 1640138916Sharti Lst_AtEnd(&stoppedJobs, job); 16411590Srgrimes } else { 1642137572Sphk if (nJobs >= maxJobs) { 16431590Srgrimes /* 16441590Srgrimes * If we're running this job locally as a special case (see above), 16451590Srgrimes * at least say the table is full. 16461590Srgrimes */ 16471590Srgrimes jobFull = TRUE; 1648103545Sjmallett DEBUGF(JOB, ("Local job queue is full.\n")); 16491590Srgrimes } 16501590Srgrimes JobExec(job, argv); 16511590Srgrimes } 1652138232Sharti return (JOB_RUNNING); 16531590Srgrimes} 16541590Srgrimes 165518730Sstevestatic char * 1656104696SjmallettJobOutput(Job *job, char *cp, char *endp, int msg) 165718730Ssteve{ 165894584Sobrien char *ecp; 165918730Ssteve 166018730Ssteve if (commandShell->noPrint) { 1661106106Sjmallett ecp = strstr(cp, commandShell->noPrint); 166218730Ssteve while (ecp != NULL) { 166318730Ssteve if (cp != ecp) { 166418730Ssteve *ecp = '\0'; 166518730Ssteve if (msg && job->node != lastNode) { 166618730Ssteve MESSAGE(stdout, job->node); 166718730Ssteve lastNode = job->node; 166818730Ssteve } 166918730Ssteve /* 167018730Ssteve * The only way there wouldn't be a newline after 167118730Ssteve * this line is if it were the last in the buffer. 167218730Ssteve * however, since the non-printable comes after it, 167318730Ssteve * there must be a newline, so we don't print one. 167418730Ssteve */ 1675138232Sharti fprintf(stdout, "%s", cp); 1676138232Sharti fflush(stdout); 167718730Ssteve } 167818730Ssteve cp = ecp + commandShell->noPLen; 167918730Ssteve if (cp != endp) { 168018730Ssteve /* 168118730Ssteve * Still more to print, look again after skipping 168218730Ssteve * the whitespace following the non-printable 168318730Ssteve * command.... 168418730Ssteve */ 168518730Ssteve cp++; 168618730Ssteve while (*cp == ' ' || *cp == '\t' || *cp == '\n') { 168718730Ssteve cp++; 168818730Ssteve } 1689106106Sjmallett ecp = strstr(cp, commandShell->noPrint); 169018730Ssteve } else { 1691138232Sharti return (cp); 169218730Ssteve } 169318730Ssteve } 169418730Ssteve } 1695138232Sharti return (cp); 169618730Ssteve} 169718730Ssteve 16981590Srgrimes/*- 16991590Srgrimes *----------------------------------------------------------------------- 17001590Srgrimes * JobDoOutput -- 17011590Srgrimes * This function is called at different times depending on 17021590Srgrimes * whether the user has specified that output is to be collected 17031590Srgrimes * via pipes or temporary files. In the former case, we are called 17041590Srgrimes * whenever there is something to read on the pipe. We collect more 17051590Srgrimes * output from the given job and store it in the job's outBuf. If 17061590Srgrimes * this makes up a line, we print it tagged by the job's identifier, 17071590Srgrimes * as necessary. 17081590Srgrimes * If output has been collected in a temporary file, we open the 17091590Srgrimes * file and read it line by line, transfering it to our own 17101590Srgrimes * output channel until the file is empty. At which point we 17111590Srgrimes * remove the temporary file. 17121590Srgrimes * In both cases, however, we keep our figurative eye out for the 17131590Srgrimes * 'noPrint' line for the shell from which the output came. If 17141590Srgrimes * we recognize a line, we don't print it. If the command is not 17151590Srgrimes * alone on the line (the character after it is not \0 or \n), we 17161590Srgrimes * do print whatever follows it. 17171590Srgrimes * 17181590Srgrimes * Results: 17191590Srgrimes * None 17201590Srgrimes * 17211590Srgrimes * Side Effects: 17221590Srgrimes * curPos may be shifted as may the contents of outBuf. 17231590Srgrimes *----------------------------------------------------------------------- 17241590Srgrimes */ 172518730SsteveSTATIC void 1726104696SjmallettJobDoOutput(Job *job, Boolean finish) 17271590Srgrimes{ 17281590Srgrimes Boolean gotNL = FALSE; /* true if got a newline */ 172918730Ssteve Boolean fbuf; /* true if our buffer filled up */ 173094584Sobrien int nr; /* number of bytes read */ 173194584Sobrien int i; /* auxiliary index into outBuf */ 173294584Sobrien int max; /* limit for i (end of current data) */ 17331590Srgrimes int nRead; /* (Temporary) number of bytes read */ 17341590Srgrimes 17351590Srgrimes FILE *oFILE; /* Stream pointer to shell's output file */ 17361590Srgrimes char inLine[132]; 17371590Srgrimes 17381590Srgrimes if (usePipes) { 17391590Srgrimes /* 17401590Srgrimes * Read as many bytes as will fit in the buffer. 17411590Srgrimes */ 17421590Srgrimesend_loop: 174318730Ssteve gotNL = FALSE; 174418730Ssteve fbuf = FALSE; 17458874Srgrimes 174618730Ssteve nRead = read(job->inPipe, &job->outBuf[job->curPos], 17471590Srgrimes JOB_BUFSIZE - job->curPos); 1748137605Sharti /* 1749137605Sharti * Check for interrupt here too, because the above read may block 1750137605Sharti * when the child process is stopped. In this case the interrupt 1751137605Sharti * will unblock it (we don't use SA_RESTART). 1752137605Sharti */ 1753137605Sharti if (interrupted) 1754137605Sharti JobPassSig(interrupted); 1755137605Sharti 17561590Srgrimes if (nRead < 0) { 1757103545Sjmallett DEBUGF(JOB, ("JobDoOutput(piperead)")); 17581590Srgrimes nr = 0; 17591590Srgrimes } else { 17601590Srgrimes nr = nRead; 17611590Srgrimes } 17621590Srgrimes 17631590Srgrimes /* 17641590Srgrimes * If we hit the end-of-file (the job is dead), we must flush its 17651590Srgrimes * remaining output, so pretend we read a newline if there's any 17661590Srgrimes * output remaining in the buffer. 17671590Srgrimes * Also clear the 'finish' flag so we stop looping. 17681590Srgrimes */ 17691590Srgrimes if ((nr == 0) && (job->curPos != 0)) { 17701590Srgrimes job->outBuf[job->curPos] = '\n'; 17711590Srgrimes nr = 1; 17721590Srgrimes finish = FALSE; 17731590Srgrimes } else if (nr == 0) { 17741590Srgrimes finish = FALSE; 17751590Srgrimes } 17768874Srgrimes 17771590Srgrimes /* 17781590Srgrimes * Look for the last newline in the bytes we just got. If there is 17791590Srgrimes * one, break out of the loop with 'i' as its index and gotNL set 17808874Srgrimes * TRUE. 17811590Srgrimes */ 17821590Srgrimes max = job->curPos + nr; 17831590Srgrimes for (i = job->curPos + nr - 1; i >= job->curPos; i--) { 17841590Srgrimes if (job->outBuf[i] == '\n') { 17851590Srgrimes gotNL = TRUE; 17861590Srgrimes break; 17871590Srgrimes } else if (job->outBuf[i] == '\0') { 17881590Srgrimes /* 17891590Srgrimes * Why? 17901590Srgrimes */ 17911590Srgrimes job->outBuf[i] = ' '; 17921590Srgrimes } 17931590Srgrimes } 17948874Srgrimes 17951590Srgrimes if (!gotNL) { 17961590Srgrimes job->curPos += nr; 17971590Srgrimes if (job->curPos == JOB_BUFSIZE) { 17981590Srgrimes /* 17991590Srgrimes * If we've run out of buffer space, we have no choice 18008874Srgrimes * but to print the stuff. sigh. 18011590Srgrimes */ 180218730Ssteve fbuf = TRUE; 18031590Srgrimes i = job->curPos; 18041590Srgrimes } 18051590Srgrimes } 180618730Ssteve if (gotNL || fbuf) { 18071590Srgrimes /* 18081590Srgrimes * Need to send the output to the screen. Null terminate it 18091590Srgrimes * first, overwriting the newline character if there was one. 18101590Srgrimes * So long as the line isn't one we should filter (according 181172645Sasmodai * to the shell description), we print the line, preceded 18121590Srgrimes * by a target banner if this target isn't the same as the 18131590Srgrimes * one for which we last printed something. 18141590Srgrimes * The rest of the data in the buffer are then shifted down 18158874Srgrimes * to the start of the buffer and curPos is set accordingly. 18161590Srgrimes */ 18171590Srgrimes job->outBuf[i] = '\0'; 18181590Srgrimes if (i >= job->curPos) { 181918730Ssteve char *cp; 18201590Srgrimes 182118730Ssteve cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); 18221590Srgrimes 18231590Srgrimes /* 18241590Srgrimes * There's still more in that thar buffer. This time, though, 18251590Srgrimes * we know there's no newline at the end, so we add one of 18261590Srgrimes * our own free will. 18271590Srgrimes */ 18281590Srgrimes if (*cp != '\0') { 18291590Srgrimes if (job->node != lastNode) { 183018730Ssteve MESSAGE(stdout, job->node); 18311590Srgrimes lastNode = job->node; 18321590Srgrimes } 1833138232Sharti fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); 1834138232Sharti fflush(stdout); 18351590Srgrimes } 18361590Srgrimes } 18371590Srgrimes if (i < max - 1) { 18381590Srgrimes /* shift the remaining characters down */ 1839138232Sharti memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); 18401590Srgrimes job->curPos = max - (i + 1); 18418874Srgrimes 18421590Srgrimes } else { 18431590Srgrimes /* 18441590Srgrimes * We have written everything out, so we just start over 18451590Srgrimes * from the start of the buffer. No copying. No nothing. 18461590Srgrimes */ 18471590Srgrimes job->curPos = 0; 18481590Srgrimes } 18491590Srgrimes } 18501590Srgrimes if (finish) { 18511590Srgrimes /* 18521590Srgrimes * If the finish flag is true, we must loop until we hit 185318730Ssteve * end-of-file on the pipe. This is guaranteed to happen 185418730Ssteve * eventually since the other end of the pipe is now closed 185518730Ssteve * (we closed it explicitly and the child has exited). When 185618730Ssteve * we do get an EOF, finish will be set FALSE and we'll fall 185718730Ssteve * through and out. 18581590Srgrimes */ 18591590Srgrimes goto end_loop; 18601590Srgrimes } 18611590Srgrimes } else { 18621590Srgrimes /* 18631590Srgrimes * We've been called to retrieve the output of the job from the 18641590Srgrimes * temporary file where it's been squirreled away. This consists of 18651590Srgrimes * opening the file, reading the output line by line, being sure not 18661590Srgrimes * to print the noPrint line for the shell we used, then close and 18671590Srgrimes * remove the temporary file. Very simple. 18681590Srgrimes * 18691590Srgrimes * Change to read in blocks and do FindSubString type things as for 18701590Srgrimes * pipes? That would allow for "@echo -n..." 18711590Srgrimes */ 187218730Ssteve oFILE = fopen(job->outFile, "r"); 187318730Ssteve if (oFILE != NULL) { 1874138264Sharti fprintf(stdout, "Results of making %s:\n", job->node->name); 1875138264Sharti fflush(stdout); 187618730Ssteve while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { 187794584Sobrien char *cp, *endp, *oendp; 18781590Srgrimes 18791590Srgrimes cp = inLine; 188018730Ssteve oendp = endp = inLine + strlen(inLine); 18811590Srgrimes if (endp[-1] == '\n') { 18821590Srgrimes *--endp = '\0'; 18831590Srgrimes } 188418730Ssteve cp = JobOutput(job, inLine, endp, FALSE); 18851590Srgrimes 18861590Srgrimes /* 18871590Srgrimes * There's still more in that thar buffer. This time, though, 18881590Srgrimes * we know there's no newline at the end, so we add one of 18891590Srgrimes * our own free will. 18901590Srgrimes */ 1891138232Sharti fprintf(stdout, "%s", cp); 1892138232Sharti fflush(stdout); 189318730Ssteve if (endp != oendp) { 1894138232Sharti fprintf(stdout, "\n"); 1895138232Sharti fflush(stdout); 18961590Srgrimes } 18971590Srgrimes } 1898138264Sharti fclose(oFILE); 1899138264Sharti eunlink(job->outFile); 19001590Srgrimes } 19011590Srgrimes } 19021590Srgrimes} 19031590Srgrimes 19041590Srgrimes/*- 19051590Srgrimes *----------------------------------------------------------------------- 19061590Srgrimes * Job_CatchChildren -- 19071590Srgrimes * Handle the exit of a child. Called from Make_Make. 19081590Srgrimes * 19091590Srgrimes * Results: 19101590Srgrimes * none. 19111590Srgrimes * 19121590Srgrimes * Side Effects: 19131590Srgrimes * The job descriptor is removed from the list of children. 19141590Srgrimes * 19151590Srgrimes * Notes: 19161590Srgrimes * We do waits, blocking or not, according to the wisdom of our 19171590Srgrimes * caller, until there are no more children to report. For each 19181590Srgrimes * job, call JobFinish to finish things off. This will take care of 19191590Srgrimes * putting jobs on the stoppedJobs queue. 19201590Srgrimes * 19211590Srgrimes *----------------------------------------------------------------------- 19221590Srgrimes */ 19231590Srgrimesvoid 1924104696SjmallettJob_CatchChildren(Boolean block) 19251590Srgrimes{ 19261590Srgrimes int pid; /* pid of dead child */ 192794584Sobrien Job *job; /* job descriptor for dead child */ 1928138512Sharti LstNode *jnode; /* list element for finding job */ 192918730Ssteve int status; /* Exit/termination status */ 19301590Srgrimes 19311590Srgrimes /* 19321590Srgrimes * Don't even bother if we know there's no one around. 19331590Srgrimes */ 1934137572Sphk if (nJobs == 0) { 19351590Srgrimes return; 19361590Srgrimes } 19378874Srgrimes 1938137606Sphk for (;;) { 1939138232Sharti pid = waitpid((pid_t)-1, &status, (block ? 0 : WNOHANG) | WUNTRACED); 1940137606Sphk if (pid <= 0) 1941137606Sphk break; 1942103545Sjmallett DEBUGF(JOB, ("Process %d exited or stopped.\n", pid)); 19431590Srgrimes 1944138916Sharti jnode = Lst_Find(&jobs, &pid, JobCmpPid); 19451590Srgrimes 194669527Swill if (jnode == NULL) { 194718730Ssteve if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) { 1948138916Sharti jnode = Lst_Find(&stoppedJobs, &pid, JobCmpPid); 194969527Swill if (jnode == NULL) { 19501590Srgrimes Error("Resumed child (%d) not in table", pid); 19511590Srgrimes continue; 19521590Srgrimes } 1953138264Sharti job = Lst_Datum(jnode); 1954138916Sharti Lst_Remove(&stoppedJobs, jnode); 19551590Srgrimes } else { 195618730Ssteve Error("Child (%d) not in table?", pid); 19571590Srgrimes continue; 19581590Srgrimes } 19591590Srgrimes } else { 1960138264Sharti job = Lst_Datum(jnode); 1961138916Sharti Lst_Remove(&jobs, jnode); 19621590Srgrimes nJobs -= 1; 1963137606Sphk if (fifoFd >= 0 && maxJobs > 1) { 1964137606Sphk write(fifoFd, "+", 1); 1965137606Sphk maxJobs--; 1966137606Sphk if (nJobs >= maxJobs) 1967137606Sphk jobFull = TRUE; 1968137606Sphk else 1969137606Sphk jobFull = FALSE; 1970137606Sphk } else { 1971137606Sphk DEBUGF(JOB, ("Job queue is no longer full.\n")); 1972137606Sphk jobFull = FALSE; 1973137606Sphk } 19741590Srgrimes } 19751590Srgrimes 197618730Ssteve JobFinish(job, &status); 19771590Srgrimes } 1978137605Sharti if (interrupted) 1979137605Sharti JobPassSig(interrupted); 19801590Srgrimes} 19811590Srgrimes 19821590Srgrimes/*- 19831590Srgrimes *----------------------------------------------------------------------- 19841590Srgrimes * Job_CatchOutput -- 19851590Srgrimes * Catch the output from our children, if we're using 19861590Srgrimes * pipes do so. Otherwise just block time until we get a 1987138232Sharti * signal(most likely a SIGCHLD) since there's no point in 19881590Srgrimes * just spinning when there's nothing to do and the reaping 19898874Srgrimes * of a child can wait for a while. 19901590Srgrimes * 19911590Srgrimes * Results: 19928874Srgrimes * None 19931590Srgrimes * 19941590Srgrimes * Side Effects: 19951590Srgrimes * Output is read from pipes if we're piping. 19961590Srgrimes * ----------------------------------------------------------------------- 19971590Srgrimes */ 19981590Srgrimesvoid 1999139064Sharti#ifdef USE_KQUEUE 2000139064ShartiJob_CatchOutput(int flag __unused) 2001139064Sharti#else 2002137606SphkJob_CatchOutput(int flag) 2003139064Sharti#endif 20041590Srgrimes{ 20051590Srgrimes int nfds; 2006104475Sphk#ifdef USE_KQUEUE 2007104475Sphk#define KEV_SIZE 4 2008104475Sphk struct kevent kev[KEV_SIZE]; 2009104475Sphk int i; 2010104475Sphk#else 20111590Srgrimes struct timeval timeout; 20121590Srgrimes fd_set readfds; 2013138512Sharti LstNode *ln; 201494584Sobrien Job *job; 2015104475Sphk#endif 20161590Srgrimes 2017138232Sharti fflush(stdout); 20181590Srgrimes 20191590Srgrimes if (usePipes) { 2020104475Sphk#ifdef USE_KQUEUE 2021104475Sphk if ((nfds = kevent(kqfd, NULL, 0, kev, KEV_SIZE, NULL)) == -1) { 2022128500Sgreen if (errno != EINTR) 2023128500Sgreen Punt("kevent: %s", strerror(errno)); 2024137605Sharti if (interrupted) 2025137605Sharti JobPassSig(interrupted); 2026104475Sphk } else { 2027104475Sphk for (i = 0; i < nfds; i++) { 2028104475Sphk if (kev[i].flags & EV_ERROR) { 2029104475Sphk warnc(kev[i].data, "kevent"); 2030104475Sphk continue; 2031104475Sphk } 2032104475Sphk switch (kev[i].filter) { 2033104475Sphk case EVFILT_READ: 2034104475Sphk JobDoOutput(kev[i].udata, FALSE); 2035104475Sphk break; 2036104475Sphk case EVFILT_PROC: 2037104475Sphk /* Just wake up and let Job_CatchChildren() collect the 2038104475Sphk * terminated job. */ 2039104475Sphk break; 2040104475Sphk } 2041104475Sphk } 2042104475Sphk } 2043104475Sphk#else 20441590Srgrimes readfds = outputs; 20451590Srgrimes timeout.tv_sec = SEL_SEC; 20461590Srgrimes timeout.tv_usec = SEL_USEC; 2047137606Sphk if (flag && jobFull && fifoFd >= 0) 2048137606Sphk FD_SET(fifoFd, &readfds); 20491590Srgrimes 2050138264Sharti nfds = select(FD_SETSIZE, &readfds, (fd_set *)NULL, 2051138264Sharti (fd_set *)NULL, &timeout); 2052137606Sphk if (nfds <= 0) { 2053138232Sharti if (interrupted) 2054137605Sharti JobPassSig(interrupted); 20551590Srgrimes return; 2056137606Sphk } 2057137606Sphk if (fifoFd >= 0 && FD_ISSET(fifoFd, &readfds)) { 2058137606Sphk if (--nfds <= 0) 2059137606Sphk return; 2060137606Sphk } 2061138916Sharti for (ln = Lst_First(&jobs); nfds != 0 && ln != NULL; ln = Lst_Succ(ln)){ 2062138264Sharti job = Lst_Datum(ln); 2063137606Sphk if (FD_ISSET(job->inPipe, &readfds)) { 2064137606Sphk JobDoOutput(job, FALSE); 2065137606Sphk nfds -= 1; 20661590Srgrimes } 20671590Srgrimes } 2068104475Sphk#endif /* !USE_KQUEUE */ 20691590Srgrimes } 20701590Srgrimes} 20711590Srgrimes 20721590Srgrimes/*- 20731590Srgrimes *----------------------------------------------------------------------- 20741590Srgrimes * Job_Make -- 20751590Srgrimes * Start the creation of a target. Basically a front-end for 20761590Srgrimes * JobStart used by the Make module. 20771590Srgrimes * 20781590Srgrimes * Results: 20791590Srgrimes * None. 20801590Srgrimes * 20811590Srgrimes * Side Effects: 20821590Srgrimes * Another job is started. 20831590Srgrimes * 20841590Srgrimes *----------------------------------------------------------------------- 20851590Srgrimes */ 20861590Srgrimesvoid 2087104696SjmallettJob_Make(GNode *gn) 20881590Srgrimes{ 2089138232Sharti 2090138232Sharti JobStart(gn, 0, NULL); 20911590Srgrimes} 20921590Srgrimes 2093138079Sharti/* 2094138079Sharti * JobCopyShell: 2095138079Sharti * 2096138079Sharti * Make a new copy of the shell structure including a copy of the strings 2097138079Sharti * in it. This also defaults some fields in case they are NULL. 2098138079Sharti * 2099138079Sharti * The function returns a pointer to the new shell structure otherwise. 2100138079Sharti */ 2101138079Shartistatic Shell * 2102138079ShartiJobCopyShell(const Shell *osh) 2103138079Sharti{ 2104138079Sharti Shell *nsh; 2105138079Sharti 2106138079Sharti nsh = emalloc(sizeof(*nsh)); 2107138079Sharti nsh->name = estrdup(osh->name); 2108138079Sharti 2109138079Sharti if (osh->echoOff != NULL) 2110138079Sharti nsh->echoOff = estrdup(osh->echoOff); 2111138079Sharti else 2112138079Sharti nsh->echoOff = NULL; 2113138079Sharti if (osh->echoOn != NULL) 2114138079Sharti nsh->echoOn = estrdup(osh->echoOn); 2115138079Sharti else 2116138079Sharti nsh->echoOn = NULL; 2117138079Sharti nsh->hasEchoCtl = osh->hasEchoCtl; 2118138079Sharti 2119138079Sharti if (osh->noPrint != NULL) 2120138079Sharti nsh->noPrint = estrdup(osh->noPrint); 2121138079Sharti else 2122138079Sharti nsh->noPrint = NULL; 2123138079Sharti nsh->noPLen = osh->noPLen; 2124138079Sharti 2125138079Sharti nsh->hasErrCtl = osh->hasErrCtl; 2126138079Sharti if (osh->errCheck == NULL) 2127138079Sharti nsh->errCheck = estrdup(""); 2128138079Sharti else 2129138079Sharti nsh->errCheck = estrdup(osh->errCheck); 2130138079Sharti if (osh->ignErr == NULL) 2131138079Sharti nsh->ignErr = estrdup("%s"); 2132138079Sharti else 2133138079Sharti nsh->ignErr = estrdup(osh->ignErr); 2134138079Sharti 2135138079Sharti if (osh->echo == NULL) 2136138079Sharti nsh->echo = estrdup(""); 2137138079Sharti else 2138138079Sharti nsh->echo = estrdup(osh->echo); 2139138079Sharti 2140138079Sharti if (osh->exit == NULL) 2141138079Sharti nsh->exit = estrdup(""); 2142138079Sharti else 2143138079Sharti nsh->exit = estrdup(osh->exit); 2144138079Sharti 2145138079Sharti return (nsh); 2146138079Sharti} 2147138079Sharti 2148138079Sharti/* 2149138079Sharti * JobFreeShell: 2150138079Sharti * 2151138079Sharti * Free a shell structure and all associated strings. 2152138079Sharti */ 2153138079Shartistatic void 2154138079ShartiJobFreeShell(Shell *sh) 2155138079Sharti{ 2156138079Sharti 2157138079Sharti if (sh != NULL) { 2158138079Sharti free(sh->name); 2159138079Sharti free(sh->echoOff); 2160138079Sharti free(sh->echoOn); 2161138079Sharti free(sh->noPrint); 2162138079Sharti free(sh->errCheck); 2163138079Sharti free(sh->ignErr); 2164138079Sharti free(sh->echo); 2165138079Sharti free(sh->exit); 2166138079Sharti free(sh); 2167138079Sharti } 2168138079Sharti} 2169138079Sharti 2170136840Sruvoid 2171136840SruShell_Init(void) 2172136840Sru{ 2173138079Sharti 2174138079Sharti if (commandShell == NULL) 2175138228Sharti commandShell = JobMatchShell(shells[DEFSHELL].name); 2176138079Sharti 2177136840Sru if (shellPath == NULL) { 2178136840Sru /* 2179136840Sru * The user didn't specify a shell to use, so we are using the 2180136840Sru * default one... Both the absolute path and the last component 2181136840Sru * must be set. The last component is taken from the 'name' field 2182136840Sru * of the default shell description pointed-to by commandShell. 2183136840Sru * All default shells are located in _PATH_DEFSHELLDIR. 2184136840Sru */ 2185136840Sru shellName = commandShell->name; 2186136840Sru shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); 2187136840Sru } 2188136840Sru} 2189136840Sru 21901590Srgrimes/*- 21911590Srgrimes *----------------------------------------------------------------------- 21921590Srgrimes * Job_Init -- 2193137572Sphk * Initialize the process module, given a maximum number of jobs. 21941590Srgrimes * 21951590Srgrimes * Results: 21961590Srgrimes * none 21971590Srgrimes * 21981590Srgrimes * Side Effects: 21991590Srgrimes * lists and counters are initialized 22001590Srgrimes *----------------------------------------------------------------------- 22011590Srgrimes */ 22021590Srgrimesvoid 2203137572SphkJob_Init(int maxproc) 22041590Srgrimes{ 22051590Srgrimes GNode *begin; /* node for commands to do at the very start */ 2206137606Sphk const char *env; 2207137605Sharti struct sigaction sa; 22081590Srgrimes 2209138232Sharti fifoFd = -1; 2210137606Sphk env = getenv("MAKE_JOBS_FIFO"); 2211137606Sphk 2212137606Sphk if (env == NULL && maxproc > 1) { 2213137606Sphk /* 2214137606Sphk * We did not find the environment variable so we are the leader. 2215137606Sphk * Create the fifo, open it, write one char per allowed job into 2216137606Sphk * the pipe. 2217137606Sphk */ 2218137606Sphk mktemp(fifoName); 2219137606Sphk if (!mkfifo(fifoName, 0600)) { 2220137606Sphk fifoFd = open(fifoName, O_RDWR | O_NONBLOCK, 0); 2221137606Sphk if (fifoFd >= 0) { 2222137606Sphk fifoMaster = 1; 2223137606Sphk fcntl(fifoFd, F_SETFL, O_NONBLOCK); 2224137606Sphk env = fifoName; 2225137606Sphk setenv("MAKE_JOBS_FIFO", env, 1); 2226137606Sphk while (maxproc-- > 0) { 2227137606Sphk write(fifoFd, "+", 1); 2228137606Sphk } 2229138264Sharti /* The master make does not get a magic token */ 2230137606Sphk jobFull = TRUE; 2231137606Sphk maxJobs = 0; 2232137606Sphk } else { 2233137606Sphk unlink(fifoName); 2234137606Sphk env = NULL; 2235137606Sphk } 2236137606Sphk } 2237137606Sphk } else if (env != NULL) { 2238137606Sphk /* 2239137606Sphk * We had the environment variable so we are a slave. 2240137606Sphk * Open fifo and give ourselves a magic token which represents 2241137606Sphk * the token our parent make has grabbed to start his make process. 2242137606Sphk * Otherwise the sub-makes would gobble up tokens and the proper 2243137610Sceri * number of tokens to specify to -j would depend on the depth of 2244137610Sceri * the tree and the order of execution. 2245137606Sphk */ 2246137606Sphk fifoFd = open(env, O_RDWR, 0); 2247137606Sphk if (fifoFd >= 0) { 2248137606Sphk fcntl(fifoFd, F_SETFL, O_NONBLOCK); 2249137606Sphk maxJobs = 1; 2250137606Sphk jobFull = FALSE; 2251137606Sphk } 2252137606Sphk } 2253137606Sphk if (fifoFd <= 0) { 2254137606Sphk maxJobs = maxproc; 2255137606Sphk jobFull = FALSE; 2256137606Sphk } else { 2257137606Sphk } 2258138232Sharti nJobs = 0; 22591590Srgrimes 2260138232Sharti aborting = 0; 2261138232Sharti errors = 0; 22621590Srgrimes 2263138232Sharti lastNode = NULL; 22641590Srgrimes 2265137606Sphk if ((maxJobs == 1 && fifoFd < 0) || beVerbose == 0) { 22661590Srgrimes /* 22671590Srgrimes * If only one job can run at a time, there's no need for a banner, 22681590Srgrimes * no is there? 22691590Srgrimes */ 22701590Srgrimes targFmt = ""; 22711590Srgrimes } else { 22721590Srgrimes targFmt = TARG_FMT; 22731590Srgrimes } 22748874Srgrimes 2275136840Sru Shell_Init(); 22761590Srgrimes 22771590Srgrimes /* 22781590Srgrimes * Catch the four signals that POSIX specifies if they aren't ignored. 2279137605Sharti * JobCatchSignal will just set global variables and hope someone 2280137605Sharti * else is going to handle the interrupt. 22811590Srgrimes */ 2282137605Sharti sa.sa_handler = JobCatchSig; 2283137605Sharti sigemptyset(&sa.sa_mask); 2284137605Sharti sa.sa_flags = 0; 2285137605Sharti 228618730Ssteve if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 2287138232Sharti sigaction(SIGINT, &sa, NULL); 22881590Srgrimes } 228918730Ssteve if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 2290138232Sharti sigaction(SIGHUP, &sa, NULL); 22911590Srgrimes } 229218730Ssteve if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 2293138232Sharti sigaction(SIGQUIT, &sa, NULL); 22941590Srgrimes } 229518730Ssteve if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 2296138232Sharti sigaction(SIGTERM, &sa, NULL); 22971590Srgrimes } 22981590Srgrimes /* 22991590Srgrimes * There are additional signals that need to be caught and passed if 23001590Srgrimes * either the export system wants to be told directly of signals or if 23011590Srgrimes * we're giving each job its own process group (since then it won't get 23021590Srgrimes * signals from the terminal driver as we own the terminal) 23031590Srgrimes */ 2304137202Sharti#if defined(USE_PGRP) 230518730Ssteve if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { 2306138232Sharti sigaction(SIGTSTP, &sa, NULL); 23071590Srgrimes } 230818730Ssteve if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { 2309138232Sharti sigaction(SIGTTOU, &sa, NULL); 23101590Srgrimes } 231118730Ssteve if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { 2312138232Sharti sigaction(SIGTTIN, &sa, NULL); 23131590Srgrimes } 231418730Ssteve if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { 2315138232Sharti sigaction(SIGWINCH, &sa, NULL); 23161590Srgrimes } 23171590Srgrimes#endif 23188874Srgrimes 2319104475Sphk#ifdef USE_KQUEUE 2320104475Sphk if ((kqfd = kqueue()) == -1) { 2321104475Sphk Punt("kqueue: %s", strerror(errno)); 2322104475Sphk } 2323104475Sphk#endif 2324104475Sphk 232518730Ssteve begin = Targ_FindNode(".BEGIN", TARG_NOCREATE); 23261590Srgrimes 232769527Swill if (begin != NULL) { 2328138264Sharti JobStart(begin, JOB_SPECIAL, (Job *)NULL); 23291590Srgrimes while (nJobs) { 2330137606Sphk Job_CatchOutput(0); 233118730Ssteve Job_CatchChildren(!usePipes); 23321590Srgrimes } 23331590Srgrimes } 233418730Ssteve postCommands = Targ_FindNode(".END", TARG_CREATE); 23351590Srgrimes} 23361590Srgrimes 23371590Srgrimes/*- 23381590Srgrimes *----------------------------------------------------------------------- 23391590Srgrimes * Job_Full -- 23401590Srgrimes * See if the job table is full. It is considered full if it is OR 23411590Srgrimes * if we are in the process of aborting OR if we have 23421590Srgrimes * reached/exceeded our local quota. This prevents any more jobs 23431590Srgrimes * from starting up. 23441590Srgrimes * 23451590Srgrimes * Results: 23461590Srgrimes * TRUE if the job table is full, FALSE otherwise 23471590Srgrimes * Side Effects: 23481590Srgrimes * None. 23491590Srgrimes *----------------------------------------------------------------------- 23501590Srgrimes */ 23511590SrgrimesBoolean 2352104696SjmallettJob_Full(void) 23531590Srgrimes{ 2354137606Sphk char c; 2355137606Sphk int i; 2356137606Sphk 2357137606Sphk if (aborting) 2358138232Sharti return (aborting); 2359137606Sphk if (fifoFd >= 0 && jobFull) { 2360137606Sphk i = read(fifoFd, &c, 1); 2361137606Sphk if (i > 0) { 2362137606Sphk maxJobs++; 2363137606Sphk jobFull = FALSE; 2364137606Sphk } 2365137606Sphk } 2366138232Sharti return (jobFull); 23671590Srgrimes} 23681590Srgrimes 23691590Srgrimes/*- 23701590Srgrimes *----------------------------------------------------------------------- 23711590Srgrimes * Job_Empty -- 23721590Srgrimes * See if the job table is empty. Because the local concurrency may 23731590Srgrimes * be set to 0, it is possible for the job table to become empty, 23741590Srgrimes * while the list of stoppedJobs remains non-empty. In such a case, 23751590Srgrimes * we want to restart as many jobs as we can. 23761590Srgrimes * 23771590Srgrimes * Results: 23781590Srgrimes * TRUE if it is. FALSE if it ain't. 23791590Srgrimes * 23801590Srgrimes * Side Effects: 23811590Srgrimes * None. 23821590Srgrimes * 23831590Srgrimes * ----------------------------------------------------------------------- 23841590Srgrimes */ 23851590SrgrimesBoolean 2386104696SjmallettJob_Empty(void) 23871590Srgrimes{ 23881590Srgrimes if (nJobs == 0) { 2389138916Sharti if (!Lst_IsEmpty(&stoppedJobs) && !aborting) { 23901590Srgrimes /* 23911590Srgrimes * The job table is obviously not full if it has no jobs in 23921590Srgrimes * it...Try and restart the stopped jobs. 23931590Srgrimes */ 23941590Srgrimes jobFull = FALSE; 239518730Ssteve JobRestartJobs(); 2396138232Sharti return (FALSE); 23971590Srgrimes } else { 2398138232Sharti return (TRUE); 23991590Srgrimes } 24001590Srgrimes } else { 2401138232Sharti return (FALSE); 24021590Srgrimes } 24031590Srgrimes} 24041590Srgrimes 24051590Srgrimes/*- 24061590Srgrimes *----------------------------------------------------------------------- 24071590Srgrimes * JobMatchShell -- 24081590Srgrimes * Find a matching shell in 'shells' given its final component. 24091590Srgrimes * 24101590Srgrimes * Results: 2411138334Sharti * A pointer to a freshly allocated Shell structure with a copy 2412138228Sharti * of the static structure or NULL if no shell with the given name 2413138228Sharti * is found. 24141590Srgrimes * 24151590Srgrimes * Side Effects: 24161590Srgrimes * None. 24171590Srgrimes * 24181590Srgrimes *----------------------------------------------------------------------- 24191590Srgrimes */ 24201590Srgrimesstatic Shell * 2421138228ShartiJobMatchShell(const char *name) 24221590Srgrimes{ 2423138228Sharti const struct CShell *sh; /* Pointer into shells table */ 2424138228Sharti struct Shell *nsh; 24251590Srgrimes 2426138334Sharti for (sh = shells; sh < shells + sizeof(shells) / sizeof(shells[0]); sh++) 2427138334Sharti if (strcmp(sh->name, name) == 0) 2428138334Sharti break; 24291590Srgrimes 2430138334Sharti if (sh == shells + sizeof(shells) / sizeof(shells[0])) 2431138228Sharti return (NULL); 2432138228Sharti 2433138228Sharti /* make a copy */ 2434138228Sharti nsh = emalloc(sizeof(*nsh)); 2435138228Sharti 2436138334Sharti nsh->name = estrdup(sh->name); 2437138334Sharti nsh->echoOff = estrdup(sh->echoOff); 2438138334Sharti nsh->echoOn = estrdup(sh->echoOn); 2439138334Sharti nsh->hasEchoCtl = sh->hasEchoCtl; 2440138334Sharti nsh->noPrint = estrdup(sh->noPrint); 2441138334Sharti nsh->noPLen = sh->noPLen; 2442138334Sharti nsh->hasErrCtl = sh->hasErrCtl; 2443138334Sharti nsh->errCheck = estrdup(sh->errCheck); 2444138334Sharti nsh->ignErr = estrdup(sh->ignErr); 2445138334Sharti nsh->echo = estrdup(sh->echo); 2446138334Sharti nsh->exit = estrdup(sh->exit); 2447138228Sharti 2448138228Sharti return (nsh); 24491590Srgrimes} 24501590Srgrimes 24511590Srgrimes/*- 24521590Srgrimes *----------------------------------------------------------------------- 24531590Srgrimes * Job_ParseShell -- 24541590Srgrimes * Parse a shell specification and set up commandShell, shellPath 24551590Srgrimes * and shellName appropriately. 24561590Srgrimes * 24571590Srgrimes * Results: 24581590Srgrimes * FAILURE if the specification was incorrect. 24591590Srgrimes * 24601590Srgrimes * Side Effects: 24611590Srgrimes * commandShell points to a Shell structure (either predefined or 24621590Srgrimes * created from the shell spec), shellPath is the full path of the 24631590Srgrimes * shell described by commandShell, while shellName is just the 24641590Srgrimes * final component of shellPath. 24651590Srgrimes * 24661590Srgrimes * Notes: 24671590Srgrimes * A shell specification consists of a .SHELL target, with dependency 24681590Srgrimes * operator, followed by a series of blank-separated words. Double 24691590Srgrimes * quotes can be used to use blanks in words. A backslash escapes 24701590Srgrimes * anything (most notably a double-quote and a space) and 24711590Srgrimes * provides the functionality it does in C. Each word consists of 24721590Srgrimes * keyword and value separated by an equal sign. There should be no 24731590Srgrimes * unnecessary spaces in the word. The keywords are as follows: 24741590Srgrimes * name Name of shell. 24751590Srgrimes * path Location of shell. Overrides "name" if given 24761590Srgrimes * quiet Command to turn off echoing. 24771590Srgrimes * echo Command to turn echoing on 24781590Srgrimes * filter Result of turning off echoing that shouldn't be 24791590Srgrimes * printed. 24801590Srgrimes * echoFlag Flag to turn echoing on at the start 24811590Srgrimes * errFlag Flag to turn error checking on at the start 24821590Srgrimes * hasErrCtl True if shell has error checking control 24831590Srgrimes * check Command to turn on error checking if hasErrCtl 24841590Srgrimes * is TRUE or template of command to echo a command 24851590Srgrimes * for which error checking is off if hasErrCtl is 24861590Srgrimes * FALSE. 24871590Srgrimes * ignore Command to turn off error checking if hasErrCtl 24881590Srgrimes * is TRUE or template of command to execute a 24891590Srgrimes * command so as to ignore any errors it returns if 24901590Srgrimes * hasErrCtl is FALSE. 24911590Srgrimes * 24921590Srgrimes *----------------------------------------------------------------------- 24931590Srgrimes */ 24941590SrgrimesReturnStatus 2495104696SjmallettJob_ParseShell(char *line) 24961590Srgrimes{ 24971590Srgrimes char **words; 24981590Srgrimes int wordCount; 249994584Sobrien char **argv; 250094584Sobrien int argc; 25011590Srgrimes char *path; 2502138228Sharti Shell newShell; 2503138228Sharti Shell *sh; 25041590Srgrimes Boolean fullSpec = FALSE; 25051590Srgrimes 2506138232Sharti while (isspace((unsigned char)*line)) { 25071590Srgrimes line++; 25081590Srgrimes } 250918730Ssteve words = brk_string(line, &wordCount, TRUE); 25101590Srgrimes 251169531Swill memset(&newShell, 0, sizeof(newShell)); 25128874Srgrimes 25131590Srgrimes /* 25141590Srgrimes * Parse the specification by keyword 25151590Srgrimes */ 251618730Ssteve for (path = NULL, argc = wordCount - 1, argv = words + 1; 25171590Srgrimes argc != 0; 25181590Srgrimes argc--, argv++) { 251918730Ssteve if (strncmp(*argv, "path=", 5) == 0) { 25201590Srgrimes path = &argv[0][5]; 252118730Ssteve } else if (strncmp(*argv, "name=", 5) == 0) { 25221590Srgrimes newShell.name = &argv[0][5]; 25231590Srgrimes } else { 252418730Ssteve if (strncmp(*argv, "quiet=", 6) == 0) { 25251590Srgrimes newShell.echoOff = &argv[0][6]; 252618730Ssteve } else if (strncmp(*argv, "echo=", 5) == 0) { 25271590Srgrimes newShell.echoOn = &argv[0][5]; 252818730Ssteve } else if (strncmp(*argv, "filter=", 7) == 0) { 25291590Srgrimes newShell.noPrint = &argv[0][7]; 25301590Srgrimes newShell.noPLen = strlen(newShell.noPrint); 253118730Ssteve } else if (strncmp(*argv, "echoFlag=", 9) == 0) { 25321590Srgrimes newShell.echo = &argv[0][9]; 253318730Ssteve } else if (strncmp(*argv, "errFlag=", 8) == 0) { 25341590Srgrimes newShell.exit = &argv[0][8]; 253518730Ssteve } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { 25361590Srgrimes char c = argv[0][10]; 25371590Srgrimes newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && 253818730Ssteve (c != 'T') && (c != 't')); 253918730Ssteve } else if (strncmp(*argv, "check=", 6) == 0) { 25401590Srgrimes newShell.errCheck = &argv[0][6]; 254118730Ssteve } else if (strncmp(*argv, "ignore=", 7) == 0) { 25421590Srgrimes newShell.ignErr = &argv[0][7]; 25431590Srgrimes } else { 254418730Ssteve Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", 25451590Srgrimes *argv); 2546138232Sharti return (FAILURE); 25471590Srgrimes } 25481590Srgrimes fullSpec = TRUE; 25491590Srgrimes } 25501590Srgrimes } 25511590Srgrimes 2552138079Sharti /* 2553138079Sharti * Some checks (could be more) 2554138079Sharti */ 2555138079Sharti if (fullSpec) { 2556138079Sharti if ((newShell.echoOn != NULL) ^ (newShell.echoOff != NULL)) 2557138079Sharti Parse_Error(PARSE_FATAL, "Shell must have either both echoOff and " 2558138079Sharti "echoOn or none of them"); 2559138079Sharti 2560138079Sharti if (newShell.echoOn != NULL && newShell.echoOff) 2561138079Sharti newShell.hasEchoCtl = TRUE; 2562138079Sharti } 2563138079Sharti 256418730Ssteve if (path == NULL) { 25651590Srgrimes /* 25661590Srgrimes * If no path was given, the user wants one of the pre-defined shells, 25671590Srgrimes * yes? So we find the one s/he wants with the help of JobMatchShell 25681590Srgrimes * and set things up the right way. shellPath will be set up by 25691590Srgrimes * Job_Init. 25701590Srgrimes */ 257118730Ssteve if (newShell.name == NULL) { 257218730Ssteve Parse_Error(PARSE_FATAL, "Neither path nor name specified"); 2573138079Sharti return (FAILURE); 25741590Srgrimes } 2575138079Sharti if ((sh = JobMatchShell(newShell.name)) == NULL) { 2576138079Sharti Parse_Error(PARSE_FATAL, "%s: no matching shell", newShell.name); 2577138079Sharti return (FAILURE); 2578138079Sharti } 2579138079Sharti 25801590Srgrimes } else { 25811590Srgrimes /* 25821590Srgrimes * The user provided a path. If s/he gave nothing else (fullSpec is 25831590Srgrimes * FALSE), try and find a matching shell in the ones we know of. 25841590Srgrimes * Else we just take the specification at its word and copy it 25851590Srgrimes * to a new location. In either case, we need to record the 25861590Srgrimes * path the user gave for the shell. 25871590Srgrimes */ 2588138079Sharti free(shellPath); 2589138079Sharti shellPath = estrdup(path); 2590138079Sharti if (newShell.name == NULL) { 2591138079Sharti /* get the base name as the name */ 2592138079Sharti path = strrchr(path, '/'); 2593138079Sharti if (path == NULL) { 2594138079Sharti path = shellPath; 2595138079Sharti } else { 2596138079Sharti path += 1; 2597138079Sharti } 2598138079Sharti newShell.name = path; 25991590Srgrimes } 2600138079Sharti 26011590Srgrimes if (!fullSpec) { 2602138079Sharti if ((sh = JobMatchShell(newShell.name)) == NULL) { 2603136840Sru Parse_Error(PARSE_FATAL, "%s: no matching shell", 2604138079Sharti newShell.name); 2605138079Sharti return (FAILURE); 2606136840Sru } 26071590Srgrimes } else { 2608138228Sharti sh = JobCopyShell(&newShell); 26091590Srgrimes } 26101590Srgrimes } 26111590Srgrimes 2612138079Sharti /* set the new shell */ 2613138079Sharti JobFreeShell(commandShell); 2614138228Sharti commandShell = sh; 26158874Srgrimes 2616138079Sharti shellName = commandShell->name; 26178874Srgrimes 2618138079Sharti return (SUCCESS); 26191590Srgrimes} 26201590Srgrimes 26211590Srgrimes/*- 26221590Srgrimes *----------------------------------------------------------------------- 26231590Srgrimes * JobInterrupt -- 26241590Srgrimes * Handle the receipt of an interrupt. 26251590Srgrimes * 26261590Srgrimes * Results: 26271590Srgrimes * None 26281590Srgrimes * 26291590Srgrimes * Side Effects: 26301590Srgrimes * All children are killed. Another job will be started if the 26311590Srgrimes * .INTERRUPT target was given. 26321590Srgrimes *----------------------------------------------------------------------- 26331590Srgrimes */ 26341590Srgrimesstatic void 2635104696SjmallettJobInterrupt(int runINTERRUPT, int signo) 26361590Srgrimes{ 2637138512Sharti LstNode *ln; /* element in job table */ 2638138564Sharti Job *job; /* job descriptor in that element */ 26391590Srgrimes GNode *interrupt; /* the node describing the .INTERRUPT target */ 26408874Srgrimes 26411590Srgrimes aborting = ABORT_INTERRUPT; 26421590Srgrimes 2643138916Sharti for (ln = Lst_First(&jobs); ln != NULL; ln = Lst_Succ(ln)) { 2644138264Sharti job = Lst_Datum(ln); 26451590Srgrimes 264618730Ssteve if (!Targ_Precious(job->node)) { 2647138232Sharti char *file = (job->node->path == NULL ? 2648138232Sharti job->node->name : 2649138232Sharti job->node->path); 265018730Ssteve if (!noExecute && eunlink(file) != -1) { 265118730Ssteve Error("*** %s removed", file); 26521590Srgrimes } 26531590Srgrimes } 26541590Srgrimes if (job->pid) { 2655103545Sjmallett DEBUGF(JOB, ("JobInterrupt passing signal to child %d.\n", 2656103545Sjmallett job->pid)); 265718730Ssteve KILL(job->pid, signo); 265818730Ssteve } 265918730Ssteve } 266018730Ssteve 26611590Srgrimes if (runINTERRUPT && !touchFlag) { 2662137605Sharti /* clear the interrupted flag because we would get an 2663137605Sharti * infinite loop otherwise */ 2664137605Sharti interrupted = 0; 2665137605Sharti 266618730Ssteve interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 266769527Swill if (interrupt != NULL) { 26681590Srgrimes ignoreErrors = FALSE; 26691590Srgrimes 2670138264Sharti JobStart(interrupt, JOB_IGNDOTS, (Job *)NULL); 26711590Srgrimes while (nJobs) { 2672137606Sphk Job_CatchOutput(0); 267318730Ssteve Job_CatchChildren(!usePipes); 26741590Srgrimes } 26751590Srgrimes } 26761590Srgrimes } 26771590Srgrimes} 26781590Srgrimes 26791590Srgrimes/* 26801590Srgrimes *----------------------------------------------------------------------- 268194594Sobrien * Job_Finish -- 26821590Srgrimes * Do final processing such as the running of the commands 26838874Srgrimes * attached to the .END target. 26841590Srgrimes * 26851590Srgrimes * Results: 26861590Srgrimes * Number of errors reported. 26871590Srgrimes *----------------------------------------------------------------------- 26881590Srgrimes */ 26891590Srgrimesint 2690104696SjmallettJob_Finish(void) 26911590Srgrimes{ 2692138232Sharti 2693138916Sharti if (postCommands != NULL && !Lst_IsEmpty(&postCommands->commands)) { 26941590Srgrimes if (errors) { 269518730Ssteve Error("Errors reported so .END ignored"); 26961590Srgrimes } else { 269718730Ssteve JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); 26981590Srgrimes 26991590Srgrimes while (nJobs) { 2700137606Sphk Job_CatchOutput(0); 270118730Ssteve Job_CatchChildren(!usePipes); 27021590Srgrimes } 27031590Srgrimes } 27041590Srgrimes } 2705137606Sphk if (fifoFd >= 0) { 2706137606Sphk close(fifoFd); 2707137606Sphk fifoFd = -1; 2708137606Sphk if (fifoMaster) 2709137606Sphk unlink(fifoName); 2710137606Sphk } 2711138232Sharti return (errors); 27121590Srgrimes} 27131590Srgrimes 27141590Srgrimes/*- 27151590Srgrimes *----------------------------------------------------------------------- 27161590Srgrimes * Job_Wait -- 27171590Srgrimes * Waits for all running jobs to finish and returns. Sets 'aborting' 27181590Srgrimes * to ABORT_WAIT to prevent other jobs from starting. 27191590Srgrimes * 27201590Srgrimes * Results: 27211590Srgrimes * None. 27221590Srgrimes * 27231590Srgrimes * Side Effects: 27241590Srgrimes * Currently running jobs finish. 27251590Srgrimes * 27261590Srgrimes *----------------------------------------------------------------------- 27271590Srgrimes */ 27281590Srgrimesvoid 2729104696SjmallettJob_Wait(void) 27301590Srgrimes{ 2731138232Sharti 27321590Srgrimes aborting = ABORT_WAIT; 27331590Srgrimes while (nJobs != 0) { 2734137606Sphk Job_CatchOutput(0); 27351590Srgrimes Job_CatchChildren(!usePipes); 27361590Srgrimes } 27371590Srgrimes aborting = 0; 27381590Srgrimes} 27391590Srgrimes 27401590Srgrimes/*- 27411590Srgrimes *----------------------------------------------------------------------- 27421590Srgrimes * Job_AbortAll -- 27431590Srgrimes * Abort all currently running jobs without handling output or anything. 27441590Srgrimes * This function is to be called only in the event of a major 27451590Srgrimes * error. Most definitely NOT to be called from JobInterrupt. 27461590Srgrimes * 27471590Srgrimes * Results: 27481590Srgrimes * None 27491590Srgrimes * 27501590Srgrimes * Side Effects: 27511590Srgrimes * All children are killed, not just the firstborn 27521590Srgrimes *----------------------------------------------------------------------- 27531590Srgrimes */ 27541590Srgrimesvoid 2755104696SjmallettJob_AbortAll(void) 27561590Srgrimes{ 2757138512Sharti LstNode *ln; /* element in job table */ 27581590Srgrimes Job *job; /* the job descriptor in that element */ 27591590Srgrimes int foo; 27608874Srgrimes 27611590Srgrimes aborting = ABORT_ERROR; 27628874Srgrimes 27631590Srgrimes if (nJobs) { 2764138916Sharti for (ln = Lst_First(&jobs); ln != NULL; ln = Lst_Succ(ln)) { 2765138264Sharti job = Lst_Datum(ln); 27661590Srgrimes 27671590Srgrimes /* 27681590Srgrimes * kill the child process with increasingly drastic signals to make 27698874Srgrimes * darn sure it's dead. 27701590Srgrimes */ 27711590Srgrimes KILL(job->pid, SIGINT); 27721590Srgrimes KILL(job->pid, SIGKILL); 27731590Srgrimes } 27741590Srgrimes } 27758874Srgrimes 27761590Srgrimes /* 27771590Srgrimes * Catch as many children as want to report in at first, then give up 27781590Srgrimes */ 2779138232Sharti while (waitpid((pid_t)-1, &foo, WNOHANG) > 0) 27801590Srgrimes continue; 27811590Srgrimes} 278218730Ssteve 278318730Ssteve/*- 278418730Ssteve *----------------------------------------------------------------------- 278518730Ssteve * JobRestartJobs -- 278618730Ssteve * Tries to restart stopped jobs if there are slots available. 278718730Ssteve * Note that this tries to restart them regardless of pending errors. 278818730Ssteve * It's not good to leave stopped jobs lying around! 278918730Ssteve * 279018730Ssteve * Results: 279118730Ssteve * None. 279218730Ssteve * 279318730Ssteve * Side Effects: 279418730Ssteve * Resumes(and possibly migrates) jobs. 279518730Ssteve * 279618730Ssteve *----------------------------------------------------------------------- 279718730Ssteve */ 279818730Sstevestatic void 2799104696SjmallettJobRestartJobs(void) 280018730Ssteve{ 2801138916Sharti while (!jobFull && !Lst_IsEmpty(&stoppedJobs)) { 2802103545Sjmallett DEBUGF(JOB, ("Job queue is not full. Restarting a stopped job.\n")); 2803138916Sharti JobRestart(Lst_DeQueue(&stoppedJobs)); 280418730Ssteve } 280518730Ssteve} 2806