Annotation of 43BSDReno/usr.bin/make/compat.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.