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