- We use vfork() so if execv fails we should use _exit().
[dragonfly.git] / usr.bin / make / compat.c
CommitLineData
984263bc 1/*
9a309bcc
MD
2 * Copyright (c) 1988, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
984263bc
MD
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. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
1de703da
MD
38 *
39 * @(#)compat.c 8.2 (Berkeley) 3/19/94
40 * $FreeBSD: src/usr.bin/make/compat.c,v 1.16.2.2 2000/07/01 12:24:21 ps Exp $
1f4d0184 41 * $DragonFly: src/usr.bin/make/Attic/compat.c,v 1.25 2005/01/22 11:28:03 okumoto Exp $
984263bc
MD
42 */
43
984263bc
MD
44/*-
45 * compat.c --
46 * The routines in this file implement the full-compatibility
47 * mode of PMake. Most of the special functionality of PMake
48 * is available in this mode. Things not supported:
49 * - different shells.
50 * - friendly variable substitution.
51 *
52 * Interface:
53 * Compat_Run Initialize things for this module and recreate
54 * thems as need creatin'
55 */
56
9863ce62
MO
57#include <sys/types.h>
58#include <sys/wait.h>
59#include <ctype.h>
60#include <errno.h>
61#include <signal.h>
62#include <stdlib.h>
63#include <string.h>
64#include <unistd.h>
65
66#include "compat.h"
67#include "config.h"
68#include "dir.h"
69#include "globals.h"
70#include "GNode.h"
71#include "job.h"
72#include "make.h"
73#include "str.h"
74#include "suff.h"
75#include "targ.h"
76#include "util.h"
77#include "var.h"
984263bc
MD
78
79/*
80 * The following array is used to make a fast determination of which
81 * characters are interpreted specially by the shell. If a command
82 * contains any of these characters, it is executed by the shell, not
83 * directly by us.
84 */
85
86static char meta[256];
87
9edd457e 88static GNode *curTarg = NULL;
984263bc 89static GNode *ENDNode;
89a1b397
JS
90static sig_atomic_t interrupted;
91
2d8a3be7 92static void CompatInterrupt(int);
9edd457e 93static int CompatMake(void *, void *);
b3820a09 94static int shellneed(char *);
984263bc 95
40763d81
JS
96static void
97CompatInit(void)
98{
271e747f 99 const char *cp; /* Pointer to string of shell meta-characters */
40763d81
JS
100
101 for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) {
fbfaa208 102 meta[(unsigned char)*cp] = 1;
40763d81
JS
103 }
104 /*
105 * The null character serves as a sentinel in the string.
106 */
107 meta[0] = 1;
108}
109
89a1b397
JS
110/*
111 * Interrupt handler - set flag and defer handling to the main code
112 */
113static void
114CompatCatchSig(int signo)
115{
116
117 interrupted = signo;
118}
119
984263bc
MD
120/*-
121 *-----------------------------------------------------------------------
122 * CompatInterrupt --
123 * Interrupt the creation of the current target and remove it if
124 * it ain't precious.
125 *
126 * Results:
127 * None.
128 *
129 * Side Effects:
130 * The target is removed and the process exits. If .INTERRUPT exists,
131 * its commands are run first WITH INTERRUPTS IGNORED..
132 *
133 *-----------------------------------------------------------------------
134 */
135static void
bf2bcf34 136CompatInterrupt(int signo)
984263bc
MD
137{
138 GNode *gn;
89a1b397
JS
139 sigset_t nmask, omask;
140
141 sigemptyset(&nmask);
142 sigaddset(&nmask, SIGINT);
143 sigaddset(&nmask, SIGTERM);
144 sigaddset(&nmask, SIGHUP);
145 sigaddset(&nmask, SIGQUIT);
146 sigprocmask(SIG_SETMASK, &nmask, &omask);
147
148 /* prevent recursion in evaluation of .INTERRUPT */
149 interrupted = 0;
984263bc 150
fbfaa208 151 if ((curTarg != NULL) && !Targ_Precious(curTarg)) {
984263bc 152 char *p1;
fbfaa208 153 char *file = Var_Value(TARGET, curTarg, &p1);
984263bc
MD
154
155 if (!noExecute && eunlink(file) != -1) {
fbfaa208 156 printf("*** %s removed\n", file);
984263bc 157 }
a4516861 158 free(p1);
89a1b397 159 }
984263bc 160
89a1b397
JS
161 /*
162 * Run .INTERRUPT only if hit with interrupt signal
163 */
164 if (signo == SIGINT) {
165 gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
166 if (gn != NULL) {
0a7e0b85 167 Lst_ForEach(&gn->commands, Compat_RunCommand, (void *)gn);
984263bc 168 }
984263bc 169 }
89a1b397
JS
170
171 sigprocmask(SIG_SETMASK, &omask, NULL);
172
984263bc
MD
173 if (signo == SIGQUIT)
174 exit(signo);
fbfaa208
MO
175 signal(signo, SIG_DFL);
176 kill(getpid(), signo);
984263bc 177}
fbfaa208 178
984263bc
MD
179/*-
180 *-----------------------------------------------------------------------
181 * shellneed --
fbfaa208 182 *
984263bc
MD
183 * Results:
184 * Returns 1 if a specified line must be executed by the shell,
35c3900b 185 * and 0 if it can be run via execve.
984263bc
MD
186 *
187 * Side Effects:
188 * None.
fbfaa208 189 *
984263bc
MD
190 *-----------------------------------------------------------------------
191 */
192static int
271e747f 193shellneed(char *cmd)
984263bc 194{
35c3900b
MO
195 static const char *sh_builtin[] = {
196 "alias", "cd", "eval", "exec",
197 "exit", "read", "set", "ulimit",
198 "unalias", "umask", "unset", "wait",
199 ":", NULL
200 };
271e747f
MO
201 char **av;
202 const char **p;
203 int ac;
984263bc
MD
204
205 av = brk_string(cmd, &ac, TRUE);
35c3900b 206 for (p = sh_builtin; *p != 0; p++)
984263bc
MD
207 if (strcmp(av[1], *p) == 0)
208 return (1);
209 return (0);
210}
fbfaa208 211
984263bc
MD
212/*-
213 *-----------------------------------------------------------------------
40763d81 214 * Compat_RunCommand --
984263bc
MD
215 * Execute the next command for a target. If the command returns an
216 * error, the node's made field is set to ERROR and creation stops.
84de9e23 217 * The node from which the command came is also given.
984263bc
MD
218 *
219 * Results:
220 * 0 if the command succeeded, 1 if an error occurred.
221 *
222 * Side Effects:
223 * The node's 'made' field may be set to ERROR.
224 *
225 *-----------------------------------------------------------------------
226 */
40763d81 227int
fbfaa208 228Compat_RunCommand(void *cmdp, void *gnp)
984263bc
MD
229{
230 char *cmdStart; /* Start of expanded command */
9a309bcc 231 char *cp;
984263bc 232 Boolean silent, /* Don't print command */
40763d81 233 doit, /* Execute even in -n */
984263bc
MD
234 errCheck; /* Check errors */
235 int reason; /* Reason for child's death */
236 int status; /* Description of child's death */
237 int cpid; /* Child actually found */
454224cf 238 ReturnStatus rstat; /* Status of fork */
e035e56b 239 LstNode *cmdNode; /* Node where current command is located */
984263bc 240 char **av; /* Argument vector for thing to exec */
984263bc 241 int internal; /* Various values.. */
9a4c88c2
MO
242 char *cmd = cmdp;
243 GNode *gn = gnp;
984263bc
MD
244
245 /*
246 * Avoid clobbered variable warnings by forcing the compiler
247 * to ``unregister'' variables
248 */
249#if __GNUC__
250 (void) &av;
251 (void) &errCheck;
252#endif
253 silent = gn->type & OP_SILENT;
254 errCheck = !(gn->type & OP_IGNORE);
40763d81 255 doit = FALSE;
984263bc 256
0a7e0b85 257 cmdNode = Lst_Member(&gn->commands, cmd);
fbfaa208 258 cmdStart = Var_Subst(NULL, cmd, gn, FALSE);
984263bc
MD
259
260 /*
261 * brk_string will return an argv with a NULL in av[0], thus causing
262 * execvp to choke and die horribly. Besides, how can we execute a null
263 * command? In any case, we warn the user that the command expanded to
264 * nothing (is this the right thing to do?).
265 */
266
267 if (*cmdStart == '\0') {
268 free(cmdStart);
269 Error("%s expands to empty string", cmd);
fbfaa208 270 return (0);
984263bc
MD
271 } else {
272 cmd = cmdStart;
273 }
bf2bcf34 274 Lst_Replace(cmdNode, cmdStart);
984263bc
MD
275
276 if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
0a7e0b85 277 Lst_AtEnd(&ENDNode->commands, cmdStart);
fbfaa208 278 return (0);
984263bc
MD
279 } else if (strcmp(cmdStart, "...") == 0) {
280 gn->type |= OP_SAVE_CMDS;
fbfaa208 281 return (0);
984263bc
MD
282 }
283
40763d81
JS
284 while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) {
285 switch (*cmd) {
286
287 case '@':
984263bc 288 silent = DEBUG(LOUD) ? FALSE : TRUE;
40763d81
JS
289 break;
290
291 case '-':
984263bc 292 errCheck = FALSE;
40763d81
JS
293 break;
294
295 case '+':
296 doit = TRUE;
297 if (!meta[0]) /* we came here from jobs */
298 CompatInit();
299 break;
984263bc
MD
300 }
301 cmd++;
302 }
303
304 while (isspace((unsigned char)*cmd))
305 cmd++;
306
307 /*
308 * Search for meta characters in the command. If there are no meta
309 * characters, there's no need to execute a shell to execute the
310 * command.
311 */
312 for (cp = cmd; !meta[(unsigned char)*cp]; cp++) {
313 continue;
314 }
315
316 /*
317 * Print the command before echoing if we're not supposed to be quiet for
40763d81 318 * this one. We also print the command if -n given, but not if '+'.
984263bc 319 */
40763d81 320 if (!silent || (noExecute && !doit)) {
fbfaa208 321 printf("%s\n", cmd);
984263bc
MD
322 fflush(stdout);
323 }
324
325 /*
326 * If we're not supposed to execute any commands, this is as far as
327 * we go...
328 */
40763d81 329 if (!doit && noExecute) {
984263bc
MD
330 return (0);
331 }
332
333 if (*cp != '\0') {
334 /*
335 * If *cp isn't the null character, we hit a "meta" character and
336 * need to pass the command off to the shell. We give the shell the
337 * -e flag as well as -c if it's supposed to exit when it hits an
338 * error.
339 */
899365c2 340 static char *shargv[4];
984263bc 341
899365c2 342 shargv[0] = shellPath;
984263bc
MD
343 shargv[1] = (errCheck ? "-ec" : "-c");
344 shargv[2] = cmd;
9a4c88c2 345 shargv[3] = NULL;
984263bc 346 av = shargv;
984263bc
MD
347 } else if ((internal = shellneed(cmd))) {
348 /*
349 * This command must be passed by the shell for other reasons..
350 * or.. possibly not at all.
351 */
899365c2 352 static char *shargv[4];
984263bc 353
899365c2 354 shargv[0] = shellPath;
984263bc
MD
355 shargv[1] = (errCheck ? "-ec" : "-c");
356 shargv[2] = cmd;
9a4c88c2 357 shargv[3] = NULL;
984263bc 358 av = shargv;
984263bc 359 } else {
fa8c3cfa 360 int argc; /* Number of arguments in av */
984263bc
MD
361 /*
362 * No meta-characters, so no need to exec a shell. Break the command
363 * into words to form an argument vector we can execute.
364 * brk_string sticks our name in av[0], so we have to
365 * skip over it...
366 */
367 av = brk_string(cmd, &argc, TRUE);
368 av += 1;
369 }
370
984263bc
MD
371 /*
372 * Fork and execute the single command. If the fork fails, we abort.
373 */
374 cpid = vfork();
375 if (cpid < 0) {
376 Fatal("Could not fork");
377 }
378 if (cpid == 0) {
454224cf 379 execvp(av[0], av);
bf2bcf34 380 write(STDERR_FILENO, av[0], strlen(av[0]));
fbfaa208
MO
381 write(STDERR_FILENO, ":", 1);
382 write(STDERR_FILENO, strerror(errno), strlen(strerror(errno)));
383 write(STDERR_FILENO, "\n", 1);
1f4d0184 384 _exit(1);
984263bc
MD
385 }
386
fbfaa208 387 /*
984263bc
MD
388 * we need to print out the command associated with this Gnode in
389 * Targ_PrintCmd from Targ_PrintGraph when debugging at level g2,
390 * in main(), Fatal() and DieHorribly(), therefore do not free it
fbfaa208 391 * when debugging.
984263bc
MD
392 */
393 if (!DEBUG(GRAPH2)) {
394 free(cmdStart);
fbfaa208 395 Lst_Replace(cmdNode, cmdp);
984263bc
MD
396 }
397
398 /*
399 * The child is off and running. Now all we can do is wait...
400 */
401 while (1) {
402
454224cf 403 while ((rstat = wait(&reason)) != cpid) {
89a1b397
JS
404 if (interrupted || (rstat == -1 && errno != EINTR)) {
405 break;
984263bc
MD
406 }
407 }
89a1b397
JS
408 if (interrupted)
409 CompatInterrupt(interrupted);
984263bc 410
454224cf 411 if (rstat > -1) {
984263bc
MD
412 if (WIFSTOPPED(reason)) {
413 status = WSTOPSIG(reason); /* stopped */
414 } else if (WIFEXITED(reason)) {
415 status = WEXITSTATUS(reason); /* exited */
416 if (status != 0) {
fbfaa208 417 printf("*** Error code %d", status);
984263bc
MD
418 }
419 } else {
420 status = WTERMSIG(reason); /* signaled */
fbfaa208 421 printf("*** Signal %d", status);
984263bc
MD
422 }
423
424
425 if (!WIFEXITED(reason) || (status != 0)) {
426 if (errCheck) {
427 gn->made = ERROR;
428 if (keepgoing) {
429 /*
430 * Abort the current target, but let others
431 * continue.
432 */
fbfaa208 433 printf(" (continuing)\n");
984263bc
MD
434 }
435 } else {
436 /*
437 * Continue executing commands for this target.
438 * If we return 0, this will happen...
439 */
fbfaa208 440 printf(" (ignored)\n");
984263bc
MD
441 status = 0;
442 }
443 }
444 break;
445 } else {
fbfaa208 446 Fatal("error in wait: %d", rstat);
984263bc
MD
447 /*NOTREACHED*/
448 }
449 }
450
451 return (status);
452}
fbfaa208 453
984263bc
MD
454/*-
455 *-----------------------------------------------------------------------
456 * CompatMake --
84de9e23 457 * Make a target, given the parent, to abort if necessary.
984263bc
MD
458 *
459 * Results:
460 * 0
461 *
462 * Side Effects:
463 * If an error is detected and not being ignored, the process exits.
464 *
465 *-----------------------------------------------------------------------
466 */
467static int
fbfaa208 468CompatMake(void *gnp, void *pgnp)
984263bc 469{
9a4c88c2
MO
470 GNode *gn = gnp;
471 GNode *pgn = pgnp;
fbfaa208 472
984263bc
MD
473 if (gn->type & OP_USE) {
474 Make_HandleUse(gn, pgn);
475 } else if (gn->made == UNMADE) {
476 /*
477 * First mark ourselves to be made, then apply whatever transformations
478 * the suffix module thinks are necessary. Once that's done, we can
479 * descend and make all our children. If any of them has an error
480 * but the -k flag was given, our 'make' field will be set FALSE again.
481 * This is our signal to not attempt to do anything but abort our
482 * parent as well.
483 */
484 gn->make = TRUE;
485 gn->made = BEINGMADE;
fbfaa208 486 Suff_FindDeps(gn);
0a7e0b85 487 Lst_ForEach(&gn->children, CompatMake, gn);
984263bc
MD
488 if (!gn->make) {
489 gn->made = ABORTED;
490 pgn->make = FALSE;
491 return (0);
492 }
493
0a7e0b85 494 if (Lst_Member(&gn->iParents, pgn) != NULL) {
984263bc 495 char *p1;
fbfaa208 496 Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
a4516861 497 free(p1);
984263bc
MD
498 }
499
500 /*
501 * All the children were made ok. Now cmtime contains the modification
502 * time of the newest child, we need to find out if we exist and when
503 * we were modified last. The criteria for datedness are defined by the
504 * Make_OODate function.
505 */
913800f5 506 DEBUGF(MAKE, ("Examining %s...", gn->name));
fbfaa208 507 if (!Make_OODate(gn)) {
984263bc 508 gn->made = UPTODATE;
913800f5 509 DEBUGF(MAKE, ("up-to-date.\n"));
984263bc 510 return (0);
913800f5
MD
511 } else {
512 DEBUGF(MAKE, ("out-of-date.\n"));
984263bc
MD
513 }
514
515 /*
516 * If the user is just seeing if something is out-of-date, exit now
517 * to tell him/her "yes".
518 */
519 if (queryFlag) {
fbfaa208 520 exit(1);
984263bc
MD
521 }
522
523 /*
524 * We need to be re-made. We also have to make sure we've got a $?
525 * variable. To be nice, we also define the $> variable using
526 * Make_DoAllVar().
527 */
528 Make_DoAllVar(gn);
529
530 /*
531 * Alter our type to tell if errors should be ignored or things
40763d81 532 * should not be printed so Compat_RunCommand knows what to do.
984263bc 533 */
fbfaa208 534 if (Targ_Ignore(gn)) {
984263bc
MD
535 gn->type |= OP_IGNORE;
536 }
fbfaa208 537 if (Targ_Silent(gn)) {
984263bc
MD
538 gn->type |= OP_SILENT;
539 }
540
fbfaa208 541 if (Job_CheckCommands(gn, Fatal)) {
984263bc
MD
542 /*
543 * Our commands are ok, but we still have to worry about the -t
544 * flag...
545 */
546 if (!touchFlag) {
547 curTarg = gn;
0a7e0b85 548 Lst_ForEach(&gn->commands, Compat_RunCommand, (void *)gn);
9edd457e 549 curTarg = NULL;
984263bc 550 } else {
fbfaa208 551 Job_Touch(gn, gn->type & OP_SILENT);
984263bc
MD
552 }
553 } else {
554 gn->made = ERROR;
555 }
556
557 if (gn->made != ERROR) {
558 /*
559 * If the node was made successfully, mark it so, update
560 * its modification time and timestamp all its parents. Note
561 * that for .ZEROTIME targets, the timestamping isn't done.
562 * This is to keep its state from affecting that of its parent.
563 */
564 gn->made = MADE;
565#ifndef RECHECK
566 /*
567 * We can't re-stat the thing, but we can at least take care of
568 * rules where a target depends on a source that actually creates
569 * the target, but only if it has changed, e.g.
570 *
571 * parse.h : parse.o
572 *
573 * parse.o : parse.y
574 * yacc -d parse.y
575 * cc -c y.tab.c
576 * mv y.tab.o parse.o
577 * cmp -s y.tab.h parse.h || mv y.tab.h parse.h
578 *
579 * In this case, if the definitions produced by yacc haven't
580 * changed from before, parse.h won't have been updated and
581 * gn->mtime will reflect the current modification time for
582 * parse.h. This is something of a kludge, I admit, but it's a
583 * useful one..
584 *
585 * XXX: People like to use a rule like
586 *
587 * FRC:
588 *
589 * To force things that depend on FRC to be made, so we have to
590 * check for gn->children being empty as well...
591 */
9863ce62 592 if (!Lst_IsEmpty(&gn->commands) || Lst_IsEmpty(&gn->children)) {
984263bc
MD
593 gn->mtime = now;
594 }
595#else
596 /*
597 * This is what Make does and it's actually a good thing, as it
598 * allows rules like
599 *
600 * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
601 *
602 * to function as intended. Unfortunately, thanks to the stateless
603 * nature of NFS (and the speed of this program), there are times
604 * when the modification time of a file created on a remote
605 * machine will not be modified before the stat() implied by
606 * the Dir_MTime occurs, thus leading us to believe that the file
607 * is unchanged, wreaking havoc with files that depend on this one.
608 *
609 * I have decided it is better to make too much than to make too
610 * little, so this stuff is commented out unless you're sure it's
611 * ok.
612 * -- ardeb 1/12/88
613 */
614 if (noExecute || Dir_MTime(gn) == 0) {
615 gn->mtime = now;
616 }
617 if (gn->cmtime > gn->mtime)
618 gn->mtime = gn->cmtime;
913800f5 619 DEBUGF(MAKE, ("update time: %s\n", Targ_FmtTime(gn->mtime)));
984263bc
MD
620#endif
621 if (!(gn->type & OP_EXEC)) {
622 pgn->childMade = TRUE;
623 Make_TimeStamp(pgn, gn);
624 }
625 } else if (keepgoing) {
626 pgn->make = FALSE;
627 } else {
628 char *p1;
629
fbfaa208 630 printf("\n\nStop in %s.\n", Var_Value(".CURDIR", gn, &p1));
a4516861 631 free(p1);
fbfaa208 632 exit(1);
984263bc
MD
633 }
634 } else if (gn->made == ERROR) {
635 /*
636 * Already had an error when making this beastie. Tell the parent
637 * to abort.
638 */
639 pgn->make = FALSE;
640 } else {
0a7e0b85 641 if (Lst_Member(&gn->iParents, pgn) != NULL) {
984263bc 642 char *p1;
fbfaa208 643 Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
a4516861 644 free(p1);
984263bc
MD
645 }
646 switch(gn->made) {
647 case BEINGMADE:
648 Error("Graph cycles through %s\n", gn->name);
649 gn->made = ERROR;
650 pgn->make = FALSE;
651 break;
652 case MADE:
653 if ((gn->type & OP_EXEC) == 0) {
654 pgn->childMade = TRUE;
655 Make_TimeStamp(pgn, gn);
656 }
657 break;
658 case UPTODATE:
659 if ((gn->type & OP_EXEC) == 0) {
660 Make_TimeStamp(pgn, gn);
661 }
662 break;
663 default:
664 break;
665 }
666 }
667
668 return (0);
669}
fbfaa208 670
984263bc
MD
671/*-
672 *-----------------------------------------------------------------------
673 * Compat_Run --
84de9e23 674 * Start making again, given a list of target nodes.
984263bc
MD
675 *
676 * Results:
677 * None.
678 *
679 * Side Effects:
680 * Guess what?
681 *
682 *-----------------------------------------------------------------------
683 */
684void
e035e56b 685Compat_Run(Lst *targs)
984263bc 686{
984263bc
MD
687 GNode *gn = NULL;/* Current root target */
688 int errors; /* Number of targets not remade due to errors */
689
40763d81 690 CompatInit();
899365c2 691 Shell_Init(); /* Set up shell. */
40763d81 692
984263bc 693 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
89a1b397 694 signal(SIGINT, CompatCatchSig);
984263bc
MD
695 }
696 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
89a1b397 697 signal(SIGTERM, CompatCatchSig);
984263bc
MD
698 }
699 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
89a1b397 700 signal(SIGHUP, CompatCatchSig);
984263bc
MD
701 }
702 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
89a1b397 703 signal(SIGQUIT, CompatCatchSig);
984263bc
MD
704 }
705
984263bc
MD
706 ENDNode = Targ_FindNode(".END", TARG_CREATE);
707 /*
708 * If the user has defined a .BEGIN target, execute the commands attached
709 * to it.
710 */
711 if (!queryFlag) {
712 gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
9edd457e 713 if (gn != NULL) {
0a7e0b85 714 Lst_ForEach(&gn->commands, Compat_RunCommand, gn);
984263bc
MD
715 if (gn->made == ERROR) {
716 printf("\n\nStop.\n");
717 exit(1);
718 }
719 }
720 }
721
722 /*
723 * For each entry in the list of targets to create, call CompatMake on
724 * it to create the thing. CompatMake will leave the 'made' field of gn
725 * in one of several states:
726 * UPTODATE gn was already up-to-date
727 * MADE gn was recreated successfully
728 * ERROR An error occurred while gn was being created
729 * ABORTED gn was not remade because one of its inferiors
730 * could not be made due to errors.
731 */
732 errors = 0;
fbfaa208 733 while (!Lst_IsEmpty(targs)) {
9a4c88c2 734 gn = Lst_DeQueue(targs);
fbfaa208 735 CompatMake(gn, gn);
984263bc
MD
736
737 if (gn->made == UPTODATE) {
fbfaa208 738 printf("`%s' is up to date.\n", gn->name);
984263bc 739 } else if (gn->made == ABORTED) {
fbfaa208 740 printf("`%s' not remade because of errors.\n", gn->name);
984263bc
MD
741 errors += 1;
742 }
743 }
744
745 /*
746 * If the user has defined a .END target, run its commands.
747 */
748 if (errors == 0) {
0a7e0b85 749 Lst_ForEach(&ENDNode->commands, Compat_RunCommand, gn);
984263bc
MD
750 }
751}