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