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