140394Sbostic /*
262092Sbostic * Copyright (c) 1988, 1989, 1990, 1993
362092Sbostic * The Regents of the University of California. All rights reserved.
440394Sbostic * Copyright (c) 1989 by Berkeley Softworks
540394Sbostic * All rights reserved.
640394Sbostic *
740394Sbostic * This code is derived from software contributed to Berkeley by
840394Sbostic * Adam de Boor.
940394Sbostic *
1042746Sbostic * %sccs.include.redist.c%
1140394Sbostic */
1240394Sbostic
1340394Sbostic #ifndef lint
14*69086Schristos static char sccsid[] = "@(#)compat.c 8.3 (Berkeley) 04/28/95";
1540394Sbostic #endif /* not lint */
1640394Sbostic
1740393Sbostic /*-
1840393Sbostic * compat.c --
1940393Sbostic * The routines in this file implement the full-compatibility
2040393Sbostic * mode of PMake. Most of the special functionality of PMake
2140393Sbostic * is available in this mode. Things not supported:
2240393Sbostic * - different shells.
2340393Sbostic * - friendly variable substitution.
2440393Sbostic *
2540393Sbostic * Interface:
2640393Sbostic * Compat_Run Initialize things for this module and recreate
2740393Sbostic * thems as need creatin'
2840393Sbostic */
2940393Sbostic
30*69086Schristos #include <stdio.h>
3140393Sbostic #include <sys/types.h>
32*69086Schristos #include <sys/signal.h>
33*69086Schristos #include <sys/wait.h>
34*69086Schristos #include <sys/errno.h>
3560304Sbostic #include <sys/stat.h>
3640393Sbostic #include <ctype.h>
3740393Sbostic #include "make.h"
3860285Sbostic #include "hash.h"
3960285Sbostic #include "dir.h"
4060285Sbostic #include "job.h"
4140393Sbostic extern int errno;
4240393Sbostic
4340393Sbostic /*
4440393Sbostic * The following array is used to make a fast determination of which
4540393Sbostic * characters are interpreted specially by the shell. If a command
4640393Sbostic * contains any of these characters, it is executed by the shell, not
4740393Sbostic * directly by us.
4840393Sbostic */
4940393Sbostic
5040393Sbostic static char meta[256];
5140393Sbostic
5240393Sbostic static GNode *curTarg = NILGNODE;
5340393Sbostic static GNode *ENDNode;
5460285Sbostic static void CompatInterrupt __P((int));
55*69086Schristos static int CompatRunCommand __P((ClientData, ClientData));
56*69086Schristos static int CompatMake __P((ClientData, ClientData));
5740393Sbostic
5840393Sbostic /*-
5940393Sbostic *-----------------------------------------------------------------------
6040393Sbostic * CompatInterrupt --
6140393Sbostic * Interrupt the creation of the current target and remove it if
6240393Sbostic * it ain't precious.
6340393Sbostic *
6440393Sbostic * Results:
6540393Sbostic * None.
6640393Sbostic *
6740393Sbostic * Side Effects:
6840393Sbostic * The target is removed and the process exits. If .INTERRUPT exists,
6940393Sbostic * its commands are run first WITH INTERRUPTS IGNORED..
7040393Sbostic *
7140393Sbostic *-----------------------------------------------------------------------
7240393Sbostic */
7346837Sbostic static void
CompatInterrupt(signo)7440393Sbostic CompatInterrupt (signo)
7540393Sbostic int signo;
7640393Sbostic {
7740393Sbostic GNode *gn;
7840393Sbostic
7940393Sbostic if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) {
80*69086Schristos char *p1;
81*69086Schristos char *file = Var_Value (TARGET, curTarg, &p1);
82*69086Schristos struct stat st;
8340393Sbostic
84*69086Schristos if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) &&
85*69086Schristos unlink(file) != -1) {
8640393Sbostic printf ("*** %s removed\n", file);
8740393Sbostic }
88*69086Schristos if (p1)
89*69086Schristos free(p1);
9040393Sbostic
9140393Sbostic /*
9240393Sbostic * Run .INTERRUPT only if hit with interrupt signal
9340393Sbostic */
9440393Sbostic if (signo == SIGINT) {
9540393Sbostic gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
9640393Sbostic if (gn != NILGNODE) {
9740393Sbostic Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
9840393Sbostic }
9940393Sbostic }
100*69086Schristos
10140393Sbostic }
102*69086Schristos exit (signo);
10340393Sbostic }
10440393Sbostic
10540393Sbostic /*-
10640393Sbostic *-----------------------------------------------------------------------
10740393Sbostic * CompatRunCommand --
10840393Sbostic * Execute the next command for a target. If the command returns an
10940393Sbostic * error, the node's made field is set to ERROR and creation stops.
11040393Sbostic *
11140393Sbostic * Results:
11240393Sbostic * 0 if the command succeeded, 1 if an error occurred.
11340393Sbostic *
11440393Sbostic * Side Effects:
11540393Sbostic * The node's 'made' field may be set to ERROR.
11640393Sbostic *
11740393Sbostic *-----------------------------------------------------------------------
11840393Sbostic */
11940393Sbostic static int
CompatRunCommand(cmdp,gnp)120*69086Schristos CompatRunCommand (cmdp, gnp)
121*69086Schristos ClientData cmdp; /* Command to execute */
122*69086Schristos ClientData gnp; /* Node from which the command came */
12340393Sbostic {
12440393Sbostic char *cmdStart; /* Start of expanded command */
12540393Sbostic register char *cp;
12640393Sbostic Boolean silent, /* Don't print command */
12740393Sbostic errCheck; /* Check errors */
12840393Sbostic union wait reason; /* Reason for child's death */
12940393Sbostic int status; /* Description of child's death */
13040393Sbostic int cpid; /* Child actually found */
13140393Sbostic ReturnStatus stat; /* Status of fork */
13240393Sbostic LstNode cmdNode; /* Node where current command is located */
13340393Sbostic char **av; /* Argument vector for thing to exec */
13440393Sbostic int argc; /* Number of arguments in av or 0 if not
13540393Sbostic * dynamically allocated */
13640393Sbostic Boolean local; /* TRUE if command should be executed
13740393Sbostic * locally */
138*69086Schristos char *cmd = (char *) cmdp;
139*69086Schristos GNode *gn = (GNode *) gnp;
14040393Sbostic
141*69086Schristos /*
14266394Schristos * Avoid clobbered variable warnings by forcing the compiler
14366394Schristos * to ``unregister'' variables
144*69086Schristos */
14566394Schristos #if __GNUC__
146*69086Schristos (void) &av;
14766394Schristos (void) &errCheck;
148*69086Schristos #endif
14940393Sbostic silent = gn->type & OP_SILENT;
15040393Sbostic errCheck = !(gn->type & OP_IGNORE);
15140393Sbostic
15240393Sbostic cmdNode = Lst_Member (gn->commands, (ClientData)cmd);
15360285Sbostic cmdStart = Var_Subst (NULL, cmd, gn, FALSE);
15440393Sbostic
15540393Sbostic /*
15640527Sbostic * brk_string will return an argv with a NULL in av[1], thus causing
15740393Sbostic * execvp to choke and die horribly. Besides, how can we execute a null
15840393Sbostic * command? In any case, we warn the user that the command expanded to
15940393Sbostic * nothing (is this the right thing to do?).
16040393Sbostic */
16140393Sbostic
16240393Sbostic if (*cmdStart == '\0') {
163*69086Schristos free(cmdStart);
16440539Sbostic Error("%s expands to empty string", cmd);
16540393Sbostic return(0);
16640393Sbostic } else {
16740393Sbostic cmd = cmdStart;
16840393Sbostic }
16940393Sbostic Lst_Replace (cmdNode, (ClientData)cmdStart);
17040393Sbostic
17140393Sbostic if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
17240393Sbostic (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart);
17340393Sbostic return(0);
17440393Sbostic } else if (strcmp(cmdStart, "...") == 0) {
17540393Sbostic gn->type |= OP_SAVE_CMDS;
17640393Sbostic return(0);
17740393Sbostic }
17840393Sbostic
17940393Sbostic while ((*cmd == '@') || (*cmd == '-')) {
18040393Sbostic if (*cmd == '@') {
18140393Sbostic silent = TRUE;
18240393Sbostic } else {
18340393Sbostic errCheck = FALSE;
18440393Sbostic }
18540393Sbostic cmd++;
18640393Sbostic }
18766394Schristos
18866394Schristos while (isspace((unsigned char)*cmd))
18966394Schristos cmd++;
19040393Sbostic
19140393Sbostic /*
19240393Sbostic * Search for meta characters in the command. If there are no meta
19340393Sbostic * characters, there's no need to execute a shell to execute the
19440393Sbostic * command.
19540393Sbostic */
19660285Sbostic for (cp = cmd; !meta[(unsigned char)*cp]; cp++) {
19740393Sbostic continue;
19840393Sbostic }
19940393Sbostic
20040393Sbostic /*
20140393Sbostic * Print the command before echoing if we're not supposed to be quiet for
20240393Sbostic * this one. We also print the command if -n given.
20340393Sbostic */
20440393Sbostic if (!silent || noExecute) {
20540393Sbostic printf ("%s\n", cmd);
20640393Sbostic fflush(stdout);
20740393Sbostic }
20840393Sbostic
20940393Sbostic /*
21040393Sbostic * If we're not supposed to execute any commands, this is as far as
21140393Sbostic * we go...
21240393Sbostic */
21340393Sbostic if (noExecute) {
21440393Sbostic return (0);
21540393Sbostic }
21640393Sbostic
21740393Sbostic if (*cp != '\0') {
21840393Sbostic /*
21940393Sbostic * If *cp isn't the null character, we hit a "meta" character and
22040393Sbostic * need to pass the command off to the shell. We give the shell the
22140393Sbostic * -e flag as well as -c if it's supposed to exit when it hits an
22240393Sbostic * error.
22340393Sbostic */
22440393Sbostic static char *shargv[4] = { "/bin/sh" };
22540393Sbostic
22640393Sbostic shargv[1] = (errCheck ? "-ec" : "-c");
22740393Sbostic shargv[2] = cmd;
22840393Sbostic shargv[3] = (char *)NULL;
22940393Sbostic av = shargv;
23040393Sbostic argc = 0;
23140393Sbostic } else {
23240393Sbostic /*
23340393Sbostic * No meta-characters, so no need to exec a shell. Break the command
23440393Sbostic * into words to form an argument vector we can execute.
23540527Sbostic * brk_string sticks our name in av[0], so we have to
23640393Sbostic * skip over it...
23740393Sbostic */
238*69086Schristos av = brk_string(cmd, &argc, TRUE);
23940393Sbostic av += 1;
24040393Sbostic }
24140393Sbostic
24240438Sbostic local = TRUE;
24340393Sbostic
24440393Sbostic /*
24540393Sbostic * Fork and execute the single command. If the fork fails, we abort.
24640393Sbostic */
24740393Sbostic cpid = vfork();
24840393Sbostic if (cpid < 0) {
24940393Sbostic Fatal("Could not fork");
25040393Sbostic }
25140393Sbostic if (cpid == 0) {
25240393Sbostic if (local) {
25340393Sbostic execvp(av[0], av);
25460285Sbostic (void) write (2, av[0], strlen (av[0]));
25560285Sbostic (void) write (2, ": not found\n", sizeof(": not found"));
25640393Sbostic } else {
25740438Sbostic (void)execv(av[0], av);
25840393Sbostic }
25940393Sbostic exit(1);
26040393Sbostic }
261*69086Schristos free(cmdStart);
262*69086Schristos Lst_Replace (cmdNode, (ClientData) NULL);
26340393Sbostic
26440393Sbostic /*
26540393Sbostic * The child is off and running. Now all we can do is wait...
26640393Sbostic */
26740393Sbostic while (1) {
26840393Sbostic
26946837Sbostic while ((stat = wait((int *)&reason)) != cpid) {
27040393Sbostic if (stat == -1 && errno != EINTR) {
27140393Sbostic break;
27240393Sbostic }
27340393Sbostic }
27440393Sbostic
27540393Sbostic if (stat > -1) {
27640393Sbostic if (WIFSTOPPED(reason)) {
27740393Sbostic status = reason.w_stopval; /* stopped */
27840393Sbostic } else if (WIFEXITED(reason)) {
27940393Sbostic status = reason.w_retcode; /* exited */
28040393Sbostic if (status != 0) {
28140393Sbostic printf ("*** Error code %d", status);
28240393Sbostic }
28340393Sbostic } else {
28440393Sbostic status = reason.w_termsig; /* signaled */
28540393Sbostic printf ("*** Signal %d", status);
28640393Sbostic }
28740393Sbostic
28840393Sbostic
28940393Sbostic if (!WIFEXITED(reason) || (status != 0)) {
29040393Sbostic if (errCheck) {
29140393Sbostic gn->made = ERROR;
29240393Sbostic if (keepgoing) {
29340393Sbostic /*
29440393Sbostic * Abort the current target, but let others
29540393Sbostic * continue.
29640393Sbostic */
29740393Sbostic printf (" (continuing)\n");
29840393Sbostic }
29940393Sbostic } else {
30040393Sbostic /*
30140393Sbostic * Continue executing commands for this target.
30240393Sbostic * If we return 0, this will happen...
30340393Sbostic */
30440393Sbostic printf (" (ignored)\n");
30540393Sbostic status = 0;
30640393Sbostic }
30740393Sbostic }
30840393Sbostic break;
30940393Sbostic } else {
31040393Sbostic Fatal ("error in wait: %d", stat);
31140393Sbostic /*NOTREACHED*/
31240393Sbostic }
31340393Sbostic }
31440393Sbostic
31540393Sbostic return (status);
31640393Sbostic }
31740393Sbostic
31840393Sbostic /*-
31940393Sbostic *-----------------------------------------------------------------------
32040393Sbostic * CompatMake --
32140393Sbostic * Make a target.
32240393Sbostic *
32340393Sbostic * Results:
32440393Sbostic * 0
32540393Sbostic *
32640393Sbostic * Side Effects:
32740393Sbostic * If an error is detected and not being ignored, the process exits.
32840393Sbostic *
32940393Sbostic *-----------------------------------------------------------------------
33040393Sbostic */
33140393Sbostic static int
CompatMake(gnp,pgnp)332*69086Schristos CompatMake (gnp, pgnp)
333*69086Schristos ClientData gnp; /* The node to make */
334*69086Schristos ClientData pgnp; /* Parent to abort if necessary */
33540393Sbostic {
336*69086Schristos GNode *gn = (GNode *) gnp;
337*69086Schristos GNode *pgn = (GNode *) pgnp;
33840393Sbostic if (gn->type & OP_USE) {
33940393Sbostic Make_HandleUse(gn, pgn);
34040393Sbostic } else if (gn->made == UNMADE) {
34140393Sbostic /*
34240393Sbostic * First mark ourselves to be made, then apply whatever transformations
34340393Sbostic * the suffix module thinks are necessary. Once that's done, we can
34440393Sbostic * descend and make all our children. If any of them has an error
34540393Sbostic * but the -k flag was given, our 'make' field will be set FALSE again.
34640393Sbostic * This is our signal to not attempt to do anything but abort our
34740393Sbostic * parent as well.
34840393Sbostic */
34940393Sbostic gn->make = TRUE;
35040393Sbostic gn->made = BEINGMADE;
35140393Sbostic Suff_FindDeps (gn);
35240393Sbostic Lst_ForEach (gn->children, CompatMake, (ClientData)gn);
35340393Sbostic if (!gn->make) {
35440393Sbostic gn->made = ABORTED;
35540393Sbostic pgn->make = FALSE;
35640393Sbostic return (0);
35740393Sbostic }
35840393Sbostic
35940393Sbostic if (Lst_Member (gn->iParents, pgn) != NILLNODE) {
360*69086Schristos char *p1;
361*69086Schristos Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
362*69086Schristos if (p1)
363*69086Schristos free(p1);
36440393Sbostic }
36540393Sbostic
36640393Sbostic /*
36740393Sbostic * All the children were made ok. Now cmtime contains the modification
36840393Sbostic * time of the newest child, we need to find out if we exist and when
36940393Sbostic * we were modified last. The criteria for datedness are defined by the
37040393Sbostic * Make_OODate function.
37140393Sbostic */
37240393Sbostic if (DEBUG(MAKE)) {
37340393Sbostic printf("Examining %s...", gn->name);
37440393Sbostic }
37540393Sbostic if (! Make_OODate(gn)) {
37640393Sbostic gn->made = UPTODATE;
37740393Sbostic if (DEBUG(MAKE)) {
37840393Sbostic printf("up-to-date.\n");
37940393Sbostic }
38040393Sbostic return (0);
38140393Sbostic } else if (DEBUG(MAKE)) {
38240393Sbostic printf("out-of-date.\n");
38340393Sbostic }
38440393Sbostic
38540393Sbostic /*
38640393Sbostic * If the user is just seeing if something is out-of-date, exit now
38740393Sbostic * to tell him/her "yes".
38840393Sbostic */
38940393Sbostic if (queryFlag) {
39040393Sbostic exit (-1);
39140393Sbostic }
39240393Sbostic
39340393Sbostic /*
39440393Sbostic * We need to be re-made. We also have to make sure we've got a $?
39540393Sbostic * variable. To be nice, we also define the $> variable using
39640393Sbostic * Make_DoAllVar().
39740393Sbostic */
39840393Sbostic Make_DoAllVar(gn);
39940393Sbostic
40040393Sbostic /*
40140393Sbostic * Alter our type to tell if errors should be ignored or things
40240393Sbostic * should not be printed so CompatRunCommand knows what to do.
40340393Sbostic */
40440393Sbostic if (Targ_Ignore (gn)) {
40540393Sbostic gn->type |= OP_IGNORE;
40640393Sbostic }
40740393Sbostic if (Targ_Silent (gn)) {
40840393Sbostic gn->type |= OP_SILENT;
40940393Sbostic }
41040393Sbostic
41140393Sbostic if (Job_CheckCommands (gn, Fatal)) {
41240393Sbostic /*
41340393Sbostic * Our commands are ok, but we still have to worry about the -t
41440393Sbostic * flag...
41540393Sbostic */
41640393Sbostic if (!touchFlag) {
41740393Sbostic curTarg = gn;
41840393Sbostic Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn);
41940393Sbostic curTarg = NILGNODE;
42040393Sbostic } else {
42140393Sbostic Job_Touch (gn, gn->type & OP_SILENT);
42240393Sbostic }
42340393Sbostic } else {
42440393Sbostic gn->made = ERROR;
42540393Sbostic }
42640393Sbostic
42740393Sbostic if (gn->made != ERROR) {
42840393Sbostic /*
42940393Sbostic * If the node was made successfully, mark it so, update
43040393Sbostic * its modification time and timestamp all its parents. Note
43140393Sbostic * that for .ZEROTIME targets, the timestamping isn't done.
43240393Sbostic * This is to keep its state from affecting that of its parent.
43340393Sbostic */
43440393Sbostic gn->made = MADE;
43540393Sbostic #ifndef RECHECK
43640393Sbostic /*
43740393Sbostic * We can't re-stat the thing, but we can at least take care of
43840393Sbostic * rules where a target depends on a source that actually creates
43940393Sbostic * the target, but only if it has changed, e.g.
44040393Sbostic *
44140393Sbostic * parse.h : parse.o
44240393Sbostic *
44340393Sbostic * parse.o : parse.y
44440393Sbostic * yacc -d parse.y
44540393Sbostic * cc -c y.tab.c
44640393Sbostic * mv y.tab.o parse.o
44740393Sbostic * cmp -s y.tab.h parse.h || mv y.tab.h parse.h
44840393Sbostic *
44940393Sbostic * In this case, if the definitions produced by yacc haven't
45040393Sbostic * changed from before, parse.h won't have been updated and
45140393Sbostic * gn->mtime will reflect the current modification time for
45240393Sbostic * parse.h. This is something of a kludge, I admit, but it's a
45340393Sbostic * useful one..
45440393Sbostic *
45540393Sbostic * XXX: People like to use a rule like
45640393Sbostic *
45740393Sbostic * FRC:
45840393Sbostic *
45940393Sbostic * To force things that depend on FRC to be made, so we have to
46040393Sbostic * check for gn->children being empty as well...
46140393Sbostic */
46240393Sbostic if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {
46340393Sbostic gn->mtime = now;
46440393Sbostic }
46540393Sbostic #else
46640393Sbostic /*
46740393Sbostic * This is what Make does and it's actually a good thing, as it
46840393Sbostic * allows rules like
46940393Sbostic *
47040393Sbostic * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
47140393Sbostic *
47240393Sbostic * to function as intended. Unfortunately, thanks to the stateless
47340393Sbostic * nature of NFS (and the speed of this program), there are times
47440393Sbostic * when the modification time of a file created on a remote
47540393Sbostic * machine will not be modified before the stat() implied by
47640393Sbostic * the Dir_MTime occurs, thus leading us to believe that the file
47740393Sbostic * is unchanged, wreaking havoc with files that depend on this one.
47840393Sbostic *
47940393Sbostic * I have decided it is better to make too much than to make too
48040393Sbostic * little, so this stuff is commented out unless you're sure it's
48140393Sbostic * ok.
48240393Sbostic * -- ardeb 1/12/88
48340393Sbostic */
48440393Sbostic if (noExecute || Dir_MTime(gn) == 0) {
48540393Sbostic gn->mtime = now;
48640393Sbostic }
48760285Sbostic if (gn->cmtime > gn->mtime)
48860285Sbostic gn->mtime = gn->cmtime;
48940393Sbostic if (DEBUG(MAKE)) {
49040393Sbostic printf("update time: %s\n", Targ_FmtTime(gn->mtime));
49140393Sbostic }
49240393Sbostic #endif
49340393Sbostic if (!(gn->type & OP_EXEC)) {
49440393Sbostic pgn->childMade = TRUE;
49540393Sbostic Make_TimeStamp(pgn, gn);
49640393Sbostic }
49740393Sbostic } else if (keepgoing) {
49840393Sbostic pgn->make = FALSE;
49940393Sbostic } else {
50040393Sbostic printf ("\n\nStop.\n");
50140393Sbostic exit (1);
50240393Sbostic }
50340393Sbostic } else if (gn->made == ERROR) {
50440393Sbostic /*
50540393Sbostic * Already had an error when making this beastie. Tell the parent
50640393Sbostic * to abort.
50740393Sbostic */
50840393Sbostic pgn->make = FALSE;
50940393Sbostic } else {
51040393Sbostic if (Lst_Member (gn->iParents, pgn) != NILLNODE) {
511*69086Schristos char *p1;
512*69086Schristos Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
513*69086Schristos if (p1)
514*69086Schristos free(p1);
51540393Sbostic }
51640393Sbostic switch(gn->made) {
51740393Sbostic case BEINGMADE:
51840393Sbostic Error("Graph cycles through %s\n", gn->name);
51940393Sbostic gn->made = ERROR;
52040393Sbostic pgn->make = FALSE;
52140393Sbostic break;
52240393Sbostic case MADE:
52340393Sbostic if ((gn->type & OP_EXEC) == 0) {
52440393Sbostic pgn->childMade = TRUE;
52540393Sbostic Make_TimeStamp(pgn, gn);
52640393Sbostic }
52740393Sbostic break;
52840393Sbostic case UPTODATE:
52940393Sbostic if ((gn->type & OP_EXEC) == 0) {
53040393Sbostic Make_TimeStamp(pgn, gn);
53140393Sbostic }
53240393Sbostic break;
53360285Sbostic default:
53460285Sbostic break;
53540393Sbostic }
53640393Sbostic }
53740393Sbostic
53840393Sbostic return (0);
53940393Sbostic }
54040393Sbostic
54140393Sbostic /*-
54240393Sbostic *-----------------------------------------------------------------------
54340393Sbostic * Compat_Run --
54440393Sbostic * Initialize this mode and start making.
54540393Sbostic *
54640393Sbostic * Results:
54740393Sbostic * None.
54840393Sbostic *
54940393Sbostic * Side Effects:
55040393Sbostic * Guess what?
55140393Sbostic *
55240393Sbostic *-----------------------------------------------------------------------
55340393Sbostic */
55440393Sbostic void
Compat_Run(targs)55540393Sbostic Compat_Run(targs)
55640393Sbostic Lst targs; /* List of target nodes to re-create */
55740393Sbostic {
55840393Sbostic char *cp; /* Pointer to string of shell meta-characters */
55960285Sbostic GNode *gn = NULL;/* Current root target */
56040393Sbostic int errors; /* Number of targets not remade due to errors */
56140393Sbostic
56240393Sbostic if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
56340393Sbostic signal(SIGINT, CompatInterrupt);
56440393Sbostic }
56540393Sbostic if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
56640393Sbostic signal(SIGTERM, CompatInterrupt);
56740393Sbostic }
56840393Sbostic if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
56940393Sbostic signal(SIGHUP, CompatInterrupt);
57040393Sbostic }
57140393Sbostic if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
57240393Sbostic signal(SIGQUIT, CompatInterrupt);
57340393Sbostic }
57440393Sbostic
57540393Sbostic for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) {
57660285Sbostic meta[(unsigned char) *cp] = 1;
57740393Sbostic }
57840393Sbostic /*
57940393Sbostic * The null character serves as a sentinel in the string.
58040393Sbostic */
58140393Sbostic meta[0] = 1;
58240393Sbostic
58340393Sbostic ENDNode = Targ_FindNode(".END", TARG_CREATE);
58440393Sbostic /*
58540393Sbostic * If the user has defined a .BEGIN target, execute the commands attached
58640393Sbostic * to it.
58740393Sbostic */
58840393Sbostic if (!queryFlag) {
58940393Sbostic gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
59040393Sbostic if (gn != NILGNODE) {
59140393Sbostic Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);
59240393Sbostic }
59340393Sbostic }
59440393Sbostic
59540393Sbostic /*
59640393Sbostic * For each entry in the list of targets to create, call CompatMake on
59740393Sbostic * it to create the thing. CompatMake will leave the 'made' field of gn
59840393Sbostic * in one of several states:
59940393Sbostic * UPTODATE gn was already up-to-date
60040393Sbostic * MADE gn was recreated successfully
60140393Sbostic * ERROR An error occurred while gn was being created
60240393Sbostic * ABORTED gn was not remade because one of its inferiors
60340393Sbostic * could not be made due to errors.
60440393Sbostic */
60540393Sbostic errors = 0;
60640393Sbostic while (!Lst_IsEmpty (targs)) {
60740393Sbostic gn = (GNode *) Lst_DeQueue (targs);
60840393Sbostic CompatMake (gn, gn);
60940393Sbostic
61040393Sbostic if (gn->made == UPTODATE) {
61140393Sbostic printf ("`%s' is up to date.\n", gn->name);
61240393Sbostic } else if (gn->made == ABORTED) {
61340393Sbostic printf ("`%s' not remade because of errors.\n", gn->name);
61440393Sbostic errors += 1;
61540393Sbostic }
61640393Sbostic }
61740393Sbostic
61840393Sbostic /*
61940393Sbostic * If the user has defined a .END target, run its commands.
62040393Sbostic */
62140393Sbostic if (errors == 0) {
62240393Sbostic Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn);
62340393Sbostic }
62440393Sbostic }
625