summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/make/PSD.doc/tutorial.ms52
-rw-r--r--usr.bin/make/arch.c22
-rw-r--r--usr.bin/make/compat.c285
-rw-r--r--usr.bin/make/defines.h3
-rw-r--r--usr.bin/make/engine.c363
-rw-r--r--usr.bin/make/engine.h12
-rw-r--r--usr.bin/make/error.c16
-rw-r--r--usr.bin/make/gnode.h4
-rw-r--r--usr.bin/make/job.c1035
-rw-r--r--usr.bin/make/job.h3
-rw-r--r--usr.bin/make/main.c6
-rw-r--r--usr.bin/make/make.110
-rw-r--r--usr.bin/make/make.c11
-rw-r--r--usr.bin/make/suff.c3
-rw-r--r--usr.bin/make/targ.c48
-rw-r--r--usr.bin/make/targ.h4
16 files changed, 744 insertions, 1133 deletions
diff --git a/usr.bin/make/PSD.doc/tutorial.ms b/usr.bin/make/PSD.doc/tutorial.ms
index 7f3a7c0ab2e..e24750daf33 100644
--- a/usr.bin/make/PSD.doc/tutorial.ms
+++ b/usr.bin/make/PSD.doc/tutorial.ms
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tutorial.ms,v 1.12 2007/09/23 09:49:18 espie Exp $
+.\" $OpenBSD: tutorial.ms,v 1.13 2007/11/02 17:27:24 espie Exp $
.\" $NetBSD: tutorial.ms,v 1.3 1996/03/06 00:15:31 christos Exp $
.\" Copyright (c) 1988, 1989 by Adam de Boor
.\" Copyright (c) 1989 by Berkeley Softworks
@@ -1765,56 +1765,6 @@ SYSTEM = <command.mk>
#include $(SYSTEM)
.DE
won't work.
-.xH 2 Saving Commands
-.No
-.LP
-.Ix 0 def ...
-There may come a time when you will want to save certain commands to
-be executed when everything else is done. For instance: you're
-making several different libraries at one time and you want to create the
-members in parallel. Problem is,
-.CW ranlib
-is another one of those programs that can't be run more than once in
-the same directory at the same time (each one creates a file called
-.CW __.SYMDEF
-into which it stuffs information for the linker to use. Two of them
-running at once will overwrite each other's file and the result will
-be garbage for both parties). You might want a way to save the ranlib
-commands til the end so they can be run one after the other, thus
-keeping them from trashing each other's file. Make allows you to do
-this by inserting an ellipsis (``.\|.\|.'') as a command between
-commands to be run at once and those to be run later.
-.LP
-So for the
-.CW ranlib
-case above, you might do this:
-.Rd 5
-.DS
-lib1.a : $(LIB1OBJS)
- rm -f $(.TARGET)
- ar cr $(.TARGET) $(.ALLSRC)
- ...
- ranlib $(.TARGET)
-
-lib2.a : $(LIB2OBJS)
- rm -f $(.TARGET)
- ar cr $(.TARGET) $(.ALLSRC)
- ...
- ranlib $(.TARGET)
-.DE
-.Ix 0 ref variable local .TARGET
-.Ix 0 ref variable local .ALLSRC
-This would save both
-.DS
-ranlib $(.TARGET)
-.DE
-commands until the end, when they would run one after the other
-(using the correct value for the
-.CW .TARGET
-variable, of course).
-.LP
-Commands saved in this manner are only executed if Make manages to
-re-create everything without an error.
.xH 2 Target Attributes
.LP
Make allows you to give attributes to targets by means of special
diff --git a/usr.bin/make/arch.c b/usr.bin/make/arch.c
index 7306b691df5..8a5b60e9c0e 100644
--- a/usr.bin/make/arch.c
+++ b/usr.bin/make/arch.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: arch.c,v 1.71 2007/09/17 12:50:59 espie Exp $ */
+/* $OpenBSD: arch.c,v 1.72 2007/11/02 17:27:24 espie Exp $ */
/* $NetBSD: arch.c,v 1.17 1996/11/06 17:58:59 christos Exp $ */
/*
@@ -934,26 +934,10 @@ Arch_MemMTime(GNode *gn)
return gn->mtime;
}
-/* If the system can handle the -L flag when linking (or we cannot find
- * the library), we assume that the user has placed the .LIBRARIES variable
- * in the final linking command (or the linker will know where to find it)
- * and set the TARGET variable for this node to be the node's name. Otherwise,
- * we set the TARGET variable to be the full path of the library,
- * as returned by Dir_FindFile.
- */
+/* we assume the system knows how to find libraries */
void
-Arch_FindLib(GNode *gn, Lst path)
+Arch_FindLib(GNode *gn, Lst path UNUSED)
{
- char *libName; /* file name for archive */
- size_t length = strlen(gn->name) + 6 - 2;
-
- libName = emalloc(length);
- snprintf(libName, length, "lib%s.a", &gn->name[2]);
-
- gn->path = Dir_FindFile(libName, path);
-
- free(libName);
-
Varq_Set(TARGET_INDEX, gn->name, gn);
}
diff --git a/usr.bin/make/compat.c b/usr.bin/make/compat.c
index bd5c6d841a1..8fc82f13a6f 100644
--- a/usr.bin/make/compat.c
+++ b/usr.bin/make/compat.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: compat.c,v 1.62 2007/10/27 08:44:12 espie Exp $ */
+/* $OpenBSD: compat.c,v 1.63 2007/11/02 17:27:24 espie Exp $ */
/* $NetBSD: compat.c,v 1.14 1996/11/06 17:59:01 christos Exp $ */
/*
@@ -36,18 +36,10 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <ctype.h>
-#include <errno.h>
#include <limits.h>
#include <signal.h>
-#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include "config.h"
#include "defines.h"
#include "dir.h"
@@ -57,272 +49,12 @@
#include "var.h"
#include "targ.h"
#include "error.h"
-#include "str.h"
#include "extern.h"
-#include "memory.h"
#include "gnode.h"
-#include "make.h"
#include "timestamp.h"
#include "lst.h"
-#include "pathnames.h"
-static void CompatInterrupt(int);
-static int CompatRunCommand(LstNode, void *);
static void CompatMake(void *, void *);
-static int run_gnode(GNode *);
-static void setup_meta(void);
-static char **recheck_command_for_shell(char **);
-static void run_command(const char *, bool);
-
-static volatile sig_atomic_t interrupted;
-
-static void
-CompatInterrupt(int signo)
-{
- if (interrupted != SIGINT)
- interrupted = signo;
-}
-
-/* The following array is used to make a fast determination of which
- * characters are interpreted specially by the shell. If a command
- * contains any of these characters, it is executed by the shell, not
- * directly by us. */
-static char meta[256];
-
-static void
-setup_meta(void)
-{
- char *p;
-
- for (p = "#=|^(){};&<>*?[]:$`\\\n"; *p != '\0'; p++)
- meta[(unsigned char) *p] = 1;
- /* The null character serves as a sentinel in the string. */
- meta[0] = 1;
-}
-
-static char **
-recheck_command_for_shell(char **av)
-{
- char *runsh[] = {
- "alias", "cd", "eval", "exit", "read", "set", "ulimit",
- "unalias", "unset", "wait", "umask", NULL
- };
-
- char **p;
-
- /* optimization: if exec cmd, we avoid the intermediate shell */
- if (strcmp(av[0], "exec") == 0)
- av++;
-
- for (p = runsh; *p; p++)
- if (strcmp(av[0], *p) == 0)
- return NULL;
-
- return av;
-}
-
-static void
-run_command(const char *cmd, bool errCheck)
-{
- const char *p;
- char *shargv[4];
- char **todo;
-
- shargv[0] = _PATH_BSHELL;
-
- shargv[1] = errCheck ? "-ec" : "-c";
- shargv[2] = (char *)cmd;
- shargv[3] = NULL;
-
- todo = shargv;
-
-
- /* Search for meta characters in the command. If there are no meta
- * characters, there's no need to execute a shell to execute the
- * command. */
- for (p = cmd; !meta[(unsigned char)*p]; p++)
- continue;
- if (*p == '\0') {
- char *bp;
- char **av;
- int argc;
- /* No meta-characters, so probably no need to exec a shell.
- * Break the command into words to form an argument vector
- * we can execute. */
- av = brk_string(cmd, &argc, &bp);
- av = recheck_command_for_shell(av);
- if (av != NULL)
- todo = av;
- }
- execvp(todo[0], todo);
-
- if (errno == ENOENT)
- fprintf(stderr, "%s: not found\n", todo[0]);
- else
- perror(todo[0]);
- _exit(1);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * CompatRunCommand --
- * Execute the next command for a target. If the command returns an
- * error, the node's made field is set to ERROR and creation stops.
- *
- * Results:
- * 0 in case of error, 1 if ok.
- *
- * Side Effects:
- * The node's 'made' field may be set to ERROR.
- *-----------------------------------------------------------------------
- */
-static int
-CompatRunCommand(LstNode cmdNode, /* Command to execute */
- void *gnp) /* Node from which the command came */
-{
- char *cmdStart; /* Start of expanded command */
- bool silent; /* Don't print command */
- bool doExecute; /* Execute the command */
- bool errCheck; /* Check errors */
- int reason; /* Reason for child's death */
- int status; /* Description of child's death */
- pid_t cpid; /* Child actually found */
- pid_t stat; /* Status of fork */
- char *cmd = (char *)Lst_Datum(cmdNode);
- GNode *gn = (GNode *)gnp;
-
- silent = gn->type & OP_SILENT;
- errCheck = !(gn->type & OP_IGNORE);
- doExecute = !noExecute;
-
- cmdStart = Var_Subst(cmd, &gn->context, false);
-
- /* How can we execute a null command ? we warn the user that the
- * command expanded to nothing (is this the right thing to do?). */
- if (*cmdStart == '\0') {
- free(cmdStart);
- Error("%s expands to empty string", cmd);
- return 1;
- } else
- cmd = cmdStart;
-
- if ((gn->type & OP_SAVE_CMDS) && (gn != end_node)) {
- Lst_AtEnd(&end_node->commands, cmdStart);
- end_node->type &= ~OP_DUMMY;
- return 1;
- } else if (strcmp(cmdStart, "...") == 0) {
- gn->type |= OP_SAVE_CMDS;
- return 1;
- }
- for (;; cmd++) {
- if (*cmd == '@')
- silent = DEBUG(LOUD) ? false : true;
- else if (*cmd == '-')
- errCheck = false;
- else if (*cmd == '+')
- doExecute = true;
- else
- break;
- }
- while (isspace(*cmd))
- cmd++;
- /* Print the command before echoing if we're not supposed to be quiet
- * for this one. We also print the command if -n given. */
- if (!silent || noExecute) {
- printf("%s\n", cmd);
- fflush(stdout);
- }
- /* If we're not supposed to execute any commands, this is as far as
- * we go... */
- if (!doExecute)
- return 1;
-
- /* Fork and execute the single command. If the fork fails, we abort. */
- switch (cpid = fork()) {
- case -1:
- Fatal("Could not fork");
- /*NOTREACHED*/
- case 0:
- run_command(cmd, errCheck);
- /*NOTREACHED*/
- default:
- break;
- }
- free(cmdStart);
-
- /* The child is off and running. Now all we can do is wait... */
- while (1) {
-
- while ((stat = wait(&reason)) != cpid) {
- if (stat == -1 && errno != EINTR)
- break;
- }
-
- if (interrupted)
- break;
-
- if (stat != -1) {
- if (WIFSTOPPED(reason))
- status = WSTOPSIG(reason); /* stopped */
- else if (WIFEXITED(reason)) {
- status = WEXITSTATUS(reason); /* exited */
- if (status != 0)
- printf("*** Error code %d", status);
- } else {
- status = WTERMSIG(reason); /* signaled */
- printf("*** Signal %d", status);
- }
-
-
- if (!WIFEXITED(reason) || status != 0) {
- if (errCheck) {
- gn->made = ERROR;
- if (keepgoing)
- /* Abort the current target,
- * but let others continue. */
- printf(" (continuing)\n");
- } else {
- /* Continue executing commands for
- * this target. If we return 0,
- * this will happen... */
- printf(" (ignored)\n");
- status = 0;
- }
- }
- return !status;
- } else
- Fatal("error in wait: %d", stat);
- /*NOTREACHED*/
- }
-
- /* This is reached only if interrupted */
- if (!Targ_Precious(gn)) {
- char *file = Varq_Value(TARGET_INDEX, gn);
-
- if (!noExecute && eunlink(file) != -1)
- Error("*** %s removed\n", file);
- }
- if (interrupted == SIGINT) {
- signal(SIGINT, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- interrupted = 0;
- run_gnode(interrupt_node);
- exit(SIGINT);
- }
- exit(interrupted);
-}
-
-static int
-run_gnode(GNode *gn)
-{
- if (gn != NULL && (gn->type & OP_DUMMY) == 0) {
- Lst_ForEachNodeWhile(&gn->commands, CompatRunCommand, gn);
- return gn->made;
- } else
- return NOSUCHNODE;
-}
/*-
*-----------------------------------------------------------------------
@@ -340,6 +72,8 @@ CompatMake(void *gnp, /* The node to make */
GNode *gn = (GNode *)gnp;
GNode *pgn = (GNode *)pgnp;
+ look_harder_for_target(gn);
+
if (pgn->type & OP_MADE) {
(void)Dir_MTime(gn);
gn->made = UPTODATE;
@@ -406,7 +140,7 @@ CompatMake(void *gnp, /* The node to make */
/* Our commands are ok, but we still have to worry
* about the -t flag... */
if (!touchFlag)
- run_gnode(gn);
+ run_gnode(gn, 0);
else
Job_Touch(gn, gn->type & OP_SILENT);
} else
@@ -495,16 +229,11 @@ Compat_Run(Lst targs) /* List of target nodes to re-create */
GNode *gn = NULL; /* Current root target */
int errors; /* Number of targets not remade due to errors */
- signal(SIGINT, CompatInterrupt);
- signal(SIGTERM, CompatInterrupt);
- signal(SIGHUP, CompatInterrupt);
- signal(SIGQUIT, CompatInterrupt);
-
- setup_meta();
+ setup_engine();
/* If the user has defined a .BEGIN target, execute the commands
* attached to it. */
if (!queryFlag) {
- if (run_gnode(begin_node) == ERROR) {
+ if (run_gnode(begin_node, 0) == ERROR) {
printf("\n\nStop.\n");
exit(1);
}
@@ -535,5 +264,5 @@ Compat_Run(Lst targs) /* List of target nodes to re-create */
/* If the user has defined a .END target, run its commands. */
if (errors == 0)
- run_gnode(end_node);
+ run_gnode(end_node, 0);
}
diff --git a/usr.bin/make/defines.h b/usr.bin/make/defines.h
index 2a926e71236..e2cb2181ac3 100644
--- a/usr.bin/make/defines.h
+++ b/usr.bin/make/defines.h
@@ -2,7 +2,7 @@
#define DEFINES_H
/* $OpenPackages$ */
-/* $OpenBSD: defines.h,v 1.3 2007/07/08 17:44:20 espie Exp $ */
+/* $OpenBSD: defines.h,v 1.4 2007/11/02 17:27:24 espie Exp $ */
/*
* Copyright (c) 2001 Marc Espie.
@@ -89,6 +89,7 @@ extern int debug;
#define DEBUG_VAR 0x0200
#define DEBUG_FOR 0x0400
#define DEBUG_LOUD 0x0800
+#define DEBUG_JOBTOKEN 0x1000
#define CONCAT(a,b) a##b
diff --git a/usr.bin/make/engine.c b/usr.bin/make/engine.c
index 4dba6633604..f49d9845937 100644
--- a/usr.bin/make/engine.c
+++ b/usr.bin/make/engine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: engine.c,v 1.9 2007/09/17 12:42:09 espie Exp $ */
+/* $OpenBSD: engine.c,v 1.10 2007/11/02 17:27:24 espie Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
* Copyright (c) 1988, 1989 by Adam de Boor
@@ -33,12 +33,17 @@
* SUCH DAMAGE.
*/
+#include <sys/types.h>
+#include <sys/wait.h>
#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
+#include <signal.h>
#include "config.h"
#include "defines.h"
#include "dir.h"
@@ -51,10 +56,22 @@
#include "lst.h"
#include "timestamp.h"
#include "make.h"
+#include "pathnames.h"
+#include "error.h"
+#include "str.h"
+#include "memory.h"
static void MakeTimeStamp(void *, void *);
static void MakeAddAllSrc(void *, void *);
static int rewrite_time(const char *);
+static void setup_signal(int);
+static void setup_all_signals(void);
+static void setup_meta(void);
+static char **recheck_command_for_shell(char **);
+
+static int setup_and_run_command(char *, GNode *, int);
+static void run_command(const char *, bool);
+static void handle_compat_interrupts(GNode *);
bool
Job_CheckCommands(GNode *gn, void (*abortProc)(char *, ...))
@@ -381,3 +398,347 @@ Make_OODate(GNode *gn)
return oodate;
}
+volatile sig_atomic_t got_signal;
+
+volatile sig_atomic_t got_SIGINT, got_SIGHUP, got_SIGQUIT,
+ got_SIGTERM, got_SIGTSTP, got_SIGTTOU, got_SIGTTIN, got_SIGWINCH;
+
+static void
+setup_signal(int sig)
+{
+ if (signal(sig, SIG_IGN) != SIG_IGN) {
+ (void)signal(sig, SigHandler);
+ }
+}
+
+void
+setup_all_signals()
+{
+ /*
+ * Catch the four signals that POSIX specifies if they aren't ignored.
+ * handle_signal will take care of calling JobInterrupt if appropriate.
+ */
+ setup_signal(SIGINT);
+ setup_signal(SIGHUP);
+ setup_signal(SIGQUIT);
+ setup_signal(SIGTERM);
+ /*
+ * There are additional signals that need to be caught and passed if
+ * either the export system wants to be told directly of signals or if
+ * we're giving each job its own process group (since then it won't get
+ * signals from the terminal driver as we own the terminal)
+ */
+#if defined(USE_PGRP)
+ setup_signal(SIGTSTP);
+ setup_signal(SIGTTOU);
+ setup_signal(SIGTTIN);
+ setup_signal(SIGWINCH);
+#endif
+}
+
+void
+SigHandler(int sig)
+{
+ switch(sig) {
+ case SIGINT:
+ got_SIGINT++;
+ got_signal = 1;
+ break;
+ case SIGHUP:
+ got_SIGHUP++;
+ got_signal = 1;
+ break;
+ case SIGQUIT:
+ got_SIGQUIT++;
+ got_signal = 1;
+ break;
+ case SIGTERM:
+ got_SIGTERM++;
+ got_signal = 1;
+ break;
+#ifdef USE_PGRP
+ case SIGTSTP:
+ got_SIGTSTP++;
+ got_signal = 1;
+ break;
+ case SIGTTOU:
+ got_SIGTTOU++;
+ got_signal = 1;
+ break;
+ case SIGTTIN:
+ got_SIGTTIN++;
+ got_signal = 1;
+ break;
+ case SIGWINCH:
+ got_SIGWINCH++;
+ got_signal = 1;
+ break;
+#endif
+ }
+}
+
+/* The following array is used to make a fast determination of which
+ * characters are interpreted specially by the shell. If a command
+ * contains any of these characters, it is executed by the shell, not
+ * directly by us. */
+static char meta[256];
+
+void
+setup_meta(void)
+{
+ char *p;
+
+ for (p = "#=|^(){};&<>*?[]:$`\\\n"; *p != '\0'; p++)
+ meta[(unsigned char) *p] = 1;
+ /* The null character serves as a sentinel in the string. */
+ meta[0] = 1;
+}
+
+static char **
+recheck_command_for_shell(char **av)
+{
+ char *runsh[] = {
+ "alias", "cd", "eval", "exit", "read", "set", "ulimit",
+ "unalias", "unset", "wait", "umask", NULL
+ };
+
+ char **p;
+
+ /* optimization: if exec cmd, we avoid the intermediate shell */
+ if (strcmp(av[0], "exec") == 0)
+ av++;
+
+ for (p = runsh; *p; p++)
+ if (strcmp(av[0], *p) == 0)
+ return NULL;
+
+ return av;
+}
+
+static void
+run_command(const char *cmd, bool errCheck)
+{
+ const char *p;
+ char *shargv[4];
+ char **todo;
+
+ shargv[0] = _PATH_BSHELL;
+
+ shargv[1] = errCheck ? "-ec" : "-c";
+ shargv[2] = (char *)cmd;
+ shargv[3] = NULL;
+
+ todo = shargv;
+
+
+ /* Search for meta characters in the command. If there are no meta
+ * characters, there's no need to execute a shell to execute the
+ * command. */
+ for (p = cmd; !meta[(unsigned char)*p]; p++)
+ continue;
+ if (*p == '\0') {
+ char *bp;
+ char **av;
+ int argc;
+ /* No meta-characters, so probably no need to exec a shell.
+ * Break the command into words to form an argument vector
+ * we can execute. */
+ av = brk_string(cmd, &argc, &bp);
+ av = recheck_command_for_shell(av);
+ if (av != NULL)
+ todo = av;
+ }
+ execvp(todo[0], todo);
+
+ if (errno == ENOENT)
+ fprintf(stderr, "%s: not found\n", todo[0]);
+ else
+ perror(todo[0]);
+ _exit(1);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * setup_and_run_command --
+ * Execute the next command for a target. If the command returns an
+ * error, the node's made field is set to ERROR and creation stops.
+ *
+ * Results:
+ * 0 in case of error, 1 if ok.
+ *
+ * Side Effects:
+ * The node's 'made' field may be set to ERROR.
+ *-----------------------------------------------------------------------
+ */
+static int
+setup_and_run_command(char *cmd, GNode *gn, int dont_fork)
+{
+ char *cmdStart; /* Start of expanded command */
+ bool silent; /* Don't print command */
+ bool doExecute; /* Execute the command */
+ bool errCheck; /* Check errors */
+ int reason; /* Reason for child's death */
+ int status; /* Description of child's death */
+ pid_t cpid; /* Child actually found */
+ pid_t stat; /* Status of fork */
+
+ silent = gn->type & OP_SILENT;
+ errCheck = !(gn->type & OP_IGNORE);
+ doExecute = !noExecute;
+
+ cmdStart = Var_Subst(cmd, &gn->context, false);
+
+ /* How can we execute a null command ? we warn the user that the
+ * command expanded to nothing (is this the right thing to do?). */
+ if (*cmdStart == '\0') {
+ free(cmdStart);
+ Error("%s expands to empty string", cmd);
+ return 1;
+ } else
+ cmd = cmdStart;
+
+ for (;; cmd++) {
+ if (*cmd == '@')
+ silent = DEBUG(LOUD) ? false : true;
+ else if (*cmd == '-')
+ errCheck = false;
+ else if (*cmd == '+')
+ doExecute = true;
+ else
+ break;
+ }
+ while (isspace(*cmd))
+ cmd++;
+ /* Print the command before echoing if we're not supposed to be quiet
+ * for this one. We also print the command if -n given. */
+ if (!silent || noExecute) {
+ printf("%s\n", cmd);
+ fflush(stdout);
+ }
+ /* If we're not supposed to execute any commands, this is as far as
+ * we go... */
+ if (!doExecute)
+ return 1;
+
+ /* if we're running in parallel mode, we try not to fork the last
+ * command, since it's exit status will be just fine... unless
+ * errCheck is not set, in which case we must deal with the
+ * status ourselves.
+ */
+ if (dont_fork && errCheck)
+ run_command(cmd, errCheck);
+ /*NOTREACHED*/
+
+ /* Fork and execute the single command. If the fork fails, we abort. */
+ switch (cpid = fork()) {
+ case -1:
+ Fatal("Could not fork");
+ /*NOTREACHED*/
+ case 0:
+ run_command(cmd, errCheck);
+ /*NOTREACHED*/
+ default:
+ break;
+ }
+ free(cmdStart);
+
+ /* The child is off and running. Now all we can do is wait... */
+ while (1) {
+
+ while ((stat = wait(&reason)) != cpid) {
+ if (stat == -1 && errno != EINTR)
+ break;
+ }
+
+ if (got_signal)
+ break;
+
+ if (stat != -1) {
+ if (WIFSTOPPED(reason))
+ status = WSTOPSIG(reason); /* stopped */
+ else if (WIFEXITED(reason)) {
+ status = WEXITSTATUS(reason); /* exited */
+ if (status != 0)
+ printf("*** Error code %d", status);
+ } else {
+ status = WTERMSIG(reason); /* signaled */
+ printf("*** Signal %d", status);
+ }
+
+
+ if (!WIFEXITED(reason) || status != 0) {
+ if (errCheck) {
+ gn->made = ERROR;
+ if (keepgoing)
+ /* Abort the current target,
+ * but let others continue. */
+ printf(" (continuing)\n");
+ } else {
+ /* Continue executing commands for
+ * this target. If we return 0,
+ * this will happen... */
+ printf(" (ignored)\n");
+ status = 0;
+ }
+ }
+ return !status;
+ } else
+ Fatal("error in wait: %d", stat);
+ /*NOTREACHED*/
+ }
+ return 0;
+}
+
+static void
+handle_compat_interrupts(GNode *gn)
+{
+ if (!Targ_Precious(gn)) {
+ char *file = Varq_Value(TARGET_INDEX, gn);
+
+ if (!noExecute && eunlink(file) != -1)
+ Error("*** %s removed\n", file);
+ }
+ if (got_SIGINT) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ got_signal = 0;
+ got_SIGINT = 0;
+ run_gnode(interrupt_node, 0);
+ exit(255);
+ }
+ exit(255);
+}
+
+int
+run_gnode(GNode *gn, int parallel)
+{
+ LstNode ln, nln;
+
+ if (gn != NULL && (gn->type & OP_DUMMY) == 0) {
+ gn->made = MADE;
+ for (ln = Lst_First(&gn->commands); ln != NULL; ln = nln) {
+ nln = Lst_Adv(ln);
+ if (setup_and_run_command(Lst_Datum(ln), gn,
+ parallel && nln == NULL) == 0)
+ break;
+ }
+ if (got_signal && !parallel)
+ handle_compat_interrupts(gn);
+ return gn->made;
+ } else
+ return NOSUCHNODE;
+}
+
+void
+setup_engine()
+{
+ static int already_setup = 0;
+
+ if (!already_setup) {
+ setup_meta();
+ setup_all_signals();
+ already_setup = 1;
+ }
+}
diff --git a/usr.bin/make/engine.h b/usr.bin/make/engine.h
index 969d244dac4..68fc47aa7a2 100644
--- a/usr.bin/make/engine.h
+++ b/usr.bin/make/engine.h
@@ -1,6 +1,6 @@
#ifndef ENGINE_H
#define ENGINE_H
-/* $OpenBSD: engine.h,v 1.2 2007/09/17 09:28:36 espie Exp $ */
+/* $OpenBSD: engine.h,v 1.3 2007/11/02 17:27:24 espie Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -65,4 +65,14 @@ extern bool Make_OODate(GNode *);
* fill all dynamic variables for a node.
*/
extern void Make_DoAllVar(GNode *);
+extern volatile sig_atomic_t got_signal;
+
+extern volatile sig_atomic_t got_SIGINT, got_SIGHUP, got_SIGQUIT,
+ got_SIGTERM, got_SIGTSTP, got_SIGTTOU, got_SIGTTIN, got_SIGWINCH;
+
+extern void SigHandler(int);
+extern int run_gnode(GNode *, int);
+
+extern void setup_engine(void);
+
#endif
diff --git a/usr.bin/make/error.c b/usr.bin/make/error.c
index d8cab775d30..314b6d7a04e 100644
--- a/usr.bin/make/error.c
+++ b/usr.bin/make/error.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: error.c,v 1.13 2007/09/17 09:28:36 espie Exp $ */
+/* $OpenBSD: error.c,v 1.14 2007/11/02 17:27:24 espie Exp $ */
/*
* Copyright (c) 2001 Marc Espie.
@@ -29,12 +29,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "config.h"
#include "defines.h"
#include "error.h"
#include "job.h"
#include "targ.h"
+#include "var.h"
#include "lowparse.h"
@@ -132,7 +135,16 @@ DieHorribly(void)
void
Finish(int errors) /* number of errors encountered in Make_Make */
{
- Fatal("%d error%s", errors, errors == 1 ? "" : "s");
+ Job_Wait();
+ if (errors != 0) {
+ Error("make pid #%ld: %d error%s in directory %s:", (long)getpid(),
+ errors, errors == 1 ? "" : "s",
+ Var_Value(".CURDIR"));
+ }
+ print_errors();
+ if (DEBUG(GRAPH2))
+ Targ_PrintGraph(2);
+ exit(2); /* Not 1 so -q can distinguish error */
}
diff --git a/usr.bin/make/gnode.h b/usr.bin/make/gnode.h
index 795a87842db..8317182d34e 100644
--- a/usr.bin/make/gnode.h
+++ b/usr.bin/make/gnode.h
@@ -1,7 +1,7 @@
#ifndef GNODE_H
#define GNODE_H
/* $OpenPackages$ */
-/* $OpenBSD: gnode.h,v 1.6 2007/09/23 09:47:56 espie Exp $ */
+/* $OpenBSD: gnode.h,v 1.7 2007/11/02 17:27:24 espie Exp $ */
/*
* Copyright (c) 2001 Marc Espie.
@@ -196,8 +196,8 @@ struct GNode_ {
#define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it should.
* Used when parsing to catch multiple
* commands for a target */
-#define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */
#define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */
+#define OP_RESOLVED 0x01000000 /* We looked harder already */
/*
* OP_NOP will return true if the node with the given type was not the
diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c
index 41112050ecb..24d6c710aa2 100644
--- a/usr.bin/make/job.c
+++ b/usr.bin/make/job.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: job.c,v 1.100 2007/10/14 09:02:10 espie Exp $ */
+/* $OpenBSD: job.c,v 1.101 2007/11/02 17:27:24 espie Exp $ */
/* $NetBSD: job.c,v 1.16 1996/11/06 17:59:08 christos Exp $ */
/*
@@ -142,61 +142,34 @@
* traversal of the dependency graph.
*/
#define JOB_BUFSIZE 1024
+struct job_pipe {
+ int fd;
+ char buffer[JOB_BUFSIZE];
+ size_t pos;
+};
+
typedef struct Job_ {
pid_t pid; /* The child's process ID */
GNode *node; /* The target the child is making */
- LstNode tailCmds; /* The node of the first command to be
- * saved when the job has been run */
- FILE *cmdFILE; /* When creating the shell script, this is
- * where the commands go */
- int rmtID; /* ID returned from Rmt module */
short flags; /* Flags to control treatment of job */
#define JOB_IGNERR 0x001 /* Ignore non-zero exits */
#define JOB_SILENT 0x002 /* no output */
#define JOB_SPECIAL 0x004 /* Target is a special one. */
-#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing
- * commands */
#define JOB_RESTART 0x080 /* Job needs to be completely restarted */
#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped,
* for some reason */
#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job.
* Used to avoid infinite recursion between
* JobFinish and JobRestart */
- int inPipe; /* Input side of pipe associated
- * with job's output channel */
- int outPipe; /* Output side of pipe associated with
- * job's output channel */
- char outBuf[JOB_BUFSIZE + 1];
- /* Buffer for storing the output of the
- * job, line by line */
- int curPos; /* Current position in op_outBuf */
+ struct job_pipe in[2];
} Job;
-/*
- * error handling variables
- */
-static int errors = 0; /* number of errors reported */
static int aborting = 0; /* why is the make aborting? */
#define ABORT_ERROR 1 /* Because of an error */
#define ABORT_INTERRUPT 2 /* Because it was interrupted */
#define ABORT_WAIT 3 /* Waiting for jobs to finish */
-static int numCommands; /* The number of commands actually printed
- * for a target. Should this number be
- * 0, no shell will be executed. */
-
-#define SHELL_ECHO_OFF "set -"
-#define SHELL_ECHO_ON "set -v"
-#define SHELL_ERROR_ON "set -e"
-#define SHELL_ERROR_OFF "set +e"
-#define SHELL_ECHO_FLAG "v"
-#define SHELL_ERROR_FLAG "e"
-
-static const char *shellPath = _PATH_BSHELL;
-static const char *shellName = "sh";
-
-
static int maxJobs; /* The most children we can run at once */
static int nJobs; /* The number of children currently running */
static LIST runningJobs; /* The structures that describe them */
@@ -207,14 +180,6 @@ static fd_set *outputsp; /* Set of descriptors of pipes connected to
static int outputsn;
static GNode *lastNode; /* The node for which output was most recently
* produced. */
-static char *targFmt; /* Format string to use to head output from a
- * job when it's not the most-recent job heard
- * from */
-
-# define TARG_FMT "--- %s ---\n" /* Default format */
-# define MESSAGE(fp, gn) \
- (void)fprintf(fp, targFmt, gn->name);
-
/*
* When JobStart attempts to run a job but isn't allowed to,
* the job is placed on the queuedJobs queue to be run
@@ -222,6 +187,13 @@ static char *targFmt; /* Format string to use to head output from a
*/
static LIST stoppedJobs;
static LIST queuedJobs;
+static LIST errorsList;
+static int errors;
+struct error_info {
+ int status;
+ char *name;
+};
+
#if defined(USE_PGRP) && defined(SYSV)
@@ -255,93 +227,68 @@ static LIST queuedJobs;
static void pass_signal_to_job(void *, void *);
-static void SigHandler(int);
static void handle_all_signals(void);
static void handle_signal(int);
static int JobCmpPid(void *, void *);
-static int JobPrintCommand(LstNode, void *);
-static void JobSaveCommand(void *, void *);
static void JobClose(Job *);
-static void JobFinish(Job *, int *);
-static void JobExec(Job *, char **);
-static void JobMakeArgv(Job *, char **);
+static void JobFinish(Job *, int);
+static void JobExec(Job *);
static void JobRestart(Job *);
static void JobStart(GNode *, int);
-static char *JobOutput(Job *, char *, char *, int);
-static void JobDoOutput(Job *, bool);
static void JobInterrupt(int, int);
static void JobRestartJobs(void);
-static void DBPRINTF(Job *, const char *, ...);
static void debug_printf(const char *, ...);
-static FILE *new_command_file(void);
-static void setup_signal(int);
-static void setup_all_signals(void);
static Job *prepare_job(GNode *, int);
static void start_queued_job(Job *);
+static void token(Job *, FILE *);
+static void print_partial_buffer(struct job_pipe *, Job *, FILE *, size_t);
+static void print_partial_buffer_and_shift(struct job_pipe *, Job *, FILE *,
+ size_t);
+static bool print_complete_lines(struct job_pipe *, Job *, FILE *, size_t);
+static void prepare_pipe(struct job_pipe *, int *);
+static void handle_job_output(Job *, int, bool);
+static void register_error(int, Job *);
-static volatile sig_atomic_t got_signal;
-
-static volatile sig_atomic_t got_SIGINT, got_SIGHUP, got_SIGQUIT,
- got_SIGTERM, got_SIGTSTP, got_SIGTTOU, got_SIGTTIN, got_SIGWINCH;
-
-
-#define TMPPAT "/tmp/makeXXXXXXXXXX"
-
-static FILE *
-new_command_file()
+static void
+register_error(int status, Job *job)
{
- int fd;
- FILE *f;
- char tmp[] = TMPPAT;
+ struct error_info *p;
+
+ errors++;
+ p = emalloc(sizeof(struct error_info));
+ p->status = status;
+ p->name = job->node->name;
+ if (p)
+ Lst_AtEnd(&errorsList, p);
+}
- fd = mkstemp(tmp);
- if (fd == -1)
- return NULL;
- f = fdopen(fd, "w");
- if (f == NULL)
- close(fd);
- eunlink(tmp);
- return f;
+void
+print_errors()
+{
+ LstNode ln;
+ struct error_info *p;
+
+ for (ln = Lst_First(&errorsList); ln != NULL; ln = Lst_Adv(ln)) {
+ p = (struct error_info *)Lst_Datum(ln);
+ if (WIFEXITED(p->status)) {
+ Error("\tExit status %d in target %s",
+ WEXITSTATUS(p->status), p->name);
+ } else if (WIFSIGNALED(p->status)) {
+ Error("\tReceived signal %d in target s",
+ WTERMSIG(p->status), p->name);
+ } else {
+ Error("\tStatus %d in target %s", p->status, p->name);
+ }
+ }
}
static void
-SigHandler(int sig)
+token(Job *job, FILE *out)
{
- switch(sig) {
- case SIGINT:
- got_SIGINT++;
- got_signal = 1;
- break;
- case SIGHUP:
- got_SIGHUP++;
- got_signal = 1;
- break;
- case SIGQUIT:
- got_SIGQUIT++;
- got_signal = 1;
- break;
- case SIGTERM:
- got_SIGTERM++;
- got_signal = 1;
- break;
-#ifdef USE_PGRP
- case SIGTSTP:
- got_SIGTSTP++;
- got_signal = 1;
- break;
- case SIGTTOU:
- got_SIGTTOU++;
- got_signal = 1;
- break;
- case SIGTTIN:
- got_SIGTTIN++;
- got_signal = 1;
- break;
- case SIGWINCH:
- got_SIGWINCH++;
- got_signal = 1;
- break;
-#endif
+ if (job->node != lastNode) {
+ if (DEBUG(JOBTOKEN))
+ (void)fprintf(out, "--- %s ---\n", job->node->name);
+ lastNode = job->node;
}
}
@@ -506,19 +453,6 @@ JobCmpPid(void *job, /* job to examine */
}
static void
-DBPRINTF(Job *job, const char *fmt, ...)
-{
- va_list va;
- va_start(va, fmt);
- if (DEBUG(JOB)) {
- (void)vfprintf(stdout, fmt, va);
- fflush(stdout);
- }
- vfprintf(job->cmdFILE, fmt, va);
- va_end(va);
-}
-
-static void
debug_printf(const char *fmt, ...)
{
if (DEBUG(JOB)) {
@@ -533,156 +467,6 @@ debug_printf(const char *fmt, ...)
/*-
*-----------------------------------------------------------------------
- * JobPrintCommand --
- * Put out another command for the given job. If the command starts
- * with an @ or a - we process it specially. In the former case,
- * so long as the -s and -n flags weren't given to make, we stick
- * a shell-specific echoOff command in the script. In the latter,
- * we ignore errors for the entire job, unless the shell has error
- * control.
- * If the command is just "..." we take all future commands for this
- * job to be commands to be executed once the entire graph has been
- * made and return non-zero to signal that the end of the commands
- * was reached. These commands are later attached to the end_node
- * node and executed by Job_End when all things are done.
- * This function is called from JobStart via Lst_Find
- *
- * Results:
- * Always 1, unless the command was "..."
- *
- * Side Effects:
- * If the command begins with a '-' and the shell has no error control,
- * the JOB_IGNERR flag is set in the job descriptor.
- * If the command is "..." and we're not ignoring such things,
- * tailCmds is set to the successor node of the cmd.
- * numCommands is incremented if the command is actually printed.
- *-----------------------------------------------------------------------
- */
-static int
-JobPrintCommand(LstNode cmdNode, /* command string to print */
- void *jobp) /* job for which to print it */
-{
- bool noSpecials; /* true if we shouldn't worry about
- * inserting special commands into
- * the input stream. */
- bool shutUp = false; /* true if we put a no echo command
- * into the command file */
- bool errOff = false; /* true if we turned error checking
- * off before printing the command
- * and need to turn it back on */
- char *cmdTemplate; /* Template to use when printing the
- * command */
- char *cmdStart; /* Start of expanded command */
- char *cmd = (char *)Lst_Datum(cmdNode);
- Job *job = (Job *)jobp;
-
- noSpecials = (noExecute && !(job->node->type & OP_MAKE));
-
- if (strcmp(cmd, "...") == 0) {
- job->node->type |= OP_SAVE_CMDS;
- if ((job->flags & JOB_IGNDOTS) == 0) {
- job->tailCmds = Lst_Succ(cmdNode);
- return 0;
- }
- return 1;
- }
-
-
- numCommands++;
-
- /* For debugging, we replace each command with the result of expanding
- * the variables in the command. */
- cmdStart = cmd = Var_Subst(cmd, &job->node->context, false);
-
- cmdTemplate = "%s\n";
-
- /*
- * Check for leading @' and -'s to control echoing and error checking.
- */
- for (;; cmd++) {
- if (*cmd == '@')
- shutUp = DEBUG(LOUD) ? false : true;
- else if (*cmd == '-')
- errOff = true;
- else if (*cmd != '+')
- break;
- }
-
- while (isspace(*cmd))
- cmd++;
-
- if (shutUp) {
- if (!(job->flags & JOB_SILENT) && !noSpecials) {
- DBPRINTF(job, "%s\n", SHELL_ECHO_OFF);
- } else {
- shutUp = false;
- }
- }
-
- if (errOff) {
- if ( !(job->flags & JOB_IGNERR) && !noSpecials) {
- /*
- * we don't want the error-control commands showing
- * up either, so we turn off echoing while executing
- * them. We could put another field in the shell
- * structure to tell JobDoOutput to look for this
- * string too, but why make it any more complex than
- * it already is?
- */
- if (!(job->flags & JOB_SILENT) && !shutUp) {
- DBPRINTF(job, "%s; %s; %s\n", SHELL_ECHO_OFF,
- SHELL_ERROR_OFF, SHELL_ECHO_ON);
- } else {
- DBPRINTF(job, "%s\n", SHELL_ERROR_OFF);
- }
- } else {
- errOff = false;
- }
- }
-
- DBPRINTF(job, cmdTemplate, cmd);
-
- if (errOff) {
- /*
- * If echoing is already off, there's no point in issuing the
- * echoOff command. Otherwise we issue it and pretend it was on
- * for the whole command...
- */
- if (!shutUp && !(job->flags & JOB_SILENT)) {
- DBPRINTF(job, "%s\n", SHELL_ECHO_OFF);
- shutUp = true;
- }
- DBPRINTF(job, "%s\n", SHELL_ERROR_ON);
- }
- if (shutUp) {
- DBPRINTF(job, "%s\n", SHELL_ECHO_ON);
- }
- return 1;
-}
-
-/*-
- *-----------------------------------------------------------------------
- * JobSaveCommand --
- * Save a command to be executed when everything else is done.
- * Callback function for JobFinish...
- *
- * Side Effects:
- * The command is tacked onto the end of end_node's commands list.
- *-----------------------------------------------------------------------
- */
-static void
-JobSaveCommand(void *cmd, void *gn)
-{
- GNode *g = (GNode *)gn;
- char *result;
-
- result = Var_Subst((char *)cmd, &g->context, false);
- Lst_AtEnd(&end_node->commands, result);
-}
-
-
-/*-
- *-----------------------------------------------------------------------
* JobClose --
* Called to close both input and output pipes when a job is finished.
*
@@ -693,12 +477,13 @@ JobSaveCommand(void *cmd, void *gn)
static void
JobClose(Job *job)
{
- FD_CLR(job->inPipe, outputsp);
- if (job->outPipe != job->inPipe) {
- (void)close(job->outPipe);
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ FD_CLR(job->in[i].fd, outputsp);
+ handle_job_output(job, i, true);
+ (void)close(job->in[i].fd);
}
- JobDoOutput(job, true);
- (void)close(job->inPipe);
}
/*-
@@ -717,20 +502,19 @@ JobClose(Job *job)
*
* If we got an error and are aborting (aborting == ABORT_ERROR) and
* the job list is now empty, we are done for the day.
- * If we recognized an error (errors !=0), we set the aborting flag
+ * If we recognized an error we set the aborting flag
* to ABORT_ERROR so no more jobs will be started.
*-----------------------------------------------------------------------
*/
/*ARGSUSED*/
static void
-JobFinish(Job *job, /* job to finish */
- int *status) /* sub-why job went away */
+JobFinish(Job *job, int status)
{
bool done;
- if ((WIFEXITED(*status) &&
- WEXITSTATUS(*status) != 0 && !(job->flags & JOB_IGNERR)) ||
- (WIFSIGNALED(*status) && WTERMSIG(*status) != SIGCONT)) {
+ if ((WIFEXITED(status) &&
+ WEXITSTATUS(status) != 0 && !(job->flags & JOB_IGNERR)) ||
+ (WIFSIGNALED(status) && WTERMSIG(status) != SIGCONT)) {
/*
* If it exited non-zero and either we're doing things our
* way or we're not ignoring errors, the job is finished.
@@ -740,11 +524,8 @@ JobFinish(Job *job, /* job to finish */
* status...
*/
JobClose(job);
- if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
- (void)fclose(job->cmdFILE);
- }
done = true;
- } else if (WIFEXITED(*status)) {
+ } else if (WIFEXITED(status)) {
/*
* Deal with ignored errors in -B mode. We need to print a
* message telling of the ignored error as well as setting
@@ -752,7 +533,7 @@ JobFinish(Job *job, /* job to finish */
* this, we set done to be true if in -B mode and the job
* exited non-zero.
*/
- done = WEXITSTATUS(*status) != 0;
+ done = WEXITSTATUS(status) != 0;
/*
* Old comment said: "Note we don't want to close down any of
* the streams until we know we're at the end." But we do.
@@ -767,49 +548,36 @@ JobFinish(Job *job, /* job to finish */
}
if (done ||
- WIFSTOPPED(*status) ||
- (WIFSIGNALED(*status) && WTERMSIG(*status) == SIGCONT) ||
+ WIFSTOPPED(status) ||
+ (WIFSIGNALED(status) && WTERMSIG(status) == SIGCONT) ||
DEBUG(JOB)) {
- FILE *out;
-
- out = stdout;
-
- if (WIFEXITED(*status)) {
+ if (WIFEXITED(status)) {
debug_printf("Process %ld exited.\n", (long)job->pid);
- if (WEXITSTATUS(*status) != 0) {
- if (job->node != lastNode) {
- MESSAGE(out, job->node);
- lastNode = job->node;
- }
- (void)fprintf(out, "*** Error code %d%s\n",
- WEXITSTATUS(*status),
+ if (WEXITSTATUS(status) != 0) {
+ token(job, stdout);
+ (void)fprintf(stdout, "*** Error code %d%s\n",
+ WEXITSTATUS(status),
(job->flags & JOB_IGNERR) ? "(ignored)" :
"");
if (job->flags & JOB_IGNERR) {
- *status = 0;
+ status = 0;
}
} else if (DEBUG(JOB)) {
- if (job->node != lastNode) {
- MESSAGE(out, job->node);
- lastNode = job->node;
- }
- (void)fprintf(out,
+ token(job, stdout);
+ (void)fprintf(stdout,
"*** Completed successfully\n");
}
- } else if (WIFSTOPPED(*status)) {
+ } else if (WIFSTOPPED(status)) {
debug_printf("Process %ld stopped.\n", (long)job->pid);
- if (job->node != lastNode) {
- MESSAGE(out, job->node);
- lastNode = job->node;
- }
- (void)fprintf(out, "*** Stopped -- signal %d\n",
- WSTOPSIG(*status));
+ token(job, stdout);
+ (void)fprintf(stdout, "*** Stopped -- signal %d\n",
+ WSTOPSIG(status));
job->flags |= JOB_RESUME;
Lst_AtEnd(&stoppedJobs, job);
- (void)fflush(out);
+ (void)fflush(stdout);
return;
- } else if (WTERMSIG(*status) == SIGCONT) {
+ } else if (WTERMSIG(status) == SIGCONT) {
/*
* If the beastie has continued, shift the Job from the
* stopped list to the running one (or re-stop it if
@@ -817,11 +585,8 @@ JobFinish(Job *job, /* job to finish */
* child.
*/
if (job->flags & (JOB_RESUME|JOB_RESTART)) {
- if (job->node != lastNode) {
- MESSAGE(out, job->node);
- lastNode = job->node;
- }
- (void)fprintf(out, "*** Continued\n");
+ token(job, stdout);
+ (void)fprintf(stdout, "*** Continued\n");
}
if (!(job->flags & JOB_CONTINUING)) {
debug_printf(
@@ -848,18 +613,15 @@ JobFinish(Job *job, /* job to finish */
jobFull = true;
debug_printf("Job queue is full.\n");
}
- (void)fflush(out);
+ (void)fflush(stdout);
return;
} else {
- if (job->node != lastNode) {
- MESSAGE(out, job->node);
- lastNode = job->node;
- }
- (void)fprintf(out, "*** Signal %d\n",
- WTERMSIG(*status));
+ token(job, stdout);
+ (void)fprintf(stdout, "*** Signal %d\n",
+ WTERMSIG(status));
}
- (void)fflush(out);
+ (void)fflush(stdout);
}
done = true;
@@ -867,17 +629,15 @@ JobFinish(Job *job, /* job to finish */
if (done &&
aborting != ABORT_ERROR &&
aborting != ABORT_INTERRUPT &&
- *status == 0) {
+ status == 0) {
/* As long as we aren't aborting and the job didn't return a
* non-zero status that we shouldn't ignore, we call
- * Make_Update to update the parents. In addition, any saved
- * commands for the node are placed on the .END target. */
- Lst_ForEachFrom(job->tailCmds, JobSaveCommand, job->node);
+ * Make_Update to update the parents. */
job->node->made = MADE;
Make_Update(job->node);
free(job);
- } else if (*status != 0) {
- errors++;
+ } else if (status != 0) {
+ register_error(status, job);
free(job);
}
@@ -886,7 +646,8 @@ JobFinish(Job *job, /* job to finish */
/*
* Set aborting if any error.
*/
- if (errors && !keepgoing && aborting != ABORT_INTERRUPT) {
+ if (errors && !keepgoing &&
+ aborting != ABORT_INTERRUPT) {
/*
* If we found any errors in this batch of children and the -k
* flag wasn't given, we set the aborting flag so no more jobs
@@ -903,6 +664,33 @@ JobFinish(Job *job, /* job to finish */
}
}
+static void
+prepare_pipe(struct job_pipe *p, int *fd)
+{
+ p->pos = 0;
+ (void)fcntl(fd[0], F_SETFD, FD_CLOEXEC);
+ p->fd = fd[0];
+ close(fd[1]);
+
+ if (outputsp == NULL || p->fd > outputsn) {
+ int fdn, ofdn;
+ fd_set *tmp;
+
+ fdn = howmany(p->fd+1, NFDBITS);
+ ofdn = outputsn ? howmany(outputsn+1, NFDBITS) : 0;
+
+ if (fdn != ofdn) {
+ tmp = recalloc(outputsp, fdn, sizeof(fd_mask));
+ if (tmp == NULL)
+ return;
+ outputsp = tmp;
+ }
+ outputsn = p->fd;
+ }
+ fcntl(p->fd, F_SETFL, O_NONBLOCK);
+ FD_SET(p->fd, outputsp);
+}
+
/*-
*-----------------------------------------------------------------------
* JobExec --
@@ -915,20 +703,17 @@ JobFinish(Job *job, /* job to finish */
*-----------------------------------------------------------------------
*/
static void
-JobExec(Job *job, char **argv)
+JobExec(Job *job)
{
pid_t cpid; /* ID of new child */
- static int signals_caught = 0;
+ int fds[4];
+ int *fdout = fds;
+ int *fderr = fds+2;
+ int result;
+ int i;
if (DEBUG(JOB)) {
- int i;
-
(void)fprintf(stdout, "Running %s\n", job->node->name);
- (void)fprintf(stdout, "\tCommand: ");
- for (i = 0; argv[i] != NULL; i++) {
- (void)fprintf(stdout, "%s ", argv[i]);
- }
- (void)fprintf(stdout, "\n");
(void)fflush(stdout);
}
@@ -938,46 +723,33 @@ JobExec(Job *job, char **argv)
* banner with their name in it never appears). This is an attempt to
* provide that feedback, even if nothing follows it.
*/
- if (lastNode != job->node && !(job->flags & JOB_SILENT)) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
+ token(job, stdout);
- if (!signals_caught) {
- signals_caught = 1;
- setup_all_signals();
- }
+ setup_engine();
+
+ /* Create the pipe by which we'll get the shell's output.
+ */
+ if (pipe(fdout) == -1)
+ Punt("Cannot create pipe: %s", strerror(errno));
+
+ if (pipe(fderr) == -1)
+ Punt("Cannot create pipe: %s", strerror(errno));
if ((cpid = fork()) == -1) {
Punt("Cannot fork");
} else if (cpid == 0) {
- /*
- * Must duplicate the input stream down to the child's input
- * and reset it to the beginning (again). Since the stream was
- * marked close-on-exec, we must clear that bit in the new
- * input.
- */
- if (dup2(fileno(job->cmdFILE), 0) == -1)
- Punt("Cannot dup2(job->cmdFile): %s", strerror(errno));
- (void)fcntl(0, F_SETFD, 0);
- (void)lseek(0, 0, SEEK_SET);
-
- /*
- * Set up the child's output to be routed through the pipe
- * we've created for it.
- */
- if (dup2(job->outPipe, 1) == -1)
- Punt("Cannot dup2(job->outPipe): %s", strerror(errno));
- /*
- * The output channels are marked close on exec. This bit was
- * duplicated by the dup2 (on some systems), so we have to
- * clear it before routing the shell's error output to the same
- * place as its standard output.
- */
- (void)fcntl(1, F_SETFD, 0);
- if (dup2(1, 2) == -1)
- Punt("Cannot dup2(stdout): %s", strerror(errno));
+ /* standard pipe code to route stdout and stderr */
+ close(fdout[0]);
+ if (dup2(fdout[1], 1) == -1)
+ Punt("Cannot dup2(outPipe): %s", strerror(errno));
+ if (fdout[1] != 1)
+ close(fdout[1]);
+ close(fderr[0]);
+ if (dup2(fderr[1], 2) == -1)
+ Punt("Cannot dup2(errPipe): %s", strerror(errno));
+ if (fderr[1] != 2)
+ close(fderr[1]);
#ifdef USE_PGRP
/*
@@ -992,43 +764,26 @@ JobExec(Job *job, char **argv)
# endif
#endif /* USE_PGRP */
- (void)execv(shellPath, argv);
-
- (void)write(STDERR_FILENO, "Could not execute shell\n",
- sizeof("Could not execute shell"));
- _exit(1);
+ /* most cases won't return, but will exit directly */
+ result = run_gnode(job->node, 1);
+ switch(result) {
+ case MADE:
+ exit(0);
+ case ERROR:
+ exit(1);
+ default:
+ fprintf(stderr,
+ "Could not run gnode, returned %d\n", result);
+ exit(1);
+ }
} else {
job->pid = cpid;
- /* we set the current position in the buffer to the beginning
+ /* we set the current position in the buffers to the beginning
* and mark another stream to watch in the outputs mask
*/
- job->curPos = 0;
-
- if (outputsp == NULL || job->inPipe > outputsn) {
- int fdn, ofdn;
- fd_set *tmp;
-
- fdn = howmany(job->inPipe+1, NFDBITS);
- ofdn = outputsn ? howmany(outputsn+1, NFDBITS) : 0;
-
- if (fdn != ofdn) {
- tmp = recalloc(outputsp, fdn, sizeof(fd_mask));
- if (tmp == NULL)
- return;
- outputsp = tmp;
- }
- outputsn = job->inPipe;
- }
- FD_SET(job->inPipe, outputsp);
-
- /*
- * XXX: Used to not happen if REMOTE. Why?
- */
- if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
- (void)fclose(job->cmdFILE);
- job->cmdFILE = NULL;
- }
+ for (i = 0; i < 2; i++)
+ prepare_pipe(&job->in[i], fds+2*i);
}
/*
@@ -1041,48 +796,9 @@ JobExec(Job *job, char **argv)
}
}
-/*-
- *-----------------------------------------------------------------------
- * JobMakeArgv --
- * Create the argv needed to execute the shell for a given job.
- *-----------------------------------------------------------------------
- */
-static void
-JobMakeArgv(Job *job, char **argv)
-{
- int argc;
- static char args[10]; /* For merged arguments */
-
- argv[0] = (char *)shellName;
- argc = 1;
-
- (void)snprintf(args, sizeof(args), "-%s%s",
- (job->flags & JOB_IGNERR) ? "" : SHELL_ERROR_FLAG,
- (job->flags & JOB_SILENT) ? "" : SHELL_ECHO_FLAG);
-
- if (args[1]) {
- argv[argc] = args;
- argc++;
- }
- argv[argc] = NULL;
-}
-
static void
start_queued_job(Job *job)
{
- /*
- * Set up the control arguments to the shell. This is based on
- * the flags set earlier for this job. If the JOB_IGNERR flag
- * is clear, the 'exit' flag of the commandShell is used to
- * cause it to exit upon receiving an error. If the JOB_SILENT
- * flag is clear, the 'echo' flag of the commandShell is used
- * to get it to start echoing as soon as it starts processing
- * commands.
- */
- char *argv[4];
-
- JobMakeArgv(job, argv);
-
if (DEBUG(JOB)) {
(void)fprintf(stdout, "Restarting %s...",
job->node->name);
@@ -1105,7 +821,7 @@ start_queued_job(Job *job)
*/
debug_printf("running locally\n");
}
- JobExec(job, argv);
+ JobExec(job);
}
/*-
@@ -1135,7 +851,7 @@ JobRestart(Job *job)
* (or maxJobs is 0), it's ok to resume the job.
*/
bool error;
- int status;
+ int status = 0;
error = KILL(job->pid, SIGCONT) != 0;
@@ -1147,16 +863,15 @@ JobRestart(Job *job)
*/
job->flags |= JOB_CONTINUING;
W_SETTERMSIG(&status, SIGCONT);
- JobFinish(job, &status);
+ JobFinish(job, status);
job->flags &= ~(JOB_RESUME|JOB_CONTINUING);
debug_printf("done\n");
} else {
Error("couldn't resume %s: %s",
job->node->name, strerror(errno));
- status = 0;
W_SETEXITSTATUS(&status, 1);
- JobFinish(job, &status);
+ JobFinish(job, status);
}
} else {
/*
@@ -1184,7 +899,6 @@ prepare_job(GNode *gn, int flags)
}
job->node = gn;
- job->tailCmds = NULL;
/*
* Set the initial value of the flags for this job based on the global
@@ -1220,66 +934,23 @@ prepare_job(GNode *gn, int flags)
DieHorribly();
}
- job->cmdFILE = new_command_file();
- if (job->cmdFILE == NULL) {
- Punt("Error creating command file");
- }
- (void)fcntl(fileno(job->cmdFILE), F_SETFD, FD_CLOEXEC);
- /*
- * Send the commands to the command file, flush all its buffers
- * then rewind and remove the thing.
- */
- noExec = false;
-
- /*
- * We can do all the commands at once. hooray for
- * sanity
- */
- numCommands = 0;
- Lst_ForEachNodeWhile(&gn->commands, JobPrintCommand,
- job);
-
- /*
- * If we didn't print out any commands to the shell
- * script, there's not much point in executing the
- * shell, is there?
- */
- if (numCommands == 0) {
+ if (Lst_IsEmpty(&gn->commands))
noExec = true;
- }
+ else
+ noExec = false;
+
} else if (noExecute) {
- /*
- * Not executing anything -- just print all the commands to
- * stdout in one fell swoop. This will still set up
- * job->tailCmds correctly.
- */
- if (lastNode != gn) {
- MESSAGE(stdout, gn);
- lastNode = gn;
- }
- job->cmdFILE = stdout;
- /*
- * Only print the commands if they're ok, but don't die if
- * they're not -- just let the user know they're bad and keep
- * going. It doesn't do any harm in this case and may do some
- * good.
- */
- if (cmdsOK) {
- Lst_ForEachNodeWhile(&gn->commands, JobPrintCommand,
- job);
- }
- /*
- * Don't execute the shell, thank you.
- */
- noExec = true;
+ if (!cmdsOK || Lst_IsEmpty(&gn->commands))
+ noExec = true;
+ else
+ noExec = false;
} else {
/*
* Just touch the target and note that no shell should be
- * executed. Set cmdFILE to stdout to make life easier. Check
+ * executed. Check
* the commands, too, but don't die if they're no good -- it
* does no harm to keep working up the graph.
*/
- job->cmdFILE = stdout;
Job_Touch(gn, job->flags & JOB_SILENT);
noExec = true;
}
@@ -1289,30 +960,17 @@ prepare_job(GNode *gn, int flags)
*/
if (noExec) {
/*
- * Unlink and close the command file if we opened one
- */
- if (job->cmdFILE != stdout) {
- if (job->cmdFILE != NULL)
- (void)fclose(job->cmdFILE);
- } else {
- (void)fflush(stdout);
- }
-
- /*
* We only want to work our way up the graph if we aren't here
* because the commands for the job were no good.
*/
if (cmdsOK) {
if (aborting == 0) {
- Lst_ForEachFrom(job->tailCmds, JobSaveCommand,
- job->node);
Make_Update(job->node);
}
}
free(job);
return NULL;
} else {
- (void)fflush(job->cmdFILE);
return job;
}
}
@@ -1334,26 +992,9 @@ JobStart(GNode *gn, /* target to create */
* e.g. JOB_SPECIAL */
{
Job *job;
- char *argv[4]; /* Argument vector to shell */
- int fd[2];
job = prepare_job(gn, flags);
if (!job)
return;
- /* Create the pipe by which we'll get the shell's output.
- */
- if (pipe(fd) == -1)
- Punt("Cannot create pipe: %s", strerror(errno));
- job->inPipe = fd[0];
- job->outPipe = fd[1];
- (void)fcntl(job->inPipe, F_SETFD, FD_CLOEXEC);
- (void)fcntl(job->outPipe, F_SETFD, FD_CLOEXEC);
-
- /*
- * Set up the control arguments to the shell. This is based on the flags
- * set earlier for this job.
- */
- JobMakeArgv(job, argv);
-
if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL) &&
maxJobs != 0) {
/*
@@ -1379,201 +1020,112 @@ JobStart(GNode *gn, /* target to create */
jobFull = true;
debug_printf("Local job queue is full.\n");
}
- JobExec(job, argv);
+ JobExec(job);
}
}
-static char *
-JobOutput(Job *job, char *cp, char *endp, int msg)
+/* Helper functions for JobDoOutput */
+
+
+/* output debugging token and print characters from 0 to endpos */
+static void
+print_partial_buffer(struct job_pipe *p, Job *job, FILE *out, size_t endPos)
+{
+ size_t i;
+
+ token(job, out);
+ for (i = 0; i < endPos; i++)
+ putc(p->buffer[i], out);
+}
+
+/* print partial buffer and shift remaining contents */
+static void
+print_partial_buffer_and_shift(struct job_pipe *p, Job *job, FILE *out,
+ size_t endPos)
{
- char *ecp;
-
- ecp = strstr(cp, SHELL_ECHO_OFF);
- while (ecp != NULL) {
- if (cp != ecp) {
- *ecp = '\0';
- if (msg && job->node != lastNode) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
- /*
- * The only way there wouldn't be a newline after
- * this line is if it were the last in the buffer.
- * however, since the non-printable comes after it,
- * there must be a newline, so we don't print one.
- */
- (void)fprintf(stdout, "%s", cp);
- (void)fflush(stdout);
- }
- cp = ecp + strlen(SHELL_ECHO_OFF);
- if (cp != endp) {
- /*
- * Still more to print, look again after skipping
- * the whitespace following the non-printable
- * command....
- */
- cp++;
- while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
- cp++;
- }
- ecp = strstr(cp, SHELL_ECHO_OFF);
- } else {
- return cp;
+ size_t i;
+
+ print_partial_buffer(p, job, out, endPos);
+
+ for (i = endPos; i < p->pos; i++)
+ p->buffer[i-endPos] = p->buffer[i];
+ p->pos -= endPos;
+}
+
+/* print complete lines, looking back to the limit position
+ * (stuff before limit was already scanned).
+ * returns true if something was printed.
+ */
+static bool
+print_complete_lines(struct job_pipe *p, Job *job, FILE *out, size_t limit)
+{
+ size_t i;
+
+ for (i = p->pos; i > limit; i--) {
+ if (p->buffer[i-1] == '\n') {
+ print_partial_buffer_and_shift(p, job, out, i);
+ return true;
}
}
- return cp;
+ return false;
}
-
/*-
*-----------------------------------------------------------------------
- * JobDoOutput --
+ * handle_pipe --
* This functions is called whenever there is something to read on the
* pipe. We collect more output from the given job and store it in the
- * job's outBuf. If this makes up a line, we print it tagged by the job's
+ * job's outBuf. If this makes up lines, we print it tagged by the job's
* identifier, as necessary.
- * We also keep our figurative eye out for the
- * 'noPrint' line for the shell from which the output came. If
- * we recognize a line, we don't print it. If the command is not
- * alone on the line (the character after it is not \0 or \n), we
- * do print whatever follows it.
*
* Side Effects:
* curPos may be shifted as may the contents of outBuf.
*-----------------------------------------------------------------------
*/
static void
-JobDoOutput(Job *job, /* the job whose output needs printing */
- bool finish) /* true if this is the last time we'll be
- * called for this job */
+handle_pipe(struct job_pipe *p,
+ Job *job, FILE *out, bool finish)
{
- bool gotNL = false; /* true if got a newline */
- bool fbuf; /* true if our buffer filled up */
int nr; /* number of bytes read */
- int i; /* auxiliary index into outBuf */
- int max; /* limit for i (end of current data) */
- int nRead; /* (Temporary) number of bytes read */
-
- /*
- * Read as many bytes as will fit in the buffer.
- */
-end_loop:
- gotNL = false;
- fbuf = false;
-
- nRead = read(job->inPipe, &job->outBuf[job->curPos],
- JOB_BUFSIZE - job->curPos);
- if (nRead == -1) {
- if (DEBUG(JOB)) {
- perror("JobDoOutput(piperead)");
- }
- nr = 0;
- } else {
- nr = nRead;
- }
-
- /*
- * If we hit the end-of-file (the job is dead), we must flush its
- * remaining output, so pretend we read a newline if there's any
- * output remaining in the buffer.
- * Also clear the 'finish' flag so we stop looping.
- */
- if (nr == 0 && job->curPos != 0) {
- job->outBuf[job->curPos] = '\n';
- nr = 1;
- finish = false;
- } else if (nr == 0) {
- finish = false;
- }
-
- /*
- * Look for the last newline in the bytes we just got. If there is
- * one, break out of the loop with 'i' as its index and gotNL set
- * true.
- */
- max = job->curPos + nr;
- for (i = job->curPos + nr - 1; i >= job->curPos; i--) {
- if (job->outBuf[i] == '\n') {
- gotNL = true;
- break;
- } else if (job->outBuf[i] == '\0') {
- /*
- * To be fixed: don't use printf, it stops at NUL bytes.
- */
- job->outBuf[i] = ' ';
- }
- }
-
- if (!gotNL) {
- job->curPos += nr;
- if (job->curPos == JOB_BUFSIZE) {
- /*
- * If we've run out of buffer space, we have no choice
- * but to print the stuff. sigh.
- */
- fbuf = true;
- i = job->curPos;
- }
- }
- if (gotNL || fbuf) {
- /*
- * Need to send the output to the screen. Null terminate it
- * first, overwriting the newline character if there was one.
- * So long as the line isn't one we should filter (according
- * to the shell description), we print the line, preceded
- * by a target banner if this target isn't the same as the
- * one for which we last printed something.
- * The rest of the data in the buffer are then shifted down
- * to the start of the buffer and curPos is set accordingly.
- */
- job->outBuf[i] = '\0';
- if (i >= job->curPos) {
- char *cp;
-
- cp = JobOutput(job, job->outBuf, &job->outBuf[i],
- false);
-
- /*
- * There's still more in that thar buffer. This time,
- * though, we know there's no newline at the end, so we
- * add one of our own free will.
- */
- if (*cp != '\0') {
- if (job->node != lastNode) {
- MESSAGE(stdout, job->node);
- lastNode = job->node;
- }
- (void)fprintf(stdout, "%s%s", cp,
- gotNL ? "\n" : "");
- (void)fflush(stdout);
+ int oldpos; /* optimization */
+
+ /* want to get everything ? -> we block */
+ if (finish)
+ fcntl(p->fd, F_SETFL, 0);
+
+ do {
+ nr = read(p->fd, &p->buffer[p->pos],
+ JOB_BUFSIZE - p->pos);
+ if (nr == -1) {
+ if (errno == EAGAIN)
+ break;
+ if (DEBUG(JOB)) {
+ perror("JobDoOutput(piperead)");
}
}
- if (i < max - 1) {
- /* shift the remaining characters down */
- (void)memcpy(job->outBuf, &job->outBuf[i + 1],
- max - (i + 1));
- job->curPos = max - (i + 1);
+ oldpos = p->pos;
+ p->pos += nr;
+ if (!print_complete_lines(p, job, out, oldpos))
+ if (p->pos == JOB_BUFSIZE) {
+ print_partial_buffer(p, job, out, p->pos);
+ p->pos = 0;
+ }
+ } while (nr != 0);
- } else {
- /*
- * We have written everything out, so we just start over
- * from the start of the buffer. No copying. No nothing.
- */
- job->curPos = 0;
- }
- }
- if (finish) {
- /*
- * If the finish flag is true, we must loop until we hit
- * end-of-file on the pipe. This is guaranteed to happen
- * eventually since the other end of the pipe is now closed
- * (we closed it explicitly and the child has exited). When
- * we do get an EOF, finish will be set false and we'll fall
- * through and out.
- */
- goto end_loop;
+ /* at end of file, we print whatever is left */
+ if (nr == 0) {
+ print_partial_buffer(p, job, out, p->pos);
+ if (p->pos > 0 && p->buffer[p->pos - 1] != '\n')
+ putchar('\n');
+ p->pos = 0;
}
}
+static void
+handle_job_output(Job *job, int i, bool finish)
+{
+ handle_pipe(&job->in[i], job, i == 0 ? stdout : stderr, finish);
+}
+
/*-
*-----------------------------------------------------------------------
* Job_CatchChildren --
@@ -1633,7 +1185,7 @@ Job_CatchChildren()
jobFull = false;
}
- JobFinish(job, &status);
+ JobFinish(job, status);
}
}
@@ -1657,6 +1209,7 @@ Job_CatchOutput(void)
struct timeval timeout;
LstNode ln;
Job *job;
+ int i;
int count = howmany(outputsn+1, NFDBITS) * sizeof(fd_mask);
fd_set *readfdsp = malloc(count);
@@ -1675,9 +1228,11 @@ Job_CatchOutput(void)
for (ln = Lst_First(&runningJobs); nfds && ln != NULL;
ln = Lst_Adv(ln)) {
job = (Job *)Lst_Datum(ln);
- if (FD_ISSET(job->inPipe, readfdsp)) {
- JobDoOutput(job, false);
- nfds--;
+ for (i = 0; i < 2; i++) {
+ if (FD_ISSET(job->in[i].fd, readfdsp)) {
+ handle_job_output(job, i, false);
+ nfds--;
+ }
}
}
}
@@ -1700,39 +1255,6 @@ Job_Make(GNode *gn)
(void)JobStart(gn, 0);
}
-static void
-setup_signal(int sig)
-{
- if (signal(sig, SIG_IGN) != SIG_IGN) {
- (void)signal(sig, SigHandler);
- }
-}
-
-static void
-setup_all_signals()
-{
- /*
- * Catch the four signals that POSIX specifies if they aren't ignored.
- * handle_signal will take care of calling JobInterrupt if appropriate.
- */
- setup_signal(SIGINT);
- setup_signal(SIGHUP);
- setup_signal(SIGQUIT);
- setup_signal(SIGTERM);
- /*
- * There are additional signals that need to be caught and passed if
- * either the export system wants to be told directly of signals or if
- * we're giving each job its own process group (since then it won't get
- * signals from the terminal driver as we own the terminal)
- */
-#if defined(USE_PGRP)
- setup_signal(SIGTSTP);
- setup_signal(SIGTTOU);
- setup_signal(SIGTTIN);
- setup_signal(SIGWINCH);
-#endif
-}
-
/*-
*-----------------------------------------------------------------------
* Job_Init --
@@ -1748,25 +1270,16 @@ Job_Init(int maxproc)
Static_Lst_Init(&runningJobs);
Static_Lst_Init(&stoppedJobs);
Static_Lst_Init(&queuedJobs);
+ Static_Lst_Init(&errorsList);
maxJobs = maxproc;
nJobs = 0;
jobFull = false;
+ errors = 0;
aborting = 0;
- errors = 0;
lastNode = NULL;
- if (maxJobs == 1) {
- /*
- * If only one job can run at a time, there's no need for a
- * banner, no is there?
- */
- targFmt = "";
- } else {
- targFmt = TARG_FMT;
- }
-
if ((begin_node->type & OP_DUMMY) == 0) {
JobStart(begin_node, JOB_SPECIAL);
while (nJobs) {
@@ -1867,7 +1380,7 @@ JobInterrupt(int runINTERRUPT, /* Non-zero if commands for the .INTERRUPT
if ((interrupt_node->type & OP_DUMMY) == 0) {
ignoreErrors = false;
- JobStart(interrupt_node, JOB_IGNDOTS);
+ JobStart(interrupt_node, 0);
while (nJobs) {
Job_CatchOutput();
Job_CatchChildren();
@@ -1895,7 +1408,7 @@ Job_Finish(void)
if (errors) {
Error("Errors reported so .END ignored");
} else {
- JobStart(end_node, JOB_SPECIAL | JOB_IGNDOTS);
+ JobStart(end_node, JOB_SPECIAL);
while (nJobs) {
Job_CatchOutput();
diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h
index 24a3f1ad7a1..d93199d0d44 100644
--- a/usr.bin/make/job.h
+++ b/usr.bin/make/job.h
@@ -2,7 +2,7 @@
#define _JOB_H_
/* $OpenPackages$ */
-/* $OpenBSD: job.h,v 1.20 2007/09/23 09:44:39 espie Exp $ */
+/* $OpenBSD: job.h,v 1.21 2007/11/02 17:27:24 espie Exp $ */
/* $NetBSD: job.h,v 1.5 1996/11/06 17:59:10 christos Exp $ */
/*
@@ -60,5 +60,6 @@ extern void Job_End(void);
#endif
extern void Job_Wait(void);
extern void Job_AbortAll(void);
+extern void print_errors(void);
#endif /* _JOB_H_ */
diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c
index 7b9c1538def..ef2ef8dde6b 100644
--- a/usr.bin/make/main.c
+++ b/usr.bin/make/main.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: main.c,v 1.86 2007/10/24 13:19:24 espie Exp $ */
+/* $OpenBSD: main.c,v 1.87 2007/11/02 17:27:24 espie Exp $ */
/* $NetBSD: main.c,v 1.34 1997/03/24 20:56:36 gwr Exp $ */
/*
@@ -258,6 +258,9 @@ MainParseArgs(int argc, char **argv)
case 'j':
debug |= DEBUG_JOB;
break;
+ case 'J':
+ debug |= DEBUG_JOBTOKEN;
+ break;
case 'l':
debug |= DEBUG_LOUD;
break;
@@ -678,6 +681,7 @@ main(int argc, char **argv)
Dir_AddDir(defaultPath, d.current);
Var_Set(".CURDIR", d.current);
Var_Set(".OBJDIR", d.object);
+ Targ_setdirs(d.current, d.object);
/*
* Initialize various variables.
diff --git a/usr.bin/make/make.1 b/usr.bin/make/make.1
index 70a814a60fa..e17a6551446 100644
--- a/usr.bin/make/make.1
+++ b/usr.bin/make/make.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: make.1,v 1.70 2007/07/09 14:47:29 jmc Exp $
+.\" $OpenBSD: make.1,v 1.71 2007/11/02 17:27:24 espie Exp $
.\" $OpenPackages$
.\" $NetBSD: make.1,v 1.18 1997/03/10 21:19:53 christos Exp $
.\"
@@ -31,7 +31,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd $Mdocdate: July 9 2007 $
+.Dd $Mdocdate: November 2 2007 $
.Dt MAKE 1
.Os
.Sh NAME
@@ -165,6 +165,8 @@ Print the input graph after making everything, or before exiting
on error.
.It Ar j
Print debugging information about running multiple shells.
+.It Ar J
+Print job tokens showing which output corresponds to what job.
.It Ar l
Print commands in Makefile targets regardless of whether or not they are
prefixed by @.
@@ -1409,7 +1411,3 @@ A+=$I
.Pp
.Sq A
will evaluate to a b c d after the loop, not z b c d.
-.Pp
-The
-.Ql +
-command modificator is ignored in parallel make mode.
diff --git a/usr.bin/make/make.c b/usr.bin/make/make.c
index a2ee3b138d9..417a0996278 100644
--- a/usr.bin/make/make.c
+++ b/usr.bin/make/make.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: make.c,v 1.42 2007/09/17 12:01:17 espie Exp $ */
+/* $OpenBSD: make.c,v 1.43 2007/11/02 17:27:24 espie Exp $ */
/* $NetBSD: make.c,v 1.10 1996/11/06 17:59:15 christos Exp $ */
/*
@@ -59,6 +59,7 @@
#include <limits.h>
#include <stdio.h>
+#include <signal.h>
#include "config.h"
#include "defines.h"
#include "dir.h"
@@ -72,6 +73,7 @@
#include "timestamp.h"
#include "engine.h"
#include "lst.h"
+#include "targ.h"
static LIST toBeMade; /* The current fringe of the graph. These
* are nodes which await examination by
@@ -166,12 +168,8 @@ Make_Update(GNode *cgn) /* the child node */
* the Dir_MTime occurs, thus leading us to believe that the
* file is unchanged, wreaking havoc with files that depend
* on this one.
- * XXX If we are saving commands pretend that
- * the target is made now. Otherwise archives with ... rules
- * don't work!
*/
- if (noExecute || (cgn->type & OP_SAVE_CMDS) ||
- is_out_of_date(Dir_MTime(cgn)))
+ if (noExecute || is_out_of_date(Dir_MTime(cgn)))
cgn->mtime = now;
if (DEBUG(MAKE))
printf("update time: %s\n", time_to_string(cgn->mtime));
@@ -409,6 +407,7 @@ Make_Run(Lst targs) /* the initial list of targets */
gn->make = true;
numNodes++;
+ look_harder_for_target(gn);
/*
* Apply any .USE rules before looking for implicit
* dependencies to make sure everything that should have
diff --git a/usr.bin/make/suff.c b/usr.bin/make/suff.c
index a42bf8f004b..2a3e33ecda8 100644
--- a/usr.bin/make/suff.c
+++ b/usr.bin/make/suff.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: suff.c,v 1.72 2007/09/18 09:15:04 espie Exp $ */
+/* $OpenBSD: suff.c,v 1.73 2007/11/02 17:27:24 espie Exp $ */
/* $NetBSD: suff.c,v 1.13 1996/11/06 17:59:25 christos Exp $ */
/*
@@ -79,6 +79,7 @@
#include <stdint.h>
#include <stddef.h>
#include <string.h>
+#include <signal.h>
#include <ohash.h>
#include "config.h"
#include "defines.h"
diff --git a/usr.bin/make/targ.c b/usr.bin/make/targ.c
index fdc86106f3c..27e678bef8a 100644
--- a/usr.bin/make/targ.c
+++ b/usr.bin/make/targ.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: targ.c,v 1.48 2007/09/18 08:51:23 espie Exp $ */
+/* $OpenBSD: targ.c,v 1.49 2007/11/02 17:27:24 espie Exp $ */
/* $NetBSD: targ.c,v 1.11 1997/02/20 16:51:50 christos Exp $ */
/*
@@ -443,3 +443,49 @@ Targ_PrintGraph(int pass) /* Which pass this is. 1 => no processing
#endif
Suff_PrintAll();
}
+
+static char *curdir, *objdir;
+static size_t curdir_len, objdir_len;
+
+void
+Targ_setdirs(const char *c, const char *o)
+{
+ curdir_len = strlen(c);
+ curdir = emalloc(curdir_len+2);
+ memcpy(curdir, c, curdir_len);
+ curdir[curdir_len++] = '/';
+ curdir[curdir_len] = 0;
+
+ objdir_len = strlen(o);
+ objdir = emalloc(objdir_len+2);
+ memcpy(objdir, o, objdir_len);
+ objdir[objdir_len++] = '/';
+ objdir[objdir_len] = 0;
+}
+
+void
+look_harder_for_target(GNode *gn)
+{
+ GNode *extra, *cgn;
+ LstNode ln;
+
+ if (gn->type & OP_RESOLVED)
+ return;
+ gn->type |= OP_RESOLVED;
+ if (strncmp(gn->name, objdir, objdir_len) == 0) {
+ extra = Targ_FindNode(gn->name + objdir_len, TARG_NOCREATE);
+ if (extra != NULL) {
+ if (Lst_IsEmpty(&gn->commands))
+ Lst_Concat(&gn->commands, &extra->commands);
+ for (ln = Lst_First(&extra->children); ln != NULL;
+ ln = Lst_Adv(ln)) {
+ cgn = (GNode *)Lst_Datum(ln);
+
+ if (Lst_AddNew(&gn->children, cgn)) {
+ Lst_AtEnd(&cgn->parents, gn);
+ gn->unmade++;
+ }
+ }
+ }
+ }
+}
diff --git a/usr.bin/make/targ.h b/usr.bin/make/targ.h
index db9080165f1..8af62308438 100644
--- a/usr.bin/make/targ.h
+++ b/usr.bin/make/targ.h
@@ -1,7 +1,7 @@
#ifndef TARG_H
#define TARG_H
/* $OpenPackages$ */
-/* $OpenBSD: targ.h,v 1.4 2007/09/18 08:51:23 espie Exp $ */
+/* $OpenBSD: targ.h,v 1.5 2007/11/02 17:27:24 espie Exp $ */
/*
* Copyright (c) 2001 Marc Espie.
@@ -77,4 +77,6 @@ struct ohash_info;
extern struct ohash_info gnode_info;
+extern void look_harder_for_target(GNode *);
+extern void Targ_setdirs(const char *, const char *);
#endif