Annotation of src/usr.bin/make/engine.c, Revision 1.10
1.10 ! espie 1: /* $OpenBSD$ */
1.1 espie 2: /*
3: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
4: * Copyright (c) 1988, 1989 by Adam de Boor
5: * Copyright (c) 1989 by Berkeley Softworks
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Adam de Boor.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
1.10 ! espie 36: #include <sys/types.h>
! 37: #include <sys/wait.h>
1.1 espie 38: #include <limits.h>
39: #include <stdio.h>
1.10 ! espie 40: #include <stdlib.h>
! 41: #include <ctype.h>
1.1 espie 42: #include <errno.h>
43: #include <fcntl.h>
44: #include <unistd.h>
45: #include <string.h>
1.10 ! espie 46: #include <signal.h>
1.1 espie 47: #include "config.h"
48: #include "defines.h"
49: #include "dir.h"
50: #include "engine.h"
51: #include "arch.h"
52: #include "gnode.h"
53: #include "targ.h"
54: #include "var.h"
55: #include "extern.h"
56: #include "lst.h"
57: #include "timestamp.h"
58: #include "make.h"
1.10 ! espie 59: #include "pathnames.h"
! 60: #include "error.h"
! 61: #include "str.h"
! 62: #include "memory.h"
1.1 espie 63:
64: static void MakeTimeStamp(void *, void *);
65: static void MakeAddAllSrc(void *, void *);
1.6 espie 66: static int rewrite_time(const char *);
1.10 ! espie 67: static void setup_signal(int);
! 68: static void setup_all_signals(void);
! 69: static void setup_meta(void);
! 70: static char **recheck_command_for_shell(char **);
! 71:
! 72: static int setup_and_run_command(char *, GNode *, int);
! 73: static void run_command(const char *, bool);
! 74: static void handle_compat_interrupts(GNode *);
1.1 espie 75:
76: bool
1.3 espie 77: Job_CheckCommands(GNode *gn, void (*abortProc)(char *, ...))
1.1 espie 78: {
1.3 espie 79: if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->commands) &&
1.9 espie 80: (gn->type & (OP_NODEFAULT | OP_LIB)) == 0) {
1.3 espie 81: /*
82: * No commands. Look for .DEFAULT rule from which we might infer
83: * commands
84: */
1.9 espie 85: if ((DEFAULT->type & OP_DUMMY) == 0 &&
86: !Lst_IsEmpty(&DEFAULT->commands)) {
1.3 espie 87: /*
88: * Make only looks for a .DEFAULT if the node was never
89: * the target of an operator, so that's what we do too.
90: * If a .DEFAULT was given, we substitute its commands
91: * for gn's commands and set the IMPSRC variable to be
92: * the target's name The DEFAULT node acts like a
93: * transformation rule, in that gn also inherits any
94: * attributes or sources attached to .DEFAULT itself.
95: */
96: Make_HandleUse(DEFAULT, gn);
97: Varq_Set(IMPSRC_INDEX, Varq_Value(TARGET_INDEX, gn), gn);
98: } else if (is_out_of_date(Dir_MTime(gn))) {
99: /*
100: * The node wasn't the target of an operator we have no
101: * .DEFAULT rule to go on and the target doesn't
102: * already exist. There's nothing more we can do for
103: * this branch. If the -k flag wasn't given, we stop in
104: * our tracks, otherwise we just don't update this
105: * node's parents so they never get examined.
106: */
1.5 espie 107: static const char msg[] =
1.3 espie 108: "make: don't know how to make";
109:
110: if (gn->type & OP_OPTIONAL) {
1.5 espie 111: (void)fprintf(stdout, "%s %s(ignored)\n", msg,
1.3 espie 112: gn->name);
113: (void)fflush(stdout);
114: } else if (keepgoing) {
1.5 espie 115: (void)fprintf(stdout, "%s %s(continuing)\n",
1.3 espie 116: msg, gn->name);
117: (void)fflush(stdout);
118: return false;
119: } else {
1.5 espie 120: (*abortProc)("%s %s. Stop in %s.", msg,
1.3 espie 121: gn->name, Var_Value(".CURDIR"));
122: return false;
123: }
124: }
1.1 espie 125: }
1.3 espie 126: return true;
1.1 espie 127: }
128:
1.6 espie 129: /* touch files the hard way, by writing stuff to them */
130: static int
131: rewrite_time(const char *name)
132: {
133: int fd;
134: char c;
135:
136: fd = open(name, O_RDWR | O_CREAT, 0666);
137: if (fd < 0)
138: return -1;
139: /*
140: * Read and write a byte to the file to change
141: * the modification time.
142: */
143: if (read(fd, &c, 1) == 1) {
144: (void)lseek(fd, 0, SEEK_SET);
145: (void)write(fd, &c, 1);
146: }
147:
148: (void)close(fd);
149: return 0;
150: }
151:
1.1 espie 152: void
1.3 espie 153: Job_Touch(GNode *gn, bool silent)
1.1 espie 154: {
1.3 espie 155: if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) {
156: /*
1.9 espie 157: * .JOIN, .USE, and .OPTIONAL targets are "virtual" targets
158: * and, as such, shouldn't really be created.
1.3 espie 159: */
160: return;
161: }
1.1 espie 162:
1.3 espie 163: if (!silent) {
164: (void)fprintf(stdout, "touch %s\n", gn->name);
165: (void)fflush(stdout);
166: }
1.1 espie 167:
1.3 espie 168: if (noExecute) {
169: return;
170: }
1.1 espie 171:
1.3 espie 172: if (gn->type & OP_ARCHV) {
173: Arch_Touch(gn);
174: } else if (gn->type & OP_LIB) {
175: Arch_TouchLib(gn);
176: } else {
177: const char *file = gn->path != NULL ? gn->path : gn->name;
178:
179: if (set_times(file) == -1){
1.6 espie 180: if (rewrite_time(file) == -1) {
1.5 espie 181: (void)fprintf(stdout,
182: "*** couldn't touch %s: %s", file,
1.3 espie 183: strerror(errno));
184: (void)fflush(stdout);
1.9 espie 185: }
1.1 espie 186: }
187: }
188: }
189:
190: void
1.7 espie 191: Make_TimeStamp(GNode *parent, GNode *child)
1.1 espie 192: {
1.8 espie 193: if (is_strictly_before(parent->cmtime, child->mtime))
194: parent->cmtime = child->mtime;
1.1 espie 195: }
196:
197: void
1.9 espie 198: Make_HandleUse(GNode *cgn, /* The .USE node */
1.1 espie 199: GNode *pgn) /* The target of the .USE node */
200: {
1.3 espie 201: GNode *gn; /* A child of the .USE node */
202: LstNode ln; /* An element in the children list */
1.1 espie 203:
1.3 espie 204: if (cgn->type & (OP_USE|OP_TRANSFORM)) {
205: if ((cgn->type & OP_USE) || Lst_IsEmpty(&pgn->commands)) {
1.9 espie 206: /* .USE or transformation and target has no commands
207: * -- append the child's commands to the parent. */
1.3 espie 208: Lst_Concat(&pgn->commands, &cgn->commands);
209: }
1.1 espie 210:
1.5 espie 211: for (ln = Lst_First(&cgn->children); ln != NULL;
1.3 espie 212: ln = Lst_Adv(ln)) {
213: gn = (GNode *)Lst_Datum(ln);
214:
215: if (Lst_AddNew(&pgn->children, gn)) {
216: Lst_AtEnd(&gn->parents, pgn);
1.4 espie 217: pgn->unmade++;
1.3 espie 218: }
219: }
1.1 espie 220:
1.3 espie 221: pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_TRANSFORM);
1.1 espie 222:
1.3 espie 223: /*
224: * This child node is now "made", so we decrement the count of
225: * unmade children in the parent... We also remove the child
226: * from the parent's list to accurately reflect the number of
227: * decent children the parent has. This is used by Make_Run to
1.9 espie 228: * decide whether to queue the parent or examine its children...
1.3 espie 229: */
1.9 espie 230: if (cgn->type & OP_USE)
1.3 espie 231: pgn->unmade--;
1.1 espie 232: }
233: }
234:
235: static void
1.9 espie 236: MakeAddAllSrc(void *cgnp, void *pgnp)
1.1 espie 237: {
1.9 espie 238: GNode *child = (GNode *)cgnp;
239: GNode *parent = (GNode *)pgnp;
240: if ((child->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) {
241: const char *target;
1.3 espie 242:
1.9 espie 243: if (OP_NOP(child->type) ||
244: (target = Varq_Value(TARGET_INDEX, child)) == NULL) {
1.3 espie 245: /*
246: * this node is only source; use the specific pathname
247: * for it
248: */
1.9 espie 249: target = child->path != NULL ? child->path :
250: child->name;
1.3 espie 251: }
1.1 espie 252:
1.9 espie 253: Varq_Append(ALLSRC_INDEX, target, parent);
254: if (parent->type & OP_JOIN) {
255: if (child->made == MADE)
256: Varq_Append(OODATE_INDEX, target, parent);
257: } else if (is_strictly_before(parent->mtime, child->mtime) ||
258: (!is_strictly_before(child->mtime, now) &&
259: child->made == MADE)) {
1.3 espie 260: /*
261: * It goes in the OODATE variable if the parent is
262: * younger than the child or if the child has been
263: * modified more recently than the start of the make.
1.9 espie 264: * This is to keep make from getting confused if
265: * something else updates the parent after the
266: * make starts (shouldn't happen, I know, but sometimes
267: * it does). In such a case, if we've updated the kid,
268: * the parent is likely to have a modification time
269: * later than that of the kid and anything that relies
270: * on the OODATE variable will be hosed.
1.3 espie 271: */
1.9 espie 272: Varq_Append(OODATE_INDEX, target, parent);
1.3 espie 273: }
1.1 espie 274: }
275: }
276:
277: void
278: Make_DoAllVar(GNode *gn)
279: {
1.3 espie 280: Lst_ForEach(&gn->children, MakeAddAllSrc, gn);
1.1 espie 281:
1.3 espie 282: if (Varq_Value(OODATE_INDEX, gn) == NULL)
283: Varq_Set(OODATE_INDEX, "", gn);
284: if (Varq_Value(ALLSRC_INDEX, gn) == NULL)
285: Varq_Set(ALLSRC_INDEX, "", gn);
1.1 espie 286:
1.3 espie 287: if (gn->type & OP_JOIN)
288: Varq_Set(TARGET_INDEX, Varq_Value(ALLSRC_INDEX, gn), gn);
1.1 espie 289: }
290:
291: /* Wrapper to call Make_TimeStamp from a forEach loop. */
292: static void
1.9 espie 293: MakeTimeStamp(void *parent, void *child)
1.1 espie 294: {
1.9 espie 295: Make_TimeStamp((GNode *)parent, (GNode *)child);
1.1 espie 296: }
297:
298: bool
1.9 espie 299: Make_OODate(GNode *gn)
1.1 espie 300: {
1.9 espie 301: bool oodate;
1.1 espie 302:
303: /*
1.3 espie 304: * Certain types of targets needn't even be sought as their datedness
305: * doesn't depend on their modification time...
1.1 espie 306: */
1.3 espie 307: if ((gn->type & (OP_JOIN|OP_USE|OP_EXEC)) == 0) {
308: (void)Dir_MTime(gn);
309: if (DEBUG(MAKE)) {
1.9 espie 310: if (!is_out_of_date(gn->mtime))
1.5 espie 311: printf("modified %s...",
1.3 espie 312: time_to_string(gn->mtime));
1.9 espie 313: else
1.3 espie 314: printf("non-existent...");
315: }
1.1 espie 316: }
317:
318: /*
1.3 espie 319: * A target is remade in one of the following circumstances:
1.9 espie 320: * - its modification time is smaller than that of its youngest child
321: * and it would actually be run (has commands or type OP_NOP)
322: * - it's the object of a force operator
323: * - it has no children, was on the lhs of an operator and doesn't
324: * exist already.
1.3 espie 325: *
326: * Libraries are only considered out-of-date if the archive module says
327: * they are.
1.1 espie 328: */
1.3 espie 329: if (gn->type & OP_USE) {
330: /*
331: * If the node is a USE node it is *never* out of date
332: * no matter *what*.
333: */
1.9 espie 334: if (DEBUG(MAKE))
1.3 espie 335: printf(".USE node...");
336: oodate = false;
337: } else if ((gn->type & OP_LIB) && Arch_IsLib(gn)) {
1.9 espie 338: if (DEBUG(MAKE))
339: printf("library...");
1.3 espie 340:
1.9 espie 341: /* always out of date if no children and :: target */
1.3 espie 342: oodate = Arch_LibOODate(gn) ||
343: (is_out_of_date(gn->cmtime) && (gn->type & OP_DOUBLEDEP));
344: } else if (gn->type & OP_JOIN) {
345: /*
346: * A target with the .JOIN attribute is only considered
347: * out-of-date if any of its children was out-of-date.
348: */
1.9 espie 349: if (DEBUG(MAKE))
1.3 espie 350: printf(".JOIN node...");
351: oodate = gn->childMade;
352: } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) {
353: /*
1.9 espie 354: * A node which is the object of the force (!) operator or which
355: * has the .EXEC attribute is always considered out-of-date.
1.3 espie 356: */
357: if (DEBUG(MAKE)) {
1.9 espie 358: if (gn->type & OP_FORCE)
1.3 espie 359: printf("! operator...");
1.9 espie 360: else if (gn->type & OP_PHONY)
1.3 espie 361: printf(".PHONY node...");
1.9 espie 362: else
1.3 espie 363: printf(".EXEC node...");
364: }
365: oodate = true;
366: } else if (is_strictly_before(gn->mtime, gn->cmtime) ||
1.9 espie 367: (is_out_of_date(gn->cmtime) &&
1.3 espie 368: (is_out_of_date(gn->mtime) || (gn->type & OP_DOUBLEDEP)))) {
369: /*
370: * A node whose modification time is less than that of its
371: * youngest child or that has no children (cmtime ==
372: * OUT_OF_DATE) and either doesn't exist (mtime == OUT_OF_DATE)
1.9 espie 373: * or was the object of a :: operator is out-of-date.
1.3 espie 374: */
375: if (DEBUG(MAKE)) {
1.9 espie 376: if (is_strictly_before(gn->mtime, gn->cmtime))
1.3 espie 377: printf("modified before source...");
1.9 espie 378: else if (is_out_of_date(gn->mtime))
1.3 espie 379: printf("non-existent and no sources...");
1.9 espie 380: else
1.3 espie 381: printf(":: operator and no sources...");
382: }
383: oodate = true;
384: } else {
385: oodate = false;
386: }
1.1 espie 387:
1.3 espie 388: /*
389: * If the target isn't out-of-date, the parents need to know its
390: * modification time. Note that targets that appear to be out-of-date
391: * but aren't, because they have no commands and aren't of type OP_NOP,
392: * have their mtime stay below their children's mtime to keep parents
393: * from thinking they're out-of-date.
394: */
395: if (!oodate)
396: Lst_ForEach(&gn->parents, MakeTimeStamp, gn);
1.1 espie 397:
1.3 espie 398: return oodate;
1.1 espie 399: }
400:
1.10 ! espie 401: volatile sig_atomic_t got_signal;
! 402:
! 403: volatile sig_atomic_t got_SIGINT, got_SIGHUP, got_SIGQUIT,
! 404: got_SIGTERM, got_SIGTSTP, got_SIGTTOU, got_SIGTTIN, got_SIGWINCH;
! 405:
! 406: static void
! 407: setup_signal(int sig)
! 408: {
! 409: if (signal(sig, SIG_IGN) != SIG_IGN) {
! 410: (void)signal(sig, SigHandler);
! 411: }
! 412: }
! 413:
! 414: void
! 415: setup_all_signals()
! 416: {
! 417: /*
! 418: * Catch the four signals that POSIX specifies if they aren't ignored.
! 419: * handle_signal will take care of calling JobInterrupt if appropriate.
! 420: */
! 421: setup_signal(SIGINT);
! 422: setup_signal(SIGHUP);
! 423: setup_signal(SIGQUIT);
! 424: setup_signal(SIGTERM);
! 425: /*
! 426: * There are additional signals that need to be caught and passed if
! 427: * either the export system wants to be told directly of signals or if
! 428: * we're giving each job its own process group (since then it won't get
! 429: * signals from the terminal driver as we own the terminal)
! 430: */
! 431: #if defined(USE_PGRP)
! 432: setup_signal(SIGTSTP);
! 433: setup_signal(SIGTTOU);
! 434: setup_signal(SIGTTIN);
! 435: setup_signal(SIGWINCH);
! 436: #endif
! 437: }
! 438:
! 439: void
! 440: SigHandler(int sig)
! 441: {
! 442: switch(sig) {
! 443: case SIGINT:
! 444: got_SIGINT++;
! 445: got_signal = 1;
! 446: break;
! 447: case SIGHUP:
! 448: got_SIGHUP++;
! 449: got_signal = 1;
! 450: break;
! 451: case SIGQUIT:
! 452: got_SIGQUIT++;
! 453: got_signal = 1;
! 454: break;
! 455: case SIGTERM:
! 456: got_SIGTERM++;
! 457: got_signal = 1;
! 458: break;
! 459: #ifdef USE_PGRP
! 460: case SIGTSTP:
! 461: got_SIGTSTP++;
! 462: got_signal = 1;
! 463: break;
! 464: case SIGTTOU:
! 465: got_SIGTTOU++;
! 466: got_signal = 1;
! 467: break;
! 468: case SIGTTIN:
! 469: got_SIGTTIN++;
! 470: got_signal = 1;
! 471: break;
! 472: case SIGWINCH:
! 473: got_SIGWINCH++;
! 474: got_signal = 1;
! 475: break;
! 476: #endif
! 477: }
! 478: }
! 479:
! 480: /* The following array is used to make a fast determination of which
! 481: * characters are interpreted specially by the shell. If a command
! 482: * contains any of these characters, it is executed by the shell, not
! 483: * directly by us. */
! 484: static char meta[256];
! 485:
! 486: void
! 487: setup_meta(void)
! 488: {
! 489: char *p;
! 490:
! 491: for (p = "#=|^(){};&<>*?[]:$`\\\n"; *p != '\0'; p++)
! 492: meta[(unsigned char) *p] = 1;
! 493: /* The null character serves as a sentinel in the string. */
! 494: meta[0] = 1;
! 495: }
! 496:
! 497: static char **
! 498: recheck_command_for_shell(char **av)
! 499: {
! 500: char *runsh[] = {
! 501: "alias", "cd", "eval", "exit", "read", "set", "ulimit",
! 502: "unalias", "unset", "wait", "umask", NULL
! 503: };
! 504:
! 505: char **p;
! 506:
! 507: /* optimization: if exec cmd, we avoid the intermediate shell */
! 508: if (strcmp(av[0], "exec") == 0)
! 509: av++;
! 510:
! 511: for (p = runsh; *p; p++)
! 512: if (strcmp(av[0], *p) == 0)
! 513: return NULL;
! 514:
! 515: return av;
! 516: }
! 517:
! 518: static void
! 519: run_command(const char *cmd, bool errCheck)
! 520: {
! 521: const char *p;
! 522: char *shargv[4];
! 523: char **todo;
! 524:
! 525: shargv[0] = _PATH_BSHELL;
! 526:
! 527: shargv[1] = errCheck ? "-ec" : "-c";
! 528: shargv[2] = (char *)cmd;
! 529: shargv[3] = NULL;
! 530:
! 531: todo = shargv;
! 532:
! 533:
! 534: /* Search for meta characters in the command. If there are no meta
! 535: * characters, there's no need to execute a shell to execute the
! 536: * command. */
! 537: for (p = cmd; !meta[(unsigned char)*p]; p++)
! 538: continue;
! 539: if (*p == '\0') {
! 540: char *bp;
! 541: char **av;
! 542: int argc;
! 543: /* No meta-characters, so probably no need to exec a shell.
! 544: * Break the command into words to form an argument vector
! 545: * we can execute. */
! 546: av = brk_string(cmd, &argc, &bp);
! 547: av = recheck_command_for_shell(av);
! 548: if (av != NULL)
! 549: todo = av;
! 550: }
! 551: execvp(todo[0], todo);
! 552:
! 553: if (errno == ENOENT)
! 554: fprintf(stderr, "%s: not found\n", todo[0]);
! 555: else
! 556: perror(todo[0]);
! 557: _exit(1);
! 558: }
! 559:
! 560: /*-
! 561: *-----------------------------------------------------------------------
! 562: * setup_and_run_command --
! 563: * Execute the next command for a target. If the command returns an
! 564: * error, the node's made field is set to ERROR and creation stops.
! 565: *
! 566: * Results:
! 567: * 0 in case of error, 1 if ok.
! 568: *
! 569: * Side Effects:
! 570: * The node's 'made' field may be set to ERROR.
! 571: *-----------------------------------------------------------------------
! 572: */
! 573: static int
! 574: setup_and_run_command(char *cmd, GNode *gn, int dont_fork)
! 575: {
! 576: char *cmdStart; /* Start of expanded command */
! 577: bool silent; /* Don't print command */
! 578: bool doExecute; /* Execute the command */
! 579: bool errCheck; /* Check errors */
! 580: int reason; /* Reason for child's death */
! 581: int status; /* Description of child's death */
! 582: pid_t cpid; /* Child actually found */
! 583: pid_t stat; /* Status of fork */
! 584:
! 585: silent = gn->type & OP_SILENT;
! 586: errCheck = !(gn->type & OP_IGNORE);
! 587: doExecute = !noExecute;
! 588:
! 589: cmdStart = Var_Subst(cmd, &gn->context, false);
! 590:
! 591: /* How can we execute a null command ? we warn the user that the
! 592: * command expanded to nothing (is this the right thing to do?). */
! 593: if (*cmdStart == '\0') {
! 594: free(cmdStart);
! 595: Error("%s expands to empty string", cmd);
! 596: return 1;
! 597: } else
! 598: cmd = cmdStart;
! 599:
! 600: for (;; cmd++) {
! 601: if (*cmd == '@')
! 602: silent = DEBUG(LOUD) ? false : true;
! 603: else if (*cmd == '-')
! 604: errCheck = false;
! 605: else if (*cmd == '+')
! 606: doExecute = true;
! 607: else
! 608: break;
! 609: }
! 610: while (isspace(*cmd))
! 611: cmd++;
! 612: /* Print the command before echoing if we're not supposed to be quiet
! 613: * for this one. We also print the command if -n given. */
! 614: if (!silent || noExecute) {
! 615: printf("%s\n", cmd);
! 616: fflush(stdout);
! 617: }
! 618: /* If we're not supposed to execute any commands, this is as far as
! 619: * we go... */
! 620: if (!doExecute)
! 621: return 1;
! 622:
! 623: /* if we're running in parallel mode, we try not to fork the last
! 624: * command, since it's exit status will be just fine... unless
! 625: * errCheck is not set, in which case we must deal with the
! 626: * status ourselves.
! 627: */
! 628: if (dont_fork && errCheck)
! 629: run_command(cmd, errCheck);
! 630: /*NOTREACHED*/
! 631:
! 632: /* Fork and execute the single command. If the fork fails, we abort. */
! 633: switch (cpid = fork()) {
! 634: case -1:
! 635: Fatal("Could not fork");
! 636: /*NOTREACHED*/
! 637: case 0:
! 638: run_command(cmd, errCheck);
! 639: /*NOTREACHED*/
! 640: default:
! 641: break;
! 642: }
! 643: free(cmdStart);
! 644:
! 645: /* The child is off and running. Now all we can do is wait... */
! 646: while (1) {
! 647:
! 648: while ((stat = wait(&reason)) != cpid) {
! 649: if (stat == -1 && errno != EINTR)
! 650: break;
! 651: }
! 652:
! 653: if (got_signal)
! 654: break;
! 655:
! 656: if (stat != -1) {
! 657: if (WIFSTOPPED(reason))
! 658: status = WSTOPSIG(reason); /* stopped */
! 659: else if (WIFEXITED(reason)) {
! 660: status = WEXITSTATUS(reason); /* exited */
! 661: if (status != 0)
! 662: printf("*** Error code %d", status);
! 663: } else {
! 664: status = WTERMSIG(reason); /* signaled */
! 665: printf("*** Signal %d", status);
! 666: }
! 667:
! 668:
! 669: if (!WIFEXITED(reason) || status != 0) {
! 670: if (errCheck) {
! 671: gn->made = ERROR;
! 672: if (keepgoing)
! 673: /* Abort the current target,
! 674: * but let others continue. */
! 675: printf(" (continuing)\n");
! 676: } else {
! 677: /* Continue executing commands for
! 678: * this target. If we return 0,
! 679: * this will happen... */
! 680: printf(" (ignored)\n");
! 681: status = 0;
! 682: }
! 683: }
! 684: return !status;
! 685: } else
! 686: Fatal("error in wait: %d", stat);
! 687: /*NOTREACHED*/
! 688: }
! 689: return 0;
! 690: }
! 691:
! 692: static void
! 693: handle_compat_interrupts(GNode *gn)
! 694: {
! 695: if (!Targ_Precious(gn)) {
! 696: char *file = Varq_Value(TARGET_INDEX, gn);
! 697:
! 698: if (!noExecute && eunlink(file) != -1)
! 699: Error("*** %s removed\n", file);
! 700: }
! 701: if (got_SIGINT) {
! 702: signal(SIGINT, SIG_IGN);
! 703: signal(SIGTERM, SIG_IGN);
! 704: signal(SIGHUP, SIG_IGN);
! 705: signal(SIGQUIT, SIG_IGN);
! 706: got_signal = 0;
! 707: got_SIGINT = 0;
! 708: run_gnode(interrupt_node, 0);
! 709: exit(255);
! 710: }
! 711: exit(255);
! 712: }
! 713:
! 714: int
! 715: run_gnode(GNode *gn, int parallel)
! 716: {
! 717: LstNode ln, nln;
! 718:
! 719: if (gn != NULL && (gn->type & OP_DUMMY) == 0) {
! 720: gn->made = MADE;
! 721: for (ln = Lst_First(&gn->commands); ln != NULL; ln = nln) {
! 722: nln = Lst_Adv(ln);
! 723: if (setup_and_run_command(Lst_Datum(ln), gn,
! 724: parallel && nln == NULL) == 0)
! 725: break;
! 726: }
! 727: if (got_signal && !parallel)
! 728: handle_compat_interrupts(gn);
! 729: return gn->made;
! 730: } else
! 731: return NOSUCHNODE;
! 732: }
! 733:
! 734: void
! 735: setup_engine()
! 736: {
! 737: static int already_setup = 0;
! 738:
! 739: if (!already_setup) {
! 740: setup_meta();
! 741: setup_all_signals();
! 742: already_setup = 1;
! 743: }
! 744: }