home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / make / compat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  17.1 KB  |  617 lines

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