diff options
Diffstat (limited to 'compat.c')
-rw-r--r-- | compat.c | 432 |
1 files changed, 195 insertions, 237 deletions
@@ -1,4 +1,4 @@ -/* $NetBSD: compat.c,v 1.139 2020/08/30 20:08:47 rillig Exp $ */ +/* $NetBSD: compat.c,v 1.173 2020/11/01 17:47:26 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -69,19 +69,6 @@ * SUCH DAMAGE. */ -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: compat.c,v 1.139 2020/08/30 20:08:47 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; -#else -__RCSID("$NetBSD: compat.c,v 1.139 2020/08/30 20:08:47 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - /*- * compat.c -- * The routines in this file implement the full-compatibility @@ -91,33 +78,30 @@ __RCSID("$NetBSD: compat.c,v 1.139 2020/08/30 20:08:47 rillig Exp $"); * - friendly variable substitution. * * Interface: - * Compat_Run Initialize things for this module and recreate - * thems as need creatin' + * Compat_Run Initialize things for this module and recreate + * thems as need creatin' */ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include <sys/types.h> -#include <sys/stat.h> -#include "wait.h" - -#include <ctype.h> -#include <errno.h> -#include <signal.h> -#include <stdio.h> - -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "job.h" -#include "metachar.h" -#include "pathnames.h" - - -static GNode *curTarg = NULL; -static GNode *ENDNode; -static void CompatInterrupt(int); +#include <sys/types.h> +#include <sys/stat.h> +#include "wait.h" + +#include <errno.h> +#include <signal.h> + +#include "make.h" +#include "dir.h" +#include "job.h" +#include "metachar.h" +#include "pathnames.h" + +/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */ +MAKE_RCSID("$NetBSD: compat.c,v 1.173 2020/11/01 17:47:26 rillig Exp $"); + +static GNode *curTarg = NULL; static pid_t compatChild; static int compatSigno; @@ -128,15 +112,12 @@ static int compatSigno; static void CompatDeleteTarget(GNode *gn) { - if ((gn != NULL) && !Targ_Precious (gn)) { - char *p1; - const char *file = Var_Value(TARGET, gn, &p1); + if (gn != NULL && !Targ_Precious(gn)) { + const char *file = GNode_VarTarget(gn); - if (!noExecute && eunlink(file) != -1) { + if (!opts.noExecute && eunlink(file) != -1) { Error("*** %s removed", file); } - - bmake_free(p1); } } @@ -155,22 +136,24 @@ CompatInterrupt(int signo) CompatDeleteTarget(curTarg); - if ((curTarg != NULL) && !Targ_Precious (curTarg)) { + if (curTarg != NULL && !Targ_Precious(curTarg)) { /* * Run .INTERRUPT only if hit with interrupt signal */ if (signo == SIGINT) { - gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); + gn = Targ_FindNode(".INTERRUPT"); if (gn != NULL) { Compat_Make(gn, gn); } } } + if (signo == SIGQUIT) _exit(signo); + /* - * If there is a child running, pass the signal on - * we will exist after it has exited. + * If there is a child running, pass the signal on. + * We will exist after it has exited. */ compatSigno = signo; if (compatChild > 0) { @@ -181,11 +164,8 @@ CompatInterrupt(int signo) } } -/*- - *----------------------------------------------------------------------- - * 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. +/* 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. * * Input: * cmdp Command to execute @@ -193,45 +173,38 @@ CompatInterrupt(int signo) * * Results: * 0 if the command succeeded, 1 if an error occurred. - * - * Side Effects: - * The node's 'made' field may be set to ERROR. - * - *----------------------------------------------------------------------- */ int -CompatRunCommand(void *cmdp, void *gnp) +Compat_RunCommand(const char *cmdp, GNode *gn) { - char *cmdStart; /* Start of expanded command */ - char *cp, *bp; - Boolean silent, /* Don't print command */ - doIt; /* Execute even if -n */ - volatile Boolean errCheck; /* Check errors */ - WAIT_T reason; /* Reason for child's death */ - int status; /* Description of child's death */ - pid_t cpid; /* Child actually found */ - pid_t retstat; /* Result of wait */ - LstNode cmdNode; /* Node where current command is located */ - const char ** volatile av; /* Argument vector for thing to exec */ - char ** volatile mav;/* Copy of the argument vector for freeing */ - Boolean useShell; /* TRUE if command should be executed + char *cmdStart; /* Start of expanded command */ + char *bp; + Boolean silent; /* Don't print command */ + Boolean doIt; /* Execute even if -n */ + volatile Boolean errCheck; /* Check errors */ + WAIT_T reason; /* Reason for child's death */ + int status; /* Description of child's death */ + pid_t cpid; /* Child actually found */ + pid_t retstat; /* Result of wait */ + StringListNode *cmdNode; /* Node where current command is located */ + const char **volatile av; /* Argument vector for thing to exec */ + char **volatile mav; /* Copy of the argument vector for freeing */ + Boolean useShell; /* TRUE if command should be executed * using a shell */ - char * volatile cmd = (char *)cmdp; - GNode *gn = (GNode *)gnp; + const char *volatile cmd = cmdp; silent = (gn->type & OP_SILENT) != 0; errCheck = !(gn->type & OP_IGNORE); doIt = FALSE; + /* Luckily the commands don't end up in a string pool, otherwise + * this comparison could match too early, in a dependency using "..." + * for delayed commands, run in parallel mode, using the same shell + * command line more than once; see JobPrintCommand. + * TODO: write a unit-test to protect against this potential bug. */ cmdNode = Lst_FindDatum(gn->commands, cmd); - cmdStart = Var_Subst(cmd, gn, VARE_WANTRES); - - /* - * brk_string will return an argv with a NULL in av[0], thus causing - * execvp to choke and die horribly. Besides, how can we execute a null - * command? In any case, we warn the user that the command expanded to - * nothing (is this the right thing to do?). - */ + (void)Var_Subst(cmd, gn, VARE_WANTRES, &cmdStart); + /* TODO: handle errors */ if (*cmdStart == '\0') { free(cmdStart); @@ -240,17 +213,19 @@ CompatRunCommand(void *cmdp, void *gnp) cmd = cmdStart; LstNode_Set(cmdNode, cmdStart); - if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { - assert(ENDNode != NULL); - Lst_Append(ENDNode->commands, cmdStart); - return 0; + if (gn->type & OP_SAVE_CMDS) { + GNode *endNode = Targ_GetEndNode(); + if (gn != endNode) { + Lst_Append(endNode->commands, cmdStart); + return 0; + } } if (strcmp(cmdStart, "...") == 0) { gn->type |= OP_SAVE_CMDS; return 0; } - while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { + while (*cmd == '@' || *cmd == '-' || *cmd == '+') { switch (*cmd) { case '@': silent = !DEBUG(LOUD); @@ -267,7 +242,7 @@ CompatRunCommand(void *cmdp, void *gnp) cmd++; } - while (isspace((unsigned char)*cmd)) + while (ch_isspace(*cmd)) cmd++; /* @@ -295,14 +270,14 @@ CompatRunCommand(void *cmdp, void *gnp) * meta characters as documented in make(1). */ - useShell = needshell(cmd, FALSE); + useShell = needshell(cmd); #endif /* * 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(gn)) { + if (!silent || !GNode_ShouldExecute(gn)) { printf("%s\n", cmd); fflush(stdout); } @@ -311,11 +286,10 @@ CompatRunCommand(void *cmdp, void *gnp) * If we're not supposed to execute any commands, this is as far as * we go... */ - if (!doIt && NoExecute(gn)) { + if (!doIt && !GNode_ShouldExecute(gn)) { return 0; } - if (DEBUG(JOB)) - fprintf(debug_file, "Execute: '%s'\n", cmd); + DEBUG1(JOB, "Execute: '%s'\n", cmd); if (useShell) { /* @@ -374,8 +348,7 @@ CompatRunCommand(void *cmdp, void *gnp) } #endif (void)execvp(av[0], (char *const *)UNCONST(av)); - execError("exec", av[0]); - _exit(1); + execDie("exec", av[0]); } free(mav); @@ -394,85 +367,77 @@ CompatRunCommand(void *cmdp, void *gnp) /* * The child is off and running. Now all we can do is wait... */ - while (1) { - - while ((retstat = wait(&reason)) != cpid) { - if (retstat > 0) - JobReapChild(retstat, reason, FALSE); /* not ours? */ - if (retstat == -1 && errno != EINTR) { - break; - } + while ((retstat = wait(&reason)) != cpid) { + if (retstat > 0) + JobReapChild(retstat, reason, FALSE); /* not ours? */ + if (retstat == -1 && errno != EINTR) { + break; } + } - if (retstat > -1) { - if (WIFSTOPPED(reason)) { - status = WSTOPSIG(reason); /* stopped */ - } else if (WIFEXITED(reason)) { - status = WEXITSTATUS(reason); /* exited */ + if (retstat < 0) + Fatal("error in wait: %d: %s", retstat, strerror(errno)); + + if (WIFSTOPPED(reason)) { + status = WSTOPSIG(reason); /* stopped */ + } else if (WIFEXITED(reason)) { + status = WEXITSTATUS(reason); /* exited */ #if defined(USE_META) && defined(USE_FILEMON_ONCE) - if (useMeta) { - meta_cmd_finish(NULL); - } + if (useMeta) { + meta_cmd_finish(NULL); + } #endif - if (status != 0) { - if (DEBUG(ERROR)) { - fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", - gn->name); - for (cp = cmd; *cp; ) { - if (isspace((unsigned char)*cp)) { - fprintf(debug_file, " "); - while (isspace((unsigned char)*cp)) - cp++; - } else { - fprintf(debug_file, "%c", *cp); - cp++; - } - } - fprintf(debug_file, "\n"); + if (status != 0) { + if (DEBUG(ERROR)) { + const char *cp; + debug_printf("\n*** Failed target: %s\n*** Failed command: ", + gn->name); + for (cp = cmd; *cp; ) { + if (ch_isspace(*cp)) { + debug_printf(" "); + while (ch_isspace(*cp)) + cp++; + } else { + debug_printf("%c", *cp); + cp++; } - printf("*** Error code %d", status); } - } else { - status = WTERMSIG(reason); /* signaled */ - printf("*** Signal %d", status); + debug_printf("\n"); } + printf("*** Error code %d", status); + } + } else { + status = WTERMSIG(reason); /* signaled */ + printf("*** Signal %d", status); + } - if (!WIFEXITED(reason) || (status != 0)) { - if (errCheck) { + if (!WIFEXITED(reason) || status != 0) { + if (errCheck) { #ifdef USE_META - if (useMeta) { - meta_job_error(NULL, gn, 0, status); - } + if (useMeta) { + meta_job_error(NULL, gn, 0, status); + } #endif - gn->made = ERROR; - if (keepgoing) { - /* - * Abort the current target, but let others - * continue. - */ - printf(" (continuing)\n"); - } else { - printf("\n"); - } - if (deleteOnError) { - CompatDeleteTarget(gn); - } - } else { - /* - * Continue executing commands for this target. - * If we return 0, this will happen... - */ - printf(" (ignored)\n"); - status = 0; - } + gn->made = ERROR; + if (opts.keepgoing) { + /* Abort the current target, but let others continue. */ + printf(" (continuing)\n"); + } else { + printf("\n"); } - break; + if (deleteOnError) + CompatDeleteTarget(gn); } else { - Fatal("error in wait: %d: %s", retstat, strerror(errno)); - /*NOTREACHED*/ + /* + * Continue executing commands for this target. + * If we return 0, this will happen... + */ + printf(" (ignored)\n"); + status = 0; } } + free(cmdStart); compatChild = 0; if (compatSigno) { @@ -483,32 +448,41 @@ CompatRunCommand(void *cmdp, void *gnp) return status; } -/*- - *----------------------------------------------------------------------- - * Compat_Make -- - * Make a target. - * - * Input: - * gnp The node to make - * pgnp Parent to abort if necessary - * - * Results: - * 0 +static void +RunCommands(GNode *gn) +{ + StringListNode *ln; + for (ln = gn->commands->first; ln != NULL; ln = ln->next) { + const char *cmd = ln->datum; + if (Compat_RunCommand(cmd, gn) != 0) + break; + } +} + +static void +MakeNodes(GNodeList *gnodes, GNode *pgn) +{ + GNodeListNode *ln; + for (ln = gnodes->first; ln != NULL; ln = ln->next) { + GNode *cohort = ln->datum; + Compat_Make(cohort, pgn); + } +} + +/* Make a target. * - * Side Effects: - * If an error is detected and not being ignored, the process exits. + * If an error is detected and not being ignored, the process exits. * - *----------------------------------------------------------------------- + * Input: + * gn The node to make + * pgn Parent to abort if necessary */ -int -Compat_Make(void *gnp, void *pgnp) +void +Compat_Make(GNode *gn, GNode *pgn) { - GNode *gn = (GNode *)gnp; - GNode *pgn = (GNode *)pgnp; - if (!shellName) /* we came here from jobs */ Shell_Init(); - if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { + if (gn->made == UNMADE && (gn == pgn || !(pgn->type & OP_MADE))) { /* * First mark ourselves to be made, then apply whatever transformations * the suffix module thinks are necessary. Once that's done, we can @@ -519,45 +493,37 @@ Compat_Make(void *gnp, void *pgnp) */ gn->flags |= REMAKE; gn->made = BEINGMADE; - if ((gn->type & OP_MADE) == 0) + if (!(gn->type & OP_MADE)) Suff_FindDeps(gn); - Lst_ForEach(gn->children, Compat_Make, gn); - if ((gn->flags & REMAKE) == 0) { + MakeNodes(gn->children, gn); + if (!(gn->flags & REMAKE)) { gn->made = ABORTED; pgn->flags &= ~(unsigned)REMAKE; goto cohorts; } - if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) { - char *p1; - Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn); - bmake_free(p1); - } + if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) + Var_Set(IMPSRC, GNode_VarTarget(gn), pgn); /* - * All the children were made ok. Now cmgn->mtime contains the + * All the children were made ok. Now youngestChild->mtime contains the * modification time of the newest child, we need to find out if we * exist and when we were modified last. The criteria for datedness * are defined by the Make_OODate function. */ - if (DEBUG(MAKE)) { - fprintf(debug_file, "Examining %s...", gn->name); - } - if (! Make_OODate(gn)) { + DEBUG1(MAKE, "Examining %s...", gn->name); + if (!Make_OODate(gn)) { gn->made = UPTODATE; - if (DEBUG(MAKE)) { - fprintf(debug_file, "up-to-date.\n"); - } + DEBUG0(MAKE, "up-to-date.\n"); goto cohorts; - } else if (DEBUG(MAKE)) { - fprintf(debug_file, "out-of-date.\n"); - } + } else + DEBUG0(MAKE, "out-of-date.\n"); /* * If the user is just seeing if something is out-of-date, exit now * to tell him/her "yes". */ - if (queryFlag) { + if (opts.queryFlag) { exit(1); } @@ -572,26 +538,24 @@ Compat_Make(void *gnp, void *pgnp) * Alter our type to tell if errors should be ignored or things * should not be printed so CompatRunCommand knows what to do. */ - if (Targ_Ignore(gn)) { + if (Targ_Ignore(gn)) gn->type |= OP_IGNORE; - } - if (Targ_Silent(gn)) { + if (Targ_Silent(gn)) gn->type |= OP_SILENT; - } if (Job_CheckCommands(gn, Fatal)) { /* * Our commands are ok, but we still have to worry about the -t * flag... */ - if (!touchFlag || (gn->type & OP_MAKE)) { + if (!opts.touchFlag || (gn->type & OP_MAKE)) { curTarg = gn; #ifdef USE_META - if (useMeta && !NoExecute(gn)) { + if (useMeta && GNode_ShouldExecute(gn)) { meta_job_start(NULL, gn); } #endif - Lst_ForEach(gn->commands, CompatRunCommand, gn); + RunCommands(gn); curTarg = NULL; } else { Job_Touch(gn, (gn->type & OP_SILENT) != 0); @@ -600,7 +564,7 @@ Compat_Make(void *gnp, void *pgnp) gn->made = ERROR; } #ifdef USE_META - if (useMeta && !NoExecute(gn)) { + if (useMeta && GNode_ShouldExecute(gn)) { if (meta_job_finish(NULL) != 0) gn->made = ERROR; } @@ -619,24 +583,19 @@ Compat_Make(void *gnp, void *pgnp) pgn->flags |= CHILDMADE; Make_TimeStamp(pgn, gn); } - } else if (keepgoing) { + } else if (opts.keepgoing) { pgn->flags &= ~(unsigned)REMAKE; } else { PrintOnError(gn, "\nStop."); exit(1); } } else if (gn->made == ERROR) { - /* - * Already had an error when making this beastie. Tell the parent - * to abort. - */ + /* Already had an error when making this. Tell the parent to abort. */ pgn->flags &= ~(unsigned)REMAKE; } else { if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) { - char *p1; - const char *target = Var_Value(TARGET, gn, &p1); + const char *target = GNode_VarTarget(gn); Var_Set(IMPSRC, target != NULL ? target : "", pgn); - bmake_free(p1); } switch(gn->made) { case BEINGMADE: @@ -661,8 +620,7 @@ Compat_Make(void *gnp, void *pgnp) } cohorts: - Lst_ForEach(gn->cohorts, Compat_Make, pgnp); - return 0; + MakeNodes(gn->cohorts, pgn); } /* Initialize this module and start making. @@ -671,35 +629,33 @@ cohorts: * targs The target nodes to re-create */ void -Compat_Run(Lst targs) +Compat_Run(GNodeList *targs) { - GNode *gn = NULL;/* Current root target */ - int errors; /* Number of targets not remade due to errors */ + GNode *gn = NULL; /* Current root target */ + int errors; /* Number of targets not remade due to errors */ if (!shellName) Shell_Init(); - if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { + if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) bmake_signal(SIGINT, CompatInterrupt); - } - if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { + if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) bmake_signal(SIGTERM, CompatInterrupt); - } - if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { + if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) bmake_signal(SIGHUP, CompatInterrupt); - } - if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { + if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) bmake_signal(SIGQUIT, CompatInterrupt); - } - ENDNode = Targ_FindNode(".END", TARG_CREATE); - ENDNode->type = OP_SPECIAL; + /* Create the .END node now, to keep the (debug) output of the + * counter.mk test the same as before 2020-09-23. This implementation + * detail probably doesn't matter though. */ + (void)Targ_GetEndNode(); /* * If the user has defined a .BEGIN target, execute the commands attached * to it. */ - if (!queryFlag) { - gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); + if (!opts.queryFlag) { + gn = Targ_FindNode(".BEGIN"); if (gn != NULL) { Compat_Make(gn, gn); if (gn->made == ERROR) { @@ -719,11 +675,11 @@ Compat_Run(Lst targs) * For each entry in the list of targets to create, call Compat_Make on * it to create the thing. Compat_Make will leave the 'made' field of gn * in one of several states: - * UPTODATE gn was already up-to-date - * MADE gn was recreated successfully - * ERROR An error occurred while gn was being created - * ABORTED gn was not remade because one of its inferiors - * could not be made due to errors. + * UPTODATE gn was already up-to-date + * MADE gn was recreated successfully + * ERROR An error occurred while gn was being created + * ABORTED gn was not remade because one of its inferiors + * could not be made due to errors. */ errors = 0; while (!Lst_IsEmpty(targs)) { @@ -734,7 +690,7 @@ Compat_Run(Lst targs) printf("`%s' is up to date.\n", gn->name); } else if (gn->made == ABORTED) { printf("`%s' not remade because of errors.\n", gn->name); - errors += 1; + errors++; } } @@ -742,7 +698,9 @@ Compat_Run(Lst targs) * If the user has defined a .END target, run its commands. */ if (errors == 0) { - Compat_Make(ENDNode, ENDNode); + GNode *endNode = Targ_GetEndNode(); + Compat_Make(endNode, endNode); + /* XXX: Did you mean endNode->made instead of gn->made? */ if (gn->made == ERROR) { PrintOnError(gn, "\nStop."); exit(1); |