From 1664a909851def7cf5c31a2423c6f76c4a9872ed Mon Sep 17 00:00:00 2001 From: jmc Date: Sat, 20 Dec 2003 00:18:22 +0000 Subject: [PATCH] Fixes for PR#18573 (make -j not stopping correctly on error). Using -e in sh/ksh to stop on error doesn't work with grouped commands. At least for any SUSE compliant sh(1). Instead, extend the Shell struct and add errOut which provides a template to use to check error status from commands. --- usr.bin/make/job.c | 102 ++++++++++++++++++++++++++++++++++----------- usr.bin/make/job.h | 15 +++++-- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index f4378c0babb7..644589fd7581 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -1,4 +1,4 @@ -/* $NetBSD: job.c,v 1.82 2003/08/07 11:14:51 agc Exp $ */ +/* $NetBSD: job.c,v 1.83 2003/12/20 00:18:22 jmc Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifdef MAKE_BOOTSTRAP -static char rcsid[] = "$NetBSD: job.c,v 1.82 2003/08/07 11:14:51 agc Exp $"; +static char rcsid[] = "$NetBSD: job.c,v 1.83 2003/12/20 00:18:22 jmc Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: job.c,v 1.82 2003/08/07 11:14:51 agc Exp $"); +__RCSID("$NetBSD: job.c,v 1.83 2003/12/20 00:18:22 jmc Exp $"); #endif #endif /* not lint */ #endif @@ -218,7 +218,7 @@ static Shell shells[] = { { "csh", TRUE, "unset verbose", "set verbose", "unset verbose", 10, - FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"", + FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"", "", '#', "v", "e", }, /* @@ -227,17 +227,14 @@ static Shell shells[] = { */ { "sh", - TRUE, "set -", "set -v", "set -", 5, - TRUE, "set -e", "set +e", -#ifdef OLDBOURNESHELL - FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n", -#endif + FALSE, "", "", "", 0, + FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", '#', #ifdef __NetBSD__ - "vq", + "q", #else - "v", + "", #endif - "e", + "", }, /* * KSH description. @@ -245,9 +242,9 @@ static Shell shells[] = { { "ksh", TRUE, "set +v", "set -v", "set +v", 6, - TRUE, "set -e", "set +e", + FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", '#', "v", - "e", + "", }, /* * UNKNOWN. @@ -255,7 +252,7 @@ static Shell shells[] = { { (char *) 0, FALSE, (char *) 0, (char *) 0, (char *) 0, 0, - FALSE, (char *) 0, (char *) 0, + FALSE, (char *) 0, (char *) 0, (char *) 0, 0, (char *) 0, (char *) 0, } }; @@ -673,10 +670,12 @@ JobPrintCommand(ClientData cmdp, ClientData jobp) const char *cmdTemplate; /* Template to use when printing the * command */ char *cmdStart; /* Start of expanded command */ + char *escCmd = NULL; /* Command with quotes/backticks escaped */ char *cmd = (char *) cmdp; Job *job = (Job *) jobp; - char *cp; - + char *cp; + int i, j; + noSpecials = NoExecute(job->node); if (strcmp(cmd, "...") == 0) { @@ -717,12 +716,31 @@ JobPrintCommand(ClientData cmdp, ClientData jobp) while (isspace((unsigned char) *cmd)) cmd++; + /* + * If the shell doesn't have error control the alternate echo'ing will + * be done (to avoid showing additional error checking code) + * and this will need the characters '$ ` \ "' escaped + */ + + if (!commandShell->hasErrCtl) { + /* Worst that could happen is every char needs escaping. */ + escCmd = (char *) emalloc((strlen(cmd) * 2) + 1); + for (i = 0, j= 0; cmd[i] != '\0'; i++, j++) { + if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || + cmd[i] == '"') + escCmd[j++] = '\\'; + escCmd[j] = cmd[i]; + } + escCmd[j] = 0; + } + if (shutUp) { if (!(job->flags & JOB_SILENT) && !noSpecials && commandShell->hasEchoCtl) { DBPRINTF("%s\n", commandShell->echoOff); } else { - shutUp = FALSE; + if (commandShell->hasErrCtl) + shutUp = FALSE; } } @@ -743,7 +761,7 @@ JobPrintCommand(ClientData cmdp, ClientData jobp) DBPRINTF("%s\n", commandShell->ignErr); DBPRINTF("%s\n", commandShell->echoOn); } else { - DBPRINTF("%s\n", commandShell->ignErr); + DBPRINTF("%s\n", commandShell->ignErr); } } else if (commandShell->ignErr && (*commandShell->ignErr != '\0')) @@ -757,11 +775,16 @@ JobPrintCommand(ClientData cmdp, ClientData jobp) * to ignore errors. Set cmdTemplate to use the weirdness * instead of the simple "%s\n" template. */ - if (!(job->flags & JOB_SILENT) && !shutUp && - commandShell->hasEchoCtl) { - DBPRINTF("%s\n", commandShell->echoOff); - DBPRINTF(commandShell->errCheck, cmd); + if (!(job->flags & JOB_SILENT) && !shutUp) { + if (commandShell->hasEchoCtl) { + DBPRINTF("%s\n", commandShell->echoOff); + } + DBPRINTF(commandShell->errCheck, escCmd); shutUp = TRUE; + } else { + if (!shutUp) { + DBPRINTF(commandShell->errCheck, escCmd); + } } cmdTemplate = commandShell->ignErr; /* @@ -776,6 +799,30 @@ JobPrintCommand(ClientData cmdp, ClientData jobp) } else { errOff = FALSE; } + } else { + + /* + * If errors are being checked and the shell doesn't have error control + * but does supply an errOut template, then setup commands to run + * through it. + */ + + if (!commandShell->hasErrCtl && commandShell->errOut && + (*commandShell->errOut != '\0')) { + if (!(job->flags & JOB_SILENT) && !shutUp) { + if (commandShell->hasEchoCtl) { + DBPRINTF("%s\n", commandShell->echoOff); + } + DBPRINTF(commandShell->errCheck, escCmd); + shutUp = TRUE; + } + /* If it's a comment line, treat it like an ignored error */ + if (escCmd[0] == commandShell->commentChar) + cmdTemplate = commandShell->ignErr; + else + cmdTemplate = commandShell->errOut; + errOff = FALSE; + } } if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0 && @@ -790,7 +837,8 @@ JobPrintCommand(ClientData cmdp, ClientData jobp) } DBPRINTF(cmdTemplate, cmd); free(cmdStart); - + if (escCmd) + free(escCmd); if (errOff) { /* * If echoing is already off, there's no point in issuing the @@ -803,7 +851,7 @@ JobPrintCommand(ClientData cmdp, ClientData jobp) } DBPRINTF("%s\n", commandShell->errCheck); } - if (shutUp) { + if (shutUp && commandShell->hasEchoCtl) { DBPRINTF("%s\n", commandShell->echoOn); } return 0; @@ -2883,6 +2931,10 @@ Job_ParseShell(char *line) newShell.errCheck = &argv[0][6]; } else if (strncmp(*argv, "ignore=", 7) == 0) { newShell.ignErr = &argv[0][7]; + } else if (strncmp(*argv, "errout=", 7) == 0) { + newShell.errOut = &argv[0][7]; + } else if (strncmp(*argv, "comment=", 8) == 0) { + newShell.commentChar = argv[0][8]; } else { Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", *argv); diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h index c5926ea87862..5fa7961a27a4 100644 --- a/usr.bin/make/job.h +++ b/usr.bin/make/job.h @@ -1,4 +1,4 @@ -/* $NetBSD: job.h,v 1.20 2003/08/07 11:14:52 agc Exp $ */ +/* $NetBSD: job.h,v 1.21 2003/12/20 00:18:22 jmc Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -235,9 +235,13 @@ typedef struct Job { * Some special stuff goes on if a shell doesn't have error control. In such * a case, errCheck becomes a printf template for echoing the command, * should echoing be on and ignErr becomes another printf template for - * executing the command while ignoring the return status. If either of these - * strings is empty when hasErrCtl is FALSE, the command will be executed - * anyway as is and if it causes an error, so be it. + * executing the command while ignoring the return status. Finally errOut + * is a printf template for running the command and causing the shell to + * exit on error. If any of these strings are empty when hasErrCtl is FALSE, + * the command will be executed anyway as is and if it causes an error, so be + * it. Any templates setup to echo the command will escape any '$ ` \ "'i + * characters in the command string to avoid common problems with + * echo "%s\n" as a template. */ typedef struct Shell { const char *name; /* the name of the shell. For Bourne and C @@ -257,6 +261,9 @@ typedef struct Shell { * individual commands */ const char *errCheck; /* string to turn error checking on */ const char *ignErr; /* string to turn off error checking */ + const char *errOut; /* string to use for testing exit code */ + char commentChar; /* character used by shell for comment lines */ + /* * command-line flags */