1*db29cad8SSimon J. Gerraty /* $NetBSD: job.c,v 1.180 2015/04/16 13:31:03 joerg Exp $ */ 23955d011SMarcel Moolenaar 33955d011SMarcel Moolenaar /* 43955d011SMarcel Moolenaar * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 53955d011SMarcel Moolenaar * All rights reserved. 63955d011SMarcel Moolenaar * 73955d011SMarcel Moolenaar * This code is derived from software contributed to Berkeley by 83955d011SMarcel Moolenaar * Adam de Boor. 93955d011SMarcel Moolenaar * 103955d011SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 113955d011SMarcel Moolenaar * modification, are permitted provided that the following conditions 123955d011SMarcel Moolenaar * are met: 133955d011SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 143955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 153955d011SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 163955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 173955d011SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 183955d011SMarcel Moolenaar * 3. Neither the name of the University nor the names of its contributors 193955d011SMarcel Moolenaar * may be used to endorse or promote products derived from this software 203955d011SMarcel Moolenaar * without specific prior written permission. 213955d011SMarcel Moolenaar * 223955d011SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 233955d011SMarcel Moolenaar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 243955d011SMarcel Moolenaar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 253955d011SMarcel Moolenaar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 263955d011SMarcel Moolenaar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 273955d011SMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 283955d011SMarcel Moolenaar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 293955d011SMarcel Moolenaar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 303955d011SMarcel Moolenaar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 313955d011SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 323955d011SMarcel Moolenaar * SUCH DAMAGE. 333955d011SMarcel Moolenaar */ 343955d011SMarcel Moolenaar 353955d011SMarcel Moolenaar /* 363955d011SMarcel Moolenaar * Copyright (c) 1988, 1989 by Adam de Boor 373955d011SMarcel Moolenaar * Copyright (c) 1989 by Berkeley Softworks 383955d011SMarcel Moolenaar * All rights reserved. 393955d011SMarcel Moolenaar * 403955d011SMarcel Moolenaar * This code is derived from software contributed to Berkeley by 413955d011SMarcel Moolenaar * Adam de Boor. 423955d011SMarcel Moolenaar * 433955d011SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 443955d011SMarcel Moolenaar * modification, are permitted provided that the following conditions 453955d011SMarcel Moolenaar * are met: 463955d011SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 473955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 483955d011SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 493955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 503955d011SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 513955d011SMarcel Moolenaar * 3. All advertising materials mentioning features or use of this software 523955d011SMarcel Moolenaar * must display the following acknowledgement: 533955d011SMarcel Moolenaar * This product includes software developed by the University of 543955d011SMarcel Moolenaar * California, Berkeley and its contributors. 553955d011SMarcel Moolenaar * 4. Neither the name of the University nor the names of its contributors 563955d011SMarcel Moolenaar * may be used to endorse or promote products derived from this software 573955d011SMarcel Moolenaar * without specific prior written permission. 583955d011SMarcel Moolenaar * 593955d011SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 603955d011SMarcel Moolenaar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 613955d011SMarcel Moolenaar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 623955d011SMarcel Moolenaar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 633955d011SMarcel Moolenaar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 643955d011SMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 653955d011SMarcel Moolenaar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 663955d011SMarcel Moolenaar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 673955d011SMarcel Moolenaar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 683955d011SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 693955d011SMarcel Moolenaar * SUCH DAMAGE. 703955d011SMarcel Moolenaar */ 713955d011SMarcel Moolenaar 723955d011SMarcel Moolenaar #ifndef MAKE_NATIVE 73*db29cad8SSimon J. Gerraty static char rcsid[] = "$NetBSD: job.c,v 1.180 2015/04/16 13:31:03 joerg Exp $"; 743955d011SMarcel Moolenaar #else 753955d011SMarcel Moolenaar #include <sys/cdefs.h> 763955d011SMarcel Moolenaar #ifndef lint 773955d011SMarcel Moolenaar #if 0 783955d011SMarcel Moolenaar static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; 793955d011SMarcel Moolenaar #else 80*db29cad8SSimon J. Gerraty __RCSID("$NetBSD: job.c,v 1.180 2015/04/16 13:31:03 joerg Exp $"); 813955d011SMarcel Moolenaar #endif 823955d011SMarcel Moolenaar #endif /* not lint */ 833955d011SMarcel Moolenaar #endif 843955d011SMarcel Moolenaar 853955d011SMarcel Moolenaar /*- 863955d011SMarcel Moolenaar * job.c -- 873955d011SMarcel Moolenaar * handle the creation etc. of our child processes. 883955d011SMarcel Moolenaar * 893955d011SMarcel Moolenaar * Interface: 903955d011SMarcel Moolenaar * Job_Make Start the creation of the given target. 913955d011SMarcel Moolenaar * 923955d011SMarcel Moolenaar * Job_CatchChildren Check for and handle the termination of any 933955d011SMarcel Moolenaar * children. This must be called reasonably 943955d011SMarcel Moolenaar * frequently to keep the whole make going at 953955d011SMarcel Moolenaar * a decent clip, since job table entries aren't 963955d011SMarcel Moolenaar * removed until their process is caught this way. 973955d011SMarcel Moolenaar * 983955d011SMarcel Moolenaar * Job_CatchOutput Print any output our children have produced. 993955d011SMarcel Moolenaar * Should also be called fairly frequently to 1003955d011SMarcel Moolenaar * keep the user informed of what's going on. 1013955d011SMarcel Moolenaar * If no output is waiting, it will block for 1023955d011SMarcel Moolenaar * a time given by the SEL_* constants, below, 1033955d011SMarcel Moolenaar * or until output is ready. 1043955d011SMarcel Moolenaar * 1053955d011SMarcel Moolenaar * Job_Init Called to intialize this module. in addition, 1063955d011SMarcel Moolenaar * any commands attached to the .BEGIN target 1073955d011SMarcel Moolenaar * are executed before this function returns. 1083955d011SMarcel Moolenaar * Hence, the makefile must have been parsed 1093955d011SMarcel Moolenaar * before this function is called. 1103955d011SMarcel Moolenaar * 1113955d011SMarcel Moolenaar * Job_End Cleanup any memory used. 1123955d011SMarcel Moolenaar * 1133955d011SMarcel Moolenaar * Job_ParseShell Given the line following a .SHELL target, parse 1143955d011SMarcel Moolenaar * the line as a shell specification. Returns 1153955d011SMarcel Moolenaar * FAILURE if the spec was incorrect. 1163955d011SMarcel Moolenaar * 1173955d011SMarcel Moolenaar * Job_Finish Perform any final processing which needs doing. 1183955d011SMarcel Moolenaar * This includes the execution of any commands 1193955d011SMarcel Moolenaar * which have been/were attached to the .END 1203955d011SMarcel Moolenaar * target. It should only be called when the 1213955d011SMarcel Moolenaar * job table is empty. 1223955d011SMarcel Moolenaar * 1233955d011SMarcel Moolenaar * Job_AbortAll Abort all currently running jobs. It doesn't 1243955d011SMarcel Moolenaar * handle output or do anything for the jobs, 1253955d011SMarcel Moolenaar * just kills them. It should only be called in 1263955d011SMarcel Moolenaar * an emergency, as it were. 1273955d011SMarcel Moolenaar * 1283955d011SMarcel Moolenaar * Job_CheckCommands Verify that the commands for a target are 1293955d011SMarcel Moolenaar * ok. Provide them if necessary and possible. 1303955d011SMarcel Moolenaar * 1313955d011SMarcel Moolenaar * Job_Touch Update a target without really updating it. 1323955d011SMarcel Moolenaar * 1333955d011SMarcel Moolenaar * Job_Wait Wait for all currently-running jobs to finish. 1343955d011SMarcel Moolenaar */ 1353955d011SMarcel Moolenaar 1363955d011SMarcel Moolenaar #ifdef HAVE_CONFIG_H 1373955d011SMarcel Moolenaar # include "config.h" 1383955d011SMarcel Moolenaar #endif 1393955d011SMarcel Moolenaar #include <sys/types.h> 1403955d011SMarcel Moolenaar #include <sys/stat.h> 1413955d011SMarcel Moolenaar #include <sys/file.h> 1423955d011SMarcel Moolenaar #include <sys/time.h> 1433955d011SMarcel Moolenaar #include "wait.h" 1443955d011SMarcel Moolenaar 1451748de26SSimon J. Gerraty #include <assert.h> 1463955d011SMarcel Moolenaar #include <errno.h> 1473955d011SMarcel Moolenaar #include <fcntl.h> 1483955d011SMarcel Moolenaar #if !defined(USE_SELECT) && defined(HAVE_POLL_H) 1493955d011SMarcel Moolenaar #include <poll.h> 1503955d011SMarcel Moolenaar #else 1513955d011SMarcel Moolenaar #ifndef USE_SELECT /* no poll.h */ 1523955d011SMarcel Moolenaar # define USE_SELECT 1533955d011SMarcel Moolenaar #endif 1543955d011SMarcel Moolenaar #if defined(HAVE_SYS_SELECT_H) 1553955d011SMarcel Moolenaar # include <sys/select.h> 1563955d011SMarcel Moolenaar #endif 1573955d011SMarcel Moolenaar #endif 1583955d011SMarcel Moolenaar #include <signal.h> 1593955d011SMarcel Moolenaar #include <stdio.h> 1603955d011SMarcel Moolenaar #include <string.h> 1613955d011SMarcel Moolenaar #include <utime.h> 1623955d011SMarcel Moolenaar #if defined(HAVE_SYS_SOCKET_H) 1633955d011SMarcel Moolenaar # include <sys/socket.h> 1643955d011SMarcel Moolenaar #endif 1653955d011SMarcel Moolenaar 1663955d011SMarcel Moolenaar #include "make.h" 1673955d011SMarcel Moolenaar #include "hash.h" 1683955d011SMarcel Moolenaar #include "dir.h" 1693955d011SMarcel Moolenaar #include "job.h" 1703955d011SMarcel Moolenaar #include "pathnames.h" 1713955d011SMarcel Moolenaar #include "trace.h" 1723955d011SMarcel Moolenaar # define STATIC static 1733955d011SMarcel Moolenaar 1743955d011SMarcel Moolenaar /* 1759a4bc556SSimon J. Gerraty * FreeBSD: traditionally .MAKE is not required to 1769a4bc556SSimon J. Gerraty * pass jobs queue to sub-makes. 1779a4bc556SSimon J. Gerraty * Use .MAKE.ALWAYS_PASS_JOB_QUEUE=no to disable. 1789a4bc556SSimon J. Gerraty */ 1799a4bc556SSimon J. Gerraty #define MAKE_ALWAYS_PASS_JOB_QUEUE ".MAKE.ALWAYS_PASS_JOB_QUEUE" 1809a4bc556SSimon J. Gerraty static int Always_pass_job_queue = TRUE; 1812d395cb5SSimon J. Gerraty /* 1822d395cb5SSimon J. Gerraty * FreeBSD: aborting entire parallel make isn't always 1832d395cb5SSimon J. Gerraty * desired. When doing tinderbox for example, failure of 1842d395cb5SSimon J. Gerraty * one architecture should not stop all. 1852d395cb5SSimon J. Gerraty * We still want to bail on interrupt though. 1862d395cb5SSimon J. Gerraty */ 1872d395cb5SSimon J. Gerraty #define MAKE_JOB_ERROR_TOKEN "MAKE_JOB_ERROR_TOKEN" 1882d395cb5SSimon J. Gerraty static int Job_error_token = TRUE; 1899a4bc556SSimon J. Gerraty 1909a4bc556SSimon J. Gerraty /* 1913955d011SMarcel Moolenaar * error handling variables 1923955d011SMarcel Moolenaar */ 1933955d011SMarcel Moolenaar static int errors = 0; /* number of errors reported */ 1943955d011SMarcel Moolenaar static int aborting = 0; /* why is the make aborting? */ 1953955d011SMarcel Moolenaar #define ABORT_ERROR 1 /* Because of an error */ 1963955d011SMarcel Moolenaar #define ABORT_INTERRUPT 2 /* Because it was interrupted */ 1973955d011SMarcel Moolenaar #define ABORT_WAIT 3 /* Waiting for jobs to finish */ 1983955d011SMarcel Moolenaar #define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */ 1993955d011SMarcel Moolenaar 2003955d011SMarcel Moolenaar /* 2013955d011SMarcel Moolenaar * this tracks the number of tokens currently "out" to build jobs. 2023955d011SMarcel Moolenaar */ 2033955d011SMarcel Moolenaar int jobTokensRunning = 0; 2043955d011SMarcel Moolenaar int not_parallel = 0; /* set if .NOT_PARALLEL */ 2053955d011SMarcel Moolenaar 2063955d011SMarcel Moolenaar /* 2073955d011SMarcel Moolenaar * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file 2083955d011SMarcel Moolenaar * is a char! So when we go above 127 we turn negative! 2093955d011SMarcel Moolenaar */ 2103955d011SMarcel Moolenaar #define FILENO(a) ((unsigned) fileno(a)) 2113955d011SMarcel Moolenaar 2123955d011SMarcel Moolenaar /* 2133955d011SMarcel Moolenaar * post-make command processing. The node postCommands is really just the 2143955d011SMarcel Moolenaar * .END target but we keep it around to avoid having to search for it 2153955d011SMarcel Moolenaar * all the time. 2163955d011SMarcel Moolenaar */ 2173955d011SMarcel Moolenaar static GNode *postCommands = NULL; 2183955d011SMarcel Moolenaar /* node containing commands to execute when 2193955d011SMarcel Moolenaar * everything else is done */ 2203955d011SMarcel Moolenaar static int numCommands; /* The number of commands actually printed 2213955d011SMarcel Moolenaar * for a target. Should this number be 2223955d011SMarcel Moolenaar * 0, no shell will be executed. */ 2233955d011SMarcel Moolenaar 2243955d011SMarcel Moolenaar /* 2253955d011SMarcel Moolenaar * Return values from JobStart. 2263955d011SMarcel Moolenaar */ 2273955d011SMarcel Moolenaar #define JOB_RUNNING 0 /* Job is running */ 2283955d011SMarcel Moolenaar #define JOB_ERROR 1 /* Error in starting the job */ 2293955d011SMarcel Moolenaar #define JOB_FINISHED 2 /* The job is already finished */ 2303955d011SMarcel Moolenaar 2313955d011SMarcel Moolenaar /* 2323955d011SMarcel Moolenaar * Descriptions for various shells. 2333955d011SMarcel Moolenaar * 2343955d011SMarcel Moolenaar * The build environment may set DEFSHELL_INDEX to one of 2353955d011SMarcel Moolenaar * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to 2363955d011SMarcel Moolenaar * select one of the prefedined shells as the default shell. 2373955d011SMarcel Moolenaar * 2383955d011SMarcel Moolenaar * Alternatively, the build environment may set DEFSHELL_CUSTOM to the 2393955d011SMarcel Moolenaar * name or the full path of a sh-compatible shell, which will be used as 2403955d011SMarcel Moolenaar * the default shell. 2413955d011SMarcel Moolenaar * 2423955d011SMarcel Moolenaar * ".SHELL" lines in Makefiles can choose the default shell from the 2433955d011SMarcel Moolenaar # set defined here, or add additional shells. 2443955d011SMarcel Moolenaar */ 2453955d011SMarcel Moolenaar 2463955d011SMarcel Moolenaar #ifdef DEFSHELL_CUSTOM 2473955d011SMarcel Moolenaar #define DEFSHELL_INDEX_CUSTOM 0 2483955d011SMarcel Moolenaar #define DEFSHELL_INDEX_SH 1 2493955d011SMarcel Moolenaar #define DEFSHELL_INDEX_KSH 2 2503955d011SMarcel Moolenaar #define DEFSHELL_INDEX_CSH 3 2513955d011SMarcel Moolenaar #else /* !DEFSHELL_CUSTOM */ 2523955d011SMarcel Moolenaar #define DEFSHELL_INDEX_SH 0 2533955d011SMarcel Moolenaar #define DEFSHELL_INDEX_KSH 1 2543955d011SMarcel Moolenaar #define DEFSHELL_INDEX_CSH 2 2553955d011SMarcel Moolenaar #endif /* !DEFSHELL_CUSTOM */ 2563955d011SMarcel Moolenaar 2573955d011SMarcel Moolenaar #ifndef DEFSHELL_INDEX 2583955d011SMarcel Moolenaar #define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */ 2593955d011SMarcel Moolenaar #endif /* !DEFSHELL_INDEX */ 2603955d011SMarcel Moolenaar 2613955d011SMarcel Moolenaar static Shell shells[] = { 2623955d011SMarcel Moolenaar #ifdef DEFSHELL_CUSTOM 2633955d011SMarcel Moolenaar /* 2643955d011SMarcel Moolenaar * An sh-compatible shell with a non-standard name. 2653955d011SMarcel Moolenaar * 2663955d011SMarcel Moolenaar * Keep this in sync with the "sh" description below, but avoid 2673955d011SMarcel Moolenaar * non-portable features that might not be supplied by all 2683955d011SMarcel Moolenaar * sh-compatible shells. 2693955d011SMarcel Moolenaar */ 2703955d011SMarcel Moolenaar { 2713955d011SMarcel Moolenaar DEFSHELL_CUSTOM, 2723955d011SMarcel Moolenaar FALSE, "", "", "", 0, 2733955d011SMarcel Moolenaar FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', 2743955d011SMarcel Moolenaar "", 2753955d011SMarcel Moolenaar "", 2763955d011SMarcel Moolenaar }, 2773955d011SMarcel Moolenaar #endif /* DEFSHELL_CUSTOM */ 2783955d011SMarcel Moolenaar /* 2793955d011SMarcel Moolenaar * SH description. Echo control is also possible and, under 2803955d011SMarcel Moolenaar * sun UNIX anyway, one can even control error checking. 2813955d011SMarcel Moolenaar */ 2823955d011SMarcel Moolenaar { 2833955d011SMarcel Moolenaar "sh", 2843955d011SMarcel Moolenaar FALSE, "", "", "", 0, 2853955d011SMarcel Moolenaar FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', 2863955d011SMarcel Moolenaar #if defined(MAKE_NATIVE) && defined(__NetBSD__) 2873955d011SMarcel Moolenaar "q", 2883955d011SMarcel Moolenaar #else 2893955d011SMarcel Moolenaar "", 2903955d011SMarcel Moolenaar #endif 2913955d011SMarcel Moolenaar "", 2923955d011SMarcel Moolenaar }, 2933955d011SMarcel Moolenaar /* 2943955d011SMarcel Moolenaar * KSH description. 2953955d011SMarcel Moolenaar */ 2963955d011SMarcel Moolenaar { 2973955d011SMarcel Moolenaar "ksh", 2983955d011SMarcel Moolenaar TRUE, "set +v", "set -v", "set +v", 6, 2993955d011SMarcel Moolenaar FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', 3003955d011SMarcel Moolenaar "v", 3013955d011SMarcel Moolenaar "", 3023955d011SMarcel Moolenaar }, 3033955d011SMarcel Moolenaar /* 3043955d011SMarcel Moolenaar * CSH description. The csh can do echo control by playing 3053955d011SMarcel Moolenaar * with the setting of the 'echo' shell variable. Sadly, 3063955d011SMarcel Moolenaar * however, it is unable to do error control nicely. 3073955d011SMarcel Moolenaar */ 3083955d011SMarcel Moolenaar { 3093955d011SMarcel Moolenaar "csh", 3103955d011SMarcel Moolenaar TRUE, "unset verbose", "set verbose", "unset verbose", 10, 3113955d011SMarcel Moolenaar FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"\n", "", "'\\\n'", '#', 3123955d011SMarcel Moolenaar "v", "e", 3133955d011SMarcel Moolenaar }, 3143955d011SMarcel Moolenaar /* 3153955d011SMarcel Moolenaar * UNKNOWN. 3163955d011SMarcel Moolenaar */ 3173955d011SMarcel Moolenaar { 3183955d011SMarcel Moolenaar NULL, 3193955d011SMarcel Moolenaar FALSE, NULL, NULL, NULL, 0, 3203955d011SMarcel Moolenaar FALSE, NULL, NULL, NULL, NULL, 0, 3213955d011SMarcel Moolenaar NULL, NULL, 3223955d011SMarcel Moolenaar } 3233955d011SMarcel Moolenaar }; 3243955d011SMarcel Moolenaar static Shell *commandShell = &shells[DEFSHELL_INDEX]; /* this is the shell to 3253955d011SMarcel Moolenaar * which we pass all 3263955d011SMarcel Moolenaar * commands in the Makefile. 3273955d011SMarcel Moolenaar * It is set by the 3283955d011SMarcel Moolenaar * Job_ParseShell function */ 3293955d011SMarcel Moolenaar const char *shellPath = NULL, /* full pathname of 3303955d011SMarcel Moolenaar * executable image */ 3313955d011SMarcel Moolenaar *shellName = NULL; /* last component of shell */ 33251ee2c1cSSimon J. Gerraty char *shellErrFlag = NULL; 3333955d011SMarcel Moolenaar static const char *shellArgv = NULL; /* Custom shell args */ 3343955d011SMarcel Moolenaar 3353955d011SMarcel Moolenaar 3363955d011SMarcel Moolenaar STATIC Job *job_table; /* The structures that describe them */ 3373955d011SMarcel Moolenaar STATIC Job *job_table_end; /* job_table + maxJobs */ 3383955d011SMarcel Moolenaar static int wantToken; /* we want a token */ 3393955d011SMarcel Moolenaar static int lurking_children = 0; 3403955d011SMarcel Moolenaar static int make_suspended = 0; /* non-zero if we've seen a SIGTSTP (etc) */ 3413955d011SMarcel Moolenaar 3423955d011SMarcel Moolenaar /* 3433955d011SMarcel Moolenaar * Set of descriptors of pipes connected to 3443955d011SMarcel Moolenaar * the output channels of children 3453955d011SMarcel Moolenaar */ 3463955d011SMarcel Moolenaar static struct pollfd *fds = NULL; 3473955d011SMarcel Moolenaar static Job **jobfds = NULL; 3483955d011SMarcel Moolenaar static int nfds = 0; 3493955d011SMarcel Moolenaar static void watchfd(Job *); 3503955d011SMarcel Moolenaar static void clearfd(Job *); 3513955d011SMarcel Moolenaar static int readyfd(Job *); 3523955d011SMarcel Moolenaar 3533955d011SMarcel Moolenaar STATIC GNode *lastNode; /* The node for which output was most recently 3543955d011SMarcel Moolenaar * produced. */ 3553955d011SMarcel Moolenaar static char *targPrefix = NULL; /* What we print at the start of TARG_FMT */ 3563955d011SMarcel Moolenaar static Job tokenWaitJob; /* token wait pseudo-job */ 3573955d011SMarcel Moolenaar 3583955d011SMarcel Moolenaar static Job childExitJob; /* child exit pseudo-job */ 3593955d011SMarcel Moolenaar #define CHILD_EXIT "." 3603955d011SMarcel Moolenaar #define DO_JOB_RESUME "R" 3613955d011SMarcel Moolenaar 3623955d011SMarcel Moolenaar #define TARG_FMT "%s %s ---\n" /* Default format */ 3633955d011SMarcel Moolenaar #define MESSAGE(fp, gn) \ 36451ee2c1cSSimon J. Gerraty if (maxJobs != 1 && targPrefix && *targPrefix) \ 3653955d011SMarcel Moolenaar (void)fprintf(fp, TARG_FMT, targPrefix, gn->name) 3663955d011SMarcel Moolenaar 3673955d011SMarcel Moolenaar static sigset_t caught_signals; /* Set of signals we handle */ 3683955d011SMarcel Moolenaar #if defined(SYSV) 3693955d011SMarcel Moolenaar #define KILLPG(pid, sig) kill(-(pid), (sig)) 3703955d011SMarcel Moolenaar #else 3713955d011SMarcel Moolenaar #define KILLPG(pid, sig) killpg((pid), (sig)) 3723955d011SMarcel Moolenaar #endif 3733955d011SMarcel Moolenaar 3743955d011SMarcel Moolenaar static void JobChildSig(int); 3753955d011SMarcel Moolenaar static void JobContinueSig(int); 3763955d011SMarcel Moolenaar static Job *JobFindPid(int, int, Boolean); 3773955d011SMarcel Moolenaar static int JobPrintCommand(void *, void *); 3783955d011SMarcel Moolenaar static int JobSaveCommand(void *, void *); 3793955d011SMarcel Moolenaar static void JobClose(Job *); 3803955d011SMarcel Moolenaar static void JobExec(Job *, char **); 3813955d011SMarcel Moolenaar static void JobMakeArgv(Job *, char **); 3823955d011SMarcel Moolenaar static int JobStart(GNode *, int); 3833955d011SMarcel Moolenaar static char *JobOutput(Job *, char *, char *, int); 3843955d011SMarcel Moolenaar static void JobDoOutput(Job *, Boolean); 3853955d011SMarcel Moolenaar static Shell *JobMatchShell(const char *); 3863955d011SMarcel Moolenaar static void JobInterrupt(int, int) MAKE_ATTR_DEAD; 3873955d011SMarcel Moolenaar static void JobRestartJobs(void); 3883955d011SMarcel Moolenaar static void JobTokenAdd(void); 3893955d011SMarcel Moolenaar static void JobSigLock(sigset_t *); 3903955d011SMarcel Moolenaar static void JobSigUnlock(sigset_t *); 3913955d011SMarcel Moolenaar static void JobSigReset(void); 3923955d011SMarcel Moolenaar 3933955d011SMarcel Moolenaar const char *malloc_options="A"; 3943955d011SMarcel Moolenaar 3953955d011SMarcel Moolenaar static void 3963955d011SMarcel Moolenaar job_table_dump(const char *where) 3973955d011SMarcel Moolenaar { 3983955d011SMarcel Moolenaar Job *job; 3993955d011SMarcel Moolenaar 4003955d011SMarcel Moolenaar fprintf(debug_file, "job table @ %s\n", where); 4013955d011SMarcel Moolenaar for (job = job_table; job < job_table_end; job++) { 4023955d011SMarcel Moolenaar fprintf(debug_file, "job %d, status %d, flags %d, pid %d\n", 4033955d011SMarcel Moolenaar (int)(job - job_table), job->job_state, job->flags, job->pid); 4043955d011SMarcel Moolenaar } 4053955d011SMarcel Moolenaar } 4063955d011SMarcel Moolenaar 4073955d011SMarcel Moolenaar /* 4083955d011SMarcel Moolenaar * JobSigLock/JobSigUnlock 4093955d011SMarcel Moolenaar * 4103955d011SMarcel Moolenaar * Signal lock routines to get exclusive access. Currently used to 4113955d011SMarcel Moolenaar * protect `jobs' and `stoppedJobs' list manipulations. 4123955d011SMarcel Moolenaar */ 4133955d011SMarcel Moolenaar static void JobSigLock(sigset_t *omaskp) 4143955d011SMarcel Moolenaar { 4153955d011SMarcel Moolenaar if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) { 4163955d011SMarcel Moolenaar Punt("JobSigLock: sigprocmask: %s", strerror(errno)); 4173955d011SMarcel Moolenaar sigemptyset(omaskp); 4183955d011SMarcel Moolenaar } 4193955d011SMarcel Moolenaar } 4203955d011SMarcel Moolenaar 4213955d011SMarcel Moolenaar static void JobSigUnlock(sigset_t *omaskp) 4223955d011SMarcel Moolenaar { 4233955d011SMarcel Moolenaar (void)sigprocmask(SIG_SETMASK, omaskp, NULL); 4243955d011SMarcel Moolenaar } 4253955d011SMarcel Moolenaar 4263955d011SMarcel Moolenaar static void 4273955d011SMarcel Moolenaar JobCreatePipe(Job *job, int minfd) 4283955d011SMarcel Moolenaar { 4293955d011SMarcel Moolenaar int i, fd; 4303955d011SMarcel Moolenaar 4313955d011SMarcel Moolenaar if (pipe(job->jobPipe) == -1) 4323955d011SMarcel Moolenaar Punt("Cannot create pipe: %s", strerror(errno)); 4333955d011SMarcel Moolenaar 43474d2e02bSSimon J. Gerraty for (i = 0; i < 2; i++) { 43574d2e02bSSimon J. Gerraty /* Avoid using low numbered fds */ 43674d2e02bSSimon J. Gerraty fd = fcntl(job->jobPipe[i], F_DUPFD, minfd); 43774d2e02bSSimon J. Gerraty if (fd != -1) { 43874d2e02bSSimon J. Gerraty close(job->jobPipe[i]); 43974d2e02bSSimon J. Gerraty job->jobPipe[i] = fd; 44074d2e02bSSimon J. Gerraty } 44174d2e02bSSimon J. Gerraty } 44274d2e02bSSimon J. Gerraty 4433955d011SMarcel Moolenaar /* Set close-on-exec flag for both */ 4443955d011SMarcel Moolenaar (void)fcntl(job->jobPipe[0], F_SETFD, 1); 4453955d011SMarcel Moolenaar (void)fcntl(job->jobPipe[1], F_SETFD, 1); 4463955d011SMarcel Moolenaar 4473955d011SMarcel Moolenaar /* 4483955d011SMarcel Moolenaar * We mark the input side of the pipe non-blocking; we poll(2) the 4493955d011SMarcel Moolenaar * pipe when we're waiting for a job token, but we might lose the 4503955d011SMarcel Moolenaar * race for the token when a new one becomes available, so the read 4513955d011SMarcel Moolenaar * from the pipe should not block. 4523955d011SMarcel Moolenaar */ 4533955d011SMarcel Moolenaar fcntl(job->jobPipe[0], F_SETFL, 4543955d011SMarcel Moolenaar fcntl(job->jobPipe[0], F_GETFL, 0) | O_NONBLOCK); 4553955d011SMarcel Moolenaar } 4563955d011SMarcel Moolenaar 4573955d011SMarcel Moolenaar /*- 4583955d011SMarcel Moolenaar *----------------------------------------------------------------------- 4593955d011SMarcel Moolenaar * JobCondPassSig -- 4603955d011SMarcel Moolenaar * Pass a signal to a job 4613955d011SMarcel Moolenaar * 4623955d011SMarcel Moolenaar * Input: 4633955d011SMarcel Moolenaar * signop Signal to send it 4643955d011SMarcel Moolenaar * 4653955d011SMarcel Moolenaar * Side Effects: 4663955d011SMarcel Moolenaar * None, except the job may bite it. 4673955d011SMarcel Moolenaar * 4683955d011SMarcel Moolenaar *----------------------------------------------------------------------- 4693955d011SMarcel Moolenaar */ 4703955d011SMarcel Moolenaar static void 4713955d011SMarcel Moolenaar JobCondPassSig(int signo) 4723955d011SMarcel Moolenaar { 4733955d011SMarcel Moolenaar Job *job; 4743955d011SMarcel Moolenaar 4753955d011SMarcel Moolenaar if (DEBUG(JOB)) { 4763955d011SMarcel Moolenaar (void)fprintf(debug_file, "JobCondPassSig(%d) called.\n", signo); 4773955d011SMarcel Moolenaar } 4783955d011SMarcel Moolenaar 4793955d011SMarcel Moolenaar for (job = job_table; job < job_table_end; job++) { 4803955d011SMarcel Moolenaar if (job->job_state != JOB_ST_RUNNING) 4813955d011SMarcel Moolenaar continue; 4823955d011SMarcel Moolenaar if (DEBUG(JOB)) { 4833955d011SMarcel Moolenaar (void)fprintf(debug_file, 4843955d011SMarcel Moolenaar "JobCondPassSig passing signal %d to child %d.\n", 4853955d011SMarcel Moolenaar signo, job->pid); 4863955d011SMarcel Moolenaar } 4873955d011SMarcel Moolenaar KILLPG(job->pid, signo); 4883955d011SMarcel Moolenaar } 4893955d011SMarcel Moolenaar } 4903955d011SMarcel Moolenaar 4913955d011SMarcel Moolenaar /*- 4923955d011SMarcel Moolenaar *----------------------------------------------------------------------- 4933955d011SMarcel Moolenaar * JobChldSig -- 4943955d011SMarcel Moolenaar * SIGCHLD handler. 4953955d011SMarcel Moolenaar * 4963955d011SMarcel Moolenaar * Input: 4973955d011SMarcel Moolenaar * signo The signal number we've received 4983955d011SMarcel Moolenaar * 4993955d011SMarcel Moolenaar * Results: 5003955d011SMarcel Moolenaar * None. 5013955d011SMarcel Moolenaar * 5023955d011SMarcel Moolenaar * Side Effects: 5033955d011SMarcel Moolenaar * Sends a token on the child exit pipe to wake us up from 5043955d011SMarcel Moolenaar * select()/poll(). 5053955d011SMarcel Moolenaar * 5063955d011SMarcel Moolenaar *----------------------------------------------------------------------- 5073955d011SMarcel Moolenaar */ 5083955d011SMarcel Moolenaar static void 5093955d011SMarcel Moolenaar JobChildSig(int signo MAKE_ATTR_UNUSED) 5103955d011SMarcel Moolenaar { 5113cbdda60SSimon J. Gerraty while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && errno == EAGAIN) 5123cbdda60SSimon J. Gerraty continue; 5133955d011SMarcel Moolenaar } 5143955d011SMarcel Moolenaar 5153955d011SMarcel Moolenaar 5163955d011SMarcel Moolenaar /*- 5173955d011SMarcel Moolenaar *----------------------------------------------------------------------- 5183955d011SMarcel Moolenaar * JobContinueSig -- 5193955d011SMarcel Moolenaar * Resume all stopped jobs. 5203955d011SMarcel Moolenaar * 5213955d011SMarcel Moolenaar * Input: 5223955d011SMarcel Moolenaar * signo The signal number we've received 5233955d011SMarcel Moolenaar * 5243955d011SMarcel Moolenaar * Results: 5253955d011SMarcel Moolenaar * None. 5263955d011SMarcel Moolenaar * 5273955d011SMarcel Moolenaar * Side Effects: 5283955d011SMarcel Moolenaar * Jobs start running again. 5293955d011SMarcel Moolenaar * 5303955d011SMarcel Moolenaar *----------------------------------------------------------------------- 5313955d011SMarcel Moolenaar */ 5323955d011SMarcel Moolenaar static void 5333955d011SMarcel Moolenaar JobContinueSig(int signo MAKE_ATTR_UNUSED) 5343955d011SMarcel Moolenaar { 5353955d011SMarcel Moolenaar /* 5363955d011SMarcel Moolenaar * Defer sending to SIGCONT to our stopped children until we return 5373955d011SMarcel Moolenaar * from the signal handler. 5383955d011SMarcel Moolenaar */ 5393cbdda60SSimon J. Gerraty while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 && 5403cbdda60SSimon J. Gerraty errno == EAGAIN) 5413cbdda60SSimon J. Gerraty continue; 5423955d011SMarcel Moolenaar } 5433955d011SMarcel Moolenaar 5443955d011SMarcel Moolenaar /*- 5453955d011SMarcel Moolenaar *----------------------------------------------------------------------- 5463955d011SMarcel Moolenaar * JobPassSig -- 5473955d011SMarcel Moolenaar * Pass a signal on to all jobs, then resend to ourselves. 5483955d011SMarcel Moolenaar * 5493955d011SMarcel Moolenaar * Input: 5503955d011SMarcel Moolenaar * signo The signal number we've received 5513955d011SMarcel Moolenaar * 5523955d011SMarcel Moolenaar * Results: 5533955d011SMarcel Moolenaar * None. 5543955d011SMarcel Moolenaar * 5553955d011SMarcel Moolenaar * Side Effects: 5563955d011SMarcel Moolenaar * We die by the same signal. 5573955d011SMarcel Moolenaar * 5583955d011SMarcel Moolenaar *----------------------------------------------------------------------- 5593955d011SMarcel Moolenaar */ 5603955d011SMarcel Moolenaar MAKE_ATTR_DEAD static void 5613955d011SMarcel Moolenaar JobPassSig_int(int signo) 5623955d011SMarcel Moolenaar { 5633955d011SMarcel Moolenaar /* Run .INTERRUPT target then exit */ 5643955d011SMarcel Moolenaar JobInterrupt(TRUE, signo); 5653955d011SMarcel Moolenaar } 5663955d011SMarcel Moolenaar 5673955d011SMarcel Moolenaar MAKE_ATTR_DEAD static void 5683955d011SMarcel Moolenaar JobPassSig_term(int signo) 5693955d011SMarcel Moolenaar { 5703955d011SMarcel Moolenaar /* Dont run .INTERRUPT target then exit */ 5713955d011SMarcel Moolenaar JobInterrupt(FALSE, signo); 5723955d011SMarcel Moolenaar } 5733955d011SMarcel Moolenaar 5743955d011SMarcel Moolenaar static void 5753955d011SMarcel Moolenaar JobPassSig_suspend(int signo) 5763955d011SMarcel Moolenaar { 5773955d011SMarcel Moolenaar sigset_t nmask, omask; 5783955d011SMarcel Moolenaar struct sigaction act; 5793955d011SMarcel Moolenaar 5803955d011SMarcel Moolenaar /* Suppress job started/continued messages */ 5813955d011SMarcel Moolenaar make_suspended = 1; 5823955d011SMarcel Moolenaar 5833955d011SMarcel Moolenaar /* Pass the signal onto every job */ 5843955d011SMarcel Moolenaar JobCondPassSig(signo); 5853955d011SMarcel Moolenaar 5863955d011SMarcel Moolenaar /* 5873955d011SMarcel Moolenaar * Send ourselves the signal now we've given the message to everyone else. 5883955d011SMarcel Moolenaar * Note we block everything else possible while we're getting the signal. 5893955d011SMarcel Moolenaar * This ensures that all our jobs get continued when we wake up before 5903955d011SMarcel Moolenaar * we take any other signal. 5913955d011SMarcel Moolenaar */ 5923955d011SMarcel Moolenaar sigfillset(&nmask); 5933955d011SMarcel Moolenaar sigdelset(&nmask, signo); 5943955d011SMarcel Moolenaar (void)sigprocmask(SIG_SETMASK, &nmask, &omask); 5953955d011SMarcel Moolenaar 5963955d011SMarcel Moolenaar act.sa_handler = SIG_DFL; 5973955d011SMarcel Moolenaar sigemptyset(&act.sa_mask); 5983955d011SMarcel Moolenaar act.sa_flags = 0; 5993955d011SMarcel Moolenaar (void)sigaction(signo, &act, NULL); 6003955d011SMarcel Moolenaar 6013955d011SMarcel Moolenaar if (DEBUG(JOB)) { 6023955d011SMarcel Moolenaar (void)fprintf(debug_file, 6033955d011SMarcel Moolenaar "JobPassSig passing signal %d to self.\n", signo); 6043955d011SMarcel Moolenaar } 6053955d011SMarcel Moolenaar 6063955d011SMarcel Moolenaar (void)kill(getpid(), signo); 6073955d011SMarcel Moolenaar 6083955d011SMarcel Moolenaar /* 6093955d011SMarcel Moolenaar * We've been continued. 6103955d011SMarcel Moolenaar * 6113955d011SMarcel Moolenaar * A whole host of signals continue to happen! 6123955d011SMarcel Moolenaar * SIGCHLD for any processes that actually suspended themselves. 6133955d011SMarcel Moolenaar * SIGCHLD for any processes that exited while we were alseep. 6143955d011SMarcel Moolenaar * The SIGCONT that actually caused us to wakeup. 6153955d011SMarcel Moolenaar * 6163955d011SMarcel Moolenaar * Since we defer passing the SIGCONT on to our children until 6173955d011SMarcel Moolenaar * the main processing loop, we can be sure that all the SIGCHLD 6183955d011SMarcel Moolenaar * events will have happened by then - and that the waitpid() will 6193955d011SMarcel Moolenaar * collect the child 'suspended' events. 6203955d011SMarcel Moolenaar * For correct sequencing we just need to ensure we process the 6213955d011SMarcel Moolenaar * waitpid() before passign on the SIGCONT. 6223955d011SMarcel Moolenaar * 6233955d011SMarcel Moolenaar * In any case nothing else is needed here. 6243955d011SMarcel Moolenaar */ 6253955d011SMarcel Moolenaar 6263955d011SMarcel Moolenaar /* Restore handler and signal mask */ 6273955d011SMarcel Moolenaar act.sa_handler = JobPassSig_suspend; 6283955d011SMarcel Moolenaar (void)sigaction(signo, &act, NULL); 6293955d011SMarcel Moolenaar (void)sigprocmask(SIG_SETMASK, &omask, NULL); 6303955d011SMarcel Moolenaar } 6313955d011SMarcel Moolenaar 6323955d011SMarcel Moolenaar /*- 6333955d011SMarcel Moolenaar *----------------------------------------------------------------------- 6343955d011SMarcel Moolenaar * JobFindPid -- 6353955d011SMarcel Moolenaar * Compare the pid of the job with the given pid and return 0 if they 6363955d011SMarcel Moolenaar * are equal. This function is called from Job_CatchChildren 6373955d011SMarcel Moolenaar * to find the job descriptor of the finished job. 6383955d011SMarcel Moolenaar * 6393955d011SMarcel Moolenaar * Input: 6403955d011SMarcel Moolenaar * job job to examine 6413955d011SMarcel Moolenaar * pid process id desired 6423955d011SMarcel Moolenaar * 6433955d011SMarcel Moolenaar * Results: 6443955d011SMarcel Moolenaar * Job with matching pid 6453955d011SMarcel Moolenaar * 6463955d011SMarcel Moolenaar * Side Effects: 6473955d011SMarcel Moolenaar * None 6483955d011SMarcel Moolenaar *----------------------------------------------------------------------- 6493955d011SMarcel Moolenaar */ 6503955d011SMarcel Moolenaar static Job * 6513955d011SMarcel Moolenaar JobFindPid(int pid, int status, Boolean isJobs) 6523955d011SMarcel Moolenaar { 6533955d011SMarcel Moolenaar Job *job; 6543955d011SMarcel Moolenaar 6553955d011SMarcel Moolenaar for (job = job_table; job < job_table_end; job++) { 6563955d011SMarcel Moolenaar if ((job->job_state == status) && job->pid == pid) 6573955d011SMarcel Moolenaar return job; 6583955d011SMarcel Moolenaar } 6593955d011SMarcel Moolenaar if (DEBUG(JOB) && isJobs) 6603955d011SMarcel Moolenaar job_table_dump("no pid"); 6613955d011SMarcel Moolenaar return NULL; 6623955d011SMarcel Moolenaar } 6633955d011SMarcel Moolenaar 6643955d011SMarcel Moolenaar /*- 6653955d011SMarcel Moolenaar *----------------------------------------------------------------------- 6663955d011SMarcel Moolenaar * JobPrintCommand -- 6673955d011SMarcel Moolenaar * Put out another command for the given job. If the command starts 6683955d011SMarcel Moolenaar * with an @ or a - we process it specially. In the former case, 6693955d011SMarcel Moolenaar * so long as the -s and -n flags weren't given to make, we stick 6703955d011SMarcel Moolenaar * a shell-specific echoOff command in the script. In the latter, 6713955d011SMarcel Moolenaar * we ignore errors for the entire job, unless the shell has error 6723955d011SMarcel Moolenaar * control. 6733955d011SMarcel Moolenaar * If the command is just "..." we take all future commands for this 6743955d011SMarcel Moolenaar * job to be commands to be executed once the entire graph has been 6753955d011SMarcel Moolenaar * made and return non-zero to signal that the end of the commands 6763955d011SMarcel Moolenaar * was reached. These commands are later attached to the postCommands 6773955d011SMarcel Moolenaar * node and executed by Job_End when all things are done. 6783955d011SMarcel Moolenaar * This function is called from JobStart via Lst_ForEach. 6793955d011SMarcel Moolenaar * 6803955d011SMarcel Moolenaar * Input: 6813955d011SMarcel Moolenaar * cmdp command string to print 6823955d011SMarcel Moolenaar * jobp job for which to print it 6833955d011SMarcel Moolenaar * 6843955d011SMarcel Moolenaar * Results: 6853955d011SMarcel Moolenaar * Always 0, unless the command was "..." 6863955d011SMarcel Moolenaar * 6873955d011SMarcel Moolenaar * Side Effects: 6883955d011SMarcel Moolenaar * If the command begins with a '-' and the shell has no error control, 6893955d011SMarcel Moolenaar * the JOB_IGNERR flag is set in the job descriptor. 6903955d011SMarcel Moolenaar * If the command is "..." and we're not ignoring such things, 6913955d011SMarcel Moolenaar * tailCmds is set to the successor node of the cmd. 6923955d011SMarcel Moolenaar * numCommands is incremented if the command is actually printed. 6933955d011SMarcel Moolenaar *----------------------------------------------------------------------- 6943955d011SMarcel Moolenaar */ 6953955d011SMarcel Moolenaar static int 6963955d011SMarcel Moolenaar JobPrintCommand(void *cmdp, void *jobp) 6973955d011SMarcel Moolenaar { 6983955d011SMarcel Moolenaar Boolean noSpecials; /* true if we shouldn't worry about 6993955d011SMarcel Moolenaar * inserting special commands into 7003955d011SMarcel Moolenaar * the input stream. */ 7013955d011SMarcel Moolenaar Boolean shutUp = FALSE; /* true if we put a no echo command 7023955d011SMarcel Moolenaar * into the command file */ 7033955d011SMarcel Moolenaar Boolean errOff = FALSE; /* true if we turned error checking 7043955d011SMarcel Moolenaar * off before printing the command 7053955d011SMarcel Moolenaar * and need to turn it back on */ 7063955d011SMarcel Moolenaar const char *cmdTemplate; /* Template to use when printing the 7073955d011SMarcel Moolenaar * command */ 7083955d011SMarcel Moolenaar char *cmdStart; /* Start of expanded command */ 7093955d011SMarcel Moolenaar char *escCmd = NULL; /* Command with quotes/backticks escaped */ 7103955d011SMarcel Moolenaar char *cmd = (char *)cmdp; 7113955d011SMarcel Moolenaar Job *job = (Job *)jobp; 7123955d011SMarcel Moolenaar int i, j; 7133955d011SMarcel Moolenaar 7143955d011SMarcel Moolenaar noSpecials = NoExecute(job->node); 7153955d011SMarcel Moolenaar 7163955d011SMarcel Moolenaar if (strcmp(cmd, "...") == 0) { 7173955d011SMarcel Moolenaar job->node->type |= OP_SAVE_CMDS; 7183955d011SMarcel Moolenaar if ((job->flags & JOB_IGNDOTS) == 0) { 7193955d011SMarcel Moolenaar job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, 7203955d011SMarcel Moolenaar cmd)); 7213955d011SMarcel Moolenaar return 1; 7223955d011SMarcel Moolenaar } 7233955d011SMarcel Moolenaar return 0; 7243955d011SMarcel Moolenaar } 7253955d011SMarcel Moolenaar 7263955d011SMarcel Moolenaar #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ 7273955d011SMarcel Moolenaar (void)fprintf(debug_file, fmt, arg); \ 7283955d011SMarcel Moolenaar } \ 7293955d011SMarcel Moolenaar (void)fprintf(job->cmdFILE, fmt, arg); \ 7303955d011SMarcel Moolenaar (void)fflush(job->cmdFILE); 7313955d011SMarcel Moolenaar 7323955d011SMarcel Moolenaar numCommands += 1; 7333955d011SMarcel Moolenaar 7343955d011SMarcel Moolenaar cmdStart = cmd = Var_Subst(NULL, cmd, job->node, FALSE); 7353955d011SMarcel Moolenaar 7363955d011SMarcel Moolenaar cmdTemplate = "%s\n"; 7373955d011SMarcel Moolenaar 7383955d011SMarcel Moolenaar /* 7393955d011SMarcel Moolenaar * Check for leading @' and -'s to control echoing and error checking. 7403955d011SMarcel Moolenaar */ 7413955d011SMarcel Moolenaar while (*cmd == '@' || *cmd == '-' || (*cmd == '+')) { 7423955d011SMarcel Moolenaar switch (*cmd) { 7433955d011SMarcel Moolenaar case '@': 7443955d011SMarcel Moolenaar shutUp = DEBUG(LOUD) ? FALSE : TRUE; 7453955d011SMarcel Moolenaar break; 7463955d011SMarcel Moolenaar case '-': 7473955d011SMarcel Moolenaar errOff = TRUE; 7483955d011SMarcel Moolenaar break; 7493955d011SMarcel Moolenaar case '+': 7503955d011SMarcel Moolenaar if (noSpecials) { 7513955d011SMarcel Moolenaar /* 7523955d011SMarcel Moolenaar * We're not actually executing anything... 7533955d011SMarcel Moolenaar * but this one needs to be - use compat mode just for it. 7543955d011SMarcel Moolenaar */ 7553955d011SMarcel Moolenaar CompatRunCommand(cmdp, job->node); 7563955d011SMarcel Moolenaar return 0; 7573955d011SMarcel Moolenaar } 7583955d011SMarcel Moolenaar break; 7593955d011SMarcel Moolenaar } 7603955d011SMarcel Moolenaar cmd++; 7613955d011SMarcel Moolenaar } 7623955d011SMarcel Moolenaar 7633955d011SMarcel Moolenaar while (isspace((unsigned char) *cmd)) 7643955d011SMarcel Moolenaar cmd++; 7653955d011SMarcel Moolenaar 7663955d011SMarcel Moolenaar /* 7673955d011SMarcel Moolenaar * If the shell doesn't have error control the alternate echo'ing will 7683955d011SMarcel Moolenaar * be done (to avoid showing additional error checking code) 7693955d011SMarcel Moolenaar * and this will need the characters '$ ` \ "' escaped 7703955d011SMarcel Moolenaar */ 7713955d011SMarcel Moolenaar 7723955d011SMarcel Moolenaar if (!commandShell->hasErrCtl) { 7733955d011SMarcel Moolenaar /* Worst that could happen is every char needs escaping. */ 7743955d011SMarcel Moolenaar escCmd = bmake_malloc((strlen(cmd) * 2) + 1); 7753955d011SMarcel Moolenaar for (i = 0, j= 0; cmd[i] != '\0'; i++, j++) { 7763955d011SMarcel Moolenaar if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || 7773955d011SMarcel Moolenaar cmd[i] == '"') 7783955d011SMarcel Moolenaar escCmd[j++] = '\\'; 7793955d011SMarcel Moolenaar escCmd[j] = cmd[i]; 7803955d011SMarcel Moolenaar } 7813955d011SMarcel Moolenaar escCmd[j] = 0; 7823955d011SMarcel Moolenaar } 7833955d011SMarcel Moolenaar 7843955d011SMarcel Moolenaar if (shutUp) { 7853955d011SMarcel Moolenaar if (!(job->flags & JOB_SILENT) && !noSpecials && 7863955d011SMarcel Moolenaar commandShell->hasEchoCtl) { 7873955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->echoOff); 7883955d011SMarcel Moolenaar } else { 7893955d011SMarcel Moolenaar if (commandShell->hasErrCtl) 7903955d011SMarcel Moolenaar shutUp = FALSE; 7913955d011SMarcel Moolenaar } 7923955d011SMarcel Moolenaar } 7933955d011SMarcel Moolenaar 7943955d011SMarcel Moolenaar if (errOff) { 7953955d011SMarcel Moolenaar if (!noSpecials) { 7963955d011SMarcel Moolenaar if (commandShell->hasErrCtl) { 7973955d011SMarcel Moolenaar /* 7983955d011SMarcel Moolenaar * we don't want the error-control commands showing 7993955d011SMarcel Moolenaar * up either, so we turn off echoing while executing 8003955d011SMarcel Moolenaar * them. We could put another field in the shell 8013955d011SMarcel Moolenaar * structure to tell JobDoOutput to look for this 8023955d011SMarcel Moolenaar * string too, but why make it any more complex than 8033955d011SMarcel Moolenaar * it already is? 8043955d011SMarcel Moolenaar */ 8053955d011SMarcel Moolenaar if (!(job->flags & JOB_SILENT) && !shutUp && 8063955d011SMarcel Moolenaar commandShell->hasEchoCtl) { 8073955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->echoOff); 8083955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->ignErr); 8093955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->echoOn); 8103955d011SMarcel Moolenaar } else { 8113955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->ignErr); 8123955d011SMarcel Moolenaar } 8133955d011SMarcel Moolenaar } else if (commandShell->ignErr && 8143955d011SMarcel Moolenaar (*commandShell->ignErr != '\0')) 8153955d011SMarcel Moolenaar { 8163955d011SMarcel Moolenaar /* 8173955d011SMarcel Moolenaar * The shell has no error control, so we need to be 8183955d011SMarcel Moolenaar * weird to get it to ignore any errors from the command. 8193955d011SMarcel Moolenaar * If echoing is turned on, we turn it off and use the 8203955d011SMarcel Moolenaar * errCheck template to echo the command. Leave echoing 8213955d011SMarcel Moolenaar * off so the user doesn't see the weirdness we go through 8223955d011SMarcel Moolenaar * to ignore errors. Set cmdTemplate to use the weirdness 8233955d011SMarcel Moolenaar * instead of the simple "%s\n" template. 8243955d011SMarcel Moolenaar */ 825*db29cad8SSimon J. Gerraty job->flags |= JOB_IGNERR; 8263955d011SMarcel Moolenaar if (!(job->flags & JOB_SILENT) && !shutUp) { 8273955d011SMarcel Moolenaar if (commandShell->hasEchoCtl) { 8283955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->echoOff); 8293955d011SMarcel Moolenaar } 8303955d011SMarcel Moolenaar DBPRINTF(commandShell->errCheck, escCmd); 8313955d011SMarcel Moolenaar shutUp = TRUE; 8323955d011SMarcel Moolenaar } else { 8333955d011SMarcel Moolenaar if (!shutUp) { 8343955d011SMarcel Moolenaar DBPRINTF(commandShell->errCheck, escCmd); 8353955d011SMarcel Moolenaar } 8363955d011SMarcel Moolenaar } 8373955d011SMarcel Moolenaar cmdTemplate = commandShell->ignErr; 8383955d011SMarcel Moolenaar /* 8393955d011SMarcel Moolenaar * The error ignoration (hee hee) is already taken care 8403955d011SMarcel Moolenaar * of by the ignErr template, so pretend error checking 8413955d011SMarcel Moolenaar * is still on. 8423955d011SMarcel Moolenaar */ 8433955d011SMarcel Moolenaar errOff = FALSE; 8443955d011SMarcel Moolenaar } else { 8453955d011SMarcel Moolenaar errOff = FALSE; 8463955d011SMarcel Moolenaar } 8473955d011SMarcel Moolenaar } else { 8483955d011SMarcel Moolenaar errOff = FALSE; 8493955d011SMarcel Moolenaar } 8503955d011SMarcel Moolenaar } else { 8513955d011SMarcel Moolenaar 8523955d011SMarcel Moolenaar /* 8533955d011SMarcel Moolenaar * If errors are being checked and the shell doesn't have error control 8543955d011SMarcel Moolenaar * but does supply an errOut template, then setup commands to run 8553955d011SMarcel Moolenaar * through it. 8563955d011SMarcel Moolenaar */ 8573955d011SMarcel Moolenaar 8583955d011SMarcel Moolenaar if (!commandShell->hasErrCtl && commandShell->errOut && 8593955d011SMarcel Moolenaar (*commandShell->errOut != '\0')) { 8603955d011SMarcel Moolenaar if (!(job->flags & JOB_SILENT) && !shutUp) { 8613955d011SMarcel Moolenaar if (commandShell->hasEchoCtl) { 8623955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->echoOff); 8633955d011SMarcel Moolenaar } 8643955d011SMarcel Moolenaar DBPRINTF(commandShell->errCheck, escCmd); 8653955d011SMarcel Moolenaar shutUp = TRUE; 8663955d011SMarcel Moolenaar } 8673955d011SMarcel Moolenaar /* If it's a comment line or blank, treat as an ignored error */ 8683955d011SMarcel Moolenaar if ((escCmd[0] == commandShell->commentChar) || 8693955d011SMarcel Moolenaar (escCmd[0] == 0)) 8703955d011SMarcel Moolenaar cmdTemplate = commandShell->ignErr; 8713955d011SMarcel Moolenaar else 8723955d011SMarcel Moolenaar cmdTemplate = commandShell->errOut; 8733955d011SMarcel Moolenaar errOff = FALSE; 8743955d011SMarcel Moolenaar } 8753955d011SMarcel Moolenaar } 8763955d011SMarcel Moolenaar 8773955d011SMarcel Moolenaar if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0 && 8783955d011SMarcel Moolenaar (job->flags & JOB_TRACED) == 0) { 8793955d011SMarcel Moolenaar DBPRINTF("set -%s\n", "x"); 8803955d011SMarcel Moolenaar job->flags |= JOB_TRACED; 8813955d011SMarcel Moolenaar } 8823955d011SMarcel Moolenaar 8833955d011SMarcel Moolenaar DBPRINTF(cmdTemplate, cmd); 8843955d011SMarcel Moolenaar free(cmdStart); 8853955d011SMarcel Moolenaar if (escCmd) 8863955d011SMarcel Moolenaar free(escCmd); 8873955d011SMarcel Moolenaar if (errOff) { 8883955d011SMarcel Moolenaar /* 8893955d011SMarcel Moolenaar * If echoing is already off, there's no point in issuing the 8903955d011SMarcel Moolenaar * echoOff command. Otherwise we issue it and pretend it was on 8913955d011SMarcel Moolenaar * for the whole command... 8923955d011SMarcel Moolenaar */ 8933955d011SMarcel Moolenaar if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ 8943955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->echoOff); 8953955d011SMarcel Moolenaar shutUp = TRUE; 8963955d011SMarcel Moolenaar } 8973955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->errCheck); 8983955d011SMarcel Moolenaar } 8993955d011SMarcel Moolenaar if (shutUp && commandShell->hasEchoCtl) { 9003955d011SMarcel Moolenaar DBPRINTF("%s\n", commandShell->echoOn); 9013955d011SMarcel Moolenaar } 9023955d011SMarcel Moolenaar return 0; 9033955d011SMarcel Moolenaar } 9043955d011SMarcel Moolenaar 9053955d011SMarcel Moolenaar /*- 9063955d011SMarcel Moolenaar *----------------------------------------------------------------------- 9073955d011SMarcel Moolenaar * JobSaveCommand -- 9083955d011SMarcel Moolenaar * Save a command to be executed when everything else is done. 9093955d011SMarcel Moolenaar * Callback function for JobFinish... 9103955d011SMarcel Moolenaar * 9113955d011SMarcel Moolenaar * Results: 9123955d011SMarcel Moolenaar * Always returns 0 9133955d011SMarcel Moolenaar * 9143955d011SMarcel Moolenaar * Side Effects: 9153955d011SMarcel Moolenaar * The command is tacked onto the end of postCommands's commands list. 9163955d011SMarcel Moolenaar * 9173955d011SMarcel Moolenaar *----------------------------------------------------------------------- 9183955d011SMarcel Moolenaar */ 9193955d011SMarcel Moolenaar static int 9203955d011SMarcel Moolenaar JobSaveCommand(void *cmd, void *gn) 9213955d011SMarcel Moolenaar { 9223955d011SMarcel Moolenaar cmd = Var_Subst(NULL, (char *)cmd, (GNode *)gn, FALSE); 9233955d011SMarcel Moolenaar (void)Lst_AtEnd(postCommands->commands, cmd); 9243955d011SMarcel Moolenaar return(0); 9253955d011SMarcel Moolenaar } 9263955d011SMarcel Moolenaar 9273955d011SMarcel Moolenaar 9283955d011SMarcel Moolenaar /*- 9293955d011SMarcel Moolenaar *----------------------------------------------------------------------- 9303955d011SMarcel Moolenaar * JobClose -- 9313955d011SMarcel Moolenaar * Called to close both input and output pipes when a job is finished. 9323955d011SMarcel Moolenaar * 9333955d011SMarcel Moolenaar * Results: 9343955d011SMarcel Moolenaar * Nada 9353955d011SMarcel Moolenaar * 9363955d011SMarcel Moolenaar * Side Effects: 9373955d011SMarcel Moolenaar * The file descriptors associated with the job are closed. 9383955d011SMarcel Moolenaar * 9393955d011SMarcel Moolenaar *----------------------------------------------------------------------- 9403955d011SMarcel Moolenaar */ 9413955d011SMarcel Moolenaar static void 9423955d011SMarcel Moolenaar JobClose(Job *job) 9433955d011SMarcel Moolenaar { 9443955d011SMarcel Moolenaar clearfd(job); 9453955d011SMarcel Moolenaar (void)close(job->outPipe); 9463955d011SMarcel Moolenaar job->outPipe = -1; 9473955d011SMarcel Moolenaar 9483955d011SMarcel Moolenaar JobDoOutput(job, TRUE); 9493955d011SMarcel Moolenaar (void)close(job->inPipe); 9503955d011SMarcel Moolenaar job->inPipe = -1; 9513955d011SMarcel Moolenaar } 9523955d011SMarcel Moolenaar 9533955d011SMarcel Moolenaar /*- 9543955d011SMarcel Moolenaar *----------------------------------------------------------------------- 9553955d011SMarcel Moolenaar * JobFinish -- 9563955d011SMarcel Moolenaar * Do final processing for the given job including updating 9573955d011SMarcel Moolenaar * parents and starting new jobs as available/necessary. Note 9583955d011SMarcel Moolenaar * that we pay no attention to the JOB_IGNERR flag here. 9593955d011SMarcel Moolenaar * This is because when we're called because of a noexecute flag 9603955d011SMarcel Moolenaar * or something, jstat.w_status is 0 and when called from 9613955d011SMarcel Moolenaar * Job_CatchChildren, the status is zeroed if it s/b ignored. 9623955d011SMarcel Moolenaar * 9633955d011SMarcel Moolenaar * Input: 9643955d011SMarcel Moolenaar * job job to finish 9653955d011SMarcel Moolenaar * status sub-why job went away 9663955d011SMarcel Moolenaar * 9673955d011SMarcel Moolenaar * Results: 9683955d011SMarcel Moolenaar * None 9693955d011SMarcel Moolenaar * 9703955d011SMarcel Moolenaar * Side Effects: 9713955d011SMarcel Moolenaar * Final commands for the job are placed on postCommands. 9723955d011SMarcel Moolenaar * 9733955d011SMarcel Moolenaar * If we got an error and are aborting (aborting == ABORT_ERROR) and 9743955d011SMarcel Moolenaar * the job list is now empty, we are done for the day. 9753955d011SMarcel Moolenaar * If we recognized an error (errors !=0), we set the aborting flag 9763955d011SMarcel Moolenaar * to ABORT_ERROR so no more jobs will be started. 9773955d011SMarcel Moolenaar *----------------------------------------------------------------------- 9783955d011SMarcel Moolenaar */ 9793955d011SMarcel Moolenaar /*ARGSUSED*/ 9803955d011SMarcel Moolenaar static void 9813955d011SMarcel Moolenaar JobFinish (Job *job, WAIT_T status) 9823955d011SMarcel Moolenaar { 9833955d011SMarcel Moolenaar Boolean done, return_job_token; 9843955d011SMarcel Moolenaar 9853955d011SMarcel Moolenaar if (DEBUG(JOB)) { 9863955d011SMarcel Moolenaar fprintf(debug_file, "Jobfinish: %d [%s], status %d\n", 9873955d011SMarcel Moolenaar job->pid, job->node->name, status); 9883955d011SMarcel Moolenaar } 9893955d011SMarcel Moolenaar 9903955d011SMarcel Moolenaar if ((WIFEXITED(status) && 9913955d011SMarcel Moolenaar (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) || 9923955d011SMarcel Moolenaar WIFSIGNALED(status)) 9933955d011SMarcel Moolenaar { 9943955d011SMarcel Moolenaar /* 9953955d011SMarcel Moolenaar * If it exited non-zero and either we're doing things our 9963955d011SMarcel Moolenaar * way or we're not ignoring errors, the job is finished. 9973955d011SMarcel Moolenaar * Similarly, if the shell died because of a signal 9983955d011SMarcel Moolenaar * the job is also finished. In these 9993955d011SMarcel Moolenaar * cases, finish out the job's output before printing the exit 10003955d011SMarcel Moolenaar * status... 10013955d011SMarcel Moolenaar */ 10023955d011SMarcel Moolenaar JobClose(job); 10033955d011SMarcel Moolenaar if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 10043955d011SMarcel Moolenaar (void)fclose(job->cmdFILE); 10053955d011SMarcel Moolenaar job->cmdFILE = NULL; 10063955d011SMarcel Moolenaar } 10073955d011SMarcel Moolenaar done = TRUE; 10083955d011SMarcel Moolenaar } else if (WIFEXITED(status)) { 10093955d011SMarcel Moolenaar /* 10103955d011SMarcel Moolenaar * Deal with ignored errors in -B mode. We need to print a message 10113955d011SMarcel Moolenaar * telling of the ignored error as well as setting status.w_status 10123955d011SMarcel Moolenaar * to 0 so the next command gets run. To do this, we set done to be 10133955d011SMarcel Moolenaar * TRUE if in -B mode and the job exited non-zero. 10143955d011SMarcel Moolenaar */ 10153955d011SMarcel Moolenaar done = WEXITSTATUS(status) != 0; 10163955d011SMarcel Moolenaar /* 10173955d011SMarcel Moolenaar * Old comment said: "Note we don't 10183955d011SMarcel Moolenaar * want to close down any of the streams until we know we're at the 10193955d011SMarcel Moolenaar * end." 10203955d011SMarcel Moolenaar * But we do. Otherwise when are we going to print the rest of the 10213955d011SMarcel Moolenaar * stuff? 10223955d011SMarcel Moolenaar */ 10233955d011SMarcel Moolenaar JobClose(job); 10243955d011SMarcel Moolenaar } else { 10253955d011SMarcel Moolenaar /* 10263955d011SMarcel Moolenaar * No need to close things down or anything. 10273955d011SMarcel Moolenaar */ 10283955d011SMarcel Moolenaar done = FALSE; 10293955d011SMarcel Moolenaar } 10303955d011SMarcel Moolenaar 10313955d011SMarcel Moolenaar if (done) { 10323955d011SMarcel Moolenaar if (WIFEXITED(status)) { 10333955d011SMarcel Moolenaar if (DEBUG(JOB)) { 10343955d011SMarcel Moolenaar (void)fprintf(debug_file, "Process %d [%s] exited.\n", 10353955d011SMarcel Moolenaar job->pid, job->node->name); 10363955d011SMarcel Moolenaar } 10373955d011SMarcel Moolenaar if (WEXITSTATUS(status) != 0) { 10383955d011SMarcel Moolenaar if (job->node != lastNode) { 10393955d011SMarcel Moolenaar MESSAGE(stdout, job->node); 10403955d011SMarcel Moolenaar lastNode = job->node; 10413955d011SMarcel Moolenaar } 10423955d011SMarcel Moolenaar #ifdef USE_META 10433955d011SMarcel Moolenaar if (useMeta) { 10443955d011SMarcel Moolenaar meta_job_error(job, job->node, job->flags, WEXITSTATUS(status)); 10453955d011SMarcel Moolenaar } 10463955d011SMarcel Moolenaar #endif 10473955d011SMarcel Moolenaar (void)printf("*** [%s] Error code %d%s\n", 10483955d011SMarcel Moolenaar job->node->name, 10493955d011SMarcel Moolenaar WEXITSTATUS(status), 10503955d011SMarcel Moolenaar (job->flags & JOB_IGNERR) ? " (ignored)" : ""); 10513955d011SMarcel Moolenaar if (job->flags & JOB_IGNERR) { 10523955d011SMarcel Moolenaar WAIT_STATUS(status) = 0; 10533955d011SMarcel Moolenaar } else { 10543955d011SMarcel Moolenaar PrintOnError(job->node, NULL); 10553955d011SMarcel Moolenaar } 10563955d011SMarcel Moolenaar } else if (DEBUG(JOB)) { 10573955d011SMarcel Moolenaar if (job->node != lastNode) { 10583955d011SMarcel Moolenaar MESSAGE(stdout, job->node); 10593955d011SMarcel Moolenaar lastNode = job->node; 10603955d011SMarcel Moolenaar } 10613955d011SMarcel Moolenaar (void)printf("*** [%s] Completed successfully\n", 10623955d011SMarcel Moolenaar job->node->name); 10633955d011SMarcel Moolenaar } 10643955d011SMarcel Moolenaar } else { 10653955d011SMarcel Moolenaar if (job->node != lastNode) { 10663955d011SMarcel Moolenaar MESSAGE(stdout, job->node); 10673955d011SMarcel Moolenaar lastNode = job->node; 10683955d011SMarcel Moolenaar } 10693955d011SMarcel Moolenaar (void)printf("*** [%s] Signal %d\n", 10703955d011SMarcel Moolenaar job->node->name, WTERMSIG(status)); 10713955d011SMarcel Moolenaar } 10723955d011SMarcel Moolenaar (void)fflush(stdout); 10733955d011SMarcel Moolenaar } 10743955d011SMarcel Moolenaar 10753955d011SMarcel Moolenaar #ifdef USE_META 10763955d011SMarcel Moolenaar if (useMeta) { 10773955d011SMarcel Moolenaar meta_job_finish(job); 10783955d011SMarcel Moolenaar } 10793955d011SMarcel Moolenaar #endif 10803955d011SMarcel Moolenaar 10813955d011SMarcel Moolenaar return_job_token = FALSE; 10823955d011SMarcel Moolenaar 10833955d011SMarcel Moolenaar Trace_Log(JOBEND, job); 10843955d011SMarcel Moolenaar if (!(job->flags & JOB_SPECIAL)) { 10853955d011SMarcel Moolenaar if ((WAIT_STATUS(status) != 0) || 10863955d011SMarcel Moolenaar (aborting == ABORT_ERROR) || 10873955d011SMarcel Moolenaar (aborting == ABORT_INTERRUPT)) 10883955d011SMarcel Moolenaar return_job_token = TRUE; 10893955d011SMarcel Moolenaar } 10903955d011SMarcel Moolenaar 10913955d011SMarcel Moolenaar if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && 10923955d011SMarcel Moolenaar (WAIT_STATUS(status) == 0)) { 10933955d011SMarcel Moolenaar /* 10943955d011SMarcel Moolenaar * As long as we aren't aborting and the job didn't return a non-zero 10953955d011SMarcel Moolenaar * status that we shouldn't ignore, we call Make_Update to update 10963955d011SMarcel Moolenaar * the parents. In addition, any saved commands for the node are placed 10973955d011SMarcel Moolenaar * on the .END target. 10983955d011SMarcel Moolenaar */ 10993955d011SMarcel Moolenaar if (job->tailCmds != NULL) { 11003955d011SMarcel Moolenaar Lst_ForEachFrom(job->node->commands, job->tailCmds, 11013955d011SMarcel Moolenaar JobSaveCommand, 11023955d011SMarcel Moolenaar job->node); 11033955d011SMarcel Moolenaar } 11043955d011SMarcel Moolenaar job->node->made = MADE; 11053955d011SMarcel Moolenaar if (!(job->flags & JOB_SPECIAL)) 11063955d011SMarcel Moolenaar return_job_token = TRUE; 11073955d011SMarcel Moolenaar Make_Update(job->node); 11083955d011SMarcel Moolenaar job->job_state = JOB_ST_FREE; 11093955d011SMarcel Moolenaar } else if (WAIT_STATUS(status)) { 11103955d011SMarcel Moolenaar errors += 1; 11113955d011SMarcel Moolenaar job->job_state = JOB_ST_FREE; 11123955d011SMarcel Moolenaar } 11133955d011SMarcel Moolenaar 11143955d011SMarcel Moolenaar /* 11153955d011SMarcel Moolenaar * Set aborting if any error. 11163955d011SMarcel Moolenaar */ 11173955d011SMarcel Moolenaar if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { 11183955d011SMarcel Moolenaar /* 11193955d011SMarcel Moolenaar * If we found any errors in this batch of children and the -k flag 11203955d011SMarcel Moolenaar * wasn't given, we set the aborting flag so no more jobs get 11213955d011SMarcel Moolenaar * started. 11223955d011SMarcel Moolenaar */ 11233955d011SMarcel Moolenaar aborting = ABORT_ERROR; 11243955d011SMarcel Moolenaar } 11253955d011SMarcel Moolenaar 11263955d011SMarcel Moolenaar if (return_job_token) 11273955d011SMarcel Moolenaar Job_TokenReturn(); 11283955d011SMarcel Moolenaar 11293955d011SMarcel Moolenaar if (aborting == ABORT_ERROR && jobTokensRunning == 0) { 11303955d011SMarcel Moolenaar /* 11313955d011SMarcel Moolenaar * If we are aborting and the job table is now empty, we finish. 11323955d011SMarcel Moolenaar */ 11333955d011SMarcel Moolenaar Finish(errors); 11343955d011SMarcel Moolenaar } 11353955d011SMarcel Moolenaar } 11363955d011SMarcel Moolenaar 11373955d011SMarcel Moolenaar /*- 11383955d011SMarcel Moolenaar *----------------------------------------------------------------------- 11393955d011SMarcel Moolenaar * Job_Touch -- 11403955d011SMarcel Moolenaar * Touch the given target. Called by JobStart when the -t flag was 11413955d011SMarcel Moolenaar * given 11423955d011SMarcel Moolenaar * 11433955d011SMarcel Moolenaar * Input: 11443955d011SMarcel Moolenaar * gn the node of the file to touch 11453955d011SMarcel Moolenaar * silent TRUE if should not print message 11463955d011SMarcel Moolenaar * 11473955d011SMarcel Moolenaar * Results: 11483955d011SMarcel Moolenaar * None 11493955d011SMarcel Moolenaar * 11503955d011SMarcel Moolenaar * Side Effects: 11513955d011SMarcel Moolenaar * The data modification of the file is changed. In addition, if the 11523955d011SMarcel Moolenaar * file did not exist, it is created. 11533955d011SMarcel Moolenaar *----------------------------------------------------------------------- 11543955d011SMarcel Moolenaar */ 11553955d011SMarcel Moolenaar void 11563955d011SMarcel Moolenaar Job_Touch(GNode *gn, Boolean silent) 11573955d011SMarcel Moolenaar { 11583955d011SMarcel Moolenaar int streamID; /* ID of stream opened to do the touch */ 11593955d011SMarcel Moolenaar struct utimbuf times; /* Times for utime() call */ 11603955d011SMarcel Moolenaar 11613955d011SMarcel Moolenaar if (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC|OP_OPTIONAL| 11623955d011SMarcel Moolenaar OP_SPECIAL|OP_PHONY)) { 11633955d011SMarcel Moolenaar /* 11643955d011SMarcel Moolenaar * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets 11653955d011SMarcel Moolenaar * and, as such, shouldn't really be created. 11663955d011SMarcel Moolenaar */ 11673955d011SMarcel Moolenaar return; 11683955d011SMarcel Moolenaar } 11693955d011SMarcel Moolenaar 11703955d011SMarcel Moolenaar if (!silent || NoExecute(gn)) { 11713955d011SMarcel Moolenaar (void)fprintf(stdout, "touch %s\n", gn->name); 11723955d011SMarcel Moolenaar (void)fflush(stdout); 11733955d011SMarcel Moolenaar } 11743955d011SMarcel Moolenaar 11753955d011SMarcel Moolenaar if (NoExecute(gn)) { 11763955d011SMarcel Moolenaar return; 11773955d011SMarcel Moolenaar } 11783955d011SMarcel Moolenaar 11793955d011SMarcel Moolenaar if (gn->type & OP_ARCHV) { 11803955d011SMarcel Moolenaar Arch_Touch(gn); 11813955d011SMarcel Moolenaar } else if (gn->type & OP_LIB) { 11823955d011SMarcel Moolenaar Arch_TouchLib(gn); 11833955d011SMarcel Moolenaar } else { 11843955d011SMarcel Moolenaar char *file = gn->path ? gn->path : gn->name; 11853955d011SMarcel Moolenaar 11863955d011SMarcel Moolenaar times.actime = times.modtime = now; 11873955d011SMarcel Moolenaar if (utime(file, ×) < 0){ 11883955d011SMarcel Moolenaar streamID = open(file, O_RDWR | O_CREAT, 0666); 11893955d011SMarcel Moolenaar 11903955d011SMarcel Moolenaar if (streamID >= 0) { 11913955d011SMarcel Moolenaar char c; 11923955d011SMarcel Moolenaar 11933955d011SMarcel Moolenaar /* 11943955d011SMarcel Moolenaar * Read and write a byte to the file to change the 11953955d011SMarcel Moolenaar * modification time, then close the file. 11963955d011SMarcel Moolenaar */ 11973955d011SMarcel Moolenaar if (read(streamID, &c, 1) == 1) { 11983955d011SMarcel Moolenaar (void)lseek(streamID, (off_t)0, SEEK_SET); 11993cbdda60SSimon J. Gerraty while (write(streamID, &c, 1) == -1 && errno == EAGAIN) 12003cbdda60SSimon J. Gerraty continue; 12013955d011SMarcel Moolenaar } 12023955d011SMarcel Moolenaar 12033955d011SMarcel Moolenaar (void)close(streamID); 12043955d011SMarcel Moolenaar } else { 12053955d011SMarcel Moolenaar (void)fprintf(stdout, "*** couldn't touch %s: %s", 12063955d011SMarcel Moolenaar file, strerror(errno)); 12073955d011SMarcel Moolenaar (void)fflush(stdout); 12083955d011SMarcel Moolenaar } 12093955d011SMarcel Moolenaar } 12103955d011SMarcel Moolenaar } 12113955d011SMarcel Moolenaar } 12123955d011SMarcel Moolenaar 12133955d011SMarcel Moolenaar /*- 12143955d011SMarcel Moolenaar *----------------------------------------------------------------------- 12153955d011SMarcel Moolenaar * Job_CheckCommands -- 12163955d011SMarcel Moolenaar * Make sure the given node has all the commands it needs. 12173955d011SMarcel Moolenaar * 12183955d011SMarcel Moolenaar * Input: 12193955d011SMarcel Moolenaar * gn The target whose commands need verifying 12203955d011SMarcel Moolenaar * abortProc Function to abort with message 12213955d011SMarcel Moolenaar * 12223955d011SMarcel Moolenaar * Results: 12233955d011SMarcel Moolenaar * TRUE if the commands list is/was ok. 12243955d011SMarcel Moolenaar * 12253955d011SMarcel Moolenaar * Side Effects: 12263955d011SMarcel Moolenaar * The node will have commands from the .DEFAULT rule added to it 12273955d011SMarcel Moolenaar * if it needs them. 12283955d011SMarcel Moolenaar *----------------------------------------------------------------------- 12293955d011SMarcel Moolenaar */ 12303955d011SMarcel Moolenaar Boolean 12313955d011SMarcel Moolenaar Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) 12323955d011SMarcel Moolenaar { 12333955d011SMarcel Moolenaar if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && 12343955d011SMarcel Moolenaar ((gn->type & OP_LIB) == 0 || Lst_IsEmpty(gn->children))) { 12353955d011SMarcel Moolenaar /* 12363955d011SMarcel Moolenaar * No commands. Look for .DEFAULT rule from which we might infer 12373955d011SMarcel Moolenaar * commands 12383955d011SMarcel Moolenaar */ 12393955d011SMarcel Moolenaar if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands) && 12403955d011SMarcel Moolenaar (gn->type & OP_SPECIAL) == 0) { 12413955d011SMarcel Moolenaar char *p1; 12423955d011SMarcel Moolenaar /* 12433955d011SMarcel Moolenaar * Make only looks for a .DEFAULT if the node was never the 12443955d011SMarcel Moolenaar * target of an operator, so that's what we do too. If 12453955d011SMarcel Moolenaar * a .DEFAULT was given, we substitute its commands for gn's 12463955d011SMarcel Moolenaar * commands and set the IMPSRC variable to be the target's name 12473955d011SMarcel Moolenaar * The DEFAULT node acts like a transformation rule, in that 12483955d011SMarcel Moolenaar * gn also inherits any attributes or sources attached to 12493955d011SMarcel Moolenaar * .DEFAULT itself. 12503955d011SMarcel Moolenaar */ 12513955d011SMarcel Moolenaar Make_HandleUse(DEFAULT, gn); 12523955d011SMarcel Moolenaar Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn, 0); 12533955d011SMarcel Moolenaar if (p1) 12543955d011SMarcel Moolenaar free(p1); 12553955d011SMarcel Moolenaar } else if (Dir_MTime(gn, 0) == 0 && (gn->type & OP_SPECIAL) == 0) { 12563955d011SMarcel Moolenaar /* 12573955d011SMarcel Moolenaar * The node wasn't the target of an operator we have no .DEFAULT 12583955d011SMarcel Moolenaar * rule to go on and the target doesn't already exist. There's 12593955d011SMarcel Moolenaar * nothing more we can do for this branch. If the -k flag wasn't 12603955d011SMarcel Moolenaar * given, we stop in our tracks, otherwise we just don't update 12613955d011SMarcel Moolenaar * this node's parents so they never get examined. 12623955d011SMarcel Moolenaar */ 12633955d011SMarcel Moolenaar static const char msg[] = ": don't know how to make"; 12643955d011SMarcel Moolenaar 12653955d011SMarcel Moolenaar if (gn->flags & FROM_DEPEND) { 12661748de26SSimon J. Gerraty if (!Job_RunTarget(".STALE", gn->fname)) 12671748de26SSimon J. Gerraty fprintf(stdout, "%s: %s, %d: ignoring stale %s for %s\n", 12681748de26SSimon J. Gerraty progname, gn->fname, gn->lineno, makeDependfile, 12691748de26SSimon J. Gerraty gn->name); 12703955d011SMarcel Moolenaar return TRUE; 12713955d011SMarcel Moolenaar } 12723955d011SMarcel Moolenaar 12733955d011SMarcel Moolenaar if (gn->type & OP_OPTIONAL) { 12743955d011SMarcel Moolenaar (void)fprintf(stdout, "%s%s %s (ignored)\n", progname, 12753955d011SMarcel Moolenaar msg, gn->name); 12763955d011SMarcel Moolenaar (void)fflush(stdout); 12773955d011SMarcel Moolenaar } else if (keepgoing) { 12783955d011SMarcel Moolenaar (void)fprintf(stdout, "%s%s %s (continuing)\n", progname, 12793955d011SMarcel Moolenaar msg, gn->name); 12803955d011SMarcel Moolenaar (void)fflush(stdout); 12813955d011SMarcel Moolenaar return FALSE; 12823955d011SMarcel Moolenaar } else { 12833955d011SMarcel Moolenaar (*abortProc)("%s%s %s. Stop", progname, msg, gn->name); 12843955d011SMarcel Moolenaar return FALSE; 12853955d011SMarcel Moolenaar } 12863955d011SMarcel Moolenaar } 12873955d011SMarcel Moolenaar } 12883955d011SMarcel Moolenaar return TRUE; 12893955d011SMarcel Moolenaar } 12903955d011SMarcel Moolenaar 12913955d011SMarcel Moolenaar /*- 12923955d011SMarcel Moolenaar *----------------------------------------------------------------------- 12933955d011SMarcel Moolenaar * JobExec -- 12943955d011SMarcel Moolenaar * Execute the shell for the given job. Called from JobStart 12953955d011SMarcel Moolenaar * 12963955d011SMarcel Moolenaar * Input: 12973955d011SMarcel Moolenaar * job Job to execute 12983955d011SMarcel Moolenaar * 12993955d011SMarcel Moolenaar * Results: 13003955d011SMarcel Moolenaar * None. 13013955d011SMarcel Moolenaar * 13023955d011SMarcel Moolenaar * Side Effects: 13033955d011SMarcel Moolenaar * A shell is executed, outputs is altered and the Job structure added 13043955d011SMarcel Moolenaar * to the job table. 13053955d011SMarcel Moolenaar * 13063955d011SMarcel Moolenaar *----------------------------------------------------------------------- 13073955d011SMarcel Moolenaar */ 13083955d011SMarcel Moolenaar static void 13093955d011SMarcel Moolenaar JobExec(Job *job, char **argv) 13103955d011SMarcel Moolenaar { 13113955d011SMarcel Moolenaar int cpid; /* ID of new child */ 13123955d011SMarcel Moolenaar sigset_t mask; 13133955d011SMarcel Moolenaar 13143955d011SMarcel Moolenaar job->flags &= ~JOB_TRACED; 13153955d011SMarcel Moolenaar 13163955d011SMarcel Moolenaar if (DEBUG(JOB)) { 13173955d011SMarcel Moolenaar int i; 13183955d011SMarcel Moolenaar 13193955d011SMarcel Moolenaar (void)fprintf(debug_file, "Running %s %sly\n", job->node->name, "local"); 13203955d011SMarcel Moolenaar (void)fprintf(debug_file, "\tCommand: "); 13213955d011SMarcel Moolenaar for (i = 0; argv[i] != NULL; i++) { 13223955d011SMarcel Moolenaar (void)fprintf(debug_file, "%s ", argv[i]); 13233955d011SMarcel Moolenaar } 13243955d011SMarcel Moolenaar (void)fprintf(debug_file, "\n"); 13253955d011SMarcel Moolenaar } 13263955d011SMarcel Moolenaar 13273955d011SMarcel Moolenaar /* 13283955d011SMarcel Moolenaar * Some jobs produce no output and it's disconcerting to have 13293955d011SMarcel Moolenaar * no feedback of their running (since they produce no output, the 13303955d011SMarcel Moolenaar * banner with their name in it never appears). This is an attempt to 13313955d011SMarcel Moolenaar * provide that feedback, even if nothing follows it. 13323955d011SMarcel Moolenaar */ 13333955d011SMarcel Moolenaar if ((lastNode != job->node) && !(job->flags & JOB_SILENT)) { 13343955d011SMarcel Moolenaar MESSAGE(stdout, job->node); 13353955d011SMarcel Moolenaar lastNode = job->node; 13363955d011SMarcel Moolenaar } 13373955d011SMarcel Moolenaar 13383955d011SMarcel Moolenaar /* No interruptions until this job is on the `jobs' list */ 13393955d011SMarcel Moolenaar JobSigLock(&mask); 13403955d011SMarcel Moolenaar 13413955d011SMarcel Moolenaar /* Pre-emptively mark job running, pid still zero though */ 13423955d011SMarcel Moolenaar job->job_state = JOB_ST_RUNNING; 13433955d011SMarcel Moolenaar 13443955d011SMarcel Moolenaar cpid = vFork(); 13453955d011SMarcel Moolenaar if (cpid == -1) 13463955d011SMarcel Moolenaar Punt("Cannot vfork: %s", strerror(errno)); 13473955d011SMarcel Moolenaar 13483955d011SMarcel Moolenaar if (cpid == 0) { 13493955d011SMarcel Moolenaar /* Child */ 13503955d011SMarcel Moolenaar sigset_t tmask; 13513955d011SMarcel Moolenaar 13523955d011SMarcel Moolenaar #ifdef USE_META 13533955d011SMarcel Moolenaar if (useMeta) { 13543955d011SMarcel Moolenaar meta_job_child(job); 13553955d011SMarcel Moolenaar } 13563955d011SMarcel Moolenaar #endif 13573955d011SMarcel Moolenaar /* 13583955d011SMarcel Moolenaar * Reset all signal handlers; this is necessary because we also 13593955d011SMarcel Moolenaar * need to unblock signals before we exec(2). 13603955d011SMarcel Moolenaar */ 13613955d011SMarcel Moolenaar JobSigReset(); 13623955d011SMarcel Moolenaar 13633955d011SMarcel Moolenaar /* Now unblock signals */ 13643955d011SMarcel Moolenaar sigemptyset(&tmask); 13653955d011SMarcel Moolenaar JobSigUnlock(&tmask); 13663955d011SMarcel Moolenaar 13673955d011SMarcel Moolenaar /* 13683955d011SMarcel Moolenaar * Must duplicate the input stream down to the child's input and 13693955d011SMarcel Moolenaar * reset it to the beginning (again). Since the stream was marked 13703955d011SMarcel Moolenaar * close-on-exec, we must clear that bit in the new input. 13713955d011SMarcel Moolenaar */ 13723955d011SMarcel Moolenaar if (dup2(FILENO(job->cmdFILE), 0) == -1) { 13733955d011SMarcel Moolenaar execError("dup2", "job->cmdFILE"); 13743955d011SMarcel Moolenaar _exit(1); 13753955d011SMarcel Moolenaar } 13763955d011SMarcel Moolenaar (void)fcntl(0, F_SETFD, 0); 13773955d011SMarcel Moolenaar (void)lseek(0, (off_t)0, SEEK_SET); 13783955d011SMarcel Moolenaar 1379*db29cad8SSimon J. Gerraty if (Always_pass_job_queue || 1380*db29cad8SSimon J. Gerraty (job->node->type & (OP_MAKE | OP_SUBMAKE))) { 13813955d011SMarcel Moolenaar /* 13823955d011SMarcel Moolenaar * Pass job token pipe to submakes. 13833955d011SMarcel Moolenaar */ 13843955d011SMarcel Moolenaar fcntl(tokenWaitJob.inPipe, F_SETFD, 0); 13853955d011SMarcel Moolenaar fcntl(tokenWaitJob.outPipe, F_SETFD, 0); 13863955d011SMarcel Moolenaar } 13873955d011SMarcel Moolenaar 13883955d011SMarcel Moolenaar /* 13893955d011SMarcel Moolenaar * Set up the child's output to be routed through the pipe 13903955d011SMarcel Moolenaar * we've created for it. 13913955d011SMarcel Moolenaar */ 13923955d011SMarcel Moolenaar if (dup2(job->outPipe, 1) == -1) { 13933955d011SMarcel Moolenaar execError("dup2", "job->outPipe"); 13943955d011SMarcel Moolenaar _exit(1); 13953955d011SMarcel Moolenaar } 13963955d011SMarcel Moolenaar /* 13973955d011SMarcel Moolenaar * The output channels are marked close on exec. This bit was 13983955d011SMarcel Moolenaar * duplicated by the dup2(on some systems), so we have to clear 13993955d011SMarcel Moolenaar * it before routing the shell's error output to the same place as 14003955d011SMarcel Moolenaar * its standard output. 14013955d011SMarcel Moolenaar */ 14023955d011SMarcel Moolenaar (void)fcntl(1, F_SETFD, 0); 14033955d011SMarcel Moolenaar if (dup2(1, 2) == -1) { 14043955d011SMarcel Moolenaar execError("dup2", "1, 2"); 14053955d011SMarcel Moolenaar _exit(1); 14063955d011SMarcel Moolenaar } 14073955d011SMarcel Moolenaar 14083955d011SMarcel Moolenaar /* 14093955d011SMarcel Moolenaar * We want to switch the child into a different process family so 14103955d011SMarcel Moolenaar * we can kill it and all its descendants in one fell swoop, 14113955d011SMarcel Moolenaar * by killing its process family, but not commit suicide. 14123955d011SMarcel Moolenaar */ 14133955d011SMarcel Moolenaar #if defined(HAVE_SETPGID) 14143955d011SMarcel Moolenaar (void)setpgid(0, getpid()); 14153955d011SMarcel Moolenaar #else 14163955d011SMarcel Moolenaar #if defined(HAVE_SETSID) 14173955d011SMarcel Moolenaar /* XXX: dsl - I'm sure this should be setpgrp()... */ 14183955d011SMarcel Moolenaar (void)setsid(); 14193955d011SMarcel Moolenaar #else 14203955d011SMarcel Moolenaar (void)setpgrp(0, getpid()); 14213955d011SMarcel Moolenaar #endif 14223955d011SMarcel Moolenaar #endif 14233955d011SMarcel Moolenaar 14243955d011SMarcel Moolenaar Var_ExportVars(); 14253955d011SMarcel Moolenaar 14263955d011SMarcel Moolenaar (void)execv(shellPath, argv); 14273955d011SMarcel Moolenaar execError("exec", shellPath); 14283955d011SMarcel Moolenaar _exit(1); 14293955d011SMarcel Moolenaar } 14303955d011SMarcel Moolenaar 14313955d011SMarcel Moolenaar /* Parent, continuing after the child exec */ 14323955d011SMarcel Moolenaar job->pid = cpid; 14333955d011SMarcel Moolenaar 14343955d011SMarcel Moolenaar Trace_Log(JOBSTART, job); 14353955d011SMarcel Moolenaar 14363955d011SMarcel Moolenaar /* 14373955d011SMarcel Moolenaar * Set the current position in the buffer to the beginning 14383955d011SMarcel Moolenaar * and mark another stream to watch in the outputs mask 14393955d011SMarcel Moolenaar */ 14403955d011SMarcel Moolenaar job->curPos = 0; 14413955d011SMarcel Moolenaar 14423955d011SMarcel Moolenaar watchfd(job); 14433955d011SMarcel Moolenaar 14443955d011SMarcel Moolenaar if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 14453955d011SMarcel Moolenaar (void)fclose(job->cmdFILE); 14463955d011SMarcel Moolenaar job->cmdFILE = NULL; 14473955d011SMarcel Moolenaar } 14483955d011SMarcel Moolenaar 14493955d011SMarcel Moolenaar /* 14503955d011SMarcel Moolenaar * Now the job is actually running, add it to the table. 14513955d011SMarcel Moolenaar */ 14523955d011SMarcel Moolenaar if (DEBUG(JOB)) { 14533955d011SMarcel Moolenaar fprintf(debug_file, "JobExec(%s): pid %d added to jobs table\n", 14543955d011SMarcel Moolenaar job->node->name, job->pid); 14553955d011SMarcel Moolenaar job_table_dump("job started"); 14563955d011SMarcel Moolenaar } 14573955d011SMarcel Moolenaar JobSigUnlock(&mask); 14583955d011SMarcel Moolenaar } 14593955d011SMarcel Moolenaar 14603955d011SMarcel Moolenaar /*- 14613955d011SMarcel Moolenaar *----------------------------------------------------------------------- 14623955d011SMarcel Moolenaar * JobMakeArgv -- 14633955d011SMarcel Moolenaar * Create the argv needed to execute the shell for a given job. 14643955d011SMarcel Moolenaar * 14653955d011SMarcel Moolenaar * 14663955d011SMarcel Moolenaar * Results: 14673955d011SMarcel Moolenaar * 14683955d011SMarcel Moolenaar * Side Effects: 14693955d011SMarcel Moolenaar * 14703955d011SMarcel Moolenaar *----------------------------------------------------------------------- 14713955d011SMarcel Moolenaar */ 14723955d011SMarcel Moolenaar static void 14733955d011SMarcel Moolenaar JobMakeArgv(Job *job, char **argv) 14743955d011SMarcel Moolenaar { 14753955d011SMarcel Moolenaar int argc; 14763955d011SMarcel Moolenaar static char args[10]; /* For merged arguments */ 14773955d011SMarcel Moolenaar 14783955d011SMarcel Moolenaar argv[0] = UNCONST(shellName); 14793955d011SMarcel Moolenaar argc = 1; 14803955d011SMarcel Moolenaar 14813955d011SMarcel Moolenaar if ((commandShell->exit && (*commandShell->exit != '-')) || 14823955d011SMarcel Moolenaar (commandShell->echo && (*commandShell->echo != '-'))) 14833955d011SMarcel Moolenaar { 14843955d011SMarcel Moolenaar /* 14853955d011SMarcel Moolenaar * At least one of the flags doesn't have a minus before it, so 14863955d011SMarcel Moolenaar * merge them together. Have to do this because the *(&(@*#*&#$# 14873955d011SMarcel Moolenaar * Bourne shell thinks its second argument is a file to source. 14883955d011SMarcel Moolenaar * Grrrr. Note the ten-character limitation on the combined arguments. 14893955d011SMarcel Moolenaar */ 14903955d011SMarcel Moolenaar (void)snprintf(args, sizeof(args), "-%s%s", 14913955d011SMarcel Moolenaar ((job->flags & JOB_IGNERR) ? "" : 14923955d011SMarcel Moolenaar (commandShell->exit ? commandShell->exit : "")), 14933955d011SMarcel Moolenaar ((job->flags & JOB_SILENT) ? "" : 14943955d011SMarcel Moolenaar (commandShell->echo ? commandShell->echo : ""))); 14953955d011SMarcel Moolenaar 14963955d011SMarcel Moolenaar if (args[1]) { 14973955d011SMarcel Moolenaar argv[argc] = args; 14983955d011SMarcel Moolenaar argc++; 14993955d011SMarcel Moolenaar } 15003955d011SMarcel Moolenaar } else { 15013955d011SMarcel Moolenaar if (!(job->flags & JOB_IGNERR) && commandShell->exit) { 15023955d011SMarcel Moolenaar argv[argc] = UNCONST(commandShell->exit); 15033955d011SMarcel Moolenaar argc++; 15043955d011SMarcel Moolenaar } 15053955d011SMarcel Moolenaar if (!(job->flags & JOB_SILENT) && commandShell->echo) { 15063955d011SMarcel Moolenaar argv[argc] = UNCONST(commandShell->echo); 15073955d011SMarcel Moolenaar argc++; 15083955d011SMarcel Moolenaar } 15093955d011SMarcel Moolenaar } 15103955d011SMarcel Moolenaar argv[argc] = NULL; 15113955d011SMarcel Moolenaar } 15123955d011SMarcel Moolenaar 15133955d011SMarcel Moolenaar /*- 15143955d011SMarcel Moolenaar *----------------------------------------------------------------------- 15153955d011SMarcel Moolenaar * JobStart -- 15163955d011SMarcel Moolenaar * Start a target-creation process going for the target described 15173955d011SMarcel Moolenaar * by the graph node gn. 15183955d011SMarcel Moolenaar * 15193955d011SMarcel Moolenaar * Input: 15203955d011SMarcel Moolenaar * gn target to create 15213955d011SMarcel Moolenaar * flags flags for the job to override normal ones. 15223955d011SMarcel Moolenaar * e.g. JOB_SPECIAL or JOB_IGNDOTS 15233955d011SMarcel Moolenaar * previous The previous Job structure for this node, if any. 15243955d011SMarcel Moolenaar * 15253955d011SMarcel Moolenaar * Results: 15263955d011SMarcel Moolenaar * JOB_ERROR if there was an error in the commands, JOB_FINISHED 15273955d011SMarcel Moolenaar * if there isn't actually anything left to do for the job and 15283955d011SMarcel Moolenaar * JOB_RUNNING if the job has been started. 15293955d011SMarcel Moolenaar * 15303955d011SMarcel Moolenaar * Side Effects: 15313955d011SMarcel Moolenaar * A new Job node is created and added to the list of running 15323955d011SMarcel Moolenaar * jobs. PMake is forked and a child shell created. 15333955d011SMarcel Moolenaar * 15343955d011SMarcel Moolenaar * NB: I'm fairly sure that this code is never called with JOB_SPECIAL set 15353955d011SMarcel Moolenaar * JOB_IGNDOTS is never set (dsl) 15363955d011SMarcel Moolenaar * Also the return value is ignored by everyone. 15373955d011SMarcel Moolenaar *----------------------------------------------------------------------- 15383955d011SMarcel Moolenaar */ 15393955d011SMarcel Moolenaar static int 15403955d011SMarcel Moolenaar JobStart(GNode *gn, int flags) 15413955d011SMarcel Moolenaar { 15423955d011SMarcel Moolenaar Job *job; /* new job descriptor */ 15433955d011SMarcel Moolenaar char *argv[10]; /* Argument vector to shell */ 15443955d011SMarcel Moolenaar Boolean cmdsOK; /* true if the nodes commands were all right */ 15453955d011SMarcel Moolenaar Boolean noExec; /* Set true if we decide not to run the job */ 15463955d011SMarcel Moolenaar int tfd; /* File descriptor to the temp file */ 15473955d011SMarcel Moolenaar 15483955d011SMarcel Moolenaar for (job = job_table; job < job_table_end; job++) { 15493955d011SMarcel Moolenaar if (job->job_state == JOB_ST_FREE) 15503955d011SMarcel Moolenaar break; 15513955d011SMarcel Moolenaar } 15523955d011SMarcel Moolenaar if (job >= job_table_end) 15533955d011SMarcel Moolenaar Punt("JobStart no job slots vacant"); 15543955d011SMarcel Moolenaar 15553955d011SMarcel Moolenaar memset(job, 0, sizeof *job); 15563955d011SMarcel Moolenaar job->job_state = JOB_ST_SETUP; 15573955d011SMarcel Moolenaar if (gn->type & OP_SPECIAL) 15583955d011SMarcel Moolenaar flags |= JOB_SPECIAL; 15593955d011SMarcel Moolenaar 15603955d011SMarcel Moolenaar job->node = gn; 15613955d011SMarcel Moolenaar job->tailCmds = NULL; 15623955d011SMarcel Moolenaar 15633955d011SMarcel Moolenaar /* 15643955d011SMarcel Moolenaar * Set the initial value of the flags for this job based on the global 15653955d011SMarcel Moolenaar * ones and the node's attributes... Any flags supplied by the caller 15663955d011SMarcel Moolenaar * are also added to the field. 15673955d011SMarcel Moolenaar */ 15683955d011SMarcel Moolenaar job->flags = 0; 15693955d011SMarcel Moolenaar if (Targ_Ignore(gn)) { 15703955d011SMarcel Moolenaar job->flags |= JOB_IGNERR; 15713955d011SMarcel Moolenaar } 15723955d011SMarcel Moolenaar if (Targ_Silent(gn)) { 15733955d011SMarcel Moolenaar job->flags |= JOB_SILENT; 15743955d011SMarcel Moolenaar } 15753955d011SMarcel Moolenaar job->flags |= flags; 15763955d011SMarcel Moolenaar 15773955d011SMarcel Moolenaar /* 15783955d011SMarcel Moolenaar * Check the commands now so any attributes from .DEFAULT have a chance 15793955d011SMarcel Moolenaar * to migrate to the node 15803955d011SMarcel Moolenaar */ 15813955d011SMarcel Moolenaar cmdsOK = Job_CheckCommands(gn, Error); 15823955d011SMarcel Moolenaar 15833955d011SMarcel Moolenaar job->inPollfd = NULL; 15843955d011SMarcel Moolenaar /* 15853955d011SMarcel Moolenaar * If the -n flag wasn't given, we open up OUR (not the child's) 15863955d011SMarcel Moolenaar * temporary file to stuff commands in it. The thing is rd/wr so we don't 15873955d011SMarcel Moolenaar * need to reopen it to feed it to the shell. If the -n flag *was* given, 15883955d011SMarcel Moolenaar * we just set the file to be stdout. Cute, huh? 15893955d011SMarcel Moolenaar */ 15903955d011SMarcel Moolenaar if (((gn->type & OP_MAKE) && !(noRecursiveExecute)) || 15913955d011SMarcel Moolenaar (!noExecute && !touchFlag)) { 15923955d011SMarcel Moolenaar /* 15933955d011SMarcel Moolenaar * tfile is the name of a file into which all shell commands are 15943955d011SMarcel Moolenaar * put. It is removed before the child shell is executed, unless 15953955d011SMarcel Moolenaar * DEBUG(SCRIPT) is set. 15963955d011SMarcel Moolenaar */ 15973955d011SMarcel Moolenaar char *tfile; 15983955d011SMarcel Moolenaar sigset_t mask; 15993955d011SMarcel Moolenaar /* 16003955d011SMarcel Moolenaar * We're serious here, but if the commands were bogus, we're 16013955d011SMarcel Moolenaar * also dead... 16023955d011SMarcel Moolenaar */ 16033955d011SMarcel Moolenaar if (!cmdsOK) { 16043955d011SMarcel Moolenaar PrintOnError(gn, NULL); /* provide some clue */ 16053955d011SMarcel Moolenaar DieHorribly(); 16063955d011SMarcel Moolenaar } 16073955d011SMarcel Moolenaar 16083955d011SMarcel Moolenaar JobSigLock(&mask); 16093955d011SMarcel Moolenaar tfd = mkTempFile(TMPPAT, &tfile); 16103955d011SMarcel Moolenaar if (!DEBUG(SCRIPT)) 16113955d011SMarcel Moolenaar (void)eunlink(tfile); 16123955d011SMarcel Moolenaar JobSigUnlock(&mask); 16133955d011SMarcel Moolenaar 16143955d011SMarcel Moolenaar job->cmdFILE = fdopen(tfd, "w+"); 16153955d011SMarcel Moolenaar if (job->cmdFILE == NULL) { 16163955d011SMarcel Moolenaar Punt("Could not fdopen %s", tfile); 16173955d011SMarcel Moolenaar } 16183955d011SMarcel Moolenaar (void)fcntl(FILENO(job->cmdFILE), F_SETFD, 1); 16193955d011SMarcel Moolenaar /* 16203955d011SMarcel Moolenaar * Send the commands to the command file, flush all its buffers then 16213955d011SMarcel Moolenaar * rewind and remove the thing. 16223955d011SMarcel Moolenaar */ 16233955d011SMarcel Moolenaar noExec = FALSE; 16243955d011SMarcel Moolenaar 16253955d011SMarcel Moolenaar #ifdef USE_META 16263955d011SMarcel Moolenaar if (useMeta) { 16273955d011SMarcel Moolenaar meta_job_start(job, gn); 16283955d011SMarcel Moolenaar if (Targ_Silent(gn)) { /* might have changed */ 16293955d011SMarcel Moolenaar job->flags |= JOB_SILENT; 16303955d011SMarcel Moolenaar } 16313955d011SMarcel Moolenaar } 16323955d011SMarcel Moolenaar #endif 16333955d011SMarcel Moolenaar /* 16343955d011SMarcel Moolenaar * We can do all the commands at once. hooray for sanity 16353955d011SMarcel Moolenaar */ 16363955d011SMarcel Moolenaar numCommands = 0; 16373955d011SMarcel Moolenaar Lst_ForEach(gn->commands, JobPrintCommand, job); 16383955d011SMarcel Moolenaar 16393955d011SMarcel Moolenaar /* 16403955d011SMarcel Moolenaar * If we didn't print out any commands to the shell script, 16413955d011SMarcel Moolenaar * there's not much point in executing the shell, is there? 16423955d011SMarcel Moolenaar */ 16433955d011SMarcel Moolenaar if (numCommands == 0) { 16443955d011SMarcel Moolenaar noExec = TRUE; 16453955d011SMarcel Moolenaar } 16463955d011SMarcel Moolenaar 16473955d011SMarcel Moolenaar free(tfile); 16483955d011SMarcel Moolenaar } else if (NoExecute(gn)) { 16493955d011SMarcel Moolenaar /* 16503955d011SMarcel Moolenaar * Not executing anything -- just print all the commands to stdout 16513955d011SMarcel Moolenaar * in one fell swoop. This will still set up job->tailCmds correctly. 16523955d011SMarcel Moolenaar */ 16533955d011SMarcel Moolenaar if (lastNode != gn) { 16543955d011SMarcel Moolenaar MESSAGE(stdout, gn); 16553955d011SMarcel Moolenaar lastNode = gn; 16563955d011SMarcel Moolenaar } 16573955d011SMarcel Moolenaar job->cmdFILE = stdout; 16583955d011SMarcel Moolenaar /* 16593955d011SMarcel Moolenaar * Only print the commands if they're ok, but don't die if they're 16603955d011SMarcel Moolenaar * not -- just let the user know they're bad and keep going. It 16613955d011SMarcel Moolenaar * doesn't do any harm in this case and may do some good. 16623955d011SMarcel Moolenaar */ 16633955d011SMarcel Moolenaar if (cmdsOK) { 16643955d011SMarcel Moolenaar Lst_ForEach(gn->commands, JobPrintCommand, job); 16653955d011SMarcel Moolenaar } 16663955d011SMarcel Moolenaar /* 16673955d011SMarcel Moolenaar * Don't execute the shell, thank you. 16683955d011SMarcel Moolenaar */ 16693955d011SMarcel Moolenaar noExec = TRUE; 16703955d011SMarcel Moolenaar } else { 16713955d011SMarcel Moolenaar /* 16723955d011SMarcel Moolenaar * Just touch the target and note that no shell should be executed. 16733955d011SMarcel Moolenaar * Set cmdFILE to stdout to make life easier. Check the commands, too, 16743955d011SMarcel Moolenaar * but don't die if they're no good -- it does no harm to keep working 16753955d011SMarcel Moolenaar * up the graph. 16763955d011SMarcel Moolenaar */ 16773955d011SMarcel Moolenaar job->cmdFILE = stdout; 16783955d011SMarcel Moolenaar Job_Touch(gn, job->flags&JOB_SILENT); 16793955d011SMarcel Moolenaar noExec = TRUE; 16803955d011SMarcel Moolenaar } 16813955d011SMarcel Moolenaar /* Just in case it isn't already... */ 16823955d011SMarcel Moolenaar (void)fflush(job->cmdFILE); 16833955d011SMarcel Moolenaar 16843955d011SMarcel Moolenaar /* 16853955d011SMarcel Moolenaar * If we're not supposed to execute a shell, don't. 16863955d011SMarcel Moolenaar */ 16873955d011SMarcel Moolenaar if (noExec) { 16883955d011SMarcel Moolenaar if (!(job->flags & JOB_SPECIAL)) 16893955d011SMarcel Moolenaar Job_TokenReturn(); 16903955d011SMarcel Moolenaar /* 16913955d011SMarcel Moolenaar * Unlink and close the command file if we opened one 16923955d011SMarcel Moolenaar */ 16933955d011SMarcel Moolenaar if (job->cmdFILE != stdout) { 16943955d011SMarcel Moolenaar if (job->cmdFILE != NULL) { 16953955d011SMarcel Moolenaar (void)fclose(job->cmdFILE); 16963955d011SMarcel Moolenaar job->cmdFILE = NULL; 16973955d011SMarcel Moolenaar } 16983955d011SMarcel Moolenaar } 16993955d011SMarcel Moolenaar 17003955d011SMarcel Moolenaar /* 17013955d011SMarcel Moolenaar * We only want to work our way up the graph if we aren't here because 17023955d011SMarcel Moolenaar * the commands for the job were no good. 17033955d011SMarcel Moolenaar */ 17043955d011SMarcel Moolenaar if (cmdsOK && aborting == 0) { 17053955d011SMarcel Moolenaar if (job->tailCmds != NULL) { 17063955d011SMarcel Moolenaar Lst_ForEachFrom(job->node->commands, job->tailCmds, 17073955d011SMarcel Moolenaar JobSaveCommand, 17083955d011SMarcel Moolenaar job->node); 17093955d011SMarcel Moolenaar } 17103955d011SMarcel Moolenaar job->node->made = MADE; 17113955d011SMarcel Moolenaar Make_Update(job->node); 17123955d011SMarcel Moolenaar } 17133955d011SMarcel Moolenaar job->job_state = JOB_ST_FREE; 17143955d011SMarcel Moolenaar return cmdsOK ? JOB_FINISHED : JOB_ERROR; 17153955d011SMarcel Moolenaar } 17163955d011SMarcel Moolenaar 17173955d011SMarcel Moolenaar /* 17183955d011SMarcel Moolenaar * Set up the control arguments to the shell. This is based on the flags 17193955d011SMarcel Moolenaar * set earlier for this job. 17203955d011SMarcel Moolenaar */ 17213955d011SMarcel Moolenaar JobMakeArgv(job, argv); 17223955d011SMarcel Moolenaar 17233955d011SMarcel Moolenaar /* Create the pipe by which we'll get the shell's output. */ 17243955d011SMarcel Moolenaar JobCreatePipe(job, 3); 17253955d011SMarcel Moolenaar 17263955d011SMarcel Moolenaar JobExec(job, argv); 17273955d011SMarcel Moolenaar return(JOB_RUNNING); 17283955d011SMarcel Moolenaar } 17293955d011SMarcel Moolenaar 17303955d011SMarcel Moolenaar static char * 17313955d011SMarcel Moolenaar JobOutput(Job *job, char *cp, char *endp, int msg) 17323955d011SMarcel Moolenaar { 17333955d011SMarcel Moolenaar char *ecp; 17343955d011SMarcel Moolenaar 17353955d011SMarcel Moolenaar if (commandShell->noPrint) { 17363955d011SMarcel Moolenaar ecp = Str_FindSubstring(cp, commandShell->noPrint); 17373955d011SMarcel Moolenaar while (ecp != NULL) { 17383955d011SMarcel Moolenaar if (cp != ecp) { 17393955d011SMarcel Moolenaar *ecp = '\0'; 17403955d011SMarcel Moolenaar if (!beSilent && msg && job->node != lastNode) { 17413955d011SMarcel Moolenaar MESSAGE(stdout, job->node); 17423955d011SMarcel Moolenaar lastNode = job->node; 17433955d011SMarcel Moolenaar } 17443955d011SMarcel Moolenaar /* 17453955d011SMarcel Moolenaar * The only way there wouldn't be a newline after 17463955d011SMarcel Moolenaar * this line is if it were the last in the buffer. 17473955d011SMarcel Moolenaar * however, since the non-printable comes after it, 17483955d011SMarcel Moolenaar * there must be a newline, so we don't print one. 17493955d011SMarcel Moolenaar */ 17503955d011SMarcel Moolenaar (void)fprintf(stdout, "%s", cp); 17513955d011SMarcel Moolenaar (void)fflush(stdout); 17523955d011SMarcel Moolenaar } 17533955d011SMarcel Moolenaar cp = ecp + commandShell->noPLen; 17543955d011SMarcel Moolenaar if (cp != endp) { 17553955d011SMarcel Moolenaar /* 17563955d011SMarcel Moolenaar * Still more to print, look again after skipping 17573955d011SMarcel Moolenaar * the whitespace following the non-printable 17583955d011SMarcel Moolenaar * command.... 17593955d011SMarcel Moolenaar */ 17603955d011SMarcel Moolenaar cp++; 17613955d011SMarcel Moolenaar while (*cp == ' ' || *cp == '\t' || *cp == '\n') { 17623955d011SMarcel Moolenaar cp++; 17633955d011SMarcel Moolenaar } 17643955d011SMarcel Moolenaar ecp = Str_FindSubstring(cp, commandShell->noPrint); 17653955d011SMarcel Moolenaar } else { 17663955d011SMarcel Moolenaar return cp; 17673955d011SMarcel Moolenaar } 17683955d011SMarcel Moolenaar } 17693955d011SMarcel Moolenaar } 17703955d011SMarcel Moolenaar return cp; 17713955d011SMarcel Moolenaar } 17723955d011SMarcel Moolenaar 17733955d011SMarcel Moolenaar /*- 17743955d011SMarcel Moolenaar *----------------------------------------------------------------------- 17753955d011SMarcel Moolenaar * JobDoOutput -- 17763955d011SMarcel Moolenaar * This function is called at different times depending on 17773955d011SMarcel Moolenaar * whether the user has specified that output is to be collected 17783955d011SMarcel Moolenaar * via pipes or temporary files. In the former case, we are called 17793955d011SMarcel Moolenaar * whenever there is something to read on the pipe. We collect more 17803955d011SMarcel Moolenaar * output from the given job and store it in the job's outBuf. If 17813955d011SMarcel Moolenaar * this makes up a line, we print it tagged by the job's identifier, 17823955d011SMarcel Moolenaar * as necessary. 17833955d011SMarcel Moolenaar * If output has been collected in a temporary file, we open the 17843955d011SMarcel Moolenaar * file and read it line by line, transfering it to our own 17853955d011SMarcel Moolenaar * output channel until the file is empty. At which point we 17863955d011SMarcel Moolenaar * remove the temporary file. 17873955d011SMarcel Moolenaar * In both cases, however, we keep our figurative eye out for the 17883955d011SMarcel Moolenaar * 'noPrint' line for the shell from which the output came. If 17893955d011SMarcel Moolenaar * we recognize a line, we don't print it. If the command is not 17903955d011SMarcel Moolenaar * alone on the line (the character after it is not \0 or \n), we 17913955d011SMarcel Moolenaar * do print whatever follows it. 17923955d011SMarcel Moolenaar * 17933955d011SMarcel Moolenaar * Input: 17943955d011SMarcel Moolenaar * job the job whose output needs printing 17953955d011SMarcel Moolenaar * finish TRUE if this is the last time we'll be called 17963955d011SMarcel Moolenaar * for this job 17973955d011SMarcel Moolenaar * 17983955d011SMarcel Moolenaar * Results: 17993955d011SMarcel Moolenaar * None 18003955d011SMarcel Moolenaar * 18013955d011SMarcel Moolenaar * Side Effects: 18023955d011SMarcel Moolenaar * curPos may be shifted as may the contents of outBuf. 18033955d011SMarcel Moolenaar *----------------------------------------------------------------------- 18043955d011SMarcel Moolenaar */ 18053955d011SMarcel Moolenaar STATIC void 18063955d011SMarcel Moolenaar JobDoOutput(Job *job, Boolean finish) 18073955d011SMarcel Moolenaar { 18083955d011SMarcel Moolenaar Boolean gotNL = FALSE; /* true if got a newline */ 18093955d011SMarcel Moolenaar Boolean fbuf; /* true if our buffer filled up */ 18103955d011SMarcel Moolenaar int nr; /* number of bytes read */ 18113955d011SMarcel Moolenaar int i; /* auxiliary index into outBuf */ 18123955d011SMarcel Moolenaar int max; /* limit for i (end of current data) */ 18133955d011SMarcel Moolenaar int nRead; /* (Temporary) number of bytes read */ 18143955d011SMarcel Moolenaar 18153955d011SMarcel Moolenaar /* 18163955d011SMarcel Moolenaar * Read as many bytes as will fit in the buffer. 18173955d011SMarcel Moolenaar */ 18183955d011SMarcel Moolenaar end_loop: 18193955d011SMarcel Moolenaar gotNL = FALSE; 18203955d011SMarcel Moolenaar fbuf = FALSE; 18213955d011SMarcel Moolenaar 18223955d011SMarcel Moolenaar nRead = read(job->inPipe, &job->outBuf[job->curPos], 18233955d011SMarcel Moolenaar JOB_BUFSIZE - job->curPos); 18243955d011SMarcel Moolenaar if (nRead < 0) { 18253955d011SMarcel Moolenaar if (errno == EAGAIN) 18263955d011SMarcel Moolenaar return; 18273955d011SMarcel Moolenaar if (DEBUG(JOB)) { 18283955d011SMarcel Moolenaar perror("JobDoOutput(piperead)"); 18293955d011SMarcel Moolenaar } 18303955d011SMarcel Moolenaar nr = 0; 18313955d011SMarcel Moolenaar } else { 18323955d011SMarcel Moolenaar nr = nRead; 18333955d011SMarcel Moolenaar } 18343955d011SMarcel Moolenaar 18353955d011SMarcel Moolenaar /* 18363955d011SMarcel Moolenaar * If we hit the end-of-file (the job is dead), we must flush its 18373955d011SMarcel Moolenaar * remaining output, so pretend we read a newline if there's any 18383955d011SMarcel Moolenaar * output remaining in the buffer. 18393955d011SMarcel Moolenaar * Also clear the 'finish' flag so we stop looping. 18403955d011SMarcel Moolenaar */ 18413955d011SMarcel Moolenaar if ((nr == 0) && (job->curPos != 0)) { 18423955d011SMarcel Moolenaar job->outBuf[job->curPos] = '\n'; 18433955d011SMarcel Moolenaar nr = 1; 18443955d011SMarcel Moolenaar finish = FALSE; 18453955d011SMarcel Moolenaar } else if (nr == 0) { 18463955d011SMarcel Moolenaar finish = FALSE; 18473955d011SMarcel Moolenaar } 18483955d011SMarcel Moolenaar 18493955d011SMarcel Moolenaar /* 18503955d011SMarcel Moolenaar * Look for the last newline in the bytes we just got. If there is 18513955d011SMarcel Moolenaar * one, break out of the loop with 'i' as its index and gotNL set 18523955d011SMarcel Moolenaar * TRUE. 18533955d011SMarcel Moolenaar */ 18543955d011SMarcel Moolenaar max = job->curPos + nr; 18553955d011SMarcel Moolenaar for (i = job->curPos + nr - 1; i >= job->curPos; i--) { 18563955d011SMarcel Moolenaar if (job->outBuf[i] == '\n') { 18573955d011SMarcel Moolenaar gotNL = TRUE; 18583955d011SMarcel Moolenaar break; 18593955d011SMarcel Moolenaar } else if (job->outBuf[i] == '\0') { 18603955d011SMarcel Moolenaar /* 18613955d011SMarcel Moolenaar * Why? 18623955d011SMarcel Moolenaar */ 18633955d011SMarcel Moolenaar job->outBuf[i] = ' '; 18643955d011SMarcel Moolenaar } 18653955d011SMarcel Moolenaar } 18663955d011SMarcel Moolenaar 18673955d011SMarcel Moolenaar if (!gotNL) { 18683955d011SMarcel Moolenaar job->curPos += nr; 18693955d011SMarcel Moolenaar if (job->curPos == JOB_BUFSIZE) { 18703955d011SMarcel Moolenaar /* 18713955d011SMarcel Moolenaar * If we've run out of buffer space, we have no choice 18723955d011SMarcel Moolenaar * but to print the stuff. sigh. 18733955d011SMarcel Moolenaar */ 18743955d011SMarcel Moolenaar fbuf = TRUE; 18753955d011SMarcel Moolenaar i = job->curPos; 18763955d011SMarcel Moolenaar } 18773955d011SMarcel Moolenaar } 18783955d011SMarcel Moolenaar if (gotNL || fbuf) { 18793955d011SMarcel Moolenaar /* 18803955d011SMarcel Moolenaar * Need to send the output to the screen. Null terminate it 18813955d011SMarcel Moolenaar * first, overwriting the newline character if there was one. 18823955d011SMarcel Moolenaar * So long as the line isn't one we should filter (according 18833955d011SMarcel Moolenaar * to the shell description), we print the line, preceded 18843955d011SMarcel Moolenaar * by a target banner if this target isn't the same as the 18853955d011SMarcel Moolenaar * one for which we last printed something. 18863955d011SMarcel Moolenaar * The rest of the data in the buffer are then shifted down 18873955d011SMarcel Moolenaar * to the start of the buffer and curPos is set accordingly. 18883955d011SMarcel Moolenaar */ 18893955d011SMarcel Moolenaar job->outBuf[i] = '\0'; 18903955d011SMarcel Moolenaar if (i >= job->curPos) { 18913955d011SMarcel Moolenaar char *cp; 18923955d011SMarcel Moolenaar 18933955d011SMarcel Moolenaar cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); 18943955d011SMarcel Moolenaar 18953955d011SMarcel Moolenaar /* 18963955d011SMarcel Moolenaar * There's still more in that thar buffer. This time, though, 18973955d011SMarcel Moolenaar * we know there's no newline at the end, so we add one of 18983955d011SMarcel Moolenaar * our own free will. 18993955d011SMarcel Moolenaar */ 19003955d011SMarcel Moolenaar if (*cp != '\0') { 19013955d011SMarcel Moolenaar if (!beSilent && job->node != lastNode) { 19023955d011SMarcel Moolenaar MESSAGE(stdout, job->node); 19033955d011SMarcel Moolenaar lastNode = job->node; 19043955d011SMarcel Moolenaar } 19053955d011SMarcel Moolenaar #ifdef USE_META 19063955d011SMarcel Moolenaar if (useMeta) { 19073955d011SMarcel Moolenaar meta_job_output(job, cp, gotNL ? "\n" : ""); 19083955d011SMarcel Moolenaar } 19093955d011SMarcel Moolenaar #endif 19103955d011SMarcel Moolenaar (void)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); 19113955d011SMarcel Moolenaar (void)fflush(stdout); 19123955d011SMarcel Moolenaar } 19133955d011SMarcel Moolenaar } 19143955d011SMarcel Moolenaar /* 1915*db29cad8SSimon J. Gerraty * max is the last offset still in the buffer. Move any remaining 1916*db29cad8SSimon J. Gerraty * characters to the start of the buffer and update the end marker 1917*db29cad8SSimon J. Gerraty * curPos. 19183955d011SMarcel Moolenaar */ 1919*db29cad8SSimon J. Gerraty if (i < max) { 1920*db29cad8SSimon J. Gerraty (void)memmove(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); 1921*db29cad8SSimon J. Gerraty job->curPos = max - (i + 1); 1922*db29cad8SSimon J. Gerraty } else { 1923*db29cad8SSimon J. Gerraty assert(i == max); 19243955d011SMarcel Moolenaar job->curPos = 0; 19253955d011SMarcel Moolenaar } 19263955d011SMarcel Moolenaar } 19273955d011SMarcel Moolenaar if (finish) { 19283955d011SMarcel Moolenaar /* 19293955d011SMarcel Moolenaar * If the finish flag is true, we must loop until we hit 19303955d011SMarcel Moolenaar * end-of-file on the pipe. This is guaranteed to happen 19313955d011SMarcel Moolenaar * eventually since the other end of the pipe is now closed 19323955d011SMarcel Moolenaar * (we closed it explicitly and the child has exited). When 19333955d011SMarcel Moolenaar * we do get an EOF, finish will be set FALSE and we'll fall 19343955d011SMarcel Moolenaar * through and out. 19353955d011SMarcel Moolenaar */ 19363955d011SMarcel Moolenaar goto end_loop; 19373955d011SMarcel Moolenaar } 19383955d011SMarcel Moolenaar } 19393955d011SMarcel Moolenaar 19403955d011SMarcel Moolenaar static void 19413955d011SMarcel Moolenaar JobRun(GNode *targ) 19423955d011SMarcel Moolenaar { 19433955d011SMarcel Moolenaar #ifdef notyet 19443955d011SMarcel Moolenaar /* 19453955d011SMarcel Moolenaar * Unfortunately it is too complicated to run .BEGIN, .END, 19463955d011SMarcel Moolenaar * and .INTERRUPT job in the parallel job module. This has 19473955d011SMarcel Moolenaar * the nice side effect that it avoids a lot of other problems. 19483955d011SMarcel Moolenaar */ 19493955d011SMarcel Moolenaar Lst lst = Lst_Init(FALSE); 19503955d011SMarcel Moolenaar Lst_AtEnd(lst, targ); 19513955d011SMarcel Moolenaar (void)Make_Run(lst); 19523955d011SMarcel Moolenaar Lst_Destroy(lst, NULL); 19533955d011SMarcel Moolenaar JobStart(targ, JOB_SPECIAL); 19543955d011SMarcel Moolenaar while (jobTokensRunning) { 19553955d011SMarcel Moolenaar Job_CatchOutput(); 19563955d011SMarcel Moolenaar } 19573955d011SMarcel Moolenaar #else 19583955d011SMarcel Moolenaar Compat_Make(targ, targ); 19593955d011SMarcel Moolenaar if (targ->made == ERROR) { 19603955d011SMarcel Moolenaar PrintOnError(targ, "\n\nStop."); 19613955d011SMarcel Moolenaar exit(1); 19623955d011SMarcel Moolenaar } 19633955d011SMarcel Moolenaar #endif 19643955d011SMarcel Moolenaar } 19653955d011SMarcel Moolenaar 19663955d011SMarcel Moolenaar /*- 19673955d011SMarcel Moolenaar *----------------------------------------------------------------------- 19683955d011SMarcel Moolenaar * Job_CatchChildren -- 19693955d011SMarcel Moolenaar * Handle the exit of a child. Called from Make_Make. 19703955d011SMarcel Moolenaar * 19713955d011SMarcel Moolenaar * Input: 19723955d011SMarcel Moolenaar * block TRUE if should block on the wait 19733955d011SMarcel Moolenaar * 19743955d011SMarcel Moolenaar * Results: 19753955d011SMarcel Moolenaar * none. 19763955d011SMarcel Moolenaar * 19773955d011SMarcel Moolenaar * Side Effects: 19783955d011SMarcel Moolenaar * The job descriptor is removed from the list of children. 19793955d011SMarcel Moolenaar * 19803955d011SMarcel Moolenaar * Notes: 19813955d011SMarcel Moolenaar * We do waits, blocking or not, according to the wisdom of our 19823955d011SMarcel Moolenaar * caller, until there are no more children to report. For each 19833955d011SMarcel Moolenaar * job, call JobFinish to finish things off. 19843955d011SMarcel Moolenaar * 19853955d011SMarcel Moolenaar *----------------------------------------------------------------------- 19863955d011SMarcel Moolenaar */ 19873955d011SMarcel Moolenaar 19883955d011SMarcel Moolenaar void 19893955d011SMarcel Moolenaar Job_CatchChildren(void) 19903955d011SMarcel Moolenaar { 19913955d011SMarcel Moolenaar int pid; /* pid of dead child */ 19923955d011SMarcel Moolenaar WAIT_T status; /* Exit/termination status */ 19933955d011SMarcel Moolenaar 19943955d011SMarcel Moolenaar /* 19953955d011SMarcel Moolenaar * Don't even bother if we know there's no one around. 19963955d011SMarcel Moolenaar */ 19973955d011SMarcel Moolenaar if (jobTokensRunning == 0) 19983955d011SMarcel Moolenaar return; 19993955d011SMarcel Moolenaar 20003955d011SMarcel Moolenaar while ((pid = waitpid((pid_t) -1, &status, WNOHANG | WUNTRACED)) > 0) { 20013955d011SMarcel Moolenaar if (DEBUG(JOB)) { 20023955d011SMarcel Moolenaar (void)fprintf(debug_file, "Process %d exited/stopped status %x.\n", pid, 20033955d011SMarcel Moolenaar WAIT_STATUS(status)); 20043955d011SMarcel Moolenaar } 20053955d011SMarcel Moolenaar JobReapChild(pid, status, TRUE); 20063955d011SMarcel Moolenaar } 20073955d011SMarcel Moolenaar } 20083955d011SMarcel Moolenaar 20093955d011SMarcel Moolenaar /* 20103955d011SMarcel Moolenaar * It is possible that wait[pid]() was called from elsewhere, 20113955d011SMarcel Moolenaar * this lets us reap jobs regardless. 20123955d011SMarcel Moolenaar */ 20133955d011SMarcel Moolenaar void 20143955d011SMarcel Moolenaar JobReapChild(pid_t pid, WAIT_T status, Boolean isJobs) 20153955d011SMarcel Moolenaar { 20163955d011SMarcel Moolenaar Job *job; /* job descriptor for dead child */ 20173955d011SMarcel Moolenaar 20183955d011SMarcel Moolenaar /* 20193955d011SMarcel Moolenaar * Don't even bother if we know there's no one around. 20203955d011SMarcel Moolenaar */ 20213955d011SMarcel Moolenaar if (jobTokensRunning == 0) 20223955d011SMarcel Moolenaar return; 20233955d011SMarcel Moolenaar 20243955d011SMarcel Moolenaar job = JobFindPid(pid, JOB_ST_RUNNING, isJobs); 20253955d011SMarcel Moolenaar if (job == NULL) { 20263955d011SMarcel Moolenaar if (isJobs) { 20273955d011SMarcel Moolenaar if (!lurking_children) 20283955d011SMarcel Moolenaar Error("Child (%d) status %x not in table?", pid, status); 20293955d011SMarcel Moolenaar } 20303955d011SMarcel Moolenaar return; /* not ours */ 20313955d011SMarcel Moolenaar } 20323955d011SMarcel Moolenaar if (WIFSTOPPED(status)) { 20333955d011SMarcel Moolenaar if (DEBUG(JOB)) { 20343955d011SMarcel Moolenaar (void)fprintf(debug_file, "Process %d (%s) stopped.\n", 20353955d011SMarcel Moolenaar job->pid, job->node->name); 20363955d011SMarcel Moolenaar } 20373955d011SMarcel Moolenaar if (!make_suspended) { 20383955d011SMarcel Moolenaar switch (WSTOPSIG(status)) { 20393955d011SMarcel Moolenaar case SIGTSTP: 20403955d011SMarcel Moolenaar (void)printf("*** [%s] Suspended\n", job->node->name); 20413955d011SMarcel Moolenaar break; 20423955d011SMarcel Moolenaar case SIGSTOP: 20433955d011SMarcel Moolenaar (void)printf("*** [%s] Stopped\n", job->node->name); 20443955d011SMarcel Moolenaar break; 20453955d011SMarcel Moolenaar default: 20463955d011SMarcel Moolenaar (void)printf("*** [%s] Stopped -- signal %d\n", 20473955d011SMarcel Moolenaar job->node->name, WSTOPSIG(status)); 20483955d011SMarcel Moolenaar } 20493955d011SMarcel Moolenaar job->job_suspended = 1; 20503955d011SMarcel Moolenaar } 20513955d011SMarcel Moolenaar (void)fflush(stdout); 20523955d011SMarcel Moolenaar return; 20533955d011SMarcel Moolenaar } 20543955d011SMarcel Moolenaar 20553955d011SMarcel Moolenaar job->job_state = JOB_ST_FINISHED; 20563955d011SMarcel Moolenaar job->exit_status = WAIT_STATUS(status); 20573955d011SMarcel Moolenaar 20583955d011SMarcel Moolenaar JobFinish(job, status); 20593955d011SMarcel Moolenaar } 20603955d011SMarcel Moolenaar 20613955d011SMarcel Moolenaar /*- 20623955d011SMarcel Moolenaar *----------------------------------------------------------------------- 20633955d011SMarcel Moolenaar * Job_CatchOutput -- 20643955d011SMarcel Moolenaar * Catch the output from our children, if we're using 20653955d011SMarcel Moolenaar * pipes do so. Otherwise just block time until we get a 20663955d011SMarcel Moolenaar * signal(most likely a SIGCHLD) since there's no point in 20673955d011SMarcel Moolenaar * just spinning when there's nothing to do and the reaping 20683955d011SMarcel Moolenaar * of a child can wait for a while. 20693955d011SMarcel Moolenaar * 20703955d011SMarcel Moolenaar * Results: 20713955d011SMarcel Moolenaar * None 20723955d011SMarcel Moolenaar * 20733955d011SMarcel Moolenaar * Side Effects: 20743955d011SMarcel Moolenaar * Output is read from pipes if we're piping. 20753955d011SMarcel Moolenaar * ----------------------------------------------------------------------- 20763955d011SMarcel Moolenaar */ 20773955d011SMarcel Moolenaar void 20783955d011SMarcel Moolenaar Job_CatchOutput(void) 20793955d011SMarcel Moolenaar { 20803955d011SMarcel Moolenaar int nready; 20813955d011SMarcel Moolenaar Job *job; 20823955d011SMarcel Moolenaar int i; 20833955d011SMarcel Moolenaar 20843955d011SMarcel Moolenaar (void)fflush(stdout); 20853955d011SMarcel Moolenaar 20863955d011SMarcel Moolenaar /* The first fd in the list is the job token pipe */ 20871748de26SSimon J. Gerraty do { 20883955d011SMarcel Moolenaar nready = poll(fds + 1 - wantToken, nfds - 1 + wantToken, POLL_MSEC); 20891748de26SSimon J. Gerraty } while (nready < 0 && errno == EINTR); 20903955d011SMarcel Moolenaar 20911748de26SSimon J. Gerraty if (nready < 0) 20921748de26SSimon J. Gerraty Punt("poll: %s", strerror(errno)); 20931748de26SSimon J. Gerraty 20941748de26SSimon J. Gerraty if (nready > 0 && readyfd(&childExitJob)) { 20953955d011SMarcel Moolenaar char token = 0; 20961748de26SSimon J. Gerraty ssize_t count; 20971748de26SSimon J. Gerraty count = read(childExitJob.inPipe, &token, 1); 20981748de26SSimon J. Gerraty switch (count) { 20991748de26SSimon J. Gerraty case 0: 21001748de26SSimon J. Gerraty Punt("unexpected eof on token pipe"); 21011748de26SSimon J. Gerraty case -1: 21021748de26SSimon J. Gerraty Punt("token pipe read: %s", strerror(errno)); 21031748de26SSimon J. Gerraty case 1: 21043955d011SMarcel Moolenaar if (token == DO_JOB_RESUME[0]) 21053955d011SMarcel Moolenaar /* Complete relay requested from our SIGCONT handler */ 21063955d011SMarcel Moolenaar JobRestartJobs(); 21071748de26SSimon J. Gerraty break; 21081748de26SSimon J. Gerraty default: 21091748de26SSimon J. Gerraty abort(); 21101748de26SSimon J. Gerraty } 21111748de26SSimon J. Gerraty --nready; 21123955d011SMarcel Moolenaar } 21133955d011SMarcel Moolenaar 21141748de26SSimon J. Gerraty Job_CatchChildren(); 21151748de26SSimon J. Gerraty if (nready == 0) 21163955d011SMarcel Moolenaar return; 21173955d011SMarcel Moolenaar 21183955d011SMarcel Moolenaar for (i = 2; i < nfds; i++) { 21193955d011SMarcel Moolenaar if (!fds[i].revents) 21203955d011SMarcel Moolenaar continue; 21213955d011SMarcel Moolenaar job = jobfds[i]; 21221748de26SSimon J. Gerraty if (job->job_state == JOB_ST_RUNNING) 21233955d011SMarcel Moolenaar JobDoOutput(job, FALSE); 21241748de26SSimon J. Gerraty if (--nready == 0) 21251748de26SSimon J. Gerraty return; 21263955d011SMarcel Moolenaar } 21273955d011SMarcel Moolenaar } 21283955d011SMarcel Moolenaar 21293955d011SMarcel Moolenaar /*- 21303955d011SMarcel Moolenaar *----------------------------------------------------------------------- 21313955d011SMarcel Moolenaar * Job_Make -- 21323955d011SMarcel Moolenaar * Start the creation of a target. Basically a front-end for 21333955d011SMarcel Moolenaar * JobStart used by the Make module. 21343955d011SMarcel Moolenaar * 21353955d011SMarcel Moolenaar * Results: 21363955d011SMarcel Moolenaar * None. 21373955d011SMarcel Moolenaar * 21383955d011SMarcel Moolenaar * Side Effects: 21393955d011SMarcel Moolenaar * Another job is started. 21403955d011SMarcel Moolenaar * 21413955d011SMarcel Moolenaar *----------------------------------------------------------------------- 21423955d011SMarcel Moolenaar */ 21433955d011SMarcel Moolenaar void 21443955d011SMarcel Moolenaar Job_Make(GNode *gn) 21453955d011SMarcel Moolenaar { 21463955d011SMarcel Moolenaar (void)JobStart(gn, 0); 21473955d011SMarcel Moolenaar } 21483955d011SMarcel Moolenaar 21493955d011SMarcel Moolenaar void 21503955d011SMarcel Moolenaar Shell_Init(void) 21513955d011SMarcel Moolenaar { 21523955d011SMarcel Moolenaar if (shellPath == NULL) { 21533955d011SMarcel Moolenaar /* 21543955d011SMarcel Moolenaar * We are using the default shell, which may be an absolute 21553955d011SMarcel Moolenaar * path if DEFSHELL_CUSTOM is defined. 21563955d011SMarcel Moolenaar */ 21573955d011SMarcel Moolenaar shellName = commandShell->name; 21583955d011SMarcel Moolenaar #ifdef DEFSHELL_CUSTOM 21593955d011SMarcel Moolenaar if (*shellName == '/') { 21603955d011SMarcel Moolenaar shellPath = shellName; 21613955d011SMarcel Moolenaar shellName = strrchr(shellPath, '/'); 21623955d011SMarcel Moolenaar shellName++; 21633955d011SMarcel Moolenaar } else 21643955d011SMarcel Moolenaar #endif 21653955d011SMarcel Moolenaar shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); 21663955d011SMarcel Moolenaar } 21673955d011SMarcel Moolenaar if (commandShell->exit == NULL) { 21683955d011SMarcel Moolenaar commandShell->exit = ""; 21693955d011SMarcel Moolenaar } 21703955d011SMarcel Moolenaar if (commandShell->echo == NULL) { 21713955d011SMarcel Moolenaar commandShell->echo = ""; 21723955d011SMarcel Moolenaar } 217351ee2c1cSSimon J. Gerraty if (commandShell->hasErrCtl && *commandShell->exit) { 217451ee2c1cSSimon J. Gerraty if (shellErrFlag && 217551ee2c1cSSimon J. Gerraty strcmp(commandShell->exit, &shellErrFlag[1]) != 0) { 217651ee2c1cSSimon J. Gerraty free(shellErrFlag); 217751ee2c1cSSimon J. Gerraty shellErrFlag = NULL; 217851ee2c1cSSimon J. Gerraty } 217951ee2c1cSSimon J. Gerraty if (!shellErrFlag) { 218051ee2c1cSSimon J. Gerraty int n = strlen(commandShell->exit) + 2; 218151ee2c1cSSimon J. Gerraty 218251ee2c1cSSimon J. Gerraty shellErrFlag = bmake_malloc(n); 218351ee2c1cSSimon J. Gerraty if (shellErrFlag) { 218451ee2c1cSSimon J. Gerraty snprintf(shellErrFlag, n, "-%s", commandShell->exit); 218551ee2c1cSSimon J. Gerraty } 218651ee2c1cSSimon J. Gerraty } 218751ee2c1cSSimon J. Gerraty } else if (shellErrFlag) { 218851ee2c1cSSimon J. Gerraty free(shellErrFlag); 218951ee2c1cSSimon J. Gerraty shellErrFlag = NULL; 219051ee2c1cSSimon J. Gerraty } 21913955d011SMarcel Moolenaar } 21923955d011SMarcel Moolenaar 21933955d011SMarcel Moolenaar /*- 21943955d011SMarcel Moolenaar * Returns the string literal that is used in the current command shell 21953955d011SMarcel Moolenaar * to produce a newline character. 21963955d011SMarcel Moolenaar */ 21973955d011SMarcel Moolenaar const char * 21983955d011SMarcel Moolenaar Shell_GetNewline(void) 21993955d011SMarcel Moolenaar { 22003955d011SMarcel Moolenaar 22013955d011SMarcel Moolenaar return commandShell->newline; 22023955d011SMarcel Moolenaar } 22033955d011SMarcel Moolenaar 22043955d011SMarcel Moolenaar void 22053955d011SMarcel Moolenaar Job_SetPrefix(void) 22063955d011SMarcel Moolenaar { 22073955d011SMarcel Moolenaar 22083955d011SMarcel Moolenaar if (targPrefix) { 22093955d011SMarcel Moolenaar free(targPrefix); 22103955d011SMarcel Moolenaar } else if (!Var_Exists(MAKE_JOB_PREFIX, VAR_GLOBAL)) { 22113955d011SMarcel Moolenaar Var_Set(MAKE_JOB_PREFIX, "---", VAR_GLOBAL, 0); 22123955d011SMarcel Moolenaar } 22133955d011SMarcel Moolenaar 22143955d011SMarcel Moolenaar targPrefix = Var_Subst(NULL, "${" MAKE_JOB_PREFIX "}", VAR_GLOBAL, 0); 22153955d011SMarcel Moolenaar } 22163955d011SMarcel Moolenaar 22173955d011SMarcel Moolenaar /*- 22183955d011SMarcel Moolenaar *----------------------------------------------------------------------- 22193955d011SMarcel Moolenaar * Job_Init -- 22203955d011SMarcel Moolenaar * Initialize the process module 22213955d011SMarcel Moolenaar * 22223955d011SMarcel Moolenaar * Input: 22233955d011SMarcel Moolenaar * 22243955d011SMarcel Moolenaar * Results: 22253955d011SMarcel Moolenaar * none 22263955d011SMarcel Moolenaar * 22273955d011SMarcel Moolenaar * Side Effects: 22283955d011SMarcel Moolenaar * lists and counters are initialized 22293955d011SMarcel Moolenaar *----------------------------------------------------------------------- 22303955d011SMarcel Moolenaar */ 22313955d011SMarcel Moolenaar void 22323955d011SMarcel Moolenaar Job_Init(void) 22333955d011SMarcel Moolenaar { 2234d191243dSSimon J. Gerraty Job_SetPrefix(); 22353955d011SMarcel Moolenaar /* Allocate space for all the job info */ 22363955d011SMarcel Moolenaar job_table = bmake_malloc(maxJobs * sizeof *job_table); 22373955d011SMarcel Moolenaar memset(job_table, 0, maxJobs * sizeof *job_table); 22383955d011SMarcel Moolenaar job_table_end = job_table + maxJobs; 22393955d011SMarcel Moolenaar wantToken = 0; 22403955d011SMarcel Moolenaar 22413955d011SMarcel Moolenaar aborting = 0; 22423955d011SMarcel Moolenaar errors = 0; 22433955d011SMarcel Moolenaar 22443955d011SMarcel Moolenaar lastNode = NULL; 22453955d011SMarcel Moolenaar 22469a4bc556SSimon J. Gerraty Always_pass_job_queue = getBoolean(MAKE_ALWAYS_PASS_JOB_QUEUE, 22479a4bc556SSimon J. Gerraty Always_pass_job_queue); 22489a4bc556SSimon J. Gerraty 22492d395cb5SSimon J. Gerraty Job_error_token = getBoolean(MAKE_JOB_ERROR_TOKEN, Job_error_token); 22502d395cb5SSimon J. Gerraty 22512d395cb5SSimon J. Gerraty 22523955d011SMarcel Moolenaar /* 22533955d011SMarcel Moolenaar * There is a non-zero chance that we already have children. 22543955d011SMarcel Moolenaar * eg after 'make -f- <<EOF' 22553955d011SMarcel Moolenaar * Since their termination causes a 'Child (pid) not in table' message, 22563955d011SMarcel Moolenaar * Collect the status of any that are already dead, and suppress the 22573955d011SMarcel Moolenaar * error message if there are any undead ones. 22583955d011SMarcel Moolenaar */ 22593955d011SMarcel Moolenaar for (;;) { 22603955d011SMarcel Moolenaar int rval, status; 22613955d011SMarcel Moolenaar rval = waitpid((pid_t) -1, &status, WNOHANG); 22623955d011SMarcel Moolenaar if (rval > 0) 22633955d011SMarcel Moolenaar continue; 22643955d011SMarcel Moolenaar if (rval == 0) 22653955d011SMarcel Moolenaar lurking_children = 1; 22663955d011SMarcel Moolenaar break; 22673955d011SMarcel Moolenaar } 22683955d011SMarcel Moolenaar 22693955d011SMarcel Moolenaar Shell_Init(); 22703955d011SMarcel Moolenaar 22713955d011SMarcel Moolenaar JobCreatePipe(&childExitJob, 3); 22723955d011SMarcel Moolenaar 22733955d011SMarcel Moolenaar /* We can only need to wait for tokens, children and output from each job */ 22743955d011SMarcel Moolenaar fds = bmake_malloc(sizeof (*fds) * (2 + maxJobs)); 22753955d011SMarcel Moolenaar jobfds = bmake_malloc(sizeof (*jobfds) * (2 + maxJobs)); 22763955d011SMarcel Moolenaar 22773955d011SMarcel Moolenaar /* These are permanent entries and take slots 0 and 1 */ 22783955d011SMarcel Moolenaar watchfd(&tokenWaitJob); 22793955d011SMarcel Moolenaar watchfd(&childExitJob); 22803955d011SMarcel Moolenaar 22813955d011SMarcel Moolenaar sigemptyset(&caught_signals); 22823955d011SMarcel Moolenaar /* 22833955d011SMarcel Moolenaar * Install a SIGCHLD handler. 22843955d011SMarcel Moolenaar */ 22853955d011SMarcel Moolenaar (void)bmake_signal(SIGCHLD, JobChildSig); 22863955d011SMarcel Moolenaar sigaddset(&caught_signals, SIGCHLD); 22873955d011SMarcel Moolenaar 22883955d011SMarcel Moolenaar #define ADDSIG(s,h) \ 22893955d011SMarcel Moolenaar if (bmake_signal(s, SIG_IGN) != SIG_IGN) { \ 22903955d011SMarcel Moolenaar sigaddset(&caught_signals, s); \ 22913955d011SMarcel Moolenaar (void)bmake_signal(s, h); \ 22923955d011SMarcel Moolenaar } 22933955d011SMarcel Moolenaar 22943955d011SMarcel Moolenaar /* 22953955d011SMarcel Moolenaar * Catch the four signals that POSIX specifies if they aren't ignored. 22963955d011SMarcel Moolenaar * JobPassSig will take care of calling JobInterrupt if appropriate. 22973955d011SMarcel Moolenaar */ 22983955d011SMarcel Moolenaar ADDSIG(SIGINT, JobPassSig_int) 22993955d011SMarcel Moolenaar ADDSIG(SIGHUP, JobPassSig_term) 23003955d011SMarcel Moolenaar ADDSIG(SIGTERM, JobPassSig_term) 23013955d011SMarcel Moolenaar ADDSIG(SIGQUIT, JobPassSig_term) 23023955d011SMarcel Moolenaar 23033955d011SMarcel Moolenaar /* 23043955d011SMarcel Moolenaar * There are additional signals that need to be caught and passed if 23053955d011SMarcel Moolenaar * either the export system wants to be told directly of signals or if 23063955d011SMarcel Moolenaar * we're giving each job its own process group (since then it won't get 23073955d011SMarcel Moolenaar * signals from the terminal driver as we own the terminal) 23083955d011SMarcel Moolenaar */ 23093955d011SMarcel Moolenaar ADDSIG(SIGTSTP, JobPassSig_suspend) 23103955d011SMarcel Moolenaar ADDSIG(SIGTTOU, JobPassSig_suspend) 23113955d011SMarcel Moolenaar ADDSIG(SIGTTIN, JobPassSig_suspend) 23123955d011SMarcel Moolenaar ADDSIG(SIGWINCH, JobCondPassSig) 23133955d011SMarcel Moolenaar ADDSIG(SIGCONT, JobContinueSig) 23143955d011SMarcel Moolenaar #undef ADDSIG 23153955d011SMarcel Moolenaar 23161748de26SSimon J. Gerraty (void)Job_RunTarget(".BEGIN", NULL); 23173955d011SMarcel Moolenaar postCommands = Targ_FindNode(".END", TARG_CREATE); 23183955d011SMarcel Moolenaar } 23193955d011SMarcel Moolenaar 23203955d011SMarcel Moolenaar static void JobSigReset(void) 23213955d011SMarcel Moolenaar { 23223955d011SMarcel Moolenaar #define DELSIG(s) \ 23233955d011SMarcel Moolenaar if (sigismember(&caught_signals, s)) { \ 23243955d011SMarcel Moolenaar (void)bmake_signal(s, SIG_DFL); \ 23253955d011SMarcel Moolenaar } 23263955d011SMarcel Moolenaar 23273955d011SMarcel Moolenaar DELSIG(SIGINT) 23283955d011SMarcel Moolenaar DELSIG(SIGHUP) 23293955d011SMarcel Moolenaar DELSIG(SIGQUIT) 23303955d011SMarcel Moolenaar DELSIG(SIGTERM) 23313955d011SMarcel Moolenaar DELSIG(SIGTSTP) 23323955d011SMarcel Moolenaar DELSIG(SIGTTOU) 23333955d011SMarcel Moolenaar DELSIG(SIGTTIN) 23343955d011SMarcel Moolenaar DELSIG(SIGWINCH) 23353955d011SMarcel Moolenaar DELSIG(SIGCONT) 23363955d011SMarcel Moolenaar #undef DELSIG 23373955d011SMarcel Moolenaar (void)bmake_signal(SIGCHLD, SIG_DFL); 23383955d011SMarcel Moolenaar } 23393955d011SMarcel Moolenaar 23403955d011SMarcel Moolenaar /*- 23413955d011SMarcel Moolenaar *----------------------------------------------------------------------- 23423955d011SMarcel Moolenaar * JobMatchShell -- 23433955d011SMarcel Moolenaar * Find a shell in 'shells' given its name. 23443955d011SMarcel Moolenaar * 23453955d011SMarcel Moolenaar * Results: 23463955d011SMarcel Moolenaar * A pointer to the Shell structure. 23473955d011SMarcel Moolenaar * 23483955d011SMarcel Moolenaar * Side Effects: 23493955d011SMarcel Moolenaar * None. 23503955d011SMarcel Moolenaar * 23513955d011SMarcel Moolenaar *----------------------------------------------------------------------- 23523955d011SMarcel Moolenaar */ 23533955d011SMarcel Moolenaar static Shell * 23543955d011SMarcel Moolenaar JobMatchShell(const char *name) 23553955d011SMarcel Moolenaar { 23563955d011SMarcel Moolenaar Shell *sh; 23573955d011SMarcel Moolenaar 23583955d011SMarcel Moolenaar for (sh = shells; sh->name != NULL; sh++) { 23593955d011SMarcel Moolenaar if (strcmp(name, sh->name) == 0) 23603955d011SMarcel Moolenaar return (sh); 23613955d011SMarcel Moolenaar } 23623955d011SMarcel Moolenaar return NULL; 23633955d011SMarcel Moolenaar } 23643955d011SMarcel Moolenaar 23653955d011SMarcel Moolenaar /*- 23663955d011SMarcel Moolenaar *----------------------------------------------------------------------- 23673955d011SMarcel Moolenaar * Job_ParseShell -- 23683955d011SMarcel Moolenaar * Parse a shell specification and set up commandShell, shellPath 23693955d011SMarcel Moolenaar * and shellName appropriately. 23703955d011SMarcel Moolenaar * 23713955d011SMarcel Moolenaar * Input: 23723955d011SMarcel Moolenaar * line The shell spec 23733955d011SMarcel Moolenaar * 23743955d011SMarcel Moolenaar * Results: 23753955d011SMarcel Moolenaar * FAILURE if the specification was incorrect. 23763955d011SMarcel Moolenaar * 23773955d011SMarcel Moolenaar * Side Effects: 23783955d011SMarcel Moolenaar * commandShell points to a Shell structure (either predefined or 23793955d011SMarcel Moolenaar * created from the shell spec), shellPath is the full path of the 23803955d011SMarcel Moolenaar * shell described by commandShell, while shellName is just the 23813955d011SMarcel Moolenaar * final component of shellPath. 23823955d011SMarcel Moolenaar * 23833955d011SMarcel Moolenaar * Notes: 23843955d011SMarcel Moolenaar * A shell specification consists of a .SHELL target, with dependency 23853955d011SMarcel Moolenaar * operator, followed by a series of blank-separated words. Double 23863955d011SMarcel Moolenaar * quotes can be used to use blanks in words. A backslash escapes 23873955d011SMarcel Moolenaar * anything (most notably a double-quote and a space) and 23883955d011SMarcel Moolenaar * provides the functionality it does in C. Each word consists of 23893955d011SMarcel Moolenaar * keyword and value separated by an equal sign. There should be no 23903955d011SMarcel Moolenaar * unnecessary spaces in the word. The keywords are as follows: 23913955d011SMarcel Moolenaar * name Name of shell. 23923955d011SMarcel Moolenaar * path Location of shell. 23933955d011SMarcel Moolenaar * quiet Command to turn off echoing. 23943955d011SMarcel Moolenaar * echo Command to turn echoing on 23953955d011SMarcel Moolenaar * filter Result of turning off echoing that shouldn't be 23963955d011SMarcel Moolenaar * printed. 23973955d011SMarcel Moolenaar * echoFlag Flag to turn echoing on at the start 23983955d011SMarcel Moolenaar * errFlag Flag to turn error checking on at the start 23993955d011SMarcel Moolenaar * hasErrCtl True if shell has error checking control 24003955d011SMarcel Moolenaar * newline String literal to represent a newline char 24013955d011SMarcel Moolenaar * check Command to turn on error checking if hasErrCtl 24023955d011SMarcel Moolenaar * is TRUE or template of command to echo a command 24033955d011SMarcel Moolenaar * for which error checking is off if hasErrCtl is 24043955d011SMarcel Moolenaar * FALSE. 24053955d011SMarcel Moolenaar * ignore Command to turn off error checking if hasErrCtl 24063955d011SMarcel Moolenaar * is TRUE or template of command to execute a 24073955d011SMarcel Moolenaar * command so as to ignore any errors it returns if 24083955d011SMarcel Moolenaar * hasErrCtl is FALSE. 24093955d011SMarcel Moolenaar * 24103955d011SMarcel Moolenaar *----------------------------------------------------------------------- 24113955d011SMarcel Moolenaar */ 24123955d011SMarcel Moolenaar ReturnStatus 24133955d011SMarcel Moolenaar Job_ParseShell(char *line) 24143955d011SMarcel Moolenaar { 24153955d011SMarcel Moolenaar char **words; 24163955d011SMarcel Moolenaar char **argv; 24173955d011SMarcel Moolenaar int argc; 24183955d011SMarcel Moolenaar char *path; 24193955d011SMarcel Moolenaar Shell newShell; 24203955d011SMarcel Moolenaar Boolean fullSpec = FALSE; 24213955d011SMarcel Moolenaar Shell *sh; 24223955d011SMarcel Moolenaar 24233955d011SMarcel Moolenaar while (isspace((unsigned char)*line)) { 24243955d011SMarcel Moolenaar line++; 24253955d011SMarcel Moolenaar } 24263955d011SMarcel Moolenaar 24273955d011SMarcel Moolenaar if (shellArgv) 24283955d011SMarcel Moolenaar free(UNCONST(shellArgv)); 24293955d011SMarcel Moolenaar 24303955d011SMarcel Moolenaar memset(&newShell, 0, sizeof(newShell)); 24313955d011SMarcel Moolenaar 24323955d011SMarcel Moolenaar /* 24333955d011SMarcel Moolenaar * Parse the specification by keyword 24343955d011SMarcel Moolenaar */ 24353955d011SMarcel Moolenaar words = brk_string(line, &argc, TRUE, &path); 24363955d011SMarcel Moolenaar if (words == NULL) { 24373955d011SMarcel Moolenaar Error("Unterminated quoted string [%s]", line); 24383955d011SMarcel Moolenaar return FAILURE; 24393955d011SMarcel Moolenaar } 24403955d011SMarcel Moolenaar shellArgv = path; 24413955d011SMarcel Moolenaar 24423955d011SMarcel Moolenaar for (path = NULL, argv = words; argc != 0; argc--, argv++) { 24433955d011SMarcel Moolenaar if (strncmp(*argv, "path=", 5) == 0) { 24443955d011SMarcel Moolenaar path = &argv[0][5]; 24453955d011SMarcel Moolenaar } else if (strncmp(*argv, "name=", 5) == 0) { 24463955d011SMarcel Moolenaar newShell.name = &argv[0][5]; 24473955d011SMarcel Moolenaar } else { 24483955d011SMarcel Moolenaar if (strncmp(*argv, "quiet=", 6) == 0) { 24493955d011SMarcel Moolenaar newShell.echoOff = &argv[0][6]; 24503955d011SMarcel Moolenaar } else if (strncmp(*argv, "echo=", 5) == 0) { 24513955d011SMarcel Moolenaar newShell.echoOn = &argv[0][5]; 24523955d011SMarcel Moolenaar } else if (strncmp(*argv, "filter=", 7) == 0) { 24533955d011SMarcel Moolenaar newShell.noPrint = &argv[0][7]; 24543955d011SMarcel Moolenaar newShell.noPLen = strlen(newShell.noPrint); 24553955d011SMarcel Moolenaar } else if (strncmp(*argv, "echoFlag=", 9) == 0) { 24563955d011SMarcel Moolenaar newShell.echo = &argv[0][9]; 24573955d011SMarcel Moolenaar } else if (strncmp(*argv, "errFlag=", 8) == 0) { 24583955d011SMarcel Moolenaar newShell.exit = &argv[0][8]; 24593955d011SMarcel Moolenaar } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { 24603955d011SMarcel Moolenaar char c = argv[0][10]; 24613955d011SMarcel Moolenaar newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && 24623955d011SMarcel Moolenaar (c != 'T') && (c != 't')); 24633955d011SMarcel Moolenaar } else if (strncmp(*argv, "newline=", 8) == 0) { 24643955d011SMarcel Moolenaar newShell.newline = &argv[0][8]; 24653955d011SMarcel Moolenaar } else if (strncmp(*argv, "check=", 6) == 0) { 24663955d011SMarcel Moolenaar newShell.errCheck = &argv[0][6]; 24673955d011SMarcel Moolenaar } else if (strncmp(*argv, "ignore=", 7) == 0) { 24683955d011SMarcel Moolenaar newShell.ignErr = &argv[0][7]; 24693955d011SMarcel Moolenaar } else if (strncmp(*argv, "errout=", 7) == 0) { 24703955d011SMarcel Moolenaar newShell.errOut = &argv[0][7]; 24713955d011SMarcel Moolenaar } else if (strncmp(*argv, "comment=", 8) == 0) { 24723955d011SMarcel Moolenaar newShell.commentChar = argv[0][8]; 24733955d011SMarcel Moolenaar } else { 24743955d011SMarcel Moolenaar Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", 24753955d011SMarcel Moolenaar *argv); 24763955d011SMarcel Moolenaar free(words); 24773955d011SMarcel Moolenaar return(FAILURE); 24783955d011SMarcel Moolenaar } 24793955d011SMarcel Moolenaar fullSpec = TRUE; 24803955d011SMarcel Moolenaar } 24813955d011SMarcel Moolenaar } 24823955d011SMarcel Moolenaar 24833955d011SMarcel Moolenaar if (path == NULL) { 24843955d011SMarcel Moolenaar /* 24853955d011SMarcel Moolenaar * If no path was given, the user wants one of the pre-defined shells, 24863955d011SMarcel Moolenaar * yes? So we find the one s/he wants with the help of JobMatchShell 24873955d011SMarcel Moolenaar * and set things up the right way. shellPath will be set up by 24883955d011SMarcel Moolenaar * Shell_Init. 24893955d011SMarcel Moolenaar */ 24903955d011SMarcel Moolenaar if (newShell.name == NULL) { 24913955d011SMarcel Moolenaar Parse_Error(PARSE_FATAL, "Neither path nor name specified"); 24923955d011SMarcel Moolenaar free(words); 24933955d011SMarcel Moolenaar return(FAILURE); 24943955d011SMarcel Moolenaar } else { 24953955d011SMarcel Moolenaar if ((sh = JobMatchShell(newShell.name)) == NULL) { 24963955d011SMarcel Moolenaar Parse_Error(PARSE_WARNING, "%s: No matching shell", 24973955d011SMarcel Moolenaar newShell.name); 24983955d011SMarcel Moolenaar free(words); 24993955d011SMarcel Moolenaar return(FAILURE); 25003955d011SMarcel Moolenaar } 25013955d011SMarcel Moolenaar commandShell = sh; 25023955d011SMarcel Moolenaar shellName = newShell.name; 25033955d011SMarcel Moolenaar if (shellPath) { 25043955d011SMarcel Moolenaar /* Shell_Init has already been called! Do it again. */ 25053955d011SMarcel Moolenaar free(UNCONST(shellPath)); 25063955d011SMarcel Moolenaar shellPath = NULL; 25073955d011SMarcel Moolenaar Shell_Init(); 25083955d011SMarcel Moolenaar } 25093955d011SMarcel Moolenaar } 25103955d011SMarcel Moolenaar } else { 25113955d011SMarcel Moolenaar /* 25123955d011SMarcel Moolenaar * The user provided a path. If s/he gave nothing else (fullSpec is 25133955d011SMarcel Moolenaar * FALSE), try and find a matching shell in the ones we know of. 25143955d011SMarcel Moolenaar * Else we just take the specification at its word and copy it 25153955d011SMarcel Moolenaar * to a new location. In either case, we need to record the 25163955d011SMarcel Moolenaar * path the user gave for the shell. 25173955d011SMarcel Moolenaar */ 25183955d011SMarcel Moolenaar shellPath = path; 25193955d011SMarcel Moolenaar path = strrchr(path, '/'); 25203955d011SMarcel Moolenaar if (path == NULL) { 25213955d011SMarcel Moolenaar path = UNCONST(shellPath); 25223955d011SMarcel Moolenaar } else { 25233955d011SMarcel Moolenaar path += 1; 25243955d011SMarcel Moolenaar } 25253955d011SMarcel Moolenaar if (newShell.name != NULL) { 25263955d011SMarcel Moolenaar shellName = newShell.name; 25273955d011SMarcel Moolenaar } else { 25283955d011SMarcel Moolenaar shellName = path; 25293955d011SMarcel Moolenaar } 25303955d011SMarcel Moolenaar if (!fullSpec) { 25313955d011SMarcel Moolenaar if ((sh = JobMatchShell(shellName)) == NULL) { 25323955d011SMarcel Moolenaar Parse_Error(PARSE_WARNING, "%s: No matching shell", 25333955d011SMarcel Moolenaar shellName); 25343955d011SMarcel Moolenaar free(words); 25353955d011SMarcel Moolenaar return(FAILURE); 25363955d011SMarcel Moolenaar } 25373955d011SMarcel Moolenaar commandShell = sh; 25383955d011SMarcel Moolenaar } else { 25393955d011SMarcel Moolenaar commandShell = bmake_malloc(sizeof(Shell)); 25403955d011SMarcel Moolenaar *commandShell = newShell; 25413955d011SMarcel Moolenaar } 254251ee2c1cSSimon J. Gerraty /* this will take care of shellErrFlag */ 254351ee2c1cSSimon J. Gerraty Shell_Init(); 25443955d011SMarcel Moolenaar } 25453955d011SMarcel Moolenaar 25463955d011SMarcel Moolenaar if (commandShell->echoOn && commandShell->echoOff) { 25473955d011SMarcel Moolenaar commandShell->hasEchoCtl = TRUE; 25483955d011SMarcel Moolenaar } 25493955d011SMarcel Moolenaar 25503955d011SMarcel Moolenaar if (!commandShell->hasErrCtl) { 25513955d011SMarcel Moolenaar if (commandShell->errCheck == NULL) { 25523955d011SMarcel Moolenaar commandShell->errCheck = ""; 25533955d011SMarcel Moolenaar } 25543955d011SMarcel Moolenaar if (commandShell->ignErr == NULL) { 25553955d011SMarcel Moolenaar commandShell->ignErr = "%s\n"; 25563955d011SMarcel Moolenaar } 25573955d011SMarcel Moolenaar } 25583955d011SMarcel Moolenaar 25593955d011SMarcel Moolenaar /* 25603955d011SMarcel Moolenaar * Do not free up the words themselves, since they might be in use by the 25613955d011SMarcel Moolenaar * shell specification. 25623955d011SMarcel Moolenaar */ 25633955d011SMarcel Moolenaar free(words); 25643955d011SMarcel Moolenaar return SUCCESS; 25653955d011SMarcel Moolenaar } 25663955d011SMarcel Moolenaar 25673955d011SMarcel Moolenaar /*- 25683955d011SMarcel Moolenaar *----------------------------------------------------------------------- 25693955d011SMarcel Moolenaar * JobInterrupt -- 25703955d011SMarcel Moolenaar * Handle the receipt of an interrupt. 25713955d011SMarcel Moolenaar * 25723955d011SMarcel Moolenaar * Input: 25733955d011SMarcel Moolenaar * runINTERRUPT Non-zero if commands for the .INTERRUPT target 25743955d011SMarcel Moolenaar * should be executed 25753955d011SMarcel Moolenaar * signo signal received 25763955d011SMarcel Moolenaar * 25773955d011SMarcel Moolenaar * Results: 25783955d011SMarcel Moolenaar * None 25793955d011SMarcel Moolenaar * 25803955d011SMarcel Moolenaar * Side Effects: 25813955d011SMarcel Moolenaar * All children are killed. Another job will be started if the 25823955d011SMarcel Moolenaar * .INTERRUPT target was given. 25833955d011SMarcel Moolenaar *----------------------------------------------------------------------- 25843955d011SMarcel Moolenaar */ 25853955d011SMarcel Moolenaar static void 25863955d011SMarcel Moolenaar JobInterrupt(int runINTERRUPT, int signo) 25873955d011SMarcel Moolenaar { 25883955d011SMarcel Moolenaar Job *job; /* job descriptor in that element */ 25893955d011SMarcel Moolenaar GNode *interrupt; /* the node describing the .INTERRUPT target */ 25903955d011SMarcel Moolenaar sigset_t mask; 25913955d011SMarcel Moolenaar GNode *gn; 25923955d011SMarcel Moolenaar 25933955d011SMarcel Moolenaar aborting = ABORT_INTERRUPT; 25943955d011SMarcel Moolenaar 25953955d011SMarcel Moolenaar JobSigLock(&mask); 25963955d011SMarcel Moolenaar 25973955d011SMarcel Moolenaar for (job = job_table; job < job_table_end; job++) { 25983955d011SMarcel Moolenaar if (job->job_state != JOB_ST_RUNNING) 25993955d011SMarcel Moolenaar continue; 26003955d011SMarcel Moolenaar 26013955d011SMarcel Moolenaar gn = job->node; 26023955d011SMarcel Moolenaar 26033955d011SMarcel Moolenaar if ((gn->type & (OP_JOIN|OP_PHONY)) == 0 && !Targ_Precious(gn)) { 26043955d011SMarcel Moolenaar char *file = (gn->path == NULL ? gn->name : gn->path); 26053955d011SMarcel Moolenaar if (!noExecute && eunlink(file) != -1) { 26063955d011SMarcel Moolenaar Error("*** %s removed", file); 26073955d011SMarcel Moolenaar } 26083955d011SMarcel Moolenaar } 26093955d011SMarcel Moolenaar if (job->pid) { 26103955d011SMarcel Moolenaar if (DEBUG(JOB)) { 26113955d011SMarcel Moolenaar (void)fprintf(debug_file, 26123955d011SMarcel Moolenaar "JobInterrupt passing signal %d to child %d.\n", 26133955d011SMarcel Moolenaar signo, job->pid); 26143955d011SMarcel Moolenaar } 26153955d011SMarcel Moolenaar KILLPG(job->pid, signo); 26163955d011SMarcel Moolenaar } 26173955d011SMarcel Moolenaar } 26183955d011SMarcel Moolenaar 26193955d011SMarcel Moolenaar JobSigUnlock(&mask); 26203955d011SMarcel Moolenaar 26213955d011SMarcel Moolenaar if (runINTERRUPT && !touchFlag) { 26223955d011SMarcel Moolenaar interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 26233955d011SMarcel Moolenaar if (interrupt != NULL) { 26243955d011SMarcel Moolenaar ignoreErrors = FALSE; 26253955d011SMarcel Moolenaar JobRun(interrupt); 26263955d011SMarcel Moolenaar } 26273955d011SMarcel Moolenaar } 26283955d011SMarcel Moolenaar Trace_Log(MAKEINTR, 0); 26293955d011SMarcel Moolenaar exit(signo); 26303955d011SMarcel Moolenaar } 26313955d011SMarcel Moolenaar 26323955d011SMarcel Moolenaar /* 26333955d011SMarcel Moolenaar *----------------------------------------------------------------------- 26343955d011SMarcel Moolenaar * Job_Finish -- 26353955d011SMarcel Moolenaar * Do final processing such as the running of the commands 26363955d011SMarcel Moolenaar * attached to the .END target. 26373955d011SMarcel Moolenaar * 26383955d011SMarcel Moolenaar * Results: 26393955d011SMarcel Moolenaar * Number of errors reported. 26403955d011SMarcel Moolenaar * 26413955d011SMarcel Moolenaar * Side Effects: 26423955d011SMarcel Moolenaar * None. 26433955d011SMarcel Moolenaar *----------------------------------------------------------------------- 26443955d011SMarcel Moolenaar */ 26453955d011SMarcel Moolenaar int 26463955d011SMarcel Moolenaar Job_Finish(void) 26473955d011SMarcel Moolenaar { 26483955d011SMarcel Moolenaar if (postCommands != NULL && 26493955d011SMarcel Moolenaar (!Lst_IsEmpty(postCommands->commands) || 26503955d011SMarcel Moolenaar !Lst_IsEmpty(postCommands->children))) { 26513955d011SMarcel Moolenaar if (errors) { 26523955d011SMarcel Moolenaar Error("Errors reported so .END ignored"); 26533955d011SMarcel Moolenaar } else { 26543955d011SMarcel Moolenaar JobRun(postCommands); 26553955d011SMarcel Moolenaar } 26563955d011SMarcel Moolenaar } 26573955d011SMarcel Moolenaar return(errors); 26583955d011SMarcel Moolenaar } 26593955d011SMarcel Moolenaar 26603955d011SMarcel Moolenaar /*- 26613955d011SMarcel Moolenaar *----------------------------------------------------------------------- 26623955d011SMarcel Moolenaar * Job_End -- 26633955d011SMarcel Moolenaar * Cleanup any memory used by the jobs module 26643955d011SMarcel Moolenaar * 26653955d011SMarcel Moolenaar * Results: 26663955d011SMarcel Moolenaar * None. 26673955d011SMarcel Moolenaar * 26683955d011SMarcel Moolenaar * Side Effects: 26693955d011SMarcel Moolenaar * Memory is freed 26703955d011SMarcel Moolenaar *----------------------------------------------------------------------- 26713955d011SMarcel Moolenaar */ 26723955d011SMarcel Moolenaar void 26733955d011SMarcel Moolenaar Job_End(void) 26743955d011SMarcel Moolenaar { 26753955d011SMarcel Moolenaar #ifdef CLEANUP 26763955d011SMarcel Moolenaar if (shellArgv) 26773955d011SMarcel Moolenaar free(shellArgv); 26783955d011SMarcel Moolenaar #endif 26793955d011SMarcel Moolenaar } 26803955d011SMarcel Moolenaar 26813955d011SMarcel Moolenaar /*- 26823955d011SMarcel Moolenaar *----------------------------------------------------------------------- 26833955d011SMarcel Moolenaar * Job_Wait -- 26843955d011SMarcel Moolenaar * Waits for all running jobs to finish and returns. Sets 'aborting' 26853955d011SMarcel Moolenaar * to ABORT_WAIT to prevent other jobs from starting. 26863955d011SMarcel Moolenaar * 26873955d011SMarcel Moolenaar * Results: 26883955d011SMarcel Moolenaar * None. 26893955d011SMarcel Moolenaar * 26903955d011SMarcel Moolenaar * Side Effects: 26913955d011SMarcel Moolenaar * Currently running jobs finish. 26923955d011SMarcel Moolenaar * 26933955d011SMarcel Moolenaar *----------------------------------------------------------------------- 26943955d011SMarcel Moolenaar */ 26953955d011SMarcel Moolenaar void 26963955d011SMarcel Moolenaar Job_Wait(void) 26973955d011SMarcel Moolenaar { 26983955d011SMarcel Moolenaar aborting = ABORT_WAIT; 26993955d011SMarcel Moolenaar while (jobTokensRunning != 0) { 27003955d011SMarcel Moolenaar Job_CatchOutput(); 27013955d011SMarcel Moolenaar } 27023955d011SMarcel Moolenaar aborting = 0; 27033955d011SMarcel Moolenaar } 27043955d011SMarcel Moolenaar 27053955d011SMarcel Moolenaar /*- 27063955d011SMarcel Moolenaar *----------------------------------------------------------------------- 27073955d011SMarcel Moolenaar * Job_AbortAll -- 27083955d011SMarcel Moolenaar * Abort all currently running jobs without handling output or anything. 27093955d011SMarcel Moolenaar * This function is to be called only in the event of a major 27103955d011SMarcel Moolenaar * error. Most definitely NOT to be called from JobInterrupt. 27113955d011SMarcel Moolenaar * 27123955d011SMarcel Moolenaar * Results: 27133955d011SMarcel Moolenaar * None 27143955d011SMarcel Moolenaar * 27153955d011SMarcel Moolenaar * Side Effects: 27163955d011SMarcel Moolenaar * All children are killed, not just the firstborn 27173955d011SMarcel Moolenaar *----------------------------------------------------------------------- 27183955d011SMarcel Moolenaar */ 27193955d011SMarcel Moolenaar void 27203955d011SMarcel Moolenaar Job_AbortAll(void) 27213955d011SMarcel Moolenaar { 27223955d011SMarcel Moolenaar Job *job; /* the job descriptor in that element */ 27233955d011SMarcel Moolenaar WAIT_T foo; 27243955d011SMarcel Moolenaar 27253955d011SMarcel Moolenaar aborting = ABORT_ERROR; 27263955d011SMarcel Moolenaar 27273955d011SMarcel Moolenaar if (jobTokensRunning) { 27283955d011SMarcel Moolenaar for (job = job_table; job < job_table_end; job++) { 27293955d011SMarcel Moolenaar if (job->job_state != JOB_ST_RUNNING) 27303955d011SMarcel Moolenaar continue; 27313955d011SMarcel Moolenaar /* 27323955d011SMarcel Moolenaar * kill the child process with increasingly drastic signals to make 27333955d011SMarcel Moolenaar * darn sure it's dead. 27343955d011SMarcel Moolenaar */ 27353955d011SMarcel Moolenaar KILLPG(job->pid, SIGINT); 27363955d011SMarcel Moolenaar KILLPG(job->pid, SIGKILL); 27373955d011SMarcel Moolenaar } 27383955d011SMarcel Moolenaar } 27393955d011SMarcel Moolenaar 27403955d011SMarcel Moolenaar /* 27413955d011SMarcel Moolenaar * Catch as many children as want to report in at first, then give up 27423955d011SMarcel Moolenaar */ 27433955d011SMarcel Moolenaar while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) 27443955d011SMarcel Moolenaar continue; 27453955d011SMarcel Moolenaar } 27463955d011SMarcel Moolenaar 27473955d011SMarcel Moolenaar 27483955d011SMarcel Moolenaar /*- 27493955d011SMarcel Moolenaar *----------------------------------------------------------------------- 27503955d011SMarcel Moolenaar * JobRestartJobs -- 27513955d011SMarcel Moolenaar * Tries to restart stopped jobs if there are slots available. 27523955d011SMarcel Moolenaar * Called in process context in response to a SIGCONT. 27533955d011SMarcel Moolenaar * 27543955d011SMarcel Moolenaar * Results: 27553955d011SMarcel Moolenaar * None. 27563955d011SMarcel Moolenaar * 27573955d011SMarcel Moolenaar * Side Effects: 27583955d011SMarcel Moolenaar * Resumes jobs. 27593955d011SMarcel Moolenaar * 27603955d011SMarcel Moolenaar *----------------------------------------------------------------------- 27613955d011SMarcel Moolenaar */ 27623955d011SMarcel Moolenaar static void 27633955d011SMarcel Moolenaar JobRestartJobs(void) 27643955d011SMarcel Moolenaar { 27653955d011SMarcel Moolenaar Job *job; 27663955d011SMarcel Moolenaar 27673955d011SMarcel Moolenaar for (job = job_table; job < job_table_end; job++) { 27683955d011SMarcel Moolenaar if (job->job_state == JOB_ST_RUNNING && 27693955d011SMarcel Moolenaar (make_suspended || job->job_suspended)) { 27703955d011SMarcel Moolenaar if (DEBUG(JOB)) { 27713955d011SMarcel Moolenaar (void)fprintf(debug_file, "Restarting stopped job pid %d.\n", 27723955d011SMarcel Moolenaar job->pid); 27733955d011SMarcel Moolenaar } 27743955d011SMarcel Moolenaar if (job->job_suspended) { 27753955d011SMarcel Moolenaar (void)printf("*** [%s] Continued\n", job->node->name); 27763955d011SMarcel Moolenaar (void)fflush(stdout); 27773955d011SMarcel Moolenaar } 27783955d011SMarcel Moolenaar job->job_suspended = 0; 27793955d011SMarcel Moolenaar if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) { 27803955d011SMarcel Moolenaar fprintf(debug_file, "Failed to send SIGCONT to %d\n", job->pid); 27813955d011SMarcel Moolenaar } 27823955d011SMarcel Moolenaar } 27833955d011SMarcel Moolenaar if (job->job_state == JOB_ST_FINISHED) 27843955d011SMarcel Moolenaar /* Job exit deferred after calling waitpid() in a signal handler */ 27853955d011SMarcel Moolenaar JobFinish(job, job->exit_status); 27863955d011SMarcel Moolenaar } 27873955d011SMarcel Moolenaar make_suspended = 0; 27883955d011SMarcel Moolenaar } 27893955d011SMarcel Moolenaar 27903955d011SMarcel Moolenaar static void 27913955d011SMarcel Moolenaar watchfd(Job *job) 27923955d011SMarcel Moolenaar { 27933955d011SMarcel Moolenaar if (job->inPollfd != NULL) 27943955d011SMarcel Moolenaar Punt("Watching watched job"); 27953955d011SMarcel Moolenaar 27963955d011SMarcel Moolenaar fds[nfds].fd = job->inPipe; 27973955d011SMarcel Moolenaar fds[nfds].events = POLLIN; 27983955d011SMarcel Moolenaar jobfds[nfds] = job; 27993955d011SMarcel Moolenaar job->inPollfd = &fds[nfds]; 28003955d011SMarcel Moolenaar nfds++; 28013955d011SMarcel Moolenaar } 28023955d011SMarcel Moolenaar 28033955d011SMarcel Moolenaar static void 28043955d011SMarcel Moolenaar clearfd(Job *job) 28053955d011SMarcel Moolenaar { 28063955d011SMarcel Moolenaar int i; 28073955d011SMarcel Moolenaar if (job->inPollfd == NULL) 28083955d011SMarcel Moolenaar Punt("Unwatching unwatched job"); 28093955d011SMarcel Moolenaar i = job->inPollfd - fds; 28103955d011SMarcel Moolenaar nfds--; 28113955d011SMarcel Moolenaar /* 28123955d011SMarcel Moolenaar * Move last job in table into hole made by dead job. 28133955d011SMarcel Moolenaar */ 28143955d011SMarcel Moolenaar if (nfds != i) { 28153955d011SMarcel Moolenaar fds[i] = fds[nfds]; 28163955d011SMarcel Moolenaar jobfds[i] = jobfds[nfds]; 28173955d011SMarcel Moolenaar jobfds[i]->inPollfd = &fds[i]; 28183955d011SMarcel Moolenaar } 28193955d011SMarcel Moolenaar job->inPollfd = NULL; 28203955d011SMarcel Moolenaar } 28213955d011SMarcel Moolenaar 28223955d011SMarcel Moolenaar static int 28233955d011SMarcel Moolenaar readyfd(Job *job) 28243955d011SMarcel Moolenaar { 28253955d011SMarcel Moolenaar if (job->inPollfd == NULL) 28263955d011SMarcel Moolenaar Punt("Polling unwatched job"); 28273955d011SMarcel Moolenaar return (job->inPollfd->revents & POLLIN) != 0; 28283955d011SMarcel Moolenaar } 28293955d011SMarcel Moolenaar 28303955d011SMarcel Moolenaar /*- 28313955d011SMarcel Moolenaar *----------------------------------------------------------------------- 28323955d011SMarcel Moolenaar * JobTokenAdd -- 28333955d011SMarcel Moolenaar * Put a token into the job pipe so that some make process can start 28343955d011SMarcel Moolenaar * another job. 28353955d011SMarcel Moolenaar * 28363955d011SMarcel Moolenaar * Side Effects: 28373955d011SMarcel Moolenaar * Allows more build jobs to be spawned somewhere. 28383955d011SMarcel Moolenaar * 28393955d011SMarcel Moolenaar *----------------------------------------------------------------------- 28403955d011SMarcel Moolenaar */ 28413955d011SMarcel Moolenaar 28423955d011SMarcel Moolenaar static void 28433955d011SMarcel Moolenaar JobTokenAdd(void) 28443955d011SMarcel Moolenaar { 28453955d011SMarcel Moolenaar char tok = JOB_TOKENS[aborting], tok1; 28463955d011SMarcel Moolenaar 28472d395cb5SSimon J. Gerraty if (!Job_error_token && aborting == ABORT_ERROR) { 28482d395cb5SSimon J. Gerraty if (jobTokensRunning == 0) 28492d395cb5SSimon J. Gerraty return; 28502d395cb5SSimon J. Gerraty tok = '+'; /* no error token */ 28512d395cb5SSimon J. Gerraty } 28522d395cb5SSimon J. Gerraty 28533955d011SMarcel Moolenaar /* If we are depositing an error token flush everything else */ 28543955d011SMarcel Moolenaar while (tok != '+' && read(tokenWaitJob.inPipe, &tok1, 1) == 1) 28553955d011SMarcel Moolenaar continue; 28563955d011SMarcel Moolenaar 28573955d011SMarcel Moolenaar if (DEBUG(JOB)) 28583955d011SMarcel Moolenaar fprintf(debug_file, "(%d) aborting %d, deposit token %c\n", 28592d395cb5SSimon J. Gerraty getpid(), aborting, tok); 28603cbdda60SSimon J. Gerraty while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN) 28613cbdda60SSimon J. Gerraty continue; 28623955d011SMarcel Moolenaar } 28633955d011SMarcel Moolenaar 28643955d011SMarcel Moolenaar /*- 28653955d011SMarcel Moolenaar *----------------------------------------------------------------------- 28663955d011SMarcel Moolenaar * Job_ServerStartTokenAdd -- 28673955d011SMarcel Moolenaar * Prep the job token pipe in the root make process. 28683955d011SMarcel Moolenaar * 28693955d011SMarcel Moolenaar *----------------------------------------------------------------------- 28703955d011SMarcel Moolenaar */ 28713955d011SMarcel Moolenaar 28723955d011SMarcel Moolenaar void 28733955d011SMarcel Moolenaar Job_ServerStart(int max_tokens, int jp_0, int jp_1) 28743955d011SMarcel Moolenaar { 28753955d011SMarcel Moolenaar int i; 28763955d011SMarcel Moolenaar char jobarg[64]; 28773955d011SMarcel Moolenaar 28783955d011SMarcel Moolenaar if (jp_0 >= 0 && jp_1 >= 0) { 28793955d011SMarcel Moolenaar /* Pipe passed in from parent */ 28803955d011SMarcel Moolenaar tokenWaitJob.inPipe = jp_0; 28813955d011SMarcel Moolenaar tokenWaitJob.outPipe = jp_1; 288274d2e02bSSimon J. Gerraty (void)fcntl(jp_0, F_SETFD, 1); 288374d2e02bSSimon J. Gerraty (void)fcntl(jp_1, F_SETFD, 1); 28843955d011SMarcel Moolenaar return; 28853955d011SMarcel Moolenaar } 28863955d011SMarcel Moolenaar 28873955d011SMarcel Moolenaar JobCreatePipe(&tokenWaitJob, 15); 28883955d011SMarcel Moolenaar 28893955d011SMarcel Moolenaar snprintf(jobarg, sizeof(jobarg), "%d,%d", 28903955d011SMarcel Moolenaar tokenWaitJob.inPipe, tokenWaitJob.outPipe); 28913955d011SMarcel Moolenaar 28923955d011SMarcel Moolenaar Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 28933955d011SMarcel Moolenaar Var_Append(MAKEFLAGS, jobarg, VAR_GLOBAL); 28943955d011SMarcel Moolenaar 28953955d011SMarcel Moolenaar /* 28963955d011SMarcel Moolenaar * Preload the job pipe with one token per job, save the one 28973955d011SMarcel Moolenaar * "extra" token for the primary job. 28983955d011SMarcel Moolenaar * 28993955d011SMarcel Moolenaar * XXX should clip maxJobs against PIPE_BUF -- if max_tokens is 29003955d011SMarcel Moolenaar * larger than the write buffer size of the pipe, we will 29013955d011SMarcel Moolenaar * deadlock here. 29023955d011SMarcel Moolenaar */ 29033955d011SMarcel Moolenaar for (i = 1; i < max_tokens; i++) 29043955d011SMarcel Moolenaar JobTokenAdd(); 29053955d011SMarcel Moolenaar } 29063955d011SMarcel Moolenaar 29073955d011SMarcel Moolenaar /*- 29083955d011SMarcel Moolenaar *----------------------------------------------------------------------- 29093955d011SMarcel Moolenaar * Job_TokenReturn -- 29103955d011SMarcel Moolenaar * Return a withdrawn token to the pool. 29113955d011SMarcel Moolenaar * 29123955d011SMarcel Moolenaar *----------------------------------------------------------------------- 29133955d011SMarcel Moolenaar */ 29143955d011SMarcel Moolenaar 29153955d011SMarcel Moolenaar void 29163955d011SMarcel Moolenaar Job_TokenReturn(void) 29173955d011SMarcel Moolenaar { 29183955d011SMarcel Moolenaar jobTokensRunning--; 29193955d011SMarcel Moolenaar if (jobTokensRunning < 0) 29203955d011SMarcel Moolenaar Punt("token botch"); 29213955d011SMarcel Moolenaar if (jobTokensRunning || JOB_TOKENS[aborting] != '+') 29223955d011SMarcel Moolenaar JobTokenAdd(); 29233955d011SMarcel Moolenaar } 29243955d011SMarcel Moolenaar 29253955d011SMarcel Moolenaar /*- 29263955d011SMarcel Moolenaar *----------------------------------------------------------------------- 29273955d011SMarcel Moolenaar * Job_TokenWithdraw -- 29283955d011SMarcel Moolenaar * Attempt to withdraw a token from the pool. 29293955d011SMarcel Moolenaar * 29303955d011SMarcel Moolenaar * Results: 29313955d011SMarcel Moolenaar * Returns TRUE if a token was withdrawn, and FALSE if the pool 29323955d011SMarcel Moolenaar * is currently empty. 29333955d011SMarcel Moolenaar * 29343955d011SMarcel Moolenaar * Side Effects: 29353955d011SMarcel Moolenaar * If pool is empty, set wantToken so that we wake up 29363955d011SMarcel Moolenaar * when a token is released. 29373955d011SMarcel Moolenaar * 29383955d011SMarcel Moolenaar *----------------------------------------------------------------------- 29393955d011SMarcel Moolenaar */ 29403955d011SMarcel Moolenaar 29413955d011SMarcel Moolenaar 29423955d011SMarcel Moolenaar Boolean 29433955d011SMarcel Moolenaar Job_TokenWithdraw(void) 29443955d011SMarcel Moolenaar { 29453955d011SMarcel Moolenaar char tok, tok1; 29463955d011SMarcel Moolenaar int count; 29473955d011SMarcel Moolenaar 29483955d011SMarcel Moolenaar wantToken = 0; 29493955d011SMarcel Moolenaar if (DEBUG(JOB)) 29503955d011SMarcel Moolenaar fprintf(debug_file, "Job_TokenWithdraw(%d): aborting %d, running %d\n", 29513955d011SMarcel Moolenaar getpid(), aborting, jobTokensRunning); 29523955d011SMarcel Moolenaar 29533955d011SMarcel Moolenaar if (aborting || (jobTokensRunning >= maxJobs)) 29543955d011SMarcel Moolenaar return FALSE; 29553955d011SMarcel Moolenaar 29563955d011SMarcel Moolenaar count = read(tokenWaitJob.inPipe, &tok, 1); 29573955d011SMarcel Moolenaar if (count == 0) 29583955d011SMarcel Moolenaar Fatal("eof on job pipe!"); 29593955d011SMarcel Moolenaar if (count < 0 && jobTokensRunning != 0) { 29603955d011SMarcel Moolenaar if (errno != EAGAIN) { 29613955d011SMarcel Moolenaar Fatal("job pipe read: %s", strerror(errno)); 29623955d011SMarcel Moolenaar } 29633955d011SMarcel Moolenaar if (DEBUG(JOB)) 29643955d011SMarcel Moolenaar fprintf(debug_file, "(%d) blocked for token\n", getpid()); 29653955d011SMarcel Moolenaar wantToken = 1; 29663955d011SMarcel Moolenaar return FALSE; 29673955d011SMarcel Moolenaar } 29683955d011SMarcel Moolenaar 29693955d011SMarcel Moolenaar if (count == 1 && tok != '+') { 29703955d011SMarcel Moolenaar /* make being abvorted - remove any other job tokens */ 29713955d011SMarcel Moolenaar if (DEBUG(JOB)) 29723955d011SMarcel Moolenaar fprintf(debug_file, "(%d) aborted by token %c\n", getpid(), tok); 29733955d011SMarcel Moolenaar while (read(tokenWaitJob.inPipe, &tok1, 1) == 1) 29743955d011SMarcel Moolenaar continue; 29753955d011SMarcel Moolenaar /* And put the stopper back */ 29763cbdda60SSimon J. Gerraty while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN) 29773cbdda60SSimon J. Gerraty continue; 29783955d011SMarcel Moolenaar Fatal("A failure has been detected in another branch of the parallel make"); 29793955d011SMarcel Moolenaar } 29803955d011SMarcel Moolenaar 29813955d011SMarcel Moolenaar if (count == 1 && jobTokensRunning == 0) 29823955d011SMarcel Moolenaar /* We didn't want the token really */ 29833cbdda60SSimon J. Gerraty while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN) 29843cbdda60SSimon J. Gerraty continue; 29853955d011SMarcel Moolenaar 29863955d011SMarcel Moolenaar jobTokensRunning++; 29873955d011SMarcel Moolenaar if (DEBUG(JOB)) 29883955d011SMarcel Moolenaar fprintf(debug_file, "(%d) withdrew token\n", getpid()); 29893955d011SMarcel Moolenaar return TRUE; 29903955d011SMarcel Moolenaar } 29913955d011SMarcel Moolenaar 29921748de26SSimon J. Gerraty /*- 29931748de26SSimon J. Gerraty *----------------------------------------------------------------------- 29941748de26SSimon J. Gerraty * Job_RunTarget -- 29951748de26SSimon J. Gerraty * Run the named target if found. If a filename is specified, then 29961748de26SSimon J. Gerraty * set that to the sources. 29971748de26SSimon J. Gerraty * 29981748de26SSimon J. Gerraty * Results: 29991748de26SSimon J. Gerraty * None 30001748de26SSimon J. Gerraty * 30011748de26SSimon J. Gerraty * Side Effects: 30021748de26SSimon J. Gerraty * exits if the target fails. 30031748de26SSimon J. Gerraty * 30041748de26SSimon J. Gerraty *----------------------------------------------------------------------- 30051748de26SSimon J. Gerraty */ 30061748de26SSimon J. Gerraty Boolean 30071748de26SSimon J. Gerraty Job_RunTarget(const char *target, const char *fname) { 30081748de26SSimon J. Gerraty GNode *gn = Targ_FindNode(target, TARG_NOCREATE); 30091748de26SSimon J. Gerraty 30101748de26SSimon J. Gerraty if (gn == NULL) 30111748de26SSimon J. Gerraty return FALSE; 30121748de26SSimon J. Gerraty 30131748de26SSimon J. Gerraty if (fname) 30141748de26SSimon J. Gerraty Var_Set(ALLSRC, fname, gn, 0); 30151748de26SSimon J. Gerraty 30161748de26SSimon J. Gerraty JobRun(gn); 30171748de26SSimon J. Gerraty if (gn->made == ERROR) { 30181748de26SSimon J. Gerraty PrintOnError(gn, "\n\nStop."); 30191748de26SSimon J. Gerraty exit(1); 30201748de26SSimon J. Gerraty } 30211748de26SSimon J. Gerraty return TRUE; 30221748de26SSimon J. Gerraty } 30231748de26SSimon J. Gerraty 30243955d011SMarcel Moolenaar #ifdef USE_SELECT 30253955d011SMarcel Moolenaar int 30263955d011SMarcel Moolenaar emul_poll(struct pollfd *fd, int nfd, int timeout) 30273955d011SMarcel Moolenaar { 30283955d011SMarcel Moolenaar fd_set rfds, wfds; 30293955d011SMarcel Moolenaar int i, maxfd, nselect, npoll; 30303955d011SMarcel Moolenaar struct timeval tv, *tvp; 30313955d011SMarcel Moolenaar long usecs; 30323955d011SMarcel Moolenaar 30333955d011SMarcel Moolenaar FD_ZERO(&rfds); 30343955d011SMarcel Moolenaar FD_ZERO(&wfds); 30353955d011SMarcel Moolenaar 30363955d011SMarcel Moolenaar maxfd = -1; 30373955d011SMarcel Moolenaar for (i = 0; i < nfd; i++) { 30383955d011SMarcel Moolenaar fd[i].revents = 0; 30393955d011SMarcel Moolenaar 30403955d011SMarcel Moolenaar if (fd[i].events & POLLIN) 30413955d011SMarcel Moolenaar FD_SET(fd[i].fd, &rfds); 30423955d011SMarcel Moolenaar 30433955d011SMarcel Moolenaar if (fd[i].events & POLLOUT) 30443955d011SMarcel Moolenaar FD_SET(fd[i].fd, &wfds); 30453955d011SMarcel Moolenaar 30463955d011SMarcel Moolenaar if (fd[i].fd > maxfd) 30473955d011SMarcel Moolenaar maxfd = fd[i].fd; 30483955d011SMarcel Moolenaar } 30493955d011SMarcel Moolenaar 30503955d011SMarcel Moolenaar if (maxfd >= FD_SETSIZE) { 30513955d011SMarcel Moolenaar Punt("Ran out of fd_set slots; " 30523955d011SMarcel Moolenaar "recompile with a larger FD_SETSIZE."); 30533955d011SMarcel Moolenaar } 30543955d011SMarcel Moolenaar 30553955d011SMarcel Moolenaar if (timeout < 0) { 30563955d011SMarcel Moolenaar tvp = NULL; 30573955d011SMarcel Moolenaar } else { 30583955d011SMarcel Moolenaar usecs = timeout * 1000; 30593955d011SMarcel Moolenaar tv.tv_sec = usecs / 1000000; 30603955d011SMarcel Moolenaar tv.tv_usec = usecs % 1000000; 30613955d011SMarcel Moolenaar tvp = &tv; 30623955d011SMarcel Moolenaar } 30633955d011SMarcel Moolenaar 30643955d011SMarcel Moolenaar nselect = select(maxfd + 1, &rfds, &wfds, 0, tvp); 30653955d011SMarcel Moolenaar 30663955d011SMarcel Moolenaar if (nselect <= 0) 30673955d011SMarcel Moolenaar return nselect; 30683955d011SMarcel Moolenaar 30693955d011SMarcel Moolenaar npoll = 0; 30703955d011SMarcel Moolenaar for (i = 0; i < nfd; i++) { 30713955d011SMarcel Moolenaar if (FD_ISSET(fd[i].fd, &rfds)) 30723955d011SMarcel Moolenaar fd[i].revents |= POLLIN; 30733955d011SMarcel Moolenaar 30743955d011SMarcel Moolenaar if (FD_ISSET(fd[i].fd, &wfds)) 30753955d011SMarcel Moolenaar fd[i].revents |= POLLOUT; 30763955d011SMarcel Moolenaar 30773955d011SMarcel Moolenaar if (fd[i].revents) 30783955d011SMarcel Moolenaar npoll++; 30793955d011SMarcel Moolenaar } 30803955d011SMarcel Moolenaar 30813955d011SMarcel Moolenaar return npoll; 30823955d011SMarcel Moolenaar } 30833955d011SMarcel Moolenaar #endif /* USE_SELECT */ 3084